You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by lk...@apache.org on 2020/01/19 00:44:18 UTC
[netbeans] branch master updated: [NETBEANS-3428] FlatLaf:
improving editor and view tabs in main window
This is an automated email from the ASF dual-hosted git repository.
lkishalmi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new ab0fedf [NETBEANS-3428] FlatLaf: improving editor and view tabs in main window
ab0fedf is described below
commit ab0fedf0a11e6b428e062d6538c209b3b2740f17
Author: Karl Tauber <ka...@jformdesigner.com>
AuthorDate: Sat Jan 18 17:40:20 2020 +0100
[NETBEANS-3428] FlatLaf: improving editor and view tabs in main window
Editor and View tabs:
- tab separators
- tab text moved up 1px
- smaller tab insets
- minimize icon improved
View tabs only:
- minimized space between tab text and close button
- center tab text if close button is hidden
- make sure that as much tab text as possible is shown by dynamically reducing left/right margins
- avoid empty tabs (truncate text if necessary)
---
.../netbeans/swing/laf/flatlaf/FlatLaf.properties | 8 ++-
.../laf/flatlaf/ui/FlatEditorTabCellRenderer.java | 29 +++++++--
.../laf/flatlaf/ui/FlatEditorTabDisplayerUI.java | 10 +++
.../swing/laf/flatlaf/ui/FlatTabControlIcon.java | 12 ++--
.../laf/flatlaf/ui/FlatViewTabDisplayerUI.java | 74 ++++++++++++++++++----
5 files changed, 106 insertions(+), 27 deletions(-)
diff --git a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/FlatLaf.properties b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/FlatLaf.properties
index 88ceb0b..affe2e0 100644
--- a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/FlatLaf.properties
+++ b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/FlatLaf.properties
@@ -34,16 +34,20 @@ TabbedContainer.view.contentBorderColor=$Component.borderColor
#---- EditorTab ----
-EditorTab.tabInsets=6,8,6,8
+EditorTab.tabInsets=5,6,7,6
EditorTab.underlineHeight=3
#EditorTab.underlineAtTop=true
+EditorTab.tabSeparatorColor=$Component.borderColor
+EditorTab.showTabSeparators=true
#---- ViewTab ----
-ViewTab.tabInsets=6,8,6,8
+ViewTab.tabInsets=5,6,7,0
ViewTab.underlineHeight=3
#ViewTab.underlineAtTop=true
+ViewTab.tabSeparatorColor=$Component.borderColor
+ViewTab.showTabSeparators=true
#---- Multi-tabs ----
diff --git a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatEditorTabCellRenderer.java b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatEditorTabCellRenderer.java
index a4048aa..db7b332 100644
--- a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatEditorTabCellRenderer.java
+++ b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatEditorTabCellRenderer.java
@@ -58,14 +58,18 @@ public class FlatEditorTabCellRenderer extends AbstractTabCellRenderer {
private static final Color underlineColor = UIManager.getColor("EditorTab.underlineColor"); // NOI18N
private static final Color inactiveUnderlineColor = UIManager.getColor("EditorTab.inactiveUnderlineColor"); // NOI18N
+ private static final Color tabSeparatorColor = UIManager.getColor("EditorTab.tabSeparatorColor"); // NOI18N
private static final Color contentBorderColor = UIManager.getColor("TabbedContainer.editor.contentBorderColor"); // NOI18N
private static final Insets tabInsets = UIScale.scale(UIManager.getInsets("EditorTab.tabInsets")); // NOI18N
private static final int underlineHeight = UIScale.scale(UIManager.getInt("EditorTab.underlineHeight")); // NOI18N
private static final boolean underlineAtTop = UIManager.getBoolean("EditorTab.underlineAtTop"); // NOI18N
+ private static boolean showTabSeparators = UIManager.getBoolean("EditorTab.showTabSeparators"); // NOI18N
private static final FlatTabPainter painter = new FlatTabPainter();
+ boolean nextTabSelected;
+
public FlatEditorTabCellRenderer() {
super(painter, new Dimension(tabInsets.left + tabInsets.right, tabInsets.top + tabInsets.bottom));
}
@@ -198,25 +202,40 @@ public class FlatEditorTabCellRenderer extends AbstractTabCellRenderer {
FlatEditorTabCellRenderer ren = (FlatEditorTabCellRenderer) c;
boolean selected = ren.isSelected();
+ // get background color
+ Color bg = ren.colorForState(
+ background, activeBackground, selectedBackground,
+ hoverBackground, attentionBackground);
+
+ boolean showSeparator = showTabSeparators && !selected && !ren.nextTabSelected;
+
+ // do not round tab separator width to get nice small lines at 125%, 150% and 175%
+ int tabSeparatorWidth = showSeparator ? (int) (1 * scale) : 0;
+
// paint background
- g.setColor(ren.colorForState(background, activeBackground, selectedBackground,
- hoverBackground, attentionBackground));
- g.fillRect(0, 0, width, height);
+ g.setColor(bg);
+ g.fillRect(0, 0, width - (bg != background ? tabSeparatorWidth : 0), height);
if (selected && underlineHeight > 0) {
// paint underline if tab is selected
int underlineHeight = (int) Math.round(FlatEditorTabCellRenderer.underlineHeight * scale);
g.setColor(ren.isActive() ? underlineColor : inactiveUnderlineColor);
if (underlineAtTop)
- g.fillRect(0, 0, width, underlineHeight);
+ g.fillRect(0, 0, width - tabSeparatorWidth, underlineHeight);
else
- g.fillRect(0, height - underlineHeight, width, underlineHeight);
+ g.fillRect(0, height - underlineHeight, width - tabSeparatorWidth, underlineHeight);
} else {
// paint bottom border
int contentBorderWidth = HiDPIUtils.deviceBorderWidth(scale, 1);
g.setColor(contentBorderColor);
g.fillRect(0, height - contentBorderWidth, width, contentBorderWidth);
}
+
+ if (showSeparator) {
+ int offset = (int) (4 * scale);
+ g.setColor(tabSeparatorColor);
+ g.fillRect(width - tabSeparatorWidth, offset, tabSeparatorWidth, height - (offset * 2) - 1);
+ }
}
private void paintCloseButton(Graphics g, FlatEditorTabCellRenderer ren) {
diff --git a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatEditorTabDisplayerUI.java b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatEditorTabDisplayerUI.java
index 1818953..c20c68b 100644
--- a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatEditorTabDisplayerUI.java
+++ b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatEditorTabDisplayerUI.java
@@ -36,6 +36,7 @@ import org.netbeans.swing.laf.flatlaf.HiDPIUtils;
import org.netbeans.swing.tabcontrol.TabDisplayer;
import org.netbeans.swing.tabcontrol.plaf.BasicScrollingTabDisplayerUI;
import org.netbeans.swing.tabcontrol.plaf.TabCellRenderer;
+import org.netbeans.swing.tabcontrol.plaf.TabState;
/**
* Tab displayer UI for FlatLaf look and feel
@@ -77,6 +78,15 @@ public class FlatEditorTabDisplayerUI extends BasicScrollingTabDisplayerUI {
}
@Override
+ public TabCellRenderer getTabCellRenderer(int tab) {
+ TabCellRenderer ren = super.getTabCellRenderer(tab);
+ if (ren instanceof FlatEditorTabCellRenderer && tab + 1 < displayer.getModel().size()) {
+ ((FlatEditorTabCellRenderer)ren).nextTabSelected = (tabState.getState(tab + 1) & TabState.SELECTED) != 0;
+ }
+ return ren;
+ }
+
+ @Override
public Insets getTabAreaInsets() {
return new Insets(0, 0, 0, getControlButtons().getPreferredSize().width + ICON_X_PAD);
}
diff --git a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatTabControlIcon.java b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatTabControlIcon.java
index 9b81fda..c506498 100644
--- a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatTabControlIcon.java
+++ b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatTabControlIcon.java
@@ -220,17 +220,17 @@ public final class FlatTabControlIcon extends VectorIcon {
g.fill(win1);
g.fill(win2);
} else if (buttonId == TabControlButton.ID_MAXIMIZE_BUTTON) {
- int xy = round(3 * scaling);
- int wh = round(10 * scaling);
+ int xy = (int) (3 * scaling);
+ int wh = width - (2 * xy);
/* Draw one larger window. The getWindowSymbol method ensures we are using the same
window border thickness as for ID_RESTORE_BUTTON. */
g.fill(getWindowSymbol(scaling, xy, xy, wh, wh));
} else if (buttonId == TabControlButton.ID_SLIDE_GROUP_BUTTON) {
// Draw a simple bar towards the bottom of the icon.
- int barX = round(3 * scaling);
- int barY = round(7 * scaling);
- int barWidth = round(10 * scaling);
- int barThickness = round(2 * scaling);
+ int barX = (int) (3 * scaling);
+ int barY = round(11 * scaling);
+ int barWidth = width - (2 * barX);
+ int barThickness = (int) (1 * scaling);
g.fill(new Rectangle2D.Double(barX, barY, barWidth, barThickness));
} else if (buttonId == TabControlButton.ID_DROP_DOWN_BUTTON ||
buttonId == TabControlButton.ID_SCROLL_LEFT_BUTTON ||
diff --git a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatViewTabDisplayerUI.java b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatViewTabDisplayerUI.java
index 89a86e0..d8d972d 100644
--- a/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatViewTabDisplayerUI.java
+++ b/platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/ui/FlatViewTabDisplayerUI.java
@@ -72,11 +72,13 @@ public class FlatViewTabDisplayerUI extends AbstractViewTabDisplayerUI {
underlineColor, // underline color of selected active tabs
inactiveUnderlineColor, // underline color of selected inactive tabs
+ tabSeparatorColor, // tab separator color
contentBorderColor; // bottom border color
private static Insets tabInsets;
private static int underlineHeight; // height of "underline" painted at bottom of tab to indicate selection
private static boolean underlineAtTop; // paint "underline" at top of tab
+ private static boolean showTabSeparators; // paint tab separators
private Font font;
@@ -115,7 +117,7 @@ public class FlatViewTabDisplayerUI extends AbstractViewTabDisplayerUI {
FontMetrics fm = getTxtFontMetrics();
// setting font already here to compute string width correctly
g.setFont(getTxtFont());
- int txtWidth = width;
+ int availTxtWidth = width - (txtLeftPad + txtRightPad);
if (isSelected(index)) {
// layout buttons
Component buttons = getControlButtons();
@@ -125,20 +127,47 @@ public class FlatViewTabDisplayerUI extends AbstractViewTabDisplayerUI {
buttons.setVisible(false);
} else {
buttons.setVisible(true);
- txtWidth = width - (buttonsSize.width + ICON_X_PAD + txtLeftPad + txtRightPad);
+ availTxtWidth -= (buttonsSize.width + ICON_X_PAD);
buttons.setLocation(x + width - buttonsSize.width - ICON_X_PAD, y + (height - buttonsSize.height) / 2);
}
}
- } else {
- txtWidth = width - (txtLeftPad + txtRightPad);
}
// paint busy icon
if (isTabBusy(index)) {
Icon busyIcon = BusyTabsSupport.getDefault().getBusyIcon(isSelected(index));
- txtWidth -= busyIcon.getIconWidth() - UIScale.scale(3) - txtLeftPad;
+ availTxtWidth -= busyIcon.getIconWidth() - UIScale.scale(3) - txtLeftPad;
busyIcon.paintIcon(displayer, g, x + txtLeftPad, y + (height - busyIcon.getIconHeight()) / 2);
- x += busyIcon.getIconWidth() + UIScale.scale(3);
+ int busyWidth = busyIcon.getIconWidth() + UIScale.scale(3);
+ x += busyWidth;
+ width -= busyWidth;
+ }
+
+ // make sure that as much text as possible is shown (and avoid empty tabs)
+ int realTxtWidth = (text.startsWith("<html") || text.startsWith("<HTML")) //NOI18N
+ ? (int) HtmlRenderer.renderString(text, g, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE,
+ getTxtFont(), foreground, HtmlRenderer.STYLE_TRUNCATE, false)
+ : fm.stringWidth(text);
+ if (realTxtWidth > availTxtWidth) {
+ // add left and right insets to available width
+ int left = Math.min(txtLeftPad - 1, realTxtWidth - availTxtWidth);
+ availTxtWidth += left + txtRightPad;
+ txtLeftPad -= left;
+
+ // Truncate text here because HtmlRenderer.renderString() does not paint any text
+ // if it is longer that 3 characters and the available width is smaller
+ // than the width of the first 3 characters plus "…".
+ if (realTxtWidth > availTxtWidth && text.length() > 3) {
+ int minWidth = fm.stringWidth(text.substring(0, 3) + "…"); //NOI18N
+ if (minWidth > availTxtWidth) {
+ // truncate text; in the worst case, text becomes "…" only
+ for (int i = 2; i >= 0; i--) {
+ text = text.substring(0, i) + "…"; //NOI18N
+ if (fm.stringWidth(text) < availTxtWidth)
+ break;
+ }
+ }
+ }
}
// text color
@@ -146,14 +175,19 @@ public class FlatViewTabDisplayerUI extends AbstractViewTabDisplayerUI {
hoverForeground, attentionForeground);
// paint text
- int txtX = x + tabInsets.left;
+ int txtX = x + txtLeftPad;
int txtY = y + tabInsets.top + fm.getAscent();
int availH = height - tabInsets.top - tabInsets.bottom;
if (availH > fm.getHeight()) {
txtY += (availH - fm.getHeight()) / 2;
}
- HtmlRenderer.renderString(text, g, txtX, txtY, txtWidth, height,
- getTxtFont(), c, HtmlRenderer.STYLE_TRUNCATE, true);
+ int style = HtmlRenderer.STYLE_TRUNCATE;
+ if (!isSelected(index)) {
+ // center text of unselected tabs
+ txtX = Math.max(x + 1, x + ((width - realTxtWidth) / 2));
+ }
+ HtmlRenderer.renderString(text, g, txtX, txtY, availTxtWidth, height,
+ getTxtFont(), c, style, true);
}
@Override
@@ -173,19 +207,23 @@ public class FlatViewTabDisplayerUI extends AbstractViewTabDisplayerUI {
}
private void paintTabBackgroundAtScale1x(Graphics2D g, int index, int width, int height, double scale) {
+ // do not round tab separator width to get nice small lines at 125%, 150% and 175%
+ int tabSeparatorWidth = (showTabSeparators && index >= 0) ? (int) (1 * scale) : 0;
+
// paint background
- g.setColor(colorForState(index, background, activeBackground, selectedBackground,
- hoverBackground, attentionBackground));
- g.fillRect(0, 0, width, height);
+ Color bg = colorForState(index, background, activeBackground, selectedBackground,
+ hoverBackground, attentionBackground);
+ g.setColor(bg);
+ g.fillRect(0, 0, width - (bg != background ? tabSeparatorWidth : 0), height);
if (isSelected(index) && underlineHeight > 0) {
// paint underline if tab is selected
int underlineHeight = (int) Math.round(this.underlineHeight * scale);
g.setColor(isActive() ? underlineColor : inactiveUnderlineColor);
if (underlineAtTop) {
- g.fillRect(0, 0, width, underlineHeight);
+ g.fillRect(0, 0, width - tabSeparatorWidth, underlineHeight);
} else {
- g.fillRect(0, height - underlineHeight, width, underlineHeight);
+ g.fillRect(0, height - underlineHeight, width - tabSeparatorWidth, underlineHeight);
}
} else {
// paint bottom border
@@ -193,6 +231,12 @@ public class FlatViewTabDisplayerUI extends AbstractViewTabDisplayerUI {
g.setColor(contentBorderColor);
g.fillRect(0, height - contentBorderWidth, width, contentBorderWidth);
}
+
+ if (showTabSeparators && index >= 0) {
+ int offset = (int) (4 * scale);
+ g.setColor(tabSeparatorColor);
+ g.fillRect(width - tabSeparatorWidth, offset, tabSeparatorWidth, height - (offset * 2) - 1);
+ }
}
@Override
@@ -251,11 +295,13 @@ public class FlatViewTabDisplayerUI extends AbstractViewTabDisplayerUI {
underlineColor = UIManager.getColor("ViewTab.underlineColor"); // NOI18N
inactiveUnderlineColor = UIManager.getColor("ViewTab.inactiveUnderlineColor"); // NOI18N
+ tabSeparatorColor = UIManager.getColor("ViewTab.tabSeparatorColor"); // NOI18N
contentBorderColor = UIManager.getColor("TabbedContainer.view.contentBorderColor"); // NOI18N
tabInsets = UIManager.getInsets("ViewTab.tabInsets"); // NOI18N
underlineHeight = UIManager.getInt("ViewTab.underlineHeight"); // NOI18N
underlineAtTop = UIManager.getBoolean("ViewTab.underlineAtTop"); // NOI18N
+ showTabSeparators = UIManager.getBoolean("ViewTab.showTabSeparators"); // NOI18N
// scale on Java 8 and Linux
tabInsets = UIScale.scale(tabInsets);
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists