allow camera image mirroring to be changed from image context menu and application view menu

This commit is contained in:
Craig Raw 2025-01-15 11:07:45 +02:00
parent 4bf02f833c
commit f057b92729
7 changed files with 91 additions and 5 deletions

View file

@ -150,6 +150,10 @@ public class AppController implements Initializable {
private CheckMenuItem useHdCameraResolution; private CheckMenuItem useHdCameraResolution;
private static final BooleanProperty useHdCameraResolutionProperty = new SimpleBooleanProperty(); private static final BooleanProperty useHdCameraResolutionProperty = new SimpleBooleanProperty();
@FXML
private CheckMenuItem mirrorCameraImage;
private static final BooleanProperty mirrorCameraImageProperty = new SimpleBooleanProperty();
@FXML @FXML
private CheckMenuItem showLoadingLog; private CheckMenuItem showLoadingLog;
private static final BooleanProperty showLoadingLogProperty = new SimpleBooleanProperty(); private static final BooleanProperty showLoadingLogProperty = new SimpleBooleanProperty();
@ -379,6 +383,8 @@ public class AppController implements Initializable {
hideEmptyUsedAddresses.selectedProperty().bindBidirectional(hideEmptyUsedAddressesProperty); hideEmptyUsedAddresses.selectedProperty().bindBidirectional(hideEmptyUsedAddressesProperty);
useHdCameraResolutionProperty.set(Config.get().isHdCapture()); useHdCameraResolutionProperty.set(Config.get().isHdCapture());
useHdCameraResolution.selectedProperty().bindBidirectional(useHdCameraResolutionProperty); useHdCameraResolution.selectedProperty().bindBidirectional(useHdCameraResolutionProperty);
mirrorCameraImageProperty.set(Config.get().isMirrorCapture());
mirrorCameraImage.selectedProperty().bindBidirectional(mirrorCameraImageProperty);
showTxHexProperty.set(Config.get().isShowTransactionHex()); showTxHexProperty.set(Config.get().isShowTransactionHex());
showTxHex.selectedProperty().bindBidirectional(showTxHexProperty); showTxHex.selectedProperty().bindBidirectional(showTxHexProperty);
showLoadingLogProperty.set(Config.get().isShowLoadingLog()); showLoadingLogProperty.set(Config.get().isShowLoadingLog());
@ -946,6 +952,11 @@ public class AppController implements Initializable {
Config.get().setHdCapture(item.isSelected()); Config.get().setHdCapture(item.isSelected());
} }
public void mirrorCameraImage(ActionEvent event) {
CheckMenuItem item = (CheckMenuItem)event.getSource();
Config.get().setMirrorCapture(item.isSelected());
}
public void showLoadingLog(ActionEvent event) { public void showLoadingLog(ActionEvent event) {
CheckMenuItem item = (CheckMenuItem)event.getSource(); CheckMenuItem item = (CheckMenuItem)event.getSource();
Config.get().setShowLoadingLog(item.isSelected()); Config.get().setShowLoadingLog(item.isSelected());
@ -3136,4 +3147,14 @@ public class AppController implements Initializable {
} }
} }
} }
@Subscribe
public void webcamResolutionChanged(WebcamResolutionChangedEvent event) {
useHdCameraResolutionProperty.set(event.isHdResolution());
}
@Subscribe
public void webcamMirroredChanged(WebcamMirroredChangedEvent event) {
mirrorCameraImageProperty.set(event.isMirrored());
}
} }

View file

@ -25,6 +25,8 @@ import com.sparrowwallet.hummingbird.URDecoder;
import com.sparrowwallet.hummingbird.registry.pathcomponent.IndexPathComponent; import com.sparrowwallet.hummingbird.registry.pathcomponent.IndexPathComponent;
import com.sparrowwallet.hummingbird.registry.pathcomponent.PathComponent; import com.sparrowwallet.hummingbird.registry.pathcomponent.PathComponent;
import com.sparrowwallet.sparrow.AppServices; import com.sparrowwallet.sparrow.AppServices;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WebcamResolutionChangedEvent;
import com.sparrowwallet.sparrow.glyphfont.FontAwesome5; import com.sparrowwallet.sparrow.glyphfont.FontAwesome5;
import com.sparrowwallet.sparrow.io.Config; import com.sparrowwallet.sparrow.io.Config;
import com.sparrowwallet.sparrow.io.bbqr.BBQRDecoder; import com.sparrowwallet.sparrow.io.bbqr.BBQRDecoder;
@ -92,7 +94,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
this.webcamService = new WebcamService(webcamResolutionProperty.get(), null, new QRScanListener(), new ScanDelayCalculator()); this.webcamService = new WebcamService(webcamResolutionProperty.get(), null, new QRScanListener(), new ScanDelayCalculator());
webcamService.setPeriod(Duration.millis(SCAN_PERIOD_MILLIS)); webcamService.setPeriod(Duration.millis(SCAN_PERIOD_MILLIS));
webcamService.setRestartOnFailure(false); webcamService.setRestartOnFailure(false);
WebcamView webcamView = new WebcamView(webcamService); WebcamView webcamView = new WebcamView(webcamService, Config.get().isMirrorCapture());
final DialogPane dialogPane = new QRScanDialogPane(); final DialogPane dialogPane = new QRScanDialogPane();
setDialogPane(dialogPane); setDialogPane(dialogPane);
@ -150,6 +152,7 @@ public class QRScanDialog extends Dialog<QRScanDialog.Result> {
webcamResolutionProperty.addListener((observable, oldValue, newResolution) -> { webcamResolutionProperty.addListener((observable, oldValue, newResolution) -> {
if(newResolution != null) { if(newResolution != null) {
setHeight(newResolution == WebcamResolution.HD ? (getHeight() - 100) : (getHeight() + 100)); setHeight(newResolution == WebcamResolution.HD ? (getHeight() - 100) : (getHeight() + 100));
EventManager.get().post(new WebcamResolutionChangedEvent(newResolution == WebcamResolution.HD));
} }
webcamService.cancel(); webcamService.cancel();
}); });

View file

@ -1,8 +1,13 @@
package com.sparrowwallet.sparrow.control; package com.sparrowwallet.sparrow.control;
import com.sparrowwallet.sparrow.EventManager;
import com.sparrowwallet.sparrow.event.WebcamMirroredChangedEvent;
import com.sparrowwallet.sparrow.io.Config;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
@ -21,12 +26,26 @@ public class WebcamView {
private final ObjectProperty<Image> imageProperty = new SimpleObjectProperty<>(null); private final ObjectProperty<Image> imageProperty = new SimpleObjectProperty<>(null);
public WebcamView(WebcamService service) { public WebcamView(WebcamService service, boolean mirrored) {
this.service = service ; this.service = service ;
this.imageView = new ImageView(); this.imageView = new ImageView();
imageView.setPreserveRatio(true); imageView.setPreserveRatio(true);
// make the cam behave like a mirror: if(mirrored) {
imageView.setScaleX(-1); setMirrored(true);
}
ContextMenu contextMenu = new ContextMenu();
CheckMenuItem mirrorItem = new CheckMenuItem("Mirror Camera");
mirrorItem.setSelected(mirrored);
mirrorItem.selectedProperty().addListener((observable, oldValue, newValue) -> {
setMirrored(newValue);
Config.get().setMirrorCapture(newValue);
EventManager.get().post(new WebcamMirroredChangedEvent(newValue));
});
contextMenu.getItems().add(mirrorItem);
imageView.setOnContextMenuRequested(event -> {
contextMenu.show(imageView, event.getScreenX(), event.getScreenY());
});
service.valueProperty().addListener((observable, oldValue, newValue) -> { service.valueProperty().addListener((observable, oldValue, newValue) -> {
if(newValue != null) { if(newValue != null) {
@ -112,4 +131,8 @@ public class WebcamView {
public Node getView() { public Node getView() {
return view; return view;
} }
public void setMirrored(boolean mirrored) {
imageView.setScaleX(mirrored ? -1 : 1);
}
} }

View file

@ -0,0 +1,13 @@
package com.sparrowwallet.sparrow.event;
public class WebcamMirroredChangedEvent {
private final boolean mirrored;
public WebcamMirroredChangedEvent(boolean mirrored) {
this.mirrored = mirrored;
}
public boolean isMirrored() {
return mirrored;
}
}

View file

@ -0,0 +1,13 @@
package com.sparrowwallet.sparrow.event;
public class WebcamResolutionChangedEvent {
private final boolean hdResolution;
public WebcamResolutionChangedEvent(boolean hdResolution) {
this.hdResolution = hdResolution;
}
public boolean isHdResolution() {
return hdResolution;
}
}

View file

@ -58,6 +58,7 @@ public class Config {
private int enumerateHwPeriod = ENUMERATE_HW_PERIOD_SECS; private int enumerateHwPeriod = ENUMERATE_HW_PERIOD_SECS;
private QRDensity qrDensity; private QRDensity qrDensity;
private Boolean hdCapture; private Boolean hdCapture;
private boolean mirrorCapture = true;
private boolean useZbar = true; private boolean useZbar = true;
private String webcamDevice; private String webcamDevice;
private ServerType serverType; private ServerType serverType;
@ -405,6 +406,15 @@ public class Config {
flush(); flush();
} }
public boolean isMirrorCapture() {
return mirrorCapture;
}
public void setMirrorCapture(boolean mirrorCapture) {
this.mirrorCapture = mirrorCapture;
flush();
}
public boolean isUseZbar() { public boolean isUseZbar() {
return useZbar; return useZbar;
} }

View file

@ -113,10 +113,13 @@
</RadioMenuItem> </RadioMenuItem>
</items> </items>
</Menu> </Menu>
<Menu mnemonicParsing="false" text="Camera">
<CheckMenuItem fx:id="useHdCameraResolution" mnemonicParsing="false" text="Use HD Resolution" onAction="#useHdCameraResolution"/>
<CheckMenuItem fx:id="mirrorCameraImage" mnemonicParsing="false" text="Mirror Image" onAction="#mirrorCameraImage"/>
</Menu>
<SeparatorMenuItem /> <SeparatorMenuItem />
<CheckMenuItem fx:id="openWalletsInNewWindows" mnemonicParsing="false" text="Open Wallets In New Windows" onAction="#openWalletsInNewWindows"/> <CheckMenuItem fx:id="openWalletsInNewWindows" mnemonicParsing="false" text="Open Wallets In New Windows" onAction="#openWalletsInNewWindows"/>
<CheckMenuItem fx:id="hideEmptyUsedAddresses" mnemonicParsing="false" text="Hide Empty Used Addresses" onAction="#hideEmptyUsedAddresses"/> <CheckMenuItem fx:id="hideEmptyUsedAddresses" mnemonicParsing="false" text="Hide Empty Used Addresses" onAction="#hideEmptyUsedAddresses"/>
<CheckMenuItem fx:id="useHdCameraResolution" mnemonicParsing="false" text="Use HD Camera Resolution" onAction="#useHdCameraResolution"/>
<CheckMenuItem fx:id="showLoadingLog" mnemonicParsing="false" text="Show Wallet Loading Log" onAction="#showLoadingLog" /> <CheckMenuItem fx:id="showLoadingLog" mnemonicParsing="false" text="Show Wallet Loading Log" onAction="#showLoadingLog" />
<CheckMenuItem fx:id="showTxHex" mnemonicParsing="false" text="Show Transaction Hex" onAction="#showTxHex"/> <CheckMenuItem fx:id="showTxHex" mnemonicParsing="false" text="Show Transaction Hex" onAction="#showTxHex"/>
<SeparatorMenuItem /> <SeparatorMenuItem />