diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/Widget.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/Widget.java index 064f1c5..24622cc 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/Widget.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/Widget.java @@ -15,6 +15,8 @@ import org.nanoboot.utils.timecalc.utils.property.StringProperty; import javax.swing.ImageIcon; import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.Timer; import java.awt.BasicStroke; @@ -22,10 +24,14 @@ import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; +import java.util.function.Consumer; /** * @author Robert Vokac @@ -74,6 +80,7 @@ public class Widget extends JPanel implements private static final Color PURPLE_STRONGLY_COLORED = new Color(153,51,255); private static final Color PURPLE_WEAKLY_COLORED = new Color(204,153,255); + private WidgetMenu widgetMenu = null; public Widget() { setBackground(BACKGROUND_COLOR); new Timer(getTimerDelay(), e -> repaint()).start(); @@ -92,6 +99,7 @@ public class Widget extends JPanel implements && y <= CLOSE_BUTTON_SIDE; } }); + addMouseListener(new MouseListener() { @Override public void mouseClicked(MouseEvent e) { @@ -105,17 +113,17 @@ public class Widget extends JPanel implements //nothing to do return; } - if (visibleProperty.isEnabled()) { - Visibility visibility - = Visibility.valueOf(visibilityProperty.getValue()); - if (visibility.isStronglyColored()) { - visibilityProperty - .setValue(Visibility.WEAKLY_COLORED.name()); - } else { - visibilityProperty - .setValue(Visibility.STRONGLY_COLORED.name()); - } - } +// if (visibleProperty.isEnabled()) { +// Visibility visibility +// = Visibility.valueOf(visibilityProperty.getValue()); +// if (visibility.isStronglyColored()) { +// visibilityProperty +// .setValue(Visibility.WEAKLY_COLORED.name()); +// } else { +// visibilityProperty +// .setValue(Visibility.STRONGLY_COLORED.name()); +// } +// } } @Override @@ -138,6 +146,46 @@ public class Widget extends JPanel implements mouseOver = false; } }); + + Widget widget = this; + addMouseListener(new MouseAdapter() { + + @Override + public void mousePressed(MouseEvent e) { + showPopup(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + showPopup(e); + } + + private void showPopup(MouseEvent e) { + if(widgetMenu == null) { + widgetMenu = new WidgetMenu(widget, createRefreshConsumer()); + List additionalMenus = createAdditionalMenus(); + if(additionalMenus != null) { + additionalMenus.forEach(m-> widgetMenu.add(m)); + } + } + widgetMenu.refresh(); + widgetMenu.markAsSelected(WidgetType.valueOf(typeProperty.getValue().toUpperCase( + Locale.ROOT))); + if (e.isPopupTrigger()) { + widgetMenu.show(e.getComponent(), + e.getX(), e.getY()); + + } + } + + + }); + } + protected Consumer createRefreshConsumer() { + return null; + } + protected List createAdditionalMenus() { + return null; } public int getTimerDelay() { diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/WidgetMenu.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/WidgetMenu.java new file mode 100644 index 0000000..534a9aa --- /dev/null +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/WidgetMenu.java @@ -0,0 +1,116 @@ +package org.nanoboot.utils.timecalc.swing.common; + +import org.nanoboot.utils.timecalc.app.TimeCalcException; +import org.nanoboot.utils.timecalc.entity.WidgetType; +import org.nanoboot.utils.timecalc.swing.progress.Battery; + +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import java.util.Locale; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * @author pc00289 + * @since 21.03.2024 + */ +public class WidgetMenu extends JPopupMenu { + private final JMenuItem typeMinuteMenuItem; + private final JMenuItem typeHourMenuItem; + private final JMenuItem typeDayMenuItem; + private final JMenuItem typeWeekMenuItem; + private final JMenuItem typeMonthMenuItem; + private final JMenuItem typeYearMenuItem; + private final Widget widget; + private WidgetType selectedType; + private Consumer refreshConsumer; + + public WidgetMenu(Widget widget) { + this(widget, null); + } + public WidgetMenu(Widget widget, Consumer refreshConsumer) { + this.widget = widget; + this.refreshConsumer = refreshConsumer; + + JMenuItem typeMenuItem = new JMenu("Type"/*,*/ + /*new ImageIcon("images/newproject.png")*/); + //menuItem.setMnemonic(KeyEvent.VK_P); + //menuItem.getAccessibleContext().setAccessibleDescription("New Project"); + add(typeMenuItem); + + this.typeMinuteMenuItem = new JMenuItem(WidgetType.MINUTE.name()); + this.typeHourMenuItem = new JMenuItem(WidgetType.HOUR.name()); + this.typeDayMenuItem = new JMenuItem(WidgetType.DAY.name()); + this.typeWeekMenuItem = new JMenuItem(WidgetType.WEEK.name()); + this.typeMonthMenuItem = new JMenuItem(WidgetType.MONTH.name()); + this.typeYearMenuItem = new JMenuItem(WidgetType.YEAR.name()); + typeMenuItem.add(typeMinuteMenuItem); + typeMenuItem.add(typeHourMenuItem); + typeMenuItem.add(typeDayMenuItem); + typeMenuItem.add(typeWeekMenuItem); + typeMenuItem.add(typeMonthMenuItem); + typeMenuItem.add(typeYearMenuItem); + + BiConsumer typeActionCreator = (m,w) -> { + m.addActionListener(e -> { + if(widget instanceof Battery && !widget.typeProperty.getValue().equals(w.name().toLowerCase(Locale.ROOT))) { + //nothing to do + return; + } + markAsSelected(w); + widget.typeProperty.setValue(w.name().toLowerCase(Locale.ROOT)); + }); + }; + typeActionCreator.accept(typeMinuteMenuItem, WidgetType.MINUTE); + typeActionCreator.accept(typeHourMenuItem, WidgetType.HOUR); + typeActionCreator.accept(typeDayMenuItem, WidgetType.DAY); + typeActionCreator.accept(typeWeekMenuItem, WidgetType.WEEK); + typeActionCreator.accept(typeMonthMenuItem, WidgetType.MONTH); + typeActionCreator.accept(typeYearMenuItem, WidgetType.YEAR); + + typeWeekMenuItem.addActionListener(e -> { + markAsSelected(WidgetType.WEEK); + widget.typeProperty.setValue(WidgetType.WEEK + .name().toLowerCase(Locale.ROOT)); + }); + typeMonthMenuItem.addActionListener(e -> { + markAsSelected(WidgetType.MONTH); + widget.typeProperty.setValue(WidgetType.MONTH + .name().toLowerCase(Locale.ROOT)); + }); + typeYearMenuItem.addActionListener(e -> { + markAsSelected(WidgetType.YEAR); + widget.typeProperty.setValue(WidgetType.YEAR + .name().toLowerCase(Locale.ROOT)); + }); + //if(!aClass.getSimpleName().contains("Battery")) { + add(typeMenuItem); + //} + } + public void markAsSelected(WidgetType widgetType) { + this.typeMinuteMenuItem.setText(WidgetType.MINUTE.name()); + this.typeHourMenuItem .setText(WidgetType.HOUR.name()); + this.typeDayMenuItem.setText(WidgetType.DAY.name()); + this.typeWeekMenuItem.setText(WidgetType.WEEK.name()); + this.typeMonthMenuItem.setText(WidgetType.MONTH.name()); + this.typeYearMenuItem.setText(WidgetType.YEAR.name()); + switch (widgetType) { + case MINUTE: typeMinuteMenuItem.setText(typeMinuteMenuItem.getText() + " (*)");break; + case HOUR: typeHourMenuItem.setText(typeHourMenuItem.getText() + " (*)");break; + case DAY: typeDayMenuItem.setText(typeDayMenuItem.getText() + " (*)");break; + case WEEK: typeWeekMenuItem.setText(typeWeekMenuItem.getText() + " (*)");break; + case MONTH: typeMonthMenuItem.setText(typeMonthMenuItem.getText() + " (*)");break; + case YEAR: typeYearMenuItem.setText(typeYearMenuItem.getText() + " (*)");break; + default: throw new TimeCalcException("Unsupported WidgetType: " + widgetType); + } + this.selectedType = widgetType; + } + public void refresh () { + if(refreshConsumer == null) { + //nothing to do + return; + } + this.refreshConsumer.accept(null); + } +} diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/controls/TMenuItem.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/controls/TMenuItem.java new file mode 100644 index 0000000..e54d8c5 --- /dev/null +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/controls/TMenuItem.java @@ -0,0 +1,40 @@ +package org.nanoboot.utils.timecalc.swing.controls; + +import javax.swing.JMenuItem; + +/** + * @author pc00289 + * @since 21.03.2024 + */ +public class TMenuItem extends JMenuItem { + private static final String ENABLED = " (*)"; + private boolean enabledMenuItem = false; + + public TMenuItem(String text) { + super(text); + } + + public void disableMenuItem() { + if(getText().endsWith(ENABLED)) { + setText(getText().substring(0, getText().length() - ENABLED.length())); + } + enabledMenuItem = false; + } + public void enableMenuItem() { + if(!getText().endsWith(ENABLED)) { + setText(getText() + ENABLED); + } + enabledMenuItem = true; + } + public void setEnabledMenuItem(boolean value) { + + if(value) {enableMenuItem();} else { + disableMenuItem(); + } + + enabledMenuItem = value; + } + public void flip() { + setEnabledMenuItem(!enabledMenuItem); + } +} diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/AnalogClock.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/AnalogClock.java index ef769f1..268c79a 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/AnalogClock.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/AnalogClock.java @@ -5,14 +5,15 @@ import org.nanoboot.utils.timecalc.entity.Visibility; import org.nanoboot.utils.timecalc.entity.WidgetType; import org.nanoboot.utils.timecalc.swing.common.SwingUtils; import org.nanoboot.utils.timecalc.swing.common.Widget; +import org.nanoboot.utils.timecalc.swing.controls.TMenuItem; import org.nanoboot.utils.timecalc.utils.common.DateFormats; -import org.nanoboot.utils.timecalc.utils.common.NumberFormats; import org.nanoboot.utils.timecalc.utils.common.TTime; import org.nanoboot.utils.timecalc.utils.property.BooleanProperty; import org.nanoboot.utils.timecalc.utils.property.IntegerProperty; import org.nanoboot.utils.timecalc.utils.property.StringProperty; import javax.swing.JFrame; +import javax.swing.JMenu; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; @@ -20,9 +21,12 @@ import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import java.util.List; import java.util.Locale; +import java.util.function.Consumer; //https://kodejava.org/how-do-i-write-a-simple-analog-clock-using-java-2d/ public class AnalogClock extends Widget { @@ -99,6 +103,11 @@ public class AnalogClock extends Widget { public final BooleanProperty percentProgressVisibleProperty = new BooleanProperty("percentProgressVisibleProperty"); private Color customCircleColor = null; private double dayProgress; + private TMenuItem millisecondHandMenuItem; + private TMenuItem secondHandMenuItem; + private TMenuItem minuteHandMenuItem; + private TMenuItem hourHandMenuItem; + private List menuItems = null; public AnalogClock() { typeProperty.setValue(WidgetType.DAY.name().toLowerCase(Locale.ROOT)); @@ -411,4 +420,76 @@ public class AnalogClock extends Widget { return 100; } + @Override + public List createAdditionalMenus() { + if(menuItems == null) { + menuItems = new ArrayList<>(); + JMenu hands = new JMenu("Hands"); + menuItems.add(hands); + + this.millisecondHandMenuItem = new TMenuItem("Millisecond"); + this.secondHandMenuItem = new TMenuItem("Second"); + this.minuteHandMenuItem = new TMenuItem("Minute"); + this.hourHandMenuItem = new TMenuItem("Hour"); + + if (millisecondEnabledProperty.isEnabled()) { + millisecondHandMenuItem.enableMenuItem(); + } + if (secondEnabledProperty.isEnabled()) { + secondHandMenuItem.enableMenuItem(); + } + if (minuteEnabledProperty.isEnabled()) { + minuteHandMenuItem.enableMenuItem(); + } + if (hourEnabledProperty.isEnabled()) { + hourHandMenuItem.enableMenuItem(); + } + millisecondEnabledProperty.addListener( + (property, oldValue, newValue) -> millisecondHandMenuItem + .setEnabledMenuItem(newValue)); + secondEnabledProperty.addListener( + (property, oldValue, newValue) -> secondHandMenuItem + .setEnabledMenuItem(newValue)); + minuteEnabledProperty.addListener( + (property, oldValue, newValue) -> minuteHandMenuItem + .setEnabledMenuItem(newValue)); + hourEnabledProperty.addListener( + (property, oldValue, newValue) -> hourHandMenuItem + .setEnabledMenuItem(newValue)); + + hands.add(millisecondHandMenuItem); + hands.add(secondHandMenuItem); + hands.add(minuteHandMenuItem); + hands.add(hourHandMenuItem); + + millisecondHandMenuItem + .addActionListener(e -> millisecondEnabledProperty.flip()); + secondHandMenuItem + .addActionListener(e -> secondEnabledProperty.flip()); + minuteHandMenuItem + .addActionListener(e -> minuteEnabledProperty.flip()); + hourHandMenuItem.addActionListener(e -> hourEnabledProperty.flip()); + } + return this.menuItems; + } + protected Consumer createRefreshConsumer() { + return (o) -> { + millisecondHandMenuItem.disableMenuItem(); + secondHandMenuItem.disableMenuItem(); + minuteHandMenuItem.disableMenuItem(); + hourHandMenuItem.disableMenuItem(); + if (millisecondEnabledProperty.isEnabled()) { + millisecondHandMenuItem.enableMenuItem(); + } + if (secondEnabledProperty.isEnabled()) { + secondHandMenuItem.enableMenuItem(); + } + if (minuteEnabledProperty.isEnabled()) { + minuteHandMenuItem.enableMenuItem(); + } + if (hourEnabledProperty.isEnabled()) { + hourHandMenuItem.enableMenuItem(); + } + }; + } }