fix(pdf): co-assinatura incremental com preservação de assinaturas anteriores e trava anti-salto no redimensionamento
This commit is contained in:
+90
-6
@@ -144,6 +144,8 @@ public final class PdfSignDialog {
|
||||
private Label lblSealScaleIndicator;
|
||||
private double resizeStartSceneX;
|
||||
private double resizeStartBaseWidth;
|
||||
private boolean isResizingSealInProgress = false;
|
||||
private long lastResizeActionTimestamp = 0;
|
||||
|
||||
// Visualizador Interativo da Folha
|
||||
private ScrollPane sheetScroll;
|
||||
@@ -547,12 +549,17 @@ public final class PdfSignDialog {
|
||||
interactiveOverlayPane = new Pane();
|
||||
interactiveOverlayPane.setCursor(Cursor.CROSSHAIR);
|
||||
interactiveOverlayPane.setOnMouseClicked(event -> {
|
||||
if (sealDragOccurred) {
|
||||
// Previne que a soltura do mouse no término do arraste cause clique residual
|
||||
if (sealDragOccurred || isResizingSealInProgress || (System.currentTimeMillis() - lastResizeActionTimestamp < 400)) {
|
||||
// Previne que a soltura do mouse no término do redimensionamento ou arraste cause clique residual
|
||||
sealDragOccurred = false;
|
||||
event.consume();
|
||||
return;
|
||||
}
|
||||
if (isResizeModeActive) {
|
||||
// No modo redimensionamento ativo, clicar fora não deve saltar o selo acidentalmente
|
||||
event.consume();
|
||||
return;
|
||||
}
|
||||
handleSheetClick(event);
|
||||
});
|
||||
|
||||
@@ -572,6 +579,10 @@ public final class PdfSignDialog {
|
||||
sealSelectionBorder.setStrokeWidth(1.8);
|
||||
sealSelectionBorder.getStrokeDashArray().addAll(5.0, 4.0);
|
||||
sealSelectionBorder.setVisible(false);
|
||||
sealSelectionBorder.setOnMousePressed(e -> e.consume());
|
||||
sealSelectionBorder.setOnMouseDragged(e -> e.consume());
|
||||
sealSelectionBorder.setOnMouseReleased(e -> e.consume());
|
||||
sealSelectionBorder.setOnMouseClicked(e -> e.consume());
|
||||
|
||||
resizeHandle = new Circle(8);
|
||||
resizeHandle.setFill(Color.rgb(2, 132, 199));
|
||||
@@ -611,10 +622,15 @@ public final class PdfSignDialog {
|
||||
event.consume();
|
||||
});
|
||||
|
||||
sealStampOverlayView.setOnMouseReleased(event -> event.consume());
|
||||
sealStampOverlayView.setOnMouseReleased(event -> {
|
||||
lastResizeActionTimestamp = System.currentTimeMillis();
|
||||
event.consume();
|
||||
});
|
||||
|
||||
// Eventos da Alça de Redimensionamento Interativa
|
||||
resizeHandle.setOnMousePressed(event -> {
|
||||
isResizingSealInProgress = true;
|
||||
sealDragOccurred = true;
|
||||
resizeStartSceneX = event.getSceneX();
|
||||
resizeStartBaseWidth = currentBaseSealWidth * zoomFactor * sealScale;
|
||||
event.consume();
|
||||
@@ -622,17 +638,28 @@ public final class PdfSignDialog {
|
||||
|
||||
resizeHandle.setOnMouseDragged(event -> {
|
||||
if (!chkVisibleSeal.isSelected() || selectedPdfBytes == null) return;
|
||||
isResizingSealInProgress = true;
|
||||
sealDragOccurred = true;
|
||||
double deltaX = event.getSceneX() - resizeStartSceneX;
|
||||
double newWidth = resizeStartBaseWidth + deltaX;
|
||||
double baseW = currentBaseSealWidth * zoomFactor;
|
||||
if (baseW > 0) {
|
||||
applySealScale(newWidth / baseW);
|
||||
applySealScalePreservingOrigin(newWidth / baseW);
|
||||
}
|
||||
event.consume();
|
||||
});
|
||||
|
||||
resizeHandle.setOnMouseReleased(event -> event.consume());
|
||||
resizeHandle.setOnMouseClicked(event -> event.consume());
|
||||
resizeHandle.setOnMouseReleased(event -> {
|
||||
isResizingSealInProgress = false;
|
||||
lastResizeActionTimestamp = System.currentTimeMillis();
|
||||
sealDragOccurred = true;
|
||||
event.consume();
|
||||
});
|
||||
resizeHandle.setOnMouseClicked(event -> {
|
||||
isResizingSealInProgress = false;
|
||||
lastResizeActionTimestamp = System.currentTimeMillis();
|
||||
event.consume();
|
||||
});
|
||||
|
||||
sealGroupPane.getChildren().addAll(sealStampOverlayView, sealSelectionBorder, resizeHandle);
|
||||
interactiveOverlayPane.getChildren().add(sealGroupPane);
|
||||
@@ -647,6 +674,7 @@ public final class PdfSignDialog {
|
||||
|
||||
private void toggleResizeMode() {
|
||||
this.isResizeModeActive = !this.isResizeModeActive;
|
||||
this.lastResizeActionTimestamp = System.currentTimeMillis();
|
||||
if (sealSelectionBorder != null) {
|
||||
sealSelectionBorder.setVisible(isResizeModeActive);
|
||||
}
|
||||
@@ -666,6 +694,62 @@ public final class PdfSignDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private void applySealScalePreservingOrigin(double newScale) {
|
||||
if (!chkVisibleSeal.isSelected() || selectedPdfBytes == null) return;
|
||||
|
||||
double currentX = sealGroupPane != null ? sealGroupPane.getLayoutX() : 0;
|
||||
double currentY = sealGroupPane != null ? sealGroupPane.getLayoutY() : 0;
|
||||
|
||||
this.sealScale = Math.max(MIN_SEAL_SCALE, Math.min(MAX_SEAL_SCALE, Math.round(newScale * 100.0) / 100.0));
|
||||
if (lblSealScaleIndicator != null) {
|
||||
lblSealScaleIndicator.setText(String.format("%.0f%%", sealScale * 100));
|
||||
}
|
||||
if (btnResetSealScale != null) {
|
||||
btnResetSealScale.setVisible(Math.abs(sealScale - 1.0) > 0.02);
|
||||
}
|
||||
|
||||
updateContainerZoomDimensions();
|
||||
|
||||
double sheetW = currentBaseSheetWidth * zoomFactor;
|
||||
double sheetH = currentBaseSheetHeight * zoomFactor;
|
||||
double sealW = currentBaseSealWidth * zoomFactor * sealScale;
|
||||
double sealH = currentBaseSealHeight * zoomFactor * sealScale;
|
||||
|
||||
// Mantém a quina superior esquerda ancorada no mesmo ponto exato
|
||||
double clampedX = Math.max(0, Math.min(currentX, sheetW - sealW));
|
||||
double clampedY = Math.max(0, Math.min(currentY, sheetH - sealH));
|
||||
|
||||
if (sealGroupPane != null) {
|
||||
sealGroupPane.setLayoutX(clampedX);
|
||||
sealGroupPane.setLayoutY(clampedY);
|
||||
sealGroupPane.setVisible(true);
|
||||
}
|
||||
|
||||
this.sealRelativeX = (sheetW > 0) ? (clampedX / sheetW) : 0;
|
||||
this.sealRelativeY = (sheetH > 0) ? (clampedY / sheetH) : 0;
|
||||
|
||||
PdfSealTheme theme = activeSealTheme != null ? activeSealTheme : PdfSealThemeRegistry.getDefaultTheme();
|
||||
float basePdfW = (float) ((theme != null) ? theme.width() * 0.72 : 144.0);
|
||||
float basePdfH = (float) ((theme != null) ? theme.height() * 0.72 : 44.0);
|
||||
float scaledPdfW = basePdfW * (float) sealScale;
|
||||
float scaledPdfH = basePdfH * (float) sealScale;
|
||||
|
||||
double scale = (currentPagePdfWidth > 0) ? (sheetW / currentPagePdfWidth) : 1.0;
|
||||
float calculatedPdfX = (float) (clampedX / scale);
|
||||
float calculatedPdfY = (float) (currentPagePdfHeight - (clampedY / scale) - scaledPdfH);
|
||||
|
||||
this.customPdfX = Math.max(0, Math.min(calculatedPdfX, currentPagePdfWidth - scaledPdfW));
|
||||
this.customPdfY = Math.max(0, Math.min(calculatedPdfY, currentPagePdfHeight - scaledPdfH));
|
||||
this.customPageNumber = currentPageIndex + 1;
|
||||
this.isCustomPositionActive = true;
|
||||
|
||||
if (positionCombo.getValue() != PositionOption.CUSTOM) {
|
||||
positionCombo.setValue(PositionOption.CUSTOM);
|
||||
}
|
||||
|
||||
updateFeedbackLabel();
|
||||
}
|
||||
|
||||
private void applySealScale(double newScale) {
|
||||
this.sealScale = Math.max(MIN_SEAL_SCALE, Math.min(MAX_SEAL_SCALE, Math.round(newScale * 100.0) / 100.0));
|
||||
if (lblSealScaleIndicator != null) {
|
||||
|
||||
Reference in New Issue
Block a user