Browse Source

Modules + MenuItem: Use java-compatibility.jar from intelliJ to replace swing internal api calls. Because this also replaces the MenuItemLayoutHelper we need to unify the implementation of DarkMenuItemUIBase and DarkMenuUI. This is done by extracting all functionality into the MenuItemUI interface for which the implementing classes need to provide the necessary details.

pull/245/head
weisj 4 years ago
parent
commit
542dbf3cb7
No known key found for this signature in database
GPG Key ID: 31124CB75461DA2A
  1. 7
      core/build.gradle.kts
  2. 231
      core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuItemUIBase.java
  3. 67
      core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuUI.java
  4. 268
      core/src/main/java/com/github/weisj/darklaf/ui/menu/MenuItemUI.java
  5. 2
      core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/checkbox/DarkCheckBoxMenuItemUI.java
  6. 9
      core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/radiobutton/DarkRadioButtonMenuItemUI.java
  7. 17
      core/src/main/java/com/github/weisj/darklaf/util/SwingUtil.java
  8. 50
      core/src/main/java/com/intellij/util/ui/ImageIconUIResource.java
  9. 37
      core/src/main/java/com/intellij/util/ui/MenuItemCheckIconFactory.java
  10. 1141
      core/src/main/java/com/intellij/util/ui/MenuItemLayoutHelper.java
  11. 40
      core/src/main/java/com/intellij/util/ui/StringUIClientPropertyKey.java
  12. 31
      core/src/main/java/com/intellij/util/ui/UIClientPropertyKey.java
  13. 1353
      core/src/main/java/com/intellij/util/ui/UIUtilities.java
  14. 51
      windows/src/main/java/com/github/weisj/darklaf/platform/windows/ui/WindowsTitlePane.java

7
core/build.gradle.kts

@ -6,6 +6,13 @@ plugins {
id("com.github.vlsi.crlf")
}
val fatJar by tasks.registering(Jar::class) {
archiveBaseName.set("fatJar")
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from(configurations["runtimeClasspath"].map { if (it.isDirectory) it else zipTree(it) })
with(tasks["jar"] as CopySpec)
}
dependencies {
api(projects.darklafTheme)
api(projects.darklafPropertyLoader)

231
core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuItemUIBase.java

@ -28,21 +28,16 @@ import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicMenuItemUI;
import sun.swing.MenuItemLayoutHelper;
import com.github.weisj.darklaf.ui.UIAction;
import com.github.weisj.darklaf.util.DarkUIUtil;
import com.github.weisj.darklaf.util.LazyActionMap;
import com.github.weisj.darklaf.util.StringUtil;
import com.github.weisj.darklaf.util.SwingUtil;
import com.github.weisj.darklaf.util.graphics.GraphicsContext;
import com.github.weisj.darklaf.util.graphics.GraphicsUtil;
import com.intellij.util.ui.MenuItemLayoutHelper;
/**
* @author Konstantin Bulenkov
* @author Jannis Weis
*/
public class DarkMenuItemUIBase extends BasicMenuItemUI {
public class DarkMenuItemUIBase extends BasicMenuItemUI implements MenuItemUI {
protected int acceleratorTextOffset;
protected boolean useEvenHeight;
@ -65,6 +60,13 @@ public class DarkMenuItemUIBase extends BasicMenuItemUI {
acceleratorFont = UIManager.getFont("MenuItem.font");
acceleratorForeground = UIManager.getColor("MenuItem.foreground");
acceleratorSelectionForeground = UIManager.getColor("MenuItem.selectionForeground");
disabledForeground = UIManager.getColor("MenuItem.disabledForeground");
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
MenuItemLayoutHelper.clearUsedParentClientProperties(menuItem);
}
@Override
@ -83,164 +85,71 @@ public class DarkMenuItemUIBase extends BasicMenuItemUI {
return menuItem.isEnabled() && ((JMenuItem) menuItem).isArmed();
}
private static void rightAlignAccText(final MenuItemLayoutHelper lh, final MenuItemLayoutHelper.LayoutResult lr) {
Rectangle accRect = lr.getAccRect();
ButtonModel model = lh.getMenuItem().getModel();
if (model.isEnabled()) {
accRect.x = lh.getViewRect().x + lh.getViewRect().width - lh.getMenuItem().getIconTextGap()
- lr.getAccRect().width;
}
}
protected void paintMenuItem(final Graphics g, final JComponent c, final Icon checkIcon, final Icon arrowIcon,
final Color background, final Color foreground, final int defaultTextIconGap) {
// Save original graphics font and color
GraphicsContext context = new GraphicsContext(g);
JMenuItem mi = (JMenuItem) c;
g.setFont(mi.getFont());
Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight());
DarkUIUtil.applyInsets(viewRect, mi.getInsets());
MenuItemLayoutHelper lh = getMenuItemLayoutHelper(checkIcon, arrowIcon, defaultTextIconGap, mi, viewRect);
MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem();
paintBackground(g, mi, background);
context.restore();
paintCheckIcon(g, mi, lh, lr, foreground);
context.restore();
paintIcon(g, mi, lh, lr);
g.setColor(foreground);
paintText(g, mi, lh, lr);
paintAccText(g, mi, lh, lr);
paintArrowIcon(g, mi, lh, lr, foreground);
context.restore();
@Override
protected void paintMenuItem(final Graphics g, final JComponent c, final Icon checkIcon,
final Icon arrowIcon, final Color background,
final Color foreground, final int defaultTextIconGap) {
paintMenuItemImpl(g, c, checkIcon, arrowIcon, background, foreground, defaultTextIconGap);
}
protected MenuItemLayoutHelper getMenuItemLayoutHelper(final Icon checkIcon, final Icon arrowIcon,
protected static MenuItemLayoutHelper getMenuItemLayoutHelperWrapper(final Icon checkIcon, final Icon arrowIcon,
final int defaultTextIconGap, final JMenuItem mi, final Rectangle viewRect) {
return new MenuItemLayoutHelper(mi, checkIcon, arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter,
mi.getComponentOrientation().isLeftToRight(), mi.getFont(), acceleratorFont,
MenuItemLayoutHelper.useCheckAndArrow(menuItem), getPropertyPrefix());
}
protected void paintCheckIcon(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr, final Color foreground) {
if (lh.getCheckIcon() != null) {
ButtonModel model = mi.getModel();
if (model.isArmed() || (mi instanceof JMenu && model.isSelected())) {
g.setColor(foreground);
}
if (lh.useCheckAndArrow()) {
lh.getCheckIcon().paintIcon(mi, g, lr.getCheckRect().x, lr.getCheckRect().y);
}
MenuItemUI ui = DarkUIUtil.getUIOfType(mi.getUI(), MenuItemUI.class);
if (ui != null) {
return ui.getMenuItemLayoutHelper(checkIcon, arrowIcon, defaultTextIconGap, mi, viewRect);
}
return getMenuItemLayoutHelperImpl("", mi.getFont(), "MenuItem",
checkIcon, arrowIcon, defaultTextIconGap, mi, viewRect);
}
protected void paintAccText(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr) {
GraphicsContext config = GraphicsUtil.setupAntialiasing(g);
rightAlignAccText(lh, lr);
if (!StringUtil.isBlank(lh.getAccText())) {
g.setFont(lh.getAccFontMetrics().getFont());
g.setColor(getAcceleratorForeground(mi));
SwingUtil.drawString(mi, g, lh.getAccText(), lr.getAccRect().x,
lr.getAccRect().y + lh.getAccFontMetrics().getAscent());
}
config.restore();
public MenuItemLayoutHelper getMenuItemLayoutHelper(final Icon checkIcon, final Icon arrowIcon,
final int defaultTextIconGap, final JMenuItem mi, final Rectangle viewRect) {
return getMenuItemLayoutHelperImpl(acceleratorDelimiter, acceleratorFont, getPropertyPrefix(), checkIcon,
arrowIcon, defaultTextIconGap, mi, viewRect);
}
@Override
protected void paintText(final Graphics g, final JMenuItem menuItem, final Rectangle textRect, final String text) {
super.paintText(g, menuItem, textRect, text);
public String getPropertyPrefix() {
return super.getPropertyPrefix();
}
protected Color getAcceleratorForeground(final AbstractButton b) {
ButtonModel model = b.getModel();
if (!model.isEnabled()) return disabledForeground;
if (model.isArmed() || (b instanceof JMenu && model.isSelected())) {
return acceleratorSelectionForeground;
} else {
return acceleratorForeground;
}
@Override
public Color getDisabledForeground() {
return disabledForeground;
}
protected void paintIcon(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr) {
if (lh.getIcon() != null) {
Icon icon;
ButtonModel model = mi.getModel();
if (!model.isEnabled()) {
icon = mi.getDisabledIcon();
} else if (model.isPressed() && model.isArmed()) {
icon = mi.getPressedIcon();
if (icon == null) {
// Use default icon
icon = mi.getIcon();
}
} else {
icon = mi.getIcon();
}
@Override
public Color getSelectionForeground() {
return selectionForeground;
}
if (icon != null) {
icon.paintIcon(mi, g, lr.getIconRect().x, lr.getIconRect().y);
}
}
@Override
public Color getAcceleratorSelectionForeground() {
return acceleratorSelectionForeground;
}
protected void paintText(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr) {
GraphicsContext config = GraphicsUtil.setupAntialiasing(g);
if (!StringUtil.isBlank(lh.getText())) {
if (lh.getHtmlView() != null) {
// Text is HTML
lh.getHtmlView().paint(g, lr.getTextRect());
} else {
// Text isn't HTML
paintText(g, mi, lr.getTextRect(), lh.getText());
}
}
config.restore();
@Override
public Color getAcceleratorForeground() {
return acceleratorForeground;
}
protected void paintArrowIcon(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr, final Color foreground) {
if (lh.getArrowIcon() != null) {
ButtonModel model = mi.getModel();
if (model.isArmed() || (mi instanceof JMenu && model.isSelected())) {
g.setColor(foreground);
}
if (lh.useCheckAndArrow()) {
lh.getArrowIcon().paintIcon(mi, g, lr.getArrowRect().x, lr.getArrowRect().y);
}
}
@Override
public int getAcceleratorTextOffset() {
return acceleratorTextOffset;
}
@Override
protected void paintBackground(final Graphics g, final JMenuItem menuItem, final Color bgColor) {
ButtonModel model = menuItem.getModel();
Color oldColor = g.getColor();
int menuWidth = menuItem.getWidth();
int menuHeight = menuItem.getHeight() + 1;
public boolean isUseEvenHeight() {
return useEvenHeight;
}
boolean parentOpaque = menuItem.getParent().isOpaque();
if (menuItem.isOpaque() && parentOpaque) {
if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) {
g.setColor(bgColor);
} else {
g.setColor(menuItem.getBackground());
}
g.fillRect(0, 0, menuWidth, menuHeight);
g.setColor(oldColor);
} else if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) {
g.setColor(bgColor);
g.fillRect(0, 0, menuWidth, menuHeight);
g.setColor(oldColor);
}
protected static MenuItemLayoutHelper getMenuItemLayoutHelperImpl(
final String acceleratorDelimiter, final Font acceleratorFont, final String propertyPrefix,
final Icon checkIcon, final Icon arrowIcon,
final int defaultTextIconGap, final JMenuItem mi, final Rectangle viewRect) {
return new MenuItemLayoutHelper(mi, checkIcon, arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter,
mi.getComponentOrientation().isLeftToRight(), mi.getFont(), acceleratorFont,
MenuItemLayoutHelper.useCheckAndArrow(mi), propertyPrefix);
}
@Override
@ -265,41 +174,7 @@ public class DarkMenuItemUIBase extends BasicMenuItemUI {
@Override
protected Dimension getPreferredMenuItemSize(final JComponent c, final Icon checkIcon, final Icon arrowIcon,
final int defaultTextIconGap) {
JMenuItem mi = (JMenuItem) c;
MenuItemLayoutHelper lh = getMenuItemLayoutHelper(checkIcon, arrowIcon, defaultTextIconGap, mi,
MenuItemLayoutHelper.createMaxRect());
Dimension result = new Dimension();
// Calculate the result width
result.width = lh.getLeadingGap();
MenuItemLayoutHelper.addMaxWidth(lh.getCheckSize(), lh.getAfterCheckIconGap(), result);
// Take into account minimal text offset.
if ((!lh.isTopLevelMenu()) && (lh.getMinTextOffset() > 0) && (result.width < lh.getMinTextOffset())) {
result.width = lh.getMinTextOffset();
}
MenuItemLayoutHelper.addMaxWidth(lh.getLabelSize(), acceleratorTextOffset, result);
MenuItemLayoutHelper.addMaxWidth(lh.getAccSize(), acceleratorTextOffset, result);
MenuItemLayoutHelper.addMaxWidth(lh.getArrowSize(), lh.getGap(), result);
// Calculate the result height
result.height = MenuItemLayoutHelper.max(lh.getCheckSize().getHeight(), lh.getLabelSize().getHeight(),
lh.getAccSize().getHeight(), lh.getArrowSize().getHeight());
// Take into account menu item insets
Insets insets = mi.getInsets();
if (insets != null) {
result.width += insets.left + insets.right;
result.height += insets.top + insets.bottom;
}
// if the height is even, bump it up one. This is critical.
// for the text to center properly
if (result.height % 2 == 0 && useEvenHeight) {
result.height++;
}
return result;
return getPreferredMenuItemSizeImpl(c, checkIcon, arrowIcon, defaultTextIconGap);
}
protected static class Actions extends UIAction {

67
core/src/main/java/com/github/weisj/darklaf/ui/menu/DarkMenuUI.java

@ -31,11 +31,12 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicMenuUI;
import com.github.weisj.darklaf.listener.MouseInputDelegate;
import com.github.weisj.darklaf.util.graphics.GraphicsContext;
import com.github.weisj.darklaf.util.graphics.GraphicsUtil;
import com.intellij.util.ui.MenuItemLayoutHelper;
public class DarkMenuUI extends BasicMenuUI {
public class DarkMenuUI extends BasicMenuUI implements MenuItemUI {
protected int acceleratorTextOffset;
protected boolean useEvenHeight;
protected Icon arrowIconHover;
protected JMenu menu;
protected MouseListener mouseListener;
@ -50,6 +51,12 @@ public class DarkMenuUI extends BasicMenuUI {
super.installUI(c);
}
@Override
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
MenuItemLayoutHelper.clearUsedParentClientProperties(menuItem);
}
@Override
protected MouseInputListener createMouseInputListener(final JComponent c) {
return new MouseInputDelegate(super.createMouseInputListener(c)) {
@ -100,13 +107,19 @@ public class DarkMenuUI extends BasicMenuUI {
acceleratorForeground = UIManager.getColor("Menu.foreground");
acceleratorSelectionForeground = UIManager.getColor("Menu.selectionForeground");
arrowIconHover = UIManager.getIcon("Menu.arrowHover.icon");
useEvenHeight = !Boolean.TRUE.equals(UIManager.get(getPropertyPrefix() + ".evenHeight"));
acceleratorTextOffset = UIManager.getInt(getPropertyPrefix() + ".acceleratorTextOffset");
}
public void paint(final Graphics g, final JComponent c) {
GraphicsContext config = GraphicsUtil.setupAntialiasing(g);
paintMenuItem(g, c, checkIcon, getArrowIcon(), selectionBackground,
paintMenuItemImpl(g, c, checkIcon, getArrowIcon(), selectionBackground,
isSelected(c) ? selectionForeground : c.getForeground(), defaultTextIconGap);
config.restore();
}
@Override
protected Dimension getPreferredMenuItemSize(final JComponent c, final Icon checkIcon, final Icon arrowIcon,
final int defaultTextIconGap) {
return getPreferredMenuItemSizeImpl(c, checkIcon, arrowIcon, defaultTextIconGap);
}
protected Icon getArrowIcon() {
@ -119,4 +132,46 @@ public class DarkMenuUI extends BasicMenuUI {
if (!(menuItem instanceof JMenuItem)) return false;
return menuItem.isEnabled() && ((JMenuItem) menuItem).isArmed();
}
@Override
public MenuItemLayoutHelper getMenuItemLayoutHelper(Icon checkIcon, Icon arrowIcon, int defaultTextIconGap,
JMenuItem mi, Rectangle viewRect) {
return DarkMenuItemUIBase.getMenuItemLayoutHelperImpl(acceleratorDelimiter, acceleratorFont,
getPropertyPrefix(), checkIcon, arrowIcon, defaultTextIconGap, mi, viewRect);
}
@Override
public String getPropertyPrefix() {
return super.getPropertyPrefix();
}
@Override
public Color getDisabledForeground() {
return disabledForeground;
}
@Override
public Color getSelectionForeground() {
return selectionForeground;
}
@Override
public Color getAcceleratorSelectionForeground() {
return acceleratorSelectionForeground;
}
@Override
public Color getAcceleratorForeground() {
return acceleratorForeground;
}
@Override
public int getAcceleratorTextOffset() {
return acceleratorTextOffset;
}
@Override
public boolean isUseEvenHeight() {
return useEvenHeight;
}
}

268
core/src/main/java/com/github/weisj/darklaf/ui/menu/MenuItemUI.java

@ -0,0 +1,268 @@
/*
* MIT License
*
* Copyright (c) 2021 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package com.github.weisj.darklaf.ui.menu;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import com.github.weisj.darklaf.util.DarkUIUtil;
import com.github.weisj.darklaf.util.StringUtil;
import com.github.weisj.darklaf.util.SwingUtil;
import com.github.weisj.darklaf.util.graphics.GraphicsContext;
import com.github.weisj.darklaf.util.graphics.GraphicsUtil;
import com.intellij.util.ui.MenuItemLayoutHelper;
public interface MenuItemUI {
MenuItemLayoutHelper getMenuItemLayoutHelper(final Icon checkIcon, final Icon arrowIcon,
final int defaultTextIconGap,
final JMenuItem mi, final Rectangle viewRect);
String getPropertyPrefix();
Color getDisabledForeground();
Color getSelectionForeground();
Color getAcceleratorSelectionForeground();
Color getAcceleratorForeground();
int getAcceleratorTextOffset();
boolean isUseEvenHeight();
default void paintMenuItemImpl(final Graphics g, final JComponent c, final Icon checkIcon,
final Icon arrowIcon,
final Color background, final Color foreground, final int defaultTextIconGap) {
// Save original graphics font and color
GraphicsContext context = new GraphicsContext(g);
JMenuItem mi = (JMenuItem) c;
g.setFont(mi.getFont());
Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight());
DarkUIUtil.applyInsets(viewRect, mi.getInsets());
MenuItemLayoutHelper lh = getMenuItemLayoutHelper(checkIcon, arrowIcon, defaultTextIconGap, mi, viewRect);
MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem();
paintBackgroundImpl(g, mi, background);
context.restore();
paintCheckIcon(g, mi, lh, lr, foreground);
context.restore();
paintIcon(g, mi, lh, lr);
g.setColor(foreground);
paintText(g, mi, lh, lr);
paintAccText(g, mi, lh, lr);
paintArrowIcon(g, mi, lh, lr, foreground);
context.restore();
}
default void paintBackgroundImpl(final Graphics g, final JMenuItem menuItem, final Color bgColor) {
ButtonModel model = menuItem.getModel();
Color oldColor = g.getColor();
int menuWidth = menuItem.getWidth();
int menuHeight = menuItem.getHeight() + 1;
boolean parentOpaque = menuItem.getParent().isOpaque();
if (menuItem.isOpaque() && parentOpaque) {
if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) {
g.setColor(bgColor);
} else {
g.setColor(menuItem.getBackground());
}
g.fillRect(0, 0, menuWidth, menuHeight);
g.setColor(oldColor);
} else if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) {
g.setColor(bgColor);
g.fillRect(0, 0, menuWidth, menuHeight);
g.setColor(oldColor);
}
}
default void paintCheckIcon(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr, final Color foreground) {
if (lh.getCheckIcon() != null) {
ButtonModel model = mi.getModel();
if (model.isArmed() || (mi instanceof JMenu && model.isSelected())) {
g.setColor(foreground);
}
if (lh.useCheckAndArrow()) {
lh.getCheckIcon().paintIcon(mi, g, lr.getCheckRect().x, lr.getCheckRect().y);
}
}
}
default void paintIcon(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr) {
if (lh.getIcon() != null) {
Icon icon;
ButtonModel model = mi.getModel();
if (!model.isEnabled()) {
icon = mi.getDisabledIcon();
} else if (model.isPressed() && model.isArmed()) {
icon = mi.getPressedIcon();
if (icon == null) {
// Use default icon
icon = mi.getIcon();
}
} else {
icon = mi.getIcon();
}
if (icon != null) {
icon.paintIcon(mi, g, lr.getIconRect().x, lr.getIconRect().y);
}
}
}
default void paintText(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr) {
GraphicsContext config = GraphicsUtil.setupAntialiasing(g);
if (!StringUtil.isBlank(lh.getText())) {
if (lh.getHtmlView() != null) {
// Text is HTML
lh.getHtmlView().paint(g, lr.getTextRect());
} else {
// Text isn't HTML
paintItemText(g, mi, lr.getTextRect(), lh.getText());
}
}
config.restore();
}
default void paintItemText(final Graphics g, final JMenuItem menuItem, final Rectangle textRect,
final String text) {
ButtonModel model = menuItem.getModel();
FontMetrics fm = SwingUtil.getFontMetrics(menuItem, g);
int mnemIndex = menuItem.getDisplayedMnemonicIndex();
if (!model.isEnabled()) {
g.setColor(getDisabledForeground());
} else {
if (model.isArmed() || (menuItem instanceof JMenu && model.isSelected())) {
g.setColor(getSelectionForeground());
}
}
SwingUtil.drawStringUnderlineCharAt(menuItem, g, text,
mnemIndex, textRect.x, textRect.y + fm.getAscent());
}
default void paintAccText(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr) {
GraphicsContext config = GraphicsUtil.setupAntialiasing(g);
rightAlignAccText(lh, lr);
if (!StringUtil.isBlank(lh.getAccText())) {
g.setFont(lh.getAccFontMetrics().getFont());
g.setColor(getAcceleratorForeground(mi));
SwingUtil.drawString(mi, g, lh.getAccText(), lr.getAccRect().x,
lr.getAccRect().y + lh.getAccFontMetrics().getAscent());
}
config.restore();
}
default Color getAcceleratorForeground(final AbstractButton b) {
ButtonModel model = b.getModel();
if (!model.isEnabled()) return getDisabledForeground();
if (model.isArmed() || (b instanceof JMenu && model.isSelected())) {
return getAcceleratorSelectionForeground();
} else {
return getAcceleratorForeground();
}
}
static void rightAlignAccText(final MenuItemLayoutHelper lh, final MenuItemLayoutHelper.LayoutResult lr) {
Rectangle accRect = lr.getAccRect();
ButtonModel model = lh.getMenuItem().getModel();
if (model.isEnabled()) {
accRect.x = lh.getViewRect().x + lh.getViewRect().width - lh.getMenuItem().getIconTextGap()
- lr.getAccRect().width;
}
}
default void paintArrowIcon(final Graphics g, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr, final Color foreground) {
if (lh.getArrowIcon() != null) {
ButtonModel model = mi.getModel();
if (model.isArmed() || (mi instanceof JMenu && model.isSelected())) {
g.setColor(foreground);
}
if (lh.useCheckAndArrow()) {
lh.getArrowIcon().paintIcon(mi, g, lr.getArrowRect().x, lr.getArrowRect().y);
}
}
}
default Dimension getPreferredMenuItemSizeImpl(final JComponent c, final Icon checkIcon, final Icon arrowIcon,
final int defaultTextIconGap) {
JMenuItem mi = (JMenuItem) c;
MenuItemLayoutHelper lh = getMenuItemLayoutHelper(checkIcon, arrowIcon, defaultTextIconGap, mi,
MenuItemLayoutHelper.createMaxRect());
Dimension result = new Dimension();
// Calculate the result width
result.width = lh.getLeadingGap();
MenuItemLayoutHelper.addMaxWidth(lh.getCheckSize(), lh.getAfterCheckIconGap(), result);
// Take into account minimal text offset.
if ((!lh.isTopLevelMenu()) && (lh.getMinTextOffset() > 0) && (result.width < lh.getMinTextOffset())) {
result.width = lh.getMinTextOffset();
}
int acceleratorTextOffset = getAcceleratorTextOffset();
MenuItemLayoutHelper.addMaxWidth(lh.getLabelSize(), acceleratorTextOffset, result);
MenuItemLayoutHelper.addMaxWidth(lh.getAccSize(), acceleratorTextOffset, result);
MenuItemLayoutHelper.addMaxWidth(lh.getArrowSize(), lh.getGap(), result);
// Calculate the result height
result.height = MenuItemLayoutHelper.max(lh.getCheckSize().getHeight(), lh.getLabelSize().getHeight(),
lh.getAccSize().getHeight(), lh.getArrowSize().getHeight());
// Take into account menu item insets
Insets insets = mi.getInsets();
if (insets != null) {
result.width += insets.left + insets.right;
result.height += insets.top + insets.bottom;
}
// if the height is even, bump it up one. This is critical.
// for the text to center properly
if (result.height % 2 == 0 && isUseEvenHeight()) {
result.height++;
}
return result;
}
}

2
core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/checkbox/DarkCheckBoxMenuItemUI.java

@ -36,7 +36,7 @@ public class DarkCheckBoxMenuItemUI extends DarkRadioButtonMenuItemUI {
}
@Override
protected String getPropertyPrefix() {
public String getPropertyPrefix() {
return "CheckBoxMenuItem";
}

9
core/src/main/java/com/github/weisj/darklaf/ui/togglebutton/radiobutton/DarkRadioButtonMenuItemUI.java

@ -26,12 +26,11 @@ import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import sun.swing.MenuItemLayoutHelper;
import com.github.weisj.darklaf.listener.MouseClickListener;
import com.github.weisj.darklaf.ui.menu.DarkMenuItemUIBase;
import com.github.weisj.darklaf.ui.menu.MenuItemLayoutDelegate;
import com.github.weisj.darklaf.ui.togglebutton.ToggleButtonMenuItemConstants;
import com.intellij.util.ui.MenuItemLayoutHelper;
/** @author Jannis Weis */
public class DarkRadioButtonMenuItemUI extends DarkMenuItemUIBase implements ToggleButtonMenuItemConstants {
@ -48,7 +47,7 @@ public class DarkRadioButtonMenuItemUI extends DarkMenuItemUIBase implements Tog
}
@Override
protected String getPropertyPrefix() {
public String getPropertyPrefix() {
return "RadioButtonMenuItem";
}
@ -80,7 +79,7 @@ public class DarkRadioButtonMenuItemUI extends DarkMenuItemUIBase implements Tog
}
@Override
protected MenuItemLayoutHelper getMenuItemLayoutHelper(final Icon checkIcon, final Icon arrowIcon,
public MenuItemLayoutHelper getMenuItemLayoutHelper(final Icon checkIcon, final Icon arrowIcon,
final int defaultTextIconGap, final JMenuItem mi, final Rectangle viewRect) {
if (mi.getIcon() == null) {
layoutDelegate.setDelegate(mi);
@ -91,7 +90,7 @@ public class DarkRadioButtonMenuItemUI extends DarkMenuItemUIBase implements Tog
}
@Override
protected void paintCheckIcon(final Graphics g2, final JMenuItem mi, final MenuItemLayoutHelper lh,
public void paintCheckIcon(final Graphics g2, final JMenuItem mi, final MenuItemLayoutHelper lh,
final MenuItemLayoutHelper.LayoutResult lr, final Color foreground) {
Rectangle rect = lr.getCheckRect();
if (mi.getIcon() == null) {

17
core/src/main/java/com/github/weisj/darklaf/util/SwingUtil.java

@ -40,8 +40,7 @@ import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.table.TableCellRenderer;
import sun.swing.SwingUtilities2;
import com.intellij.util.ui.UIUtilities;
public final class SwingUtil {
@ -49,28 +48,28 @@ public final class SwingUtil {
public static void drawStringUnderlineCharAt(JComponent c, Graphics g,
String text, int underlinedIndex, int x, int y) {
SwingUtilities2.drawStringUnderlineCharAt(c, g, text, underlinedIndex, x, y);
UIUtilities.drawStringUnderlineCharAt(c, g, text, underlinedIndex, x, y);
}
public static void drawString(final JComponent c, final Graphics g, final String text, int x, int y) {
SwingUtilities2.drawString(c, g, text, x, y);
UIUtilities.drawString(c, g, text, x, y);
}
public static void setSkipClickCount(final Component comp, int count) {
SwingUtilities2.setSkipClickCount(comp, count);
UIUtilities.setSkipClickCount(comp, count);
}
public static int stringWidth(final JComponent c, final FontMetrics fm, final String string) {
return SwingUtilities2.stringWidth(c, fm, string);
return UIUtilities.stringWidth(c, fm, string);
}
public static String clipStringIfNecessary(final JComponent c, final FontMetrics fm,
final String string, int availTextWidth) {
return SwingUtilities2.clipStringIfNecessary(c, fm, string, availTextWidth);
return UIUtilities.clipStringIfNecessary(c, fm, string, availTextWidth);
}
public static int getFocusAcceleratorKeyMask() {
return SwingUtilities2.getSystemMnemonicKeyMask();
return UIUtilities.getSystemMnemonicKeyMask();
}
public static FontMetrics getFontMetrics(final JComponent c, final Graphics g) {
@ -166,7 +165,7 @@ public final class SwingUtil {
public static boolean tabbedPaneChangeFocusTo(final Component comp) {
if (comp != null) {
if (comp.isFocusable()) {
SwingUtilities2.compositeRequestFocus(comp);
UIUtilities.compositeRequestFocus(comp);
return true;
} else {
return comp instanceof JComponent && requestDefaultFocus((JComponent) comp);

50
core/src/main/java/com/intellij/util/ui/ImageIconUIResource.java

@ -0,0 +1,50 @@
/*
* MIT License
*
* Copyright (c) 2021 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package com.intellij.util.ui;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.plaf.UIResource;
public class ImageIconUIResource extends ImageIcon implements UIResource {
/**
* Calls the superclass constructor with the same parameter.
*
* @param imageData an array of pixels
* @see javax.swing.ImageIcon#ImageIcon(byte[])
*/
public ImageIconUIResource(byte[] imageData) {
super(imageData);
}
/**
* Calls the superclass constructor with the same parameter.
*
* @param image an image
* @see javax.swing.ImageIcon#ImageIcon(Image)
*/
public ImageIconUIResource(Image image) {
super(image);
}
}

37
core/src/main/java/com/intellij/util/ui/MenuItemCheckIconFactory.java

@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2021 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.intellij.util.ui;
import javax.swing.Icon;
import javax.swing.JMenuItem;
public interface MenuItemCheckIconFactory {
Icon getIcon(JMenuItem var1);
boolean isCompatible(Object var1, String var2);
}

1141
core/src/main/java/com/intellij/util/ui/MenuItemLayoutHelper.java

File diff suppressed because it is too large Load Diff

40
core/src/main/java/com/intellij/util/ui/StringUIClientPropertyKey.java

@ -0,0 +1,40 @@
/*
* MIT License
*
* Copyright (c) 2021 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.intellij.util.ui;
public class StringUIClientPropertyKey implements UIClientPropertyKey {
private final String key;
public StringUIClientPropertyKey(String key) {
this.key = key;
}
public String toString() {
return this.key;
}
}

31
core/src/main/java/com/intellij/util/ui/UIClientPropertyKey.java

@ -0,0 +1,31 @@
/*
* MIT License
*
* Copyright (c) 2021 Jannis Weis
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.intellij.util.ui;
public interface UIClientPropertyKey {
}

1353
core/src/main/java/com/intellij/util/ui/UIUtilities.java

File diff suppressed because it is too large Load Diff

51
windows/src/main/java/com/github/weisj/darklaf/platform/windows/ui/WindowsTitlePane.java

@ -23,6 +23,7 @@ package com.github.weisj.darklaf.platform.windows.ui;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
@ -33,8 +34,6 @@ import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.UIResource;
import sun.awt.SunToolkit;
import com.github.weisj.darklaf.icons.ScaledIcon;
import com.github.weisj.darklaf.icons.ToggleIcon;
import com.github.weisj.darklaf.platform.decorations.CustomTitlePane;
@ -658,7 +657,8 @@ public class WindowsTitlePane extends CustomTitlePane {
systemIcon = new ScaledIcon(icons.get(0).getScaledInstance((int) Scale.scaleWidth(ICON_SIZE, gc),
(int) Scale.scaleHeight(ICON_SIZE, gc), Image.SCALE_AREA_AVERAGING), this);
} else {
systemIcon = new ScaledIcon(SunToolkit.getScaledIconImage(icons, (int) Scale.scaleWidth(ICON_SIZE, gc),
systemIcon = new ScaledIcon(getScaledIconImage(this, icons,
(int) Scale.scaleWidth(ICON_SIZE, gc),
(int) Scale.scaleHeight(ICON_SIZE, gc)), this);
}
if (windowIconButton != null) {
@ -667,6 +667,51 @@ public class WindowsTitlePane extends CustomTitlePane {
}
}
private Image getScaledIconImage(final Component c, final List<Image> images,
final int width, final int height) {
Image bestImage = null;
int dw = 0;
int dh = 0;
for (Image image : images) {
ensureImageLoaded(c, image);
int dwi = Math.abs(dw - image.getWidth(c));
int dhi = Math.abs(dh - image.getHeight(c));
if (bestImage == null || (dwi + dhi < dw + dh)) {
bestImage = image;
dw = dwi;
dh = dhi;
}
}
if (bestImage == null) return null;
int iw = bestImage.getWidth(null);
int ih = bestImage.getHeight(null);
double scaleFactor = Math.min((double) width / (double) iw, (double) height / (double) ih);
int bestWidth = (int) (scaleFactor * iw);
int bestHeight = (int) (scaleFactor * ih);
BufferedImage bimage =
new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bimage.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
try {
int x = (width - bestWidth) / 2;
int y = (height - bestHeight) / 2;
g.drawImage(bestImage, x, y, bestWidth, bestHeight, c);
} finally {
g.dispose();
}
return bimage;
}
private void ensureImageLoaded(final Component c, final Image img) {
MediaTracker tracker = new MediaTracker(c);
tracker.addImage(img, 0);
try {
tracker.waitForAll();
} catch (final InterruptedException ignored) {
}
}
private class CloseAction extends AbstractAction {
public CloseAction() {
super(UIManager.getString("Actions.close", getLocale()), closeIcon);

Loading…
Cancel
Save