refactoring of k-map, see #536

This commit is contained in:
hneemann 2020-10-24 11:43:11 +02:00
parent 9e478d9f5a
commit cb2657a65b
4 changed files with 141 additions and 68 deletions

View File

@ -50,18 +50,15 @@ public class KarnaughMap implements Iterable<KarnaughMap.Cover> {
cells = new ArrayList<>(); cells = new ArrayList<>();
covers = new ArrayList<>(); covers = new ArrayList<>();
boolean leftMode = mapLayout.getInvert(0);
boolean rightMode = mapLayout.getInvert(1);
boolean topMode = mapLayout.getInvert(2);
boolean bottomMode = mapLayout.getInvert(3);
switch (vars.size()) { switch (vars.size()) {
case 2: // create the needed KV cells case 2: // create the needed KV cells
for (int row = 0; row < 2; row++) for (int row = 0; row < 2; row++)
for (int col = 0; col < 2; col++) for (int col = 0; col < 2; col++)
cells.add(new Cell(row, col)); cells.add(new Cell(row, col));
boolean leftMode = mapLayout.getInvert(0);
headerLeft = new Header(mapLayout.get(0), !leftMode, leftMode).toRows(2, this); headerLeft = new Header(mapLayout.get(0), !leftMode, leftMode).toRows(2, this);
boolean topMode = mapLayout.getInvert(1);
headerTop = new Header(mapLayout.get(1), !topMode, topMode).toCols(2, this); headerTop = new Header(mapLayout.get(1), !topMode, topMode).toCols(2, this);
headerRight = null; headerRight = null;
headerBottom = null; headerBottom = null;
@ -71,8 +68,11 @@ public class KarnaughMap implements Iterable<KarnaughMap.Cover> {
for (int col = 0; col < 4; col++) for (int col = 0; col < 4; col++)
cells.add(new Cell(row, col)); cells.add(new Cell(row, col));
leftMode = mapLayout.getInvert(0);
headerLeft = new Header(mapLayout.get(0), !leftMode, leftMode).toRows(4, this); headerLeft = new Header(mapLayout.get(0), !leftMode, leftMode).toRows(4, this);
topMode = mapLayout.getInvert(1);
headerTop = new Header(mapLayout.get(1), !topMode, !topMode, topMode, topMode).toCols(2, this); headerTop = new Header(mapLayout.get(1), !topMode, !topMode, topMode, topMode).toCols(2, this);
boolean bottomMode = mapLayout.getInvert(2);
headerBottom = new Header(mapLayout.get(2), !bottomMode, bottomMode, bottomMode, !bottomMode).toCols(2, this); headerBottom = new Header(mapLayout.get(2), !bottomMode, bottomMode, bottomMode, !bottomMode).toCols(2, this);
headerRight = null; headerRight = null;
break; break;
@ -81,9 +81,13 @@ public class KarnaughMap implements Iterable<KarnaughMap.Cover> {
for (int col = 0; col < 4; col++) for (int col = 0; col < 4; col++)
cells.add(new Cell(row, col)); cells.add(new Cell(row, col));
leftMode = mapLayout.getInvert(0);
headerLeft = new Header(mapLayout.get(0), !leftMode, !leftMode, leftMode, leftMode).toRows(4, this); headerLeft = new Header(mapLayout.get(0), !leftMode, !leftMode, leftMode, leftMode).toRows(4, this);
boolean rightMode = mapLayout.getInvert(1);
headerRight = new Header(mapLayout.get(1), !rightMode, rightMode, rightMode, !rightMode).toRows(4, this); headerRight = new Header(mapLayout.get(1), !rightMode, rightMode, rightMode, !rightMode).toRows(4, this);
topMode = mapLayout.getInvert(2);
headerTop = new Header(mapLayout.get(2), !topMode, !topMode, topMode, topMode).toCols(4, this); headerTop = new Header(mapLayout.get(2), !topMode, !topMode, topMode, topMode).toCols(4, this);
bottomMode = mapLayout.getInvert(3);
headerBottom = new Header(mapLayout.get(3), !bottomMode, bottomMode, bottomMode, !bottomMode).toCols(4, this); headerBottom = new Header(mapLayout.get(3), !bottomMode, bottomMode, bottomMode, !bottomMode).toCols(4, this);
break; break;
default: default:

View File

@ -38,14 +38,14 @@ public class KarnaughMapComponent extends JComponent {
private Graphics2D gr; private Graphics2D gr;
private String message = Lang.get("msg_noKVMapAvailable"); private String message = Lang.get("msg_noKVMapAvailable");
private final MapLayout mapLayout = new MapLayout(0); private final MapLayout mapLayout = new MapLayout(0);
private final ArrayList<VarRect> varPosList = new ArrayList<>(); private final VarRectList varRectList = new VarRectList();
private int xOffs; private int xOffs;
private int yOffs; private int yOffs;
private int cellSize; private int cellSize;
private int xDrag; private int xDrag;
private int yDrag; private int yDrag;
private VarRect startVarRect = null; private VarRectList.VarRect startVarRect = null;
/** /**
* Creates a new instance * Creates a new instance
@ -97,7 +97,6 @@ public class KarnaughMapComponent extends JComponent {
@Override @Override
protected void paintComponent(Graphics graphics) { protected void paintComponent(Graphics graphics) {
varPosList.clear();
gr = (Graphics2D) graphics; gr = (Graphics2D) graphics;
gr.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); gr.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
@ -109,9 +108,6 @@ public class KarnaughMapComponent extends JComponent {
gr.fillRect(0, 0, width, height); gr.fillRect(0, 0, width, height);
gr.setColor(Color.BLACK); gr.setColor(Color.BLACK);
if (startVarRect != null)
startVarRect.fragment.draw(gr, xDrag, yDrag);
if (kv != null) { if (kv != null) {
AffineTransform trans = gr.getTransform(); // store the old transform AffineTransform trans = gr.getTransform(); // store the old transform
@ -166,6 +162,9 @@ public class KarnaughMapComponent extends JComponent {
(cell.getRow() + 2) * cellSize - 1); (cell.getRow() + 2) * cellSize - 1);
} }
// remove old var rectangles
varRectList.reset(xOffs, yOffs);
// draw the text in the borders // draw the text in the borders
gr.setColor(Color.BLACK); gr.setColor(Color.BLACK);
gr.setFont(headerFont); gr.setFont(headerFont);
@ -214,6 +213,11 @@ public class KarnaughMapComponent extends JComponent {
gr.setTransform(trans); gr.setTransform(trans);
} else } else
gr.drawString(message, 10, 20); gr.drawString(message, 10, 20);
if (startVarRect != null) {
gr.setColor(Color.BLACK);
startVarRect.getFragment().draw(gr, xDrag, yDrag);
}
} }
private boolean isNoHeaderLine(KarnaughMap.Header header, int i) { private boolean isNoHeaderLine(KarnaughMap.Header header, int i) {
@ -232,7 +236,8 @@ public class KarnaughMapComponent extends JComponent {
dx = cellSize / 2; dx = cellSize / 2;
} }
int var = header.getVar(); int var = header.getVar();
drawFragment(getFragment(var, header.getInvert(i)), i + 1, pos, dx, 0, var); boolean invert = header.getInvert(i);
drawFragment(var, invert, i + 1, pos, dx, 0);
} }
} }
@ -245,7 +250,8 @@ public class KarnaughMapComponent extends JComponent {
dy = cellSize / 2; dy = cellSize / 2;
} }
int var = header.getVar(); int var = header.getVar();
drawFragment(getFragment(var, header.getInvert(i)), pos, i + 1, 0, dy, var); boolean invert = header.getInvert(i);
drawFragment(var, invert, pos, i + 1, 0, dy);
} }
} }
//CHECKSTYLE.ON: ModifiedControlVariable //CHECKSTYLE.ON: ModifiedControlVariable
@ -258,7 +264,8 @@ public class KarnaughMapComponent extends JComponent {
gr.drawString(s, row * cellSize + xPos, col * cellSize + yPos); gr.drawString(s, row * cellSize + xPos, col * cellSize + yPos);
} }
private void drawFragment(GraphicsFormatter.Fragment fr, int row, int col, int xOffs, int yOffs, int var) { private void drawFragment(int var, boolean invert, int row, int col, int xOffs, int yOffs) {
GraphicsFormatter.Fragment fr = getFragment(var, invert);
if (fr == null) if (fr == null)
return; return;
FontMetrics fontMetrics = gr.getFontMetrics(); FontMetrics fontMetrics = gr.getFontMetrics();
@ -267,7 +274,10 @@ public class KarnaughMapComponent extends JComponent {
int xFr = row * cellSize + xPos - xOffs; int xFr = row * cellSize + xPos - xOffs;
int yFr = col * cellSize + yPos - yOffs; int yFr = col * cellSize + yPos - yOffs;
fr.draw(gr, xFr, yFr); fr.draw(gr, xFr, yFr);
varPosList.add(new VarRect(var, xFr, yFr + fontMetrics.getDescent() - fr.getHeight(), fr.getWidth(), fr.getHeight(), fr));
// register fragment for drag&drop action
Rectangle r = new Rectangle(xFr, yFr + fontMetrics.getDescent() - fr.getHeight(), fr.getWidth(), fr.getHeight());
varRectList.add(var, invert, r, fr);
} }
private GraphicsFormatter.Fragment getFragment(int var, boolean invert) { private GraphicsFormatter.Fragment getFragment(int var, boolean invert) {
@ -311,19 +321,13 @@ public class KarnaughMapComponent extends JComponent {
if (x >= 0 && x < kv.getColumns() && y >= 0 && y < kv.getRows()) { if (x >= 0 && x < kv.getColumns() && y >= 0 && y < kv.getRows()) {
int row = kv.getCell(y, x).getBoolTableRow(); int row = kv.getCell(y, x).getBoolTableRow();
tableCellModifier.modify(boolTable, row); tableCellModifier.modify(boolTable, row);
} else {
VarRect varAt = findVarRect(mouseEvent);
if (varAt != null) {
mapLayout.toggleInvertByMouse(varAt.var);
update();
}
} }
} }
} }
@Override @Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
startVarRect = findVarRect(e); startVarRect = varRectList.findVarRect(e);
} }
@Override @Override
@ -337,45 +341,12 @@ public class KarnaughMapComponent extends JComponent {
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
VarRect endVarRect = findVarRect(e); VarRectList.VarRect endVarRect = varRectList.findVarRect(e);
if (startVarRect != null && endVarRect != null if (mapLayout.swapByDragAndDrop(startVarRect, endVarRect))
&& startVarRect.isValid(vars.size())
&& endVarRect.isValid(vars.size())
&& startVarRect.var != endVarRect.var) {
mapLayout.swapByMouse(startVarRect.var, endVarRect.var);
startVarRect = null;
update(); update();
} else { else
startVarRect = null;
repaint(); repaint();
} startVarRect = null;
} }
} }
private VarRect findVarRect(MouseEvent e) {
int x = e.getX() - xOffs;
int y = e.getY() - yOffs;
for (VarRect r : varPosList) {
if (r.rect.contains(x, y))
return r;
}
return null;
}
private static final class VarRect {
private final Rectangle rect;
private final int var;
private final GraphicsFormatter.Fragment fragment;
private VarRect(int var, int x, int y, int width, int height, GraphicsFormatter.Fragment fragment) {
this.var = var;
rect = new Rectangle(x, y, width, height);
this.fragment = fragment;
}
private boolean isValid(int size) {
return var >= 0 && var < size;
}
}
} }

View File

@ -23,12 +23,16 @@ public class MapLayout {
return -1; return -1;
} }
void swapVars(int startVar, int endVar) { private void swapVars(int startVar, int endVar) {
int t = swap[startVar]; int t = swap[startVar];
swap[startVar] = swap[endVar]; swap[startVar] = swap[endVar];
swap[endVar] = t; swap[endVar] = t;
} }
private void toggleInvert(int n) {
mode ^= (1 << n);
}
/** /**
* Checks is the given swap list is valid (not null and of the correct size). * Checks is the given swap list is valid (not null and of the correct size).
* If so, the given list is preserved, if not, a simple, non swapping default swap * If so, the given list is preserved, if not, a simple, non swapping default swap
@ -45,16 +49,19 @@ public class MapLayout {
mode = 0; mode = 0;
} }
void swapByMouse(int startVar, int endVar) { boolean swapByDragAndDrop(VarRectList.VarRect startVar, VarRectList.VarRect endVar) {
swapVars(indexOf(startVar), indexOf(endVar)); if (startVar == null || endVar == null || startVar.equals(endVar))
} return false;
void toggleInvert(int n) { int start = indexOf(startVar.getVar());
mode ^= (1 << n); int end = indexOf(endVar.getVar());
} if (start != end)
swapVars(start, end);
void toggleInvertByMouse(int n) { if (startVar.getInvert() != endVar.getInvert())
toggleInvert(indexOf(n)); toggleInvert(end);
return true;
} }
boolean getInvert(int n) { boolean getInvert(int n) {

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2020 Helmut Neemann.
* Use of this source code is governed by the GPL v3 license
* that can be found in the LICENSE file.
*/
package de.neemann.digital.gui.components.karnaugh;
import de.neemann.digital.draw.graphics.text.formatter.GraphicsFormatter;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Objects;
final class VarRectList {
private final ArrayList<VarRect> varRectList;
private int xOffs;
private int yOffs;
VarRectList() {
varRectList = new ArrayList<>();
}
public void reset(int xOffs, int yOffs) {
this.xOffs = xOffs;
this.yOffs = yOffs;
varRectList.clear();
}
public void add(int var, boolean invert, Rectangle r, GraphicsFormatter.Fragment fr) {
varRectList.add(new VarRect(var, invert, r, fr));
}
VarRect findVarRect(MouseEvent e) {
int x = e.getX() - xOffs;
int y = e.getY() - yOffs;
for (VarRect r : varRectList) {
if (r.rect.contains(x, y))
return r;
}
return null;
}
static final class VarRect {
private final boolean invert;
private final Rectangle rect;
private final int var;
private final GraphicsFormatter.Fragment fragment;
private VarRect(int var, boolean invert, Rectangle rect, GraphicsFormatter.Fragment fragment) {
this.var = var;
this.invert = invert;
this.rect = rect;
this.fragment = fragment;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VarRect varRect = (VarRect) o;
return invert == varRect.invert && var == varRect.var;
}
@Override
public int hashCode() {
return Objects.hash(invert, var);
}
int getVar() {
return var;
}
boolean getInvert() {
return invert;
}
GraphicsFormatter.Fragment getFragment() {
return fragment;
}
@Override
public String toString() {
return "VarRect{"
+ "invert="
+ invert
+ ", var=" + var
+ '}';
}
}
}