From a1f03c844b02778a3a3315913062bfaf26754e98 Mon Sep 17 00:00:00 2001 From: OUNZAR Aymane Date: Tue, 24 Mar 2026 18:27:56 +0100 Subject: [PATCH] Enhance multi-page PDF layout with advanced customization options (#397, #3655) (#5859) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../api/MultiPageLayoutController.java | 239 +++++++++++++++--- .../general/MergeMultiplePagesRequest.java | 101 +++++++- .../api/MultiPageLayoutControllerTest.java | 4 +- .../public/locales/en-GB/translation.toml | 113 ++++++++- .../tools/pageLayout/LayoutPreview.tsx | 72 ++++++ .../pageLayout/PageLayoutAdvancedSettings.tsx | 75 ++++++ .../PageLayoutMarginsBordersSettings.tsx | 134 ++++++++++ .../tools/pageLayout/PageLayoutPreview.tsx | 18 ++ .../tools/pageLayout/PageLayoutSettings.tsx | 100 +++++--- .../components/tools/pageLayout/constants.ts | 5 - .../tools/pageLayout/utils/computeBoxes.ts | 62 +++++ .../PageLayout/usePageLayoutAdvancedTips.ts | 43 ++++ .../usePageLayoutMarginsBordersTips.ts | 42 +++ .../tooltips/PageLayout/usePageLayoutTips.ts | 34 +++ .../pageLayout/usePageLayoutOperation.ts | 12 + .../pageLayout/usePageLayoutParameters.ts | 54 ++++ frontend/src/core/tools/PageLayout.tsx | 64 ++++- 17 files changed, 1094 insertions(+), 78 deletions(-) create mode 100644 frontend/src/core/components/tools/pageLayout/LayoutPreview.tsx create mode 100644 frontend/src/core/components/tools/pageLayout/PageLayoutAdvancedSettings.tsx create mode 100644 frontend/src/core/components/tools/pageLayout/PageLayoutMarginsBordersSettings.tsx create mode 100644 frontend/src/core/components/tools/pageLayout/PageLayoutPreview.tsx create mode 100644 frontend/src/core/components/tools/pageLayout/utils/computeBoxes.ts create mode 100644 frontend/src/core/components/tooltips/PageLayout/usePageLayoutAdvancedTips.ts create mode 100644 frontend/src/core/components/tooltips/PageLayout/usePageLayoutMarginsBordersTips.ts create mode 100644 frontend/src/core/components/tooltips/PageLayout/usePageLayoutTips.ts diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java index f9c223564e..7dcd67a02a 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/MultiPageLayoutController.java @@ -48,25 +48,144 @@ public class MultiPageLayoutController { public ResponseEntity mergeMultiplePagesIntoOne( @ModelAttribute MergeMultiplePagesRequest request) throws IOException { - int pagesPerSheet = request.getPagesPerSheet(); - MultipartFile file = request.getFileInput(); - boolean addBorder = Boolean.TRUE.equals(request.getAddBorder()); + int MAX_PAGES = 100000; + int MAX_COLS = 300; + int MAX_ROWS = 300; - if (pagesPerSheet != 2 - && pagesPerSheet != 3 - && pagesPerSheet != (int) Math.sqrt(pagesPerSheet) * Math.sqrt(pagesPerSheet)) { + String mode = request.getMode(); + if (mode == null || mode.trim().isEmpty()) { + mode = "DEFAULT"; + } + + int rows; + int cols; + int pagesPerSheet; + + switch (mode) { + case "DEFAULT": + pagesPerSheet = request.getPagesPerSheet(); + if (pagesPerSheet != 2 + && pagesPerSheet + != (int) Math.sqrt(pagesPerSheet) * Math.sqrt(pagesPerSheet)) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "pagesPerSheet", + "must be 2 or a perfect square"); + } + + cols = pagesPerSheet == 2 ? pagesPerSheet : (int) Math.sqrt(pagesPerSheet); + rows = pagesPerSheet == 2 ? 1 : (int) Math.sqrt(pagesPerSheet); + break; + case "CUSTOM": + rows = request.getRows(); + cols = request.getCols(); + if (rows <= 0 || cols <= 0) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "rows and cols", + "only strictly positive values are allowed"); + } + pagesPerSheet = cols * rows; + break; + default: + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "mode", + "only 'DEFAULT' and 'CUSTOM' are supported"); + } + + if (pagesPerSheet > MAX_PAGES) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidArgument", + "Invalid {0} format: {1}", + "pagesPerSheet", + "must be less than " + MAX_PAGES); + } + if (cols > MAX_COLS) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidArgument", + "Invalid {0} format: {1}", + "cols", + "must be less than " + MAX_COLS); + } + if (rows > MAX_ROWS) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidArgument", + "Invalid {0} format: {1}", + "rows", + "must be less than " + MAX_ROWS); + } + + String orientation = request.getOrientation(); + if (orientation == null || orientation.trim().isEmpty()) { + orientation = "PORTRAIT"; + } + if (!"PORTRAIT".equals(orientation) && !"LANDSCAPE".equals(orientation)) { throw ExceptionUtils.createIllegalArgumentException( "error.invalidFormat", "Invalid {0} format: {1}", - "pagesPerSheet", - "must be 2, 3 or a perfect square"); + "orientation", + "only 'PORTRAIT' and 'LANDSCAPE' are supported"); } - int cols = - pagesPerSheet == 2 || pagesPerSheet == 3 - ? pagesPerSheet - : (int) Math.sqrt(pagesPerSheet); - int rows = pagesPerSheet == 2 || pagesPerSheet == 3 ? 1 : (int) Math.sqrt(pagesPerSheet); + String arrangement = request.getArrangement(); + if (arrangement == null || arrangement.trim().isEmpty()) { + arrangement = "BY_ROWS"; + } + if (!"BY_ROWS".equals(arrangement) && !"BY_COLUMNS".equals(arrangement)) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "arrangement", + "only 'BY_ROWS' and 'BY_COLUMNS' are supported"); + } + + String readingDirection = request.getReadingDirection(); + if (readingDirection == null || readingDirection.trim().isEmpty()) { + readingDirection = "LTR"; + } + if (!"LTR".equals(readingDirection) && !"RTL".equals(readingDirection)) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "readingDirection", + "only 'LTR' and 'RTL' are supported"); + } + + boolean addBorder = Boolean.TRUE.equals(request.getAddBorder()); + + int topMargin = request.getTopMargin(); + int bottomMargin = request.getBottomMargin(); + int leftMargin = request.getLeftMargin(); + int rightMargin = request.getRightMargin(); + int innerMargin = request.getInnerMargin(); + + if (topMargin < 0 + || bottomMargin < 0 + || leftMargin < 0 + || rightMargin < 0 + || innerMargin < 0) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "Margins", + "only positive values are allowed"); + } + + int borderWidth = request.getBorderWidth() == 0 ? 1 : request.getBorderWidth(); + + if (addBorder && borderWidth <= 0) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "borderWidth", + "only strictly positive values are allowed when addBorder is true"); + } + + MultipartFile file = request.getFileInput(); try (PDDocument sourceDocument = pdfDocumentFactory.load(file)) { try (PDDocument newDocument = @@ -74,16 +193,53 @@ public class MultiPageLayoutController { int totalPages = sourceDocument.getNumberOfPages(); LayerUtility layerUtility = new LayerUtility(newDocument); + // Margin between page and content: + float pageWidth = + "PORTRAIT".equals(orientation) + ? PDRectangle.A4.getWidth() + : PDRectangle.A4.getHeight(); + float pageHeight = + "PORTRAIT".equals(orientation) + ? PDRectangle.A4.getHeight() + : PDRectangle.A4.getWidth(); + // Calculate cell dimensions once (all output pages are A4) - declare outside try // blocks - float cellWidth = PDRectangle.A4.getWidth() / cols; - float cellHeight = PDRectangle.A4.getHeight() / rows; + float cellWidth = (pageWidth - leftMargin - rightMargin) / cols; + float cellHeight = (pageHeight - topMargin - bottomMargin) / rows; + // Validate that outer margins and grid configuration yield positive cell size + if (cellWidth <= 0 || cellHeight <= 0) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "margin/layout configuration", + "Invalid margin or layout configuration: resulting cell size is non-positive. " + + "Please reduce outer margins or adjust rows/columns."); + } + + float innerWidth = cellWidth - 2 * innerMargin; + float innerHeight = cellHeight - 2 * innerMargin; + // Validate that inner margin fits within each cell + if (innerWidth <= 0 || innerHeight <= 0) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidFormat", + "Invalid {0} format: {1}", + "inner margin", + "Invalid inner margin: resulting inner content area is non-positive. " + + "Please reduce inner margin or adjust outer margins/layout."); + } // Process pages in groups of pagesPerSheet, creating a new page and content stream // for each group for (int i = 0; i < totalPages; i += pagesPerSheet) { // Create a new output page for each group of pagesPerSheet - PDPage newPage = new PDPage(PDRectangle.A4); + // Create a new A4 landscape rectangle that we use when orientation is landscape + PDRectangle a4Landscape = + new PDRectangle(PDRectangle.A4.getHeight(), PDRectangle.A4.getWidth()); + PDPage newPage = + "PORTRAIT".equals(orientation) + ? new PDPage(PDRectangle.A4) + : new PDPage(a4Landscape); newDocument.addPage(newPage); // Use try-with-resources for each content stream to ensure proper cleanup @@ -95,30 +251,52 @@ public class MultiPageLayoutController { PDPageContentStream.AppendMode.APPEND, true, true)) { - float borderThickness = 1.5f; // Specify border thickness as required - contentStream.setLineWidth(borderThickness); - contentStream.setStrokingColor(Color.BLACK); + + if (addBorder) { + contentStream.setLineWidth(borderWidth); + contentStream.setStrokingColor(Color.BLACK); + } // Process all pages in this group for (int j = 0; j < pagesPerSheet && (i + j) < totalPages; j++) { int pageIndex = i + j; PDPage sourcePage = sourceDocument.getPage(pageIndex); PDRectangle rect = sourcePage.getMediaBox(); - float scaleWidth = cellWidth / rect.getWidth(); - float scaleHeight = cellHeight / rect.getHeight(); + float scaleWidth = innerWidth / rect.getWidth(); + float scaleHeight = innerHeight / rect.getHeight(); float scale = Math.min(scaleWidth, scaleHeight); int adjustedPageIndex = j % pagesPerSheet; - int rowIndex = adjustedPageIndex / cols; - int colIndex = adjustedPageIndex % cols; + int rowIndex; + int colIndex; + + if ("BY_ROWS".equals(arrangement)) { + rowIndex = adjustedPageIndex / cols; + if ("LTR".equals(readingDirection)) { + colIndex = adjustedPageIndex % cols; + } else { + colIndex = cols - 1 - (adjustedPageIndex % cols); + } + } else { + rowIndex = adjustedPageIndex % rows; + if ("LTR".equals(readingDirection)) { + colIndex = adjustedPageIndex / rows; + } else { + colIndex = cols - 1 - (adjustedPageIndex / rows); + } + } float x = - colIndex * cellWidth - + (cellWidth - rect.getWidth() * scale) / 2; + leftMargin + + colIndex * cellWidth + + innerMargin + + (innerWidth - rect.getWidth() * scale) / 2; float y = newPage.getMediaBox().getHeight() + - topMargin - ((rowIndex + 1) * cellHeight - - (cellHeight - rect.getHeight() * scale) / 2); + - innerMargin + - (innerHeight - rect.getHeight() * scale) / 2); contentStream.saveGraphicsState(); contentStream.transform(Matrix.getTranslateInstance(x, y)); @@ -132,11 +310,8 @@ public class MultiPageLayoutController { if (addBorder) { // Draw border around each page - float borderX = colIndex * cellWidth; - float borderY = - newPage.getMediaBox().getHeight() - - (rowIndex + 1) * cellHeight; - contentStream.addRect(borderX, borderY, cellWidth, cellHeight); + contentStream.addRect( + x, y, rect.getWidth() * scale, rect.getHeight() * scale); contentStream.stroke(); } } @@ -145,7 +320,7 @@ public class MultiPageLayoutController { // If any source page is rotated, skip form copying/transformation entirely boolean hasRotation = GeneralFormCopyUtils.hasAnyRotatedPage(sourceDocument); - if (hasRotation) { + if (hasRotation || "LANDSCAPE".equals(orientation)) { log.info("Source document has rotated pages; skipping form field copying."); } else { try { diff --git a/app/core/src/main/java/stirling/software/SPDF/model/api/general/MergeMultiplePagesRequest.java b/app/core/src/main/java/stirling/software/SPDF/model/api/general/MergeMultiplePagesRequest.java index 972db7ce3a..27b9c539fd 100644 --- a/app/core/src/main/java/stirling/software/SPDF/model/api/general/MergeMultiplePagesRequest.java +++ b/app/core/src/main/java/stirling/software/SPDF/model/api/general/MergeMultiplePagesRequest.java @@ -11,13 +11,110 @@ import stirling.software.common.model.api.PDFFile; @EqualsAndHashCode(callSuper = true) public class MergeMultiplePagesRequest extends PDFFile { + @Schema( + description = + "Input mode: DEFAULT uses pagesPerSheet; CUSTOM uses explicit cols x rows.", + requiredMode = Schema.RequiredMode.REQUIRED, + type = "string", + defaultValue = "DEFAULT", + allowableValues = {"DEFAULT", "CUSTOM"}) + private String mode; + @Schema( description = "The number of pages to fit onto a single sheet in the output PDF.", type = "integer", - requiredMode = Schema.RequiredMode.REQUIRED, - allowableValues = {"2", "3", "4", "9", "16"}) + allowableValues = {"2", "4", "9", "16"}) private int pagesPerSheet = 2; + @Schema( + description = + "The arrangement of pages on the sheet: BY_ROWS fills pages row by row, while BY_COLUMNS fills pages column by column.", + type = "string", + defaultValue = "BY_ROWS", + allowableValues = {"BY_ROWS", "BY_COLUMNS"}) + private String arrangement; + + @Schema( + description = + "The direction in which pages are arranged on the sheet: LTR (left-to-right) or RTL (right-to-left).", + type = "string", + defaultValue = "LTR", + allowableValues = {"LTR", "RTL"}) + private String readingDirection; + + @Schema( + description = "Number of rows", + type = "number", + defaultValue = "1", + maximum = "300", + minimum = "1", + example = "3") + private int rows; + + @Schema( + description = "Number of columns", + type = "number", + defaultValue = "2", + maximum = "300", + minimum = "1", + example = "2") + private int cols; + + @Schema( + description = "The orientation of the output PDF pages", + type = "string", + defaultValue = "PORTRAIT", + allowableValues = {"PORTRAIT", "LANDSCAPE"}) + private String orientation; + + @Schema( + description = "Inner margin (in points) to apply around each page when merging", + type = "number", + defaultValue = "0", + minimum = "0", + example = "200") + private int innerMargin; + + @Schema( + description = "Top margin (in points) to apply to the output pages when merging", + type = "number", + defaultValue = "0", + minimum = "0", + example = "200") + private int topMargin; + + @Schema( + description = "Bottom margin (in points) to apply to the output pages when merging", + type = "number", + defaultValue = "0", + minimum = "0", + example = "200") + private int bottomMargin; + + @Schema( + description = "Left margin (in points) to apply to the output pages when merging", + type = "number", + defaultValue = "0", + minimum = "0", + example = "200") + private int leftMargin; + + @Schema( + description = "Right margin (in points) to apply to the output pages when merging", + type = "number", + defaultValue = "0", + minimum = "0", + example = "200") + private int rightMargin; + + @Schema( + description = "Border width (in points) to apply around each page when merging", + type = "number", + defaultValue = "1", + minimum = "0", + example = "2") + private int borderWidth; + @Schema(description = "Boolean for if you wish to add border around the pages") private Boolean addBorder; } diff --git a/app/core/src/test/java/stirling/software/SPDF/controller/api/MultiPageLayoutControllerTest.java b/app/core/src/test/java/stirling/software/SPDF/controller/api/MultiPageLayoutControllerTest.java index eb593772ac..0a1f3bc3b1 100644 --- a/app/core/src/test/java/stirling/software/SPDF/controller/api/MultiPageLayoutControllerTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/controller/api/MultiPageLayoutControllerTest.java @@ -106,7 +106,9 @@ class MultiPageLayoutControllerTest { .thenReturn(target); MergeMultiplePagesRequest req = new MergeMultiplePagesRequest(); - req.setPagesPerSheet(3); + req.setMode("CUSTOM"); + req.setCols(3); + req.setRows(1); req.setAddBorder(Boolean.TRUE); req.setFileInput(fileNoExt); diff --git a/frontend/public/locales/en-GB/translation.toml b/frontend/public/locales/en-GB/translation.toml index 70d1c41fcd..8602832fec 100644 --- a/frontend/public/locales/en-GB/translation.toml +++ b/frontend/public/locales/en-GB/translation.toml @@ -4511,21 +4511,132 @@ title = "Extract Pages" [pageLayout] addBorder = "Add Borders" +borderWidth = "Border Thickness" +bottom = "Bottom Margin" +cols = "Columns" header = "Multi Page Layout" +innerMargin = "Inner Margin" +left = "Left Margin" pagesPerSheet = "Pages per sheet:" +right = "Right Margin" +rows = "Rows" submit = "Submit" tags = "merge,composite,single-view,organize" title = "Multi Page Layout" +top = "Top Margin" + +[pageLayout.mode] +default = "Default" +custom = "Custom" +label = "Mode:" + +[pageLayout.arrangement] +byColumns = "By Columns" +byRows = "By Rows" +label = "Page arrangement:" [pageLayout.desc] 16 = "Place 16 pages on a single sheet (4 × 4 grid)." 2 = "Place 2 pages side-by-side on a single sheet." -3 = "Place 3 pages on a single sheet in a single row." 4 = "Place 4 pages on a single sheet (2 × 2 grid)." 9 = "Place 9 pages on a single sheet (3 × 3 grid)." [pageLayout.error] failed = "An error occurred while creating the multi-page layout." +outerVerticalMarginsTooLarge = "Top/Bottom margins are too large for this page size." +outerHorizontalMarginsTooLarge = "Left/Right margins are too large for this page size." +innerMarginTooLarge = "Inner margin is too large for the selected layout." + +[pageLayout.orientation] +landscape = "Landscape" +portrait = "Portrait" +label = "Orientation:" + +[pageLayout.readingDirection] +ltr = "Left to Right" +rtl = "Right to Left" +label = "Reading Direction:" + +[pageLayout.tooltip.header] +title = "Page Layout Guide" + +[pageLayout.tooltip.overview] +title = "What is Page Layout?" +text = "Fit multiple pages onto a single sheet for handouts or to save paper." + +[pageLayout.tooltip.mode] +title = "Mode" +text = "Choose how the grid is configured:" +bullet1 = "Default: Pick a preset and the grid is calculated automatically." +bullet2 = "Custom: Set rows and columns manually." + +[pageLayout.tooltip.pagesPerSheet] +title = "Pages per Sheet (Default Mode)" +text = "Choose how many pages per sheet (e.g. 4 → 2×2, 9 → 3×3)." + +[pageLayout.tooltip.rowsCols] +title = "Rows & Columns (Custom Mode)" +text = "Set exact grid dimensions. Total pages per sheet = rows × columns." + +[pageLayout.tooltip.orientation] +title = "Orientation" +text = "Sets the output sheet orientation:" +bullet1 = "Portrait: Taller than wide." +bullet2 = "Landscape: Wider than tall." + +[pageLayout.tooltip.arrangement] +title = "Page Arrangement" +text = "Controls the order pages fill the grid:" +bullet1 = "By Rows: Fill row by row (left-to-right or right-to-left)." +bullet2 = "By Columns: Fill top-to-bottom, column by column." + +[pageLayout.tooltip.readingDirection] +title = "Reading Direction" +text = "Controls the horizontal order of pages:" +bullet1 = "LTR: Left to right." +bullet2 = "RTL: Right to left." + +[pageLayout.tooltip.addBorder] +title = "Add Borders" +text = "Draws border lines around each page cell for cutting guides or visual separation." + +[pageLayout.marginsBorders.tooltip.header] +title = "Margins and Borders" + +[pageLayout.marginsBorders.tooltip.margins] +title = "Margins" +text = "Use top, bottom, left, and right margins to control spacing around the full sheet output." + +[pageLayout.marginsBorders.tooltip.innerMargin] +title = "Inner Margin" +text = "Inner margin adds spacing between cells in the page grid to improve separation and readability." + +[pageLayout.marginsBorders.tooltip.borders] +title = "Add Borders" +text = "Enable borders to draw lines around each placed page. This can help visual separation or trimming." + +[pageLayout.marginsBorders.tooltip.borderWidth] +title = "Border Thickness" +text = "Border thickness is only applied when borders are enabled. Higher values produce thicker lines." + +[pageLayout.advanced.tooltip.header] +title = "Advanced Layout Options" + +[pageLayout.advanced.tooltip.orientation] +title = "Orientation" +text = "Choose the final sheet direction. Portrait works better for tall content, while landscape fits wider layouts." + +[pageLayout.advanced.tooltip.arrangement] +title = "Page Arrangement" +text = "Controls whether pages fill the grid row-by-row or column-by-column." +bullet1 = "By Rows: Fill each row first." +bullet2 = "By Columns: Fill each column first." + +[pageLayout.advanced.tooltip.readingDirection] +title = "Reading Direction" +text = "Sets horizontal ordering in the grid, useful for left-to-right and right-to-left document conventions." +bullet1 = "LTR: Left to right order." +bullet2 = "RTL: Right to left order." [pageRemover] header = "PDF Page remover" diff --git a/frontend/src/core/components/tools/pageLayout/LayoutPreview.tsx b/frontend/src/core/components/tools/pageLayout/LayoutPreview.tsx new file mode 100644 index 0000000000..04b029d2a0 --- /dev/null +++ b/frontend/src/core/components/tools/pageLayout/LayoutPreview.tsx @@ -0,0 +1,72 @@ +import { PageLayoutParameters } from '@app/hooks/tools/pageLayout/usePageLayoutParameters'; +import { computeBoxes } from '@app/components/tools/pageLayout/utils/computeBoxes'; + +export default function LayoutPreview({ + parameters +}: { + parameters: PageLayoutParameters +}) { + + const sheet = { + x: 0, + y: 0, + width: parameters.orientation === "LANDSCAPE" ? 297 : 210, + height: parameters.orientation === "LANDSCAPE" ? 210 : 297 + } + + const boxes = computeBoxes(sheet, parameters); + const aspectRatio = sheet.width / sheet.height; + + return ( + + + {boxes.map(box => ( + + + + {box.label} + + )) + } + + + ) +} diff --git a/frontend/src/core/components/tools/pageLayout/PageLayoutAdvancedSettings.tsx b/frontend/src/core/components/tools/pageLayout/PageLayoutAdvancedSettings.tsx new file mode 100644 index 0000000000..82b0992e24 --- /dev/null +++ b/frontend/src/core/components/tools/pageLayout/PageLayoutAdvancedSettings.tsx @@ -0,0 +1,75 @@ +import { Divider, Select, Stack } from '@mantine/core'; +import { useTranslation } from 'react-i18next'; +import { PageLayoutParameters } from '@app/hooks/tools/pageLayout/usePageLayoutParameters'; +import { Z_INDEX_AUTOMATE_DROPDOWN } from "@app/styles/zIndex"; + +export default function PageLayoutAdvancedSettings({ + parameters, + onParameterChange, + disabled, +}: { + parameters: PageLayoutParameters; + onParameterChange: ( + key: K, + value: PageLayoutParameters[K] + ) => void; + disabled?: boolean; +}) { + const { t } = useTranslation(); + return ( + + + { + if (v === "BY_COLUMNS" || v === "BY_ROWS") { + onParameterChange('arrangement', v) + } + }} + disabled={disabled} + comboboxProps={{ withinPortal: true, zIndex: Z_INDEX_AUTOMATE_DROPDOWN }} + /> + + ({ value: String(o.value), label: o.label }))} - value={String(parameters.pagesPerSheet)} - onChange={(v) => onParameterChange('pagesPerSheet', Number(v))} - disabled={disabled} - comboboxProps={{ withinPortal: true, zIndex: Z_INDEX_AUTOMATE_DROPDOWN }} - /> - - {selected && ( -
- {selected.description} -
- )} - - - - onParameterChange('addBorder', e.currentTarget.checked)} - label={t('pageLayout.addBorder', 'Add Borders')} + { + if (v === "CUSTOM" || v === "DEFAULT") { + onParameterChange('mode', v) + } + }} disabled={disabled} /> + + {parameters.mode === "DEFAULT" && <> +