Skip to content

Commit 6652779

Browse files
authored
Merge pull request #1638 from virtualcell/dan-ss-batch-render
SpringSaLaD graphic editor fixes
2 parents f6e94f3 + fe37be2 commit 6652779

2 files changed

Lines changed: 114 additions & 31 deletions

File tree

vcell-client/src/main/java/cbit/vcell/mapping/gui/MolecularStructuresPropertiesPanel.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class MolecularStructuresPropertiesPanel extends DocumentEditorSubPanel {
4646

4747
private MolecularComponentPattern mcpSelected = null;
4848
private MolecularInternalLinkSpec milsSelected = null;
49+
private Object lastSelectedObject = null; // may be either MolecularComponentPattern or MolecularInternalLinkSpec
4950

5051
private JButton zoomLargerButton = null;
5152
private JButton zoomSmallerButton = null;
@@ -80,16 +81,32 @@ public void propertyChange(PropertyChangeEvent evt) {
8081
Object o = evt.getNewValue();
8182
if(o instanceof MolecularComponentPattern mcp) {
8283
mcpSelected = mcp;
84+
lastSelectedObject = mcpSelected;
8385
} else {
8486
mcpSelected = null;
87+
if(milsSelected != null) {
88+
// if we had a link selected before, it becomes the last (and only) selected
89+
lastSelectedObject = milsSelected;
90+
} else {
91+
// nothing is selected anymore
92+
lastSelectedObject = null;
93+
}
8594
}
8695
updateShape();
8796
} else if(evt.getSource() instanceof SpeciesContextSpec && evt.getPropertyName().equals(SpeciesContextSpec.PROPERTY_NAME_LINK_SELECTED_IN_TABLE)) {
8897
Object o = evt.getNewValue();
8998
if(o instanceof MolecularInternalLinkSpec mils) {
9099
milsSelected = mils;
100+
lastSelectedObject = milsSelected;
91101
} else {
92102
milsSelected = null;
103+
if(mcpSelected != null) {
104+
// if we had a site selected before, it becomes the last (and only) selected
105+
lastSelectedObject = mcpSelected;
106+
} else {
107+
// nothing is selected anymore
108+
lastSelectedObject = null;
109+
}
93110
}
94111
updateShape();
95112
}
@@ -121,7 +138,7 @@ public void paintComponent(Graphics g) {
121138
return;
122139
}
123140
scsls = new SpeciesContextSpecLargeShape(speciesContextSpec, shapePanel, speciesContextSpec,
124-
mcpSelected, milsSelected, issueManager);
141+
mcpSelected, milsSelected, lastSelectedObject, issueManager);
125142
scsls.paintSelf(g);
126143
}
127144
@Override
@@ -188,12 +205,14 @@ public void mouseClicked(MouseEvent e) {
188205
Object overObject = scsls.contains(overWhat); // check if we clicked inside a site oval or link line
189206
if(overObject instanceof MolecularInternalLinkSpec mils) {
190207
milsSelected = mils;
208+
lastSelectedObject = milsSelected;
191209
// redraw the whole shape to highlight the selected site oval
192210
updateShape();
193211
// we tell the table in the upper panel to update the selected row
194212
speciesContextSpec.firePropertyChange(PROPERTY_NAME_LINK_SELECTED_IN_SHAPE, null, milsSelected);
195213
} else if(overObject instanceof SiteAttributesSpec sas) {
196214
mcpSelected = sas.getMolecularComponentPattern();
215+
lastSelectedObject = mcpSelected;
197216
// redraw the whole shape to highlight the selected link line
198217
updateShape();
199218
// we tell the table in the upper panel to update the selected row
@@ -282,7 +301,7 @@ private void updateShape() {
282301
return;
283302
}
284303
scsls = new SpeciesContextSpecLargeShape(speciesContextSpec, shapePanel, speciesContextSpec,
285-
mcpSelected, milsSelected, issueManager);
304+
mcpSelected, milsSelected, lastSelectedObject, issueManager);
286305

287306
// shapePanel.setPreferredSize(scsls.getMaxSize());
288307

vcell-core/src/main/java/cbit/vcell/graph/SpeciesContextSpecLargeShape.java

Lines changed: 93 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import java.awt.geom.Ellipse2D;
1616
import java.awt.geom.Line2D;
1717
import java.util.*;
18-
import java.util.List;
1918

2019
public class SpeciesContextSpecLargeShape extends AbstractComponentShape implements HighlightableShapeInterface {
2120

@@ -33,9 +32,9 @@ public boolean contains(double x, double y) {
3332
}
3433
}
3534

36-
private static final double NmToPixelRatio = 25;
37-
private static final double DEFAULT_UPPER_CORNER = 3; // default screen coordinates where we want to display the first site
38-
private static final double DEFAULT_LEFT_CORNER = 10; // in nm
35+
private static final double NmToPixelRatio = 18;
36+
private static final double DEFAULT_UPPER_CORNER = 5.3; // default screen coordinates where we want to display the first site
37+
private static final double DEFAULT_LEFT_CORNER = 13; // in nm
3938

4039
// x, y positions where we want to begin drawing the shape (nm from top and left of painting area)
4140
private double x_offset = DEFAULT_LEFT_CORNER;
@@ -73,13 +72,17 @@ public boolean contains(double x, double y) {
7372

7473
Map<Ellipse2D, SiteAttributesSpec> ellipseToSasMap = new LinkedHashMap<>(); // site oval to site attributes map
7574
Map<CustomLine2D, MolecularInternalLinkSpec> lineToMilsMap = new LinkedHashMap<>(); // link line to link spec
75+
// we need also the inverse association
76+
Map<SiteAttributesSpec, Ellipse2D> sasToEllipseMap = new LinkedHashMap<>();
77+
Map<MolecularInternalLinkSpec, CustomLine2D> milsToLineMap = new LinkedHashMap<>();
7678

77-
private MolecularComponentPattern mcpSelected = null; // any or both of these may be selected in their tables
79+
private MolecularComponentPattern mcpSelected = null; // any or both of these may be selected in their tables, they are highlighted on the shape
7880
private MolecularInternalLinkSpec milsSelected = null;
81+
private Object lastSelectedObject = null; // this is the last selected object, we show it on top of everything else
7982

8083
public SpeciesContextSpecLargeShape(SpeciesContextSpec scs, LargeShapeCanvas shapePanel, Displayable owner,
8184
MolecularComponentPattern mcpSelected, MolecularInternalLinkSpec milsSelected,
82-
IssueListProvider issueListProvider) {
85+
Object lastSelectedObject, IssueListProvider issueListProvider) {
8386
super(issueListProvider);
8487

8588
this.owner = owner;
@@ -88,6 +91,7 @@ public SpeciesContextSpecLargeShape(SpeciesContextSpec scs, LargeShapeCanvas sha
8891

8992
this.mcpSelected = mcpSelected;
9093
this.milsSelected = milsSelected;
94+
this.lastSelectedObject = lastSelectedObject;
9195

9296
if(scs != null) {
9397
this.sc = scs.getSpeciesContext();
@@ -204,36 +208,30 @@ private void paintCompartments(Graphics g) {
204208
Stroke strokeOld = g2.getStroke();
205209

206210
Font font;
207-
int z = shapePanel.getZoomFactor();
208-
nmToPixelRatio = NmToPixelRatio + z;
211+
int zoomFactor = shapePanel.getZoomFactor();
212+
nmToPixelRatio = NmToPixelRatio + zoomFactor;
209213
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
210214

211215
String name = structure.getName();
212-
if(z > -3) {
216+
if(zoomFactor > -3) {
213217
font = fontOld.deriveFont(Font.BOLD);
214218
g.setFont(font);
215-
216219
} else {
217220
font = fontOld;
218221
g.setFont(font);
219222
}
220223

221224
g.setColor(Color.black);
225+
double VerticalTextOffset = 1.0; // vertical means y coord
222226
if(!hasMembraneSite) {
223227
double x = minX+x_offset;
224-
double y = 1;
225-
g2.drawString(name, (int)(nmToPixelRatio * x), (int)(nmToPixelRatio * y));
228+
double y = VerticalTextOffset;
229+
g2.drawString(name, (int)(nmToPixelRatio * x), (int)(NmToPixelRatio * y));
226230
} else {
227-
double x = membraneX+x_offset-5;
228-
double y = 1;
229-
g2.drawString("Extracellular", (int)(nmToPixelRatio * x), (int)(nmToPixelRatio * y));
230-
231-
x = membraneX+x_offset;
232-
y = 1;
233-
g2.drawString("Membrane Intracellular",
234-
(int)(nmToPixelRatio * x),
235-
// (int)(nmToPixelRatio * (x-membraneRadius)), // move it slightly to the left
236-
(int)(nmToPixelRatio * y));
231+
double x = membraneX+x_offset; // position of membrane bar
232+
double y = VerticalTextOffset;
233+
g2.drawString("Extracellular", (int)(nmToPixelRatio * (x-7)), (int)(NmToPixelRatio * y));
234+
g2.drawString("Intracellular", (int)(nmToPixelRatio * (x+3)), (int)(NmToPixelRatio * y));
237235

238236
g2.setColor(NamedColor.darker(Color.orange, 0.8));
239237
float thickness = 4.0f;
@@ -343,14 +341,14 @@ public Ellipse2D drawCenteredCircle(Graphics g, NamedColor namedColor, double xd
343341
nmToPixelRatio = NmToPixelRatio + z;
344342
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
345343

346-
xd = xd-(rd/2);
347-
yd = yd-(rd/2);
344+
xd = xd-rd;
345+
yd = yd-rd;
348346

349347
int x = (int)(nmToPixelRatio * xd);
350348
int y = (int)(nmToPixelRatio * yd);
351349
int r = (int)(nmToPixelRatio * rd);
352350

353-
Ellipse2D oval = new Ellipse2D.Double(x, y, r, r);
351+
Ellipse2D oval = new Ellipse2D.Double(x, y, 2*r, 2*r);
354352
g2.setColor(namedColor.getColor());
355353
g2.fill(oval);
356354

@@ -416,6 +414,9 @@ public void paintSelf(Graphics g, boolean bPaintContour) {
416414
}
417415
Map<MolecularComponentPattern, SiteAttributesSpec> sasMap = scs.getSiteAttributesMap();
418416
Set<MolecularInternalLinkSpec> internalLinkSet = scs.getInternalLinkSet();
417+
418+
// we draw all objects as unselected first, and then we redraw the selected objects on top of everything else,
419+
// so that they look highlighted and are not hidden behind other objects
419420
for(MolecularInternalLinkSpec mils : internalLinkSet) {
420421
Pair<MolecularComponentPattern, MolecularComponentPattern> link = mils.getLink();
421422
SiteAttributesSpec sas1 = sasMap.get(link.one);
@@ -424,9 +425,9 @@ public void paintSelf(Graphics g, boolean bPaintContour) {
424425
double x2 = x_offset + sas2.getCoordinate().getZ();
425426
double y1 = y_offset + sas1.getCoordinate().getY();
426427
double y2 = y_offset + sas2.getCoordinate().getY();
427-
boolean isSelected = mils == milsSelected ? true : false;
428-
CustomLine2D line = drawLink(g, x1, y1, x2, y2, isSelected);
428+
CustomLine2D line = drawLink(g, x1, y1, x2, y2, false);
429429
lineToMilsMap.put(line, mils);
430+
milsToLineMap.put(mils, line);
430431
}
431432
for(MolecularComponentPattern mcp : mtp.getComponentPatternList()) {
432433
SiteAttributesSpec sas = sasMap.get(mcp);
@@ -435,9 +436,72 @@ public void paintSelf(Graphics g, boolean bPaintContour) {
435436
NamedColor color = sas.getColor();
436437
double x = x_offset + coord.getZ();
437438
double y = y_offset + coord.getY();
438-
boolean isSelected = mcp == mcpSelected ? true : false;
439-
Ellipse2D oval = drawCenteredCircle(g, color, x, y, radius, isSelected);
439+
Ellipse2D oval = drawCenteredCircle(g, color, x, y, radius, false);
440440
ellipseToSasMap.put(oval, sas);
441+
sasToEllipseMap.put(sas, oval);
442+
}
443+
444+
// we redraw the selected objects on top of all unselected objects
445+
if(mcpSelected != null) {
446+
SiteAttributesSpec sas = sasMap.get(mcpSelected);
447+
Coordinate coord = sas.getCoordinate();
448+
double radius = sas.getRadius();
449+
NamedColor color = sas.getColor();
450+
double x = x_offset + coord.getZ();
451+
double y = y_offset + coord.getY();
452+
Ellipse2D newOval = drawCenteredCircle(g, color, x, y, radius, true);
453+
Ellipse2D oldOval = sasToEllipseMap.get(sas);
454+
sasToEllipseMap.put(sas, newOval);
455+
ellipseToSasMap.remove(oldOval);
456+
ellipseToSasMap.put(newOval, sas);
457+
}
458+
if(milsSelected != null) {
459+
Pair<MolecularComponentPattern, MolecularComponentPattern> link = milsSelected.getLink();
460+
SiteAttributesSpec sas1 = sasMap.get(link.one);
461+
SiteAttributesSpec sas2 = sasMap.get(link.two);
462+
double x1 = x_offset + sas1.getCoordinate().getZ();
463+
double x2 = x_offset + sas2.getCoordinate().getZ();
464+
double y1 = y_offset + sas1.getCoordinate().getY();
465+
double y2 = y_offset + sas2.getCoordinate().getY();
466+
CustomLine2D newLine = drawLink(g, x1, y1, x2, y2, true);
467+
// we need to extract the mils from the lineToMilsMap, because the line we just drew is not the same
468+
// as the one we drew in the first loop (and that is the one in the map)
469+
CustomLine2D oldLine = milsToLineMap.get(milsSelected);
470+
milsToLineMap.put(milsSelected, newLine);
471+
lineToMilsMap.remove(oldLine);
472+
lineToMilsMap.put(newLine, milsSelected);
473+
}
474+
475+
// we now redraw the last selected object on top of everything else
476+
if(lastSelectedObject != null) {
477+
if(lastSelectedObject instanceof MolecularComponentPattern) {
478+
MolecularComponentPattern mcp = (MolecularComponentPattern)lastSelectedObject;
479+
SiteAttributesSpec sas = sasMap.get(mcp);
480+
Coordinate coord = sas.getCoordinate();
481+
double radius = sas.getRadius();
482+
NamedColor color = sas.getColor();
483+
double x = x_offset + coord.getZ();
484+
double y = y_offset + coord.getY();
485+
Ellipse2D newOval = drawCenteredCircle(g, color, x, y, radius, true);
486+
Ellipse2D oldOval = sasToEllipseMap.get(sas);
487+
sasToEllipseMap.put(sas, newOval);
488+
ellipseToSasMap.remove(oldOval);
489+
ellipseToSasMap.put(newOval, sas);
490+
} else if(lastSelectedObject instanceof MolecularInternalLinkSpec) {
491+
MolecularInternalLinkSpec mils = (MolecularInternalLinkSpec)lastSelectedObject;
492+
Pair<MolecularComponentPattern, MolecularComponentPattern> link = mils.getLink();
493+
SiteAttributesSpec sas1 = sasMap.get(link.one);
494+
SiteAttributesSpec sas2 = sasMap.get(link.two);
495+
double x1 = x_offset + sas1.getCoordinate().getZ();
496+
double x2 = x_offset + sas2.getCoordinate().getZ();
497+
double y1 = y_offset + sas1.getCoordinate().getY();
498+
double y2 = y_offset + sas2.getCoordinate().getY();
499+
CustomLine2D newLine = drawLink(g, x1, y1, x2, y2, true);
500+
CustomLine2D oldLine = milsToLineMap.get(mils);
501+
milsToLineMap.put(mils, newLine);
502+
lineToMilsMap.remove(oldLine);
503+
lineToMilsMap.put(newLine, mils);
504+
}
441505
}
442506
}
443507

0 commit comments

Comments
 (0)