From b140fc494e03f5eaf29375392569391a092a87b4 Mon Sep 17 00:00:00 2001 From: ShadelessFox Date: Thu, 29 Feb 2024 19:38:30 +0100 Subject: [PATCH] Application: Replace "no projects" hint with onboarding messages --- .../java/com/shade/decima/ui/Application.java | 10 - .../impl/DefaultEditorOnboardingProvider.java | 23 ++ .../shade/decima/ui/menu/menus/EditMenu.java | 4 +- .../shade/decima/ui/menu/menus/FileMenu.java | 4 +- .../shade/decima/ui/menu/menus/ViewMenu.java | 4 +- ...rm.ui.editors.spi.EditorOnboardingProvider | 1 + .../platform/ui/controls/HintManager.java | 290 ------------------ .../ui/editors/spi/EditorOnboarding.java | 27 ++ .../editors/spi/EditorOnboardingProvider.java | 8 + .../editors/stack/EditorStackContainer.java | 9 + .../ui/editors/stack/EditorStackManager.java | 142 ++++++++- .../shade/platform/ui/menus/MenuManager.java | 4 + .../com/shade/platform/ui/util/UIUtils.java | 19 ++ .../resources/themes/FlatDarkLaf.properties | 7 +- .../main/resources/themes/FlatLaf.properties | 10 +- 15 files changed, 240 insertions(+), 322 deletions(-) create mode 100644 modules/decima-ui/src/main/java/com/shade/decima/ui/editor/impl/DefaultEditorOnboardingProvider.java create mode 100644 modules/decima-ui/src/main/resources/META-INF/services/com.shade.platform.ui.editors.spi.EditorOnboardingProvider delete mode 100644 modules/platform-ui/src/main/java/com/shade/platform/ui/controls/HintManager.java create mode 100644 modules/platform-ui/src/main/java/com/shade/platform/ui/editors/spi/EditorOnboarding.java create mode 100644 modules/platform-ui/src/main/java/com/shade/platform/ui/editors/spi/EditorOnboardingProvider.java diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/Application.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/Application.java index 13c416229..f70050634 100644 --- a/modules/decima-ui/src/main/java/com/shade/decima/ui/Application.java +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/Application.java @@ -35,7 +35,6 @@ import com.shade.platform.model.runtime.VoidProgressMonitor; import com.shade.platform.ui.PlatformMenuConstants; import com.shade.platform.ui.UIColor; -import com.shade.platform.ui.controls.HintManager; import com.shade.platform.ui.editors.Editor; import com.shade.platform.ui.editors.EditorChangeListener; import com.shade.platform.ui.editors.EditorInput; @@ -279,15 +278,6 @@ public void windowOpened(WindowEvent event) { if (!BuildConfig.APP_VERSION.equals(preferences.get("version", BuildConfig.APP_VERSION))) { HelpMenu.ChangelogItem.open(); } - - if (ProjectManager.getInstance().getProjects().length == 0) { - HintManager.showHint(new HintManager.Hint( - "It looks like you don't have any projects.

Use FileNewProject to start.", - frame.getRootPane().getJMenuBar(), - SwingConstants.BOTTOM, - null - )); - } } @Override diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/editor/impl/DefaultEditorOnboardingProvider.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/editor/impl/DefaultEditorOnboardingProvider.java new file mode 100644 index 000000000..06efa39ae --- /dev/null +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/editor/impl/DefaultEditorOnboardingProvider.java @@ -0,0 +1,23 @@ +package com.shade.decima.ui.editor.impl; + +import com.shade.decima.ui.menu.menus.EditMenu; +import com.shade.decima.ui.menu.menus.FileMenu; +import com.shade.decima.ui.menu.menus.ViewMenu; +import com.shade.platform.ui.editors.spi.EditorOnboarding; +import com.shade.platform.ui.editors.spi.EditorOnboardingProvider; +import com.shade.util.NotNull; + +import java.util.List; + +public class DefaultEditorOnboardingProvider implements EditorOnboardingProvider { + @NotNull + @Override + public Iterable getOnboardings() { + return List.of( + new EditorOnboarding.Action(FileMenu.NewProjectItem.ID, "Create new project"), + new EditorOnboarding.Action(EditMenu.FindFilesItem.ID, "Find files"), + new EditorOnboarding.Action(ViewMenu.RecentFilesItem.ID, "Show recent files"), + new EditorOnboarding.Text("Drop files here to open them") + ); + } +} diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/EditMenu.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/EditMenu.java index 7ae929742..ba0323fa5 100644 --- a/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/EditMenu.java +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/EditMenu.java @@ -80,8 +80,10 @@ public String getName(@NotNull MenuItemContext ctx) { } } - @MenuItemRegistration(parent = APP_MENU_EDIT_ID, name = "Find &Files\u2026", icon = "Action.searchIcon", keystroke = "ctrl shift F", group = APP_MENU_EDIT_GROUP_GENERAL, order = 1000) + @MenuItemRegistration(id = FindFilesItem.ID, parent = APP_MENU_EDIT_ID, name = "Find &Files\u2026", icon = "Action.searchIcon", keystroke = "ctrl shift F", group = APP_MENU_EDIT_GROUP_GENERAL, order = 1000) public static class FindFilesItem extends MenuItem { + public static final String ID = APP_MENU_EDIT_ID + ".findFiles"; + @Override public void perform(@NotNull MenuItemContext ctx) { final Project project = ctx.getData(CommonDataKeys.PROJECT_KEY); diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/FileMenu.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/FileMenu.java index 9beeb7008..a80c1c53b 100644 --- a/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/FileMenu.java +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/FileMenu.java @@ -36,8 +36,10 @@ public final class FileMenu extends Menu { @MenuItemRegistration(id = APP_MENU_FILE_NEW_ID, parent = APP_MENU_FILE_ID, name = "&New", group = APP_MENU_FILE_GROUP_OPEN, order = 1000) public static class NewItem extends MenuItem {} - @MenuItemRegistration(parent = APP_MENU_FILE_NEW_ID, name = "&Project\u2026", group = APP_MENU_FILE_GROUP_OPEN, order = 1000) + @MenuItemRegistration(id = NewProjectItem.ID, parent = APP_MENU_FILE_NEW_ID, name = "&Project\u2026", keystroke = "ctrl N", group = APP_MENU_FILE_GROUP_OPEN, order = 1000) public static class NewProjectItem extends MenuItem { + public static final String ID = APP_MENU_FILE_NEW_ID + ".project"; + @Override public void perform(@NotNull MenuItemContext ctx) { final ProjectEditDialog dialog = new ProjectEditDialog(false); diff --git a/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/ViewMenu.java b/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/ViewMenu.java index 967a2349a..6532f9520 100644 --- a/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/ViewMenu.java +++ b/modules/decima-ui/src/main/java/com/shade/decima/ui/menu/menus/ViewMenu.java @@ -57,8 +57,10 @@ public void perform(@NotNull MenuItemContext ctx) { } } - @MenuItemRegistration(parent = APP_MENU_VIEW_ID, name = "Rec&ent Editors", keystroke = "ctrl E", group = APP_MENU_VIEW_GROUP_GENERAL, order = 1000) + @MenuItemRegistration(id = RecentFilesItem.ID, parent = APP_MENU_VIEW_ID, name = "Rec&ent Editors", keystroke = "ctrl E", group = APP_MENU_VIEW_GROUP_GENERAL, order = 1000) public static class RecentFilesItem extends MenuItem { + public static final String ID = APP_MENU_VIEW_ID + ".recentEditors"; + @Override public void perform(@NotNull MenuItemContext ctx) { new RecentEditorsDialog(JOptionPane.getRootFrame()); diff --git a/modules/decima-ui/src/main/resources/META-INF/services/com.shade.platform.ui.editors.spi.EditorOnboardingProvider b/modules/decima-ui/src/main/resources/META-INF/services/com.shade.platform.ui.editors.spi.EditorOnboardingProvider new file mode 100644 index 000000000..755158f46 --- /dev/null +++ b/modules/decima-ui/src/main/resources/META-INF/services/com.shade.platform.ui.editors.spi.EditorOnboardingProvider @@ -0,0 +1 @@ +com.shade.decima.ui.editor.impl.DefaultEditorOnboardingProvider diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/controls/HintManager.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/controls/HintManager.java deleted file mode 100644 index 204901415..000000000 --- a/modules/platform-ui/src/main/java/com/shade/platform/ui/controls/HintManager.java +++ /dev/null @@ -1,290 +0,0 @@ -package com.shade.platform.ui.controls; - -import com.formdev.flatlaf.FlatLaf; -import com.formdev.flatlaf.ui.FlatDropShadowBorder; -import com.formdev.flatlaf.ui.FlatEmptyBorder; -import com.formdev.flatlaf.ui.FlatUIUtils; -import com.formdev.flatlaf.util.UIScale; -import net.miginfocom.swing.MigLayout; - -import javax.swing.*; -import javax.swing.border.Border; -import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.geom.Area; -import java.awt.geom.RoundRectangle2D; -import java.util.ArrayList; -import java.util.List; - -/** - * Taken from FlatLaf Demo project - * - * @see HintManager.java - */ -public class HintManager { - private static final List hintPanels = new ArrayList<>(); - - public static void showHint(Hint hint) { - HintPanel hintPanel = new HintPanel(hint); - hintPanel.showHint(); - - hintPanels.add(hintPanel); - } - - public static void hideAllHints() { - HintPanel[] hintPanels2 = hintPanels.toArray(new HintPanel[0]); - for (HintPanel hintPanel : hintPanels2) - hintPanel.hideHint(); - } - - private static class HintPanel extends JPanel { - private final Hint hint; - - private JPanel popup; - private JLabel hintLabel; - - private HintPanel(Hint hint) { - this.hint = hint; - - initComponents(); - - setOpaque(false); - updateBalloonBorder(); - - hintLabel.setText("" + hint.message + ""); - - // grab all mouse events to avoid that components overlapped - // by the hint panel receive them - addMouseListener(new MouseAdapter() {}); - } - - @Override - public void updateUI() { - super.updateUI(); - - setBackground(UIManager.getColor("HintPanel.backgroundColor")); - - if (hint != null) { - updateBalloonBorder(); - } - } - - private void updateBalloonBorder() { - int direction = switch (hint.position) { - case SwingConstants.LEFT -> SwingConstants.RIGHT; - case SwingConstants.TOP -> SwingConstants.BOTTOM; - case SwingConstants.RIGHT -> SwingConstants.LEFT; - case SwingConstants.BOTTOM -> SwingConstants.TOP; - default -> throw new IllegalArgumentException(); - }; - - setBorder(new BalloonBorder(direction, FlatUIUtils.getUIColor("PopupMenu.borderColor", Color.gray))); - } - - void showHint() { - JRootPane rootPane = SwingUtilities.getRootPane(hint.owner); - if (rootPane == null) - return; - - JLayeredPane layeredPane = rootPane.getLayeredPane(); - - // create a popup panel that has a drop shadow - popup = new JPanel(new BorderLayout()) { - @Override - public void updateUI() { - super.updateUI(); - - // use invokeLater because at this time the UI delegates - // of child components are not yet updated - EventQueue.invokeLater(() -> { - validate(); - setSize(getPreferredSize()); - }); - } - }; - popup.setOpaque(false); - popup.add(this); - - // calculate x/y location for hint popup - Point pt = SwingUtilities.convertPoint(hint.owner, 0, 0, layeredPane); - int x = pt.x; - int y = pt.y; - Dimension size = popup.getPreferredSize(); - int gap = UIScale.scale(6); - - switch (hint.position) { - case SwingConstants.LEFT -> x -= size.width + gap; - case SwingConstants.TOP -> y -= size.height + gap; - case SwingConstants.RIGHT -> x += hint.owner.getWidth() + gap; - case SwingConstants.BOTTOM -> y += hint.owner.getHeight() + gap; - } - - // set hint popup size and show it - popup.setBounds(x, y, size.width, size.height); - layeredPane.add(popup, JLayeredPane.POPUP_LAYER); - } - - void hideHint() { - if (popup != null) { - Container parent = popup.getParent(); - if (parent != null) { - parent.remove(popup); - parent.repaint(popup.getX(), popup.getY(), popup.getWidth(), popup.getHeight()); - } - } - - hintPanels.remove(this); - } - - private void gotIt() { - // hide hint - hideHint(); - - // show next hint (if any) - if (hint.nextHint != null) - HintManager.showHint(hint.nextHint); - } - - private void initComponents() { - hintLabel = new JLabel(); - JButton gotItButton = new JButton(); - - setLayout(new MigLayout("insets dialog,hidemode 3", "[::250,fill]", "[]para[]")); - - hintLabel.setText("hint"); - add(hintLabel, "cell 0 0"); - - gotItButton.setText("Got it!"); - gotItButton.setFocusable(false); - gotItButton.addActionListener(e -> gotIt()); - add(gotItButton, "cell 0 1,alignx right,growx 0"); - } - - } - - private static class BalloonBorder extends FlatEmptyBorder { - private static final int ARC = 8; - private static final int ARROW_XY = 16; - private static final int ARROW_SIZE = 8; - private static final int SHADOW_SIZE = 6; - private static final int SHADOW_TOP_SIZE = 3; - private static final int SHADOW_SIZE2 = SHADOW_SIZE + 2; - - private final int direction; - private final Color borderColor; - - private final Border shadowBorder; - - public BalloonBorder(int direction, Color borderColor) { - super(1 + SHADOW_TOP_SIZE, 1 + SHADOW_SIZE, 1 + SHADOW_SIZE, 1 + SHADOW_SIZE); - - this.direction = direction; - this.borderColor = borderColor; - - switch (direction) { - case SwingConstants.LEFT -> left += ARROW_SIZE; - case SwingConstants.TOP -> top += ARROW_SIZE; - case SwingConstants.RIGHT -> right += ARROW_SIZE; - case SwingConstants.BOTTOM -> bottom += ARROW_SIZE; - } - - if (UIManager.getLookAndFeel() instanceof FlatLaf) { - shadowBorder = new FlatDropShadowBorder( - UIManager.getColor("Popup.dropShadowColor"), - new Insets(SHADOW_SIZE2, SHADOW_SIZE2, SHADOW_SIZE2, SHADOW_SIZE2), - FlatUIUtils.getUIFloat("Popup.dropShadowOpacity", 0.5f) - ); - } else { - shadowBorder = null; - } - } - - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - Graphics2D g2 = (Graphics2D) g.create(); - try { - FlatUIUtils.setRenderingHints(g2); - g2.translate(x, y); - - // shadow coordinates - int sx = 0; - int sy = 0; - int sw = width; - int sh = height; - int arrowSize = UIScale.scale(ARROW_SIZE); - switch (direction) { - case SwingConstants.LEFT -> { - sx += arrowSize; - sw -= arrowSize; - } - case SwingConstants.TOP -> { - sy += arrowSize; - sh -= arrowSize; - } - case SwingConstants.RIGHT -> sw -= arrowSize; - case SwingConstants.BOTTOM -> sh -= arrowSize; - } - - // paint shadow - if (shadowBorder != null) - shadowBorder.paintBorder(c, g2, sx, sy, sw, sh); - - // create balloon shape - int bx = UIScale.scale(SHADOW_SIZE); - int by = UIScale.scale(SHADOW_TOP_SIZE); - int bw = width - UIScale.scale(SHADOW_SIZE + SHADOW_SIZE); - int bh = height - UIScale.scale(SHADOW_TOP_SIZE + SHADOW_SIZE); - g2.translate(bx, by); - Shape shape = createBalloonShape(bw, bh); - - // fill balloon background - g2.setColor(c.getBackground()); - g2.fill(shape); - - // paint balloon border - g2.setColor(borderColor); - g2.setStroke(new BasicStroke(UIScale.scale(1f))); - g2.draw(shape); - } finally { - g2.dispose(); - } - } - - private Shape createBalloonShape(int width, int height) { - int arc = UIScale.scale(ARC); - int xy = UIScale.scale(ARROW_XY); - int awh = UIScale.scale(ARROW_SIZE); - - Shape rect; - Shape arrow; - - switch (direction) { - case SwingConstants.LEFT -> { - rect = new RoundRectangle2D.Float(awh, 0, width - 1 - awh, height - 1, arc, arc); - arrow = FlatUIUtils.createPath(awh, xy, 0, xy + awh, awh, xy + awh + awh); - } - case SwingConstants.TOP -> { - rect = new RoundRectangle2D.Float(0, awh, width - 1, height - 1 - awh, arc, arc); - arrow = FlatUIUtils.createPath(xy, awh, xy + awh, 0, xy + awh + awh, awh); - } - case SwingConstants.RIGHT -> { - rect = new RoundRectangle2D.Float(0, 0, width - 1 - awh, height - 1, arc, arc); - int x = width - 1 - awh; - arrow = FlatUIUtils.createPath(x, xy, x + awh, xy + awh, x, xy + awh + awh); - } - case SwingConstants.BOTTOM -> { - rect = new RoundRectangle2D.Float(0, 0, width - 1, height - 1 - awh, arc, arc); - int y = height - 1 - awh; - arrow = FlatUIUtils.createPath(xy, y, xy + awh, y + awh, xy + awh + awh, y); - } - default -> throw new RuntimeException(); - } - - Area area = new Area(rect); - area.add(new Area(arrow)); - return area; - } - } - - public record Hint(String message, Component owner, int position, HintManager.Hint nextHint) {} -} diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/spi/EditorOnboarding.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/spi/EditorOnboarding.java new file mode 100644 index 000000000..17a705b02 --- /dev/null +++ b/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/spi/EditorOnboarding.java @@ -0,0 +1,27 @@ +package com.shade.platform.ui.editors.spi; + +import com.shade.platform.ui.menus.MenuItemRegistration; +import com.shade.util.NotNull; +import com.shade.util.Nullable; + +public sealed interface EditorOnboarding { + /** + * Action (menu item) reference to be shown on the onboarding screen. + * + * @param id identifier of the menu item, see {@link MenuItemRegistration#id()} + * @param name custom name for the menu item. If {@code null}, the name of the menu item will be used + */ + record Action(@NotNull String id, @Nullable String name) implements EditorOnboarding { + public Action(@NotNull String id) { + this(id, null); + } + } + + /** + * Arbitrary text to be shown on the onboarding screen. + * + * @param text text to be shown + */ + record Text(@NotNull String text) implements EditorOnboarding { + } +} diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/spi/EditorOnboardingProvider.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/spi/EditorOnboardingProvider.java new file mode 100644 index 000000000..91cc6fdc0 --- /dev/null +++ b/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/spi/EditorOnboardingProvider.java @@ -0,0 +1,8 @@ +package com.shade.platform.ui.editors.spi; + +import com.shade.util.NotNull; + +public interface EditorOnboardingProvider { + @NotNull + Iterable getOnboardings(); +} diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/stack/EditorStackContainer.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/stack/EditorStackContainer.java index f822d470d..eee1ff684 100644 --- a/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/stack/EditorStackContainer.java +++ b/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/stack/EditorStackContainer.java @@ -85,6 +85,15 @@ public boolean isSplit() { return getComponent(0) instanceof JSplitPane; } + public boolean isLeaf() { + return getComponent(0) instanceof EditorStack; + } + + @NotNull + public EditorStack asEditorStack() { + return (EditorStack) getComponent(0); + } + @NotNull public EditorStackContainer getLeftContainer() { return (EditorStackContainer) ((JSplitPane) getComponent(0)).getLeftComponent(); diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/stack/EditorStackManager.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/stack/EditorStackManager.java index 4a8d013ce..e380efcb2 100644 --- a/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/stack/EditorStackManager.java +++ b/modules/platform-ui/src/main/java/com/shade/platform/ui/editors/stack/EditorStackManager.java @@ -13,7 +13,11 @@ import com.shade.platform.model.util.IOUtils; import com.shade.platform.ui.PlatformDataKeys; import com.shade.platform.ui.editors.*; +import com.shade.platform.ui.editors.spi.EditorOnboarding; +import com.shade.platform.ui.editors.spi.EditorOnboardingProvider; +import com.shade.platform.ui.menus.MenuItemRegistration; import com.shade.platform.ui.menus.MenuManager; +import com.shade.platform.ui.util.UIUtils; import com.shade.util.NotNull; import com.shade.util.Nullable; import org.slf4j.Logger; @@ -112,16 +116,7 @@ public void editorChanged(@Nullable Editor editor) { } }); - this.container = new EditorStackContainer(this, null); - this.container.addHierarchyListener(new HierarchyListener() { - @Override - public void hierarchyChanged(HierarchyEvent e) { - if ((e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0) { - container.removeHierarchyListener(this); - container.layoutContainer(); - } - } - }); + this.container = new RootEditorStackContainer(this); } @Nullable @@ -751,7 +746,7 @@ private void forEachStack(@NotNull Component component, @NotNull Consumer elements = new ArrayList<>(); + + for (EditorOnboardingProvider provider : ServiceLoader.load(EditorOnboardingProvider.class)) { + for (EditorOnboarding onboarding : provider.getOnboardings()) { + final OnboardingElement element = resolveElement(onboarding); + if (element == null) { + continue; + } + elements.add(element); + } + } + + return elements.toArray(OnboardingElement[]::new); + } + + @Nullable + private static OnboardingElement resolveElement(@NotNull EditorOnboarding onboarding) { + if (onboarding instanceof EditorOnboarding.Action action) { + final MenuItemRegistration item = MenuManager.getInstance().findItem(action.id()); + if (item == null) { + log.warn("Unable to resolve onboarding command: " + action.id()); + return null; + } + + final String name; + if (action.name() == null) { + name = item.name(); + } else { + name = action.name(); + } + + final String description; + if (item.keystroke().isEmpty()) { + description = null; + } else { + description = UIUtils.getTextForAccelerator(KeyStroke.getKeyStroke(item.keystroke())); + } + + return new OnboardingElement(name, description); + } else if (onboarding instanceof EditorOnboarding.Text text) { + return new OnboardingElement(text.text(), null); + } else { + return null; + } + } + + private record OnboardingElement(@NotNull String text, @Nullable String description) {} + } } diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/menus/MenuManager.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/menus/MenuManager.java index 6758acbb1..d2eb3f101 100644 --- a/modules/platform-ui/src/main/java/com/shade/platform/ui/menus/MenuManager.java +++ b/modules/platform-ui/src/main/java/com/shade/platform/ui/menus/MenuManager.java @@ -4,6 +4,7 @@ import com.shade.platform.model.data.DataContext; import com.shade.platform.model.data.DataKey; import com.shade.util.NotNull; +import com.shade.util.Nullable; import javax.swing.*; @@ -30,4 +31,7 @@ static MenuManager getInstance() { void installMenuBar(@NotNull JRootPane pane, @NotNull String id, @NotNull DataContext context); void update(@NotNull JToolBar toolBar); + + @Nullable + MenuItemRegistration findItem(@NotNull String id); } diff --git a/modules/platform-ui/src/main/java/com/shade/platform/ui/util/UIUtils.java b/modules/platform-ui/src/main/java/com/shade/platform/ui/util/UIUtils.java index e8f7b29d0..1949b7cb2 100644 --- a/modules/platform-ui/src/main/java/com/shade/platform/ui/util/UIUtils.java +++ b/modules/platform-ui/src/main/java/com/shade/platform/ui/util/UIUtils.java @@ -467,6 +467,25 @@ public static DataFlavor createLocalDataFlavor(@NotNull Class cls) { } } + @NotNull + public static String getTextForAccelerator(@NotNull KeyStroke accelerator) { + final StringBuilder sb = new StringBuilder(); + + final int modifiers = accelerator.getModifiers(); + if (modifiers != 0) { + sb.append(InputEvent.getModifiersExText(modifiers)).append('+'); + } + + final int keyCode = accelerator.getKeyCode(); + if (keyCode != 0) { + sb.append(KeyEvent.getKeyText(keyCode)); + } else { + sb.append(accelerator.getKeyChar()); + } + + return sb.toString(); + } + public interface SelectionProvider { @Nullable U getSelection(@NotNull T component, @Nullable MouseEvent event); diff --git a/modules/platform-ui/src/main/resources/themes/FlatDarkLaf.properties b/modules/platform-ui/src/main/resources/themes/FlatDarkLaf.properties index 0b5bf0df2..35ce220af 100644 --- a/modules/platform-ui/src/main/resources/themes/FlatDarkLaf.properties +++ b/modules/platform-ui/src/main/resources/themes/FlatDarkLaf.properties @@ -5,9 +5,6 @@ Component.warning.background = darken($Component.warning.borderColor, 10%) # Dialog Dialog.buttonBackground = lighten(@background,2%) -# Hint Panel -HintPanel.backgroundColor = darken(#ffffe1,80%) - # Color Icon ColorIcon.oddBackground = @background ColorIcon.evenBackground = lighten(ColorIcon.oddBackground,10%,lazy) @@ -32,3 +29,7 @@ HexEditor.dividerForeground = lighten(HexEditor.background,10%,lazy) # Graph Graph.nodeSelectionBackground = mix($Component.focusColor, $Graph.nodeBackground, 25%) + +# Editor onboarding +Onboarding.textForeground = #8a8a8a +Onboarding.descriptionForeground = #e2e2e2 \ No newline at end of file diff --git a/modules/platform-ui/src/main/resources/themes/FlatLaf.properties b/modules/platform-ui/src/main/resources/themes/FlatLaf.properties index 48af65b3b..15f0eaa59 100644 --- a/modules/platform-ui/src/main/resources/themes/FlatLaf.properties +++ b/modules/platform-ui/src/main/resources/themes/FlatLaf.properties @@ -31,9 +31,6 @@ Component.warning.background = lighten($Component.warning.borderColor, 10%) # Dialog Dialog.buttonBackground = darken(@background,3%) -# Hint Panel -HintPanel.backgroundColor = #ffffe1 - # LabeledSeparator LabeledSeparator.labelForeground = @foreground @@ -77,4 +74,9 @@ Graph.nodeBorderColor = $Component.borderColor Graph.nodeSelectionBackground = changeLightness($Component.focusColor,95%) Graph.nodeBorderSelectionColor = $Component.focusedBorderColor Graph.edgeBackground = $Graph.nodeBorderColor -Graph.edgeSelectionBackground = @selectionBackground \ No newline at end of file +Graph.edgeSelectionBackground = @selectionBackground + +# Editor onboarding +Onboarding.font = $h2.regular.font +Onboarding.textForeground = #8a8a8a +Onboarding.descriptionForeground = #393939 \ No newline at end of file