Skip to content

Commit

Permalink
Change rendering of dirty indicator in tabs - using a circle
Browse files Browse the repository at this point in the history
Tabs render dirty parts by showing a `*` in front of the tab name (e.g.,
in front of the file name.

This information is hard to see by developers. This change introduces a
graphical indicator on the close button to highlight dirty (unsaved)
changes.
  • Loading branch information
schneidermic0 committed Dec 18, 2024
1 parent f50772b commit af3fc88
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -877,44 +877,57 @@ void drawBody(GC gc, Rectangle bounds, int state) {
}
}

void drawClose(GC gc, Rectangle closeRect, int closeImageState) {
void drawClose(GC gc, Rectangle closeRect, int closeImageState, boolean showDirtyIndicator) {
if (closeRect.width == 0 || closeRect.height == 0) return;

// draw X with length of this constant
final int lineLength = 8;
int x = closeRect.x + Math.max(1, (closeRect.width-lineLength)/2);
int y = closeRect.y + Math.max(1, (closeRect.height-lineLength)/2);
y += parent.onBottom ? -1 : 1;
int originalLineWidth = gc.getLineWidth();
Color originalForeground = gc.getForeground();
switch (closeImageState & (SWT.HOT | SWT.SELECTED | SWT.BACKGROUND)) {
case SWT.NONE: {
drawCloseLines(gc, x, y , lineLength, false);
break;
}
case SWT.HOT: {
drawCloseLines(gc, x, y , lineLength, true);
break;
}
case SWT.SELECTED: {
drawCloseLines(gc, x, y , lineLength, true);
break;
}
case SWT.BACKGROUND: {
int[] shape = new int[] {x,y, x+10,y, x+10,y+10, x,y+10};
drawBackground(gc, shape, false);
break;
}
}
gc.setLineWidth(originalLineWidth);
gc.setForeground(originalForeground);
int state = closeImageState & (SWT.HOT | SWT.SELECTED | SWT.BACKGROUND);
if (state == SWT.NONE) {
if (showDirtyIndicator)
drawDirtyIndicator(gc, closeRect, false);
else
drawCloseButton(gc, closeRect, false);
} else if (state == SWT.HOT || state == SWT.SELECTED) {
drawCloseButton(gc, closeRect, true);
} else if (state == SWT.BACKGROUND) {
if (showDirtyIndicator)
drawDirtyIndicator(gc, closeRect, false);
else
drawBackground(gc, closeRect, SWT.BACKGROUND);
}
gc.setLineWidth(originalLineWidth);
}

private void drawDirtyIndicator(GC gc, Rectangle closeRect, boolean hot) {
String DIRTY_INDICATOR = "●";

Point stringExtent = gc.stringExtent(DIRTY_INDICATOR);
int x = closeRect.x + (closeRect.width - stringExtent.x) / 2;
int y = closeRect.y + (closeRect.height - stringExtent.y) / 2;
gc.drawString(DIRTY_INDICATOR, x, y, true);
}

private void drawCloseBackground(GC gc, Rectangle closeRect, Color backgroundColor) {
Color originalBackground = gc.getBackground();
gc.setBackground(backgroundColor);
gc.setForeground(originalBackground);
gc.fillRoundRectangle(closeRect.x + 1, closeRect.y + 2, closeRect.width - 2, closeRect.height - 2, 4, 4);
gc.setBackground(originalBackground);
}

private void drawCloseLines(GC gc, int x, int y, int lineLength, boolean hot) {

private void drawCloseButton(GC gc, Rectangle closeRect, boolean hot) {
if (hot) {
gc.setLineWidth(gc.getLineWidth() + 2);
gc.setForeground(getFillColor());
drawCloseBackground(gc, closeRect, parent.getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
// gc.setLineWidth(gc.getLineWidth() + 2);
gc.setForeground(gc.getBackground());
}
// draw X with length of this constant
final int lineLength = 9;
int x = closeRect.x + Math.max(1, (closeRect.width-lineLength)/2);
int y = closeRect.y + Math.max(1, (closeRect.height-lineLength)/2);
y += parent.onBottom ? -1 : 1;

gc.setLineCap(SWT.CAP_ROUND);
gc.drawLine(x, y, x + lineLength, y + lineLength);
gc.drawLine(x, y + lineLength, x + lineLength, y);
Expand Down Expand Up @@ -1463,7 +1476,7 @@ void drawSelected(int itemIndex, GC gc, Rectangle bounds, int state ) {
gc.setBackground(orginalBackground);
}
}
if (shouldDrawCloseIcon(item)) drawClose(gc, item.closeRect, item.closeImageState);
if (shouldDrawCloseIcon(item)) drawClose(gc, item.closeRect, item.closeImageState, item.showDirty);
}
}

Expand Down Expand Up @@ -1672,7 +1685,7 @@ void drawUnselected(int index, GC gc, Rectangle bounds, int state) {
gc.setFont(gcFont);
}
// draw close
if (shouldDrawCloseIcon(item)) drawClose(gc, item.closeRect, item.closeImageState);
if (shouldDrawCloseIcon(item)) drawClose(gc, item.closeRect, item.closeImageState, item.showDirty);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class CTabItem extends Item {
int closeImageState = SWT.BACKGROUND;
int state = SWT.NONE;
boolean showClose = false;
boolean showDirty = false;
boolean showing = false;

/**
Expand Down Expand Up @@ -276,6 +277,20 @@ public boolean getShowClose() {
checkWidget();
return showClose;
}

/**
* Returns <code>true</code> to indicate that the dirty indicator should be shown.
* Otherwise return <code>false</code>.
*
* @return <code>true</code> if the dirty indicatorn should be shown
*
* @since 4.35
*/
public boolean getShowDirty() {
checkWidget();
return showClose;
}

/**
* Returns the receiver's tool tip text, or null if it has
* not been set.
Expand Down Expand Up @@ -490,6 +505,21 @@ public void setShowClose(boolean close) {
showClose = close;
parent.updateFolder(CTabFolder.REDRAW_TABS);
}

/**
* Sets to <code>true</code> to indicate that the dirty indicator should be shown.
*
* @param dirty the new value whether the dirty indicator shall be shown
*
* @since 4.35
*/
public void setShowDirty(boolean dirty) {
checkWidget();
if (showDirty == dirty) return;
showDirty = dirty;
parent.updateFolder(CTabFolder.REDRAW_TABS);
}

/**
* Sets the text to display on the tab.
* A carriage return '\n' allows to display multi line text.
Expand Down

0 comments on commit af3fc88

Please sign in to comment.