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 <k...@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-unsubscr...@netbeans.apache.org For additional commands, e-mail: commits-h...@netbeans.apache.org For further information about the NetBeans mailing lists, visit: https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists