diff --git a/gui/src/main/java/mscalc/gui/viewmodel/ScientificCalculatorViewModel.java b/gui/src/main/java/mscalc/gui/viewmodel/ScientificCalculatorViewModel.java index 1beb735..d8592a9 100644 --- a/gui/src/main/java/mscalc/gui/viewmodel/ScientificCalculatorViewModel.java +++ b/gui/src/main/java/mscalc/gui/viewmodel/ScientificCalculatorViewModel.java @@ -61,6 +61,57 @@ public class ScientificCalculatorViewModel { .withKeyboardShortcut(KeyCode.F8) .build(); + // -- ANGLE TYPE SELECT -- + public final InputViewModel angleDegreesButton = newInputViewModel() + .withText("Degrees") + .withCommand(Command.CommandDEG) + .withKeyboardShortcut(KeyCode.F2) + .onlyActiveWhen(radixProperty.isEqualTo(RadixType.Decimal)) + .build(); + + public final InputViewModel angleRadiansButton = newInputViewModel() + .withText("Radians") + .withCommand(Command.CommandRAD) + .withKeyboardShortcut(KeyCode.F3) + .onlyActiveWhen(radixProperty.isEqualTo(RadixType.Decimal)) + .build(); + + public final InputViewModel angleGradiansButton = newInputViewModel() + .withText("Gradians") + .withCommand(Command.CommandGRAD) + .withKeyboardShortcut(KeyCode.F4) + .onlyActiveWhen(radixProperty.isEqualTo(RadixType.Decimal)) + .build(); + + // --- WORD WIDTH SELECT --- + public final InputViewModel radixWordWidthQWord = newInputViewModel() + .withText("QWORD") + .withCommand(Command.CommandQword) + .withKeyboardShortcut(KeyCode.F12) + .onlyActiveWhen(radixProperty.isNotEqualTo(RadixType.Decimal)) + .build(); + + public final InputViewModel radixWordWidthDWord = newInputViewModel() + .withText("DWORD") + .withCommand(Command.CommandDword) + .withKeyboardShortcut(KeyCode.F2) + .onlyActiveWhen(radixProperty.isNotEqualTo(RadixType.Decimal)) + .build(); + + public final InputViewModel radixWordWidthWord = newInputViewModel() + .withText("WORD") + .withCommand(Command.CommandWord) + .withKeyboardShortcut(KeyCode.F3) + .onlyActiveWhen(radixProperty.isNotEqualTo(RadixType.Decimal)) + .build(); + + public final InputViewModel radixWordWidthByte = newInputViewModel() + .withText("BYTE") + .withCommand(Command.CommandByte) + .withKeyboardShortcut(KeyCode.F4) + .onlyActiveWhen(radixProperty.isNotEqualTo(RadixType.Decimal)) + .build(); + // -- INVERT & HYP BUTTONS --- public final InputViewModel invertButton = newInputViewModel() .withText("Inverse") @@ -433,7 +484,9 @@ public class ScientificCalculatorViewModel { public ScientificCalculatorViewModel() { // Initialize Scientific mode calculatorManager.sendCommand(Command.ModeScientific); - // Select radians + // Setup some initial configuration + calculatorManager.sendCommand(Command.CommandQword); + calculatorManager.sendCommand(Command.CommandDec); calculatorManager.sendCommand(Command.CommandRAD); } @@ -476,12 +529,18 @@ public String toShortcutDescription() { } public class InputViewModelBuilder { + private BooleanExpression activeProperty = new ReadOnlyBooleanWrapper(true); private StringExpression textProperty; private StringExpression tooltipProperty = new ReadOnlyStringWrapper(null); private ObjectExpression commandProperty; private BooleanExpression enabledProperty = new ReadOnlyBooleanWrapper(true); private KeyboardCode keyboardShortcut; + public InputViewModelBuilder onlyActiveWhen(BooleanExpression condition) { + this.activeProperty = condition; + return this; + } + /* * Set text for normal, inverted, hyperbolic and hyperbolic-inverted modes. * You may specify only one, two or four names. @@ -568,24 +627,27 @@ public InputViewModel build() { keyboardShortcut.toShortcutDescription()); } - return new InputViewModel(textProperty, tooltipProperty, + return new InputViewModel(activeProperty, textProperty, tooltipProperty, commandProperty, enabledProperty, keyboardShortcut); } } public class InputViewModel { + private final BooleanExpression activeProperty; private final StringExpression textProperty; private final StringExpression tooltipProperty; private final ObjectExpression commandProperty; private final BooleanExpression enabledProperty; private final KeyboardCode keyboardShortcut; - public InputViewModel(StringExpression textProperty, + public InputViewModel(BooleanExpression activeProperty, + StringExpression textProperty, StringExpression tooltipProperty, ObjectExpression commandProperty, BooleanExpression enabledProperty, @Nullable KeyboardCode keyboardShortcut) { + this.activeProperty = Objects.requireNonNull(activeProperty); this.textProperty = Objects.requireNonNull(textProperty); this.tooltipProperty = Objects.requireNonNull(tooltipProperty); this.commandProperty = Objects.requireNonNull(commandProperty); @@ -593,7 +655,15 @@ public InputViewModel(StringExpression textProperty, this.keyboardShortcut = keyboardShortcut; } + public boolean isActive() { + return activeProperty.get(); + } + public void execute() { + if (!activeProperty.get()) { + return; + } + switch (this.commandProperty.get()) { case CommandINV -> { invertedModeProperty.set(!invertedModeProperty.get()); diff --git a/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.fxml b/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.fxml index 2cdb905..02398e3 100644 --- a/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.fxml +++ b/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.fxml @@ -20,14 +20,25 @@ - + - - - + + + + + + + + + + + + + + diff --git a/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.java b/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.java index 9c15615..5fe72fe 100644 --- a/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.java +++ b/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.java @@ -5,23 +5,28 @@ import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.input.KeyEvent; +import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -import javafx.scene.text.Font; import mscalc.engine.RadixType; import mscalc.gui.viewmodel.ScientificCalculatorViewModel; +import mscalc.gui.viewmodel.ScientificCalculatorViewModel.InputViewModel; import mscalc.gui.viewmodel.ScientificCalculatorViewModel.KeyboardCode; import mscalc.gui.views.CalculatorView; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; public class ScientificView extends VBox implements CalculatorView { private static final Logger logger = LogManager.getLogger(ScientificView.class); private final ScientificCalculatorViewModel viewModel = new ScientificCalculatorViewModel(); - private final HashMap keyboardMapping = new HashMap<>(); + + // Some buttons share same shortcuts but are not active at the same time + private final HashMap> keyboardMapping = new HashMap<>(); public ScientificView() { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("ScientificView.fxml")); @@ -42,6 +47,7 @@ public ScientificView() { @FXML private TextField display; + // Radix selection @FXML private ToggleGroup radixToggleGroup; @FXML @@ -53,6 +59,33 @@ public ScientificView() { @FXML private RadioButton radioRadixBin; + // Angle type selection + @FXML + private ToggleGroup angleTypeToggleGroup; + @FXML + private RadioButton radioAngleDegrees; + @FXML + private RadioButton radioAngleRadians; + @FXML + private RadioButton radioAngleGradians; + @FXML + private HBox selectAngleTypeArea; + + // Word width selection + @FXML + private ToggleGroup wordWidthToggleGroup; + @FXML + private RadioButton radioWidthQWord; + @FXML + private RadioButton radioWidthDWord; + @FXML + private RadioButton radioWidthWord; + @FXML + private RadioButton radioWidthByte; + @FXML + private HBox selectWordWidthArea; + + // Invert & Hyperbolic @FXML private CheckBox cbInvert; @@ -237,27 +270,22 @@ public void install(Scene scene) { bindButton(radioRadixDec, viewModel.radixDecButton); bindButton(radioRadixOct, viewModel.radixOctButton); bindButton(radioRadixBin, viewModel.radixBinButton); - /* - viewModel.radixProperty.addListener((observable, oldValue, newValue) -> { - logger.info("Selected radix from ViewModel: {}", newValue); - radixToggleGroup.selectToggle(switch (newValue) { - case Hex -> radioRadixHex; - case Decimal -> radioRadixDec; - case Octal -> radioRadixOct; - case Binary -> radioRadixBin; - default -> null; - }); - }); - radixToggleGroup.selectedToggleProperty().addListener((observableValue, oldValue, newValue) -> { - RadixType radix = - (newValue == radioRadixHex) ? RadixType.Hex : - (newValue == radioRadixDec) ? RadixType.Decimal : - (newValue == radioRadixOct) ? RadixType.Octal : - (newValue == radioRadixBin) ? RadixType.Binary : - null; - logger.info("Selected radix from UI: {}", radix); - viewModel.radixProperty.set(radix); - });*/ + + selectAngleTypeArea.visibleProperty().bind(viewModel.radixProperty.isEqualTo(RadixType.Decimal)); + selectAngleTypeArea.managedProperty().bind(selectAngleTypeArea.visibleProperty()); + selectWordWidthArea.visibleProperty().bind(viewModel.radixProperty.isNotEqualTo(RadixType.Decimal)); + selectWordWidthArea.managedProperty().bind(selectWordWidthArea.visibleProperty()); + + angleTypeToggleGroup.selectToggle(radioAngleRadians); + bindButton(radioAngleDegrees, viewModel.angleDegreesButton); + bindButton(radioAngleRadians, viewModel.angleRadiansButton); + bindButton(radioAngleGradians, viewModel.angleGradiansButton); + + wordWidthToggleGroup.selectToggle(radioWidthQWord); + bindButton(radioWidthQWord, viewModel.radixWordWidthQWord); + bindButton(radioWidthDWord, viewModel.radixWordWidthDWord); + bindButton(radioWidthWord, viewModel.radixWordWidthWord); + bindButton(radioWidthByte, viewModel.radixWordWidthByte); bindButton(bClear, viewModel.clearButton); bindButton(bClearEntry, viewModel.clearEntryButton); @@ -335,7 +363,7 @@ public void uninstall() { throw new RuntimeException("TODO"); } - private void bindButton(ButtonBase button, ScientificCalculatorViewModel.InputViewModel operation) { + private void bindButton(ButtonBase button, InputViewModel operation) { button.textProperty().bind(operation.textProperty()); // Pre-create the tooltip object @@ -356,10 +384,8 @@ private void bindButton(ButtonBase button, ScientificCalculatorViewModel.InputVi button.setUserData(operation); operation.keyboardShortcut().ifPresent(ks -> { - var conflict = keyboardMapping.put(ks, button); - if (conflict != null) { - logger.error("Conflicting keyboard mapping: {}", ks); - } + keyboardMapping.putIfAbsent(ks, new ArrayList<>()); + keyboardMapping.get(ks).add(button); }); } @@ -367,7 +393,9 @@ private void onKeyPressed(KeyEvent e) { KeyboardCode kc = new KeyboardCode(e.getCode(), e.isControlDown(), e.isShiftDown()); if (keyboardMapping.containsKey(kc)) { - keyboardMapping.get(kc).arm(); + keyboardMapping.get(kc).stream() + .filter(input -> ((InputViewModel)input.getUserData()).isActive()) + .forEach(ButtonBase::arm); e.consume(); } } @@ -376,9 +404,12 @@ private void onKeyReleased(KeyEvent e) { KeyboardCode kc = new KeyboardCode(e.getCode(), e.isControlDown(), e.isShiftDown()); if (keyboardMapping.containsKey(kc)) { - var button = keyboardMapping.get(kc); - button.disarm(); - button.fire(); + keyboardMapping.get(kc).stream() + .filter(input -> ((InputViewModel)input.getUserData()).isActive()) + .forEach(button -> { + button.disarm(); + button.fire(); + }); e.consume(); } } diff --git a/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.scss b/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.scss index ee248a1..c8415c8 100644 --- a/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.scss +++ b/gui/src/main/java/mscalc/gui/views/scientific/ScientificView.scss @@ -93,6 +93,10 @@ @include selectArea(); } + .selectWordWidthArea { + @include selectArea(); + } + .functionSelectArea { @include selectArea(); }