Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve UI Indication for Unsaved Changes in Tabs #1632

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -877,44 +877,58 @@ 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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this code, and, in general, tab presentation (font style, color, text decoration, borders, close icon) could be delegated to a new callback interface that, if the callback is not set, would by default use current SWT implementation, and if set, would give the callback full control of the tab visuals.
This way SWT could keep its code independent of the application needs and application (like workbench renderers) could implement whatever possible.

I personally would like to see dirty tabs in bold red font and I don't want to see close buttons at all to save space. I've had that in my Extended VS Presentation plugin for Eclipse 3.x many years ago before e4 killed Presentation API.
That's of course much more as proposal here, but it shouldbe doable and it would allow 3rd parties to decide whether they want close buttons turned into circles or disappear completely or just stay "old good" black crosses etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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);
int state = closeImageState & (SWT.HOT | SWT.SELECTED | SWT.BACKGROUND);
if (state == SWT.NONE) {
if (showDirtyIndicator)
drawDirtyIndicator(gc, closeRect, originalForeground, 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, originalForeground, false);
else
drawBackground(gc, closeRect, SWT.BACKGROUND);

}
gc.setLineWidth(originalLineWidth);
gc.setForeground(originalForeground);
}

private void drawCloseLines(GC gc, int x, int y, int lineLength, boolean hot) {
private void drawDirtyIndicator(GC gc, Rectangle closeRect, Color originalForeground, boolean hot) {
Color originalBackground = gc.getBackground();
gc.setBackground(originalForeground);
gc.fillOval(closeRect.x + 3, closeRect.y + 4, closeRect.width - 6, closeRect.height - 6);
gc.setBackground(originalBackground);
}

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 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 +1477,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 +1686,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
Loading