Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,12 @@ public class EditorConfig extends ReflectiveConfig {

@Comment("Settings for editors' entry tooltips.")
public final EntryTooltipsSection entryTooltips = new EntryTooltipsSection();

@Comment(
"""
Settings for the editor's selection highlighting; used to highlight entries that have been navigated to.
The color of the highlight is defined per-theme (in themes/) by [syntax_pane_colors] > selection_highlight.\
"""
)
public final SelectionHighlightSection selectionHighlight = new SelectionHighlightSection();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.quiltmc.enigma.gui.config;

import org.quiltmc.config.api.ReflectiveConfig;
import org.quiltmc.config.api.annotations.Comment;
import org.quiltmc.config.api.annotations.IntegerRange;
import org.quiltmc.config.api.annotations.SerializedNameConvention;
import org.quiltmc.config.api.metadata.NamingSchemes;
import org.quiltmc.config.api.values.TrackedValue;

@SerializedNameConvention(NamingSchemes.SNAKE_CASE)
public class SelectionHighlightSection extends ReflectiveConfig.Section {
public static final int MIN_BLINKS = 0;
public static final int MAX_BLINKS = 10;
public static final int MIN_BLINK_DELAY = 10;
public static final int MAX_BLINK_DELAY = 5000;

@Comment("The number of times the highlighting blinks. Set to 0 to disable highlighting.")
@IntegerRange(min = MIN_BLINKS, max = MAX_BLINKS)
public final TrackedValue<Integer> blinks = this.value(3);

@Comment("The milliseconds the highlighting should be on and then off when blinking.")
@IntegerRange(min = MIN_BLINK_DELAY, max = MAX_BLINK_DELAY)
public final TrackedValue<Integer> blinkDelay = this.value(200);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.util.Iterator;
import java.util.concurrent.CompletableFuture;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
Expand All @@ -41,52 +42,71 @@ public EditorTabbedPane(Gui gui) {

public EditorPanel openClass(ClassEntry entry) {
EditorPanel activeEditor = this.getActiveEditor();
EditorPanel entryEditor = this.editors.computeIfAbsent(entry, editing -> {
ClassHandle classHandle = this.gui.getController().getClassHandleProvider().openClass(editing);
if (classHandle == null) {
return null;
}

this.navigator = new NavigatorPanel(this.gui);
EditorPanel newEditor = new EditorPanel(this.gui, this.navigator);
newEditor.setClassHandle(classHandle);
this.openFiles.addTab(newEditor.getSimpleClassName(), newEditor.getUi());

ClosableTabTitlePane titlePane = new ClosableTabTitlePane(newEditor.getSimpleClassName(), newEditor.getFullClassName(), () -> this.closeEditor(newEditor));
this.openFiles.setTabComponentAt(this.openFiles.indexOfComponent(newEditor.getUi()), titlePane.getUi());
titlePane.setTabbedPane(this.openFiles);

newEditor.addListener(new EditorActionListener() {
@Override
public void onCursorReferenceChanged(EditorPanel editor, EntryReference<Entry<?>, Entry<?>> ref) {
if (editor == EditorTabbedPane.this.getActiveEditor()) {
EditorTabbedPane.this.gui.showCursorReference(ref);
}
}

@Override
public void onClassHandleChanged(EditorPanel editor, ClassEntry old, ClassHandle ch) {
EditorTabbedPane.this.editors.remove(old);
EditorTabbedPane.this.editors.put(ch.getRef(), editor);
final EditorPanel entryEditor;
final CompletableFuture<?> entryEditorReady;
{
final EditorPanel existingEditor = this.editors.get(entry);

if (existingEditor == null) {
ClassHandle classHandle = this.gui.getController().getClassHandleProvider().openClass(entry);
if (classHandle == null) {
entryEditor = null;
entryEditorReady = null;
} else {
this.navigator = new NavigatorPanel(this.gui);
final EditorPanel newEditor = new EditorPanel(this.gui, this.navigator);
entryEditorReady = newEditor.setClassHandle(classHandle);
this.openFiles.addTab(newEditor.getSimpleClassName(), newEditor.getUi());

ClosableTabTitlePane titlePane = new ClosableTabTitlePane(newEditor.getSimpleClassName(), newEditor.getFullClassName(), () -> this.closeEditor(newEditor));
this.openFiles.setTabComponentAt(this.openFiles.indexOfComponent(newEditor.getUi()), titlePane.getUi());
titlePane.setTabbedPane(this.openFiles);

newEditor.addListener(new EditorActionListener() {
@Override
public void onCursorReferenceChanged(EditorPanel editor, EntryReference<Entry<?>, Entry<?>> ref) {
if (editor == EditorTabbedPane.this.getActiveEditor()) {
EditorTabbedPane.this.gui.showCursorReference(ref);
}
}

@Override
public void onClassHandleChanged(EditorPanel editor, ClassEntry old, ClassHandle ch) {
EditorTabbedPane.this.editors.remove(old);
EditorTabbedPane.this.editors.put(ch.getRef(), editor);
}

@Override
public void onTitleChanged(EditorPanel editor, String title) {
titlePane.setText(editor.getSimpleClassName(), editor.getFullClassName());
}
});

putKeyBindAction(KeyBinds.EDITOR_CLOSE_TAB, newEditor.getEditor(), e -> this.closeEditor(newEditor));
putKeyBindAction(KeyBinds.ENTRY_NAVIGATOR_NEXT, newEditor.getEditor(), e -> newEditor.getNavigatorPanel().navigateDown());
putKeyBindAction(KeyBinds.ENTRY_NAVIGATOR_LAST, newEditor.getEditor(), e -> newEditor.getNavigatorPanel().navigateUp());

this.editors.put(entry, newEditor);

entryEditor = newEditor;
}

@Override
public void onTitleChanged(EditorPanel editor, String title) {
titlePane.setText(editor.getSimpleClassName(), editor.getFullClassName());
}
});

putKeyBindAction(KeyBinds.EDITOR_CLOSE_TAB, newEditor.getEditor(), e -> this.closeEditor(newEditor));
putKeyBindAction(KeyBinds.ENTRY_NAVIGATOR_NEXT, newEditor.getEditor(), e -> newEditor.getNavigatorPanel().navigateDown());
putKeyBindAction(KeyBinds.ENTRY_NAVIGATOR_LAST, newEditor.getEditor(), e -> newEditor.getNavigatorPanel().navigateUp());

return newEditor;
});
} else {
entryEditor = existingEditor;
entryEditorReady = null;
}
}

if (entryEditor != null && activeEditor != entryEditor) {
this.openFiles.setSelectedComponent(this.editors.get(entry).getUi());
this.openFiles.setSelectedComponent(entryEditor.getUi());
this.gui.updateStructure(entryEditor);
this.gui.showCursorReference(entryEditor.getCursorReference());

final Runnable showReference = () -> this.gui.showCursorReference(entryEditor.getCursorReference());
if (entryEditorReady == null) {
showReference.run();
} else {
entryEditorReady.thenRunAsync(showReference, SwingUtilities::invokeLater);
}
}

return entryEditor;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package org.quiltmc.enigma.gui.element;

import org.quiltmc.config.api.values.TrackedValue;
import org.quiltmc.enigma.gui.Gui;
import org.quiltmc.enigma.util.I18n;
import org.quiltmc.enigma.util.Utils;

import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import java.util.Optional;

public class IntRangeConfigMenuItem extends JMenuItem {
public static final String DIALOG_TITLE_TRANSLATION_KEY_SUFFIX = ".dialog_title";
public static final String DIALOG_EXPLANATION_TRANSLATION_KEY_SUFFIX = ".dialog_explanation";
private final TrackedValue<Integer> config;

private final String translationKey;

/**
* Constructs a menu item that, when clicked, prompts the user for an integer between the passed {@code min} and
* {@code max} using a dialog.<br>
* The menu item will be kept in sync with the passed {@code config}.
*
* @param gui the gui
* @param config the config value to sync with
* @param min the minimum allowed value;
* this should coincide with any minimum imposed on the passed {@code config}
* @param max the maximum allowed value
* this should coincide with any maximum imposed on the passed {@code config}
* @param rootTranslationKey a translation key for deriving translations as follows:
* <ul>
* <li> this component's text: the unmodified key
* <li> the title of the dialog: the key with
* {@value #DIALOG_TITLE_TRANSLATION_KEY_SUFFIX} appended
* <li> the explanation of the dialog: the key with
* {@value #DIALOG_EXPLANATION_TRANSLATION_KEY_SUFFIX} appended
* </ul>
*/
public IntRangeConfigMenuItem(Gui gui, TrackedValue<Integer> config, int min, int max, String rootTranslationKey) {
this(
gui, config, min, max, rootTranslationKey,
rootTranslationKey + DIALOG_TITLE_TRANSLATION_KEY_SUFFIX,
rootTranslationKey + DIALOG_EXPLANATION_TRANSLATION_KEY_SUFFIX
);
}

private IntRangeConfigMenuItem(
Gui gui, TrackedValue<Integer> config, int min, int max,
String translationKey, String dialogTitleTranslationKey, String dialogExplanationTranslationKey
) {
this.config = config;
this.translationKey = translationKey;

this.addActionListener(e ->
getRangedIntInput(
gui, config.value(), min, max,
I18n.translate(dialogTitleTranslationKey),
I18n.translate(dialogExplanationTranslationKey)
)
.ifPresent(input -> {
if (!input.equals(config.value())) {
config.setValue(input);
}
})
);

config.registerCallback(updated -> {
this.retranslate();
});
}

public void retranslate() {
this.setText(I18n.translateFormatted(this.translationKey, this.config.value()));
}

private static Optional<Integer> getRangedIntInput(
Gui gui, int initialValue, int min, int max, String title, String explanation
) {
final String prompt = I18n.translateFormatted("prompt.input.int_range", min, max);
final String input = (String) JOptionPane.showInputDialog(
gui.getFrame(),
explanation + "\n" + prompt,
title,
JOptionPane.QUESTION_MESSAGE, null, null, initialValue
);

if (input != null) {
try {
return Optional.of(Utils.clamp(Integer.parseInt(input), min, max));
} catch (NumberFormatException e) {
return Optional.empty();
}
} else {
return Optional.empty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import javax.swing.JMenu;

public class AbstractEnigmaMenu extends JMenu implements EnigmaMenu {
public abstract class AbstractEnigmaMenu extends JMenu implements EnigmaMenu {
protected final Gui gui;

protected AbstractEnigmaMenu(Gui gui) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.quiltmc.enigma.gui.element.menu_bar.view;

import org.quiltmc.enigma.gui.Gui;
import org.quiltmc.enigma.gui.config.Config;
import org.quiltmc.enigma.gui.config.SelectionHighlightSection;
import org.quiltmc.enigma.gui.element.IntRangeConfigMenuItem;
import org.quiltmc.enigma.gui.element.menu_bar.AbstractEnigmaMenu;
import org.quiltmc.enigma.gui.util.GuiUtil;
import org.quiltmc.enigma.util.I18n;

import javax.swing.JMenu;

public class SelectionHighlightMenu extends AbstractEnigmaMenu {
private final JMenu blinksMenu;
private final IntRangeConfigMenuItem blinkDelay;

protected SelectionHighlightMenu(Gui gui) {
super(gui);

final SelectionHighlightSection config = Config.editor().selectionHighlight;

this.blinksMenu = GuiUtil.createIntConfigRadioMenu(
config.blinks,
SelectionHighlightSection.MIN_BLINKS, SelectionHighlightSection.MAX_BLINKS,
this::retranslateBlinksMenu
);

this.blinkDelay = new IntRangeConfigMenuItem(
gui, config.blinkDelay,
SelectionHighlightSection.MIN_BLINK_DELAY, SelectionHighlightSection.MAX_BLINK_DELAY,
"menu.view.selection_highlight.blink_delay"
);

this.add(this.blinksMenu);
this.add(this.blinkDelay);

this.retranslate();
}

@Override
public void retranslate() {
this.setText(I18n.translate("menu.view.selection_highlight"));

this.retranslateBlinksMenu();
this.blinkDelay.retranslate();
}

private void retranslateBlinksMenu() {
this.blinksMenu.setText(I18n.translateFormatted(
"menu.view.selection_highlight.blinks",
Config.editor().selectionHighlight.blinks.value())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class ViewMenu extends AbstractEnigmaMenu {
private final ThemesMenu themes;
private final ScaleMenu scale;
private final EntryTooltipsMenu entryTooltips;
private final SelectionHighlightMenu selectionHighlight;

private final JMenuItem fontItem = new JMenuItem();

Expand All @@ -26,8 +27,10 @@ public ViewMenu(Gui gui) {
this.themes = new ThemesMenu(gui);
this.scale = new ScaleMenu(gui);
this.entryTooltips = new EntryTooltipsMenu(gui);
this.selectionHighlight = new SelectionHighlightMenu(gui);

this.add(this.themes);
this.add(this.selectionHighlight);
this.add(this.languages);
this.add(this.notifications);
this.add(this.scale);
Expand All @@ -48,6 +51,7 @@ public void retranslate() {
this.scale.retranslate();
this.stats.retranslate();
this.entryTooltips.retranslate();
this.selectionHighlight.retranslate();
this.fontItem.setText(I18n.translate("menu.view.font"));
}

Expand Down
Loading