/* Copyright (C) 2007 Felipe A. Lessa * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ package tirateima.gui.variaveis; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.geom.RoundRectangle2D.Float; import javax.swing.JComponent; import tirateima.gui.Constantes; import tirateima.gui.arquivos.IDataReader; /** * * Representa um tipo do Pascal. É responsável por desenhar a variável e manter * seu conteúdo em ordem. * * @author felipe.lessa * @since 2007/04/03 * */ @SuppressWarnings("serial") public abstract class Variavel extends JComponent implements IDataReader { protected String nome; protected Boolean mostraNome; protected boolean modificado = true; protected boolean destacado; protected double proporcao; protected Color cor = null; protected Color corExterna = null; //Usada para arrays e matrizes protected Dimension dimensao = null; protected Point posicao = null; /** * Cria uma nova variável com este nome. * @param nome nome da variável. */ protected Variavel(String nome) { this.nome = nome; } /** * Cria uma cópia exata porém desconexa desta variável. * @return A cópia. */ public abstract Variavel criarCopia(); /** * Retorna uma "assinatura" para essa variável, * na forma <tipo> <nome> <dimensão (talvez)>. * * @return */ public abstract String signature(); /** * Retorna o nome do tipo dessa variável. * * @return */ public abstract String typeName(); /** * Usado para que outro componente defina a proporção necessária * para que este tipo caiba bem. * * @return O tamanho padrão deste tipo (em pixels). */ public abstract Dimension getTamanhoPadrao(); /** * Desenha o conteúdo atual desta variável a uma determinada proporção. * @param g o Graphics2D onde será desenhado. * @see #setProporcao(double) */ @Override public void paint(Graphics g) { // Dimension tamAtual = dimensao == null? super.getSize() : dimensao; // Configura o tamanho por variavel. Causa bug em array. Ver figuras: tamanho_interno_auto e tamanho_interno_manual Dimension tamAtual = super.getSize(); int arc = (int) (5 * proporcao); g.setColor(Color.GRAY); g.fillRoundRect(0, 0, tamAtual.width, tamAtual.height, arc, arc); g.setColor(modificado ? Constantes.COR_FUNDO_MODIFICADO : Constantes.COR_FUNDO_NORMAL); g.fillRoundRect(1, 1, tamAtual.width-2, tamAtual.height-2, arc, arc); Float rect = new RoundRectangle2D.Float(0, 0, tamAtual.width, tamAtual.height, arc, arc); ((Graphics2D)g).clip(rect); } /** * O estado atual da variável, modificada ou não. Quando modificada, * seu desenho passa ser destacado. * @return true se o estado for "modificado". * @see #setModificado(boolean) * * @author Luciano Santos */ public boolean getModificado() { return modificado; } /** * Define se a variável deve ser desenhada como modificada ou não. * @param modificado * @see #getModificado() */ public void setModificado(boolean modificado) { this.modificado = modificado; repaint(); } /** * Retorna o valor atual da variável. Use com cuidado pois a variável * pode ser de qualquer tipo. * @return o valor atual. */ public abstract Object getValor(); /** * Define o valor atual da variável. Uma chamada a este método *não* * modifica o valor de "modificado". Caso você deseje destacar a variável, * chame o método setModificado. * @param valor o novo valor da variável. */ public abstract void setValor(Object valor); /** * A proporção que será utilizada quando o desenho da variável for feito. * @return a proporção (onde 1.0 é equivalente a 100%). * @see #setProporcao(double) */ public double getProporcao() { return proporcao; } /** * Define a proporção que será utilizada. Deve ser um número positivo. * @param prop a nova proporção (onde 1.0 é equivalente a 100%). * @see #setProporcao(Dimension) * @see #getProporcao() */ public void setProporcao(double prop) { if (prop <= 0) throw new AssertionError("Proporção deve ser positiva."); proporcao = prop; setSize(getSize()); validate(); } /** * O nome desta variável. Pode não ser um identificador válido Pascal * (e.g. quando a variável for elemento de um array) ou pode ser nulo. * @return o nome da variável. */ @Override public String getName() { return nome; } /** * A cor do título da janela dependendo do tipo de variável. * @return a cor do título. */ public abstract Color getCorTitulo(); /** * Define a proporção que será utilizada quando o desenho da variável for * feito a partir de um tamanho máximo. Caso o tamanho não seja um múltiplo * do tamanho padrão, parte da área não será utilizada. * @param tamanho tamanho máximo a ser usado no desenho. * @see #setProporcao(double) */ public void setProporcao(Dimension tamanho) { if (tamanho.width <= 0 || tamanho.height <= 0) throw new AssertionError("Tamanho negativo ou nulo"); Dimension padrao = getTamanhoPadrao(); double propWidth = tamanho.width / (double) padrao.width; double propHeight = tamanho.height / (double) padrao.height; setProporcao(Math.min(propWidth, propHeight)); } /** * Calcula o tamanho final desta variável para uma certa proporação. * Basicamente multiplica o tamanho padrão pela proporção. * @return o tamanho final. * @see #getTamanhoPadrao() * @see #setProporcao(double) */ @Override public Dimension getSize() { double prop = getProporcao(); Dimension original = getTamanhoPadrao(); double newWidth = original.width * prop; double newHeight = original.height * prop; return new Dimension((int) Math.ceil(newWidth), (int) Math.ceil(newHeight)); } // Métodos protegidos auxiliares /** * Retorna uma fonte igual à original, porém com a proporção atual aplicada * ao seu tamanho. * @param original fonte original a ser modificada. * @return a fonte original com o tamnho modificado. */ protected Font proporcional(Font original) { double tamanho = original.getSize2D() * proporcao; return original.deriveFont((float) tamanho); } /** * Retorna uma fonte igual à original, porém com a proporção atual aplicada * ao seu tamanho. * @param original fonte original a ser modificada. * @param tamanhoCaixa usado para calcular a fonte dependendo do tamanho da variável (tamanho(x,y)) * @param texto a ser escrito * @param g Graphics * @return a fonte original com o tamnho modificado. */ protected Font proporcional(Font original, Dimension tamanhoCaixa, String texto, Graphics g) { Font nova; double tamanho; float razao = 0.6f; Rectangle2D rect; int loop = 100; do{ tamanho = original.getSize2D() * proporcao + tamanhoCaixa.height * razao; nova = original.deriveFont((float) tamanho); FontMetrics metrics = g.getFontMetrics(nova); rect = metrics.getStringBounds(texto, g); razao = razao - 0.1f; loop--; if(loop < 0) break; }while(rect.getWidth() > tamanhoCaixa.width); return nova; } /** * Retorna o tamanho real desta variável. * @return o tamanho dado pelo container. */ protected Dimension getRealSize() { return super.getSize(); } /** * Chama o método paint da classe pai (JComponent). * @param g */ protected void realPaint(Graphics g) { super.paint(g); } // Não vamos usar estes métodos, mesmo porque dependendo da proporção // uma determinada variável pode ficar "invisível" de tão pequena. @Override public Dimension getMinimumSize() { return new Dimension(0, 0); } @Override public Dimension getMaximumSize() { return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); } @Override public void setName(String name) { //throw new AssertionError("O nome não deve ser modificado."); this.nome = name == null ? "" : name; } public Boolean getMostraNome() { return mostraNome; } public void setMostraNome(Boolean mostraNome) { this.mostraNome = mostraNome; } }