/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution 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 3 of the License, or * (at your option) any later version. * * logisim-evolution 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 logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.cburch.hex; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; class Measures { private HexEditor hex; private int headerChars; private int cellChars; private int headerWidth; private int spacerWidth; private int cellWidth; private int cellHeight; private int cols; private int baseX; private boolean guessed; public Measures(HexEditor hex) { this.hex = hex; this.guessed = true; this.cols = 1; this.cellWidth = -1; this.cellHeight = -1; this.cellChars = 2; this.headerChars = 4; computeCellSize(null); } private void computeCellSize(Graphics g) { HexModel model = hex.getModel(); // compute number of characters in headers and cells if (model == null) { headerChars = 4; cellChars = 2; } else { int logSize = 0; long addrEnd = model.getLastOffset(); while (addrEnd > (1L << logSize)) { logSize++; } headerChars = (logSize + 3) / 4; cellChars = (model.getValueWidth() + 3) / 4; } // compute character sizes FontMetrics fm = g == null ? null : g.getFontMetrics(hex.getFont()); int charWidth; int spaceWidth; int lineHeight; if (fm == null) { charWidth = 8; spaceWidth = 6; Font font = hex.getFont(); if (font == null) { lineHeight = 16; } else { lineHeight = font.getSize(); } } else { guessed = false; charWidth = 0; for (int i = 0; i < 16; i++) { int width = fm.stringWidth(Integer.toHexString(i)); if (width > charWidth) charWidth = width; } spaceWidth = fm.stringWidth(" "); lineHeight = fm.getHeight(); } // update header and cell dimensions headerWidth = headerChars * charWidth + spaceWidth; spacerWidth = spaceWidth; cellWidth = cellChars * charWidth + spaceWidth; cellHeight = lineHeight; // compute preferred size int width = headerWidth + cols * cellWidth + (cols / 4) * spacerWidth; long height; if (model == null) { height = 16 * cellHeight; } else { long addr0 = getBaseAddress(model); long addr1 = model.getLastOffset(); long rows = (int) (((addr1 - addr0 + 1) + cols - 1) / cols); height = rows * cellHeight; if (height > Integer.MAX_VALUE) height = Integer.MAX_VALUE; } // update preferred size Dimension pref = hex.getPreferredSize(); if (pref.width != width || pref.height != height) { pref.width = width; pref.height = (int) height; hex.setPreferredSize(pref); hex.revalidate(); } widthChanged(); } void ensureComputed(Graphics g) { if (guessed || cellWidth < 0) computeCellSize(g); } public long getBaseAddress(HexModel model) { if (model == null) { return 0; } else { long addr0 = model.getFirstOffset(); return addr0 - addr0 % cols; } } public int getBaseX() { return baseX; } public int getCellChars() { return cellChars; } public int getCellHeight() { return cellHeight; } public int getCellWidth() { return cellWidth; } public int getColumnCount() { return cols; } public int getLabelChars() { return headerChars; } public int getLabelWidth() { return headerWidth; } public int getValuesWidth() { return ((cols - 1) / 4) * spacerWidth + cols * cellWidth; } public int getValuesX() { return baseX + spacerWidth; } void recompute() { computeCellSize(hex.getGraphics()); } public long toAddress(int x, int y) { HexModel model = hex.getModel(); if (model == null) return Integer.MIN_VALUE; long addr0 = model.getFirstOffset(); long addr1 = model.getLastOffset(); long base = getBaseAddress(model) + ((long) y / cellHeight) * cols; int offs = (x - baseX) / (cellWidth + (spacerWidth + 2) / 4); if (offs < 0) offs = 0; if (offs >= cols) offs = cols - 1; long ret = base + offs; if (ret > addr1) ret = addr1; if (ret < addr0) ret = addr0; return ret; } public int toX(long addr) { int col = (int) (addr % cols); return baseX + (1 + (col / 4)) * spacerWidth + col * cellWidth; } public int toY(long addr) { long row = (addr - getBaseAddress(hex.getModel())) / cols; long ret = row * cellHeight; return ret < Integer.MAX_VALUE ? (int) ret : Integer.MAX_VALUE; } void widthChanged() { int oldCols = cols; int width; if (guessed || cellWidth < 0) { cols = 16; width = hex.getPreferredSize().width; } else { width = hex.getWidth(); int ret = (width - headerWidth) / (cellWidth + (spacerWidth + 3) / 4); if (ret >= 16) cols = 16; else if (ret >= 8) cols = 8; else cols = 4; } int lineWidth = headerWidth + cols * cellWidth + ((cols / 4) - 1) * spacerWidth; int newBase = headerWidth + Math.max(0, (width - lineWidth) / 2); if (baseX != newBase) { baseX = newBase; hex.repaint(); } if (cols != oldCols) recompute(); } }