From ace2ea9a2c010756636cf938dc380eac539f028d Mon Sep 17 00:00:00 2001 From: shufeng2012 <277665039@qq.com> Date: Sun, 16 Aug 2026 19:44:05 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A5=20=E5=88=A0=E9=99=A4gui=E7=9B=B8?= =?UTF-8?q?=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- entry/src/main/cpp/src/core/gui/Builder.cpp | 10 - entry/src/main/cpp/src/core/gui/Builder.h | 42 - .../cpp/src/core/gui/CreatePreviewImage.cpp | 39 - .../cpp/src/core/gui/CreatePreviewImage.h | 26 - .../main/cpp/src/core/gui/FloatingToolbox.cpp | 217 --- .../main/cpp/src/core/gui/FloatingToolbox.h | 94 -- entry/src/main/cpp/src/core/gui/GladeGui.cpp | 57 - entry/src/main/cpp/src/core/gui/GladeGui.h | 55 - .../main/cpp/src/core/gui/GladeSearchpath.cpp | 52 - .../main/cpp/src/core/gui/GladeSearchpath.h | 41 - .../main/cpp/src/core/gui/IconNameHelper.cpp | 15 - .../main/cpp/src/core/gui/IconNameHelper.h | 27 - entry/src/main/cpp/src/core/gui/Layout.cpp | 432 ------ entry/src/main/cpp/src/core/gui/Layout.h | 175 --- .../main/cpp/src/core/gui/LayoutMapper.cpp | 177 --- .../src/main/cpp/src/core/gui/LayoutMapper.h | 114 -- .../cpp/src/core/gui/LegacyRedrawable.cpp | 18 - .../main/cpp/src/core/gui/LegacyRedrawable.h | 87 -- .../src/main/cpp/src/core/gui/MainWindow.cpp | 742 ---------- entry/src/main/cpp/src/core/gui/MainWindow.h | 196 --- .../src/core/gui/PagePreviewDecoration.cpp | 129 -- .../cpp/src/core/gui/PagePreviewDecoration.h | 70 - entry/src/main/cpp/src/core/gui/PageView.cpp | 1205 ----------------- entry/src/main/cpp/src/core/gui/PageView.h | 323 ----- .../src/core/gui/PageViewFindObjectHelper.h | 204 --- .../cpp/src/core/gui/PaperFormatUtils.cpp | 57 - .../main/cpp/src/core/gui/PaperFormatUtils.h | 42 - .../cpp/src/core/gui/PdfFloatingToolbox.cpp | 239 ---- .../cpp/src/core/gui/PdfFloatingToolbox.h | 97 -- .../main/cpp/src/core/gui/PopoverFactory.h | 23 - .../main/cpp/src/core/gui/RepaintHandler.cpp | 29 - .../main/cpp/src/core/gui/RepaintHandler.h | 40 - entry/src/main/cpp/src/core/gui/SearchBar.cpp | 198 --- entry/src/main/cpp/src/core/gui/SearchBar.h | 65 - entry/src/main/cpp/src/core/gui/Shadow.cpp | 217 --- entry/src/main/cpp/src/core/gui/Shadow.h | 52 - entry/src/main/cpp/src/core/gui/ShadowCode.c | 99 -- .../cpp/src/core/gui/ToolbarDefinitions.h | 44 - .../cpp/src/core/gui/ToolitemDragDrop.cpp | 88 -- .../main/cpp/src/core/gui/ToolitemDragDrop.h | 57 - .../src/main/cpp/src/core/gui/XournalView.cpp | 861 ------------ entry/src/main/cpp/src/core/gui/XournalView.h | 195 --- .../main/cpp/src/core/gui/XournalppCursor.cpp | 648 --------- .../main/cpp/src/core/gui/XournalppCursor.h | 76 -- .../cpp/src/core/gui/dialog/AboutDialog.cpp | 76 -- .../cpp/src/core/gui/dialog/AboutDialog.h | 29 - .../core/gui/dialog/AbstractLatexDialog.cpp | 106 -- .../src/core/gui/dialog/AbstractLatexDialog.h | 93 -- .../src/core/gui/dialog/ButtonConfigGui.cpp | 284 ---- .../cpp/src/core/gui/dialog/ButtonConfigGui.h | 62 - .../core/gui/dialog/DeviceClassConfigGui.cpp | 61 - .../core/gui/dialog/DeviceClassConfigGui.h | 42 - .../src/core/gui/dialog/DeviceListDialog.cpp | 39 - .../src/core/gui/dialog/DeviceListDialog.h | 37 - .../src/core/gui/dialog/DeviceTestingArea.cpp | 425 ------ .../src/core/gui/dialog/DeviceTestingArea.h | 82 -- .../cpp/src/core/gui/dialog/ExportDialog.cpp | 192 --- .../cpp/src/core/gui/dialog/ExportDialog.h | 76 -- .../src/core/gui/dialog/ExtEdLatexDialog.cpp | 192 --- .../src/core/gui/dialog/ExtEdLatexDialog.h | 48 - .../gui/dialog/FileChooserFiltersHelper.cpp | 44 - .../gui/dialog/FileChooserFiltersHelper.h | 26 - .../cpp/src/core/gui/dialog/FormatDialog.cpp | 216 --- .../cpp/src/core/gui/dialog/FormatDialog.h | 72 - .../cpp/src/core/gui/dialog/GotoDialog.cpp | 34 - .../main/cpp/src/core/gui/dialog/GotoDialog.h | 38 - .../src/core/gui/dialog/IntEdLatexDialog.cpp | 184 --- .../src/core/gui/dialog/IntEdLatexDialog.h | 55 - .../src/core/gui/dialog/LanguageConfigGui.cpp | 88 -- .../src/core/gui/dialog/LanguageConfigGui.h | 37 - .../core/gui/dialog/LatexSettingsPanel.cpp | 205 --- .../src/core/gui/dialog/LatexSettingsPanel.h | 50 - .../core/gui/dialog/PageTemplateDialog.cpp | 224 --- .../src/core/gui/dialog/PageTemplateDialog.h | 80 -- .../cpp/src/core/gui/dialog/PluginDialog.cpp | 48 - .../cpp/src/core/gui/dialog/PluginDialog.h | 48 - .../src/core/gui/dialog/PluginDialogEntry.cpp | 52 - .../src/core/gui/dialog/PluginDialogEntry.h | 40 - .../src/core/gui/dialog/RenameLayerDialog.cpp | 40 - .../src/core/gui/dialog/RenameLayerDialog.h | 36 - .../dialog/SelectBackgroundColorDialog.cpp | 119 -- .../gui/dialog/SelectBackgroundColorDialog.h | 50 - .../core/gui/dialog/SelectOpacityDialog.cpp | 121 -- .../src/core/gui/dialog/SelectOpacityDialog.h | 41 - .../src/core/gui/dialog/SettingsDialog.cpp | 1104 --------------- .../cpp/src/core/gui/dialog/SettingsDialog.h | 105 -- .../gui/dialog/SettingsDialogPaletteTab.cpp | 213 --- .../gui/dialog/SettingsDialogPaletteTab.h | 36 - .../core/gui/dialog/ToolbarManageDialog.cpp | 187 --- .../src/core/gui/dialog/ToolbarManageDialog.h | 60 - .../cpp/src/core/gui/dialog/XojOpenDlg.cpp | 211 --- .../main/cpp/src/core/gui/dialog/XojOpenDlg.h | 32 - .../cpp/src/core/gui/dialog/XojSaveDlg.cpp | 91 -- .../main/cpp/src/core/gui/dialog/XojSaveDlg.h | 56 - .../BackgroundSelectDialogBase.cpp | 111 -- .../BackgroundSelectDialogBase.h | 64 - .../backgroundSelect/BaseElementView.cpp | 145 -- .../dialog/backgroundSelect/BaseElementView.h | 87 -- .../backgroundSelect/ImageElementView.cpp | 46 - .../backgroundSelect/ImageElementView.h | 58 - .../dialog/backgroundSelect/ImagesDialog.cpp | 120 -- .../dialog/backgroundSelect/ImagesDialog.h | 47 - .../backgroundSelect/PdfElementView.cpp | 34 - .../dialog/backgroundSelect/PdfElementView.h | 55 - .../backgroundSelect/PdfPagesDialog.cpp | 98 -- .../dialog/backgroundSelect/PdfPagesDialog.h | 41 - .../ToolItemDragCurrentData.cpp | 47 - .../ToolItemDragCurrentData.h | 38 - .../toolbarCustomize/ToolbarAdapter.cpp | 345 ----- .../dialog/toolbarCustomize/ToolbarAdapter.h | 83 -- .../ToolbarCustomizeDialog.cpp | 325 ----- .../toolbarCustomize/ToolbarCustomizeDialog.h | 93 -- .../ToolbarDragDropHandler.cpp | 57 - .../toolbarCustomize/ToolbarDragDropHandler.h | 42 - .../ToolbarDragDropHelper.cpp | 105 -- .../toolbarCustomize/ToolbarDragDropHelper.h | 25 - .../gui/inputdevices/AbstractInputHandler.cpp | 97 -- .../gui/inputdevices/AbstractInputHandler.h | 45 - .../gui/inputdevices/CompassInputHandler.cpp | 90 -- .../gui/inputdevices/CompassInputHandler.h | 42 - .../src/core/gui/inputdevices/DeviceId.cpp | 17 - .../cpp/src/core/gui/inputdevices/DeviceId.h | 26 - .../inputdevices/GeometryToolInputHandler.cpp | 309 ----- .../inputdevices/GeometryToolInputHandler.h | 164 --- .../core/gui/inputdevices/HandRecognition.cpp | 183 --- .../core/gui/inputdevices/HandRecognition.h | 112 -- .../core/gui/inputdevices/InputContext.cpp | 327 ----- .../src/core/gui/inputdevices/InputContext.h | 113 -- .../src/core/gui/inputdevices/InputEvents.cpp | 111 -- .../src/core/gui/inputdevices/InputEvents.h | 83 -- .../src/core/gui/inputdevices/InputUtils.cpp | 42 - .../src/core/gui/inputdevices/InputUtils.h | 50 - .../gui/inputdevices/KeyboardInputHandler.cpp | 17 - .../gui/inputdevices/KeyboardInputHandler.h | 27 - .../gui/inputdevices/MouseInputHandler.cpp | 157 --- .../core/gui/inputdevices/MouseInputHandler.h | 51 - .../core/gui/inputdevices/PenInputHandler.cpp | 585 -------- .../core/gui/inputdevices/PenInputHandler.h | 158 --- .../gui/inputdevices/PositionInputData.cpp | 7 - .../core/gui/inputdevices/PositionInputData.h | 37 - .../src/core/gui/inputdevices/PrintEvent.cpp | 172 --- .../src/core/gui/inputdevices/PrintEvent.h | 23 - .../inputdevices/SetsquareInputHandler.cpp | 90 -- .../gui/inputdevices/SetsquareInputHandler.h | 40 - .../gui/inputdevices/StylusInputHandler.cpp | 209 --- .../gui/inputdevices/StylusInputHandler.h | 49 - .../inputdevices/TouchDrawingInputHandler.cpp | 158 --- .../inputdevices/TouchDrawingInputHandler.h | 44 - .../gui/inputdevices/TouchInputHandler.cpp | 221 --- .../core/gui/inputdevices/TouchInputHandler.h | 61 - .../touchdisable/TouchDisableCustom.cpp | 15 - .../touchdisable/TouchDisableCustom.h | 31 - .../touchdisable/TouchDisableInterface.cpp | 7 - .../touchdisable/TouchDisableInterface.h | 26 - .../touchdisable/TouchDisableX11.cpp | 86 -- .../touchdisable/TouchDisableX11.h | 57 - .../gui/menus/PageTypeSelectionMenuBase.cpp | 86 -- .../gui/menus/PageTypeSelectionMenuBase.h | 60 - .../gui/menus/StaticAssertActionNamespace.h | 52 - .../core/gui/menus/menubar/AbstractSubmenu.h | 26 - .../src/core/gui/menus/menubar/Menubar.cpp | 102 -- .../cpp/src/core/gui/menus/menubar/Menubar.h | 80 -- .../gui/menus/menubar/PageTypeSubmenu.cpp | 93 -- .../core/gui/menus/menubar/PageTypeSubmenu.h | 43 - .../core/gui/menus/menubar/PluginsSubmenu.cpp | 33 - .../core/gui/menus/menubar/PluginsSubmenu.h | 34 - .../menus/menubar/RecentDocumentsSubmenu.cpp | 231 ---- .../menus/menubar/RecentDocumentsSubmenu.h | 74 - .../menus/menubar/ToolbarSelectionSubmenu.cpp | 88 -- .../menus/menubar/ToolbarSelectionSubmenu.h | 38 - .../popoverMenus/PageTypeSelectionPopover.cpp | 458 ------- .../popoverMenus/PageTypeSelectionPopover.h | 79 -- .../PageTypeSelectionPopoverGridOnly.cpp | 83 -- .../PageTypeSelectionPopoverGridOnly.h | 45 - .../src/core/gui/scroll/ScrollHandling.cpp | 41 - .../cpp/src/core/gui/scroll/ScrollHandling.h | 39 - .../core/gui/sidebar/AbstractSidebarPage.cpp | 30 - .../core/gui/sidebar/AbstractSidebarPage.h | 81 -- .../main/cpp/src/core/gui/sidebar/Sidebar.cpp | 171 --- .../main/cpp/src/core/gui/sidebar/Sidebar.h | 139 -- .../sidebar/indextree/SidebarIndexPage.cpp | 305 ----- .../gui/sidebar/indextree/SidebarIndexPage.h | 126 -- .../sidebar/previews/base/SidebarLayout.cpp | 107 -- .../gui/sidebar/previews/base/SidebarLayout.h | 28 - .../previews/base/SidebarPreviewBase.cpp | 152 --- .../previews/base/SidebarPreviewBase.h | 138 -- .../previews/base/SidebarPreviewBaseEntry.cpp | 165 --- .../previews/base/SidebarPreviewBaseEntry.h | 103 -- .../layer/SidebarPreviewLayerEntry.cpp | 72 - .../previews/layer/SidebarPreviewLayerEntry.h | 79 -- .../previews/layer/SidebarPreviewLayers.cpp | 143 -- .../previews/layer/SidebarPreviewLayers.h | 86 -- .../previews/page/SidebarPreviewPageEntry.cpp | 56 - .../previews/page/SidebarPreviewPageEntry.h | 45 - .../previews/page/SidebarPreviewPages.cpp | 139 -- .../previews/page/SidebarPreviewPages.h | 76 -- .../gui/toolbarMenubar/AbstractSliderItem.cpp | 6 - .../gui/toolbarMenubar/AbstractSliderItem.h | 50 - .../gui/toolbarMenubar/AbstractToolItem.cpp | 25 - .../gui/toolbarMenubar/AbstractToolItem.h | 64 - .../toolbarMenubar/ColorSelectorToolItem.cpp | 61 - .../toolbarMenubar/ColorSelectorToolItem.h | 41 - .../core/gui/toolbarMenubar/ColorToolItem.cpp | 77 -- .../core/gui/toolbarMenubar/ColorToolItem.h | 63 - .../gui/toolbarMenubar/ComboToolButton.cpp | 126 -- .../core/gui/toolbarMenubar/ComboToolButton.h | 63 - .../DrawingTypeComboToolButton.cpp | 172 --- .../DrawingTypeComboToolButton.h | 72 - .../core/gui/toolbarMenubar/FontButton.cpp | 78 -- .../src/core/gui/toolbarMenubar/FontButton.h | 37 - .../toolbarMenubar/PluginPlaceholderLabel.cpp | 80 -- .../toolbarMenubar/PluginPlaceholderLabel.h | 52 - .../gui/toolbarMenubar/PluginToolButton.cpp | 44 - .../gui/toolbarMenubar/PluginToolButton.h | 35 - .../toolbarMenubar/SliderItemCreationHelper.h | 88 -- .../toolbarMenubar/StylePopoverFactory.cpp | 57 - .../gui/toolbarMenubar/StylePopoverFactory.h | 46 - .../core/gui/toolbarMenubar/ToolButton.cpp | 111 -- .../src/core/gui/toolbarMenubar/ToolButton.h | 52 - .../gui/toolbarMenubar/ToolMenuHandler.cpp | 550 -------- .../core/gui/toolbarMenubar/ToolMenuHandler.h | 142 -- .../core/gui/toolbarMenubar/ToolPageLayer.cpp | 315 ----- .../core/gui/toolbarMenubar/ToolPageLayer.h | 42 - .../gui/toolbarMenubar/ToolPageSpinner.cpp | 138 -- .../core/gui/toolbarMenubar/ToolPageSpinner.h | 50 - .../toolbarMenubar/ToolPdfCombocontrol.cpp | 17 - .../gui/toolbarMenubar/ToolPdfCombocontrol.h | 14 - .../toolbarMenubar/ToolSelectCombocontrol.cpp | 29 - .../toolbarMenubar/ToolSelectCombocontrol.h | 24 - .../gui/toolbarMenubar/ToolZoomSlider.cpp | 78 -- .../core/gui/toolbarMenubar/ToolZoomSlider.h | 61 - .../gui/toolbarMenubar/TooltipToolButton.cpp | 33 - .../gui/toolbarMenubar/TooltipToolButton.h | 36 - .../gui/toolbarMenubar/icon/ColorIcon.cpp | 62 - .../core/gui/toolbarMenubar/icon/ColorIcon.h | 35 - .../icon/ToolbarSeparatorImage.cpp | 48 - .../icon/ToolbarSeparatorImage.h | 40 - .../gui/toolbarMenubar/model/ColorPalette.cpp | 182 --- .../gui/toolbarMenubar/model/ColorPalette.h | 217 --- .../gui/toolbarMenubar/model/ToolbarData.cpp | 163 --- .../gui/toolbarMenubar/model/ToolbarData.h | 53 - .../gui/toolbarMenubar/model/ToolbarEntry.cpp | 55 - .../gui/toolbarMenubar/model/ToolbarEntry.h | 51 - .../gui/toolbarMenubar/model/ToolbarItem.cpp | 22 - .../gui/toolbarMenubar/model/ToolbarItem.h | 40 - .../gui/toolbarMenubar/model/ToolbarModel.cpp | 162 --- .../gui/toolbarMenubar/model/ToolbarModel.h | 48 - .../src/core/gui/widgets/SpinPageAdapter.cpp | 70 - .../src/core/gui/widgets/SpinPageAdapter.h | 65 - .../src/core/gui/widgets/XournalWidget.cpp | 327 ----- .../cpp/src/core/gui/widgets/XournalWidget.h | 88 -- .../cpp/src/core/gui/widgets/ZoomCallib.cpp | 155 --- .../cpp/src/core/gui/widgets/ZoomCallib.h | 43 - .../main/cpp/src/core/view/CompassView.cpp | 156 --- .../src/main/cpp/src/core/view/CompassView.h | 105 -- .../src/core/view/DebugShowRepaintBounds.h | 9 - .../main/cpp/src/core/view/DocumentView.cpp | 115 -- .../src/main/cpp/src/core/view/DocumentView.h | 93 -- .../src/core/view/ElementContainerView.cpp | 20 - .../cpp/src/core/view/ElementContainerView.h | 31 - .../main/cpp/src/core/view/ElementView.cpp | 32 - .../cpp/src/core/view/ErasableStrokeView.cpp | 309 ----- .../cpp/src/core/view/ErasableStrokeView.h | 62 - .../cpp/src/core/view/GeometryToolView.cpp | 71 - .../main/cpp/src/core/view/GeometryToolView.h | 132 -- .../src/main/cpp/src/core/view/ImageView.cpp | 39 - entry/src/main/cpp/src/core/view/ImageView.h | 30 - .../src/main/cpp/src/core/view/LayerView.cpp | 48 - entry/src/main/cpp/src/core/view/LayerView.h | 32 - entry/src/main/cpp/src/core/view/Mask.cpp | 211 --- entry/src/main/cpp/src/core/view/Mask.h | 91 -- .../src/main/cpp/src/core/view/Repaintable.h | 68 - .../main/cpp/src/core/view/SetsquareView.cpp | 293 ---- .../main/cpp/src/core/view/SetsquareView.h | 113 -- .../src/main/cpp/src/core/view/StrokeView.cpp | 169 --- entry/src/main/cpp/src/core/view/StrokeView.h | 45 - .../cpp/src/core/view/StrokeViewHelper.cpp | 73 - .../main/cpp/src/core/view/StrokeViewHelper.h | 40 - .../main/cpp/src/core/view/TexImageView.cpp | 92 -- .../src/main/cpp/src/core/view/TexImageView.h | 30 - entry/src/main/cpp/src/core/view/TextView.cpp | 53 - entry/src/main/cpp/src/core/view/TextView.h | 42 - entry/src/main/cpp/src/core/view/View.h | 52 - .../core/view/background/BackgroundFlags.h | 37 - .../core/view/background/BackgroundView.cpp | 95 -- .../src/core/view/background/BackgroundView.h | 52 - .../BaseIsometricBackgroundView.cpp | 86 -- .../background/BaseIsometricBackgroundView.h | 41 - .../view/background/DottedBackgroundView.cpp | 57 - .../view/background/DottedBackgroundView.h | 37 - .../view/background/GraphBackgroundView.cpp | 136 -- .../view/background/GraphBackgroundView.h | 42 - .../view/background/ImageBackgroundView.cpp | 33 - .../view/background/ImageBackgroundView.h | 33 - .../background/IsoDottedBackgroundView.cpp | 34 - .../view/background/IsoDottedBackgroundView.h | 35 - .../background/IsoGraphBackgroundView.cpp | 89 -- .../view/background/IsoGraphBackgroundView.h | 35 - .../view/background/LinedBackgroundView.cpp | 42 - .../view/background/LinedBackgroundView.h | 36 - .../background/OneColorBackgroundView.cpp | 34 - .../view/background/OneColorBackgroundView.h | 42 - .../view/background/PdfBackgroundView.cpp | 30 - .../core/view/background/PdfBackgroundView.h | 41 - .../view/background/PlainBackgroundView.cpp | 21 - .../view/background/PlainBackgroundView.h | 35 - .../view/background/RuledBackgroundView.cpp | 48 - .../view/background/RuledBackgroundView.h | 40 - .../view/background/StavesBackgroundView.cpp | 55 - .../view/background/StavesBackgroundView.h | 41 - .../TransparentCheckerboardBackgroundView.cpp | 43 - .../TransparentCheckerboardBackgroundView.h | 37 - .../overlays/BaseShapeOrSplineToolView.cpp | 85 -- .../view/overlays/BaseShapeOrSplineToolView.h | 45 - .../core/view/overlays/BaseStrokeToolView.cpp | 58 - .../core/view/overlays/BaseStrokeToolView.h | 51 - .../view/overlays/ImageSizeSelectionView.cpp | 57 - .../view/overlays/ImageSizeSelectionView.h | 56 - .../core/view/overlays/LaserPointerView.cpp | 85 -- .../src/core/view/overlays/LaserPointerView.h | 83 -- .../cpp/src/core/view/overlays/OverlayView.h | 45 - .../view/overlays/PdfElementSelectionView.cpp | 37 - .../view/overlays/PdfElementSelectionView.h | 57 - .../core/view/overlays/SearchResultView.cpp | 47 - .../src/core/view/overlays/SearchResultView.h | 57 - .../src/core/view/overlays/SelectorView.cpp | 56 - .../cpp/src/core/view/overlays/SelectorView.h | 51 - .../src/core/view/overlays/ShapeToolView.cpp | 45 - .../src/core/view/overlays/ShapeToolView.h | 58 - .../src/core/view/overlays/SplineToolView.cpp | 135 -- .../src/core/view/overlays/SplineToolView.h | 79 -- .../StrokeToolFilledHighlighterView.cpp | 73 - .../StrokeToolFilledHighlighterView.h | 25 - .../view/overlays/StrokeToolFilledView.cpp | 62 - .../core/view/overlays/StrokeToolFilledView.h | 59 - .../src/core/view/overlays/StrokeToolView.cpp | 147 -- .../src/core/view/overlays/StrokeToolView.h | 108 -- .../core/view/overlays/TextEditionView.cpp | 90 -- .../src/core/view/overlays/TextEditionView.h | 68 - .../core/view/overlays/VerticalToolView.cpp | 127 -- .../src/core/view/overlays/VerticalToolView.h | 82 -- 341 files changed, 34818 deletions(-) delete mode 100644 entry/src/main/cpp/src/core/gui/Builder.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/Builder.h delete mode 100644 entry/src/main/cpp/src/core/gui/CreatePreviewImage.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/CreatePreviewImage.h delete mode 100644 entry/src/main/cpp/src/core/gui/FloatingToolbox.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/FloatingToolbox.h delete mode 100644 entry/src/main/cpp/src/core/gui/GladeGui.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/GladeGui.h delete mode 100644 entry/src/main/cpp/src/core/gui/GladeSearchpath.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/GladeSearchpath.h delete mode 100644 entry/src/main/cpp/src/core/gui/IconNameHelper.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/IconNameHelper.h delete mode 100644 entry/src/main/cpp/src/core/gui/Layout.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/Layout.h delete mode 100644 entry/src/main/cpp/src/core/gui/LayoutMapper.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/LayoutMapper.h delete mode 100644 entry/src/main/cpp/src/core/gui/LegacyRedrawable.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/LegacyRedrawable.h delete mode 100644 entry/src/main/cpp/src/core/gui/MainWindow.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/MainWindow.h delete mode 100644 entry/src/main/cpp/src/core/gui/PagePreviewDecoration.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/PagePreviewDecoration.h delete mode 100644 entry/src/main/cpp/src/core/gui/PageView.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/PageView.h delete mode 100644 entry/src/main/cpp/src/core/gui/PageViewFindObjectHelper.h delete mode 100644 entry/src/main/cpp/src/core/gui/PaperFormatUtils.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/PaperFormatUtils.h delete mode 100644 entry/src/main/cpp/src/core/gui/PdfFloatingToolbox.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/PdfFloatingToolbox.h delete mode 100644 entry/src/main/cpp/src/core/gui/PopoverFactory.h delete mode 100644 entry/src/main/cpp/src/core/gui/RepaintHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/RepaintHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/SearchBar.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/SearchBar.h delete mode 100644 entry/src/main/cpp/src/core/gui/Shadow.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/Shadow.h delete mode 100644 entry/src/main/cpp/src/core/gui/ShadowCode.c delete mode 100644 entry/src/main/cpp/src/core/gui/ToolbarDefinitions.h delete mode 100644 entry/src/main/cpp/src/core/gui/ToolitemDragDrop.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/ToolitemDragDrop.h delete mode 100644 entry/src/main/cpp/src/core/gui/XournalView.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/XournalView.h delete mode 100644 entry/src/main/cpp/src/core/gui/XournalppCursor.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/XournalppCursor.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/AboutDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/AboutDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/AbstractLatexDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/AbstractLatexDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/ButtonConfigGui.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/ButtonConfigGui.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/DeviceClassConfigGui.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/DeviceClassConfigGui.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/DeviceListDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/DeviceListDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/DeviceTestingArea.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/DeviceTestingArea.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/ExportDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/ExportDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/ExtEdLatexDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/ExtEdLatexDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/FileChooserFiltersHelper.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/FileChooserFiltersHelper.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/FormatDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/FormatDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/GotoDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/GotoDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/IntEdLatexDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/IntEdLatexDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/LanguageConfigGui.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/LanguageConfigGui.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/LatexSettingsPanel.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/LatexSettingsPanel.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/PageTemplateDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/PageTemplateDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/PluginDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/PluginDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/PluginDialogEntry.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/PluginDialogEntry.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/RenameLayerDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/RenameLayerDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/SelectBackgroundColorDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/SelectBackgroundColorDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/SelectOpacityDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/SelectOpacityDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/SettingsDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/SettingsDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/SettingsDialogPaletteTab.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/SettingsDialogPaletteTab.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/ToolbarManageDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/ToolbarManageDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/XojOpenDlg.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/XojOpenDlg.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/XojSaveDlg.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/XojSaveDlg.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BackgroundSelectDialogBase.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BackgroundSelectDialogBase.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BaseElementView.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BaseElementView.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImageElementView.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImageElementView.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImagesDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImagesDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfElementView.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfElementView.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfPagesDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfPagesDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolItemDragCurrentData.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolItemDragCurrentData.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarAdapter.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarAdapter.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarCustomizeDialog.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarCustomizeDialog.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHelper.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHelper.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/AbstractInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/AbstractInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/CompassInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/CompassInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/DeviceId.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/DeviceId.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/GeometryToolInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/GeometryToolInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/HandRecognition.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/HandRecognition.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/InputContext.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/InputContext.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/InputEvents.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/InputEvents.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/InputUtils.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/InputUtils.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/KeyboardInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/KeyboardInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/MouseInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/MouseInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/PenInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/PenInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/PositionInputData.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/PositionInputData.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/PrintEvent.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/PrintEvent.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/SetsquareInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/SetsquareInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/StylusInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/StylusInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/TouchDrawingInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/TouchDrawingInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/TouchInputHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/TouchInputHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableCustom.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableCustom.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableInterface.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableInterface.h delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableX11.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableX11.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/PageTypeSelectionMenuBase.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/menus/PageTypeSelectionMenuBase.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/StaticAssertActionNamespace.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/AbstractSubmenu.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/Menubar.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/Menubar.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/PageTypeSubmenu.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/PageTypeSubmenu.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/PluginsSubmenu.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/PluginsSubmenu.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/RecentDocumentsSubmenu.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/RecentDocumentsSubmenu.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/ToolbarSelectionSubmenu.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/menus/menubar/ToolbarSelectionSubmenu.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopover.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopover.h delete mode 100644 entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.h delete mode 100644 entry/src/main/cpp/src/core/gui/scroll/ScrollHandling.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/scroll/ScrollHandling.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/AbstractSidebarPage.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/AbstractSidebarPage.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/Sidebar.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/Sidebar.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/indextree/SidebarIndexPage.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/indextree/SidebarIndexPage.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarLayout.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarLayout.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBase.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBase.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBaseEntry.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBaseEntry.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayerEntry.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayerEntry.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayers.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayers.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPageEntry.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPageEntry.h delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPages.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPages.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractSliderItem.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractSliderItem.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractToolItem.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractToolItem.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorSelectorToolItem.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorSelectorToolItem.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorToolItem.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorToolItem.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ComboToolButton.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ComboToolButton.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/DrawingTypeComboToolButton.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/DrawingTypeComboToolButton.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/FontButton.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/FontButton.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginPlaceholderLabel.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginPlaceholderLabel.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginToolButton.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginToolButton.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/SliderItemCreationHelper.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/StylePopoverFactory.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/StylePopoverFactory.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolButton.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolButton.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolMenuHandler.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolMenuHandler.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageLayer.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageLayer.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageSpinner.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageSpinner.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPdfCombocontrol.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPdfCombocontrol.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolSelectCombocontrol.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolSelectCombocontrol.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolZoomSlider.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolZoomSlider.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/TooltipToolButton.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/TooltipToolButton.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ColorIcon.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ColorIcon.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ToolbarSeparatorImage.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ToolbarSeparatorImage.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ColorPalette.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ColorPalette.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarData.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarData.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarEntry.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarEntry.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarItem.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarItem.h delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarModel.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarModel.h delete mode 100644 entry/src/main/cpp/src/core/gui/widgets/SpinPageAdapter.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/widgets/SpinPageAdapter.h delete mode 100644 entry/src/main/cpp/src/core/gui/widgets/XournalWidget.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/widgets/XournalWidget.h delete mode 100644 entry/src/main/cpp/src/core/gui/widgets/ZoomCallib.cpp delete mode 100644 entry/src/main/cpp/src/core/gui/widgets/ZoomCallib.h delete mode 100644 entry/src/main/cpp/src/core/view/CompassView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/CompassView.h delete mode 100644 entry/src/main/cpp/src/core/view/DebugShowRepaintBounds.h delete mode 100644 entry/src/main/cpp/src/core/view/DocumentView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/DocumentView.h delete mode 100644 entry/src/main/cpp/src/core/view/ElementContainerView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/ElementContainerView.h delete mode 100644 entry/src/main/cpp/src/core/view/ElementView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/ErasableStrokeView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/ErasableStrokeView.h delete mode 100644 entry/src/main/cpp/src/core/view/GeometryToolView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/GeometryToolView.h delete mode 100644 entry/src/main/cpp/src/core/view/ImageView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/ImageView.h delete mode 100644 entry/src/main/cpp/src/core/view/LayerView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/LayerView.h delete mode 100644 entry/src/main/cpp/src/core/view/Mask.cpp delete mode 100644 entry/src/main/cpp/src/core/view/Mask.h delete mode 100644 entry/src/main/cpp/src/core/view/Repaintable.h delete mode 100644 entry/src/main/cpp/src/core/view/SetsquareView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/SetsquareView.h delete mode 100644 entry/src/main/cpp/src/core/view/StrokeView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/StrokeView.h delete mode 100644 entry/src/main/cpp/src/core/view/StrokeViewHelper.cpp delete mode 100644 entry/src/main/cpp/src/core/view/StrokeViewHelper.h delete mode 100644 entry/src/main/cpp/src/core/view/TexImageView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/TexImageView.h delete mode 100644 entry/src/main/cpp/src/core/view/TextView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/TextView.h delete mode 100644 entry/src/main/cpp/src/core/view/View.h delete mode 100644 entry/src/main/cpp/src/core/view/background/BackgroundFlags.h delete mode 100644 entry/src/main/cpp/src/core/view/background/BackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/BackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/BaseIsometricBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/BaseIsometricBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/DottedBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/DottedBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/GraphBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/GraphBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/ImageBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/ImageBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/IsoDottedBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/IsoDottedBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/IsoGraphBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/IsoGraphBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/LinedBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/LinedBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/OneColorBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/OneColorBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/PdfBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/PdfBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/PlainBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/PlainBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/RuledBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/RuledBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/StavesBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/StavesBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/background/TransparentCheckerboardBackgroundView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/background/TransparentCheckerboardBackgroundView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/BaseShapeOrSplineToolView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/BaseShapeOrSplineToolView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/BaseStrokeToolView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/BaseStrokeToolView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/ImageSizeSelectionView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/ImageSizeSelectionView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/LaserPointerView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/LaserPointerView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/OverlayView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/PdfElementSelectionView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/PdfElementSelectionView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/SearchResultView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/SearchResultView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/SelectorView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/SelectorView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/ShapeToolView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/ShapeToolView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/SplineToolView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/SplineToolView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledHighlighterView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledHighlighterView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/StrokeToolView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/StrokeToolView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/TextEditionView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/TextEditionView.h delete mode 100644 entry/src/main/cpp/src/core/view/overlays/VerticalToolView.cpp delete mode 100644 entry/src/main/cpp/src/core/view/overlays/VerticalToolView.h diff --git a/entry/src/main/cpp/src/core/gui/Builder.cpp b/entry/src/main/cpp/src/core/gui/Builder.cpp deleted file mode 100644 index 990b342..0000000 --- a/entry/src/main/cpp/src/core/gui/Builder.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "Builder.h" - -#include "util/StringUtils.h" - -#include "GladeSearchpath.h" // for GladeSearchpath -#include "filesystem.h" // for path - -Builder::Builder(GladeSearchpath* gladeSearchPath, const std::string& uiFile): - builder(gtk_builder_new_from_file(char_cast(gladeSearchPath->findFile("", uiFile).u8string().c_str())), - xoj::util::adopt) {} diff --git a/entry/src/main/cpp/src/core/gui/Builder.h b/entry/src/main/cpp/src/core/gui/Builder.h deleted file mode 100644 index 271e973..0000000 --- a/entry/src/main/cpp/src/core/gui/Builder.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * gtk_builder wrapper to parse ui files - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include - -#include - -#include "util/Assert.h" -#include "util/raii/GObjectSPtr.h" - -class GladeSearchpath; - -class Builder final { -public: - Builder(GladeSearchpath* gladeSearchPath, const std::string& uiFile); - - template - GObjectType* get(const std::string& name) { - GObjectType* res = static_cast(gtk_builder_get_object(builder.get(), name.c_str())); - xoj_assert_message(res, "ERROR: Builder::get: Could not find UI object: " + name + "\n"); - return res; - } - - inline GtkWidget* get(const std::string& name) { return GTK_WIDGET(get(name)); } - -private: - /** - * The Glade resources - */ - xoj::util::GObjectSPtr builder; -}; diff --git a/entry/src/main/cpp/src/core/gui/CreatePreviewImage.cpp b/entry/src/main/cpp/src/core/gui/CreatePreviewImage.cpp deleted file mode 100644 index 319215f..0000000 --- a/entry/src/main/cpp/src/core/gui/CreatePreviewImage.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "CreatePreviewImage.h" - -#include "model/PageType.h" // for PageType -#include "util/Color.h" // for Color -#include "util/raii/CairoWrappers.h" -#include "util/raii/GObjectSPtr.h" -#include "view/background/BackgroundView.h" // for BackgroundView - -namespace xoj::helper { -auto createPreviewImage(const PageType& pt) -> GtkWidget* { - const double zoom = 0.5; - - xoj::util::CairoSurfaceSPtr surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PREVIEW_WIDTH, PREVIEW_HEIGHT), - xoj::util::adopt); - xoj::util::CairoSPtr crSPtr(cairo_create(surface.get()), xoj::util::adopt); - auto cr = crSPtr.get(); - - cairo_scale(cr, zoom, zoom); - - auto bgView = xoj::view::BackgroundView::createRuled(PREVIEW_WIDTH / zoom, PREVIEW_HEIGHT / zoom, Colors::white, pt, - 1. / zoom); - bgView->draw(cr); - - cairo_identity_matrix(cr); - - cairo_set_line_width(cr, 2); - cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, PREVIEW_WIDTH, 0); - cairo_line_to(cr, PREVIEW_WIDTH, PREVIEW_HEIGHT); - cairo_line_to(cr, 0, PREVIEW_HEIGHT); - cairo_line_to(cr, 0, 0); - cairo_stroke(cr); - - xoj::util::GObjectSPtr pixbuf( - gdk_pixbuf_get_from_surface(surface.get(), 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT), xoj::util::adopt); - return gtk_image_new_from_pixbuf(pixbuf.get()); -} -}; // namespace xoj::helper diff --git a/entry/src/main/cpp/src/core/gui/CreatePreviewImage.h b/entry/src/main/cpp/src/core/gui/CreatePreviewImage.h deleted file mode 100644 index 705a67f..0000000 --- a/entry/src/main/cpp/src/core/gui/CreatePreviewImage.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Xournal++ - * - * Helper function - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GtkWidget - -class PageType; - -namespace xoj::helper { -constexpr auto PREVIEW_WIDTH = 100; -constexpr auto PREVIEW_HEIGHT = 141; -/** - * @brief Create a GtkImage containing a miniature of the given (standard) page type - * The returned widget is a floating ref. - */ -auto createPreviewImage(const PageType& pt) -> GtkWidget*; -}; // namespace xoj::helper diff --git a/entry/src/main/cpp/src/core/gui/FloatingToolbox.cpp b/entry/src/main/cpp/src/core/gui/FloatingToolbox.cpp deleted file mode 100644 index 9641693..0000000 --- a/entry/src/main/cpp/src/core/gui/FloatingToolbox.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "FloatingToolbox.h" - -#include // for max -#include // for allocator - -#include // for GdkRectangle, GDK_LEAVE_... -#include // for G_CALLBACK, g_signal_con... - -#include "control/Control.h" // for Control -#include "control/ToolEnums.h" // for TOOL_FLOATING_TOOLBOX -#include "control/settings/ButtonConfig.h" // for ButtonConfig -#include "control/settings/Settings.h" // for Settings -#include "control/settings/SettingsEnums.h" // for BUTTON_COUNT -#include "util/glib_casts.h" - -#include "MainWindow.h" // for MainWindow -#include "ToolbarDefinitions.h" // for ToolbarEntryDefintion - - -FloatingToolbox::FloatingToolbox(MainWindow* theMainWindow, GtkOverlay* overlay) { - this->mainWindow = theMainWindow; - this->floatingToolbox = theMainWindow->get("floatingToolbox"); - this->floatingToolboxX = 200; - this->floatingToolboxY = 200; - this->floatingToolboxState = recalcSize; - - gtk_overlay_add_overlay(overlay, this->floatingToolbox); - gtk_overlay_set_overlay_pass_through(overlay, this->floatingToolbox, true); - gtk_widget_add_events(this->floatingToolbox, GDK_LEAVE_NOTIFY_MASK); - g_signal_connect(this->floatingToolbox, "leave-notify-event", - xoj::util::wrap_for_g_callback_v, this); - // position overlay widgets - g_signal_connect(overlay, "get-child-position", xoj::util::wrap_for_g_callback_v, this); -} - - -FloatingToolbox::~FloatingToolbox() = default; - - -void FloatingToolbox::show(int x, int y) { - this->floatingToolboxX = x; - this->floatingToolboxY = y; - this->show(); -} - - -/**** - * floatingToolboxActivated - * True if the user has: - * assigned a mouse or stylus button to bring up the floatingToolbox; - * or enabled tapAction and Show FloatingToolbox( prefs->DrawingArea->ActionOnToolTap ); - * or put tools in the FloatingToolbox. - * - */ -auto FloatingToolbox::floatingToolboxActivated() -> bool { - Settings* settings = this->mainWindow->getControl()->getSettings(); - ButtonConfig* cfg = nullptr; - - // check if any buttons assigned to bring up toolbox - for (unsigned int id = 0; id < BUTTON_COUNT; id++) { - cfg = settings->getButtonConfig(id); - - if (cfg->getAction() == TOOL_FLOATING_TOOLBOX) { - return true; // return true - } - } - - // check if user can show Floating Menu with tap. - if (settings->getDoActionOnStrokeFiltered() && settings->getStrokeFilterEnabled()) { - return true; // return true - } - - return this->hasWidgets(); -} - - -auto FloatingToolbox::hasWidgets() -> bool { - for (int index = TBFloatFirst; index <= TBFloatLast; index++) { - GtkToolbar* toolbar1 = GTK_TOOLBAR(this->mainWindow->get(TOOLBAR_DEFINITIONS[index].guiName)); - if (gtk_toolbar_get_n_items(toolbar1) > 0) { - return true; - } - } - return false; -} - - -void FloatingToolbox::showForConfiguration() { - if (this->floatingToolboxActivated()) // Do not show if not being used - at least while experimental. - { - GtkWidget* boxContents = this->mainWindow->get("boxContents"); - gint wx = 0, wy = 0; - gtk_widget_translate_coordinates(boxContents, gtk_widget_get_toplevel(boxContents), 0, 0, &wx, &wy); - this->floatingToolboxX = wx + 40; // when configuration state these are - this->floatingToolboxY = wy + 40; // topleft coordinates( otherwise center). - this->floatingToolboxState = configuration; - this->show(); - } -} - - -void FloatingToolbox::show() { - gtk_widget_show_all(this->floatingToolbox); - gtk_widget_set_visible(this->mainWindow->get("labelFloatingToolbox"), this->floatingToolboxState == configuration); - gtk_widget_set_visible(this->mainWindow->get("showIfEmpty"), - this->floatingToolboxState != configuration && !hasWidgets()); -} - - -void FloatingToolbox::hide() { - if (this->floatingToolboxState == configuration) { - this->floatingToolboxState = recalcSize; - } - - gtk_widget_hide(this->floatingToolbox); -} - - -void FloatingToolbox::flagRecalculateSizeRequired() { this->floatingToolboxState = recalcSize; } - - -/** - * getOverlayPosition - this is how we position the widget in the overlay under the mouse - * - * The requested location is communicated via the FloatingToolbox member variables: - * ->floatingToolbox, so we can operate on the right widget - * ->floatingToolboxState, are we configuring, resizing or just moving - * ->floatingToolboxX, where to display - * ->floatingToolboxY. - * - */ -auto FloatingToolbox::getOverlayPosition(GtkOverlay* overlay, GtkWidget* widget, GdkRectangle* allocation, - FloatingToolbox* self) -> bool { - if (widget != self->floatingToolbox) { - return false; - } - - gtk_widget_get_allocation(widget, allocation); - - if (self->floatingToolboxState != noChange || allocation->height < 2) { - GtkRequisition natural; - gtk_widget_get_preferred_size(widget, nullptr, &natural); - allocation->width = natural.width; - allocation->height = natural.height; - } - - // Get scrolled window for boundary clamping - GtkWidget* mainBox = self->mainWindow->get("mainBox"); - GtkWidget* boxContents = self->mainWindow->get("boxContents"); - - GtkWidget* scrolledWindow = nullptr; - GList* children = gtk_container_get_children(GTK_CONTAINER(boxContents)); - if (children != nullptr) { - scrolledWindow = GTK_WIDGET(children->data); - g_list_free(children); - } - - if (scrolledWindow == nullptr) { - // Fallback: no clamping if scrolled window not found - allocation->x = self->floatingToolboxX - allocation->width / 2; - allocation->y = self->floatingToolboxY - allocation->height / 2; - self->floatingToolboxState = noChange; - return true; - } - - // Get scrolled window position relative to mainBox - gint scrollX, scrollY; - gtk_widget_translate_coordinates(scrolledWindow, mainBox, 0, 0, &scrollX, &scrollY); - - GtkAllocation scrollAllocation; - gtk_widget_get_allocation(scrolledWindow, &scrollAllocation); - - switch (self->floatingToolboxState) { - case recalcSize: - [[fallthrough]]; - case noChange: { - int centerX = self->floatingToolboxX - allocation->width / 2; - int centerY = self->floatingToolboxY - allocation->height / 2; - - // Clamp to scrolled window bounds with margin - constexpr int margin = 10; - int minX = scrollX + margin; - int maxX = scrollX + scrollAllocation.width - allocation->width - margin; - int minY = scrollY + margin; - int maxY = scrollY + scrollAllocation.height - allocation->height - margin; - - // Ensure valid clamp bounds when toolbox is larger than viewport - maxX = std::max(maxX, minX); - maxY = std::max(maxY, minY); - - allocation->x = std::clamp(centerX, minX, maxX); - allocation->y = std::clamp(centerY, minY, maxY); - self->floatingToolboxState = noChange; - break; - } - - case configuration: - allocation->x = self->floatingToolboxX; - allocation->y = self->floatingToolboxY; - allocation->width = std::max(allocation->width + 32, 50); - allocation->height = std::max(allocation->height, 50); - break; - } - - return true; -} - - -bool FloatingToolbox::handleLeaveFloatingToolbox(GtkWidget* floatingToolbox, GdkEvent* event, FloatingToolbox* self) { - if (floatingToolbox == self->floatingToolbox) { - if (self->floatingToolboxState != configuration) { - self->hide(); - } - return true; - } - return false; -} diff --git a/entry/src/main/cpp/src/core/gui/FloatingToolbox.h b/entry/src/main/cpp/src/core/gui/FloatingToolbox.h deleted file mode 100644 index 82b21e4..0000000 --- a/entry/src/main/cpp/src/core/gui/FloatingToolbox.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Xournal++ - * - * The Floating Toolbox - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - - -#include // for GdkEvent, GdkRectangle -#include // for gboolean -#include // for GtkWidget, GtkOverlay - -class MainWindow; - -enum FloatingToolBoxState { recalcSize = 0, configuration, noChange }; - -/************************ - * FloatingToolbox: - * Uses a GtkOverlay to show a widget containing toolbars. - * The getOverlayPosition callback is used to position the toolbox widget relative to the users input device. - * The ui/main.glade file defines the floatingToolbox as a GtkRevealer widget - attempts to use another widget - * had issues with leave-notify-event. - */ - -class FloatingToolbox { -public: - FloatingToolbox(MainWindow* theMainWindow, GtkOverlay* overlay); - virtual ~FloatingToolbox(); - -public: - /** - * show(x,y): Show Toolbox at centered at x,y relative to main window. - */ - void show(int x, int y); - - /** - * showForConfiguration - * i.e. appear in fixed position in top left, extra space and do not hide automatically. - */ - void showForConfiguration(); - - void hide(); - - /** - * flagRecalculateSizeRequired(): trigger recalc size on next getOverlayPosition. Used when new toolbars loaded. - */ - void flagRecalculateSizeRequired(); - -private: - /** - * Callback for positioning overlayed floating menu - */ - static bool getOverlayPosition(GtkOverlay* overlay, GtkWidget* widget, GdkRectangle* alloc, FloatingToolbox* self); - - /** - * Callback to hide floating Toolbar when mouse leaves it - */ - static bool handleLeaveFloatingToolbox(GtkWidget* floatingToolbox, GdkEvent* event, FloatingToolbox* self); - - /** - * Show the Floating Toolbox - * ... but hide some labels depending on conditions. - */ - void show(); - - /** - * check if user has assigned a button to activate, or has put tools in the FloatingToolbox. - */ - bool floatingToolboxActivated(); - - /** - * Whether there are items in the toolbox. - * Note this includes non-tools such as spacers and separators. - */ - bool hasWidgets(); - - -private: - MainWindow* mainWindow; - GtkWidget* floatingToolbox; - - /** - * Communicating with getOverlayPosition callback - * */ - int floatingToolboxX = 0; - int floatingToolboxY = 0; - FloatingToolBoxState floatingToolboxState = recalcSize; -}; diff --git a/entry/src/main/cpp/src/core/gui/GladeGui.cpp b/entry/src/main/cpp/src/core/gui/GladeGui.cpp deleted file mode 100644 index c5ff9cd..0000000 --- a/entry/src/main/cpp/src/core/gui/GladeGui.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "GladeGui.h" - -#include // for exit - -#include // for g_object_unref -#include // for g_error_free, GError, g_warning - -#include "util/PlaceholderString.h" // for PlaceholderString -#include "util/StringUtils.h" // for char_cast -#include "util/XojMsgBox.h" // for XojMsgBox -#include "util/i18n.h" // for FS, _F - -#include "GladeSearchpath.h" // for GladeSearchpath -#include "filesystem.h" // for path - -GladeGui::GladeGui(GladeSearchpath* gladeSearchPath, const std::string& glade, const std::string& mainWnd) { - this->gladeSearchPath = gladeSearchPath; - - auto filepath = this->gladeSearchPath->findFile("", glade); - - GError* error = nullptr; - builder.reset(gtk_builder_new(), xoj::util::adopt); - - if (!gtk_builder_add_from_file(builder.get(), char_cast(filepath.u8string().c_str()), &error)) { - std::string msg = FS(_F("Error loading glade file \"{1}\" (try to load \"{2}\")") % glade % - char_cast(filepath.u8string())); - - if (error != nullptr) { - msg += "\n"; - msg += error->message; - g_error_free(error); - } - XojMsgBox::showErrorAndQuit(msg, -1); - } - - this->window = get(mainWnd); -} - -GladeGui::~GladeGui() { - if (!gtk_widget_get_parent(window)) { - gtk_widget_destroy(window); - } -} - -auto GladeGui::get(const std::string& name) -> GtkWidget* { - GtkWidget* w = GTK_WIDGET(gtk_builder_get_object(builder.get(), name.c_str())); - if (w == nullptr) { - g_warning("GladeGui::get: Could not find glade Widget: \"%s\"", name.c_str()); - } - return w; -} - -auto GladeGui::getWindow() const -> GtkWidget* { return this->window; } - -auto GladeGui::getGladeSearchPath() const -> GladeSearchpath* { return this->gladeSearchPath; } - -auto GladeGui::getBuilder() const -> GtkBuilder* { return this->builder.get(); } diff --git a/entry/src/main/cpp/src/core/gui/GladeGui.h b/entry/src/main/cpp/src/core/gui/GladeGui.h deleted file mode 100644 index 224b30d..0000000 --- a/entry/src/main/cpp/src/core/gui/GladeGui.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Xournal++ - * - * Abstract GUI class, which loads the glade objects - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - -#include // for GdkWindow -#include // for GtkWidget, GtkWindow, GtkBuilder - -#include "util/raii/GObjectSPtr.h" - -class GladeSearchpath; - -class GladeGui { -public: - GladeGui(GladeSearchpath* gladeSearchPath, const std::string& glade, const std::string& mainWnd); - virtual ~GladeGui(); - - virtual void show(GtkWindow* parent) = 0; - - GtkWidget* get(const std::string& name); - - void setThemePath(std::string themePath); - - GtkWidget* getWindow() const; - GladeSearchpath* getGladeSearchPath() const; - - GtkBuilder* getBuilder() const; - -private: - /** - * The Glade resources - */ - xoj::util::GObjectSPtr builder; - - /** - * Our search paths - */ - GladeSearchpath* gladeSearchPath; - -protected: - /** - * This window - */ - GtkWidget* window = nullptr; -}; diff --git a/entry/src/main/cpp/src/core/gui/GladeSearchpath.cpp b/entry/src/main/cpp/src/core/gui/GladeSearchpath.cpp deleted file mode 100644 index ce12925..0000000 --- a/entry/src/main/cpp/src/core/gui/GladeSearchpath.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Xournal++ - * - * Search directory for icons and Glade files - * - * @author andreas - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#include "GladeSearchpath.h" - -GladeSearchpath::GladeSearchpath() = default; - -GladeSearchpath::~GladeSearchpath() { directories.clear(); } - -auto GladeSearchpath::findFile(fs::path const& subdir, fs::path const& file) const -> fs::path { - fs::path filepath; - if (subdir.empty()) { - filepath = file; - } else { - filepath = subdir / file; - } - - // We step through each directory to find it. - for (const auto& dir: directories) { - auto pathname = dir / filepath; - - if (fs::exists(pathname)) { - return pathname; - } - } - - return fs::path{}; -} - -/** - * @return The first search path - */ -auto GladeSearchpath::getFirstSearchPath() const -> fs::path { - if (this->directories.empty()) { - return {}; - } - - return this->directories[0]; -} - -/** - * Use this function to set the directory containing installed pixmaps and Glade XML files. - */ -void GladeSearchpath::addSearchDirectory(fs::path const& directory) { this->directories.push_back(directory); } diff --git a/entry/src/main/cpp/src/core/gui/GladeSearchpath.h b/entry/src/main/cpp/src/core/gui/GladeSearchpath.h deleted file mode 100644 index c4faa6c..0000000 --- a/entry/src/main/cpp/src/core/gui/GladeSearchpath.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Xournal++ - * - * Search directory for icons and Glade files - * - * @author andreas - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for vector - -#include "filesystem.h" // for path - -class GladeSearchpath { -public: - GladeSearchpath(); - virtual ~GladeSearchpath(); - -public: - void addSearchDirectory(fs::path const& directory); - - /** - * Searches for a path, return the path, an empty string if not found - */ - fs::path findFile(fs::path const& subdir, fs::path const& file) const; - - /** - * @return The first search path - */ - fs::path getFirstSearchPath() const; - -private: - /** - * Search directory for icons and Glade files - */ - std::vector directories; -}; diff --git a/entry/src/main/cpp/src/core/gui/IconNameHelper.cpp b/entry/src/main/cpp/src/core/gui/IconNameHelper.cpp deleted file mode 100644 index eb5d919..0000000 --- a/entry/src/main/cpp/src/core/gui/IconNameHelper.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "IconNameHelper.h" - -#include // for gtk_icon_theme_get_default - -#include "control/settings/Settings.h" // for Settings - -IconNameHelper::IconNameHelper(Settings* settings): settings(settings) {} - -auto IconNameHelper::iconName(const char* icon) const -> std::string { - std::string xoppName = std::string("xopp-") + icon; - auto iconName = this->settings->areStockIconsUsed() && gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), icon) ? - std::string(icon) : - xoppName; - return iconName; -} diff --git a/entry/src/main/cpp/src/core/gui/IconNameHelper.h b/entry/src/main/cpp/src/core/gui/IconNameHelper.h deleted file mode 100644 index bbc4c99..0000000 --- a/entry/src/main/cpp/src/core/gui/IconNameHelper.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Xournal++ - * - * Helper which allows to switch between Xournal++ icons and stock icons - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include - -class Settings; - -class IconNameHelper final { - -public: - IconNameHelper(Settings* settings); - -protected: - const Settings* settings; - -public: - std::string iconName(const char* icon) const; -}; diff --git a/entry/src/main/cpp/src/core/gui/Layout.cpp b/entry/src/main/cpp/src/core/gui/Layout.cpp deleted file mode 100644 index 492fca7..0000000 --- a/entry/src/main/cpp/src/core/gui/Layout.cpp +++ /dev/null @@ -1,432 +0,0 @@ -#include "Layout.h" - -#include // for max, lower_bound, transform -#include // for abs -#include // for begin, end, distance -#include // for accumulate -#include // for optional -#include // for make_signed_t, remove_referen... - -#include // for G_CALLBACK, g_signal_connect - -#include "control/Control.h" // for Control -#include "control/settings/Settings.h" // for Settings -#include "gui/LayoutMapper.h" // for LayoutMapper, GridPosition -#include "gui/PageView.h" // for XojPageView -#include "gui/scroll/ScrollHandling.h" // for ScrollHandling -#include "model/Document.h" // for Document -#include "util/Rectangle.h" // for Rectangle -#include "util/safe_casts.h" // for strict_cast, as_signed, as_si... - -#include "XournalView.h" // for XournalView - -using xoj::util::Rectangle; - -/** - * Padding outside the pages, including shadow - */ -constexpr auto const XOURNAL_PADDING = 10; - -/** - * Allowance for shadow between page pairs in paired page mode - */ -constexpr auto const XOURNAL_ROOM_FOR_SHADOW = 3; - -/** - * Padding between the pages - */ -constexpr auto const XOURNAL_PADDING_BETWEEN = 15; - - -Layout::Layout(XournalView* view, ScrollHandling* scrollHandling): view(view), scrollHandling(scrollHandling) { - g_signal_connect(scrollHandling->getHorizontal(), "value-changed", G_CALLBACK(horizontalScrollChanged), this); - g_signal_connect(scrollHandling->getVertical(), "value-changed", G_CALLBACK(verticalScrollChanged), this); - - - lastScrollHorizontal = gtk_adjustment_get_value(scrollHandling->getHorizontal()); - lastScrollVertical = gtk_adjustment_get_value(scrollHandling->getVertical()); -} - -void Layout::horizontalScrollChanged(GtkAdjustment* adjustment, Layout* layout) { - Layout::checkScroll(adjustment, layout->lastScrollHorizontal); - layout->updateVisibility(); -} - -void Layout::verticalScrollChanged(GtkAdjustment* adjustment, Layout* layout) { - Layout::checkScroll(adjustment, layout->lastScrollVertical); - layout->updateVisibility(); - - layout->maybeAddLastPage(layout); -} - -void Layout::maybeAddLastPage(Layout* layout) { - auto* control = this->view->getControl(); - auto* settings = control->getSettings(); - if (settings->getEmptyLastPageAppend() == EmptyLastPageAppendType::OnScrollToEndOfLastPage) { - // If the layout is 5px away from the end of the last page - if (std::abs((layout->getMinimalHeight() - layout->getVisibleRect().y) - layout->getVisibleRect().height) < 5) { - auto* doc = control->getDocument(); - doc->lock_shared(); - auto pdfPageCount = doc->getPdfPageCount(); - auto lastPage = doc->getPageCount() - 1; - doc->unlock_shared(); - if (pdfPageCount == 0) { - auto currentPage = control->getCurrentPageNo(); - if (currentPage == lastPage) { - control->insertNewPage(currentPage + 1, true); - } - } - } - } -} - -void Layout::checkScroll(GtkAdjustment* adjustment, double& lastScroll) { - lastScroll = gtk_adjustment_get_value(adjustment); -} - -void Layout::updateVisibility() { - Rectangle visRect = getVisibleRect(); - - // step through every possible page position and update using p->setIsVisible() - // Using initial grid aprox speeds things up by a factor of 5. See previous git check-in for specifics. - int x1 = 0; - int y1 = 0; - - // Data to select page based on visibility - std::optional mostPageNr; - double mostPagePercent = 0; - - for (size_t row = 0; row < this->rowYStart.size(); ++row) { - auto y2 = as_signed_strict(this->rowYStart[row]); - for (size_t col = 0; col < this->colXStart.size(); ++col) { - auto x2 = as_signed_strict(this->colXStart[col]); - auto optionalPage = this->mapper.at({col, row}); - if (optionalPage) // a page exists at this grid location - { - auto& pageView = this->view->viewPages[*optionalPage]; - - // check if grid location is visible as an aprox for page visiblity: - if (!(visRect.x > x2 || visRect.x + visRect.width < x1) // visrect not outside current row/col - && !(visRect.y > y2 || visRect.y + visRect.height < y1)) { - // now use exact check of page itself: - // visrect not outside current page dimensions: - auto const& pageRect = pageView->getRect(); - if (auto intersection = pageRect.intersects(visRect); intersection) { - pageView->setIsVisible(true); - // Set the selected page - double percent = intersection->area() / pageRect.area(); - - if (percent > mostPagePercent) { - mostPageNr = *optionalPage; - mostPagePercent = percent; - } - } - } else { - pageView->setIsVisible(false); - } - } - x1 = x2; - } - y1 = y2; - x1 = 0; - } - - if (mostPageNr) { - this->view->getControl()->firePageSelected(*mostPageNr); - } -} - -auto Layout::getVisibleRect() -> Rectangle { - return Rectangle(gtk_adjustment_get_value(scrollHandling->getHorizontal()), - gtk_adjustment_get_value(scrollHandling->getVertical()), - gtk_adjustment_get_page_size(scrollHandling->getHorizontal()), - gtk_adjustment_get_page_size(scrollHandling->getVertical())); -} - -/** - * adds the addend to base if the predicate is true - */ - -[[maybe_unused]] constexpr auto sumIf = [](auto base, auto addend, bool predicate) { - if constexpr (std::is_signed_v || std::is_signed_v) { - using RT = std::make_signed_t; - if (predicate) { - return RT(base) + RT(addend); - } - return RT(base); - } else if constexpr (!(std::is_signed_v || std::is_signed_v)) { - using RT = decltype(base + addend); - if (predicate) { - return RT(base) + RT(addend); - } - return RT(base); - } -}; -void Layout::recalculate_int() const { - auto* settings = view->getControl()->getSettings(); - auto len = view->viewPages.size(); - mapper.configureFromSettings(len, settings); - auto colCount = mapper.getColumns(); - auto rowCount = mapper.getRows(); - - pc.widthCols.assign(colCount, 0); - pc.heightRows.assign(rowCount, 0); - - for (size_t pageIdx{}; pageIdx < len; ++pageIdx) { - auto const& raster_p = mapper.at(pageIdx); // auto [c, r] raster = mapper.at(); - auto const& c = raster_p.col; - auto const& r = raster_p.row; - auto& v = view->viewPages[pageIdx]; - pc.widthCols[c] = std::max(pc.widthCols[c], v->getDisplayWidthDouble()); - pc.heightRows[r] = std::max(pc.heightRows[r], v->getDisplayHeightDouble()); - } - - // add space around the entire page area to accommodate older Wacom tablets with limited sense area. - auto vPadding = 2 * XOURNAL_PADDING; - if (settings->getUnlimitedScrolling()) { - vPadding += 2 * static_cast(gtk_adjustment_get_page_size(scrollHandling->getVertical())); - } else if (settings->getAddVerticalSpace()) { - vPadding += settings->getAddVerticalSpaceAmountAbove(); - vPadding += settings->getAddVerticalSpaceAmountBelow(); - } - - auto hPadding = 2 * XOURNAL_PADDING; - if (settings->getUnlimitedScrolling()) { - hPadding += 2 * static_cast(gtk_adjustment_get_page_size(scrollHandling->getHorizontal())); - } else if (settings->getAddHorizontalSpace()) { - hPadding += settings->getAddHorizontalSpaceAmountLeft(); - hPadding += settings->getAddHorizontalSpaceAmountRight(); - } - - pc.minWidth = as_unsigned(hPadding + as_signed_strict((pc.widthCols.size() - 1) * XOURNAL_PADDING_BETWEEN)); - pc.minHeight = as_unsigned(vPadding + as_signed_strict((pc.heightRows.size() - 1) * XOURNAL_PADDING_BETWEEN)); - - pc.minWidth = floor_cast(std::accumulate(begin(pc.widthCols), end(pc.widthCols), double(pc.minWidth))); - pc.minHeight = floor_cast(std::accumulate(begin(pc.heightRows), end(pc.heightRows), double(pc.minHeight))); - pc.valid = true; -} - -void Layout::recalculate() { - pc.valid = false; - gtk_widget_queue_resize(view->getWidget()); -} - -void Layout::layoutPages(int width, int height) { - std::lock_guard g{pc.m}; - if (!pc.valid) { - recalculate_int(); - } - // Todo: remove, just a hack-hotfix - scrollHandling->setLayoutSize(std::max(width, strict_cast(this->pc.minWidth)), - std::max(height, strict_cast(this->pc.minHeight))); - - size_t const len = this->view->viewPages.size(); - Settings* settings = this->view->getControl()->getSettings(); - - // get from mapper (some may have changed to accommodate paired setting etc.) - bool const isPairedPages = this->mapper.isPairedPages(); - - auto const rows = this->pc.heightRows.size(); - auto const columns = this->pc.widthCols.size(); - - - // add space around the entire page area to accommodate older Wacom tablets with limited sense area. - auto v_padding = XOURNAL_PADDING; - if (settings->getUnlimitedScrolling()) { - v_padding += ceil_cast(gtk_adjustment_get_page_size(scrollHandling->getVertical())); - } else if (settings->getAddVerticalSpace()) { - v_padding += settings->getAddVerticalSpaceAmountAbove(); - } - - auto h_padding = XOURNAL_PADDING; - if (settings->getUnlimitedScrolling()) { - h_padding += ceil_cast(gtk_adjustment_get_page_size(scrollHandling->getHorizontal())); - } else if (settings->getAddHorizontalSpace()) { - h_padding += settings->getAddHorizontalSpaceAmountLeft(); - } - - auto const centeringXBorder = (width - as_signed(pc.minWidth)) / 2; - auto const centeringYBorder = (height - as_signed(pc.minHeight)) / 2; - - using SBig = decltype(as_signed(h_padding * centeringXBorder)); - auto const borderX = static_cast(std::max(h_padding, centeringXBorder)); - auto const borderY = static_cast(std::max(v_padding, centeringYBorder)); - - // initialize here and x again in loop below. - auto x = borderX; - auto y = borderY; - - - // Iterate over ALL possible rows and columns. - // We don't know which page, if any, is to be displayed in each row, column - ask the mapper object! - // Then assign that page coordinates with center, left or right justify within row,column grid cell as required. - for (size_t r = 0; r < rows; r++) { - for (size_t c = 0; c < columns; c++) { - auto optionalPage = this->mapper.at({c, r}); - - if (optionalPage) { - - auto& v = this->view->viewPages[*optionalPage]; - v->setMappedRowCol(strict_cast(r), - strict_cast(c)); // store row and column for e.g. proper arrow key navigation - auto vDisplayWidth = v->getDisplayWidthDouble(); - { - auto paddingLeft = 0.0; - auto paddingRight = 0.0; - auto columnPadding = this->pc.widthCols[c] - vDisplayWidth; - - if (isPairedPages && len > 1) { - // pair pages mode - if (c % 2 == 0) { - // align right - paddingLeft = XOURNAL_PADDING_BETWEEN - XOURNAL_ROOM_FOR_SHADOW + columnPadding; - paddingRight = XOURNAL_ROOM_FOR_SHADOW; - } else { // align left - paddingLeft = XOURNAL_ROOM_FOR_SHADOW; - paddingRight = XOURNAL_PADDING_BETWEEN - XOURNAL_ROOM_FOR_SHADOW + columnPadding; - } - } else { // not paired page mode - center - paddingLeft = XOURNAL_PADDING_BETWEEN / 2.0 + columnPadding / 2.0; // center justify - paddingRight = XOURNAL_PADDING_BETWEEN - paddingLeft + columnPadding; - } - - x += paddingLeft; - - v->setX(floor_cast(x)); // set the page position - v->setY(floor_cast(y)); - - x += vDisplayWidth + paddingRight; - } - } else { - x += this->pc.widthCols[c] + XOURNAL_PADDING_BETWEEN; - } - } - x = borderX; - y += this->pc.heightRows[r] + XOURNAL_PADDING_BETWEEN; - } - - this->colXStart.resize(this->pc.widthCols.size()); - this->rowYStart.resize(this->pc.heightRows.size()); - - - // accumulated - absolute pixel location for use by getViewAt() and updateVisibility() - auto totalWidth = borderX; - std::transform( - begin(this->pc.widthCols), end(this->pc.widthCols), begin(this->colXStart), [&totalWidth](auto&& widthCol) { - return strict_cast>(totalWidth += - widthCol + XOURNAL_PADDING_BETWEEN); - }); - auto totalHeight = borderY; - std::transform(begin(this->pc.heightRows), end(this->pc.heightRows), begin(this->rowYStart), - [&totalHeight](auto&& heightRow) { - return strict_cast>( - (totalHeight += heightRow + XOURNAL_PADDING_BETWEEN)); - }); -} - - -auto Layout::getPaddingAbovePage(size_t pageIndex) const -> int { - const Settings* settings = this->view->getControl()->getSettings(); - - // User-configured padding above all pages. - auto paddingAbove = XOURNAL_PADDING; - if (settings->getUnlimitedScrolling()) { - paddingAbove += ceil_cast(gtk_adjustment_get_page_size(scrollHandling->getVertical())); - } else if (settings->getAddVerticalSpace()) { - paddingAbove += settings->getAddVerticalSpaceAmountAbove(); - } - - // (x, y) coordinate pair gives grid indices. This handles paired pages and different page layouts for us. - auto pageYLocation = strict_cast(this->mapper.at(pageIndex).row); - return pageYLocation * XOURNAL_PADDING_BETWEEN + paddingAbove; -} - - -auto Layout::getPaddingLeftOfPage(size_t pageIndex) const -> int { - bool isPairedPages = this->mapper.isPairedPages(); - const Settings* settings = this->view->getControl()->getSettings(); - - auto paddingBefore = XOURNAL_PADDING; - if (settings->getUnlimitedScrolling()) { - paddingBefore += ceil_cast(gtk_adjustment_get_page_size(scrollHandling->getHorizontal())); - } else if (settings->getAddHorizontalSpace()) { - paddingBefore += settings->getAddHorizontalSpaceAmountLeft(); - } - - auto const pageXLocation = strict_cast(this->mapper.at(pageIndex).col); - - // No page pairing or we haven't rendered enough pages in the row for page pairing to have an effect, - if (!isPairedPages) { - return pageXLocation * XOURNAL_PADDING_BETWEEN + XOURNAL_PADDING_BETWEEN / 2 + paddingBefore; - } else { - auto columnPadding = XOURNAL_PADDING_BETWEEN + pageXLocation * XOURNAL_PADDING_BETWEEN; - if (pageXLocation % 2 == 0) { - return columnPadding - XOURNAL_ROOM_FOR_SHADOW + paddingBefore; - } else { - return columnPadding + XOURNAL_ROOM_FOR_SHADOW + paddingBefore; - } - } -} - -void Layout::scrollRelative(double x, double y) { - if (this->view->getControl()->getSettings()->isPresentationMode()) { - return; - } - - gtk_adjustment_set_value(scrollHandling->getHorizontal(), - gtk_adjustment_get_value(scrollHandling->getHorizontal()) + x); - gtk_adjustment_set_value(scrollHandling->getVertical(), - gtk_adjustment_get_value(scrollHandling->getVertical()) + y); -} - -void Layout::scrollAbs(double x, double y) { - if (this->view->getControl()->getSettings()->isPresentationMode()) { - return; - } - - gtk_adjustment_set_value(scrollHandling->getHorizontal(), x); - gtk_adjustment_set_value(scrollHandling->getVertical(), y); -} - - -void Layout::ensureRectIsVisible(int x, int y, int width, int height) { - gtk_adjustment_clamp_page(scrollHandling->getHorizontal(), x - 5, x + width + 10); - gtk_adjustment_clamp_page(scrollHandling->getVertical(), y - 5, y + height + 10); -} - - -auto Layout::getPageViewAt(int x, int y) -> XojPageView* { - // Binary Search: - auto rit = std::lower_bound(this->rowYStart.begin(), this->rowYStart.end(), y); - auto const foundRow = size_t(std::distance(this->rowYStart.begin(), rit)); - auto cit = std::lower_bound(this->colXStart.begin(), this->colXStart.end(), x); - auto const foundCol = size_t(std::distance(this->colXStart.begin(), cit)); - - auto optionalPage = this->mapper.at({foundCol, foundRow}); - - if (optionalPage && this->view->viewPages[*optionalPage]->containsPoint(x, y, false)) { - return this->view->viewPages[*optionalPage].get(); - } - - return nullptr; -} - -auto Layout::getPageIndexAtGridMap(size_t row, size_t col) -> std::optional { - return this->mapper.at({col, row}); // watch out.. x,y --> c,r -} - -auto Layout::getMinimalHeight() const -> int { - std::lock_guard g{pc.m}; - if (!pc.valid) { - recalculate_int(); - } - return strict_cast(this->pc.minHeight); -} - -auto Layout::getMinimalWidth() const -> int { - std::lock_guard g{pc.m}; - if (!pc.valid) { - recalculate_int(); - } - return strict_cast(this->pc.minWidth); -} diff --git a/entry/src/main/cpp/src/core/gui/Layout.h b/entry/src/main/cpp/src/core/gui/Layout.h deleted file mode 100644 index 8f5bdc9..0000000 --- a/entry/src/main/cpp/src/core/gui/Layout.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Xournal++ - * - * Handles the layout of the pages within a Xournal document - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for mutex -#include // for optional -#include // for vector - -#include // for GtkAdjustment - -#include "util/Rectangle.h" // for Rectangle - -#include "LayoutMapper.h" // for LayoutMapper - -class XojPageView; -class XournalView; -class ScrollHandling; - - -/** - * @brief The Layout manager for the XournalWidget - * - * This class manages the layout of the XojPageView's contained - * in the XournalWidget - */ -class Layout final { -public: - Layout(XournalView* view, ScrollHandling* scrollHandling); - struct PreCalculated { - std::mutex m; - - // The width and height of all our pages - size_t minWidth = 0; - size_t minHeight = 0; - std::vector widthCols; - std::vector heightRows; - bool valid = false; - }; - -public: - // Todo(Fabian): move to ScrollHandling also it must not depend on Layout - /** - * Increases the adjustments by the given amounts - */ - void scrollRelative(double x, double y); - - // Todo(Fabian): move to ScrollHandling also it must not depend on Layout - /** - * Changes the adjustments by absolute amounts (for pinch-to-zoom) - */ - void scrollAbs(double x, double y); - - // Todo(Fabian): move to XournalView - /** - * Changes the adjustments in such a way as to make sure that - * the given Rectangle is visible - * - * @remark If the given Rectangle won't fit into the scrolled window - * then only its top left corner will be visible - */ - void ensureRectIsVisible(int x, int y, int width, int height); - - /** - * Returns the height of the entire Layout - */ - int getMinimalHeight() const; - - /** - * Returns the width of the entire Layout - */ - int getMinimalWidth() const; - - // Todo(Fabian): move to XournalView this must not depend on Layout directly - /** - * Returns the Rectangle which is currently visible - */ - xoj::util::Rectangle getVisibleRect(); - - - /** - * recalculate and resize Layout - */ - void recalculate(); - - /** - * Performs a layout of the XojPageView's managed in this Layout - * Sets out pages in a grid. - * Document pages are assigned to grid positions by the mapper object and may be ordered in a myriad of ways. - * ONLY call this on size allocation - */ - void layoutPages(int width, int height); - - // Todo(Fabian): move to View: - /** - * Updates the current XojPageView. The XojPageView is selected based on - * the percentage of the visible area of the XojPageView relative - * to its total area. - */ - void updateVisibility(); - - /** - * Return the pageview containing co-ordinates. - */ - XojPageView* getPageViewAt(int x, int y); - - /** - * Return the page index found ( or std::nullopt if not found) at layout grid row,col - * - */ - std::optional getPageIndexAtGridMap(size_t row, size_t col); - - /** - * @brief Get the total padding above the page at the given index. - * - * The size of this padding does not scale with pages as the user zooms in and out. - * As such, it is often necessary to get _just_ this padding. - * - * @param pageIndex is the index of the XojPageView as returned by [getIndexAtGridMap] - * @return the sum of the padding between pages above the page with the given index - * and any padding the user added vertically above all pages (i.e. in settings). - */ - int getPaddingAbovePage(size_t pageIndex) const; - - /** - * @brief Get the static padding added to the left of the current page. - * - * This does not include padding added to center the page on the screen. - * - * @param pageIndex is the index of the XojPageView, as given by [getIndexAtGridMap] - * @return the sum of the padding between pages left of the page at [pageIndex] and - * any horizontal padding the user decided to add (from settings) - */ - int getPaddingLeftOfPage(size_t pageIndex) const; - -protected: - // Todo(Fabian): move to ScrollHandling also it must not depend on Layout - static void horizontalScrollChanged(GtkAdjustment* adjustment, Layout* layout); - static void verticalScrollChanged(GtkAdjustment* adjustment, Layout* layout); - -private: - void recalculate_int() const; - - void maybeAddLastPage(Layout* layout); - - // Todo(Fabian): move to ScrollHandling also it must not depend on Layout - static void checkScroll(GtkAdjustment* adjustment, double& lastScroll); - -private: - XournalView* view = nullptr; - ScrollHandling* scrollHandling = nullptr; - - // Todo(Fabian): move to ScrollHandling also it must not depend on Layout - double lastScrollHorizontal = -1; - double lastScrollVertical = -1; - - /** - * layoutPages invalidates the precalculation of recalculate - * this bool prevents that layotPages can be called without a previously call to recalculate - * Todo: we may want to remove the additional calculation in layoutPages, since we stored those values in - */ - mutable LayoutMapper mapper; - mutable PreCalculated pc{}; - mutable std::vector colXStart; - mutable std::vector rowYStart; -}; diff --git a/entry/src/main/cpp/src/core/gui/LayoutMapper.cpp b/entry/src/main/cpp/src/core/gui/LayoutMapper.cpp deleted file mode 100644 index 1fdcd44..0000000 --- a/entry/src/main/cpp/src/core/gui/LayoutMapper.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "LayoutMapper.h" - -#include // for max -#include // for __alloc_traits<>::value_type - -#include "control/settings/Settings.h" // for Settings - -constexpr auto calc_default_grid_pos = [](size_t page_nr, GridPosition grid_size, - LayoutSettings::Orientation orientation) { - return orientation == LayoutSettings::Orientation::Vertical ? - GridPosition{page_nr / grid_size.row, page_nr % grid_size.row} : - GridPosition{page_nr % grid_size.col, page_nr / grid_size.col}; -}; - -constexpr auto map1 = [](LayoutSettings const& data, size_t page_nr) { - GridPosition grid_pos{}; - auto new_nr = page_nr + static_cast(data.offset); - if (data.showPairedPages) { - auto grid_size = GridPosition{data.cols / 2, data.rows}; - grid_pos = calc_default_grid_pos(new_nr / 2, grid_size, data.orientation); - (grid_pos.col *= 2) += (new_nr % 2); - } else { - grid_pos = calc_default_grid_pos(new_nr, {data.cols, data.rows}, data.orientation); - } - decltype(grid_pos) grid_pos2 = { - (data.horizontalDir == LayoutSettings::HorizontalDirection::RightToLeft ? data.cols - 1 - grid_pos.col : - grid_pos.col), - (data.verticalDir == LayoutSettings::VerticalDirection::BottomToTop ? data.rows - 1 - grid_pos.row : - grid_pos.row)}; - return grid_pos2; -}; - -constexpr auto map2 = [](LayoutSettings const& data, GridPosition pos) -> std::optional { - auto isRightToLeft = [&]() { return data.horizontalDir == LayoutSettings::RightToLeft; }; - auto isBottomToTop = [&]() { return data.verticalDir == LayoutSettings::BottomToTop; }; - auto isVertical = [&]() { return data.orientation == LayoutSettings::Vertical; }; - - if (isRightToLeft()) { // reverse x - pos.col = data.cols - 1 - pos.col; - } - if (isBottomToTop()) { // reverse y - pos.row = data.rows - 1 - pos.row; - } - size_t res{}; - if (isVertical()) { - if (data.showPairedPages) { - res = ((pos.row + data.rows * (pos.col / 2)) * 2) + pos.col % 2; - } else { - res = pos.row + data.rows * pos.col; - } - } else { // Horizontal - res = pos.col + data.cols * pos.row; - } - res -= data.offset; - if (res >= data.actualPages) { - return {}; - } - return res; -}; - -// Testers - -constexpr LayoutSettings my_data0{1, 91, 92, 1}; -constexpr LayoutSettings my_data1{91, 1, 90, 1}; -constexpr LayoutSettings my_data2{ - 6, 6, 35, 1, true, LayoutSettings::Vertical, LayoutSettings::RightToLeft, LayoutSettings::BottomToTop}; -constexpr GridPosition test_pos0{0, 3}; -constexpr GridPosition test_pos1{3, 0}; -constexpr GridPosition test_pos2{3, 3}; - -static_assert(map1(my_data0, *map2(my_data0, test_pos0)) == test_pos0); -static_assert(map1(my_data1, *map2(my_data1, test_pos1)) == test_pos1); -static_assert(map1(my_data2, *map2(my_data2, test_pos2)) == test_pos2); - -template -constexpr auto hash(T&& data_, GridPosition const& pos) { - return pos.col + pos.row * data_.cols; -} - - -/** - * calculate - * - * Set mapper to LayoutType with number of pages and of fixed rows or columns - * @param data the data to be configured - * @param numRows Number of rows ( used if useRows ) - * @param numCols Number of columns ( used if !useRows ) - * @param useRows use pages/rows to recalculate cols else recalculate rows - * @param firstPageOffset Pages to offset - usually one or zero in order to pair up properly - */ - -void calculate(LayoutSettings& data, size_t numRows, size_t numCols, bool useRows, uint32_t firstPageOffset) { - if (useRows) { - data.rows = std::max(1UL, numRows); - - // using + ( rows-1) to round up (int)pages/rows - data.cols = std::max(1UL, (data.actualPages + firstPageOffset + (data.rows - 1)) / data.rows); - if (data.showPairedPages) { - data.cols += data.cols % 2; // make even - } - } else { - data.cols = std::max(1UL, numCols); - if (data.showPairedPages) { - data.cols += data.cols % 2; // make even - } - data.rows = std::max(1UL, (data.actualPages + firstPageOffset + (data.cols - 1)) / data.cols); - } - - - if (data.orientation == LayoutSettings::Vertical) { - // Vertical Layout - if (data.showPairedPages) { - data.offset = firstPageOffset % static_cast(2 * data.rows); - } else { - data.offset = firstPageOffset % static_cast(data.rows); - } - } else { - // Horizontal Layout - data.offset = firstPageOffset % static_cast(data.cols); - } -} - -void LayoutMapper::configureFromSettings(size_t numPages, Settings* settings) { - LayoutSettings data; - // get from user settings: - data.actualPages = numPages; - data.showPairedPages = settings->isShowPairedPages(); - auto const& pairsOffset = data.showPairedPages ? static_cast(settings->getPairsOffset()) : 0U; - - auto const& isPresentationMode = settings->isPresentationMode(); - auto const& fixRows = !isPresentationMode && settings->isViewFixedRows(); - auto const& numCols = size_t(isPresentationMode ? 1 : settings->getViewColumns()); - auto const& numRows = size_t(isPresentationMode ? 1 : settings->getViewRows()); - - // assemble bitflags for LayoutType - data.orientation = (isPresentationMode || settings->getViewLayoutVert()) ? LayoutSettings::Vertical : - LayoutSettings::Horizontal; - data.horizontalDir = settings->getViewLayoutR2L() ? LayoutSettings::RightToLeft : LayoutSettings::LeftToRight; - data.verticalDir = settings->getViewLayoutB2T() ? LayoutSettings::BottomToTop : LayoutSettings::TopToBottom; - - calculate(data, numRows, numCols, fixRows, pairsOffset); - if (data == data_) { - return; - } - data_ = data; - precalculateMappers(); -} - -void LayoutMapper::precalculateMappers() { - this->pageToRaster.clear(); - this->rasterToPage.clear(); - this->pageToRaster.resize(data_.actualPages); - this->rasterToPage.resize(data_.rows * data_.cols, size_t(-1)); - - for (size_t i = 0; i != data_.actualPages; ++i) { - auto&& val = map1(data_, i); - this->pageToRaster[i] = val; - this->rasterToPage[hash(data_, val)] = i; - } -} - -auto LayoutMapper::getColumns() const -> size_t { return data_.cols; } - -auto LayoutMapper::getRows() const -> size_t { return data_.rows; } - -auto LayoutMapper::isPairedPages() const -> bool { return data_.showPairedPages; } - -auto LayoutMapper::at(size_t page) const -> GridPosition { return pageToRaster.at(page); } - -auto LayoutMapper::at(GridPosition const& rasterXY) const -> std::optional { - auto index = hash(data_, rasterXY); - if (index >= rasterToPage.size()) { - return std::nullopt; - } - auto val = rasterToPage[index]; - return val >= data_.actualPages ? std::nullopt : std::optional(val); // Maybe optimize this -} diff --git a/entry/src/main/cpp/src/core/gui/LayoutMapper.h b/entry/src/main/cpp/src/core/gui/LayoutMapper.h deleted file mode 100644 index dc3eb6a..0000000 --- a/entry/src/main/cpp/src/core/gui/LayoutMapper.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Xournal++ - * - * A layout manager - map where( row,column) to which page( document index) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for uint32_t -#include // for optional -#include // for operator==, tie, tuple -#include // for vector - -class Settings; - -struct GridPosition { - size_t col{}; - size_t row{}; - - constexpr friend bool operator==(GridPosition const& lhs, GridPosition const& rhs) noexcept { - return lhs.col == rhs.col && lhs.row == rhs.row; - } -}; - -struct LayoutSettings { - /// @brief The Layout of the pages - enum Orientation : bool { - Horizontal = false, - Vertical = true, - }; - - /// Horizontal read direction - enum HorizontalDirection : bool { - LeftToRight = false, - RightToLeft = true, - }; - - /// Vertical read direction - enum VerticalDirection : bool { - TopToBottom = false, - BottomToTop = true, - }; - - size_t cols = 0; - size_t rows = 0; - size_t actualPages = 0; - uint32_t offset = 0; - - bool showPairedPages = false; - Orientation orientation = Vertical; - HorizontalDirection horizontalDir = LeftToRight; - VerticalDirection verticalDir = TopToBottom; - - constexpr friend auto operator==(LayoutSettings const& lhs, LayoutSettings const& rhs) { - auto tier = [](auto&& other) { - return std::tie(other.cols, other.rows, other.actualPages, other.offset, other.showPairedPages, - other.orientation, other.horizontalDir, other.verticalDir); - }; - return tier(lhs) == tier(rhs); - } -}; -auto layoutSettings(Settings const*) -> LayoutSettings; - -/** - * @brief Layout asks this mapper what page ( if any ) should be at a given column,row. - */ -class LayoutMapper { -public: - LayoutMapper() = default; - - /** - * configureFromSettings - * Obtain user settings to determine arguments to configure(). - * - * @param pages The number of pages in the document - * @param settings The Settings from which users settings are obtained - */ - - void configureFromSettings(size_t numPages, Settings* settings); - - auto at(size_t) const -> GridPosition; - auto at(GridPosition const&) const -> std::optional; - - size_t getColumns() const; - size_t getRows() const; - - bool isPairedPages() const; - -private: - void precalculateMappers(); - - /** - * Map page location to document index - * - * @param x Row we are interested in - * @param y Column we are interested in - * - * @return Page index to put at coordinates - */ - -public: - LayoutSettings data_; - - friend void calculate(LayoutSettings& data, size_t numRows, size_t numCols, bool useRows, uint32_t firstPageOffset); - - std::vector pageToRaster; - std::vector rasterToPage; // access with x*y_max+y+ -}; diff --git a/entry/src/main/cpp/src/core/gui/LegacyRedrawable.cpp b/entry/src/main/cpp/src/core/gui/LegacyRedrawable.cpp deleted file mode 100644 index 1fadfc6..0000000 --- a/entry/src/main/cpp/src/core/gui/LegacyRedrawable.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "LegacyRedrawable.h" - -#include "model/Element.h" // for Element -#include "util/Range.h" // for Range - -void LegacyRedrawable::repaintElement(Element* e) const { - repaintArea(e->getX(), e->getY(), e->getElementWidth() + e->getX(), e->getElementHeight() + e->getY()); -} - -void LegacyRedrawable::repaintRect(double x, double y, double width, double height) const { - repaintArea(x, y, x + width, y + height); -} - -void LegacyRedrawable::rerenderRange(const Range& r) { rerenderRect(r.getX(), r.getY(), r.getWidth(), r.getHeight()); } - -void LegacyRedrawable::rerenderElement(const Element* e) { - rerenderRect(e->getX(), e->getY(), e->getElementWidth(), e->getElementHeight()); -} diff --git a/entry/src/main/cpp/src/core/gui/LegacyRedrawable.h b/entry/src/main/cpp/src/core/gui/LegacyRedrawable.h deleted file mode 100644 index 6fc56cb..0000000 --- a/entry/src/main/cpp/src/core/gui/LegacyRedrawable.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Xournal++ - * - * Interface for GUI handling - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GdkRGBA - -class Element; -class Range; - -/* - * The (base) class Redrawable (now LegacyRedrawable) is deprecated. Use xoj::view::Repaintable instead. - * - * Reasons for the deprecation: - * - * * It is basically used synonymously to XojPageView. - * * More importantly, the coexistence of Redrawable::repaint... and Redrawable::rerender... is bothersome. - * it is not clear (without diving in the code) what the difference should be. - * (repaint = ask gtk to call us back to blitt the buffer, rerender = change the buffer's content) - * The rerender... methods should not exist. The derived class should be told what happened (something changed), - * and decide by itself if the buffer should be updated or not (if there is a buffer to begin with). - */ -class [[deprecated]] LegacyRedrawable { -protected: - LegacyRedrawable() = default; - -public: - LegacyRedrawable(LegacyRedrawable&&) = default; - LegacyRedrawable(LegacyRedrawable const&) = default; - virtual ~LegacyRedrawable() = default; - LegacyRedrawable& operator=(LegacyRedrawable&&) = default; - LegacyRedrawable& operator=(LegacyRedrawable const&) = default; - - /** - * Call this if you only need to repaint the view, this means the buffer will be painted again, - * and all selections, text editors etc. are drawn again, but the view buffer is not refreshed. - * - * for refreshing the view buffer (if you have changed the document) call rerender. - */ - virtual void repaintArea(double x1, double y1, double x2, double y2) const = 0; - [[maybe_unused]] void repaintRect(double x, double y, double width, double height) const; - [[maybe_unused]] void repaintElement(Element* e) const; - - /** - * Call this if you only need to redraw the view, this means the buffer will be painted again, - * and all selections, text editors etc. are drawn again, but the view buffer is not refreshed. - * - * for refreshing the view buffer (if you have changed the document) call rerender. - */ - virtual void repaintPage() const = 0; - - /** - * Rerender our buffer, then redraw the widget - * @param sizeChanged whether or not this rerendering is caused by the size of the page changing - */ - virtual void rerenderPage(bool sizeChanged = false) = 0; - - /** - * Call this if you add an element, remove an element etc. - */ - void rerenderElement(const Element* e); - void rerenderRange(const Range& r); - - /** - * This updated the view buffer and then rerender the the region, call this if you changed the document - */ - virtual void rerenderRect(double x, double y, double width, double height) = 0; - - /** - * Return the GTK selection color - */ - virtual GdkRGBA getSelectionColor() = 0; - - - virtual void deleteViewBuffer() = 0; - - virtual int getX() const = 0; - virtual int getY() const = 0; -}; diff --git a/entry/src/main/cpp/src/core/gui/MainWindow.cpp b/entry/src/main/cpp/src/core/gui/MainWindow.cpp deleted file mode 100644 index 37181cf..0000000 --- a/entry/src/main/cpp/src/core/gui/MainWindow.cpp +++ /dev/null @@ -1,742 +0,0 @@ -#include "MainWindow.h" - -#include - -#include // for gdk_pixbuf_new_fr... -#include // for gdk_screen_get_de... -#include // for g_cancellable_is_... -#include // for gtk_css_provider_... - -#include "control/AudioController.h" // for AudioController -#include "control/Control.h" // for Control -#include "control/DeviceListHelper.h" // for getSourceMapping -#include "control/ScrollHandler.h" // for ScrollHandler -#include "control/actions/ActionDatabase.h" // for ActionDatabase -#include "control/jobs/XournalScheduler.h" // for XournalScheduler -#include "control/layer/LayerController.h" // for LayerController -#include "control/settings/Settings.h" // for Settings -#include "control/settings/SettingsEnums.h" // for SCROLLBAR_HIDE_HO... -#include "control/zoom/ZoomControl.h" // for ZoomControl -#include "gui/FloatingToolbox.h" // for FloatingToolbox -#include "gui/GladeGui.h" // for GladeGui -#include "gui/PdfFloatingToolbox.h" // for PdfFloatingToolbox -#include "gui/SearchBar.h" // for SearchBar -#include "gui/inputdevices/InputEvents.h" // for INPUT_DEVICE_TOUC... -#include "gui/menus/menubar/Menubar.h" // for Menubar -#include "gui/menus/menubar/ToolbarSelectionSubmenu.h" // for ToolbarSelectionSubmenu -#include "gui/scroll/ScrollHandling.h" // for ScrollHandling -#include "gui/sidebar/Sidebar.h" // for Sidebar -#include "gui/toolbarMenubar/ToolMenuHandler.h" // for ToolMenuHandler -#include "gui/toolbarMenubar/model/ToolbarData.h" // for ToolbarData -#include "gui/toolbarMenubar/model/ToolbarModel.h" // for ToolbarModel -#include "gui/widgets/SpinPageAdapter.h" // for SpinPageAdapter -#include "gui/widgets/XournalWidget.h" // for gtk_xournal_get_l... -#include "util/GListView.h" // for GListView, GListV... -#include "util/GtkUtil.h" // for getWidgetDPI -#include "util/PathUtil.h" // for getConfigFile -#include "util/StringUtils.h" // for char_cast -#include "util/Util.h" // for execInUiThread, npos -#include "util/XojMsgBox.h" // for XojMsgBox -#include "util/glib_casts.h" // for wrap_for_once_v -#include "util/gtk4_helper.h" // for gtk_widget_get_width -#include "util/i18n.h" // for FS, _F -#include "util/raii/CStringWrapper.h" // for OwnedCString - -#include "GladeSearchpath.h" // for GladeSearchpath -#include "ToolbarDefinitions.h" // for TOOLBAR_DEFINITIO... -#include "XournalView.h" // for XournalView -#include "config-dev.h" // for TOOLBAR_CONFIG -#include "filesystem.h" // for path, exists - -#ifdef __APPLE__ -// the following header file contains a definition of struct Point that conflicts with model/Point.h -#define Point Point_CF -#include -#undef Point -#endif - -using std::string; - - -static void themeCallback(GObject*, GParamSpec*, gpointer data) { static_cast(data)->updateColorscheme(); } - -MainWindow::MainWindow(GladeSearchpath* gladeSearchPath, Control* control, GtkApplication* parent): - GladeGui(gladeSearchPath, "main.glade", "mainWindow"), - control(control), - toolbar(std::make_unique(control, this)), - menubar(std::make_unique()) { - gtk_window_set_application(GTK_WINDOW(getWindow()), parent); - - panedContainerWidget.reset(get("panelMainContents"), xoj::util::ref); - boxContainerWidget.reset(get("mainContentContainer"), xoj::util::ref); - mainContentWidget.reset(get("boxContents"), xoj::util::ref); - sidebarWidget.reset(get("sidebar"), xoj::util::ref); - - loadMainCSS(gladeSearchPath, "xournalpp.css"); - - GtkOverlay* overlay = GTK_OVERLAY(get("mainOverlay")); - this->pdfFloatingToolBox = std::make_unique(this, overlay); - this->floatingToolbox = std::make_unique(this, overlay); - - for (size_t i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) { - this->toolbarWidgets[i].reset(get(TOOLBAR_DEFINITIONS[i].guiName), xoj::util::ref); - } - - initXournalWidget(); - - setSidebarVisible(control->getSettings()->isSidebarVisible()); - - // Window handler - g_signal_connect(this->window, "delete-event", xoj::util::wrap_for_g_callback_v, - this->control); -#if GTK_MAJOR_VERSION == 3 - g_signal_connect(this->window, "notify::is-maximized", xoj::util::wrap_for_g_callback_v, - this); -#else - g_signal_connect(this->window, "notify::maximized", xoj::util::wrap_for_g_callback_v, - this); -#endif - - // "watch over" all key events - auto keyPropagate = +[](GtkWidget* w, GdkEvent* e, gpointer) { - return gtk_window_propagate_key_event(GTK_WINDOW(w), (GdkEventKey*)(e)); - }; - g_signal_connect(this->window, "key-press-event", G_CALLBACK(keyPropagate), nullptr); - g_signal_connect(this->window, "key-release-event", G_CALLBACK(keyPropagate), nullptr); - - updateScrollbarSidebarPosition(); - - gtk_window_set_default_size(GTK_WINDOW(this->window), control->getSettings()->getMainWndWidth(), - control->getSettings()->getMainWndHeight()); - - if (control->getSettings()->isMainWndMaximized()) { - gtk_window_maximize(GTK_WINDOW(this->window)); - } else { - gtk_window_unmaximize(GTK_WINDOW(this->window)); - } - - Util::execInUiThread([=]() { - // Execute after the window is visible, else the check won't work - control->setShowMenubar(control->getSettings()->isMenubarVisible()); - }); - - // Drag and Drop - g_signal_connect(this->window, "drag-data-received", G_CALLBACK(dragDataRecived), this); - - gtk_drag_dest_set(this->window, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_COPY); - gtk_drag_dest_add_uri_targets(this->window); - gtk_drag_dest_add_image_targets(this->window); - gtk_drag_dest_add_text_targets(this->window); - - g_signal_connect(gtk_widget_get_settings(this->window), "notify::gtk-theme-name", G_CALLBACK(themeCallback), this); - g_signal_connect(gtk_widget_get_settings(this->window), "notify::gtk-application-prefer-dark-theme", - G_CALLBACK(themeCallback), this); - - updateColorscheme(); -} - -void MainWindow::populate(GladeSearchpath* gladeSearchPath) { - - toolbar->populate(gladeSearchPath); - menubar->populate(gladeSearchPath, this); - - // need to create tool buttons registered in plugins, so they can be added to toolbars - control->registerPluginToolButtons(this->toolbar.get()); - - createToolbar(); - - setToolbarVisible(control->getSettings()->isToolbarVisible()); -} - -GMenuModel* MainWindow::getMenuModel() const { return menubar->getModel(); } - -MainWindow::~MainWindow() = default; - -struct ThemeProperties { - bool dark; - bool darkSuffix; - std::string rootname; ///< Name without any putative -dark suffix -}; -static ThemeProperties getThemeProperties(GtkWidget* w) { - xoj::util::OwnedCString name; - [[maybe_unused]] bool useEnv = false; - // Gtk prioritizes GTK_THEME over GtkSettings content - // cf https://gitlab.gnome.org/GNOME/gtk/blob/90d84a2af8b367bd5a5312b3fa3b67563462c0ef/gtk/gtksettings.c#L1567-L1622 - if (auto* p = g_getenv("GTK_THEME")) { - *(name.contentReplacer()) = g_strdup(p); - useEnv = true; - } else { - g_object_get(gtk_widget_get_settings(w), "gtk-theme-name", name.contentReplacer(), nullptr); - } - - // Try to figure out if the theme is dark or light - // Some themes handle their dark variant via "gtk-application-prefer-dark-theme" while other just append "-dark" - const std::regex nameparser("([a-zA-Z-]+?)([:-][dD]ark)?"); - std::cmatch sm; - std::regex_match(name.get(), sm, nameparser); - - ThemeProperties props; - if (sm.size() < 3) { - g_warning("Fails to extract theme root name from: \"%s\"", name.get()); - props.rootname = name.get(); - props.darkSuffix = false; - } else { - props.rootname = sm[1]; - props.darkSuffix = sm[2].length() > 0; - } - gboolean dark = false; - -#ifdef __APPLE__ - if (!useEnv) { - CFStringRef interfaceStyle = - (CFStringRef)CFPreferencesCopyAppValue(CFSTR("AppleInterfaceStyle"), kCFPreferencesCurrentApplication); - if (interfaceStyle) { - char buffer[128]; - if (CFStringGetCString(interfaceStyle, buffer, sizeof(buffer), kCFStringEncodingUTF8)) { - std::string style = buffer; - if (auto pos = style.find("Dark"); pos != std::string::npos) { - dark = true; - } - } - } - } -#else - g_object_get(gtk_widget_get_settings(w), "gtk-application-prefer-dark-theme", &dark, nullptr); -#endif - - g_debug("Extracted theme info: Name = %s, rootname = %s, dark = %s", name.get(), props.rootname.c_str(), - dark ? "true" : "false"); - - props.dark = props.darkSuffix || dark; // Some themes handle their dark variant via this setting - - return props; -} - -void MainWindow::updateColorscheme() { - g_signal_handlers_block_by_func(gtk_widget_get_settings(this->window), - reinterpret_cast(G_CALLBACK(themeCallback)), this); - auto variant = control->getSettings()->getThemeVariant(); - if (variant == THEME_VARIANT_USE_SYSTEM) { - gtk_settings_reset_property(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme"); - if (modifiedGtkSettingsTheme) { - // Some bug in Gtk makes an infinite loop despite us blocking the signals - gtk_settings_reset_property(gtk_widget_get_settings(this->window), "gtk-theme-name"); - modifiedGtkSettingsTheme = false; - } - } - auto props = getThemeProperties(this->window); - - this->darkMode = (props.dark && variant != THEME_VARIANT_FORCE_LIGHT) || variant == THEME_VARIANT_FORCE_DARK; - - // Set up icons - { - const auto uiPath = this->getGladeSearchPath()->getFirstSearchPath(); - const auto lightColorIcons = (uiPath / "iconsColor-light"); - const auto darkColorIcons = (uiPath / "iconsColor-dark"); - const auto lightLucideIcons = (uiPath / "iconsLucide-light"); - const auto darkLucideIcons = (uiPath / "iconsLucide-dark"); - - // icon load order from lowest priority to highest priority - std::vector iconLoadOrder = {}; - const auto chosenTheme = control->getSettings()->getIconTheme(); - switch (chosenTheme) { - case ICON_THEME_COLOR: - iconLoadOrder = {darkLucideIcons, lightLucideIcons, darkColorIcons, lightColorIcons}; - break; - case ICON_THEME_LUCIDE: - iconLoadOrder = {darkColorIcons, lightColorIcons, darkLucideIcons, lightLucideIcons}; - break; - default: - g_message("Unknown icon theme!"); - } - - if (this->darkMode) { - for (size_t i = 0; 2 * i + 1 < iconLoadOrder.size(); ++i) { - std::swap(iconLoadOrder[2 * i], iconLoadOrder[2 * i + 1]); - } - } - - for (auto& p: iconLoadOrder) { - gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), char_cast(p.u8string().c_str())); - } - } - - GtkStyleContext* context = gtk_widget_get_style_context(GTK_WIDGET(this->window)); - - if (this->darkMode) { - gtk_style_context_add_class(context, "darkMode"); - g_object_set(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme", true, nullptr); - } else { - gtk_style_context_remove_class(context, "darkMode"); - g_object_set(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme", false, nullptr); - if (props.darkSuffix) { // The active theme is all dark. Remove the trailing "-dark" - g_object_set(gtk_widget_get_settings(this->window), "gtk-theme-name", props.rootname.c_str(), nullptr); - modifiedGtkSettingsTheme = true; - } - } - - { - gchar* name = nullptr; - g_object_get(gtk_widget_get_settings(this->window), "gtk-theme-name", &name, nullptr); - g_debug("Theme name: %s", name); - g_debug("Modified in GtkSettings: %s", modifiedGtkSettingsTheme ? "true" : "false"); - g_free(name); - gboolean gtkdark = true; - g_object_get(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme", >kdark, nullptr); - g_debug("Theme variant: %s", gtkdark ? "dark" : "light"); - g_debug("Icon theme: %s", iconThemeToString(control->getSettings()->getIconTheme())); - } - g_signal_handlers_unblock_by_func(gtk_widget_get_settings(this->window), reinterpret_cast(themeCallback), - this); -} - -void MainWindow::initXournalWidget() { - winXournal = gtk_scrolled_window_new(); - - setGtkTouchscreenScrollingForDeviceMapping(); - - gtk_box_append(GTK_BOX(get("boxContents")), winXournal); - - GtkWidget* vpXournal = gtk_viewport_new(nullptr, nullptr); - - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(winXournal), vpXournal); - - scrollHandling = std::make_unique(GTK_SCROLLED_WINDOW(winXournal)); - - this->xournal = std::make_unique(vpXournal, control, scrollHandling.get()); - - control->getZoomControl()->initZoomHandler(this->window, winXournal, xournal.get(), control); - gtk_widget_show_all(winXournal); - - scrollHandling->init(this->xournal->getWidget(), this->xournal->getLayout()); -} - -void MainWindow::setGtkTouchscreenScrollingForDeviceMapping() { - InputDeviceClass touchscreenClass = - DeviceListHelper::getSourceMapping(GDK_SOURCE_TOUCHSCREEN, this->getControl()->getSettings()); - - setGtkTouchscreenScrollingEnabled(touchscreenClass == INPUT_DEVICE_TOUCHSCREEN && - !control->getSettings()->getTouchDrawingEnabled()); -} - -void MainWindow::setGtkTouchscreenScrollingEnabled(bool enabled) { - if (!control->getSettings()->getGtkTouchInertialScrollingEnabled()) { - enabled = false; - } - gtk_scrolled_window_set_kinetic_scrolling(GTK_SCROLLED_WINDOW(winXournal), enabled); -} - -auto MainWindow::getLayout() const -> Layout* { return this->xournal->getLayout(); } - -auto MainWindow::getNegativeXournalWidgetPos() const -> xoj::util::Point { - return Util::toWidgetCoords(this->winXournal, xoj::util::Point{0.0, 0.0}); -} - -auto cancellable_cancel(GCancellable* cancel) -> bool { - g_cancellable_cancel(cancel); - - g_warning("Timeout... Cancel loading URL"); - - return false; -} - -void MainWindow::dragDataRecived(GtkWidget* widget, GdkDragContext* dragContext, gint x, gint y, GtkSelectionData* data, - guint info, guint time, MainWindow* win) { - GtkWidget* source = gtk_drag_get_source_widget(dragContext); - if (source && widget == gtk_widget_get_toplevel(source)) { - gtk_drag_finish(dragContext, false, false, time); - return; - } - - guchar* text = gtk_selection_data_get_text(data); - if (text) { - win->control->clipboardPasteText(reinterpret_cast(text)); - - g_free(text); - gtk_drag_finish(dragContext, true, false, time); - return; - } - - xoj::util::GObjectSPtr image(gtk_selection_data_get_pixbuf(data), xoj::util::adopt); - if (image) { - win->control->clipboardPasteImage(image.get()); - - gtk_drag_finish(dragContext, true, false, time); - return; - } - - gchar** uris = gtk_selection_data_get_uris(data); - if (uris) { - for (int i = 0; uris[i] != nullptr && i < 3; i++) { - const char* uri = uris[i]; - - GCancellable* cancel = g_cancellable_new(); - auto cancelTimeout = g_timeout_add(3000, xoj::util::wrap_for_once_v, cancel); - - xoj::util::GObjectSPtr file(g_file_new_for_uri(uri), xoj::util::adopt); - GError* err = nullptr; - GFileInputStream* in = g_file_read(file.get(), cancel, &err); - if (g_cancellable_is_cancelled(cancel)) { - continue; - } - - if (err == nullptr) { - xoj::util::GObjectSPtr pixbuf( - gdk_pixbuf_new_from_stream(G_INPUT_STREAM(in), cancel, nullptr), xoj::util::adopt); - if (g_cancellable_is_cancelled(cancel)) { - continue; - } - g_input_stream_close(G_INPUT_STREAM(in), cancel, nullptr); - if (g_cancellable_is_cancelled(cancel)) { - continue; - } - - if (pixbuf) { - win->control->clipboardPasteImage(pixbuf.get()); - } - } else { - g_error_free(err); - } - - if (!g_cancellable_is_cancelled(cancel)) { - g_source_remove(cancelTimeout); - } - g_object_unref(cancel); - } - - gtk_drag_finish(dragContext, true, false, time); - - g_strfreev(uris); - } - - gtk_drag_finish(dragContext, false, false, time); -} - -auto MainWindow::getControl() const -> Control* { return control; } - -void MainWindow::updateScrollbarSidebarPosition() { - // Part 1: update scrollbar position - if (winXournal != nullptr) { - GtkScrolledWindow* scrolledWindow = GTK_SCROLLED_WINDOW(winXournal); - - ScrollbarHideType type = this->getControl()->getSettings()->getScrollbarHideType(); - - bool scrollbarOnLeft = control->getSettings()->isScrollbarOnLeft(); - if (scrollbarOnLeft) { - gtk_scrolled_window_set_placement(scrolledWindow, GTK_CORNER_TOP_RIGHT); - } else { - gtk_scrolled_window_set_placement(scrolledWindow, GTK_CORNER_TOP_LEFT); - } - - gtk_widget_set_visible(gtk_scrolled_window_get_hscrollbar(scrolledWindow), !(type & SCROLLBAR_HIDE_HORIZONTAL)); - gtk_widget_set_visible(gtk_scrolled_window_get_vscrollbar(scrolledWindow), !(type & SCROLLBAR_HIDE_VERTICAL)); - - gtk_scrolled_window_set_overlay_scrolling(scrolledWindow, - !control->getSettings()->isScrollbarFadeoutDisabled()); - } - - // Part 2: update sidebar position - GtkPaned* paned = GTK_PANED(this->panedContainerWidget.get()); - - // Allocation is reset when we switch up the contained elements. Fetch the - // width here in case we need it afterwards. - int contentWidth = gtk_widget_get_width(this->boxContainerWidget.get()); - - bool sidebarRight = control->getSettings()->isSidebarOnRight(); - if (sidebarRight != (gtk_paned_get_child2(paned) == this->sidebarWidget.get())) { - // switch sidebar and main content - GtkWidget* sidebar = this->sidebarWidget.get(); - GtkWidget* mainContent = this->sidebarVisible ? this->mainContentWidget.get() : nullptr; -#if GTK_MAJOR_VERSION == 3 - if (this->sidebarVisible) { - gtk_container_remove(GTK_CONTAINER(paned), sidebar); - gtk_container_remove(GTK_CONTAINER(paned), mainContent); - - if (sidebarRight) { - gtk_paned_pack1(paned, mainContent, true, false); - gtk_paned_pack2(paned, sidebar, false, false); - } else { - gtk_paned_pack1(paned, sidebar, false, false); - gtk_paned_pack2(paned, mainContent, true, false); - } - } else { - // The sidebar is hidden. That means the paned widget only contains the - // sidebar while the main contents are shown alone in the box container. - gtk_container_remove(GTK_CONTAINER(paned), sidebar); - - if (sidebarRight) { - gtk_paned_pack2(paned, sidebar, false, false); - } else { - gtk_paned_pack1(paned, sidebar, false, false); - } - } -#else - gtk_paned_set_start_child(paned, nullptr); - gtk_paned_set_end_child(paned, nullptr); - if (sidebarRight) { - gtk_paned_set_start_child(paned, mainContent); - gtk_paned_set_resize_start_child(paned, true); - gtk_paned_set_shrink_start_child(paned, false); - gtk_paned_set_end_child(paned, sidebar); - gtk_paned_set_resize_end_child(paned, false); - gtk_paned_set_shrink_end_child(paned, false); - } else { - gtk_paned_set_end_child(paned, mainContent); - gtk_paned_set_resize_end_child(paned, true); - gtk_paned_set_shrink_end_child(paned, false); - gtk_paned_set_start_child(paned, sidebar); - gtk_paned_set_resize_start_child(paned, false); - gtk_paned_set_shrink_start_child(paned, false); - } -#endif - } - - if (this->sidebarVisible) { - updatePanedPosition(contentWidth); - } -} - -auto MainWindow::deleteEventCallback(GtkWidget* widget, GdkEvent* event, Control* control) -> bool { - control->quit(); - - return true; -} - -void MainWindow::setSidebarVisible(bool visible) { - if (!visible && (this->control->getSidebar() != nullptr)) { - this->control->getSidebar()->saveSize(); - } - - if (visible != this->sidebarVisible) { - // Due to a GTK bug, we can't just hide the sidebar widget in the GtkPaned. - // If we do this, we create a dead region where the pane separator was previously. - // In this region, we can't use the touchscreen to start horizontal strokes. - // As such: - if (!visible) { - // hide sidebar -#if GTK_MAJOR_VERSION == 3 - gtk_container_remove(GTK_CONTAINER(panedContainerWidget.get()), mainContentWidget.get()); -#else - if (control->getSettings()->isSidebarOnRight()) { - gtk_paned_set_start_child(GTK_PANED(panedContainerWidget.get()), nullptr); - } else { - gtk_paned_set_end_child(GTK_PANED(panedContainerWidget.get()), nullptr); - } -#endif - gtk_box_remove(GTK_BOX(boxContainerWidget.get()), panedContainerWidget.get()); - gtk_box_append(GTK_BOX(boxContainerWidget.get()), mainContentWidget.get()); - this->sidebarVisible = false; - } else { - // show sidebar - - // Allocation is reset when we switch up the contained elements. Fetch the - // width here in case we need it afterwards. - int contentWidth = gtk_widget_get_width(boxContainerWidget.get()); - - gtk_box_remove(GTK_BOX(boxContainerWidget.get()), mainContentWidget.get()); - -#if GTK_MAJOR_VERSION == 3 - if (control->getSettings()->isSidebarOnRight()) { - gtk_paned_pack1(GTK_PANED(panedContainerWidget.get()), mainContentWidget.get(), true, false); - } else { - gtk_paned_pack2(GTK_PANED(panedContainerWidget.get()), mainContentWidget.get(), true, false); - } -#else - if (control->getSettings()->isSidebarOnRight()) { - gtk_paned_set_start_child(GTK_PANED(panedContainerWidget.get()), mainContentWidget.get()); - } else { - gtk_paned_set_end_child(GTK_PANED(panedContainerWidget.get()), mainContentWidget.get()); - } -#endif - - gtk_box_append(GTK_BOX(boxContainerWidget.get()), panedContainerWidget.get()); - this->sidebarVisible = true; - - updatePanedPosition(contentWidth); - } - } - - gtk_widget_set_visible(sidebarWidget.get(), visible); -} - -/** - * Invert the position of the paned widget and disconnect from the signal. - * @param handlerId should be the ID of the signal handler that should be disconnected. - */ -static void invertPanedPosition(GtkWidget* widget, GtkAllocation* allocation, gulong* handlerId) { - int newDividerPos = allocation->width - gtk_paned_get_position(GTK_PANED(widget)); - gtk_paned_set_position(GTK_PANED(widget), newDividerPos); - - // We only need to switch the position once, so disconnect the signal right away. - g_signal_handler_disconnect(widget, *handlerId); -} - -void MainWindow::updatePanedPosition(int contentWidth) { - if (!this->control->getSettings()->isSidebarOnRight()) { - // Sidebar is on the left side. - gtk_paned_set_position(GTK_PANED(this->panedContainerWidget.get()), - this->control->getSettings()->getSidebarWidth()); - } else { - // Sidebar is on the right side. - if (contentWidth > 0) { - int dividerPos = contentWidth - this->control->getSettings()->getSidebarWidth(); - gtk_paned_set_position(GTK_PANED(this->panedContainerWidget.get()), dividerPos); - } else { - // Allocation is unkown (window hasn't been shown yet). We have to wait for the signal. - // Set position as if the sidebar was on the left side, and let the signal handler - // simply invert the position when the allocation is known. - gtk_paned_set_position(GTK_PANED(this->panedContainerWidget.get()), - this->control->getSettings()->getSidebarWidth()); - gulong* signal_id = new gulong{}; - *signal_id = g_signal_connect_data( - this->panedContainerWidget.get(), "size-allocate", - xoj::util::wrap_for_g_callback_v, signal_id, - [](gpointer d, GClosure*) { delete reinterpret_cast(d); }, GConnectFlags(0)); - } - } -} - -void MainWindow::setToolbarVisible(bool visible) { - Settings* settings = control->getSettings(); - - settings->setToolbarVisible(visible); - for (auto& w: this->toolbarWidgets) { - if (!visible || (gtk_toolbar_get_n_items(GTK_TOOLBAR(w.get())) != 0)) { - gtk_widget_set_visible(w.get(), visible); - } - } -} - -void MainWindow::setMenubarVisible(bool visible) { - gtk_application_window_set_show_menubar(GTK_APPLICATION_WINDOW(this->getWindow()), visible); -} - -void MainWindow::setMaximized(bool maximized) { this->maximized = maximized; } - -auto MainWindow::isMaximized() const -> bool { return this->maximized; } - -auto MainWindow::setFullscreen(bool enabled) const -> void { - if (enabled) { - gtk_window_fullscreen(GTK_WINDOW(this->getWindow())); - } else { - gtk_window_unfullscreen(GTK_WINDOW(this->getWindow())); - } -} - -auto MainWindow::isDarkTheme() const -> bool { return this->darkMode; } - -auto MainWindow::getXournal() const -> XournalView* { return xournal.get(); } - -auto MainWindow::windowMaximizedCallback(GObject* window, GParamSpec*, MainWindow* win) -> void { - win->setMaximized(gtk_window_is_maximized(GTK_WINDOW(window))); -} - -void MainWindow::toolbarSelected(const std::string& id) { - const auto& toolbars = toolbar->getModel()->getToolbars(); - auto it = std::find_if(toolbars.begin(), toolbars.end(), [&](const auto& d) { return d->getId() == id; }); - toolbarSelected(it == toolbars.end() ? nullptr : it->get()); -} - -void MainWindow::toolbarSelected(ToolbarData* d) { - if (!d || this->selectedToolbar == d) { - return; - } - - Settings* settings = control->getSettings(); - settings->setSelectedToolbar(d->getId()); - - this->clearToolbar(); - this->loadToolbar(d); -} - -auto MainWindow::clearToolbar() -> const ToolbarData* { - if (this->selectedToolbar != nullptr) { - for (size_t i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) { - ToolMenuHandler::unloadToolbar(this->toolbarWidgets[i].get()); - } - - this->toolbar->freeDynamicToolbarItems(); - } - return std::exchange(this->selectedToolbar, nullptr); -} - -void MainWindow::loadToolbar(ToolbarData* d) { - this->selectedToolbar = d; - - for (size_t i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) { - this->toolbar->load(d, this->toolbarWidgets[i].get(), TOOLBAR_DEFINITIONS[i].propName, - TOOLBAR_DEFINITIONS[i].horizontal); - } - - this->floatingToolbox->flagRecalculateSizeRequired(); -} - -void MainWindow::reloadToolbars() { - ToolbarData* d = getSelectedToolbar(); - this->clearToolbar(); - this->toolbarSelected(d); -} - -auto MainWindow::getSelectedToolbar() const -> ToolbarData* { return this->selectedToolbar; } - -auto MainWindow::getToolbarWidgets() const -> const ToolbarWidgetArray& { return toolbarWidgets; } - -auto MainWindow::getToolbarName(GtkToolbar* toolbar) const -> const char* { - for (size_t i = 0; i < TOOLBAR_DEFINITIONS_LEN; i++) { - if (static_cast(this->toolbarWidgets[i].get()) == static_cast(toolbar)) { - return TOOLBAR_DEFINITIONS[i].propName; - } - } - - return ""; -} - -void MainWindow::setDynamicallyGeneratedSubmenuDisabled(bool disabled) { menubar->setDisabled(disabled); } - -void MainWindow::updateToolbarMenu() { - menubar->getToolbarSelectionSubmenu().update(toolbar.get(), this->selectedToolbar); -} - -void MainWindow::createToolbar() { - toolbarSelected(control->getSettings()->getSelectedToolbar()); - - this->control->getScheduler()->unblockRerenderZoom(); -} - -void MainWindow::updatePageNumbers(size_t page, size_t pagecount, size_t pdfpage) { - toolbar->setPageInfo(page, pagecount, pdfpage); -} - -auto MainWindow::getMenubar() const -> Menubar* { return menubar.get(); } - -void MainWindow::show(GtkWindow* parent) { gtk_widget_show(this->window); } - -void MainWindow::setUndoDescription(const string& description) { menubar->setUndoDescription(description); } - -void MainWindow::setRedoDescription(const string& description) { menubar->setRedoDescription(description); } - -auto MainWindow::getToolbarModel() const -> ToolbarModel* { return this->toolbar->getModel(); } - -auto MainWindow::getToolMenuHandler() const -> ToolMenuHandler* { return this->toolbar.get(); } - -void MainWindow::loadMainCSS(GladeSearchpath* gladeSearchPath, const gchar* cssFilename) { - auto filepath = gladeSearchPath->findFile("", cssFilename); - xoj::util::GObjectSPtr provider(gtk_css_provider_new(), xoj::util::adopt); - gtk_css_provider_load_from_path(provider.get(), char_cast(filepath.u8string().c_str()), nullptr); - gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider.get()), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); -} - -PdfFloatingToolbox* MainWindow::getPdfToolbox() const { return this->pdfFloatingToolBox.get(); } - -FloatingToolbox* MainWindow::getFloatingToolbox() const { return this->floatingToolbox.get(); } - -void MainWindow::setDPI() const { - if (auto dpi = this->getControl()->getSettings()->getDisplayDpi(); dpi == -1) { - auto res = xoj::util::gtk::getWidgetDPI(this->window); - this->getControl()->getZoomControl()->setZoom100Value(res.value_or(Util::DPI_NORMALIZATION_FACTOR) / - Util::DPI_NORMALIZATION_FACTOR); - } else { - this->getControl()->getZoomControl()->setZoom100Value(dpi / Util::DPI_NORMALIZATION_FACTOR); - } -} diff --git a/entry/src/main/cpp/src/core/gui/MainWindow.h b/entry/src/main/cpp/src/core/gui/MainWindow.h deleted file mode 100644 index 6e5df4e..0000000 --- a/entry/src/main/cpp/src/core/gui/MainWindow.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Xournal++ - * - * The Main window - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for array -#include // for atomic_bool -#include // for size_t -#include // for unique_ptr -#include // for string - -#include // for GdkDragContext, GdkEvent -#include // for GClosure -#include // for gpointer, gboolean, gint -#include // for GtkWidget, GtkCheckMenu... - -#include "util/Point.h" -#include "util/raii/GObjectSPtr.h" - -#include "GladeGui.h" // for GladeGui -#include "ToolbarDefinitions.h" // for TOOLBAR_DEFINITIONS_LEN - -class Control; -class Layout; -class SpinPageAdapter; -class ScrollHandling; -class ToolMenuHandler; -class ToolbarData; -class ToolbarModel; -class XournalView; -class PdfFloatingToolbox; -class FloatingToolbox; -class GladeSearchpath; - -class Menubar; - -typedef std::array ToolbarWidgetArray; - -class MainWindow: public GladeGui { -public: - MainWindow(GladeSearchpath* gladeSearchPath, Control* control, GtkApplication* parent); - ~MainWindow() override; - - void populate(GladeSearchpath* gladeSearchPath); - -public: - GMenuModel* getMenuModel() const; - - void show(GtkWindow* parent) override; - - void toolbarSelected(const std::string& id); - void toolbarSelected(ToolbarData* d); - ToolbarData* getSelectedToolbar() const; - -private: - const ToolbarData* clearToolbar(); - void loadToolbar(ToolbarData* d); - -public: - /** - * reloadToolbars reloads the currently selected toolbar - * - * This is especially useful when a change in the SettingsDialog should be reflected right away - */ - void reloadToolbars(); - - void updatePageNumbers(size_t page, size_t pagecount, size_t pdfpage); - - void setMaximized(bool maximized); - bool isMaximized() const; - - void setFullscreen(bool enabled) const; - - bool isDarkTheme() const; - - XournalView* getXournal() const; - - void setMenubarVisible(bool visible); - void setSidebarVisible(bool visible); - void setToolbarVisible(bool visible); - - Control* getControl() const; - - PdfFloatingToolbox* getPdfToolbox() const; - FloatingToolbox* getFloatingToolbox() const; - - void updateScrollbarSidebarPosition(); - - void setUndoDescription(const std::string& description); - void setRedoDescription(const std::string& description); - - ToolbarModel* getToolbarModel() const; - ToolMenuHandler* getToolMenuHandler() const; - - void setDynamicallyGeneratedSubmenuDisabled(bool disabled); - - void updateToolbarMenu(); - void updateColorscheme(); - - const ToolbarWidgetArray& getToolbarWidgets() const; - const char* getToolbarName(GtkToolbar* toolbar) const; - - Layout* getLayout() const; - - [[maybe_unused]] Menubar* getMenubar() const; - - /** - * Get the position of the top left corner of screen (X11) or the window (Wayland) - * relative to the Xournal Widget top left corner - * - * @see Util::toWidgetCoords() - */ - xoj::util::Point getNegativeXournalWidgetPos() const; - - /** - * Disable kinetic scrolling if there is a touchscreen device that was manually mapped to another enabled input - * device class. This is required so the GtkScrolledWindow does not swallow all the events. - */ - void setGtkTouchscreenScrollingForDeviceMapping(); - void setGtkTouchscreenScrollingEnabled(bool enabled); - - /// Infer the window's DPI from available monitor info and use it to set the default zoom value. - void setDPI() const; - -private: - void initXournalWidget(); - - void createToolbar(); - - /** - * Update the position of the separator in the paned container, adjusting it to the saved sidebar width. - * @param contentWidth should be the width of the paned container. The caller should retrieve the width - * of the container before any modifications to it, as that will reset its allocation. - */ - void updatePanedPosition(int contentWidth); - - /** - * Window close Button is pressed - */ - static bool deleteEventCallback(GtkWidget* widget, GdkEvent* event, Control* control); - - /** - * Window is maximized/minimized - */ - static void windowMaximizedCallback(GObject* window, GParamSpec*, MainWindow* win); - - /** - * Callback for drag & drop files - */ - static void dragDataRecived(GtkWidget* widget, GdkDragContext* dragContext, gint x, gint y, GtkSelectionData* data, - guint info, guint time, MainWindow* win); - - /** - * Load Overall CSS file with custom icons, other styling and potentially, user changes - */ - static void loadMainCSS(GladeSearchpath* gladeSearchPath, const gchar* cssFilename); - -private: - Control* control; - - std::unique_ptr xournal; - GtkWidget* winXournal = nullptr; - std::unique_ptr scrollHandling; - - std::atomic_bool gtkTouchscreenScrollingEnabled{true}; - - std::unique_ptr pdfFloatingToolBox; - std::unique_ptr floatingToolbox; - - // Toolbars - std::unique_ptr toolbar; - ToolbarData* selectedToolbar = nullptr; - - std::unique_ptr menubar; - - bool maximized = false; - bool darkMode = false; - bool modifiedGtkSettingsTheme = false; - - ToolbarWidgetArray toolbarWidgets; - - bool sidebarVisible = true; - - xoj::util::WidgetSPtr boxContainerWidget; - xoj::util::WidgetSPtr panedContainerWidget; - xoj::util::WidgetSPtr mainContentWidget; - xoj::util::WidgetSPtr sidebarWidget; -}; diff --git a/entry/src/main/cpp/src/core/gui/PagePreviewDecoration.cpp b/entry/src/main/cpp/src/core/gui/PagePreviewDecoration.cpp deleted file mode 100644 index 06ce2d6..0000000 --- a/entry/src/main/cpp/src/core/gui/PagePreviewDecoration.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "PagePreviewDecoration.h" - -#include - -#include "control/Control.h" -#include "control/settings/Settings.h" -#include "gui/MainWindow.h" -#include "util/raii/CairoWrappers.h" - -void PagePreviewDecoration::drawDecoration(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, Control* control) { - switch (control->getSettings()->getSidebarNumberingStyle()) { - case SidebarNumberingStyle::NUMBER_BELOW_PREVIEW: - PagePreviewDecoration::drawPageNumberBelowPreview(cr, pageEntry, control); - break; - case SidebarNumberingStyle::NUMBER_WITH_CIRCULAR_BACKGROUND: - PagePreviewDecoration::drawPageNumberWithCircleBackground(cr, pageEntry, control); - break; - case SidebarNumberingStyle::NUMBER_WITH_SQUARE_BACKGROUND: - PagePreviewDecoration::drawPageNumberWithSquareBackground(cr, pageEntry, control); - break; - default: - break; - } -} - -void PagePreviewDecoration::drawPageNumberBelowPreview(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, - Control* control) { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_text_extents_t extents; - std::string pageNumber = std::to_string(pageEntry->getIndex() + 1); - Color color = control->getWindow()->isDarkTheme() ? Colors::white : Colors::xopp_darkslategray; - if (pageEntry->isSelected()) { - color = control->getSettings()->getBorderColor(); - } - Util::cairo_set_source_rgbi(cr, color); - cairo_select_font_face(cr, FONT_NAME, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, FONT_SIZE); - cairo_text_extents(cr, pageNumber.c_str(), &extents); - double x = pageEntry->getWidth() / 2 - (extents.width / 2 + extents.x_bearing); - double y = pageEntry->getHeight() - MARGIN_BOTTOM - (extents.height / 2 + extents.y_bearing); - cairo_move_to(cr, x, y); - cairo_show_text(cr, pageNumber.c_str()); -} - -void PagePreviewDecoration::drawPageNumberWithCircleBackground(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, - Control* control) { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_text_extents_t extents; - std::string pageNumber = std::to_string(pageEntry->getIndex() + 1); - cairo_select_font_face(cr, FONT_NAME, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, FONT_SIZE); - cairo_text_extents(cr, pageNumber.c_str(), &extents); - - // Set the color for drawing the circle. This circle is required to provide good contrast for the page number. - if (pageEntry->isSelected()) { - Color color = control->getSettings()->getBorderColor(); - Util::cairo_set_source_rgbi(cr, color, CIRCLE_LABEL_OPACITY); - } else { - Util::cairo_set_source_rgbi(cr, Colors::xopp_darkslategray, CIRCLE_LABEL_OPACITY); - } - - // How many pixels to indent the circle center from the widget border - double indentRight = pageEntry->getWidth() * CIRCLE_INDENT_RIGHT; - double indentBottom = pageEntry->getHeight() * CIRCLE_INDENT_BOTTOM; - - // Pixel position of circle center - double x = pageEntry->getWidth() - indentRight; - double y = pageEntry->getHeight() - indentBottom; - - // Inner circle width depends on the actual text width - double addititionalWidth = std::max((extents.width - 2 * CIRCLE_RADIUS) + CIRCLE_TEXT_PADDING, 0.0); - - // Draw an slightly transparent circle in the lower right corner of the preview - cairo_set_line_width(cr, LINE_WIDTH); - cairo_arc(cr, x - addititionalWidth, y, CIRCLE_RADIUS, M_PI * 0.5, M_PI * 1.5); - cairo_arc(cr, x, y, CIRCLE_RADIUS, M_PI * 1.5, M_PI * 0.5); - cairo_close_path(cr); - cairo_stroke_preserve(cr); - cairo_fill(cr); - - // Draw the page number in the center of the previously drawn circle - cairo_move_to(cr, x - addititionalWidth / 2 - (extents.width / 2 + extents.x_bearing), y + CIRCLE_TEXT_Y); - Util::cairo_set_source_argb(cr, Colors::white); - cairo_show_text(cr, pageNumber.c_str()); -} - -void PagePreviewDecoration::drawPageNumberWithSquareBackground(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, - Control* control) { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_text_extents_t extents; - std::string pageNumber = std::to_string(pageEntry->getIndex() + 1); - cairo_select_font_face(cr, FONT_NAME, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, FONT_SIZE); - cairo_text_extents(cr, pageNumber.c_str(), &extents); - - // Select the color for painting the square background - if (pageEntry->isSelected()) { - Util::cairo_set_source_rgbi(cr, control->getSettings()->getBorderColor()); - } else { - Util::cairo_set_source_rgbi(cr, Colors::xopp_darkslategray); - - // In case the page is not selected draw a border around the preview to match the selected - // See discussion: - cairo_set_line_width(cr, PREVIEW_BORDER_LINE_WIDTH); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); - cairo_rectangle(cr, PREVIEW_UPPER_LEFT, PREVIEW_UPPER_LEFT, pageEntry->getWidth() - PREVIEW_WIDTH_INDENT, - pageEntry->getHeight() - PREVIEW_HEIGHT_INDENT); - cairo_stroke(cr); - } - - // Calculate the rectangle width depending on the page index number of digits - double recWidth = std::max(extents.width + 8, SQUARE_SIZE); - - // Calculate the position of the upper left corner of the square - double x = pageEntry->getWidth() - SQUARE_INDENT_RIGHT - recWidth; - double y = pageEntry->getHeight() - SQUARE_INDENT_BOTTOM - SQUARE_SIZE; - - // Draw an square in the lower right corner - cairo_set_line_width(cr, LINE_WIDTH); - cairo_rectangle(cr, x, y, recWidth, SQUARE_SIZE); - cairo_stroke_preserve(cr); - cairo_fill(cr); - - // Draw the page number in the center of the square - cairo_move_to(cr, x + recWidth / 2 - (extents.width / 2 + extents.x_bearing), y + SQUARE_TEXT_Y); - Util::cairo_set_source_argb(cr, Colors::white); - cairo_show_text(cr, pageNumber.c_str()); -} diff --git a/entry/src/main/cpp/src/core/gui/PagePreviewDecoration.h b/entry/src/main/cpp/src/core/gui/PagePreviewDecoration.h deleted file mode 100644 index 3b3bbaa..0000000 --- a/entry/src/main/cpp/src/core/gui/PagePreviewDecoration.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Xournal++ - * - * Settings Dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_surface_t, cairo_t - -#include "sidebar/previews/page/SidebarPreviewPageEntry.h" - -class Control; - -class PagePreviewDecoration { -public: - static void drawDecoration(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, Control* control); - -private: - static void drawPageNumberBelowPreview(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, Control* control); - static void drawPageNumberWithCircleBackground(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, Control* control); - static void drawPageNumberWithSquareBackground(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, Control* control); - -public: - /* For the style with the page numbers below the preview the widget height has to be extended by this amount */ - static constexpr int MARGIN_BOTTOM = 20; - -private: - /* The font sized used for drawing the page number*/ - static constexpr double FONT_SIZE = 16.0; - - /* Line width for drawing the circle and the square background*/ - static constexpr double LINE_WIDTH = 1.0; - - /* Indention of the circle from the right border as percentage to the total widget width */ - static constexpr double CIRCLE_INDENT_RIGHT = 0.28; - /* Indention of the circle from the bottom border as percentage to the total widget height */ - static constexpr double CIRCLE_INDENT_BOTTOM = 0.2; - /* Transparency value for the circle background */ - static constexpr double CIRCLE_LABEL_OPACITY = 0.6; - /* Circle radius in pixels */ - static constexpr double CIRCLE_RADIUS = 11; - /* Vertical alignment of page number to circle center */ - static constexpr double CIRCLE_TEXT_Y = 6; - /* Padding for the text in the circle */ - static constexpr double CIRCLE_TEXT_PADDING = 8; - - /* Height and minimum width of background square in pixels */ - static constexpr double SQUARE_SIZE = 20; - /* Pixel-Distance form widgets right border to previews right border */ - static constexpr double SQUARE_INDENT_RIGHT = 12; - /* Pixel-Distance from widgets bottom border to previews bottom border */ - static constexpr double SQUARE_INDENT_BOTTOM = 12; - /* Vertical alignment of the page number in the square */ - static constexpr double SQUARE_TEXT_Y = 16; - /* Padding for the text in the circle, to be applied on both sides*/ - static constexpr double SQUARE_TEXT_PADDING = 4; - - static constexpr double PREVIEW_BORDER_LINE_WIDTH = 2.0; - static constexpr double PREVIEW_UPPER_LEFT = 8.5; - static constexpr double PREVIEW_WIDTH_INDENT = 21; - static constexpr double PREVIEW_HEIGHT_INDENT = 21; - - static constexpr char FONT_NAME[] = "Sans"; -}; diff --git a/entry/src/main/cpp/src/core/gui/PageView.cpp b/entry/src/main/cpp/src/core/gui/PageView.cpp deleted file mode 100644 index 2754261..0000000 --- a/entry/src/main/cpp/src/core/gui/PageView.cpp +++ /dev/null @@ -1,1205 +0,0 @@ -#include "PageView.h" - -#include // for max, find_if -#include // for int64_t -#include // for int64_t -#include // for size_t -#include // for operator<<, quoted -#include // for unique_ptr, make_... -#include // for optional -#include // for operator<<, basic... -#include // for tuple, tie -#include // for move - -#include // for GdkRectangle, Gdk... -#include // for GDK_KEY_Escape -#include // for G_CALLBACK, g_sig... -#include // for gint, g_free, g_g... -#include // for GtkWidget, gtk_co... - -#include "control/AudioController.h" // for AudioController -#include "control/Control.h" // for Control -#include "control/ScrollHandler.h" // for ScrollHandler -#include "control/SearchControl.h" // for SearchControl -#include "control/Tool.h" // for Tool -#include "control/ToolEnums.h" // for DRAWING_TYPE_SPLINE -#include "control/ToolHandler.h" // for ToolHandler -#include "control/jobs/XournalScheduler.h" // for XournalScheduler -#include "control/layer/LayerController.h" // for LayerControl -#include "control/settings/Settings.h" // for Settings -#include "control/tools/ArrowHandler.h" // for ArrowHandler -#include "control/tools/CoordinateSystemHandler.h" // for CoordinateSystemH... -#include "control/tools/EditSelection.h" // for EditSelection -#include "control/tools/EllipseHandler.h" // for EllipseHandler -#include "control/tools/EraseHandler.h" // for EraseHandler -#include "control/tools/ImageHandler.h" // for ImageHandler -#include "control/tools/ImageSizeSelection.h" // for ImageSizeSelection -#include "control/tools/InputHandler.h" // for InputHandler -#include "control/tools/LaserPointerHandler.h" // for LaserPointerHandler -#include "control/tools/PdfElemSelection.h" // for PdfElemSelection -#include "control/tools/RectangleHandler.h" // for RectangleHandler -#include "control/tools/RulerHandler.h" // for RulerHandler -#include "control/tools/Selector.h" // for RectangularSelector -#include "control/tools/SplineHandler.h" // for SplineHandler -#include "control/tools/StrokeHandler.h" // for StrokeHandler -#include "control/tools/TextEditor.h" // for TextEditor, TextE... -#include "control/tools/VerticalToolHandler.h" // for VerticalToolHandler -#include "gui/FloatingToolbox.h" // for FloatingToolbox -#include "gui/MainWindow.h" // for MainWindow -#include "gui/PdfFloatingToolbox.h" // for PdfFloatingToolbox -#include "gui/SearchBar.h" // for SearchBar -#include "gui/inputdevices/PositionInputData.h" // for PositionInputData -#include "model/Document.h" // for Document -#include "model/Element.h" // for Element, ELEMENT_... -#include "model/Layer.h" // for Layer, Layer::Index -#include "model/LinkDestination.h" // for LinkDestination -#include "model/PageRef.h" // for PageRef -#include "model/Stroke.h" // for Stroke -#include "model/TexImage.h" // for TexImage -#include "model/Text.h" // for Text -#include "model/XojPage.h" // for XojPage -#include "pdf/base/XojPdfAction.h" // for XojPdfAction -#include "pdf/base/XojPdfDocument.h" // for XojPdfDocument -#include "pdf/base/XojPdfPage.h" // for XojPdfRectangle -#include "undo/DeleteUndoAction.h" // for DeleteUndoAction -#include "undo/InsertUndoAction.h" // for InsertUndoAction -#include "undo/MoveUndoAction.h" // for MoveUndoAction -#include "undo/TextBoxUndoAction.h" // for TextBoxUndoAction -#include "undo/UndoRedoHandler.h" // for UndoRedoHandler -#include "util/Assert.h" // for xoj_assert -#include "util/Color.h" // for rgb_to_GdkRGBA -#include "util/Range.h" // for Range -#include "util/Rectangle.h" // for Rectangle -#include "util/Util.h" // for npos -#include "util/XojMsgBox.h" // for XojMsgBox -#include "util/gtk4_helper.h" // for gtk_box_append -#include "util/i18n.h" // for _F, FC, FS, _ -#include "util/raii/CLibrariesSPtr.h" // for adopt -#include "util/safe_casts.h" // for ceil_cast, floor_cast, round_cast -#include "util/serdesstream.h" // for serdes_stream -#include "view/DebugShowRepaintBounds.h" // for IF_DEBUG_REPAINT -#include "view/overlays/OverlayView.h" // for OverlayView, Tool... -#include "view/overlays/PdfElementSelectionView.h" // for PdfElementSelecti... -#include "view/overlays/SearchResultView.h" // for SearchResultView -#include "view/overlays/SelectorView.h" // for SelectionView -#include "view/overlays/TextEditionView.h" // for TextEditionView - -#include "PageViewFindObjectHelper.h" // for SelectObject, Pla... -#include "RepaintHandler.h" // for RepaintHandler -#include "XournalView.h" // for XournalView -#include "XournalppCursor.h" // for XournalppCursor -#include "filesystem.h" // for path - -class OverlayBase; - -using std::string; -using xoj::util::Rectangle; - -XojPageView::XojPageView(XournalView* xournal, const PageRef& page): - page(page), - xournal(xournal), - settings(xournal->getControl()->getSettings()), - eraser(std::make_unique(xournal->getControl()->getUndoRedoHandler(), - xournal->getControl()->getDocument(), this->page, - xournal->getControl()->getToolHandler(), this)), - oldtext(nullptr) { - this->registerToHandler(this->page); -} - -XojPageView::~XojPageView() { - this->unregisterFromHandler(); - - this->xournal->getControl()->getScheduler()->removePage(this); - - this->overlayViews.clear(); - endText(); - deleteViewBuffer(); // Ensures the mutex is locked during the buffer's destruction -} - -void XojPageView::addOverlayView(std::unique_ptr overlay) { - this->overlayViews.emplace_back(std::move(overlay)); -} - -void XojPageView::setIsVisible(bool visible) { this->visible = visible; } - -void XojPageView::deleteViewBuffer() { - std::lock_guard lock(this->drawingMutex); - this->buffer.reset(); -} - -auto XojPageView::containsPoint(int x, int y, bool local) const -> bool { - if (!local) { - bool leftOk = this->getX() <= x; - bool rightOk = x <= this->getX() + this->getDisplayWidth(); - bool topOk = this->getY() <= y; - bool bottomOk = y <= this->getY() + this->getDisplayHeight(); - - return leftOk && rightOk && topOk && bottomOk; - } - - - return x >= 0 && y >= 0 && x <= this->getWidth() && y <= this->getHeight(); -} - -auto XojPageView::searchTextOnPage(const std::string& text, size_t index, size_t* occurrences, - XojPdfRectangle* matchRect) -> bool { - if (!this->search) { - if (text.empty()) { - return true; - } - - auto pNr = this->page->getPdfPageNr(); - XojPdfPageSPtr pdf = nullptr; - if (pNr != npos) { - Document* doc = xournal->getControl()->getDocument(); - - doc->lock_shared(); - pdf = doc->getPdfPage(pNr); - doc->unlock_shared(); - } - this->search = std::make_unique(page, pdf); - this->overlayViews.emplace_back(std::make_unique( - this->search.get(), this, settings->getSelectionColor(), settings->getActiveSelectionColor())); - } - - bool found = this->search->search(text, index, occurrences, matchRect); - - repaintPage(); - - return found; -} - -void XojPageView::endText() { this->textEditor.reset(); } - -void XojPageView::startText(double x, double y) { - this->xournal->endTextAllPages(this); - this->xournal->getControl()->getSearchBar()->showSearchBar(false); - - if (this->textEditor != nullptr) { - const Text* text = this->textEditor->getTextElement(); - GdkRectangle matchRect = {gint(x), gint(y), 1, 1}; - if (!text->intersectsArea(&matchRect)) { - endText(); - } else { - this->textEditor->mousePressed(x - text->getX(), y - text->getY()); - } - } - - if (this->textEditor == nullptr) { - this->textEditor = std::make_unique(xournal->getControl(), page, xournal->getWidget(), x, y); - this->overlayViews.emplace_back(std::make_unique(this->textEditor.get(), this)); - } -} - -#ifndef NDEBUG -// used in xoj_assert() -[[maybe_unused]] static bool hasNoViewOf(const std::vector>& views, - const OverlayBase* o) { - return std::find_if(views.begin(), views.end(), [o](auto& v) { return v->isViewOf(o); }) == views.end(); -} -#endif - -static void eraseViewsOf(std::vector>& views, const OverlayBase* o) { - views.erase(std::remove_if(views.begin(), views.end(), [o](auto& v) { return v->isViewOf(o); }), views.end()); - xoj_assert(hasNoViewOf(views, o)); -} - -void XojPageView::endSpline() { - if (SplineHandler* h = dynamic_cast(this->inputHandler.get()); h) { - h->finalizeSpline(); - xoj_assert(hasNoViewOf(overlayViews, inputHandler.get())); - this->inputHandler.reset(); - } -} - -void XojPageView::deleteLaserPointerHandler() { - xoj_assert(hasNoViewOf(overlayViews, laserPointer.get())); - laserPointer.reset(); -} - -auto XojPageView::onButtonPressEvent(const PositionInputData& pos) -> bool { - if (currentSequenceDeviceId) { - // An input sequence is already under way from another device - return false; - } - currentSequenceDeviceId = pos.deviceId; - - Control* control = xournal->getControl(); - - if (!this->selected) { - control->firePageSelected(this->page); - } - - ToolHandler* h = control->getToolHandler(); - - double x = pos.x; - double y = pos.y; - - if (x < 0 || y < 0) { - return false; - } - - double zoom = xournal->getZoom(); - x /= zoom; - y /= zoom; - - XournalppCursor* cursor = xournal->getCursor(); - cursor->setMouseDown(true); - - if (((h->getToolType() == TOOL_PEN || h->getToolType() == TOOL_HIGHLIGHTER) && - h->getDrawingType() != DRAWING_TYPE_SPLINE) || - (h->getToolType() == TOOL_ERASER && h->getEraserType() == ERASER_TYPE_WHITEOUT)) { - - if (this->inputHandler) { - /** - * Due to https://github.com/xournalpp/xournalpp/issues/4377 - * some devices under some configurations can start an action while another one has already started - * This is a workaround to avoid mem leaks and segfaults - * This `if` statement can probably be replaced by an `assert` once #4377 is fixed - */ - g_warning("InputHandler already exists upon XojPageView::onButtonPressEvent. Deleting it (and its views)"); - eraseViewsOf(this->overlayViews, this->inputHandler.get()); - this->inputHandler.reset(); - } - - Control* control = this->xournal->getControl(); - switch (h->getDrawingType()) { - case DRAWING_TYPE_LINE: - this->inputHandler = std::make_unique(control, getPage()); - break; - case DRAWING_TYPE_RECTANGLE: - this->inputHandler = std::make_unique(control, getPage()); - break; - case DRAWING_TYPE_ELLIPSE: - this->inputHandler = std::make_unique(control, getPage()); - break; - case DRAWING_TYPE_ARROW: - this->inputHandler = std::make_unique(control, getPage(), false); - break; - case DRAWING_TYPE_DOUBLE_ARROW: - this->inputHandler = std::make_unique(control, getPage(), true); - break; - case DRAWING_TYPE_COORDINATE_SYSTEM: - this->inputHandler = std::make_unique(control, getPage()); - break; - default: - this->inputHandler = std::make_unique(control, getPage()); - } - this->inputHandler->onButtonPressEvent(pos, zoom); - this->overlayViews.emplace_back(this->inputHandler->createView(this)); - - } else if ((h->getToolType() == TOOL_PEN || h->getToolType() == TOOL_HIGHLIGHTER) && - h->getDrawingType() == DRAWING_TYPE_SPLINE) { - if (!this->inputHandler) { - this->inputHandler = std::make_unique(this->xournal->getControl(), getPage()); - this->inputHandler->onButtonPressEvent(pos, zoom); - this->overlayViews.emplace_back(this->inputHandler->createView(this)); - } else { - this->inputHandler->onButtonPressEvent(pos, zoom); - } - } else if (h->getToolType() == TOOL_ERASER) { - this->eraser->erase(x, y); - this->inEraser = true; - } else if (h->getToolType() == TOOL_LASER_POINTER_PEN || h->getToolType() == TOOL_LASER_POINTER_HIGHLIGHTER) { - if (!this->laserPointer) { - this->laserPointer = std::make_unique(this, control, getPage()); - this->laserPointer->onButtonPressEvent(pos, zoom); - this->overlayViews.emplace_back(this->laserPointer->createView(this)); - } else { - this->laserPointer->onButtonPressEvent(pos, zoom); - } - } else if (h->getToolType() == TOOL_VERTICAL_SPACE) { - if (this->verticalSpace) { - control->getUndoRedoHandler()->addUndoAction(this->verticalSpace->finalize()); - this->verticalSpace.reset(); - } - auto* zoomControl = this->getXournal()->getControl()->getZoomControl(); - this->verticalSpace = std::make_unique(this->page, this->getXournal()->getControl(), y, - pos.isControlDown()); - this->overlayViews.emplace_back(this->verticalSpace->createView(this, zoomControl, this->settings)); - } else if (h->getToolType() == TOOL_SELECT_RECT || h->getToolType() == TOOL_SELECT_REGION || - h->getToolType() == TOOL_SELECT_MULTILAYER_RECT || h->getToolType() == TOOL_SELECT_MULTILAYER_REGION || - h->getToolType() == TOOL_PLAY_OBJECT || h->getToolType() == TOOL_SELECT_OBJECT || - h->getToolType() == TOOL_SELECT_PDF_TEXT_LINEAR || h->getToolType() == TOOL_SELECT_PDF_TEXT_RECT) { - if (h->getToolType() == TOOL_SELECT_RECT) { - if (!selector) { - this->selector = std::make_unique(x, y); - this->overlayViews.emplace_back(std::make_unique( - this->selector.get(), this, this->settings->getSelectionColor())); - } else { - xoj_assert_message( - settings->getInputSystemTPCButtonEnabled(), - "the selection has already been created by a stylus button press while the stylus was " - "hovering!"); - } - } else if (h->getToolType() == TOOL_SELECT_REGION) { - if (!selector) { - this->selector = std::make_unique(x, y); - this->overlayViews.emplace_back(std::make_unique( - this->selector.get(), this, this->settings->getSelectionColor())); - } else { - xoj_assert_message( - settings->getInputSystemTPCButtonEnabled(), - "the selection has already been created by a stylus button press while the stylus was " - "hovering!"); - } - } else if (h->getToolType() == TOOL_SELECT_MULTILAYER_RECT) { - if (!selector) { - this->selector = std::make_unique(x, y, /*multiLayer*/ true); - this->overlayViews.emplace_back(std::make_unique( - this->selector.get(), this, this->settings->getSelectionColor())); - } else { - xoj_assert_message( - settings->getInputSystemTPCButtonEnabled(), - "the selection has already been created by a stylus button press while the stylus was " - "hovering!"); - } - } else if (h->getToolType() == TOOL_SELECT_MULTILAYER_REGION) { - if (!selector) { - this->selector = std::make_unique(x, y, /*multiLayer*/ true); - this->overlayViews.emplace_back(std::make_unique( - this->selector.get(), this, this->settings->getSelectionColor())); - } else { - xoj_assert_message( - settings->getInputSystemTPCButtonEnabled(), - "the selection has already been created by a stylus button press while the stylus was " - "hovering!"); - } - } else if (h->getToolType() == TOOL_SELECT_PDF_TEXT_LINEAR || h->getToolType() == TOOL_SELECT_PDF_TEXT_RECT) { - // so if we selected something && the pdf selection toolbox is hidden && we hit within the selection - // we could call the pdf floating toolbox again - auto* pdfToolbox = control->getWindow()->getPdfToolbox(); - - if (pdfToolbox->hasSelection()) { - bool isPdfToolboxHidden = pdfToolbox->isHidden(); - bool keepOldSelection = isPdfToolboxHidden && pdfToolbox->getSelection()->contains(x, y); - if (!keepOldSelection) { - pdfToolbox->userCancelSelection(); - repaintPage(); - } else { - showPdfToolbox(pos); - } - } - - if (this->page->getPdfPageNr() != npos && !pdfToolbox->hasSelection()) { - pdfToolbox->selectionStyle = PdfElemSelection::selectionStyleForToolType(h->getToolType()); - auto sel = pdfToolbox->newSelection(x, y); - this->overlayViews.emplace_back( - std::make_unique(sel, this, settings->getSelectionColor())); - } - } else if (h->getToolType() == TOOL_SELECT_OBJECT) { - SelectObject select(this); - if (pos.isShiftDown() && xournal->getSelection()) { - select.atAggregate(x, y); - } else { - select.at(x, y); - } - } else if (h->getToolType() == TOOL_PLAY_OBJECT) { - PlayObject play(this); - play.at(x, y); - if (play.playbackStatus) { - auto& status = *play.playbackStatus; - if (!status.success) { - string message = FS(_F("Unable to play audio recording {1}") % status.filename.u8string()); - XojMsgBox::showErrorToUser(this->xournal->getControl()->getGtkWindow(), message); - } - } - } - } else if (h->getToolType() == TOOL_TEXT) { - startText(x, y); - } else if (h->getToolType() == TOOL_IMAGE) { - // start selecting the size for the image - this->imageSizeSelection = std::make_unique(x, y); - this->overlayViews.emplace_back(std::make_unique( - this->imageSizeSelection.get(), this, settings->getSelectionColor())); - } - - this->onButtonClickEvent(pos); - - return true; -} - -auto XojPageView::onButtonClickEvent(const PositionInputData& pos) -> bool { - Control* control = xournal->getControl(); - double x = pos.x; - double y = pos.y; - - if (x < 0 || y < 0) { - return false; - } - - ToolHandler* h = control->getToolHandler(); - - if (h->getToolType() == TOOL_FLOATING_TOOLBOX) { - this->showFloatingToolbox(pos); - } - - return true; -} - -auto XojPageView::onButtonDoublePressEvent(const PositionInputData& pos) -> bool { - // This method assumes that it is called after onButtonPressEvent but before - // onButtonReleaseEvent - double zoom = this->xournal->getZoom(); - double x = pos.x / zoom; - double y = pos.y / zoom; - if (x < 0 || y < 0) { - return false; - } - - ToolHandler* toolHandler = this->xournal->getControl()->getToolHandler(); - ToolType toolType = toolHandler->getToolType(); - DrawingType drawingType = toolHandler->getDrawingType(); - - EditSelection* selection = xournal->getSelection(); - bool hasNoModifiers = !pos.isShiftDown() && !pos.isControlDown(); - - if (hasNoModifiers && selection != nullptr) { - // Find a selected object under the cursor, if possible. The selection doesn't change the - // element coordinates until it is finalized, so we need to use position relative to the - // original coordinates of the selection. - double origx = x - (selection->getXOnView() - selection->getOriginalXOnView()); - double origy = y - (selection->getYOnView() - selection->getOriginalYOnView()); - auto elems = selection->getElementsView(); - auto it = std::find_if(elems.begin(), elems.end(), - [&](const Element* elem) { return elem->intersectsArea(origx - 5, origy - 5, 5, 5); }); - if (it != elems.end()) { - // Enter editing mode on the selected object - const Element* object = *it; - ElementType elemType = object->getType(); - if (elemType == ELEMENT_TEXT) { - this->xournal->clearSelection(); - toolHandler->selectTool(TOOL_TEXT); - toolHandler->fireToolChanged(); - // Simulate a button press; there's too many things that we - // could forget to do if we manually call startText - this->onButtonPressEvent(pos); - } else if (elemType == ELEMENT_TEXIMAGE) { - Control* control = this->xournal->getControl(); - if (elems.size() > 1) { - // Deselect the other elements - this->xournal->clearSelection(); - auto sel = SelectionFactory::createFromElementOnActiveLayer(control, getPage(), this, object); - this->xournal->setSelection(sel.release()); - } - control->runLatex(); - } - } - } else if (toolType == TOOL_TEXT) { - this->startText(x, y); - this->textEditor->selectAtCursor(TextEditor::SelectType::WORD); - } else if (toolType == TOOL_SELECT_PDF_TEXT_LINEAR || toolType == TOOL_SELECT_PDF_TEXT_RECT) { - auto* pdfToolbox = this->xournal->getControl()->getWindow()->getPdfToolbox(); - if (auto* selection = pdfToolbox->getSelection()) { - pdfToolbox->selectionStyle = XojPdfPageSelectionStyle::Word; - selection->currentPos(x, y, pdfToolbox->selectionStyle); - } - } else if (drawingType == DRAWING_TYPE_SPLINE) { - if (this->inputHandler) { - this->inputHandler->onButtonDoublePressEvent(pos, zoom); - xoj_assert(hasNoViewOf(overlayViews, inputHandler.get())); - this->inputHandler.reset(); - } - } - - return true; -} - -auto XojPageView::onButtonTriplePressEvent(const PositionInputData& pos) -> bool { - // This method assumes that it is called after onButtonDoubleEvent but before - // onButtonReleaseEvent - double zoom = this->xournal->getZoom(); - double x = pos.x / zoom; - double y = pos.y / zoom; - if (x < 0 || y < 0) { - return false; - } - - ToolHandler* toolHandler = this->xournal->getControl()->getToolHandler(); - ToolType toolType = toolHandler->getToolType(); - - if (toolType == TOOL_TEXT) { - this->startText(x, y); - this->textEditor->selectAtCursor(TextEditor::SelectType::PARAGRAPH); - } else if (toolType == TOOL_SELECT_PDF_TEXT_LINEAR || toolType == TOOL_SELECT_PDF_TEXT_RECT) { - auto* pdfToolbox = this->xournal->getControl()->getWindow()->getPdfToolbox(); - if (auto* selection = pdfToolbox->getSelection()) { - pdfToolbox->selectionStyle = XojPdfPageSelectionStyle::Line; - selection->currentPos(x, y, pdfToolbox->selectionStyle); - } - } - return true; -} - -auto XojPageView::onMotionNotifyEvent(const PositionInputData& pos) -> bool { - if (currentSequenceDeviceId && currentSequenceDeviceId != pos.deviceId) { - // This motion event is not from the device which started the sequence: reject it - return false; - } - - double zoom = xournal->getZoom(); - double x = pos.x / zoom; - double y = pos.y / zoom; - - ToolHandler* h = xournal->getControl()->getToolHandler(); - auto* pdfToolbox = this->xournal->getControl()->getWindow()->getPdfToolbox(); - - if (this->inputHandler && this->inputHandler->onMotionNotifyEvent(pos, zoom)) { - // input handler used this event - } else if (this->imageSizeSelection) { - this->imageSizeSelection->updatePosition(x, y); - } else if (this->selector) { - this->selector->currentPos(x, y); - } else if (auto* selection = pdfToolbox->getSelection(); selection && !selection->isFinalized()) { - selection->currentPos(x, y, pdfToolbox->selectionStyle); - } else if (this->verticalSpace) { - this->verticalSpace->currentPos(x, y); - } else if (this->textEditor) { - XournalppCursor* cursor = getXournal()->getCursor(); - cursor->setInvisible(false); - - const Text* text = this->textEditor->getTextElement(); - this->textEditor->mouseMoved(x - text->getX(), y - text->getY()); - } else if (this->laserPointer && this->laserPointer->onMotionNotifyEvent(pos, zoom)) { - // used this event - } else if (h->getToolType() == TOOL_ERASER && h->getEraserType() != ERASER_TYPE_WHITEOUT && this->inEraser) { - this->eraser->erase(x, y); - } - - return false; -} - -void XojPageView::onSequenceCancelEvent(DeviceId deviceId) { - if (currentSequenceDeviceId != deviceId) { - // This motion event is not from the device which started the sequence: reject it - return; - } - currentSequenceDeviceId.reset(); - - if (this->inputHandler) { - this->inputHandler->onSequenceCancelEvent(); - - if (auto* h = dynamic_cast(this->inputHandler.get()); h) { - // SplineHandler can survive a sequence cancellation - if (!h->getStroke()) { - xoj_assert(hasNoViewOf(overlayViews, inputHandler.get())); - this->inputHandler.reset(); - } - } else { - xoj_assert(hasNoViewOf(overlayViews, inputHandler.get())); - this->inputHandler.reset(); - } - } else if (this->laserPointer) { - this->laserPointer->onSequenceCancelEvent(); - } -} - -void XojPageView::onTapEvent(const PositionInputData& pos) { - if (this->inputHandler) { - /* - * We only want tap events to trigger special actions if no tool is currently under use - * (e.g. a spline is currently under edition) - * Feed the event to the InputHandler as a click - */ - const double zoom = getZoom(); - this->inputHandler->onButtonPressEvent(pos, zoom); - this->inputHandler->onButtonReleaseEvent(pos, zoom); - if (!this->inputHandler->getStroke()) { - // The InputHandler finalized its edition - xoj_assert(hasNoViewOf(overlayViews, inputHandler.get())); - this->inputHandler.reset(); - } - return; - } - - auto* settings = xournal->getControl()->getSettings(); - bool doAction = settings->getDoActionOnStrokeFiltered(); - if (settings->getTrySelectOnStrokeFiltered()) { - double zoom = xournal->getZoom(); - SelectObject select(this); - if (pos.isShiftDown()) { - if (select.atAggregate(pos.x / zoom, pos.y / zoom)) { - doAction = false; // selection made.. no action. - } - } else { - if (select.at(pos.x / zoom, pos.y / zoom)) { - doAction = false; // selection made.. no action. - } - } - } - - if (doAction) // pop up a menu - { - this->showFloatingToolbox(pos); - } -} - -auto XojPageView::showPdfToolbox(const PositionInputData& pos) -> void { - // Compute coords of the canvas relative to the application window origin. - gint wx = 0, wy = 0; - GtkWidget* widget = xournal->getWidget(); - gtk_widget_translate_coordinates(widget, gtk_widget_get_toplevel(widget), 0, 0, &wx, &wy); - - // Add the position of the current page view widget (relative to canvas origin) - // and add the input position (relative to the current page view widget). - wx += this->getX() + round_cast(pos.x); - wy += this->getY() + round_cast(pos.y); - - auto* pdfToolbox = this->xournal->getControl()->getWindow()->getPdfToolbox(); - pdfToolbox->show(wx, wy); -} - -void XojPageView::deleteView(xoj::view::OverlayView* view) { - auto it = std::find_if(this->overlayViews.begin(), this->overlayViews.end(), - [view](const auto& v) { return view == v.get(); }); - if (it != this->overlayViews.end()) { - this->overlayViews.erase(it); - } -} - -auto XojPageView::onButtonReleaseEvent(const PositionInputData& pos) -> bool { - if (currentSequenceDeviceId != pos.deviceId) { - // This event is not from the device which started the sequence: reject it - return false; - } - currentSequenceDeviceId.reset(); - - Control* control = xournal->getControl(); - - if (this->inputHandler) { - double zoom = xournal->getZoom(); - this->inputHandler->onButtonReleaseEvent(pos, zoom); - - ToolHandler* h = control->getToolHandler(); - bool isDrawingTypeSpline = h->getDrawingType() == DRAWING_TYPE_SPLINE; - if (!isDrawingTypeSpline || !this->inputHandler->getStroke()) { // The Spline Tool finalizes drawing manually - xoj_assert(hasNoViewOf(overlayViews, inputHandler.get())); - this->inputHandler.reset(); - } - } else if (auto tt = control->getToolHandler()->getToolType(); - this->laserPointer && (tt == TOOL_LASER_POINTER_PEN || tt == TOOL_LASER_POINTER_HIGHLIGHTER)) { - this->laserPointer->onButtonReleaseEvent(pos, xournal->getZoom()); - } - - if (this->inEraser) { - this->inEraser = false; - Document* doc = this->xournal->getControl()->getDocument(); - doc->lock(); - this->eraser->finalize(); - doc->unlock(); - } - - if (this->verticalSpace) { - control->getUndoRedoHandler()->addUndoAction(this->verticalSpace->finalize()); - this->verticalSpace.reset(); - } - - auto* pdfToolbox = control->getWindow()->getPdfToolbox(); - if (auto* selection = pdfToolbox->getSelection()) { - if (!selection->isFinalized() && selection->finalizeSelectionAndRepaint(pdfToolbox->selectionStyle)) { - // Selection was created, so reposition the toolbox and display. - showPdfToolbox(pos); - } - } - - ToolType toolType = control->getToolHandler()->getActiveTool()->getToolType(); - if (xoj::tool::isPdfSelectionTool(toolType)) { - const double zoom = xournal->getZoom(); - // Attempt PDF selection - auto& pdfDoc = this->xournal->getDocument()->getPdfDocument(); - if (this->getPage()->getPdfPageNr() != npos) { - auto page = pdfDoc.getPage(this->getPage()->getPdfPageNr()); - - const double pageX = pos.x / zoom; - const double pageY = pos.y / zoom; - - displayLinkPopover(page, pageX, pageY); - } - } - - if (this->selector) { - const bool aggregate = pos.isShiftDown() && xournal->getSelection(); - size_t layerOfFinalizedSel = this->selector->finalize(this->page, aggregate, control->getDocument()); - - if (layerOfFinalizedSel) { - xournal->setSelection([&]() { - if (aggregate) { - // Aggregate selection - auto sel = selector->releaseElements(); - return SelectionFactory::addElementsFromActiveLayer(control, xournal->getSelection(), sel); - } else { - // if selection->multiLayer == true, the selected objects might be on another layer - xournal->getControl()->getLayerController()->switchToLay(layerOfFinalizedSel); - return SelectionFactory::createFromElementsOnActiveLayer(control, page, this, - selector->releaseElements()); - } - }() - .release()); - } else if (const double zoom = xournal->getZoom(); selector->userTapped(zoom)) { - if (aggregate) { - SelectObject(this).atAggregate(pos.x / zoom, pos.y / zoom); - } else { - SelectObject(this).at(pos.x / zoom, pos.y / zoom, this->selector->isMultiLayerSelection()); - } - } - this->selector.reset(); - } else if (this->textEditor) { - this->textEditor->mouseReleased(); - } - - if (this->imageSizeSelection) { - // size for image has been selected, now the image can be added - auto spaceForImage = this->imageSizeSelection->getSelectedSpace(); - ImageHandler imgHandler(control); - imgHandler.insertImageWithSize(this->page, spaceForImage); - - imageSizeSelection->finalize(); - this->imageSizeSelection.reset(); - } - - return false; -} - -auto XojPageView::onKeyPressEvent(const KeyEvent& event) -> bool { - if (this->textEditor) { - if (this->textEditor->onKeyPressEvent(event)) { - return true; - } - } else if (this->inputHandler) { - if (this->inputHandler->onKeyPressEvent(event)) { - return true; - } - } else if (this->verticalSpace) { - if (this->verticalSpace->onKeyPressEvent(event)) { - return true; - } - } - - // Esc leaves text edition - if (event.keyval == GDK_KEY_Escape) { - if (this->textEditor) { - endText(); - return true; - } - - return false; - } - - return false; -} - -auto XojPageView::onKeyReleaseEvent(const KeyEvent& event) -> bool { - if (this->textEditor && this->textEditor->onKeyReleaseEvent(event)) { - return true; - } - - if (this->inputHandler && this->inputHandler->onKeyReleaseEvent(event)) { - DrawingType drawingType = this->xournal->getControl()->getToolHandler()->getDrawingType(); - if (drawingType == DRAWING_TYPE_SPLINE) { // Spline drawing has been finalized - if (this->inputHandler) { - xoj_assert(hasNoViewOf(overlayViews, inputHandler.get())); - this->inputHandler.reset(); - } - } - - return true; - } - - if (this->verticalSpace && this->verticalSpace->onKeyReleaseEvent(event)) { - return true; - } - - return false; -} - -void XojPageView::rerenderPage(bool sizeChanged) { - this->rerenderComplete = true; - this->sizeChanged = sizeChanged; - this->xournal->getControl()->getScheduler()->addRerenderPage(this); -} - -void XojPageView::repaintPage() const { xournal->getRepaintHandler()->repaintPage(this); } - -void XojPageView::repaintArea(double x1, double y1, double x2, double y2) const { - double zoom = xournal->getZoom(); - xournal->getRepaintHandler()->repaintPageArea(this, floor_cast(x1 * zoom), floor_cast(y1 * zoom), - ceil_cast(x2 * zoom), ceil_cast(y2 * zoom)); -} - -void XojPageView::flagDirtyRegion(const Range& rg) const { repaintArea(rg.minX, rg.minY, rg.maxX, rg.maxY); } - -void XojPageView::drawAndDeleteToolView(xoj::view::ToolView* v, const Range& rg) { - if (v->isViewOf(this->inputHandler.get()) || v->isViewOf(this->verticalSpace.get()) || - v->isViewOf(this->textEditor.get())) { - // Draw the inputHandler's view onto the page buffer. - std::lock_guard lock(this->drawingMutex); - if (auto cr = buffer.get(); cr) { - v->drawWithoutDrawingAids(cr); - } else { - rerenderPage(); - } - } - this->deleteOverlayView(v, rg); -} - -void XojPageView::deleteOverlayView(xoj::view::OverlayView* v, const Range& rg) { - this->deleteView(v); - if (!rg.empty()) { - xoj_assert(rg.isValid()); - this->flagDirtyRegion(rg); - } -} - -double XojPageView::getZoom() const { return xournal->getZoom(); } - -ZoomControl* XojPageView::getZoomControl() const { return this->getXournal()->getControl()->getZoomControl(); } - -Range XojPageView::getVisiblePart() const { - std::unique_ptr> rect(xournal->getVisibleRect(this)); - if (rect) { - return Range(*rect); - } - return Range(); // empty range -} - -double XojPageView::getWidth() const { return page->getWidth(); } - -double XojPageView::getHeight() const { return page->getHeight(); } - -auto XojPageView::toWindowCoordinates(const xoj::util::Rectangle& r) const -> xoj::util::Rectangle { - double zoom = this->getZoom(); - return {r.x * zoom + this->getX(), r.y * zoom + this->getY(), r.width * zoom, r.height * zoom}; -} - -void XojPageView::rerenderRect(double x, double y, double width, double height) { - if (this->rerenderComplete) { - return; - } - - auto rect = Rectangle{x, y, width, height}; - - this->repaintRectMutex.lock(); - - for (auto&& r: this->rerenderRects) { - // its faster to redraw only one rect than repaint twice the same area - // so loop through the rectangles to be redrawn, if new rectangle - // intersects any of them, replace it by the union with the new one - if (r.intersects(rect)) { - r.unite(rect); - this->repaintRectMutex.unlock(); - return; - } - } - - this->rerenderRects.push_back(rect); - this->repaintRectMutex.unlock(); - - this->xournal->getControl()->getScheduler()->addRerenderPage(this); -} - -void XojPageView::setSelected(bool selected) { - this->selected = selected; - - if (selected) { - this->xournal->requestFocus(); - this->xournal->getRepaintHandler()->repaintPageBorder(this); - } else { - this->endSpline(); - } -} - -auto XojPageView::cut() -> bool { - if (this->textEditor) { - this->textEditor->cutToClipboard(); - return true; - } - return false; -} - -auto XojPageView::copy() -> bool { - if (this->textEditor) { - this->textEditor->copyToClipboard(); - return true; - } - return false; -} - -auto XojPageView::paste() -> bool { - if (this->textEditor) { - this->textEditor->pasteFromClipboard(); - return true; - } - return false; -} - -auto XojPageView::actionDelete() -> bool { - if (this->textEditor) { - this->textEditor->deleteFromCursor(GTK_DELETE_CHARS, 1); - return true; - } - return false; -} - -void XojPageView::drawLoadingPage(cairo_t* cr) { - static const string txtLoading = _("Loading..."); - - cairo_set_source_rgb(cr, 1, 1, 1); - cairo_rectangle(cr, 0, 0, page->getWidth(), page->getHeight()); - cairo_fill(cr); - - cairo_set_source_rgb(cr, 0.5, 0.5, 0.5); - cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); - cairo_set_font_size(cr, 32.0); - cairo_text_extents_t ex; - cairo_text_extents(cr, txtLoading.c_str(), &ex); - cairo_move_to(cr, (page->getWidth() - ex.width) / 2 - ex.x_bearing, - (page->getHeight() - ex.height) / 2 - ex.y_bearing); - cairo_text_path(cr, txtLoading.c_str()); - - rerenderPage(); -} - -bool XojPageView::displayLinkPopover(std::shared_ptr page, double pageX, double pageY) { - // Search for selected link - const auto links = page->getLinks(); - - for (auto&& [rect, action]: links) { - std::shared_ptr dest = action->getDestination(); - - if (!(rect.x1 <= pageX && pageX <= rect.x2 && rect.y1 <= pageY && pageY <= rect.y2)) { - continue; - } - - GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); - GtkWidget* popover = makePopover(rect, box); - - if (auto uriOpt = dest->getURI()) { - const std::string& uri = uriOpt.value(); - char* uriLabel = g_markup_escape_text(uri.c_str(), -1); - - auto labelMarkup = serdes_stream(); - labelMarkup << "" << uriLabel << ""; - - std::string linkMarkup = labelMarkup.str(); - - g_free(uriLabel); - - GtkWidget* label = gtk_label_new(nullptr); - gtk_label_set_markup(GTK_LABEL(label), linkMarkup.c_str()); - gtk_box_append(GTK_BOX(box), label); - } else { - size_t pdfPage = dest->getPdfPage(); - - Document* doc = xournal->getControl()->getDocument(); - doc->lock_shared(); - const size_t pageId = doc->findPdfPage(pdfPage); - doc->unlock_shared(); - - GtkWidget* button{}; - if (pageId != npos) { - const auto pageNo = static_cast(pageId + 1); - button = gtk_button_new_with_label(FC(_F("Scroll to page {1}") % pageNo)); - } else { - button = gtk_button_new_with_label(FC(_F("Add missing page"))); - } - gtk_box_append(GTK_BOX(box), button); - - using State = std::tuple, GtkWidget*>; - g_signal_connect_data(GTK_BUTTON(button), "clicked", G_CALLBACK(+[](GtkButton* bt, gpointer state) { - XojPageView* self; - std::shared_ptr dest; - GtkWidget* popover; - std::tie(self, dest, popover) = *static_cast(state); - - self->getXournal()->getControl()->getScrollHandler()->scrollToLinkDest(*dest); - gtk_popover_popdown(GTK_POPOVER(popover)); - }), - new State(this, dest, popover), xoj::util::closure_notify_cb, - (GConnectFlags)0); - } - - gtk_widget_show_all(popover); - gtk_popover_popup(GTK_POPOVER(popover)); - return true; - } - - return false; -} - -GtkWidget* XojPageView::makePopover(const XojPdfRectangle& rect, GtkWidget* child) { - double zoom = xournal->getZoom(); - - GtkWidget* popover = gtk_popover_new(this->getXournal()->getWidget()); - gtk_popover_set_child(GTK_POPOVER(popover), child); - - auto x = floor_cast(this->getX() + rect.x1 * zoom); - auto y = floor_cast(this->getY() + rect.y1 * zoom); - auto w = ceil_cast((rect.x2 - rect.x1) * zoom); - auto h = ceil_cast((rect.y2 - rect.y1) * zoom); - - GdkRectangle canvasRect{x, y, w, h}; - gtk_popover_set_pointing_to(GTK_POPOVER(popover), &canvasRect); - gtk_popover_set_constrain_to(GTK_POPOVER(popover), GTK_POPOVER_CONSTRAINT_WINDOW); - - return popover; -} - -auto XojPageView::paintPage(cairo_t* cr, GdkRectangle* rect) -> bool { - - double zoom = xournal->getZoom(); - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_scale(cr, zoom, zoom); - - { - std::lock_guard lock(this->drawingMutex); // Lock the mutex first - xoj::util::CairoSaveGuard saveGuard(cr); // see comment at the end of the scope - if (!this->hasBuffer()) { - drawLoadingPage(cr); - return true; - } - - if (this->buffer.getZoom() != zoom) { - rerenderPage(); - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST); - } - this->buffer.paintTo(cr); - } // Restore the state of cr and then release the mutex - // restoring the state of cr ensures this->buffer.surface is not longer referenced as the source in cr. - - /** - * All the overlay painters below follow the assumption: - * * The given cairo context is in page coordinates: no further scaling/offset is ever required. - * - * To anyone adding another painter here: please keep this assumption true - */ - for (const auto& v: this->overlayViews) { - v->draw(cr); - } - - return true; -} - -/** - * GETTER / SETTER - */ - -auto XojPageView::isSelected() const -> bool { return selected; } - -auto XojPageView::hasBuffer() const -> bool { return this->buffer.isInitialized(); } - -auto XojPageView::getSelectionColor() -> GdkRGBA { return Util::rgb_to_GdkRGBA(settings->getSelectionColor()); } - -auto XojPageView::getTextEditor() -> TextEditor* { return textEditor.get(); } - -auto XojPageView::getX() const -> int { return this->dispX; } - -void XojPageView::setX(int x) { this->dispX = x; } - -auto XojPageView::getY() const -> int { return this->dispY; } - -void XojPageView::setY(int y) { this->dispY = y; } - -void XojPageView::setMappedRowCol(int row, int col) { - this->mappedRow = row; - this->mappedCol = col; -} - - -auto XojPageView::getMappedRow() const -> int { return this->mappedRow; } - - -auto XojPageView::getMappedCol() const -> int { return this->mappedCol; } - - -auto XojPageView::getPage() const -> const PageRef { return page; } - -auto XojPageView::getXournal() const -> XournalView* { return this->xournal; } - -auto XojPageView::getDisplayWidth() const -> int { - return round_cast(this->page->getWidth() * this->xournal->getZoom()); -} - -auto XojPageView::getDisplayHeight() const -> int { - return round_cast(this->page->getHeight() * this->xournal->getZoom()); -} - -auto XojPageView::getDisplayWidthDouble() const -> double { return this->page->getWidth() * this->xournal->getZoom(); } - -auto XojPageView::getDisplayHeightDouble() const -> double { - return this->page->getHeight() * this->xournal->getZoom(); -} - -auto XojPageView::getSelectedTex() const -> const TexImage* { - EditSelection* theSelection = this->xournal->getSelection(); - if (!theSelection) { - return nullptr; - } - - for (const Element* e: theSelection->getElementsView()) { - if (e->getType() == ELEMENT_TEXIMAGE) { - return dynamic_cast(e); - } - } - return nullptr; -} - -auto XojPageView::getSelectedText() const -> const Text* { - EditSelection* theSelection = this->xournal->getSelection(); - if (!theSelection) { - return nullptr; - } - - for (const Element* e: theSelection->getElementsView()) { - if (e->getType() == ELEMENT_TEXT) { - return dynamic_cast(e); - } - } - return nullptr; -} - -auto XojPageView::getRect() const -> Rectangle { - return Rectangle(getX(), getY(), getDisplayWidth(), getDisplayHeight()); -} - -void XojPageView::rectChanged(Rectangle& rect) { rerenderRect(rect.x, rect.y, rect.width, rect.height); } - -void XojPageView::rangeChanged(Range& range) { rerenderRange(range); } - -void XojPageView::pageChanged() { rerenderPage(); } - -void XojPageView::elementChanged(const Element* elem) { - /* - * The input handlers issue an elementChanged event when creating an element. - * There is however no need to redraw the element in this case: the element was already painted to the buffer via a - * call to drawAndDeleteToolView - * There are a couple of exceptions: - * * if the added element is not on the top-most layer, a rerendering is required to draw it under the upper layers - * * if the added element overflows out of the visible part of the page, the ToolView may not have drawn to the - * page buffer the part outside the visible area. Rerendering as well - */ - const bool noRerender = inputHandler && elem == inputHandler->getStroke() && - page->getSelectedLayerId() == page->getLayerCount() && - getVisiblePart().contains(elem->boundingRect()); - if (!noRerender) { - rerenderElement(elem); - } -} - -void XojPageView::elementsChanged(const std::vector& elements, const Range& range) { - if (!range.empty()) { - rerenderRange(range); - } -} - -void XojPageView::showFloatingToolbox(const PositionInputData& pos) { - Control* control = xournal->getControl(); - - gint wx = 0, wy = 0; - GtkWidget* widget = xournal->getWidget(); - gtk_widget_translate_coordinates(widget, gtk_widget_get_toplevel(widget), 0, 0, &wx, &wy); - - wx += round_cast(pos.x) + this->getX(); - wy += round_cast(pos.y) + this->getY(); - - control->getWindow()->getFloatingToolbox()->show(wx, wy); -} diff --git a/entry/src/main/cpp/src/core/gui/PageView.h b/entry/src/main/cpp/src/core/gui/PageView.h deleted file mode 100644 index 0d2ce7f..0000000 --- a/entry/src/main/cpp/src/core/gui/PageView.h +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Xournal++ - * - * Displays a single page - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for unique_ptr, shared_ptr -#include // for mutex -#include // for string -#include // for vector - -#include // for cairo_t -#include // for GdkEventKey, GdkRGBA, GdkRectangle -#include // for GtkWidget - -#include "gui/inputdevices/DeviceId.h" -#include "gui/inputdevices/InputEvents.h" -#include "model/PageListener.h" // for PageListener -#include "model/PageRef.h" // for PageRef -#include "util/Rectangle.h" // for Rectangle -#include "util/raii/CairoWrappers.h" // for CairoSurfaceSPtr -#include "view/Mask.h" // for Mask -#include "view/Repaintable.h" // for Repaintable - -#include "Layout.h" // for Layout -#include "LegacyRedrawable.h" // for LegacyRedrawable - -class EraseHandler; -class ImageSizeSelection; -class InputHandler; -class LaserPointerHandler; -class SearchControl; -class Selector; -class Settings; -class Text; -class TextEditor; -class VerticalToolHandler; -class XournalView; -class Element; -class PositionInputData; -class Range; -class TexImage; -class XojPdfRectangle; -class XojPdfPage; - -namespace xoj::view { -class OverlayView; -class ToolView; -} // namespace xoj::view - -class XojPageView: public LegacyRedrawable, public PageListener, public xoj::view::Repaintable { -public: - XojPageView(XournalView* xournal, const PageRef& page); - ~XojPageView() override; - -public: - void addOverlayView(std::unique_ptr); - void rerenderPage(bool sizeChanged = false) override; - void rerenderRect(double x, double y, double width, double height) override; - - void repaintPage() const override; - void repaintArea(double x1, double y1, double x2, double y2) const override; - - // Repaintable interface - void flagDirtyRegion(const Range& rg) const override; - /** - * @brief This draws the ToolView directly onto the buffer, deletes the view and repaints the given range - * Used to avoid blinking when a tool finished editing an element - */ - void drawAndDeleteToolView(xoj::view::ToolView* v, const Range& rg) override; - /** - * @brief Simply deletes an overlay and any trace of it on the display (provided the overlay is contained in the - * given range) - */ - void deleteOverlayView(xoj::view::OverlayView* v, const Range& rg) override; - - double getZoom() const override; - ZoomControl* getZoomControl() const override; - Range getVisiblePart() const override; - - double getWidth() const override; - double getHeight() const override; - // End of Repaintable interface - - xoj::util::Rectangle toWindowCoordinates(const xoj::util::Rectangle& r) const override; - - - void setSelected(bool selected); - - void setIsVisible(bool visible); - - bool isSelected() const; - inline bool isVisible() const { return visible; } - - void endText(); - - void endSpline(); - - bool searchTextOnPage(const std::string& text, size_t index, size_t* occurrences, XojPdfRectangle* matchRect); - - bool onKeyPressEvent(const KeyEvent& event); - bool onKeyReleaseEvent(const KeyEvent& event); - - bool cut(); - bool copy(); - bool paste(); - - bool actionDelete(); - - void deleteViewBuffer() override; - - /** - * Returns whether this PageView contains the - * given point on the display - */ - bool containsPoint(int x, int y, bool local = false) const; - - /** - * Returns Row assigned in current layout - */ - int getMappedRow() const; - - /** - * Returns Column assigned in current layout - */ - int getMappedCol() const; - - GdkRGBA getSelectionColor() override; - bool hasBuffer() const; - - TextEditor* getTextEditor(); - - /** - * Returns a reference to the XojPage belonging to - * this PageView - */ - const PageRef getPage() const; - - XournalView* getXournal() const; - - /** - * Returns the width of this XojPageView as displayed - * on the display taking into account the current zoom - */ - int getDisplayWidth() const; - double getDisplayWidthDouble() const; - /** - * Returns the height of this XojPageView as displayed - * on the display taking into account the current zoom - */ - int getDisplayHeight() const; - double getDisplayHeightDouble() const; - - /** - * Returns the x coordinate of this XojPageView with - * respect to the display - */ - int getX() const override; - - /** - * Returns the y coordinate of this XojPageView with - * respect to the display - */ - int getY() const override; - - const TexImage* getSelectedTex() const; - const Text* getSelectedText() const; - - xoj::util::Rectangle getRect() const; - -public: // event handler - bool onButtonPressEvent(const PositionInputData& pos); - bool onButtonReleaseEvent(const PositionInputData& pos); - bool onButtonDoublePressEvent(const PositionInputData& pos); - bool onButtonTriplePressEvent(const PositionInputData& pos); - bool onMotionNotifyEvent(const PositionInputData& pos); - void onSequenceCancelEvent(DeviceId id); - void onTapEvent(const PositionInputData& pos); - - /** - * This event fires after onButtonPressEvent and also - * if no input sequence is actively running and a stylus button was pressed - */ - bool onButtonClickEvent(const PositionInputData& pos); - - /** - * This method actually repaints the XojPageView, triggering - * a rerender call if necessary - */ - bool paintPage(cairo_t* cr, GdkRectangle* rect); - - void deleteLaserPointerHandler(); - -public: // listener - void rectChanged(xoj::util::Rectangle& rect) override; - void rangeChanged(Range& range) override; - void pageChanged() override; - void elementChanged(const Element* elem) override; - void elementsChanged(const std::vector& elements, const Range& range) override; - -private: - void startText(double x, double y); - - void drawLoadingPage(cairo_t* cr); - - /** - * @brief Make and display a popover dialog near the given location. - * - * @param rect specifies the location of the dialog. - * @param child is added to the dialog before displaying. - * @returns a pointer to the popover dialog. - */ - GtkWidget* makePopover(const XojPdfRectangle& rect, GtkWidget* child); - - /** - * @brief Display a popover with link-related actions, if one - * is at a given location on the page. - * - * @param page is the current page - * @param targetX - * @param targetY the link must contain (targetX, targetY) - * @returns true iff a URI link exists near/at (targetX, targetY) => a popover was shown - */ - bool displayLinkPopover(std::shared_ptr page, double targetX, double targetY); - - void setX(int x); - void setY(int y); - - void setMappedRowCol(int row, int col); // row, column assigned by mapper during layout. - - /** - * Shows the floating toolbox at the location of an input event - */ - void showFloatingToolbox(const PositionInputData& pos); - - /** - * Shows the PDF toolbox at the location of an input event - */ - void showPdfToolbox(const PositionInputData& pos); - - void deleteView(xoj::view::OverlayView* v); - -private: - PageRef page; - XournalView* xournal = nullptr; - Settings* settings = nullptr; - std::unique_ptr eraser; - std::unique_ptr inputHandler; - - std::vector> overlayViews; - - /** - * The selected (while selection) - */ - std::unique_ptr selector; - - /** - * The text editor - */ - std::unique_ptr textEditor; - - /** - * For image insertion with size (selects the size) - */ - std::unique_ptr imageSizeSelection; - - std::unique_ptr laserPointer; - - /** - * For keeping old text changes to undo! - */ - Text* oldtext; - - bool visible = true; - bool selected = false; - - xoj::view::Mask buffer; - std::mutex drawingMutex; - - bool inEraser = false; - - /** - * Vertical Space - */ - std::unique_ptr verticalSpace; - - /** - * Search handling - */ - std::unique_ptr search; - - std::mutex repaintRectMutex; - std::vector> rerenderRects; - bool rerenderComplete = false; - bool sizeChanged = false; - - int dispX{}; // position on display - set in Layout::layoutPages - int dispY{}; - - - int mappedRow{}; - int mappedCol{}; - - DeviceId currentSequenceDeviceId; - - - friend class RenderJob; - friend class InputHandler; - friend class BaseSelectObject; - friend class SelectObject; - friend class PlayObject; - friend class PdfFloatingToolbox; - // only function allowed to setX(), setY(), setMappedRowCol(): - friend void Layout::layoutPages(int width, int height); -}; diff --git a/entry/src/main/cpp/src/core/gui/PageViewFindObjectHelper.h b/entry/src/main/cpp/src/core/gui/PageViewFindObjectHelper.h deleted file mode 100644 index 661abe4..0000000 --- a/entry/src/main/cpp/src/core/gui/PageViewFindObjectHelper.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Xournal++ - * - * Helper classes to find / select objects - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -// No include needed, this is included after PageView.h - -#include -#include -#include - -#include "control/AudioController.h" -#include "control/Control.h" -#include "control/layer/LayerController.h" -#include "control/settings/Settings.h" -#include "control/tools/EditSelection.h" -#include "gui/PageView.h" -#include "model/Layer.h" -#include "model/XojPage.h" -#include "util/safe_casts.h" - -#include "XournalView.h" - -class BaseSelectObject { -public: - BaseSelectObject(XojPageView* view): view(view) {} - - virtual ~BaseSelectObject() = default; - -public: - bool findAt(double x, double y, bool multiLayer = false, bool clearSelection = true) { - this->x = x; - this->y = y; - - Control* ctrl = this->view->getXournal()->getControl(); - - if (clearSelection) { - ctrl->clearSelection(); - } - - std::shared_lock lock(*ctrl->getDocument()); - if (multiLayer) { - const auto& layers = this->view->getPage()->getLayers(); - size_t layerNo = layers.size(); - for (auto l = layers.rbegin(); l != layers.rend(); l++, layerNo--) { - if (checkLayer(*l)) { - ctrl->getLayerController()->switchToLay(as_unsigned(std::distance(l, layers.rend()))); - return true; - } - } - return false; - } else { - Layer* layer = this->view->getPage()->getSelectedLayer(); - return checkLayer(layer); - } - } - -protected: - virtual bool checkLayer(const Layer* l) = 0; - -protected: - XojPageView* view{}; - double x{0}; - double y{0}; -}; - -class SelectObject: public BaseSelectObject { -public: - SelectObject(XojPageView* view): BaseSelectObject(view), match(nullptr) {} - - ~SelectObject() override = default; - - bool at(double x, double y, bool multiLayer = false) { - findAt(x, y, multiLayer); - - if (match) { - Control* ctrl = view->getXournal()->getControl(); - auto sel = SelectionFactory::createFromElementOnActiveLayer(ctrl, view->getPage(), view, match, matchIndex); - view->xournal->setSelection(sel.release()); - view->repaintPage(); - return true; - } - - return false; - } - - bool atAggregate(double x, double y) { - EditSelection* previousSelection = view->getXournal()->getSelection(); - xoj_assert(previousSelection); - - findAt(x, y, false, false); - if (match) { - auto sel = SelectionFactory::addElementFromActiveLayer(view->getXournal()->getControl(), previousSelection, - match, matchIndex); - view->getXournal()->setSelection(sel.release()); - view->repaintPage(); - - return true; - } - return false; - } - - static constexpr double ACTION_RADIUS = 5.; - - bool checkLayer(const Layer* l) override { - double minDistance = ACTION_RADIUS; - // Iterate starting from the front-most element - Element::Index pos = as_signed(l->getElementsView().size()); - for (auto it = l->getElementsView().rbegin(); it < l->getElementsView().rend(); ++it) { - pos--; - // First perform a rough check to avoid expensive calls to Stroke::distanceTo() - if ((*it)->intersectsArea(x - minDistance, y - minDistance, 2. * minDistance, 2. * minDistance)) { - double d = (*it)->distanceTo(x, y); - if (d == 0.0) { - this->match = *it; - this->matchIndex = pos; - return true; - } - if (d < minDistance) { - this->match = *it; - this->matchIndex = pos; - minDistance = d; - // Keep going, we may find something closer - } - } - } - return minDistance != ACTION_RADIUS; - } - -private: - const Element* match; - Element::Index matchIndex; -}; - -class PlayObject: public BaseSelectObject { -public: - PlayObject(XojPageView* view): BaseSelectObject(view), playbackStatus() {} - - ~PlayObject() override = default; - - struct Status { - bool success; - fs::path filename; - }; - - std::optional playbackStatus; - -public: - bool at(double x, double y, bool multiLayer = false) { return findAt(x, y, multiLayer); } - -protected: - static constexpr double ACTION_RADIUS = 15.; - - /// Plays every element of the layer that are closer than ACTION_RADIUS - bool checkLayer(const Layer* l) override { - bool found = false; - for (auto&& e: l->getElementsView()) { - if (auto* audio = dynamic_cast(e); audio) { - // First perform a rough check to avoid expensive calls to Stroke::distanceTo() - if (audio->intersectsArea(x - ACTION_RADIUS, y - ACTION_RADIUS, 2. * ACTION_RADIUS, - 2. * ACTION_RADIUS)) { - double d = audio->distanceTo(x, y); - if (d < ACTION_RADIUS) { - found = playElement(audio) || found; - } - } - } - } - return found; - } - - bool playElement(const AudioElement* s) { -#ifdef ENABLE_AUDIO - size_t ts = s->getTimestamp(); - - if (auto fn = s->getAudioFilename(); !fn.empty()) { - if (!fn.has_parent_path() || fs::weakly_canonical(fn.parent_path()) == "/") { - auto const& path = view->settings->getAudioFolder(); - // Assume path exists - fn = path / fn; - } - auto* audioController = view->getXournal()->getControl()->getAudioController(); - if (!audioController) { - g_warning("Audio has been disabled"); - return false; - } - bool success = audioController->startPlayback(fn, (unsigned int)ts); - playbackStatus = {success, std::move(fn)}; - return success; - } -#else - g_warning("Audio support was disabled at compile time"); -#endif - return false; - } -}; diff --git a/entry/src/main/cpp/src/core/gui/PaperFormatUtils.cpp b/entry/src/main/cpp/src/core/gui/PaperFormatUtils.cpp deleted file mode 100644 index 637a573..0000000 --- a/entry/src/main/cpp/src/core/gui/PaperFormatUtils.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "PaperFormatUtils.h" - -#include "util/GListView.h" -#include "util/StringUtils.h" -#include "util/raii/GObjectSPtr.h" - -using xoj::util::GtkPaperSizeUPtr; - -void PaperFormatUtils::loadDefaultPaperSizes(PaperFormatMenuOptionVector& paperSizes) { - GList* default_sizes = gtk_paper_size_get_paper_sizes(false); - for (auto& s: GListView(default_sizes)) { - std::string name = gtk_paper_size_get_name(&s); - if (name == GTK_PAPER_NAME_A3 || name == GTK_PAPER_NAME_A4 || name == GTK_PAPER_NAME_A5 || - name == GTK_PAPER_NAME_LETTER || name == GTK_PAPER_NAME_LEGAL) { - paperSizes.emplace_back(GtkPaperSizeUPtr(&s)); - } else { - gtk_paper_size_free(&s); - } - } - g_list_free(default_sizes); - - // Name format: ftp://ftp.pwg.org/pub/pwg/candidates/cs-pwgmsn10-20020226-5101.1.pdf - paperSizes.emplace_back(GtkPaperSizeUPtr(gtk_paper_size_new("custom_16x9_320x180mm"))); - paperSizes.emplace_back(GtkPaperSizeUPtr(gtk_paper_size_new("custom_4x3_320x240mm"))); -} -void PaperFormatUtils::fillPaperFormatDropDown(const PaperFormatMenuOptionVector& menuOptions, - GtkComboBox* paperFormatComboBox) { - // Todo (gtk4) Use GtkDropDown instead and use another model accordingly - GtkCellRenderer* cell = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(paperFormatComboBox), cell, true); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(paperFormatComboBox), cell, "text", 0, nullptr); - - GtkListStore* store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); - gtk_combo_box_set_model(GTK_COMBO_BOX(paperFormatComboBox), GTK_TREE_MODEL(store)); - g_object_unref(store); // store is now owned by paperFormatComboBox - - for (auto& menuOption: menuOptions) { - GtkTreeIter iter; - gtk_list_store_append(store, &iter); - - if (menuOption.index()) { - auto& size = std::get(menuOption); - - std::string displayName = gtk_paper_size_get_display_name(size.get()); - if (StringUtils::startsWith(displayName, "custom_")) { - displayName = displayName.substr(7); - } - gtk_list_store_set(store, &iter, 0, displayName.c_str(), -1); - gtk_list_store_set(store, &iter, 1, size.get(), -1); - } else { - // When special non-GtkPaperSize option - const std::string_view displayName = std::get(menuOption); - gtk_list_store_set(store, &iter, 0, displayName.data(), -1); - gtk_list_store_set(store, &iter, 1, nullptr, -1); - } - } -} diff --git a/entry/src/main/cpp/src/core/gui/PaperFormatUtils.h b/entry/src/main/cpp/src/core/gui/PaperFormatUtils.h deleted file mode 100644 index 95b1c6b..0000000 --- a/entry/src/main/cpp/src/core/gui/PaperFormatUtils.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * Paper format utilities - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#include -#include -#include - -#include - -#include "util/raii/GtkPaperSizeUPtr.h" - -#pragma once - -namespace PaperFormatUtils { -/** - * @brief A vector of menu options, either being a GtkPaperSize or the displayed name of the option. - * @details The variant facilitates adding options which can't be expressed as a GtkPaperSize (e.g. a custom option - * or a copy current page format option) - */ -using PaperFormatMenuOptionVector = std::vector>; - -/** - * @brief Loads the default PaperSizes into the passed vector - * @param menuOptions The vector containg the menu options - */ -void loadDefaultPaperSizes(PaperFormatMenuOptionVector& menuOptions); - -/** - * @brief Adds the entries passed as vector of GtkPaperSize entries and/or special entries to the given combo box - * @param menuOptions The vector of menu options - * @param paperFormatComboBox A pointer to the combo box which should be configured as a paper format dropdown - */ -void fillPaperFormatDropDown(const PaperFormatMenuOptionVector& menuOptions, GtkComboBox* paperFormatComboBox); -} // namespace PaperFormatUtils \ No newline at end of file diff --git a/entry/src/main/cpp/src/core/gui/PdfFloatingToolbox.cpp b/entry/src/main/cpp/src/core/gui/PdfFloatingToolbox.cpp deleted file mode 100644 index 7f589e7..0000000 --- a/entry/src/main/cpp/src/core/gui/PdfFloatingToolbox.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#include "PdfFloatingToolbox.h" - -#include // for max, min -#include // for abs -#include // for size_t -#include -#include // for string -#include // for move -#include // for vector - -#include // for G_CALLBACK, g_signal_connect -#include - -#include "control/Control.h" // for Control -#include "control/ToolEnums.h" // for ToolType, TOOL_SELECT_PDF_TEXT_LI... -#include "control/ToolHandler.h" // for ToolHandler -#include "control/tools/PdfElemSelection.h" -#include "gui/PageView.h" // for XojPageView -#include "gui/XournalView.h" // for XournalView -#include "model/Document.h" // for Document -#include "model/Layer.h" // for Layer -#include "model/PageRef.h" // for PageRef -#include "model/Point.h" // for Point -#include "model/Stroke.h" // for Stroke, BUTT, StrokeTool::HIGHLIG... -#include "model/XojPage.h" // for XojPage -#include "undo/GroupUndoAction.h" // for GroupUndoAction -#include "undo/InsertUndoAction.h" // for InsertUndoAction -#include "undo/UndoAction.h" // for UndoAction -#include "undo/UndoRedoHandler.h" // for UndoRedoHandler -#include "util/Assert.h" // for xoj_assert -#include "util/gtk4_helper.h" // for gtk_widget_get_clipboard - -#include "MainWindow.h" // for MainWindow - -PdfFloatingToolbox::PdfFloatingToolbox(MainWindow* theMainWindow, GtkOverlay* overlay): - theMainWindow(theMainWindow), overlay(overlay, xoj::util::ref), position({0, 0}) { - this->floatingToolbox = theMainWindow->get("pdfFloatingToolbox"); - - gtk_overlay_add_overlay(overlay, this->floatingToolbox); - gtk_overlay_set_overlay_pass_through(overlay, this->floatingToolbox, true); - - g_signal_connect(overlay, "get-child-position", G_CALLBACK(this->getOverlayPosition), this); - - g_signal_connect(theMainWindow->get("pdfTbHighlight"), "clicked", G_CALLBACK(this->highlightCb), this); - g_signal_connect(theMainWindow->get("pdfTbCopyText"), "clicked", G_CALLBACK(this->copyTextCb), this); - g_signal_connect(theMainWindow->get("pdfTbUnderline"), "clicked", G_CALLBACK(this->underlineCb), this); - g_signal_connect(theMainWindow->get("pdfTbStrikethrough"), "clicked", G_CALLBACK(this->strikethroughCb), this); - g_signal_connect(theMainWindow->get("pdfTbChangeType"), "clicked", G_CALLBACK(this->switchSelectTypeCb), this); - - this->clearSelection(); - this->hide(); -} - -PdfFloatingToolbox::~PdfFloatingToolbox() = default; - -PdfElemSelection* PdfFloatingToolbox::getSelection() const { return this->pdfElemSelection.get(); } -bool PdfFloatingToolbox::hasSelection() const { return this->getSelection() != nullptr; } - -void PdfFloatingToolbox::clearSelection() { this->pdfElemSelection.reset(); } - -auto PdfFloatingToolbox::newSelection(double x, double y) -> const PdfElemSelection* { - this->pdfElemSelection = std::make_unique(x, y, this->theMainWindow->getControl()); - return this->pdfElemSelection.get(); -} - -void PdfFloatingToolbox::show(int x, int y) { - xoj_assert(this->getSelection()); - - // (x, y) are in the gtk window's coordinates. - // However, we actually show the toolbox in the overlay's coordinate system. - gtk_widget_translate_coordinates(gtk_widget_get_toplevel(this->floatingToolbox), GTK_WIDGET(overlay.get()), x, y, - &this->position.x, &this->position.y); - this->show(); - - // Record the color now: the active tool may change while the toolbox is up (e.g. if the tool is linked to a button) - this->color = theMainWindow->getXournal()->getControl()->getToolHandler()->getColor(); -} - -void PdfFloatingToolbox::hide() { - if (isHidden()) - return; - - gtk_widget_hide(this->floatingToolbox); -} - -auto PdfFloatingToolbox::getOverlayPosition(GtkOverlay* overlay, GtkWidget* widget, GdkRectangle* allocation, - PdfFloatingToolbox* self) -> gboolean { - if (widget == self->floatingToolbox) { - // Get existing width and height - GtkRequisition natural; - gtk_widget_get_preferred_size(widget, nullptr, &natural); - allocation->width = natural.width; - allocation->height = natural.height; - - // Make sure the "pdfFloatingToolbox" is fully displayed. - const int gap = 5; - - // By default, we show the toolbox below and to the right of the selected text. - // If the toolbox will go out of the window, then we'll flip the corresponding directions. - - GtkAllocation windowAlloc{}; - gtk_widget_get_allocation(GTK_WIDGET(overlay), &windowAlloc); - - bool rightOK = self->position.x + allocation->width + gap <= windowAlloc.width; - bool bottomOK = self->position.y + allocation->height + gap <= windowAlloc.height; - - allocation->x = rightOK ? self->position.x + gap : self->position.x - allocation->width - gap; - allocation->y = bottomOK ? self->position.y + gap : self->position.y - allocation->height - gap; - - return true; - } - - return false; -} - -void PdfFloatingToolbox::userCancelSelection() { - this->pdfElemSelection.reset(); - this->hide(); -} - -void PdfFloatingToolbox::highlightCb(GtkButton* button, PdfFloatingToolbox* pft) { - int markerOpacity = pft->theMainWindow->getControl()->getToolHandler()->getSelectPDFTextMarkerOpacity(); - pft->createStrokes(PdfMarkerStyle::POS_TEXT_MIDDLE, PdfMarkerStyle::WIDTH_TEXT_HEIGHT, markerOpacity); - pft->userCancelSelection(); -} - -void PdfFloatingToolbox::copyTextCb(GtkButton* button, PdfFloatingToolbox* pft) { - pft->copyTextToClipboard(); - pft->userCancelSelection(); -} - -void PdfFloatingToolbox::underlineCb(GtkButton* button, PdfFloatingToolbox* pft) { - pft->createStrokes(PdfMarkerStyle::POS_TEXT_BOTTOM, PdfMarkerStyle::WIDTH_TEXT_LINE, 230); - pft->userCancelSelection(); -} - -void PdfFloatingToolbox::strikethroughCb(GtkButton* button, PdfFloatingToolbox* pft) { - pft->createStrokes(PdfMarkerStyle::POS_TEXT_MIDDLE, PdfMarkerStyle::WIDTH_TEXT_LINE, 230); - pft->userCancelSelection(); -} - -void PdfFloatingToolbox::show() { - gtk_widget_hide(this->floatingToolbox); // force showing in new position - gtk_widget_show_all(this->floatingToolbox); -} - -void PdfFloatingToolbox::copyTextToClipboard() { - GtkClipboard* clipboard = gtk_widget_get_clipboard(this->theMainWindow->getWindow()); - if (const std::string& text = this->pdfElemSelection->getSelectedText(); !text.empty()) { - gtk_clipboard_set_text(clipboard, text.c_str(), -1); - } -} - -void PdfFloatingToolbox::createStrokes(PdfMarkerStyle position, PdfMarkerStyle width, int markerOpacity) { - const size_t pdfPageNo = this->pdfElemSelection->getSelectionPageNr(); - const size_t currentPage = theMainWindow->getXournal()->getCurrentPage(); - - // Get the PDF page that the current page corresponds to. - // It should be the same as the PDF page of the selection. - auto doc = this->theMainWindow->getControl()->getDocument(); - doc->lock_shared(); - const size_t pdfPageOfCurrentPage = doc->getPage(currentPage)->getPdfPageNr(); - doc->unlock_shared(); - - if (pdfPageOfCurrentPage != pdfPageNo) { - // There's probably a bug that violates our assumptions, so no-op. - g_warning("The current page's PDF page is not the same as the PDF page of the selection!"); - return; - } - - const auto textRects = this->pdfElemSelection->getSelectedTextRects(); - if (textRects.empty()) { - return; - } - - auto* control = this->theMainWindow->getControl(); - PageRef page = control->getCurrentPage(); - Layer* layer = page->getSelectedLayer(); - - Range dirtyRange; - std::vector strokes; - for (XojPdfRectangle rect: textRects) { - const double topOfLine = std::min(rect.y1, rect.y2); - const double middleOfLine = (rect.y1 + rect.y2) / 2; - const double bottomOfLine = std::max(rect.y1, rect.y2); - const double rectWidth = std::abs(rect.y2 - rect.y1); - - // the center line position of stroke - const double h = position == PdfMarkerStyle::POS_TEXT_BOTTOM ? bottomOfLine : - position == PdfMarkerStyle::POS_TEXT_MIDDLE ? middleOfLine : - topOfLine; - // the width of stroke - const double w = width == PdfMarkerStyle::WIDTH_TEXT_LINE ? 1 : rectWidth; - - auto stroke = std::make_unique(); - stroke->setColor(this->color); - stroke->setFill(markerOpacity); - stroke->setToolType(StrokeTool::HIGHLIGHTER); - stroke->setWidth(w); - stroke->addPoint(Point(rect.x1, h, -1)); - stroke->addPoint(Point(rect.x2, h, -1)); - stroke->setStrokeCapStyle(StrokeCapStyle::BUTT); - - dirtyRange.addPoint(rect.x1, h - 0.5 * w); - dirtyRange.addPoint(rect.x2, h + 0.5 * w); - - strokes.push_back(std::move(stroke)); - } - - std::vector strokePtrs(strokes.size()); - std::transform(strokes.begin(), strokes.end(), strokePtrs.begin(), [](auto& e) { return e.get(); }); - - doc->lock(); - for (auto&& s: strokes) { - layer->addElement(std::move(s)); - } - doc->unlock(); - page->fireElementsChanged(strokePtrs, dirtyRange); - - auto undoAct = std::make_unique(); - for (auto* stroke: strokePtrs) { - undoAct->addAction(std::make_unique(page, layer, stroke)); - } - control->getUndoRedoHandler()->addUndoAction(std::move(undoAct)); -} - -void PdfFloatingToolbox::switchSelectTypeCb(GtkButton* button, PdfFloatingToolbox* pft) { - ToolType type = pft->theMainWindow->getControl()->getToolHandler()->getToolType(); - - type = type == ToolType::TOOL_SELECT_PDF_TEXT_LINEAR ? ToolType::TOOL_SELECT_PDF_TEXT_RECT : - ToolType::TOOL_SELECT_PDF_TEXT_LINEAR; - - pft->theMainWindow->getControl()->selectTool(type); - - pft->pdfElemSelection->setToolType(type); - pft->pdfElemSelection->finalizeSelection(PdfElemSelection::selectionStyleForToolType(type)); -} - -bool PdfFloatingToolbox::isHidden() const { return !gtk_widget_is_visible(this->floatingToolbox); } diff --git a/entry/src/main/cpp/src/core/gui/PdfFloatingToolbox.h b/entry/src/main/cpp/src/core/gui/PdfFloatingToolbox.h deleted file mode 100644 index 54b41c1..0000000 --- a/entry/src/main/cpp/src/core/gui/PdfFloatingToolbox.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include // for uint8_t -#include // for unique_ptr - -#include // for GdkRectangle -#include // for gboolean -#include // for GtkButton, GtkOverlay - -#include "pdf/base/XojPdfPage.h" // for XojPdfPageSelectionStyle -#include "util/Color.h" // for Color -#include "util/raii/GObjectSPtr.h" // for GObjectSPtr - -class MainWindow; -class PdfElemSelection; - -enum class PdfMarkerStyle : uint8_t { - POS_TEXT_BOTTOM = 0, - POS_TEXT_MIDDLE, - POS_TEXT_TOP, - - WIDTH_TEXT_LINE, - WIDTH_TEXT_HEIGHT -}; - - -class PdfFloatingToolbox { -public: - PdfFloatingToolbox(MainWindow* theMainWindow, GtkOverlay* overlay); - PdfFloatingToolbox& operator=(const PdfFloatingToolbox&) = delete; - PdfFloatingToolbox(const PdfFloatingToolbox&) = delete; - PdfFloatingToolbox& operator=(PdfFloatingToolbox&&) = delete; - PdfFloatingToolbox(PdfFloatingToolbox&&) = delete; - ~PdfFloatingToolbox(); - -public: - /// Show the toolbox at the provided coordinates (relative to the application GTK window). - /// - /// Must have an active selection. - void show(int x, int y); - - /// Hide the floating toolbox widget (keeping the current selection). - void hide(); - - /// Returns true if the toolbox is currently hidden. - bool isHidden() const; - - /// Returns the selection, or nullptr if no PDF element is selected. - PdfElemSelection* getSelection() const; - - /// Clears the current selection (without any visual effects). - void clearSelection(); - - /// Create a new selection (without any visual effects) - const PdfElemSelection* newSelection(double x, double y); - - /// Returns true iff a PDF element is selected; - bool hasSelection() const; - - /// Cancel the selection, rerender the page, and hide the toolbox. - void userCancelSelection(); - - /// Track selection style used for unfinalized selections - XojPdfPageSelectionStyle selectionStyle = XojPdfPageSelectionStyle::Linear; - - /// Copy Selection to the Clipboard. - void copyTextToClipboard(); - -private: - void show(); - - static gboolean getOverlayPosition(GtkOverlay* overlay, GtkWidget* widget, GdkRectangle* allocation, - PdfFloatingToolbox* self); - - static void switchSelectTypeCb(GtkButton* button, PdfFloatingToolbox* pft); - static void strikethroughCb(GtkButton* button, PdfFloatingToolbox* pft); - static void underlineCb(GtkButton* button, PdfFloatingToolbox* pft); - static void copyTextCb(GtkButton* button, PdfFloatingToolbox* pft); - static void highlightCb(GtkButton* button, PdfFloatingToolbox* pft); - - void createStrokes(PdfMarkerStyle position, PdfMarkerStyle width, int markerOpacity); - -private: - GtkWidget* floatingToolbox; - MainWindow* theMainWindow; - Color color; ///< Used for strokes/highlighting - - /// The overlay that the toolbox should be displayed in. - xoj::util::GObjectSPtr overlay; - - std::unique_ptr pdfElemSelection; - - struct { - int x; - int y; - } position; -}; diff --git a/entry/src/main/cpp/src/core/gui/PopoverFactory.h b/entry/src/main/cpp/src/core/gui/PopoverFactory.h deleted file mode 100644 index 925130c..0000000 --- a/entry/src/main/cpp/src/core/gui/PopoverFactory.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Xournal++ - * - * Abstract class for creating popovers - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GtkWidget - -class PopoverFactory { -public: - PopoverFactory() = default; - virtual ~PopoverFactory() = default; - - /// Creates a GtkPopover. The returned ref is floating - virtual GtkWidget* createPopover() const = 0; -}; diff --git a/entry/src/main/cpp/src/core/gui/RepaintHandler.cpp b/entry/src/main/cpp/src/core/gui/RepaintHandler.cpp deleted file mode 100644 index 2aa21da..0000000 --- a/entry/src/main/cpp/src/core/gui/RepaintHandler.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "RepaintHandler.h" - -#include // for gtk_widget_queue_draw - -#include "gui/widgets/XournalWidget.h" // for gtk_xournal_repaint_area - -#include "PageView.h" // for XojPageView -#include "XournalView.h" // for XournalView - -RepaintHandler::RepaintHandler(XournalView* xournal): xournal(xournal) {} - -RepaintHandler::~RepaintHandler() { this->xournal = nullptr; } - -void RepaintHandler::repaintPage(const XojPageView* view) { - int x1 = view->getX(); - int y1 = view->getY(); - int x2 = x1 + view->getDisplayWidth(); - int y2 = y1 + view->getDisplayHeight(); - - gtk_xournal_repaint_area(this->xournal->getWidget(), x1, y1, x2, y2); -} - -void RepaintHandler::repaintPageArea(const XojPageView* view, int x1, int y1, int x2, int y2) { - int x = view->getX(); - int y = view->getY(); - gtk_xournal_repaint_area(this->xournal->getWidget(), x + x1, y + y1, x + x2, y + y2); -} - -void RepaintHandler::repaintPageBorder(const XojPageView* view) { gtk_widget_queue_draw(this->xournal->getWidget()); } diff --git a/entry/src/main/cpp/src/core/gui/RepaintHandler.h b/entry/src/main/cpp/src/core/gui/RepaintHandler.h deleted file mode 100644 index 9f72e33..0000000 --- a/entry/src/main/cpp/src/core/gui/RepaintHandler.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Xournal++ - * - * Class for render and repaint pages - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -class XojPageView; -class XournalView; - -class RepaintHandler { -public: - RepaintHandler(XournalView* xournal); - virtual ~RepaintHandler(); - -public: - /** - * Repaint a page - */ - void repaintPage(const XojPageView* view); - - /** - * Repaint a page area, coordinates are in view coordinates - */ - void repaintPageArea(const XojPageView* view, int x1, int y1, int x2, int y2); - - /** - * Repaints the page border (at least) - */ - void repaintPageBorder(const XojPageView* view); - -private: - XournalView* xournal; -}; diff --git a/entry/src/main/cpp/src/core/gui/SearchBar.cpp b/entry/src/main/cpp/src/core/gui/SearchBar.cpp deleted file mode 100644 index 06099b8..0000000 --- a/entry/src/main/cpp/src/core/gui/SearchBar.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#include "SearchBar.h" - -#include // for allocator, string - -#include // for GdkEventKey, GDK_SHIFT_MASK -#include // for GDK_KEY_Return -#include // for G_CALLBACK, g_signal_connect -#include // for g_free, g_strdup_printf - -#include "control/Control.h" // for Control -#include "control/ScrollHandler.h" // for ScrollHandler -#include "control/zoom/ZoomControl.h" // for ZoomControl -#include "gui/MainWindow.h" // for MainWindow -#include "model/Document.h" // for Document -#include "util/PlaceholderString.h" // for PlaceholderString -#include "util/i18n.h" // for _, FC, _F - -SearchBar::SearchBar(Control* control): control(control) { - MainWindow* win = control->getWindow(); - - GtkWidget* close = win->get("buttonCloseSearch"); - g_signal_connect(close, "clicked", G_CALLBACK(buttonCloseSearchClicked), this); - - GtkWidget* next = win->get("btSearchForward"); - GtkWidget* previous = win->get("btSearchBack"); - g_signal_connect(next, "clicked", - G_CALLBACK(+[](GtkButton*, gpointer d) { static_cast(d)->searchNext(); }), this); - g_signal_connect(previous, "clicked", - G_CALLBACK(+[](GtkButton*, gpointer d) { static_cast(d)->searchPrevious(); }), this); - - GtkWidget* searchTextField = win->get("searchTextField"); - g_signal_connect(searchTextField, "search-changed", G_CALLBACK(searchTextChangedCallback), this); - g_signal_connect(searchTextField, "stop-search", - G_CALLBACK(+[](GtkSearchEntry*, gpointer d) { static_cast(d)->showSearchBar(false); }), - this); - g_signal_connect(searchTextField, "next-match", G_CALLBACK(+[](GtkSearchEntry* e, gpointer d) { - static_cast(d)->searchNext(); - // Grab focus again since searching will take away focus - gtk_widget_grab_focus(GTK_WIDGET(e)); - }), - this); - g_signal_connect(searchTextField, "previous-match", G_CALLBACK(+[](GtkSearchEntry* e, gpointer d) { - static_cast(d)->searchPrevious(); - // Grab focus again since searching will take away focus - gtk_widget_grab_focus(GTK_WIDGET(e)); - }), - this); -#if GTK_MAJOR_VERSION == 3 - GtkBindingSet* bindingSet = gtk_binding_set_by_class(GTK_SEARCH_ENTRY_GET_CLASS(searchTextField)); - gtk_binding_entry_add_signal(bindingSet, GDK_KEY_Return, GdkModifierType(0), "next-match", 0); - gtk_binding_entry_add_signal(bindingSet, GDK_KEY_Return, GDK_SHIFT_MASK, "previous-match", 0); -#else - GtkEventController* ctrl = gtk_shortcut_controller_new(); - gtk_shortcut_controller_add_shortcut(GTK_SHORTCUT_CONTROLLER(ctrl), - gtk_shortcut_new(gtk_keyval_trigger_new(GDK_KEY_Return, GdkModifierType(0)), - gtk_signal_action_new("next-match"))); - gtk_shortcut_controller_add_shortcut(GTK_SHORTCUT_CONTROLLER(ctrl), - gtk_shortcut_new(gtk_keyval_trigger_new(GDK_KEY_Return, GDK_SHIFT_MASK), - gtk_signal_action_new("previous-match"))); - gtk_widget_add_controller(searchTextField, ctrl); -#endif - - cssTextFild = gtk_css_provider_new(); - gtk_style_context_add_provider(gtk_widget_get_style_context(win->get("searchTextField")), - GTK_STYLE_PROVIDER(cssTextFild), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); -} - -SearchBar::~SearchBar() { this->control = nullptr; } - -auto SearchBar::searchTextonCurrentPage(const char* text, size_t index, size_t* occurrences, XojPdfRectangle* matchRect) - -> bool { - size_t p = control->getCurrentPageNo(); - this->page = p; - - return control->searchTextOnPage(text, p, index, occurrences, matchRect); -} - -void SearchBar::search(const char* text) { - MainWindow* win = control->getWindow(); - GtkWidget* lbSearchState = win->get("lbSearchState"); - - bool found = true; - this->indexInPage = 0; - - if (*text != 0) { - found = searchTextonCurrentPage(text, 1, &this->occurrences, nullptr); - if (found) { - if (occurrences == 1) { - gtk_label_set_text(GTK_LABEL(lbSearchState), _("Text found once on this page")); - } else { - char* msg = g_strdup_printf(_("Text found %zu times on this page"), occurrences); - gtk_label_set_text(GTK_LABEL(lbSearchState), msg); - g_free(msg); - } - } else { - gtk_label_set_text(GTK_LABEL(lbSearchState), _("Text not found")); - } - } else { - searchTextonCurrentPage("", 1, nullptr, nullptr); - gtk_label_set_text(GTK_LABEL(lbSearchState), ""); - } - - if (found) { - gtk_css_provider_load_from_data(cssTextFild, "GtkSearchEntry {}", -1, nullptr); - } else { - gtk_css_provider_load_from_data(cssTextFild, "GtkSearchEntry { color: #ff0000; }", -1, nullptr); - } -} - -void SearchBar::searchTextChangedCallback(GtkSearchEntry* entry, SearchBar* searchBar) { - const char* text = gtk_entry_get_text(GTK_ENTRY(entry)); - searchBar->search(text); -} - -void SearchBar::buttonCloseSearchClicked(GtkButton* button, SearchBar* searchBar) { searchBar->showSearchBar(false); } - -template -void SearchBar::search(Fun next) { - - MainWindow* win = control->getWindow(); - GtkWidget* searchTextField = win->get("searchTextField"); - const char* text = gtk_entry_get_text(GTK_ENTRY(searchTextField)); - GtkWidget* lbSearchState = win->get("lbSearchState"); - if (*text == 0) { - return; - } - const size_t originalPage = page; - - XojPdfRectangle matchRect = XojPdfRectangle(); - // Search backwards through the pages, wrapping around if needed. - for (;;) { - next(text); - const bool found = control->searchTextOnPage(text, page, indexInPage, &occurrences, &matchRect); - - if (found) { - control->getScrollHandler()->scrollToPage(page, matchRect); - control->getScrollHandler(); - gtk_label_set_text(GTK_LABEL(lbSearchState), - (occurrences == 1 ? FC(_F("Text found once on page {1}") % (page + 1)) : - FC(_F("Text found {1} times on page {2} ({3} of {1})") % - occurrences % (page + 1) % indexInPage))); - return; - } - if (page == originalPage) { - gtk_label_set_text(GTK_LABEL(lbSearchState), _("Text not found, searched on all pages")); - return; - } - } -} - -void SearchBar::searchNext() { - size_t pageCount = control->getDocument()->getPageCount(); - search([&](const char* text) { - indexInPage++; - if (indexInPage > occurrences) { - control->searchTextOnPage(text, page, 1, &occurrences, nullptr); // clear the active marker - page++; - if (page >= pageCount) { - page = 0; - } - indexInPage = 1; - } - }); -} - -void SearchBar::searchPrevious() { - size_t pageCount = control->getDocument()->getPageCount(); - search([&](const char* text) { - indexInPage--; - if (indexInPage == 0 || indexInPage >= occurrences) { - control->searchTextOnPage(text, page, 1, &occurrences, nullptr); // clear the active marker - page--; - if (page > pageCount) { - page = pageCount - 1; - } - control->searchTextOnPage(text, page, 1, &occurrences, nullptr); - indexInPage = occurrences; - } - }); -} - -void SearchBar::showSearchBar(bool show) { - MainWindow* win = control->getWindow(); - GtkWidget* searchBar = win->get("searchBar"); - - if (show) { - GtkWidget* searchTextField = win->get("searchTextField"); - gtk_widget_show_all(searchBar); - gtk_widget_grab_focus(searchTextField); - this->indexInPage = 0; - } else { - gtk_widget_hide(searchBar); - const size_t pageCount = control->getDocument()->getPageCount(); - for (size_t i = pageCount - 1; i < pageCount; i--) { - control->searchTextOnPage("", i, 0, nullptr, nullptr); - } - } -} diff --git a/entry/src/main/cpp/src/core/gui/SearchBar.h b/entry/src/main/cpp/src/core/gui/SearchBar.h deleted file mode 100644 index c1cfc0b..0000000 --- a/entry/src/main/cpp/src/core/gui/SearchBar.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Xournal++ - * - * Handles the searchbar and search events - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GtkButton, GtkEntry -#include // for GtkCssProvider - -class Control; -class XojPdfRectangle; - -class SearchBar { -public: - SearchBar(Control* control); - virtual ~SearchBar(); - - void showSearchBar(bool show); - -private: - static void buttonCloseSearchClicked(GtkButton* button, SearchBar* searchBar); - static void searchTextChangedCallback(GtkSearchEntry* entry, SearchBar* searchBar); - - static void buttonNextSearchClicked(GtkButton* button, SearchBar* searchBar); - static void buttonPreviousSearchClicked(GtkButton* button, SearchBar* searchBar); - - /** - * @brief Searches the entire document until a match is found, starting from `page = next(currentPage)` and - * iterating through the pages via page = next(page). The search stops after the first page with at least one match. - * All the match on that page are stored in XojPageView::search of the corresponding page. The current page is not - * search! - * @param next The parameter `next` must be convertible to size_t(size_t) and satisfy the following assertions - * * Iterating from page = next(currentPage) by page = next(page) must reach page == currentPage at - * some point. - * * If page is a valid page number, then so is next(page). - */ - template - void search(Fun next); - - /** - * @brief Named specialization of search(), where next(page) = (page + 1) % pageCount - */ - void searchNext(); - /** - * @brief Named specialization of search(), where next(page) = (page + pageCount - 1) % pageCount - */ - void searchPrevious(); - - void search(const char* text); - bool searchTextonCurrentPage(const char* text, size_t index, size_t* occurrences, XojPdfRectangle* matchRect); - -private: - Control* control; - GtkCssProvider* cssTextFild; - size_t page = 0; - size_t indexInPage = 0; - size_t occurrences = 0; -}; diff --git a/entry/src/main/cpp/src/core/gui/Shadow.cpp b/entry/src/main/cpp/src/core/gui/Shadow.cpp deleted file mode 100644 index 7450bc3..0000000 --- a/entry/src/main/cpp/src/core/gui/Shadow.cpp +++ /dev/null @@ -1,217 +0,0 @@ -#include "Shadow.h" - -#include - -#include "ShadowCode.c" - -Shadow* Shadow::instance = new Shadow(); - -using u8ptr = const unsigned char*; - -Shadow::Shadow() { - const int sBrSize = shadowBottomRightSize; - const int sTlSize = shadowTopLeftSize; - - this->edgeTopLeft = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sTlSize * 2, sTlSize * 2); - cairo_t* cr = cairo_create(this->edgeTopLeft); - drawShadowEdge(cr, 0, 0, sTlSize, sTlSize, reinterpret_cast(shadowEdge1), 0, 0, 0); - cairo_destroy(cr); - - this->edgeTopRight = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sBrSize * 2, sTlSize * 2); - cr = cairo_create(this->edgeTopRight); - drawShadowEdge(cr, 0, 0, sBrSize, sTlSize, reinterpret_cast(shadowEdge2), 0, 0, 0); - cairo_destroy(cr); - - this->edgeBottomRight = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sBrSize * 2, sBrSize * 2); - cr = cairo_create(this->edgeBottomRight); - drawShadowEdge(cr, 0, 0, sBrSize, sBrSize, reinterpret_cast(shadowEdge3), 0, 0, 0); - cairo_destroy(cr); - - this->edgeBottomLeft = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, sTlSize * 2, sBrSize * 2); - cr = cairo_create(this->edgeBottomLeft); - drawShadowEdge(cr, 0, 0, sTlSize, sBrSize, reinterpret_cast(shadowEdge4), 0, 0, 0); - cairo_destroy(cr); -} - -Shadow::~Shadow() { - cairo_surface_destroy(this->edgeBottomLeft); - cairo_surface_destroy(this->edgeBottomRight); - cairo_surface_destroy(this->edgeTopLeft); - cairo_surface_destroy(this->edgeTopRight); - this->edgeBottomLeft = nullptr; - this->edgeBottomRight = nullptr; - this->edgeTopLeft = nullptr; - this->edgeTopRight = nullptr; - - if (this->left) { - cairo_surface_destroy(this->left); - } - if (this->top) { - cairo_surface_destroy(this->top); - } - if (this->right) { - cairo_surface_destroy(this->right); - } - if (this->bottom) { - cairo_surface_destroy(this->bottom); - } - - this->left = nullptr; - this->top = nullptr; - this->right = nullptr; - this->bottom = nullptr; -} - -auto Shadow::getShadowBottomRightSize() -> int { return shadowBottomRightSize; } - -auto Shadow::getShadowTopLeftSize() -> int { return shadowTopLeftSize; } - -void Shadow::drawShadowEdge(cairo_t* cr, int x, int y, int width, int height, const unsigned char* edge, double r, - double g, double b) { - int w = width * 2; - int h = height * 2; - - for (int u = 0; u < h; u++) { - for (int i = 0; i < w; i++) { - double a = edge[u * w + i] / 255.0; - cairo_set_source_rgba(cr, r, g, b, a); - - cairo_rectangle(cr, x + i, y + u, 1, 1); - cairo_fill(cr); - } - } -} - -void Shadow::paintEdge(cairo_t* cr, cairo_surface_t* image, int x, int y, int width, int height) { - cairo_set_source_surface(cr, image, x - width, y - height); - cairo_rectangle(cr, x - width, y - height, width * 2, height * 2); - cairo_fill(cr); -} - -static constexpr int PATTERN_LENGTH = 200; ///< Why not? - -static void setPattern(cairo_t* cr, cairo_surface_t* patt, double offsetX, double offsetY) { - cairo_pattern_t* p = cairo_pattern_create_for_surface(patt); - cairo_pattern_set_extend(p, CAIRO_EXTEND_REPEAT); - cairo_matrix_t m; - cairo_matrix_init_translate(&m, -offsetX, -offsetY); - cairo_pattern_set_matrix(p, &m); - cairo_set_source(cr, p); - cairo_pattern_destroy(p); -} - -void Shadow::drawShadowTop(cairo_t* cr, int x, int y, int width, double r, double g, double b) { - - if (!this->top) { - this->top = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PATTERN_LENGTH, shadowTopLeftSize); - cairo_t* cr2 = cairo_create(this->top); - - double a = NAN; - - // draw shadow on top and left - for (int i = 0; i < shadowTopLeftSize; i++) { - a = shadowTopLeft[i] / 255.0; - cairo_set_source_rgba(cr2, r, g, b, a); - - cairo_rectangle(cr2, 0, i, PATTERN_LENGTH, 1); - cairo_fill(cr2); - } - - cairo_destroy(cr2); - } - - setPattern(cr, this->top, x + shadowTopLeftSize, y - shadowTopLeftSize); - cairo_rectangle(cr, x + shadowTopLeftSize, y - shadowTopLeftSize, width - 2 * shadowTopLeftSize, shadowTopLeftSize); - cairo_fill(cr); -} - -void Shadow::drawShadowLeft(cairo_t* cr, int x, int y, int height, double r, double g, double b) { - if (!this->left) { - this->left = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, shadowTopLeftSize, PATTERN_LENGTH); - cairo_t* cr2 = cairo_create(this->left); - - double a = NAN; - - // draw shadow on top and left - for (int i = 0; i < shadowTopLeftSize; i++) { - a = shadowTopLeft[i] / 255.0; - cairo_set_source_rgba(cr2, r, g, b, a); - - cairo_rectangle(cr2, i, 0, 1, PATTERN_LENGTH); - cairo_fill(cr2); - } - - cairo_destroy(cr2); - } - - setPattern(cr, this->left, x - shadowTopLeftSize, y + shadowTopLeftSize); - cairo_rectangle(cr, x - shadowTopLeftSize, y + shadowTopLeftSize, shadowTopLeftSize, - height - 2 * shadowTopLeftSize); - cairo_fill(cr); -} - -void Shadow::drawShadowRight(cairo_t* cr, int x, int y, int height, double r, double g, double b) { - if (!this->right) { - this->right = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, shadowBottomRightSize, PATTERN_LENGTH); - cairo_t* cr2 = cairo_create(this->right); - - double a = NAN; - - // draw shadow on top and left - for (int i = 0; i < shadowBottomRightSize; i++) { - a = shadowBottomRight[i] / 255.0; - cairo_set_source_rgba(cr2, r, g, b, a); - - cairo_rectangle(cr2, i, 0, 1, PATTERN_LENGTH); - cairo_fill(cr2); - } - - cairo_destroy(cr2); - } - - setPattern(cr, this->right, x, y + shadowBottomRightSize); - cairo_rectangle(cr, x, y + shadowBottomRightSize, shadowBottomRightSize, height - 2 * shadowBottomRightSize); - cairo_fill(cr); -} - -void Shadow::drawShadowBottom(cairo_t* cr, int x, int y, int width, double r, double g, double b) { - if (!this->bottom) { - this->bottom = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PATTERN_LENGTH, shadowBottomRightSize); - cairo_t* cr2 = cairo_create(this->bottom); - - - // draw shadow on top and left - for (int i = 0; i < shadowBottomRightSize; i++) { - auto a = shadowBottomRight[i] / 255.0; - cairo_set_source_rgba(cr2, r, g, b, a); - - cairo_rectangle(cr2, 0, i, PATTERN_LENGTH, 1); - cairo_fill(cr2); - } - - cairo_destroy(cr2); - } - - setPattern(cr, this->bottom, x + shadowBottomRightSize, y); - cairo_rectangle(cr, x + shadowBottomRightSize, y, width - 2 * shadowBottomRightSize, shadowBottomRightSize); - cairo_fill(cr); -} - -void Shadow::drawShadowImpl(cairo_t* cr, int x, int y, int width, int height) { - const int sBrSize = shadowBottomRightSize; - const int sTlSize = shadowTopLeftSize; - - drawShadowTop(cr, x, y, width - 3, 0, 0, 0); - drawShadowLeft(cr, x, y, height - 3, 0, 0, 0); - drawShadowRight(cr, x + width, y - 4, height + 5, 0, 0, 0); - drawShadowBottom(cr, x - 4, y + height, width + 5, 0, 0, 0); - - paintEdge(cr, this->edgeTopLeft, x, y, sTlSize, sTlSize); - paintEdge(cr, this->edgeTopRight, x + width + 1, y, sBrSize, sTlSize); - paintEdge(cr, this->edgeBottomLeft, x, y + height + 1, sTlSize, sBrSize); - paintEdge(cr, this->edgeBottomRight, x + width + 1, y + height + 1, sBrSize, sBrSize); -} - -void Shadow::drawShadow(cairo_t* cr, int x, int y, int width, int height) { - Shadow::instance->drawShadowImpl(cr, x, y, width, height); -} diff --git a/entry/src/main/cpp/src/core/gui/Shadow.h b/entry/src/main/cpp/src/core/gui/Shadow.h deleted file mode 100644 index 29f8b25..0000000 --- a/entry/src/main/cpp/src/core/gui/Shadow.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Xournal++ - * - * Settings Dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_surface_t, cairo_t - -class Shadow { -private: - Shadow(); - virtual ~Shadow(); - - static void drawShadowEdge(cairo_t* cr, int x, int y, int width, int height, const unsigned char* edge, double r, - double g, double b); - void drawShadowImpl(cairo_t* cr, int x, int y, int width, int height); - - static void paintEdge(cairo_t* cr, cairo_surface_t* image, int x, int y, int width, int height); - - void drawShadowTop(cairo_t* cr, int x, int y, int width, double r, double g, double b); - void drawShadowLeft(cairo_t* cr, int x, int y, int height, double r, double g, double b); - void drawShadowRight(cairo_t* cr, int x, int y, int height, double r, double g, double b); - void drawShadowBottom(cairo_t* cr, int x, int y, int width, double r, double g, double b); - -public: - /** - * This is the public interface of this class - */ - static void drawShadow(cairo_t* cr, int x, int y, int width, int height); - static int getShadowBottomRightSize(); - static int getShadowTopLeftSize(); - -private: - static Shadow* instance; - - cairo_surface_t* edgeTopLeft = nullptr; - cairo_surface_t* edgeTopRight = nullptr; - cairo_surface_t* edgeBottomLeft = nullptr; - cairo_surface_t* edgeBottomRight = nullptr; - - cairo_surface_t* top = nullptr; - cairo_surface_t* right = nullptr; - cairo_surface_t* bottom = nullptr; - cairo_surface_t* left = nullptr; -}; diff --git a/entry/src/main/cpp/src/core/gui/ShadowCode.c b/entry/src/main/cpp/src/core/gui/ShadowCode.c deleted file mode 100644 index d923164..0000000 --- a/entry/src/main/cpp/src/core/gui/ShadowCode.c +++ /dev/null @@ -1,99 +0,0 @@ -/////////////////////////////////////////////// -// Auto-generated from image source -const int shadowTopLeftSize = 8; -const int shadowBottomRightSize = 12; -const unsigned char shadowTopLeft[] = {0, 1, 3, 6, 12, 22, 36, 57}; -const unsigned char shadowBottomRight[] = {171, 142, 111, 82, 56, 37, 22, 12, 6, 3, 1, 0}; -const unsigned char shadowEdge1[16][16] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, - {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3}, - {0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3, 4, 5, 5, 5, 6}, - {0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 11}, - {0, 0, 0, 1, 1, 2, 3, 5, 7, 10, 12, 15, 17, 19, 20, 21}, - {0, 0, 0, 1, 2, 3, 5, 8, 12, 16, 20, 24, 28, 31, 33, 34}, - {0, 0, 1, 1, 3, 5, 8, 13, 18, 25, 32, 39, 44, 49, 52, 54}, - {0, 0, 1, 2, 4, 7, 12, 18, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 1, 3, 5, 9, 16, 25, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 1, 3, 7, 12, 20, 32, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 4, 8, 15, 25, 38, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 5, 9, 17, 28, 44, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 5, 10, 18, 31, 49, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 5, 11, 20, 33, 52, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 6, 11, 21, 35, 54, 0, 0, 0, 0, 0, 0, 0, 0}, - -}; -const unsigned char shadowEdge2[16][24] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 4, 3, 3, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0}, - {12, 12, 12, 12, 12, 12, 12, 11, 11, 10, 9, 8, 7, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0}, - {22, 22, 22, 22, 22, 22, 21, 21, 20, 19, 17, 15, 12, 10, 7, 5, 3, 2, 1, 1, 0, 0, 0, 0}, - {36, 36, 36, 36, 36, 36, 35, 34, 33, 31, 28, 24, 20, 16, 12, 8, 5, 3, 2, 1, 0, 0, 0, 0}, - {57, 57, 57, 57, 57, 56, 56, 54, 52, 49, 44, 39, 32, 25, 18, 13, 8, 5, 3, 1, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 46, 36, 27, 18, 12, 7, 4, 2, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 63, 49, 36, 25, 16, 10, 5, 3, 1, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 80, 63, 46, 32, 20, 12, 7, 3, 1, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116, 96, 76, 56, 38, 25, 15, 8, 4, 2, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 111, 87, 64, 44, 28, 17, 9, 5, 2, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 147, 122, 96, 71, 49, 31, 19, 10, 5, 2, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 131, 102, 75, 52, 33, 20, 11, 5, 2, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 136, 107, 79, 54, 35, 21, 11, 6, 3, 1, 0, 0}, - -}; -const unsigned char shadowEdge3[24][24] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 143, 112, 83, 57, 37, 22, 12, 6, 3, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 143, 112, 83, 57, 37, 22, 12, 6, 3, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 143, 112, 83, 57, 37, 22, 12, 6, 3, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 143, 112, 83, 57, 37, 22, 12, 6, 3, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 172, 142, 112, 82, 57, 36, 22, 12, 6, 3, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 170, 141, 111, 82, 56, 36, 21, 12, 6, 3, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 168, 140, 109, 81, 56, 36, 21, 12, 6, 3, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 136, 107, 79, 54, 35, 21, 11, 6, 3, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 158, 131, 102, 75, 52, 33, 20, 11, 5, 2, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 148, 123, 96, 71, 49, 31, 19, 10, 5, 2, 1, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 134, 111, 87, 64, 44, 28, 17, 9, 5, 2, 1, 0, 0}, - {173, 173, 173, 173, 172, 171, 169, 165, 158, 148, 134, 117, 97, 76, 56, 39, 25, 15, 8, 4, 2, 1, 0, 0}, - {143, 143, 143, 143, 142, 142, 140, 136, 131, 123, 111, 97, 80, 63, 46, 32, 20, 12, 7, 3, 1, 1, 0, 0}, - {112, 112, 112, 112, 112, 111, 109, 107, 103, 96, 87, 76, 63, 49, 36, 25, 16, 10, 5, 3, 1, 0, 0, 0}, - {83, 83, 83, 83, 83, 82, 81, 79, 76, 71, 65, 56, 47, 36, 27, 19, 12, 7, 4, 2, 1, 0, 0, 0}, - {57, 57, 57, 57, 57, 56, 56, 54, 52, 49, 44, 39, 32, 25, 18, 13, 8, 5, 3, 1, 1, 0, 0, 0}, - {37, 37, 37, 37, 37, 37, 36, 35, 34, 32, 29, 25, 21, 16, 12, 8, 5, 3, 2, 1, 0, 0, 0, 0}, - {22, 22, 22, 22, 22, 22, 21, 21, 20, 19, 17, 15, 12, 10, 7, 5, 3, 2, 1, 1, 0, 0, 0, 0}, - {12, 12, 12, 12, 12, 12, 12, 11, 11, 10, 9, 8, 7, 5, 4, 3, 2, 1, 1, 0, 0, 0, 0, 0}, - {6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 4, 3, 3, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0}, - {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - -}; -const unsigned char shadowEdge4[24][16] = { - {0, 1, 3, 6, 12, 22, 36, 57, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 3, 6, 12, 22, 36, 57, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 3, 6, 12, 22, 36, 57, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 3, 6, 12, 22, 36, 57, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 3, 6, 12, 22, 36, 57, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 3, 6, 12, 21, 36, 56, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 6, 11, 21, 36, 55, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 6, 11, 21, 35, 54, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 5, 11, 20, 33, 52, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 5, 10, 19, 31, 49, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 5, 9, 17, 28, 44, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 1, 2, 4, 8, 15, 25, 39, 56, 76, 97, 117, 134, 148, 158, 165}, - {0, 1, 1, 3, 7, 12, 20, 32, 46, 63, 80, 97, 111, 123, 131, 136}, - {0, 0, 1, 3, 5, 9, 16, 25, 36, 49, 63, 76, 87, 96, 102, 107}, - {0, 0, 1, 2, 4, 7, 12, 18, 27, 36, 47, 56, 64, 71, 76, 79}, - {0, 0, 1, 1, 3, 5, 8, 13, 18, 25, 32, 39, 44, 49, 52, 54}, - {0, 0, 0, 1, 2, 3, 5, 8, 12, 16, 21, 25, 29, 32, 34, 35}, - {0, 0, 0, 1, 1, 2, 3, 5, 7, 10, 12, 15, 17, 19, 20, 21}, - {0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 11}, - {0, 0, 0, 0, 0, 1, 1, 1, 2, 3, 3, 4, 5, 5, 5, 6}, - {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - -}; -/////////////////////////////////////////////// diff --git a/entry/src/main/cpp/src/core/gui/ToolbarDefinitions.h b/entry/src/main/cpp/src/core/gui/ToolbarDefinitions.h deleted file mode 100644 index 91e1051..0000000 --- a/entry/src/main/cpp/src/core/gui/ToolbarDefinitions.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Xournal++ - * - * The definitions for the possibel toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -typedef struct { - /** - * The name in the glade.xml file - */ - const char* guiName; - - /** - * The name in the .ini file - */ - const char* propName; - - /** - * if horizontal (true) or vertical (false) - */ - bool horizontal; -} ToolbarEntryDefintion; - -const static ToolbarEntryDefintion TOOLBAR_DEFINITIONS[] = { - {"tbTop1", "toolbarTop1", true}, {"tbTop2", "toolbarTop2", true}, - {"tbLeft1", "toolbarLeft1", false}, {"tbLeft2", "toolbarLeft2", false}, - {"tbRight1", "toolbarRight1", false}, {"tbRight2", "toolbarRight2", false}, - {"tbBottom1", "toolbarBottom1", true}, {"tbBottom2", "toolbarBottom2", true}, - {"tbFloat1", "toolbarFloat1", true}, // define this index below as TBFloatFirst - {"tbFloat2", "toolbarFloat2", true}, {"tbFloat3", "toolbarFloat3", true}, - {"tbFloat4", "toolbarFloat4", true} // define this index below as TBFloatLast -}; - - -const static int TOOLBAR_DEFINITIONS_LEN = G_N_ELEMENTS(TOOLBAR_DEFINITIONS); - -#define TBFloatFirst 8 -#define TBFloatLast 11 diff --git a/entry/src/main/cpp/src/core/gui/ToolitemDragDrop.cpp b/entry/src/main/cpp/src/core/gui/ToolitemDragDrop.cpp deleted file mode 100644 index 41a2108..0000000 --- a/entry/src/main/cpp/src/core/gui/ToolitemDragDrop.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "ToolitemDragDrop.h" - -#include // for g_object_... -#include // for g_malloc - -#include "gui/toolbarMenubar/AbstractToolItem.h" // for AbstractT... -#include "gui/toolbarMenubar/icon/ToolbarSeparatorImage.h" // for getNewToo... - -struct NamedColor; - -const char* ATTACH_DRAG_DROP_DATA = "XOJ_DRAG_DROP_DATA"; - -void ToolitemDragDrop::attachMetadata(GtkWidget* w, int id, AbstractToolItem* ait) { - ToolItemDragDropData* d = g_new(ToolItemDragDropData, 1); - d->identify = ToolItemDragDropData_Identify; - d->id = id; - d->item = ait; - d->type = TOOL_ITEM_ITEM; - d->paletteColorIndex = 0; - - g_object_set_data_full(G_OBJECT(w), ATTACH_DRAG_DROP_DATA, d, static_cast(g_free)); -} - -auto ToolitemDragDrop::ToolItemDragDropData_new(AbstractToolItem* item) -> std::unique_ptr { - auto d = std::make_unique(); - d->identify = ToolItemDragDropData_Identify; - d->id = -1; - d->item = item; - d->type = TOOL_ITEM_ITEM; - d->paletteColorIndex = 0; - - return d; -} - -void ToolitemDragDrop::attachMetadata(GtkWidget* w, int id, ToolItemType type) { - ToolItemDragDropData* d = g_new(ToolItemDragDropData, 1); - d->identify = ToolItemDragDropData_Identify; - d->id = id; - d->item = nullptr; - d->type = type; - d->paletteColorIndex = 0; - - g_object_set_data_full(G_OBJECT(w), ATTACH_DRAG_DROP_DATA, d, static_cast(g_free)); -} - -void ToolitemDragDrop::attachMetadataColor(GtkWidget* w, int id, size_t paletteColorIndex, AbstractToolItem* item) { - ToolItemDragDropData* d = g_new(ToolItemDragDropData, 1); - d->identify = ToolItemDragDropData_Identify; - d->id = id; - d->item = item; - d->type = TOOL_ITEM_COLOR; - d->paletteColorIndex = paletteColorIndex; - - g_object_set_data_full(G_OBJECT(w), ATTACH_DRAG_DROP_DATA, d, static_cast(g_free)); -} - -auto ToolitemDragDrop::getIcon(ToolItemDragDropData* data) -> GtkWidget* { - if (data->type == TOOL_ITEM_ITEM || data->type == TOOL_ITEM_COLOR) { - return data->item->getNewToolIcon(); - } - if (data->type == TOOL_ITEM_SEPARATOR) { - return ToolbarSeparatorImage::newImage(SeparatorType::SEPARATOR); - } - if (data->type == TOOL_ITEM_SPACER) { - return ToolbarSeparatorImage::newImage(SeparatorType::SPACER); - } - - g_warning("ToolitemDragDrop::getIcon unhandled type: %i\n", data->type); - return gtk_image_new(); -} - -auto ToolitemDragDrop::checkToolItemDragDropData(ToolItemDragDropData const* d) -> bool { - return d->identify == ToolItemDragDropData_Identify; -} - -auto ToolitemDragDrop::metadataGetMetadata(GtkWidget* w) -> ToolItemDragDropData* { - void* ptr = g_object_get_data(G_OBJECT(w), ATTACH_DRAG_DROP_DATA); - if (ptr == nullptr) { - g_warning("ToolitemDragDrop::metadataGetMetadata Could not get Metadata %s from %s\n", ATTACH_DRAG_DROP_DATA, - g_type_name(G_TYPE_FROM_INSTANCE(w))); - return nullptr; - } - if (!checkToolItemDragDropData(static_cast(ptr))) { - g_warning("ToolitemDragDrop::metadataGetMetadata data is not an instance of ToolItemDragDropData!"); - return nullptr; - } - return static_cast(ptr); -} diff --git a/entry/src/main/cpp/src/core/gui/ToolitemDragDrop.h b/entry/src/main/cpp/src/core/gui/ToolitemDragDrop.h deleted file mode 100644 index f56fc27..0000000 --- a/entry/src/main/cpp/src/core/gui/ToolitemDragDrop.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Xournal++ - * - * Helper for Toolbar Drag & Drop implementation - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for GdkPixbuf -#include // for GtkWidget - -class AbstractToolItem; -struct NamedColor; - -enum ToolItemType { TOOL_ITEM_SEPARATOR = 0, TOOL_ITEM_SPACER, TOOL_ITEM_ITEM, TOOL_ITEM_COLOR }; - -#define ToolItemDragDropData_Identify 0xFA090201 - -struct ToolItemDragDropData { - unsigned int identify; - ToolItemType type; - int id; - AbstractToolItem* item; - size_t paletteColorIndex; -}; - -class ToolitemDragDrop { -private: - ToolitemDragDrop(); - virtual ~ToolitemDragDrop(); - -public: - static void attachMetadata(GtkWidget* w, int id, AbstractToolItem* ait); - static void attachMetadata(GtkWidget* w, int id, ToolItemType type); - static void attachMetadataColor(GtkWidget* w, int id, size_t paletteColorIndex, AbstractToolItem* item); - -public: - static std::unique_ptr ToolItemDragDropData_new(AbstractToolItem* item); - static bool checkToolItemDragDropData(ToolItemDragDropData const* d); - - static ToolItemDragDropData* metadataGetMetadata(GtkWidget* w); - - /** - * Returns: (transfer floating) - */ - static GtkWidget* getIcon(ToolItemDragDropData* data); - -public: - static void removeFromToolbarForMove(GtkWidget* widget); -}; diff --git a/entry/src/main/cpp/src/core/gui/XournalView.cpp b/entry/src/main/cpp/src/core/gui/XournalView.cpp deleted file mode 100644 index b953ff2..0000000 --- a/entry/src/main/cpp/src/core/gui/XournalView.cpp +++ /dev/null @@ -1,861 +0,0 @@ -#include "XournalView.h" - -#include // for max, min -#include // for begin -#include // for unique_ptr, make_unique -#include // for optional -#include - -#include // for GdkEventKey, GDK_SHIF... -#include // for GDK_KEY_Page_Down -#include // for g_object_ref_sink - -#include "control/Control.h" // for Control -#include "control/PdfCache.h" // for PdfCache -#include "control/ScrollHandler.h" // for ScrollHandler -#include "control/ToolHandler.h" // for ToolHandler -#include "control/actions/ActionDatabase.h" // for ActionDatabase -#include "control/jobs/XournalScheduler.h" // for XournalScheduler -#include "control/settings/MetadataManager.h" // for MetadataManager -#include "control/settings/Settings.h" // for Settings -#include "control/tools/CursorSelectionType.h" // for CURSOR_SELECTION_NONE -#include "control/tools/EditSelection.h" // for EditSelection -#include "control/zoom/ZoomControl.h" // for ZoomControl -#include "gui/MainWindow.h" // for MainWindow -#include "gui/PdfFloatingToolbox.h" // for PdfFloatingToolbox -#include "gui/inputdevices/GeometryToolInputHandler.h" // for GeometryToolInputHandler -#include "gui/inputdevices/HandRecognition.h" // for HandRecognition -#include "gui/inputdevices/InputContext.h" // for InputContext -#include "gui/toolbarMenubar/ColorToolItem.h" // for ColorToolItem -#include "gui/toolbarMenubar/ToolMenuHandler.h" // for ToolMenuHandler -#include "gui/widgets/XournalWidget.h" // for gtk_xournal_get_layout -#include "model/Document.h" // for Document -#include "model/Element.h" // for Element, ELEMENT_STROKE -#include "model/PageRef.h" // for PageRef -#include "model/Stroke.h" // for Stroke, StrokeTool::E... -#include "model/XojPage.h" // for XojPage -#include "undo/DeleteUndoAction.h" // for DeleteUndoAction -#include "undo/UndoRedoHandler.h" // for UndoRedoHandler -#include "util/Assert.h" // for xoj_assert -#include "util/Point.h" // for Point -#include "util/Rectangle.h" // for Rectangle -#include "util/Util.h" // for npos -#include "util/glib_casts.h" // for wrap_v -#include "util/gtk4_helper.h" // for gtk_scrolled_window_set_child -#include "util/safe_casts.h" // for round_cast - -#include "Layout.h" // for Layout -#include "PageView.h" // for XojPageView -#include "RepaintHandler.h" // for RepaintHandler -#include "XournalppCursor.h" // for XournalppCursor - -using xoj::util::Rectangle; - -constexpr int REGULAR_MOVE_AMOUNT = 3; -constexpr int SMALL_MOVE_AMOUNT = 1; -constexpr int LARGE_MOVE_AMOUNT = 10; - -std::pair XournalView::preloadPageBounds(size_t page, size_t maxPage) { - const size_t preloadBefore = this->control->getSettings()->getPreloadPagesBefore(); - const size_t preloadAfter = this->control->getSettings()->getPreloadPagesAfter(); - const size_t lower = page > preloadBefore ? page - preloadBefore : 0; - const size_t upper = std::min(maxPage, page + preloadAfter + 1); - return {lower, upper}; -} - -XournalView::XournalView(GtkWidget* parent, Control* control, ScrollHandling* scrollHandling): - scrollHandling(scrollHandling), control(control) { - Document* doc = control->getDocument(); - doc->lock_shared(); - if (doc->getPdfPageCount() != 0) { - this->cache = std::make_unique(doc->getPdfDocument(), control->getSettings()); - } - doc->unlock_shared(); - - registerListener(control); - - InputContext* inputContext = new InputContext(this, scrollHandling); - this->widget = gtk_xournal_new(this, inputContext); - g_object_ref_sink(this->widget); // take ownership without increasing the ref count - - gtk_container_add(GTK_CONTAINER(parent), this->widget); - gtk_widget_show(this->widget); - - - g_signal_connect(getWidget(), "realize", G_CALLBACK(+[](GtkWidget* widget, gpointer) { - // Disable event compression - if (gtk_widget_get_realized(widget)) { - gdk_window_set_event_compression(gtk_widget_get_window(widget), false); - } else { - g_warning("could not disable event compression"); - } - }), - nullptr); - - this->repaintHandler = std::make_unique(this); - - control->getZoomControl()->addZoomListener(this); - - gtk_widget_set_can_default(this->widget, true); - gtk_widget_grab_default(this->widget); - - gtk_widget_grab_focus(this->widget); - - this->cleanupTimeout = g_timeout_add_seconds(5, xoj::util::wrap_v, this); -} - -XournalView::~XournalView() { - g_source_remove(this->cleanupTimeout); - - gtk_widget_destroy(this->widget); - this->widget = nullptr; -} - - -auto XournalView::clearMemoryTimer(XournalView* widget) -> gboolean { - widget->cleanupBufferCache(); - return G_SOURCE_CONTINUE; -} - -auto XournalView::cleanupBufferCache() -> void { - const auto& [pagesLower, pagesUpper] = this->preloadPageBounds(this->currentPage, this->viewPages.size()); - xoj_assert(pagesLower <= pagesUpper); - - std::unordered_set retainedPdfPages; - - for (size_t i = 0; i < this->viewPages.size(); i++) { - auto&& page = this->viewPages[i]; - const bool isPreload = pagesLower <= i && i < pagesUpper; - const bool shouldRetain = isPreload || page->isVisible(); - - if (shouldRetain) { - const size_t pdfPageNo = page->getPage()->getPdfPageNr(); - if (pdfPageNo != npos) { - retainedPdfPages.insert(pdfPageNo); - } - continue; - } else if (page->hasBuffer()) { - page->deleteViewBuffer(); - } - } - - if (this->cache) { - this->cache->evictAllExcept(retainedPdfPages); - } -} - -auto XournalView::getCurrentPage() const -> size_t { return currentPage; } - -const int scrollKeySize = 30; - -auto XournalView::onKeyPressEvent(const KeyEvent& event) -> bool { - size_t p = getCurrentPage(); - if (p != npos && p < this->viewPages.size()) { - auto& v = this->viewPages[p]; - if (v->onKeyPressEvent(event)) { - return true; - } - } - - auto keyval = event.keyval; - auto state = event.state; - if (auto* tool = getControl()->getWindow()->getPdfToolbox(); tool->hasSelection()) { - if ((keyval == GDK_KEY_c && state == GDK_CONTROL_MASK) || keyval == GDK_KEY_Copy) { - // Shortcut to get selected PDF text. - tool->copyTextToClipboard(); - return true; - } - } - - if (auto* selection = getSelection(); selection) { - if (keyval == GDK_KEY_Escape) { - clearSelection(); - return true; - } - - int d = REGULAR_MOVE_AMOUNT; - if (state == GDK_MOD1_MASK) { - d = SMALL_MOVE_AMOUNT; - } else if (state == GDK_SHIFT_MASK) { - d = LARGE_MOVE_AMOUNT; - } - - int xdir = 0; - int ydir = 0; - if (keyval == GDK_KEY_Left) { - xdir = -1; - } else if (keyval == GDK_KEY_Up) { - ydir = -1; - } else if (keyval == GDK_KEY_Right) { - xdir = 1; - } else if (keyval == GDK_KEY_Down) { - ydir = 1; - } - if (xdir != 0 || ydir != 0) { - selection->moveSelection(d * xdir, d * ydir, /*addMoveUndo=*/true); - selection->ensureWithinVisibleArea(); - return true; - } - } - - if (auto* geom = GTK_XOURNAL(widget)->input->getGeometryToolInputHandler(); geom && geom->keyPressed(event)) { - return true; - } - - Layout* layout = this->getLayout(); - - if (!state) { - if (keyval == GDK_KEY_Page_Down || keyval == GDK_KEY_KP_Page_Down) { - control->getScrollHandler()->goToNextPage(); - return true; - } - if (keyval == GDK_KEY_Page_Up || keyval == GDK_KEY_KP_Page_Up) { - control->getScrollHandler()->goToPreviousPage(); - return true; - } - } - - if (keyval == GDK_KEY_space) { - GtkAllocation alloc = {0}; - gtk_widget_get_allocation(gtk_widget_get_parent(this->widget), &alloc); - int windowHeight = alloc.height - scrollKeySize; - - if (!state) { - layout->scrollRelative(0, windowHeight); - return true; - } - if (state == GDK_SHIFT_MASK) { - layout->scrollRelative(0, -windowHeight); - return true; - } - } - - // Numeric keypad always navigates by page - if (keyval == GDK_KEY_KP_Up) { - this->pageRelativeXY(0, -1); - return true; - } - - if (keyval == GDK_KEY_KP_Down) { - this->pageRelativeXY(0, 1); - return true; - } - - if (keyval == GDK_KEY_KP_Left) { - this->pageRelativeXY(-1, 0); - return true; - } - - if (keyval == GDK_KEY_KP_Right) { - this->pageRelativeXY(1, 0); - return true; - } - - - if (keyval == GDK_KEY_Up || keyval == GDK_KEY_k || keyval == GDK_KEY_K) { - if (control->getSettings()->isPresentationMode()) { - control->getScrollHandler()->goToPreviousPage(); - return true; - } - - if (state == GDK_SHIFT_MASK) { - this->pageRelativeXY(0, -1); - return true; - } - if (!state) { - layout->scrollRelative(0, -scrollKeySize); - return true; - } - } - - if (keyval == GDK_KEY_Down || keyval == GDK_KEY_j || keyval == GDK_KEY_J) { - if (control->getSettings()->isPresentationMode()) { - control->getScrollHandler()->goToNextPage(); - return true; - } - - if (state == GDK_SHIFT_MASK) { - this->pageRelativeXY(0, 1); - return true; - } - if (!state) { - layout->scrollRelative(0, scrollKeySize); - return true; - } - } - - if (keyval == GDK_KEY_Left || keyval == GDK_KEY_h) { - if (state == GDK_SHIFT_MASK) { - this->pageRelativeXY(-1, 0); - return true; - } - if (!state) { - if (control->getSettings()->isPresentationMode()) { - control->getScrollHandler()->goToPreviousPage(); - } else { - layout->scrollRelative(-scrollKeySize, 0); - } - return true; - } - } - - if (keyval == GDK_KEY_Right || keyval == GDK_KEY_l) { - if (state == GDK_SHIFT_MASK) { - this->pageRelativeXY(1, 0); - return true; - } - - if (!state) { - if (control->getSettings()->isPresentationMode()) { - control->getScrollHandler()->goToNextPage(); - } else { - layout->scrollRelative(scrollKeySize, 0); - } - return true; - } - } - - if (keyval == GDK_KEY_End || keyval == GDK_KEY_KP_End) { - control->getScrollHandler()->goToLastPage(); - return true; - } - - if (keyval == GDK_KEY_Home || keyval == GDK_KEY_KP_Home) { - control->getScrollHandler()->goToFirstPage(); - return true; - } - - // Switch color on number key - auto& colors = control->getWindow()->getToolMenuHandler()->getColorToolItems(); - if (!state && (keyval >= GDK_KEY_0) && (keyval < GDK_KEY_0 + std::min((std::size_t)10, colors.size()))) { - std::size_t index = std::min(colors.size() - 1, (std::size_t)(9 + (keyval - GDK_KEY_0)) % 10); - const auto& colorToolItem = colors.at(index); - if (auto* db = control->getActionDatabase(); db->isActionEnabled(Action::TOOL_COLOR)) { - control->getActionDatabase()->fireChangeActionState(Action::TOOL_COLOR, colorToolItem->getColor()); - } - return true; - } - return false; -} - -auto XournalView::getRepaintHandler() const -> RepaintHandler* { return this->repaintHandler.get(); } - -auto XournalView::onKeyReleaseEvent(const KeyEvent& event) -> bool { - size_t p = getCurrentPage(); - if (p != npos && p < this->viewPages.size()) { - auto& v = this->viewPages[p]; - if (v->onKeyReleaseEvent(event)) { - return true; - } - } - - return false; -} - -void XournalView::onSettingsChanged() { - if (this->cache) { - this->cache->updateSettings(control->getSettings()); - } -} - -// send the focus back to the appropriate widget -void XournalView::requestFocus() { gtk_widget_grab_focus(this->widget); } - -auto XournalView::searchTextOnPage(const std::string& text, size_t pageNumber, size_t index, size_t* occurrences, - XojPdfRectangle* matchRect) -> bool { - if (pageNumber == npos || pageNumber >= this->viewPages.size()) { - return false; - } - auto& v = this->viewPages[pageNumber]; - - return v->searchTextOnPage(text, index, occurrences, matchRect); -} - -void XournalView::forceUpdatePagenumbers() { - size_t p = this->currentPage; - this->currentPage = npos; - - control->firePageSelected(p); -} - -auto XournalView::getViewFor(size_t pageNr) const -> XojPageView* { - if (pageNr == npos || pageNr >= this->viewPages.size()) { - return nullptr; - } - return this->viewPages[pageNr].get(); -} - -void XournalView::pageSelected(size_t page) { - if (this->currentPage == page && this->lastSelectedPage == page) { - return; - } - - control->getWindow()->getPdfToolbox()->userCancelSelection(); - - if (this->lastSelectedPage != npos && this->lastSelectedPage < this->viewPages.size()) { - this->viewPages[this->lastSelectedPage]->setSelected(false); - } - - endTextAllPages(); - - this->currentPage = page; - - size_t pdfPage = npos; - - if (page != npos && page < viewPages.size()) { - auto& vp = viewPages[page]; - vp->setSelected(true); - lastSelectedPage = page; - pdfPage = vp->getPage()->getPdfPageNr(); - } - - control->updatePageNumbers(currentPage, pdfPage); - - control->updateBackgroundSizeButton(); - control->updatePageActions(); - - if (control->getSettings()->isEagerPageCleanup()) { - this->cleanupBufferCache(); - } - - // Load surrounding pages if they are not - const auto& [pagesLower, pagesUpper] = preloadPageBounds(page, this->viewPages.size()); - xoj_assert(pagesLower <= pagesUpper); - for (size_t i = pagesLower; i < pagesUpper; i++) { - if (!this->viewPages[i]->hasBuffer()) { - this->viewPages[i]->rerenderPage(); - } - } -} - -auto XournalView::getControl() const -> Control* { return control; } - -void XournalView::scrollTo(size_t pageNo, XojPdfRectangle rect) { - double zoom = getZoom(); - if (pageNo >= this->viewPages.size()) { - return; - } - - auto& v = this->viewPages[pageNo]; - - // Make sure it is visible - Layout* layout = this->getLayout(); - - int x = v->getX() + round_cast(rect.x1 * zoom); - int y = v->getY() + round_cast(rect.y1 * zoom); - int width; - int height; - if (rect.x2 == -1 || rect.y2 == -1) { - width = v->getDisplayWidth(); - height = v->getDisplayHeight(); - } else { - width = round_cast((rect.x2 - rect.x1) * zoom); - height = round_cast((rect.y2 - rect.y1) * zoom); - } - - layout->ensureRectIsVisible(x, y, width, height); - - // Select the page - control->firePageSelected(pageNo); -} - - -void XournalView::pageRelativeXY(int offCol, int offRow) { - size_t currPage = getCurrentPage(); - - XojPageView* view = getViewFor(currPage); - int row = view->getMappedRow(); - int col = view->getMappedCol(); - - Layout* layout = this->getLayout(); - auto optionalPageIndex = layout->getPageIndexAtGridMap(as_unsigned(row + offRow), as_unsigned(col + offCol)); - if (optionalPageIndex) { - this->scrollTo(*optionalPageIndex); - } -} - - -void XournalView::endTextAllPages(XojPageView* except) const { - for (auto& v: this->viewPages) { - if (except != v.get()) { - v->endText(); - } - } -} - -void XournalView::endSplineAllPages() const { - for (auto& v: this->viewPages) { - v->endSpline(); - } -} - -void XournalView::layerChanged(size_t page) { - if (page != npos && page < this->viewPages.size()) { - this->viewPages[page]->rerenderPage(); - } -} - -void XournalView::getPasteTarget(double& x, double& y) const { - size_t pageNo = getCurrentPage(); - if (pageNo == npos) { - return; - } - - Rectangle* rect = getVisibleRect(pageNo); - - if (rect) { - x = rect->x + rect->width / 2; - y = rect->y + rect->height / 2; - delete rect; - } -} - -/** - * Return the rectangle which is visible on screen, in document cooordinates - * - * Or nullptr if the page is not visible - */ -auto XournalView::getVisibleRect(size_t page) const -> Rectangle* { - if (page == npos || page >= this->viewPages.size()) { - return nullptr; - } - auto& p = this->viewPages[page]; - - return getVisibleRect(p.get()); -} - -auto XournalView::getVisibleRect(const XojPageView* redrawable) const -> Rectangle* { - return gtk_xournal_get_visible_area(this->widget, redrawable); -} - -void XournalView::recreatePdfCache() { - this->cache.reset(); - - Document* doc = control->getDocument(); - doc->lock_shared(); - if (doc->getPdfPageCount() != 0) { - this->cache = std::make_unique(doc->getPdfDocument(), control->getSettings()); - } - doc->unlock_shared(); -} - -/** - * @return Helper class for Touch specific fixes - */ -auto XournalView::getHandRecognition() const -> HandRecognition* { - return GTK_XOURNAL(widget)->input->getHandRecognition(); -} - -/** - * @return Scrollbars - */ -auto XournalView::getScrollHandling() const -> ScrollHandling* { return scrollHandling; } - -auto XournalView::getWidget() const -> GtkWidget* { return widget; } - -void XournalView::ensureRectIsVisible(int x, int y, int width, int height) { - Layout* layout = this->getLayout(); - layout->ensureRectIsVisible(x, y, width, height); -} - -void XournalView::zoomChanged() { - - size_t currentPage = this->getCurrentPage(); - XojPageView* view = getViewFor(currentPage); - - ZoomControl* zoom = control->getZoomControl(); - - if (!view) { - return; - } - - layoutPages(); - - if (zoom->isZoomPresentationMode()) { - scrollTo(currentPage); - } else if (zoom->isZoomSequenceActive()) { - auto pos = zoom->getScrollPositionAfterZoom(); - Layout* layout = this->getLayout(); - layout->scrollAbs(pos.x, pos.y); - } - - // Updates the Eraser's cursor icon in order to make it as big as the erasing area - control->getCursor()->updateCursor(); - - // if we changed the zoom of the page, we should hide the pdf floating toolbox - // and if user clicked the selection again, the floating toolbox shows again - control->getWindow()->getPdfToolbox()->hide(); - - this->control->getScheduler()->blockRerenderZoom(); -} - -void XournalView::pageSizeChanged(size_t page) { - layoutPages(); - if (page != npos && page < this->viewPages.size()) { - this->viewPages[page]->rerenderPage(/* sizeChanged */ true); - } -} - -void XournalView::pageChanged(size_t page) { - if (page != npos && page < this->viewPages.size()) { - this->viewPages[page]->rerenderPage(); - } -} - -void XournalView::pageDeleted(size_t page) { - const size_t currentPageNo = control->getCurrentPageNo(); - - viewPages.erase(begin(viewPages) + static_cast(page)); - - layoutPages(); - - if (currentPageNo > page) { - control->getScrollHandler()->scrollToPage(currentPageNo - 1); - } else { - control->getScrollHandler()->scrollToPage(currentPageNo); - } -} - -auto XournalView::getTextEditor() const -> TextEditor* { - for (auto&& page: viewPages) { - if (page->getTextEditor()) { - return page->getTextEditor(); - } - } - - return nullptr; -} - -auto XournalView::getCache() const -> PdfCache* { return this->cache.get(); } - -void XournalView::pageInserted(size_t page) { - Document* doc = control->getDocument(); - doc->lock_shared(); - auto pageView = std::make_unique(this, doc->getPage(page)); - doc->unlock_shared(); - - viewPages.insert(begin(viewPages) + as_signed(page), std::move(pageView)); - - layoutPages(); - // check which pages are visible and select the most visible page - Layout* layout = this->getLayout(); - layout->updateVisibility(); -} - -auto XournalView::getZoom() const -> double { return control->getZoomControl()->getZoom(); } - -auto XournalView::getDpiScaleFactor() const -> int { return gtk_widget_get_scale_factor(widget); } - -void XournalView::clearSelection() { - EditSelection* sel = GTK_XOURNAL(widget)->selection; - GTK_XOURNAL(widget)->selection = nullptr; - delete sel; - - control->setClipboardHandlerSelection(getSelection()); - - getCursor()->setMouseSelectionType(CURSOR_SELECTION_NONE); - control->getToolHandler()->setSelectionEditTools(false, false, false, false); -} - -void XournalView::deleteSelection(EditSelection* sel) { - if (sel == nullptr) { - sel = getSelection(); - } - - if (sel) { - auto undo = std::make_unique(sel->getSourcePage(), false); - sel->fillUndoItem(undo.get()); - control->getUndoRedoHandler()->addUndoAction(std::move(undo)); - - clearSelection(); - - repaintSelection(true); - } -} - -void XournalView::setSelection(EditSelection* selection) { - clearSelection(); - GTK_XOURNAL(this->widget)->selection = selection; - - control->setClipboardHandlerSelection(getSelection()); - - bool canChangeSize = false; - bool canChangeColor = false; - bool canChangeFill = false; - bool canChangeLineStyle = false; - - for (const Element* e: selection->getElementsView()) { - switch (e->getType()) { - case ELEMENT_TEXT: - canChangeColor = true; - continue; - case ELEMENT_STROKE: { - canChangeSize = true; - - const auto* s = dynamic_cast(e); - if (s->getToolType() == StrokeTool::PEN) { - // can change everything, leave loop with break - canChangeColor = true; - canChangeFill = true; - canChangeLineStyle = true; - break; - } - if (s->getToolType() == StrokeTool::HIGHLIGHTER) { - canChangeColor = true; - canChangeFill = true; - } - continue; - } - default: - continue; - } - - // leave loop - break; - } - - control->getToolHandler()->setSelectionEditTools(canChangeColor, canChangeSize, canChangeFill, canChangeLineStyle); - - repaintSelection(); -} - -void XournalView::repaintSelection(bool evenWithoutSelection) { - if (evenWithoutSelection) { - gtk_widget_queue_draw(this->widget); - return; - } - - EditSelection* selection = getSelection(); - if (selection == nullptr) { - return; - } - - // repaint always the whole widget - gtk_widget_queue_draw(this->widget); -} - -void XournalView::layoutPages() { - Layout* layout = this->getLayout(); - layout->recalculate(); - - // Todo (fabian): the following lines are conceptually wrong, the Layout::layoutPages function is meant to be - // called by an expose event, but removing it, will break "add page". - auto rectangle = layout->getVisibleRect(); - layout->layoutPages(std::max(layout->getMinimalWidth(), round_cast(rectangle.width)), - std::max(layout->getMinimalHeight(), round_cast(rectangle.height))); -} - -auto XournalView::getDisplayHeight() const -> int { - GtkAllocation allocation = {0}; - gtk_widget_get_allocation(this->widget, &allocation); - return allocation.height; -} - -auto XournalView::getDisplayWidth() const -> int { - GtkAllocation allocation = {0}; - gtk_widget_get_allocation(this->widget, &allocation); - return allocation.width; -} - -auto XournalView::isPageVisible(size_t page, int* visibleHeight) const -> bool { - Rectangle* rect = getVisibleRect(page); - if (rect) { - if (visibleHeight) { - *visibleHeight = round_cast(rect->height); - } - - delete rect; - return true; - } - if (visibleHeight) { - *visibleHeight = 0; - } - - return false; -} - -void XournalView::documentChanged(DocumentChangeType type) { - if (type != DOCUMENT_CHANGE_CLEARED && type != DOCUMENT_CHANGE_COMPLETE) { - return; - } - - XournalScheduler* scheduler = this->control->getScheduler(); - scheduler->lock(); - scheduler->removeAllJobs(); - - clearSelection(); - - recreatePdfCache(); - - Document* doc = control->getDocument(); - doc->lock_shared(); - - viewPages.clear(); - size_t pagecount = doc->getPageCount(); - viewPages.reserve(pagecount); - for (size_t i = 0; i < pagecount; i++) { - viewPages.emplace_back(std::make_unique(this, doc->getPage(i))); - } - - doc->unlock_shared(); - - layoutPages(); - scrollTo(0); - - scheduler->unlock(); -} - -auto XournalView::cut() -> bool { - size_t p = getCurrentPage(); - if (p == npos || p >= viewPages.size()) { - return false; - } - - auto& page = viewPages[p]; - return page->cut(); -} - -auto XournalView::copy() -> bool { - size_t p = getCurrentPage(); - if (p == npos || p >= viewPages.size()) { - return false; - } - - auto& page = viewPages[p]; - return page->copy(); -} - -auto XournalView::paste() -> bool { - size_t p = getCurrentPage(); - if (p == npos || p >= viewPages.size()) { - return false; - } - - auto& page = viewPages[p]; - return page->paste(); -} - -auto XournalView::actionDelete() -> bool { - size_t p = getCurrentPage(); - if (p == npos || p >= viewPages.size()) { - return false; - } - - auto& page = viewPages[p]; - return page->actionDelete(); -} - -auto XournalView::getDocument() const -> Document* { return control->getDocument(); } - -auto XournalView::getViewPages() const -> std::vector> const& { return viewPages; } - -auto XournalView::getCursor() const -> XournalppCursor* { return control->getCursor(); } - -auto XournalView::getSelection() const -> EditSelection* { - g_return_val_if_fail(this->widget != nullptr, nullptr); - g_return_val_if_fail(GTK_IS_XOURNAL(this->widget), nullptr); - - return GTK_XOURNAL(this->widget)->selection; -} - -auto XournalView::getLayout() const -> Layout* { return gtk_xournal_get_layout(getWidget()); } diff --git a/entry/src/main/cpp/src/core/gui/XournalView.h b/entry/src/main/cpp/src/core/gui/XournalView.h deleted file mode 100644 index 7973b5b..0000000 --- a/entry/src/main/cpp/src/core/gui/XournalView.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Xournal++ - * - * The widget which displays the PDF and the drawings - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for numeric_limits -#include // for unique_ptr -#include // for string -#include // for pair -#include // for vector - -#include // for GdkEventKey, GdkEventExpose -#include // for gboolean -#include // for GtkWidget, GtkAllocation - -#include "control/zoom/ZoomListener.h" // for ZoomListener -#include "gui/inputdevices/InputEvents.h" // for KeyEvent -#include "model/DocumentChangeType.h" // for DocumentChangeType -#include "model/DocumentListener.h" // for DocumentListener -#include "pdf/base/XojPdfPage.h" // for XojPdfRectangle -#include "util/Util.h" // for npos - -class Control; -class XournalppCursor; -class Document; -class EditSelection; -class XojPageView; -class XojPdfRectangle; -class PdfCache; -class RepaintHandler; -class ScrollHandling; -class TextEditor; -class HandRecognition; -class Layout; -namespace xoj::util { -template -class Rectangle; -} // namespace xoj::util - -class XournalView: public DocumentListener, public ZoomListener { -public: - XournalView(GtkWidget* parent, Control* control, ScrollHandling* scrollHandling); - ~XournalView() override; - -public: - // Recalculate the layout width and height amd layout the pages with the updated layout size - void layoutPages(); - - void scrollTo(size_t pageNo, XojPdfRectangle rect = {0, 0, -1, -1}); - - // Relative navigation in current layout: - void pageRelativeXY(int offCol, int offRow); - - size_t getCurrentPage() const; - - void clearSelection(); - - void layerChanged(size_t page); - - void requestFocus(); - - void forceUpdatePagenumbers(); - - XojPageView* getViewFor(size_t pageNr) const; - - bool searchTextOnPage(const std::string& text, size_t pageNumber, size_t index, size_t* occurrences, - XojPdfRectangle* matchRect); - - bool cut(); - bool copy(); - bool paste(); - - void getPasteTarget(double& x, double& y) const; - - bool actionDelete(); - - void endTextAllPages(XojPageView* except = nullptr) const; - - void endSplineAllPages() const; - - int getDisplayWidth() const; - int getDisplayHeight() const; - - bool isPageVisible(size_t page, int* visibleHeight) const; - - void ensureRectIsVisible(int x, int y, int width, int height); - - void setSelection(EditSelection* selection); - EditSelection* getSelection() const; - void deleteSelection(EditSelection* sel = nullptr); - void repaintSelection(bool evenWithoutSelection = false); - - TextEditor* getTextEditor() const; - std::vector> const& getViewPages() const; - - Control* getControl() const; - double getZoom() const; - int getDpiScaleFactor() const; - Document* getDocument() const; - PdfCache* getCache() const; - RepaintHandler* getRepaintHandler() const; - GtkWidget* getWidget() const; - XournalppCursor* getCursor() const; - Layout* getLayout() const; - - xoj::util::Rectangle* getVisibleRect(size_t page) const; - xoj::util::Rectangle* getVisibleRect(const XojPageView* redrawable) const; - - /** - * Recreate the PDF cache, for example after the underlying PDF file has changed - */ - void recreatePdfCache(); - - /** - * A pen action was detected now, therefore ignore touch events - * for a short time - */ - void penActionDetected(); - - /** - * @return Helper class for Touch specific fixes - */ - HandRecognition* getHandRecognition() const; - - /** - * @return Scrollbars - */ - ScrollHandling* getScrollHandling() const; - -public: - // ZoomListener interface - void zoomChanged() override; - -public: - // DocumentListener interface - void pageSelected(size_t page) override; - void pageSizeChanged(size_t page) override; - void pageChanged(size_t page) override; - void pageInserted(size_t page) override; - void pageDeleted(size_t page) override; - void documentChanged(DocumentChangeType type) override; - -public: - bool onKeyPressEvent(const KeyEvent& event); - bool onKeyReleaseEvent(const KeyEvent& event); - - void onSettingsChanged(); - -private: - void fireZoomChanged(); - - std::pair preloadPageBounds(size_t page, size_t maxPage); - - static auto clearMemoryTimer(XournalView* widget) -> gboolean; - - void cleanupBufferCache(); - -private: - /** - * Scrollbars - */ - ScrollHandling* scrollHandling = nullptr; - - GtkWidget* widget = nullptr; - - std::vector> viewPages; - - Control* control = nullptr; - - size_t currentPage = 0; - size_t lastSelectedPage = npos; - - std::unique_ptr cache; - - /** - * Handler for rerendering pages / repainting pages - */ - std::unique_ptr repaintHandler; - - /** - * Memory cleanup timeout - */ - guint cleanupTimeout = std::numeric_limits::max(); - - friend class Layout; -}; diff --git a/entry/src/main/cpp/src/core/gui/XournalppCursor.cpp b/entry/src/main/cpp/src/core/gui/XournalppCursor.cpp deleted file mode 100644 index dff44d9..0000000 --- a/entry/src/main/cpp/src/core/gui/XournalppCursor.cpp +++ /dev/null @@ -1,648 +0,0 @@ -#include "XournalppCursor.h" - -#include // for cos, sin, M_PI, NAN, fmod -#include // for uint32_t -#include // for initializer_list - -#include // for cairo_move_to, cairo_lin... -#include // for GdkPixbuf -#include // for g_object_unref -#include // for gtk_widget_get_window - -#include "control/Control.h" // for Control -#include "control/ToolEnums.h" // for TOOL_HAND, TOOL_PEN, TOO... -#include "control/ToolHandler.h" // for ToolHandler -#include "control/settings/Settings.h" // for Settings -#include "control/settings/SettingsEnums.h" // for STYLUS_CURSOR_BIG, STYLU... -#include "control/zoom/ZoomControl.h" // for ZoomControl -#include "gui/MainWindow.h" // for MainWindow -#include "util/Color.h" // for argb_to_GdkRGBA, rgb_to_... -#include "util/safe_casts.h" // for ceil_cast - -#include "XournalView.h" // for XournalView - - -// NOTE: Every cursor change must result in the setting of this->currentCursor to the new cursor type even for custom -// cursors. -// Custom cursors can also compare then set this->currentCursorFlavour to notice changes in colour or size etc. The -// flavour calculation is specific to each cursor type and is calculated differently within each type. - - -// All the cursors we want to use. WARNING Make sure to set their css names in cssCursors[] below WARNING -enum AVAILABLECURSORS { - CRSR_nullptr = 0, // <--- Do Not Modify - CRSR_BUSY, - CRSR_MOVE, - CRSR_MOVING, - CRSR_GRAB, - CRSR_GRABBING, - CRSR_TOP_LEFT_CORNER, - CRSR_TOP_RIGHT_CORNER, - CRSR_BOTTOM_LEFT_CORNER, - CRSR_BOTTOM_RIGHT_CORNER, - CRSR_SB_H_DOUBLE_ARROW, - CRSR_EXCHANGE, - CRSR_PIRATE, - CRSR_SB_V_DOUBLE_ARROW, - CRSR_ARROW, - CRSR_BLANK_CURSOR, - CRSR_XTERM, - CRSR_DEFAULT, - CRSR_HAND2, - CRSR_TCROSS, - CRSR_PENORHIGHLIGHTER, - CRSR_ERASER, - CRSR_DRAWDIRNONE, // drawdir* keep these consecutive and in order: none,shift,ctrl,shiftctrl - CRSR_DRAWDIRSHIFT, // " - CRSR_DRAWDIRCTRL, // " - CRSR_DRAWDIRSHIFTCTRL, // " - CRSR_RESIZE, - - CRSR_END_OF_CURSORS -}; - - -struct cursorStruct { - const gchar* cssName; - const gchar* cssBackupName; -}; - - -// our enum mapped to css name and a place to store the cursor pointer. -// Note: including enum as error check (for now?) -cursorStruct cssCursors[CRSR_END_OF_CURSORS]; - - -XournalppCursor::XournalppCursor(Control* control): control(control) { - // clang-format off - // NOTE: Go ahead and use a fancy css cursor... but specify a common backup cursor. - cssCursors[CRSR_nullptr ] = {"",""}; - cssCursors[CRSR_BUSY ] = {"wait", "" }; - cssCursors[CRSR_MOVE ] = {"all-scroll", "" }; - cssCursors[CRSR_MOVING ] = {"grabbing", "" }; - cssCursors[CRSR_GRAB ] = {"grab", "" }; - cssCursors[CRSR_GRABBING ] = {"grabbing", "" }; - cssCursors[CRSR_TOP_LEFT_CORNER ] = {"nw-resize", "" }; - cssCursors[CRSR_TOP_RIGHT_CORNER ] = {"ne-resize", "" }; - cssCursors[CRSR_BOTTOM_LEFT_CORNER ] = {"sw-resize", "" }; - cssCursors[CRSR_BOTTOM_RIGHT_CORNER ] = {"se-resize", "" }; - cssCursors[CRSR_SB_H_DOUBLE_ARROW ] = {"ew-resize", "" }; - cssCursors[CRSR_EXCHANGE ] = {"exchange", "arrow" }; - cssCursors[CRSR_PIRATE ] = {"pirate", "arrow" }; - cssCursors[CRSR_SB_V_DOUBLE_ARROW ] = {"ns-resize", "" }; - cssCursors[CRSR_ARROW ] = {"default", "" }; - cssCursors[CRSR_BLANK_CURSOR ] = {"none", "" }; - cssCursors[CRSR_XTERM ] = {"text", "" }; - cssCursors[CRSR_DEFAULT ] = {"default", "" }; - cssCursors[CRSR_HAND2 ] = {"hand2", "" }; - cssCursors[CRSR_TCROSS ] = {"crosshair", "" }; - cssCursors[CRSR_PENORHIGHLIGHTER ] = {"",""}; // custom cursors - enum used only for check - cssCursors[CRSR_ERASER ] = {"",""}; // " - cssCursors[CRSR_DRAWDIRNONE ] = {"",""}; // " - cssCursors[CRSR_DRAWDIRSHIFT ] = {"",""}; // " - cssCursors[CRSR_DRAWDIRCTRL ] = {"",""}; // " - cssCursors[CRSR_DRAWDIRSHIFTCTRL ] = {"",""}; // " - cssCursors[CRSR_RESIZE ] = {"",""}; // " -}; -// clang-format on - -constexpr auto RESIZE_CURSOR_SIZE = 16; -constexpr auto DELTA_ANGLE_ARROW_HEAD = M_PI / 6.0; -constexpr auto LENGTH_ARROW_HEAD = 0.7; -constexpr auto RESIZE_CURSOR_HASH_PRECISION = 1000; - - -XournalppCursor::~XournalppCursor() = default; - - -void XournalppCursor::setInputDeviceClass(InputDeviceClass device) { this->inputDevice = device; } - - -// pen or hi-light cursor will be a DrawDir cursor instead -void XournalppCursor::activateDrawDirCursor(bool enable, bool shift, bool ctrl) { - this->drawDirActive = enable; - this->drawDirShift = shift; - this->drawDirCtrl = ctrl; -} - - -void XournalppCursor::setMouseDown(bool mouseDown) { - if (this->mouseDown == mouseDown) { - return; - } - - this->mouseDown = mouseDown; - ToolHandler* handler = control->getToolHandler(); - ToolType type = handler->getToolType(); - - // Not always an update is needed - if (type == TOOL_HAND || type == TOOL_VERTICAL_SPACE || type == TOOL_ERASER) { - updateCursor(); - } -} - - -void XournalppCursor::setMouseSelectionType(CursorSelectionType selectionType) { - if (this->selectionType == selectionType) { - return; - } - this->selectionType = selectionType; - updateCursor(); -} - -void XournalppCursor::setRotationAngle(double angle) { this->angle = angle; } -void XournalppCursor::setMirror(bool mirror) { this->mirror = mirror; } - -/*This handles setting the busy cursor for the main window and calls - * updateCursor to set the busy cursor for the XournalWidget region. - */ -void XournalppCursor::setCursorBusy(bool busy) { - MainWindow* win = control->getWindow(); - if (!win) { - return; - } - - if (this->busy == busy) { - return; - } - - this->busy = busy; - - if (busy) { - GdkWindow* window = gtk_widget_get_window(win->getWindow()); - xoj::util::GObjectSPtr cursor( - gdk_cursor_new_from_name(gdk_window_get_display(window), cssCursors[CRSR_BUSY].cssName), - xoj::util::adopt); - gdk_window_set_cursor(window, cursor.get()); - } else { - if (gtk_widget_get_window(win->getWindow())) { - gdk_window_set_cursor(gtk_widget_get_window(win->getWindow()), nullptr); - } - } - - updateCursor(); -} - - -void XournalppCursor::setInsidePage(bool insidePage) { - if (this->insidePage == insidePage) { - return; - } - - this->insidePage = insidePage; - - updateCursor(); -} - - -void XournalppCursor::setInvisible(bool invisible) { - if (this->invisible == invisible) { - return; - } - - this->invisible = invisible; - - updateCursor(); -} - - -void XournalppCursor::updateCursor() { - MainWindow* win = control->getWindow(); - if (!win) { - return; - } - - XournalView* xournal = win->getXournal(); - if (!xournal) { - return; - } - - GdkCursor* cursor = nullptr; - - - if (this->busy) { - setCursor(CRSR_BUSY); - } else { - ToolHandler* handler = control->getToolHandler(); - ToolType type = handler->getToolType(); - - - if (type == TOOL_HAND) { - if (this->mouseDown) { - setCursor(CRSR_GRABBING); - } else { - setCursor(CRSR_GRAB); - } - } else if (!this->insidePage) { - setCursor(CRSR_DEFAULT); - } else if (this->selectionType) { - switch (this->selectionType) { - case CURSOR_SELECTION_MOVE: - if (this->mouseDown) { - setCursor(CRSR_MOVING); - } else { - setCursor(CRSR_MOVE); - } - break; - case CURSOR_SELECTION_TOP_LEFT: - [[fallthrough]]; - case CURSOR_SELECTION_BOTTOM_RIGHT: - cursor = getResizeCursor(45); - break; - case CURSOR_SELECTION_TOP_RIGHT: - [[fallthrough]]; - case CURSOR_SELECTION_BOTTOM_LEFT: - cursor = getResizeCursor(135); - break; - case CURSOR_SELECTION_LEFT: - [[fallthrough]]; - case CURSOR_SELECTION_RIGHT: - cursor = getResizeCursor(180); - break; - case CURSOR_SELECTION_TOP: - [[fallthrough]]; - case CURSOR_SELECTION_BOTTOM: - cursor = getResizeCursor(90); - break; - case CURSOR_SELECTION_ROTATE: - setCursor(CRSR_EXCHANGE); - break; - case CURSOR_SELECTION_DELETE: - setCursor(CRSR_PIRATE); - break; - default: - break; - } - } else if (type == TOOL_PEN || type == TOOL_HIGHLIGHTER || type == TOOL_LASER_POINTER_PEN || - type == TOOL_LASER_POINTER_HIGHLIGHTER) { - if (this->inputDevice == INPUT_DEVICE_MOUSE && !this->mouseDown) { - // mouse and not pressed - setCursor(CRSR_ARROW); - } else { - if (type == TOOL_PEN || type == TOOL_LASER_POINTER_PEN) { - cursor = getPenCursor(); - } else // must be: if (type == TOOL_HIGHLIGHTER || type == TOOL_LASER_POINTER_HIGHLIGHTER) - { - cursor = getHighlighterCursor(); - } - } - } else if (type == TOOL_ERASER) { - EraserVisibility visibility = control->getSettings()->getEraserVisibility(); - if ((this->inputDevice == INPUT_DEVICE_PEN || this->inputDevice == INPUT_DEVICE_ERASER) && - (visibility == ERASER_VISIBILITY_NEVER || (visibility == ERASER_VISIBILITY_HOVER && this->mouseDown) || - (visibility == ERASER_VISIBILITY_TOUCH && !this->mouseDown))) { - setCursor(CRSR_BLANK_CURSOR); - } else { - cursor = getEraserCursor(); - } - } - - else if (type == TOOL_TEXT) { - if (this->invisible) { - setCursor(CRSR_BLANK_CURSOR); - } else { - setCursor(CRSR_XTERM); - } - } else if (type == TOOL_IMAGE) { - setCursor(CRSR_TCROSS); - } else if (type == TOOL_FLOATING_TOOLBOX) { - setCursor(CRSR_DEFAULT); - } else if (type == TOOL_VERTICAL_SPACE) { - setCursor(CRSR_SB_V_DOUBLE_ARROW); - } else if (type == TOOL_SELECT_OBJECT) { - setCursor(CRSR_DEFAULT); - } else if (type == TOOL_PLAY_OBJECT) { - setCursor(CRSR_HAND2); - } else if (type == TOOL_SELECT_PDF_TEXT_LINEAR) { - setCursor(CRSR_XTERM); - } else // other selections are handled before anyway, because you can move a selection with every tool - { - setCursor(CRSR_TCROSS); - } - } - - GdkWindow* window = gtk_widget_get_window(xournal->getWidget()); - if (window) { - if (cursor != nullptr) { - gdk_window_set_cursor(window, cursor); - } - gtk_widget_set_sensitive(xournal->getWidget(), !this->busy); - } - // Performance removal! - // If this line is ever required, make sure this function is never called, when the cursor is not set. - // gdk_display_sync(gdk_display_get_default()); - - if (cursor != nullptr) { - g_object_unref(cursor); - } -} - -auto XournalppCursor::getResizeCursor(double deltaAngle) -> GdkCursor* { - if (this->mirror) { - deltaAngle = -deltaAngle; - } - gulong flavour = static_cast(RESIZE_CURSOR_HASH_PRECISION * fmod(angle + deltaAngle, 180.0)); - if (CRSR_RESIZE == this->currentCursor && flavour == this->currentCursorFlavour) { - return nullptr; - } - this->currentCursor = CRSR_RESIZE; - this->currentCursorFlavour = flavour; - - double a = (this->angle + deltaAngle) * M_PI / 180; - cairo_surface_t* crCursor = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, RESIZE_CURSOR_SIZE, RESIZE_CURSOR_SIZE); - cairo_t* cr = cairo_create(crCursor); - cairo_set_source_rgba(cr, 0.1, 0.1, 0.1, 1); - cairo_translate(cr, RESIZE_CURSOR_SIZE / 2, RESIZE_CURSOR_SIZE / 2); - cairo_scale(cr, RESIZE_CURSOR_SIZE / 2, RESIZE_CURSOR_SIZE / 2); - cairo_set_line_width(cr, 0.2); - // draw double headed arrow rotated accordingly - cairo_move_to(cr, cos(a), sin(a)); - cairo_line_to(cr, -cos(a), -sin(a)); - cairo_stroke(cr); - // head and tail - for (auto s: {-1, 1}) { - cairo_move_to(cr, s * cos(a), s * sin(a)); - cairo_rel_line_to(cr, s * cos(a + M_PI + DELTA_ANGLE_ARROW_HEAD) * LENGTH_ARROW_HEAD, - s * sin(a + M_PI + DELTA_ANGLE_ARROW_HEAD) * LENGTH_ARROW_HEAD); - cairo_move_to(cr, s * cos(a), s * sin(a)); - cairo_rel_line_to(cr, s * cos(a + M_PI - DELTA_ANGLE_ARROW_HEAD) * LENGTH_ARROW_HEAD, - s * sin(a + M_PI - DELTA_ANGLE_ARROW_HEAD) * LENGTH_ARROW_HEAD); - cairo_stroke(cr); - } - - cairo_destroy(cr); - GdkPixbuf* pixbuf = gdk_pixbuf_get_from_surface(crCursor, 0, 0, RESIZE_CURSOR_SIZE, RESIZE_CURSOR_SIZE); - cairo_surface_destroy(crCursor); - GdkCursor* cursor = - gdk_cursor_new_from_pixbuf(gtk_widget_get_display(control->getWindow()->getXournal()->getWidget()), pixbuf, - RESIZE_CURSOR_SIZE / 2, RESIZE_CURSOR_SIZE / 2); - g_object_unref(pixbuf); - return cursor; -} - -auto XournalppCursor::getEraserCursor() -> GdkCursor* { - - // Eraser's size follow a quadratic increment, so the cursor will do the same - double cursorSize = control->getToolHandler()->getThickness() * 2.0 * control->getZoomControl()->getZoom(); - gulong flavour = static_cast(64 * cursorSize); - - if (CRSR_ERASER == this->currentCursor && flavour == this->currentCursorFlavour) { - return nullptr; // cursor already set - } - this->currentCursor = CRSR_ERASER; - this->currentCursorFlavour = flavour; - - cairo_surface_t* surface = - cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ceil_cast(cursorSize), ceil_cast(cursorSize)); - cairo_t* cr = cairo_create(surface); - cairo_rectangle(cr, 0, 0, cursorSize, cursorSize); - cairo_set_source_rgb(cr, 1, 1, 1); - cairo_fill(cr); - cairo_rectangle(cr, 0, 0, cursorSize, cursorSize); - cairo_set_source_rgb(cr, 0, 0, 0); - cairo_stroke(cr); - cairo_destroy(cr); - GdkCursor* cursor = - gdk_cursor_new_from_surface(gdk_display_get_default(), surface, cursorSize / 2.0, cursorSize / 2.0); - cairo_surface_destroy(surface); - return cursor; -} - - -auto XournalppCursor::getHighlighterCursor() -> GdkCursor* { - if (this->drawDirActive) { - return createCustomDrawDirCursor(48, this->drawDirShift, this->drawDirCtrl); - } - - return createHighlighterOrPenCursor(120 / 255.0); -} - - -auto XournalppCursor::getPenCursor() -> GdkCursor* { - if ((control->getSettings()->getStylusCursorType() == STYLUS_CURSOR_NONE) && - !control->getSettings()->isHighlightPosition()) { - setCursor(CRSR_BLANK_CURSOR); - return nullptr; - } - if (control->getSettings()->getStylusCursorType() == STYLUS_CURSOR_ARROW) { - setCursor(CRSR_ARROW); - return nullptr; - } - if ((control->getSettings()->getStylusCursorType() != STYLUS_CURSOR_NONE) && this->drawDirActive) { - return createCustomDrawDirCursor(48, this->drawDirShift, this->drawDirCtrl); - } - - return createHighlighterOrPenCursor(1.0); -} - -auto XournalppCursor::createHighlighterOrPenCursor(double alpha) -> GdkCursor* { - auto irgb = control->getToolHandler()->getColor(); - if (const auto& params = control->getSettings()->getRecolorParameters(); params.recolorizeMainView) { - irgb = params.recolor.convertColor(irgb); - } - auto drgb = Util::rgb_to_GdkRGBA(irgb); - auto cursorType = control->getSettings()->getStylusCursorType(); - auto cursor = (cursorType == STYLUS_CURSOR_NONE) ? CRSR_BLANK_CURSOR : CRSR_PENORHIGHLIGHTER; - bool bright = control->getSettings()->isHighlightPosition(); - double cursorSize = std::min(90., control->getToolHandler()->getThickness() * control->getZoomControl()->getZoom()); - int height = ceil_cast(cursorSize); - int width = height; - - // create a hash of variables so we notice if one changes despite being the same cursor type: - gulong flavour = (cursorType == STYLUS_CURSOR_DOT ? 1U : 0U) | (cursorType == STYLUS_CURSOR_BIG ? 2U : 0U) | - (bright ? 4U : 0U) | static_cast(64 * alpha) << 3U | - static_cast(cursorSize) << 10U | static_cast(uint32_t(irgb)) << 15U; - - if ((cursor == this->currentCursor) && (flavour == this->currentCursorFlavour)) { - return nullptr; - } - this->currentCursor = cursor; - this->currentCursorFlavour = flavour; - - if ((cursorType == STYLUS_CURSOR_BIG) || bright) { - height = width = 90; - } - - // We change the drawing method, now the center with the colored dot of the pen - // is at the center of the cairo surface, and when we load the cursor, we load it - // with the relative offset - int centerX = width / 2; - int centerY = height / 2; - cairo_surface_t* crCursor = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cairo_t* cr = cairo_create(crCursor); - - if (cursorType == STYLUS_CURSOR_BIG) { - // When using highlighter, paint the icon with the current color - if (alpha != 1.0) { - gdk_cairo_set_source_rgba(cr, &drgb); - } else { - cairo_set_source_rgb(cr, 1, 1, 1); - } - cairo_set_line_width(cr, 1.2); - - // Starting point - cairo_move_to(cr, centerX + 2, centerY); - // Pencil cursor - cairo_line_to(cr, centerX + 2, centerY - 4); - cairo_line_to(cr, centerX + 15, centerY - 17.5); - cairo_line_to(cr, centerX + 19, centerY - 14); - cairo_line_to(cr, centerX + 6, centerY); - - cairo_close_path(cr); - cairo_fill_preserve(cr); - cairo_set_source_rgb(cr, 0, 0, 0); - cairo_stroke(cr); - - cairo_fill_preserve(cr); - } - - if (bright) { - // Highlight cursor with a circle - auto&& color = Util::argb_to_GdkRGBA(control->getSettings()->getCursorHighlightColor()); - gdk_cairo_set_source_rgba(cr, &color); - cairo_arc(cr, centerX, centerY, control->getSettings()->getCursorHighlightRadius(), 0, 2 * M_PI); - cairo_fill_preserve(cr); - auto&& borderColor = Util::argb_to_GdkRGBA(control->getSettings()->getCursorHighlightBorderColor()); - gdk_cairo_set_source_rgba(cr, &borderColor); - cairo_set_line_width(cr, control->getSettings()->getCursorHighlightBorderWidth()); - cairo_stroke(cr); - } - - if (cursorType != STYLUS_CURSOR_NONE) { - auto drgbCopy = drgb; - drgbCopy.alpha = alpha; - gdk_cairo_set_source_rgba(cr, &drgbCopy); - cairo_arc(cr, centerX, centerY, cursorSize / 2., 0, 2. * M_PI); - cairo_fill(cr); - } - - cairo_destroy(cr); - GdkPixbuf* pixbuf = gdk_pixbuf_get_from_surface(crCursor, 0, 0, width, height); - cairo_surface_destroy(crCursor); - GdkCursor* gdkCursor = gdk_cursor_new_from_pixbuf( - gtk_widget_get_display(control->getWindow()->getXournal()->getWidget()), pixbuf, centerX, centerY); - g_object_unref(pixbuf); - return gdkCursor; -} - - -void XournalppCursor::setCursor(guint cursorID) { - if (cursorID == this->currentCursor) { - return; - } - - MainWindow* win = control->getWindow(); - if (!win) { - return; - } - - XournalView* xournal = win->getXournal(); - if (!xournal) { - return; - } - - GdkWindow* window = gtk_widget_get_window(xournal->getWidget()); - if (!window) { - return; - } - - GdkCursor* cursor = gdk_cursor_new_from_name(gdk_window_get_display(window), cssCursors[cursorID].cssName); - if (cursor == nullptr) // failed to get a cursor, try backup cursor. - { - if (cursorID != CRSR_nullptr) { - cursor = gdk_cursor_new_from_name(gdk_window_get_display(window), cssCursors[cursorID].cssBackupName); - - // Null cursor is ok but not wanted ... warn user - if (cursor == nullptr) { - if (CRSR_nullptr == this->currentCursor) { - return; // We've already been here - } - g_warning("CSS Cursor and backup not valid '%s', '%s'", cssCursors[cursorID].cssName, - cssCursors[cursorID].cssBackupName); - } - } - cursorID = cursor == nullptr ? CRSR_nullptr : cursorID; - } - - this->currentCursor = cursorID; - gdk_window_set_cursor(gtk_widget_get_window(xournal->getWidget()), cursor); - gdk_window_set_cursor(window, cursor); - if (cursor) { - g_object_unref(cursor); - } -} - - -auto XournalppCursor::createCustomDrawDirCursor(int size, bool shift, bool ctrl) -> GdkCursor* { - bool big = control->getSettings()->getStylusCursorType() == STYLUS_CURSOR_BIG; - bool bright = control->getSettings()->isHighlightPosition(); - - guint newCursorID = CRSR_DRAWDIRNONE + (shift ? 1 : 0) + (ctrl ? 2 : 0); - gulong flavour = - (big ? 1 : 0) | (bright ? 2 : 0) | static_cast(size) << 2; // hash of variables for comparison only - - if (newCursorID == this->currentCursor && flavour == this->currentCursorFlavour) { - return nullptr; - } - this->currentCursor = newCursorID; - this->currentCursorFlavour = flavour; - - int height = size; - int width = size; - int fontSize = 8; - if (big || bright) { - height = width = 60; - fontSize = 12; - } - int centerX = width - width / 4; - int centerY = height - height / 4; - - - cairo_surface_t* crCursor = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cairo_t* cr = cairo_create(crCursor); - cairo_set_line_width(cr, 1.2); - - // Starting point - cairo_move_to(cr, centerX, height / 2); - cairo_line_to(cr, centerX, height); - cairo_stroke(cr); - - cairo_move_to(cr, width / 2, centerY); - cairo_line_to(cr, width, centerY); - cairo_stroke(cr); - - if (ctrl) { - cairo_text_extents_t extents; - const char* utf8 = "CONTROL"; - double x = NAN, y = NAN; - cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, fontSize); - cairo_text_extents(cr, utf8, &extents); - x = 0; - y = extents.height; - cairo_move_to(cr, x, y); - cairo_show_text(cr, utf8); - } - - if (shift) { - cairo_text_extents_t extents; - const char* utf8 = "SHIFT"; - double x = NAN, y = NAN; - cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, fontSize); - cairo_text_extents(cr, utf8, &extents); - x = 0; - y = extents.height * 2.5; - cairo_move_to(cr, x, y); - cairo_show_text(cr, utf8); - } - - cairo_destroy(cr); - GdkPixbuf* pixbuf = gdk_pixbuf_get_from_surface(crCursor, 0, 0, width, height); - cairo_surface_destroy(crCursor); - GdkCursor* cursor = gdk_cursor_new_from_pixbuf( - gtk_widget_get_display(control->getWindow()->getXournal()->getWidget()), pixbuf, centerX, centerY); - g_object_unref(pixbuf); - - return cursor; -} diff --git a/entry/src/main/cpp/src/core/gui/XournalppCursor.h b/entry/src/main/cpp/src/core/gui/XournalppCursor.h deleted file mode 100644 index 4ce135c..0000000 --- a/entry/src/main/cpp/src/core/gui/XournalppCursor.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Xournal++ - * - * Handles the XournalppCursor - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GdkCursor -#include // for guint, gulong - -#include "control/tools/CursorSelectionType.h" // for CursorSelectionType -#include "gui/inputdevices/InputEvents.h" // for InputDeviceClass, INP... - -class Control; - -class XournalppCursor { -public: - XournalppCursor(Control* control); - virtual ~XournalppCursor(); - - void setCursorBusy(bool busy); - void updateCursor(); - - void setMouseSelectionType(CursorSelectionType selectionType); - - void setMouseDown(bool mouseDown); - void setInvisible(bool invisible); - void setInsidePage(bool insidePage); - void activateDrawDirCursor(bool enable, bool shift = false, bool ctrl = false); - void setInputDeviceClass(InputDeviceClass inputDevice); - void setRotationAngle(double angle); - void setMirror(bool mirror); - -private: - void setCursor(guint id); - - GdkCursor* getPenCursor(); - - GdkCursor* getEraserCursor(); - GdkCursor* getHighlighterCursor(); - GdkCursor* getResizeCursor(double deltaAngle); - - GdkCursor* createHighlighterOrPenCursor(double alpha); - GdkCursor* createCustomDrawDirCursor(int size, bool shift, bool ctrl); - -private: - InputDeviceClass inputDevice = INPUT_DEVICE_MOUSE; - - Control* control = nullptr; - bool busy = false; - bool insidePage = false; - CursorSelectionType selectionType = CURSOR_SELECTION_NONE; - - bool mouseDown = false; - bool invisible = false; - - // One shot drawDir custom cursor -drawn instead of pen/stylus then cleared. - bool drawDirActive = false; - bool drawDirShift = false; - bool drawDirCtrl = false; - - // avoid re-assigning same cursor - guint currentCursor = 0; // enum AVAILABLECURSORS - gulong currentCursorFlavour{}; // for different flavours of a cursor (i.e. drawdir, pen and highlighter custom - // cursors) - - // for resizing rotated/mirrored selections - double angle = 0; - bool mirror = false; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/AboutDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/AboutDialog.cpp deleted file mode 100644 index 4c3fd1f..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/AboutDialog.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "AboutDialog.h" - -#include - -#include "gui/Builder.h" -#include "util/PlaceholderString.h" // for PlaceholderString -#include "util/gtk4_helper.h" // for gtk_box_append -#include "util/i18n.h" // for _ - -#include "config-git.h" // for GIT_COMMIT_ID -#include "config.h" // for PROJECT_VERSION - -class GladeSearchpath; - -constexpr auto UI_FILE = "about.glade"; -constexpr auto UI_DIALOG_NAME = "aboutDialog"; -constexpr auto GIT_REPO = "https://github.com/xournalpp/xournalpp"; -constexpr auto WEBSITE = "https://xournalpp.github.io"; -constexpr auto AUTHORS_LINK = "https://raw.githubusercontent.com/xournalpp/xournalpp/master/AUTHORS"; -constexpr auto LICENCE_LINK = "https://raw.githubusercontent.com/xournalpp/xournalpp/master/LICENSE"; - -static GtkWindow* constructWindow(GladeSearchpath* gladeSearchPath) { - Builder builder(gladeSearchPath, UI_FILE); - GtkWindow* window = GTK_WINDOW(builder.get(UI_DIALOG_NAME)); - - auto insertPropertyKey = [](GtkGrid* grid, std::string&& str, gint top) { - auto widget = gtk_label_new(nullptr); - gtk_label_set_markup(GTK_LABEL(widget), str.insert(0, "").append("").c_str()); - gtk_widget_set_halign(widget, GtkAlign::GTK_ALIGN_START); - gtk_grid_attach(grid, widget, 0, top, 1, 1); - }; - - auto insertPropertyValue = [](GtkGrid* grid, std::string const& str, gint top) { - auto widget = gtk_label_new(str.c_str()); - gtk_widget_set_halign(widget, GtkAlign::GTK_ALIGN_START); - gtk_grid_attach(grid, widget, 1, top, 1, 1); - }; - - auto infoGrid = GTK_GRID(builder.get("versionInfoGrid")); - - insertPropertyKey(infoGrid, _("Version"), 0); - insertPropertyValue(infoGrid, PROJECT_VERSION, 0); - - insertPropertyKey(infoGrid, _("Built on"), 1); - insertPropertyValue(infoGrid, __DATE__ ", " __TIME__, 1); - - insertPropertyKey(infoGrid, _("GTK Version"), 2); - auto gtkVersion = - FS(FORMAT_STR("{1}.{2}.{3}") % gtk_get_major_version() % gtk_get_minor_version() % gtk_get_micro_version()); - insertPropertyValue(infoGrid, gtkVersion, 2); - - auto const gitCommitId = std::string{GIT_COMMIT_ID}; - if (!gitCommitId.empty()) { - insertPropertyKey(infoGrid, _("Git commit"), 3); - insertPropertyValue(infoGrid, gitCommitId.c_str(), 3); - } - - gtk_box_append(GTK_BOX(builder.get("vboxRepo")), gtk_link_button_new(GIT_REPO)); - gtk_box_append(GTK_BOX(builder.get("vboxWebsite")), gtk_link_button_new(WEBSITE)); - gtk_box_append(GTK_BOX(builder.get("vboxCommunity")), - gtk_link_button_new_with_label(AUTHORS_LINK, _("See the full list of contributors"))); - gtk_box_append(GTK_BOX(builder.get("vboxLicense")), - gtk_link_button_new_with_label(LICENCE_LINK, _("GNU GPLv2 or later"))); - - g_signal_connect_swapped(GTK_BUTTON(builder.get("closebutton")), "clicked", G_CALLBACK(gtk_window_close), window); - -#if GTK_MAJOR_VERSION == 3 - // Widgets are visible by default in gtk4 - gtk_widget_show_all(builder.get("dialog-main-box")); -#endif - return window; -} - -xoj::popup::AboutDialog::AboutDialog(GladeSearchpath* gladeSearchPath): window(constructWindow(gladeSearchPath)) {} - -xoj::popup::AboutDialog::~AboutDialog() = default; diff --git a/entry/src/main/cpp/src/core/gui/dialog/AboutDialog.h b/entry/src/main/cpp/src/core/gui/dialog/AboutDialog.h deleted file mode 100644 index c8e2883..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/AboutDialog.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Xournal++ - * - * The about dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "util/raii/GtkWindowUPtr.h" - -class GladeSearchpath; - -namespace xoj::popup { -class AboutDialog { -public: - AboutDialog(GladeSearchpath* gladeSearchPath); - ~AboutDialog(); - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - xoj::util::GtkWindowUPtr window; -}; -}; // namespace xoj::popup diff --git a/entry/src/main/cpp/src/core/gui/dialog/AbstractLatexDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/AbstractLatexDialog.cpp deleted file mode 100644 index c5ea987..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/AbstractLatexDialog.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "gui/dialog/AbstractLatexDialog.h" - -#include // for max, min -#include - -#include "control/LatexController.h" -#include "model/TexImage.h" -#include "util/Range.h" - -// Default background color of the preview. -const Color DEFAULT_PREVIEW_BACKGROUND = Colors::white; - -AbstractLatexDialog::AbstractLatexDialog(std::unique_ptr ctrl): - texCtrl{std::move(ctrl)}, previewBackgroundColor{DEFAULT_PREVIEW_BACKGROUND} { - texCtrl->dlg = this; -} - -AbstractLatexDialog::~AbstractLatexDialog() { texCtrl->dlg = nullptr; }; - -void AbstractLatexDialog::setCompilationStatus(bool isTexValid, bool isCompilationDone, - const std::string& compilationOutput) { - gtk_widget_set_sensitive(GTK_WIDGET(btOk), isTexValid && isCompilationDone); - - // Show error warning only if LaTeX is invalid. - gtk_widget_set_opacity(GTK_WIDGET(texErrorLabel), isTexValid ? 0 : 1); - - // Update the output pane. - gtk_text_buffer_set_text(compilationOutputTextBuffer, compilationOutput.c_str(), -1); -} - -void AbstractLatexDialog::setTempRender(PopplerDocument* pdf) { - if (poppler_document_get_n_pages(pdf) < 1) { - return; - } - - this->previewPdfPage.reset(poppler_document_get_page(pdf, 0), xoj::util::adopt); - this->previewMask.reset(); - - // Queue rendering the changed preview. - gtk_widget_queue_draw(GTK_WIDGET(this->previewDrawingArea)); -} - -void AbstractLatexDialog::setPreviewBackgroundColor(Color newColor) { this->previewBackgroundColor = newColor; } - -void AbstractLatexDialog::previewDrawFunc(GtkDrawingArea*, cairo_t* cr, int width, int height, - AbstractLatexDialog* self) { - - // If we have nothing to render, do nothing! - if (!self->previewPdfPage) { - return; - } - - Range pageRange(0, 0, 0, 0); - poppler_page_get_size(self->previewPdfPage.get(), &pageRange.maxX, &pageRange.maxY); - - const double zoom = - std::min(static_cast(width) / pageRange.maxX, static_cast(height) / pageRange.maxY); - - - if (!self->previewMask.isInitialized() || self->previewMask.getZoom() < zoom) { - // Need to rerender the preview - self->previewMask = xoj::view::Mask(gtk_widget_get_scale_factor(GTK_WIDGET(self->previewDrawingArea)), - pageRange, zoom, CAIRO_CONTENT_COLOR_ALPHA); - poppler_page_render(self->previewPdfPage.get(), self->previewMask.get()); - } - - - Util::cairo_set_source_rgbi(cr, self->previewBackgroundColor); - cairo_paint(cr); - - // Center the rendering - const double extraHorizontalSpace = std::max(0.0, width - pageRange.maxX * zoom); - const double extraVerticalSpace = std::max(0.0, height - pageRange.maxY * zoom); - cairo_translate(cr, 0.5 * extraHorizontalSpace, 0.5 * extraVerticalSpace); - cairo_scale(cr, zoom, zoom); - self->previewMask.paintTo(cr); -} - -void AbstractLatexDialog::populateStandardWidgetsFromBuilder(Builder& builder) { - previewDrawingArea = GTK_DRAWING_AREA(builder.get("texImage")); - btOk = GTK_BUTTON(builder.get("btOk")); - btCancel = GTK_BUTTON(builder.get("btCancel")); - texErrorLabel = GTK_LABEL(builder.get("texErrorLabel")); - compilationOutputTextBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(builder.get("texCommandOutputText"))); -} - -void AbstractLatexDialog::connectStandardSignals() { - g_signal_connect(btCancel, "clicked", G_CALLBACK(+[](GtkButton*, gpointer d) { - auto* self = static_cast(d); - self->texCtrl->cancelEditing(); - gtk_window_close(self->window.get()); - }), - this); - g_signal_connect(btOk, "clicked", G_CALLBACK(+[](GtkButton*, gpointer d) { - auto* self = static_cast(d); - self->texCtrl->insertTexImage(); - gtk_window_close(self->window.get()); - }), - this); - - gtk_drawing_area_set_draw_func(this->previewDrawingArea, GtkDrawingAreaDrawFunc(previewDrawFunc), this, nullptr); - if (texCtrl->temporaryRender) { - // Use preexisting pdf - setTempRender(texCtrl->temporaryRender->getPdf()); - } -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/AbstractLatexDialog.h b/entry/src/main/cpp/src/core/gui/dialog/AbstractLatexDialog.h deleted file mode 100644 index 6540ea4..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/AbstractLatexDialog.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Xournal++ - * - * Latex implementation - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include // for unique_ptr - -#include // for PopplerDocument - -#include "gui/Builder.h" // for Builder -#include "util/Color.h" // for Color -#include "util/raii/GObjectSPtr.h" // for GObjectSPtr -#include "util/raii/GtkWindowUPtr.h" // for GtkWindowUPtr -#include "view/Mask.h" // for Mask - -class LatexController; - -class AbstractLatexDialog { -public: - AbstractLatexDialog() = delete; - AbstractLatexDialog(const AbstractLatexDialog& other) = delete; - AbstractLatexDialog& operator=(const AbstractLatexDialog& other) = delete; - AbstractLatexDialog(std::unique_ptr texCtrl); - virtual ~AbstractLatexDialog(); - -public: - virtual void setCompilationStatus(bool isTexValid, bool isCompilationDone, const std::string& compilationOutput); - - virtual std::string getBufferContents() = 0; - - /** - * Set temporary Tex render and queue a re-draw. - * @param pdf PDF document with rendered TeX. - */ - void setTempRender(PopplerDocument* pdf); - - /** - * Set TeX preview background color to the given color. - * @param color New preview background color. - */ - void setPreviewBackgroundColor(Color color); - - inline GtkWindow* getWindow() const { return window.get(); } - -protected: - /** - * @brief Preview DrawingArea draw function - */ - static void previewDrawFunc(GtkDrawingArea* drawing_area, cairo_t* cr, int width, int height, - AbstractLatexDialog* self); - - /** - * @brief populate the widgets stored in AbstractLatexDialog from the given builder with their - * standard names. - */ - void populateStandardWidgetsFromBuilder(Builder& builder); - - /** - * Connect the cancel button to cancelEditing, the Ok button to insertTexImage as well as the - * draw handler for the preview area. - */ - void connectStandardSignals(); - -protected: - std::unique_ptr texCtrl; - xoj::util::GtkWindowUPtr window; - GtkButton* btOk; - GtkButton* btCancel; - - // Preview - GtkDrawingArea* previewDrawingArea; - xoj::view::Mask previewMask; - - /** - * Source page from which we render the preview. - */ - xoj::util::GObjectSPtr previewPdfPage; - - GtkLabel* texErrorLabel; - GtkTextBuffer* compilationOutputTextBuffer; - - /** - * Background color for the LaTeX preview. - */ - Color previewBackgroundColor; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/ButtonConfigGui.cpp b/entry/src/main/cpp/src/core/gui/dialog/ButtonConfigGui.cpp deleted file mode 100644 index cb0524c..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/ButtonConfigGui.cpp +++ /dev/null @@ -1,284 +0,0 @@ -#include "ButtonConfigGui.h" - -#include // for allocator, allocator_trai... -#include // for pair - -#include // for GDK_TYPE_PIXBUF, GdkPixbuf -#include // for GdkRGBA -#include // for g_value_get_int, GValue - -#include "control/DeviceListHelper.h" // for InputDevice, getDeviceList -#include "control/settings/ButtonConfig.h" // for ButtonConfig -#include "control/settings/Settings.h" // for Settings -#include "gui/Builder.h" -#include "util/Color.h" // for GdkRGBA_to_argb, rgb_to_G... -#include "util/gtk4_helper.h" -#include "util/i18n.h" // for _ - -class GladeSearchpath; - -constexpr auto UI_FILE = "settingsButtonConfig.glade"; -constexpr auto UI_WIDGET_NAME = "mainBox"; - -ButtonConfigGui::ToolSizeIndexMap ButtonConfigGui::toolSizeIndexMap = {{0, TOOL_SIZE_NONE}, {1, TOOL_SIZE_VERY_FINE}, - {2, TOOL_SIZE_FINE}, {3, TOOL_SIZE_MEDIUM}, - {4, TOOL_SIZE_THICK}, {5, TOOL_SIZE_VERY_THICK}}; - -std::string ButtonConfigGui::toolSizeToLabel(ToolSize size) { - switch (size) { - case TOOL_SIZE_NONE: - return _("Thickness - don't change"); - case TOOL_SIZE_VERY_FINE: - return _("Very thin"); - case TOOL_SIZE_FINE: - return _("Thin"); - case TOOL_SIZE_MEDIUM: - return _("Medium"); - case TOOL_SIZE_THICK: - return _("Thick"); - case TOOL_SIZE_VERY_THICK: - return _("Very thick"); - default: - return ""; - } -} - -ButtonConfigGui::ButtonConfigGui(GladeSearchpath* gladeSearchPath, GtkBox* box, Settings* settings, unsigned int button, - bool withDevice): - settings(settings), button(button), withDevice(withDevice), iconNameHelper(settings) { - Builder builder(gladeSearchPath, UI_FILE); - - gtk_box_append(box, builder.get(UI_WIDGET_NAME)); // box takes ownership of it all! - - this->cbDevice = builder.get("labelDevice"); - this->cbDisableDrawing = builder.get("cbDisableDrawing"); - - if (withDevice) { - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDevice), _("No device")); - - this->deviceList = DeviceListHelper::getDeviceList(this->settings, true); - for (InputDevice const& dev: this->deviceList) { - std::string txt = dev.getName() + " (" + dev.getType() + ")"; - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDevice), txt.c_str()); - } - } else { - gtk_widget_hide(builder.get("lbDevice")); - gtk_widget_hide(this->cbDevice); - gtk_widget_hide(this->cbDisableDrawing); - } - - GtkListStore* typeModel = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT); - - auto addTypeCB = [&](const char* icon, const char* name, ToolType action) { - GtkTreeIter iter; - gtk_list_store_append(typeModel, &iter); - gtk_list_store_set(typeModel, &iter, 0, iconNameHelper.iconName(icon).c_str(), 1, name, 2, action, -1); - }; - - addTypeCB("transparent", _("Tool - don't change"), TOOL_NONE); - addTypeCB("tool-pencil", _("Pen"), TOOL_PEN); - addTypeCB("tool-eraser", _("Eraser"), TOOL_ERASER); - addTypeCB("tool-highlighter", _("Highlighter"), TOOL_HIGHLIGHTER); - addTypeCB("tool-text", _("Text"), TOOL_TEXT); - addTypeCB("tool-image", _("Insert image"), TOOL_IMAGE); - addTypeCB("laser-pointer", _("Laser Pointer - Pen"), TOOL_LASER_POINTER_PEN); - addTypeCB("laser-pointer", _("Laser Pointer - Highlighter"), TOOL_LASER_POINTER_HIGHLIGHTER); - addTypeCB("spacer", _("Vertical space"), TOOL_VERTICAL_SPACE); - addTypeCB("select-lasso", _("Select region"), TOOL_SELECT_REGION); - addTypeCB("select-rect", _("Select rectangle"), TOOL_SELECT_RECT); - addTypeCB("select-multilayer-lasso", _("Select multi layer region"), TOOL_SELECT_MULTILAYER_REGION); - addTypeCB("select-multilayer-rect", _("Select multi layer rect"), TOOL_SELECT_MULTILAYER_RECT); - addTypeCB("hand", _("Hand"), TOOL_HAND); - addTypeCB("floating-toolbox", _("Floating Toolbox (experimental)"), TOOL_FLOATING_TOOLBOX); - addTypeCB("select-pdf-text-ht", _("Select Text from pdf"), TOOL_SELECT_PDF_TEXT_LINEAR); - addTypeCB("select-pdf-text-area", _("Select Area Text from pdf"), TOOL_SELECT_PDF_TEXT_RECT); - - this->cbTool = builder.get("cbTool"); - gtk_combo_box_set_model(GTK_COMBO_BOX(this->cbTool), GTK_TREE_MODEL(typeModel)); - g_signal_connect(cbTool, "changed", G_CALLBACK(&cbSelectCallback), this); - - GtkCellRenderer* renderer = gtk_cell_renderer_pixbuf_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(this->cbTool), renderer, false); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(this->cbTool), renderer, "icon-name", 0, nullptr); - - renderer = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(this->cbTool), renderer, true); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(this->cbTool), renderer, "text", 1, nullptr); - - this->cbThickness = builder.get("cbThickness"); - for (auto const& size: toolSizeIndexMap) { - gtk_combo_box_text_insert_text(GTK_COMBO_BOX_TEXT(cbThickness), size.first, - toolSizeToLabel(size.second).c_str()); - } - gtk_combo_box_set_active(GTK_COMBO_BOX(cbThickness), 0); - - this->colorButton = builder.get("colorButton"); - - this->cbDrawingType = builder.get("cbDrawingType"); - // DRAWING_TYPE_DONT_CHANGE - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Drawing Type - don't change")); - // DRAWING_TYPE_DEFAULT - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Normal drawing")); - // DRAWING_TYPE_RULER - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Draw Line")); - // DRAWING_TYPE_RECTANGLE - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Draw Rectangle")); - // DRAWING_TYPE_ELLIPSE - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Draw Ellipse")); - // DRAWING_TYPE_ARROW - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Draw Arrow")); - // DRAWING_TYPE_DOUBLE_ARROW - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Draw Double Arrow")); - // DRAWING_TYPE_COORDINATE_SYSTEM - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Draw Coordinate System")); - // DRAWING_TYPE_STROKE_RECOGNIZER - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Shape Recognizer")); - // DRAWING_TYPE_SPLINE - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(this->cbDrawingType), _("Draw Spline")); - - - // Values in glade GUI! - this->cbEraserType = builder.get("cbEraserType"); - - // Possible values are defined in the .glade file - this->cbStrokeType = builder.get("cbStrokeType"); - - loadSettings(); -} - -void ButtonConfigGui::loadSettings() { - ButtonConfig* cfg = settings->getButtonConfig(button); - - GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(cbTool)); - GtkTreeIter iter; - - if (!gtk_tree_model_get_iter_first(model, &iter)) { - return; - } - - GValue value = {0}; - int i = 0; - - gtk_combo_box_set_active(GTK_COMBO_BOX(cbTool), 0); - - do { - gtk_tree_model_get_value(model, &iter, 2, &value); - - int action = g_value_get_int(&value); - - if (action == cfg->action) { - gtk_combo_box_set_active(GTK_COMBO_BOX(cbTool), i); - break; - } - - i++; - g_value_unset(&value); - } while (gtk_tree_model_iter_next(model, &iter)); - - // select thickness in combo box - gtk_combo_box_set_active(GTK_COMBO_BOX(cbThickness), 0); - for (auto const& size: toolSizeIndexMap) { - if (size.second == cfg->size) { - gtk_combo_box_set_active(GTK_COMBO_BOX(cbThickness), size.first); - } - } - - GdkRGBA color = Util::rgb_to_GdkRGBA(cfg->color); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(colorButton), &color); - - gtk_combo_box_set_active(GTK_COMBO_BOX(this->cbDrawingType), cfg->drawingType); - - if (cfg->eraserMode == ERASER_TYPE_DEFAULT) { - gtk_combo_box_set_active(GTK_COMBO_BOX(cbEraserType), 1); - } else if (cfg->eraserMode == ERASER_TYPE_WHITEOUT) { - gtk_combo_box_set_active(GTK_COMBO_BOX(cbEraserType), 2); - } else if (cfg->eraserMode == ERASER_TYPE_DELETE_STROKE) { - gtk_combo_box_set_active(GTK_COMBO_BOX(cbEraserType), 3); - } else { - gtk_combo_box_set_active(GTK_COMBO_BOX(cbEraserType), 0); - } - - gtk_combo_box_set_active(GTK_COMBO_BOX(cbStrokeType), cfg->strokeType); - - if (withDevice) { - gtk_combo_box_set_active(GTK_COMBO_BOX(cbDevice), 0); - - int i = 1; - for (InputDevice const& dev: this->deviceList) { - if (cfg->device == dev.getName()) { - gtk_combo_box_set_active(GTK_COMBO_BOX(cbDevice), i); - break; - } - - ++i; - } - - gtk_check_button_set_active(GTK_CHECK_BUTTON(cbDisableDrawing), cfg->disableDrawing); - } -} - -void ButtonConfigGui::saveSettings() { - GtkTreeIter iter; - gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cbTool), &iter); - - GValue value = {0}; - GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(cbTool)); - gtk_tree_model_get_value(model, &iter, 2, &value); - - auto action = static_cast(g_value_get_int(&value)); - ButtonConfig* cfg = settings->getButtonConfig(button); - cfg->action = action; - - int thickness = gtk_combo_box_get_active(GTK_COMBO_BOX(cbThickness)); - if (toolSizeIndexMap.count(thickness) == 0) { - cfg->size = TOOL_SIZE_NONE; - } else { - cfg->size = toolSizeIndexMap[thickness]; - } - - GdkRGBA color; - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(colorButton), &color); - cfg->color = Util::GdkRGBA_to_argb(color); - - cfg->drawingType = static_cast(gtk_combo_box_get_active(GTK_COMBO_BOX(this->cbDrawingType))); - - int eraserMode = gtk_combo_box_get_active(GTK_COMBO_BOX(this->cbEraserType)); - - if (eraserMode == 1) { - cfg->eraserMode = ERASER_TYPE_DEFAULT; - } else if (eraserMode == 2) { - cfg->eraserMode = ERASER_TYPE_WHITEOUT; - } else if (eraserMode == 3) { - cfg->eraserMode = ERASER_TYPE_DELETE_STROKE; - } else { - cfg->eraserMode = ERASER_TYPE_NONE; - } - - cfg->strokeType = static_cast(gtk_combo_box_get_active(GTK_COMBO_BOX(this->cbStrokeType))); - - if (this->withDevice) { - size_t dev = static_cast(gtk_combo_box_get_active(GTK_COMBO_BOX(cbDevice)) - 1); - cfg->device = (dev < 0 || this->deviceList.size() <= dev) ? "" : this->deviceList[dev].getName(); - cfg->disableDrawing = gtk_check_button_get_active(GTK_CHECK_BUTTON(cbDisableDrawing)); - } - - settings->customSettingsChanged(); -} - -void ButtonConfigGui::cbSelectCallback(GtkComboBox*, ButtonConfigGui* gui) { gui->enableDisableTools(); } - -void ButtonConfigGui::enableDisableTools() { - GtkTreeIter iter; - gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cbTool), &iter); - GtkTreeModel* model = gtk_combo_box_get_model(GTK_COMBO_BOX(cbTool)); - - GValue value = {0}; - gtk_tree_model_get_value(model, &iter, 2, &value); - auto action = static_cast(g_value_get_int(&value)); - - gtk_widget_set_visible(cbThickness, action != TOOL_NONE && xoj::tool::hasCapability(action, TOOL_CAP_SIZE)); - gtk_widget_set_visible(colorButton, action != TOOL_NONE && xoj::tool::hasCapability(action, TOOL_CAP_COLOR)); - gtk_widget_set_visible(cbDrawingType, action != TOOL_NONE && xoj::tool::hasCapability(action, TOOL_CAP_RECTANGLE)); - gtk_widget_set_visible(cbEraserType, action == TOOL_ERASER); - gtk_widget_set_visible(cbStrokeType, action == TOOL_PEN); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/ButtonConfigGui.h b/entry/src/main/cpp/src/core/gui/dialog/ButtonConfigGui.h deleted file mode 100644 index 22ffefa..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/ButtonConfigGui.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Xournal++ - * - * The configuration for a button in the Settings Dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for map, map<>::value_compare -#include // for string -#include // for vector - -#include // for GtkWidget, GtkComboBox, GtkWindow - -#include "control/DeviceListHelper.h" // for InputDevice -#include "control/ToolEnums.h" // for ToolSize -#include "gui/IconNameHelper.h" // for IconNameHelper - -class Settings; -class GladeSearchpath; - -class ButtonConfigGui { -public: - ButtonConfigGui(GladeSearchpath* gladeSearchPath, GtkBox* box, Settings* settings, unsigned int button, - bool withDevice); - -public: - void loadSettings(); - void saveSettings(); - -private: - static void cbSelectCallback(GtkComboBox* widget, ButtonConfigGui* gui); - void enableDisableTools(); - std::string toolSizeToLabel(ToolSize size); - -private: - Settings* settings; - - GtkWidget* cbDevice; - GtkWidget* cbDisableDrawing; - - GtkWidget* cbTool; - GtkWidget* cbThickness; - GtkWidget* colorButton; - GtkWidget* cbEraserType; - GtkWidget* cbDrawingType; - GtkWidget* cbStrokeType; - - std::vector deviceList; - - unsigned int button = 0; - bool withDevice = false; - - typedef std::map ToolSizeIndexMap; - static ToolSizeIndexMap toolSizeIndexMap; - IconNameHelper iconNameHelper; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/DeviceClassConfigGui.cpp b/entry/src/main/cpp/src/core/gui/dialog/DeviceClassConfigGui.cpp deleted file mode 100644 index a7ca12c..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/DeviceClassConfigGui.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "DeviceClassConfigGui.h" - -#include // for allocator, char_traits - -#include // for g_ascii_strtoll, g_strdu... - -#include "control/DeviceListHelper.h" // for InputDevice -#include "control/settings/Settings.h" // for Settings -#include "control/settings/SettingsEnums.h" // for InputDeviceTypeOption -#include "gui/Builder.h" // for Builder -#include "util/Assert.h" // for xoj_assert -#include "util/gtk4_helper.h" // for gtk_box_append - -class GladeSearchpath; - -constexpr auto UI_FILE = "settingsDeviceClassConfig.glade"; -constexpr auto UI_WIDGET_NAME = "deviceClassBox"; - -DeviceClassConfigGui::DeviceClassConfigGui(GladeSearchpath* gladeSearchPath, GtkBox* box, Settings* settings, - bool showApplyBtn): - settings(settings) { - Builder builder(gladeSearchPath, UI_FILE); - gtk_box_append(box, builder.get(UI_WIDGET_NAME)); // box takes ownership of it all! - - this->labelDevice = builder.get("labelDevice"); - this->cbDeviceClass = builder.get("cbDeviceClass"); - auto* applyBtn = builder.get("btnApply"); - - gtk_widget_set_visible(applyBtn, showApplyBtn); - if (showApplyBtn) { - g_signal_connect(applyBtn, "clicked", G_CALLBACK(+[](GtkButton*, gpointer d) { - static_cast(d)->saveSettings(); - }), - this); - } -} - -DeviceClassConfigGui::~DeviceClassConfigGui() = default; - -void DeviceClassConfigGui::setDevice(const InputDevice& d) { - this->device = d; - gtk_label_set_text(GTK_LABEL(this->labelDevice), (device.getName() + " (" + device.getType() + ")").c_str()); - - loadSettings(); -} - -void DeviceClassConfigGui::loadSettings() { - // Get device class of device if available or - InputDeviceTypeOption deviceType = - this->settings->getDeviceClassForDevice(this->device.getName(), this->device.getSource()); - // Use the ID of each option in case the combo box options get rearranged in the future - gtk_combo_box_set_active_id(GTK_COMBO_BOX(this->cbDeviceClass), - std::to_string(static_cast(deviceType)).c_str()); -} - -void DeviceClassConfigGui::saveSettings() { - const gchar* deviceClassId = gtk_combo_box_get_active_id(GTK_COMBO_BOX(this->cbDeviceClass)); - xoj_assert(deviceClassId != nullptr); - auto deviceClass = static_cast(g_ascii_strtoll(deviceClassId, nullptr, 10)); - this->settings->setDeviceClassForDevice(this->device.getName(), this->device.getSource(), deviceClass); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/DeviceClassConfigGui.h b/entry/src/main/cpp/src/core/gui/dialog/DeviceClassConfigGui.h deleted file mode 100644 index 571c6e9..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/DeviceClassConfigGui.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * The configuration for a button in the Settings Dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GtkWidget, GtkComboBox, GtkWindow - -#include "control/DeviceListHelper.h" // for InputDevice - -class Settings; -class GladeSearchpath; - -class DeviceClassConfigGui { -public: - DeviceClassConfigGui(GladeSearchpath* gladeSearchPath, GtkBox* box, Settings* settings, bool showApplyBtn = false); - ~DeviceClassConfigGui(); - -public: - void loadSettings(); - void saveSettings(); - - /// Set the device represented by the entry. - /// Please call saveSettings() beforehand if the settings of the previous device need to be saved. - void setDevice(const InputDevice& device); - - inline bool representsDevice(const InputDevice& dev) const { return dev == device; } - -private: - Settings* settings; - InputDevice device; - - GtkWidget* labelDevice; - GtkWidget* cbDeviceClass; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/DeviceListDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/DeviceListDialog.cpp deleted file mode 100644 index 6ea0354..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/DeviceListDialog.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "DeviceListDialog.h" - -#include "control/settings/Settings.h" -#include "gui/Builder.h" -#include "util/gtk4_helper.h" // for gtk_box_append, ... - -#include "DeviceClassConfigGui.h" - -constexpr auto UI_FILE_NAME = "deviceList.glade"; -constexpr auto UI_MAIN_ID = "deviceListDialog"; -constexpr auto UI_CONTENT_BOX = "contentBox"; - -DeviceListDialog::DeviceListDialog(GladeSearchpath* gladeSearchPath, Settings* settings): settings(settings) { - - Builder builder(gladeSearchPath, UI_FILE_NAME); - window.reset(GTK_WINDOW(builder.get(UI_MAIN_ID))); - - auto deviceList = DeviceListHelper::getDeviceList(settings); - auto* box = GTK_BOX(builder.get(UI_CONTENT_BOX)); - for (const InputDevice& inputDevice: deviceList) { - auto& entry = this->deviceClassConfigs.emplace_back(gladeSearchPath, box, settings); - entry.setDevice(inputDevice); - } - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); - g_signal_connect_swapped(builder.get("btOk"), "clicked", G_CALLBACK(+[](DeviceListDialog* self) { - self->saveSettings(); - gtk_window_close(self->window.get()); - }), - this); -} - -void DeviceListDialog::saveSettings() { - this->settings->transactionStart(); - for (auto& deviceClassConfigGui: this->deviceClassConfigs) { - deviceClassConfigGui.saveSettings(); - } - this->settings->transactionEnd(); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/DeviceListDialog.h b/entry/src/main/cpp/src/core/gui/dialog/DeviceListDialog.h deleted file mode 100644 index fcb15d6..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/DeviceListDialog.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Xournal++ - * - * Dialog listing known devices - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for vector - -#include "util/raii/GtkWindowUPtr.h" - -class Settings; -class GladeSearchpath; -class DeviceClassConfigGui; - -class DeviceListDialog { -public: - DeviceListDialog(GladeSearchpath* gladeSearchPath, Settings* settings); - -public: - inline GtkWindow* getWindow() const { return window.get(); } - -private: - void saveSettings(); - -private: - Settings* settings; - std::vector deviceClassConfigs; - - xoj::util::GtkWindowUPtr window; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/DeviceTestingArea.cpp b/entry/src/main/cpp/src/core/gui/dialog/DeviceTestingArea.cpp deleted file mode 100644 index 8633be9..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/DeviceTestingArea.cpp +++ /dev/null @@ -1,425 +0,0 @@ -#include "DeviceTestingArea.h" - -#include -#include - -#include -#include -#include - -#include "control/settings/Settings.h" -#include "gui/Builder.h" -#include "gui/dialog/XojSaveDlg.h" -#include "gui/inputdevices/InputContext.h" -#include "gui/inputdevices/InputEvents.h" -#include "gui/inputdevices/PrintEvent.h" -#include "model/Point.h" -#include "util/CircularBuffer.h" -#include "util/EnumIndexedArray.h" -#include "util/PathUtil.h" -#include "util/PopupWindowWrapper.h" -#include "util/VersionInfo.h" -#include "util/glib_casts.h" -#include "util/gtk4_helper.h" // for gtk_box_append, ... -#include "util/i18n.h" -#include "util/raii/GtkWindowUPtr.h" - -#include "DeviceClassConfigGui.h" -#include "DeviceListDialog.h" -#include "filesystem.h" - -constexpr auto UI_FILE_NAME = "deviceTestingArea.glade"; -constexpr auto UI_MAIN_ID = "mainBox"; - -static constexpr double PRESSURE_FACTOR = 20; -static constexpr size_t CONTACT_BUTTON_INDEX = 1; ///< Corresponds to button == 1 in GdkEvent -static constexpr double PRESSURELESS_INDICATOR_HALF_SIZE = 3; - -static constexpr size_t MAX_NB_BUTTONS = 4; -static constexpr std::bitset CONSIDERED_FOR_TIP_EMULATION(0b1100); -static constexpr std::bitset MOUSE_BUTTONS_MASK(0b1110); - -static constexpr unsigned int IN_USE_RESET_DELAY = 100; ///< in ms - -struct Ev { - Point point; - std::bitset pressedButtons; - DeviceTestingArea::HandlerType type; -}; - - -enum class DevCategory : size_t { - MOUSE = 0, - STYLUS = 1, - ERASER = 2, - TOUCHSCREEN = 3, - ENUMERATOR_COUNT = 4 ///< Used as bound -}; /// Used as indices for buttonsStatus - -struct DeviceTestingArea::Data { - CircularBuffer lastEvs{20}; - EnumIndexedArray, DevCategory> buttonsStatus; - size_t nbTouchSequences; - std::stringstream log; ///< all the events as received (after conversion) by the handlers - std::stringstream ellipsizedLog; ///< Same as log, but sequences of MOTION_EVENT's are ellipsized - std::stringstream allGdkEvents; ///< all the events, as emitted by GDK - size_t nbOfConsecutiveMotionEvents = 0; - GdkDevice* lastMotionDevice = nullptr; - guint32 timeReference = 0; ///< timestamp of DeviceTestingArea's creation -}; - -static void draw(GtkDrawingArea*, cairo_t* cr, int width, int height, gpointer lastEvs) { - cairo_set_source_rgb(cr, 1., 1., 1.); - cairo_paint(cr); - cairo_set_source_rgb(cr, 0., 0., 0.); - cairo_set_line_width(cr, 2); - - // Draw a frame - using CSS seems not to work for GtkDrawingArea's - cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); - cairo_line_to(cr, 0., 0.); - cairo_line_to(cr, width, 0.); - cairo_line_to(cr, width, height); - cairo_line_to(cr, 0., height); - cairo_close_path(cr); - cairo_stroke(cr); - - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - - for (auto&& e: *static_cast*>(lastEvs)) { - if (e.pressedButtons[CONTACT_BUTTON_INDEX] || - (e.type == DeviceTestingArea::MOUSE && (e.pressedButtons & MOUSE_BUTTONS_MASK).any())) { - // Contact - if (e.point.z == Point::NO_PRESSURE) { - cairo_set_source_rgb(cr, 1., 0., 0.); - cairo_move_to(cr, e.point.x, e.point.y); - cairo_rel_move_to(cr, -PRESSURELESS_INDICATOR_HALF_SIZE, -PRESSURELESS_INDICATOR_HALF_SIZE); - cairo_rel_line_to(cr, 2 * PRESSURELESS_INDICATOR_HALF_SIZE, 2 * PRESSURELESS_INDICATOR_HALF_SIZE); - cairo_rel_move_to(cr, -2 * PRESSURELESS_INDICATOR_HALF_SIZE, 0); - cairo_rel_line_to(cr, 2 * PRESSURELESS_INDICATOR_HALF_SIZE, -2 * PRESSURELESS_INDICATOR_HALF_SIZE); - } else { - cairo_set_source_rgb(cr, .4, 1., 0.); - cairo_arc(cr, e.point.x, e.point.y, PRESSURE_FACTOR * e.point.z, 0, 2. * M_PI); - } - } else { - // No contact: hovering - cairo_set_source_rgb(cr, .5, .5, .5); - cairo_move_to(cr, e.point.x, e.point.y); - cairo_rel_line_to(cr, 0, 0); - } - cairo_stroke(cr); - } -} - -static void saveLog(const std::stringstream& fullLog, const std::stringstream& ellipsizedLog, - const std::stringstream& gdkeventslog, GtkWidget* parent, Settings* settings) { - - auto pathValidation = [](fs::path& p, const char* filterName) { - Util::clearExtensions(p, ".zip"); - p += ".zip"; - return true; - }; - - auto callback = [fullLog = fullLog.str(), ellipsizedLog = ellipsizedLog.str(), gdkeventslog = gdkeventslog.str(), - settings = settings->getSettingsFile()](std::optional p) { - if (p && !p->empty()) { - int errorCode = 0; - auto* zip = zip_open(char_cast(p->u8string().c_str()), ZIP_CREATE | ZIP_TRUNCATE, &errorCode); - if (!zip) { - // TODO handle error - // errorCode contains the error - return; - } - auto addSource = [&](const char* name, zip_source_t* source) { - if (!source) { - // TODO handle error - // zip_strerror(zip) returns the error string - } else if (zip_file_add(zip, name, source, ZIP_FL_ENC_UTF_8) < 0) { - // TODO handler error - // zip_strerror(zip) returns the error string - zip_source_free(source); - } - }; - addSource("ellipsized-logs.txt", zip_source_buffer(zip, ellipsizedLog.data(), ellipsizedLog.length(), 0)); - addSource("full-logs.txt", zip_source_buffer(zip, fullLog.data(), fullLog.length(), 0)); - addSource("input-gdk_events.txt", zip_source_buffer(zip, gdkeventslog.data(), gdkeventslog.length(), 0)); -#ifdef ZIP_LENGTH_TO_END // Only introduced in libzip 1.10.1 - ubuntu 22 has v1.7.3 - addSource("settings.xml", - zip_source_file(zip, char_cast(settings.u8string().c_str()), 0, ZIP_LENGTH_TO_END)); -#else - addSource("settings.xml", zip_source_file(zip, char_cast(settings.u8string().c_str()), 0, -1)); -#endif - auto version = xoj::util::getVersionInfo(); - addSource("version.txt", zip_source_buffer(zip, version.data(), version.length(), 0)); - - errorCode = zip_close(zip); - if (errorCode) { - // TODO handle error - } - } - }; - - auto popup = xoj::popup::PopupWindowWrapper( - nullptr, fs::path(), _("Export Logs"), _("Export"), std::move(pathValidation), std::move(callback)); - - auto* fc = GTK_FILE_CHOOSER(popup.getPopup()->getWindow()); - - GtkFileFilter* filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, "ZIP archive"); - gtk_file_filter_add_mime_type(filter, "application/zip"); - gtk_file_chooser_add_filter(fc, filter); - - popup.show(GTK_WINDOW(gtk_widget_get_ancestor(parent, GTK_TYPE_WINDOW))); -} - -DeviceTestingArea::DeviceTestingArea(GladeSearchpath* gladeSearchPath, GtkBox* parent, Settings* settings): - settings(settings), - gladeSearchPath(gladeSearchPath), - emulateTipContactOnButtonPress(settings->getInputSystemTPCButtonEnabled()), - inputContext(std::make_unique(settings, *this)), - ancestorScrolledWindow(gtk_widget_get_ancestor(GTK_WIDGET(parent), GTK_TYPE_SCROLLED_WINDOW), xoj::util::ref), - data(std::make_unique()) { - data->log << std::setprecision(6); - data->log.imbue(std::locale::classic()); - data->allGdkEvents << std::setprecision(6); - data->allGdkEvents.imbue(std::locale::classic()); - data->ellipsizedLog << std::setprecision(6); - data->ellipsizedLog.imbue(std::locale::classic()); - - data->timeReference = strict_cast(as_unsigned(g_get_monotonic_time()) / 1000); - - Builder builder(gladeSearchPath, UI_FILE_NAME); - gtk_box_append(parent, builder.get(UI_MAIN_ID)); - - struct D { - std::stringstream* log; - GtkTextBuffer* view; - }; - g_signal_connect_data(builder.get("logpopover"), "show", G_CALLBACK(+[](GtkWidget*, gpointer d) { - auto* dd = static_cast(d); - gtk_text_buffer_set_text(dd->view, dd->log->str().c_str(), -1); - }), - new D{&data->ellipsizedLog, GTK_TEXT_BUFFER(builder.get("logbuffer"))}, - xoj::util::closure_notify_cb, GConnectFlags(0)); - - auto* cbEmulateTipContactOnButtonPress = builder.get("cbEmulateTipContactOnButtonPress"); - gtk_check_button_set_active(GTK_CHECK_BUTTON(cbEmulateTipContactOnButtonPress), emulateTipContactOnButtonPress); - g_signal_connect(cbEmulateTipContactOnButtonPress, "toggled", - G_CALLBACK(+[] -#if GTK_MAJOR_VERSION == 3 - (GtkToggleButton* btn, gpointer d) { - static_cast(d)->emulateTipContactOnButtonPress = - gtk_toggle_button_get_active(btn); - }), -#else - (GtkCheckButton* btn, gpointer d) { - static_cast(d)->emulateTipContactOnButtonPress = - gtk_check_button_get_active(btn); - }), -#endif - this); - - g_signal_connect(builder.get("btnExportLogs"), "clicked", G_CALLBACK(+[](GtkButton* btn, gpointer d) { - auto* self = static_cast(d); - saveLog(self->data->log, self->data->ellipsizedLog, self->data->allGdkEvents, GTK_WIDGET(btn), - self->settings); - }), - this); - - g_signal_connect(builder.get("btnAllDevices"), "clicked", G_CALLBACK(+[](GtkButton* btn, gpointer d) { - auto* self = static_cast(d); - auto dlg = xoj::popup::PopupWindowWrapper(self->gladeSearchPath, - self->settings); - dlg.show(GTK_WINDOW(gtk_widget_get_ancestor(GTK_WIDGET(btn), GTK_TYPE_WINDOW))); - }), - this); - - - lastDeviceClassConfig = std::make_unique( - gladeSearchPath, GTK_BOX(builder.get("boxLastDevice")), settings, true); - drawingArea.reset(builder.get("testArea"), xoj::util::ref); - - mouseIndicators[0].reset(builder.get("mouse-in-use"), xoj::util::ref); - mouseIndicators[GDK_BUTTON_PRIMARY].reset(builder.get("mouse-left"), xoj::util::ref); - mouseIndicators[GDK_BUTTON_MIDDLE].reset(builder.get("mouse-middle"), xoj::util::ref); - mouseIndicators[GDK_BUTTON_SECONDARY].reset(builder.get("mouse-right"), xoj::util::ref); - stylusIndicators[0].reset(builder.get("stylus-hover"), xoj::util::ref); - stylusIndicators[1].reset(builder.get("stylus-tip"), xoj::util::ref); - stylusIndicators[2].reset(builder.get("stylus-1"), xoj::util::ref); - stylusIndicators[3].reset(builder.get("stylus-2"), xoj::util::ref); - eraserIndicators[0].reset(builder.get("eraser-hover"), xoj::util::ref); - eraserIndicators[1].reset(builder.get("eraser-tip"), xoj::util::ref); - touchIndicators[0].reset(builder.get("touch-1"), xoj::util::ref); - touchIndicators[1].reset(builder.get("touch-2"), xoj::util::ref); - touchIndicators[2].reset(builder.get("touch-3"), xoj::util::ref); - touchIndicators[3].reset(builder.get("touch-4"), xoj::util::ref); - touchIndicators[4].reset(builder.get("touch-5"), xoj::util::ref); - - inputContext->connect(drawingArea.get(), /* connectKeyboardHandler */ false, [data = data.get()](GdkEvent* e) { - xoj::input::printGdkEvent(data->allGdkEvents, e, data->timeReference); - }); - - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(drawingArea.get()), draw, &data->lastEvs, nullptr); -} - -DeviceTestingArea::~DeviceTestingArea() = default; - - -static constexpr const char* handlerTypeToString[] = {"MOUSE", "STYLUS", "TOUCH"}; - - -bool DeviceTestingArea::handle(const InputEvent& e, HandlerType handlerType) { - if (e.deviceClass == INPUT_DEVICE_TOUCHSCREEN) { - /* - * kinetic scrolling will capture touch event if the sequence looks like a scroll. - * We do not want to scroll when testing touch devices in the testing area, so we disable it - */ - if (e.type == ENTER_EVENT) { - gtk_scrolled_window_set_kinetic_scrolling(GTK_SCROLLED_WINDOW(ancestorScrolledWindow.get()), false); - } else if (e.type == LEAVE_EVENT) { - gtk_scrolled_window_set_kinetic_scrolling(GTK_SCROLLED_WINDOW(ancestorScrolledWindow.get()), true); - } - } - data->log << "Handler " << handlerTypeToString[handlerType] << " received:\n"; - xoj::input::printEvent(data->log, e, data->timeReference); - - if (e.type != MOTION_EVENT || e.device != data->lastMotionDevice) { - if (data->nbOfConsecutiveMotionEvents > 1) { - data->ellipsizedLog << " ⦙\n " << data->nbOfConsecutiveMotionEvents - 1 - << " motion events omitted\n ⦙\n"; - } - if (e.type == MOTION_EVENT) { - data->nbOfConsecutiveMotionEvents = 1; - data->lastMotionDevice = e.device; - } else { - data->nbOfConsecutiveMotionEvents = 0; - data->lastMotionDevice = nullptr; - } - data->ellipsizedLog << "Handler " << handlerTypeToString[handlerType] << " received:\n"; - xoj::input::printEvent(data->ellipsizedLog, e, data->timeReference); - } else { - if (data->nbOfConsecutiveMotionEvents == 0) { - data->ellipsizedLog << "Handler " << handlerTypeToString[handlerType] << " received:\n"; - xoj::input::printEvent(data->ellipsizedLog, e, data->timeReference); - data->lastMotionDevice = e.device; - } - data->nbOfConsecutiveMotionEvents++; - } - - auto queueEvent = [&]() { - auto category = [&]() { - switch (e.deviceClass) { - case INPUT_DEVICE_MOUSE: - return DevCategory::MOUSE; - case INPUT_DEVICE_PEN: - return DevCategory::STYLUS; - case INPUT_DEVICE_ERASER: - return DevCategory::ERASER; - case INPUT_DEVICE_TOUCHSCREEN: - return DevCategory::TOUCHSCREEN; - default: - return DevCategory::MOUSE; - } - }(); - data->lastEvs.push_front( - Ev{Point(e.relative.x, e.relative.y, e.pressure), data->buttonsStatus[category], handlerType}); - gtk_widget_queue_draw(drawingArea.get()); - }; - - // The mouse rarely issues LEAVE_EVENT. We turn off the "in-use" indicator after a short time of inactivity - auto resetInUseTimer = [](xoj::util::GSourceURef& timer, GtkWidget* indicator) { - if (!timer) { - gtk_widget_add_css_class(indicator, "pressed"); - } - struct cbData { - GtkWidget* indicator; - xoj::util::GSourceURef* timer; - }; - timer = g_timeout_add_full( - G_PRIORITY_DEFAULT, IN_USE_RESET_DELAY, - +[](gpointer d) { - auto* data = static_cast(d); - gtk_widget_remove_css_class(data->indicator, "pressed"); - data->timer->consume(); - return G_SOURCE_REMOVE; - }, - new cbData{indicator, &timer}, xoj::util::destroy_cb); - }; - - if (e.type == BUTTON_PRESS_EVENT) { - lastDeviceClassConfig->setDevice(InputDevice(e.device)); - if (handlerType == MOUSE && e.button < mouseIndicators.size()) { - data->buttonsStatus[DevCategory::MOUSE].set(e.button); - gtk_widget_add_css_class(mouseIndicators[e.button].get(), "pressed"); - resetInUseTimer(mouseInUseTimer, mouseIndicators[0].get()); - } else if (handlerType == STYLUS) { - if (e.deviceClass == INPUT_DEVICE_PEN && e.button < stylusIndicators.size()) { - data->buttonsStatus[DevCategory::STYLUS].set(e.button); - gtk_widget_add_css_class(stylusIndicators[e.button].get(), "pressed"); - resetInUseTimer(stylusInUseTimer, stylusIndicators[0].get()); - if (e.button != CONTACT_BUTTON_INDEX && emulateTipContactOnButtonPress && - CONSIDERED_FOR_TIP_EMULATION[e.button]) { - data->buttonsStatus[DevCategory::STYLUS].set(CONTACT_BUTTON_INDEX); - gtk_widget_add_css_class(stylusIndicators[CONTACT_BUTTON_INDEX].get(), "pressed"); - } - } else if (e.deviceClass == INPUT_DEVICE_ERASER && e.button < eraserIndicators.size()) { - data->buttonsStatus[DevCategory::ERASER].set(e.button); - gtk_widget_add_css_class(eraserIndicators[e.button].get(), "pressed"); - resetInUseTimer(eraserInUseTimer, eraserIndicators[0].get()); - } - } else if (handlerType == TOUCH) { - data->nbTouchSequences++; - if (data->nbTouchSequences <= 5) { - gtk_widget_add_css_class(touchIndicators[data->nbTouchSequences - 1].get(), "pressed"); - } - data->buttonsStatus[DevCategory::TOUCHSCREEN].set(CONTACT_BUTTON_INDEX); - } - queueEvent(); - } else if (e.type == BUTTON_RELEASE_EVENT) { - if (handlerType == MOUSE && e.button < mouseIndicators.size()) { - data->buttonsStatus[DevCategory::MOUSE].reset(e.button); - gtk_widget_remove_css_class(mouseIndicators[e.button].get(), "pressed"); - resetInUseTimer(mouseInUseTimer, mouseIndicators[0].get()); - } else if (handlerType == TOUCH) { - if (data->nbTouchSequences == 0) { - data->log << "ERROR: Terminating more touch sequences than had been started" << std::endl; - } else if (data->nbTouchSequences <= 5) { - gtk_widget_remove_css_class(touchIndicators[data->nbTouchSequences - 1].get(), "pressed"); - if (--data->nbTouchSequences == 0) { - data->buttonsStatus[DevCategory::TOUCHSCREEN].reset(0); - } - } - } else { - if (e.deviceClass == INPUT_DEVICE_PEN && e.button < stylusIndicators.size()) { - data->buttonsStatus[DevCategory::STYLUS].reset(e.button); - gtk_widget_remove_css_class(stylusIndicators[e.button].get(), "pressed"); - resetInUseTimer(stylusInUseTimer, stylusIndicators[0].get()); - if (e.button != CONTACT_BUTTON_INDEX && emulateTipContactOnButtonPress) { - data->buttonsStatus[DevCategory::STYLUS].reset(CONTACT_BUTTON_INDEX); - gtk_widget_remove_css_class(stylusIndicators[CONTACT_BUTTON_INDEX].get(), "pressed"); - } - } else if (e.deviceClass == INPUT_DEVICE_ERASER && e.button < eraserIndicators.size()) { - data->buttonsStatus[DevCategory::ERASER].reset(e.button); - gtk_widget_remove_css_class(eraserIndicators[e.button].get(), "pressed"); - resetInUseTimer(eraserInUseTimer, eraserIndicators[0].get()); - } - } - queueEvent(); - } else if (e.type == MOTION_EVENT) { - if (handlerType == MOUSE) { - resetInUseTimer(mouseInUseTimer, mouseIndicators[0].get()); - } else if (handlerType == STYLUS) { - if (e.deviceClass == INPUT_DEVICE_PEN) { - resetInUseTimer(stylusInUseTimer, stylusIndicators[0].get()); - } else { - resetInUseTimer(eraserInUseTimer, eraserIndicators[0].get()); - } - } - queueEvent(); - } - return true; -} - -void DeviceTestingArea::saveSettings() const { - this->settings->setInputSystemTPCButtonEnabled(this->emulateTipContactOnButtonPress); - this->lastDeviceClassConfig->saveSettings(); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/DeviceTestingArea.h b/entry/src/main/cpp/src/core/gui/dialog/DeviceTestingArea.h deleted file mode 100644 index de8b6b7..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/DeviceTestingArea.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Xournal++ - * - * An area to test input devices - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include -#include - -#include // for GtkWidget, ... - -#include "util/raii/GObjectSPtr.h" -#include "util/raii/GSourceURef.h" - -class Settings; -class InputContext; -struct InputEvent; -class DeviceClassConfigGui; -class GladeSearchpath; - -class DeviceTestingArea { -public: - DeviceTestingArea(GladeSearchpath* path, GtkBox* parent, Settings* settings); - ~DeviceTestingArea(); - - enum HandlerType { MOUSE = 0, STYLUS = 1, TOUCH = 2 }; - bool handle(const InputEvent& e, HandlerType t); - - void saveSettings() const; - -private: - Settings* settings; - GladeSearchpath* gladeSearchPath; - - bool emulateTipContactOnButtonPress; - - std::unique_ptr inputContext; - xoj::util::WidgetSPtr drawingArea; - - /// Indicators for button status - std::array mouseIndicators; ///< 0 = in use, 1 = left, 2 = middle, 3 = right - std::array stylusIndicators; ///< 0 = in use, 1 = tip, 2 = button-1, 3 = button-2 - std::array eraserIndicators; ///< 0 = in use, 1 = tip - std::array touchIndicators; - - /// Mouse "in use" timer: the mouse stays in use 100ms after its last event - xoj::util::GSourceURef mouseInUseTimer; - xoj::util::GSourceURef stylusInUseTimer; - xoj::util::GSourceURef eraserInUseTimer; - - /// Used to disable kinetic scrolling in order to properly test touchscreens - xoj::util::WidgetSPtr ancestorScrolledWindow; - - /// Show and edit the configuration of the last device used - std::unique_ptr lastDeviceClassConfig; - - struct Data; - std::unique_ptr data; -}; - - -template -class TestingHandler: public Handler { -public: - explicit TestingHandler(InputContext* context, DeviceTestingArea::HandlerType t, DeviceTestingArea& testing): - Handler(context), deviceType(t), testing(testing) {} - ~TestingHandler() = default; - - bool handleImpl(const InputEvent& e) override { return testing.handle(e, deviceType); } - -private: - const DeviceTestingArea::HandlerType deviceType; - DeviceTestingArea& testing; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/ExportDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/ExportDialog.cpp deleted file mode 100644 index b7268fd..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/ExportDialog.cpp +++ /dev/null @@ -1,192 +0,0 @@ -#include "ExportDialog.h" - -#include // for max -#include // for invalid_argument -#include // for string, to_string, operator+ -#include // for allocator - -#include // for G_CALLBACK, g_signal_connect - -#include "gui/Builder.h" -#include "util/ElementRange.h" // for parse, PageRangeVector -#include "util/gtk4_helper.h" - -class GladeSearchpath; - -constexpr auto UI_FILE = "exportSettings.glade"; -constexpr auto UI_DIALOG_NAME = "exportDialog"; - -using namespace xoj::popup; - -ExportDialog::ExportDialog(GladeSearchpath* gladeSearchPath, ExportGraphicsFormat format, size_t currentPage, - size_t pageCount, bool hasPdfBackground, - std::function callbackFun): - currentPage(currentPage), pageCount(pageCount), builder(gladeSearchPath, UI_FILE), callbackFun(callbackFun) { - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - - gtk_label_set_text(GTK_LABEL(builder.get("lbAllPagesInfo")), ("1 - " + std::to_string(pageCount)).c_str()); - gtk_label_set_text(GTK_LABEL(builder.get("lbCurrentPage")), std::to_string(currentPage).c_str()); - -#if GTK_MAJOR_VERSION == 3 - // Widgets are visible by default in gtk4 - gtk_widget_show_all(builder.get("dialog-main-box")); -#endif - - auto removeQualitySetting = [&builder = this->builder]() { - gtk_widget_hide(builder.get("lbQuality")); - gtk_widget_hide(builder.get("boxQuality")); - gtk_widget_hide(builder.get("cbQuality")); - }; - - if (format == EXPORT_GRAPHICS_PDF) { - removeQualitySetting(); - auto* cbt = GTK_COMBO_BOX_TEXT(builder.get("cbtPdfExportBackend")); - for (auto&& [id, name]: ExportBackend::getPrettyNamesOfAvailableBackends()) { - gtk_combo_box_text_append(cbt, id, name); - } - gtk_combo_box_set_active_id(GTK_COMBO_BOX(cbt), ExportBackend::DEFAULT_ID_STRING); - if (!hasPdfBackground) { - // No need for backend selection if no pdf background is present. - gtk_widget_set_sensitive(builder.get("boxPdfBackend"), false); - } - } else if (format == EXPORT_GRAPHICS_PNG) { - gtk_widget_hide(builder.get("cbProgressiveMode")); - gtk_widget_hide(builder.get("boxPdfBackend")); - } else { // (format == EXPORT_GRAPHICS_SVG) - removeQualitySetting(); - gtk_widget_hide(builder.get("cbProgressiveMode")); - gtk_widget_hide(builder.get("boxPdfBackend")); - } - - // rdRangePages toggled signal handler - // - // Sets and unsets the sensitivity of the text form, OK button and - // displays an error when the text form is selected and contains - // invalid user data. The error goes away when the text form is de-selected. - auto toggledHandler = G_CALLBACK(+[](GtkCheckButton* button, ExportDialog* self) { - auto active = gtk_check_button_get_active(button); - auto btOk = self->builder.get("btOk"); - auto txtPages = self->builder.get("txtPages"); - gtk_widget_set_sensitive(txtPages, active); - if (active) { - const std::string text_form(gtk_editable_get_text(GTK_EDITABLE(txtPages))); - try { - ElementRange::parse(text_form, self->pageCount); - gtk_widget_remove_css_class(txtPages, "error"); - gtk_widget_set_sensitive(btOk, true); - } catch (const std::invalid_argument&) { - gtk_widget_add_css_class(txtPages, "error"); - gtk_widget_set_sensitive(btOk, false); - } - } else { - gtk_widget_remove_css_class(txtPages, "error"); - gtk_widget_set_sensitive(btOk, true); - } - }); - // txtPages changed signal handler - // - // Displays an error when the user inputs invalid page ranges in the text form, - // and sets the sensitivity of the OK button to FALSE. These actions are - // reversed when the text form contains a valid page range. - auto changedHandler = G_CALLBACK(+[](GtkEditable* txtPages, ExportDialog* self) { - const std::string text_form(gtk_editable_get_text(txtPages)); - auto btOk = self->builder.get("btOk"); - try { - ElementRange::parse(text_form, self->pageCount); - gtk_widget_remove_css_class(GTK_WIDGET(txtPages), "error"); - gtk_widget_set_sensitive(btOk, true); - } catch (const std::invalid_argument& e) { - gtk_widget_add_css_class(GTK_WIDGET(txtPages), "error"); - gtk_widget_set_sensitive(btOk, false); - } - }); - - g_signal_connect(builder.get("rdRangePages"), "toggled", toggledHandler, this); - g_signal_connect(builder.get("cbQuality"), "changed", G_CALLBACK(ExportDialog::selectQualityCriterion), this); - g_signal_connect(builder.get("txtPages"), "changed", changedHandler, this); - - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); - g_signal_connect_swapped(builder.get("btOk"), "clicked", G_CALLBACK(ExportDialog::onSuccessCallback), this); - - /** - * By calling this->callbackFun() here, we make sure that `control->unblock()` is run even if the user clicks on - * the close-window button. - * - * The callback returns `false` so that the PopupWindowManager callback deleting `this` gets called as well. - */ -#if GTK_MAJOR_VERSION == 3 - g_signal_connect_swapped(window.get(), "delete-event", G_CALLBACK(+[](ExportDialog* self) { - self->callbackFun(*self); - return false; - }), - this); -#else - g_signal_connect_swapped(window.get(), "close-request", G_CALLBACK(+[](ExportDialog* self) { - self->callbackFun(*self); - return false; - }), - this); -#endif -} - -ExportDialog::~ExportDialog() = default; - -void ExportDialog::selectQualityCriterion(GtkComboBox* comboBox, ExportDialog* self) { - int activeCriterion = gtk_combo_box_get_active(comboBox); - switch (activeCriterion) { - case EXPORT_QUALITY_DPI: - gtk_label_set_text(GTK_LABEL(self->builder.get("lbQualityUnit")), "dpi"); - gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(self->builder.get("sbQualityValue")), - GTK_ADJUSTMENT(self->builder.get("adjustmentDpi"))); - break; - case EXPORT_QUALITY_WIDTH: - case EXPORT_QUALITY_HEIGHT: - gtk_label_set_text(GTK_LABEL(self->builder.get("lbQualityUnit")), "px"); - gtk_spin_button_set_adjustment(GTK_SPIN_BUTTON(self->builder.get("sbQualityValue")), - GTK_ADJUSTMENT(self->builder.get("adjustmentHeightWidth"))); - break; - } -} - -void ExportDialog::onSuccessCallback(ExportDialog* self) { - self->confirmed = true; - self->progressiveMode = gtk_check_button_get_active(GTK_CHECK_BUTTON(self->builder.get("cbProgressiveMode"))); - self->backgroundType = static_cast( - gtk_combo_box_get_active(GTK_COMBO_BOX(self->builder.get("cbBackgroundType")))); - self->pageRanges = [self]() { - GtkWidget* rdRangeCurrent = self->builder.get("rdRangeCurrent"); - GtkWidget* rdRangePages = self->builder.get("rdRangePages"); - - if (gtk_check_button_get_active(GTK_CHECK_BUTTON(rdRangePages))) { - return ElementRange::parse(gtk_editable_get_text(GTK_EDITABLE(self->builder.get("txtPages"))), - self->pageCount); - } - if (gtk_check_button_get_active(GTK_CHECK_BUTTON(rdRangeCurrent))) { - PageRangeVector range; - range.emplace_back(self->currentPage - 1, self->currentPage - 1); - return range; - } - - PageRangeVector range; - range.emplace_back(0, self->pageCount - 1); - return range; - }(); - self->pdfExportBackend = ExportBackend::fromString( - gtk_combo_box_get_active_id(GTK_COMBO_BOX(self->builder.get("cbtPdfExportBackend")))); - self->qualityParameter = RasterImageQualityParameter( - static_cast( - gtk_combo_box_get_active(GTK_COMBO_BOX(self->builder.get("cbQuality")))), - gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(self->builder.get("sbQualityValue")))); - gtk_window_close(self->window.get()); -} - -auto ExportDialog::getPngQualityParameter() const -> RasterImageQualityParameter { return qualityParameter; } - -auto ExportDialog::isConfirmed() const -> bool { return this->confirmed; } - -auto ExportDialog::progressiveModeSelected() const -> bool { return this->progressiveMode; } - -auto ExportDialog::getBackgroundType() const -> ExportBackgroundType { return backgroundType; } - -auto ExportDialog::getRange() const -> const PageRangeVector& { return pageRanges; } diff --git a/entry/src/main/cpp/src/core/gui/dialog/ExportDialog.h b/entry/src/main/cpp/src/core/gui/dialog/ExportDialog.h deleted file mode 100644 index 78fe879..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/ExportDialog.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Xournal++ - * - * Dialog with export settings - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include - -#include // for GtkComboBox, GtkWindow - -#include "control/jobs/BaseExportJob.h" // for ExportBackgroundType -#include "control/jobs/ImageExport.h" // for RasterImageQualityParameter -#include "gui/Builder.h" -#include "pdf/base/PdfExportBackend.h" -#include "util/ElementRange.h" // for PageRangeVector -#include "util/raii/GtkWindowUPtr.h" - -class GladeSearchpath; - -namespace xoj::popup { -class ExportDialog { -public: - ExportDialog(GladeSearchpath* gladeSearchPath, ExportGraphicsFormat format, size_t currentPage, size_t pageCount, - bool hasPdfBackground, std::function callbackFun); - ~ExportDialog(); - -public: - bool isConfirmed() const; - const PageRangeVector& getRange() const; - bool progressiveModeSelected() const; - ExportBackgroundType getBackgroundType() const; - inline ExportBackend getPdfExportBackend() const { return pdfExportBackend; } - - /** - * @brief Reads the quality parameter from the dialog - * - * @return The selected quality parameter - */ - RasterImageQualityParameter getPngQualityParameter() const; - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - /** - * @brief Handler for changes in combobox cbQuality - */ - static void selectQualityCriterion(GtkComboBox* comboBox, ExportDialog* self); - - static void onSuccessCallback(ExportDialog* self); - -private: - xoj::util::GtkWindowUPtr window; - - size_t currentPage = 0; - size_t pageCount = 0; - - bool confirmed = false; - bool progressiveMode; - ExportBackgroundType backgroundType; - ExportBackend pdfExportBackend; - RasterImageQualityParameter qualityParameter; - PageRangeVector pageRanges; - - Builder builder; - - std::function callbackFun; -}; -}; // namespace xoj::popup diff --git a/entry/src/main/cpp/src/core/gui/dialog/ExtEdLatexDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/ExtEdLatexDialog.cpp deleted file mode 100644 index d27c5a5..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/ExtEdLatexDialog.cpp +++ /dev/null @@ -1,192 +0,0 @@ -#include "ExtEdLatexDialog.h" - -#include // for ofstream -#include - -#include // for g_subprocess* -#include // for g_object_unref, g_clear_object -#include -#include // for gtk_widget_set_sensitive - -#include "control/Control.h" -#include "control/LatexController.h" -#include "control/settings/LatexSettings.h" -#include "gui/Builder.h" -#include "gui/GladeSearchpath.h" -#include "util/PathUtil.h" // for readString -#include "util/XojMsgBox.h" // for XojMsgBox -#include "util/i18n.h" // for FS, _, _F, N_ -#include "util/raii/GLibGuards.h" // for GErrorGuard, GStrvGuard - -#include "AbstractLatexDialog.h" - -constexpr auto UI_FILE_NAME = "extEdTexDialog.glade"; -constexpr auto UI_DIALOG_ID = "extEdTexDialog"; - -ExtEdLatexDialog::ExtEdLatexDialog(GladeSearchpath* gladeSearchPath, std::unique_ptr ctrl): - AbstractLatexDialog(std::move(ctrl)) { - Builder builder(gladeSearchPath, UI_FILE_NAME); - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_ID))); - populateStandardWidgetsFromBuilder(builder); - btContEdit = GTK_BUTTON(builder.get("btContEdit")); - connectStandardSignals(); - - tempf = texCtrl->texTmpDir / "edit."; - - // Append file extension. - tempf += texCtrl->settings.temporaryFileExt; - - // Write initial content - std::ofstream os{tempf}; - if (!texCtrl->initialTex.empty()) { - os << texCtrl->initialTex; - } else { - os << texCtrl->settings.defaultText; - } - os.close(); - - g_signal_connect(getWindow(), "show", G_CALLBACK(+[](GtkWidget*, gpointer d) { - auto self = static_cast(d); - if (!self->texCtrl->temporaryRender) { - // Trigger an asynchronous compilation if we are not using a preexisting TexImage - // Keep this after popup.show() so that if an error message is to be displayed (e.g. - // missing Tex executable), it'll appear on top of the LatexDialog. - LatexController::handleTexChanged(self->texCtrl.get()); - } - - self->openEditor(); - }), - this); - g_signal_connect(btContEdit, "clicked", G_CALLBACK(+[](GtkButton*, gpointer d) { - auto* self = static_cast(d); - self->openEditor(); - }), - this); -} - -ExtEdLatexDialog::~ExtEdLatexDialog() { - try { - fs::remove(tempf); - } catch (const std::system_error& e) { - g_warning("Failed to remove LaTeX edit file: %s", e.what()); - } - if (editorCancellable) { - g_cancellable_cancel(editorCancellable); - g_object_unref(editorCancellable); - } -}; - -void ExtEdLatexDialog::setCompilationStatus(bool isTexValid, bool isCompilationDone, - const std::string& compilationOutput) { - if (texCtrl->settings.externalEditorAutoConfirm && !editorCancellable && isTexValid && isCompilationDone) { - texCtrl->insertTexImage(); - gtk_window_close(getWindow()); - return; - } - - AbstractLatexDialog::setCompilationStatus(isTexValid, isCompilationDone, compilationOutput); -}; - -void ExtEdLatexDialog::openEditor() { - if (editorCancellable) { - return; - } - - xoj::util::GErrorGuard err{}; - xoj::util::GStrvGuard argv{}; - - std::string editorCmd = texCtrl->settings.externalEditorCmd; - if (editorCmd.empty()) { - auto maybeEditor = g_getenv("EDITOR"); - if (!maybeEditor) { - XojMsgBox::showErrorToUser( - getWindow(), - "No external editor configured and no $EDITOR environment variable set. Please configure an " - "external editor command or disable the external editor functionality to use a built-in one."); - return; - } - editorCmd = maybeEditor; - } - editorCmd += " '"; - editorCmd += char_cast(tempf.u8string()); - editorCmd += "'"; - - if (!g_shell_parse_argv(editorCmd.c_str(), nullptr, xoj::util::out_ptr(argv), xoj::util::out_ptr(err))) { - XojMsgBox::showErrorToUser(getWindow(), FS(_F("Failed to parse external editor command: {1}") % err->message)); - return; - } - - xoj::util::GObjectSPtr launcher(g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_NONE), - xoj::util::adopt); - - Color textColor = texCtrl->control->getToolHandler()->getTool(TOOL_TEXT).getColor(); - std::string colorStr = Util::rgb_to_hex_string(textColor).substr(1); - - g_subprocess_launcher_setenv(launcher.get(), "XPP_TEXT_COLOR", colorStr.c_str(), TRUE); - - xoj::util::GObjectSPtr process( - g_subprocess_launcher_spawnv(launcher.get(), argv.get(), xoj::util::out_ptr(err)), xoj::util::adopt); - - if (err) { - XojMsgBox::showErrorToUser(getWindow(), FS(_F("Could not spawn editor: {1}") % err->message)); - return; - } - - gtk_widget_set_sensitive(GTK_WIDGET(btContEdit), false); - - editorCancellable = g_cancellable_new(); - g_subprocess_wait_async(process.get(), editorCancellable, reinterpret_cast(editorWaitCallback), - this); -} - -void ExtEdLatexDialog::editorWaitCallback(GObject* processObj, GAsyncResult* res, ExtEdLatexDialog* self) { - auto process = G_SUBPROCESS(processObj); - - xoj::util::GErrorGuard err; - if (!g_subprocess_wait_finish(process, res, xoj::util::out_ptr(err))) { - // If we cancelled the operation, that's because the user closed the popup while the editor was still open. We - // must not interact with self now, because that's likely already been destroyed. We kill the editor and then - // return. - if (g_error_matches(err.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED)) { -#ifdef G_OS_UNIX - g_subprocess_send_signal(process, SIGTERM); -#else - // The g_subprocess_send_signal API is unavailable on non-unix platforms, so we use the cross-platform - // g_subprocess_force_exit function. We don't use it on supported platforms so we can send a "nicer" exit - // signal if available, as g_subprocess_force_exit sends SIGKILL on Unices. - g_subprocess_force_exit(process); -#endif - return; - } - - XojMsgBox::showErrorToUser(self->getWindow(), FS(_F("Could not wait for editor: {1}") % err->message)); - return; - } - - g_clear_object(&self->editorCancellable); - gtk_widget_set_sensitive(GTK_WIDGET(self->btContEdit), true); - - auto status = g_subprocess_get_status(process); - if (status != 0) { - XojMsgBox::showErrorToUser(self->getWindow(), FS(_F("Editor exited with bad status {1}") % status)); - return; - } - - auto content = self->getBufferContents(); - - self->texCtrl->triggerImageUpdate(content); -} - -std::string ExtEdLatexDialog::getBufferContents() { - auto content = Util::readString(tempf); - if (!content) { - return std::string(); - } - - // Remove a possible trailing newline - if (!content->empty() && content->back() == '\n') { - content->pop_back(); - } - - return *content; -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/ExtEdLatexDialog.h b/entry/src/main/cpp/src/core/gui/dialog/ExtEdLatexDialog.h deleted file mode 100644 index 734db10..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/ExtEdLatexDialog.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Xournal++ - * - * Latex dialog for an external editor - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include // for gpointer -#include // for GtkWidget - -#include "gui/GladeSearchpath.h" -#include "gui/dialog/AbstractLatexDialog.h" - -class LatexController; - -class ExtEdLatexDialog final: public AbstractLatexDialog { -public: - ExtEdLatexDialog() = delete; - ExtEdLatexDialog(const ExtEdLatexDialog& other) = delete; - ExtEdLatexDialog& operator=(const ExtEdLatexDialog& other) = delete; - ExtEdLatexDialog(GladeSearchpath* gladeSearchPath, std::unique_ptr texCtrl); - ~ExtEdLatexDialog() override; - - std::string getBufferContents() override; - -private: - void setCompilationStatus(bool isTexValid, bool isCompilationDone, const std::string& compilationOutput) override; - - /** - * @brief a callback for the editor exiting - */ - static void editorWaitCallback(GObject* processObj, GAsyncResult* res, ExtEdLatexDialog* self); - - /** - * @brief Open the editor or do nothing if it's already open. - */ - void openEditor(); - -private: - GtkButton* btContEdit; - fs::path tempf; - GCancellable* editorCancellable = nullptr; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/FileChooserFiltersHelper.cpp b/entry/src/main/cpp/src/core/gui/dialog/FileChooserFiltersHelper.cpp deleted file mode 100644 index 1492791..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/FileChooserFiltersHelper.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "FileChooserFiltersHelper.h" - -#include "util/i18n.h" - -namespace xoj { -static void addMimeTypeFilter(GtkFileChooser* fc, const char* name, const char* mime) { - GtkFileFilter* filterPdf = gtk_file_filter_new(); - gtk_file_filter_set_name(filterPdf, name); - gtk_file_filter_add_mime_type(filterPdf, mime); - gtk_file_chooser_add_filter(fc, filterPdf); -} - -void addFilterAllFiles(GtkFileChooser* fc) { - GtkFileFilter* filterAll = gtk_file_filter_new(); - gtk_file_filter_set_name(filterAll, _("All files")); - gtk_file_filter_add_pattern(filterAll, "*"); - gtk_file_chooser_add_filter(fc, filterAll); -} - -void addFilterSupported(GtkFileChooser* fc) { - GtkFileFilter* filterSupported = gtk_file_filter_new(); - gtk_file_filter_set_name(filterSupported, _("Supported files")); - gtk_file_filter_add_mime_type(filterSupported, "application/x-xojpp"); - gtk_file_filter_add_mime_type(filterSupported, "application/x-xopp"); - gtk_file_filter_add_mime_type(filterSupported, "application/x-xopt"); - gtk_file_filter_add_mime_type(filterSupported, "application/pdf"); - gtk_file_filter_add_pattern(filterSupported, "*.moj"); // MrWriter - gtk_file_chooser_add_filter(fc, filterSupported); -} - -void addFilterPdf(GtkFileChooser* fc) { addMimeTypeFilter(fc, _("PDF files"), "application/pdf"); } -void addFilterXoj(GtkFileChooser* fc) { addMimeTypeFilter(fc, _("Xournal files"), "application/x-xojpp"); } -void addFilterXopp(GtkFileChooser* fc) { addMimeTypeFilter(fc, _("Xournal++ files"), "application/x-xopp"); } -void addFilterXopt(GtkFileChooser* fc) { addMimeTypeFilter(fc, _("Xournal++ template"), "application/x-xopt"); } -void addFilterSvg(GtkFileChooser* fc) { addMimeTypeFilter(fc, _("SVG graphics"), "image/svg+xml"); } -void addFilterPng(GtkFileChooser* fc) { addMimeTypeFilter(fc, _("PNG graphics"), "image/png"); } - -void addFilterImages(GtkFileChooser* fc) { - GtkFileFilter* filter = gtk_file_filter_new(); - gtk_file_filter_set_name(filter, _("Image files")); - gtk_file_filter_add_pixbuf_formats(filter); - gtk_file_chooser_add_filter(fc, filter); -} -}; // namespace xoj diff --git a/entry/src/main/cpp/src/core/gui/dialog/FileChooserFiltersHelper.h b/entry/src/main/cpp/src/core/gui/dialog/FileChooserFiltersHelper.h deleted file mode 100644 index 024ddfd..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/FileChooserFiltersHelper.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Xournal++ - * - * Helper functions to add filters to GtkFileChooserDialogs - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -namespace xoj { -void addFilterAllFiles(GtkFileChooser* fc); -void addFilterSupported(GtkFileChooser* fc); -void addFilterPdf(GtkFileChooser* fc); -void addFilterXoj(GtkFileChooser* fc); -void addFilterXopp(GtkFileChooser* fc); -void addFilterXopt(GtkFileChooser* fc); -void addFilterSvg(GtkFileChooser* fc); -void addFilterPng(GtkFileChooser* fc); -void addFilterImages(GtkFileChooser* fc); ///< All images supported by GdkPixbuf -}; // namespace xoj diff --git a/entry/src/main/cpp/src/core/gui/dialog/FormatDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/FormatDialog.cpp deleted file mode 100644 index 2e9adcf..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/FormatDialog.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include "FormatDialog.h" - -#include // for operator==, string, basic_string - -#include // for G_CALLBACK, g_signal_connect -#include // for g_list_free, GList - -#include "control/settings/Settings.h" // for Settings -#include "gui/PaperFormatUtils.h" // for PaperFormatUtils -#include "model/FormatDefinitions.h" // for FormatUnits, XOJ_UNITS, XOJ_U... -#include "util/GListView.h" // for GListView, GListView<>::GList... -#include "util/StringUtils.h" // for StringUtils -#include "util/i18n.h" // for _ - -class GladeSearchpath; - -constexpr auto UI_FILE = "pageFormat.glade"; -constexpr auto UI_DIALOG_NAME = "pageFormatDialog"; - -using namespace xoj::popup; -using xoj::util::GtkPaperSizeUPtr; - -FormatDialog::FormatDialog(GladeSearchpath* gladeSearchPath, Settings* settings, double width, double height, - std::function callback): - settings(settings), - selectedScale(settings->getSizeUnitIndex()), - scale(XOJ_UNITS[selectedScale].scale), - origWidth(width), - origHeight(height), - callbackFun(callback) { - - Builder builder(gladeSearchPath, UI_FILE); - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - - paperTemplatesCombo = GTK_COMBO_BOX(builder.get("cbTemplate")); - landscapeButton = GTK_TOGGLE_BUTTON(builder.get("btLandscape")); - portraitButton = GTK_TOGGLE_BUTTON(builder.get("btPortrait")); - widthSpin = GTK_SPIN_BUTTON(builder.get("spinWidth")); - heightSpin = GTK_SPIN_BUTTON(builder.get("spinHeight")); - - GtkWidget* cbUnit = builder.get("cbUnit"); - - for (int i = 0; i < XOJ_UNIT_COUNT; i++) { - gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cbUnit), XOJ_UNITS[i].name); - } - gtk_combo_box_set_active(GTK_COMBO_BOX(cbUnit), this->selectedScale); - - - PaperFormatUtils::loadDefaultPaperSizes(paperSizes); - paperSizes.emplace_back(_("Custom")); - PaperFormatUtils::fillPaperFormatDropDown(paperSizes, paperTemplatesCombo); - paperSizes.pop_back(); // Remove the custom option to prevent it from being matched in the - // spinValueChangedCb function, as its presence would lead to errors - - reset(this); - - g_signal_connect(landscapeButton, "toggled", G_CALLBACK(landscapeSelectedCb), this); - g_signal_connect(portraitButton, "toggled", G_CALLBACK(portraitSelectedCb), this); - g_signal_connect(paperTemplatesCombo, "changed", G_CALLBACK(cbFormatChangedCb), this); - g_signal_connect(cbUnit, "changed", G_CALLBACK(cbUnitChanged), this); - - g_signal_connect_swapped(widthSpin, "value-changed", G_CALLBACK(spinValueChangedCb), this); - g_signal_connect_swapped(heightSpin, "value-changed", G_CALLBACK(spinValueChangedCb), this); - - g_signal_connect_swapped(builder.get("btReset"), "clicked", G_CALLBACK(reset), this); - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); - g_signal_connect_swapped(builder.get("btOk"), "clicked", G_CALLBACK(+[](FormatDialog* self) { - self->settings->setSizeUnitIndex(self->selectedScale); - self->callbackFun(gtk_spin_button_get_value(self->widthSpin) * self->scale, - gtk_spin_button_get_value(self->heightSpin) * self->scale); - gtk_window_close(self->window.get()); - }), - this); -} - -void FormatDialog::setOrientation(Orientation orientation) { - if (this->orientation == orientation) { - return; - } - this->orientation = orientation; - - gtk_toggle_button_set_active(portraitButton, orientation == ORIENTATION_PORTRAIT); - gtk_toggle_button_set_active(landscapeButton, orientation == ORIENTATION_LANDSCAPE); -} - -void FormatDialog::spinValueChangedCb(FormatDialog* dlg) { - if (dlg->ignoreSpinChange) { - return; - } - - double width = gtk_spin_button_get_value(dlg->widthSpin) * dlg->scale; - double height = gtk_spin_button_get_value(dlg->heightSpin) * dlg->scale; - - if (width < height) { - dlg->setOrientation(ORIENTATION_PORTRAIT); - } else if (width > height) { - dlg->setOrientation(ORIENTATION_LANDSCAPE); - } else { - dlg->setOrientation(ORIENTATION_NOT_DEFINED); - } - - int i = 0; - for (auto& size: dlg->paperSizes) { - xoj_assert(std::holds_alternative(size)); - double w = gtk_paper_size_get_width(std::get(size).get(), GTK_UNIT_POINTS); - double h = gtk_paper_size_get_height(std::get(size).get(), GTK_UNIT_POINTS); - - if ((static_cast(w - width) == 0 && static_cast(h - height) == 0) || - (static_cast(h - width) == 0 && static_cast(w - height) == 0)) { - break; - } - i++; - } - - gtk_combo_box_set_active(dlg->paperTemplatesCombo, i); -} - -void FormatDialog::cbUnitChanged(GtkComboBox* widget, FormatDialog* dlg) { - int selectd = gtk_combo_box_get_active(widget); - if (dlg->selectedScale == selectd) { - return; - } - - double width = gtk_spin_button_get_value(dlg->widthSpin) * dlg->scale; - double height = gtk_spin_button_get_value(dlg->heightSpin) * dlg->scale; - - dlg->selectedScale = selectd; - dlg->scale = XOJ_UNITS[dlg->selectedScale].scale; - - dlg->setSpinValues(width / dlg->scale, height / dlg->scale); -} - -void FormatDialog::cbFormatChangedCb(GtkComboBox* widget, FormatDialog* dlg) { - GtkTreeIter iter; - - if (!gtk_combo_box_get_active_iter(widget, &iter)) { - return; - } - GtkTreeModel* model = gtk_combo_box_get_model(widget); - - GValue value = {0}; - gtk_tree_model_get_value(model, &iter, 1, &value); - - if (!G_VALUE_HOLDS_POINTER(&value)) { - return; - } - auto* s = static_cast(g_value_get_pointer(&value)); - - if (s == nullptr) { - return; - } - - double width = gtk_paper_size_get_width(s, GTK_UNIT_POINTS) / dlg->scale; - double height = gtk_paper_size_get_height(s, GTK_UNIT_POINTS) / dlg->scale; - - if (dlg->orientation == ORIENTATION_LANDSCAPE) { - if (width < height) { - std::swap(width, height); - } - } else { - if (width > height) { - std::swap(width, height); - } - - dlg->setOrientation(ORIENTATION_PORTRAIT); - } - - dlg->setSpinValues(width, height); -} - -void FormatDialog::portraitSelectedCb(GtkToggleButton* bt, FormatDialog* dlg) { - bool activated = gtk_toggle_button_get_active(bt); - - if (activated) { - gtk_toggle_button_set_active(dlg->landscapeButton, false); - dlg->orientation = ORIENTATION_PORTRAIT; - - double width = gtk_spin_button_get_value(dlg->widthSpin); - double height = gtk_spin_button_get_value(dlg->heightSpin); - - if (width > height) { - // Exchange width and height - dlg->setSpinValues(height, width); - } - } -} - -void FormatDialog::landscapeSelectedCb(GtkToggleButton* bt, FormatDialog* dlg) { - bool activated = gtk_toggle_button_get_active(bt); - - if (activated) { - gtk_toggle_button_set_active(dlg->portraitButton, false); - dlg->orientation = ORIENTATION_LANDSCAPE; - - double width = gtk_spin_button_get_value(dlg->widthSpin); - double height = gtk_spin_button_get_value(dlg->heightSpin); - - if (width < height) { - // Exchange width and height - dlg->setSpinValues(height, width); - } - } -} - -void FormatDialog::reset(FormatDialog* self) { - self->setSpinValues(self->origWidth / self->scale, self->origHeight / self->scale); - spinValueChangedCb(self); -} - -void FormatDialog::setSpinValues(double width, double height) { - ignoreSpinChange = true; - gtk_spin_button_set_value(widthSpin, width); - gtk_spin_button_set_value(heightSpin, height); - ignoreSpinChange = false; -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/FormatDialog.h b/entry/src/main/cpp/src/core/gui/dialog/FormatDialog.h deleted file mode 100644 index 44fe5ba..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/FormatDialog.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Xournal++ - * - * The page format dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include // for unique_ptr -#include // for vector - -#include // for gtk_paper_size_free, GtkComboBox, GtkToggl... - -#include "gui/Builder.h" -#include "gui/PaperFormatUtils.h" // for PaperFormatMenuOptionVector -#include "util/raii/GtkWindowUPtr.h" - -class GladeSearchpath; -class Settings; - -namespace xoj::popup { -class FormatDialog { -public: - FormatDialog(GladeSearchpath* gladeSearchPath, Settings* settings, double width, double height, - std::function callback); - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - enum Orientation { ORIENTATION_NOT_DEFINED, ORIENTATION_LANDSCAPE, ORIENTATION_PORTRAIT }; - - void setOrientation(Orientation orientation); - void setSpinValues(double width, double heigth); - - static void portraitSelectedCb(GtkToggleButton* bt, FormatDialog* dlg); - static void landscapeSelectedCb(GtkToggleButton* bt, FormatDialog* dlg); - static void cbFormatChangedCb(GtkComboBox* widget, FormatDialog* dlg); - static void cbUnitChanged(GtkComboBox* widget, FormatDialog* dlg); - static void spinValueChangedCb(FormatDialog* dlg); - static void reset(FormatDialog* self); - -private: - Settings* settings = nullptr; - - PaperFormatUtils::PaperFormatMenuOptionVector paperSizes; - - Orientation orientation = ORIENTATION_NOT_DEFINED; - int selectedScale = 0; - double scale = 0; - - double origWidth = 0; - double origHeight = 0; - - bool ignoreSpinChange = false; - - - GtkComboBox* paperTemplatesCombo; - GtkSpinButton* widthSpin; - GtkSpinButton* heightSpin; - GtkToggleButton* landscapeButton; - GtkToggleButton* portraitButton; - - xoj::util::GtkWindowUPtr window; - std::function callbackFun; -}; -}; // namespace xoj::popup diff --git a/entry/src/main/cpp/src/core/gui/dialog/GotoDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/GotoDialog.cpp deleted file mode 100644 index 4b7da17..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/GotoDialog.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "GotoDialog.h" - -#include // for allocator - -#include "gui/Builder.h" - - -class GladeSearchpath; - -constexpr auto UI_FILE = "goto.glade"; -constexpr auto UI_DIALOG_NAME = "gotoDialog"; - -using namespace xoj::popup; - -GotoDialog::GotoDialog(GladeSearchpath* gladeSearchPath, size_t initialPage, size_t maxPage, - std::function callback): - callback(callback) { - Builder builder(gladeSearchPath, UI_FILE); - this->window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - this->spinButton = GTK_SPIN_BUTTON(builder.get("spinPage")); - gtk_spin_button_set_range(this->spinButton, 1, static_cast(maxPage)); - gtk_spin_button_set_value(this->spinButton, static_cast(initialPage + 1)); - gtk_editable_select_region(GTK_EDITABLE(this->spinButton), 0, -1); // Select the entire content - - auto onSuccessCallback = G_CALLBACK(+[](GotoDialog* self) { - self->callback(static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(self->spinButton)))); - gtk_window_close(self->window.get()); - }); - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); - g_signal_connect_swapped(builder.get("btOk"), "clicked", onSuccessCallback, this); -} - -GotoDialog::~GotoDialog() = default; diff --git a/entry/src/main/cpp/src/core/gui/dialog/GotoDialog.h b/entry/src/main/cpp/src/core/gui/dialog/GotoDialog.h deleted file mode 100644 index b984317..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/GotoDialog.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Xournal++ - * - * Goto-Page dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include - -#include "util/raii/GtkWindowUPtr.h" - -class GladeSearchpath; - -namespace xoj::popup { -class GotoDialog { -public: - GotoDialog(GladeSearchpath* gladeSearchPath, size_t initialPage, size_t maxPage, - std::function callback); - ~GotoDialog(); - -public: - inline GtkWindow* getWindow() const { return window.get(); } - -private: - xoj::util::GtkWindowUPtr window; - GtkSpinButton* spinButton = nullptr; - - std::function callback; -}; -}; // namespace xoj::popup diff --git a/entry/src/main/cpp/src/core/gui/dialog/IntEdLatexDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/IntEdLatexDialog.cpp deleted file mode 100644 index da170d3..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/IntEdLatexDialog.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Xournal++ - * - * Latex implementation - * - * @author W Brenna - * http://wbrenna.ca - * - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#include "IntEdLatexDialog.h" - -#include // for operator<<, basic_ostream -#include // for move - -#include // for g_free, gpointer, guint -#include // for poppler_document_get_n_p... -#include // for poppler_page_get_size - -#include "AbstractLatexDialog.h" -#include "config-features.h" - -#ifdef ENABLE_GTK_SOURCEVIEW -#include // for GTK_SOURCE_VIEW, gtk_sou... -#endif - -#include "control/LatexController.h" -#include "control/settings/LatexSettings.h" // for LatexSettings -#include "gui/Builder.h" -#include "model/Font.h" // for XojFont -#include "util/StringUtils.h" // for replace_pair, StringUtils -#include "util/raii/CStringWrapper.h" - -class GladeSearchpath; - -constexpr auto UI_FILE_NAME = "intEdTexDialog.glade"; -constexpr auto UI_DIALOG_ID = "intEdTexDialog"; - -constexpr auto TEX_BOX_WIDGET_NAME = "texBox"; - -IntEdLatexDialog::IntEdLatexDialog(GladeSearchpath* gladeSearchPath, std::unique_ptr ctrl): - AbstractLatexDialog(std::move(ctrl)), cssProvider(gtk_css_provider_new(), xoj::util::adopt) { - - Builder builder(gladeSearchPath, UI_FILE_NAME); - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_ID))); - - populateStandardWidgetsFromBuilder(builder); - -#ifdef ENABLE_GTK_SOURCEVIEW - this->texBox = gtk_source_view_new(); -#else - this->texBox = gtk_text_view_new(); -#endif - - gtk_widget_set_name(this->texBox, TEX_BOX_WIDGET_NAME); - gtk_text_view_set_editable(GTK_TEXT_VIEW(this->texBox), true); - - this->textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(this->texBox)); - const auto& settings = texCtrl->settings; - if (texCtrl->initialTex.empty()) { - gtk_text_buffer_set_text(this->textBuffer, settings.defaultText.c_str(), -1); - // Preselect the default - GtkTextIter start, end; - gtk_text_buffer_get_bounds(this->textBuffer, &start, &end); - gtk_text_buffer_select_range(this->textBuffer, &start, &end); - } else { - gtk_text_buffer_set_text(this->textBuffer, texCtrl->initialTex.c_str(), -1); - } - -#if GTK_MAJOR_VERSION == 3 - // Widgets are visible by default in gtk4 - gtk_widget_show_all(GTK_WIDGET(texBox)); -#endif - - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(builder.get("texBoxContainer")), this->texBox); - - -#ifdef ENABLE_GTK_SOURCEVIEW - // We own neither the languageManager, the styleSchemeManager, nor the sourceLanguage. - // Do not attempt to free them. - GtkSourceStyleSchemeManager* styleSchemeManager = gtk_source_style_scheme_manager_get_default(); - GtkSourceLanguageManager* lm = gtk_source_language_manager_get_default(); - - // Select the TeX highlighting scheme - GtkSourceLanguage* lang = gtk_source_language_manager_guess_language(lm, "file.tex", nullptr); - std::string styleSchemeId = settings.sourceViewThemeId; - GtkSourceStyleScheme* styleScheme = - gtk_source_style_scheme_manager_get_scheme(styleSchemeManager, styleSchemeId.c_str()); - - if (settings.sourceViewSyntaxHighlight) { - gtk_source_buffer_set_language(GTK_SOURCE_BUFFER(this->textBuffer), lang); - } - - gtk_source_view_set_auto_indent(GTK_SOURCE_VIEW(this->texBox), settings.sourceViewAutoIndent); - gtk_source_view_set_indent_on_tab(GTK_SOURCE_VIEW(this->texBox), settings.sourceViewAutoIndent); - - gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(this->texBox), settings.sourceViewShowLineNumbers); - - if (styleScheme) { - gtk_source_buffer_set_style_scheme(GTK_SOURCE_BUFFER(this->textBuffer), styleScheme); - } -#endif - - // Enable/disable word-wrap. - GtkWrapMode texBoxWrapMode = GTK_WRAP_NONE; - if (settings.editorWordWrap) { - texBoxWrapMode = GTK_WRAP_WORD_CHAR; - } - - gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(this->texBox), texBoxWrapMode); - - std::stringstream texBoxCssBuilder; - if (settings.useCustomEditorFont) { - std::string fontName = settings.editorFont.getName(); - - // Escape "'" and "\" characters in the fontName - StringUtils::replaceAllChars(fontName, {replace_pair('\\', "\\\\")}); - StringUtils::replaceAllChars(fontName, {replace_pair('\'', "\\'")}); - - texBoxCssBuilder << "#" << TEX_BOX_WIDGET_NAME << " {"; - texBoxCssBuilder << " font-size: " << settings.editorFont.getSize() << "pt;"; - texBoxCssBuilder << " font-family: '" << fontName << "';"; - texBoxCssBuilder << " } "; - - gtk_css_provider_load_from_data(this->cssProvider.get(), texBoxCssBuilder.str().c_str(), -1, nullptr); - - // Apply the CSS to both the texBox and the drawing area. - gtk_style_context_add_provider(gtk_widget_get_style_context(GTK_WIDGET(this->previewDrawingArea)), - GTK_STYLE_PROVIDER(this->cssProvider.get()), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - gtk_style_context_add_provider(gtk_widget_get_style_context(GTK_WIDGET(this->texBox)), - GTK_STYLE_PROVIDER(this->cssProvider.get()), - GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - } - - connectStandardSignals(); - - /* - * Connect handleTexChanged() to the text buffer containing the latex code, to trigger rebuilds upon code changes. - */ - g_signal_connect(this->getTextBuffer(), "changed", G_CALLBACK(+[](GtkTextBuffer*, gpointer ctrl) { - LatexController::handleTexChanged(static_cast(ctrl)); - }), - texCtrl.get()); - - g_signal_connect(this->getWindow(), "delete-event", G_CALLBACK(+[](GtkWidget*, GdkEvent*, gpointer d) -> gboolean { - auto self = static_cast(d); - /** - * dlg->getTextBuffer() may survive the dialog. When copying all of its content, the - * clipboard owns a ref to the GtkTextBuffer. We must disconnect the signal to avoid - * dereferencing `self` after its destruction - */ - g_signal_handlers_disconnect_by_data(self->getTextBuffer(), self->texCtrl.get()); - return false; // Let the callback from PopupWindowWrapper delete the dialog - }), - this); - - g_signal_connect(this->getWindow(), "show", G_CALLBACK(+[](GtkWidget*, gpointer d) { - auto texCtrl = static_cast(d); - if (!texCtrl->temporaryRender) { - // Trigger an asynchronous compilation if we are not using a preexisting TexImage - // Keep this after popup.show() so that if an error message is to be displayed (e.g. - // missing Tex executable), it'll appear on top of the LatexDialog. - LatexController::handleTexChanged(texCtrl); - } - }), - texCtrl.get()); -} - -IntEdLatexDialog::~IntEdLatexDialog() = default; - - -auto IntEdLatexDialog::getTextBuffer() -> GtkTextBuffer* { return this->textBuffer; } - -auto IntEdLatexDialog::getBufferContents() -> std::string { - GtkTextIter start, end; - gtk_text_buffer_get_bounds(this->textBuffer, &start, &end); - auto content = - xoj::util::OwnedCString::assumeOwnership(gtk_text_buffer_get_text(this->textBuffer, &start, &end, false)); - return content.get(); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/IntEdLatexDialog.h b/entry/src/main/cpp/src/core/gui/dialog/IntEdLatexDialog.h deleted file mode 100644 index d8fec4e..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/IntEdLatexDialog.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Xournal++ - * - * Latex dialog for the internal editor - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - -#include // for cairo_t -#include // for GtkWidget, GtkTextBuffer, GtkWindow -#include // for GtkCssProvider -#include // for PopplerDocument, PopplerPage - -#include "util/raii/GObjectSPtr.h" - -#include "AbstractLatexDialog.h" - -class LatexController; -class LatexSettings; -class GladeSearchpath; - -class IntEdLatexDialog final: public AbstractLatexDialog { -public: - IntEdLatexDialog() = delete; - IntEdLatexDialog(const IntEdLatexDialog& other) = delete; - IntEdLatexDialog& operator=(const IntEdLatexDialog& other) = delete; - IntEdLatexDialog(GladeSearchpath* gladeSearchPath, std::unique_ptr texCtrl); - virtual ~IntEdLatexDialog(); - -public: - // Necessary for the controller in order to connect the 'text-changed' - // signal handler - GtkTextBuffer* getTextBuffer(); - std::string getBufferContents() override; - -private: - // Text field - xoj::util::GObjectSPtr cssProvider; ///< For tex code display font and size - GtkWidget* texBox; - GtkTextBuffer* textBuffer; - - /** - * The final LaTeX string to save once the dialog is closed. - */ - std::string finalLatex; - - std::function callback; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/LanguageConfigGui.cpp b/entry/src/main/cpp/src/core/gui/dialog/LanguageConfigGui.cpp deleted file mode 100644 index e08f905..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/LanguageConfigGui.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "LanguageConfigGui.h" - -#include // for find, lower_bound, sort -#include // for setenv -#include // for allocator, __alloc_traits<>::... - -#include // for G_TYPE_STRING -#include // for g_warning, gint - -#include "control/settings/Settings.h" // for Settings -#include "util/PathUtil.h" // for getGettextFilepath, getLocale... -#include "util/StringUtils.h" // for StringUtils -#include "util/XojMsgBox.h" // for XojMsgBox -#include "util/i18n.h" // for _ -#include "util/safe_casts.h" // for as_unsigned - -#include "config.h" // for GETTEXT_PACKAGE -#include "filesystem.h" // for directory_iterator, operator/ - -LanguageConfigGui::LanguageConfigGui(GtkBox* parent, Settings* settings): - comboBox(gtk_combo_box_text_new(), xoj::util::adopt), settings(settings) { - gtk_box_append(parent, comboBox.get()); -#if GTK_MAJOR_VERSION == 3 - gtk_widget_show_all(comboBox.get()); -#endif - - // Fetch available locales - try { - fs::path baseLocaleDir = Util::getGettextFilepath(Util::getLocalePath()); - for (auto const& d: fs::directory_iterator(baseLocaleDir)) { - if (auto mofile = (d.path() / "LC_MESSAGES" / GETTEXT_PACKAGE) += ".mo"; fs::exists(mofile)) { - auto u8path = d.path().filename().u8string(); - auto casted = char_cast(u8path); - availableLocales.emplace_back(casted.begin(), casted.end()); - } - } - } catch (const fs::filesystem_error& e) { - g_warning("Failed to fetch available locales:\n%s", e.what()); - } - std::sort(availableLocales.begin(), availableLocales.end()); - - // No pot file for English - if (auto enPos = std::lower_bound(availableLocales.begin(), availableLocales.end(), "en"); - enPos != availableLocales.end() && !StringUtils::startsWith(*enPos, "en")) { - availableLocales.insert(enPos, "en"); - } - - // Default - availableLocales.insert(availableLocales.begin(), _("System Default")); - - auto gtkAvailableLocales = gtk_list_store_new(1, G_TYPE_STRING); - for (auto const& i: availableLocales) { - GtkTreeIter iter; - gtk_list_store_append(gtkAvailableLocales, &iter); - gtk_list_store_set(gtkAvailableLocales, &iter, 0, i.c_str(), -1); - } - gtk_combo_box_set_model(GTK_COMBO_BOX(comboBox.get()), GTK_TREE_MODEL(gtkAvailableLocales)); - - - // Set the current locale if previously selected - auto prefPos = [&]() { - if (auto preferred = settings->getPreferredLocale(); !preferred.empty()) { - if (auto &&endi = availableLocales.end(), prefPos = std::find(availableLocales.begin(), endi, preferred); - prefPos != endi) { - return prefPos; - } - XojMsgBox::showErrorToUser(nullptr, _("Previously selected language not available anymore!")); - } - // Use system default - return availableLocales.begin(); - }(); - gtk_combo_box_set_active(GTK_COMBO_BOX(comboBox.get()), - static_cast(std::distance(availableLocales.begin(), prefPos))); -} - - -void LanguageConfigGui::saveSettings() { - gint pos = gtk_combo_box_get_active(GTK_COMBO_BOX(comboBox.get())); - auto pref = (pos == 0) ? "" : availableLocales[as_unsigned(pos)]; - - settings->setPreferredLocale(pref); - settings->customSettingsChanged(); -#ifdef _WIN32 - _putenv_s("LANGUAGE", this->settings->getPreferredLocale().c_str()); -#else - setenv("LANGUAGE", this->settings->getPreferredLocale().c_str(), 1); -#endif -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/LanguageConfigGui.h b/entry/src/main/cpp/src/core/gui/dialog/LanguageConfigGui.h deleted file mode 100644 index 4d12b22..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/LanguageConfigGui.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Xournal++ - * - * The configuration for a language in the Settings Dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string, basic_string -#include // for vector - -#include // for GtkWidget, GtkBox - -#include "util/raii/GObjectSPtr.h" - -class Settings; -class GladeSearchpath; - -class LanguageConfigGui { -public: - LanguageConfigGui(GtkBox* parent, Settings* settings); - -public: - void saveSettings(); - -private: - std::vector availableLocales; - - xoj::util::WidgetSPtr comboBox; - - Settings* settings; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/LatexSettingsPanel.cpp b/entry/src/main/cpp/src/core/gui/dialog/LatexSettingsPanel.cpp deleted file mode 100644 index 4cea5d3..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/LatexSettingsPanel.cpp +++ /dev/null @@ -1,205 +0,0 @@ -#include "LatexSettingsPanel.h" - -#include // for ifstream, basic_istream -#include // for istreambuf_iterator, ope... -#include // for allocator, string -#include // for get_if - -#include // for GSubprocess, g_subproces... -#include // for g_object_unref, g_object... -#include // for g_error_free, GError - -#include "config-features.h" // for ENABLE_GTK_SOURCEVIEW -#ifdef ENABLE_GTK_SOURCEVIEW -#include // for gtk_source_style_scheme_... -#endif - -#include "control/latex/LatexGenerator.h" // for LatexGenerator::GenError -#include "control/settings/LatexSettings.h" // for LatexSettings -#include "gui/Builder.h" -#include "model/Font.h" // for XojFont -#include "util/Color.h" // for Color -#include "util/PathUtil.h" // for fromGFile, getTmpDir... -#include "util/PlaceholderString.h" // for PlaceholderString -#include "util/XojMsgBox.h" -#include "util/gtk4_helper.h" -#include "util/i18n.h" // for FS, _F, _ -#include "util/raii/CStringWrapper.h" - -#include "filesystem.h" // for path, is_regular_file - -class GladeSearchpath; - -constexpr auto UI_FILE = "latexSettings.glade"; -constexpr auto UI_PANEL_NAME = "latexSettingsPanel"; - -LatexSettingsPanel::LatexSettingsPanel(GladeSearchpath* gladeSearchPath): - builder(gladeSearchPath, UI_FILE), - panel(GTK_SCROLLED_WINDOW(builder.get(UI_PANEL_NAME))), - cbAutoDepCheck(GTK_CHECK_BUTTON(builder.get("latexSettingsRunCheck"))), - // Todo(gtk4): replace this GtkFileChooserButton (by what?) - globalTemplateChooser(GTK_FILE_CHOOSER(builder.get("latexSettingsTemplateFile"))), - cbUseSystemFont(GTK_CHECK_BUTTON(builder.get("cbUseSystemFont"))) { - - g_signal_connect_swapped(builder.get("latexSettingsTestBtn"), "clicked", - G_CALLBACK(+[](LatexSettingsPanel* self) { self->checkDeps(); }), this); - g_signal_connect_swapped(this->cbUseSystemFont, "toggled", - G_CALLBACK(+[](LatexSettingsPanel* self) { self->updateWidgetSensitivity(); }), this); - g_signal_connect_swapped(builder.get("cbUseExternalEditor"), "toggled", - G_CALLBACK(+[](LatexSettingsPanel* self) { self->updateWidgetSensitivity(); }), this); - -#ifdef ENABLE_GTK_SOURCEVIEW - GtkBox* themeSelectionBox = GTK_BOX(builder.get("bxThemeSelectionContainer")); - this->sourceViewThemeSelector = gtk_source_style_scheme_chooser_button_new(); - gtk_box_append(themeSelectionBox, sourceViewThemeSelector); - - gtk_label_set_text(GTK_LABEL(builder.get("lbSourceviewSettingsDescription")), _("LaTeX editor theme:")); - -#if GTK_MAJOR_VERSION == 3 - // Widgets are visible by default in gtk4 - gtk_widget_show(sourceViewThemeSelector); -#endif -#else - this->sourceViewThemeSelector = nullptr; - - gtk_label_set_text(GTK_LABEL(builder.get("lbSourceviewSettingsDescription")), - _("GtkSourceView was disabled when building Xournal++! " - "Some options will not be available.")); -#endif -} - -void LatexSettingsPanel::load(const LatexSettings& settings) { - gtk_check_button_set_active(this->cbAutoDepCheck, settings.autoCheckDependencies); - gtk_editable_set_text(GTK_EDITABLE(builder.get("latexDefaultEntry")), settings.defaultText.c_str()); - if (!settings.globalTemplatePath.empty()) { - gtk_file_chooser_set_file(this->globalTemplateChooser, Util::toGFile(settings.globalTemplatePath).get(), - nullptr); - } - gtk_editable_set_text(GTK_EDITABLE(builder.get("latexSettingsGenCmd")), settings.genCmd.c_str()); - - -#ifdef ENABLE_GTK_SOURCEVIEW - std::string themeId = settings.sourceViewThemeId; - GtkSourceStyleSchemeManager* themeManager = gtk_source_style_scheme_manager_get_default(); - GtkSourceStyleScheme* theme = gtk_source_style_scheme_manager_get_scheme(themeManager, themeId.c_str()); - - if (theme) { - gtk_source_style_scheme_chooser_set_style_scheme(GTK_SOURCE_STYLE_SCHEME_CHOOSER(this->sourceViewThemeSelector), - theme); - } -#endif - - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get("cbShowLineNumbers")), settings.sourceViewShowLineNumbers); - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get("cbAutoIndent")), settings.sourceViewAutoIndent); - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get("cbSyntaxHighlight")), settings.sourceViewSyntaxHighlight); - - // Editor font - std::string editorFontDescription{settings.editorFont.asString()}; - gtk_font_chooser_set_font(GTK_FONT_CHOOSER(builder.get("selBtnEditorFont")), editorFontDescription.c_str()); - - // Should we use the custom editor font? - gtk_check_button_set_active(this->cbUseSystemFont, !settings.useCustomEditorFont); - - // Editor word wrap. - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get("cbWordWrap")), settings.editorWordWrap); - - // External editor - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get("cbUseExternalEditor")), settings.useExternalEditor); - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get("cbExternalEditorAutoConfirm")), - settings.externalEditorAutoConfirm); - gtk_editable_set_text(GTK_EDITABLE(builder.get("latexExternalEditorCmd")), settings.externalEditorCmd.c_str()); - gtk_editable_set_text(GTK_EDITABLE(builder.get("latexTemporaryFileExt")), settings.temporaryFileExt.c_str()); - - this->updateWidgetSensitivity(); -} - -void LatexSettingsPanel::save(LatexSettings& settings) { - settings.autoCheckDependencies = gtk_check_button_get_active(this->cbAutoDepCheck); - settings.defaultText = gtk_editable_get_text(GTK_EDITABLE(builder.get("latexDefaultEntry"))); - settings.globalTemplatePath = Util::fromGFile( - xoj::util::GObjectSPtr(gtk_file_chooser_get_file(this->globalTemplateChooser), xoj::util::adopt) - .get()); - settings.genCmd = gtk_editable_get_text(GTK_EDITABLE(builder.get("latexSettingsGenCmd"))); - -#ifdef ENABLE_GTK_SOURCEVIEW - GtkSourceStyleScheme* theme = gtk_source_style_scheme_chooser_get_style_scheme( - GTK_SOURCE_STYLE_SCHEME_CHOOSER(this->sourceViewThemeSelector)); - settings.sourceViewThemeId = gtk_source_style_scheme_get_id(theme); -#endif - - settings.sourceViewShowLineNumbers = - gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get("cbShowLineNumbers"))); - settings.sourceViewAutoIndent = gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get("cbAutoIndent"))); - settings.sourceViewSyntaxHighlight = - gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get("cbSyntaxHighlight"))); - - GtkFontChooser* fontSelector = GTK_FONT_CHOOSER(builder.get("selBtnEditorFont")); - settings.editorFont = xoj::util::OwnedCString::assumeOwnership(gtk_font_chooser_get_font(fontSelector)).get(); - settings.useCustomEditorFont = !gtk_check_button_get_active(this->cbUseSystemFont); - settings.editorWordWrap = gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get("cbWordWrap"))); - - settings.useExternalEditor = gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get("cbUseExternalEditor"))); - settings.externalEditorAutoConfirm = - gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get("cbExternalEditorAutoConfirm"))); - settings.externalEditorCmd = gtk_editable_get_text(GTK_EDITABLE(builder.get("latexExternalEditorCmd"))); - settings.temporaryFileExt = gtk_editable_get_text(GTK_EDITABLE(builder.get("latexTemporaryFileExt"))); -} - -void LatexSettingsPanel::checkDeps() { - LatexSettings settings; - this->save(settings); - std::string msg; - bool fail = false; - - if (fs::is_regular_file(settings.globalTemplatePath)) { - // Assume the file is encoded as UTF-8 (open in binary mode to avoid surprises) - std::ifstream is(settings.globalTemplatePath, std::ios_base::binary); - if (!is.is_open()) { - msg = FS(_F("Unable to open global template file at {1}. Does it exist?") % - settings.globalTemplatePath.u8string()); - fail = true; - } else { - std::string templ(std::istreambuf_iterator(is), {}); - std::string sample = LatexGenerator::templateSub(settings.defaultText, templ, Colors::black); - auto const& tmpDir = Util::getTmpDirSubfolder("tex"); - auto result = LatexGenerator(settings).asyncRun(tmpDir, sample); - if (auto* proc = std::get_if(&result)) { - GError* err = nullptr; - if (g_subprocess_wait_check(*proc, nullptr, &err)) { - msg = _("Sample LaTeX file generated successfully."); - } else { - msg = FS(_F("Error: {1}. Please check the contents of {2}") % err->message % tmpDir.u8string()); - g_error_free(err); - fail = true; - } - g_object_unref(*proc); - } else if (auto* err = std::get_if(&result)) { - msg = err->message; - fail = true; - } - } - } else { - msg = FS(_F("Error: {1} is not a regular file. Please check your LaTeX template file settings. ") % - settings.globalTemplatePath.u8string()); - fail = true; - } - - GtkWindow* win = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(panel))); - XojMsgBox::showMessageToUser(win, msg, fail ? GTK_MESSAGE_ERROR : GTK_MESSAGE_INFO); -} - -void LatexSettingsPanel::updateWidgetSensitivity() { - bool useSystemFont = gtk_check_button_get_active(this->cbUseSystemFont); - - // Only select a custom font if we're not using the system's. - gtk_widget_set_sensitive(builder.get("boxCustomFontOptions"), !useSystemFont); - -#ifndef ENABLE_GTK_SOURCEVIEW - gtk_widget_set_sensitive(builder.get("bxGtkSourceviewSettings"), false); -#endif - - auto useExternalEditor = gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get("cbUseExternalEditor"))); - gtk_widget_set_sensitive(builder.get("cbExternalEditorAutoConfirm"), useExternalEditor); - gtk_widget_set_sensitive(builder.get("latexExternalEditorCmd"), useExternalEditor); - gtk_widget_set_sensitive(builder.get("latexTemporaryFileExt"), useExternalEditor); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/LatexSettingsPanel.h b/entry/src/main/cpp/src/core/gui/dialog/LatexSettingsPanel.h deleted file mode 100644 index 61c32bb..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/LatexSettingsPanel.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Xournal++ - * - * Latex settings panel - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GtkToggleButton, GtkFileChooser, GtkWidget - -#include "gui/Builder.h" - -class GladeSearchpath; -class LatexSettings; - -class LatexSettingsPanel { -public: - explicit LatexSettingsPanel(GladeSearchpath*); - LatexSettingsPanel(const LatexSettingsPanel&) = delete; - LatexSettingsPanel& operator=(const LatexSettingsPanel&) = delete; - LatexSettingsPanel(const LatexSettingsPanel&&) = delete; - LatexSettingsPanel& operator=(const LatexSettingsPanel&&) = delete; - - void load(const LatexSettings& settings); - void save(LatexSettings& settings); - - inline GtkWidget* getPanel() const { return GTK_WIDGET(panel); } - -private: - void checkDeps(); - - /** - * @brief Update whether options accept input ("grayed-out" or not) - * based on the current panel state. - */ - void updateWidgetSensitivity(); - - Builder builder; - GtkScrolledWindow* panel; - - GtkCheckButton* cbAutoDepCheck; - GtkFileChooser* globalTemplateChooser; - GtkWidget* sourceViewThemeSelector; - GtkCheckButton* cbUseSystemFont; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/PageTemplateDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/PageTemplateDialog.cpp deleted file mode 100644 index eedad86..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/PageTemplateDialog.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "PageTemplateDialog.h" - -#include // for sprintf -#include // for localtime, strftime, time -#include // for ofstream, basic_ostream -#include // for allocator, unique_ptr -#include // for optional -#include // for string, operator<< - -#include // for GdkRGBA -#include // for G_CALLBACK, g_signal_c... - -#include "control/pagetype/PageTypeHandler.h" // for PageTypeInfo, PageType... -#include "control/settings/Settings.h" // for Settings -#include "gui/Builder.h" // for Builder -#include "gui/dialog/XojOpenDlg.h" // for XojOpenDlg -#include "gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.h" -#include "gui/toolbarMenubar/ToolMenuHandler.h" -#include "model/FormatDefinitions.h" // for FormatUnits, XOJ_UNITS -#include "model/PageType.h" // for PageType -#include "util/Color.h" // for GdkRGBA_to_argb, rgb_t... -#include "util/PathUtil.h" // for fromGFile, readString -#include "util/PopupWindowWrapper.h" // for PopupWindowWrapper -#include "util/XojMsgBox.h" // for XojMsgBox -#include "util/i18n.h" // for _ -#include "util/serdesstream.h" // for serdes_stream - -#include "FormatDialog.h" // for FormatDialog -#include "filesystem.h" // for path - -class GladeSearchpath; - -constexpr auto UI_FILE = "pageTemplate.glade"; -constexpr auto UI_DIALOG_NAME = "templateDialog"; - -using namespace xoj::popup; - -PageTemplateDialog::PageTemplateDialog(GladeSearchpath* gladeSearchPath, Settings* settings, ToolMenuHandler* toolmenu, - PageTypeHandler* types): - gladeSearchPath(gladeSearchPath), settings(settings), toolMenuHandler(toolmenu), types(types) { - model.parse(settings->getPageTemplate()); - - Builder builder(gladeSearchPath, UI_FILE); - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - - // Needs to be initialized after this->window - pageTypeSelectionMenu = std::make_unique(types, settings, this); - gtk_menu_button_set_popup(GTK_MENU_BUTTON(builder.get("btBackgroundDropdown")), - pageTypeSelectionMenu->getPopover()); - - pageSizeLabel = GTK_LABEL(builder.get("lbPageSize")); - backgroundTypeLabel = GTK_LABEL(builder.get("lbBackgroundType")); - backgroundColorChooser = GTK_COLOR_CHOOSER(builder.get("cbBackgroundButton")); - copyLastPageButton = GTK_TOGGLE_BUTTON(builder.get("cbCopyLastPage")); - copyLastPageSizeButton = GTK_TOGGLE_BUTTON(builder.get("cbCopyLastPageSize")); - - - g_signal_connect_swapped(builder.get("btChangePaperSize"), "clicked", - G_CALLBACK(+[](PageTemplateDialog* self) { self->showPageSizeDialog(); }), this); - - g_signal_connect_swapped(builder.get("btLoad"), "clicked", - G_CALLBACK(+[](PageTemplateDialog* self) { self->loadFromFile(); }), this); - - g_signal_connect_swapped(builder.get("btSave"), "clicked", - G_CALLBACK(+[](PageTemplateDialog* self) { self->saveToFile(); }), this); - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->getWindow()); - g_signal_connect_swapped(builder.get("btOk"), "clicked", G_CALLBACK(+[](PageTemplateDialog* self) { - self->saveToModel(); - self->settings->setPageTemplate(self->model.toString()); - self->toolMenuHandler->setDefaultNewPageType(self->model.getPageInsertType()); - self->toolMenuHandler->setDefaultNewPaperSize( - self->model.isCopyLastPageSize() ? std::nullopt : - std::optional(PaperSize(self->model))); - gtk_window_close(self->getWindow()); - }), - this); - - updateDataFromModel(); -} - -PageTemplateDialog::~PageTemplateDialog() = default; - -void PageTemplateDialog::updateDataFromModel() { - GdkRGBA color = Util::rgb_to_GdkRGBA(model.getBackgroundColor()); - gtk_color_chooser_set_rgba(backgroundColorChooser, &color); - - updatePageSize(); - - pageTypeSelectionMenu->setSelectedPT(model.getBackgroundType()); - changeCurrentPageBackground(types->getInfoOn(model.getBackgroundType())); - - gtk_toggle_button_set_active(copyLastPageButton, model.isCopyLastPageSettings()); - gtk_toggle_button_set_active(copyLastPageSizeButton, model.isCopyLastPageSize()); -} - -void PageTemplateDialog::changeCurrentPageBackground(const PageTypeInfo* info) { - model.setBackgroundType(info->page); - - gtk_label_set_text(backgroundTypeLabel, info->name.c_str()); -} - -void PageTemplateDialog::saveToModel() { - model.setCopyLastPageSettings(gtk_toggle_button_get_active(copyLastPageButton)); - model.setCopyLastPageSize(gtk_toggle_button_get_active(copyLastPageSizeButton)); - - GdkRGBA color; - gtk_color_chooser_get_rgba(backgroundColorChooser, &color); - model.setBackgroundColor(Util::GdkRGBA_to_argb(color)); -} - -void PageTemplateDialog::saveToFile() { - saveToModel(); - - GtkWidget* dialog = - gtk_file_chooser_dialog_new(_("Save File"), this->getWindow(), GTK_FILE_CHOOSER_ACTION_SAVE, _("_Cancel"), - GTK_RESPONSE_CANCEL, _("_Save"), GTK_RESPONSE_OK, nullptr); - - GtkFileFilter* filterXoj = gtk_file_filter_new(); - gtk_file_filter_set_name(filterXoj, _("Xournal++ template")); - gtk_file_filter_add_mime_type(filterXoj, "application/x-xopt"); - gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filterXoj); - - if (!settings->getLastSavePath().empty()) { - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), Util::toGFile(settings->getLastSavePath()).get(), - nullptr); - } - - time_t curtime = time(nullptr); - char stime[128]; - strftime(stime, sizeof(stime), "%F-Template-%H-%M.xopt", localtime(&curtime)); - fs::path saveFilename = stime; // There may be an issue here, if the C and C++ locales do not use the same encoding - - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), Util::toGFilename(saveFilename).c_str()); - - class FileDlg final { - public: - FileDlg(GtkDialog* dialog, PageTemplateDialog* parent): window(GTK_WINDOW(dialog)), parent(parent) { - this->signalId = g_signal_connect( - dialog, "response", G_CALLBACK((+[](GtkDialog* dialog, int response, gpointer data) { - FileDlg* self = static_cast(data); - if (response == GTK_RESPONSE_OK) { - auto file = Util::fromGFile( - xoj::util::GObjectSPtr(gtk_file_chooser_get_file(GTK_FILE_CHOOSER(dialog)), - xoj::util::adopt) - .get()); - - auto saveTemplate = [self, dialog](const fs::path& file) { - // Closing the window causes another "response" signal, which we want to ignore - g_signal_handler_disconnect(dialog, self->signalId); - gtk_window_close(GTK_WINDOW(dialog)); - self->parent->settings->setLastSavePath(file.parent_path()); - - auto out = serdes_stream(file); - out << self->parent->model.toString(); - }; - XojMsgBox::replaceFileQuestion(GTK_WINDOW(dialog), std::move(file), - std::move(saveTemplate)); - } else { - // Closing the window causes another "response" signal, which we want to ignore - g_signal_handler_disconnect(dialog, self->signalId); - gtk_window_close(GTK_WINDOW(dialog)); // Deletes self, don't do anything after this - } - })), - this); - } - ~FileDlg() = default; - - inline GtkWindow* getWindow() const { return window.get(); } - - private: - xoj::util::GtkWindowUPtr window; - PageTemplateDialog* parent; - gulong signalId; - }; - - auto popup = xoj::popup::PopupWindowWrapper(GTK_DIALOG(dialog), this); - popup.show(GTK_WINDOW(this->getWindow())); -} - -void PageTemplateDialog::loadFromFile() { - xoj::OpenDlg::showOpenTemplateDialog(this->getWindow(), settings, [this](fs::path path) { - auto contents = Util::readString(path); - if (!contents.has_value()) { - return; - } - model.parse(*contents); - - updateDataFromModel(); - }); -} - -void PageTemplateDialog::updatePageSize() { - const FormatUnits* formatUnit = &XOJ_UNITS[settings->getSizeUnitIndex()]; - - char buffer[64]; - sprintf(buffer, "%0.2lf", model.getPageWidth() / formatUnit->scale); - std::string pageSize = buffer; - pageSize += formatUnit->name; - pageSize += " x "; - - sprintf(buffer, "%0.2lf", model.getPageHeight() / formatUnit->scale); - pageSize += buffer; - pageSize += formatUnit->name; - - gtk_label_set_text(pageSizeLabel, pageSize.c_str()); -} - -void PageTemplateDialog::showPageSizeDialog() { - auto popup = xoj::popup::PopupWindowWrapper(gladeSearchPath, settings, - model.getPageWidth(), model.getPageHeight(), - [dlg = this](double width, double height) { - dlg->model.setPageWidth(width); - dlg->model.setPageHeight(height); - - dlg->updatePageSize(); - }); - popup.show(this->getWindow()); -} - -/** - * The dialog was confirmed / saved - */ -auto PageTemplateDialog::isSaved() const -> bool { return saved; } diff --git a/entry/src/main/cpp/src/core/gui/dialog/PageTemplateDialog.h b/entry/src/main/cpp/src/core/gui/dialog/PageTemplateDialog.h deleted file mode 100644 index 7958fa5..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/PageTemplateDialog.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Xournal++ - * - * Dialog to configure page template for new pages - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for unique_ptr - -#include "control/settings/PageTemplateSettings.h" // for PageTemplateSettings -#include "util/raii/GtkWindowUPtr.h" - -class PageTypeHandler; -class PageTypeInfo; -class GladeSearchpath; -class Settings; -class ToolMenuHandler; -class PageTypeSelectionPopoverGridOnly; - -namespace xoj::popup { -class PageTemplateDialog final { -public: - PageTemplateDialog(GladeSearchpath* gladeSearchPath, Settings* settings, ToolMenuHandler* toolmenu, - PageTypeHandler* types); - PageTemplateDialog(PageTemplateDialog&) = delete; - PageTemplateDialog(PageTemplateDialog&&) = delete; - PageTemplateDialog& operator=(PageTemplateDialog&) = delete; - PageTemplateDialog&& operator=(PageTemplateDialog&&) = delete; - ~PageTemplateDialog(); - -public: - /** - * The dialog was confirmed / saved - */ - bool isSaved() const; - - void changeCurrentPageBackground(const PageTypeInfo* info); - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - void showPageSizeDialog(); - void updatePageSize(); - void saveToFile(); - void loadFromFile(); - void updateDataFromModel(); - void saveToModel(); - -private: - GladeSearchpath* gladeSearchPath; // For opening subdialogs as needed - xoj::util::GtkWindowUPtr window; - - Settings* settings; - ToolMenuHandler* toolMenuHandler; - PageTypeHandler* types; - - PageTemplateSettings model; - - std::unique_ptr pageTypeSelectionMenu; - - /** - * The dialog was confirmed / saved - */ - bool saved = false; - -private: - // Sub-widgets, owned by this->window - GtkLabel* pageSizeLabel; - GtkLabel* backgroundTypeLabel; - GtkColorChooser* backgroundColorChooser; - GtkToggleButton* copyLastPageButton; - GtkToggleButton* copyLastPageSizeButton; -}; -}; // namespace xoj::popup diff --git a/entry/src/main/cpp/src/core/gui/dialog/PluginDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/PluginDialog.cpp deleted file mode 100644 index 5e8e5fc..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/PluginDialog.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "PluginDialog.h" - -#ifdef ENABLE_PLUGINS - -#include -#include // for string - -#include "control/settings/Settings.h" // for Settings -#include "gui/Builder.h" -#include "gui/dialog/PluginDialogEntry.h" // for PluginDialogEntry -#include "plugin/PluginController.h" // for PluginController - -class GladeSearchpath; -class Plugin; - -constexpr auto UI_FILE = "plugin.glade"; -constexpr auto UI_DIALOG_NAME = "pluginDialog"; - -PluginDialog::PluginDialog(GladeSearchpath* gladeSearchPath, Settings* settings, - const std::vector>& pluginList): - settings(settings) { - Builder builder(gladeSearchPath, UI_FILE); - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - - GtkBox* pluginBox = GTK_BOX(builder.get("pluginBox")); - std::transform(pluginList.begin(), pluginList.end(), std::back_inserter(this->plugins), - [&](auto& p) { return std::make_unique(p.get(), gladeSearchPath, pluginBox); }); - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); - g_signal_connect_swapped(builder.get("btOk"), "clicked", G_CALLBACK(+[](PluginDialog* self) { - self->saveSettings(); - gtk_window_close(self->window.get()); - }), - this); -} - -void PluginDialog::saveSettings() { - std::string pluginEnabled; - std::string pluginDisabled; - - // Save plugin settings - for (auto&& bcg: this->plugins) { bcg->saveSettings(pluginEnabled, pluginDisabled); } - - settings->setPluginEnabled(pluginEnabled); - settings->setPluginDisabled(pluginDisabled); -} - -#endif diff --git a/entry/src/main/cpp/src/core/gui/dialog/PluginDialog.h b/entry/src/main/cpp/src/core/gui/dialog/PluginDialog.h deleted file mode 100644 index fa02358..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/PluginDialog.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Xournal++ - * - * Plugin manage dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "config-features.h" - -#ifdef ENABLE_PLUGINS - -#include // for unique_ptr -#include // for vector - -#include "util/raii/GtkWindowUPtr.h" - -#include "PluginDialogEntry.h" // for PluginDialogEntry - -class Plugin; -class PluginController; -class Settings; -class GladeSearchpath; - -class PluginDialog { -public: - PluginDialog(GladeSearchpath* gladeSearchPath, Settings* settings, - const std::vector>& plugins); - -public: - inline GtkWindow* getWindow() const { return window.get(); } - -private: - void saveSettings(); - -private: - Settings* settings; - - std::vector> plugins; - xoj::util::GtkWindowUPtr window; -}; - -#endif diff --git a/entry/src/main/cpp/src/core/gui/dialog/PluginDialogEntry.cpp b/entry/src/main/cpp/src/core/gui/dialog/PluginDialogEntry.cpp deleted file mode 100644 index 4cdb35d..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/PluginDialogEntry.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "PluginDialogEntry.h" - -#ifdef ENABLE_PLUGINS - -#include "gui/Builder.h" -#include "plugin/Plugin.h" -#include "util/gtk4_helper.h" -#include "util/i18n.h" - -#include "filesystem.h" // for path - -class GladeSearchpath; - -constexpr auto UI_FILE = "pluginEntry.glade"; -constexpr auto UI_WIDGET_NAME = "pluginMainBox"; - -PluginDialogEntry::PluginDialogEntry(Plugin* plugin, GladeSearchpath* gladeSearchPath, GtkBox* box): plugin(plugin) { - Builder builder(gladeSearchPath, UI_FILE); - gtk_box_append(box, builder.get(UI_WIDGET_NAME)); - stateButton = GTK_CHECK_BUTTON(builder.get("cbEnabled")); - - gtk_label_set_text(GTK_LABEL(builder.get("pluginName")), plugin->getName().c_str()); - gtk_label_set_text(GTK_LABEL(builder.get("lbAuthor")), plugin->getAuthor().c_str()); - gtk_label_set_text(GTK_LABEL(builder.get("lbVersion")), plugin->getVersion().c_str()); - gtk_label_set_text(GTK_LABEL(builder.get("lbDescription")), plugin->getDescription().c_str()); - gtk_label_set_text(GTK_LABEL(builder.get("lbPath")), char_cast(plugin->getPath().u8string().c_str())); - gtk_label_set_text(GTK_LABEL(builder.get("lbDefaultText")), - plugin->isDefaultEnabled() ? _("default enabled") : _("default disabled")); - gtk_check_button_set_active(stateButton, plugin->isEnabled()); -} - -void PluginDialogEntry::saveSettings(std::string& pluginEnabled, std::string& pluginDisabled) { - bool state = gtk_check_button_get_active(stateButton); - - if (state == plugin->isDefaultEnabled()) { - return; - } - - if (state) { - if (!pluginEnabled.empty()) { - pluginEnabled += ","; - } - pluginEnabled.append(char_cast(plugin->getPath().u8string())); - } else { - if (!pluginDisabled.empty()) { - pluginDisabled += ","; - } - pluginDisabled.append(char_cast(plugin->getPath().u8string())); - } -} - -#endif diff --git a/entry/src/main/cpp/src/core/gui/dialog/PluginDialogEntry.h b/entry/src/main/cpp/src/core/gui/dialog/PluginDialogEntry.h deleted file mode 100644 index 3f163ce..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/PluginDialogEntry.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Xournal++ - * - * Configuration of a single plugin - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "config-features.h" - -#ifdef ENABLE_PLUGINS -#include // for string - -#include - -class Plugin; -class GladeSearchpath; - -class PluginDialogEntry { -public: - PluginDialogEntry(Plugin* plugin, GladeSearchpath* gladeSearchPath, GtkBox* box); - -public: - void saveSettings(std::string& pluginEnabled, std::string& pluginDisabled); - - -private: - /** - * Plugin instance - */ - Plugin* plugin; - - GtkCheckButton* stateButton; -}; -#endif diff --git a/entry/src/main/cpp/src/core/gui/dialog/RenameLayerDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/RenameLayerDialog.cpp deleted file mode 100644 index 7e6696d..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/RenameLayerDialog.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "RenameLayerDialog.h" - -#include // for allocator, make_unique -#include // for string - -#include // for G_CALLBACK, g_signal_connect - -#include "control/layer/LayerController.h" // for LayerController -#include "gui/Builder.h" -#include "undo/LayerRenameUndoAction.h" // for LayerRenameUndoAction -#include "undo/UndoRedoHandler.h" // for UndoRedoHandler -#include "util/gtk4_helper.h" - -class GladeSearchpath; -class Layer; - -constexpr auto UI_FILE = "renameLayerDialog.glade"; -constexpr auto UI_DIALOG_NAME = "renameLayerDialog"; - -RenameLayerDialog::RenameLayerDialog(GladeSearchpath* gladeSearchPath, UndoRedoHandler* undo, LayerController* lc, - Layer* l): - lc(lc), undo(undo), l(l) { - Builder builder(gladeSearchPath, UI_FILE); - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - layerNameEntry = GTK_ENTRY(builder.get("layerNameEntry")); - - gtk_editable_set_text(GTK_EDITABLE(layerNameEntry), lc->getCurrentLayerName().c_str()); - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); - g_signal_connect_swapped(builder.get("btOk"), "clicked", G_CALLBACK(+[](RenameLayerDialog* self) { - std::string newName = gtk_editable_get_text(GTK_EDITABLE(self->layerNameEntry)); - - self->undo->addUndoAction(std::make_unique( - self->lc, self->l, newName, self->lc->getCurrentLayerName())); - - self->lc->setCurrentLayerName(newName); - gtk_window_close(self->window.get()); - }), - this); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/RenameLayerDialog.h b/entry/src/main/cpp/src/core/gui/dialog/RenameLayerDialog.h deleted file mode 100644 index 843f5ed..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/RenameLayerDialog.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Xournal++ - * - * The rename layer dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include "util/raii/GtkWindowUPtr.h" - -class GladeSearchpath; -class Layer; -class LayerController; -class UndoRedoHandler; - -class RenameLayerDialog { -public: - RenameLayerDialog(GladeSearchpath* gladeSearchPath, UndoRedoHandler* undo, LayerController* lc, Layer* l); - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - LayerController* lc; - UndoRedoHandler* undo; - Layer* l; - - xoj::util::GtkWindowUPtr window; - GtkEntry* layerNameEntry; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/SelectBackgroundColorDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/SelectBackgroundColorDialog.cpp deleted file mode 100644 index c439989..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/SelectBackgroundColorDialog.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "SelectBackgroundColorDialog.h" - -#include // for uint32_t -#include // for allocator - -#include // for g_free, g_strdup_printf - -#include "control/Control.h" // for Control -#include "control/settings/Settings.h" // for SElement, Settings -#include "util/Color.h" -#include "util/i18n.h" // for _ -#include "util/safe_casts.h" // for as_unsigned - -static inline std::array background1 = { - Util::rgb_to_GdkRGBA(Colors::xopp_lightpink), // - Util::rgb_to_GdkRGBA(Colors::xopp_bisque), // - Util::rgb_to_GdkRGBA(Colors::xopp_lemonchifon), // - Util::rgb_to_GdkRGBA(Colors::xopp_palegoldenrod), // - Util::rgb_to_GdkRGBA(Colors::xopp_lavender), // - Util::rgb_to_GdkRGBA(Colors::xopp_gainsboro03), // - Util::rgb_to_GdkRGBA(Colors::xopp_antiquewhite), // - Util::rgb_to_GdkRGBA(Colors::xopp_gainsboro), // - Util::rgb_to_GdkRGBA(Colors::xopp_snow) // -}; - -static inline std::array backgroundXournal = { - Util::rgb_to_GdkRGBA(Colors::white), // - Util::rgb_to_GdkRGBA(Colors::xopp_paleturqoise), // - Util::rgb_to_GdkRGBA(Colors::xopp_aquamarine), // - Util::rgb_to_GdkRGBA(Colors::xopp_pink), // - Util::rgb_to_GdkRGBA(Colors::xopp_lightsalmon), // - Util::rgb_to_GdkRGBA(Colors::xopp_khaki) // -}; - -SelectBackgroundColorDialog::SelectBackgroundColorDialog(Control* control, std::function callback): - control(control), callback(callback) { - lastBackgroundColors.fill(Util::rgb_to_GdkRGBA(Colors::white)); - Settings* settings = control->getSettings(); - SElement& el = settings->getCustomElement("lastUsedPageBgColor"); - - int count = 0; - el.getInt("count", count); - - auto index = 0ULL; - - for (int i = 0; i < count && index < LAST_BACKGROUND_COLOR_COUNT; i++) { - int iColor{}; - char* settingName = g_strdup_printf("color%02i", i); - bool read = el.getInt(settingName, iColor); - g_free(settingName); - - if (!read) { - continue; - } - - lastBackgroundColors[index] = Util::rgb_to_GdkRGBA(Color(as_unsigned(iColor))); - - ++index; - } - - - window.reset(GTK_WINDOW(gtk_color_chooser_dialog_new(_("Select background color"), nullptr))); - GtkColorChooser* chooser = GTK_COLOR_CHOOSER(window.get()); - gtk_color_chooser_set_use_alpha(chooser, false); - - gtk_color_chooser_add_palette(chooser, GTK_ORIENTATION_HORIZONTAL, 9, background1.size(), background1.data()); - - gtk_color_chooser_add_palette(chooser, GTK_ORIENTATION_HORIZONTAL, 9, backgroundXournal.size(), - backgroundXournal.data()); - - // Last used colors (only by background, the general last used are shared with the - // pen and highlighter etc.) - gtk_color_chooser_add_palette(chooser, GTK_ORIENTATION_HORIZONTAL, 9, static_cast(lastBackgroundColors.size()), - lastBackgroundColors.data()); - - g_signal_connect(window.get(), "response", - G_CALLBACK(+[](GtkColorChooser*, int response, SelectBackgroundColorDialog* self) { - if (response == GTK_RESPONSE_DELETE_EVENT) { - // Ignore DELETE_EVENT, as this is caught by the PopupWindowWrapper - return; - } - if (response == GTK_RESPONSE_OK) { - GdkRGBA color; - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(self->window.get()), &color); - self->storeLastUsedValuesInSettings(color); - self->callback(Util::GdkRGBA_to_argb(color)); - } - gtk_window_close(self->window.get()); - }), - this); -} - -void SelectBackgroundColorDialog::storeLastUsedValuesInSettings(GdkRGBA color) { - for (auto& lastBackgroundColor: lastBackgroundColors) { - if (gdk_rgba_equal(&lastBackgroundColor, &color)) { - // The new color is already in the list, do not save - return; - } - } - - Settings* settings = control->getSettings(); - SElement& el = settings->getCustomElement("lastUsedPageBgColor"); - - // Move all colors one step back - for (size_t i = LAST_BACKGROUND_COLOR_COUNT - 1; i > 0; i--) { - lastBackgroundColors[i] = lastBackgroundColors[i - 1]; - } - - lastBackgroundColors[0] = color; - - el.setInt("count", LAST_BACKGROUND_COLOR_COUNT); - for (size_t i = 0; i < LAST_BACKGROUND_COLOR_COUNT; i++) { - char* settingName = g_strdup_printf("color%02zu", i); - el.setIntHex(settingName, int(uint32_t(Util::GdkRGBA_to_argb(lastBackgroundColors[i])))); - g_free(settingName); - } - - settings->customSettingsChanged(); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/SelectBackgroundColorDialog.h b/entry/src/main/cpp/src/core/gui/dialog/SelectBackgroundColorDialog.h deleted file mode 100644 index fbbf332..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/SelectBackgroundColorDialog.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Xournal++ - * - * Dialog for selecting a background color - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for array -#include - -#include // for GdkRGBA -#include // for GtkWindow - -#include "util/Color.h" -#include "util/raii/GtkWindowUPtr.h" - -class Control; - -/** - * Count of last background colors - */ -const int LAST_BACKGROUND_COLOR_COUNT = 9; - - -class SelectBackgroundColorDialog { -public: - SelectBackgroundColorDialog(Control* control, std::function callback); - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - void storeLastUsedValuesInSettings(GdkRGBA color); - -private: - Control* control{nullptr}; - - /** - * Last used background colors (stored in settings) - */ - std::array lastBackgroundColors{}; - - xoj::util::GtkWindowUPtr window; - std::function callback; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/SelectOpacityDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/SelectOpacityDialog.cpp deleted file mode 100644 index 8736381..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/SelectOpacityDialog.cpp +++ /dev/null @@ -1,121 +0,0 @@ -#include "SelectOpacityDialog.h" - -#include // for cairo_set_operator, cairo_rectangle, cairo_... -#include // for G_CALLBACK, g_signal_connect -#include // for gdouble - -#include "gui/Builder.h" -#include "util/Stacktrace.h" -#include "util/i18n.h" -#include "util/raii/CairoWrappers.h" -#include "util/raii/GObjectSPtr.h" -#include "util/safe_casts.h" // for round_cast - -class GladeSearchpath; - -constexpr auto UI_FILE = "selectOpacity.glade"; -constexpr auto UI_DIALOG_NAME = "selectOpacityDialog"; - -static int percentToByte(double percent) { return round_cast(percent * 2.55); } -static double byteToPercent(int byte) { return byte / 2.55; } - -static inline void buildLabel(Builder& builder, OpacityFeature opacityFeature) { - // Used to set the label of the dialog in the form of: - // {toolOptionsDesc}\n - // Select opacity for: {opacityFeatureDesc} - std::string toolOptionsDesc; - std::string selectOpacityFor = _("Select opacity for: "); - std::string opacityFeatureDesc; - - switch (opacityFeature) { - case OPACITY_FILL_HIGHLIGHTER: - toolOptionsDesc = _("Highlighter Options"); - opacityFeatureDesc = _("Fill color"); - break; - case OPACITY_FILL_PEN: - toolOptionsDesc = _("Pen Options"); - opacityFeatureDesc = _("Fill color"); - break; - case OPACITY_SELECT_PDF_TEXT_MARKER: - toolOptionsDesc = _("PDF Text Options"); - opacityFeatureDesc = _("PDF Text Marker"); - break; - default: - g_warning("No opacityFeature description set for '%s'", opacityFeatureToString(opacityFeature).data()); - Stacktrace::printStacktrace(); - break; - } - gtk_label_set_label(GTK_LABEL(builder.get("label1")), - FC(_F("{1}\n{2}{3}") % toolOptionsDesc % selectOpacityFor % opacityFeatureDesc)); -} - -xoj::popup::SelectOpacityDialog::SelectOpacityDialog(GladeSearchpath* gladeSearchPath, int alpha, - OpacityFeature feature, - std::function callback): - opacityFeature(feature), callback(callback) { - Builder builder(gladeSearchPath, UI_FILE); - this->window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - - buildLabel(builder, opacityFeature); - previewImage = GTK_IMAGE(builder.get("imgPreview")); - alphaRange = GTK_RANGE(builder.get("scaleAlpha")); - - gtk_range_set_value(alphaRange, byteToPercent(alpha)); - - setPreviewImage(alpha); - - - g_signal_connect(alphaRange, "value-changed", G_CALLBACK(+[](GtkRange* range, gpointer self) { - static_cast(self)->setPreviewImage( - percentToByte(round_cast(gtk_range_get_value(range)))); - }), - this); - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); - g_signal_connect(builder.get("btOk"), "clicked", G_CALLBACK(+[](GtkButton*, SelectOpacityDialog* self) { - self->callback(percentToByte(gtk_range_get_value(self->alphaRange)), self->opacityFeature); - gtk_window_close(self->window.get()); - }), - this); - -#if GTK_MAJOR_VERSION == 3 - // Widgets are visible by default in gtk4 - gtk_widget_show_all(builder.get("dialog-main-box")); -#endif -} - -xoj::popup::SelectOpacityDialog::~SelectOpacityDialog() = default; - -const int PREVIEW_WIDTH = 70; -const int PREVIEW_HEIGTH = 50; -const int PREVIEW_BORDER = 10; - -void xoj::popup::SelectOpacityDialog::setPreviewImage(int alpha) { - xoj::util::CairoSurfaceSPtr surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, PREVIEW_WIDTH, PREVIEW_HEIGTH), - xoj::util::adopt); - xoj::util::CairoSPtr cairo(cairo_create(surface.get()), xoj::util::adopt); - cairo_t* cr = cairo.get(); - - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgb(cr, 255, 255, 255); - cairo_paint(cr); - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_source_rgba(cr, 0, 0x80 / 255.0, 0, alpha / 255.0); - cairo_rectangle(cr, PREVIEW_BORDER, PREVIEW_BORDER, PREVIEW_WIDTH - PREVIEW_BORDER * 2, - PREVIEW_HEIGTH - PREVIEW_BORDER * 2); - cairo_fill(cr); - - if (opacityFeature == OPACITY_FILL_PEN) { - cairo_set_line_width(cr, 5); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgb(cr, 0, 0x80 / 255.0, 0); - cairo_rectangle(cr, PREVIEW_BORDER, PREVIEW_BORDER, PREVIEW_WIDTH - PREVIEW_BORDER * 2, - PREVIEW_HEIGTH - PREVIEW_BORDER * 2); - cairo_stroke(cr); - } - - xoj::util::GObjectSPtr pixbuf( - gdk_pixbuf_get_from_surface(surface.get(), 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGTH), xoj::util::adopt); - gtk_image_set_from_pixbuf(previewImage, pixbuf.get()); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/SelectOpacityDialog.h b/entry/src/main/cpp/src/core/gui/dialog/SelectOpacityDialog.h deleted file mode 100644 index 13080dc..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/SelectOpacityDialog.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Xournal++ - * - * The about dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include "control/ToolEnums.h" -#include "util/raii/GtkWindowUPtr.h" - -class GladeSearchpath; - -namespace xoj::popup { -class SelectOpacityDialog { -public: - SelectOpacityDialog(GladeSearchpath* gladeSearchPath, int alpha, OpacityFeature type, - std::function callback); - ~SelectOpacityDialog(); - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - void setPreviewImage(int alpha); - -private: - xoj::util::GtkWindowUPtr window; - GtkImage* previewImage; - GtkRange* alphaRange; - - OpacityFeature opacityFeature; - std::function callback; -}; -}; // namespace xoj::popup diff --git a/entry/src/main/cpp/src/core/gui/dialog/SettingsDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/SettingsDialog.cpp deleted file mode 100644 index 7279648..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/SettingsDialog.cpp +++ /dev/null @@ -1,1104 +0,0 @@ -#include "SettingsDialog.h" - -#include // for max -#include // for NULL, size_t -#include // for __underlying_type_im... - -#include // for GdkRGBA, GdkRectangle -#include // for G_CALLBACK, g_signal... - -#include "control/AudioController.h" // for AudioController -#include "control/Control.h" // for Control -#include "control/settings/Settings.h" // for Settings, SElement -#include "control/settings/SettingsEnums.h" // for STYLUS_CURSOR_ARROW -#include "control/tools/StrokeStabilizerEnum.h" // for AveragingMethod, Pre... -#include "gui/CreatePreviewImage.h" // for createPreviewImage -#include "gui/MainWindow.h" // for MainWindow -#include "gui/XournalView.h" // for XournalView -#include "gui/toolbarMenubar/ToolMenuHandler.h" // for ToolMenuHandler -#include "gui/toolbarMenubar/icon/ColorIcon.h" -#include "gui/toolbarMenubar/model/ColorPalette.h" // for Palette -#include "gui/widgets/ZoomCallib.h" // for zoomcallib_new, zoom... -#include "model/PageType.h" // for PageType -#include "util/Color.h" // for GdkRGBA_to_argb, rgb... -#include "util/GtkUtil.h" // for getWidgetDPI -#include "util/PathUtil.h" // for fromGFile, toGFilename -#include "util/Util.h" // for systemWithMessage -#include "util/gtk4_helper.h" // -#include "util/i18n.h" // for _ -#include "util/raii/CairoWrappers.h" // for CairoSurfaceSPtr -#include "util/safe_casts.h" // for round_cast -#include "util/utf8_view.h" // for utf8 - -#include "ButtonConfigGui.h" // for ButtonConfigGui -#include "DeviceTestingArea.h" // for DeviceTestingArea -#include "LanguageConfigGui.h" // for LanguageConfigGui -#include "LatexSettingsPanel.h" // for LatexSettingsPanel -#include "filesystem.h" // for is_directory - -class GladeSearchpath; - -using std::string; -using std::vector; - -constexpr auto UI_FILE = "settings.glade"; -constexpr auto UI_DIALOG_NAME = "settingsDialog"; - -SettingsDialog::SettingsDialog(GladeSearchpath* gladeSearchPath, Settings* settings, Control* control, - const std::vector& paletteDirectories, std::function callback): - settings(settings), - control(control), - callib(zoomcallib_new()), - builder(gladeSearchPath, UI_FILE), - window(GTK_WINDOW(builder.get(UI_DIALOG_NAME))), - languageConfig(GTK_BOX(builder.get("hboxLanguageSelect")), settings), - latexPanel(gladeSearchPath), - paletteTab(gladeSearchPath, paletteDirectories), - callback(callback) { - - gtk_box_append(GTK_BOX(builder.get("zoomVBox")), callib); - gtk_widget_show(callib); - - GtkWidget* preview = xoj::helper::createPreviewImage(PageType{PageTypeFormat::Lined}); - gtk_box_append(GTK_BOX(builder.get("pagePreviewImage")), preview); - gtk_widget_show(preview); - - initMouseButtonEvents(gladeSearchPath); - - GtkBox* container = GTK_BOX(builder.get("hboxInputDeviceClasses")); - deviceTestingArea = std::make_unique(gladeSearchPath, container, this->settings); - - gtk_box_append(GTK_BOX(builder.get("latexTabBox")), this->latexPanel.getPanel()); - gtk_box_append(GTK_BOX(builder.get("paletteTabBox")), this->paletteTab.getPanel()); - - g_signal_connect(GTK_RANGE(builder.get("zoomCallibSlider")), "value-changed", - G_CALLBACK(+[](GtkRange* range, gpointer self) { - static_cast(self)->setDpi(round_cast(gtk_range_get_value(range))); - }), - this); - - g_signal_connect_swapped(builder.get("cbEnablePressureInference"), "toggled", - G_CALLBACK(+[](SettingsDialog* self) { self->updatePressureSensitivityOptions(); }), this); - - g_signal_connect_swapped(builder.get("cbSettingPresureSensitivity"), "toggled", - G_CALLBACK(+[](SettingsDialog* self) { self->updatePressureSensitivityOptions(); }), this); - - g_signal_connect_swapped( - builder.get("cbAutosave"), "toggled", - G_CALLBACK(+[](SettingsDialog* self) { self->enableWithCheckbox("cbAutosave", "boxAutosave"); }), this); - - g_signal_connect_swapped(builder.get("cbIgnoreFirstStylusEvents"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->enableWithCheckbox("cbIgnoreFirstStylusEvents", "spNumIgnoredStylusEvents"); - }), - this); - - - g_signal_connect_swapped(builder.get("btTestEnable"), "clicked", G_CALLBACK(+[](SettingsDialog* self) { - Util::systemWithMessage(gtk_editable_get_text( - GTK_EDITABLE(self->builder.get("txtEnableTouchCommand")))); - }), - this); - - g_signal_connect_swapped(builder.get("btTestDisable"), "clicked", G_CALLBACK(+[](SettingsDialog* self) { - Util::systemWithMessage(gtk_editable_get_text( - GTK_EDITABLE(self->builder.get("txtDisableTouchCommand")))); - }), - this); - - g_signal_connect_swapped(builder.get("cbAddVerticalSpace"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->enableWithCheckbox("cbAddVerticalSpace", "spAddVerticalSpaceAbove"); - self->enableWithCheckbox("cbAddVerticalSpace", "spAddVerticalSpaceBelow"); - }), - this); - - g_signal_connect_swapped(builder.get("cbAddHorizontalSpace"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->enableWithCheckbox("cbAddHorizontalSpace", "spAddHorizontalSpaceLeft"); - self->enableWithCheckbox("cbAddHorizontalSpace", "spAddHorizontalSpaceRight"); - }), - this); - - g_signal_connect_swapped(builder.get("cbUnlimitedScrolling"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->disableWithCheckbox("cbUnlimitedScrolling", "cbAddHorizontalSpace"); - self->disableWithCheckbox("cbUnlimitedScrolling", "cbAddVerticalSpace"); - self->enableWithEnabledCheckbox("cbAddHorizontalSpace", "spAddHorizontalSpaceLeft"); - self->enableWithEnabledCheckbox("cbAddVerticalSpace", "spAddVerticalSpaceAbove"); - self->enableWithEnabledCheckbox("cbAddHorizontalSpace", "spAddHorizontalSpaceRight"); - self->enableWithEnabledCheckbox("cbAddVerticalSpace", "spAddVerticalSpaceBelow"); - }), - this); - - g_signal_connect_swapped(builder.get("cbDrawDirModsEnabled"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->enableWithCheckbox("cbDrawDirModsEnabled", "spDrawDirModsRadius"); - }), - this); - - g_signal_connect_swapped(builder.get("cbStrokeFilterEnabled"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->enableWithCheckbox("cbStrokeFilterEnabled", "spStrokeIgnoreTime"); - self->enableWithCheckbox("cbStrokeFilterEnabled", "spStrokeIgnoreLength"); - self->enableWithCheckbox("cbStrokeFilterEnabled", "spStrokeSuccessiveTime"); - self->enableWithCheckbox("cbStrokeFilterEnabled", "cbDoActionOnStrokeFiltered"); - self->enableWithCheckbox("cbStrokeFilterEnabled", "cbTrySelectOnStrokeFiltered"); - }), - this); - - g_signal_connect_swapped(builder.get("cbDisableAudio"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->disableWithCheckbox("cbDisableAudio", "sidAudio1"); - self->disableWithCheckbox("cbDisableAudio", "sidAudio2"); - self->disableWithCheckbox("cbDisableAudio", "sidAudio3"); - self->disableWithCheckbox("cbDisableAudio", "sidAudio4"); - self->disableWithCheckbox("cbDisableAudio", "sidAudioLbl"); - }), - this); - - g_signal_connect_swapped(builder.get("cbDisableTouchOnPenNear"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->enableWithCheckbox("cbDisableTouchOnPenNear", "boxInternalHandRecognition"); - }), - this); - - g_signal_connect_swapped(builder.get("cbTouchDisableMethod"), "changed", - G_CALLBACK(+[](SettingsDialog* self) { self->customHandRecognitionToggled(); }), this); - - g_signal_connect_swapped(builder.get("cbEnableZoomGestures"), "toggled", G_CALLBACK(+[](SettingsDialog* self) { - self->enableWithCheckbox("cbEnableZoomGestures", "gdStartZoomAtSetting"); - }), - this); - - g_signal_connect_swapped(builder.get("cbStylusCursorType"), "changed", - G_CALLBACK(+[](SettingsDialog* self) { self->customStylusIconTypeChanged(); }), this); - - g_signal_connect(GTK_COMBO_BOX(builder.get("cbStabilizerAveragingMethods")), "changed", - G_CALLBACK(+[](GtkComboBox* comboBox, gpointer self) { - static_cast(self)->showStabilizerAvMethodOptions( - static_cast(gtk_combo_box_get_active(comboBox))); - }), - this); - - g_signal_connect(GTK_COMBO_BOX(builder.get("cbStabilizerPreprocessors")), "changed", - G_CALLBACK(+[](GtkComboBox* comboBox, gpointer self) { - static_cast(self)->showStabilizerPreprocessorOptions( - static_cast(gtk_combo_box_get_active(comboBox))); - }), - this); - - g_signal_connect_swapped(builder.get("btOk"), "clicked", G_CALLBACK(+[](SettingsDialog* self) { - self->save(); - self->callback(); - gtk_window_close(self->window.get()); - }), - this); - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), window.get()); - - g_signal_connect(builder.get("cbUseSpacesAsTab"), "toggled", - G_CALLBACK(+[](GtkCheckButton* checkBox, SettingsDialog* self) { - self->enableWithCheckbox("cbUseSpacesAsTab", "numberOfSpacesContainer"); - }), - this); - - load(); -} - -SettingsDialog::~SettingsDialog() = default; - -void SettingsDialog::initMouseButtonEvents(GladeSearchpath* gladeSearchPath) { - auto emplaceButton = [gladeSearchPath, &btns = buttonConfigs, settings = settings, &bld = builder]( - const char* hbox, Button button, bool withDevice = false) { - btns.emplace_back(std::make_unique(gladeSearchPath, GTK_BOX(bld.get(hbox)), settings, button, - withDevice)); - }; - - emplaceButton("hboxLeftMouse", BUTTON_MOUSE_LEFT); - emplaceButton("hboxMiddleMouse", BUTTON_MOUSE_MIDDLE); - emplaceButton("hboxRightMouse", BUTTON_MOUSE_RIGHT); - emplaceButton("hboxEraser", BUTTON_ERASER); - emplaceButton("hboxTouch", BUTTON_TOUCH, true); - emplaceButton("hboxPenButton1", BUTTON_STYLUS_ONE); - emplaceButton("hboxPenButton2", BUTTON_STYLUS_TWO); - emplaceButton("hboxDefaultTool", BUTTON_DEFAULT); -} - -void SettingsDialog::setDpi(int dpi) { - if (this->dpi == dpi) { - return; - } - - this->dpi = dpi; - zoomcallib_set_val(ZOOM_CALLIB(callib), dpi); -} - -void SettingsDialog::loadCheckbox(const char* name, bool value) { - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get(name)), value); -} - -auto SettingsDialog::getCheckbox(const char* name) -> bool { - return gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get(name))); -} - -void SettingsDialog::loadSlider(const char* name, double value) { - GtkRange* range = GTK_RANGE(builder.get(name)); - gtk_range_set_value(range, value); -} - -auto SettingsDialog::getSlider(const char* name) -> double { - GtkRange* range = GTK_RANGE(builder.get(name)); - return gtk_range_get_value(range); -} - -/** - * Checkbox was toggled, enable / disable it - */ -void SettingsDialog::enableWithCheckbox(const string& checkboxId, const string& widgetId) { - bool enabled = gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get(checkboxId))); - gtk_widget_set_sensitive(builder.get(widgetId), enabled); -} - -void SettingsDialog::disableWithCheckbox(const string& checkboxId, const string& widgetId) { - bool enabled = gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get(checkboxId))); - gtk_widget_set_sensitive(builder.get(widgetId), !enabled); -} - -/** - * similar to enableWithCheckbox, but also disables widget if the checkbox is disabled - */ -void SettingsDialog::enableWithEnabledCheckbox(const string& checkboxId, const string& widgetId) { - GtkWidget* checkboxWidget = builder.get(checkboxId); - bool const enabled = - gtk_widget_get_sensitive(checkboxWidget) && gtk_check_button_get_active(GTK_CHECK_BUTTON(checkboxWidget)); - gtk_widget_set_sensitive(builder.get(widgetId), enabled); -} - -void SettingsDialog::updatePressureSensitivityOptions() { - GtkWidget* sensitivityOptionsFrame = builder.get("framePressureSensitivityScale"); - bool havePressureInput = getCheckbox("cbSettingPresureSensitivity") || getCheckbox("cbEnablePressureInference"); - - if (!havePressureInput) { - gtk_widget_set_tooltip_text(sensitivityOptionsFrame, - _("Enable pressure sensitivity or pressure inference to change this setting!")); - } else { - - gtk_widget_set_tooltip_text(sensitivityOptionsFrame, - _("Filter input pressure. Multiply the pressure by the pressure multiplier." - " If less than the minimum, use the minimum pressure.")); - } - gtk_widget_set_sensitive(sensitivityOptionsFrame, havePressureInput); -} - -void SettingsDialog::customHandRecognitionToggled() { - GtkWidget* cbTouchDisableMethod = builder.get("cbTouchDisableMethod"); - int touchMethod = gtk_combo_box_get_active(GTK_COMBO_BOX(cbTouchDisableMethod)); - gtk_widget_set_sensitive(builder.get("boxCustomTouchDisableSettings"), touchMethod == 2); -} - -void SettingsDialog::customStylusIconTypeChanged() { - GtkWidget* cbStylusCursorType = builder.get("cbStylusCursorType"); - int stylusCursorType = gtk_combo_box_get_active(GTK_COMBO_BOX(cbStylusCursorType)); - bool showCursorHighlightOptions = - (stylusCursorType != STYLUS_CURSOR_NONE && stylusCursorType != STYLUS_CURSOR_ARROW); - gtk_widget_set_sensitive(builder.get("highlightCursorGrid"), showCursorHighlightOptions); -} - -void SettingsDialog::showStabilizerAvMethodOptions(StrokeStabilizer::AveragingMethod method) { - bool showArithmetic = method == StrokeStabilizer::AveragingMethod::ARITHMETIC; - gtk_widget_set_visible(builder.get("lbStabilizerBuffersize"), showArithmetic); - gtk_widget_set_visible(builder.get("sbStabilizerBuffersize"), showArithmetic); - - bool showSigma = method == StrokeStabilizer::AveragingMethod::VELOCITY_GAUSSIAN; - gtk_widget_set_visible(builder.get("lbStabilizerSigma"), showSigma); - gtk_widget_set_visible(builder.get("sbStabilizerSigma"), showSigma); - - bool preprocessorOn = static_cast(gtk_combo_box_get_active(GTK_COMBO_BOX( - builder.get("cbStabilizerPreprocessors")))) != StrokeStabilizer::Preprocessor::NONE; - bool sensitive = showSigma || showArithmetic || preprocessorOn; - gtk_widget_set_sensitive(builder.get("cbStabilizerEnableFinalizeStroke"), sensitive); -} - -void SettingsDialog::showStabilizerPreprocessorOptions(StrokeStabilizer::Preprocessor preprocessor) { - bool showDeadzone = preprocessor == StrokeStabilizer::Preprocessor::DEADZONE; - gtk_widget_set_visible(builder.get("lbStabilizerDeadzoneRadius"), showDeadzone); - gtk_widget_set_visible(builder.get("sbStabilizerDeadzoneRadius"), showDeadzone); - gtk_widget_set_visible(builder.get("cbStabilizerEnableCuspDetection"), showDeadzone); - - bool showInertia = preprocessor == StrokeStabilizer::Preprocessor::INERTIA; - gtk_widget_set_visible(builder.get("lbStabilizerDrag"), showInertia); - gtk_widget_set_visible(builder.get("sbStabilizerDrag"), showInertia); - gtk_widget_set_visible(builder.get("lbStabilizerMass"), showInertia); - gtk_widget_set_visible(builder.get("sbStabilizerMass"), showInertia); - - bool averagingOn = static_cast( - gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbStabilizerAveragingMethods")))) != - StrokeStabilizer::AveragingMethod::NONE; - bool sensitive = showDeadzone || showInertia || averagingOn; - gtk_widget_set_sensitive(builder.get("cbStabilizerEnableFinalizeStroke"), sensitive); -} - -void SettingsDialog::load() { - loadCheckbox("cbSettingPresureSensitivity", settings->isPressureSensitivity()); - loadCheckbox("cbEnableZoomGestures", settings->isZoomGesturesEnabled()); - loadCheckbox("cbShowSidebarRight", settings->isSidebarOnRight()); - loadCheckbox("cbShowScrollbarLeft", settings->isScrollbarOnLeft()); - loadCheckbox("cbAutoloadMostRecent", settings->isAutoloadMostRecent()); - loadCheckbox("cbAutoloadXoj", settings->isAutoloadPdfXoj()); - loadCheckbox("cbAutosave", settings->isAutosaveEnabled()); - loadCheckbox("cbAddVerticalSpace", settings->getAddVerticalSpace()); - loadCheckbox("cbAddHorizontalSpace", settings->getAddHorizontalSpace()); - loadCheckbox("cbUnlimitedScrolling", settings->getUnlimitedScrolling()); - loadCheckbox("cbDrawDirModsEnabled", settings->getDrawDirModsEnabled()); - loadCheckbox("cbStrokeFilterEnabled", settings->getStrokeFilterEnabled()); - loadCheckbox("cbDoActionOnStrokeFiltered", settings->getDoActionOnStrokeFiltered()); - loadCheckbox("cbTrySelectOnStrokeFiltered", settings->getTrySelectOnStrokeFiltered()); - loadCheckbox("cbSnapRecognizedShapesEnabled", settings->getSnapRecognizedShapesEnabled()); - loadCheckbox("cbRestoreLineWidthEnabled", settings->getRestoreLineWidthEnabled()); - loadCheckbox("cbStockIcons", settings->areStockIconsUsed()); - loadCheckbox("cbHideHorizontalScrollbar", settings->getScrollbarHideType() & SCROLLBAR_HIDE_HORIZONTAL); - loadCheckbox("cbHideVerticalScrollbar", settings->getScrollbarHideType() & SCROLLBAR_HIDE_VERTICAL); - loadCheckbox("cbDisableScrollbarFadeout", settings->isScrollbarFadeoutDisabled()); - loadCheckbox("cbDisableAudio", settings->isAudioDisabled()); - loadCheckbox("cbEnablePressureInference", settings->isPressureGuessingEnabled()); - loadCheckbox("cbTouchDrawing", settings->getTouchDrawingEnabled()); - loadCheckbox("cbDisableGtkInertialScroll", !settings->getGtkTouchInertialScrollingEnabled()); - const bool ignoreStylusEventsEnabled = settings->getIgnoredStylusEvents() != 0; // 0 means disabled, >0 enabled - loadCheckbox("cbIgnoreFirstStylusEvents", ignoreStylusEventsEnabled); - loadCheckbox("cbInputSystemDrawOutsideWindow", settings->getInputSystemDrawOutsideWindowEnabled()); - - /** - * Tab size related settings - */ - loadCheckbox("cbUseSpacesAsTab", settings->getUseSpacesAsTab()); - GtkSpinButton* sbNumberOfSpacesForTab = GTK_SPIN_BUTTON(builder.get("sbNumberOfSpacesForTab")); - gtk_spin_button_set_value(sbNumberOfSpacesForTab, settings->getNumberOfSpacesForTab()); - gtk_widget_set_sensitive(GTK_WIDGET(builder.get("numberOfSpacesContainer")), settings->getUseSpacesAsTab()); - - // Laser pointer - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("sbLaserFadeOutTime")), - settings->getLaserPointerFadeOutTime()); - - /** - * Stabilizer related settings - */ - loadCheckbox("cbStabilizerEnableCuspDetection", settings->getStabilizerCuspDetection()); - loadCheckbox("cbStabilizerEnableFinalizeStroke", settings->getStabilizerFinalizeStroke()); - - GtkWidget* sbStabilizerBuffersize = builder.get("sbStabilizerBuffersize"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(sbStabilizerBuffersize), - static_cast(settings->getStabilizerBuffersize())); - GtkWidget* sbStabilizerDeadzoneRadius = builder.get("sbStabilizerDeadzoneRadius"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(sbStabilizerDeadzoneRadius), settings->getStabilizerDeadzoneRadius()); - GtkWidget* sbStabilizerDrag = builder.get("sbStabilizerDrag"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(sbStabilizerDrag), settings->getStabilizerDrag()); - GtkWidget* sbStabilizerMass = builder.get("sbStabilizerMass"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(sbStabilizerMass), settings->getStabilizerMass()); - GtkWidget* sbStabilizerSigma = builder.get("sbStabilizerSigma"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(sbStabilizerSigma), settings->getStabilizerSigma()); - - GtkComboBox* cbStabilizerAveragingMethods = GTK_COMBO_BOX(builder.get("cbStabilizerAveragingMethods")); - gtk_combo_box_set_active(cbStabilizerAveragingMethods, static_cast(settings->getStabilizerAveragingMethod())); - showStabilizerAvMethodOptions(settings->getStabilizerAveragingMethod()); - GtkComboBox* cbStabilizerPreprocessors = GTK_COMBO_BOX(builder.get("cbStabilizerPreprocessors")); - gtk_combo_box_set_active(cbStabilizerPreprocessors, static_cast(settings->getStabilizerPreprocessor())); - showStabilizerPreprocessorOptions(settings->getStabilizerPreprocessor()); - /***********/ - - GtkComboBox* cbSidebarNumberingStyle = GTK_COMBO_BOX(builder.get("cbSidebarPageNumberStyle")); - gtk_combo_box_set_active(cbSidebarNumberingStyle, static_cast(settings->getSidebarNumberingStyle())); - - GtkWidget* txtDefaultSaveName = builder.get("txtDefaultSaveName"); - gtk_editable_set_text(GTK_EDITABLE(txtDefaultSaveName), char_cast(settings->getDefaultSaveName().c_str())); - - GtkWidget* txtDefaultPdfName = builder.get("txtDefaultPdfName"); - gtk_editable_set_text(GTK_EDITABLE(txtDefaultPdfName), char_cast(settings->getDefaultPdfExportName().c_str())); - - GtkWidget* spAutosaveTimeout = builder.get("spAutosaveTimeout"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spAutosaveTimeout), settings->getAutosaveTimeout()); - - GtkWidget* spNumIgnoredStylusEvents = builder.get("spNumIgnoredStylusEvents"); - if (!ignoreStylusEventsEnabled) { // The spinButton's value should be >= 1 - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spNumIgnoredStylusEvents), 1); - } else { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spNumIgnoredStylusEvents), settings->getIgnoredStylusEvents()); - } - - GtkWidget* spPairsOffset = builder.get("spPairsOffset"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spPairsOffset), settings->getPairsOffset()); - - EmptyLastPageAppendType append = settings->getEmptyLastPageAppend(); - loadCheckbox("rdLastPageAppendOnDrawOfLastPage", append == EmptyLastPageAppendType::OnDrawOfLastPage); - loadCheckbox("rdLastPageAppendOnScrollToEndOfLastPage", append == EmptyLastPageAppendType::OnScrollToEndOfLastPage); - loadCheckbox("rdLastPageAppendDisabled", append == EmptyLastPageAppendType::Disabled); - - GtkWidget* spSnapRotationTolerance = builder.get("spSnapRotationTolerance"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spSnapRotationTolerance), settings->getSnapRotationTolerance()); - - GtkWidget* spSnapGridTolerance = builder.get("spSnapGridTolerance"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spSnapGridTolerance), settings->getSnapGridTolerance()); - - GtkWidget* spSnapGridSize = builder.get("spSnapGridSize"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spSnapGridSize), settings->getSnapGridSize() / DEFAULT_GRID_SIZE); - - GtkWidget* spStrokeRecognizerMinSize = builder.get("spStrokeRecognizerMinSize"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spStrokeRecognizerMinSize), settings->getStrokeRecognizerMinSize()); - - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("edgePanSpeed")), settings->getEdgePanSpeed()); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("edgePanMaxMult")), settings->getEdgePanMaxMult()); - - GtkWidget* spZoomStep = builder.get("spZoomStep"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spZoomStep), settings->getZoomStep()); - - GtkWidget* spZoomStepScroll = builder.get("spZoomStepScroll"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spZoomStepScroll), settings->getZoomStepScroll()); - - GtkWidget* spAddHorizontalSpaceRight = builder.get("spAddHorizontalSpaceRight"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spAddHorizontalSpaceRight), settings->getAddHorizontalSpaceAmountRight()); - - GtkWidget* spAddVerticalSpaceAbove = builder.get("spAddVerticalSpaceAbove"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spAddVerticalSpaceAbove), settings->getAddVerticalSpaceAmountAbove()); - - GtkWidget* spAddHorizontalSpaceLeft = builder.get("spAddHorizontalSpaceLeft"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spAddHorizontalSpaceLeft), settings->getAddHorizontalSpaceAmountLeft()); - - GtkWidget* spAddVerticalSpaceBelow = builder.get("spAddVerticalSpaceBelow"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spAddVerticalSpaceBelow), settings->getAddVerticalSpaceAmountBelow()); - - GtkWidget* spDrawDirModsRadius = builder.get("spDrawDirModsRadius"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spDrawDirModsRadius), settings->getDrawDirModsRadius()); - - GtkWidget* spReRenderThreshold = builder.get("spReRenderThreshold"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spReRenderThreshold), settings->getPDFPageRerenderThreshold()); - - GtkWidget* spTouchZoomStartThreshold = builder.get("spTouchZoomStartThreshold"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spTouchZoomStartThreshold), settings->getTouchZoomStartThreshold()); - - { - int time = 0; - double length = 0; - int successive = 0; - settings->getStrokeFilter(&time, &length, &successive); - - GtkWidget* spStrokeIgnoreTime = builder.get("spStrokeIgnoreTime"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spStrokeIgnoreTime), time); - GtkWidget* spStrokeIgnoreLength = builder.get("spStrokeIgnoreLength"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spStrokeIgnoreLength), length); - GtkWidget* spStrokeSuccessiveTime = builder.get("spStrokeSuccessiveTime"); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(spStrokeSuccessiveTime), successive); - } - - - auto* zoomCallibAutomaticCb = GTK_CHECK_BUTTON(builder.get("zoomCallibAutomaticCb")); - auto* zoomCallibSlider = GTK_RANGE(builder.get("zoomCallibSlider")); - - g_signal_connect_object( - zoomCallibAutomaticCb, "notify::active", G_CALLBACK(+[](GObject* btn, GParamSpec*, gpointer slider) { - bool active = gtk_check_button_get_active(GTK_CHECK_BUTTON(btn)); - gtk_widget_set_sensitive(GTK_WIDGET(slider), !active); - if (active) { - auto dpi = xoj::util::gtk::getWidgetDPI(GTK_WIDGET(slider)); - gtk_range_set_value(GTK_RANGE(slider), dpi.value_or(Util::DPI_NORMALIZATION_FACTOR)); - } - }), - zoomCallibSlider, GConnectFlags(0)); - - if (auto dpi = settings->getDisplayDpi(); dpi == -1) { - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get("zoomCallibAutomaticCb")), true); - g_signal_connect(zoomCallibSlider, "realize", G_CALLBACK(+[](GtkWidget* slider, gpointer) { - auto dpi = xoj::util::gtk::getWidgetDPI(slider); - gtk_range_set_value(GTK_RANGE(slider), dpi.value_or(Util::DPI_NORMALIZATION_FACTOR)); - }), - nullptr); - this->setDpi(72); - } else { - gtk_check_button_set_active(GTK_CHECK_BUTTON(builder.get("zoomCallibAutomaticCb")), false); - this->setDpi(dpi); - } - gtk_range_set_value(zoomCallibSlider, this->dpi); - - - loadSlider("scaleMinimumPressure", settings->getMinimumPressure()); - loadSlider("scalePressureMultiplier", settings->getPressureMultiplier()); - - GdkRGBA color = Util::rgb_to_GdkRGBA(settings->getBorderColor()); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(builder.get("colorBorder")), &color); - color = Util::rgb_to_GdkRGBA(settings->getBackgroundColor()); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(builder.get("colorBackground")), &color); - color = Util::rgb_to_GdkRGBA(settings->getSelectionColor()); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(builder.get("colorSelection")), &color); - color = Util::rgb_to_GdkRGBA(settings->getActiveSelectionColor()); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(builder.get("colorSelectionActive")), &color); - - { - const auto& recolor = settings->getRecolorParameters(); - loadCheckbox("cbRecolorDrawingArea", recolor.recolorizeMainView); - loadCheckbox("cbRecolorPreviewSidebar", recolor.recolorizeSidebarMiniatures); - color = Util::argb_to_GdkRGBA(recolor.recolor.getLight()); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(builder.get("recolorLight")), &color); - color = Util::argb_to_GdkRGBA(recolor.recolor.getDark()); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(builder.get("recolorDark")), &color); - } - - loadCheckbox("cbHighlightPosition", settings->isHighlightPosition()); - color = Util::argb_to_GdkRGBA(settings->getCursorHighlightColor()); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(builder.get("cursorHighlightColor")), &color); - color = Util::argb_to_GdkRGBA(settings->getCursorHighlightBorderColor()); - gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(builder.get("cursorHighlightBorderColor")), &color); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("cursorHighlightRadius")), - settings->getCursorHighlightRadius()); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("cursorHighlightBorderWidth")), - settings->getCursorHighlightBorderWidth()); - - switch (settings->getStylusCursorType()) { - case STYLUS_CURSOR_NONE: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbStylusCursorType")), 0); - break; - case STYLUS_CURSOR_BIG: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbStylusCursorType")), 2); - break; - case STYLUS_CURSOR_ARROW: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbStylusCursorType")), 3); - break; - case STYLUS_CURSOR_DOT: - default: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbStylusCursorType")), 1); - break; - } - - switch (settings->getEraserVisibility()) { - case ERASER_VISIBILITY_NEVER: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbEraserVisibility")), 0); - break; - case ERASER_VISIBILITY_HOVER: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbEraserVisibility")), 2); - break; - case ERASER_VISIBILITY_TOUCH: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbEraserVisibility")), 3); - break; - case ERASER_VISIBILITY_ALWAYS: - default: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbEraserVisibility")), 1); - break; - } - - switch (settings->getIconTheme()) { - case ICON_THEME_LUCIDE: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbIconTheme")), 1); - break; - case ICON_THEME_COLOR: - default: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbIconTheme")), 0); - break; - } - - switch (settings->getThemeVariant()) { - case THEME_VARIANT_FORCE_LIGHT: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbThemeVariant")), 1); - break; - case THEME_VARIANT_FORCE_DARK: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbThemeVariant")), 2); - break; - case THEME_VARIANT_USE_SYSTEM: - default: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbThemeVariant")), 0); - break; - } - - auto viewMode = settings->getViewModes().at(PresetViewModeIds::VIEW_MODE_FULLSCREEN); - bool showFullscreenMenubar = viewMode.showMenubar; - bool showFullscreenToolbar = viewMode.showToolbar; - bool showFullscreenSidebar = viewMode.showSidebar; - viewMode = settings->getViewModes().at(PresetViewModeIds::VIEW_MODE_PRESENTATION); - bool showPresentationMenubar = viewMode.showMenubar; - bool showPresentationToolbar = viewMode.showToolbar; - bool showPresentationSidebar = viewMode.showSidebar; - bool goPresentationFullscreen = viewMode.goFullscreen; - - loadCheckbox("cbShowFullscreenMenubar", showFullscreenMenubar); - loadCheckbox("cbShowFullscreenToolbar", showFullscreenToolbar); - loadCheckbox("cbShowFullscreenSidebar", showFullscreenSidebar); - loadCheckbox("cbShowPresentationMenubar", showPresentationMenubar); - loadCheckbox("cbShowPresentationToolbar", showPresentationToolbar); - loadCheckbox("cbShowPresentationSidebar", showPresentationSidebar); - loadCheckbox("cbPresentationGoFullscreen", goPresentationFullscreen); - loadCheckbox("cbHideMenubarStartup", settings->isMenubarVisible()); - loadCheckbox("cbShowFilepathInTitlebar", settings->isFilepathInTitlebarShown()); - loadCheckbox("cbShowPageNumberInTitlebar", settings->isPageNumberInTitlebarShown()); - - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("preloadPagesBefore")), - static_cast(settings->getPreloadPagesBefore())); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("preloadPagesAfter")), - static_cast(settings->getPreloadPagesAfter())); - loadCheckbox("cbEagerPageCleanup", settings->isEagerPageCleanup()); - - disableWithCheckbox("cbUnlimitedScrolling", "cbAddVerticalSpace"); - disableWithCheckbox("cbUnlimitedScrolling", "cbAddHorizontalSpace"); - - enableWithCheckbox("cbAutosave", "boxAutosave"); - enableWithCheckbox("cbIgnoreFirstStylusEvents", "spNumIgnoredStylusEvents"); - enableWithEnabledCheckbox("cbAddVerticalSpace", "spAddVerticalSpaceAbove"); - enableWithEnabledCheckbox("cbAddHorizontalSpace", "spAddHorizontalSpaceRight"); - enableWithEnabledCheckbox("cbAddVerticalSpace", "spAddVerticalSpaceBelow"); - enableWithEnabledCheckbox("cbAddHorizontalSpace", "spAddHorizontalSpaceLeft"); - enableWithCheckbox("cbDrawDirModsEnabled", "spDrawDirModsRadius"); - enableWithCheckbox("cbStrokeFilterEnabled", "spStrokeIgnoreTime"); - enableWithCheckbox("cbStrokeFilterEnabled", "spStrokeIgnoreLength"); - enableWithCheckbox("cbStrokeFilterEnabled", "spStrokeSuccessiveTime"); - enableWithCheckbox("cbStrokeFilterEnabled", "cbDoActionOnStrokeFiltered"); - enableWithCheckbox("cbStrokeFilterEnabled", "cbTrySelectOnStrokeFiltered"); - enableWithCheckbox("cbEnableZoomGestures", "gdStartZoomAtSetting"); - enableWithCheckbox("cbDisableTouchOnPenNear", "boxInternalHandRecognition"); - customHandRecognitionToggled(); - customStylusIconTypeChanged(); - updatePressureSensitivityOptions(); - - - SElement& touch = settings->getCustomElement("touch"); - bool disablePen = false; - touch.getBool("disableTouch", disablePen); - loadCheckbox("cbDisableTouchOnPenNear", disablePen); - - string disableMethod; - touch.getString("method", disableMethod); - int methodId = 0; - if (disableMethod == "X11") { - methodId = 1; - } else if (disableMethod == "custom") { - methodId = 2; - } - - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbTouchDisableMethod")), methodId); - - string cmd; - touch.getString("cmdEnable", cmd); - gtk_editable_set_text(GTK_EDITABLE(builder.get("txtEnableTouchCommand")), cmd.c_str()); - - cmd = ""; - touch.getString("cmdDisable", cmd); - gtk_editable_set_text(GTK_EDITABLE(builder.get("txtDisableTouchCommand")), cmd.c_str()); - - int timeoutMs = 1000; - touch.getInt("timeout", timeoutMs); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("spTouchDisableTimeout")), timeoutMs / 1000.0); - -#ifdef ENABLE_AUDIO - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(builder.get("fcAudioPath")), - Util::toGFilename(settings->getAudioFolder()).c_str()); - if (this->control->getAudioController()) { - this->audioInputDevices = this->control->getAudioController()->getInputDevices(); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(builder.get("cbAudioInputDevice")), "", "System default"); - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbAudioInputDevice")), 0); - for (auto& audioInputDevice: this->audioInputDevices) { - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(builder.get("cbAudioInputDevice")), "", - audioInputDevice.getDeviceName().c_str()); - } - for (size_t i = 0; i < this->audioInputDevices.size(); i++) { - if (this->audioInputDevices[i].getSelected()) { - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbAudioInputDevice")), static_cast(i + 1)); - } - } - - this->audioOutputDevices = this->control->getAudioController()->getOutputDevices(); - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(builder.get("cbAudioOutputDevice")), "", "System default"); - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbAudioOutputDevice")), 0); - for (auto& audioOutputDevice: this->audioOutputDevices) { - gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(builder.get("cbAudioOutputDevice")), "", - audioOutputDevice.getDeviceName().c_str()); - } - for (size_t i = 0; i < this->audioOutputDevices.size(); i++) { - if (this->audioOutputDevices[i].getSelected()) { - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbAudioOutputDevice")), static_cast(i + 1)); - } - } - - switch (static_cast(settings->getAudioSampleRate())) { - case 16000: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbAudioSampleRate")), 0); - break; - case 96000: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbAudioSampleRate")), 2); - break; - case 192000: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbAudioSampleRate")), 3); - break; - case 44100: - default: - gtk_combo_box_set_active(GTK_COMBO_BOX(builder.get("cbAudioSampleRate")), 1); - break; - } - - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("spAudioGain")), settings->getAudioGain()); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(builder.get("spDefaultSeekTime")), settings->getDefaultSeekTime()); - } -#else - gtk_widget_destroy(builder.get("audioRecordingTabBox")); -#endif - - this->latexPanel.load(settings->latexSettings); - paletteTab.renderPaletteTab(this->control->getPalette().getFilePath()); -} - -void SettingsDialog::save() { - settings->transactionStart(); - - settings->setPressureSensitivity(getCheckbox("cbSettingPresureSensitivity")); - settings->setMinimumPressure(getSlider("scaleMinimumPressure")); - settings->setPressureMultiplier(getSlider("scalePressureMultiplier")); - settings->setZoomGesturesEnabled(getCheckbox("cbEnableZoomGestures")); - settings->setSidebarOnRight(getCheckbox("cbShowSidebarRight")); - settings->setScrollbarOnLeft(getCheckbox("cbShowScrollbarLeft")); - settings->setAutoloadMostRecent(getCheckbox("cbAutoloadMostRecent")); - settings->setAutoloadPdfXoj(getCheckbox("cbAutoloadXoj")); - settings->setAutosaveEnabled(getCheckbox("cbAutosave")); - settings->setAddVerticalSpace(getCheckbox("cbAddVerticalSpace")); - settings->setAddHorizontalSpace(getCheckbox("cbAddHorizontalSpace")); - settings->setUnlimitedScrolling(getCheckbox("cbUnlimitedScrolling")); - settings->setDrawDirModsEnabled(getCheckbox("cbDrawDirModsEnabled")); - settings->setStrokeFilterEnabled(getCheckbox("cbStrokeFilterEnabled")); - settings->setDoActionOnStrokeFiltered(getCheckbox("cbDoActionOnStrokeFiltered")); - settings->setTrySelectOnStrokeFiltered(getCheckbox("cbTrySelectOnStrokeFiltered")); - settings->setSnapRecognizedShapesEnabled(getCheckbox("cbSnapRecognizedShapesEnabled")); - settings->setRestoreLineWidthEnabled(getCheckbox("cbRestoreLineWidthEnabled")); - settings->setAreStockIconsUsed(getCheckbox("cbStockIcons")); - settings->setPressureGuessingEnabled(getCheckbox("cbEnablePressureInference")); - settings->setTouchDrawingEnabled(getCheckbox("cbTouchDrawing")); - settings->setGtkTouchInertialScrollingEnabled(!getCheckbox("cbDisableGtkInertialScroll")); - settings->setInputSystemDrawOutsideWindowEnabled(getCheckbox("cbInputSystemDrawOutsideWindow")); - settings->setScrollbarFadeoutDisabled(getCheckbox("cbDisableScrollbarFadeout")); - settings->setAudioDisabled(getCheckbox("cbDisableAudio")); - - /** - * Tab size relate settings - */ - settings->setUseSpacesAsTab(getCheckbox("cbUseSpacesAsTab")); - settings->setNumberOfSpacesForTab(static_cast( - gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(builder.get("sbNumberOfSpacesForTab"))))); - - settings->setLaserPointerFadeOutTime(static_cast( - gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(builder.get("sbLaserFadeOutTime"))))); - - /** - * Stabilizer related settings - */ - settings->setStabilizerAveragingMethod(static_cast( - gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbStabilizerAveragingMethods"))))); - settings->setStabilizerPreprocessor(static_cast( - gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbStabilizerPreprocessors"))))); - settings->setStabilizerBuffersize(static_cast( - gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(builder.get("sbStabilizerBuffersize"))))); - settings->setStabilizerDeadzoneRadius( - gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("sbStabilizerDeadzoneRadius")))); - settings->setStabilizerDrag(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("sbStabilizerDrag")))); - settings->setStabilizerMass(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("sbStabilizerMass")))); - settings->setStabilizerSigma(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("sbStabilizerSigma")))); - settings->setStabilizerCuspDetection(getCheckbox("cbStabilizerEnableCuspDetection")); - settings->setStabilizerFinalizeStroke(getCheckbox("cbStabilizerEnableFinalizeStroke")); - - settings->setSidebarNumberingStyle(static_cast( - gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbSidebarPageNumberStyle"))))); - - auto scrollbarHideType = - static_cast::type>::type>(SCROLLBAR_HIDE_NONE); - if (getCheckbox("cbHideHorizontalScrollbar")) { - scrollbarHideType |= SCROLLBAR_HIDE_HORIZONTAL; - } - if (getCheckbox("cbHideVerticalScrollbar")) { - scrollbarHideType |= SCROLLBAR_HIDE_VERTICAL; - } - settings->setScrollbarHideType(static_cast(scrollbarHideType)); - - GdkRGBA color; - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(builder.get("colorBorder")), &color); - settings->setBorderColor(Util::GdkRGBA_to_argb(color)); - - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(builder.get("colorBackground")), &color); - settings->setBackgroundColor(Util::GdkRGBA_to_argb(color)); - - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(builder.get("colorSelection")), &color); - settings->setSelectionColor(Util::GdkRGBA_to_argb(color)); - - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(builder.get("colorSelectionActive")), &color); - settings->setActiveSelectionColor(Util::GdkRGBA_to_argb(color)); - - { - GdkRGBA color2; - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(builder.get("recolorLight")), &color); - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(builder.get("recolorDark")), &color2); - - settings->setRecolorParameters({getCheckbox("cbRecolorDrawingArea"), getCheckbox("cbRecolorPreviewSidebar"), - Recolor(Util::GdkRGBA_to_argb(color), Util::GdkRGBA_to_argb(color2))}); - } - - settings->setHighlightPosition(getCheckbox("cbHighlightPosition")); - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(builder.get("cursorHighlightColor")), &color); - settings->setCursorHighlightColor(Util::GdkRGBA_to_argb(color)); - gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(builder.get("cursorHighlightBorderColor")), &color); - settings->setCursorHighlightBorderColor(Util::GdkRGBA_to_argb(color)); - GtkWidget* spCursorHighlightRadius = builder.get("cursorHighlightRadius"); - settings->setCursorHighlightRadius(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spCursorHighlightRadius))); - GtkWidget* spCursorHighlightBorderWidth = builder.get("cursorHighlightBorderWidth"); - settings->setCursorHighlightBorderWidth(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spCursorHighlightBorderWidth))); - - switch (gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbStylusCursorType")))) { - case 0: - settings->setStylusCursorType(STYLUS_CURSOR_NONE); - break; - case 2: - settings->setStylusCursorType(STYLUS_CURSOR_BIG); - break; - case 3: - settings->setStylusCursorType(STYLUS_CURSOR_ARROW); - break; - case 1: - default: - settings->setStylusCursorType(STYLUS_CURSOR_DOT); - break; - } - - switch (gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbEraserVisibility")))) { - case 0: - settings->setEraserVisibility(ERASER_VISIBILITY_NEVER); - break; - case 2: - settings->setEraserVisibility(ERASER_VISIBILITY_HOVER); - break; - case 3: - settings->setEraserVisibility(ERASER_VISIBILITY_TOUCH); - break; - case 1: - default: - settings->setEraserVisibility(ERASER_VISIBILITY_ALWAYS); - break; - } - - switch (gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbIconTheme")))) { - case 1: - settings->setIconTheme(ICON_THEME_LUCIDE); - break; - case 0: - default: - settings->setIconTheme(ICON_THEME_COLOR); - break; - } - - switch (gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbThemeVariant")))) { - case 1: - settings->setThemeVariant(THEME_VARIANT_FORCE_LIGHT); - break; - case 2: - settings->setThemeVariant(THEME_VARIANT_FORCE_DARK); - break; - case 0: - default: - settings->setThemeVariant(THEME_VARIANT_USE_SYSTEM); - break; - } - - ViewMode viewModeFullscreen; - viewModeFullscreen.goFullscreen = true; - viewModeFullscreen.showMenubar = getCheckbox("cbShowFullscreenMenubar"); - viewModeFullscreen.showToolbar = getCheckbox("cbShowFullscreenToolbar"); - viewModeFullscreen.showSidebar = getCheckbox("cbShowFullscreenSidebar"); - settings->setViewMode(PresetViewModeIds::VIEW_MODE_FULLSCREEN, viewModeFullscreen); - - ViewMode viewModePresentation; - viewModePresentation.showMenubar = getCheckbox("cbShowPresentationMenubar"); - viewModePresentation.showToolbar = getCheckbox("cbShowPresentationToolbar"); - viewModePresentation.showSidebar = getCheckbox("cbShowPresentationSidebar"); - viewModePresentation.goFullscreen = getCheckbox("cbPresentationGoFullscreen"); - settings->setViewMode(PresetViewModeIds::VIEW_MODE_PRESENTATION, viewModePresentation); - - settings->setMenubarVisible(getCheckbox("cbHideMenubarStartup")); - settings->setFilepathInTitlebarShown(getCheckbox("cbShowFilepathInTitlebar")); - settings->setPageNumberInTitlebarShown(getCheckbox("cbShowPageNumberInTitlebar")); - - constexpr auto spinAsUint = [&](GtkSpinButton* btn) { - int v = gtk_spin_button_get_value_as_int(btn); - return v < 0 ? 0U : static_cast(v); - }; - unsigned int preloadPagesBefore = spinAsUint(GTK_SPIN_BUTTON(builder.get("preloadPagesBefore"))); - unsigned int preloadPagesAfter = spinAsUint(GTK_SPIN_BUTTON(builder.get("preloadPagesAfter"))); - settings->setPreloadPagesAfter(preloadPagesAfter); - settings->setPreloadPagesBefore(preloadPagesBefore); - settings->setEagerPageCleanup(getCheckbox("cbEagerPageCleanup")); - - settings->setDefaultSaveName( - xoj::util::utf8(gtk_editable_get_text(GTK_EDITABLE(builder.get("txtDefaultSaveName")))).str()); - settings->setDefaultPdfExportName( - xoj::util::utf8(gtk_editable_get_text(GTK_EDITABLE(builder.get("txtDefaultPdfName")))).str()); - - GtkWidget* spAutosaveTimeout = builder.get("spAutosaveTimeout"); - int autosaveTimeout = static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spAutosaveTimeout))); - settings->setAutosaveTimeout(autosaveTimeout); - - if (getCheckbox("cbIgnoreFirstStylusEvents")) { - GtkWidget* spNumIgnoredStylusEvents = builder.get("spNumIgnoredStylusEvents"); - int numIgnoredStylusEvents = - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spNumIgnoredStylusEvents))); - settings->setIgnoredStylusEvents(numIgnoredStylusEvents); - } else { - settings->setIgnoredStylusEvents(0); // This means nothing will be ignored - } - - GtkWidget* spPairsOffset = builder.get("spPairsOffset"); - int numPairsOffset = static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spPairsOffset))); - settings->setPairsOffset(numPairsOffset); - - if (getCheckbox("rdLastPageAppendDisabled")) { - settings->setEmptyLastPageAppend(EmptyLastPageAppendType::Disabled); - } else if (getCheckbox("rdLastPageAppendOnDrawOfLastPage")) { - settings->setEmptyLastPageAppend(EmptyLastPageAppendType::OnDrawOfLastPage); - } else if (getCheckbox("rdLastPageAppendOnScrollToEndOfLastPage")) { - settings->setEmptyLastPageAppend(EmptyLastPageAppendType::OnScrollToEndOfLastPage); - } else { - settings->setEmptyLastPageAppend(EmptyLastPageAppendType::Disabled); - } - - settings->setEdgePanSpeed(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("edgePanSpeed")))); - settings->setEdgePanMaxMult(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("edgePanMaxMult")))); - - GtkWidget* spZoomStep = builder.get("spZoomStep"); - double zoomStep = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spZoomStep)); - settings->setZoomStep(zoomStep); - - GtkWidget* spZoomStepScroll = builder.get("spZoomStepScroll"); - double zoomStepScroll = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spZoomStepScroll)); - settings->setZoomStepScroll(zoomStepScroll); - - - GtkWidget* spAddHorizontalSpaceRight = builder.get("spAddHorizontalSpaceRight"); - const int addHorizontalSpaceAmountRight = - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spAddHorizontalSpaceRight))); - settings->setAddHorizontalSpaceAmountRight(addHorizontalSpaceAmountRight); - - GtkWidget* spAddVerticalSpaceAbove = builder.get("spAddVerticalSpaceAbove"); - const int addVerticalSpaceAmountAbove = - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spAddVerticalSpaceAbove))); - settings->setAddVerticalSpaceAmountAbove(addVerticalSpaceAmountAbove); - - GtkWidget* spAddHorizontalSpaceLeft = builder.get("spAddHorizontalSpaceLeft"); - const int addHorizontalSpaceAmountLeft = - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spAddHorizontalSpaceLeft))); - settings->setAddHorizontalSpaceAmountLeft(addHorizontalSpaceAmountLeft); - - GtkWidget* spAddVerticalSpaceBelow = builder.get("spAddVerticalSpaceBelow"); - const int addVerticalSpaceAmountBelow = - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spAddVerticalSpaceBelow))); - settings->setAddVerticalSpaceAmountBelow(addVerticalSpaceAmountBelow); - - - GtkWidget* spDrawDirModsRadius = builder.get("spDrawDirModsRadius"); - int drawDirModsRadius = static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spDrawDirModsRadius))); - settings->setDrawDirModsRadius(drawDirModsRadius); - - GtkWidget* spStrokeIgnoreTime = builder.get("spStrokeIgnoreTime"); - int strokeIgnoreTime = static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spStrokeIgnoreTime))); - GtkWidget* spStrokeIgnoreLength = builder.get("spStrokeIgnoreLength"); - double strokeIgnoreLength = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spStrokeIgnoreLength)); - GtkWidget* spStrokeSuccessiveTime = builder.get("spStrokeSuccessiveTime"); - int strokeSuccessiveTime = static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(spStrokeSuccessiveTime))); - settings->setStrokeFilter(strokeIgnoreTime, strokeIgnoreLength, strokeSuccessiveTime); - - GtkWidget* spTouchZoomStartThreshold = builder.get("spTouchZoomStartThreshold"); - double zoomStartThreshold = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spTouchZoomStartThreshold)); - settings->setTouchZoomStartThreshold(zoomStartThreshold); - - GtkWidget* spReRenderThreshold = builder.get("spReRenderThreshold"); - double rerenderThreshold = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spReRenderThreshold)); - settings->setPDFPageRerenderThreshold(rerenderThreshold); - - settings->setDisplayDpi(gtk_check_button_get_active(GTK_CHECK_BUTTON(builder.get("zoomCallibAutomaticCb"))) ? -1 : - dpi); - - for (auto&& bcg: this->buttonConfigs) { - bcg->saveSettings(); - } - - languageConfig.saveSettings(); - - SElement& touch = settings->getCustomElement("touch"); - touch.setBool("disableTouch", getCheckbox("cbDisableTouchOnPenNear")); - int touchMethod = gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbTouchDisableMethod"))); - - switch (touchMethod) { - case 1: - touch.setString("method", "X11"); - break; - case 2: - touch.setString("method", "custom"); - break; - case 0: - default: - touch.setString("method", "auto"); - } - touch.setString("cmdEnable", gtk_editable_get_text(GTK_EDITABLE(builder.get("txtEnableTouchCommand")))); - touch.setString("cmdDisable", gtk_editable_get_text(GTK_EDITABLE(builder.get("txtDisableTouchCommand")))); - - touch.setInt( - "timeout", - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("spTouchDisableTimeout"))) * 1000)); - - settings->setSnapRotationTolerance( - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("spSnapRotationTolerance"))))); - settings->setSnapGridTolerance( - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("spSnapGridTolerance"))))); - settings->setSnapGridSize(static_cast( - gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("spSnapGridSize"))) * DEFAULT_GRID_SIZE)); - - settings->setStrokeRecognizerMinSize( - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("spStrokeRecognizerMinSize"))))); - -#ifdef ENABLE_AUDIO - auto file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(builder.get("fcAudioPath"))); - auto path = Util::fromGFile(file); - g_object_unref(file); - if (fs::is_directory(path)) { - settings->setAudioFolder(path); - } - - size_t selectedInputDeviceIndex = - static_cast(gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbAudioInputDevice")))); - if (selectedInputDeviceIndex == 0) { - settings->setAudioInputDevice(Settings::AUDIO_INPUT_SYSTEM_DEFAULT); - } else if (selectedInputDeviceIndex - 1 < this->audioInputDevices.size()) { - settings->setAudioInputDevice(this->audioInputDevices[selectedInputDeviceIndex - 1].getIndex()); - } - - size_t selectedOutputDeviceIndex = - static_cast(gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbAudioOutputDevice")))); - if (selectedOutputDeviceIndex == 0) { - settings->setAudioOutputDevice(Settings::AUDIO_OUTPUT_SYSTEM_DEFAULT); - } else if (selectedOutputDeviceIndex - 1 < this->audioOutputDevices.size()) { - settings->setAudioOutputDevice(this->audioOutputDevices[selectedOutputDeviceIndex - 1].getIndex()); - } - - switch (gtk_combo_box_get_active(GTK_COMBO_BOX(builder.get("cbAudioSampleRate")))) { - case 0: - settings->setAudioSampleRate(16000.0); - break; - case 2: - settings->setAudioSampleRate(96000.0); - break; - case 3: - settings->setAudioSampleRate(192000.0); - break; - case 1: - default: - settings->setAudioSampleRate(44100.0); - break; - } - - settings->setAudioGain(static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("spAudioGain"))))); - settings->setDefaultSeekTime( - static_cast(gtk_spin_button_get_value(GTK_SPIN_BUTTON(builder.get("spDefaultSeekTime"))))); -#endif - - const std::optional selectedPalette = paletteTab.getSelectedPalette(); - if (selectedPalette.has_value()) { - settings->setColorPaletteSetting(selectedPalette.value()); - } - - this->deviceTestingArea->saveSettings(); - - this->latexPanel.save(settings->latexSettings); - - settings->transactionEnd(); - - this->control->getWindow()->setGtkTouchscreenScrollingForDeviceMapping(); - - this->control->initButtonTool(); - this->control->getWindow()->getXournal()->onSettingsChanged(); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/SettingsDialog.h b/entry/src/main/cpp/src/core/gui/dialog/SettingsDialog.h deleted file mode 100644 index 9b36489..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/SettingsDialog.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Xournal++ - * - * Settings Dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include // for string -#include // for vector - -#include // for GtkWidget, GtkWindow - -#include "audio/DeviceInfo.h" // for DeviceInfo -#include "control/tools/StrokeStabilizerEnum.h" // for AveragingMethod, Pre... -#include "gui/Builder.h" -#include "util/raii/GtkWindowUPtr.h" - -#include "ButtonConfigGui.h" -#include "LanguageConfigGui.h" -#include "LatexSettingsPanel.h" -#include "SettingsDialogPaletteTab.h" -#include "config-features.h" // for ENABLE_AUDIO -#include "filesystem.h" // for path - -class Control; -class Settings; -class DeviceTestingArea; - -struct Palette; - -class SettingsDialog { -public: - SettingsDialog(GladeSearchpath* gladeSearchPath, Settings* settings, Control* control, - const std::vector& paletteDirectories, std::function callback); - ~SettingsDialog(); - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - void save(); - void setDpi(int dpi); - - /** - * Set active regions - */ - void enableWithCheckbox(const std::string& checkbox, const std::string& widget); - void disableWithCheckbox(const std::string& checkbox, const std::string& widget); - void enableWithEnabledCheckbox(const std::string& checkbox, const std::string& widget); - - /* - * Listeners for changes to settings. - */ - void customHandRecognitionToggled(); - void customStylusIconTypeChanged(); - - /** - * Update whether options can be selected, tooltips, etc. for - * pressure sensitivity options (e.g. pressure multiplier). - */ - void updatePressureSensitivityOptions(); - -private: - void load(); - void loadCheckbox(const char* name, bool value); - bool getCheckbox(const char* name); - - void loadSlider(const char* name, double value); - double getSlider(const char* name); - - void initMouseButtonEvents(GladeSearchpath* gladeSearchPath); - - void showStabilizerAvMethodOptions(StrokeStabilizer::AveragingMethod method); - void showStabilizerPreprocessorOptions(StrokeStabilizer::Preprocessor preprocessor); - -private: - Settings* settings = nullptr; - Control* control = nullptr; - GtkWidget* callib = nullptr; - int dpi = 72; - -#ifdef ENABLE_AUDIO - std::vector audioInputDevices; - std::vector audioOutputDevices; -#endif - - Builder builder; - xoj::util::GtkWindowUPtr window; - - std::unique_ptr deviceTestingArea; - - LanguageConfigGui languageConfig; - std::vector> buttonConfigs; - - LatexSettingsPanel latexPanel; - SettingsDialogPaletteTab paletteTab; - - std::function callback; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/SettingsDialogPaletteTab.cpp b/entry/src/main/cpp/src/core/gui/dialog/SettingsDialogPaletteTab.cpp deleted file mode 100644 index 19adb52..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/SettingsDialogPaletteTab.cpp +++ /dev/null @@ -1,213 +0,0 @@ -#include "SettingsDialogPaletteTab.h" - -#include "gui/toolbarMenubar/icon/ColorIcon.h" -#include "util/PathUtil.h" -#include "util/XojMsgBox.h" -#include "util/gtk4_helper.h" -#include "util/i18n.h" - -static const char* const G_OBJECT_PALETTE_PATH = "xournalpp.palettePath"; - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// HELPER -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -auto colorize(const std::string& text, const std::string& color) -> std::string { - return std::string{""} + text + std::string{""}; -} - -void setGObjectPalettePath(GObject* gObject, const fs::path& path) { - g_object_set_data(gObject, G_OBJECT_PALETTE_PATH, (gpointer)&path); -} - -auto getGObjectPalettePath(GObject* gObject) -> fs::path { - auto* pathPointer = (fs::path*)g_object_get_data(gObject, G_OBJECT_PALETTE_PATH); - return *pathPointer; -} - -auto getDisplayPalettePath(const fs::path& path) -> std::string { - if (path.parent_path() == Util::getBuiltInPaletteDirectoryPath()) { - return std::string{"└─ "} + "" + FS(_F("Built-in palettes")) + "/ " + - char_cast(path.filename().u8string().c_str()); - } else if (path.parent_path() == Util::getCustomPaletteDirectoryPath()) { - return std::string{"└─ "} + "" + FS(_F("User palettes")) + "/ " + - char_cast(path.filename().u8string().c_str()); - } else { - g_warning("Unexpected type of palette path encountered %s", char_cast(path.parent_path().u8string().c_str())); - return std::string{"└─ "} + char_cast(path.u8string().c_str()); - } -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Public Methods -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -constexpr auto UI_FILE = "paletteSettings.glade"; -constexpr auto UI_PANEL_NAME = "paletteSettingsPanel"; - -SettingsDialogPaletteTab::SettingsDialogPaletteTab(GladeSearchpath* gladeSearchPath, - const std::vector& paletteDirectories): - builder(gladeSearchPath, UI_FILE) { - colorPaletteExplainLabel = GTK_LABEL(builder.get("colorPaletteExplainLabel")); - paletteListBox = GTK_LIST_BOX(builder.get("paletteListBox")); - panel = GTK_SCROLLED_WINDOW(builder.get(UI_PANEL_NAME)); - renderColorPaletteExplainLabel(); - setAllPaletteFilePaths(paletteDirectories); -} - -void SettingsDialogPaletteTab::renderPaletteTab(const fs::path& currentlySetPalettePath) { - GtkListBox* lb = paletteListBox; - if (allPaletteFilePaths.empty()) { - renderNoPaletteFoundDisclaimer(lb); - return; - } - - for (const fs::path& p: allPaletteFilePaths) { - GtkWidget* listBoxRow = renderPaletteListBoxRow(lb, p); - - if (p == currentlySetPalettePath) { - gtk_list_box_select_row(GTK_LIST_BOX(lb), GTK_LIST_BOX_ROW(listBoxRow)); - } - } - gtk_widget_show_all(GTK_WIDGET(lb)); -} - - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Private Methods -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -auto SettingsDialogPaletteTab::renderPaletteListBoxRow(GtkListBox* lb, const fs::path& p) -> GtkWidget* { - Palette palette{p}; - GtkWidget* listBoxRow = nullptr; - - try { - palette.load(); - listBoxRow = newPaletteListBoxRow(palette); - } catch (const std::exception& e) { - listBoxRow = newErrorListBoxRow(p, e.what()); - } - setGObjectPalettePath(G_OBJECT(listBoxRow), p); - - gtk_list_box_prepend(lb, listBoxRow); - return listBoxRow; -} - -void SettingsDialogPaletteTab::renderColorPaletteExplainLabel() const { - gtk_label_set_label(colorPaletteExplainLabel, FS(_F("The palettes shown below are obtained from the " - "Built-in palettes and " - "User palettes directories:\n") % - Util::toUri(Util::getBuiltInPaletteDirectoryPath()).value() % - Util::toUri(Util::getCustomPaletteDirectoryPath()).value()) - .c_str()); - gtk_label_set_wrap(colorPaletteExplainLabel, true); - gtk_label_set_use_markup(colorPaletteExplainLabel, true); - g_signal_connect(colorPaletteExplainLabel, "activate-link", G_CALLBACK(+[](GtkLabel*, gchar* uri, gpointer) { - XojMsgBox::openURL(nullptr, uri); - return true; // default handler does not work on Windows - }), - nullptr); -} - -void SettingsDialogPaletteTab::renderNoPaletteFoundDisclaimer(GtkListBox* lb) { - GtkWidget* listBoxRow = gtk_list_box_row_new(); - GtkWidget* label = gtk_label_new(("" + - FS(_F("No palette files (i.e. with extension .gpl) could be found.\n" - "Using the default until another palette is configured.")) + - "") - .c_str()); - gtk_label_set_use_markup(GTK_LABEL(label), true); - - gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(listBoxRow), label); - gtk_list_box_row_set_activatable(GTK_LIST_BOX_ROW(listBoxRow), FALSE); - gtk_list_box_row_set_selectable(GTK_LIST_BOX_ROW(listBoxRow), FALSE); - - gtk_list_box_prepend(lb, listBoxRow); -} - -// use list of fs::path as input -void SettingsDialogPaletteTab::setAllPaletteFilePaths(const std::vector& paletteDirectories) { - for (const fs::path& paletteDirectory: paletteDirectories) { - std::vector const files = Util::listFilesSorted(paletteDirectory); - for (const fs::path& paletteFile: files) { - if (paletteFile.extension() == ".gpl") { - allPaletteFilePaths.push_back(paletteFile); - } - } - } -} - -auto SettingsDialogPaletteTab::getSelectedPalette() const -> std::optional { - GtkListBoxRow* selected_listbox_row = gtk_list_box_get_selected_row(paletteListBox); - if (allPaletteFilePaths.empty()) { - return std::nullopt; - } - if (!G_IS_OBJECT(selected_listbox_row)) { - return std::nullopt; - } - - return getGObjectPalettePath(G_OBJECT(selected_listbox_row)); -} - -auto SettingsDialogPaletteTab::newErrorListBoxRow(const fs::path& palettePath, const std::string& error) -> GtkWidget* { - GtkWidget* listBoxRow = gtk_list_box_row_new(); - GtkWidget* rowContent = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3); - gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(listBoxRow), rowContent); - - std::string const formattedError = colorize(FS(_F("Error")) + ": " + error, "red"); - GtkWidget* text = newPaletteTextBox(formattedError, palettePath); - gtk_box_append(GTK_BOX(rowContent), text); - - return listBoxRow; -} - -auto SettingsDialogPaletteTab::newPaletteListBoxRow(Palette& palette) -> GtkWidget* { - GtkWidget* listBoxRow = gtk_list_box_row_new(); - GtkWidget* rowContent = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3); - gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(listBoxRow), rowContent); - - std::string const paletteName = palette.getHeader(std::string{FS(_F("Name"))}); - GtkWidget* text = nullptr; - if (paletteName.empty()) { - text = newPaletteTextBox(std::string{"" + FS(_F("Palette has no Name")) + ""}, palette.getFilePath()); - } else { - text = newPaletteTextBox(paletteName, palette.getFilePath().u8string()); - } - gtk_box_append(GTK_BOX(rowContent), text); - - GtkWidget* colorIcons = newPaletteColorIconsBox(palette); - gtk_widget_set_hexpand(colorIcons, true); - gtk_box_append(GTK_BOX(rowContent), colorIcons); - - return listBoxRow; -} - -auto SettingsDialogPaletteTab::newPaletteTextBox(const std::string& mainContent, const fs::path& path) -> GtkWidget* { - GtkWidget* textBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3); - - GtkWidget* mainLabel = gtk_label_new(mainContent.c_str()); - gtk_widget_set_halign(mainLabel, GTK_ALIGN_START); - gtk_label_set_use_markup(GTK_LABEL(mainLabel), true); - gtk_box_append(GTK_BOX(textBox), mainLabel); - - GtkWidget* secondaryLabel = gtk_label_new(getDisplayPalettePath(path).c_str()); - gtk_widget_set_halign(secondaryLabel, GTK_ALIGN_START); - gtk_label_set_use_markup(GTK_LABEL(secondaryLabel), true); - gtk_box_append(GTK_BOX(textBox), secondaryLabel); - - return textBox; -} - -auto SettingsDialogPaletteTab::newPaletteColorIconsBox(const Palette& palette) -> GtkWidget* { - GtkWidget* colors = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3); - for (unsigned long i = 0; i < palette.size(); i++) { - const NamedColor& namedColor = palette.getColorAt(i); - const Color c = namedColor.getColor(); - GtkWidget* icon = ColorIcon::newGtkImage(c, 16, true); - gtk_box_append(GTK_BOX(colors), icon); - } - gtk_widget_set_halign(colors, GTK_ALIGN_END); - return colors; -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/SettingsDialogPaletteTab.h b/entry/src/main/cpp/src/core/gui/dialog/SettingsDialogPaletteTab.h deleted file mode 100644 index 30178c3..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/SettingsDialogPaletteTab.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - - -#include -#include -#include - -#include - -#include "gui/Builder.h" -#include "gui/GladeGui.h" -#include "gui/toolbarMenubar/model/ColorPalette.h" -class SettingsDialogPaletteTab { -public: - SettingsDialogPaletteTab(GladeSearchpath* gladeSearchPath, const std::vector& paletteDirectories); - void renderPaletteTab(const fs::path& currentlySetPalettePath); - auto getSelectedPalette() const -> std::optional; - inline GtkWidget* getPanel() const { return GTK_WIDGET(panel); } - -private: - std::vector allPaletteFilePaths; - GtkLabel* colorPaletteExplainLabel; - GtkListBox* paletteListBox; - Builder builder; - GtkScrolledWindow* panel; - - void setAllPaletteFilePaths(const std::vector& paletteDirectories); - void renderColorPaletteExplainLabel() const; - - static auto newErrorListBoxRow(const fs::path& palettePath, const std::string& error) -> GtkWidget*; - static auto newPaletteTextBox(const std::string& mainContent, const fs::path& path) -> GtkWidget*; - static auto newPaletteColorIconsBox(const Palette& palette) -> GtkWidget*; - static auto newPaletteListBoxRow(Palette& palette) -> GtkWidget*; - static void renderNoPaletteFoundDisclaimer(GtkListBox* lb); - static auto renderPaletteListBoxRow(GtkListBox* lb, const fs::path& p) -> GtkWidget*; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/ToolbarManageDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/ToolbarManageDialog.cpp deleted file mode 100644 index 148bb85..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/ToolbarManageDialog.cpp +++ /dev/null @@ -1,187 +0,0 @@ -#include "ToolbarManageDialog.h" - -#include // for allocator, string -#include // for vector - -#include // for g_signal_connect -#include // for PANGO_WEIGHT_NORMAL - -#include "gui/Builder.h" -#include "gui/toolbarMenubar/model/ToolbarData.h" // for ToolbarData -#include "gui/toolbarMenubar/model/ToolbarModel.h" // for ToolbarModel -#include "util/Assert.h" // for xoj_assert -#include "util/i18n.h" // for _ - -class GladeSearchpath; - -constexpr auto UI_FILE = "toolbarManageDialog.glade"; -constexpr auto UI_DIALOG_NAME = "manageToolbarsDialog"; - -enum { COLUMN_STRING, COLUMN_BOLD, COLUMN_POINTER, COLUMN_EDITABLE, N_COLUMNS }; - -static xoj::util::GObjectSPtr createModel(ToolbarModel* tb) { - xoj_assert(tb); - GtkTreeIter iter; - GtkListStore* model = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING, G_TYPE_INT, G_TYPE_POINTER, G_TYPE_BOOLEAN); - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, COLUMN_STRING, _("Predefined"), COLUMN_BOLD, PANGO_WEIGHT_BOLD, COLUMN_POINTER, - nullptr, COLUMN_EDITABLE, false, -1); - - for (const auto& data: tb->getToolbars()) { - if (data->isPredefined()) { - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, COLUMN_STRING, data->getName().c_str(), COLUMN_BOLD, PANGO_WEIGHT_NORMAL, - COLUMN_POINTER, data.get(), COLUMN_EDITABLE, false, -1); - } - } - - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, COLUMN_STRING, _("Customized"), COLUMN_BOLD, PANGO_WEIGHT_BOLD, COLUMN_POINTER, - nullptr, COLUMN_EDITABLE, false, -1); - - for (const auto& data: tb->getToolbars()) { - if (!data->isPredefined()) { - gtk_list_store_append(model, &iter); - gtk_list_store_set(model, &iter, COLUMN_STRING, data->getName().c_str(), COLUMN_BOLD, PANGO_WEIGHT_NORMAL, - COLUMN_POINTER, data.get(), COLUMN_EDITABLE, true, -1); - } - } - return xoj::util::GObjectSPtr(model, xoj::util::adopt); -} - -ToolbarManageDialog::ToolbarManageDialog(GladeSearchpath* gladeSearchPath, ToolbarModel* tbModel, - std::function callback): - tbModel(tbModel), model(createModel(tbModel)), callback(callback) { - Builder builder(gladeSearchPath, UI_FILE); - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - tree = GTK_TREE_VIEW(builder.get("toolbarList")); - copyButton = builder.get("btCopy"); - deleteButton = builder.get("btDelete"); - - gtk_tree_view_set_model(tree, GTK_TREE_MODEL(this->model.get())); - - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - GtkTreeViewColumn* column = - gtk_tree_view_column_new_with_attributes(_("Toolbars"), renderer, "text", COLUMN_STRING, "weight", - COLUMN_BOLD, "editable", COLUMN_EDITABLE, nullptr); - - gtk_tree_view_append_column(tree, column); - - GtkTreeSelection* select = gtk_tree_view_get_selection(tree); - gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); - g_signal_connect(select, "changed", G_CALLBACK(treeSelectionChangedCallback), this); - - g_signal_connect(renderer, "edited", G_CALLBACK(treeCellEditedCallback), this); - - g_signal_connect(builder.get("btNew"), "clicked", G_CALLBACK(buttonNewCallback), this); - g_signal_connect(deleteButton, "clicked", G_CALLBACK(buttonDeleteCallback), this); - g_signal_connect(copyButton, "clicked", G_CALLBACK(buttonCopyCallback), this); - - g_signal_connect_swapped(builder.get("btClose"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); -} - -ToolbarManageDialog::~ToolbarManageDialog() { this->callback(); } - -void ToolbarManageDialog::buttonNewCallback(GtkButton* button, ToolbarManageDialog* dlg) { - auto data = std::make_unique(false); - data->setName(_("New")); - data->setId("custom"); - dlg->tbModel->initCopyNameId(data.get()); - dlg->addToolbarData(std::move(data)); -} - -void ToolbarManageDialog::buttonDeleteCallback(GtkButton* button, ToolbarManageDialog* dlg) { - ToolbarData* selected = dlg->getSelectedEntry(); - if (selected == nullptr) { - return; - } - - GtkTreeModel* model = GTK_TREE_MODEL(dlg->model.get()); - GtkTreeIter iter; - if (gtk_tree_model_get_iter_first(model, &iter)) { - do { - ToolbarData* data = nullptr; - gtk_tree_model_get(model, &iter, COLUMN_POINTER, &data, -1); - - if (data == selected) { - gtk_list_store_remove(dlg->model.get(), &iter); - break; - } - } while (gtk_tree_model_iter_next(model, &iter)); - } - - dlg->tbModel->remove(selected); - dlg->updateSelectionData(); -} - -void ToolbarManageDialog::buttonCopyCallback(GtkButton* button, ToolbarManageDialog* dlg) { - ToolbarData* selected = dlg->getSelectedEntry(); - if (selected == nullptr) { - return; - } - - auto data = std::make_unique(*selected); - dlg->tbModel->initCopyNameId(data.get()); - dlg->addToolbarData(std::move(data)); -} - -void ToolbarManageDialog::addToolbarData(std::unique_ptr tbd) { - auto* data = this->tbModel->add(std::move(tbd)); - - GtkTreeIter iter; - gtk_list_store_append(this->model.get(), &iter); - gtk_list_store_set(this->model.get(), &iter, COLUMN_STRING, data->getName().c_str(), COLUMN_BOLD, - PANGO_WEIGHT_NORMAL, COLUMN_POINTER, data, COLUMN_EDITABLE, true, -1); - - GtkTreePath* path = gtk_tree_model_get_path(GTK_TREE_MODEL(this->model.get()), &iter); - GtkTreeViewColumn* column = gtk_tree_view_get_column(tree, 0); - - gtk_tree_view_set_cursor(tree, path, column, true); -} - -void ToolbarManageDialog::treeCellEditedCallback(GtkCellRendererText* renderer, gchar* pathString, gchar* newText, - ToolbarManageDialog* dlg) { - GtkTreeIter iter; - ToolbarData* data = nullptr; - - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(dlg->model.get()), &iter, pathString); - gtk_tree_model_get(GTK_TREE_MODEL(dlg->model.get()), &iter, COLUMN_POINTER, &data, -1); - if (data) { - gtk_list_store_set(dlg->model.get(), &iter, COLUMN_STRING, newText, -1); - data->setName(newText); - } -} - -void ToolbarManageDialog::entrySelected(ToolbarData* data) { - if (data == nullptr) { - gtk_widget_set_sensitive(copyButton, false); - gtk_widget_set_sensitive(deleteButton, false); - } else { - gtk_widget_set_sensitive(copyButton, true); - gtk_widget_set_sensitive(deleteButton, !data->isPredefined()); - } -} - -auto ToolbarManageDialog::getSelectedEntry() -> ToolbarData* { - GtkTreeIter iter; - GtkTreeModel* model = nullptr; - ToolbarData* data = nullptr; - - GtkTreeSelection* selection = gtk_tree_view_get_selection(tree); - if (selection == nullptr) { - return nullptr; - } - - if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - gtk_tree_model_get(model, &iter, COLUMN_POINTER, &data, -1); - return data; - } - - return nullptr; -} - -void ToolbarManageDialog::updateSelectionData() { entrySelected(getSelectedEntry()); } - -void ToolbarManageDialog::treeSelectionChangedCallback(GtkTreeSelection* selection, ToolbarManageDialog* dlg) { - dlg->updateSelectionData(); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/ToolbarManageDialog.h b/entry/src/main/cpp/src/core/gui/dialog/ToolbarManageDialog.h deleted file mode 100644 index 4c2d7bb..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/ToolbarManageDialog.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Xournal++ - * - * Toolbar edit dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for gchar -#include // for GtkButton, GtkCellRendererText, GtkListStore - -#include "util/raii/GObjectSPtr.h" -#include "util/raii/GtkWindowUPtr.h" - -class ToolbarData; -class ToolbarModel; -class GladeSearchpath; - -class ToolbarManageDialog { -public: - ToolbarManageDialog(GladeSearchpath* gladeSearchPath, ToolbarModel* model, std::function callback); - ~ToolbarManageDialog(); - -public: - inline GtkWindow* getWindow() const { return window.get(); } - -private: - static void treeSelectionChangedCallback(GtkTreeSelection* selection, ToolbarManageDialog* dlg); - static void treeCellEditedCallback(GtkCellRendererText* renderer, gchar* pathString, gchar* newText, - ToolbarManageDialog* dlg); - - static void buttonNewCallback(GtkButton* button, ToolbarManageDialog* dlg); - static void buttonDeleteCallback(GtkButton* button, ToolbarManageDialog* dlg); - static void buttonCopyCallback(GtkButton* button, ToolbarManageDialog* dlg); - - void addToolbarData(std::unique_ptr tbd); - void entrySelected(ToolbarData* data); - - void updateSelectionData(); - - ToolbarData* getSelectedEntry(); - -private: - ToolbarModel* tbModel; - xoj::util::GObjectSPtr model; - - GtkTreeView* tree; - GtkWidget* copyButton; - GtkWidget* deleteButton; - - xoj::util::GtkWindowUPtr window; - std::function callback; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/XojOpenDlg.cpp b/entry/src/main/cpp/src/core/gui/dialog/XojOpenDlg.cpp deleted file mode 100644 index 58f5eab..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/XojOpenDlg.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "XojOpenDlg.h" - -#include "control/settings/Settings.h" // for Settings -#include "util/PathUtil.h" // for fromGFile, toGFile -#include "util/PopupWindowWrapper.h" // for PopupWindowWrapper -#include "util/Util.h" -#include "util/gtk4_helper.h" // for gtk_file_chooser_set_current_folder -#include "util/i18n.h" // for _ -#include "util/raii/GObjectSPtr.h" // for GObjectSPtr -#include "util/raii/GtkWindowUPtr.h" // for GtkWindowUPtr - -#include "FileChooserFiltersHelper.h" - -static void addlastSavePathShortcut(GtkFileChooser* fc, Settings* settings) { - auto lastSavePath = settings->getLastSavePath(); - if (!lastSavePath.empty()) { -#if GTK_MAJOR_VERSION == 3 - gtk_file_chooser_add_shortcut_folder(fc, char_cast(lastSavePath.u8string().c_str()), nullptr); -#else - gtk_file_chooser_add_shortcut_folder(fc, Util::toGFile(lastSavePath).get(), nullptr); -#endif - } -} - -static void setCurrentFolderToLastOpenPath(GtkFileChooser* fc, Settings* settings) { - xoj::util::GObjectSPtr currentFolder; - if (settings && !settings->getLastOpenPath().empty()) { - currentFolder = Util::toGFile(settings->getLastOpenPath()); - } else { - currentFolder.reset(g_file_new_for_path(g_get_home_dir()), xoj::util::adopt); - } - gtk_file_chooser_set_current_folder(fc, currentFolder.get(), nullptr); -} - -template -static std::function addSetLastSavePathToCallback( - std::function callback, Settings* settings) { - return [cb = std::move(callback), settings](fs::path path, Args... args) { - if (settings && !path.empty()) { - settings->setLastOpenPath(path.parent_path()); - } - cb(std::move(path), std::forward(args)...); - }; -} - - -constexpr auto ATTACH_CHOICE_ID = "attachPdfChoice"; -static void addAttachChoice(GtkFileChooser* fc) { - gtk_file_chooser_add_choice(fc, ATTACH_CHOICE_ID, _("Attach file to the journal"), nullptr, nullptr); - gtk_file_chooser_set_choice(fc, ATTACH_CHOICE_ID, "false"); -} - -// Helper class, for a single open dialog -class FileDlg { -public: - /** - * Creates an open file dialog. The callback is only called if a file is actually chosen - * @param callback(path, attachPdf) - */ - FileDlg(const char* title, std::function callback); - /** - * Creates an open file dialog. The callback is only called if a file is actually chosen - * @param callback(path) - */ - FileDlg(const char* title, std::function callback); - ~FileDlg() = default; - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - xoj::util::GtkWindowUPtr window; - - std::function callback; - gulong signalId{}; -}; - -static GtkWindow* makeWindow(const char* title) { - // Todo(maybe) - // Restore previews using https://discourse.gnome.org/t/file-chooser-gtk-4-image-preview/11510/2 - auto* win = gtk_file_chooser_dialog_new(title, nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, _("_Cancel"), - GTK_RESPONSE_CANCEL, _("_Open"), GTK_RESPONSE_OK, nullptr); - return GTK_WINDOW(win); -} - -FileDlg::FileDlg(const char* title, std::function callback): - window(makeWindow(title)), callback(std::move(callback)) { - this->signalId = g_signal_connect( - window.get(), "response", G_CALLBACK(+[](GtkDialog* win, int response, gpointer data) { - auto* self = static_cast(data); - - if (response == GTK_RESPONSE_OK) { - auto path = - Util::fromGFile(xoj::util::GObjectSPtr( - gtk_file_chooser_get_file(GTK_FILE_CHOOSER(win)), xoj::util::adopt) - .get()); - - bool attach = false; - if (const char* choice = gtk_file_chooser_get_choice(GTK_FILE_CHOOSER(win), ATTACH_CHOICE_ID); - choice) { - attach = std::strcmp(choice, "true") == 0; - } - - // We need to call gtk_window_close() before invoking the callback, because if the callback pops up - // another dialog, the first one won't close... - // So we postpone the callback - Util::execInUiThread([cb = std::move(self->callback), path = std::move(path), attach]() { - cb(std::move(path), attach); - }); - } - // Closing the window causes another "response" signal, which we want to ignore - g_signal_handler_disconnect(win, self->signalId); - gtk_window_close(self->getWindow()); // Destroys *self. Beware! - }), - this); -} - -FileDlg::FileDlg(const char* title, std::function callback): - FileDlg(title, [cb = std::move(callback)](fs::path path, bool) { cb(std::move(path)); }) {} - - -void xoj::OpenDlg::showOpenTemplateDialog(GtkWindow* parent, Settings* settings, - std::function callback) { - auto popup = xoj::popup::PopupWindowWrapper(_("Open template file"), - addSetLastSavePathToCallback(std::move(callback), settings)); - - auto* fc = GTK_FILE_CHOOSER(popup.getPopup()->getWindow()); - xoj::addFilterAllFiles(fc); - xoj::addFilterXopt(fc); - setCurrentFolderToLastOpenPath(fc, settings); - - popup.show(parent); -} - - -void xoj::OpenDlg::showOpenFileDialog(GtkWindow* parent, Settings* settings, std::function callback) { - auto popup = xoj::popup::PopupWindowWrapper(_("Open file"), - addSetLastSavePathToCallback(std::move(callback), settings)); - - auto* fc = GTK_FILE_CHOOSER(popup.getPopup()->getWindow()); - xoj::addFilterSupported(fc); - xoj::addFilterXoj(fc); - xoj::addFilterXopt(fc); - xoj::addFilterXopp(fc); - xoj::addFilterPdf(fc); - xoj::addFilterAllFiles(fc); - - addlastSavePathShortcut(fc, settings); - setCurrentFolderToLastOpenPath(fc, settings); - - popup.show(parent); -} - -void xoj::OpenDlg::showAnnotatePdfDialog(GtkWindow* parent, Settings* settings, - std::function callback) { - auto popup = xoj::popup::PopupWindowWrapper(_("Annotate Pdf file"), - addSetLastSavePathToCallback(std::move(callback), settings)); - - auto* fc = GTK_FILE_CHOOSER(popup.getPopup()->getWindow()); - - xoj::addFilterPdf(fc); - xoj::addFilterAllFiles(fc); - - addlastSavePathShortcut(fc, settings); - setCurrentFolderToLastOpenPath(fc, settings); - - addAttachChoice(fc); - - popup.show(parent); -} - -void xoj::OpenDlg::showOpenImageDialog(GtkWindow* parent, Settings* settings, - std::function callback) { - auto popup = xoj::popup::PopupWindowWrapper(_("Choose image file"), - [cb = std::move(callback), settings](fs::path p, bool attach) { - if (auto folder = p.parent_path(); !folder.empty()) { - settings->setLastImagePath(folder); - } - cb(std::move(p), attach); - }); - - auto* fc = GTK_FILE_CHOOSER(popup.getPopup()->getWindow()); - - xoj::addFilterImages(fc); - xoj::addFilterAllFiles(fc); - - if (!settings->getLastImagePath().empty()) { - gtk_file_chooser_set_current_folder(fc, Util::toGFile(settings->getLastImagePath()).get(), nullptr); - } - - addAttachChoice(fc); - - popup.show(parent); -} - -void xoj::OpenDlg::showMultiFormatDialog(GtkWindow* parent, std::vector formats, - std::function callback) { - auto popup = xoj::popup::PopupWindowWrapper(_("Open file"), std::move(callback)); - - auto* fc = GTK_FILE_CHOOSER(popup.getPopup()->getWindow()); - - if (formats.size() > 0) { - GtkFileFilter* filterSupported = gtk_file_filter_new(); - gtk_file_filter_set_name(filterSupported, _("Supported files")); - for (std::string format: formats) { - gtk_file_filter_add_pattern(filterSupported, format.c_str()); - } - gtk_file_chooser_add_filter(fc, filterSupported); - } - - popup.show(parent); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/XojOpenDlg.h b/entry/src/main/cpp/src/core/gui/dialog/XojOpenDlg.h deleted file mode 100644 index 70fca8e..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/XojOpenDlg.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Xournal++ - * - * GTK Open dialog to select XOJ (or PDF) file with preview - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for GtkWindow - -#include "filesystem.h" // for path - -class Settings; - -namespace xoj::OpenDlg { -void showOpenFileDialog(GtkWindow* parent, Settings* settings, std::function callback); -/// @param callback(path, attachPdf) -void showAnnotatePdfDialog(GtkWindow* parent, Settings* settings, std::function callback); -void showOpenTemplateDialog(GtkWindow* parent, Settings* settings, std::function callback); - -/// @param callback(path, attachImg) -void showOpenImageDialog(GtkWindow* parent, Settings* settings, std::function callback); - -void showMultiFormatDialog(GtkWindow* parent, std::vector formats, std::function callback); -}; // namespace xoj::OpenDlg diff --git a/entry/src/main/cpp/src/core/gui/dialog/XojSaveDlg.cpp b/entry/src/main/cpp/src/core/gui/dialog/XojSaveDlg.cpp deleted file mode 100644 index b014f7c..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/XojSaveDlg.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "XojSaveDlg.h" - -#include - -#include "control/settings/Settings.h" -#include "util/PathUtil.h" // for fromGFile, toGFile -#include "util/PopupWindowWrapper.h" // for PopupWindowWrapper -#include "util/Util.h" -#include "util/XojMsgBox.h" -#include "util/gtk4_helper.h" // for gtk_file_chooser_set_current_folder -#include "util/i18n.h" // for _ -#include "util/raii/GObjectSPtr.h" // for GObjectSPtr -#include "util/raii/GtkWindowUPtr.h" // for GtkWindowUPtr - -#include "FileChooserFiltersHelper.h" - -static GtkWindow* makeWindow(Settings* settings, fs::path suggestedPath, const char* windowTitle, - const char* buttonLabel) { - GtkWidget* dialog = gtk_file_chooser_dialog_new(windowTitle, nullptr, GTK_FILE_CHOOSER_ACTION_SAVE, _("_Cancel"), - GTK_RESPONSE_CANCEL, buttonLabel, GTK_RESPONSE_OK, nullptr); - - if (!suggestedPath.empty()) { - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), Util::toGFile(suggestedPath.parent_path()).get(), - nullptr); - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), - Util::toGFilename(suggestedPath.filename()).c_str()); - } - if (settings) { - gtk_file_chooser_add_shortcut_folder(GTK_FILE_CHOOSER(dialog), Util::toGFile(settings->getLastOpenPath()).get(), - nullptr); - } - - return GTK_WINDOW(dialog); -} - -xoj::SaveExportDialog::SaveExportDialog(Settings* settings, fs::path suggestedPath, const char* windowTitle, - const char* buttonLabel, - std::function pathValidation, - std::function)> callback): - window(makeWindow(settings, std::move(suggestedPath), windowTitle, buttonLabel)), - callback(std::move(callback)), - pathValidation(std::move(pathValidation)) { - this->signalId = g_signal_connect( - window.get(), "response", G_CALLBACK(+[](GtkDialog* win, int response, gpointer data) { - auto* self = static_cast(data); - auto* fc = GTK_FILE_CHOOSER(win); - if (response == GTK_RESPONSE_OK) { - auto file = Util::fromGFile( - xoj::util::GObjectSPtr(gtk_file_chooser_get_file(fc), xoj::util::adopt).get()); - - if (self->pathValidation(file, gtk_file_filter_get_name(gtk_file_chooser_get_filter(fc)))) { - XojMsgBox::replaceFileQuestion( - GTK_WINDOW(win), std::move(file), - std::bind(&SaveExportDialog::close, self, std::placeholders::_1)); - } // else the dialog stays on until a suitable destination is found or cancel is hit. - } else { - self->close(std::nullopt); - } - }), - this); -} - -void xoj::SaveExportDialog::close(std::optional path) { - // We need to call gtk_window_close() before invoking the callback, because if the callback pops up another dialog, - // the first one won't close... - // But since gtk_window_close() triggers the destruction of *this, we first move the callback - auto cb = std::move(this->callback); - - // Closing the window causes another "response" signal, which we want to ignore - g_signal_handler_disconnect(window.get(), signalId); - gtk_window_close(window.get()); // Destroys *this. Don't do anything after this call - - cb(std::move(path)); -} - -static bool xoppPathValidation(fs::path& p, const char*) { - Util::clearExtensions(p); - p += ".xopp"; - return true; -} - -void xoj::SaveExportDialog::showSaveFileDialog(GtkWindow* parent, Settings* settings, fs::path suggestedPath, - std::function)> callback) { - auto popup = xoj::popup::PopupWindowWrapper(settings, std::move(suggestedPath), _("Save File"), - _("Save"), xoppPathValidation, std::move(callback)); - - auto* fc = GTK_FILE_CHOOSER(popup.getPopup()->getWindow()); - xoj::addFilterXopp(fc); - - popup.show(parent); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/XojSaveDlg.h b/entry/src/main/cpp/src/core/gui/dialog/XojSaveDlg.h deleted file mode 100644 index 1976ff8..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/XojSaveDlg.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Xournal++ - * - * GTK Save/Export dialog to select destination file - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include - -#include // for GtkWindow - -#include "util/raii/GtkWindowUPtr.h" - -#include "filesystem.h" // for path - -class Settings; - -namespace xoj { -/// Helper class, for a single dialog -class SaveExportDialog { -public: - /** - * Shows a save file dialog. The callback is called with std::nullopt if no path were selected - */ - static void showSaveFileDialog(GtkWindow* parent, Settings* settings, fs::path suggestedPath, - std::function)> callback); - - /** - * Creates a save or export file dialog. The callback is called with std::nullopt if no path were selected - * @param pathValidation May modify the given path. Returns true if the path is (now) valid for saving/exporting. - * @param callback(path) - */ - SaveExportDialog(Settings* settings, fs::path suggestedPath, const char* windowTitle, const char* buttonLabel, - std::function pathValidation, - std::function)> callback); - ~SaveExportDialog() = default; - - inline GtkWindow* getWindow() const { return window.get(); } - -private: - /// Closes the dialog and calls the callback on `path` - void close(std::optional path); - - xoj::util::GtkWindowUPtr window; - std::function)> callback; - std::function pathValidation; - gulong signalId{}; -}; -}; // namespace xoj diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BackgroundSelectDialogBase.cpp b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BackgroundSelectDialogBase.cpp deleted file mode 100644 index 1d7c1c6..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BackgroundSelectDialogBase.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "BackgroundSelectDialogBase.h" - -#include // for max -#include // for move - -#include // for GDK_EXPOSURE_MASK -#include // for G_CALLBACK, g_signal_connect - -#include "gui/Builder.h" -#include "util/Util.h" // for paintBackgroundWhite -#include "util/gtk4_helper.h" -#include "util/safe_casts.h" // for round_cast - -#include "BaseElementView.h" // for BaseElementView - -class GladeSearchpath; - - -constexpr auto UI_FILE = "backgroundSelection.glade"; -constexpr auto UI_DIALOG_NAME = "Dialog"; - -BackgroundSelectDialogBase::BackgroundSelectDialogBase(GladeSearchpath* gladeSearchPath, Document* doc, - Settings* settings, const char* title): - settings(settings), doc(doc) { - Builder builder(gladeSearchPath, UI_FILE); - this->window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - gtk_window_set_title(window.get(), title); - - this->container = GTK_FIXED(gtk_fixed_new()); - gtk_widget_set_hexpand(GTK_WIDGET(this->container), true); - this->okButton = builder.get("btOk"); - this->vbox = GTK_BOX(builder.get("vbox")); - - this->scrolledWindow = GTK_SCROLLED_WINDOW(builder.get("scrollContents")); - gtk_scrolled_window_set_child(scrolledWindow, GTK_WIDGET(container)); - - g_signal_connect(gtk_scrolled_window_get_hadjustment(scrolledWindow), "notify::page-size", - G_CALLBACK(+[](GObject*, GParamSpec*, gpointer d) { - static_cast(d)->layout(); - }), - this); - - gtk_window_set_default_size(this->window.get(), 800, 600); - gtk_widget_set_sensitive(this->okButton, false); - - g_signal_connect_swapped(builder.get("btCancel"), "clicked", G_CALLBACK(gtk_window_close), this->window.get()); - - g_signal_connect(this->container, "realize", G_CALLBACK(+[](GtkWidget*, gpointer self) { - static_cast(self)->layout(); - }), - this); -} - -BackgroundSelectDialogBase::~BackgroundSelectDialogBase() = default; - -auto BackgroundSelectDialogBase::getSettings() -> Settings* { return this->settings; } - -void BackgroundSelectDialogBase::layout() { - int x = 0; - int y = 0; - int row_height = 0; - - auto width = gtk_adjustment_get_page_size(gtk_scrolled_window_get_hadjustment(scrolledWindow)); - - for (const auto& p: this->entries) { - if (!gtk_widget_get_visible(p->getWidget())) { - continue; - } - - if (x + p->getWidth() > width) { - y += row_height; - x = 0; - row_height = 0; - } - gtk_fixed_move(this->container, p->getWidget(), x, y); - - row_height = std::max(row_height, p->getHeight()); - x += p->getWidth(); - } -} - -void BackgroundSelectDialogBase::populate() { - for (const auto& e: entries) { - gtk_fixed_put(this->container, e->getWidget(), 0, 0); - } - - if (!entries.empty()) { - setSelected(0); - } - - layout(); -} - -void BackgroundSelectDialogBase::setSelected(size_t selected) { - if (this->selected == selected) { - return; - } - - size_t lastSelected = this->selected; - if (lastSelected < entries.size()) { - entries[lastSelected]->setSelected(false); - } - - if (selected < entries.size()) { - entries[selected]->setSelected(true); - this->selected = selected; - gtk_widget_set_sensitive(okButton, true); - } -} - -void BackgroundSelectDialogBase::ok() { gtk_button_clicked(GTK_BUTTON(okButton)); } diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BackgroundSelectDialogBase.h b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BackgroundSelectDialogBase.h deleted file mode 100644 index 292834b..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BackgroundSelectDialogBase.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Xournal++ - * - * Base class for Background selection dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include // for vector - -#include // for GtkWidget, GtkWindow - -#include "util/Util.h" // for npos -#include "util/raii/GtkWindowUPtr.h" - -class Document; -class Settings; -class BaseElementView; -class GladeSearchpath; - -class BackgroundSelectDialogBase { -protected: - BackgroundSelectDialogBase(GladeSearchpath* gladeSearchPath, Document* doc, Settings* settings, const char* title); - ~BackgroundSelectDialogBase(); - -public: - Settings* getSettings(); - void setSelected(size_t selected); - - void ok(); ///< As if the Ok button was clicked - - inline GtkWindow* getWindow() const { return window.get(); } - -protected: - /// Adds the entry widgets - void populate(); - void layout(); - -protected: - xoj::util::GtkWindowUPtr window; - - Settings* settings = nullptr; - GtkScrolledWindow* scrolledWindow = nullptr; - GtkFixed* container = nullptr; ///< Area where miniatures are layed out - GtkWidget* okButton = nullptr; - GtkBox* vbox = nullptr; ///< Vertical GtkBox containing all. - - Document* doc = nullptr; - - /// Selection confirmed - bool confirmed = false; - - /// Selected entry, none if npos - size_t selected = npos; - - /// Entries to display - std::vector> entries; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BaseElementView.cpp b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BaseElementView.cpp deleted file mode 100644 index 831f03a..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BaseElementView.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "BaseElementView.h" - -#include // for G_CALLBACK, g_signal_connect - -#include "control/settings/Settings.h" // for Settings -#include "gui/Shadow.h" // for Shadow -#include "util/Color.h" // for cairo_set_source_rgbi -#include "util/gtk4_helper.h" - -#include "BackgroundSelectDialogBase.h" // for BackgroundSelectDialogBase - -constexpr int BORDER_WIDTH = 2; - -BaseElementView::BaseElementView(size_t id, BackgroundSelectDialogBase* dlg): dlg(dlg), id(id) { - this->widget = gtk_drawing_area_new(); - gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(widget), - GtkDrawingAreaDrawFunc(+[](GtkWidget*, cairo_t* cr, int, int, gpointer element) { - static_cast(element)->paint(cr); - }), - this, nullptr); - -#if GTK_MAJOR_VERSION == 3 - gtk_widget_show(this->widget); - gtk_widget_add_events(widget, GDK_BUTTON_PRESS_MASK); - g_signal_connect(this->widget, "button-press-event", G_CALLBACK(+[](GtkWidget*, GdkEventButton* e, gpointer d) { - auto* element = static_cast(d); - if (e->type == GDK_BUTTON_PRESS) { - element->dlg->setSelected(element->id); - } else if (e->type == GDK_2BUTTON_PRESS) { - element->dlg->ok(); - } - return true; - }), - this); -#else - auto* ctrl = gtk_gesture_click_new(); - gtk_widget_add_controller(widget, GTK_EVENT_CONTROLLER(ctrl)); - gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(ctrl), GDK_BUTTON_PRIMARY); - g_signal_connect(ctrl, "pressed", - G_CALLBACK(+[](GtkGestureClick* g, gint n_press, gdouble x, gdouble y, gpointer d) { - auto* element = static_cast(d); - if (n_press == 1) { - element->dlg->setSelected(element->id); - } else if (n_press == 2) { - element->dlg->ok(); - } - }), - this); -#endif -} - -BaseElementView::~BaseElementView() { - gtk_widget_destroy(this->widget); - - if (this->crBuffer) { - cairo_surface_destroy(this->crBuffer); - this->crBuffer = nullptr; - } -} - -void BaseElementView::setSelected(bool selected) { - if (this->selected == selected) { - return; - } - this->selected = selected; - - repaint(); -} - -void BaseElementView::repaint() { - if (this->crBuffer) { - cairo_surface_destroy(this->crBuffer); - this->crBuffer = nullptr; - } - gtk_widget_queue_draw(this->widget); -} - -void BaseElementView::paint(cairo_t* cr) { - GtkAllocation alloc; - gtk_widget_get_allocation(this->widget, &alloc); - - if (this->crBuffer == nullptr) { - this->crBuffer = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, alloc.width, alloc.height); - - int width = getContentWidth(); - int height = getContentHeight(); - - cairo_t* cr2 = cairo_create(this->crBuffer); - - cairo_save(cr2); - cairo_translate(cr2, Shadow::getShadowTopLeftSize() + BORDER_WIDTH, - Shadow::getShadowTopLeftSize() + BORDER_WIDTH); - paintContents(cr2); - cairo_restore(cr2); - - cairo_set_operator(cr2, CAIRO_OPERATOR_OVER); - - if (this->selected) { - // Draw border - Util::cairo_set_source_rgbi(cr2, dlg->getSettings()->getBorderColor()); - cairo_set_line_width(cr2, BORDER_WIDTH); - cairo_set_line_cap(cr2, CAIRO_LINE_CAP_BUTT); - cairo_set_line_join(cr2, CAIRO_LINE_JOIN_BEVEL); - - cairo_rectangle(cr2, Shadow::getShadowTopLeftSize() + BORDER_WIDTH / 2, - Shadow::getShadowTopLeftSize() + BORDER_WIDTH / 2, width + BORDER_WIDTH, - height + BORDER_WIDTH); - - cairo_stroke(cr2); - - Shadow::drawShadow(cr2, Shadow::getShadowTopLeftSize(), Shadow::getShadowTopLeftSize(), - width + 2 * BORDER_WIDTH, height + 2 * BORDER_WIDTH); - } else { - Shadow::drawShadow(cr2, Shadow::getShadowTopLeftSize() + BORDER_WIDTH, - Shadow::getShadowTopLeftSize() + BORDER_WIDTH, width, height); - } - - cairo_destroy(cr2); - } - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_source_surface(cr, this->crBuffer, 0, 0); - cairo_paint(cr); -} - -auto BaseElementView::getWidget() -> GtkWidget* { - updateSize(); - return this->widget; -} - -auto BaseElementView::getWidth() -> int { - calcSize(); - return getContentWidth() + Shadow::getShadowBottomRightSize() + Shadow::getShadowTopLeftSize() + 2 * BORDER_WIDTH; -} - -auto BaseElementView::getHeight() -> int { - calcSize(); - return getContentHeight() + Shadow::getShadowBottomRightSize() + Shadow::getShadowTopLeftSize() + 2 * BORDER_WIDTH; -} - -void BaseElementView::calcSize() { - // Not implemented in the base class -} - -void BaseElementView::updateSize() { gtk_widget_set_size_request(this->widget, this->getWidth(), this->getHeight()); } diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BaseElementView.h b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BaseElementView.h deleted file mode 100644 index d794b3f..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/BaseElementView.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Xournal++ - * - * Base class for Background selection dialog entry - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t, cairo_surface_t -#include // for GdkEventButton -#include // for gboolean -#include // for GtkWidget - -#include "util/Util.h" // for npos - -class BackgroundSelectDialogBase; - -class BaseElementView { -public: - BaseElementView(size_t id, BackgroundSelectDialogBase* dlg); - virtual ~BaseElementView(); - -public: - GtkWidget* getWidget(); - int getWidth(); - int getHeight(); - - /** - * Select / unselect this entry - */ - void setSelected(bool selected); - - /** - * Repaint this widget - */ - void repaint(); - -protected: - /** - * Apply the size to the Widget - */ - void updateSize(); - - /** - * Paint the whole widget - */ - void paint(cairo_t* cr); - - /** - * Paint the contents (without border / selection) - */ - virtual void paintContents(cairo_t* cr) = 0; - - /** - * Get the width in pixel, without shadow / border - */ - virtual int getContentWidth() = 0; - - /** - * Get the height in pixel, without shadow / border - */ - virtual int getContentHeight() = 0; - - /** - * Will be called before getContentWidth() / getContentHeight(), can be overwritten - */ - virtual void calcSize(); - -protected: - BackgroundSelectDialogBase* dlg; - -private: - /** - * Element ID - */ - size_t id = npos; - - bool selected = false; - - GtkWidget* widget = nullptr; - cairo_surface_t* crBuffer = nullptr; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImageElementView.cpp b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImageElementView.cpp deleted file mode 100644 index 2d30806..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImageElementView.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "ImageElementView.h" - -#include // for gdk_pixbuf_... -#include // for gdk_cairo_s... - -#include "gui/Shadow.h" // for Shadow -#include "gui/dialog/backgroundSelect/BaseElementView.h" // for BaseElement... -#include "util/safe_casts.h" // for ceil_cast - -class BackgroundSelectDialogBase; - -constexpr int MINIATURE_PIXEL_SIZE = 128; - -ImageElementView::ImageElementView(size_t id, BackgroundSelectDialogBase* dlg): BaseElementView(id, dlg) {} - -ImageElementView::~ImageElementView() = default; - -void ImageElementView::calcSize() { - if (this->width == -1) { - GdkPixbuf* p = backgroundImage.getPixbuf(); - this->width = gdk_pixbuf_get_width(p); - this->height = gdk_pixbuf_get_height(p); - - if (this->width < this->height) { - zoom = static_cast(MINIATURE_PIXEL_SIZE) / this->height; - this->height = MINIATURE_PIXEL_SIZE; - this->width = floor_cast(this->width * zoom); - } else { - zoom = static_cast(MINIATURE_PIXEL_SIZE) / this->width; - this->width = MINIATURE_PIXEL_SIZE; - this->height = floor_cast(this->height * zoom); - } - } -} - -void ImageElementView::paintContents(cairo_t* cr) { - cairo_scale(cr, this->zoom, this->zoom); - - GdkPixbuf* p = this->backgroundImage.getPixbuf(); - gdk_cairo_set_source_pixbuf(cr, p, 0, 0); - cairo_paint(cr); -} - -auto ImageElementView::getContentWidth() -> int { return width; } - -auto ImageElementView::getContentHeight() -> int { return height; } diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImageElementView.h b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImageElementView.h deleted file mode 100644 index 82c7a4a..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImageElementView.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Xournal++ - * - * Image view - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "model/BackgroundImage.h" // for BackgroundImage -#include "util/Util.h" // for npos - -#include "BaseElementView.h" // for BaseElementView - -class BackgroundSelectDialogBase; - - -class ImageElementView: public BaseElementView { -public: - ImageElementView(size_t id, BackgroundSelectDialogBase* dlg); - ~ImageElementView() override; - -protected: - /** - * Paint the contents (without border / selection) - */ - void paintContents(cairo_t* cr) override; - - /** - * Get the width in pixel, without shadow / border - */ - int getContentWidth() override; - - /** - * Get the height in pixel, without shadow / border - */ - int getContentHeight() override; - - /** - * Will be called before getContentWidth() / getContentHeight(), can be overwritten - */ - void calcSize() override; - -private: - double zoom = 1; - - BackgroundImage backgroundImage; - int width = -1; - int height = -1; - - friend class ImagesDialog; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImagesDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImagesDialog.cpp deleted file mode 100644 index 963bae3..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImagesDialog.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include "ImagesDialog.h" - -#include -#include -#include -#include - -#include - -#include "gui/dialog/XojOpenDlg.h" // for showOpenImageDialog -#include "gui/dialog/backgroundSelect/BackgroundSelectDialogBase.h" -#include "gui/dialog/backgroundSelect/BaseElementView.h" -#include "model/BackgroundImage.h" -#include "model/Document.h" -#include "model/PageRef.h" -#include "model/PageType.h" -#include "model/XojPage.h" -#include "util/PathUtil.h" -#include "util/Util.h" // for npos -#include "util/XojMsgBox.h" -#include "util/i18n.h" - -#include "ImageElementView.h" - -class GladeSearchpath; -class Settings; - -ImagesDialog::ImagesDialog(GladeSearchpath* gladeSearchPath, Document* doc, Settings* settings, - std::function callback): - BackgroundSelectDialogBase(gladeSearchPath, doc, settings, _("Select Image")), callback(std::move(callback)) { - loadImagesFromPages(); - - GtkWidget* lbl = gtk_label_new(_("... or select already used Image:")); - gtk_label_set_use_markup(GTK_LABEL(lbl), true); - gtk_box_prepend(vbox, lbl); - - fileChooserButton = GTK_BUTTON(gtk_button_new_with_label(_("Load file"))); - gtk_box_prepend(vbox, GTK_WIDGET(fileChooserButton)); - -#if GTK_MAJOR_VERSION == 3 - gtk_widget_show_all(GTK_WIDGET(vbox)); -#endif - - g_signal_connect(fileChooserButton, "clicked", G_CALLBACK(filechooserButtonCallback), this); - - g_signal_connect_swapped( - okButton, "clicked", G_CALLBACK(+[](ImagesDialog* self) { - if (self->selected < self->entries.size()) { - auto img = (static_cast(self->entries[self->selected].get()))->backgroundImage; - if (!img.isEmpty()) { - self->callback(std::move(img)); - } - } - gtk_window_close(self->window.get()); - }), - this); - - populate(); -} - -ImagesDialog::~ImagesDialog() = default; - -void ImagesDialog::loadImagesFromPages() { - doc->lock_shared(); - for (size_t i = 0; i < doc->getPageCount(); i++) { - PageRef p = doc->getPage(i); - - if (!p->getBackgroundType().isImagePage()) { - continue; - } - - if (p->getBackgroundImage().isEmpty()) { - continue; - } - - if (isImageAlreadyInTheList(p->getBackgroundImage())) { - // Do not display the same image twice - continue; - } - - auto* iv = new ImageElementView(this->entries.size(), this); - iv->backgroundImage = p->getBackgroundImage(); - this->entries.emplace_back(iv); - } - doc->unlock_shared(); -} - -auto ImagesDialog::isImageAlreadyInTheList(BackgroundImage& image) -> bool { - for (const auto& v: this->entries) { - auto* iv = static_cast(v.get()); - if (iv->backgroundImage == image) { - return true; - } - } - - return false; -} - -void ImagesDialog::filechooserButtonCallback(GtkButton*, ImagesDialog* dlg) { - xoj::OpenDlg::showOpenImageDialog(dlg->window.get(), dlg->settings, [dlg](fs::path p, bool attach) { - BackgroundImage img; - GError* err = nullptr; - img.loadFile(p, &err); - img.setAttach(attach); - if (err) { - XojMsgBox::showErrorToUser(dlg->window.get(), - FS(_F("This image could not be loaded. Error message: {1}") % err->message)); - g_error_free(err); - return; - } - - if (img.isEmpty()) { - XojMsgBox::showErrorToUser(dlg->window.get(), _("This image could not be loaded.")); - return; - } - - dlg->callback(std::move(img)); - gtk_window_close(dlg->window.get()); - }); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImagesDialog.h b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImagesDialog.h deleted file mode 100644 index d88a69c..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/ImagesDialog.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Xournal++ - * - * Dialog to select a Image (to insert as background) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GtkButton, GtkWindow - -#include "BackgroundSelectDialogBase.h" // for BackgroundSelectDialogBase - -struct BackgroundImage; -class Document; -class GladeSearchpath; -class Settings; - -class ImagesDialog final: public BackgroundSelectDialogBase { -public: - ImagesDialog(GladeSearchpath* gladeSearchPath, Document* doc, Settings* settings, - std::function callback); - ~ImagesDialog(); - -private: - /** - * Load all images form all pages - */ - void loadImagesFromPages(); - - /** - * Check if this image is already displayed - */ - bool isImageAlreadyInTheList(BackgroundImage& image); - - static void okButtonCallback(GtkButton* button, ImagesDialog* dlg); - static void filechooserButtonCallback(GtkButton* button, ImagesDialog* dlg); - -private: - GtkButton* fileChooserButton = nullptr; - - std::function callback; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfElementView.cpp b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfElementView.cpp deleted file mode 100644 index 3cb4db7..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfElementView.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "PdfElementView.h" - -#include // for __shared_pt... -#include // for move - -#include // for gtk_widget_... - -#include "gui/dialog/backgroundSelect/BaseElementView.h" // for BaseElement... -#include "pdf/base/XojPdfPage.h" // for XojPdfPageSPtr -#include "util/safe_casts.h" // for ceil_cast - -#include "PdfPagesDialog.h" // for PdfPagesDialog - -PdfElementView::PdfElementView(size_t id, XojPdfPageSPtr page, PdfPagesDialog* dlg): - BaseElementView(id, dlg), page(std::move(page)) {} - -PdfElementView::~PdfElementView() = default; - -auto PdfElementView::isUsed() const -> bool { return this->used; } - -void PdfElementView::setUsed(bool used) { this->used = used; } - -void PdfElementView::setHideIfUsed(bool hideIfUsed) { gtk_widget_set_visible(getWidget(), !(hideIfUsed && isUsed())); } - -void PdfElementView::paintContents(cairo_t* cr) { - cairo_scale(cr, PdfPagesDialog::ZOOM_VALUE, PdfPagesDialog::ZOOM_VALUE); - page->render(cr); -} - -auto PdfElementView::getContentWidth() -> int { return floor_cast(page->getWidth() * PdfPagesDialog::ZOOM_VALUE); } - -auto PdfElementView::getContentHeight() -> int { - return floor_cast(page->getHeight() * PdfPagesDialog::ZOOM_VALUE); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfElementView.h b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfElementView.h deleted file mode 100644 index ce0e628..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfElementView.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Xournal++ - * - * PDF view - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "pdf/base/XojPdfPage.h" // for XojPdfPageSPtr - -#include "BaseElementView.h" // for BaseElementView - -class PdfPagesDialog; - -class PdfElementView: public BaseElementView { -public: - PdfElementView(size_t id, XojPdfPageSPtr page, PdfPagesDialog* dlg); - ~PdfElementView() override; - -protected: - /** - * Paint the contents (without border / selection) - */ - void paintContents(cairo_t* cr) override; - - /** - * Get the width in pixel, without shadow / border - */ - int getContentWidth() override; - - /** - * Get the height in pixel, without shadow / border - */ - int getContentHeight() override; - -public: - bool isUsed() const; - void setUsed(bool used); - void setHideIfUsed(bool hideIfUsed); - -private: - XojPdfPageSPtr page; - - /** - * This page is already used as background - */ - bool used = false; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfPagesDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfPagesDialog.cpp deleted file mode 100644 index 74566d5..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfPagesDialog.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "PdfPagesDialog.h" - -#include -#include -#include -#include - -#include - -#include "gui/dialog/backgroundSelect/BackgroundSelectDialogBase.h" -#include "gui/dialog/backgroundSelect/BaseElementView.h" -#include "model/Document.h" -#include "model/PageRef.h" -#include "model/PageType.h" -#include "model/XojPage.h" -#include "pdf/base/XojPdfPage.h" -#include "util/Assert.h" -#include "util/Util.h" // for npos -#include "util/i18n.h" // for FC - -#include "PdfElementView.h" - -class GladeSearchpath; -class Settings; - -PdfPagesDialog::PdfPagesDialog(GladeSearchpath* gladeSearchPath, Document* doc, Settings* settings, - std::function callback): - BackgroundSelectDialogBase(gladeSearchPath, doc, settings, _("Select PDF Page")), - callback(std::move(callback)) { - doc->lock_shared(); - for (size_t i = 0; i < doc->getPdfPageCount(); i++) { - XojPdfPageSPtr p = doc->getPdfPage(i); - entries.emplace_back(std::make_unique(entries.size(), p, this)); - } - - size_t used = 0; - for (size_t i = 0; i < doc->getPageCount(); i++) { - PageRef p = doc->getPage(i); - - if (p->getBackgroundType().isPdfPage()) { - auto pdfPage = p->getPdfPageNr(); - if (pdfPage >= 0 && pdfPage < entries.size()) { - auto* pv = (static_cast(entries[pdfPage].get())); - if (!pv->isUsed()) { - pv->setUsed(true); - used++; - } - } - } - } - xoj_assert(used <= doc->getPdfPageCount()); - auto unused = doc->getPdfPageCount() - used; - doc->unlock_shared(); - - cbUnusedOnly = GTK_CHECK_BUTTON(gtk_check_button_new_with_label( - (unused == 1 ? _("Show only not used pages (one unused page)") : - FC(_F("Show only not used pages ({1} unused pages)") % unused)))); - - gtk_box_prepend(vbox, GTK_WIDGET(cbUnusedOnly)); - -#if GTK_MAJOR_VERSION == 3 - gtk_widget_show_all(GTK_WIDGET(vbox)); -#endif - - g_signal_connect(cbUnusedOnly, "toggled", G_CALLBACK(onlyNotUsedCallback), this); - - g_signal_connect_swapped(okButton, "clicked", G_CALLBACK(+[](PdfPagesDialog* self) { - if (self->selected < self->entries.size()) { - self->callback(self->selected); - } - gtk_window_close(self->window.get()); - }), - this); - - populate(); -} - -PdfPagesDialog::~PdfPagesDialog() = default; - -void PdfPagesDialog::updateOkButton() { - bool valid = selected < entries.size() && gtk_widget_get_visible(this->entries[this->selected]->getWidget()); - gtk_widget_set_sensitive(okButton, valid); -} - -void PdfPagesDialog::onlyNotUsedCallback(GtkToggleButton* tb, PdfPagesDialog* dlg) { - bool hideIfUsed = gtk_toggle_button_get_active(tb); - for (const auto& p: dlg->entries) { - auto* pv = static_cast(p.get()); - pv->setHideIfUsed(hideIfUsed); - } - - dlg->layout(); - dlg->updateOkButton(); - - // For some reason (a bug in GtkViewport, maybe?), the GtkFixed's size is not always updated here. - // This hack seems to fix that... - gtk_widget_queue_resize(gtk_widget_get_parent(GTK_WIDGET(dlg->container))); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfPagesDialog.h b/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfPagesDialog.h deleted file mode 100644 index 7efdd68..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/backgroundSelect/PdfPagesDialog.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Xournal++ - * - * Dialog to select a PDF page (to insert as background) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GtkButton, GtkToggleButton - -#include "BackgroundSelectDialogBase.h" // for BackgroundSelectDialogBase - -class Document; -class GladeSearchpath; -class Settings; - - -class PdfPagesDialog final: public BackgroundSelectDialogBase { -public: - PdfPagesDialog(GladeSearchpath* gladeSearchPath, Document* doc, Settings* settings, - std::function callback); - ~PdfPagesDialog(); - -public: - void updateOkButton(); - - static constexpr double ZOOM_VALUE = 0.25; - -private: - static void onlyNotUsedCallback(GtkToggleButton* tb, PdfPagesDialog* dlg); - - GtkCheckButton* cbUnusedOnly; - - /// Takes parameter the pdf page number - std::function callback; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolItemDragCurrentData.cpp b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolItemDragCurrentData.cpp deleted file mode 100644 index b957e3e..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolItemDragCurrentData.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "ToolItemDragCurrentData.h" - -#include // for g_malloc, g_malloc_n, g_free, g_new - -#include "util/Stacktrace.h" // for Stacktrace - -class AbstractToolItem; -struct NamedColor; - -std::unique_ptr ToolItemDragCurrentData::data = nullptr; - -void ToolItemDragCurrentData::clearData() { data.reset(); } - -void ToolItemDragCurrentData::setData(GtkWidget* widget) { - data = std::make_unique(); - - ToolItemDragDropData* d = ToolitemDragDrop::metadataGetMetadata(widget); - if (d == nullptr) { - g_warning("ToolItemDragCurrentData::setData(GtkWidget * widget) could not get data!"); - Stacktrace::printStacktrace(); - return; - } - - *data = *d; -} - -void ToolItemDragCurrentData::setData(ToolItemType type, int id, AbstractToolItem* item) { - g_return_if_fail(item != nullptr || type != TOOL_ITEM_ITEM); - - data = ToolitemDragDrop::ToolItemDragDropData_new(item); - data->type = type; - data->id = id; -} - -void ToolItemDragCurrentData::setDataColor(int id, size_t paletteColorIndex) { - data = ToolitemDragDrop::ToolItemDragDropData_new(nullptr); - data->type = TOOL_ITEM_COLOR; - data->id = id; - data->paletteColorIndex = paletteColorIndex; -} - -void ToolItemDragCurrentData::setData(ToolItemDragDropData* d) { - data = std::make_unique(); - *data = *d; -} - -auto ToolItemDragCurrentData::getData() -> const ToolItemDragDropData* { return data.get(); } diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolItemDragCurrentData.h b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolItemDragCurrentData.h deleted file mode 100644 index 26671c0..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolItemDragCurrentData.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Xournal++ - * - * Toolbar drag & drop helper class - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for GtkWidget - -#include "gui/ToolitemDragDrop.h" // for ToolItemDragDropData (ptr only) - -class AbstractToolItem; -struct NamedColor; - -class ToolItemDragCurrentData { -private: - ToolItemDragCurrentData(); - virtual ~ToolItemDragCurrentData(); - -public: - static void clearData(); - static void setData(ToolItemDragDropData* d); - static void setData(ToolItemType type, int id, AbstractToolItem* item); - static void setData(GtkWidget* widget); - static void setDataColor(int id, size_t paletteColorIndex); - static const ToolItemDragDropData* getData(); - -private: - static std::unique_ptr data; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarAdapter.cpp b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarAdapter.cpp deleted file mode 100644 index 46c8127..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarAdapter.cpp +++ /dev/null @@ -1,345 +0,0 @@ -#include "ToolbarAdapter.h" - -#include // for move - -#include // for G_CALLBACK - -#include "control/Control.h" // for Control -#include "control/settings/Settings.h" // for Settings -#include "gui/MainWindow.h" // for MainWindow -#include "gui/ToolitemDragDrop.h" // for ToolItemDragDr... -#include "gui/toolbarMenubar/AbstractToolItem.h" // for AbstractToolItem -#include "gui/toolbarMenubar/ColorToolItem.h" // for ColorToolItem -#include "gui/toolbarMenubar/ToolMenuHandler.h" // for ToolMenuHandler -#include "gui/toolbarMenubar/icon/ColorIcon.h" // for ColorIcon -#include "gui/toolbarMenubar/model/ToolbarData.h" // for ToolbarData -#include "util/Assert.h" // for xoj_assert -#include "util/NamedColor.h" // for NamedColor -#include "util/PlaceholderString.h" // for PlaceholderString -#include "util/gtk4_helper.h" -#include "util/i18n.h" - -#include "ToolItemDragCurrentData.h" // for ToolItemDragCu... -#include "ToolbarDragDropHelper.h" // for dragDestAddToo... - -using std::string; - -ToolbarAdapter::ToolbarAdapter(GtkWidget* toolbar, string toolbarName, ToolMenuHandler* toolHandler, - MainWindow* window): - palette(toolHandler->getControl()->getPalette()) { - this->w = toolbar; - g_object_ref(this->w); - this->toolbarName = std::move(toolbarName); - this->window = window; - - // prepare drag & drop - gtk_drag_dest_set(toolbar, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_MOVE); - ToolbarDragDropHelper::dragDestAddToolbar(toolbar); - - g_signal_connect(toolbar, "drag_motion", G_CALLBACK(toolbarDragMotionCb), this); - g_signal_connect(toolbar, "drag_leave", G_CALLBACK(toolbarDragLeafeCb), this); - g_signal_connect(toolbar, "drag_data_received", G_CALLBACK(toolbarDragDataReceivedCb), this); - - showToolbar(); - prepareToolItems(); - - gtk_widget_add_css_class(w, "editing"); -} - -ToolbarAdapter::~ToolbarAdapter() { - // remove drag & drop handler - g_signal_handlers_disconnect_by_func(this->w, (gpointer)toolbarDragMotionCb, this); - g_signal_handlers_disconnect_by_func(this->w, (gpointer)toolbarDragLeafeCb, this); - g_signal_handlers_disconnect_by_func(this->w, (gpointer)toolbarDragDataReceivedCb, this); - - cleanupToolbars(); - - gtk_widget_remove_css_class(w, "editing"); - - g_object_unref(this->w); -} - -void ToolbarAdapter::cleanupToolbars() { - GtkToolbar* tb = GTK_TOOLBAR(this->w); - if (gtk_toolbar_get_n_items(tb) == 0) { - gtk_widget_hide(this->w); - } else { - for (int i = 0; i < gtk_toolbar_get_n_items(tb); i++) { - GtkToolItem* it = gtk_toolbar_get_nth_item(tb, i); - cleanToolItem(it); - } - } -} - -void ToolbarAdapter::prepareToolItems() { - GtkToolbar* tb = GTK_TOOLBAR(this->w); - - for (int i = 0; i < gtk_toolbar_get_n_items(tb); i++) { - GtkToolItem* it = gtk_toolbar_get_nth_item(tb, i); - prepareToolItem(it); - } -} - -void ToolbarAdapter::cleanToolItem(GtkToolItem* it) { - GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(it)); - - if (window) { - gdk_window_set_cursor(window, nullptr); - } - - gtk_tool_item_set_use_drag_window(it, false); - gtk_drag_source_unset(GTK_WIDGET(it)); - - g_signal_handlers_disconnect_by_func(it, (gpointer)toolitemDragBegin, nullptr); - g_signal_handlers_disconnect_by_func(it, (gpointer)toolitemDragEnd, nullptr); - g_signal_handlers_disconnect_by_func(it, (gpointer)toolitemDragDataGet, this); -} - -void ToolbarAdapter::prepareToolItem(GtkToolItem* it) { - gtk_tool_item_set_use_drag_window(it, true); - - /* - * Set cursor of drag drop to hand. Note: the tool item must be realized for - * this to work! - */ - { - gtk_widget_realize(GTK_WIDGET(it)); - GdkDisplay* display = gtk_widget_get_display(GTK_WIDGET(it)); - GdkCursor* cursor = gdk_cursor_new_for_display(display, GDK_HAND2); - xoj_assert(cursor); - GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(it)); - xoj_assert(window); - gdk_window_set_cursor(window, cursor); - g_object_unref(cursor); - } - - gtk_drag_source_set(GTK_WIDGET(it), GDK_BUTTON1_MASK, &ToolbarDragDropHelper::dropTargetEntry, 1, GDK_ACTION_MOVE); - ToolbarDragDropHelper::dragSourceAddToolbar(GTK_WIDGET(it)); - - g_signal_connect(it, "drag-begin", G_CALLBACK(toolitemDragBegin), nullptr); - g_signal_connect(it, "drag-end", G_CALLBACK(toolitemDragEnd), nullptr); - g_signal_connect(it, "drag-data-get", G_CALLBACK(toolitemDragDataGet), this); -} - -void ToolbarAdapter::showToolbar() { - // force the toolbar to be shown even if empty - gtk_widget_show(this->w); -} - -/** - * Drag a Toolitem from toolbar - */ -void ToolbarAdapter::toolitemDragBegin(GtkWidget* widget, GdkDragContext* context, void* unused) { - ToolItemDragDropData* data = ToolitemDragDrop::metadataGetMetadata(widget); - g_return_if_fail(data != nullptr); - ToolItemDragCurrentData::setData(data); - - auto* icon = ToolitemDragDrop::getIcon(data); - g_object_ref_sink(icon); - ToolbarDragDropHelper::gdk_context_set_icon_from_image(context, icon); - g_object_unref(icon); - - gtk_widget_hide(widget); -} - -/** - * Drag a Toolitem from toolbar STOPPED - */ -void ToolbarAdapter::toolitemDragEnd(GtkWidget* widget, GdkDragContext* context, void* unused) { - ToolItemDragCurrentData::clearData(); - gtk_widget_show(widget); -} - -/** - * Remove a toolbar item from the tool where it was - */ -void ToolbarAdapter::removeFromToolbar(AbstractToolItem* item, const string& toolbarName, int id) { - ToolbarData* d = this->window->getSelectedToolbar(); - if (d->removeItemByID(toolbarName, id)) { - if (item != nullptr) { - g_message( - "%s", - FS(_F("Removed tool item {1} from Toolbar {2} ID {3}") % item->getId() % toolbarName % id).c_str()); - } else { - g_message("%s", FS(_F("Removed tool item from Toolbar {1} ID {2}") % toolbarName % id).c_str()); - } - } else { - if (item != nullptr) { - g_message("%s", FS(_F("Could not remove tool item {1} from Toolbar {2} on position {3}") % item->getId() % - toolbarName % id) - .c_str()); - } else { - g_message("%s", - FS(_F("Could not remove tool item from Toolbar {1} on position {2}") % toolbarName % id).c_str()); - } - } -} - -void ToolbarAdapter::toolitemDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selection_data, - guint info, guint time, ToolbarAdapter* adapter) { - ToolItemDragDropData* data = ToolitemDragDrop::metadataGetMetadata(widget); - - g_return_if_fail(data != nullptr); - - GtkToolbar* tb = GTK_TOOLBAR(adapter->w); - int position = -1; - for (int i = 0; i < gtk_toolbar_get_n_items(tb); i++) { - GtkToolItem* it = gtk_toolbar_get_nth_item(tb, i); - - if (static_cast(it) == static_cast(widget)) { - adapter->cleanToolItem(it); - gtk_container_remove(GTK_CONTAINER(tb), GTK_WIDGET(it)); - position = i; - break; - } - } - - g_return_if_fail(position != -1); - - adapter->removeFromToolbar(data->item, adapter->toolbarName, data->id); - - gtk_selection_data_set(selection_data, ToolbarDragDropHelper::atomToolItem, 0, - reinterpret_cast(data), sizeof(ToolItemDragDropData)); -} - -/** - * A tool item was dragged to the toolbar - */ -auto ToolbarAdapter::toolbarDragMotionCb(GtkToolbar* toolbar, GdkDragContext* context, gint x, gint y, guint time, - ToolbarAdapter* adapter) -> bool { - GdkAtom target = gtk_drag_dest_find_target(GTK_WIDGET(toolbar), context, nullptr); - if (target != ToolbarDragDropHelper::atomToolItem) { - gdk_drag_status(context, static_cast(0), time); - return false; - } - - GtkOrientation orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(toolbar)); - - bool horizontal = orientation == GTK_ORIENTATION_HORIZONTAL; - gint ipos = toolbarGetDropIndex(toolbar, x, y, horizontal); - - gdk_drag_status(context, gdk_drag_context_get_suggested_action(context), time); - - const ToolItemDragDropData* d = ToolItemDragCurrentData::getData(); - - if (d == nullptr) { - g_warning("ToolbarAdapter.cpp, ToolItemDragDropData == nullptr"); - return false; - } - - if (d->type == TOOL_ITEM_ITEM) { - GtkWidget* iconWidget = d->item->getNewToolIcon(); - GtkToolItem* it = gtk_tool_button_new(iconWidget, ""); - gtk_toolbar_set_drop_highlight_item(toolbar, it, ipos); - } else if (d->type == TOOL_ITEM_SEPARATOR) { - GtkToolItem* it = gtk_separator_tool_item_new(); - gtk_toolbar_set_drop_highlight_item(toolbar, it, ipos); - } else if (d->type == TOOL_ITEM_SPACER) { - GtkToolItem* it = gtk_separator_tool_item_new(); - gtk_tool_item_set_expand(it, true); - gtk_toolbar_set_drop_highlight_item(toolbar, it, ipos); - } else if (d->type == TOOL_ITEM_COLOR) { - auto namedColor = adapter->palette.getColorAt(d->paletteColorIndex); - GtkWidget* iconWidget = ColorIcon::newGtkImage(namedColor.getColor(), 16, true); - GtkToolItem* it = gtk_tool_button_new(iconWidget, ""); - gtk_toolbar_set_drop_highlight_item(toolbar, it, ipos); - } else { - g_warning("ToolbarAdapter::toolbarDragMotionCb Unhandled type %i", d->type); - } - - return true; -} - -void ToolbarAdapter::toolbarDragLeafeCb(GtkToolbar* toolbar, GdkDragContext* context, guint time, - ToolbarAdapter* adapter) { - gtk_toolbar_set_drop_highlight_item(toolbar, nullptr, -1); -} - -void ToolbarAdapter::toolbarDragDataReceivedCb(GtkToolbar* toolbar, GdkDragContext* context, gint x, gint y, - GtkSelectionData* data, guint info, guint time, - ToolbarAdapter* adapter) { - auto* d = reinterpret_cast(gtk_selection_data_get_data(data)); - g_return_if_fail(ToolitemDragDrop::checkToolItemDragDropData(d)); - - bool horizontal = gtk_orientable_get_orientation(GTK_ORIENTABLE(toolbar)) == GTK_ORIENTATION_HORIZONTAL; - gint pos = toolbarGetDropIndex(toolbar, x, y, horizontal); - - if (d->type == TOOL_ITEM_ITEM) { - auto it = d->item->createToolItem(horizontal); - - gtk_toolbar_insert(toolbar, GTK_TOOL_ITEM(it.get()), pos); // Increases the ref-count of *it - adapter->prepareToolItem(GTK_TOOL_ITEM(it.get())); - - ToolbarData* tb = adapter->window->getSelectedToolbar(); - const char* name = adapter->window->getToolbarName(toolbar); - - string id = d->item->getId(); - - int newId = tb->insertItem(name, id, pos); - ToolitemDragDrop::attachMetadata(it.get(), newId, d->item); - } else if (d->type == TOOL_ITEM_COLOR) { - const auto& r = adapter->window->getControl()->getSettings()->getRecolorParameters(); - auto recolor = r.recolorizeMainView ? std::make_optional(r.recolor) : std::nullopt; - - auto namedColor = adapter->palette.getColorAt(d->paletteColorIndex); - auto item = std::make_unique(namedColor, recolor); - - auto it = item->createToolItem(horizontal); - - gtk_toolbar_insert(toolbar, GTK_TOOL_ITEM(it.get()), pos); - adapter->prepareToolItem(GTK_TOOL_ITEM(it.get())); - - ToolbarData* tb = adapter->window->getSelectedToolbar(); - const char* name = adapter->window->getToolbarName(toolbar); - - string id = item->getId(); - - int newId = tb->insertItem(name, id, pos); - ToolitemDragDrop::attachMetadataColor(it.get(), newId, d->paletteColorIndex, item.get()); - - adapter->window->getToolMenuHandler()->addColorToolItem(std::move(item)); - } else if (d->type == TOOL_ITEM_SEPARATOR) { - GtkToolItem* it = gtk_separator_tool_item_new(); - gtk_widget_show_all(GTK_WIDGET(it)); - gtk_toolbar_insert(toolbar, it, pos); - adapter->prepareToolItem(it); - - ToolbarData* tb = adapter->window->getSelectedToolbar(); - const char* name = adapter->window->getToolbarName(toolbar); - - int newId = tb->insertItem(name, "SEPARATOR", pos); - ToolitemDragDrop::attachMetadata(GTK_WIDGET(it), newId, TOOL_ITEM_SEPARATOR); - } else if (d->type == TOOL_ITEM_SPACER) { - GtkToolItem* it = gtk_separator_tool_item_new(); - gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(it), false); - gtk_tool_item_set_expand(it, true); - gtk_widget_show_all(GTK_WIDGET(it)); - gtk_toolbar_insert(toolbar, it, pos); - adapter->prepareToolItem(it); - - ToolbarData* tb = adapter->window->getSelectedToolbar(); - const char* name = adapter->window->getToolbarName(toolbar); - - int newId = tb->insertItem(name, "SPACER", pos); - ToolitemDragDrop::attachMetadata(GTK_WIDGET(it), newId, TOOL_ITEM_SPACER); - } else { - g_warning("toolbarDragDataReceivedCb: ToolItemType %i not handled!", d->type); - } -} - -auto ToolbarAdapter::toolbarGetDropIndex(GtkToolbar* toolbar, gint x, gint y, bool horizontal) -> gint { - /* - * gtk_toolbar_get_drop_index does not use the correct coordinate system for the y coordinate - * since the y coordinate is only relevant in vertical toolbars the transformation is NOT required for horizontal - * toolbars - */ - if (horizontal) { - return gtk_toolbar_get_drop_index(toolbar, x, y); - } else { - gint wx = 0; - gint wy = 0; - gtk_widget_translate_coordinates(GTK_WIDGET(toolbar), gtk_widget_get_toplevel(GTK_WIDGET(toolbar)), x, y, &wx, - &wy); - return gtk_toolbar_get_drop_index(toolbar, x, wy); - } -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarAdapter.h b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarAdapter.h deleted file mode 100644 index 51882d5..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarAdapter.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Xournal++ - * - * Toolbar drag & drop helper class - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - - -#include // for string - -#include // for GdkDragContext -#include // for gint, guint -#include // for GtkWidget, GtkToolbar, GtkToolItem, GtkSelectio... - -#include "gui/toolbarMenubar/model/ColorPalette.h" - -class AbstractToolItem; -class MainWindow; -class ToolMenuHandler; - -class ToolbarAdapter { -public: - ToolbarAdapter(GtkWidget* toolbar, std::string toolbarName, ToolMenuHandler* toolHandler, MainWindow* window); - ~ToolbarAdapter(); - -private: - void cleanupToolbars(); - void prepareToolItems(); - void cleanToolItem(GtkToolItem* it); - void prepareToolItem(GtkToolItem* it); - void showToolbar(); - -private: - /** - * Drag a Toolitem from toolbar - */ - static void toolitemDragBegin(GtkWidget* widget, GdkDragContext* context, void* unused); - - /** - * Drag a Toolitem from toolbar STOPPED - */ - static void toolitemDragEnd(GtkWidget* widget, GdkDragContext* context, void* unused); - - /** - * Remove a toolbar item from the tool where it was - */ - void removeFromToolbar(AbstractToolItem* item, const std::string& toolbarName, int id); - static void toolitemDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selection_data, - guint info, guint time, ToolbarAdapter* adapter); - - /** - * A tool item was dragged to the toolbar - */ - static bool toolbarDragMotionCb(GtkToolbar* toolbar, GdkDragContext* context, gint x, gint y, guint time, - ToolbarAdapter* adapter); - static void toolbarDragLeafeCb(GtkToolbar* toolbar, GdkDragContext* context, guint time, ToolbarAdapter* adapter); - static void toolbarDragDataReceivedCb(GtkToolbar* toolbar, GdkDragContext* context, gint x, gint y, - GtkSelectionData* data, guint info, guint time, ToolbarAdapter* adapter); - - /** - * @brief Wrapper around gtk_toolbar_get_drop index with coorect coordinate handling - * - * @param toolbar the corresponding toolbar for the drop index - * @param x coordinate in toolbar coordinate system - * @param y coordinate in toolbar coordinate system - * @param horizontal denotes whether the toolbar is horizontal - * @return gint position at which drop item should be inserted - */ - static gint toolbarGetDropIndex(GtkToolbar* toolbar, gint x, gint y, bool horizontal); - -private: - GtkWidget* w; - std::string toolbarName; - MainWindow* window; - - Palette palette; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarCustomizeDialog.cpp b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarCustomizeDialog.cpp deleted file mode 100644 index 8fc73cd..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarCustomizeDialog.cpp +++ /dev/null @@ -1,325 +0,0 @@ -#include "ToolbarCustomizeDialog.h" - -#include // for size_t -#include // for numeric_l... -#include // for allocator -#include // for vector - -#include // for GdkPixbuf -#include // for G_CALLBACK - -#include "control/Control.h" // for Control -#include "control/settings/Settings.h" // for Settings -#include "gui/Builder.h" -#include "gui/MainWindow.h" // for MainWindow -#include "gui/ToolitemDragDrop.h" // for ToolItemD... -#include "gui/toolbarMenubar/AbstractToolItem.h" // for AbstractT... -#include "gui/toolbarMenubar/ToolMenuHandler.h" // for ToolMenuH... -#include "gui/toolbarMenubar/icon/ColorIcon.h" // for ColorIcon -#include "gui/toolbarMenubar/icon/ToolbarSeparatorImage.h" // for getNewToo... -#include "gui/toolbarMenubar/model/ColorPalette.h" // for Palette -#include "util/Assert.h" // for xoj_assert -#include "util/Color.h" // for Color -#include "util/EnumIndexedArray.h" -#include "util/GListView.h" // for GListView -#include "util/NamedColor.h" // for NamedColor -#include "util/gtk4_helper.h" -#include "util/i18n.h" // for _ -#include "util/raii/GObjectSPtr.h" - -#include "ToolItemDragCurrentData.h" // for ToolItemD... -#include "ToolbarDragDropHandler.h" // for ToolbarDr... -#include "ToolbarDragDropHelper.h" // for dragSourc... - -class GladeSearchpath; - -/* - * struct used for data necessary for dragging - * during toolbar customization - */ -struct ToolbarCustomizeDialog::ToolItemDragData { - ToolbarCustomizeDialog* dlg; - GtkWidget* icon; ///< Currently must be an GtkImage - AbstractToolItem* item; - xoj::util::WidgetSPtr ebox; -}; - -struct ToolbarCustomizeDialog::ColorToolItemDragData { - ToolbarCustomizeDialog* dlg; - size_t paletteColorIndex; - xoj::util::WidgetSPtr ebox; -}; - -// Separator and spacer -struct ToolbarCustomizeDialog::SeparatorData { - ToolItemType type; - SeparatorType separator; - const char* label; -}; - -std::array ToolbarCustomizeDialog::separators = { - ToolbarCustomizeDialog::SeparatorData{TOOL_ITEM_SEPARATOR, SeparatorType::SEPARATOR, _("Separator")}, - ToolbarCustomizeDialog::SeparatorData{TOOL_ITEM_SPACER, SeparatorType::SPACER, _("Spacer")}}; - - -constexpr auto UI_FILE = "toolbarCustomizeDialog.glade"; -constexpr auto UI_DIALOG_NAME = "DialogCustomizeToolbar"; - -ToolbarCustomizeDialog::ToolbarCustomizeDialog(GladeSearchpath* gladeSearchPath, MainWindow* win, - ToolbarDragDropHandler* handler): - itemData(buildToolDataVector(win->getToolMenuHandler()->getToolItems())), - colorItemData(buildColorDataVector(handler->getControl()->getPalette())), - palette(handler->getControl()->getPalette()) { - Builder builder(gladeSearchPath, UI_FILE); - window.reset(GTK_WINDOW(builder.get(UI_DIALOG_NAME))); - notebook = GTK_NOTEBOOK(builder.get("notebook")); - - using Cat = AbstractToolItem::Category; - EnumIndexedArray labels; - labels[Cat::AUDIO] = C_("Item category in toolbar customization dialog", "Audio"); - labels[Cat::COLORS] = C_("Item category in toolbar customization dialog", "Colors"); - labels[Cat::FILES] = C_("Item category in toolbar customization dialog", "Files"); - labels[Cat::MISC] = C_("Item category in toolbar customization dialog", "Miscellaneous"); - labels[Cat::NAVIGATION] = C_("Item category in toolbar customization dialog", "Navigation"); - labels[Cat::SELECTION] = C_("Item category in toolbar customization dialog", "Selection"); - labels[Cat::TOOLS] = C_("Item category in toolbar customization dialog", "Tools"); - labels[Cat::SEPARATORS] = C_("Item category in toolbar customization dialog", "Separators"); - labels[Cat::PLUGINS] = C_("Item category in toolbar customization dialog", "Plugins"); - EnumIndexedArray tabs; - - for (std::underlying_type_t n = 0; n < xoj::to_underlying(Cat::ENUMERATOR_COUNT); n++) { - Cat c = static_cast(n); - tabs[c] = gtk_list_box_new(); - GtkWidget* w = gtk_scrolled_window_new(); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(w), tabs[c]); - gtk_notebook_append_page(notebook, w, gtk_label_new(labels[c].c_str())); - } - - auto addEntry = [&tabs](GtkWidget* w, Cat c) { - GtkWidget* row = gtk_list_box_row_new(); - gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row), w); - gtk_list_box_row_set_selectable(GTK_LIST_BOX_ROW(row), false); - gtk_list_box_append(GTK_LIST_BOX(tabs[c]), row); - }; - - for (auto& data: itemData) { - addEntry(data.ebox.get(), data.item->getCategory()); - } - - for (auto& data: colorItemData) { - addEntry(data.ebox.get(), Cat::COLORS); - } - - // init separator and spacer - for (SeparatorData& data: separators) { - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2)); - gtk_box_append(box, ToolbarSeparatorImage::newImage(data.separator)); - gtk_box_append(box, gtk_label_new(data.label)); - - GtkWidget* ebox = gtk_event_box_new(); - gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(box)); - gtk_widget_show_all(ebox); - - // make ebox a drag source - gtk_drag_source_set(ebox, GDK_BUTTON1_MASK, &ToolbarDragDropHelper::dropTargetEntry, 1, GDK_ACTION_MOVE); - ToolbarDragDropHelper::dragSourceAddToolbar(ebox); - - g_signal_connect(ebox, "drag-begin", G_CALLBACK(toolitemDragBeginSeparator), &data); - g_signal_connect(ebox, "drag-end", G_CALLBACK(toolitemDragEndSeparator), &data); - g_signal_connect(ebox, "drag-data-get", G_CALLBACK(toolitemDragDataGetSeparator), &data); - - addEntry(ebox, Cat::SEPARATORS); - } - - GtkWidget* target = GTK_WIDGET(notebook); // builder.get("viewport1"); - // prepare drag & drop - gtk_drag_dest_set(target, GTK_DEST_DEFAULT_ALL, nullptr, 0, GDK_ACTION_MOVE); - ToolbarDragDropHelper::dragDestAddToolbar(target); - - g_signal_connect(target, "drag-data-received", G_CALLBACK(dragDataReceived), this); - - g_signal_connect_swapped(builder.get("btClose"), "clicked", G_CALLBACK(gtk_window_close), window.get()); - g_signal_connect_swapped(window.get(), "delete-event", - G_CALLBACK(+[](ToolbarDragDropHandler* h) { h->toolbarConfigDialogClosed(); }), handler); -} - -ToolbarCustomizeDialog::~ToolbarCustomizeDialog() = default; - -void ToolbarCustomizeDialog::toolitemDragBeginSeparator(GtkWidget* widget, GdkDragContext* context, void* data) { - SeparatorData* sepData = static_cast(data); - ToolItemDragCurrentData::setData(sepData->type, -1, nullptr); - GdkPixbuf* pixbuf = ToolbarSeparatorImage::getNewToolPixbuf(sepData->separator); - gtk_drag_set_icon_pixbuf(context, pixbuf, -2, -2); - g_object_unref(pixbuf); -} - -void ToolbarCustomizeDialog::toolitemDragEndSeparator(GtkWidget* widget, GdkDragContext* context, void* unused) { - ToolItemDragCurrentData::clearData(); -} - -void ToolbarCustomizeDialog::toolitemDragDataGetSeparator(GtkWidget* widget, GdkDragContext* context, - GtkSelectionData* selection_data, guint info, guint time, - void* data) { - SeparatorData* sepData = static_cast(data); - auto it = ToolitemDragDrop::ToolItemDragDropData_new(nullptr); - it->type = sepData->type; - - gtk_selection_data_set(selection_data, ToolbarDragDropHelper::atomToolItem, 0, - reinterpret_cast(it.get()), sizeof(ToolItemDragDropData)); -} - -/** - * Drag a Toolitem from dialog - */ -void ToolbarCustomizeDialog::toolitemDragBegin(GtkWidget* widget, GdkDragContext* context, ToolItemDragData* data) { - ToolItemDragCurrentData::setData(TOOL_ITEM_ITEM, -1, data->item); - if (data->icon) { - ToolbarDragDropHelper::gdk_context_set_icon_from_image(context, data->icon); - } -} - -/** - * Drag a Toolitem from dialog STOPPED - */ -void ToolbarCustomizeDialog::toolitemDragEnd(GtkWidget* widget, GdkDragContext* context, ToolItemDragData* data) { - ToolItemDragCurrentData::clearData(); -} - -void ToolbarCustomizeDialog::toolitemDragDataGet(GtkWidget* widget, GdkDragContext* context, - GtkSelectionData* selection_data, guint info, guint time, - ToolItemDragData* data) { - g_return_if_fail(data != nullptr); - g_return_if_fail(data->item != nullptr); - - auto it = ToolitemDragDrop::ToolItemDragDropData_new(data->item); - - gtk_selection_data_set(selection_data, ToolbarDragDropHelper::atomToolItem, 0, - reinterpret_cast(it.get()), sizeof(ToolItemDragDropData)); -} - -/** - * Drag a ColorToolitem from dialog - */ -void ToolbarCustomizeDialog::toolitemColorDragBegin(GtkWidget* widget, GdkDragContext* context, - ColorToolItemDragData* data) { - ToolItemDragCurrentData::setDataColor(-1, data->paletteColorIndex); - - auto namedColor = data->dlg->palette.getColorAt(data->paletteColorIndex); - auto image = ColorIcon::newGdkPixbuf(namedColor.getColor(), 16, true); - gtk_drag_set_icon_pixbuf(context, image.get(), -2, -2); -} - -/** - * Drag a ColorToolitem from dialog STOPPED - */ -void ToolbarCustomizeDialog::toolitemColorDragEnd(GtkWidget* widget, GdkDragContext* context, - ColorToolItemDragData* data) { - ToolItemDragCurrentData::clearData(); -} - -void ToolbarCustomizeDialog::toolitemColorDragDataGet(GtkWidget* widget, GdkDragContext* context, - GtkSelectionData* selection_data, guint info, guint time, - ColorToolItemDragData* data) { - ToolItemDragCurrentData::setDataColor(-1, data->paletteColorIndex); - - auto it = ToolitemDragDrop::ToolItemDragDropData_new(nullptr); - it->type = TOOL_ITEM_COLOR; - it->paletteColorIndex = data->paletteColorIndex; - - gtk_selection_data_set(selection_data, ToolbarDragDropHelper::atomToolItem, 0, - reinterpret_cast(it.get()), sizeof(ToolItemDragDropData)); -} - -/** - * A tool item was dragged to the dialog - */ -void ToolbarCustomizeDialog::dragDataReceived(GtkWidget* widget, GdkDragContext* dragContext, gint x, gint y, - GtkSelectionData* data, guint info, guint time, - ToolbarCustomizeDialog* dlg) { - if (gtk_selection_data_get_data_type(data) != ToolbarDragDropHelper::atomToolItem) { - gtk_drag_finish(dragContext, false, false, time); - return; - } - - auto* d = reinterpret_cast(gtk_selection_data_get_data(data)); - g_return_if_fail(ToolitemDragDrop::checkToolItemDragDropData(d)); - - gtk_drag_finish(dragContext, true, false, time); -} - -/** - * builds up the icon list - */ -auto ToolbarCustomizeDialog::buildToolDataVector(const std::vector>& tools) - -> std::vector { - // By reserving, we ensure no reallocation is done, so the pointer `&data` used below is not invalidated - std::vector database; - database.reserve(tools.size()); - for (auto&& item: tools) { - std::string name = item->getToolDisplayName(); - GtkWidget* icon = item->getNewToolIcon(); /* floating */ - xoj_assert(icon); - - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2)); - gtk_box_append(box, icon); - gtk_box_append(box, gtk_label_new(name.c_str())); - - GtkWidget* ebox = gtk_event_box_new(); - gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(box)); - gtk_widget_show_all(GTK_WIDGET(ebox)); - - auto& data = database.emplace_back(); - data.dlg = this; - data.icon = icon; - data.item = item.get(); - data.ebox.reset(ebox, xoj::util::adopt); - - // make ebox a drag source - gtk_drag_source_set(ebox, GDK_BUTTON1_MASK, &ToolbarDragDropHelper::dropTargetEntry, 1, GDK_ACTION_MOVE); - ToolbarDragDropHelper::dragSourceAddToolbar(ebox); - - g_signal_connect(ebox, "drag-begin", G_CALLBACK(toolitemDragBegin), &data); - g_signal_connect(ebox, "drag-end", G_CALLBACK(toolitemDragEnd), &data); - g_signal_connect(ebox, "drag-data-get", G_CALLBACK(toolitemDragDataGet), &data); - } - return database; -} - -auto ToolbarCustomizeDialog::buildColorDataVector(const Palette& palette) -> std::vector { - // By reserving, we ensure no reallocation is done, so the pointer `&data` used below is not invalidated - std::vector database; - database.reserve(palette.size()); - for (size_t paletteColorIndex = 0; paletteColorIndex < palette.size(); paletteColorIndex++) { - // namedColor needs to be a pointer to pass it into a ColorToolItemDragData - const NamedColor& namedColor = palette.getColorAt(paletteColorIndex); - - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 2)); - gtk_box_append(box, ColorIcon::newGtkImage(namedColor.getColor(), 16, true)); - gtk_box_append(box, gtk_label_new(namedColor.getName().c_str())); - - GtkWidget* ebox = gtk_event_box_new(); - gtk_container_add(GTK_CONTAINER(ebox), GTK_WIDGET(box)); - gtk_widget_show_all(GTK_WIDGET(ebox)); - - // make ebox a drag source - gtk_drag_source_set(ebox, GDK_BUTTON1_MASK, &ToolbarDragDropHelper::dropTargetEntry, 1, GDK_ACTION_MOVE); - ToolbarDragDropHelper::dragSourceAddToolbar(ebox); - - auto& data = database.emplace_back(); - data.dlg = this; - data.paletteColorIndex = paletteColorIndex; - data.ebox.reset(ebox, xoj::util::ref); - - g_signal_connect(ebox, "drag-begin", G_CALLBACK(toolitemColorDragBegin), &data); - g_signal_connect(ebox, "drag-end", G_CALLBACK(toolitemColorDragEnd), &data); - g_signal_connect(ebox, "drag-data-get", G_CALLBACK(toolitemColorDragDataGet), &data); - } - return database; -} - -void ToolbarCustomizeDialog::show(GtkWindow* parent) { - gtk_window_set_transient_for(this->window.get(), parent); - - gtk_window_set_position(this->window.get(), GTK_WIN_POS_CENTER_ON_PARENT); - gtk_widget_show_all(GTK_WIDGET(this->window.get())); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarCustomizeDialog.h b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarCustomizeDialog.h deleted file mode 100644 index 148c110..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarCustomizeDialog.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Xournal++ - * - * Toolbar edit dialog - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include -#include - -#include // for GdkDragContext -#include // for guint, gint -#include // for GtkWidget, GtkSelectionData, GtkToolbar - -#include "gui/toolbarMenubar/model/ColorPalette.h" -#include "util/raii/GtkWindowUPtr.h" - -class AbstractToolItem; -struct Palette; -class MainWindow; -class ToolbarDragDropHandler; -class GladeSearchpath; - -class ToolbarCustomizeDialog { -public: - ToolbarCustomizeDialog(GladeSearchpath* gladeSearchPath, MainWindow* win, ToolbarDragDropHandler* handler); - ~ToolbarCustomizeDialog(); - -public: - inline GtkWindow* getWindow() const { return window.get(); } - - void show(GtkWindow* parent); - -private: - struct ToolItemDragData; - struct ColorToolItemDragData; - struct SeparatorData; - - std::vector buildToolDataVector(const std::vector>& tools); - std::vector buildColorDataVector(const Palette& palette); - - // void rebuildIconview(); - - -private: - static void dragDataReceived(GtkWidget* widget, GdkDragContext* dragContext, gint x, gint y, GtkSelectionData* data, - guint info, guint time, ToolbarCustomizeDialog* dlg); - static void toolbarDragLeafeCb(GtkToolbar* toolbar, GdkDragContext* context, guint time, - ToolbarCustomizeDialog* dlg); - static void toolbarDragDataReceivedCb(GtkToolbar* toolbar, GdkDragContext* context, gint x, gint y, - GtkSelectionData* data, guint info, guint time, ToolbarCustomizeDialog* dlg); - - static void toolitemDragBegin(GtkWidget* widget, GdkDragContext* context, ToolItemDragData* data); - static void toolitemDragEnd(GtkWidget* widget, GdkDragContext* context, ToolItemDragData* data); - static void toolitemDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selection_data, - guint info, guint time, ToolItemDragData* data); - - static void toolitemColorDragBegin(GtkWidget* widget, GdkDragContext* context, ColorToolItemDragData* data); - static void toolitemColorDragEnd(GtkWidget* widget, GdkDragContext* context, ColorToolItemDragData* data); - static void toolitemColorDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selection_data, - guint info, guint time, ColorToolItemDragData* data); - - static void toolitemDragBeginSeparator(GtkWidget* widget, GdkDragContext* context, void* unused); - static void toolitemDragEndSeparator(GtkWidget* widget, GdkDragContext* context, void* unused); - static void toolitemDragDataGetSeparator(GtkWidget* widget, GdkDragContext* context, - GtkSelectionData* selection_data, guint info, guint time, void* unused); - - // void freeIconview(); - -private: - /** - * @brief Stores the widget and other data associated to each drag-able toolbar item - * Modifications are not allowed to avoid vector reallocation and pointer invalidation - * (pointers are feed to g_signal's callback data) - */ - const std::vector itemData; - /** - * @brief Stores the widget and other data associated to each drag-able color item - */ - const std::vector colorItemData; - static std::array separators; - - xoj::util::GtkWindowUPtr window; - GtkNotebook* notebook; - Palette palette; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHandler.cpp b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHandler.cpp deleted file mode 100644 index 46ce806..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHandler.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "ToolbarDragDropHandler.h" - -#include // for allocator, string - -#include // for GtkWidget, GTK_TO... - -#include "control/Control.h" // for Control -#include "gui/FloatingToolbox.h" // for FloatingToolbox -#include "gui/MainWindow.h" // for MainWindow -#include "gui/toolbarMenubar/model/ToolbarModel.h" // for ToolbarModel -#include "util/PathUtil.h" // for getConfigFile - -#include "ToolbarAdapter.h" // for ToolbarAdapter -#include "ToolbarCustomizeDialog.h" // for ToolbarCustomizeD... -#include "config-dev.h" // for TOOLBAR_CONFIG - -ToolbarDragDropHandler::ToolbarDragDropHandler(Control* control): control(control) {} - -ToolbarDragDropHandler::~ToolbarDragDropHandler() = default; - -void ToolbarDragDropHandler::prepareToolbarsForDragAndDrop() { - MainWindow* win = control->getWindow(); - - this->toolbars.clear(); - - for (auto w: win->getToolbarWidgets()) { - this->toolbars.emplace_back(std::make_unique(w.get(), win->getToolbarName(GTK_TOOLBAR(w.get())), - control->getWindow()->getToolMenuHandler(), win)); - } -} - -void ToolbarDragDropHandler::clearToolbarsFromDragAndDrop() { this->toolbars.clear(); } - -void ToolbarDragDropHandler::toolbarConfigDialogClosed() { - this->customizeDialog.reset(); - - MainWindow* win = control->getWindow(); - - this->clearToolbarsFromDragAndDrop(); - - auto file = Util::getConfigFile(TOOLBAR_CONFIG); - win->getToolbarModel()->save(file); - win->getFloatingToolbox()->hide(); -} - -void ToolbarDragDropHandler::configure() { - MainWindow* win = control->getWindow(); - - - win->getFloatingToolbox()->showForConfiguration(); - - this->prepareToolbarsForDragAndDrop(); - - this->customizeDialog = std::make_unique(control->getGladeSearchPath(), win, this); - - this->customizeDialog->show(GTK_WINDOW(win->getWindow())); -} diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHandler.h b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHandler.h deleted file mode 100644 index 50c8fee..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHandler.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * Toolbar drag & drop controller - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include - -class Control; -class ToolbarAdapter; -class ToolbarCustomizeDialog; - -class ToolbarDragDropHandler { -public: - ToolbarDragDropHandler(Control* control); - virtual ~ToolbarDragDropHandler(); - -public: - void configure(); - - void toolbarConfigDialogClosed(); - -public: - void prepareToolbarsForDragAndDrop(); - void clearToolbarsFromDragAndDrop(); - - inline Control* getControl() const { return control; } - -private: - Control* control; - - std::vector> toolbars; - std::unique_ptr customizeDialog; -}; diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHelper.cpp b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHelper.cpp deleted file mode 100644 index 1e27127..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHelper.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "ToolbarDragDropHelper.h" - -#include // for cairo_surface_set_device_offset, cairo_surf... -#include // for GIcon -#include // for g_object_get, G_OBJECT -#include // for g_warning, gchar - -namespace ToolbarDragDropHelper { - -const GdkAtom atomToolItem = gdk_atom_intern_static_string("application/xournal-ToolbarItem"); -const GtkTargetEntry dropTargetEntry = {const_cast("move-buffer"), GTK_TARGET_SAME_APP, 1}; - -auto gdk_context_set_icon_from_image(GdkDragContext* ctx, GtkWidget* widget) -> bool { - auto image = GTK_IMAGE(widget); - auto storage = gtk_image_get_storage_type(image); - switch (storage) { - case GTK_IMAGE_PIXBUF: { - gtk_drag_set_icon_pixbuf(ctx, gtk_image_get_pixbuf(image), -2, -2); - return true; - } - case GTK_IMAGE_ICON_NAME: { - gchar const* icon_name{}; - gtk_image_get_icon_name(image, &icon_name, nullptr); - gtk_drag_set_icon_name(ctx, icon_name, -2, -2); - return true; - } - case GTK_IMAGE_GICON: { -#ifndef __APPLE__ - GIcon* icon{}; - gtk_image_get_gicon(image, &icon, nullptr); - gtk_drag_set_icon_gicon(ctx, icon, -2, -2); - return true; -#else - // Todo (fabian): check, if `gtk_drag_set_icon_gicon` is still unimplemented - g_warning("ToolbarDragDropHelper::gdk_context_set_icon_from_image: GTK_IMAGE_GICON is not handled because " - "`gtk_drag_set_icon_gicon` is not implemented. Please create an issue, if this has changed."); - break; -#endif - } - case GTK_IMAGE_SURFACE: { - cairo_surface_t* surface{}; - g_object_get(G_OBJECT(image), "surface", &surface, nullptr); - cairo_surface_set_device_offset(surface, -2, -2); - gtk_drag_set_icon_surface(ctx, surface); - return true; - } - case GTK_IMAGE_EMPTY: { ///< Does nothing - - g_warning("ToolbarDragDropHelper::gdk_context_set_icon_from_image: Image storage is empty"); - break; - } - case GTK_IMAGE_ICON_SET: { ///< Deprecated - g_warning("ToolbarDragDropHelper::gdk_context_set_icon_from_image: Image storage GTK_IMAGE_ICON_SET is " - "deprecated"); - break; - } - case GTK_IMAGE_STOCK: { ///< Deprecated - g_warning("ToolbarDragDropHelper::gdk_context_set_icon_from_image: Image storage GTK_IMAGE_STOCK is " - "deprecated"); - break; - } - case GTK_IMAGE_ANIMATION: { ///< Can't be handled as we know - g_warning("ToolbarDragDropHelper::gdk_context_set_icon_from_image: Image storage GTK_IMAGE_ANIMATION can't " - "be handled"); - break; - } - } - gtk_drag_set_icon_widget(ctx, widget, -2, -2); - return false; -} - -void dragDestAddToolbar(GtkWidget* target) { - GtkTargetList* targetList = gtk_drag_dest_get_target_list(target); - if (targetList) { - gtk_target_list_ref(targetList); - } else { - targetList = gtk_target_list_new(nullptr, 0); - } - - // If not exist add, else do nothing - if (!gtk_target_list_find(targetList, atomToolItem, nullptr)) { - gtk_target_list_add(targetList, atomToolItem, 0, 0); - } - - gtk_drag_dest_set_target_list(target, targetList); - gtk_target_list_unref(targetList); -} - -void dragSourceAddToolbar(GtkWidget* widget) { - GtkTargetList* targetList = gtk_drag_source_get_target_list(widget); - if (targetList) { - // List contains already this type - if (gtk_target_list_find(targetList, atomToolItem, nullptr)) { - return; - } - - gtk_target_list_ref(targetList); - } else { - targetList = gtk_target_list_new(nullptr, 0); - } - gtk_target_list_add(targetList, atomToolItem, 0, 0); - gtk_drag_source_set_target_list(widget, targetList); - gtk_target_list_unref(targetList); -} -} // namespace ToolbarDragDropHelper diff --git a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHelper.h b/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHelper.h deleted file mode 100644 index f3a6706..0000000 --- a/entry/src/main/cpp/src/core/gui/dialog/toolbarCustomize/ToolbarDragDropHelper.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Xournal++ - * - * Toolbar drag and drop helpers - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GdkAtom, GdkDragContext, _GdkAtom -#include // for GtkWidget, GtkTargetEntry - -namespace ToolbarDragDropHelper { -void dragDestAddToolbar(GtkWidget* target); -void dragSourceAddToolbar(GtkWidget* widget); - -auto gdk_context_set_icon_from_image(GdkDragContext* ctx, GtkWidget* image) -> bool; - -extern const GdkAtom atomToolItem; -extern const GtkTargetEntry dropTargetEntry; -}; // namespace ToolbarDragDropHelper diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/AbstractInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/AbstractInputHandler.cpp deleted file mode 100644 index 4356b8f..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/AbstractInputHandler.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// -// Created by ulrich on 06.04.19. -// - -#include "AbstractInputHandler.h" - -#include - -#include // for gdouble - -#include "control/settings/Settings.h" // for Settings -#include "gui/Layout.h" // for Layout -#include "gui/PageView.h" // for XojPageView -#include "gui/XournalView.h" // for XournalView -#include "gui/XournalppCursor.h" // for XournalppCursor -#include "gui/inputdevices/InputEvents.h" // for InputEvent -#include "gui/inputdevices/PositionInputData.h" // for PositionInputData -#include "gui/widgets/XournalWidget.h" // for GtkXournal -#include "model/Point.h" // for Point, Point::NO_PRE... -#include "util/Assert.h" // for xoj_assert -#include "util/safe_casts.h" // for round_cast - -#include "InputContext.h" // for InputContext - -AbstractInputHandler::AbstractInputHandler(InputContext* inputContext) { this->inputContext = inputContext; } - -AbstractInputHandler::~AbstractInputHandler() = default; - -void AbstractInputHandler::block(bool block) { - if (block == this->blocked) { - return; - } - this->blocked = block; - if (!this->blocked) { - this->onUnblock(); - } else { - this->onBlock(); - } -} - -auto AbstractInputHandler::isBlocked() const -> bool { return this->blocked; } - -auto AbstractInputHandler::handle(InputEvent const& event) -> bool { - if (!this->blocked) { - if (auto* v = this->inputContext->getView(); v) { - v->getCursor()->setInputDeviceClass(event.deviceClass); - } - return this->handleImpl(event); - } - return true; -} - -/** - * Get Page at current position - * - * @return page or nullptr if none - */ -auto AbstractInputHandler::getPageAtCurrentPosition(InputEvent const& event) const -> XojPageView* { - if (!event) { - return nullptr; - } - - GtkXournal* xournal = this->inputContext->getXournal(); - - int x = round_cast(event.relative.x); - int y = round_cast(event.relative.y); - - return xournal->layout->getPageViewAt(x, y); -} - -/** - * Get input data relative to current input page - */ -auto AbstractInputHandler::getInputDataRelativeToCurrentPage(XojPageView* page, InputEvent const& event) const - -> PositionInputData { - xoj_assert(page != nullptr); - - PositionInputData pos = {}; - pos.x = event.relative.x - static_cast(page->getX()); - pos.y = event.relative.y - static_cast(page->getY()); - pos.pressure = Point::NO_PRESSURE; - - if (this->inputContext->getSettings()->isPressureSensitivity()) { - pos.pressure = event.pressure; - } - - pos.state = event.state; - pos.timestamp = event.timestamp; - - pos.deviceId = event.deviceId; - - return pos; -} - -void AbstractInputHandler::onBlock() {} - -void AbstractInputHandler::onUnblock() {} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/AbstractInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/AbstractInputHandler.h deleted file mode 100644 index df9217e..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/AbstractInputHandler.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "PositionInputData.h" // for PositionInputData - -class InputContext; -class XojPageView; -struct InputEvent; - -/** - * Abstract class for a specific input state - */ -class AbstractInputHandler { -private: - bool blocked = false; - -protected: - InputContext* inputContext; - bool inputRunning = false; - -protected: - XojPageView* getPageAtCurrentPosition(InputEvent const& event) const; - PositionInputData getInputDataRelativeToCurrentPage(XojPageView* page, InputEvent const& event) const; - -public: - explicit AbstractInputHandler(InputContext* inputContext); - virtual ~AbstractInputHandler(); - - void block(bool block); - bool isBlocked() const; - virtual void onBlock(); - virtual void onUnblock(); - bool handle(InputEvent const& event); - virtual bool handleImpl(InputEvent const& event) = 0; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/CompassInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/CompassInputHandler.cpp deleted file mode 100644 index f2f03a3..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/CompassInputHandler.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "CompassInputHandler.h" - -#include // for __shared_ptr_access, shar... - -#include "control/CompassController.h" // for CompassController, HYPOTENUSE -#include "control/Control.h" -#include "control/ToolEnums.h" // for TOOL_HAND, TOOL_HIGHLIGHTER -#include "control/ToolHandler.h" // for ToolHandler -#include "gui/XournalView.h" // for XournalView -#include "gui/inputdevices/InputEvents.h" -#include "model/Compass.h" - -constexpr double MIN_HEIGHT = 0.5; -constexpr double MAX_HEIGHT = 10.0; - -CompassInputHandler::CompassInputHandler(XournalView* xournal, GeometryToolController* controller): - GeometryToolInputHandler(xournal, controller) {} - -CompassInputHandler::~CompassInputHandler() noexcept = default; - -auto CompassInputHandler::handlePointer(InputEvent const& event) -> bool { - const auto coords = getCoords(event); - CompassController* compassController = static_cast(controller); - const auto p = compassController->posRelToSide(coords.x, coords.y); - - const auto toolHandler = xournal->getControl()->getToolHandler(); - switch (toolHandler->getToolType()) { - case TOOL_HIGHLIGHTER: - case TOOL_PEN: - if (event.type == BUTTON_PRESS_EVENT) { - if (controller->isInsideGeometryTool(coords.x, coords.y, 0) && - !controller->isInsideGeometryTool(coords.x, coords.y, -0.5)) { - // initialize range - lastProj = std::atan2(-p.y, p.x); - compassController->createOutlineStroke(lastProj); - return true; - } else if (double h = controller->getGeometryTool()->getHeight(); - controller->isInsideGeometryTool(coords.x, coords.y, 0.) && - std::abs(compassController->posRelToSide(coords.x, coords.y).y) <= 0.5 && - std::abs(compassController->posRelToSide(coords.x, coords.y).x - 0.5 * h) <= 0.5 * h) { - compassController->createRadialStroke(std::hypot(p.x, p.y)); - return true; - } - return false; - } else if (event.type == MOTION_EVENT) { - // update range and paint - if (compassController->existsOutlineStroke()) { - auto proj = std::atan2(-p.y, p.x); - proj = lastProj + std::remainder(proj - lastProj, 2 * M_PI); - compassController->updateOutlineStroke(proj); - lastProj = proj; - return true; - } else if (compassController->existsRadialStroke()) { - compassController->updateRadialStroke(std::hypot(p.x, p.y)); - } - return false; - } else if (event.type == BUTTON_RELEASE_EVENT) { - // add stroke to layer and reset - if (compassController->existsOutlineStroke()) { - compassController->finalizeOutlineStroke(); - lastProj = NAN; - return true; - } else if (compassController->existsRadialStroke()) { - compassController->finalizeRadialStroke(); - return true; - } - } - return false; - case TOOL_HAND: - if (event.type == BUTTON_PRESS_EVENT) { - if (!controller->isInsideGeometryTool(coords.x, coords.y, 0)) { - return false; - } else { - sequenceStart(event); - this->handScrolling = true; - return true; - } - } else if (event.type == MOTION_EVENT && this->handScrolling) { - scrollMotion(event); - return true; - } else if (event.type == BUTTON_RELEASE_EVENT && this->handScrolling) { - this->handScrolling = false; - } - default: - return false; - } -} - -auto CompassInputHandler::getMinHeight() const -> double { return MIN_HEIGHT; } -auto CompassInputHandler::getMaxHeight() const -> double { return MAX_HEIGHT; } diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/CompassInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/CompassInputHandler.h deleted file mode 100644 index a7ec15b..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/CompassInputHandler.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * Input handler for the compass. - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "GeometryToolInputHandler.h" - -class Stroke; -class GeometryToolController; -struct InputEvent; - -/** - * @brief Input handler for the compass - * - * Only the pointer handling (mouse / stylus) is defined in this class. - * The rest comes from the GeometryToolHandler - * */ -class CompassInputHandler: public GeometryToolInputHandler { - -public: - explicit CompassInputHandler(XournalView* xournalView, GeometryToolController* controller); - ~CompassInputHandler() noexcept override; - -private: - /** - * @brief handles input from mouse and stylus for the compass - */ - bool handlePointer(InputEvent const& event) override; - - double lastProj = NAN; - - double getMinHeight() const override; - double getMaxHeight() const override; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/DeviceId.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/DeviceId.cpp deleted file mode 100644 index 1a2c36f..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/DeviceId.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "DeviceId.h" - -#include - -DeviceId::DeviceId(const GdkDevice* id): id(id) { - if (id) { - auto source = gdk_device_get_source(const_cast(id)); - trackpointOrTouchpad = source == GDK_SOURCE_TRACKPOINT || source == GDK_SOURCE_TOUCHPAD; - } -} -void DeviceId::reset(const GdkDevice* id) { *this = DeviceId(id); } -DeviceId::operator bool() const { return id != nullptr; } -bool DeviceId::operator==(const DeviceId& o) const { - // For laptops with both touchpad and trackpoint, allow to use the trackpoint buttons above the touchpad - return (id == o.id) || (trackpointOrTouchpad && o.trackpointOrTouchpad); -} -bool DeviceId::operator!=(const DeviceId& o) const { return !(*this == o); } diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/DeviceId.h b/entry/src/main/cpp/src/core/gui/inputdevices/DeviceId.h deleted file mode 100644 index c3248fa..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/DeviceId.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Xournal++ - * - * Device identifier - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include - -struct DeviceId { - constexpr DeviceId() = default; - explicit DeviceId(const GdkDevice* id); - void reset(const GdkDevice* id = nullptr); - explicit operator bool() const; - bool operator==(const DeviceId& o) const; - bool operator!=(const DeviceId& o) const; - -private: - const void* id = nullptr; - bool trackpointOrTouchpad = false; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/GeometryToolInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/GeometryToolInputHandler.cpp deleted file mode 100644 index 6d95bbe..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/GeometryToolInputHandler.cpp +++ /dev/null @@ -1,309 +0,0 @@ -#include "GeometryToolInputHandler.h" - -#include // for max -#include // for atan2, abs, cos, remainder -#include // for __shared_ptr_access, shar... - -#include // for GDK_KEY_Down, GDK_KEY_Left -#include // for g_warning - -#include "control/Control.h" // for Control -#include "control/GeometryToolController.h" // for GeometryToolController -#include "control/ToolEnums.h" // for TOOL_HAND, TOOL_HIGHLIGHTER -#include "control/ToolHandler.h" // for ToolHandler -#include "control/settings/Settings.h" // for Settings -#include "gui/XournalView.h" // for XournalView -#include "gui/inputdevices/InputContext.h" // for InputContext::DeviceType -#include "gui/inputdevices/InputEvents.h" // for InputEvent, BUTTON_PRESS_... -#include "model/Document.h" // for Document -#include "model/Element.h" // for Element, ELEMENT_STROKE -#include "model/GeometryTool.h" // for HALF_CM -#include "model/Layer.h" // for Layer -#include "model/Snapping.h" // for distanceLine -#include "model/Stroke.h" // for Stroke -#include "model/XojPage.h" // for XojPage - -constexpr double MOVE_AMOUNT = HALF_CM / 2.0; -constexpr double MOVE_AMOUNT_SMALL = HALF_CM / 20.0; -constexpr double ROTATE_AMOUNT = M_PI * 5.0 / 180.0; -constexpr double ROTATE_AMOUNT_SMALL = M_PI * 0.2 / 180.0; -constexpr double SCALE_AMOUNT = 1.1; -constexpr double SCALE_AMOUNT_SMALL = 1.01; -constexpr double SNAPPING_DISTANCE_TOLERANCE = 5.0; // pt -constexpr double SNAPPING_ROTATION_TOLERANCE = 3.0 * M_PI / 180.0; // rad -constexpr double ZOOM_DISTANCE_MIN = 0.01; - -GeometryToolInputHandler::GeometryToolInputHandler(XournalView* xournal, GeometryToolController* controller): - xournal(xournal), controller(controller) {} - -GeometryToolInputHandler::~GeometryToolInputHandler() = default; - -auto GeometryToolInputHandler::handle(InputEvent const& event) -> bool { - if (xournal->getSelection() || xournal->getControl()->getTextEditor()) { - return false; - } - const auto device = event.deviceClass; - if ((device == INPUT_DEVICE_MOUSE && isBlocked[InputContext::DeviceType::MOUSE]) || - (device == INPUT_DEVICE_PEN && isBlocked[InputContext::DeviceType::STYLUS]) || - (device == INPUT_DEVICE_TOUCHSCREEN && isBlocked[InputContext::DeviceType::TOUCHSCREEN])) { - return false; // don't intervene - } - - switch (device) { - case INPUT_DEVICE_TOUCHSCREEN: - return this->handleTouchscreen(event); - case INPUT_DEVICE_PEN: - case INPUT_DEVICE_MOUSE: - return this->handlePointer(event); - default: - g_warning("Device class %d not handled by geometry tool", event.deviceClass); - return false; - } -} - -auto GeometryToolInputHandler::handleTouchscreen(InputEvent const& event) -> bool { - // Don't handle more than 2 inputs - if (this->primarySequence && this->primarySequence != event.sequence && this->secondarySequence && - this->secondarySequence != event.sequence) { - return false; - } - if (event.type == BUTTON_PRESS_EVENT) { - // Start scrolling when a sequence starts and we currently have none other - if (this->primarySequence == nullptr && this->secondarySequence == nullptr) { - const xoj::util::Point coords = getCoords(event); - - if (controller->isInsideGeometryTool(coords.x, coords.y, 0)) { - // Set sequence data - this->primarySequence = event.sequence; - sequenceStart(event); - return true; - } else { - return false; - } - - } - // Start zooming as soon as we have two sequences. - else if (this->primarySequence && this->primarySequence != event.sequence && - this->secondarySequence == nullptr) { - this->secondarySequence = event.sequence; - - // Set sequence data - sequenceStart(event); - rotateAndZoomStart(); - return true; - } - } - - if (event.type == MOTION_EVENT && this->primarySequence) { - if (this->secondarySequence) { - rotateAndZoomMotion(event); - return true; - } else if (event.sequence == this->primarySequence) { - scrollMotion(event); - return true; - } - return false; - } - - if (event.type == BUTTON_RELEASE_EVENT) { - if (event.sequence == this->primarySequence) { - // If secondarySequence is nullptr, this sets primarySequence - // to nullptr. If it isn't, then it is now the primary sequence! - this->primarySequence = std::exchange(this->secondarySequence, nullptr); - this->priLastPageRel = this->secLastPageRel; - return true; - } else if (event.sequence == this->secondarySequence) { - this->secondarySequence = nullptr; - return true; - } - } - return false; -} - -auto GeometryToolInputHandler::keyPressed(KeyEvent const& event) -> bool { - double xdir = 0; - double ydir = 0; - double angle = 0.0; - double scale = 1.0; - switch (event.keyval) { - case GDK_KEY_Left: - xdir = -1; - break; - case GDK_KEY_Up: - ydir = -1; - break; - case GDK_KEY_Right: - xdir = 1; - break; - case GDK_KEY_Down: - ydir = 1; - break; - case GDK_KEY_r: - angle = (event.state & GDK_MOD1_MASK) ? -ROTATE_AMOUNT_SMALL : -ROTATE_AMOUNT; - break; - case GDK_KEY_R: // r like "rotate" - angle = (event.state & GDK_MOD1_MASK) ? ROTATE_AMOUNT_SMALL : ROTATE_AMOUNT; - break; - case GDK_KEY_s: - scale = (event.state & GDK_MOD1_MASK) ? SCALE_AMOUNT_SMALL : SCALE_AMOUNT; - break; - case GDK_KEY_S: - scale = (event.state & GDK_MOD1_MASK) ? 1. / SCALE_AMOUNT_SMALL : 1. / SCALE_AMOUNT; - break; - case GDK_KEY_m: - controller->markOrigin(); - return true; - } - - if (xdir != 0 || ydir != 0) { - xoj::util::Point offset; - const double amount = (event.state & GDK_MOD1_MASK) ? MOVE_AMOUNT_SMALL : MOVE_AMOUNT; - if (event.state & GDK_SHIFT_MASK) { - double angle = controller->getGeometryTool()->getRotation(); - const double c = std::cos(angle); - const double s = std::sin(angle); - offset = {amount * (c * xdir - s * ydir), amount * (s * xdir + c * ydir)}; - } else { - offset = {amount * xdir, amount * ydir}; - } - controller->translate(offset); - return true; - } - - if (angle != 0) { - controller->rotate(angle); - return true; - } - if (scale != 1.0) { - const double h = controller->getGeometryTool()->getHeight() * scale; - if (h <= getMaxHeight() && h >= getMinHeight()) { - controller->scale(scale); - return true; - } - } - return false; -} - -void GeometryToolInputHandler::sequenceStart(InputEvent const& event) { - if (event.sequence == this->primarySequence) { - this->priLastPageRel = this->getCoords(event); - } else { - this->secLastPageRel = this->getCoords(event); - } - const auto page = controller->getPage(); - - const Layer* layer = page->getSelectedLayer(); - this->lines.clear(); - Document* doc = xournal->getDocument(); - doc->lock_shared(); - // Performance improvement might be obtained by avoiding filtering all elements each - // time a finger has been put onto the screen - for (const auto& e: layer->getElementsView()) { - if (e->getType() == ELEMENT_STROKE) { - auto* s = dynamic_cast(e); - if (s->getPointCount() == 2) { - lines.push_back(s); - } - } - } - doc->unlock_shared(); -} - -void GeometryToolInputHandler::scrollMotion(InputEvent const& event) { - // Will only be called if there is a single sequence (rotation/zooming handles two sequences) - auto offset = [&]() { - xoj::util::Point coords = this->getCoords(event); - if (event.sequence == this->primarySequence) { - const xoj::util::Point offset = coords - this->priLastPageRel; - this->priLastPageRel = coords; - return offset; - } else { - const xoj::util::Point offset = coords - this->secLastPageRel; - this->secLastPageRel = coords; - return offset; - } - }(); - const auto& origin = controller->getGeometryTool()->getOrigin(); - const auto pos = Point(origin.x + offset.x, origin.y + offset.y); - double minDist = SNAPPING_DISTANCE_TOLERANCE; - double diffAngle{NAN}; - for (const auto& l: lines) { - const Point first = l->getPoint(0); - const Point second = l->getPoint(1); - const double dist = Snapping::distanceLine(pos, first, second); - const double angleLine = std::atan2(second.y - first.y, second.x - first.x); - const double diff = std::remainder(angleLine - controller->getGeometryTool()->getRotation(), M_PI_2); - if (dist < minDist && std::abs(diff) <= SNAPPING_ROTATION_TOLERANCE) { - minDist = dist; - diffAngle = diff; - } - } - if (!std::isnan(diffAngle)) { - controller->rotate(diffAngle, xoj::util::Point(pos.x, pos.y)); - } - controller->translate(offset); -} - -void GeometryToolInputHandler::rotateAndZoomStart() { - this->startZoomDistance = std::max(this->priLastPageRel.distance(this->secLastPageRel), ZOOM_DISTANCE_MIN); - - // Whether we can ignore the zoom portion of the gesture (e.g. distance between touch points - // hasn't changed enough or zoom gestures are disabled). - this->canBlockZoom = true; - - this->lastZoomScrollCenter = (this->priLastPageRel + this->secLastPageRel) / 2.0; - const xoj::util::Point shift = this->secLastPageRel - this->priLastPageRel; - this->lastAngle = atan2(shift.y, shift.x); - this->lastDist = this->startZoomDistance; -} - -void GeometryToolInputHandler::rotateAndZoomMotion(InputEvent const& event) { - if (event.sequence == this->primarySequence) { - this->priLastPageRel = this->getCoords(event); - } else { - this->secLastPageRel = this->getCoords(event); - } - - const double dist = std::max(this->priLastPageRel.distance(this->secLastPageRel), ZOOM_DISTANCE_MIN); - - const double zoomTriggerThreshold = xournal->getControl()->getSettings()->getTouchZoomStartThreshold(); - const double zoomChangePercentage = std::abs(dist - startZoomDistance) / startZoomDistance * 100; - - // Has the touch points moved far enough to trigger a zoom and are zoom gestures enabled? - const bool zoomGesturesEnabled = xournal->getControl()->getSettings()->isZoomGesturesEnabled(); - if (zoomChangePercentage >= zoomTriggerThreshold && zoomGesturesEnabled) { - this->canBlockZoom = false; - } - - const xoj::util::Point center = (this->priLastPageRel + this->secLastPageRel) / 2; - const xoj::util::Point shift = this->secLastPageRel - this->priLastPageRel; - const double angle = atan2(shift.y, shift.x); - - const xoj::util::Point offset = center - lastZoomScrollCenter; - controller->translate(offset); - const double angleIncrease = angle - lastAngle; - const xoj::util::Point centerRel = (this->priLastPageRel + this->secLastPageRel) / 2.0; - if (controller->isInsideGeometryTool(secLastPageRel.x, secLastPageRel.y, 0.0)) { - controller->rotate(angleIncrease, centerRel); - } // allow moving without accidental rotation - const double scaleFactor = dist / lastDist; - const double h = controller->getGeometryTool()->getHeight() * scaleFactor; - - if (!canBlockZoom && h <= getMaxHeight() && h >= getMinHeight()) { - controller->scale(scaleFactor, centerRel); - } - - this->lastZoomScrollCenter = center; - this->lastAngle = angle; - this->lastDist = dist; -} - -auto GeometryToolInputHandler::getCoords(InputEvent const& event) -> xoj::util::Point { - const double zoom = xournal->getZoom(); - const auto view = controller->getView(); - return (event.relative - xoj::util::Point(view->getX(), view->getY())) / zoom; -} - -void GeometryToolInputHandler::blockDevice(InputContext::DeviceType deviceType) { isBlocked[deviceType] = true; } - -void GeometryToolInputHandler::unblockDevice(InputContext::DeviceType deviceType) { isBlocked[deviceType] = false; } diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/GeometryToolInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/GeometryToolInputHandler.h deleted file mode 100644 index d1c0aaf..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/GeometryToolInputHandler.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Xournal++ - * - * Input handler for the geometry tool. - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for map -#include // for vector - -#include // for GdkEventSequence - -#include "util/DispatchPool.h" // for xoj::util::Listener -#include "util/Point.h" // for Point - -#include "InputContext.h" // for InputContext::DeviceType, InputContext - -class Stroke; -class GeometryToolController; -struct InputEvent; -struct KeyEvent; - -/** - * @brief Input handler for the geometry tool - * - * The geometry tool is designed to be used with touch/keyboard with one hand and mouse/stylus with the other hand - * Keyboard and Touch are used to move the geometry tool (and the page), to rotate it and change its size, whereas - * Stylus/Mouse are used to draw/annotate. - * - * The touch handling part is adopted from the TouchInputHandler class - */ -class GeometryToolInputHandler { - -protected: - /** - * @brief the XournalView attached to this handler - */ - XournalView* xournal; - - /** - * @brief the geometry tool controller - * - */ - GeometryToolController* controller; - - /** - * @brief saves which devices are blocked, so they don't need to be handled - * This is currently used for the automatic hand recognition, that can be turned on in the settings - */ - std::map isBlocked{}; - - /** - * @brief the touch event sequence corresponding to the first finger touching the screen - */ - GdkEventSequence* primarySequence{}; - /** - * @brief the touch event sequence corresponding to the second finger touching the screen - */ - GdkEventSequence* secondarySequence{}; - - /** - * @brief the distance between the two fingers touching the screen at the start of a zoom sequence - */ - double startZoomDistance{0.0}; - - /** - * @brief the previous mid point between the two fingers in a zoom sequence - */ - xoj::util::Point lastZoomScrollCenter{}; - - /** - * @brief The current positions of the first (primary) finger and second (secondary) finger in page coordinates - */ - xoj::util::Point priLastPageRel{-1.0, -1.0}; - xoj::util::Point secLastPageRel{-1.0, -1.0}; - - /** - * @brief The previous angle between the line through the positions of the two fingers and the x-axis - */ - double lastAngle{0.0}; - - /** - * @brief The previous distance between the two fingers touching the screen - */ - double lastDist{1.0}; - - /** - * @brief whether resizing the geometry tool can be blocked, because the distance between the fingers hasn't changed - * enough - */ - bool canBlockZoom{false}; - - /** - * @brief whether a scrolling for the hand tool takes place (after touching the geometry tool with the hand tool) - */ - bool handScrolling{false}; - - /** - * @brief the line segments (strokes with two points) of the current layer, that are used for rotation snapping the - * geometry tool - */ - std::vector lines; - -protected: - /** - * @brief initializes an input sequence (right after the first or second finger is put onto the screen) - * @param event the input event initializing the sequence - */ - void sequenceStart(InputEvent const& event); - - /** - * @brief scrolling method - * @param event the current input event - */ - void scrollMotion(InputEvent const& event); - - /** - * @brief start rotating and zooming (after the second finger is put onto the screen) - * only zooms, when zoom gestures are enabled - */ - void rotateAndZoomStart(); - - /** - * @brief rotation and zooming method, only zooms when zoom gestures are enabled - * @param event the current input event - */ - void rotateAndZoomMotion(InputEvent const& event); - - /** - * @brief handles input from the touchscreen for the geometry tool - */ - bool handleTouchscreen(InputEvent const& event); - - /** - * @brief handles input from mouse and stylus for the geometry tool - */ - virtual bool handlePointer(InputEvent const& event) = 0; - - /** - * @brief the document coordinates derived from an input event - * @param event an input event - */ - xoj::util::Point getCoords(InputEvent const& event); - - virtual double getMinHeight() const = 0; - virtual double getMaxHeight() const = 0; - -public: - explicit GeometryToolInputHandler(XournalView* xournalView, GeometryToolController* controller); - virtual ~GeometryToolInputHandler(); - - bool handle(InputEvent const& event); - void blockDevice(InputContext::DeviceType deviceType); - void unblockDevice(InputContext::DeviceType deviceType); - - bool keyPressed(KeyEvent const& event); - // bool keyReleased(KeyEvent const& event); // Implement if needed -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/HandRecognition.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/HandRecognition.cpp deleted file mode 100644 index 5426845..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/HandRecognition.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "HandRecognition.h" - -#include // for strcmp -#include // for all... - -#include "control/settings/Settings.h" // for SEl... -#include "gtk/gtk.h" // for Gtk... -#include "gui/inputdevices/InputEvents.h" // for INP... -#include "gui/inputdevices/touchdisable/TouchDisableCustom.h" // for Tou... -#include "gui/inputdevices/touchdisable/TouchDisableInterface.h" // for Tou... -#include "gui/inputdevices/touchdisable/TouchDisableX11.h" // for Tou... -#include "util/glib_casts.h" // for wrap_v -#include "util/safe_casts.h" // for as_unsigned - -#include "InputContext.h" // for Inp... - -using std::string; - -HandRecognition::HandRecognition(InputContext* inputContext): - inputContext(inputContext), settings(inputContext->getSettings()) { -#ifdef X11_ENABLED - const char* sessionType = g_getenv("XDG_SESSION_TYPE"); - if (sessionType != nullptr && strcmp(sessionType, "x11") == 0) { - x11Session = true; - } -#endif - - reload(); -} - -HandRecognition::~HandRecognition() { - // Enable touchscreen on quit application - if (!touchState && enabled && touchImpl) { - touchImpl->enableTouch(); - } - - delete touchImpl; - touchImpl = nullptr; -} - -/** - * Reload settings - */ -void HandRecognition::reload() { - SElement& touch = settings->getCustomElement("touch"); - - enabled = false; - touch.getBool("disableTouch", enabled); - - if (!enabled) { - delete touchImpl; - touchImpl = nullptr; - return; - } - - disableTimeout = 1000; - touch.getInt("timeout", disableTimeout); - if (disableTimeout < 500) { - disableTimeout = 500; - } - - delete touchImpl; - touchImpl = nullptr; - - string disableMethod; - touch.getString("method", disableMethod); - if (disableMethod == "X11") { - if (!x11Session) { - g_warning("X11 Touch workaround is selected, but no X11 Session running!"); - enabled = false; - return; - } -#ifdef X11_ENABLED - touchImpl = new TouchDisableX11(); -#endif - } else if (disableMethod == "custom") { - string enableCommand; - touch.getString("cmdEnable", enableCommand); - string disableCommand; - touch.getString("cmdDisable", disableCommand); - - touchImpl = new TouchDisableCustom(enableCommand, disableCommand); - } else // Auto detect - { -#ifdef X11_ENABLED - if (x11Session) { - touchImpl = new TouchDisableX11(); - } -#endif - } - - if (touchImpl) { - touchImpl->init(); - } -} - -/** - * Called after the timeout - * - * @return true to call again - */ -auto HandRecognition::enableTimeout(HandRecognition* self) -> bool { - gint64 now = g_get_monotonic_time() / 1000; - gint64 lastPenActionTime = now - self->lastPenAction; - if (lastPenActionTime < 20) { - // Pen action within the last 20ms, so simple restart timeout - return true; - } - - if (lastPenActionTime > self->disableTimeout) { - // Timeout elapsed, enable touch again - self->enableTouch(); - self->touchState = true; - - // Do not call again - self->timer.consume(); - return false; - } - - auto nextTime = static_cast(now - self->lastPenAction + self->disableTimeout); - - self->timer.consume(); - self->timer = g_timeout_add(strict_cast(nextTime), xoj::util::wrap_v, self); - - // Do not call again, a new time is scheduled - return false; -} - -/** - * There was a pen event, restart the timer - */ -void HandRecognition::penEvent() { - lastPenAction = g_get_monotonic_time() / 1000; - - if (touchState) { - touchState = false; - if (enabled) { - disableTouch(); - } - timer = g_timeout_add(strict_cast(disableTimeout), xoj::util::wrap_v, this); - } -} - -/** - * Enable touchscreen - */ -void HandRecognition::enableTouch() { - if (inputContext) { - inputContext->unblockDevice(InputContext::DeviceType::TOUCHSCREEN); - } - if (touchImpl && enabled) { - touchImpl->enableTouch(); - } -} - -/** - * Disable touchscreen - */ -void HandRecognition::disableTouch() { - if (inputContext) { - inputContext->blockDevice(InputContext::DeviceType::TOUCHSCREEN); - } - if (touchImpl) { - touchImpl->disableTouch(); - } -} - -/** - * An event from a device occurred - */ -void HandRecognition::event(InputDeviceClass device) { - if (!enabled) { - return; - } - if (device == INPUT_DEVICE_PEN || device == INPUT_DEVICE_ERASER) { - penEvent(); - } -} - -void HandRecognition::unblock() { - this->enableTouch(); - this->touchState = true; -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/HandRecognition.h b/entry/src/main/cpp/src/core/gui/inputdevices/HandRecognition.h deleted file mode 100644 index 47ccbf5..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/HandRecognition.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Xournal++ - * - * Helper class for Touch specific fixes - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GdkDevice -#include // for gint64 -#include // for GtkWidget - -#include "util/raii/GSourceURef.h" - -#include "InputEvents.h" // for InputDeviceClass - -class Settings; -class TouchDisableInterface; -class InputContext; - -class HandRecognition final { -public: - HandRecognition(InputContext* inputContext); - ~HandRecognition(); - -public: - /** - * Reload settings - */ - void reload(); - - /** - * An event from a device occurred - */ - void event(InputDeviceClass device); - - /** - * Unblock the touchscreen immediately - */ - void unblock(); - -private: - /** - * Called after the timeout - * - * @return true to call again - */ - static bool enableTimeout(HandRecognition* self); - - /** - * There was a pen event, restart the timer - */ - void penEvent(); - - /** - * Enable touchscreen - */ - void enableTouch(); - - /** - * Disable touchscreen - */ - void disableTouch(); - -private: - /** - * If touch disabling is enabled - */ - bool enabled = false; - - /** - * true if touch is enabled, false if disabled - */ - bool touchState = true; - - /** - * When the pen last was seen - */ - gint64 lastPenAction = -1; - - /** - * Timeout in ms - */ - int disableTimeout = 500; - - xoj::util::GSourceURef timer; - - /** - * True if an X11 session is running - */ - bool x11Session = false; - - /** - * Implementation for touch disabling - */ - TouchDisableInterface* touchImpl = nullptr; - - /** - * InputContext - */ - InputContext* inputContext; - - /** - * Settings - */ - Settings* settings = nullptr; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/InputContext.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/InputContext.cpp deleted file mode 100644 index 26e121f..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/InputContext.cpp +++ /dev/null @@ -1,327 +0,0 @@ -// -// Created by ulrich on 06.04.19. -// - -#include "InputContext.h" - -#include // for NULL -#include // for vector - -#include // for g_signal_hand... - -#include "control/Control.h" // for Control -#include "control/DeviceListHelper.h" // for InputDevice -#include "control/settings/Settings.h" // for Settings -#include "gui/XournalView.h" // for XournalView -#include "gui/dialog/DeviceTestingArea.h" // for DeviceTestingArea -#include "gui/inputdevices/GeometryToolInputHandler.h" // for GeometryToolInputHandler -#include "gui/inputdevices/HandRecognition.h" // for HandRecognition -#include "gui/inputdevices/KeyboardInputHandler.h" // for KeyboardInput... -#include "gui/inputdevices/MouseInputHandler.h" // for MouseInputHan... -#include "gui/inputdevices/StylusInputHandler.h" // for StylusInputHa... -#include "gui/inputdevices/TouchDrawingInputHandler.h" // for TouchDrawingI... -#include "gui/inputdevices/TouchInputHandler.h" // for TouchInputHan... -#include "util/Assert.h" // for xoj_assert -#include "util/gdk4_helper.h" -#include "util/glib_casts.h" // for wrap_for_g_callback -#include "util/gtk4_helper.h" - -#include "InputEvents.h" // for InputEvent -#include "config-debug.h" // for DEBUG_INPUT - -#ifdef DEBUG_INPUT -#include "PrintEvent.h" -#endif - -class ScrollHandling; -class ToolHandler; - -InputContext::InputContext(XournalView* view, ScrollHandling* scrollHandling): - view(view), - scrollHandling(scrollHandling), - settings(view->getControl()->getSettings()), - stylusHandler(std::make_unique(this)), - mouseHandler(std::make_unique(this)), - touchDrawingHandler(std::make_unique(this)), - keyboardHandler(std::make_unique(this)), - touchHandler(std::make_unique(this)), - handRecognition(std::make_unique(this)) { - for (const InputDevice& savedDevices: this->view->getControl()->getSettings()->getKnownInputDevices()) { - this->knownDevices.insert(savedDevices.getName()); - } -} - -InputContext::InputContext(Settings* settings, DeviceTestingArea& testing): - view(nullptr), - scrollHandling(nullptr), - settings(settings), - stylusHandler(std::make_unique>(this, DeviceTestingArea::HandlerType::STYLUS, - testing)), - mouseHandler(std::make_unique>(this, DeviceTestingArea::HandlerType::MOUSE, - testing)), - touchHandler(std::make_unique>(this, DeviceTestingArea::HandlerType::TOUCH, - testing)), - handRecognition(std::make_unique(this)) { - for (const InputDevice& savedDevices: settings->getKnownInputDevices()) { - this->knownDevices.insert(savedDevices.getName()); - } -} - -template -static gboolean keyboardCallback(GtkEventControllerKey* self, guint keyval, guint, GdkModifierType state, gpointer d) { - auto* gdkEvent = gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(self)); - KeyEvent e; - e.keyval = keyval; - e.state = static_cast(state & gtk_accelerator_get_default_mod_mask() & - ~gdk_key_event_get_consumed_modifiers(gdkEvent)); - e.sourceEvent = gdkEvent; - return (static_cast(d)->*handler)(e); -} - -InputContext::~InputContext() { - // Destructor is called in xournal_widget_dispose, so it can still accept events - g_signal_handler_disconnect(this->widget, signal_id); -} - -void InputContext::connect(GtkWidget* pWidget, bool connectKeyboardHandler, - std::optional> logfunction) { - xoj_assert(!this->widget && pWidget); - this->widget = pWidget; - gtk_widget_set_support_multidevice(widget, true); - - if (connectKeyboardHandler) { -#if GTK_MAJOR_VERSION == 3 - auto* keyCtrl = gtk_event_controller_key_new(widget); -#else - auto* keyCtrl = gtk_event_controller_key_new(); - gtk_widget_add_controller(keyCtrl); -#endif - - g_signal_connect(keyCtrl, "key-pressed", G_CALLBACK(keyboardCallback<&KeyboardInputHandler::keyPressed>), - keyboardHandler.get()); - g_signal_connect(keyCtrl, "key-released", G_CALLBACK(keyboardCallback<&KeyboardInputHandler::keyReleased>), - keyboardHandler.get()); - } - - int mask = - // Allow scrolling - GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK | - - // Touch / Pen / Mouse - GDK_TOUCH_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_PROXIMITY_IN_MASK | GDK_PROXIMITY_OUT_MASK; - - gtk_widget_add_events(pWidget, mask); - - - if (!logfunction) { - signal_id = - g_signal_connect(pWidget, "event", G_CALLBACK(+[](GtkWidget* widget, GdkEvent* event, gpointer self) { - return static_cast(self)->handle(event); - }), - this); - } else { - struct D { - InputContext* self; - std::function logfunction; - }; - signal_id = g_signal_connect_data( - pWidget, "event", G_CALLBACK(+[](GtkWidget* widget, GdkEvent* event, gpointer d) { - auto* data = static_cast(d); - data->logfunction(event); - return data->self->handle(event); - }), - new D{this, logfunction.value()}, xoj::util::closure_notify_cb, GConnectFlags(0)); - } -} - -auto InputContext::handle(GdkEvent* sourceEvent) -> bool { - printDebug(sourceEvent); - - GdkDevice* sourceDevice = gdk_event_get_source_device(sourceEvent); - if (sourceDevice == NULL) { - return false; - } - - GdkInputSource inputSource = gdk_device_get_source(sourceDevice); - if (inputSource == GDK_SOURCE_KEYBOARD) { - // Keyboard events are handled via the GtkEventControllerKey instance - return false; - } - - InputEvent event = InputEvents::translateEvent(sourceEvent, this->getSettings()); - - // Add the device to the list of known devices if it is currently unknown - if (gdk_device_get_device_type(sourceDevice) != GDK_DEVICE_TYPE_MASTER && - this->knownDevices.find(std::string(event.deviceName)) == this->knownDevices.end()) { - - this->knownDevices.insert(std::string(event.deviceName)); - this->getSettings()->transactionStart(); - auto deviceClassOption = - this->getSettings()->getDeviceClassForDevice(std::string(event.deviceName), inputSource); - this->getSettings()->setDeviceClassForDevice(sourceDevice, deviceClassOption); - this->getSettings()->transactionEnd(); - } - - // We do not handle scroll events manually but let GTK do it for us - if (event.type == SCROLL_EVENT) { - // Hand over to standard GTK Scroll / Zoom handling - return false; - } - - // Deactivate touchscreen when a pen event occurs - this->handRecognition->event(event.deviceClass); - - // separate events to appropriate handlers - // handle geometry tool - if (geometryToolInputHandler && geometryToolInputHandler->handle(event)) { - return true; - } - - // handle tablet stylus - if (event.deviceClass == INPUT_DEVICE_PEN || event.deviceClass == INPUT_DEVICE_ERASER) { - return this->stylusHandler->handle(event); - } - - // handle mouse devices - if (event.deviceClass == INPUT_DEVICE_MOUSE) { - return this->mouseHandler->handle(event); - } - - // handle touchscreens - if (event.deviceClass == INPUT_DEVICE_TOUCHSCREEN) { - bool touchDrawingEnabled = this->getSettings()->getTouchDrawingEnabled(); - - // trigger touch drawing depending on the setting - if (touchDrawingEnabled && this->touchDrawingHandler) { - return this->touchDrawingHandler->handle(event) || this->touchHandler->handle(event); - } - - return this->touchHandler->handle(event); - } - - if (event.deviceClass == INPUT_DEVICE_IGNORE) { - return true; - } - return false; -} - -auto InputContext::getXournal() const -> GtkXournal* { return GTK_XOURNAL(widget); } - -auto InputContext::getView() const -> XournalView* { return view; } - -auto InputContext::getSettings() const -> Settings* { return settings; } - -auto InputContext::getToolHandler() const -> ToolHandler* { return view->getControl()->getToolHandler(); } - -auto InputContext::getScrollHandling() const -> ScrollHandling* { return this->scrollHandling; } - -auto InputContext::getHandRecognition() const -> HandRecognition* { return this->handRecognition.get(); } - -void InputContext::setGeometryToolInputHandler(std::unique_ptr handler) { - this->geometryToolInputHandler = std::move(handler); -} - -auto InputContext::getGeometryToolInputHandler() const -> GeometryToolInputHandler* { - return geometryToolInputHandler.get(); -} - -void InputContext::resetGeometryToolInputHandler() { this->geometryToolInputHandler.reset(); } - -/** - * Focus the widget - */ -void InputContext::focusWidget() { - if (!gtk_widget_has_focus(widget)) { - gtk_widget_grab_focus(widget); - } -} - -void InputContext::blockDevice(InputContext::DeviceType deviceType) { - if (geometryToolInputHandler) { - geometryToolInputHandler->blockDevice(deviceType); - } - switch (deviceType) { - case MOUSE: - this->mouseHandler->block(true); - break; - case STYLUS: - this->stylusHandler->block(true); - break; - case TOUCHSCREEN: - if (this->touchDrawingHandler) { - this->touchDrawingHandler->block(true); - } - this->touchHandler->block(true); - break; - } -} - -void InputContext::unblockDevice(InputContext::DeviceType deviceType) { - if (geometryToolInputHandler) { - geometryToolInputHandler->unblockDevice(deviceType); - } - switch (deviceType) { - case MOUSE: - this->mouseHandler->block(false); - break; - case STYLUS: - this->stylusHandler->block(false); - break; - case TOUCHSCREEN: - if (this->touchDrawingHandler) { - this->touchDrawingHandler->block(false); - } - this->touchHandler->block(false); - break; - } -} - -auto InputContext::isBlocked(InputContext::DeviceType deviceType) -> bool { - switch (deviceType) { - case MOUSE: - return this->mouseHandler->isBlocked(); - case STYLUS: - return this->stylusHandler->isBlocked(); - case TOUCHSCREEN: - return this->touchDrawingHandler && this->touchDrawingHandler->isBlocked(); - } - return false; -} - -void InputContext::printDebug(GdkEvent* event) { -#ifdef DEBUG_INPUT_GDK_PRINT_EVENTS - gdk_set_show_events(true); -#else -#ifdef DEBUG_INPUT - auto print = [&]() { - GdkDevice* device = gdk_event_get_source_device(event); - if (device) { - static constexpr const char* inputClassToString[] = {"INPUT_DEVICE_MOUSE", "INPUT_DEVICE_PEN", - "INPUT_DEVICE_ERASER", "INPUT_DEVICE_TOUCHSCREEN", - "INPUT_DEVICE_IGNORE"}; - InputDeviceClass deviceClass = InputEvents::translateDeviceType(device, this->getSettings()); - std::cout << "Device Class:\t" << inputClassToString[deviceClass] << "\treceived:\n"; - } else { - std::cout << "Device Class:\t: none (source device is NULL)\n"; - } - xoj::input::printGdkEvent(std::cout, event, 0); - }; - -#ifndef DEBUG_INPUT_PRINT_ALL_MOTION_EVENTS - static bool motionEventBlock = false; - if (gdk_event_get_event_type(event) == GDK_MOTION_NOTIFY) { - if (!motionEventBlock) { - motionEventBlock = true; - print(); - } - } else { - motionEventBlock = false; - print(); - } -#else - print(); -#endif // DEBUG_INPUT_PRINT_ALL_MOTION_EVENTS -#endif // DEBUG_INPUT -#endif // DEBUG_INPUT_PRINT_EVENTS -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/InputContext.h b/entry/src/main/cpp/src/core/gui/inputdevices/InputContext.h deleted file mode 100644 index 6e20e47..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/InputContext.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include // for unique_ptr -#include -#include // for set -#include // for string - -#include // for GdkEvent, GdkModifierType -#include // for gulong -#include // for GtkWidget - -#include "gui/widgets/XournalWidget.h" // for GtkXournal - -class GeometryToolInputHandler; -class KeyboardInputHandler; -class MouseInputHandler; -class ScrollHandling; -class Settings; -class StylusInputHandler; -class ToolHandler; -class TouchDrawingInputHandler; -class TouchInputHandler; -class XournalView; -class DeviceTestingArea; -class HandRecognition; - -class InputContext final { - -private: - XournalView* view; - ScrollHandling* scrollHandling; - Settings* settings; - - gulong signal_id{0}; - std::unique_ptr stylusHandler; - std::unique_ptr mouseHandler; - std::unique_ptr touchDrawingHandler; - std::unique_ptr keyboardHandler; - std::unique_ptr touchHandler; - std::unique_ptr geometryToolInputHandler; - - /** - * Helper class for Touch specific fixes - */ - std::unique_ptr handRecognition; - - GtkWidget* widget = nullptr; - - std::set knownDevices; - -public: - enum DeviceType { - MOUSE, - STYLUS, - TOUCHSCREEN, - }; - -public: - InputContext(XournalView* view, ScrollHandling* scrollHandling); - ~InputContext(); - - /// Make an input context for testing purposes - InputContext(Settings* settings, DeviceTestingArea& testing); - -private: - /** - * Handle the events - * @param event The event to handle - * @return Whether the event was handled - */ - bool handle(GdkEvent* event); - - /** - * Print debug output - */ - void printDebug(GdkEvent* event); - -public: - /** - * Connect the input handling to the window to receive events - * - * If logfunction is provided, it will be called on all the received events - */ - void connect(GtkWidget* widget, bool connectKeyboardHandler = true, - std::optional> logfunction = std::nullopt); - - GtkXournal* getXournal() const; - XournalView* getView() const; - ToolHandler* getToolHandler() const; - Settings* getSettings() const; - HandRecognition* getHandRecognition() const; - ScrollHandling* getScrollHandling() const; - void setGeometryToolInputHandler(std::unique_ptr handler); - GeometryToolInputHandler* getGeometryToolInputHandler() const; - void resetGeometryToolInputHandler(); - - void focusWidget(); - void blockDevice(DeviceType deviceType); - void unblockDevice(DeviceType deviceType); - bool isBlocked(DeviceType deviceType); -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/InputEvents.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/InputEvents.cpp deleted file mode 100644 index 5ad3575..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/InputEvents.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// -// Created by ulrich on 17.05.19. -// - -#include "InputEvents.h" - -#include "control/settings/Settings.h" // for Settings -#include "control/settings/SettingsEnums.h" // for InputDeviceTypeOption -#include "util/Point.h" -#include "util/gdk4_helper.h" - -static auto translateEventType(GdkEventType type) -> InputEventType { - switch (type) { - case GDK_MOTION_NOTIFY: - case GDK_TOUCH_UPDATE: - return MOTION_EVENT; - case GDK_BUTTON_PRESS: - case GDK_TOUCH_BEGIN: - return BUTTON_PRESS_EVENT; - case GDK_2BUTTON_PRESS: - return BUTTON_2_PRESS_EVENT; - case GDK_3BUTTON_PRESS: - return BUTTON_3_PRESS_EVENT; - case GDK_BUTTON_RELEASE: - case GDK_TOUCH_END: - case GDK_TOUCH_CANCEL: - return BUTTON_RELEASE_EVENT; - case GDK_ENTER_NOTIFY: - return ENTER_EVENT; - case GDK_LEAVE_NOTIFY: - return LEAVE_EVENT; - case GDK_PROXIMITY_IN: - return PROXIMITY_IN_EVENT; - case GDK_PROXIMITY_OUT: - return PROXIMITY_OUT_EVENT; - case GDK_SCROLL: - return SCROLL_EVENT; - case GDK_GRAB_BROKEN: - return GRAB_BROKEN_EVENT; - default: - // Events we do not care about or handle otherwise (e.g. key events) - return UNKNOWN; - } -} - -auto InputEvents::translateDeviceType(const std::string& name, GdkInputSource source, Settings* settings) - -> InputDeviceClass { - InputDeviceTypeOption deviceType = settings->getDeviceClassForDevice(name, source); - switch (deviceType) { - case InputDeviceTypeOption::Disabled: - return INPUT_DEVICE_IGNORE; - case InputDeviceTypeOption::Mouse: - case InputDeviceTypeOption::MouseKeyboardCombo: - return INPUT_DEVICE_MOUSE; - case InputDeviceTypeOption::Pen: - return INPUT_DEVICE_PEN; - case InputDeviceTypeOption::Eraser: - return INPUT_DEVICE_ERASER; - case InputDeviceTypeOption::Touchscreen: - return INPUT_DEVICE_TOUCHSCREEN; - default: - return INPUT_DEVICE_IGNORE; - } -} - -auto InputEvents::translateDeviceType(GdkDevice* device, Settings* settings) -> InputDeviceClass { - return translateDeviceType(gdk_device_get_name(device), gdk_device_get_source(device), settings); -} - -auto InputEvents::translateEvent(GdkEvent* sourceEvent, Settings* settings) -> InputEvent { - InputEvent targetEvent{}; - - // Map the event type to our internal ones - GdkEventType sourceEventType = gdk_event_get_event_type(sourceEvent); - targetEvent.type = translateEventType(sourceEventType); - - targetEvent.device = gdk_event_get_source_device(sourceEvent); - targetEvent.deviceClass = translateDeviceType(targetEvent.device, settings); - - targetEvent.deviceName = gdk_device_get_name(targetEvent.device); - targetEvent.deviceId = DeviceId(targetEvent.device); - - // Copy both coordinates of the event - gdk_event_get_root_coords(sourceEvent, &targetEvent.absolute.x, &targetEvent.absolute.y); - gdk_event_get_coords(sourceEvent, &targetEvent.relative.x, &targetEvent.relative.y); - - // Copy the event button if there is any - if (targetEvent.type == BUTTON_PRESS_EVENT || targetEvent.type == BUTTON_RELEASE_EVENT) { - gdk_event_get_button(sourceEvent, &targetEvent.button); - } - if (sourceEventType == GDK_TOUCH_BEGIN || sourceEventType == GDK_TOUCH_END || sourceEventType == GDK_TOUCH_CANCEL) { - // As we only handle single finger events we can set the button statically to 1 - targetEvent.button = 1; - } - targetEvent.state = gdk_event_get_modifier_state(sourceEvent); - - // Copy the timestamp - targetEvent.timestamp = gdk_event_get_time(sourceEvent); - - // Copy the pressure data - gdk_event_get_axis(sourceEvent, GDK_AXIS_PRESSURE, &targetEvent.pressure); - - // Copy the event sequence if there is any, and report no pressure - if (sourceEventType == GDK_TOUCH_BEGIN || sourceEventType == GDK_TOUCH_UPDATE || sourceEventType == GDK_TOUCH_END || - sourceEventType == GDK_TOUCH_CANCEL) { - targetEvent.sequence = gdk_event_get_event_sequence(sourceEvent); - targetEvent.pressure = Point::NO_PRESSURE; - } - - return targetEvent; -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/InputEvents.h b/entry/src/main/cpp/src/core/gui/inputdevices/InputEvents.h deleted file mode 100644 index 2b207ad..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/InputEvents.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - -#include // for GdkEvent, gdk_event_free, gdk_event_copy -#include // for gdouble, gchar, guint, guint32 - -#include "model/Point.h" // for Point::NO_PRESSURE -#include "util/Point.h" - -#include "DeviceId.h" - -class Settings; - -enum InputEventType { - UNKNOWN, - BUTTON_PRESS_EVENT, - BUTTON_2_PRESS_EVENT, - BUTTON_3_PRESS_EVENT, - BUTTON_RELEASE_EVENT, - MOTION_EVENT, - ENTER_EVENT, - LEAVE_EVENT, - PROXIMITY_IN_EVENT, - PROXIMITY_OUT_EVENT, - SCROLL_EVENT, - GRAB_BROKEN_EVENT -}; - -enum InputDeviceClass { - INPUT_DEVICE_MOUSE, - INPUT_DEVICE_PEN, - INPUT_DEVICE_ERASER, - INPUT_DEVICE_TOUCHSCREEN, - INPUT_DEVICE_IGNORE -}; - -struct InputEvent final { - /*explicit(false)*/ explicit operator bool() const { return device; } - - GdkDevice* device{nullptr}; ///< Source device. Avoid using if possible. - - InputEventType type{UNKNOWN}; - InputDeviceClass deviceClass{INPUT_DEVICE_IGNORE}; - const gchar* deviceName{}; - - xoj::util::Point absolute; ///< In GdkSurface coordinates - xoj::util::Point relative; ///< In XournalWidget coordinates - - guint button{0}; - GdkModifierType state{}; - gdouble pressure{Point::NO_PRESSURE}; - - GdkEventSequence* sequence{}; - guint32 timestamp{0}; - - DeviceId deviceId; -}; - -struct KeyEvent final { - guint keyval{0}; - GdkModifierType state{}; ///< Consumed modifiers have been masked out - - GdkEvent* sourceEvent; ///< Original GdkEvent. Avoid using if possible. Will be destroyed when the callback returns -}; - -struct InputEvents { - static InputDeviceClass translateDeviceType(GdkDevice* device, Settings* settings); - static InputDeviceClass translateDeviceType(const std::string& name, GdkInputSource source, Settings* settings); - - static InputEvent translateEvent(GdkEvent* sourceEvent, Settings* settings); -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/InputUtils.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/InputUtils.cpp deleted file mode 100644 index e9d0cfa..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/InputUtils.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "InputUtils.h" - -#include // for g_message - -#include "control/ToolEnums.h" // for TOOL_NONE -#include "control/ToolHandler.h" // for ToolHandler -#include "control/settings/ButtonConfig.h" // for ButtonConfig -#include "control/settings/Settings.h" // for Settings -#include "control/settings/SettingsEnums.h" // for Button, BUTTON_TOUCH -#include "util/Assert.h" - - -bool InputUtils::applyButton(ToolHandler* toolHandler, Settings* settings, Button button) { - // if active tool already points to the correct tool nothing needs to be done - if (toolHandler->pointActiveToolToButtonTool(button)) { - ButtonConfig* cfg = settings->getButtonConfig(button); - - xoj_assert(cfg->getAction() != TOOL_NONE); - cfg->applyNoChangeSettings(toolHandler, button); - return true; - } - return false; -} - -bool InputUtils::touchDrawingDisallowed(ToolHandler* toolHandler, Settings* settings) { - static bool warningAlreadyShown{false}; - ButtonConfig* cfg = settings->getButtonConfig(Button::BUTTON_TOUCH); - if (cfg->getDisableDrawing() && cfg->getAction() == TOOL_NONE && toolHandler->isDrawingTool()) { - if (!warningAlreadyShown) - g_message("Ignoring touchscreen for drawing:\n" - " Please check the settings for Touchscreen.\n" - " The current combination of \"Disable Drawing for this device\"\n" - " together with \"Tool - don't change\"\n" - " prevents any drawing with the selected tool using the TouchScreen."); - warningAlreadyShown = true; - return true; - } - // reset warningAlreadyShown this allows the message to be sent multiple times - // in case the user switches the settings in between multiple times - warningAlreadyShown = false; - return false; -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/InputUtils.h b/entry/src/main/cpp/src/core/gui/inputdevices/InputUtils.h deleted file mode 100644 index c6f4074..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/InputUtils.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - * @brief Helper functions in use in the different InputHandlers as for example StylusInputHandler.h - */ - -#pragma once - -#include "control/settings/SettingsEnums.h" - -// forward declaration to avoid cyclic dependencies -class ToolHandler; -class Settings; - -class InputUtils { -public: - /** - * @brief Change the active tool based on the pressed button and its corresponding settings. - * In case the current tool is already selected nothing is done. - * - * @param toolHandler the toolHandler containing the tools - * @param settings settings storing the information for the buttons - * @param button the button pressed - * @return true if the tool was changed as a result of the function. - * @return false if the tool was not changed as it already was pointing to the correct tool. - */ - static bool applyButton(ToolHandler* toolHandler, Settings* settings, Button button); - - /** - * @brief Check whether touch Drawing is disallowed and warn user about this - * Warn the user in case all of the following are true: - * 1. Disable Drawing for this device is set for Touchscreen - * 2. Tool - don't change is set for Touchscreen - * 3. current Tool in the toolbar is a Drawing tool (i.e. Pen/Highlighter/Eraser) - * As this results in xournalpp just using the currently selected tool to draw - * which might be surprising to users. Hence it's logged as warning. - * - * @param toolHandler the toolHandler containing the tools - * @param settings settings storing the information for the buttons - * @return true all above conditions are met - * @return false any of the above conditions is false - */ - static bool touchDrawingDisallowed(ToolHandler* toolHandler, Settings* settings); -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/KeyboardInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/KeyboardInputHandler.cpp deleted file mode 100644 index 74fcbfa..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/KeyboardInputHandler.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "KeyboardInputHandler.h" - -#include "gui/XournalView.h" // for XournalView -#include "gui/inputdevices/GeometryToolInputHandler.h" // for GeometryToolInputHandler - -#include "InputContext.h" // for InputContext -#include "InputEvents.h" // for KeyEvent - -KeyboardInputHandler::KeyboardInputHandler(InputContext* inputContext): inputContext(inputContext) {} - -KeyboardInputHandler::~KeyboardInputHandler() = default; - -bool KeyboardInputHandler::keyPressed(const KeyEvent& e) const { return inputContext->getView()->onKeyPressEvent(e); } - -bool KeyboardInputHandler::keyReleased(const KeyEvent& e) const { - return inputContext->getView()->onKeyReleaseEvent(e); -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/KeyboardInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/KeyboardInputHandler.h deleted file mode 100644 index 81dc570..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/KeyboardInputHandler.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -class InputContext; -struct KeyEvent; - -class KeyboardInputHandler { -private: -public: - explicit KeyboardInputHandler(InputContext* inputContext); - ~KeyboardInputHandler(); - bool keyPressed(const KeyEvent& e) const; - bool keyReleased(const KeyEvent& e) const; - -private: - InputContext* inputContext; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/MouseInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/MouseInputHandler.cpp deleted file mode 100644 index 636bc13..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/MouseInputHandler.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// -// Created by ulrich on 08.04.19. -// - -#include "MouseInputHandler.h" - -#include "control/ToolHandler.h" // for ToolHandler -#include "control/settings/SettingsEnums.h" // for Button, BUTTON_MOUSE_M... -#include "gui/XournalView.h" // for XournalView -#include "gui/XournalppCursor.h" // for XournalppCursor -#include "gui/inputdevices/InputEvents.h" // for InputEvent, BUTTON_PRE... -#include "gui/inputdevices/PenInputHandler.h" // for PenInputHandler -#include "gui/widgets/XournalWidget.h" // for GtkXournal - -#include "InputContext.h" // for InputContext -#include "InputUtils.h" // for InputUtils - -class Settings; -class XojPageView; - -MouseInputHandler::MouseInputHandler(InputContext* inputContext): PenInputHandler(inputContext) {} - -MouseInputHandler::~MouseInputHandler() = default; - -auto MouseInputHandler::handleImpl(InputEvent const& event) -> bool { - // Only handle events when there is no active gesture - GtkXournal* xournal = inputContext->getXournal(); - - // Determine the pressed states of devices and associate them to the current event - setPressedState(event); - - /* - * Trigger start action - */ - // Trigger start of action when pen/mouse is pressed - if (event.type == BUTTON_PRESS_EVENT) { - if (pressedButton == BUTTON_NONE || !inputRunning) { - pressedButton = event.button; - this->actionStart(event); - } else if (event.button == pressedButton) { - g_warning("MouseInputHandler: Double BUTTON_PRESS_EVENT on button %u", event.button); - } - return true; - } - - if (event.type == BUTTON_2_PRESS_EVENT || event.type == BUTTON_3_PRESS_EVENT) { - this->actionPerform(event); - return true; - } - - /* - * Trigger motion actions - */ - // Trigger motion action when pen/mouse is pressed and moved - if (event.type == MOTION_EVENT) // mouse or pen moved - { - this->actionMotion(event); - XournalppCursor* cursor = xournal->view->getCursor(); - cursor->setInvisible(false); - cursor->updateCursor(); - } - - // Notify if mouse enters/leaves widget - if (event.type == ENTER_EVENT) { - this->actionEnterWindow(event); - } - if (event.type == LEAVE_EVENT) { - // this->inputContext->unblockDevice(InputContext::TOUCHSCREEN); - // this->inputContext->getHandRecognition()->unblock(); - this->actionLeaveWindow(event); - } - - // Trigger end of action if mouse button is released - if (event.type == BUTTON_RELEASE_EVENT) { - if (event.button == pressedButton) { - pressedButton = BUTTON_NONE; - this->actionEnd(event); - } - return true; - } - - // If we loose our Grab on the device end the current action - if (event.type == GRAB_BROKEN_EVENT && this->deviceClassPressed) { - // TODO(fabian): We may need to update pressed state manually here - pressedButton = BUTTON_NONE; - this->actionEnd(event); - return true; - } - - return false; -} - -void MouseInputHandler::setPressedState(InputEvent const& event) { - XojPageView* currentPage = getPageAtCurrentPosition(event); - - this->inputContext->getXournal()->view->getCursor()->setInsidePage(currentPage != nullptr); - - if (event.type == BUTTON_PRESS_EVENT) // mouse button pressed or pen touching surface - { - this->deviceClassPressed = true; - - switch (event.button) { - case 2: - this->modifier2 = true; - break; - case 3: - this->modifier3 = true; - default: - break; - } - } - if (event.type == BUTTON_RELEASE_EVENT) // mouse button released or pen not touching surface anymore - { - this->deviceClassPressed = false; - - switch (event.button) { - case 2: - this->modifier2 = false; - break; - case 3: - this->modifier3 = false; - default: - break; - } - } -} - -auto MouseInputHandler::changeTool(InputEvent const& event) -> bool { - Settings* settings = this->inputContext->getSettings(); - ToolHandler* toolHandler = this->inputContext->getToolHandler(); - bool isClickOnSelection = this->inputContext->getXournal()->selection; - bool toolChanged = false; - - if (!isClickOnSelection) { - if (modifier2) { - toolChanged = InputUtils::applyButton(toolHandler, settings, Button::BUTTON_MOUSE_MIDDLE); - } else if (modifier3) { - toolChanged = InputUtils::applyButton(toolHandler, settings, Button::BUTTON_MOUSE_RIGHT); - } else { - toolChanged = InputUtils::applyButton(toolHandler, settings, Button::BUTTON_MOUSE_LEFT); - } - } else { - toolChanged = toolHandler->pointActiveToolToToolbarTool(); - } - - if (toolChanged) { - ToolType toolType = toolHandler->getToolType(); - if (toolType == TOOL_TEXT) { - toolHandler->selectTool(toolType); - } - toolHandler->fireToolChanged(); - } - - return true; -} - -void MouseInputHandler::onBlock() {} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/MouseInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/MouseInputHandler.h deleted file mode 100644 index 289beaf..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/MouseInputHandler.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for guint - -#include "PenInputHandler.h" // for PenInputHandler - -class InputContext; -struct InputEvent; - - -class MouseInputHandler: public PenInputHandler { -private: - void setPressedState(InputEvent const& event); - -public: - explicit MouseInputHandler(InputContext* inputContext); - ~MouseInputHandler() override; - - bool handleImpl(InputEvent const& event) override; - - /** - * @brief Change the tool based on the settings and the Button pressed. - * In case - * - no button is pressed - * - or the settings for that button are "No Toolchange" - * - or the click is happening on top of a selection on the canvas - * this function ensures that the tool selected in the toolbar remains selected. - * - * @param event - * @return true if tool was changed successfully - * @return false if tool was not changed successfully - */ - bool changeTool(InputEvent const& event) override; - void onBlock() override; - -private: - // see button member in https://docs.gtk.org/gdk3/struct.EventButton.html - static constexpr guint BUTTON_NONE = 0; - guint pressedButton = BUTTON_NONE; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/PenInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/PenInputHandler.cpp deleted file mode 100644 index 58b1763..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/PenInputHandler.cpp +++ /dev/null @@ -1,585 +0,0 @@ -// -// Created by ulrich on 06.04.19. -// - -#include "PenInputHandler.h" - -#include // for max, min -#include // for abs, atan, sqrt -#include // for thread -#include // for move - -#include // for gdouble, gint, g_message -#include // for gtk_adjustment_get_value - -#include "control/Control.h" // for Control -#include "control/ToolEnums.h" // for TOOL_HAND, TOOL_IMAGE -#include "control/ToolHandler.h" // for ToolHandler -#include "control/settings/Settings.h" // for Settings -#include "control/tools/CursorSelectionType.h" // for CursorSelectionType -#include "control/tools/EditSelection.h" // for EditSelection -#include "control/zoom/ZoomControl.h" // for ZoomControl -#include "gui/Layout.h" // for Layout -#include "gui/PageView.h" // for XojPageView -#include "gui/XournalView.h" // for XournalView -#include "gui/XournalppCursor.h" // for XournalppCursor -#include "gui/scroll/ScrollHandling.h" // for ScrollHandling -#include "gui/widgets/XournalWidget.h" // for GtkXournal -#include "model/Point.h" // for Point, Point::NO_PRES... -#include "util/Assert.h" // for xoj_assert -#include "util/Point.h" // for Point -#include "util/Util.h" // for execInUiThread -#include "util/safe_casts.h" - -#include "AbstractInputHandler.h" // for AbstractInputHandler -#include "InputContext.h" // for InputContext -#include "PositionInputData.h" // for PositionInputData -#include "config-debug.h" // for DEBUG_INPUT - -#define WIDGET_SCROLL_BORDER 25 - -PenInputHandler::PenInputHandler(InputContext* inputContext): AbstractInputHandler(inputContext) {} - -PenInputHandler::~PenInputHandler() = default; - -void PenInputHandler::updateLastEvent(InputEvent const& event) { - if (!event) { - return; - } - this->lastEvent = event; - if (getPageAtCurrentPosition(event)) { - this->lastHitEvent = event; - } -} - -void PenInputHandler::handleScrollEvent(InputEvent const& event) { - // use root coordinates as reference point because - // scrolling changes window relative coordinates - // see github Gnome/evince@1adce5486b10e763bed869 - - // GTK handles event compression/filtering differently between versions - this may be needed on certain hardware/GTK - // combinations. - if (std::abs((this->scrollStartPosition.x - event.absolute.x)) < 0.1 && - std::abs((this->scrollStartPosition.y - event.absolute.y)) < 0.1) { - return; - } - - if (this->scrollOffsetVector == xoj::util::Point(0., 0.)) { - this->scrollOffsetVector = this->scrollStartPosition - event.absolute; - - Util::execInUiThread([&]() { - this->inputContext->getXournal()->layout->scrollRelative(this->scrollOffsetVector.x, - this->scrollOffsetVector.y); - - // Scrolling done, so reset our counters - this->scrollOffsetVector = xoj::util::Point(0., 0.); - }); - - // Update the reference for the scroll-offset - this->scrollStartPosition = event.absolute; - } -} - -auto PenInputHandler::actionStart(InputEvent const& event) -> bool { - this->inputContext->focusWidget(); - - this->lastActionStartTimeStamp = event.timestamp; - this->sequenceStartPosition = event.absolute; - - XojPageView* currentPage = this->getPageAtCurrentPosition(event); - // set reference data for handling of entering/leaving page - this->updateLastEvent(event); - - // Change the tool depending on the key - if (!changeTool(event)) - return false; - - // Used for pressure inference - this->lastPressure = 0.0; - - // Flag running input - ToolHandler* toolHandler = this->inputContext->getToolHandler(); - ToolType toolType = toolHandler->getToolType(); - - // - if (toolType != TOOL_IMAGE) { - this->inputRunning = true; - } else { - this->deviceClassPressed = false; - } - - this->penInWidget = true; - - GtkXournal* xournal = this->inputContext->getXournal(); - - XournalppCursor* cursor = xournal->view->getCursor(); - cursor->setMouseDown(true); - - - // Save the starting offset when hand-tool is selected to get a reference for the scroll-offset - if (toolType == TOOL_HAND) { - this->scrollStartPosition = event.absolute; - } - - this->sequenceStartPage = currentPage; - - // hand tool don't change the selection, so you can scroll e.g. with your touchscreen without remove the selection - bool changeSelection = xournal->selection && toolHandler->getToolType() != TOOL_HAND; - if ((event.state & GDK_SHIFT_MASK)) { - // When tap single selection is enabled - if (toolHandler->supportsTapFilter() && inputContext->getSettings()->getStrokeFilterEnabled()) { - changeSelection = false; - } - // Selection tools does not change selection with Shift pressed - if (isSelectToolTypeSingleLayer(toolType)) { - changeSelection = false; - } - } - if (changeSelection) { - EditSelection* selection = xournal->selection; - - XojPageView* view = selection->getView(); - PositionInputData selectionPos = this->getInputDataRelativeToCurrentPage(view, event); - - // Check if event modifies selection instead of page - CursorSelectionType selType = - selection->getSelectionTypeForPos(selectionPos.x, selectionPos.y, xournal->view->getZoom()); - if (selType) { - - if (selType == CURSOR_SELECTION_MOVE && modifier3) { - selection->copySelection(); - } - - xournal->selection->mouseDown(selType, selectionPos.x, selectionPos.y); - return true; - } - - xournal->view->clearSelection(); - changeTool(event); - // stop early to prevent drawing when clicking outside of the selection with the intention of deselecting - if (toolHandler->isDrawingTool()) { - return true; - } - } - - // Forward event to page - if (currentPage) { - PositionInputData pos = this->getInputDataRelativeToCurrentPage(currentPage, event); - if (pos.pressure != Point::NO_PRESSURE) { - pressureMode = PressureMode::DEVICE_PRESSURE; - } else if (this->inputContext->getSettings()->isPressureGuessingEnabled()) { - pressureMode = PressureMode::INFERRED_PRESSURE; - } else { - pressureMode = PressureMode::NO_PRESSURE; - } - pos.pressure = this->filterPressure(pos, currentPage); - - return currentPage->onButtonPressEvent(pos); - } - - return true; -} - -double PenInputHandler::inferPressureValue(PositionInputData const& pos, XojPageView* page) { - PositionInputData lastPos = getInputDataRelativeToCurrentPage(page, this->lastEvent); - - double dt = (pos.timestamp - lastPos.timestamp) / 10.0; - double distance = xoj::util::Point(pos.x, pos.y).distance(xoj::util::Point(lastPos.x, lastPos.y)); - double inverseSpeed = dt / (distance + 0.001); - - // This doesn't have to be exact. Arctan is used here for its sigmoid-like shape, - // so that lim inverseSpeed->infinity (newPressure) is some finite value. - double newPressure = 3.142 / 2.0 + std::atan(inverseSpeed * 3.14 - 1.3); - - // This weighted average both smooths abrupt changes in newPressure caused - // by changes to inverseSpeed and causes an initial increase in pressure. - newPressure = std::min(newPressure, 2.0) / 5.0 + this->lastPressure * 4.0 / 5.0; - - // Handle the single-point case. - if (distance == 0) { - newPressure = std::sqrt(dt / 10.0) - 0.1; - } - - this->lastPressure = newPressure; - - // Final pressure tweaks... - return (newPressure * 1.1 + 0.8) / 2.0; -} - -double PenInputHandler::filterPressure(PositionInputData const& pos, XojPageView* page) { - if (pressureMode == PressureMode::NO_PRESSURE) { - return Point::NO_PRESSURE; - } - - double filteredPressure; - if (pressureMode == PressureMode::INFERRED_PRESSURE) { - filteredPressure = inferPressureValue(pos, page); - } else { - xoj_assert(pressureMode == PressureMode::DEVICE_PRESSURE); - /** - * On some devices, the pressure value of some events is missing. Use the last recorded pressure value then. - */ - if (pos.pressure == Point::NO_PRESSURE) { - g_debug("Pressure-sensitive device omitted pressure this time"); - filteredPressure = lastPressure; - } else { - filteredPressure = pos.pressure; - lastPressure = pos.pressure; // Record in case the pressure value is omitted in the next event - } - } - - Settings* settings = this->inputContext->getSettings(); - xoj_assert(settings->getMinimumPressure() >= 0.01); - return std::max(settings->getMinimumPressure(), filteredPressure * settings->getPressureMultiplier()); -} - -bool PenInputHandler::isCurrentTapSelection(InputEvent const& event) const { - if (!inputContext->getToolHandler()->supportsTapFilter()) { - return false; - } - - auto* settings = inputContext->getSettings(); - if (!settings->getStrokeFilterEnabled()) { - return false; - } - - int tapMaxDuration = 0, filterRepetitionTime = 0; - double tapMaxDistance = NAN; // in mm - - settings->getStrokeFilter(&tapMaxDuration, &tapMaxDistance, &filterRepetitionTime); - - const double dpmm = inputContext->getView()->getControl()->getZoomControl()->getZoom100Value() * - Util::DPI_NORMALIZATION_FACTOR / 25.4; - const double dist = this->sequenceStartPosition.distance(event.absolute); - - const bool noMovement = dist < tapMaxDistance * dpmm; - const bool fastEnoughTap = event.timestamp - this->lastActionStartTimeStamp < as_unsigned(tapMaxDuration); - const bool notAnAftershock = event.timestamp - this->lastActionEndTimeStamp > as_unsigned(filterRepetitionTime); - - auto* selection = inputContext->getView()->getSelection(); - const bool notInSelectionDeleteButton = !selection || !selection->isDeleting(); - - return noMovement && fastEnoughTap && notAnAftershock && notInSelectionDeleteButton; -} - -auto PenInputHandler::actionMotion(InputEvent const& event) -> bool { - /* - * Workaround for misbehaving devices where Enter events are not published every time - * This is required to disable outside scrolling again - */ - gdouble eventX = event.relative.x; - gdouble eventY = event.relative.y; - - GtkAdjustment* adjHorizontal = this->inputContext->getScrollHandling()->getHorizontal(); - GtkAdjustment* adjVertical = this->inputContext->getScrollHandling()->getVertical(); - double h = gtk_adjustment_get_value(adjHorizontal); - double v = gtk_adjustment_get_value(adjVertical); - eventX -= h; - eventY -= v; - - GtkWidget* widget = gtk_widget_get_parent(this->inputContext->getView()->getWidget()); - gint width = gtk_widget_get_allocated_width(widget); - gint height = gtk_widget_get_allocated_height(widget); - - if (!this->penInWidget && eventX > WIDGET_SCROLL_BORDER && eventY > WIDGET_SCROLL_BORDER && - eventX < width - WIDGET_SCROLL_BORDER && eventY < height - WIDGET_SCROLL_BORDER) { - this->penInWidget = true; - } - - - GtkXournal* xournal = this->inputContext->getXournal(); - ToolHandler* toolHandler = this->inputContext->getToolHandler(); - - this->changeTool(event); - - if (toolHandler->getToolType() == TOOL_HAND) { - if (this->deviceClassPressed) { - this->handleScrollEvent(event); - return true; - } - return false; - } - - bool isShiftDown = (event.state & GDK_SHIFT_MASK); - bool handleSelectionMove = xournal->selection != nullptr; - - if (xournal->selection && isSelectToolTypeSingleLayer(toolHandler->getToolType()) && - !xournal->selection->isMoving()) { - if (isShiftDown || this->deviceClassPressed) { - handleSelectionMove = false; - // Cursor mode to match the multiple-selection mode - xournal->view->getCursor()->setMouseSelectionType(CURSOR_SELECTION_NONE); - } - } - - if (handleSelectionMove) { - EditSelection* selection = xournal->selection; - XojPageView* view = selection->getView(); - - PositionInputData pos = this->getInputDataRelativeToCurrentPage(view, event); - - if (xournal->selection->isMoving()) { - selection->mouseMove(pos.x, pos.y, pos.isAltDown()); - } else if (!isShiftDown) { - CursorSelectionType selType = selection->getSelectionTypeForPos(pos.x, pos.y, xournal->view->getZoom()); - xournal->view->getCursor()->setMouseSelectionType(selType); - } - return true; - } - - // Check if page was left / entered - XojPageView* lastEventPage = getPageAtCurrentPosition(this->lastEvent); - XojPageView* lastHitEventPage = getPageAtCurrentPosition(this->lastHitEvent); - XojPageView* currentPage = getPageAtCurrentPosition(event); - - if (!toolHandler->isSinglePageTool()) { - /* - * Get all events where the input sequence moved from one page to another without stopping the input. - * Only trigger once the new page was entered to ensure that an input device can leave the page temporarily. - * For these events we need to fake an end point in the old page and a start point in the new page. - */ - if (this->deviceClassPressed && currentPage && currentPage != sequenceStartPage && lastHitEventPage) { -#ifdef DEBUG_INPUT - g_message("PenInputHandler: Start new input on switching page..."); -#endif - this->actionEnd(this->lastHitEvent); - this->updateLastEvent(event); - - bool result = this->actionStart(event); - this->updateLastEvent(event); - return result; - } - /* - * Get all events where the input sequence started outside of a page and moved into one. - * For these events we need to fake a start point in the current page. - */ - if (this->deviceClassPressed && currentPage && !lastEventPage && !lastHitEventPage) { -#ifdef DEBUG_INPUT - g_message("PenInputHandler: Start new input on entering page..."); -#endif - bool result = this->actionStart(event); - this->updateLastEvent(event); - return result; - } - } - - // Update the cursor - xournal->view->getCursor()->setInsidePage(currentPage != nullptr); - - // Selections and single-page elements will always work on one page so we need to handle them differently - if (this->sequenceStartPage && toolHandler->isSinglePageTool()) { - // Relay the event to the page - PositionInputData pos = getInputDataRelativeToCurrentPage(sequenceStartPage, event); - - if (!toolHandler->acceptsOutOfPageEvents()) { - // Enforce input to stay within page - pos.x = std::clamp(pos.x, 0.0, static_cast(sequenceStartPage->getDisplayWidth())); - pos.y = std::clamp(pos.y, 0.0, static_cast(sequenceStartPage->getDisplayHeight())); - } - - pos.pressure = this->filterPressure(pos, sequenceStartPage); - - bool result = sequenceStartPage->onMotionNotifyEvent(pos); - - this->updateLastEvent(event); // Update the last position of the input device - return result; - } - - if (currentPage && this->penInWidget) { - // Relay the event to the page - PositionInputData pos = getInputDataRelativeToCurrentPage(currentPage, event); - pos.pressure = this->filterPressure(pos, currentPage); - - bool result = currentPage->onMotionNotifyEvent(pos); - - this->updateLastEvent(event); // Update the last position of the input device - return result; - } - - this->updateLastEvent(event); // Update the last position of the input device - return false; -} - -auto PenInputHandler::actionEnd(InputEvent const& event) -> bool { - GtkXournal* xournal = inputContext->getXournal(); - XournalppCursor* cursor = xournal->view->getCursor(); - ToolHandler* toolHandler = inputContext->getToolHandler(); - EditSelection* selection = xournal->view->getSelection(); - - cursor->setMouseDown(false); - - bool cancelAction = isCurrentTapSelection(event); - - // Holding shift (with selections) also does not imply drawing - if (toolHandler->supportsTapFilter()) { - if (inputContext->getSettings()->getStrokeFilterEnabled()) { - // Tapping/Clicking in the selection delete button should still delete the selection - cancelAction |= (event.state & GDK_SHIFT_MASK) && xournal->selection != nullptr && !selection->isDeleting(); - } - } - - if (cancelAction) { - // Cancel the sequence and trigger the necessary action - XojPageView* pageUnderTap = this->sequenceStartPage ? this->sequenceStartPage : getPageAtCurrentPosition(event); - if (pageUnderTap) { - PositionInputData pos = getInputDataRelativeToCurrentPage(pageUnderTap, event); - pageUnderTap->onSequenceCancelEvent(pos.deviceId); - pageUnderTap->onTapEvent(pos); - } - this->sequenceStartPage = nullptr; - this->inputRunning = false; - this->lastActionEndTimeStamp = event.timestamp; - return false; - } - this->lastActionEndTimeStamp = event.timestamp; - - if (selection) { - selection->mouseUp(); - } - - // Selections and single-page elements will always work on one page so we need to handle them differently - if (this->sequenceStartPage && toolHandler->isSinglePageTool()) { - PositionInputData pos = getInputDataRelativeToCurrentPage(this->sequenceStartPage, event); - pos.pressure = this->filterPressure(pos, this->sequenceStartPage); - - this->sequenceStartPage->onButtonReleaseEvent(pos); - } else { - // Relay the event to the page - XojPageView* currentPage = getPageAtCurrentPosition(event); - - /* - * Use the last active page if you can't find a page under the cursor position. - * This is a workaround for input leaving the page while being active and then stopping outside. - */ - if (!currentPage) { - if (!this->lastHitEvent) { - return false; - } - currentPage = getPageAtCurrentPosition(this->lastHitEvent); - } - - if (currentPage) { - PositionInputData pos = getInputDataRelativeToCurrentPage(currentPage, event); - pos.pressure = this->filterPressure(pos, currentPage); - - currentPage->onButtonReleaseEvent(pos); - } - } - - // Reset the selection - EditSelection* tmpSelection = xournal->selection; - xournal->selection = nullptr; - this->sequenceStartPage = nullptr; - - if (toolHandler->pointActiveToolToToolbarTool()) { - toolHandler->fireToolChanged(); - } - - // we need this workaround so it's possible to select something with the middle button - if (tmpSelection) { - xournal->view->setSelection(tmpSelection); - } - - this->inputRunning = false; - - return false; -} - -void PenInputHandler::actionPerform(InputEvent const& event) { -#ifdef DEBUG_INPUT - g_message("Discrete input action; modifier1=%s, modifier2=%s", this->modifier2 ? "true" : "false", - this->modifier3 ? "true" : "false"); -#endif - - XojPageView* currentPage = this->getPageAtCurrentPosition(event); - if (currentPage == nullptr) { - return; - } - - PositionInputData pos = this->getInputDataRelativeToCurrentPage(currentPage, event); - if (event.type == BUTTON_2_PRESS_EVENT) { - currentPage->onButtonDoublePressEvent(pos); - } else if (event.type == BUTTON_3_PRESS_EVENT) { - currentPage->onButtonTriplePressEvent(pos); - } -} - -void PenInputHandler::actionLeaveWindow(InputEvent const& event) { - if (!this->penInWidget) { - return; - } - - if (!this->inputContext->getSettings()->getInputSystemDrawOutsideWindowEnabled()) { - this->penInWidget = false; - } - - // Stop input sequence if the tool is not a selection tool - ToolHandler* toolHandler = this->inputContext->getToolHandler(); - if (this->inputRunning && !toolHandler->isSinglePageTool()) { - if (!this->inputContext->getSettings()->getInputSystemDrawOutsideWindowEnabled()) { - this->actionEnd(this->lastHitEvent); - } - } else if (this->deviceClassPressed) { - // scroll if we have an active selection - gdouble eventX = event.relative.x; - gdouble eventY = event.relative.y; - - GtkAdjustment* adjHorizontal = this->inputContext->getScrollHandling()->getHorizontal(); - GtkAdjustment* adjVertical = this->inputContext->getScrollHandling()->getVertical(); - double h = gtk_adjustment_get_value(adjHorizontal); - double v = gtk_adjustment_get_value(adjVertical); - eventX -= h; - eventY -= v; - - GtkWidget* widget = gtk_widget_get_parent(this->inputContext->getView()->getWidget()); - gint width = gtk_widget_get_allocated_width(widget); - gint height = gtk_widget_get_allocated_height(widget); - - new std::thread([&, eventX, eventY, width, height]() { - int offsetX = 0, offsetY = 0; - - // TODO(fabian): make offset dependent on how big the distance between pen and view is - if (eventX < WIDGET_SCROLL_BORDER) { - offsetX = -10; - } - - if (eventY < WIDGET_SCROLL_BORDER) { - offsetY = -10; - } - - if (eventX > width - WIDGET_SCROLL_BORDER) { - offsetX = 10; - } - - if (eventY > height - WIDGET_SCROLL_BORDER) { - offsetY = 10; - } - -#ifdef DEBUG_INPUT - g_message("Offset: X:%d\tY:%d", offsetX, offsetY); -#endif - - while (!this->penInWidget) { - Util::execInUiThread([&]() { - GtkXournal* xournal = this->inputContext->getXournal(); - xournal->layout->scrollRelative(offsetX, offsetY); - }); - - // sleep for half a second until we scroll again - g_usleep(static_cast(0.5 * G_USEC_PER_SEC)); - } - }); - } -} - -void PenInputHandler::actionEnterWindow(InputEvent const& event) { - this->penInWidget = true; - - if (!this->inputContext->getSettings()->getInputSystemDrawOutsideWindowEnabled()) { - // Restart input sequence if the tool is pressed and not a single-page tool - ToolHandler* toolHandler = this->inputContext->getToolHandler(); - if (this->deviceClassPressed && !toolHandler->isSinglePageTool()) { - this->actionStart(event); - } - } -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/PenInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/PenInputHandler.h deleted file mode 100644 index 042002a..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/PenInputHandler.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "gui/inputdevices/InputEvents.h" // for InputEvent -#include "util/Point.h" - -#include "AbstractInputHandler.h" // for AbstractInputHandler - -class InputContext; -class PositionInputData; -class XojPageView; - -enum class PressureMode { NO_PRESSURE, DEVICE_PRESSURE, INFERRED_PRESSURE }; - -class PenInputHandler: public AbstractInputHandler { -protected: - /** - * Whether the current device class has a device with button 1 in pressed state - */ - bool deviceClassPressed = false; - /** - * modifier variables storing whether button 2 and 3 are pressed - */ - bool modifier2 = false; - bool modifier3 = false; - - /** - * Reference to the last event - */ - InputEvent lastEvent{}; - - PressureMode pressureMode{PressureMode::NO_PRESSURE}; - - /** - * Last pressure measured or inferred. - */ - double lastPressure{0.0}; - - /** - * Reference to the last event actually hitting a page - */ - InputEvent lastHitEvent{}; - - /** - * Start position to reference scroll offset - */ - xoj::util::Point scrollStartPosition{0., 0.}; - - /** - * The scroll offset vector - */ - xoj::util::Point scrollOffsetVector{0., 0.}; - - /** - * Flag whether pen is within the widget - */ - bool penInWidget = false; - - /** - * Page a selection started at as we require this for motion updates - */ - XojPageView* sequenceStartPage = nullptr; - - /** - * For tap event filtering. See Preferences->Drawing Area->Action on Tool Tap - */ - guint32 lastActionEndTimeStamp = 0U; - guint32 lastActionStartTimeStamp = 0U; - xoj::util::Point sequenceStartPosition; - -public: - explicit PenInputHandler(InputContext* inputContext); - ~PenInputHandler() override; - -protected: - /** - * Action for the start of an input - * @param event The event triggering the action - */ - bool actionStart(InputEvent const& event); - - /** - * Action for motion during an input - * @param event The event triggering the action - */ - bool actionMotion(InputEvent const& event); - - /** - * Action for a discrete input. - */ - void actionPerform(InputEvent const& event); - - void actionLeaveWindow(InputEvent const& event); - void actionEnterWindow(InputEvent const& event); - - /** - * Action for the end of an input - * @param event The event triggering the action - */ - bool actionEnd(InputEvent const& event); - - /** - * @brief Change the tool according to the InputHandler and buttons pressed - * - * @param event some Inputevent - * @return true if tool was changed successfully - * @return false if tool was not changed successfully (currently only in TouchDrawingInputHandler) - */ - virtual bool changeTool(InputEvent const& event) = 0; - - /** - * Do the scrolling with the hand tool - */ - void handleScrollEvent(InputEvent const& event); - - /** - * Stores references to the provided event in lastEvent and lastHitEvent - * Use this to update the references for the last event. - * lastHitEvent will only be updated when the event did hit a page - * @param event - */ - void updateLastEvent(InputEvent const& event); - - /** - * Estimate pressure based on pen speed using the previous event. - * - * @param pos The position of the current event - * @param page The page the event is relative to. - * @return The filtered pressure. - */ - double inferPressureValue(PositionInputData const& pos, XojPageView* page); - - /** - * @brief Apply filters (e.g. minimum pressure, pressure inference, etc.) to - * the pressure at pos. - * - * @param pos The position of the current event - * @param page The page the event is relative to - * @return The filtered pressure. - */ - double filterPressure(PositionInputData const& pos, XojPageView* page); - - /** - * @brief Detects whether the current input event is to be used as a selection - * rather than drawing - */ - bool isCurrentTapSelection(InputEvent const& event) const; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/PositionInputData.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/PositionInputData.cpp deleted file mode 100644 index 0a30153..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/PositionInputData.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "PositionInputData.h" - -auto PositionInputData::isShiftDown() const -> bool { return state & GDK_SHIFT_MASK; } - -auto PositionInputData::isControlDown() const -> bool { return state & GDK_CONTROL_MASK; } - -auto PositionInputData::isAltDown() const -> bool { return state & GDK_MOD1_MASK; } diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/PositionInputData.h b/entry/src/main/cpp/src/core/gui/inputdevices/PositionInputData.h deleted file mode 100644 index 5bf96c4..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/PositionInputData.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Xournal++ - * - * Base class for device input handling - * Data to do an input - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GdkModifierType -#include // for guint32 - -#include "DeviceId.h" - -class PositionInputData { -public: - bool isShiftDown() const; - bool isControlDown() const; - bool isAltDown() const; - -public: - double x; - double y; - double pressure; - guint32 timestamp; - DeviceId deviceId; - - /** - * State flags from GDKevent (Shift down etc.) - */ - GdkModifierType state; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/PrintEvent.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/PrintEvent.cpp deleted file mode 100644 index cecf183..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/PrintEvent.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "PrintEvent.h" - -#include -#include - -using namespace xoj::input; - - -struct TimeToReadable { - guint32 ts; - guint32 reference; -}; -template -static StreamType& operator<<(StreamType& str, TimeToReadable t) { - if (t.ts > t.reference) { - static constexpr guint32 SECOND = 1000; - static constexpr guint32 MINUTE = 60 * SECOND; - static constexpr guint32 HOUR = 60 * MINUTE; - - guint32 diff = t.ts - t.reference; - auto h = diff / HOUR; - auto m = (diff % HOUR) / MINUTE; - auto s = (diff % MINUTE) / SECOND; - auto ms = diff % SECOND; - - auto fill = str.fill(); - str.fill('0'); - str << h << ":" << std::setw(2) << m << ":" << std::setw(2) << s << "." << std::setw(3) << ms; - str.fill(fill); - } else { - str << "Erronous value"; - } - str << " (" << t.ts << ")"; - return str; -} - -void xoj::input::printEvent(std::ostream& str, const InputEvent& e, guint32 referenceTime) { - static constexpr const char* deviceClassToString[] = {"INPUT_DEVICE_MOUSE", "INPUT_DEVICE_PEN", - "INPUT_DEVICE_ERASER", "INPUT_DEVICE_TOUCHSCREEN", - "INPUT_DEVICE_IGNORE"}; - - static constexpr const char* inputEventTypeToString[] = {"UNKNOWN", - "BUTTON_PRESS_EVENT", - "BUTTON_2_PRESS_EVENT", - "BUTTON_3_PRESS_EVENT", - "BUTTON_RELEASE_EVENT", - "MOTION_EVENT", - "ENTER_EVENT", - "LEAVE_EVENT", - "PROXIMITY_IN_EVENT", - "PROXIMITY_OUT_EVENT", - "SCROLL_EVENT", - "GRAB_BROKEN_EVENT"}; - - static constexpr const char* gdkInputSources[] = { - "GDK_SOURCE_MOUSE", "GDK_SOURCE_PEN", "GDK_SOURCE_ERASER", - "GDK_SOURCE_CURSOR", "GDK_SOURCE_KEYBOARD", "GDK_SOURCE_TOUCHSCREEN", - "GDK_SOURCE_TOUCHPAD", "GDK_SOURCE_TRACKPOINT", "GDK_SOURCE_TABLET_PAD"}; - - str << "Device " << e.device << ": " << deviceClassToString[e.deviceClass] << " - Name: " << e.deviceName << "\n"; - str << " Timestamp: " << TimeToReadable{e.timestamp, referenceTime} << "\n"; - str << " GdkInputSource: " << gdkInputSources[gdk_device_get_source(e.device)] << "\n"; - str << " EvType: " << inputEventTypeToString[e.type] << "\n"; - str << " Button: " << e.button << "\n"; - str << " Touch Seq.: " << e.sequence << "\n"; - str << " x: " << e.absolute.x << " y: " << e.absolute.y << " pressure: " << e.pressure << "\n"; - str << " State: " << std::bitset<8 * sizeof(decltype(e.state))>(e.state) << std::endl; -} - -void xoj::input::printGdkEvent(std::ostream& str, GdkEvent* e, guint32 referenceTime) { - static constexpr const char* gdkInputSources[] = { - "GDK_SOURCE_MOUSE ", "GDK_SOURCE_PEN ", "GDK_SOURCE_ERASER ", - "GDK_SOURCE_CURSOR ", "GDK_SOURCE_KEYBOARD ", "GDK_SOURCE_TOUCHSCREEN", - "GDK_SOURCE_TOUCHPAD ", "GDK_SOURCE_TRACKPOINT ", "GDK_SOURCE_TABLET_PAD "}; - - /// Indexes are shifted by 1 because GDK_NOTHING == -1 - static constexpr const char* gdkEventTypeWithIndexShiftedByOne[] = {"GDK_NOTHING", - "GDK_DELETE", - "GDK_DESTROY", - "GDK_EXPOSE", - "GDK_MOTION_NOTIFY", - "GDK_BUTTON_PRESS", - "GDK_DOUBLE_BUTTON_PRESS", - "GDK_TRIPLE_BUTTON_PRESS", - "GDK_BUTTON_RELEASE", - "GDK_KEY_PRESS", - "GDK_KEY_RELEASE", - "GDK_ENTER_NOTIFY", - "GDK_LEAVE_NOTIFY", - "GDK_FOCUS_CHANGE", - "GDK_CONFIGURE", - "GDK_MAP", - "GDK_UNMAP", - "GDK_PROPERTY_NOTIFY", - "GDK_SELECTION_CLEAR", - "GDK_SELECTION_REQUEST", - "GDK_SELECTION_NOTIFY", - "GDK_PROXIMITY_IN", - "GDK_PROXIMITY_OUT", - "GDK_DRAG_ENTER", - "GDK_DRAG_LEAVE", - "GDK_DRAG_MOTION", - "GDK_DRAG_STATUS", - "GDK_DROP_START", - "GDK_DROP_FINISHED", - "GDK_CLIENT_EVENT", - "GDK_VISIBILITY_NOTIFY", - "UNKNOWN_GAP_IN_GDK_EVENT_TYPE_ENUM", - "GDK_SCROLL", - "GDK_WINDOW_STATE", - "GDK_SETTING", - "GDK_OWNER_CHANGE", - "GDK_GRAB_BROKEN", - "GDK_DAMAGE", - "GDK_TOUCH_BEGIN", - "GDK_TOUCH_UPDATE", - "GDK_TOUCH_END", - "GDK_TOUCH_CANCEL", - "GDK_TOUCHPAD_SWIPE", - "GDK_TOUCHPAD_PINCH", - "GDK_PAD_BUTTON_PRESS", - "GDK_PAD_BUTTON_RELEASE", - "GDK_PAD_RING", - "GDK_PAD_STRIP", - "GDK_PAD_GROUP_MODE"}; - - static constexpr const char* gdkScrollDirection[] = { - "GDK_SCROLL_UP", "GDK_SCROLL_DOWN", "GDK_SCROLL_LEFT", "GDK_SCROLL_RIGHT", "GDK_SCROLL_SMOOTH", - }; - - str << "Event: " << e << "\n"; - str << " Timestamp: " << TimeToReadable{gdk_event_get_time(e), referenceTime} << "\n"; - str << " Type: " << gdkEventTypeWithIndexShiftedByOne[gdk_event_get_event_type(e) + 1] << "\n"; - if (GdkDevice* d = gdk_event_get_device(e); d) { - str << " Device: " << d << " : " << gdkInputSources[gdk_device_get_source(d)] << " -- " - << gdk_device_get_name(d) << "\n"; - } - if (GdkDevice* d = gdk_event_get_source_device(e); d) { - str << " Source dev: " << d << " : " << gdkInputSources[gdk_device_get_source(d)] << " -- " - << gdk_device_get_name(d) << "\n"; - } - if (GdkDeviceTool* t = gdk_event_get_device_tool(e); t) { - str << " DeviceTool: " << t << "\n"; - } - if (guint btn; gdk_event_get_button(e, &btn)) { - str << " Button: " << btn << "\n"; - } - if (guint key; gdk_event_get_keyval(e, &key)) { - str << " Key: " << key << "\n"; - } - if (guint clickcount; gdk_event_get_click_count(e, &clickcount)) { - str << " Click count: " << clickcount << "\n"; - } - if (auto* seq = gdk_event_get_event_sequence(e); seq) { - str << " Sequence: " << seq << "\n"; - } - if (GdkModifierType state; gdk_event_get_state(e, &state)) { - str << " State: " << std::bitset<8 * sizeof(decltype(state))>(state) << std::endl; - } - if (double x, y; gdk_event_get_coords(e, &x, &y)) { - str << " Coords: " << x << " " << y << "\n"; - } - if (double p; gdk_event_get_axis(e, GDK_AXIS_PRESSURE, &p)) { - str << " Pressure: " << p << "\n"; - } - if (GdkScrollDirection dir; gdk_event_get_scroll_direction(e, &dir)) { - str << " ScrollDir: " << gdkScrollDirection[dir] << "\n"; - } - if (double dx, dy; gdk_event_get_scroll_deltas(e, &dx, &dy)) { - str << " ScrollDelta: " << dx << " " << dy << "\n"; - } -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/PrintEvent.h b/entry/src/main/cpp/src/core/gui/inputdevices/PrintEvent.h deleted file mode 100644 index d881532..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/PrintEvent.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include - -#include "InputEvents.h" - -namespace xoj::input { -void printEvent(std::ostream& str, const InputEvent& e, guint32 timeRef); -void printGdkEvent(std::ostream& str, GdkEvent* e, guint32 timeRef); -}; // namespace xoj::input diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/SetsquareInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/SetsquareInputHandler.cpp deleted file mode 100644 index f9399ac..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/SetsquareInputHandler.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "SetsquareInputHandler.h" - -#include // for __shared_ptr_access, shar... - -#include "control/Control.h" // for Control -#include "control/SetsquareController.h" // for SetsquareController, HYPOTENUSE -#include "control/ToolEnums.h" // for TOOL_HAND, TOOL_HIGHLIGHTER -#include "control/ToolHandler.h" // for ToolHandler -#include "gui/XournalView.h" // for XournalView -#include "gui/inputdevices/InputEvents.h" // for InputEvent -#include "model/Setsquare.h" // for Setsquare::INITIAL_HEIGHT,... - -constexpr double MIN_HEIGHT = 4.5; -constexpr double MAX_HEIGHT = 15.0; - -SetsquareInputHandler::SetsquareInputHandler(XournalView* xournal, GeometryToolController* controller): - GeometryToolInputHandler(xournal, controller) {} - -SetsquareInputHandler::~SetsquareInputHandler() noexcept = default; - -auto SetsquareInputHandler::handlePointer(InputEvent const& event) -> bool { - const auto coords = getCoords(event); - SetsquareController* setsquareController = static_cast(controller); - - const auto toolHandler = xournal->getControl()->getToolHandler(); - switch (toolHandler->getToolType()) { - case TOOL_HIGHLIGHTER: - case TOOL_PEN: - if (event.type == BUTTON_PRESS_EVENT) { - if (controller->isInsideGeometryTool(coords.x, coords.y, 0) && - setsquareController->posRelToSide(HYPOTENUSE, coords.x, coords.y).y >= -0.5) { - // initialize range - const auto proj = setsquareController->posRelToSide(HYPOTENUSE, coords.x, coords.y).x; - setsquareController->createEdgeStroke(proj); - return true; - } else if (controller->isInsideGeometryTool(coords.x, coords.y, 0) && - (setsquareController->posRelToSide(LEFT_LEG, coords.x, coords.y).y >= -0.5 || - setsquareController->posRelToSide(RIGHT_LEG, coords.x, coords.y).y >= -0.5)) { - - // initialize point - setsquareController->createRadialStroke(coords.x, coords.y); - return true; - } else { - return false; - } - - } else if (event.type == MOTION_EVENT) { - // update range and paint - if (setsquareController->existsEdgeStroke()) { - const auto proj = setsquareController->posRelToSide(HYPOTENUSE, coords.x, coords.y).x; - setsquareController->updateEdgeStroke(proj); - return true; - } else if (setsquareController->existsRadialStroke()) { - setsquareController->updateRadialStroke(coords.x, coords.y); - return true; - } - return false; - } else if (event.type == BUTTON_RELEASE_EVENT) { - // add stroke to layer and reset - if (setsquareController->existsEdgeStroke()) { - setsquareController->finalizeEdgeStroke(); - return true; - } else if (setsquareController->existsRadialStroke()) { - setsquareController->finalizeRadialStroke(); - return true; - } - } - return false; - case TOOL_HAND: - if (event.type == BUTTON_PRESS_EVENT) { - if (!controller->isInsideGeometryTool(coords.x, coords.y, 0)) { - return false; - } else { - sequenceStart(event); - this->handScrolling = true; - return true; - } - } else if (event.type == MOTION_EVENT && this->handScrolling) { - scrollMotion(event); - return true; - } else if (event.type == BUTTON_RELEASE_EVENT && this->handScrolling) { - this->handScrolling = false; - } - default: - return false; - } -} - -auto SetsquareInputHandler::getMinHeight() const -> double { return MIN_HEIGHT; } -auto SetsquareInputHandler::getMaxHeight() const -> double { return MAX_HEIGHT; } diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/SetsquareInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/SetsquareInputHandler.h deleted file mode 100644 index 256a464..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/SetsquareInputHandler.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Xournal++ - * - * Input handler for the setsquare. - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "GeometryToolInputHandler.h" - -class Stroke; -class GeometryToolController; -struct InputEvent; - -/** - * @brief Input handler for the setsquare - * - * Only the pointer handling (mouse / stylus) is defined in this class. - * The rest comes from the GeometryToolInputHandler - * */ -class SetsquareInputHandler: public GeometryToolInputHandler { - -public: - explicit SetsquareInputHandler(XournalView* xournalView, GeometryToolController* controller); - ~SetsquareInputHandler() noexcept override; - -private: - /** - * @brief handles input from mouse and stylus for the setsquare - */ - bool handlePointer(InputEvent const& event) override; - - double getMinHeight() const override; - double getMaxHeight() const override; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/StylusInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/StylusInputHandler.cpp deleted file mode 100644 index 2e59186..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/StylusInputHandler.cpp +++ /dev/null @@ -1,209 +0,0 @@ -// -// Created by ulrich on 08.04.19. -// - -#include "StylusInputHandler.h" - -#include // for abs - -#include // for g_message - -#include "control/ToolHandler.h" // for ToolHandler -#include "control/settings/Settings.h" // for Settings -#include "control/settings/SettingsEnums.h" // for Button, BUTTON_ERASER -#include "gui/PageView.h" // for XojPageView -#include "gui/XournalView.h" // for XournalView -#include "gui/XournalppCursor.h" // for XournalppCursor -#include "gui/inputdevices/HandRecognition.h" // for HandRecognition -#include "gui/inputdevices/InputEvents.h" // for InputEvent, BUTTON_P... -#include "gui/inputdevices/PenInputHandler.h" // for PenInputHandler -#include "gui/inputdevices/PositionInputData.h" // for PositionInputData -#include "gui/widgets/XournalWidget.h" // for GtkXournal - -#include "InputContext.h" // for InputContext -#include "InputUtils.h" // for InputUtils - -StylusInputHandler::StylusInputHandler(InputContext* inputContext): PenInputHandler(inputContext) {} - -StylusInputHandler::~StylusInputHandler() = default; - -auto StylusInputHandler::handleImpl(InputEvent const& event) -> bool { - // Only handle events when there is no active gesture - GtkXournal* xournal = inputContext->getXournal(); - - // Determine the pressed states of devices and associate them to the current event - setPressedState(event); - - // Trigger start of action when pen/mouse is pressed - if (event.type == BUTTON_PRESS_EVENT) { - - if (event.button == 1 || this->inputContext->getSettings()->getInputSystemTPCButtonEnabled()) { - this->eventsToIgnore = this->inputContext->getSettings()->getIgnoredStylusEvents(); - if (this->eventsToIgnore > 0) { - this->eventsToIgnore--; // This is already the first ignored event - } else { - this->eventsToIgnore = -1; - this->actionStart(event); - } - return true; - } - if (this->inputRunning) { - // TPCButton is disabled and modifier button was pressed - this->actionEnd(event); - this->actionStart(event); - } else { - // No input running but modifier key was pressed - // Change the tool depending on the key - changeTool(event); - - XojPageView* currentPage = getPageAtCurrentPosition(event); - if (currentPage) { - PositionInputData pos = this->getInputDataRelativeToCurrentPage(currentPage, event); - currentPage->onButtonClickEvent(pos); - } - } - } - - // Trigger discrete action on double tap - if (event.type == BUTTON_2_PRESS_EVENT || event.type == BUTTON_3_PRESS_EVENT) { - this->actionPerform(event); - return true; - } - - // Trigger motion action when pen/mouse is pressed and moved - if (event.type == MOTION_EVENT) // mouse or pen moved - { - if (this->eventsToIgnore > 0) { - this->eventsToIgnore--; - } else if (this->eventsToIgnore == 0) { - this->eventsToIgnore = -1; - this->actionStart(event); - } else { - this->actionMotion(event); - } - XournalppCursor* cursor = xournal->view->getCursor(); - cursor->setInvisible(false); - cursor->updateCursor(); - } - - - // Check if enter/leave events occur in possible locations. This is a bug of the hardware (there are such devices!) - if ((event.type == ENTER_EVENT || event.type == LEAVE_EVENT) && this->deviceClassPressed && this->lastEvent) { - if (std::abs(event.relative.x - lastEvent.relative.x) > 100 || - std::abs(event.relative.y - lastEvent.relative.y) > 100) { - g_message("Discard impossible event - this is a sign of bugged hardware or drivers"); - return true; - } - } - - // Notify if pen enters/leaves widget - if (event.type == ENTER_EVENT && !this->inputRunning) { - this->actionEnterWindow(event); - } - if (event.type == LEAVE_EVENT) { - this->inputContext->getHandRecognition()->unblock(); - this->actionLeaveWindow(event); - } - - // Trigger end of action if pen tip leaves screen or mouse button is released - if (event.type == BUTTON_RELEASE_EVENT) { - if (event.button == 1 || this->inputContext->getSettings()->getInputSystemTPCButtonEnabled()) { - if (this->eventsToIgnore < 0) { - this->actionEnd(event); - } else { - this->eventsToIgnore = -1; - } - return true; - } - if (this->inputRunning) { - // TPCButton is disabled and modifier button was released - this->actionEnd(event); - this->actionStart(event); - } else { - // No input running but modifier key was pressed - // Change the tool depending on the key - changeTool(event); - } - } - - // If we loose our Grab on the device end the current action - if (event.type == GRAB_BROKEN_EVENT && this->deviceClassPressed) { - // TODO(fabian): We may need to update pressed state manually here - this->actionEnd(event); - return true; - } - - return false; -} - -void StylusInputHandler::setPressedState(InputEvent const& event) { - XojPageView* currentPage = getPageAtCurrentPosition(event); - - this->inputContext->getXournal()->view->getCursor()->setInsidePage(currentPage != nullptr); - - if (event.type == BUTTON_PRESS_EVENT) // mouse button pressed or pen touching surface - { - switch (event.button) { - case 1: - if (this->inputContext->getSettings()->getIgnoredStylusEvents() <= 0) { - this->deviceClassPressed = true; - } - break; - case 2: - this->modifier2 = true; - break; - case 3: - this->modifier3 = true; - default: - break; - } - } else if (event.type == MOTION_EVENT) { - if (this->eventsToIgnore == 0) { - this->deviceClassPressed = true; - } - } else if (event.type == BUTTON_RELEASE_EVENT) // mouse button released or pen not touching surface anymore - { - switch (event.button) { - case 1: - this->deviceClassPressed = false; - break; - case 2: - this->modifier2 = false; - if (this->inputContext->getSettings()->getInputSystemTPCButtonEnabled()) { - this->deviceClassPressed = false; - } - break; - case 3: - this->modifier3 = false; - if (this->inputContext->getSettings()->getInputSystemTPCButtonEnabled()) { - this->deviceClassPressed = false; - } - default: - break; - } - } -} - -auto StylusInputHandler::changeTool(InputEvent const& event) -> bool { - Settings* settings = this->inputContext->getSettings(); - ToolHandler* toolHandler = this->inputContext->getToolHandler(); - bool toolChanged = false; - - if (event.deviceClass == INPUT_DEVICE_PEN && this->modifier2) - toolChanged = InputUtils::applyButton(toolHandler, settings, Button::BUTTON_STYLUS_ONE); - else if (event.deviceClass == INPUT_DEVICE_PEN && this->modifier3) - toolChanged = InputUtils::applyButton(toolHandler, settings, Button::BUTTON_STYLUS_TWO); - else if (event.deviceClass == INPUT_DEVICE_ERASER) - toolChanged = InputUtils::applyButton(toolHandler, settings, Button::BUTTON_ERASER); - else - toolChanged = toolHandler->pointActiveToolToToolbarTool(); - - if (toolChanged) { - ToolType toolType = toolHandler->getToolType(); - if (toolType == TOOL_TEXT) - toolHandler->selectTool(toolType); - toolHandler->fireToolChanged(); - } - - return true; -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/StylusInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/StylusInputHandler.h deleted file mode 100644 index d258ce1..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/StylusInputHandler.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "PenInputHandler.h" // for PenInputHandler - -class InputContext; -struct InputEvent; - -class StylusInputHandler: public PenInputHandler { -public: - explicit StylusInputHandler(InputContext* inputContext); - ~StylusInputHandler() override; - - bool handleImpl(InputEvent const& event) override; - - /** - * @brief Change the tool based on the settings and the Button pressed. - * In case no button is pressed or the settings for that button are "No Toolchange" this function ensures that the - * tool selected in the toolbar remains selected. - * - * @param event - * @return true if tool was changed successfully - * @return false if tool was not changed successfully - */ - bool changeTool(InputEvent const& event) override; - -private: - /** - * How many events since hitting the screen with the stylus are still left to be ignored before actually starting - * the action. Set according to the user's setting on every button-1-press-event. Will be evaluated and then - * decreased by one (down to -1) on every button-1-press-event and motion-event. Set to -1 on button-1-release.\n - * If >0: Ignore the (button-1-press- or motion-) event\n - * If 0: Start the action (on the next button-1-press- or motion-event)\n - * If -1: Stylus not touching or action already started, handle the event normally - */ - int eventsToIgnore = -1; - - void setPressedState(InputEvent const& event); -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/TouchDrawingInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/TouchDrawingInputHandler.cpp deleted file mode 100644 index 2f34bef..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/TouchDrawingInputHandler.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// -// Created by ulrich on 08.04.19. -// - -#include "TouchDrawingInputHandler.h" - -#include // for operator==, basic_string - -#include "control/Control.h" // for Control -#include "control/DeviceListHelper.h" // for getSourceMapping -#include "control/ToolEnums.h" // for TOOL_HAND, ToolType -#include "control/ToolHandler.h" // for ToolHandler -#include "control/settings/ButtonConfig.h" // for ButtonConfig -#include "control/settings/Settings.h" // for Settings -#include "control/settings/SettingsEnums.h" // for BUTTON_TOUCH, Button -#include "gui/MainWindow.h" // for MainWindow -#include "gui/PageView.h" // for XojPageView -#include "gui/XournalView.h" // for XournalView -#include "gui/XournalppCursor.h" // for XournalppCursor -#include "gui/inputdevices/InputEvents.h" // for InputEvent, BUTTON_PRE... -#include "gui/inputdevices/PenInputHandler.h" // for PenInputHandler -#include "gui/widgets/XournalWidget.h" // for GtkXournal - -#include "InputContext.h" // for InputContext -#include "InputUtils.h" // for InputUtils - -TouchDrawingInputHandler::TouchDrawingInputHandler(InputContext* inputContext): PenInputHandler(inputContext) { - inputContext->getToolHandler()->addToolChangedListener([&](ToolType newToolType) { - InputDeviceClass touchscreenClass = - DeviceListHelper::getSourceMapping(GDK_SOURCE_TOUCHSCREEN, this->inputContext->getSettings()); - - // If using the touchscreen as a touchscreen... - if (touchscreenClass == INPUT_DEVICE_TOUCHSCREEN) { - updateKineticScrollingEnabled(); - } - }); -} - -TouchDrawingInputHandler::~TouchDrawingInputHandler() = default; - -auto TouchDrawingInputHandler::handleImpl(InputEvent const& event) -> bool { - ToolHandler* toolHandler = this->inputContext->getToolHandler(); - - // Do we need to end the touch sequence? - bool mustEnd = event.type == BUTTON_RELEASE_EVENT; - mustEnd = mustEnd || (event.type == GRAB_BROKEN_EVENT && this->deviceClassPressed); - - // Notify if finger enters/leaves widget - // Note: Drawing outside window doesn't seem to work - // if this is put later in handleImpl. - if (event.type == ENTER_EVENT) { - this->changeTool(event); - this->actionEnterWindow(event); - return false; - } - - if (event.type == LEAVE_EVENT) { - this->actionLeaveWindow(event); - return false; - } - - // Multitouch - if ((this->primarySequence && this->primarySequence != event.sequence) || this->secondarySequence) { - if (!this->secondarySequence) { - this->secondarySequence = event.sequence; - XojPageView* currentPage = this->getPageAtCurrentPosition(event); - - if (currentPage) { - currentPage->onSequenceCancelEvent(event.deviceId); - } - } - - if (mustEnd) { - // Ending two-finger panning/zooming? We should now only have a primary sequence. - if (event.sequence == this->primarySequence) { - this->primarySequence = this->secondarySequence; - this->secondarySequence = nullptr; - } else if (event.sequence == this->secondarySequence) { - this->secondarySequence = nullptr; - } - } - - // false lets another input handler (e.g. TouchInputHandler) handle the event. - return false; - } - - // Trigger start of action when pen/mouse is pressed - if (event.type == BUTTON_PRESS_EVENT && this->primarySequence == nullptr) { - this->primarySequence = event.sequence; - this->deviceClassPressed = true; - - this->actionStart(event); - - return false; - } - - // Trigger motion action when finger is pressed and moved, - // unless a hand tool, in which case, we return false to - // let an alternate handler (e.g. TouchInputHandler) decide - // what to do... - if (this->deviceClassPressed && event.type == MOTION_EVENT && toolHandler->getToolType() != TOOL_HAND) { - GtkXournal* xournal = inputContext->getXournal(); - - this->inputContext->getView()->getCursor()->setRotationAngle(event.relative.x); - - this->actionMotion(event); - XournalppCursor* cursor = xournal->view->getCursor(); - cursor->updateCursor(); - - return true; - } - - if (mustEnd) { - this->primarySequence = nullptr; - this->actionEnd(event); - - this->deviceClassPressed = false; - - return false; // Any alternates should also end. - } - - return false; -} - -auto TouchDrawingInputHandler::changeTool(InputEvent const& event) -> bool { - Settings* settings = this->inputContext->getSettings(); - ButtonConfig* cfg = settings->getButtonConfig(Button::BUTTON_TOUCH); - ToolHandler* toolHandler = this->inputContext->getToolHandler(); - bool toolChanged = false; - - if (cfg->device == event.deviceName) { - if (InputUtils::touchDrawingDisallowed(toolHandler, settings)) { - return false; - } - toolChanged = InputUtils::applyButton(toolHandler, settings, Button::BUTTON_TOUCH); - } else { - toolChanged = toolHandler->pointActiveToolToToolbarTool(); - } - - this->updateKineticScrollingEnabled(); - - if (toolChanged) { - toolHandler->fireToolChanged(); - } - - return true; -} - -void TouchDrawingInputHandler::updateKineticScrollingEnabled() { - auto* control = inputContext->getView()->getControl(); - auto* mainWindow = control->getWindow(); - auto* toolHandler = this->inputContext->getToolHandler(); - - // Kinetic scrolling is nice; however, we need to disable it so we can draw (it steals single-finger input). - if (mainWindow != nullptr && control->getSettings()->getTouchDrawingEnabled()) { - mainWindow->setGtkTouchscreenScrollingEnabled(toolHandler->getToolType() == TOOL_HAND); - } -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/TouchDrawingInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/TouchDrawingInputHandler.h deleted file mode 100644 index 49381bd..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/TouchDrawingInputHandler.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Xournal++ - * - * [Header description] - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GdkEventSequence - -#include "PenInputHandler.h" // for PenInputHandler - -class InputContext; -struct InputEvent; - -class TouchDrawingInputHandler: public PenInputHandler { -private: - GdkEventSequence* primarySequence = nullptr; - GdkEventSequence* secondarySequence = nullptr; - -public: - explicit TouchDrawingInputHandler(InputContext* inputContext); - ~TouchDrawingInputHandler() override; - - bool handleImpl(InputEvent const& event) override; - -protected: - /** - * @brief Change the tool according to Touch Settings - * - * @param event some Inputevent - * @return true if tool was changed successfully - * @return false if tool was not changed successfully - */ - bool changeTool(InputEvent const& event) override; - -private: - void updateKineticScrollingEnabled(); -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/TouchInputHandler.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/TouchInputHandler.cpp deleted file mode 100644 index d1f1e16..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/TouchInputHandler.cpp +++ /dev/null @@ -1,221 +0,0 @@ -// -// Created by ulrich on 08.04.19. -// - -#include "TouchInputHandler.h" - -#include // for abs - -#include "control/Control.h" // for Control -#include "control/settings/Settings.h" // for Settings -#include "control/zoom/ZoomControl.h" // for ZoomControl -#include "gui/Layout.h" // for Layout -#include "gui/MainWindow.h" // for MainWindow -#include "gui/XournalView.h" // for XournalView -#include "gui/inputdevices/AbstractInputHandler.h" // for AbstractInputHandler -#include "gui/inputdevices/InputEvents.h" // for InputEvent, BUTTO... - -#include "InputContext.h" // for InputContext - -TouchInputHandler::TouchInputHandler(InputContext* inputContext): AbstractInputHandler(inputContext) {} - -auto TouchInputHandler::handleImpl(InputEvent const& event) -> bool { - if (!event.sequence) { - // On x11, a GDK_MOTION_EVENT with sequence == nullptr is emitted before TOUCH_BEGIN: Ignore it - // In general, every valid touch event must have a sequence - return false; - } - bool zoomGesturesEnabled = inputContext->getSettings()->isZoomGesturesEnabled(); - - if (event.type == BUTTON_PRESS_EVENT) { - if (invalidActive.find(event.sequence) != invalidActive.end()) { - g_warning("Missed touch end/cancel event. Resetting touch input handler."); - invalidActive.clear(); - } - if (invalidActive.empty() && event.sequence != primarySequence && event.sequence != secondarySequence) { - // All touches are previously valid and we did not miss an end/cancel event for the current touch - if (primarySequence && secondarySequence) { - // All touches become invalid - g_debug("All touches become invalid"); - invalidActive.insert({primarySequence, secondarySequence, event.sequence}); - primarySequence = secondarySequence = nullptr; - } else { - if (primarySequence) { - secondarySequence = event.sequence; - } else { - primarySequence = event.sequence; - } - sequenceStart(event); - if (secondarySequence) { - startZoomReady = true; - } - } - } else { - invalidActive.insert(event.sequence); - g_debug("Add touch as invalid. %zu touches are invalid now.", invalidActive.size()); - } - return true; - } - - if (event.type == MOTION_EVENT) { - if (primarySequence == event.sequence && !secondarySequence) { - scrollMotion(event); - return true; - } else if (event.sequence && (primarySequence == event.sequence || secondarySequence == event.sequence)) { - xoj_assert(primarySequence); - if (zoomGesturesEnabled) { - if (startZoomReady) { - if (this->primarySequence == event.sequence) { - sequenceStart(event); - zoomStart(); - } - } else { - zoomMotion(event); - } - } else { - scrollMotion(event); - } - return true; - } - } - - if (event.type == BUTTON_RELEASE_EVENT) { - if (zooming && primarySequence && secondarySequence && - (event.sequence == primarySequence || event.sequence == secondarySequence)) { - zoomEnd(); - } - - if (event.sequence == primarySequence) { - // If secondarySequence is nullptr, this sets primarySequence - // to nullptr. If it isn't, then it is now the primary sequence! - primarySequence = std::exchange(secondarySequence, nullptr); - - this->priLastAbs = this->secLastAbs; - this->priLastRel = this->secLastRel; - } else if (event.sequence == secondarySequence) { - secondarySequence = nullptr; - } else { - invalidActive.erase(event.sequence); - g_debug("Removing sequence from invalid list, %zu inputs remain invalid.", invalidActive.size()); - } - return true; - } - - return false; -} - -void TouchInputHandler::sequenceStart(InputEvent const& event) { - if (event.sequence == this->primarySequence) { - this->priLastAbs = event.absolute; - this->priLastRel = event.relative; - } else { - this->secLastAbs = event.absolute; - this->secLastRel = event.relative; - } -} - -void TouchInputHandler::scrollMotion(InputEvent const& event) { - // Will only be called if there is a single sequence (zooming handles two sequences) - auto offset = [&]() { - if (event.sequence == this->primarySequence) { - auto offset = event.absolute - this->priLastAbs; - this->priLastAbs = event.absolute; - return offset; - } else { - auto offset = event.absolute - this->secLastAbs; - this->secLastAbs = event.absolute; - return offset; - } - }(); - - inputContext->getView()->getLayout()->scrollRelative(-offset.x, -offset.y); -} - -void TouchInputHandler::zoomStart() { - this->zooming = true; - this->startZoomDistance = this->priLastAbs.distance(this->secLastAbs); - - if (this->startZoomDistance == 0.0) { - this->startZoomDistance = 0.01; - } - - // Whether we can ignore the zoom portion of the gesture (e.g. distance between touch points - // hasn't changed enough). - this->canBlockZoom = true; - - ZoomControl* zoomControl = this->inputContext->getView()->getControl()->getZoomControl(); - - // Disable zoom fit as we are zooming currently - // TODO(fabian): this should happen internally!!! - if (zoomControl->isZoomFitMode()) { - zoomControl->setZoomFitMode(false); - } - - // use screen pixel coordinates for the zoom center - // as relative coordinates depend on the changing zoom level - auto center = (this->priLastAbs + this->secLastAbs) / 2.0; - this->lastZoomScrollCenter = center; - - // translate absolute window coordinates to the widget-local coordinates - const auto* mainWindow = inputContext->getView()->getControl()->getWindow(); - const auto translation = mainWindow->getNegativeXournalWidgetPos(); - center += translation; - - zoomControl->startZoomSequence(center); - - this->startZoomReady = false; -} - -void TouchInputHandler::zoomMotion(InputEvent const& event) { - if (event.sequence == this->primarySequence) { - this->priLastAbs = event.absolute; - } else { - this->secLastAbs = event.absolute; - } - - double distance = this->priLastAbs.distance(this->secLastAbs); - double zoom = distance / this->startZoomDistance; - - double zoomTriggerThreshold = inputContext->getSettings()->getTouchZoomStartThreshold(); - double zoomChangePercentage = std::abs(distance - startZoomDistance) / startZoomDistance * 100; - - // Has the touch points moved far enough to trigger a zoom? - if (this->canBlockZoom && zoomChangePercentage < zoomTriggerThreshold) { - zoom = 1.0; - } else { - // Touches have moved far enough from their initial location that we - // no longer prevent touchscreen zooming. - this->canBlockZoom = false; - } - - ZoomControl* zoomControl = this->inputContext->getView()->getControl()->getZoomControl(); - const auto center = (this->priLastAbs + this->secLastAbs) / 2; - zoomControl->zoomSequenceChange(zoom, true, center - lastZoomScrollCenter); - lastZoomScrollCenter = center; -} - -void TouchInputHandler::zoomEnd() { - this->zooming = false; - ZoomControl* zoomControl = this->inputContext->getView()->getControl()->getZoomControl(); - zoomControl->endZoomSequence(); -} - -void TouchInputHandler::onBlock() { - if (this->zooming) { - zoomEnd(); - } -} - -void TouchInputHandler::onUnblock() { - this->invalidActive.clear(); - this->primarySequence = nullptr; - this->secondarySequence = nullptr; - - this->startZoomDistance = 0.0; - this->lastZoomScrollCenter = {}; - - priLastAbs = {-1.0, -1.0}; - secLastAbs = {-1.0, -1.0}; - priLastRel = {-1.0, -1.0}; - secLastRel = {-1.0, -1.0}; -} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/TouchInputHandler.h b/entry/src/main/cpp/src/core/gui/inputdevices/TouchInputHandler.h deleted file mode 100644 index 2b14d2c..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/TouchInputHandler.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Xournal++ - * - * Handle touchscreen zooming and panning. - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for GdkEventSequence - -#include "util/Point.h" // for Point - -#include "AbstractInputHandler.h" // for AbstractInputHandler - -class InputContext; -struct InputEvent; - -class TouchInputHandler: public AbstractInputHandler { -private: - bool zooming = false; - std::set invalidActive; - - GdkEventSequence* primarySequence{}; - GdkEventSequence* secondarySequence{}; - - double startZoomDistance = 0.0; - xoj::util::Point lastZoomScrollCenter{}; - - xoj::util::Point priLastAbs{-1.0, -1.0}; - xoj::util::Point secLastAbs{-1.0, -1.0}; - - xoj::util::Point priLastRel{-1.0, -1.0}; - xoj::util::Point secLastRel{-1.0, -1.0}; - - // True, if a zoom sequence may be started by a motion event. - bool startZoomReady{false}; - - bool canBlockZoom{false}; - -private: - void sequenceStart(InputEvent const& event); - void scrollMotion(InputEvent const& event); - void zoomStart(); - void zoomMotion(InputEvent const& event); - void zoomEnd(); - -public: - explicit TouchInputHandler(InputContext* inputContext); - ~TouchInputHandler() override = default; - - bool handleImpl(InputEvent const& event) override; - void onBlock() override; - void onUnblock() override; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableCustom.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableCustom.cpp deleted file mode 100644 index 44f4e30..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableCustom.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "TouchDisableCustom.h" - -#include - -#include "util/Util.h" - - -TouchDisableCustom::TouchDisableCustom(std::string enableCommand, std::string disableCommand): - enableCommand(std::move(enableCommand)), disableCommand(std::move(disableCommand)) {} - -TouchDisableCustom::~TouchDisableCustom() = default; - -void TouchDisableCustom::enableTouch() { Util::systemWithMessage(enableCommand.c_str()); } - -void TouchDisableCustom::disableTouch() { Util::systemWithMessage(disableCommand.c_str()); } diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableCustom.h b/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableCustom.h deleted file mode 100644 index 7afda4f..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableCustom.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Xournal++ - * - * Interface for touch disable implementations - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - -#include "TouchDisableInterface.h" // for TouchDisableInterface - - -class TouchDisableCustom: public TouchDisableInterface { -public: - TouchDisableCustom(std::string enableCommand, std::string disableCommand); - ~TouchDisableCustom() override; - -public: - void enableTouch() override; - void disableTouch() override; - -private: - std::string enableCommand; - std::string disableCommand; -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableInterface.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableInterface.cpp deleted file mode 100644 index 7a963b7..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableInterface.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "TouchDisableInterface.h" - -TouchDisableInterface::TouchDisableInterface() = default; - -TouchDisableInterface::~TouchDisableInterface() = default; - -void TouchDisableInterface::init() {} diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableInterface.h b/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableInterface.h deleted file mode 100644 index e9abf39..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableInterface.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Xournal++ - * - * Interface for touch disable implementations - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - - -class TouchDisableInterface { -public: - TouchDisableInterface(); - virtual ~TouchDisableInterface(); - -public: - virtual void enableTouch() = 0; - virtual void disableTouch() = 0; - virtual void init(); - -private: -}; diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableX11.cpp b/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableX11.cpp deleted file mode 100644 index 3f51251..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableX11.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "TouchDisableX11.h" - -#ifdef X11_ENABLED - -#include // for vector - -#include // for XA_INTEGER -#include // for XI_TOUCHSCREEN -#include // for gdk_display_get_default -#include // for gdk_x11_display_get_xdisplay -#include // for g_message, g_warning, g_error - -TouchDisableX11::TouchDisableX11() = default; - -TouchDisableX11::~TouchDisableX11() { - for (auto dev: touchdevs) { - XCloseDevice(display, dev); - } - touchdevs.clear(); - - display = nullptr; -} - -void TouchDisableX11::init() { - // Get display from GTK - display = gdk_x11_display_get_xdisplay(gdk_display_get_default()); - if (display == nullptr) { - g_error("Could not open X11 display"); - return; - } - - touchAtom = XInternAtom(display, "TOUCHSCREEN", true); - if (touchAtom == None) { - touchAtom = XInternAtom(display, XI_TOUCHSCREEN, false); - } - - - int inputDeviceCount = 0; - XDeviceInfo* devices = XListInputDevices(display, &inputDeviceCount); - for (int i = 0; i < inputDeviceCount; i++) { - if (devices[i].type == touchAtom) { - const auto dev = XOpenDevice(display, devices[i].id); - if (!dev) { - g_warning("Failed to open touch device \"%s\"", devices[i].name); - continue; - } - - g_message("X11 Touch disabler active for device \"%s\"", devices[i].name); - touchdevs.emplace_back(dev); - } - } - XFreeDeviceList(devices); - - if (touchdevs.empty()) { - g_warning("Could not find touchscreen device for disabling"); - return; - } - - enabledAtom = XInternAtom(display, "Device Enabled", false); -} - -void TouchDisableX11::enableTouch() { - if (touchdevs.empty()) { - return; - } - - unsigned char value = 1; - for (auto dev: touchdevs) { - XChangeDeviceProperty(display, dev, enabledAtom, XA_INTEGER, 8, PropModeReplace, &value, 1); - } - g_message("X11 Touch enabled"); -} - -void TouchDisableX11::disableTouch() { - if (touchdevs.empty()) { - return; - } - - unsigned char value = 0; - for (auto dev: touchdevs) { - XChangeDeviceProperty(display, dev, enabledAtom, XA_INTEGER, 8, PropModeReplace, &value, 1); - } - g_message("X11 Touch disabled"); -} - -#endif diff --git a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableX11.h b/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableX11.h deleted file mode 100644 index db618a8..0000000 --- a/entry/src/main/cpp/src/core/gui/inputdevices/touchdisable/TouchDisableX11.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Xournal++ - * - * Interface for touch disable implementations - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#ifdef X11_ENABLED - -#include // for vector - -#include // for Atom, None -#include // for Display -#include // for XDevice, XDeviceInfo - -#include "TouchDisableInterface.h" // for TouchDisableInterface - - -class TouchDisableX11: public TouchDisableInterface { -public: - TouchDisableX11(); - virtual ~TouchDisableX11(); - -public: - virtual void enableTouch(); - virtual void disableTouch(); - virtual void init(); - -private: - /** - * X11 Display - */ - Display* display = nullptr; - - /** - * Touch device ID - */ - Atom touchAtom = None; - - /** - * Touch devices - */ - std::vector touchdevs; - - /** - * Enable flag - */ - Atom enabledAtom = None; -}; - -#endif diff --git a/entry/src/main/cpp/src/core/gui/menus/PageTypeSelectionMenuBase.cpp b/entry/src/main/cpp/src/core/gui/menus/PageTypeSelectionMenuBase.cpp deleted file mode 100644 index f9f4a24..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/PageTypeSelectionMenuBase.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "PageTypeSelectionMenuBase.h" - -#include // for find_if -#include -#include -#include - -#include // for G_CALLBACK, g_sig... - -#include "control/pagetype/PageTypeHandler.h" // for PageTypeInfo, Pag... -#include "control/settings/PageTemplateSettings.h" // for PageTemplateSettings -#include "control/settings/Settings.h" // for Settings -#include "util/raii/GVariantSPtr.h" - -namespace { -std::optional getInitiallySelectedPageType(const Settings* settings) { - if (settings) { - return settings->getPageTemplateSettings().getPageInsertType(); - } - return std::nullopt; -} - -/** - * @brief Returns the action target value associated to the given page type. - */ -size_t findIndex(PageTypeHandler* types, const std::optional& pt) { - auto find_index_of = [](const std::vector>& types, const PageType& pt) { - auto it = std::find_if(types.begin(), types.end(), [&pt](const auto& info) { return info->page == pt; }); - return it != types.end() ? static_cast(std::distance(types.begin(), it)) : - PageTypeSelectionMenuBase::COPY_CURRENT_PLACEHOLDER; - }; - - return pt ? (pt->isSpecial() ? - find_index_of(types->getSpecialPageTypes(), pt.value()) + types->getPageTypes().size() : - find_index_of(types->getPageTypes(), pt.value())) : - PageTypeSelectionMenuBase::COPY_CURRENT_PLACEHOLDER; -} - -GSimpleAction* createPageTypeSelectionAction(PageTypeHandler* types, const std::optional& pt, - const std::string_view& actionName) { - size_t index = findIndex(types, pt); - return g_simple_action_new_stateful(actionName.data(), G_VARIANT_TYPE_UINT64, g_variant_new_uint64(index)); -} -}; // namespace - - -PageTypeSelectionMenuBase::PageTypeSelectionMenuBase(PageTypeHandler* typesHandler, const Settings* settings, - const std::string_view& actionName): - selectedPT(getInitiallySelectedPageType(settings)), - typeSelectionAction(createPageTypeSelectionAction(typesHandler, selectedPT, actionName), xoj::util::adopt), - types(typesHandler) { - g_signal_connect(G_OBJECT(typeSelectionAction.get()), "change-state", G_CALLBACK(changeSelectionCallback), this); - - // The GAction is not yet added to any GActionMap/GActionGroup - do it in derived classes -} - -void PageTypeSelectionMenuBase::changeSelectionCallback(GSimpleAction* ga, GVariant* parameter, - PageTypeSelectionMenuBase* self) { - if (g_variant_equal(parameter, xoj::util::GVariantSPtr(g_action_get_state(G_ACTION(ga)), xoj::util::adopt).get())) { - return; - } - - g_simple_action_set_state(ga, parameter); - auto id = g_variant_get_uint64(parameter); - const auto& types = self->types; - const auto& genTypes = types->getPageTypes(); - const auto& specialTypes = types->getSpecialPageTypes(); - - PageTypeInfo* info = nullptr; - if (id < genTypes.size()) { - info = genTypes[id].get(); - } else if (id < genTypes.size() + specialTypes.size()) { - info = specialTypes[id - genTypes.size()].get(); - } // The "Copy current page" type has id == npos - - self->selectedPT = info ? std::make_optional(info->page) : std::nullopt; - self->entrySelected(info); -} - -void PageTypeSelectionMenuBase::setSelectedPT(const std::optional& selected) { - if (this->selectedPT != selected) { - size_t index = findIndex(types, selected); - g_simple_action_set_state(typeSelectionAction.get(), g_variant_new_uint64(index)); - this->selectedPT = selected; - } -} diff --git a/entry/src/main/cpp/src/core/gui/menus/PageTypeSelectionMenuBase.h b/entry/src/main/cpp/src/core/gui/menus/PageTypeSelectionMenuBase.h deleted file mode 100644 index 15dbeff..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/PageTypeSelectionMenuBase.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Xournal++ - * - * Handles page selection menus -- Base - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include -#include - -#include // for GSimpleAction -#include - -#include "model/PageType.h" // for PageType -#include "util/raii/GObjectSPtr.h" - -class PageTypeHandler; -class PageTypeInfo; -class Settings; - -class PageTypeSelectionMenuBase { -protected: - PageTypeSelectionMenuBase(PageTypeHandler* typesHandler, const Settings* settings, - const std::string_view& actionName); - ~PageTypeSelectionMenuBase() = default; - -public: - /** - * @brief Set the selected page type in the menu. Does not trigger any signals but updates the radio buttons. - */ - void setSelectedPT(const std::optional& selected); - -private: - /** - * @brief callback subfunction - */ - virtual void entrySelected(const PageTypeInfo* info) = 0; - - static void changeSelectionCallback(GSimpleAction* ga, GVariant* parameter, - PageTypeSelectionMenuBase* pageTypeMenu); - -protected: - std::optional selectedPT; - - xoj::util::GObjectSPtr typeSelectionAction; - - PageTypeHandler* types; - - bool changeCurrentPageUponCallback = false; - -public: - static constexpr size_t COPY_CURRENT_PLACEHOLDER = std::numeric_limits::max(); -}; diff --git a/entry/src/main/cpp/src/core/gui/menus/StaticAssertActionNamespace.h b/entry/src/main/cpp/src/core/gui/menus/StaticAssertActionNamespace.h deleted file mode 100644 index 35bdfba..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/StaticAssertActionNamespace.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Xournal++ - * - * A helper class to statically assert the action namespace is correct - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include "gtk/gtk.h" - -class MainWindow; - -/** - * @brief Returns true if the provided GAction namespace matches the provided type - * (i.e. "win" for GtkApplicationWindow and "app" for GtkApplication) - */ -template -constexpr bool is_action_namespace_match(const char* nspace) { - return false; -} - -template <> -constexpr bool is_action_namespace_match(const char* nspace) { - return std::string_view(nspace) == std::string_view("win."); -} - -template <> -constexpr bool is_action_namespace_match(const char* nspace) { - return std::string_view(nspace) == std::string_view("win."); -} - -template <> -constexpr bool is_action_namespace_match(const char* nspace) { - return std::string_view(nspace) == std::string_view("win."); -} - -template <> -constexpr bool is_action_namespace_match(const char* nspace) { - return std::string_view(nspace) == std::string_view("app."); -} - -template <> -constexpr bool is_action_namespace_match(const char* nspace) { - return std::string_view(nspace) == std::string_view("app"); -} diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/AbstractSubmenu.h b/entry/src/main/cpp/src/core/gui/menus/menubar/AbstractSubmenu.h deleted file mode 100644 index 584a4ed..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/AbstractSubmenu.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Xournal++ - * - * A submenu - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "util/raii/GObjectSPtr.h" - -class Menubar; - -class Submenu { -protected: - Submenu() = default; - ~Submenu() noexcept = default; - -public: - virtual void setDisabled(bool disabled) = 0; - virtual void addToMenubar(Menubar& menubar) = 0; -}; diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/Menubar.cpp b/entry/src/main/cpp/src/core/gui/menus/menubar/Menubar.cpp deleted file mode 100644 index 161b0b5..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/Menubar.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "Menubar.h" - -#include "control/Control.h" -#include "gui/GladeSearchpath.h" -#include "gui/MainWindow.h" -#include "util/Assert.h" -#include "util/XojMsgBox.h" -#include "util/i18n.h" -#include "util/raii/GVariantSPtr.h" - -#include "PageTypeSubmenu.h" -#include "PluginsSubmenu.h" -#include "RecentDocumentsSubmenu.h" -#include "ToolbarSelectionSubmenu.h" -#include "config-features.h" // for ENABLE_PLUGINS - -constexpr auto MENU_XML_FILE = "mainmenubar.xml"; -constexpr auto MENU_ID = "menubar"; -constexpr auto UNDO_REDO_SECTION_ID = "sectionUndoRedo"; - -Menubar::Menubar() = default; -Menubar::~Menubar() noexcept = default; - -/// @brief Recursively removes all items with attribute "class" with value classname -static void removeItemsWithClass(GMenu* menu, const char* classname) { - int N = g_menu_model_get_n_items(G_MENU_MODEL(menu)); - for (int n = 0; n < N; ++n) { - xoj::util::GVariantSPtr c( - g_menu_model_get_item_attribute_value(G_MENU_MODEL(menu), n, "class", G_VARIANT_TYPE_STRING), - xoj::util::adopt); - if (c && std::string_view(g_variant_get_string(c.get(), nullptr)) == classname) { - g_menu_remove(menu, n--); - N--; - } else { - xoj::util::GObjectSPtr it(g_menu_model_iterate_item_links(G_MENU_MODEL(menu), n), - xoj::util::adopt); - while (g_menu_link_iter_next(it.get())) { - xoj::util::GObjectSPtr sub(g_menu_link_iter_get_value(it.get()), xoj::util::adopt); - if (sub && G_IS_MENU(sub.get())) { - removeItemsWithClass(G_MENU(sub.get()), classname); - } - } - } - } -} - -void Menubar::populate(const GladeSearchpath* gladeSearchPath, MainWindow* win) { - builder.reset(gtk_builder_new(), xoj::util::adopt); - - auto filepath = gladeSearchPath->findFile("", MENU_XML_FILE); - GError* error = nullptr; - - if (auto u8fp = filepath.u8string(); !gtk_builder_add_from_file(builder.get(), char_cast(u8fp.c_str()), &error)) { - std::string msg = FS(_F("Error loading menubar XML file (try to load \"{1}\")") % u8fp); - - if (error != nullptr) { - msg += "\n"; - msg += error->message; - g_error_free(error); - } - XojMsgBox::showErrorToUser(nullptr, msg); - return; - } - - menu = G_MENU_MODEL(gtk_builder_get_object(builder.get(), MENU_ID)); - - Control* ctrl = win->getControl(); - - recentDocumentsSubmenu = std::make_unique(ctrl, GTK_APPLICATION_WINDOW(win->getWindow())); - toolbarSelectionSubmenu = - std::make_unique(win, ctrl->getSettings(), win->getToolMenuHandler()); - pageTypeSubmenu = std::make_unique(ctrl->getPageTypes(), ctrl->getPageBackgroundChangeController(), - ctrl->getSettings(), GTK_APPLICATION_WINDOW(win->getWindow())); -#ifdef ENABLE_PLUGINS - pluginsSubmenu = - std::make_unique(ctrl->getPluginController(), GTK_APPLICATION_WINDOW(win->getWindow())); -#endif - - forEachSubmenu([&](auto& subm) { subm.addToMenubar(*this); }); - - if (!ctrl->getAudioController()) { - removeItemsWithClass(G_MENU(menu), "audio"); - } - - undoRedoSection = G_MENU(gtk_builder_get_object(builder.get(), UNDO_REDO_SECTION_ID)); -} - -void Menubar::setUndoDescription(const std::string& description) { - xoj_assert(undoRedoSection); - g_menu_remove(undoRedoSection, 0); - g_menu_prepend(undoRedoSection, description.c_str(), "win.undo"); -} - -void Menubar::setRedoDescription(const std::string& description) { - xoj_assert(undoRedoSection); - g_menu_remove(undoRedoSection, 1); - g_menu_append(undoRedoSection, description.c_str(), "win.redo"); -} - -void Menubar::setDisabled(bool disabled) { - forEachSubmenu([&](auto& subm) { subm.setDisabled(disabled); }); -} diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/Menubar.h b/entry/src/main/cpp/src/core/gui/menus/menubar/Menubar.h deleted file mode 100644 index d250ec6..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/Menubar.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Xournal++ - * - * The Main menu bar - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include - -#include // for GMenu, GMenuItem... - -#include "util/raii/GObjectSPtr.h" - -#include "config-features.h" // for ENABLE_PLUGINS - -class GladeSearchpath; -class MainWindow; - -class RecentDocumentsSubmenu; -class ToolbarSelectionSubmenu; -class PageTypeSubmenu; -class PluginsSubmenu; - -class Menubar { -public: - Menubar(); - ~Menubar() noexcept; - - void populate(const GladeSearchpath* gladeSearchPath, MainWindow* win); - -public: - inline GMenuModel* getModel() const { return menu; } - inline ToolbarSelectionSubmenu& getToolbarSelectionSubmenu() const { return *toolbarSelectionSubmenu; } - inline PageTypeSubmenu& getPageTypeSubmenu() const { return *pageTypeSubmenu; } - - void setDisabled(bool disabled); - - void setUndoDescription(const std::string& description); - void setRedoDescription(const std::string& description); - - template - gobj* get(const std::string_view& name, Fun&& converter) const { - gobj* w = converter(gtk_builder_get_object(const_cast(builder.get()), name.data())); - if (w == nullptr) { - g_warning("Menubar::get: Could not find menu object: \"%s\"", name.data()); - } - return w; - } - -private: - xoj::util::GObjectSPtr builder; - GMenuModel* menu; // owned by `builder` - - // Dynamically created submenus -- also add to forEachSubmenu() below - std::unique_ptr recentDocumentsSubmenu; - std::unique_ptr toolbarSelectionSubmenu; - std::unique_ptr pageTypeSubmenu; -#ifdef ENABLE_PLUGINS - std::unique_ptr pluginsSubmenu; -#endif - - template - void forEachSubmenu(Fun&& fun) { - fun(*recentDocumentsSubmenu); - fun(*toolbarSelectionSubmenu); - fun(*pageTypeSubmenu); -#ifdef ENABLE_PLUGINS - fun(*pluginsSubmenu); -#endif - } - - GMenu* undoRedoSection; // owned by `builder` -}; diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/PageTypeSubmenu.cpp b/entry/src/main/cpp/src/core/gui/menus/menubar/PageTypeSubmenu.cpp deleted file mode 100644 index d81380e..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/PageTypeSubmenu.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "PageTypeSubmenu.h" - -#include // for unique_ptr -#include -#include // for string -#include - -#include // for G_CALLBACK, g_sig... - -#include "control/PageBackgroundChangeController.h" -#include "control/pagetype/PageTypeHandler.h" // for PageTypeInfo, Pag... -#include "gui/menus/StaticAssertActionNamespace.h" -#include "util/i18n.h" // for _ -#include "util/raii/GVariantSPtr.h" - -#include "Menubar.h" - -namespace { -static constexpr auto G_ACTION_NAMESPACE = "win."; -static constexpr auto SELECTION_ACTION_NAME = "menu.pick-page-type"; -static constexpr auto APPLY_ALL_ACTION_NAME = "menu.apply-current-page-type-to-all-pages"; -static constexpr auto SUBMENU_ID = "menuJournalPaperBackground"; - -auto createPageTypesSection(const std::vector>& pageTypes, size_t index) { - GMenu* menu = g_menu_new(); - - // Todo(c++20) constexpr this - std::string actionName = G_ACTION_NAMESPACE; - actionName += SELECTION_ACTION_NAME; - - for (auto& pageInfo: pageTypes) { - xoj::util::GObjectSPtr item(g_menu_item_new(pageInfo->name.c_str(), nullptr), xoj::util::adopt); - g_menu_item_set_action_and_target_value(item.get(), actionName.c_str(), - xoj::util::makeGVariantSPtr(index++).get()); - g_menu_append_item(menu, item.get()); - } - return xoj::util::GObjectSPtr(menu, xoj::util::adopt); -} - -auto createApplyToAllPagesSection() { - GMenu* menu = g_menu_new(); - - // Todo(c++20) constexpr this - std::string actionName = G_ACTION_NAMESPACE; - actionName += APPLY_ALL_ACTION_NAME; - - g_menu_append(menu, _("Apply to all pages"), actionName.c_str()); - return xoj::util::GObjectSPtr(menu, xoj::util::adopt); -} -}; // namespace - - -PageTypeSubmenu::PageTypeSubmenu(PageTypeHandler* typesHandler, PageBackgroundChangeController* controller, - const Settings* settings, GtkApplicationWindow* win): - PageTypeSelectionMenuBase(typesHandler, settings, SELECTION_ACTION_NAME), - controller(controller), - generatedPageTypesSection(createPageTypesSection(typesHandler->getPageTypes(), 0)), - specialPageTypesSection( - createPageTypesSection(typesHandler->getSpecialPageTypes(), typesHandler->getPageTypes().size())), - applyToAllPagesSection(createApplyToAllPagesSection()), - applyToAllPagesAction(g_simple_action_new(APPLY_ALL_ACTION_NAME, nullptr), xoj::util::adopt) { - - this->changeCurrentPageUponCallback = true; - - static_assert(is_action_namespace_match(G_ACTION_NAMESPACE)); - - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(typeSelectionAction.get())); - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(applyToAllPagesAction.get())); - - g_signal_connect(G_OBJECT(applyToAllPagesAction.get()), "activate", - G_CALLBACK(+[](GSimpleAction*, GVariant*, PageBackgroundChangeController* controller) { - controller->applyCurrentPageBackgroundToAll(); - }), - this->controller); -} - -void PageTypeSubmenu::setDisabled(bool disabled) { - g_simple_action_set_enabled(typeSelectionAction.get(), !disabled); - g_simple_action_set_enabled(applyToAllPagesAction.get(), !disabled); -} - -void PageTypeSubmenu::addToMenubar(Menubar& menubar) { - GMenu* submenu = menubar.get(SUBMENU_ID, [](auto* p) { return G_MENU(p); }); - g_menu_append_section(submenu, nullptr, G_MENU_MODEL(generatedPageTypesSection.get())); - g_menu_append_section(submenu, nullptr, G_MENU_MODEL(specialPageTypesSection.get())); - g_menu_append_section(submenu, nullptr, G_MENU_MODEL(applyToAllPagesSection.get())); -} - -void PageTypeSubmenu::entrySelected(const PageTypeInfo*) { - if (this->selectedPT && this->controller) { - this->controller->changeCurrentPageBackground(this->selectedPT.value()); - } -} diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/PageTypeSubmenu.h b/entry/src/main/cpp/src/core/gui/menus/menubar/PageTypeSubmenu.h deleted file mode 100644 index ba96e6b..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/PageTypeSubmenu.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Xournal++ - * - * Handles page selection menu - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GMenu, GSimpleAction - -#include "gui/menus/PageTypeSelectionMenuBase.h" -#include "util/raii/GObjectSPtr.h" - -#include "AbstractSubmenu.h" - -class PageTypeHandler; -class Settings; -class PageBackgroundChangeController; - -class PageTypeSubmenu final: public Submenu, public PageTypeSelectionMenuBase { -public: - PageTypeSubmenu(PageTypeHandler* typesHandler, PageBackgroundChangeController* controller, const Settings* settings, - GtkApplicationWindow* win); - ~PageTypeSubmenu() = default; - - void setDisabled(bool disabled) override; - void addToMenubar(Menubar& menubar) override; - -private: - void entrySelected(const PageTypeInfo*) override; - - PageBackgroundChangeController* controller; - - xoj::util::GObjectSPtr generatedPageTypesSection; - xoj::util::GObjectSPtr specialPageTypesSection; - xoj::util::GObjectSPtr applyToAllPagesSection; - xoj::util::GObjectSPtr applyToAllPagesAction; -}; diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/PluginsSubmenu.cpp b/entry/src/main/cpp/src/core/gui/menus/menubar/PluginsSubmenu.cpp deleted file mode 100644 index 3799644..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/PluginsSubmenu.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "PluginsSubmenu.h" - -#include "plugin/PluginController.h" -#include "util/Assert.h" -#include "util/i18n.h" - -#include "Menubar.h" - -/// position of the plugin submenu, from the end of the menu bar: 1 means just before the last one (About) -static constexpr int POSITION_IN_MENUBAR_FROM_END = 1; - -PluginsSubmenu::PluginsSubmenu(PluginController* pluginController, GtkApplicationWindow* win): - submenu(g_menu_new(), xoj::util::adopt) { - xoj::util::GObjectSPtr firstSection(g_menu_new(), xoj::util::adopt); - g_menu_append(firstSection.get(), _("Plugin Manager"), "win.plugin-manager"); - - g_menu_append_section(submenu.get(), nullptr, G_MENU_MODEL(firstSection.get())); - - for (auto* section: pluginController->createMenuSections(win)) { - g_menu_append_section(submenu.get(), nullptr, section); - } -} - -void PluginsSubmenu::setDisabled(bool disabled) { - // TODO!! -} - -void PluginsSubmenu::addToMenubar(Menubar& menubar) { - GMenuModel* mainmenu = menubar.getModel(); - int insertionPlace = g_menu_model_get_n_items(mainmenu) - POSITION_IN_MENUBAR_FROM_END; - xoj_assert(insertionPlace >= 0); - g_menu_insert_submenu(G_MENU(mainmenu), insertionPlace, _("Plugin"), G_MENU_MODEL(submenu.get())); -} diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/PluginsSubmenu.h b/entry/src/main/cpp/src/core/gui/menus/menubar/PluginsSubmenu.h deleted file mode 100644 index c2f0d1f..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/PluginsSubmenu.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Xournal++ - * - * Submenu listing plugins - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include -#include - -#include "AbstractSubmenu.h" - -class PluginController; - -class PluginsSubmenu final: public Submenu { -public: - PluginsSubmenu(PluginController* pluginController, GtkApplicationWindow* win); - ~PluginsSubmenu() noexcept = default; - -public: - void setDisabled(bool disabled) override; - void addToMenubar(Menubar& menubar) override; - -private: - xoj::util::GObjectSPtr submenu; -}; diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/RecentDocumentsSubmenu.cpp b/entry/src/main/cpp/src/core/gui/menus/menubar/RecentDocumentsSubmenu.cpp deleted file mode 100644 index 4ee869e..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/RecentDocumentsSubmenu.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include "RecentDocumentsSubmenu.h" - -#include // for string, allocator, operator+ - -#include // for GMenu - -#include "control/Control.h" -#include "control/RecentManager.h" -#include "gui/menus/StaticAssertActionNamespace.h" -#include "util/Assert.h" -#include "util/PathUtil.h" // for fromUri, toUri, hasPdfFileExt -#include "util/PlaceholderString.h" // for PlaceholderString -#include "util/StringUtils.h" // for replace_pair, StringUtils -#include "util/TinyVector.h" // for TinyVector -#include "util/i18n.h" // for FS, FORMAT_STR, C_F - -#include "Menubar.h" - -namespace { -constexpr auto SUBMENU_ID = "menuFileRecent"; -constexpr auto G_ACTION_NAMESPACE = "win."; -constexpr auto OPEN_ACTION_NAME = "open-file-at"; -constexpr auto REMOVE_ACTION_NAME = "remove-file-at"; - -/** - * @brief For a disable placeholder saying "No recent files" - * To disable a GMenu entry, give it an action name that does not correspond to any GAction - */ -constexpr auto DISABLED_ACTION_NAME = "always-disabled-action"; -constexpr auto CLEAR_LIST_ACTION_NAME = "clear-recent-files"; - -void recentManagerChangedCallback(GtkRecentManager* /*manager*/, RecentDocumentsSubmenu* recentDocsSubmenu) { - recentDocsSubmenu->updateMenu(); -} - -void clearRecentFilesCallback(GSimpleAction*, GVariant*, gpointer) { RecentManager::clearRecentFiles(); } - -auto createRecentMenuItem(const GtkRecentInfo* info, size_t i) { - std::string display_name = gtk_recent_info_get_display_name(const_cast(info)); - - // escape underscore - StringUtils::replaceAllChars(display_name, {replace_pair('_', "__")}); - std::string label = FS(FORMAT_STR("{1}. {2}") % (i + 1) % display_name); - - std::string action = G_ACTION_NAMESPACE; - action += OPEN_ACTION_NAME; - action += "(uint64 "; - action += std::to_string(i); - action += ")"; - - return xoj::util::GObjectSPtr(g_menu_item_new(label.c_str(), action.c_str()), xoj::util::adopt); -} - -auto createRemoveMenuItem(const GtkRecentInfo* info, size_t i) { - std::string display_name = gtk_recent_info_get_display_name(const_cast(info)); - - // escape underscore - StringUtils::replaceAllChars(display_name, {replace_pair('_', "__")}); - std::string label = - FS(FORMAT_STR("{1}. {2} {3}") % (i + 1) % - C_("The selected document will be removed from the recent files list", "Dismiss") % display_name); - - std::string action = G_ACTION_NAMESPACE; - action += REMOVE_ACTION_NAME; - action += "(uint64 "; - action += std::to_string(i); - action += ")"; - - return xoj::util::GObjectSPtr(g_menu_item_new(label.c_str(), action.c_str()), xoj::util::adopt); -} - -template -auto createRecentMenu(const container& recentFiles, size_t start_index) -> xoj::util::GObjectSPtr { - if (recentFiles.empty()) { - return nullptr; - } - GMenu* menu = g_menu_new(); - - for (auto& recent: recentFiles) { - g_menu_append_item(menu, createRecentMenuItem(recent.get(), start_index++).get()); - } - return xoj::util::GObjectSPtr(menu, xoj::util::adopt); -} - -template -auto createRemoveSubmenu(const container& recentFiles, size_t start_index) -> xoj::util::GObjectSPtr { - if (recentFiles.empty()) { - return nullptr; - } - GMenu* menu = g_menu_new(); - - for (auto& recent: recentFiles) { - g_menu_append_item(menu, createRemoveMenuItem(recent.get(), start_index++).get()); - } - - return xoj::util::GObjectSPtr(menu, xoj::util::adopt); -} - -auto createEmptyListPlaceholder() { - return xoj::util::GObjectSPtr(g_menu_item_new(_("No recent files"), DISABLED_ACTION_NAME), - xoj::util::adopt); -} - -auto createClearListSection() { - // Todo(cpp20): constexpr this concatenation - std::string action = G_ACTION_NAMESPACE; - action += CLEAR_LIST_ACTION_NAME; - - GMenu* menu = g_menu_new(); - g_menu_append(menu, _("Clear list"), action.c_str()); - - return xoj::util::GObjectSPtr(menu, xoj::util::adopt); -} -} // namespace - -RecentDocumentsSubmenu::RecentDocumentsSubmenu(Control* control, GtkApplicationWindow* win): control(control) { - GtkRecentManager* recentManager = gtk_recent_manager_get_default(); - this->recentHandlerId = g_signal_connect(recentManager, "changed", G_CALLBACK(recentManagerChangedCallback), this); - - if (!win) { - g_warning("RecentDocumentsSubmenu::RecentDocumentsSubmenu: no GtkApplicationWindow provided. Cannot push the " - "appropriate GAction."); - } else { - static_assert(is_action_namespace_match(G_ACTION_NAMESPACE)); - - openFileAction.reset(g_simple_action_new(OPEN_ACTION_NAME, G_VARIANT_TYPE_UINT64), xoj::util::adopt); - g_signal_connect(G_OBJECT(openFileAction.get()), "activate", G_CALLBACK(openFileCallback), this); - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(openFileAction.get())); - - clearListAction.reset(g_simple_action_new(CLEAR_LIST_ACTION_NAME, nullptr), xoj::util::adopt); - g_signal_connect(G_OBJECT(clearListAction.get()), "activate", G_CALLBACK(clearRecentFilesCallback), nullptr); - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(clearListAction.get())); - - removeFileAction.reset(g_simple_action_new(REMOVE_ACTION_NAME, G_VARIANT_TYPE_UINT64), xoj::util::adopt); - g_signal_connect(G_OBJECT(removeFileAction.get()), "activate", G_CALLBACK(removeFileCallback), this); - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(removeFileAction.get())); - } -} - -RecentDocumentsSubmenu::~RecentDocumentsSubmenu() { - if (this->recentHandlerId) { - GtkRecentManager* recentManager = gtk_recent_manager_get_default(); - g_signal_handler_disconnect(recentManager, this->recentHandlerId); - this->recentHandlerId = 0; - } -} - -void RecentDocumentsSubmenu::updateMenu() { - auto fileList = RecentManager::getRecentFiles(); - - xoppFiles.clear(); - std::transform(fileList.recentXoppFiles.begin(), fileList.recentXoppFiles.end(), std::back_inserter(xoppFiles), - [](auto& info) { return Util::fromUri(gtk_recent_info_get_uri(info.get())).value(); }); - pdfFiles.clear(); - std::transform(fileList.recentPdfFiles.begin(), fileList.recentPdfFiles.end(), std::back_inserter(pdfFiles), - [](auto& info) { return Util::fromUri(gtk_recent_info_get_uri(info.get())).value(); }); - - this->menuXoppFiles = createRecentMenu(fileList.recentXoppFiles, 0); - this->menuPdfFiles = createRecentMenu(fileList.recentPdfFiles, fileList.recentXoppFiles.size()); - - xoj_assert(recentFilesSubmenu); - g_menu_remove_all(recentFilesSubmenu.get()); - - if (this->menuXoppFiles) { - g_menu_append_section(recentFilesSubmenu.get(), nullptr, G_MENU_MODEL(this->menuXoppFiles.get())); - } - if (this->menuPdfFiles) { - g_menu_append_section(recentFilesSubmenu.get(), nullptr, G_MENU_MODEL(this->menuPdfFiles.get())); - } - if (this->menuXoppFiles || this->menuPdfFiles) { - g_menu_append_section(recentFilesSubmenu.get(), nullptr, G_MENU_MODEL(createClearListSection().get())); - } - - if (!fileList.recentXoppFiles.empty() || !fileList.recentPdfFiles.empty()) { - GMenu* removeSubmenu = g_menu_new(); - - if (!fileList.recentXoppFiles.empty()) { - auto removeXoppMenu = createRemoveSubmenu(fileList.recentXoppFiles, 0); - g_menu_append_section(removeSubmenu, - C_("In the submenu for removing recent documents, this will display on top of the " - "list xournal++ files to separate them from PDF files", - "Xournal++ Files"), - G_MENU_MODEL(removeXoppMenu.get())); - } - - if (!fileList.recentPdfFiles.empty()) { - auto removePdfMenu = createRemoveSubmenu(fileList.recentPdfFiles, fileList.recentXoppFiles.size()); - g_menu_append_section(removeSubmenu, - C_("In the submenu for removing recent documents, this will display on top of the " - "list PDF files to separate them from xournal++ files", - "PDF Files"), - G_MENU_MODEL(removePdfMenu.get())); - } - - GMenuItem* removeSubmenuItem = - g_menu_item_new_submenu(C_("This opens a submenu of the recent files list, and clicking on individual " - "entries in this submenu will remove it from the recent files list", - "Dismiss a single document"), - G_MENU_MODEL(removeSubmenu)); - g_menu_append_item(recentFilesSubmenu.get(), removeSubmenuItem); - - g_object_unref(removeSubmenu); - } else { - g_menu_append_item(recentFilesSubmenu.get(), createEmptyListPlaceholder().get()); - } -} - -void RecentDocumentsSubmenu::addToMenubar(Menubar& menubar) { - recentFilesSubmenu.reset(menubar.get(SUBMENU_ID, [](auto* p) { return G_MENU(p); }), xoj::util::ref); - updateMenu(); -} - -void RecentDocumentsSubmenu::setDisabled(bool disabled) { - g_simple_action_set_enabled(openFileAction.get(), !disabled); - g_simple_action_set_enabled(clearListAction.get(), !disabled); -} - -void RecentDocumentsSubmenu::openFileCallback(GSimpleAction* ga, GVariant* parameter, RecentDocumentsSubmenu* self) { - auto index = g_variant_get_uint64(parameter); - auto& path = - index < self->xoppFiles.size() ? self->xoppFiles[index] : self->pdfFiles[index - self->xoppFiles.size()]; - self->control->openFile(path); -} - -void RecentDocumentsSubmenu::removeFileCallback(GSimpleAction* ga, GVariant* parameter, RecentDocumentsSubmenu* self) { - auto index = g_variant_get_uint64(parameter); - auto& path = - index < self->xoppFiles.size() ? self->xoppFiles[index] : self->pdfFiles[index - self->xoppFiles.size()]; - RecentManager::removeRecentFileFilename(path); - self->updateMenu(); -} diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/RecentDocumentsSubmenu.h b/entry/src/main/cpp/src/core/gui/menus/menubar/RecentDocumentsSubmenu.h deleted file mode 100644 index 9d8f3cd..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/RecentDocumentsSubmenu.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Xournal++ - * - * The recent opened files - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GMenu -#include // for gulong -#include - -#include "control/RecentManager.h" -#include "util/raii/GObjectSPtr.h" - -#include "AbstractSubmenu.h" - -class Control; -class Menubar; - -/** - * @brief Handles the GtkMenu displaying the recent files - */ -class RecentDocumentsSubmenu final: public Submenu { -public: - RecentDocumentsSubmenu(Control* control, GtkApplicationWindow* win); - ~RecentDocumentsSubmenu(); - - /** - * Updates the menu of recent files - */ - void updateMenu(); - - void setDisabled(bool disabled) override; - void addToMenubar(Menubar& menubar) override; - -private: - static void openFileCallback(GSimpleAction* ga, GVariant* parameter, RecentDocumentsSubmenu* self); - static void removeFileCallback(GSimpleAction* ga, GVariant* parameter, RecentDocumentsSubmenu* self); - - gulong recentHandlerId{}; - - TinyVector xoppFiles; - TinyVector pdfFiles; - Control* control; - - /** - * Keep one menu for each section! - * Using a single menu with two sections does not work: when adding this to the suitable submenu in the main - * menubar, it would give - * - *
- *
- * ... - *
- *
- * ... - *
- *
- *
- * and the section separator does not appear in this case... - */ - xoj::util::GObjectSPtr recentFilesSubmenu; - xoj::util::GObjectSPtr menuXoppFiles; - xoj::util::GObjectSPtr menuPdfFiles; - xoj::util::GObjectSPtr openFileAction; - xoj::util::GObjectSPtr clearListAction; - xoj::util::GObjectSPtr removeFileAction; -}; diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/ToolbarSelectionSubmenu.cpp b/entry/src/main/cpp/src/core/gui/menus/menubar/ToolbarSelectionSubmenu.cpp deleted file mode 100644 index 72a5397..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/ToolbarSelectionSubmenu.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "ToolbarSelectionSubmenu.h" - -#include -#include // for operator==, string - -#include // for G_CALLBACK, g_sig... - -#include "control/settings/Settings.h" // for Settings -#include "gui/MainWindow.h" // for MainWindow -#include "gui/menus/StaticAssertActionNamespace.h" -#include "gui/toolbarMenubar/ToolMenuHandler.h" // for ToolMenuHandler -#include "gui/toolbarMenubar/model/ToolbarData.h" // for ToolbarData -#include "gui/toolbarMenubar/model/ToolbarModel.h" // for ToolbarModel - -#include "Menubar.h" - -namespace { -constexpr auto G_ACTION_NAMESPACE = "win."; -constexpr auto G_ACTION_NAME = "select-toolbar"; -/// id from ui/mainmenubar.xml -constexpr auto SUBMENU_ID = "menuViewToolbar"; - -auto createToolbarSelectionMenuItem(const ToolbarData* toolbarData) { - - std::string action = G_ACTION_NAMESPACE; - action += G_ACTION_NAME; - action += "('"; - action += toolbarData->getId(); - action += "')"; - - return xoj::util::GObjectSPtr(g_menu_item_new(toolbarData->getName().c_str(), action.c_str()), - xoj::util::adopt); -} - -void toolbarSelectionMenuChangeStateCallback(GSimpleAction* ga, GVariant* parameter, MainWindow* window) { - g_simple_action_set_state(ga, parameter); - - gsize l = 0; - const char* p = g_variant_get_string(parameter, &l); - std::string toolbarId(p, l); - - window->toolbarSelected(toolbarId); -} -}; // namespace - -ToolbarSelectionSubmenu::ToolbarSelectionSubmenu(MainWindow* win, Settings* settings, ToolMenuHandler* toolbar): - gAction(g_simple_action_new_stateful(G_ACTION_NAME, G_VARIANT_TYPE_STRING, - g_variant_new_string(settings->getSelectedToolbar().c_str())), - xoj::util::adopt) { - const auto& toolbars = toolbar->getModel()->getToolbars(); - - auto it = toolbars.begin(); - this->stockConfigurationsSection.reset(g_menu_new(), xoj::util::adopt); - for (; it != toolbars.end() && (*it)->isPredefined(); ++it) { - g_menu_append_item(this->stockConfigurationsSection.get(), createToolbarSelectionMenuItem(it->get()).get()); - } - this->customConfigurationsSection.reset(g_menu_new(), xoj::util::adopt); - for (; it != toolbars.end(); ++it) { - g_menu_append_item(this->customConfigurationsSection.get(), createToolbarSelectionMenuItem(it->get()).get()); - } - - g_signal_connect(G_OBJECT(gAction.get()), "change-state", G_CALLBACK(toolbarSelectionMenuChangeStateCallback), win); - static_assert(is_action_namespace_match(G_ACTION_NAMESPACE)); - g_action_map_add_action(G_ACTION_MAP(win->getWindow()), G_ACTION(gAction.get())); -} - -ToolbarSelectionSubmenu::~ToolbarSelectionSubmenu() = default; - -void ToolbarSelectionSubmenu::setDisabled(bool disabled) { g_simple_action_set_enabled(gAction.get(), !disabled); } - -void ToolbarSelectionSubmenu::addToMenubar(Menubar& menubar) { - GMenu* submenu = menubar.get(SUBMENU_ID, [](auto* p) { return G_MENU(p); }); - g_menu_prepend_section(submenu, nullptr, G_MENU_MODEL(customConfigurationsSection.get())); - g_menu_prepend_section(submenu, nullptr, G_MENU_MODEL(stockConfigurationsSection.get())); -} - -void ToolbarSelectionSubmenu::update(ToolMenuHandler* toolbarHandler, const ToolbarData* tb) { - const auto& toolbars = toolbarHandler->getModel()->getToolbars(); - // The first half stockConfigurationsSection of the menu has already been generated: fast forward to the first - // custom config - auto it = std::find_if_not(toolbars.begin(), toolbars.end(), [](const auto& d) { return d->isPredefined(); }); - g_menu_remove_all(this->customConfigurationsSection.get()); - for (; it != toolbars.end(); ++it) { - g_menu_append_item(this->customConfigurationsSection.get(), createToolbarSelectionMenuItem(it->get()).get()); - } - // Does not fire a "change-state" signal - g_simple_action_set_state(gAction.get(), g_variant_new_string(tb ? tb->getId().c_str() : "")); -} diff --git a/entry/src/main/cpp/src/core/gui/menus/menubar/ToolbarSelectionSubmenu.h b/entry/src/main/cpp/src/core/gui/menus/menubar/ToolbarSelectionSubmenu.h deleted file mode 100644 index 895c9aa..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/menubar/ToolbarSelectionSubmenu.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Xournal++ - * - * Submenu for toolbar selection - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "util/raii/GObjectSPtr.h" - -#include "AbstractSubmenu.h" - -class Settings; -class ToolMenuHandler; -class ToolbarData; -class MainWindow; - -class ToolbarSelectionSubmenu final: public Submenu { -public: - ToolbarSelectionSubmenu(MainWindow* win, Settings* settings, ToolMenuHandler* toolbar); - ~ToolbarSelectionSubmenu(); - -public: - void update(ToolMenuHandler* toolbarHandler, const ToolbarData* selectedToolbar); - - void setDisabled(bool disabled) override; - void addToMenubar(Menubar& menubar) override; - -private: - xoj::util::GObjectSPtr stockConfigurationsSection; - xoj::util::GObjectSPtr customConfigurationsSection; - xoj::util::GObjectSPtr gAction; -}; diff --git a/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopover.cpp b/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopover.cpp deleted file mode 100644 index 82943a7..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopover.cpp +++ /dev/null @@ -1,458 +0,0 @@ -#include "PageTypeSelectionPopover.h" - -#include // for unique_ptr -#include // for string - -#include -#include - -#include "control/PageBackgroundChangeController.h" -#include "control/pagetype/PageTypeHandler.h" // for PageTypeInfo -#include "control/settings/Settings.h" -#include "gui/CreatePreviewImage.h" -#include "gui/dialog/FormatDialog.h" -#include "gui/menus/StaticAssertActionNamespace.h" -#include "model/XojPage.h" -#include "util/Assert.h" -#include "util/GtkUtil.h" -#include "util/PopupWindowWrapper.h" -#include "util/Util.h" -#include "util/gtk4_helper.h" // for gtk_box_append -#include "util/i18n.h" // for _ -#include "util/raii/GVariantSPtr.h" - - -namespace { -static constexpr auto PAGE_TYPES_PER_ROW = 4; -static constexpr auto G_ACTION_NAMESPACE = "win."; -static constexpr auto PAGETYPE_SELECTION_ACTION_NAME = "select-page-type-of-new-page"; -static constexpr auto ORIENTATION_SELECTION_ACTION_NAME = "select-page-orientation-of-new-page"; -static constexpr auto PAGESIZE_COMBOBOX_CHANGE_ACTION_NAME = "change-combobox-page-size-selection-new-page"; -static constexpr auto PAGESIZE_CHANGED_ACTION_NAME = "changed-page-size-selection-new-page"; - -GtkWidget* createEntryWithoutPreview(const char* label, size_t entryNb, const std::string_view& prefixedActionName) { - GtkWidget* button = gtk_toggle_button_new(); - - GtkWidget* labelWidget = gtk_label_new(label); - gtk_label_set_wrap_mode(GTK_LABEL(labelWidget), PANGO_WRAP_WORD); - gtk_label_set_wrap(GTK_LABEL(labelWidget), true); - gtk_label_set_justify(GTK_LABEL(labelWidget), GTK_JUSTIFY_CENTER); - gtk_label_set_max_width_chars(GTK_LABEL(labelWidget), 1); - gtk_widget_set_size_request(labelWidget, xoj::helper::PREVIEW_WIDTH, xoj::helper::PREVIEW_HEIGHT); - - gtk_button_set_child(GTK_BUTTON(button), labelWidget); - gtk_actionable_set_action_name(GTK_ACTIONABLE(button), prefixedActionName.data()); - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(button), xoj::util::makeGVariantSPtr(entryNb).get()); - xoj::util::gtk::setToggleButtonUnreleasable(GTK_TOGGLE_BUTTON(button)); - return button; -} - -GtkGrid* createEmptyGrid() { - GtkGrid* grid = GTK_GRID(gtk_grid_new()); - - gtk_grid_set_column_homogeneous(grid, true); - gtk_grid_set_row_homogeneous(grid, true); - gtk_grid_set_column_spacing(grid, 10); - gtk_grid_set_row_spacing(grid, 10); - gtk_widget_set_margin_start(GTK_WIDGET(grid), 10); - gtk_widget_set_margin_end(GTK_WIDGET(grid), 10); - - return grid; -} -auto getInitiallySelectedPaperSize(const Settings* settings) -> std::optional { - if (settings) { - PageTemplateSettings model; - model.parse(settings->getPageTemplate()); - return model.isCopyLastPageSize() ? std::nullopt : std::optional(PaperSize(model)); - } - return std::nullopt; -} -auto createOrientationGAction(PaperOrientation orientation) -> GSimpleAction* { - return g_simple_action_new_stateful(ORIENTATION_SELECTION_ACTION_NAME, G_VARIANT_TYPE_BOOLEAN, - g_variant_new_boolean(static_cast(orientation))); -} -auto createPageSizeComboBoxChangeSelectionGAction() -> GSimpleAction* { - return g_simple_action_new(PAGESIZE_COMBOBOX_CHANGE_ACTION_NAME, G_VARIANT_TYPE_UINT32); -} -auto createPageSizeChangedGAction() -> GSimpleAction* { - return g_simple_action_new(PAGESIZE_CHANGED_ACTION_NAME, nullptr); -} - -/** - * @brief Create a togglebutton containing a miniature of the given (standard) page type - * The toggle button is initialized to follow a GAction with the given action name and target value entryNb. - * The returned widget is a floating ref. - */ -GtkWidget* createEntryWithPreview(const PageTypeInfo* pti, size_t entryNb, const std::string_view& prefixedActionName) { - GtkWidget* button = gtk_toggle_button_new(); - - // // Use to restore labels in the menu - // GtkWidget* label = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); - // gtk_box_append(GTK_BOX(label), createPreviewImage(*pti)); - // gtk_box_append(GTK_BOX(label), gtk_label_new(pti->name.c_str())); - // gtk_button_set_child(GTK_BUTTON(button), label); - - GtkWidget* preview = xoj::helper::createPreviewImage(pti->page); - gtk_widget_set_tooltip_text(preview, pti->name.c_str()); - gtk_button_set_child(GTK_BUTTON(button), preview); // takes ownership of preview - gtk_actionable_set_action_name(GTK_ACTIONABLE(button), prefixedActionName.data()); - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(button), xoj::util::makeGVariantSPtr(entryNb).get()); - xoj::util::gtk::setToggleButtonUnreleasable(GTK_TOGGLE_BUTTON(button)); - return button; -} - -/** - * @brief Create a grid containing a miniature for each one the given (standard) page types - * The returned widget is a floating ref. - */ -GtkWidget* createPreviewGrid(const std::vector>& pageTypes, - const std::string_view& prefixedActionName) { - GtkGrid* grid = createEmptyGrid(); - gtk_widget_set_margin_top(GTK_WIDGET(grid), 10); - - size_t n = 0; - int gridX = 0; - int gridY = 0; - - for (const auto& pageInfo: pageTypes) { - // Special page types do not get a preview - xoj_assert(!pageInfo->page.isSpecial()); - auto* entry = createEntryWithPreview(pageInfo.get(), n++, prefixedActionName); - if (gridX >= PAGE_TYPES_PER_ROW) { - gridX = 0; - gridY++; - } - gtk_grid_attach(grid, entry, gridX, gridY, 1, 1); - gridX++; - } - return GTK_WIDGET(grid); -} - -GtkWidget* createOrientationButton(std::string_view actionName, GtkOrientation orientation, std::string_view icon) { - GtkWidget* button = gtk_toggle_button_new(); - gtk_button_set_icon_name(GTK_BUTTON(button), icon.data()); - gtk_actionable_set_action_name(GTK_ACTIONABLE(button), actionName.data()); - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(button), g_variant_new_boolean(orientation)); - return button; -} - -/** - * @brief Create a separator with custom margins - */ -GtkWidget* createSeparator() { - GtkWidget* separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - gtk_widget_set_margin_start(separator, 7); - gtk_widget_set_margin_end(separator, 7); - return separator; -} - -}; // namespace - -PageTypeSelectionPopover::PageTypeSelectionPopover(Control* control, Settings* settings, GtkApplicationWindow* win): - PageTypeSelectionMenuBase(control->getPageTypes(), settings, PAGETYPE_SELECTION_ACTION_NAME), - control(control), - controller(control->getPageBackgroundChangeController()), - settings(settings), - selectedPageSize(getInitiallySelectedPaperSize(settings)), - selectedOrientation(selectedPageSize ? selectedPageSize->orientation() : PaperOrientation::VERTICAL) { - static_assert(is_action_namespace_match(G_ACTION_NAMESPACE)); - - PaperFormatUtils::loadDefaultPaperSizes(paperSizeMenuOptions); - // Add Special options - customPaperSizeIndex = static_cast(paperSizeMenuOptions.size()); - paperSizeMenuOptions.emplace_back(_("Custom")); - copyCurrentPaperSizeIndex = static_cast(paperSizeMenuOptions.size()); - paperSizeMenuOptions.emplace_back(_("Copy current page")); - - this->controller->setPaperSizeForNewPages(this->selectedPageSize); - - orientationAction.reset(createOrientationGAction(selectedOrientation), xoj::util::adopt); - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(orientationAction.get())); - g_simple_action_set_enabled(orientationAction.get(), selectedPageSize.has_value()); - g_signal_connect(G_OBJECT(orientationAction.get()), "change-state", G_CALLBACK(changedOrientationSelectionCallback), - this); - - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(typeSelectionAction.get())); - - comboBoxChangeSelectionAction.reset(createPageSizeComboBoxChangeSelectionGAction(), xoj::util::adopt); - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(comboBoxChangeSelectionAction.get())); - - pageSizeChangedAction.reset(createPageSizeChangedGAction(), xoj::util::adopt); - g_action_map_add_action(G_ACTION_MAP(win), G_ACTION(pageSizeChangedAction.get())); -} -template -void PageTypeSelectionPopover::setSelectedPaperSize(const std::optional& newPageSize) { - if (newPageSize != selectedPageSize) { - if constexpr (changeComboBoxSelection) { - ignoreComboBoxSelectionChange = true; - g_action_activate(G_ACTION(comboBoxChangeSelectionAction.get()), - g_variant_new_uint32(static_cast(getComboBoxIndexForPaperSize(newPageSize)))); - ignoreComboBoxSelectionChange = false; - } - - selectedPageSize = newPageSize; - if (selectedPageSize) { - g_simple_action_set_state(orientationAction.get(), - g_variant_new_boolean(static_cast(selectedPageSize->orientation()))); - } - g_simple_action_set_enabled(orientationAction.get(), selectedPageSize.has_value()); - - // Updates sensitivity of 'apply to current'-button - g_action_activate(G_ACTION(this->pageSizeChangedAction.get()), nullptr); - - controller->setPaperSizeForNewPages(selectedPageSize); - } -} -// Explicit instantiation of the two possible bool values to avoid having to put the function template into header -template void PageTypeSelectionPopover::setSelectedPaperSize(const std::optional& newPageSize); -template void PageTypeSelectionPopover::setSelectedPaperSize(const std::optional& newPageSize); - -unsigned int PageTypeSelectionPopover::getComboBoxIndexForPaperSize(const std::optional& paperSize) const { - if (!paperSize) { - return copyCurrentPaperSizeIndex; - } - - for (unsigned int i = 0; i < customPaperSizeIndex; i++) { - auto& currentPaperSize = std::get(paperSizeMenuOptions[i]); - const PaperSize aDefaultPaperSize(currentPaperSize); - if (paperSize->equalDimensions(aDefaultPaperSize)) { - return i; - } - } - return customPaperSizeIndex; // Custom option is returned if no matching format is found -} -GtkWidget* PageTypeSelectionPopover::createPopover() const { - /** - * Used to connect to GAction changes: the GAction can outlive the widget. This ensures the callback is disabled - * when the widget is destroyed. Like g_signal_connect_object() except the callback data contains a pointer to *this - */ - auto connectToLonglivedAction = [this](GSimpleAction* act, const char* signalname, GCallback cb, GtkWidget* w) { - auto* closure = - g_cclosure_new(cb, new std::pair(w, this), - xoj::util::closure_notify_cb>); - g_object_watch_closure(G_OBJECT(w), closure); - g_signal_connect_closure(G_OBJECT(act), signalname, closure, GConnectFlags(0)); - }; - - GtkWidget* popover = gtk_popover_new(); - - // Todo(cpp20): constexpr this - std::string prefixedPageTypeActionName = G_ACTION_NAMESPACE; - prefixedPageTypeActionName += PAGETYPE_SELECTION_ACTION_NAME; - std::string prefixedOrientationActionName = std::string(G_ACTION_NAMESPACE) + ORIENTATION_SELECTION_ACTION_NAME; - - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); - gtk_popover_set_child(GTK_POPOVER(popover), GTK_WIDGET(box)); - - GtkWidget* previewGrid = createPreviewGrid(types->getPageTypes(), prefixedPageTypeActionName); - gtk_widget_set_margin_bottom(previewGrid, 5); - gtk_box_append(box, previewGrid); - - gtk_box_append(box, createSeparator()); - - GtkGrid* specialTypesGrid = createEmptyGrid(); - gtk_widget_set_margin_top(GTK_WIDGET(specialTypesGrid), 5); - gtk_widget_set_margin_bottom(GTK_WIDGET(specialTypesGrid), 5); - - int gridX = 0; - // Create a special entry for copying the current page's background - // It has index == npos - gtk_grid_attach(specialTypesGrid, - createEntryWithoutPreview(_("Copy current background"), npos, prefixedPageTypeActionName), gridX++, - 0, 1, 1); - - // The indices of special page types start after the normal page types' - size_t n = types->getPageTypes().size(); - for (const auto& pageInfo: types->getSpecialPageTypes()) { - gtk_grid_attach(specialTypesGrid, - createEntryWithoutPreview(pageInfo->name.c_str(), n++, prefixedPageTypeActionName), gridX++, 0, - 1, 1); - } - - while (gridX < PAGE_TYPES_PER_ROW) { - // Add empty cells to the grid so the buttons don't get extended - gtk_grid_attach(specialTypesGrid, gtk_label_new(""), gridX++, 0, 1, 1); - } - - GtkBox* pageFormatBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)); - gtk_widget_set_margin_start(GTK_WIDGET(pageFormatBox), 10); - gtk_widget_set_margin_end(GTK_WIDGET(pageFormatBox), 10); - gtk_widget_set_margin_top(GTK_WIDGET(pageFormatBox), 7); - gtk_widget_set_margin_bottom(GTK_WIDGET(pageFormatBox), 10); - - GtkBox* orientationFormatBox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)); - gtk_widget_add_css_class(GTK_WIDGET(orientationFormatBox), "linked"); - gtk_widget_add_css_class(GTK_WIDGET(orientationFormatBox), "orientationFormatBox"); - - std::array orientationButtons{}; - orientationButtons[GTK_ORIENTATION_VERTICAL] = createOrientationButton( - prefixedOrientationActionName, GTK_ORIENTATION_VERTICAL, "xopp-orientation-portrait"); - orientationButtons[GTK_ORIENTATION_HORIZONTAL] = createOrientationButton( - prefixedOrientationActionName, GTK_ORIENTATION_HORIZONTAL, "xopp-orientation-landscape"); - - xoj::util::gtk::setToggleButtonUnreleasable(GTK_TOGGLE_BUTTON(orientationButtons[GTK_ORIENTATION_VERTICAL])); - xoj::util::gtk::setToggleButtonUnreleasable(GTK_TOGGLE_BUTTON(orientationButtons[GTK_ORIENTATION_HORIZONTAL])); - - gtk_box_append(orientationFormatBox, orientationButtons[GTK_ORIENTATION_VERTICAL]); - gtk_box_append(orientationFormatBox, orientationButtons[GTK_ORIENTATION_HORIZONTAL]); - - gtk_box_append(pageFormatBox, GTK_WIDGET(orientationFormatBox)); - gtk_widget_set_hexpand(GTK_WIDGET(orientationFormatBox), true); - - GtkWidget* pageFormatComboBox = gtk_combo_box_new(); - PaperFormatUtils::fillPaperFormatDropDown(paperSizeMenuOptions, GTK_COMBO_BOX(pageFormatComboBox)); - gtk_widget_set_halign(pageFormatComboBox, GTK_ALIGN_END); - gtk_combo_box_set_active(GTK_COMBO_BOX(pageFormatComboBox), - static_cast(getComboBoxIndexForPaperSize(selectedPageSize))); - g_signal_connect(pageFormatComboBox, "changed", G_CALLBACK(changedPaperFormatTemplateCb), - const_cast(this)); - gtk_box_append(pageFormatBox, pageFormatComboBox); - - connectToLonglivedAction( - this->typeSelectionAction.get(), "notify::state", - G_CALLBACK((+[](GObject* a, GParamSpec*, gpointer pointerTuple) { - auto [pageFormatCB, self] = - *static_cast*>(pointerTuple); - xoj::util::GVariantSPtr state(g_action_get_state(G_ACTION(a)), xoj::util::adopt); - auto selectedIndex = getGVariantValue(state.get()); - // Enable page format selection for all page types except special ones (PDF and image) - bool shouldPageFormatSettingsBeEnabled = - selectedIndex == COPY_CURRENT_PLACEHOLDER || selectedIndex < self->types->getPageTypes().size(); - gtk_widget_set_sensitive(pageFormatCB, shouldPageFormatSettingsBeEnabled); - - g_simple_action_set_enabled(self->orientationAction.get(), - shouldPageFormatSettingsBeEnabled && self->selectedPageSize.has_value()); - })), - pageFormatComboBox); - - gtk_box_append(box, GTK_WIDGET(specialTypesGrid)); - gtk_box_append(box, createSeparator()); - gtk_box_append(box, GTK_WIDGET(pageFormatBox)); - - GtkWidget* applyToCurrentPageButton = gtk_button_new_with_label(_("Apply to current page")); - g_signal_connect_data( - applyToCurrentPageButton, "clicked", G_CALLBACK((+[](GtkButton*, gpointer pointerTuple) { - auto [self, popover] = - *static_cast*>(pointerTuple); - if (self->selectedPT) { - self->controller->changeCurrentPageBackground(self->selectedPT.value()); - } - if (self->selectedPageSize && (!self->selectedPT.has_value() || !self->selectedPT->isSpecial())) { - self->controller->changeCurrentPageSize(self->selectedPageSize.value()); - } - })), - new std::tuple(this, GTK_POPOVER(popover)), - xoj::util::closure_notify_cb>, GConnectFlags(0)); - gtk_widget_set_margin_start(applyToCurrentPageButton, 10); - gtk_widget_set_margin_end(applyToCurrentPageButton, 10); - gtk_widget_set_margin_bottom(applyToCurrentPageButton, 3); - gtk_box_append(box, applyToCurrentPageButton); - - // We cannot "Apply to current page" if neither page type nor page size is selected... - gtk_widget_set_sensitive(applyToCurrentPageButton, - this->selectedPT.has_value() || this->selectedPageSize.has_value()); - - connectToLonglivedAction( - this->typeSelectionAction.get(), "notify::state", - G_CALLBACK((+[](GObject* a, GParamSpec*, gpointer pointerTuple) { - auto [btn, self] = *static_cast*>(pointerTuple); - xoj::util::GVariantSPtr state(g_action_get_state(G_ACTION(a)), xoj::util::adopt); - auto selectedIndex = getGVariantValue(state.get()); - gtk_widget_set_sensitive( - btn, selectedIndex != COPY_CURRENT_PLACEHOLDER || self->selectedPageSize.has_value()); - })), - applyToCurrentPageButton); - - connectToLonglivedAction( - this->pageSizeChangedAction.get(), "activate", - G_CALLBACK((+[](GSimpleAction*, GVariant*, gpointer pointerTuple) { - auto [btn, self] = *static_cast*>(pointerTuple); - gtk_widget_set_sensitive(btn, self->selectedPT.has_value() || self->selectedPageSize.has_value()); - })), - applyToCurrentPageButton); - - g_signal_connect_object(this->comboBoxChangeSelectionAction.get(), "activate", - G_CALLBACK(+[](GSimpleAction*, GVariant* comboBoxIndex, gpointer comboBoxPtr) { - auto* comboBox = static_cast(comboBoxPtr); - gtk_combo_box_set_active(GTK_COMBO_BOX(comboBox), - static_cast(getGVariantValue(comboBoxIndex))); - }), - pageFormatComboBox, GConnectFlags(0)); - - GtkWidget* applyToAllPagesButton = gtk_button_new_with_label(_("Apply to all pages")); - g_signal_connect_data( - applyToAllPagesButton, "clicked", G_CALLBACK((+[](GtkWidget*, gpointer pointerTuple) { - auto [self, popover] = - *static_cast*>(pointerTuple); - const PageRef currentPage = self->control->getCurrentPage(); - PageType pt = self->selectedPT.value_or(currentPage->getBackgroundType()); - self->controller->applyBackgroundToAllPages(pt); - - if (!pt.isSpecial()) { // Special backgrounds come with their size - self->controller->applyPageSizeToAllPages(self->selectedPageSize.value_or( - PaperSize(currentPage->getWidth(), currentPage->getHeight()))); - } - })), - new std::tuple(this, GTK_POPOVER(popover)), - xoj::util::closure_notify_cb>, GConnectFlags(0)); - gtk_widget_set_margin_start(applyToAllPagesButton, 10); - gtk_widget_set_margin_end(applyToAllPagesButton, 10); - gtk_widget_set_margin_top(applyToAllPagesButton, 3); - gtk_widget_set_margin_bottom(applyToAllPagesButton, 10); - gtk_box_append(box, applyToAllPagesButton); - - gtk_widget_show_all(GTK_WIDGET(box)); - - return popover; -} -void PageTypeSelectionPopover::changedPaperFormatTemplateCb(GtkComboBox* widget, PageTypeSelectionPopover* self) { - if (self->ignoreComboBoxSelectionChange) { - return; - } - auto selected = static_cast(gtk_combo_box_get_active(widget)); - if (selected < self->customPaperSizeIndex) { - auto orientation = static_cast(getGVariantValue( - xoj::util::GVariantSPtr(g_action_get_state(G_ACTION(self->orientationAction.get())), xoj::util::adopt) - .get())); - - PaperSize paperSize(std::get(self->paperSizeMenuOptions[selected])); - if (paperSize.orientation() != orientation) { - paperSize.swapWidthHeight(); - } - - self->setSelectedPaperSize(paperSize); - } else if (selected == self->customPaperSizeIndex) { - std::unique_ptr> popup; - auto callback = [self](double width, double height) { - self->setSelectedPaperSize(PaperSize(width, height)); - }; - if (self->selectedPageSize) { - popup = std::make_unique>( - self->control->getGladeSearchPath(), self->settings, self->selectedPageSize->width, - self->selectedPageSize->height, callback); - } else { - PageTemplateSettings model; - model.parse(self->settings->getPageTemplate()); - popup = std::make_unique>( - self->control->getGladeSearchPath(), self->settings, model.getPageWidth(), model.getPageHeight(), - callback); - } - popup->show(self->control->getGtkWindow()); - - } else if (selected == self->copyCurrentPaperSizeIndex) { - self->setSelectedPaperSize(std::nullopt); - } -} -void PageTypeSelectionPopover::changedOrientationSelectionCallback(GSimpleAction* ga, GVariant* parameter, - PageTypeSelectionPopover* self) { - g_simple_action_set_state(ga, parameter); - self->selectedOrientation = static_cast(getGVariantValue(parameter)); - if (self->selectedPageSize && (self->selectedPageSize->orientation() != self->selectedOrientation)) { - self->selectedPageSize->swapWidthHeight(); - self->controller->setPaperSizeForNewPages(self->selectedPageSize); - } -} - -void PageTypeSelectionPopover::entrySelected(const PageTypeInfo*) { - this->controller->setPageTypeForNewPages(this->selectedPT); -} diff --git a/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopover.h b/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopover.h deleted file mode 100644 index b56ed28..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopover.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Xournal++ - * - * Handles page selection menu - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include // for vector - -#include // for GtkWidget - -#include "control/Control.h" -#include "control/settings/PageTemplateSettings.h" -#include "gui/PaperFormatUtils.h" -#include "gui/PopoverFactory.h" -#include "gui/menus/PageTypeSelectionMenuBase.h" -#include "model/PaperSize.h" -#include "util/raii/GObjectSPtr.h" - -class PageBackgroundChangeController; -class PageTypeHandler; -class PageTypeInfo; -class Settings; - -class PageTypeSelectionPopover final: public PageTypeSelectionMenuBase, public PopoverFactory { -public: - PageTypeSelectionPopover(Control* control, Settings* settings, GtkApplicationWindow* win); - ~PageTypeSelectionPopover() override = default; - -public: - GtkWidget* createPopover() const override; - - /** - * @brief Sets the selected paper size of the menu. - * @tparam changeComboBoxSelection Whether the combo box selection will be changed to a fitting option - */ - template - void setSelectedPaperSize(const std::optional& newPageSize); - -private: - void entrySelected(const PageTypeInfo* info) override; - - static void changedOrientationSelectionCallback(GSimpleAction* ga, GVariant* parameter, - PageTypeSelectionPopover* self); - static void changedPaperFormatTemplateCb(GtkComboBox* widget, PageTypeSelectionPopover* dlg); - - [[nodiscard]] unsigned int getComboBoxIndexForPaperSize(const std::optional& paperSize) const; - -private: - Control* control; - PageBackgroundChangeController* controller; - Settings* settings; - - std::optional selectedPageSize; - - PaperOrientation selectedOrientation; - xoj::util::GObjectSPtr orientationAction; - - // By activating the comboBoxChangeSelectionAction the option selected by the page size comboBox is changed to the - // specified index - xoj::util::GObjectSPtr comboBoxChangeSelectionAction; - - // The pageSizeChangedAction is activated when the pageSize changed - xoj::util::GObjectSPtr pageSizeChangedAction; - - PaperFormatUtils::PaperFormatMenuOptionVector paperSizeMenuOptions; - - bool ignoreComboBoxSelectionChange = false; - - uint32_t customPaperSizeIndex; // this - 1 is the last index of an actual PaperSize option - uint32_t copyCurrentPaperSizeIndex; -}; diff --git a/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.cpp b/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.cpp deleted file mode 100644 index 7a0261b..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "PageTypeSelectionPopoverGridOnly.h" - -#include // for unique_ptr -#include // for string - -#include -#include - -#include "control/pagetype/PageTypeHandler.h" // for PageTypeInfo -#include "gui/CreatePreviewImage.h" -#include "gui/dialog/PageTemplateDialog.h" -#include "model/PageType.h" // for PageType -#include "util/Assert.h" -#include "util/raii/GVariantSPtr.h" - -namespace { -static constexpr auto PAGE_TYPES_PER_ROW = 4; -static constexpr auto G_ACTION_NAMESPACE = "popover"; -static constexpr auto SELECTION_ACTION_NAME = "select-page-type-template"; - -GtkWidget* createPreviewGrid(const std::vector>& pageTypes, - const std::string_view& prefixedActionName) { - /* - * Todo(gtk4): replace the GtkMenu with a GtkPopover, using PageTypeSelectionPopover::createPreviewGrid instead. - * Note that GtkPopover is no good with GTK 3, as the popover gets cropped to the dialog window (so part of it is - * not displayed). GtkMenus don't have this restriction but are removed in GTK 4. Popovers in GTK 4 do not have this - * restriction. - */ - GtkMenu* gtkMenu = GTK_MENU(gtk_menu_new()); - - size_t n = 0; - unsigned int gridX = 0; - unsigned int gridY = 0; - - for (const auto& pageInfo: pageTypes) { - // Special page types do not get a preview - xoj_assert(!pageInfo->page.isSpecial()); - auto* entry = gtk_check_menu_item_new(); - gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(entry), true); - gtk_actionable_set_action_name(GTK_ACTIONABLE(entry), prefixedActionName.data()); - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(entry), xoj::util::makeGVariantSPtr(n++).get()); - GtkWidget* preview = xoj::helper::createPreviewImage(pageInfo->page); - gtk_widget_set_tooltip_text(preview, pageInfo->name.c_str()); - gtk_container_add(GTK_CONTAINER(entry), preview); // takes ownership of preview - if (gridX >= PAGE_TYPES_PER_ROW) { - gridX = 0; - gridY++; - } - gtk_menu_attach(gtkMenu, entry, gridX, gridX + 1, gridY, gridY + 1); - gridX++; - } - return GTK_WIDGET(gtkMenu); -} -}; // namespace - - -PageTypeSelectionPopoverGridOnly::PageTypeSelectionPopoverGridOnly(PageTypeHandler* typesHandler, - const Settings* settings, - xoj::popup::PageTemplateDialog* parent): - PageTypeSelectionMenuBase(typesHandler, settings, SELECTION_ACTION_NAME), - parent(parent), - popover(createPopover()) { - - xoj::util::GObjectSPtr group(g_simple_action_group_new(), xoj::util::adopt); - g_action_map_add_action(G_ACTION_MAP(group.get()), G_ACTION(typeSelectionAction.get())); - gtk_widget_insert_action_group(GTK_WIDGET(parent->getWindow()), G_ACTION_NAMESPACE, G_ACTION_GROUP(group.get())); -} - -xoj::util::WidgetSPtr PageTypeSelectionPopoverGridOnly::createPopover() { - // Todo(cpp20): constexpr this - std::string prefixedActionName = G_ACTION_NAMESPACE; - prefixedActionName += "."; - prefixedActionName += SELECTION_ACTION_NAME; - - xoj::util::WidgetSPtr popover(createPreviewGrid(types->getPageTypes(), prefixedActionName), xoj::util::adopt); - gtk_widget_show_all(popover.get()); - return popover; -} - -void PageTypeSelectionPopoverGridOnly::entrySelected(const PageTypeInfo* info) { - xoj_assert(info); - parent->changeCurrentPageBackground(info); -} diff --git a/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.h b/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.h deleted file mode 100644 index 5eff044..0000000 --- a/entry/src/main/cpp/src/core/gui/menus/popoverMenus/PageTypeSelectionPopoverGridOnly.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Xournal++ - * - * Handles page selection menu - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include // for vector - -#include // for GtkWidget - -#include "gui/menus/PageTypeSelectionMenuBase.h" -#include "util/raii/GObjectSPtr.h" - -namespace xoj::popup { -class PageTemplateDialog; -} -class PageTypeHandler; -class PageTypeInfo; -class Settings; - -class PageTypeSelectionPopoverGridOnly final: public PageTypeSelectionMenuBase { -public: - PageTypeSelectionPopoverGridOnly(PageTypeHandler* typesHandler, const Settings* settings, - xoj::popup::PageTemplateDialog* parent); - ~PageTypeSelectionPopoverGridOnly() = default; - -public: - inline GtkWidget* getPopover() { return popover.get(); } - -private: - xoj::util::WidgetSPtr createPopover(); - void entrySelected(const PageTypeInfo* info) override; - -private: - xoj::popup::PageTemplateDialog* parent; - xoj::util::WidgetSPtr popover; -}; diff --git a/entry/src/main/cpp/src/core/gui/scroll/ScrollHandling.cpp b/entry/src/main/cpp/src/core/gui/scroll/ScrollHandling.cpp deleted file mode 100644 index 1453110..0000000 --- a/entry/src/main/cpp/src/core/gui/scroll/ScrollHandling.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "ScrollHandling.h" - -#include "gui/Layout.h" - - -ScrollHandling::ScrollHandling(GtkAdjustment* adjHorizontal, GtkAdjustment* adjVertical): - adjHorizontal(adjHorizontal), adjVertical(adjVertical) {} - - -ScrollHandling::ScrollHandling(GtkScrolledWindow* win): - ScrollHandling(gtk_scrolled_window_get_hadjustment(win), gtk_scrolled_window_get_vadjustment(win)) {} - - -ScrollHandling::~ScrollHandling() = default; - -auto ScrollHandling::getHorizontal() -> GtkAdjustment* { return adjHorizontal; } - -auto ScrollHandling::getVertical() -> GtkAdjustment* { return adjVertical; } - -void ScrollHandling::init(GtkWidget* xournal, Layout* layout) { - this->xournal = xournal; - this->layout = layout; -} - - -#define TEMP_FIX true - -void ScrollHandling::setLayoutSize(int width, int height) { - // after a page has been inserted the layout size must be updated immediately, - // otherwise it comes down to a race deciding if scrolling happens normally or not -#if TEMP_FIX - // Todo(Fabian): remove that fix, since it is conceptually wrong behavior - // the adjustment is/must be changed implicitly by the layout and the resulting expose event - if (gtk_adjustment_get_upper(getHorizontal()) != width) { - gtk_adjustment_set_upper(getHorizontal(), width); - } - if (gtk_adjustment_get_upper(getVertical()) != height) { - gtk_adjustment_set_upper(getVertical(), height); - } -#endif -} diff --git a/entry/src/main/cpp/src/core/gui/scroll/ScrollHandling.h b/entry/src/main/cpp/src/core/gui/scroll/ScrollHandling.h deleted file mode 100644 index df71e5d..0000000 --- a/entry/src/main/cpp/src/core/gui/scroll/ScrollHandling.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Xournal++ - * - * Scroll handling for different scroll implementations - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GtkAdjustment, GtkWidget, GtkScrollable - -class Layout; - -class ScrollHandling { -public: - ScrollHandling(GtkAdjustment* adjHorizontal, GtkAdjustment* adjVertical); - ScrollHandling(GtkScrolledWindow* scrollable); - ~ScrollHandling(); - -public: - GtkAdjustment* getHorizontal(); - GtkAdjustment* getVertical(); - - void init(GtkWidget* xournal, Layout* layout); - - void setLayoutSize(int width, int height); - -private: -protected: - GtkAdjustment* adjHorizontal = nullptr; - GtkAdjustment* adjVertical = nullptr; - - GtkWidget* xournal = nullptr; - Layout* layout = nullptr; -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/AbstractSidebarPage.cpp b/entry/src/main/cpp/src/core/gui/sidebar/AbstractSidebarPage.cpp deleted file mode 100644 index 72a8f24..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/AbstractSidebarPage.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "AbstractSidebarPage.h" - -#include // for gdk_cursor_new_for_display, gdk_display_get... -#include // for g_object_unref - -AbstractSidebarPage::AbstractSidebarPage(Control* control): control(control) {} - -AbstractSidebarPage::~AbstractSidebarPage() = default; - -void AbstractSidebarPage::selectPageNr(size_t page, size_t pdfPage) {} - -auto AbstractSidebarPage::getControl() -> Control* { return this->control; } - -void AbstractSidebarPage::setTmpDisabled(bool disabled) { - GdkCursor* cursor = nullptr; - if (disabled) { - cursor = gdk_cursor_new_for_display(gdk_display_get_default(), GDK_WATCH); - } - - if (gtk_widget_get_window(this->getWidget())) { - gdk_window_set_cursor(gtk_widget_get_window(this->getWidget()), cursor); - } - - gtk_widget_set_sensitive(this->getWidget(), !disabled); - - - if (cursor) { - g_object_unref(cursor); - } -} diff --git a/entry/src/main/cpp/src/core/gui/sidebar/AbstractSidebarPage.h b/entry/src/main/cpp/src/core/gui/sidebar/AbstractSidebarPage.h deleted file mode 100644 index a2b0adc..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/AbstractSidebarPage.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Xournal++ - * - * Abstract Sidebar Page - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for string - -#include // for GtkToolItem - -#include "model/DocumentListener.h" // for DocumentListener - -class Control; - -class AbstractSidebarPage: public DocumentListener { -public: - AbstractSidebarPage(Control* control); - ~AbstractSidebarPage() override; - -public: - virtual void enableSidebar() = 0; - virtual void disableSidebar() = 0; - - virtual void layout() = 0; - - /** - * The name of this sidebar page - */ - virtual std::string getName() = 0; - - /** - * The name of this sidebar page - */ - virtual std::string getIconName() = 0; - - /** - * If this sidebar page has data for the current document, e.g. if there are bookmarks or not - */ - virtual bool hasData() = 0; - - /** - * Gets the Widget to display - */ - virtual GtkWidget* getWidget() = 0; - - /** - * Temporary disable Sidebar (e.g. while saving) - */ - virtual void setTmpDisabled(bool disabled); - - /** - * A page was selected, supply additional to the Document Page the PDF Page - */ - virtual void selectPageNr(size_t page, size_t pdfPage); - - /** - * Returns the Application controller - */ - Control* getControl(); - -private: -protected: - /** - * The Control of the Application - */ - Control* control = nullptr; - -public: - /** - * The Sidebar button - */ - GtkWidget* tabButton = nullptr; -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/Sidebar.cpp b/entry/src/main/cpp/src/core/gui/sidebar/Sidebar.cpp deleted file mode 100644 index 0599cba..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/Sidebar.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include "Sidebar.h" - -#include // for int64_t -#include // for std::make_unique and std::make_shared -#include // for string - -#include -#include // for gdk_display_get... -#include // for G_CALLBACK, g_s... -#include // for gtk_toggle_tool_button_new... - -#include "control/Control.h" // for Control -#include "control/settings/Settings.h" // for Settings -#include "gui/GladeGui.h" // for GladeGui -#include "gui/sidebar/AbstractSidebarPage.h" // for AbstractSidebar... -#include "gui/sidebar/indextree/SidebarIndexPage.h" // for SidebarIndexPage -#include "model/Document.h" // for Document -#include "model/XojPage.h" // for XojPage -#include "pdf/base/XojPdfPage.h" // for XojPdfPageSPtr -#include "previews/layer/SidebarPreviewLayers.h" // for SidebarPreviewL... -#include "previews/page/SidebarPreviewPages.h" // for SidebarPreviewP... -#include "util/Util.h" // for npos -#include "util/glib_casts.h" // for closure_notify_cb -#include "util/gtk4_helper.h" // -#include "util/i18n.h" // for _, FC, _F - -Sidebar::Sidebar(GladeGui* gui, Control* control): control(control) { - this->tbSelectTab = GTK_BOX(gui->get("bxSidebarTopActions")); - this->buttonCloseSidebar = gui->get("buttonCloseSidebar"); - - this->sidebarContents = gui->get("sidebarContents"); - - this->initTabs(sidebarContents); - - registerListener(control); -} - -void Sidebar::initTabs(GtkWidget* sidebarContents) { - addTab(std::make_unique(this->control)); - addTab(std::make_unique(this->control)); - addTab(std::make_unique(this->control, false)); - addTab(std::make_unique(this->control, true)); - - // Init toolbar with icons - - size_t i = 0; - for (auto&& p: this->tabs) { - GtkWidget* btn = gtk_toggle_button_new(); - p->tabButton = btn; - - gtk_button_set_icon_name(GTK_BUTTON(btn), p->getIconName().c_str()); - g_signal_connect_data(btn, "clicked", G_CALLBACK(&buttonClicked), new SidebarTabButton(this, i, p.get()), - xoj::util::closure_notify_cb, GConnectFlags(0)); - gtk_widget_set_tooltip_text(btn, p->getName().c_str()); - gtk_box_append(tbSelectTab, btn); - - // Add widget to sidebar - gtk_widget_set_vexpand(p->getWidget(), true); - gtk_box_append(GTK_BOX(sidebarContents), p->getWidget()); - - i++; - } - - updateVisibleTabs(); -} - -void Sidebar::buttonClicked(GtkButton* button, SidebarTabButton* buttonData) { - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { - if (buttonData->sidebar->visibleTab != buttonData->page->getWidget()) { - buttonData->sidebar->setSelectedTab(buttonData->index); - } - } else if (buttonData->sidebar->visibleTab == buttonData->page->getWidget()) { - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), true); - } -} - -void Sidebar::addTab(std::unique_ptr tab) { this->tabs.push_back(std::move(tab)); } - -Sidebar::~Sidebar() = default; - -void Sidebar::selectPageNr(size_t page, size_t pdfPage) { - for (auto&& p: this->tabs) { - p->selectPageNr(page, pdfPage); - } -} - -void Sidebar::setSelectedTab(size_t tab) { - this->visibleTab = nullptr; - - size_t i = 0; - for (auto&& t: this->tabs) { - if (tab == i) { - gtk_widget_show(t->getWidget()); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t->tabButton), true); - this->visibleTab = t->getWidget(); - this->currentTabIdx = i; - t->enableSidebar(); - } else { - t->disableSidebar(); - gtk_widget_hide(t->getWidget()); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(t->tabButton), false); - } - - i++; - } - if (this->visibleTab) { - g_idle_add( - [](gpointer data) -> gboolean { - Sidebar* sidebar = static_cast(data); - sidebar->layout(); - return G_SOURCE_REMOVE; - }, - this); - } -} - -void Sidebar::updateVisibleTabs() { - size_t i = 0; - size_t selected = npos; - - for (auto&& p: this->tabs) { - gtk_widget_set_visible(GTK_WIDGET(p->tabButton), p->hasData()); - - if (p->hasData() && selected == npos) { - selected = i; - } - - i++; - } - - setSelectedTab(selected); -} - -void Sidebar::setTmpDisabled(bool disabled) { - gtk_widget_set_sensitive(this->buttonCloseSidebar, !disabled); - gtk_widget_set_sensitive(GTK_WIDGET(this->tbSelectTab), !disabled); - - for (auto&& t: this->tabs) { - t->setTmpDisabled(disabled); - } - - gdk_display_sync(gdk_display_get_default()); -} - -void Sidebar::saveSize() { - GtkAllocation alloc; - gtk_widget_get_allocation(this->sidebarContents, &alloc); - - this->control->getSettings()->setSidebarWidth(alloc.width); -} - -size_t Sidebar::getNumberOfTabs() const { return this->tabs.size(); } - -size_t Sidebar::getSelectedTab() const { return this->currentTabIdx; } - -auto Sidebar::getControl() -> Control* { return this->control; } - -void Sidebar::documentChanged(DocumentChangeType type) { - if (type == DOCUMENT_CHANGE_CLEARED || type == DOCUMENT_CHANGE_COMPLETE || type == DOCUMENT_CHANGE_PDF_BOOKMARKS) { - updateVisibleTabs(); - } -} - -SidebarTabButton::SidebarTabButton(Sidebar* sidebar, size_t index, AbstractSidebarPage* page): - sidebar(sidebar), index(index), page(page) {} - -void Sidebar::layout() { - for (auto&& tab: this->tabs) { - tab->layout(); - } -} diff --git a/entry/src/main/cpp/src/core/gui/sidebar/Sidebar.h b/entry/src/main/cpp/src/core/gui/sidebar/Sidebar.h deleted file mode 100644 index e0a2af4..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/Sidebar.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Xournal++ - * - * The Sidebar - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for unique_ptr -#include // for vector - -#include // for GtkWidget, Gtk... - -#include "model/DocumentChangeType.h" // for DocumentChange... -#include "model/DocumentListener.h" // for DocumentListener - -class AbstractSidebarPage; -class Control; -class GladeGui; -class SidebarTabButton; - -class Sidebar: public DocumentListener { -public: - Sidebar(GladeGui* gui, Control* control); - ~Sidebar() override; - -private: - void initTabs(GtkWidget* sidebarContents); - void addTab(std::unique_ptr tab); - -public: - /** - * Layout sidebar - */ - void layout(); - - /** - * A page was selected, so also select this page in the sidebar - */ - void selectPageNr(size_t page, size_t pdfPage); - - Control* getControl(); - - /** - * Temporary disable Sidebar (e.g. while saving) - */ - void setTmpDisabled(bool disabled); - - /** - * Saves the current size to the settings - */ - void saveSize(); - - /** - * Get how many pages are contained in this sidebar - * - * Todo: it makes no sense to expose this, as the caller has no way of knowing what those pages correspond to - */ - [[deprecated]] size_t getNumberOfTabs() const; - - /** - * Get index of the currently selected page - * - * Todo: it makes no sense to expose this, as the caller has no way of knowing what this number corresponds to - */ - [[deprecated]] size_t getSelectedTab() const; - - /** - * Sets the current selected tab - * - * Todo: this should be private - */ - void setSelectedTab(size_t tab); - -public: - // DocumentListener interface - void documentChanged(DocumentChangeType type) override; - -private: - /** - * Page selected - */ - static void buttonClicked(GtkButton* button, SidebarTabButton* buttonData); - - /** - * Show/hide tabs based on whether they have content. Select first active tab (page). - */ - void updateVisibleTabs(); - - -private: - Control* control = nullptr; - - /** - * The sidebar pages - */ - std::vector> tabs; - - /** - * The bar with the tab selection - */ - GtkBox* tbSelectTab = nullptr; - - /** - * The close button of the sidebar - */ - GtkWidget* buttonCloseSidebar = nullptr; - - /** - * The current visible page in the sidebar - */ - GtkWidget* visibleTab = nullptr; - - /** - * Current active page - */ - size_t currentTabIdx{0}; - - /** - * The sidebarContents widget - */ - GtkWidget* sidebarContents = nullptr; -}; - -class SidebarTabButton { -public: - SidebarTabButton(Sidebar* sidebar, size_t index, AbstractSidebarPage* page); - -public: - Sidebar* sidebar = nullptr; - size_t index = 0; - AbstractSidebarPage* page = nullptr; -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/indextree/SidebarIndexPage.cpp b/entry/src/main/cpp/src/core/gui/sidebar/indextree/SidebarIndexPage.cpp deleted file mode 100644 index db57042..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/indextree/SidebarIndexPage.cpp +++ /dev/null @@ -1,305 +0,0 @@ -#include "SidebarIndexPage.h" - -#include // for strlen - -#include // for g_object_unref -#include // for PangoLogAttr - -#include "control/Control.h" // for Control -#include "control/ScrollHandler.h" // for ScrollHandler -#include "model/Document.h" // for Document -#include "model/LinkDestination.h" // for XojLinkDest -#include "util/Assert.h" // for xoj_assert -#include "util/glib_casts.h" // for wrap_v -#include "util/gtk4_helper.h" // -#include "util/i18n.h" // for _ -#include "util/safe_casts.h" // for as_unsigned - -SidebarIndexPage::SidebarIndexPage(Control* control): - AbstractSidebarPage(control), iconNameHelper(control->getSettings()) { - this->treeViewBookmarks = gtk_tree_view_new(); - g_object_ref(this->treeViewBookmarks); - - gtk_tree_view_set_enable_search(GTK_TREE_VIEW(treeViewBookmarks), true); - gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeViewBookmarks), DOCUMENT_LINKS_COLUMN_NAME); - gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeViewBookmarks), - reinterpret_cast(treeSearchFunction), this, - nullptr); - - this->scrollBookmarks = gtk_scrolled_window_new(); - g_object_ref(this->scrollBookmarks); - - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollBookmarks), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeViewBookmarks)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeViewBookmarks), false); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollBookmarks), treeViewBookmarks); - - - GtkTreeViewColumn* column = gtk_tree_view_column_new(); - gtk_tree_view_column_set_expand(GTK_TREE_VIEW_COLUMN(column), true); - gtk_tree_view_append_column(GTK_TREE_VIEW(treeViewBookmarks), column); - - auto* renderer = static_cast( - g_object_new(GTK_TYPE_CELL_RENDERER_TEXT, "ellipsize", PANGO_ELLIPSIZE_END, nullptr)); - gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column), renderer, true); - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "markup", DOCUMENT_LINKS_COLUMN_NAME, - nullptr); - - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_column_pack_end(GTK_TREE_VIEW_COLUMN(column), renderer, false); - gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column), renderer, "text", - DOCUMENT_LINKS_COLUMN_PAGE_NUMBER, nullptr); - g_object_set(G_OBJECT(renderer), "style", PANGO_STYLE_ITALIC, nullptr); - - this->selectHandler = g_signal_connect(treeViewBookmarks, "cursor-changed", G_CALLBACK(treeBookmarkSelected), this); - xoj_assert(this->selectHandler != 0); - - gtk_widget_show(this->treeViewBookmarks); - - registerListener(control); -} - -SidebarIndexPage::~SidebarIndexPage() { - if (this->searchTimeout) { - g_source_remove(this->searchTimeout); - this->searchTimeout = 0; - } - - g_object_unref(this->treeViewBookmarks); - g_object_unref(this->scrollBookmarks); -} - -void SidebarIndexPage::enableSidebar() {} - -void SidebarIndexPage::disableSidebar() { - // Nothing to do at the moment -} - -void SidebarIndexPage::treeBookmarkSelected(GtkTreeView* treeview, SidebarIndexPage* sidebar) { - if (sidebar->searchTimeout) { - return; - } - - gtk_widget_grab_focus(GTK_WIDGET(treeview)); - - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - - if (selection) { - GtkTreeModel* model = nullptr; - GtkTreeIter iter = {0}; - - if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - XojLinkDest* link = nullptr; - - gtk_tree_model_get(model, &iter, DOCUMENT_LINKS_COLUMN_LINK, &link, -1); - if (link && link->dest) { - LinkDestination* dest = link->dest; - - sidebar->control->getScrollHandler()->scrollToLinkDest(*dest); - } - g_object_unref(link); - } - } -} - -auto SidebarIndexPage::searchTimeoutFunc(SidebarIndexPage* sidebar) -> bool { - sidebar->searchTimeout = 0; - - treeBookmarkSelected(GTK_TREE_VIEW(sidebar->treeViewBookmarks), sidebar); - - return false; -} - -auto SidebarIndexPage::treeSearchFunction(GtkTreeModel* model, gint column, const gchar* key, GtkTreeIter* iter, - SidebarIndexPage* sidebar) -> gboolean { - if (sidebar->searchTimeout) { - g_source_remove(sidebar->searchTimeout); - sidebar->searchTimeout = 0; - } - sidebar->searchTimeout = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE, 2, - xoj::util::wrap_v, sidebar, nullptr); - - // Source: Pidgin - gchar* text = nullptr; - gtk_tree_model_get(model, iter, DOCUMENT_LINKS_COLUMN_NAME, &text, -1); - if (text == nullptr) { - return true; - } - - gchar* tmp = g_utf8_normalize(key, -1, G_NORMALIZE_DEFAULT); - gchar* enteredstring = g_utf8_casefold(tmp, -1); - g_free(tmp); - - tmp = g_utf8_normalize(text, -1, G_NORMALIZE_DEFAULT); - gchar* normalized = g_utf8_casefold(tmp, -1); - g_free(tmp); - - if (g_str_has_prefix(normalized, enteredstring)) { - g_free(enteredstring); - g_free(normalized); - return false; - } - - /* Use Pango to separate by words. */ - size_t len = as_unsigned(g_utf8_strlen(normalized, -1)); - PangoLogAttr* log_attrs = g_new(PangoLogAttr, len + 1); - - pango_get_log_attrs(normalized, static_cast(strlen(normalized)), -1, nullptr, log_attrs, - static_cast(len + 1)); - - gchar* word = normalized; - gboolean result = true; - for (size_t i = 0; i < (len - 1); i++) { - if (log_attrs[i].is_word_start && g_str_has_prefix(word, enteredstring)) { - result = false; - break; - } - word = g_utf8_next_char(word); - } - g_free(log_attrs); - - g_free(enteredstring); - g_free(normalized); - - return result; -} - -auto SidebarIndexPage::getName() -> std::string { return _("Contents"); } - -auto SidebarIndexPage::getIconName() -> std::string { return this->iconNameHelper.iconName("sidebar-index"); } - -auto SidebarIndexPage::hasData() -> bool { return this->hasContents; } - -auto SidebarIndexPage::getWidget() -> GtkWidget* { return this->scrollBookmarks; } - -auto SidebarIndexPage::expandOpenLinks(GtkTreeModel* model, GtkTreeIter* parent) -> int { - GtkTreeIter iter = {0}; - XojLinkDest* link = nullptr; - if (model == nullptr) { - return 0; - } - - int count = 0; - - if (gtk_tree_model_iter_children(model, &iter, parent)) { - do { - gtk_tree_model_get(model, &iter, DOCUMENT_LINKS_COLUMN_LINK, &link, -1); - - if (link->dest->getExpand()) { - GtkTreePath* path = gtk_tree_model_get_path(model, &iter); - gtk_tree_view_expand_row(GTK_TREE_VIEW(treeViewBookmarks), path, false); - gtk_tree_path_free(path); - } - - g_object_unref(link); - - count++; - - count += expandOpenLinks(model, &iter); - } while (gtk_tree_model_iter_next(model, &iter)); - } - - return count; -} - -void SidebarIndexPage::selectPageNr(size_t page, size_t pdfPage) { selectPageNr(page, pdfPage, nullptr); } - -auto SidebarIndexPage::selectPageNr(size_t page, size_t pdfPage, GtkTreeIter* parent) -> bool { - GtkTreeIter iter; - - Document* doc = control->getDocument(); - doc->lock_shared(); - GtkTreeModel* model = doc->getContentsModel(); - if (model == nullptr) { - doc->unlock_shared(); - return false; - } - - g_object_ref(model); - doc->unlock_shared(); - - if (parent == nullptr) { - - // check if there is already the current page selected - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeViewBookmarks)); - - if (gtk_tree_selection_get_selected(selection, &model, &iter)) { - XojLinkDest* link = nullptr; - - gtk_tree_model_get(model, &iter, DOCUMENT_LINKS_COLUMN_LINK, &link, -1); - - if (link && link->dest) { - LinkDestination* dest = link->dest; - - if (dest->getPdfPage() == pdfPage) { - - g_object_unref(model); - g_object_unref(link); - - // already a bookmark from this page selected - return true; - } - } - - g_object_unref(link); - } - } - - gboolean valid = gtk_tree_model_iter_children(model, &iter, parent); - - while (valid) { - XojLinkDest* link = nullptr; - - gtk_tree_model_get(model, &iter, DOCUMENT_LINKS_COLUMN_LINK, &link, -1); - - if (link->dest->getPdfPage() == pdfPage) { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeViewBookmarks)); - gtk_tree_selection_select_iter(selection, &iter); - - g_object_unref(link); - g_object_unref(model); - return true; - } - - - g_object_unref(link); - - if (selectPageNr(page, pdfPage, &iter)) { - g_object_unref(model); - return true; - } - - - valid = gtk_tree_model_iter_next(model, &iter); - } - - g_object_unref(model); - return false; -} - -void SidebarIndexPage::documentChanged(DocumentChangeType type) { - if (type == DOCUMENT_CHANGE_CLEARED) { - gtk_tree_view_set_model(GTK_TREE_VIEW(this->treeViewBookmarks), nullptr); - } else if (type == DOCUMENT_CHANGE_PDF_BOOKMARKS || type == DOCUMENT_CHANGE_COMPLETE) { - - Document* doc = this->control->getDocument(); - - // Block the cursor-change signal when the document changes, otherwise - // there will be a deadlock: both the selectHandler and this code will - // lock the document. - g_signal_handler_block(this->treeViewBookmarks, this->selectHandler); - doc->lock_shared(); - GtkTreeModel* model = doc->getContentsModel(); - gtk_tree_view_set_model(GTK_TREE_VIEW(this->treeViewBookmarks), model); - int count = expandOpenLinks(model, nullptr); - doc->unlock_shared(); - g_signal_handler_unblock(this->treeViewBookmarks, this->selectHandler); - this->treeBookmarkSelected(GTK_TREE_VIEW(this->treeViewBookmarks), this); - - hasContents = (count != 0); - } -} - -void SidebarIndexPage::layout() {} diff --git a/entry/src/main/cpp/src/core/gui/sidebar/indextree/SidebarIndexPage.h b/entry/src/main/cpp/src/core/gui/sidebar/indextree/SidebarIndexPage.h deleted file mode 100644 index 322b084..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/indextree/SidebarIndexPage.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Xournal++ - * - * Index Sidebar Page - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for string - -#include // for gboolean, gchar, gint -#include // for GtkWidget, GtkTreeIter - -#include "gui/IconNameHelper.h" // for IconNameHelper -#include "gui/sidebar/AbstractSidebarPage.h" // for AbstractSidebarPage -#include "model/DocumentChangeType.h" // for DocumentChangeType - -class Control; -class SidebarToolbar; - -class SidebarIndexPage: public AbstractSidebarPage { -public: - SidebarIndexPage(Control* control); - ~SidebarIndexPage() override; - -public: - void enableSidebar() override; - void disableSidebar() override; - - void layout() override; - - /** - * @overwrite - */ - std::string getName() override; - - /** - * @overwrite - */ - std::string getIconName() override; - - /** - * @overwrite - */ - bool hasData() override; - - /** - * @overwrite - */ - GtkWidget* getWidget() override; - - /** - * @overwrite - */ - void selectPageNr(size_t page, size_t pdfPage) override; - - /** - * Select page in the tree - */ - bool selectPageNr(size_t page, size_t pdfPage, GtkTreeIter* parent); - - /** - * @overwrite - */ - void documentChanged(DocumentChangeType type) override; - -private: - /** - * Tree search function if you type chars within the tree. Source: Pidgin - */ - static gboolean treeSearchFunction(GtkTreeModel* model, gint column, const gchar* key, GtkTreeIter* iter, - SidebarIndexPage* sidebar); - - /** - * A bookmark was selected - */ - static void treeBookmarkSelected(GtkTreeView* treeview, SidebarIndexPage* sidebar); - - /** - * The function which is called after a search timeout - */ - static auto searchTimeoutFunc(SidebarIndexPage* sidebar) -> bool; - -private: - /** - * Expand links - */ - int expandOpenLinks(GtkTreeModel* model, GtkTreeIter* parent); - -private: - /** - * The Tree with the Bookmarks - */ - GtkWidget* treeViewBookmarks = nullptr; - - /** - * The scrollbars for the Tree - */ - GtkWidget* scrollBookmarks = nullptr; - - /** - * Keep track of the tree bookmark selection handler; see documentChanged - * method for why this is necessary. - */ - unsigned long selectHandler = 0; // g_signal_connect uses 0 as error value - - /** - * If currently searching, scroll to the page is disable, else search is not really working - * - * After a timeout we scroll to the selected page - */ - guint searchTimeout = 0; - - /** - * If there is something to display in the tree - */ - bool hasContents = false; - - IconNameHelper iconNameHelper; -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarLayout.cpp b/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarLayout.cpp deleted file mode 100644 index 752f5a3..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarLayout.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "SidebarLayout.h" - -#include // for max -#include // for vector - -#include // for GTK_FIXED, gtk_fixed_move - -#include "util/gtk4_helper.h" -#include "util/safe_casts.h" // for as_unsigned - -#include "SidebarPreviewBase.h" // for SidebarPreviewBase -#include "SidebarPreviewBaseEntry.h" // for SidebarPreviewBaseEntry - -class SidebarRow { -public: - explicit SidebarRow(int width) { - this->width = width; - this->currentWidth = 0; - } - - ~SidebarRow() { clear(); } - - - auto isSpaceFor(SidebarPreviewBaseEntry* p) -> bool { - if (this->list.empty()) { - return true; - } - - if (this->currentWidth + p->getWidth() < width) { - return true; - } - return false; - } - - void add(SidebarPreviewBaseEntry* p) { - this->list.push_back(p); - this->currentWidth += p->getWidth(); - } - - void clear() { - this->list.clear(); - this->currentWidth = 0; - } - - auto getCount() -> size_t { return this->list.size(); } - - auto getWidth() const -> int { return this->currentWidth; } - - auto placeAt(int y, GtkFixed* layout) -> int { - int height = 0; - int x = 0; - - for (SidebarPreviewBaseEntry* p: this->list) { height = std::max(height, p->getHeight()); } - - - for (SidebarPreviewBaseEntry* p: this->list) { - int currentY = (height - p->getHeight()) / 2; - - gtk_fixed_move(layout, p->getWidget(), x, y + currentY); - - x += p->getWidth(); - } - - - return height; - } - -private: - int width; - int currentWidth; - - std::vector list; -}; - -void SidebarLayout::layout(SidebarPreviewBase* sidebar) { - int y = 0; - int width = 0; - - int sidebarWidth = gtk_widget_get_width(sidebar->scrollableBox.get()); - - SidebarRow row(sidebarWidth); - GtkFixed* w = sidebar->miniaturesContainer.get(); - - for (auto& p: sidebar->previews) { - if (row.isSpaceFor(p.get())) { - row.add(p.get()); - } else { - y += row.placeAt(y, w); - - width = std::max(width, row.getWidth()); - - row.clear(); - row.add(p.get()); - } - } - - if (row.getCount() != 0) { - y += row.placeAt(y, w); - - width = std::max(width, row.getWidth()); - - row.clear(); - } - - gtk_widget_set_size_request(GTK_WIDGET(w), width, y); - gtk_widget_show_all(GTK_WIDGET(w)); -} diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarLayout.h b/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarLayout.h deleted file mode 100644 index 5ca6a1f..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarLayout.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Xournal++ - * - * Sidebar preview layout - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -class SidebarPreviewBase; - -class SidebarLayout { -public: - SidebarLayout() = delete; - ~SidebarLayout() = delete; - -public: - /** - * Layouts the sidebar - */ - static void layout(SidebarPreviewBase* sidebar); - -private: -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBase.cpp b/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBase.cpp deleted file mode 100644 index da93df4..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBase.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "SidebarPreviewBase.h" - -#include // for abs, size_t - -#include // for g_object_ref, G_CALLBACK, g_sig... -#include // for g_idle_add - -#include "control/Control.h" // for Control -#include "control/PdfCache.h" // for PdfCache -#include "gui/Builder.h" // for Builder -#include "gui/MainWindow.h" // for MainWindow -#include "model/Document.h" // for Document -#include "util/Util.h" // for npos -#include "util/glib_casts.h" // for wrap_for_once_v -#include "util/gtk4_helper.h" - -#include "SidebarLayout.h" // for SidebarLayout -#include "SidebarPreviewBaseEntry.h" // for SidebarPreviewBaseEntry - -constexpr auto XML_FILE = "sidebar.ui"; - -SidebarPreviewBase::SidebarPreviewBase(Control* control, const char* menuId, const char* toolbarId): - AbstractSidebarPage(control), - scrollableBox(gtk_scrolled_window_new(), xoj::util::adopt), - mainBox(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0), xoj::util::adopt), - miniaturesContainer(GTK_FIXED(gtk_fixed_new()), xoj::util::adopt) { - gtk_box_append(GTK_BOX(mainBox.get()), scrollableBox.get()); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollableBox.get()), GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scrollableBox.get()), GTK_WIDGET(miniaturesContainer.get())); - gtk_widget_set_vexpand(scrollableBox.get(), true); - - Document* doc = this->control->getDocument(); - doc->lock_shared(); - if (doc->getPdfPageCount() != 0) { - this->cache = std::make_unique(doc->getPdfDocument(), control->getSettings()); - } - doc->unlock_shared(); - - - registerListener(this->control); - this->control->addChangedDocumentListener(this); - - auto* adj = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(scrollableBox.get())); - g_signal_connect( - adj, "notify::page-size", G_CALLBACK(+[](GObject* adj, GParamSpec*, gpointer d) { - static_cast(d)->newWidth(gtk_adjustment_get_page_size(GTK_ADJUSTMENT(adj))); - }), - this); - - Builder builder(control->getGladeSearchPath(), XML_FILE); - GMenuModel* menu = G_MENU_MODEL(builder.get(menuId)); - contextMenu.reset(GTK_MENU(gtk_menu_new_from_model(menu)), xoj::util::adopt); - gtk_menu_attach_to_widget(contextMenu.get(), mainBox.get(), nullptr); - - gtk_box_append(GTK_BOX(mainBox.get()), builder.get(toolbarId)); - - gtk_widget_show_all(mainBox.get()); -} - -SidebarPreviewBase::~SidebarPreviewBase() { this->control->removeChangedDocumentListener(this); } - -void SidebarPreviewBase::enableSidebar() { - if (!this->enabled) { - enabled = true; - layout(); - } -} - -void SidebarPreviewBase::disableSidebar() { enabled = false; } - -void SidebarPreviewBase::newWidth(double width) { - static constexpr double TRIGGER = 20.; - - if (std::abs(lastWidth - width) > TRIGGER) { - this->layout(); - lastWidth = width; - } -} - -auto SidebarPreviewBase::getZoom() const -> double { return this->zoom; } - -auto SidebarPreviewBase::getCache() -> PdfCache* { return this->cache.get(); } - -void SidebarPreviewBase::layout() { - if (enabled) { - SidebarLayout::layout(this); - } -} - -auto SidebarPreviewBase::hasData() -> bool { return true; } - -auto SidebarPreviewBase::getWidget() -> GtkWidget* { return this->mainBox.get(); } - -void SidebarPreviewBase::documentChanged(DocumentChangeType type) { - if (type == DOCUMENT_CHANGE_COMPLETE || type == DOCUMENT_CHANGE_CLEARED) { - this->cache.reset(); - - Document* doc = control->getDocument(); - doc->lock_shared(); - if (doc->getPdfPageCount() != 0) { - this->cache = std::make_unique(doc->getPdfDocument(), control->getSettings()); - } - doc->unlock_shared(); - updatePreviews(); - } -} - -auto SidebarPreviewBase::scrollToPreview(SidebarPreviewBase* sidebar) -> bool { - if (!sidebar->enabled) { - return false; - } - - MainWindow* win = sidebar->control->getWindow(); - if (win == nullptr) { - return false; - } - - GtkWidget* w = win->get("sidebar"); - if (!gtk_widget_get_visible(w)) { - return false; - } - - if (sidebar->selectedEntry != npos && sidebar->selectedEntry < sidebar->previews.size()) { - auto& p = sidebar->previews[sidebar->selectedEntry]; - - // scroll to preview - GtkAdjustment* vadj = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(sidebar->scrollableBox.get())); - GtkWidget* widget = p->getWidget(); - - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - int x = allocation.x; - int y = allocation.y; - - if (x == -1) { - g_idle_add(xoj::util::wrap_for_once_v, sidebar); - return false; - } - - gtk_adjustment_clamp_page(vadj, y, y + allocation.height); - } - return false; -} - -void SidebarPreviewBase::pageDeleted(size_t page) {} - -void SidebarPreviewBase::pageInserted(size_t page) {} - -void SidebarPreviewBase::openPreviewContextMenu(GdkEvent* currentEvent) { - gtk_menu_popup_at_pointer(contextMenu.get(), currentEvent); -} diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBase.h b/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBase.h deleted file mode 100644 index d259c13..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBase.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Xournal++ - * - * Base class for prviews in the sidebar - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for unique_ptr -#include // for vector - -#include // for GtkWidget, GtkAllocation - -#include "gui/sidebar/AbstractSidebarPage.h" // for AbstractSidebarPage -#include "model/DocumentChangeType.h" // for DocumentChangeType -#include "util/Util.h" -#include "util/raii/GObjectSPtr.h" - -class PdfCache; -class SidebarLayout; -class SidebarPreviewBaseEntry; -class Control; - -class SidebarPreviewBase: public AbstractSidebarPage { -public: - SidebarPreviewBase(Control* control, const char* menuId, const char* toolbarId); - ~SidebarPreviewBase() override; - -public: - void enableSidebar() override; - void disableSidebar() override; - - /** - * Layout the pages to the current size of the sidebar - */ - void layout() override; - - /** - * Update the preview images - */ - virtual void updatePreviews() = 0; - - /** - * @overwrite - */ - bool hasData() override; - - /** - * @overwrite - */ - GtkWidget* getWidget() override; - - /** - * Gets the zoom factor for the previews - */ - double getZoom() const; - - /** - * Gets the PDF cache for preview rendering - */ - PdfCache* getCache(); - -public: - // DocumentListener interface (only the part handled by SidebarPreviewBase) - void documentChanged(DocumentChangeType type) override; - void pageInserted(size_t page) override; - void pageDeleted(size_t page) override; - -protected: - /** - * Timeout callback to scroll to a page - */ - static bool scrollToPreview(SidebarPreviewBase* sidebar); - - /// The width of the sidebar has changed - void newWidth(double width); - -public: - /** - * Opens a context menu, at the current cursor position. - */ - void openPreviewContextMenu(GdkEvent* currentEvent); - -private: - /** - * The Zoom of the previews - */ - double zoom = 0.15; - - /// last recorded width of the sidebar - double lastWidth = -1; - - /** - * For preview rendering - */ - std::unique_ptr cache; - -protected: - /// The scrollable area with the miniatures - xoj::util::WidgetSPtr scrollableBox; - - /// Main box, containing the scrollable area and the toolbar. - xoj::util::WidgetSPtr mainBox; - - /// The widget within the scrollable area with the page miniatures - xoj::util::GObjectSPtr miniaturesContainer; - - /** - * The context menu to display when a miniature is right-clicked. - * This must be populated by the derived classes constructors. - * It must be a GtkPopover parented (gtk_widget_set_parent()) by this->miniaturesContainer - */ - xoj::util::GObjectSPtr contextMenu; - - /** - * The currently selected entry in the sidebar, starting from 0 - * -1 means no valid selection - */ - size_t selectedEntry = npos; - - /** - * The previews - */ - std::vector> previews; - - /** - * The sidebar is enabled - */ - bool enabled = false; - - friend class SidebarLayout; -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBaseEntry.cpp b/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBaseEntry.cpp deleted file mode 100644 index 74a117c..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBaseEntry.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "SidebarPreviewBaseEntry.h" - -#include // for GdkEvent, GDK_BUTTON_PRESS -#include // for G_CALLBACK, g_object_ref -#include // - -#include "control/Control.h" // for Control -#include "control/jobs/XournalScheduler.h" // for XournalScheduler -#include "control/settings/Settings.h" // for Settings -#include "gui/Shadow.h" // for Shadow -#include "model/XojPage.h" // for XojPage -#include "util/Color.h" // for cairo_set_source_rgbi -#include "util/gtk4_helper.h" // -#include "util/i18n.h" // for _ -#include "util/safe_casts.h" // for floor_cast - -#include "SidebarPreviewBase.h" // for SidebarPreviewBase - -static constexpr int MAX_MINIATURE_SIZE = 500; ///< in pixels - avoid things going very wrong when pages are huge - -SidebarPreviewBaseEntry::SidebarPreviewBaseEntry(SidebarPreviewBase* sidebar, const PageRef& page): - sidebar(sidebar), page(page), button(gtk_button_new(), xoj::util::adopt) { - - updateSize(); - gtk_widget_set_events(this->button.get(), GDK_EXPOSURE_MASK); - - g_signal_connect(this->button.get(), "draw", G_CALLBACK(drawCallback), this); - - g_signal_connect(this->button.get(), "clicked", G_CALLBACK(+[](GtkButton*, gpointer self) { - static_cast(self)->mouseButtonPressCallback(); - }), - this); - - const auto clickCallback = G_CALLBACK(+[](GtkWidget*, GdkEvent* event, gpointer self) { - // Open context menu on right mouse click - if (event->type == GDK_BUTTON_PRESS) { - auto mouseEvent = reinterpret_cast(event); - if (mouseEvent->button == 3) { - static_cast(self)->mouseButtonPressCallback(); - static_cast(self)->sidebar->openPreviewContextMenu(event); - return true; - } - } - return false; - }); - g_signal_connect_after(this->button.get(), "button-press-event", clickCallback, this); -} - -SidebarPreviewBaseEntry::~SidebarPreviewBaseEntry() { - this->sidebar->getControl()->getScheduler()->removeSidebar(this); -} - -auto SidebarPreviewBaseEntry::drawCallback(GtkWidget* widget, cairo_t* cr, SidebarPreviewBaseEntry* preview) - -> gboolean { - preview->paint(cr); - return true; -} - -void SidebarPreviewBaseEntry::setSelected(bool selected) { - if (this->selected == selected) { - return; - } - this->selected = selected; - - gtk_widget_queue_draw(this->button.get()); -} - -void SidebarPreviewBaseEntry::repaint() { sidebar->getControl()->getScheduler()->addRepaintSidebar(this); } - -void SidebarPreviewBaseEntry::drawLoadingPage() { - this->buffer.reset(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, imageWidth, imageHeight), xoj::util::adopt); - - double zoom = sidebar->getZoom(); - - cairo_t* cr2 = cairo_create(this->buffer.get()); - cairo_matrix_t defaultMatrix = {0}; - cairo_get_matrix(cr2, &defaultMatrix); - - cairo_translate(cr2, Shadow::getShadowTopLeftSize() + 2, Shadow::getShadowTopLeftSize() + 2); - - cairo_scale(cr2, zoom, zoom); - - const char* txtLoading = _("Loading..."); - - cairo_text_extents_t ex; - cairo_set_source_rgb(cr2, 0.5, 0.5, 0.5); - cairo_select_font_face(cr2, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); - cairo_set_font_size(cr2, 70.0); - cairo_text_extents(cr2, txtLoading, &ex); - cairo_move_to(cr2, (page->getWidth() - ex.width) / 2 - ex.x_bearing, - (page->getHeight() - ex.height) / 2 - ex.y_bearing); - cairo_text_path(cr2, txtLoading); - - cairo_destroy(cr2); -} - -void SidebarPreviewBaseEntry::paint(cairo_t* cr) { - double height = page->getHeight() * sidebar->getZoom(); - double width = page->getWidth() * sidebar->getZoom(); - - if (this->selected) { - Shadow::drawShadow(cr, Shadow::getShadowTopLeftSize(), Shadow::getShadowTopLeftSize(), - round_cast(width) + 4, round_cast(height) + 4); - // Draw border - Util::cairo_set_source_rgbi(cr, sidebar->getControl()->getSettings()->getBorderColor()); - cairo_set_line_width(cr, 2); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); - - cairo_rectangle(cr, Shadow::getShadowTopLeftSize() + 0.5, Shadow::getShadowTopLeftSize() + 0.5, width + 3, - height + 3); - - cairo_stroke(cr); - } else { - Shadow::drawShadow(cr, Shadow::getShadowTopLeftSize() + 2, Shadow::getShadowTopLeftSize() + 2, - round_cast(width), round_cast(height)); - } - - this->drawingMutex.lock(); - - bool doRepaint = false; - if (!this->buffer) { - drawLoadingPage(); - doRepaint = true; - } - - cairo_set_source_surface(cr, this->buffer.get(), 0, 0); - cairo_paint(cr); - - this->drawingMutex.unlock(); - - const auto& recolorParams = sidebar->getControl()->getSettings()->getRecolorParameters(); - auto recolor = recolorParams.recolorizeSidebarMiniatures ? std::make_optional(recolorParams.recolor) : std::nullopt; - - if (recolor) { - // encapsulate in save/restore to limit the scope of the clip operation - xoj::util::CairoSaveGuard const saveGuard(cr); - cairo_rectangle(cr, Shadow::getShadowTopLeftSize() + 2, Shadow::getShadowTopLeftSize() + 2, width, height); - // constrain the area which is painted on - cairo_clip(cr); - recolor->recolorCurrentCairoRegion(cr); - } - - if (doRepaint) { - repaint(); - } -} - -void SidebarPreviewBaseEntry::updateSize() { - this->DPIscaling = gtk_widget_get_scale_factor(this->button.get()); - - const int shadowPadding = Shadow::getShadowBottomRightSize() + Shadow::getShadowTopLeftSize() + 4; - // To avoid having a black line, we use floor rather than ceil - this->imageWidth = - std::min(floor_cast(page->getWidth() * sidebar->getZoom()) + shadowPadding, MAX_MINIATURE_SIZE); - this->imageHeight = - std::min(floor_cast(page->getHeight() * sidebar->getZoom()) + shadowPadding, MAX_MINIATURE_SIZE); - gtk_widget_set_size_request(this->button.get(), imageWidth, imageHeight); -} - -auto SidebarPreviewBaseEntry::getWidget() const -> GtkWidget* { return this->button.get(); } - -auto SidebarPreviewBaseEntry::getWidth() const -> int { return imageWidth; } - -auto SidebarPreviewBaseEntry::getHeight() const -> int { return imageHeight; } diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBaseEntry.h b/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBaseEntry.h deleted file mode 100644 index 6f87e53..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/base/SidebarPreviewBaseEntry.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Xournal++ - * - * A preview entry in a sidebar - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for mutex - -#include // for cairo_t, cairo_surface_t -#include // for gboolean -#include // for GtkWidget - -#include "model/PageRef.h" // for PageRef -#include "util/raii/CairoWrappers.h" -#include "util/raii/GObjectSPtr.h" - -class SidebarPreviewBase; - -typedef enum { - /** - * Render the whole page - */ - RENDER_TYPE_PAGE_PREVIEW = 1, - - /** - * Render only a layer - */ - RENDER_TYPE_PAGE_LAYER, - - /** - * Render the stack up to a layer - */ - RENDER_TYPE_PAGE_LAYERSTACK -} PreviewRenderType; - - -class SidebarPreviewBaseEntry { -public: - SidebarPreviewBaseEntry(SidebarPreviewBase* sidebar, const PageRef& page); - virtual ~SidebarPreviewBaseEntry(); - -public: - virtual GtkWidget* getWidget() const; - virtual int getWidth() const; - virtual int getHeight() const; - - virtual void setSelected(bool selected); - - virtual void repaint(); - virtual void updateSize(); - - /** - * @return What should be rendered - */ - virtual PreviewRenderType getRenderType() const = 0; - -private: - static gboolean drawCallback(GtkWidget* widget, cairo_t* cr, SidebarPreviewBaseEntry* preview); - -protected: - virtual void mouseButtonPressCallback() = 0; - - virtual void drawLoadingPage(); - virtual void paint(cairo_t* cr); - -protected: - /** - * If this page is currently selected - */ - bool selected = false; - - int imageWidth; - int imageHeight; - int DPIscaling; ///< 1, maybe 2 in HiDPI setups - - /** - * The sidebar which displays the previews - */ - SidebarPreviewBase* sidebar; - - /** - * The page which is representated - */ - PageRef page; - - /// Mutex protecting the buffer - std::mutex drawingMutex{}; - - /// Buffer because of performance reasons - xoj::util::CairoSurfaceSPtr buffer; - - /// The main widget, containing the miniature - xoj::util::WidgetSPtr button; - - friend class PreviewJob; -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayerEntry.cpp b/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayerEntry.cpp deleted file mode 100644 index d7ee069..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayerEntry.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "SidebarPreviewLayerEntry.h" - -#include // for GdkEvent, GDK_BUTTON_PRESS, GdkEve... -#include // for G_CALLBACK, g_signal_connect, g_si... - -#include "gui/Shadow.h" // for Shadow -#include "util/gtk4_helper.h" - -#include "SidebarPreviewLayers.h" // for SidebarPreviewLayers - - -SidebarPreviewLayerEntry::SidebarPreviewLayerEntry(SidebarPreviewLayers* sidebar, const PageRef& page, - Layer::Index layerId, const std::string& layerName, bool stacked): - SidebarPreviewBaseEntry(sidebar, page), - sidebar(sidebar), - layerId(layerId), - box(gtk_box_new(GTK_ORIENTATION_VERTICAL, 4), xoj::util::adopt), - stacked(stacked) { - -#if GTK_CHECK_VERSION(4, 8, 0) - cbVisible = gtk_check_button_new(); - GtkWidget* lbl = gtk_label_new(layerName.c_str()); - gtk_label_set_ellipsize(GTK_LABEL(lbl), PANGO_ELLIPSIZE_END); - gtk_check_button_set_child(GTK_CHECK_BUTTON(cbVisible), lbl); -#else - cbVisible = gtk_check_button_new_with_label(layerName.c_str()); -#endif - - callbackId = g_signal_connect( - cbVisible, "toggled", G_CALLBACK(+[](GtkCheckButton* btn, gpointer d) { - auto* self = static_cast(d); - bool check = gtk_check_button_get_active(btn); - (dynamic_cast(self->sidebar))->layerVisibilityChanged(self->layerId, check); - }), - this); - gtk_widget_set_margin_start(cbVisible, Shadow::getShadowTopLeftSize()); - - // This doesn't really do it. gtk_widget_get_allocated_height() always returns 1... - toolbarHeight = gtk_widget_get_allocated_height(cbVisible) + Shadow::getShadowTopLeftSize() + 20; - gtk_box_append(GTK_BOX(box.get()), this->button.get()); - gtk_box_append(GTK_BOX(box.get()), cbVisible); - - gtk_widget_show_all(box.get()); -} - -SidebarPreviewLayerEntry::~SidebarPreviewLayerEntry() { - GtkWidget* w = this->getWidget(); - gtk_fixed_remove(GTK_FIXED(gtk_widget_get_parent(w)), w); -} - -void SidebarPreviewLayerEntry::mouseButtonPressCallback() { - (dynamic_cast(sidebar))->layerSelected(layerId); -} - -auto SidebarPreviewLayerEntry::getRenderType() const -> PreviewRenderType { - return stacked ? RENDER_TYPE_PAGE_LAYERSTACK : RENDER_TYPE_PAGE_LAYER; -} - -auto SidebarPreviewLayerEntry::getHeight() const -> int { return imageHeight + toolbarHeight; } - -auto SidebarPreviewLayerEntry::getLayer() const -> Layer::Index { return layerId; } - -auto SidebarPreviewLayerEntry::getWidget() const -> GtkWidget* { return this->box.get(); } - -/** - * Set the value of the visible checkbox - */ -void SidebarPreviewLayerEntry::setVisibleCheckbox(bool enabled) { - g_signal_handler_block(cbVisible, callbackId); - gtk_check_button_set_active(GTK_CHECK_BUTTON(cbVisible), enabled); - g_signal_handler_unblock(cbVisible, callbackId); -} diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayerEntry.h b/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayerEntry.h deleted file mode 100644 index 3a8ec3a..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayerEntry.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Xournal++ - * - * A Sidebar preview widget - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for string - -#include // for GtkWi... - -#include "gui/sidebar/previews/base/SidebarPreviewBaseEntry.h" // for Previ... -#include "model/Layer.h" // for Layer -#include "model/PageRef.h" // for PageRef -#include "util/raii/GObjectSPtr.h" - -class SidebarPreviewLayers; - -class SidebarPreviewLayerEntry: public SidebarPreviewBaseEntry { -public: - SidebarPreviewLayerEntry(SidebarPreviewLayers* sidebar, const PageRef& page, Layer::Index layerId, - const std::string& layerName, bool stacked); - ~SidebarPreviewLayerEntry() override; - -public: - int getHeight() const override; - - /** - * @return What should be rendered - * @override - */ - PreviewRenderType getRenderType() const override; - - /** - * @return The layer to be rendered - */ - Layer::Index getLayer() const; - - GtkWidget* getWidget() const override; - - /** - * Set the value of the visible checkbox - */ - void setVisibleCheckbox(bool enabled); - -protected: - void mouseButtonPressCallback() override; - void checkboxToggled(); - - SidebarPreviewLayers* sidebar; - -private: - /// Layer to render - Layer::Index layerId; - - /** - * Toolbar with controls - */ - int toolbarHeight = 0; - - /// Container box for the preview and the button - xoj::util::WidgetSPtr box; - - /// Visibility checkbox - GtkWidget* cbVisible = nullptr; - gulong callbackId = 0; - - /// render as stacked - bool stacked = false; - - friend class PreviewJob; -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayers.cpp b/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayers.cpp deleted file mode 100644 index 53535ce..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayers.cpp +++ /dev/null @@ -1,143 +0,0 @@ -#include "SidebarPreviewLayers.h" - -#include // for max -#include // for vector - -#include // for gtk... - -#include "control/Control.h" // for Con... -#include "control/layer/LayerController.h" // for Lay... -#include "gui/sidebar/previews/base/SidebarPreviewBaseEntry.h" // for Sid... -#include "model/PageRef.h" // for Pag... -#include "model/XojPage.h" // for Xoj... -#include "util/Util.h" // for npos -#include "util/gtk4_helper.h" -#include "util/i18n.h" // for _ - -#include "SidebarPreviewLayerEntry.h" // for Sid... - -constexpr auto MENU_ID = "PreviewLayersContextMenu"; -constexpr auto TOOLBAR_ID = "PreviewLayersToolbar"; - -SidebarPreviewLayers::SidebarPreviewLayers(Control* control, bool stacked): - SidebarPreviewBase(control, MENU_ID, TOOLBAR_ID), - lc(control->getLayerController()), - stacked(stacked), - iconNameHelper(control->getSettings()) { - LayerCtrlListener::registerListener(lc); -} - -SidebarPreviewLayers::~SidebarPreviewLayers() = default; - -void SidebarPreviewLayers::enableSidebar() { - SidebarPreviewBase::enableSidebar(); - rebuildLayerMenu(); -} - -auto SidebarPreviewLayers::getName() -> std::string { return stacked ? _("Layerstack Preview") : _("Layer Preview"); } - -auto SidebarPreviewLayers::getIconName() -> std::string { - const char* icon = stacked ? "sidebar-layerstack" : "sidebar-layer"; - return this->iconNameHelper.iconName(icon); -} - -void SidebarPreviewLayers::pageSizeChanged(size_t page) { - if (page != this->lc->getCurrentPageId() || !enabled) { - return; - } - - updatePreviews(); -} - -void SidebarPreviewLayers::pageChanged(size_t page) { - if (page != this->lc->getCurrentPageId() || !enabled) { - return; - } - - // Repaint all layer - for (auto& p: this->previews) { p->repaint(); } -} - -void SidebarPreviewLayers::updatePreviews() { - if (!enabled) { - return; - } - - // clear old previews - this->previews.clear(); - this->selectedEntry = npos; - - PageRef page = lc->getCurrentPage(); - if (!page) { - return; - } - - auto layerCount = page->getLayerCount(); - - for (auto i = layerCount + 1; i != 0;) { - --i; - std::string name = lc->getLayerNameById(i); - auto p = std::make_unique(this, page, i, name, this->stacked); - gtk_fixed_put(this->miniaturesContainer.get(), p->getWidget(), 0, 0); - this->previews.emplace_back(std::move(p)); - } - - layout(); - updateSelectedLayer(); - layerVisibilityChanged(); -} - -void SidebarPreviewLayers::rebuildLayerMenu() { - if (!enabled) { - return; - } - - updatePreviews(); -} - -void SidebarPreviewLayers::layerVisibilityChanged() { - PageRef p = lc->getCurrentPage(); - if (!p) { - return; - } - - Layer::Index i = p->getLayerCount(); - for (auto& e: this->previews) { - dynamic_cast(e.get())->setVisibleCheckbox(p->isLayerVisible(i--)); - } - updateSelectedLayer(); -} - -void SidebarPreviewLayers::updateSelectedLayer() { - // Layers are in reverse order (top index: 0, but bottom preview is 0) - size_t entryIndex = this->previews.size() - lc->getCurrentLayerId() - 1; - - if (this->selectedEntry == entryIndex) { - return; - } - - if (this->selectedEntry != npos && this->selectedEntry < this->previews.size()) { - this->previews[this->selectedEntry]->setSelected(false); - } - - this->selectedEntry = entryIndex; - if (this->selectedEntry != npos && this->selectedEntry < this->previews.size()) { - auto& p = this->previews[this->selectedEntry]; - p->setSelected(true); - scrollToPreview(this); - } -} - -void SidebarPreviewLayers::layerSelected(Layer::Index layerId) { - if (layerId != 0) { // We can't select the background - lc->switchToLay(layerId); - updateSelectedLayer(); - } -} - -/** - * A layer was hidden / showed - */ -void SidebarPreviewLayers::layerVisibilityChanged(Layer::Index layerIndex, bool enabled) { - lc->setLayerVisible(layerIndex, enabled); -} diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayers.h b/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayers.h deleted file mode 100644 index 4beb439..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/layer/SidebarPreviewLayers.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Xournal++ - * - * Previews of the layers in the current page - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for shared_ptr -#include // for string - -#include "control/layer/LayerCtrlListener.h" // for LayerCtrlL... -#include "gui/IconNameHelper.h" // for IconNameHe... -#include "gui/sidebar/previews/base/SidebarPreviewBase.h" // for SidebarPre... -#include "model/Layer.h" // for Layer, Lay... - -class Control; -class GladeGui; -class LayerController; -class SidebarLayersContextMenu; - - -class SidebarPreviewLayers: public SidebarPreviewBase, public LayerCtrlListener { -public: - SidebarPreviewLayers(Control* control, bool stacked); - - ~SidebarPreviewLayers() override; - -public: - void rebuildLayerMenu() override; - void layerVisibilityChanged() override; - void updateSelectedLayer() override; - -public: - void enableSidebar() override; - - /** - * @overwrite - */ - std::string getName() override; - - /** - * @overwrite - */ - std::string getIconName() override; - - /** - * Update the preview images - * @overwrite - */ - void updatePreviews() override; - - /** - * Select a layer - */ - void layerSelected(Layer::Index layerIndex); - - /** - * A layer was hidden / showed - */ - void layerVisibilityChanged(Layer::Index layerIndex, bool enabled); - -public: - // DocumentListener interface (only the part which is not handled by SidebarPreviewBase) - void pageSizeChanged(size_t page) override; - void pageChanged(size_t page) override; - -private: - /** - * Layer Controller - */ - LayerController* lc; - - /** - * render as stacked - */ - bool stacked; - - IconNameHelper iconNameHelper; -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPageEntry.cpp b/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPageEntry.cpp deleted file mode 100644 index 38a1a99..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPageEntry.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "SidebarPreviewPageEntry.h" - -#include "control/Control.h" // for Control -#include "control/ScrollHandler.h" // for ScrollHan... -#include "control/settings/Settings.h" // for Settings -#include "gui/PagePreviewDecoration.h" // for Drawing ... -#include "gui/sidebar/previews/page/SidebarPreviewPages.h" // for SidebarPr... -#include "util/gtk4_helper.h" - -SidebarPreviewPageEntry::SidebarPreviewPageEntry(SidebarPreviewPages* sidebar, const PageRef& page, size_t index): - SidebarPreviewBaseEntry(sidebar, page), sidebar(sidebar), index(index) { - if (sidebar->getControl()->getSettings()->getSidebarNumberingStyle() == - SidebarNumberingStyle::NUMBER_BELOW_PREVIEW) { - gtk_widget_set_size_request(this->button.get(), imageWidth, imageHeight + PagePreviewDecoration::MARGIN_BOTTOM); - } -} - -SidebarPreviewPageEntry::~SidebarPreviewPageEntry() { - GtkWidget* w = this->getWidget(); - gtk_fixed_remove(GTK_FIXED(gtk_widget_get_parent(w)), w); -} - -auto SidebarPreviewPageEntry::getRenderType() const -> PreviewRenderType { return RENDER_TYPE_PAGE_PREVIEW; } - -void SidebarPreviewPageEntry::mouseButtonPressCallback() { - sidebar->getControl()->getScrollHandler()->scrollToPage(page); - sidebar->getControl()->firePageSelected(page); -} - -void SidebarPreviewPageEntry::paint(cairo_t* cr) { - SidebarPreviewBaseEntry::paint(cr); - if (sidebar->getControl()->getSettings()->getSidebarNumberingStyle() == SidebarNumberingStyle::NONE) { - return; - } - drawEntryNumber(cr); -} - -void SidebarPreviewPageEntry::drawEntryNumber(cairo_t* cr) { - PagePreviewDecoration::drawDecoration(cr, this, this->sidebar->getControl()); -} - -auto SidebarPreviewPageEntry::getHeight() const -> int { - if (sidebar->getControl()->getSettings()->getSidebarNumberingStyle() == - SidebarNumberingStyle::NUMBER_BELOW_PREVIEW) { - return imageHeight + PagePreviewDecoration::MARGIN_BOTTOM; - } - return imageHeight; -} - -void SidebarPreviewPageEntry::setIndex(size_t index) { this->index = index; } - -size_t SidebarPreviewPageEntry::getIndex() const { return this->index; } - -bool SidebarPreviewPageEntry::isSelected() const { return this->selected; } - -double SidebarPreviewPageEntry::getZoom() const { return this->sidebar->getZoom(); } diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPageEntry.h b/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPageEntry.h deleted file mode 100644 index fc5ff99..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPageEntry.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Xournal++ - * - * A Sidebar preview widget - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "gui/sidebar/previews/base/SidebarPreviewBaseEntry.h" // for Previ... -#include "model/PageRef.h" // for PageRef - -class SidebarPreviewPages; - -class SidebarPreviewPageEntry: public SidebarPreviewBaseEntry { -public: - SidebarPreviewPageEntry(SidebarPreviewPages* sidebar, const PageRef& page, size_t index); - ~SidebarPreviewPageEntry() override; - -public: - int getHeight() const override; - - PreviewRenderType getRenderType() const override; - - void setIndex(size_t index); - size_t getIndex() const; - - bool isSelected() const; - double getZoom() const; - -protected: - SidebarPreviewPages* sidebar; - void mouseButtonPressCallback() override; - void paint(cairo_t* cr) override; - -private: - size_t index; - friend class PreviewJob; - - void drawEntryNumber(cairo_t* cr); -}; diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPages.cpp b/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPages.cpp deleted file mode 100644 index c4271a5..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPages.cpp +++ /dev/null @@ -1,139 +0,0 @@ -#include "SidebarPreviewPages.h" - -#include // for max -#include // for map -#include // for uniqu... -#include // for pair - -#include // for g_obj... - -#include "control/Control.h" // for Control -#include "gui/sidebar/previews/base/SidebarPreviewBaseEntry.h" // for Sideb... -#include "model/Document.h" // for Document -#include "model/PageRef.h" // for PageRef -#include "util/Assert.h" // for xoj_assert -#include "util/Util.h" // for npos -#include "util/gtk4_helper.h" -#include "util/i18n.h" // for _ -#include "util/safe_casts.h" // for as_signed - -#include "SidebarPreviewPageEntry.h" // for Sideb... - -constexpr auto MENU_ID = "PreviewPagesContextMenu"; -constexpr auto TOOLBAR_ID = "PreviewPagesToolbar"; - -SidebarPreviewPages::SidebarPreviewPages(Control* control): - SidebarPreviewBase(control, MENU_ID, TOOLBAR_ID), iconNameHelper(control->getSettings()) {} - -SidebarPreviewPages::~SidebarPreviewPages() = default; - -void SidebarPreviewPages::enableSidebar() { - SidebarPreviewBase::enableSidebar(); - - pageSelected(this->selectedEntry); -} - -auto SidebarPreviewPages::getName() -> std::string { return _("Page Preview"); } - -auto SidebarPreviewPages::getIconName() -> std::string { return this->iconNameHelper.iconName("sidebar-page-preview"); } - -void SidebarPreviewPages::updatePreviews() { - this->previews.clear(); - - Document* doc = this->getControl()->getDocument(); - doc->lock_shared(); - size_t len = doc->getPageCount(); - for (size_t i = 0; i < len; i++) { - auto p = std::make_unique(this, doc->getPage(i), i); - gtk_fixed_put(this->miniaturesContainer.get(), p->getWidget(), 0, 0); - this->previews.emplace_back(std::move(p)); - } - doc->unlock_shared(); - - layout(); -} - -void SidebarPreviewPages::pageSizeChanged(size_t page) { - if (page == npos || page >= this->previews.size()) { - return; - } - auto& p = this->previews[page]; - p->updateSize(); - p->repaint(); - - layout(); -} - -void SidebarPreviewPages::pageChanged(size_t page) { - if (page == npos || page >= this->previews.size()) { - return; - } - - auto& p = this->previews[page]; - p->repaint(); -} - -void SidebarPreviewPages::pageDeleted(size_t page) { - if (page >= previews.size()) { - return; - } - - previews.erase(previews.begin() + as_signed(page)); - - // Unselect page, to prevent double selection displaying - unselectPage(); - - updateIndices(); - - layout(); -} - -void SidebarPreviewPages::pageInserted(size_t page) { - Document* doc = control->getDocument(); - doc->lock_shared(); - auto p = std::make_unique(this, doc->getPage(page), page); - doc->unlock_shared(); - - gtk_fixed_put(this->miniaturesContainer.get(), p->getWidget(), 0, 0); - this->previews.insert(this->previews.begin() + as_signed(page), std::move(p)); - - // Unselect page, to prevent double selection displaying - unselectPage(); - - updateIndices(); - - layout(); -} - -/** - * Unselect the last selected page, if any - */ -void SidebarPreviewPages::unselectPage() { - for (auto& p: this->previews) { - p->setSelected(false); - } -} - -void SidebarPreviewPages::pageSelected(size_t page) { - if (this->selectedEntry != npos && this->selectedEntry < this->previews.size()) { - this->previews[this->selectedEntry]->setSelected(false); - } - this->selectedEntry = page; - - if (!this->enabled) { - return; - } - - if (this->selectedEntry != npos && this->selectedEntry < this->previews.size()) { - auto& p = this->previews[this->selectedEntry]; - p->setSelected(true); - scrollToPreview(this); - } -} - -void SidebarPreviewPages::updateIndices() { - size_t index = 0; - for (auto& preview: this->previews) { - dynamic_cast(preview.get())->setIndex(index++); - } -} diff --git a/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPages.h b/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPages.h deleted file mode 100644 index 314163b..0000000 --- a/entry/src/main/cpp/src/core/gui/sidebar/previews/page/SidebarPreviewPages.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Xournal++ - * - * Previews of the pages in the document - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for unique_ptr -#include // for string -#include // for tuple -#include // for vector - -#include // for gulong -#include // for GtkWidget - -#include "gui/IconNameHelper.h" // for IconNameHe... -#include "gui/sidebar/previews/base/SidebarPreviewBase.h" // for SidebarPre... -#include "util/raii/GObjectSPtr.h" - -class Control; -class GladeGui; - - -class SidebarPreviewPages: public SidebarPreviewBase { -public: - SidebarPreviewPages(Control* control); - ~SidebarPreviewPages() override; - -public: - void enableSidebar() override; - - /** - * @overwrite - */ - std::string getName() override; - - /** - * @overwrite - */ - std::string getIconName() override; - - /** - * Update the preview images - * @overwrite - */ - void updatePreviews() override; - -public: - // DocumentListener interface (only the part which is not handled by SidebarPreviewBase) - void pageSizeChanged(size_t page) override; - void pageChanged(size_t page) override; - void pageSelected(size_t page) override; - void pageInserted(size_t page) override; - void pageDeleted(size_t page) override; - -private: - /** - * Unselect the last selected page, if any - */ - void unselectPage(); - - /** - * Updates the indices of the pages - */ - void updateIndices(); - -private: - IconNameHelper iconNameHelper; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractSliderItem.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractSliderItem.cpp deleted file mode 100644 index bfedb89..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractSliderItem.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "AbstractSliderItem.h" - -#include // for move - -AbstractSliderItem::AbstractSliderItem(std::string id, Category cat, SliderRange range, ActionRef gAction): - AbstractToolItem(std::move(id), cat), range(range), gAction(std::move(gAction)) {} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractSliderItem.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractSliderItem.h deleted file mode 100644 index ea49e99..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractSliderItem.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Xournal++ - * - * Abstract representation of slider-based tools. - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for unique_ptr -#include // for string - -#include // for GtkToolItem, GtkRange - -#include "control/actions/ActionRef.h" - -#include "AbstractToolItem.h" // for AbstractToolItem - -class AbstractSliderItem: public AbstractToolItem { -public: - struct SliderRange { - // Internal units: minimum and maximum slider values. - double min; - double max; - - // Number of fine/coarse steps between min and max. - int nbFineSteps; - int nbCoarseSteps; - }; - -public: - /** - * @param id Unique identifier for this. e.g. `TOOL_FOO_SLIDER`. - * @param range The minimum/maximum/step in internal units. {@see #scaleFunc}. - * @param gAction A GAction whose (double) state is synced with the slider's value - */ - AbstractSliderItem(std::string id, Category cat, SliderRange range, ActionRef gAction); - ~AbstractSliderItem() override = default; - -protected: - SliderRange range; - ActionRef gAction; - - template - friend class SliderItemCreationHelper; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractToolItem.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractToolItem.cpp deleted file mode 100644 index 5eff905..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractToolItem.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "AbstractToolItem.h" - -#include // for move - -AbstractToolItem::AbstractToolItem(std::string id, Category cat): id(std::move(id)), category(cat) {} - -AbstractToolItem::~AbstractToolItem() = default; - -auto AbstractToolItem::getId() const -> const std::string& { return id; } -auto AbstractToolItem::getCategory() const -> Category { return category; } - -xoj::util::WidgetSPtr AbstractToolItem::createToolItem(bool horizontal) { - xoj::util::WidgetSPtr item = createItem(horizontal); - gtk_widget_set_can_focus(item.get(), false); // todo(gtk4) not necessary anymore - if (GTK_IS_TOOL_ITEM(item.get())) { - gtk_widget_show_all(item.get()); - return item; - } - - // Wrap in a GtkToolItem - GtkToolItem* wrap = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(wrap), item.get()); - gtk_widget_show_all(GTK_WIDGET(wrap)); - return xoj::util::WidgetSPtr(GTK_WIDGET(wrap), xoj::util::adopt); -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractToolItem.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractToolItem.h deleted file mode 100644 index bcd44e9..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/AbstractToolItem.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string -#include - -#include // for GtkWidget - -#include "enums/Action.enum.h" -#include "util/raii/GObjectSPtr.h" -#include "util/raii/GVariantSPtr.h" - -class AbstractToolItem { -public: - // If you add a category, don't forget to give it a label in ToolbarCustomizeDialog.cpp. - // Keep the enum contiguous - enum class Category : unsigned char { - FILES, - TOOLS, - COLORS, - NAVIGATION, - MISC, - SELECTION, - AUDIO, - SEPARATORS, - PLUGINS, - ENUMERATOR_COUNT // Keep last - }; - AbstractToolItem(std::string id, Category cat); - virtual ~AbstractToolItem(); - - AbstractToolItem(AbstractToolItem const&) = delete; - auto operator=(AbstractToolItem const&) -> AbstractToolItem& = delete; - AbstractToolItem(AbstractToolItem&&) = delete; // Implement if desired - auto operator=(AbstractToolItem&&) -> AbstractToolItem& = delete; // Implement if desired - -public: - virtual xoj::util::WidgetSPtr createItem(bool horizontal) = 0; - - xoj::util::WidgetSPtr createToolItem(bool horizontal); - - const std::string& getId() const; - Category getCategory() const; - virtual std::string getToolDisplayName() const = 0; - - /** - * Returns: (transfer floating) - */ - virtual GtkWidget* getNewToolIcon() const = 0; - -protected: - std::string id; - const Category category; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorSelectorToolItem.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorSelectorToolItem.cpp deleted file mode 100644 index d87a17d..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorSelectorToolItem.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "ColorSelectorToolItem.h" - -#include - -#include "control/actions/ActionDatabase.h" -#include "gui/toolbarMenubar/icon/ColorIcon.h" // for ColorIcon -#include "util/GtkUtil.h" // for fixActionableInitialSensitivity -#include "util/gtk4_helper.h" // for gtk_button_set_child -#include "util/i18n.h" // for _ - -constexpr int ICON_SIZE = 22; - -ColorSelectorToolItem::ColorSelectorToolItem(ActionDatabase& db): - AbstractToolItem("COLOR_SELECT", Category::COLORS), gAction(db.getAction(Action::TOOL_COLOR)) {} - -auto ColorSelectorToolItem::createItem(bool) -> xoj::util::WidgetSPtr { - GtkWidget* btn = gtk_button_new(); - gtk_widget_set_can_focus(btn, false); // todo(gtk4) not necessary anymore - xoj::util::GVariantSPtr v(g_action_get_state(G_ACTION(gAction.get())), xoj::util::adopt); - Color initialColor = getGVariantValue(v.get()); - gtk_button_set_child(GTK_BUTTON(btn), ColorIcon::newGtkImage(initialColor, ICON_SIZE, false)); - - gtk_widget_set_tooltip_text(btn, this->getToolDisplayName().c_str()); - gtk_widget_set_sensitive(btn, g_action_get_enabled(G_ACTION(gAction.get()))); - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), - (std::string("win.") + Action_toString(Action::SELECT_COLOR)).c_str()); - - // The color follows the value of the GAction state - // NB: we use the notify::state signal because "change-state" is not raised by g_simple_action_set_state() - g_signal_connect_object(gAction.get(), "notify::state", G_CALLBACK(+[](GObject* a, GParamSpec*, gpointer btn) { - xoj::util::GVariantSPtr state(g_action_get_state(G_ACTION(a)), xoj::util::adopt); - auto c = getGVariantValue(state.get()); - gtk_button_set_child(GTK_BUTTON(btn), ColorIcon::newGtkImage(c, ICON_SIZE, false)); - }), - btn, GConnectFlags(0)); - - // Make a proxy for GtkToolbar - GtkToolItem* it = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(it), btn); - /// Makes a proxy item for the toolbar's overflow menu - auto createProxy = [&]() { - constexpr int PROXY_ICON_SIZE = 16; - GtkWidget* proxy = gtk_menu_item_new(); - auto* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_container_add(GTK_CONTAINER(proxy), box); - gtk_box_append(GTK_BOX(box), ColorIcon::newGtkImage(Colors::gray, PROXY_ICON_SIZE, false)); - gtk_box_append(GTK_BOX(box), gtk_label_new(getToolDisplayName().c_str())); - gtk_actionable_set_action_name(GTK_ACTIONABLE(proxy), - (std::string("win.") + Action_toString(Action::SELECT_COLOR)).c_str()); - xoj::util::gtk::fixActionableInitialSensitivity(GTK_ACTIONABLE(proxy)); - return proxy; - }; - gtk_tool_item_set_proxy_menu_item(it, "", createProxy()); - return xoj::util::WidgetSPtr(GTK_WIDGET(it), xoj::util::adopt); -} - -auto ColorSelectorToolItem::getToolDisplayName() const -> std::string { return _("Select color"); } - -auto ColorSelectorToolItem::getNewToolIcon() const -> GtkWidget* { - return ColorIcon::newGtkImage(Colors::gray, ICON_SIZE, false); -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorSelectorToolItem.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorSelectorToolItem.h deleted file mode 100644 index b514426..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorSelectorToolItem.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - -#include // for GtkWindget - -#include "control/actions/ActionRef.h" - -#include "AbstractToolItem.h" // for AbstractToolItem - -class ActionDatabase; - -class ColorSelectorToolItem: public AbstractToolItem { -public: - ColorSelectorToolItem(ActionDatabase& db); - ColorSelectorToolItem(ColorSelectorToolItem const&) = delete; - ColorSelectorToolItem(ColorSelectorToolItem&&) noexcept = delete; - auto operator=(ColorSelectorToolItem const&) -> ColorSelectorToolItem& = delete; - auto operator=(ColorSelectorToolItem&&) noexcept -> ColorSelectorToolItem& = delete; - ~ColorSelectorToolItem() override = default; - -public: - std::string getToolDisplayName() const override; - GtkWidget* getNewToolIcon() const override; - - xoj::util::WidgetSPtr createItem(bool horizontal) override; - -private: - ActionRef gAction; ///< Corresponds to Action::TOOL_COLOR -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorToolItem.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorToolItem.cpp deleted file mode 100644 index 33a3ade..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorToolItem.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "ColorToolItem.h" - -#include // for move - -#include "enums/Action.enum.h" // for Action -#include "gui/toolbarMenubar/icon/ColorIcon.h" // for ColorIcon -#include "util/GtkUtil.h" // for setToggleButtonUnreleasable -#include "util/gtk4_helper.h" // for gtk_button_set_child - -ColorToolItem::ColorToolItem(NamedColor namedColor, const std::optional& recolor): - AbstractToolItem(std::string("COLOR(") + std::to_string(namedColor.getIndex()) + ")", Category::COLORS), - namedColor(std::move(namedColor)), - target(xoj::util::makeGVariantSPtr(this->namedColor.getColor())) { - if (recolor) { - secondaryColor = std::make_optional(recolor->convertColor(namedColor.getColor())); - } else { - secondaryColor = std::nullopt; - } -} - -ColorToolItem::~ColorToolItem() = default; - -auto ColorToolItem::getColor() const -> Color { return this->namedColor.getColor(); } - -auto ColorToolItem::createItem(bool) -> xoj::util::WidgetSPtr { - auto* btn = gtk_toggle_button_new(); - gtk_widget_set_can_focus(btn, false); // todo(gtk4) not necessary anymore - auto actionName = std::string("win.") + Action_toString(Action::TOOL_COLOR); - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), actionName.data()); - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(btn), target.get()); - xoj::util::gtk::setToggleButtonUnreleasable(GTK_TOGGLE_BUTTON(btn)); - - gtk_widget_set_tooltip_text(btn, this->namedColor.getName().c_str()); - gtk_button_set_child(GTK_BUTTON(btn), getNewToolIcon()); - - - // For the sake of deprecated GtkToolbar, wrap the button in a GtkToolItem - // Todo(gtk4): remove - GtkToolItem* it = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(it), btn); - /// Makes a proxy item for the toolbar's overflow menu - auto createProxy = [this]() { - GtkWidget* proxy = gtk_check_menu_item_new(); - gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(proxy), true); - - auto* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_container_add(GTK_CONTAINER(proxy), box); - gtk_box_append(GTK_BOX(box), getNewToolIcon()); - gtk_box_append(GTK_BOX(box), gtk_label_new(getToolDisplayName().c_str())); - - gtk_actionable_set_action_name(GTK_ACTIONABLE(proxy), - (std::string("win.") + Action_toString(Action::TOOL_COLOR)).c_str()); - if (target) { - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(proxy), target.get()); - } - xoj::util::gtk::fixActionableInitialSensitivity(GTK_ACTIONABLE(proxy)); - return proxy; - }; - gtk_tool_item_set_proxy_menu_item(it, "", createProxy()); - return xoj::util::WidgetSPtr(GTK_WIDGET(it), xoj::util::adopt); -} - -auto ColorToolItem::getToolDisplayName() const -> std::string { return this->namedColor.getName(); } - -auto ColorToolItem::getNewToolIcon() const -> GtkWidget* { - return ColorIcon::newGtkImage(this->namedColor.getColor(), 16, true, this->secondaryColor); -} - -void ColorToolItem::updateColor(const Palette& palette) { namedColor = palette.getColorAt(namedColor.getIndex()); } - -void ColorToolItem::updateSecondaryColor(const std::optional& recolor) { - if (recolor) { - secondaryColor = std::make_optional(recolor->convertColor(namedColor.getColor())); - } else { - secondaryColor = std::nullopt; - } -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorToolItem.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorToolItem.h deleted file mode 100644 index 1249b42..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ColorToolItem.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for GtkWidget - -#include "gui/toolbarMenubar/model/ColorPalette.h" -#include "util/Color.h" // for Color -#include "util/NamedColor.h" // for NamedColor -#include "util/Recolor.h" // for Recolor - -#include "AbstractToolItem.h" // for AbstractToolItem - -class ActionDatabase; - -class ColorToolItem: public AbstractToolItem { -public: - ColorToolItem(NamedColor namedColor, const std::optional& recolor); - ColorToolItem(ColorToolItem const&) = delete; - ColorToolItem(ColorToolItem&&) noexcept = delete; - auto operator=(ColorToolItem const&) -> ColorToolItem& = delete; - auto operator=(ColorToolItem&&) noexcept -> ColorToolItem& = delete; - ~ColorToolItem() override; - - -public: - std::string getToolDisplayName() const override; - GtkWidget* getNewToolIcon() const override; - - Color getColor() const; - - /** - * @brief Update Color based on (new) palette - * - * @param palette - */ - void updateColor(const Palette& palette); - - /** - * @brief Update secondary Color based on (new) recoloring settings - * - * @param recolor - */ - void updateSecondaryColor(const std::optional& recolor); - - xoj::util::WidgetSPtr createItem(bool horizontal) override; - -private: - NamedColor namedColor; - xoj::util::GVariantSPtr target; ///< Contains the color in ARGB as a uint32_t - std::optional secondaryColor; //< color for small disk when recoloring is active -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ComboToolButton.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ComboToolButton.cpp deleted file mode 100644 index 846814a..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ComboToolButton.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "ComboToolButton.h" - -#include // for find_if -#include // for shared_ptr -#include // for move - -#include - -#include "util/GtkUtil.h" // for setToggleButtonUnreleasable -#include "util/glib_casts.h" -#include "util/gtk4_helper.h" // for gtk_popover_new - -/// Returns a floating ref -static GtkWidget* createEmptyButton(GSimpleAction* a, const ComboToolButton::Entry& e) { - GtkWidget* btn = gtk_toggle_button_new(); - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), (std::string("win.") + g_action_get_name(G_ACTION(a))).c_str()); - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(btn), e.target.get()); - xoj::util::gtk::setToggleButtonUnreleasable(GTK_TOGGLE_BUTTON(btn)); - gtk_widget_set_tooltip_text(btn, e.name.c_str()); - gtk_widget_set_can_focus(btn, false); // todo(gtk4) not necessary anymore - return btn; -} -/// Returns a floating ref -static GtkWidget* createPopoverEntry(GSimpleAction* a, const ComboToolButton::Entry& e) { - GtkWidget* entry = createEmptyButton(a, e); - - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6)); - gtk_box_append(box, gtk_image_new_from_icon_name(e.icon.c_str(), GTK_ICON_SIZE_SMALL_TOOLBAR)); - gtk_box_append(box, gtk_label_new(e.name.c_str())); - gtk_button_set_child(GTK_BUTTON(entry), GTK_WIDGET(box)); - - return entry; -} - -ComboToolButton::ComboToolButton(std::string id, Category cat, std::string iconName, std::string description, - Entries entries, ActionRef gAction): - AbstractToolItem(std::move(id), cat), - entries(std::move(entries)), - gAction(std::move(gAction)), - iconName(std::move(iconName)), - description(std::move(description)) {} - -/// Data structure for callbacks -struct ComboToolInstanceData { - GAction* action; - GtkButton* btn; - GtkPopover* popover; - const std::vector* entries; -}; - -/// change the prominent icon depending on G_ACTION(a)'s state -static void setProminentIconCallback(GObject* a, GParamSpec*, ComboToolInstanceData* data) { - xoj::util::GVariantSPtr state(g_action_get_state(G_ACTION(a)), xoj::util::adopt); - auto it = std::find_if(data->entries->begin(), data->entries->end(), - [s = state.get()](const auto& e) { return g_variant_equal(e.target.get(), s); }); - if (it != data->entries->end()) { - gtk_button_set_icon_name(data->btn, it->icon.c_str()); - gtk_widget_set_tooltip_text(GTK_WIDGET(data->btn), it->name.c_str()); - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(data->btn), state.get()); - gtk_popover_popdown(data->popover); - } -}; - -auto ComboToolButton::createItem(bool horizontal) -> xoj::util::WidgetSPtr { - - auto data = std::make_unique(); - data->entries = &this->entries; - data->action = G_ACTION(this->gAction.get()); - - { // Create popover - data->popover = GTK_POPOVER(gtk_popover_new()); - gtk_widget_add_css_class(GTK_WIDGET(data->popover), "toolbar"); - - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); - gtk_popover_set_child(data->popover, GTK_WIDGET(box)); - - for (const Entry& t: this->entries) { - gtk_box_append(box, createPopoverEntry(gAction.get(), t)); - } - - gtk_widget_show_all(GTK_WIDGET(box)); - } - - { // Create prominent button - const Entry& e = entries.front(); // Select the first entry by default - data->btn = GTK_BUTTON(createEmptyButton(gAction.get(), e)); - gtk_button_set_icon_name(data->btn, e.icon.c_str()); - } - - // Create item - GtkMenuButton* menubutton = GTK_MENU_BUTTON(gtk_menu_button_new()); - gtk_widget_set_can_focus(GTK_WIDGET(menubutton), false); // todo(gtk4) not necessary anymore - gtk_menu_button_set_popover(menubutton, GTK_WIDGET(data->popover)); - gtk_menu_button_set_direction(menubutton, - horizontal ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT); // TODO: fix directions - - GtkBox* box = GTK_BOX(gtk_box_new(horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL, 0)); - gtk_box_append(box, GTK_WIDGET(data->btn)); - gtk_box_append(box, GTK_WIDGET(menubutton)); - - auto item = xoj::util::WidgetSPtr(GTK_WIDGET(box), xoj::util::adopt); - - // Set up the prominent button according to the action state - setProminentIconCallback(G_OBJECT(gAction.get()), nullptr, data.get()); - - g_signal_connect(gAction.get(), "notify::state", xoj::util::wrap_for_g_callback_v, - data.get()); - - // Disconnect the signal and destroy *data if the widget is destroyed - g_object_weak_ref( - G_OBJECT(item.get()), - +[](gpointer d, GObject* item) { - auto* data = static_cast(d); - g_signal_handlers_disconnect_by_data(data->action, d); - delete data; - }, - data.release()); - - return item; -} - -auto ComboToolButton::getToolDisplayName() const -> std::string { return this->description; } - -auto ComboToolButton::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name(iconName.c_str(), GTK_ICON_SIZE_SMALL_TOOLBAR); -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ComboToolButton.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ComboToolButton.h deleted file mode 100644 index 89d9495..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ComboToolButton.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include -#include - -#include -#include - -#include "control/actions/ActionRef.h" -#include "util/raii/GObjectSPtr.h" // for WidgetSPtr - -#include "AbstractToolItem.h" // for AbstractToolItem - -class ActionDatabase; - -class ComboToolButton: public AbstractToolItem { -public: - struct Entry { - template - Entry(std::string name, std::string icon, T t): - name(std::move(name)), icon(std::move(icon)), target(xoj::util::makeGVariantSPtr(t)) {} - std::string name; - std::string icon; - xoj::util::GVariantSPtr target; /// Target value of the associated GSimpleAction corresponding to the entry - }; - using Entries = std::vector; - /** - * @brief When all entries correspond to a single action (but different target values) - * @param iconName Icon used in the toolbar customization dialog to represent this combo button. - * @param description Description used in the toolbar customization dialog to explain this combo button. - * @param entries Entries of the combo menu. - */ - ComboToolButton(std::string id, Category cat, std::string iconName, std::string description, Entries entries, - ActionRef gAction); - - ~ComboToolButton() override = default; - -public: - std::string getToolDisplayName() const override; - -protected: - xoj::util::WidgetSPtr createItem(bool horizontal) override; - - GtkWidget* getNewToolIcon() const override; - -protected: - const Entries entries; - ActionRef gAction; - std::string iconName; - std::string description; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/DrawingTypeComboToolButton.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/DrawingTypeComboToolButton.cpp deleted file mode 100644 index 6cf5001..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/DrawingTypeComboToolButton.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "DrawingTypeComboToolButton.h" - -#include // for find_if -#include // for move - -#include - -#include "control/actions/ActionDatabase.h" -#include "gui/IconNameHelper.h" -#include "util/glib_casts.h" -#include "util/gtk4_helper.h" // for gtk_popover_new -#include "util/i18n.h" - -/// Returns a floating ref -static GtkWidget* createPopoverEntry(const DrawingTypeComboToolButton::Entry& e) { - GtkWidget* entry = gtk_toggle_button_new(); - gtk_widget_set_can_focus(entry, false); // todo(gtk4) not necessary anymore - auto actionName = std::string("win.") + g_action_get_name(G_ACTION(e.gAction.get())); - gtk_actionable_set_action_name(GTK_ACTIONABLE(entry), actionName.data()); - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6)); - gtk_button_set_child(GTK_BUTTON(entry), GTK_WIDGET(box)); - gtk_box_append(box, gtk_image_new_from_icon_name(e.icon.c_str(), GTK_ICON_SIZE_SMALL_TOOLBAR)); - gtk_box_append(box, gtk_label_new(e.name.c_str())); - gtk_widget_set_tooltip_text(entry, e.name.c_str()); - return entry; -} - -static auto makeEntries(IconNameHelper& icons, const ActionDatabase& db) - -> std::shared_ptr> { - using Type = DrawingTypeComboToolButton::Type; - using Entry = DrawingTypeComboToolButton::Entry; - auto res = std::make_shared>(); - auto& entries = *res; - entries[Type::RECTANGLE] = Entry(_("Draw Rectangle"), icons.iconName("draw-rect"), db, Action::TOOL_DRAW_RECTANGLE); - entries[Type::ELLIPSE] = Entry(_("Draw Ellipse"), icons.iconName("draw-ellipse"), db, Action::TOOL_DRAW_ELLIPSE); - entries[Type::ARROW] = Entry(_("Draw Arrow"), icons.iconName("draw-arrow"), db, Action::TOOL_DRAW_ARROW); - entries[Type::DOUBLE_ARROW] = - Entry(_("Draw Double Arrow"), icons.iconName("draw-double-arrow"), db, Action::TOOL_DRAW_DOUBLE_ARROW); - entries[Type::LINE] = Entry(_("Draw Line"), icons.iconName("draw-line"), db, Action::TOOL_DRAW_LINE); - entries[Type::COORDINATE_SYSTEM] = Entry(_("Draw coordinate system"), icons.iconName("draw-coordinate-system"), db, - Action::TOOL_DRAW_COORDINATE_SYSTEM); - entries[Type::SPLINE] = Entry(_("Draw Spline"), icons.iconName("draw-spline"), db, Action::TOOL_DRAW_SPLINE); - entries[Type::SHAPE_RECOGNIZER] = - Entry(_("Stroke recognizer"), icons.iconName("shape-recognizer"), db, Action::TOOL_DRAW_SHAPE_RECOGNIZER); - return res; -} - -DrawingTypeComboToolButton::Entry::Entry(std::string name, std::string icon, const ActionDatabase& db, Action a): - name(std::move(name)), - icon(std::move(icon)), - gAction(db.getAction(a)), - fullActionName(std::string("win.") + g_action_get_name(G_ACTION(gAction.get()))) {} - -DrawingTypeComboToolButton::DrawingTypeComboToolButton(std::string id, IconNameHelper& icons, const ActionDatabase& db): - AbstractToolItem(std::move(id), Category::TOOLS), - entries(makeEntries(icons, db)), - iconName(icons.iconName("combo-drawing-type")), - description(_("Drawing Type Combo")) {} - -DrawingTypeComboToolButton::~DrawingTypeComboToolButton() = default; - -/// Data structure for callbacks -struct Data { - GtkButton* button; - GtkPopover* popover; - std::shared_ptr> - entries; - - template - static void setProminentIconCallback(GObject* action, GParamSpec*, Data* self) { - xoj::util::GVariantSPtr state(g_action_get_state(G_ACTION(action)), xoj::util::adopt); - if (getGVariantValue(state.get())) { - auto& e = (*self->entries)[s]; - gtk_button_set_icon_name(self->button, e.icon.c_str()); - gtk_widget_set_tooltip_text(GTK_WIDGET(self->button), e.name.c_str()); - gtk_actionable_set_action_name(GTK_ACTIONABLE(self->button), e.fullActionName.c_str()); - } - gtk_popover_popdown(self->popover); - } -}; - -auto DrawingTypeComboToolButton::createItem(bool horizontal) -> xoj::util::WidgetSPtr { - auto data = std::make_unique(); - data->entries = this->entries; - - { // Create popover - data->popover = GTK_POPOVER(gtk_popover_new()); - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); - gtk_popover_set_child(data->popover, GTK_WIDGET(box)); - gtk_widget_add_css_class(GTK_WIDGET(data->popover), "toolbar"); - - for (const Entry& t: *this->entries) { - gtk_box_append(box, createPopoverEntry(t)); - } - - gtk_widget_show_all(GTK_WIDGET(box)); - } - - { // Create prominent button - GtkWidget* btn = gtk_toggle_button_new(); - data->button = GTK_BUTTON(btn); - - gtk_widget_set_can_focus(btn, false); // todo(gtk4) not necessary anymore - - auto it = std::find_if(entries->begin(), entries->end(), [](auto& e) { - xoj::util::GVariantSPtr state(g_action_get_state(G_ACTION(e.gAction.get())), xoj::util::adopt); - return getGVariantValue(state.get()); - }); - const Entry& e = it == entries->end() ? (*entries)[Type::RECTANGLE] : *it; // Select an entry by default - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), e.fullActionName.data()); - gtk_button_set_icon_name(GTK_BUTTON(btn), e.icon.c_str()); - gtk_widget_set_tooltip_text(btn, e.name.c_str()); - } - - // Create item - GtkMenuButton* menubutton = GTK_MENU_BUTTON(gtk_menu_button_new()); - gtk_widget_set_can_focus(GTK_WIDGET(menubutton), false); // todo(gtk4) not necessary anymore - gtk_menu_button_set_popover(menubutton, GTK_WIDGET(data->popover)); - gtk_menu_button_set_direction(menubutton, - horizontal ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT); // TODO: fix directions - - GtkBox* box = GTK_BOX(gtk_box_new(horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL, 0)); - gtk_box_append(box, GTK_WIDGET(data->button)); - gtk_box_append(box, GTK_WIDGET(menubutton)); - - auto item = xoj::util::WidgetSPtr(GTK_WIDGET(box), xoj::util::adopt); - - /// change the prominent icon when selecting an entry (by any means) - g_signal_connect((*entries)[Type::RECTANGLE].gAction.get(), "notify::state", - xoj::util::wrap_for_g_callback_v>, data.get()); - g_signal_connect((*entries)[Type::ELLIPSE].gAction.get(), "notify::state", - xoj::util::wrap_for_g_callback_v>, data.get()); - g_signal_connect((*entries)[Type::ARROW].gAction.get(), "notify::state", - xoj::util::wrap_for_g_callback_v>, data.get()); - g_signal_connect((*entries)[Type::DOUBLE_ARROW].gAction.get(), "notify::state", - xoj::util::wrap_for_g_callback_v>, data.get()); - g_signal_connect((*entries)[Type::LINE].gAction.get(), "notify::state", - xoj::util::wrap_for_g_callback_v>, data.get()); - g_signal_connect((*entries)[Type::COORDINATE_SYSTEM].gAction.get(), "notify::state", - xoj::util::wrap_for_g_callback_v>, - data.get()); - g_signal_connect((*entries)[Type::SPLINE].gAction.get(), "notify::state", - xoj::util::wrap_for_g_callback_v>, data.get()); - g_signal_connect((*entries)[Type::SHAPE_RECOGNIZER].gAction.get(), "notify::state", - xoj::util::wrap_for_g_callback_v>, - data.get()); - - // Disconnect the signal and destroy *data if the widget is destroyed - g_object_weak_ref( - G_OBJECT(item.get()), - +[](gpointer d, GObject*) { - Data* data = static_cast(d); - g_signal_handlers_disconnect_by_data((*data->entries)[Type::RECTANGLE].gAction.get(), d); - g_signal_handlers_disconnect_by_data((*data->entries)[Type::ELLIPSE].gAction.get(), d); - g_signal_handlers_disconnect_by_data((*data->entries)[Type::ARROW].gAction.get(), d); - g_signal_handlers_disconnect_by_data((*data->entries)[Type::DOUBLE_ARROW].gAction.get(), d); - g_signal_handlers_disconnect_by_data((*data->entries)[Type::LINE].gAction.get(), d); - g_signal_handlers_disconnect_by_data((*data->entries)[Type::COORDINATE_SYSTEM].gAction.get(), d); - g_signal_handlers_disconnect_by_data((*data->entries)[Type::SPLINE].gAction.get(), d); - g_signal_handlers_disconnect_by_data((*data->entries)[Type::SHAPE_RECOGNIZER].gAction.get(), d); - delete data; - }, - data.release()); - - return item; -} - -auto DrawingTypeComboToolButton::getToolDisplayName() const -> std::string { return this->description; } - -auto DrawingTypeComboToolButton::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name(iconName.c_str(), GTK_ICON_SIZE_SMALL_TOOLBAR); -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/DrawingTypeComboToolButton.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/DrawingTypeComboToolButton.h deleted file mode 100644 index c94d815..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/DrawingTypeComboToolButton.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include - -#include -#include - -#include "control/actions/ActionRef.h" -#include "enums/Action.enum.h" // for Action -#include "util/EnumIndexedArray.h" -#include "util/raii/GObjectSPtr.h" // for WidgetSPtr - -#include "AbstractToolItem.h" // for AbstractToolItem - -class ActionDatabase; -class IconNameHelper; - -class DrawingTypeComboToolButton: public AbstractToolItem { -public: - struct Entry { - Entry() = default; - Entry(std::string name, std::string icon, const ActionDatabase& db, Action a); - std::string name; - std::string icon; - ActionRef gAction; - std::string fullActionName; - }; - DrawingTypeComboToolButton(std::string id, IconNameHelper& icons, const ActionDatabase& db); - - ~DrawingTypeComboToolButton() override; - -public: - std::string getToolDisplayName() const override; - - enum class Type : size_t { - RECTANGLE, - ELLIPSE, - ARROW, - DOUBLE_ARROW, - LINE, - COORDINATE_SYSTEM, - SPLINE, - SHAPE_RECOGNIZER, - ENUMERATOR_COUNT - }; - -protected: - xoj::util::WidgetSPtr createItem(bool horizontal) override; - - GtkWidget* getNewToolIcon() const override; - -private: - template - static void setProminentIconCallback(GObject* action, GParamSpec*, DrawingTypeComboToolButton* self); - -protected: - std::shared_ptr> entries; - std::string iconName; - std::string description; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/FontButton.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/FontButton.cpp deleted file mode 100644 index 814b6f9..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/FontButton.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "FontButton.h" - -#include // for stringstream -#include // for move - -#include // for g_object_ref, g_obj... - -#include "control/Control.h" // for Control -#include "control/actions/ActionDatabase.h" // for ActionDatabase -#include "gui/toolbarMenubar/AbstractToolItem.h" // for AbstractToolItem -#include "model/Font.h" // for Font -#include "util/GtkUtil.h" // for fixActionableInitialSensitivity -#include "util/gtk4_helper.h" // for gtk_button_set_child -#include "util/i18n.h" // for _ -#include "util/raii/GVariantSPtr.h" -#include "util/serdesstream.h" - - -FontButton::FontButton(std::string id, ActionDatabase& db): - AbstractToolItem(std::move(id), Category::TOOLS), gAction(db.getAction(Action::FONT)) {} - -static GtkWidget* makeChild(const char* desc) { - XojFont font(desc); - GtkWidget* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_widget_set_margin_start(box, 4); - gtk_widget_set_margin_end(box, 4); - GtkWidget* label = gtk_label_new(nullptr); - auto markup = "" + font.getName() + ""; - gtk_label_set_markup(GTK_LABEL(label), markup.c_str()); - gtk_box_append(GTK_BOX(box), label); - - auto size = serdes_stream(); - size << font.getSize(); - gtk_box_append(GTK_BOX(box), gtk_label_new(size.str().c_str())); - gtk_widget_show_all(box); - return box; -} - -auto FontButton::createItem(bool horizontal) -> xoj::util::WidgetSPtr { - GtkWidget* btn = gtk_button_new(); - gtk_widget_set_can_focus(btn, false); // todo(gtk4) not necessary anymore - xoj::util::GVariantSPtr font(g_action_get_state(G_ACTION(gAction.get())), xoj::util::adopt); - const char* desc = g_variant_get_string(font.get(), nullptr); - gtk_button_set_child(GTK_BUTTON(btn), makeChild(desc)); - gtk_widget_set_tooltip_text(btn, getToolDisplayName().c_str()); - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), - (std::string("win.") + Action_toString(Action::SELECT_FONT)).c_str()); - - g_signal_connect_object(gAction.get(), "notify::state", G_CALLBACK(+[](GObject* action, GParamSpec*, gpointer btn) { - xoj::util::GVariantSPtr font(g_action_get_state(G_ACTION(action)), xoj::util::adopt); - const char* desc = g_variant_get_string(font.get(), nullptr); - gtk_button_set_child(GTK_BUTTON(btn), makeChild(desc)); - }), - btn, GConnectFlags(0)); - - GtkToolItem* it = gtk_tool_item_new(); - gtk_container_add(GTK_CONTAINER(it), btn); - /// Makes a proxy item for the toolbar's overflow menu - auto createProxy = [this]() { - GtkWidget* proxy = gtk_menu_item_new(); - auto* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_container_add(GTK_CONTAINER(proxy), box); - gtk_box_append(GTK_BOX(box), getNewToolIcon()); - gtk_box_append(GTK_BOX(box), gtk_label_new(getToolDisplayName().c_str())); - gtk_actionable_set_action_name(GTK_ACTIONABLE(proxy), - (std::string("win.") + Action_toString(Action::SELECT_FONT)).c_str()); - xoj::util::gtk::fixActionableInitialSensitivity(GTK_ACTIONABLE(proxy)); - return proxy; - }; - gtk_tool_item_set_proxy_menu_item(it, "", createProxy()); - return xoj::util::WidgetSPtr(GTK_WIDGET(it), xoj::util::adopt); -} - -auto FontButton::getToolDisplayName() const -> std::string { return _("Font"); } - -auto FontButton::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name("font-x-generic", GTK_ICON_SIZE_LARGE_TOOLBAR); -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/FontButton.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/FontButton.h deleted file mode 100644 index 3c68e89..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/FontButton.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - -#include // for GtkWidget - -#include "control/actions/ActionRef.h" - -#include "AbstractToolItem.h" - -class ActionDatabase; - -class FontButton: public AbstractToolItem { -public: - FontButton(std::string id, ActionDatabase& db); - ~FontButton() override = default; - -public: - GtkWidget* getNewToolIcon() const override; - std::string getToolDisplayName() const override; - - xoj::util::WidgetSPtr createItem(bool horizontal) override; - -private: - ActionRef gAction; ///< Points to the GAction corresponding to Action::FONT -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginPlaceholderLabel.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginPlaceholderLabel.cpp deleted file mode 100644 index d102132..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginPlaceholderLabel.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "PluginPlaceholderLabel.h" - -#include // for std::replace - -#include "plugin/Plugin.h" // for ToolbarPlaceholderEntry -#include "util/glib_casts.h" -#include "util/gtk4_helper.h" // for gtk_popover_new - -#include "config-features.h" - -#ifdef ENABLE_PLUGINS - -PluginPlaceholderLabel::PluginPlaceholderLabel(ToolbarPlaceholderEntry* t): - AbstractToolItem(t->toolbarId, Category::PLUGINS), t(t) { - t->label = this; -} - -PluginPlaceholderLabel::~PluginPlaceholderLabel() { - for (auto* label: labelWidgets) { - if (GTK_IS_WIDGET(label)) { - g_signal_handlers_disconnect_by_data(label, this); - } - } - labelWidgets.clear(); -} - -auto PluginPlaceholderLabel::sanitizeText(const std::string& text) const -> std::string { - std::string sanitized = text; - std::replace(sanitized.begin(), sanitized.end(), '\n', ' '); - std::replace(sanitized.begin(), sanitized.end(), '\r', ' '); - return sanitized; -} - -auto PluginPlaceholderLabel::getDisplayText() const -> std::string { - std::string text = t->value; - if (text.empty()) { - text = getDisplayId(t->toolbarId); - } - return sanitizeText(text); -} - -auto PluginPlaceholderLabel::createItem(bool) -> xoj::util::WidgetSPtr { - const std::string labelText = getDisplayText(); - - xoj::util::WidgetSPtr item(gtk_label_new(labelText.c_str()), xoj::util::adopt); - GtkWidget* rawLabel = item.get(); - labelWidgets.push_back(rawLabel); - gtk_widget_set_can_focus(rawLabel, false); - gtk_widget_set_size_request(rawLabel, 200, -1); - gtk_label_set_ellipsize(GTK_LABEL(rawLabel), PANGO_ELLIPSIZE_END); - - // Remove label from vector when destroyed - g_signal_connect(rawLabel, "destroy", G_CALLBACK(+[](GtkWidget* widget, gpointer user_data) { - auto self = static_cast(user_data); - auto& widgets = self->labelWidgets; - widgets.erase(std::remove(widgets.begin(), widgets.end(), widget), widgets.end()); - }), - this); - return item; -} - -void PluginPlaceholderLabel::setText(std::string text) { - t->value = std::move(text); - const std::string displayText = getDisplayText(); - - for (auto* label: labelWidgets) { - if (GTK_IS_WIDGET(label)) { - gtk_label_set_text(GTK_LABEL(label), displayText.c_str()); - gtk_widget_queue_draw(label); - } - } -} - -auto PluginPlaceholderLabel::getToolDisplayName() const -> std::string { return this->t->description; } - -auto PluginPlaceholderLabel::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name("dialog-information", GTK_ICON_SIZE_LARGE_TOOLBAR); -} - -#endif /* ENABLE_PLUGINS */ diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginPlaceholderLabel.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginPlaceholderLabel.h deleted file mode 100644 index c6b8bc2..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginPlaceholderLabel.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include - -#include - -#include "AbstractToolItem.h" - -struct ToolbarPlaceholderEntry; - -class PluginPlaceholderLabel: public AbstractToolItem { -public: - /// Constructor: links placeholder entry to this label - explicit PluginPlaceholderLabel(ToolbarPlaceholderEntry* t); - - /// Destructor: disconnects signal handlers and clears label widget vector - ~PluginPlaceholderLabel() override; - - /// Returns the display name for the placeholder tool - std::string getToolDisplayName() const override; - - /// Updates all label widgets with new text - void setText(std::string text); - -protected: - /// Creates a label widget for the placeholder; stores and tracks it - xoj::util::WidgetSPtr createItem(bool horizontal) override; - - /// Returns a theme-supported icon for the placeholder tool - GtkWidget* getNewToolIcon() const override; - -private: - ToolbarPlaceholderEntry* t; - std::vector labelWidgets; - - auto sanitizeText(const std::string& text) const -> std::string; - - /// Gets the display text, using toolbarId as fallback if value is empty - auto getDisplayText() const -> std::string; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginToolButton.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginToolButton.cpp deleted file mode 100644 index 8a418de..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginToolButton.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "PluginToolButton.h" - -#include "config-features.h" // for ENABLE_PLUGINS - -#ifdef ENABLE_PLUGINS - -#include // for move - -#include "plugin/Plugin.h" // for ToolbarButtonEntry -#include "util/glib_casts.h" -#include "util/gtk4_helper.h" - - -PluginToolButton::PluginToolButton(ToolbarButtonEntry* t): - AbstractToolItem(std::move(t->toolbarId), Category::PLUGINS), t(t) {} - -PluginToolButton::~PluginToolButton() = default; - -auto PluginToolButton::createItem(bool) -> xoj::util::WidgetSPtr { - xoj::util::WidgetSPtr item(gtk_button_new(), xoj::util::adopt); - gtk_widget_set_can_focus(item.get(), false); // todo(gtk4) not necessary anymore - - GtkButton* btn = GTK_BUTTON(item.get()); - gtk_button_set_relief(btn, GTK_RELIEF_NONE); - gtk_button_set_icon_name(btn, t->iconName.c_str()); - gtk_widget_set_tooltip_text(GTK_WIDGET(btn), t->description.c_str()); - - // Connect signal - g_signal_connect(item.get(), "clicked", G_CALLBACK(+[](GtkButton*, gpointer d) { - auto* te = static_cast(d); - te->plugin->executeToolbarButton(te); - }), - this->t); - - return item; -} - -auto PluginToolButton::getToolDisplayName() const -> std::string { return this->t->description; } - -auto PluginToolButton::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name(t->iconName.c_str(), GTK_ICON_SIZE_SMALL_TOOLBAR); -} - -#endif /* ENABLE_PLUGINS */ diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginToolButton.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginToolButton.h deleted file mode 100644 index 68db133..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/PluginToolButton.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string, allocator - -#include // for GtkWidget, GtkToolItem - -#include "AbstractToolItem.h" // for AbstractToolItem - -struct ToolbarButtonEntry; - -class PluginToolButton: public AbstractToolItem { -public: - PluginToolButton(ToolbarButtonEntry* t); - - ~PluginToolButton() override; - std::string getToolDisplayName() const override; - -protected: - xoj::util::WidgetSPtr createItem(bool horizontal) override; - GtkWidget* getNewToolIcon() const override; - -private: - ToolbarButtonEntry* t; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/SliderItemCreationHelper.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/SliderItemCreationHelper.h deleted file mode 100644 index 04e2e6d..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/SliderItemCreationHelper.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Xournal++ - * - * Abstract representation of slider-based tools. - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - -#include // for GtkRange - -#include "control/actions/ActionRef.h" -#include "util/GVariantTemplate.h" // for makeGVariant -#include "util/GtkUtil.h" // for setWidgetFollowActionEnabled -#include "util/glib_casts.h" // for wrap_for_g_callback_v -#include "util/gtk4_helper.h" // for gtk_scale_set_format_value_func - -#include "AbstractSliderItem.h" - -/** - * @brief Helper function. We rely on a template to avoid adding a vtable to every callback data - */ -template -class SliderItemCreationHelper { -public: - static void valueChangedCb(GtkRange* slider, gpointer gAction) { - double state = FinalSliderType::scaleInverseFunction(gtk_range_get_value(slider)); - g_action_change_state(G_ACTION(gAction), makeGVariant(state)); - } - - static xoj::util::WidgetSPtr createItem(AbstractSliderItem* self, bool horizontal) { - GtkOrientation orientation = horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; - const double min = FinalSliderType::scaleFunction(self->range.min); - const double max = FinalSliderType::scaleFunction(self->range.max); - const double fineStepSize = (max - min) / self->range.nbFineSteps; - const double coarseStepSize = (max - min) / self->range.nbCoarseSteps; - - GtkRange* slider = GTK_RANGE(gtk_scale_new_with_range(orientation, min, max, fineStepSize)); - gtk_range_set_increments(slider, fineStepSize, coarseStepSize); - - if (horizontal) { - gtk_widget_set_size_request(GTK_WIDGET(slider), 120, 16); - } else { - gtk_widget_set_size_request(GTK_WIDGET(slider), 16, 120); - } - - gtk_widget_set_can_focus(GTK_WIDGET(slider), false); // todo(gtk4) not necessary anymore - - // gAction does not own the return GVariant and it is not floating either! - xoj::util::GVariantSPtr state(g_action_get_state(G_ACTION(self->gAction.get())), xoj::util::adopt); - gtk_range_set_value(slider, FinalSliderType::scaleFunction(getGVariantValue(state.get()))); - - g_signal_connect_object(slider, "value-changed", G_CALLBACK(valueChangedCb), self->gAction.get(), - GConnectFlags(0)); - - g_signal_connect_object( - self->gAction.get(), "notify::state", G_CALLBACK(+[](GObject* action, GParamSpec*, gpointer slider) { - // action does not own the return GVariant and it is not floating either! - xoj::util::GVariantSPtr state(g_action_get_state(G_ACTION(action)), xoj::util::adopt); - xoj_assert(state); - g_signal_handlers_block_by_func(slider, (gpointer)valueChangedCb, action); - gtk_range_set_value(GTK_RANGE(slider), - FinalSliderType::scaleFunction(getGVariantValue(state.get()))); - g_signal_handlers_unblock_by_func(slider, (gpointer)valueChangedCb, action); - }), - slider, GConnectFlags(0)); - - xoj::util::gtk::setWidgetFollowActionEnabled(GTK_WIDGET(slider), G_ACTION(self->gAction.get())); - - if constexpr (FinalSliderType::DISPLAY_VALUE) { - gtk_scale_set_draw_value(GTK_SCALE(slider), true); - gtk_scale_set_format_value_func( - GTK_SCALE(slider), - +[](GtkScale*, double value, gpointer) -> char* { - return g_strdup(FinalSliderType::formatSliderValue(value).c_str()); - }, - nullptr, nullptr); - } - - return xoj::util::WidgetSPtr(GTK_WIDGET(slider), xoj::util::adopt); - } -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/StylePopoverFactory.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/StylePopoverFactory.cpp deleted file mode 100644 index 279cbec..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/StylePopoverFactory.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "StylePopoverFactory.h" - -#include // for move - -#include -#include - -#include "util/GtkUtil.h" -#include "util/gtk4_helper.h" - - -StylePopoverFactory::StylePopoverFactory(Action styleAction, std::vector entries): - entries(std::move(entries)), styleAction(styleAction) {} - -GtkWidget* StylePopoverFactory::createPopover() const { - GtkWidget* popover = gtk_popover_new(); - GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - gtk_popover_set_child(GTK_POPOVER(popover), box); - -#if GTK_MAJOR_VERSION == 3 - GtkRadioButton* group = nullptr; - const char* actionName = Action_toString(styleAction); - auto appendItem = [&](const StylePopoverFactory::Entry& e) { - GtkWidget* btn = gtk_radio_button_new_from_widget(group); - group = GTK_RADIO_BUTTON(btn); - xoj::util::gtk::setRadioButtonActionName(GTK_RADIO_BUTTON(btn), "win", actionName); - g_signal_connect_object(btn, "clicked", G_CALLBACK(+[](GtkButton*, gpointer popover) { - gtk_popover_popdown(GTK_POPOVER(popover)); - }), - popover, GConnectFlags(0)); -#else - std::string actionName = std::string("win.") + Action_toString(Action::TOOL_PEN_LINE_STYLE); - auto appendLineStyleItem = [&](const char* label, const char* target, const char* icon) { - GtkWidget* btn = gtk_check_button_new_with_label(layerName.c_str()); - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), actionName.c_str()); - g_signal_connect_object(btn, "toggled", G_CALLBACK(+[](GtkCheckButton*, gpointer popover){ - gtk_popover_popdown(GTK_POPOVER(popover));}), popover, GConnectFlags(0)); -#endif - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(btn), e.target.get()); - if (!e.icon.empty()) { - GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); - gtk_box_append(GTK_BOX(hbox), gtk_image_new_from_icon_name(e.icon.c_str(), GTK_ICON_SIZE_LARGE_TOOLBAR)); - gtk_box_append(GTK_BOX(hbox), gtk_label_new(e.name.c_str())); - gtk_button_set_child(GTK_BUTTON(btn), hbox); - } else { - gtk_button_set_label(GTK_BUTTON(btn), e.name.c_str()); - } - gtk_box_append(GTK_BOX(box), btn); - }; - - for (const auto& e: entries) { - appendItem(e); - } - - gtk_widget_show_all(box); - return popover; -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/StylePopoverFactory.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/StylePopoverFactory.h deleted file mode 100644 index 20a69ef..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/StylePopoverFactory.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string, allocator -#include - -#include // for GtkWidget - -#include "enums/Action.enum.h" // for Action -#include "gui/PopoverFactory.h" -#include "util/raii/GVariantSPtr.h" - -class StylePopoverFactory final: public PopoverFactory { -public: - struct Entry { - template - Entry(std::string name, std::string icon, T t): - name(std::move(name)), icon(std::move(icon)), target(xoj::util::makeGVariantSPtr(t)) {} - template - Entry(std::string name, T t): name(std::move(name)), target(xoj::util::makeGVariantSPtr(t)) {} - std::string name; - std::string icon; - xoj::util::GVariantSPtr target; /// Target value of the associated GSimpleAction corresponding to the entry - }; - - /// @param styleAction The action activated when an entry in the popover is clicked - StylePopoverFactory(Action styleAction, std::vector entries); - ~StylePopoverFactory() override = default; - - GtkWidget* createPopover() const override; - -private: - std::vector entries; - /// The action activated when an entry in the popover is clicked - Action styleAction; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolButton.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolButton.cpp deleted file mode 100644 index 756a9d8..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolButton.cpp +++ /dev/null @@ -1,111 +0,0 @@ -#include "ToolButton.h" - -#include // for move - -#include -#include - -#include "gui/toolbarMenubar/AbstractToolItem.h" // for AbstractToolItem -#include "util/GVariantTemplate.h" -#include "util/GtkUtil.h" -#include "util/gtk4_helper.h" -#include "util/raii/GObjectSPtr.h" // for WidgetSPtr - - -ToolButton::ToolButton(std::string id, Category cat, Action action, std::string iconName, std::string description, - bool toggle): - AbstractToolItem(std::move(id), cat), - iconName(std::move(iconName)), - description(std::move(description)), - action(action), - toggle(toggle) {} - -ToolButton::ToolButton(std::string id, Category cat, Action action, GVariant* target, std::string iconName, - std::string description): - AbstractToolItem(std::move(id), cat), - iconName(std::move(iconName)), - description(std::move(description)), - action(action), - target(target, xoj::util::refsink), - toggle(true) {} - -auto ToolButton::createItem(bool horizontal) -> xoj::util::WidgetSPtr { - GtkWidget* btn = toggle ? gtk_toggle_button_new() : gtk_button_new(); - gtk_widget_set_can_focus(btn, false); // todo(gtk4) not necessary anymore - gtk_button_set_child(GTK_BUTTON(btn), getNewToolIcon()); - gtk_widget_set_tooltip_text(btn, getToolDisplayName().c_str()); - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), (std::string("win.") + Action_toString(action)).c_str()); - if (target) { - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(btn), target.get()); - xoj::util::gtk::setToggleButtonUnreleasable(GTK_TOGGLE_BUTTON(btn)); - } - - // For the sake of deprecated GtkToolbar, wrap the button in a GtkToolItem - // Todo(gtk4): remove - GtkToolItem* it = gtk_tool_item_new(); - if (popoverFactory) { - GtkMenuButton* menubutton = GTK_MENU_BUTTON(gtk_menu_button_new()); - gtk_widget_set_can_focus(GTK_WIDGET(menubutton), false); // todo(gtk4) not necessary anymore - gtk_menu_button_set_popover(menubutton, popoverFactory->createPopover()); - gtk_menu_button_set_direction(menubutton, GTK_ARROW_DOWN); - - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)); - gtk_box_append(box, btn); - gtk_box_append(box, GTK_WIDGET(menubutton)); - - gtk_container_add(GTK_CONTAINER(it), GTK_WIDGET(box)); - - g_signal_connect_object(it, "toolbar-reconfigured", G_CALLBACK(+[](GtkToolItem* it, gpointer box) { - gtk_orientable_set_orientation(GTK_ORIENTABLE(box), - gtk_tool_item_get_orientation(it)); - }), - box, GConnectFlags(0)); - g_signal_connect_object(it, "toolbar-reconfigured", G_CALLBACK(+[](GtkToolItem* it, gpointer btn) { - const bool h = gtk_tool_item_get_orientation(it) == GTK_ORIENTATION_HORIZONTAL; - gtk_menu_button_set_direction(GTK_MENU_BUTTON(btn), - h ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT); - if (!gtk_menu_button_get_popover(GTK_MENU_BUTTON(btn))) { - printf("no popover in callback\n"); - } - }), - menubutton, GConnectFlags(0)); - - } else { - gtk_container_add(GTK_CONTAINER(it), GTK_WIDGET(btn)); - } - - /// Makes a proxy item for the toolbar's overflow menu - auto createProxy = [this]() { - GtkWidget* proxy; - if (toggle) { - proxy = gtk_check_menu_item_new(); - if (target) { - gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(proxy), true); - } - } else { - proxy = gtk_menu_item_new(); - } - - auto* box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); - gtk_container_add(GTK_CONTAINER(proxy), box); - gtk_box_append(GTK_BOX(box), getNewToolIcon()); - gtk_box_append(GTK_BOX(box), gtk_label_new(getToolDisplayName().c_str())); - - gtk_actionable_set_action_name(GTK_ACTIONABLE(proxy), (std::string("win.") + Action_toString(action)).c_str()); - if (target) { - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(proxy), target.get()); - } - xoj::util::gtk::fixActionableInitialSensitivity(GTK_ACTIONABLE(proxy)); - return proxy; - }; - gtk_tool_item_set_proxy_menu_item(it, "", createProxy()); - return xoj::util::WidgetSPtr(GTK_WIDGET(it), xoj::util::adopt); -} - -auto ToolButton::getToolDisplayName() const -> std::string { return description; } - -auto ToolButton::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name(iconName.c_str(), GTK_ICON_SIZE_LARGE_TOOLBAR); -} - -void ToolButton::setPopoverFactory(const PopoverFactory* factory) { popoverFactory = factory; } diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolButton.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolButton.h deleted file mode 100644 index 71fa655..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolButton.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include // for string, allocator - -#include // for GtkWidget - -#include "enums/Action.enum.h" // for Action -#include "gui/PopoverFactory.h" -#include "util/raii/GVariantSPtr.h" - -#include "AbstractToolItem.h" // for AbstractToolItem - - -class ToolButton: public AbstractToolItem { -public: - ToolButton(std::string id, Category cat, Action action, std::string iconName, std::string description, bool toggle); - ToolButton(std::string id, Category cat, Action action, GVariant* target, std::string iconName, - std::string description); - ~ToolButton() override = default; - -public: - std::string getToolDisplayName() const override; - void setPopoverFactory(const PopoverFactory* factory); - -protected: - xoj::util::WidgetSPtr createItem(bool horizontal) override; - - GtkWidget* getNewToolIcon() const override; - -protected: - std::string iconName; - std::string description; - /// @brief If set, a MenuButton is added with this popover - const PopoverFactory* popoverFactory = nullptr; - Action action; - /// @brief If set, the action target value the button corresponds to - xoj::util::GVariantSPtr target; - /// @brief Whether or not the button is a ToggleButton. - bool toggle; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolMenuHandler.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolMenuHandler.cpp deleted file mode 100644 index 91becef..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolMenuHandler.cpp +++ /dev/null @@ -1,550 +0,0 @@ -#include "ToolMenuHandler.h" - -#include // for max -#include // for istringstream - -#include "control/Control.h" // for Control -#include "control/PageBackgroundChangeController.h" // for PageBackgroundChangeController -#include "control/ScrollHandler.h" // for ScrollHandler -#include "control/actions/ActionDatabase.h" // for ActionDatabase -#include "control/settings/Settings.h" // for Settings -#include "gui/GladeGui.h" // for GladeGui -#include "gui/GladeSearchpath.h" -#include "gui/ToolitemDragDrop.h" // for ToolitemDragDrop -#include "gui/menus/popoverMenus/PageTypeSelectionPopover.h" -#include "gui/toolbarMenubar/model/ColorPalette.h" // for Palette -#include "gui/toolbarMenubar/model/ToolbarData.h" // for ToolbarData -#include "gui/toolbarMenubar/model/ToolbarEntry.h" // for ToolbarEntry -#include "gui/toolbarMenubar/model/ToolbarItem.h" // for ToolbarItem -#include "gui/toolbarMenubar/model/ToolbarModel.h" // for ToolbarModel -#include "plugin/Plugin.h" // for ToolbarButtonEntr< -#include "util/GVariantTemplate.h" // for gVariantType -#include "util/GtkUtil.h" -#include "util/NamedColor.h" // for NamedColor -#include "util/PathUtil.h" -#include "util/StringUtils.h" // for StringUtils -#include "util/XojMsgBox.h" -#include "util/gtk4_helper.h" -#include "util/i18n.h" // for _ - -#include "AbstractToolItem.h" // for AbstractToolItem -#include "ColorSelectorToolItem.h" // for ColorSelectorToolItem -#include "ColorToolItem.h" // for ColorToolItem -#include "DrawingTypeComboToolButton.h" // for DrawingTypeComboToolButton -#include "FontButton.h" // for FontButton -#include "PluginPlaceholderLabel.h" // for PluginPlaceholderLabel -#include "PluginToolButton.h" // for PluginToolButton -#include "StylePopoverFactory.h" // for ToolButtonWithStylePopover -#include "ToolButton.h" // for ToolButton -#include "ToolPageLayer.h" // for ToolPageLayer -#include "ToolPageSpinner.h" // for ToolPageSpinner -#include "ToolPdfCombocontrol.h" // for ToolPdfCombocontrol -#include "ToolSelectCombocontrol.h" // for ToolSelectComboc... -#include "ToolZoomSlider.h" // for ToolZoomSlider -#include "TooltipToolButton.h" // for TooltipToolButton -#include "config-dev.h" // for TOOLBAR_CONFIG -#include "config-features.h" // for ENABLE_PLUGINS -#include "filesystem.h" // for exists - - -using std::string; - -ToolMenuHandler::ToolMenuHandler(Control* control, GladeGui* gui): - parent(GTK_WINDOW(gui->getWindow())), - control(control), - zoom(control->getZoomControl()), - gui(gui), - toolHandler(control->getToolHandler()), - tbModel(std::make_unique()), - pageBackgroundChangeController(control->getPageBackgroundChangeController()), - iconNameHelper(control->getSettings()), - pageTypeSelectionPopup(std::make_unique(control, control->getSettings(), - GTK_APPLICATION_WINDOW(parent))) {} - -void ToolMenuHandler::populate(const GladeSearchpath* gladeSearchPath) { - initToolItems(); - - auto file = gladeSearchPath->findFile("", "toolbar.ini"); - if (!tbModel->parse(file, true, this->control->getPalette())) { - std::string msg = FS(_F("Could not parse general toolbar.ini file: {1}\n" - "No Toolbars will be available") % - file.u8string()); - XojMsgBox::showErrorToUser(control->getGtkWindow(), msg); - } - - file = Util::getConfigFile(TOOLBAR_CONFIG); - if (fs::exists(file)) { - if (!tbModel->parse(file, false, this->control->getPalette())) { - string msg = FS(_F("Could not parse custom toolbar.ini file: {1}\n" - "Toolbars will not be available") % - file.u8string()); - XojMsgBox::showErrorToUser(control->getGtkWindow(), msg); - } - } -} - -ToolMenuHandler::~ToolMenuHandler() = default; - -void ToolMenuHandler::freeDynamicToolbarItems() { this->toolbarColorItems.clear(); } - -void ToolMenuHandler::unloadToolbar(GtkWidget* toolbar) { - for (int i = gtk_toolbar_get_n_items(GTK_TOOLBAR(toolbar)) - 1; i >= 0; i--) { - GtkToolItem* tbItem = gtk_toolbar_get_nth_item(GTK_TOOLBAR(toolbar), i); - gtk_container_remove(GTK_CONTAINER(toolbar), GTK_WIDGET(tbItem)); - } - - gtk_widget_hide(toolbar); -} - -void ToolMenuHandler::load(const ToolbarData* d, GtkWidget* toolbar, const char* toolbarName, bool horizontal) { - int count = 0; - const auto palette = this->control->getPalette(); - - const auto& recolorParams = control->getSettings()->getRecolorParameters(); - auto recolor = recolorParams.recolorizeMainView ? std::make_optional(recolorParams.recolor) : std::nullopt; - - for (const ToolbarEntry& e: d->contents) { - if (e.getName() == toolbarName) { - for (const ToolbarItem& dataItem: e.getItems()) { - std::string name = dataItem.getName(); - - if (!this->control->getAudioController() && - (name == "AUDIO_RECORDING" || name == "AUDIO_SEEK_BACKWARDS" || name == "AUDIO_PAUSE_PLAYBACK" || - name == "AUDIO_STOP_PLAYBACK" || name == "AUDIO_SEEK_FORWARDS" || name == "PLAY_OBJECT")) { - continue; - } - - if (name == "SEPARATOR") { - GtkToolItem* it = gtk_separator_tool_item_new(); - gtk_widget_show(GTK_WIDGET(it)); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), it, -1); - - ToolitemDragDrop::attachMetadata(GTK_WIDGET(it), dataItem.getId(), TOOL_ITEM_SEPARATOR); - - continue; - } - - if (name == "SPACER") { - GtkToolItem* toolItem = gtk_separator_tool_item_new(); - gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolItem), false); - gtk_tool_item_set_expand(toolItem, true); - gtk_widget_show(GTK_WIDGET(toolItem)); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolItem, -1); - - ToolitemDragDrop::attachMetadata(GTK_WIDGET(toolItem), dataItem.getId(), TOOL_ITEM_SPACER); - - continue; - } - if (StringUtils::startsWith(name, "COLOR(") && StringUtils::endsWith(name, ")")) { - std::string arg = name.substr(6, name.length() - 7); - - size_t paletteIndex{}; - std::istringstream colorStream(arg); - colorStream >> paletteIndex; - if (!colorStream.eof() || colorStream.fail()) { - g_warning("Toolbar:COLOR(N) has wrong format: %s", arg.c_str()); - continue; - } - - count++; - const NamedColor& namedColor = palette.getColorAt(paletteIndex); - auto& item = - this->toolbarColorItems.emplace_back(std::make_unique(namedColor, recolor)); - - auto it = item->createToolItem(horizontal); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(it.get()), -1); - - ToolitemDragDrop::attachMetadataColor(it.get(), dataItem.getId(), paletteIndex, item.get()); - - continue; - } - - bool found = false; - for (auto& item: this->toolItems) { - if (name == item->getId()) { - count++; - auto it = item->createToolItem(horizontal); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(it.get()), -1); - - ToolitemDragDrop::attachMetadata(it.get(), dataItem.getId(), item.get()); - - found = true; - break; - } - } - if (!found) { - g_warning("Toolbar item \"%s\" not found!", name.c_str()); - } - } - - break; - } - } - - if (count == 0) { - gtk_widget_hide(toolbar); - } else { - gtk_widget_show(toolbar); - } -} - -void ToolMenuHandler::removeColorToolItem(AbstractToolItem* it) { - g_return_if_fail(it != nullptr); - this->toolbarColorItems.erase(std::find_if(this->toolbarColorItems.begin(), this->toolbarColorItems.end(), - [it](const auto& p) { return p.get() == it; })); -} - -void ToolMenuHandler::addColorToolItem(std::unique_ptr it) { - g_return_if_fail(it != nullptr); - this->toolbarColorItems.emplace_back(std::move(it)); -} - -template -tool_item& ToolMenuHandler::emplaceItem(Args&&... args) { - return static_cast(*toolItems.emplace_back(std::make_unique(std::forward(args)...))); -} - -#ifdef ENABLE_PLUGINS -void ToolMenuHandler::addPluginItem(ToolbarButtonEntry* t) { emplaceItem(t); } -void ToolMenuHandler::addPluginPlaceholderItem(ToolbarPlaceholderEntry* entry) { - emplaceItem(entry); -} -#endif /* ENABLE_PLUGINS */ - - -void ToolMenuHandler::initToolItems() { - using Cat = AbstractToolItem::Category; - /** - * @brief Simple button, with a GTK stock icon name - * The corresponding action in ActionDatabase[action] should have no state (it can have a parameter) - **/ - auto emplaceStockItem = [this](const char* name, Cat c, Action action, const char* icon, std::string description) { - emplaceItem(name, c, action, icon, description, false); - }; - /** - * @brief Simple button, with a custom loaded icon - * The corresponding action in ActionDatabase[action] should have no state (it can have a parameter) - **/ - auto emplaceCustomItem = [this](const char* name, Cat c, Action action, const char* icon, std::string description) { - emplaceItem(name, c, action, iconName(icon), description, false); - }; - - /** - * @brief Toggle button, with a GTK stock icon name - * The corresponding action in ActionDatabase[action] should have a boolean state and no parameter - **/ - auto emplaceStockItemTgl = [this](const char* name, Cat c, Action action, const char* icon, - std::string description) { - emplaceItem(name, c, action, icon, description, true); - }; - - /** - * @brief Toggle button, with a custom loaded icon - * The corresponding action in ActionDatabase[action] should have a boolean state and no parameter - **/ - auto emplaceCustomItemTgl = [this](const char* name, Cat c, Action action, const char* icon, - std::string description) { - emplaceItem(name, c, action, iconName(icon), description, true); - }; - - /** - * @brief Toggle button linked to others sharing the same action (with a custom loaded icon) - * The corresponding action in ActionDatabase[action] should have a state and a parameter. The button is "on" - *when the action state matches `target`. - **/ - auto emplaceCustomItemWithTarget = [this](const char* name, Cat c, Action action, auto target, const char* icon, - std::string description) { - emplaceItem(name, c, action, makeGVariant(target), iconName(icon), description); - }; - - /** - * @brief Simple button (with a custom loaded icon), with a popover menu to change parameters of the tool - * The corresponding action in ActionDatabase[action] should have no state (it can have a parameter) - **/ - auto emplaceCustomItemWithPopover = [this](const char* name, Cat c, Action action, const char* icon, - std::string description, const PopoverFactory* popover) { - auto&& tb = emplaceItem(name, c, action, iconName(icon), description, false); - tb.setPopoverFactory(popover); - }; - - auto emplaceCustomItemWithTargetAndMenu = [this](const char* name, Cat c, Action action, auto target, - const char* icon, std::string description, - const PopoverFactory* popover) { - auto&& tb = emplaceItem(name, c, action, makeGVariant(target), iconName(icon), description); - tb.setPopoverFactory(popover); - }; - - - /* - * Items ordered by menu, if possible. - * There are some entries which are not available in the menu, like the Zoom slider - * All menu items without tool icon are not listed here - they are connected by ActionDatabase - */ - - /* - * Menu File - * ------------------------------------------------------------------------ - */ - - emplaceCustomItem("NEW", Cat::FILES, Action::NEW_FILE, "document-new", _("New Xournal")); - emplaceCustomItem("OPEN", Cat::FILES, Action::OPEN, "document-open", _("Open file")); - emplaceCustomItem("SAVE", Cat::FILES, Action::SAVE, "document-save", _("Save")); - emplaceCustomItem("SAVEPDF", Cat::FILES, Action::EXPORT_AS_PDF, "document-export-pdf", _("Export as PDF")); - emplaceCustomItem("PRINT", Cat::FILES, Action::PRINT, "document-print", _("Print")); - - /* - * Menu Edit - * ------------------------------------------------------------------------ - */ - - // Undo / Redo Texts are updated - emplaceItem( - "UNDO", Cat::MISC, Action::UNDO, iconName("edit-undo"), _("Undo"), - [undoredo = control->getUndoRedoHandler()]() { return undoredo->undoDescription(); }); - emplaceItem( - "REDO", Cat::MISC, Action::REDO, iconName("edit-redo"), _("Redo"), - [undoredo = control->getUndoRedoHandler()]() { return undoredo->redoDescription(); }); - - emplaceCustomItem("CUT", Cat::MISC, Action::CUT, "edit-cut", _("Cut")); - emplaceCustomItem("COPY", Cat::MISC, Action::COPY, "edit-copy", _("Copy")); - emplaceCustomItem("PASTE", Cat::MISC, Action::PASTE, "edit-paste", _("Paste")); - - emplaceStockItem("SEARCH", Cat::MISC, Action::SEARCH, "edit-find", _("Search")); - - emplaceStockItem("DELETE", Cat::MISC, Action::DELETE, "edit-delete", _("Delete")); - - emplaceCustomItemTgl("ROTATION_SNAPPING", Cat::MISC, Action::ROTATION_SNAPPING, "snapping-rotation", - _("Rotation Snapping")); - emplaceCustomItemTgl("GRID_SNAPPING", Cat::MISC, Action::GRID_SNAPPING, "snapping-grid", _("Grid Snapping")); - - /* - * Menu View - * ------------------------------------------------------------------------ - */ - - emplaceCustomItemTgl("PAIRED_PAGES", Cat::NAVIGATION, Action::PAIRED_PAGES_MODE, "show-paired-pages", - _("Paired pages")); - emplaceCustomItemTgl("PRESENTATION_MODE", Cat::NAVIGATION, Action::PRESENTATION_MODE, "presentation-mode", - _("Presentation mode")); - emplaceCustomItemTgl("FULLSCREEN", Cat::NAVIGATION, Action::FULLSCREEN, "fullscreen", _("Toggle fullscreen")); - emplaceCustomItemTgl("SHOW_SIDEBAR", Cat::NAVIGATION, Action::SHOW_SIDEBAR, "sidebar-show", _("Toggle sidebar")); - - emplaceCustomItem("MANAGE_TOOLBAR", Cat::MISC, Action::MANAGE_TOOLBAR, "toolbars-manage", _("Manage Toolbars")); - emplaceCustomItem("CUSTOMIZE_TOOLBAR", Cat::MISC, Action::CUSTOMIZE_TOOLBAR, "toolbars-customize", - _("Customize Toolbars")); - - emplaceStockItem("ZOOM_OUT", Cat::NAVIGATION, Action::ZOOM_OUT, "zoom-out", _("Zoom out")); - emplaceStockItem("ZOOM_IN", Cat::NAVIGATION, Action::ZOOM_IN, "zoom-in", _("Zoom in")); - emplaceStockItemTgl("ZOOM_FIT", Cat::NAVIGATION, Action::ZOOM_FIT, "zoom-fit-best", _("Zoom fit to screen")); - emplaceStockItem("ZOOM_100", Cat::NAVIGATION, Action::ZOOM_100, "zoom-original", _("Zoom to 100%")); - - /* - * Menu Navigation - * ------------------------------------------------------------------------ - */ - - emplaceStockItem("GOTO_FIRST", Cat::NAVIGATION, Action::GOTO_FIRST, "go-first", _("Go to first page")); - emplaceStockItem("GOTO_BACK", Cat::NAVIGATION, Action::GOTO_PREVIOUS, "go-previous", _("Back")); - emplaceCustomItem("GOTO_PAGE", Cat::NAVIGATION, Action::GOTO_PAGE, "go-to", _("Go to page")); - emplaceStockItem("GOTO_NEXT", Cat::NAVIGATION, Action::GOTO_NEXT, "go-next", _("Next")); - emplaceStockItem("GOTO_LAST", Cat::NAVIGATION, Action::GOTO_LAST, "go-last", _("Go to last page")); - - emplaceStockItem("GOTO_PREVIOUS_LAYER", Cat::NAVIGATION, Action::LAYER_GOTO_PREVIOUS, "go-previous", - _("Go to previous layer")); - emplaceStockItem("GOTO_NEXT_LAYER", Cat::NAVIGATION, Action::LAYER_GOTO_NEXT, "go-next", _("Go to next layer")); - emplaceStockItem("GOTO_TOP_LAYER", Cat::NAVIGATION, Action::LAYER_GOTO_TOP, "go-top", _("Go to top layer")); - - emplaceCustomItem("GOTO_NEXT_ANNOTATED_PAGE", Cat::NAVIGATION, Action::GOTO_NEXT_ANNOTATED_PAGE, - "page-annotated-next", _("Next annotated page")); - - /* Menu Journal - * ------------------------------------------------------------------------ - */ - - emplaceCustomItemWithPopover("INSERT_NEW_PAGE", Cat::TOOLS, Action::NEW_PAGE_AFTER, "page-add", _("Insert page"), - this->pageTypeSelectionPopup.get()); - emplaceCustomItem("DELETE_CURRENT_PAGE", Cat::TOOLS, Action::DELETE_PAGE, "page-delete", _("Delete current page")); - - /* - * Menu Tool - * ------------------------------------------------------------------------ - */ - this->penLineStylePopover = std::make_unique( - Action::TOOL_PEN_LINE_STYLE, - std::vector{{_("standard"), iconName("line-style-plain"), "plain"}, - {_("dashed"), iconName("line-style-dash"), "dash"}, - {_("dash-/ dotted"), iconName("line-style-dash-dot"), "dashdot"}, - {_("dotted"), iconName("line-style-dot"), "dot"}}); - emplaceCustomItemWithTargetAndMenu("PEN", Cat::TOOLS, Action::SELECT_TOOL, TOOL_PEN, "tool-pencil", _("Pen"), - this->penLineStylePopover.get()); - - this->eraserTypePopover = std::make_unique( - Action::TOOL_ERASER_TYPE, - std::vector{{_("standard"), ERASER_TYPE_DEFAULT}, - {_("whiteout"), ERASER_TYPE_WHITEOUT}, - {_("delete stroke"), ERASER_TYPE_DELETE_STROKE}}); - emplaceCustomItemWithTargetAndMenu("ERASER", Cat::TOOLS, Action::SELECT_TOOL, TOOL_ERASER, "tool-eraser", - _("Eraser"), this->eraserTypePopover.get()); - - // Add individual line styles as toolbar items - emplaceCustomItemWithTarget("PLAIN", Cat::TOOLS, Action::TOOL_PEN_LINE_STYLE, "plain", "line-style-plain-with-pen", - _("standard")); - emplaceCustomItemWithTarget("DASHED", Cat::TOOLS, Action::TOOL_PEN_LINE_STYLE, "dash", "line-style-dash-with-pen", - _("dashed")); - emplaceCustomItemWithTarget("DASH-/ DOTTED", Cat::TOOLS, Action::TOOL_PEN_LINE_STYLE, "dashdot", - "line-style-dash-dot-with-pen", _("dash-/ dotted")); - emplaceCustomItemWithTarget("DOTTED", Cat::TOOLS, Action::TOOL_PEN_LINE_STYLE, "dot", "line-style-dot-with-pen", - _("dotted")); - - - emplaceCustomItemWithTarget("HIGHLIGHTER", Cat::TOOLS, Action::SELECT_TOOL, TOOL_HIGHLIGHTER, "tool-highlighter", - _("Highlighter")); - - emplaceCustomItemWithTarget("TEXT", Cat::TOOLS, Action::SELECT_TOOL, TOOL_TEXT, "tool-text", _("Text")); - emplaceCustomItem("MATH_TEX", Cat::TOOLS, Action::TEX, "tool-math-tex", _("Add/Edit TeX")); - emplaceCustomItemWithTarget("IMAGE", Cat::TOOLS, Action::SELECT_TOOL, TOOL_IMAGE, "tool-image", _("Image")); - emplaceCustomItem("DEFAULT_TOOL", Cat::TOOLS, Action::SELECT_DEFAULT_TOOL, "default", _("Default Tool")); - emplaceCustomItemWithTarget("SELECT_PDF_TEXT_LINEAR", Cat::SELECTION, Action::SELECT_TOOL, - TOOL_SELECT_PDF_TEXT_LINEAR, "select-pdf-text-ht", _("Select Linear PDF Text")); - emplaceCustomItemWithTarget("SELECT_PDF_TEXT_RECT", Cat::SELECTION, Action::SELECT_TOOL, TOOL_SELECT_PDF_TEXT_RECT, - "select-pdf-text-area", _("Select PDF Text in Rectangle")); - - emplaceCustomItemTgl("SETSQUARE", Cat::MISC, Action::SETSQUARE, "setsquare", _("Setsquare")); - emplaceCustomItemTgl("COMPASS", Cat::MISC, Action::COMPASS, "compass", _("Compass")); - - emplaceCustomItemTgl("TOGGLE_TOUCH_DRAWING", Cat::MISC, Action::TOGGLE_TOUCH_DRAWING, "touch-drawing", - _("Toggle Touch Drawing")); - - - emplaceCustomItemTgl("SHAPE_RECOGNIZER", Cat::TOOLS, Action::TOOL_DRAW_SHAPE_RECOGNIZER, "shape-recognizer", - _("Shape Recognizer")); - emplaceCustomItemTgl("DRAW_RECTANGLE", Cat::TOOLS, Action::TOOL_DRAW_RECTANGLE, "draw-rect", _("Draw Rectangle")); - emplaceCustomItemTgl("DRAW_ELLIPSE", Cat::TOOLS, Action::TOOL_DRAW_ELLIPSE, "draw-ellipse", _("Draw Ellipse")); - emplaceCustomItemTgl("DRAW_ARROW", Cat::TOOLS, Action::TOOL_DRAW_ARROW, "draw-arrow", _("Draw Arrow")); - emplaceCustomItemTgl("DRAW_DOUBLE_ARROW", Cat::TOOLS, Action::TOOL_DRAW_DOUBLE_ARROW, "draw-double-arrow", - _("Draw Double Arrow")); - emplaceCustomItemTgl("DRAW_COORDINATE_SYSTEM", Cat::TOOLS, Action::TOOL_DRAW_COORDINATE_SYSTEM, - "draw-coordinate-system", _("Draw Coordinate System")); - emplaceCustomItemTgl("RULER", Cat::TOOLS, Action::TOOL_DRAW_LINE, "draw-line", _("Draw Line")); - emplaceCustomItemTgl("DRAW_SPLINE", Cat::TOOLS, Action::TOOL_DRAW_SPLINE, "draw-spline", _("Draw Spline")); - - emplaceCustomItemWithTarget("SELECT_REGION", Cat::SELECTION, Action::SELECT_TOOL, TOOL_SELECT_REGION, - "select-lasso", _("Select Region")); - emplaceCustomItemWithTarget("SELECT_RECTANGLE", Cat::SELECTION, Action::SELECT_TOOL, TOOL_SELECT_RECT, - "select-rect", _("Select Rectangle")); - emplaceCustomItemWithTarget("SELECT_MULTILAYER_REGION", Cat::SELECTION, Action::SELECT_TOOL, - TOOL_SELECT_MULTILAYER_REGION, "select-multilayer-lasso", - _("Select Multi-Layer Region")); - emplaceCustomItemWithTarget("SELECT_MULTILAYER_RECTANGLE", Cat::SELECTION, Action::SELECT_TOOL, - TOOL_SELECT_MULTILAYER_RECT, "select-multilayer-rect", - _("Select Multi-Layer Rectangle")); - emplaceCustomItemWithTarget("SELECT_OBJECT", Cat::SELECTION, Action::SELECT_TOOL, TOOL_SELECT_OBJECT, - "object-select", _("Select Object")); - emplaceCustomItemWithTarget("VERTICAL_SPACE", Cat::SELECTION, Action::SELECT_TOOL, TOOL_VERTICAL_SPACE, "spacer", - _("Vertical Space")); - emplaceCustomItemWithTarget("PLAY_OBJECT", Cat::SELECTION, Action::SELECT_TOOL, TOOL_PLAY_OBJECT, "object-play", - _("Play Object")); - emplaceCustomItemWithTarget("HAND", Cat::SELECTION, Action::SELECT_TOOL, TOOL_HAND, "hand", _("Hand")); - - emplaceItem("SELECT_FONT", *control->getActionDatabase()); - - emplaceCustomItemTgl("AUDIO_RECORDING", Cat::AUDIO, Action::AUDIO_RECORD, "audio-record", - _("Record Audio / Stop Recording")); - emplaceCustomItemTgl("AUDIO_PAUSE_PLAYBACK", Cat::AUDIO, Action::AUDIO_PAUSE_PLAYBACK, "audio-playback-pause", - _("Pause / Play")); - emplaceCustomItem("AUDIO_STOP_PLAYBACK", Cat::AUDIO, Action::AUDIO_STOP_PLAYBACK, "audio-playback-stop", _("Stop")); - emplaceCustomItem("AUDIO_SEEK_FORWARDS", Cat::AUDIO, Action::AUDIO_SEEK_FORWARDS, "audio-seek-forwards", - _("Forward")); - emplaceCustomItem("AUDIO_SEEK_BACKWARDS", Cat::AUDIO, Action::AUDIO_SEEK_BACKWARDS, "audio-seek-backwards", - _("Back")); - - - /////////////////////////////////////////////////////////////////////////// - - - /* - * Footer tools - * ------------------------------------------------------------------------ - */ - toolPageSpinner = &emplaceItem("PAGE_SPIN", iconNameHelper, control->getScrollHandler()); - - emplaceItem("ZOOM_SLIDER", zoom, iconNameHelper, *control->getActionDatabase()); - - emplaceItem("LAYER", control->getLayerController(), iconNameHelper); - - /* - * Non-menu items - * ------------------------------------------------------------------------ - */ - - /* - * Color item - not in the menu - * aka. COLOR_SELECT - */ - emplaceItem(*control->getActionDatabase()); - - bool hideAudio = !this->control->getAudioController(); - emplaceItem("SELECT", this->iconNameHelper, *this->control->getActionDatabase(), hideAudio); - emplaceItem("DRAW", this->iconNameHelper, *this->control->getActionDatabase()); - emplaceItem("PDF_TOOL", this->iconNameHelper, *this->control->getActionDatabase()); - - auto laserIcon = this->iconNameHelper.iconName("laser-pointer"); - emplaceItem( - "LASER_POINTER", Cat::TOOLS, laserIcon, _("Laser pointer"), - ComboToolButton::Entries{{_("Pen"), laserIcon, TOOL_LASER_POINTER_PEN}, - {_("Highlighter"), laserIcon, TOOL_LASER_POINTER_HIGHLIGHTER}}, - this->control->getActionDatabase()->getAction(Action::SELECT_TOOL)); - - // General tool configuration - working for every tool which support it - emplaceCustomItemTgl("TOOL_FILL", Cat::TOOLS, Action::TOOL_FILL, "fill", _("Fill")); - emplaceCustomItem("FILL_OPACITY", Cat::TOOLS, Action::TOOL_FILL_OPACITY, "fill-opacity", _("Fill Opacity")); - - emplaceCustomItemWithTarget("VERY_FINE", Cat::TOOLS, Action::TOOL_SIZE, TOOL_SIZE_VERY_FINE, "thickness-finer", - _("Very Fine")); - emplaceCustomItemWithTarget("FINE", Cat::TOOLS, Action::TOOL_SIZE, TOOL_SIZE_FINE, "thickness-fine", _("Fine")); - emplaceCustomItemWithTarget("MEDIUM", Cat::TOOLS, Action::TOOL_SIZE, TOOL_SIZE_MEDIUM, "thickness-medium", - _("Medium")); - emplaceCustomItemWithTarget("THICK", Cat::TOOLS, Action::TOOL_SIZE, TOOL_SIZE_THICK, "thickness-thick", _("Thick")); - emplaceCustomItemWithTarget("VERY_THICK", Cat::TOOLS, Action::TOOL_SIZE, TOOL_SIZE_VERY_THICK, "thickness-thicker", - _("Very Thick")); -} - -void ToolMenuHandler::setPageInfo(size_t currentPage, size_t pageCount, size_t pdfpage) { - if (this->toolPageSpinner) { - this->toolPageSpinner->setPageInfo(currentPage, pageCount, pdfpage); - } -} - -auto ToolMenuHandler::getModel() -> ToolbarModel* { return this->tbModel.get(); } - -auto ToolMenuHandler::getControl() -> Control* { return this->control; } - -auto ToolMenuHandler::getToolItems() const -> const std::vector>& { - return this->toolItems; -} - -auto ToolMenuHandler::getColorToolItems() const -> const std::vector>& { - return this->toolbarColorItems; -} - -auto ToolMenuHandler::iconName(const char* icon) -> std::string { return iconNameHelper.iconName(icon); } - -void ToolMenuHandler::updateColorToolItems(const Palette& palette) { - for (const auto& it: this->toolbarColorItems) { - it->updateColor(palette); - } -} - -void ToolMenuHandler::updateColorToolItemsRecoloring(const std::optional& recolor) { - for (const auto& it: this->toolbarColorItems) { - it->updateSecondaryColor(recolor); - } -} - -void ToolMenuHandler::setDefaultNewPageType(const std::optional& pt) { - this->pageTypeSelectionPopup->setSelectedPT(pt); - this->control->getPageBackgroundChangeController()->setPageTypeForNewPages(pt); -} -void ToolMenuHandler::setDefaultNewPaperSize(const std::optional& paperSize) { - this->pageTypeSelectionPopup->setSelectedPaperSize(paperSize); -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolMenuHandler.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolMenuHandler.h deleted file mode 100644 index 3d9528e..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolMenuHandler.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for unique_ptr -#include // for optional -#include // for string -#include // for vector - -#include -#include // for GObject, GConnectFlags -#include // for gchar -#include // for GtkWidget, GtkWindow, GtkBuilder - -#include "gui/IconNameHelper.h" // for IconNameHelper -#include "model/PaperSize.h" -#include "util/raii/GObjectSPtr.h" - -class AbstractToolItem; -class GladeGui; -class GladeSearchpath; -class ToolbarData; -class ToolbarModel; -class ToolButton; -class ToolHandler; -class ToolPageLayer; -class ToolPageSpinner; -class PageTypeMenu; -class SpinPageAdapter; -class ZoomControl; -class Control; -class PageBackgroundChangeController; -class ColorToolItem; -struct ToolbarButtonEntry; -struct ToolbarPlaceholderEntry; -class PageTypeSelectionPopover; -class PageType; -struct Palette; -class StylePopoverFactory; -class Recolor; - -class ToolMenuHandler { -public: - ToolMenuHandler(Control* control, GladeGui* gui); - virtual ~ToolMenuHandler(); - - void populate(const GladeSearchpath* gladeSearchPath); - -public: - void freeDynamicToolbarItems(); - static void unloadToolbar(GtkWidget* toolbar); - - /** - * @brief Load the toolbar.ini file - * This file persists the customized toolbars and is loaded upon starting the application. - * - * @param d Data Object representing the selected toolbars (e.g Portrait) - * @param toolbar reference to the widget representing the toolbar - * @param toolbarName toolbarName which should be read from the file - * @param horizontal whether the toolbar is horizontal - */ - void load(const ToolbarData* d, GtkWidget* toolbar, const char* toolbarName, bool horizontal); - - /** - * @brief Update all ColorToolItems based on palette - * - * @param palette - */ - void updateColorToolItems(const Palette& palette); - - /** - * @brief Update all ColorToolItems based on recolor settings - * - * @param recolor - */ - void updateColorToolItemsRecoloring(const std::optional& recolor); - - void initToolItems(); - void addPluginItem(ToolbarButtonEntry* t); - void addPluginPlaceholderItem(ToolbarPlaceholderEntry* entry); - - void setPageInfo(size_t currentPage, size_t pageCount, size_t pdfpage); - - [[maybe_unused]] void removeColorToolItem(AbstractToolItem* it); - void addColorToolItem(std::unique_ptr it); - - ToolbarModel* getModel(); - - const std::vector>& getToolItems() const; - const std::vector>& getColorToolItems() const; - - Control* getControl(); - - void hideAudioMenuItems(); - - std::string iconName(const char* icon); - - void setDefaultNewPageType(const std::optional& pt); - void setDefaultNewPaperSize(const std::optional& paperSize); - -private: - template - tool_item& emplaceItem(Args&&... args); - - void initPenToolItem(); - void initEraserToolItem(); - -private: - std::vector> toolbarColorItems; - GtkWindow* parent = nullptr; - - std::vector> toolItems; - - ToolPageSpinner* toolPageSpinner = nullptr; - - Control* control = nullptr; - ZoomControl* zoom = nullptr; - GladeGui* gui = nullptr; - ToolHandler* toolHandler = nullptr; - - std::unique_ptr tbModel; - - PageTypeMenu* newPageType = nullptr; - PageBackgroundChangeController* pageBackgroundChangeController = nullptr; - IconNameHelper iconNameHelper; - - std::unique_ptr pageTypeSelectionPopup; - std::unique_ptr penLineStylePopover; - std::unique_ptr eraserTypePopover; - - xoj::util::GObjectSPtr gAction; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageLayer.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageLayer.cpp deleted file mode 100644 index ef4481d..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageLayer.cpp +++ /dev/null @@ -1,315 +0,0 @@ -#include "ToolPageLayer.h" - -#include // for move - -#include // for G_CALLBACK, g_signa... -#include // for g_warning -#include // for pango_attr_list_insert - -#include "control/layer/LayerController.h" // for LayerController -#include "enums/Action.enum.h" // for Action -#include "gui/IconNameHelper.h" // for IconNameHelper -#include "gui/toolbarMenubar/AbstractToolItem.h" // for AbstractToolItem -#include "model/PageRef.h" // for PageRef -#include "model/XojPage.h" // for XojPage -#include "util/GtkUtil.h" // for setRadioButtonActionName -#include "util/glib_casts.h" // for closure_notify_cb -#include "util/gtk4_helper.h" // for gtk_box_append -#include "util/i18n.h" // for _ -#include "util/raii/PangoSPtr.h" // for PangoAttrListSPtr - - -class ShowLayerEntry final { -public: - ShowLayerEntry(LayerController* lc, Layer::Index id) noexcept; - ShowLayerEntry(const ShowLayerEntry&) = delete; // No copies, otherwise we'll get an issue with the signals - ShowLayerEntry& operator=(const ShowLayerEntry&) = delete; - ShowLayerEntry(ShowLayerEntry&& e) noexcept; - ShowLayerEntry& operator=(ShowLayerEntry&&) noexcept; - ~ShowLayerEntry() noexcept; - GtkWidget* checkButton; - gulong callbackHandler; -}; - -ShowLayerEntry::ShowLayerEntry(LayerController* lc, Layer::Index id) noexcept: checkButton(gtk_check_button_new()) { - gtk_widget_set_can_focus(checkButton, false); // todo(gtk4) not necessary anymore - struct Data { - LayerController* lc; - Layer::Index id; - }; - this->callbackHandler = - g_signal_connect_data(checkButton, "toggled", G_CALLBACK(+[](GtkToggleButton* btn, gpointer data) { - Data* d = reinterpret_cast(data); - d->lc->setLayerVisible(d->id, gtk_toggle_button_get_active(btn)); - }), - new Data{lc, id}, xoj::util::closure_notify_cb, GConnectFlags(0)); - gtk_widget_set_margin_end(checkButton, 4); -} - -ShowLayerEntry::ShowLayerEntry(ShowLayerEntry&& e) noexcept: - checkButton(std::move(e.checkButton)), callbackHandler(std::exchange(e.callbackHandler, 0U)) {} - -auto ShowLayerEntry::operator=(ShowLayerEntry&& e) noexcept -> ShowLayerEntry& { - checkButton = std::move(e.checkButton); - callbackHandler = std::exchange(e.callbackHandler, 0U); - return *this; -} - -ShowLayerEntry::~ShowLayerEntry() noexcept = default; - -/// @return The GtkWidget* is a floating ref -static std::tuple, std::vector>> createGrid( - LayerController* lc, GtkPopover* popover) { - -#if GTK_MAJOR_VERSION == 3 - GtkRadioButton* group = nullptr; - auto createLayerRadioButton = [&group, popover](const std::string& layerName, - Layer::Index id) -> std::pair { - GtkWidget* btn = gtk_radio_button_new_with_label_from_widget(group, layerName.c_str()); - gtk_widget_set_can_focus(btn, false); - group = GTK_RADIO_BUTTON(btn); - - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(btn), xoj::util::makeGVariantSPtr(id).get()); - /** - * RadioButton's and GAction don't work as expected in GTK3 - * To circumvent this, we have our own GAction/RadioButton interactions - */ - xoj::util::gtk::setRadioButtonActionName(GTK_RADIO_BUTTON(btn), "win", Action_toString(Action::LAYER_ACTIVE)); - - // Callback to hide the popover when a new layer is selected - auto sig = g_signal_connect_object(btn, "toggled", G_CALLBACK(+[](GtkToggleButton*, gpointer popover) { - gtk_popover_popdown(GTK_POPOVER(popover)); - }), - popover, GConnectFlags(0)); - // Block this callback for now, otherwise it is called when the grid is added to the popover - g_signal_handler_block(btn, sig); - - return {btn, sig}; - }; - - auto createBackgroundRadioButton = [](LayerController* lc) { - GtkWidget* btn = gtk_radio_button_new_with_label(nullptr, lc->getLayerNameById(0U).c_str()); - gtk_widget_set_can_focus(btn, false); - gtk_widget_add_css_class(btn, "invisible"); - gtk_widget_set_hexpand(btn, true); - return btn; - }; -#else // GTK4 - std::string actionName = std::string("win.") + Action_toString(Action::LAYER_ACTIVE); // Todo(cpp20) constexpr - auto createLayerRadioButton = [&actionName, popover](const std::string& layerName, - Layer::Index id) -> std::pair { - GtkWidget* btn = gtk_check_button_new_with_label(layerName.c_str()); - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), actionName.c_str()); - gtk_actionable_set_action_target_value(GTK_ACTIONABLE(btn), xoj::util::makeGVariantSPtr(id).get()); - // Callback to hide the popover when a new layer is selected - auto sig = g_signal_connect_object(btn, "toggled", G_CALLBACK(+[](GtkToggleButton*, gpointer popover) { - gtk_popover_popdown(GTK_POPOVER(popover)); }), popover, GConnectFlags(0)); - // Block this callback for now, otherwise it is called when the grid is added to the popover - g_signal_handler_block(btn, sig); - - return {btn, sig}; - }; - auto createBackgroundRadioButton = [](LayerController* lc) { - GtkWidget* btn = gtk_check_button_new_with_label(lc->getLayerNameById(0U).c_str()); - // Todo(gtk4): adapt the css class - gtk_widget_add_css_class(btn, "invisible"); - gtk_widget_set_hexpand(btn, true); - return btn; - }; -#endif - - GtkGrid* grid = GTK_GRID(gtk_grid_new()); - - auto layerCount = lc->getLayerCount(); - std::vector entries; - entries.reserve(layerCount + 1); - std::vector> radioButtons; - radioButtons.reserve(layerCount); - // Handle the background separately, as it cannot be selected - gtk_grid_attach(grid, createBackgroundRadioButton(lc), 0, static_cast(layerCount), 1, 1); - gtk_grid_attach(grid, entries.emplace_back(lc, 0).checkButton, 1, static_cast(layerCount), 1, 1); - // Then the other layers - for (Layer::Index id = 1; id <= layerCount; id++) { - int y = static_cast(layerCount - id); - auto [btn, _] = radioButtons.emplace_back(createLayerRadioButton(lc->getLayerNameById(id), id)); - gtk_grid_attach(grid, btn, 0, y, 1, 1); - gtk_grid_attach(grid, entries.emplace_back(lc, id).checkButton, 1, y, 1, 1); - } - - gtk_widget_show_all(GTK_WIDGET(grid)); - return {GTK_WIDGET(grid), std::move(entries), std::move(radioButtons)}; -} - -/// @return floating ref -static GtkLabel* makeLabel() { - auto* label = GTK_LABEL(gtk_label_new(_("Loading..."))); - xoj::util::PangoAttrListSPtr attrs(pango_attr_list_new(), xoj::util::adopt); - pango_attr_list_insert(attrs.get(), pango_attr_weight_new(PANGO_WEIGHT_BOLD)); - gtk_label_set_attributes(label, attrs.get()); - return label; -} - -/// @brief Appends to `box` a button with bold label `name` activating the Action `action` -static void addSpecialButton(GtkBox* box, const std::string& name, Action action) { - GtkWidget* btn = gtk_button_new(); - gtk_widget_set_can_focus(btn, false); // todo(gtk4) not necessary anymore - GtkWidget* lb = gtk_label_new(name.c_str()); - gtk_widget_set_halign(lb, GTK_ALIGN_START); - - xoj::util::PangoAttrListSPtr attrs(pango_attr_list_new(), xoj::util::adopt); - pango_attr_list_insert(attrs.get(), pango_attr_weight_new(PANGO_WEIGHT_BOLD)); - gtk_label_set_attributes(GTK_LABEL(lb), attrs.get()); - - gtk_button_set_child(GTK_BUTTON(btn), lb); - std::string fullActionName = std::string("win.") + Action_toString(action); - gtk_actionable_set_action_name(GTK_ACTIONABLE(btn), fullActionName.c_str()); - gtk_box_append(box, btn); -} - -/// @return floating ref -static GtkBox* makePopoverContent() { - GtkBox* box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)); - addSpecialButton(box, _("Show all"), Action::LAYER_SHOW_ALL); - addSpecialButton(box, _("Hide all"), Action::LAYER_HIDE_ALL); - gtk_box_append(box, gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)); - addSpecialButton(box, _("Add a layer above the active layer"), Action::LAYER_NEW_ABOVE_CURRENT); - addSpecialButton(box, _("Add a layer below the active layer"), Action::LAYER_NEW_BELOW_CURRENT); - gtk_box_append(box, gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)); - gtk_widget_show_all(GTK_WIDGET(box)); - return box; -} - -/// @return floating ref -static GtkPopover* makePopover(GtkBox* content) { - auto popover = GTK_POPOVER(gtk_popover_new()); - gtk_widget_add_css_class(GTK_WIDGET(popover), "toolbar"); - gtk_popover_set_child(popover, GTK_WIDGET(content)); - return popover; -} - -class InstanceData: public LayerCtrlListener { -public: - InstanceData(LayerController* lc): - lc(lc), - label(makeLabel()), - popoverBox(makePopoverContent()), - popover(makePopover(popoverBox)), - grid(nullptr) {} - ~InstanceData() = default; - - xoj::util::WidgetSPtr makeWidget(bool horizontal) { - xoj::util::WidgetSPtr item(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1), xoj::util::adopt); - GtkBox* hbox = GTK_BOX(item.get()); - GtkWidget* lbl = gtk_label_new(_("Layer")); - gtk_widget_set_margin_start(lbl, 7); - gtk_widget_set_margin_end(lbl, 7); - gtk_box_append(hbox, lbl); - GtkWidget* menuButton = gtk_menu_button_new(); -#if GTK_MAJOR_VERSION == 3 - gtk_widget_set_can_focus(menuButton, false); - gtk_box_append(hbox, GTK_WIDGET(this->label)); -#else - gtk_menu_button_set_child(GTK_MENU_BUTTON(menuButton), GTK_WIDGET(this->label)); - gtk_menu_button_set_always_show_arrow(GTK_MENU_BUTTON(menuButton), true); -#endif - gtk_box_append(hbox, menuButton); - // TODO: fix orientation - gtk_menu_button_set_direction(GTK_MENU_BUTTON(menuButton), horizontal ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT); - gtk_menu_button_set_popover(GTK_MENU_BUTTON(menuButton), GTK_WIDGET(this->popover)); - - LayerCtrlListener::registerListener(lc); - - // *this is destroyed once the widget (hence *popover) has been destroyed. No need to disconnect those signals - g_signal_connect(popover, "show", xoj::util::wrap_for_g_callback_v, this); - g_signal_connect(popover, "hide", xoj::util::wrap_for_g_callback_v, this); - - updateSelectedLayer(); - - return item; - } - - static void popoverShown(GtkWidget*, InstanceData* data) { - xoj_assert(!data->grid && data->showLayerItems.empty()); - data->setupLayersGrid(); - } - static void popoverHidden(GtkWidget*, InstanceData* data) { - if (data->grid) { - data->showLayerItems.clear(); - gtk_box_remove(data->popoverBox, data->grid); - data->grid = nullptr; - } - } - -private: - void setupLayersGrid() { - auto [grid, entries, radioButtons] = createGrid(lc, popover); - this->grid = grid; - gtk_box_append(this->popoverBox, grid); - this->showLayerItems = std::move(entries); - for (auto [btn, sig]: radioButtons) { - g_signal_handler_unblock(btn, sig); - } - - layerVisibilityChanged(); - } - - void rebuildLayerMenu() override { - if (grid) { - // Only rebuild if the popover is shown - showLayerItems.clear(); - gtk_box_remove(popoverBox, grid); - grid = nullptr; - - setupLayersGrid(); - } - updateSelectedLayer(); - } - - void layerVisibilityChanged() override { - PageRef page = lc->getCurrentPage(); - if (page) { - Layer::Index n = 0; - for (auto& e: showLayerItems) { - g_signal_handler_block(e.checkButton, e.callbackHandler); - gtk_check_button_set_active(GTK_CHECK_BUTTON(e.checkButton), page->isLayerVisible(n++)); - g_signal_handler_unblock(e.checkButton, e.callbackHandler); - } - } - } - - void updateSelectedLayer() override { gtk_label_set_text(label, lc->getCurrentLayerName().c_str()); } - -private: - LayerController* lc; - GtkLabel* label; - GtkBox* popoverBox; - GtkPopover* popover; - GtkWidget* grid; - - std::vector showLayerItems; ///< Widgets for the layer menu. Index = 0 is for background. -}; - - -ToolPageLayer::ToolPageLayer(std::string id, LayerController* lc, IconNameHelper iconNameHelper): - AbstractToolItem(std::move(id), Category::NAVIGATION), - lc(lc), - iconName(iconNameHelper.iconName("combo-layer")) {} - -ToolPageLayer::~ToolPageLayer() = default; - -auto ToolPageLayer::getToolDisplayName() const -> std::string { return _("Layer Combo"); } - -auto ToolPageLayer::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name(this->iconName.c_str(), GTK_ICON_SIZE_SMALL_TOOLBAR); -} - -auto ToolPageLayer::createItem(bool horizontal) -> xoj::util::WidgetSPtr { - auto data = std::make_unique(lc); - auto item = data->makeWidget(horizontal); - - // Destroy *data if the widget is destroyed - g_object_weak_ref( - G_OBJECT(item.get()), +[](gpointer d, GObject*) { delete static_cast(d); }, data.release()); - - return item; -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageLayer.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageLayer.h deleted file mode 100644 index a2725c1..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageLayer.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string -#include // for vector - -#include // for GtkWidget, GtkToolItem - -#include "control/layer/LayerCtrlListener.h" // for LayerCtrlListener -#include "model/Layer.h" // for Layer, Layer::Index -#include "util/raii/GObjectSPtr.h" // for WidgetSPtr - -#include "AbstractToolItem.h" // for AbstractToolItem - -class LayerController; -class IconNameHelper; - -class ToolPageLayer: public AbstractToolItem { -public: - ToolPageLayer(std::string id, LayerController* lc, IconNameHelper iconNameHelper); - ~ToolPageLayer() override; - -public: - std::string getToolDisplayName() const override; - xoj::util::WidgetSPtr createItem(bool horizontal) override; - - GtkWidget* getNewToolIcon() const override; - -private: - LayerController* lc = nullptr; - std::string iconName; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageSpinner.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageSpinner.cpp deleted file mode 100644 index e1f8653..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageSpinner.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "ToolPageSpinner.h" - -#include // for find -#include // for move - -#include // for g_object_ref_sink - -#include "gui/toolbarMenubar/AbstractToolItem.h" // for AbstractToolItem -#include "gui/widgets/SpinPageAdapter.h" // for SpinPageAdapter -#include "util/Assert.h" // for xoj_assert -#include "util/Util.h" -#include "util/gtk4_helper.h" // for gtk_box_append -#include "util/i18n.h" // for FS, _, _F, C_F - -class ToolPageSpinner::Instance final { -public: - Instance(ToolPageSpinner* handler, GtkOrientation orientation): handler(handler), orientation(orientation) {} - - xoj::util::WidgetSPtr makeWidget() { - GtkWidget* spinner = gtk_spin_button_new_with_range(0, 1, 1); - gtk_orientable_set_orientation(GTK_ORIENTABLE(spinner), orientation); - this->spinner.setWidget(spinner); // takes ownership of spinner reference - this->spinner.addListener(handler->getListener()); - - GtkWidget* numberLabel = gtk_label_new(""); - GtkWidget* pageLabel = gtk_label_new(_("Page")); - if (orientation == GTK_ORIENTATION_HORIZONTAL) { - gtk_widget_set_valign(pageLabel, GTK_ALIGN_BASELINE); - gtk_widget_set_margin_start(pageLabel, 7); - gtk_widget_set_margin_end(pageLabel, 7); - gtk_widget_set_valign(spinner, GTK_ALIGN_BASELINE); - gtk_widget_set_valign(numberLabel, GTK_ALIGN_BASELINE); - gtk_widget_set_margin_start(numberLabel, 7); - gtk_widget_set_margin_end(numberLabel, 7); - } else { - gtk_widget_set_halign(pageLabel, GTK_ALIGN_CENTER); - gtk_widget_set_margin_top(pageLabel, 7); - gtk_widget_set_margin_bottom(pageLabel, 7); - gtk_widget_set_halign(spinner, GTK_ALIGN_CENTER); - gtk_widget_set_halign(numberLabel, GTK_ALIGN_CENTER); - gtk_widget_set_valign(spinner, GTK_ALIGN_BASELINE); - gtk_widget_set_valign(numberLabel, GTK_ALIGN_BASELINE); - gtk_label_set_justify(GTK_LABEL(numberLabel), GTK_JUSTIFY_CENTER); - gtk_widget_set_margin_top(numberLabel, 7); - gtk_widget_set_margin_bottom(numberLabel, 7); - } - this->numberLabel = GTK_LABEL(numberLabel); - - xoj::util::WidgetSPtr item(gtk_box_new(orientation, 1), xoj::util::adopt); - GtkBox* box = GTK_BOX(item.get()); - gtk_box_append(box, pageLabel); - gtk_box_append(box, spinner); - gtk_box_append(box, numberLabel); - - return item; - } - - void disconnect() { handler = nullptr; } - -private: - ToolPageSpinner* handler; - GtkOrientation orientation; - SpinPageAdapter spinner; - GtkLabel* numberLabel; - -public: - void setPageInfo(size_t currentPage, size_t pageCount, size_t pdfPage) { - if (pageCount == 0) { - spinner.setMinMaxPage(0, 0); - spinner.setPage(0); - } else { - spinner.setMinMaxPage(1, pageCount); - spinner.setPage(currentPage + 1); - } - - updateLabel(pageCount, pdfPage); - } - ToolPageSpinner* getHandler() const { return handler; } - -private: - void updateLabel(const size_t pageCount, const size_t pdfPage) { - std::string ofString = FS(C_F("Page {pagenumber} \"of {pagecount}\"", " of {1}") % pageCount); - if (pdfPage != npos) { - if (this->orientation == GTK_ORIENTATION_HORIZONTAL) { - ofString += std::string(", ") + FS(_F("PDF Page {1}") % (pdfPage + 1)); - } else { - ofString += std::string("\n") + FS(_F("PDF {1}") % (pdfPage + 1)); - } - } - gtk_label_set_text(this->numberLabel, ofString.c_str()); - } -}; - -ToolPageSpinner::ToolPageSpinner(std::string id, IconNameHelper iconNameHelper, SpinPageListener* listener): - AbstractToolItem(std::move(id), Category::NAVIGATION), iconNameHelper(iconNameHelper), listener(listener) {} - -ToolPageSpinner::~ToolPageSpinner() { - for (auto* i: instances) { - i->disconnect(); - } -} - -void ToolPageSpinner::setPageInfo(size_t currentPage, size_t pageCount, size_t pdfPage) { - for (auto* i: instances) { - i->setPageInfo(currentPage, pageCount, pdfPage); - } -} - -auto ToolPageSpinner::getToolDisplayName() const -> std::string { return _("Page number"); } - -auto ToolPageSpinner::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name(iconNameHelper.iconName("page-spinner").c_str(), GTK_ICON_SIZE_SMALL_TOOLBAR); -} - -auto ToolPageSpinner::createItem(bool horizontal) -> xoj::util::WidgetSPtr { - auto orientation = horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; - auto data = std::make_unique(this, orientation); - auto item = data->makeWidget(); - - this->instances.emplace_back(data.get()); // Keep a ref for callback propagation - - // Destroy *data if the widget is destroyed - g_object_weak_ref( - G_OBJECT(item.get()), - +[](gpointer d, GObject*) { - auto* data = static_cast(d); - if (auto* h = data->getHandler(); h) { - auto& instances = h->instances; - if (auto it = std::find(instances.begin(), instances.end(), data); it != instances.end()) { - instances.erase(it); - } - } - delete data; - }, - data.release()); - - return item; -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageSpinner.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageSpinner.h deleted file mode 100644 index 9a8ace0..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPageSpinner.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for unique_ptr -#include // for string - -#include // for GdkPixbuf -#include // for GtkWidget, GtkToolItem, GTK_ORIEN... - -#include "gui/IconNameHelper.h" // for IconNameHelper -#include "util/raii/GObjectSPtr.h" // for WidgetSPtr - -#include "AbstractToolItem.h" // for AbstractToolItem - -class SpinPageListener; - -class ToolPageSpinner: public AbstractToolItem { -public: - ToolPageSpinner(std::string id, IconNameHelper iconNameHelper, SpinPageListener* listener); - ~ToolPageSpinner() override; - -public: - /// Propagates the info to all instances of the Page Spinner - void setPageInfo(size_t currentPage, size_t pageCount, size_t pdfPage); - std::string getToolDisplayName() const override; - xoj::util::WidgetSPtr createItem(bool horizontal) override; - - inline SpinPageListener* getListener() const { return listener; } - -protected: - GtkWidget* getNewToolIcon() const override; - -private: - IconNameHelper iconNameHelper; - SpinPageListener* listener; - - class Instance; - std::vector instances; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPdfCombocontrol.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPdfCombocontrol.cpp deleted file mode 100644 index 9674194..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPdfCombocontrol.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "ToolPdfCombocontrol.h" - -#include // for move - -#include "control/ToolEnums.h" -#include "control/actions/ActionDatabase.h" -#include "gui/IconNameHelper.h" -#include "util/i18n.h" - -ToolPdfCombocontrol::ToolPdfCombocontrol(std::string id, IconNameHelper& icons, const ActionDatabase& db): - ComboToolButton( - std::move(id), Category::SELECTION, icons.iconName("select-pdf-text-ht"), - _("PDF text selection dropdown menu"), - {Entry(_("Select Linear PDF Text"), icons.iconName("select-pdf-text-ht"), TOOL_SELECT_PDF_TEXT_LINEAR), - Entry(_("Select PDF Text In Rectangle"), icons.iconName("select-pdf-text-area"), - TOOL_SELECT_PDF_TEXT_RECT)}, - db.getAction(Action::SELECT_TOOL)) {} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPdfCombocontrol.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPdfCombocontrol.h deleted file mode 100644 index 94b5bd3..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolPdfCombocontrol.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -#include "ComboToolButton.h" - -class IconNameHelper; -class ActionDatabase; - -class ToolPdfCombocontrol: public ComboToolButton { -public: - ToolPdfCombocontrol(std::string id, IconNameHelper& icons, const ActionDatabase& db); - ~ToolPdfCombocontrol() override = default; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolSelectCombocontrol.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolSelectCombocontrol.cpp deleted file mode 100644 index b734ce8..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolSelectCombocontrol.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "ToolSelectCombocontrol.h" - -#include // for move - -#include "control/ToolEnums.h" -#include "control/actions/ActionDatabase.h" -#include "gui/IconNameHelper.h" -#include "util/i18n.h" - -static std::vector makeEntries(IconNameHelper& icons, bool hideAudio) { - using Entry = ComboToolButton::Entry; - std::vector res = {Entry(_("Select Rectangle"), icons.iconName("select-rect"), TOOL_SELECT_RECT), - Entry(_("Select Region"), icons.iconName("select-lasso"), TOOL_SELECT_REGION), - Entry(_("Select Multi-Layer Rectangle"), icons.iconName("select-multilayer-rect"), - TOOL_SELECT_MULTILAYER_RECT), - Entry(_("Select Multi-Layer Region"), icons.iconName("select-multilayer-lasso"), - TOOL_SELECT_MULTILAYER_REGION), - Entry(_("Select Object"), icons.iconName("object-select"), TOOL_SELECT_OBJECT), - Entry(_("Play Object"), icons.iconName("object-play"), TOOL_PLAY_OBJECT)}; - if (hideAudio) { - res.pop_back(); - } - return res; -} - -ToolSelectCombocontrol::ToolSelectCombocontrol(std::string id, IconNameHelper& icons, const ActionDatabase& db, - bool hideAudio): - ComboToolButton(std::move(id), Category::TOOLS, icons.iconName("combo-selection"), _("Selection dropdown menu"), - makeEntries(icons, hideAudio), db.getAction(Action::SELECT_TOOL)) {} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolSelectCombocontrol.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolSelectCombocontrol.h deleted file mode 100644 index 401d244..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolSelectCombocontrol.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include - -#include "ComboToolButton.h" - -class IconNameHelper; -class ActionDatabase; - -class ToolSelectCombocontrol: public ComboToolButton { -public: - ToolSelectCombocontrol(std::string id, IconNameHelper& icons, const ActionDatabase& db, bool hideAudio); - ~ToolSelectCombocontrol() override = default; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolZoomSlider.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolZoomSlider.cpp deleted file mode 100644 index 155ac24..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolZoomSlider.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "ToolZoomSlider.h" - -#include // for exp, log -#include // for stringstream, bas... -#include // for move - -#include // for g_get_monotonic_time - -#include "control/actions/ActionDatabase.h" -#include "control/zoom/ZoomControl.h" // for ZoomControl, DEFA... -#include "util/i18n.h" // for _ - -#include "SliderItemCreationHelper.h" - -constexpr double SCALE_LOG_OFFSET = 0.20753; - -constexpr int FINE_STEP_COUNT = 100; -constexpr int COARSE_STEP_COUNT = 10; - -// TODO(personalizedrefrigerator): Update the range to reflect the min and max zoom settings. -constexpr auto SLIDER_RANGE = - AbstractSliderItem::SliderRange{DEFAULT_ZOOM_MIN, DEFAULT_ZOOM_MAX, FINE_STEP_COUNT, COARSE_STEP_COUNT}; - -ToolZoomSlider::ToolZoomSlider(std::string id, ZoomControl* zoom, IconNameHelper iconNameHelper, ActionDatabase& db): - AbstractSliderItem{std::move(id), Category::NAVIGATION, SLIDER_RANGE, db.getAction(Action::ZOOM)}, - iconName(iconNameHelper.iconName("zoom-slider")), - zoomCtrl(zoom) {} - -auto ToolZoomSlider::formatSliderValue(double value) -> std::string { - std::stringstream out; - out << static_cast(std::round(100 * scaleInverseFunction(value))); - out << "%"; - return out.str(); -} - -auto ToolZoomSlider::createItem(bool horizontal) -> xoj::util::WidgetSPtr { - auto item = SliderItemCreationHelper::createItem(this, horizontal); - - class Listener: public ZoomListener { - public: - Listener(GtkScale* slider, ZoomControl* zoomCtrl): slider(slider), zoomCtrl(zoomCtrl) { - zoomCtrl->addZoomListener(this); - } - ~Listener() override { zoomCtrl->removeZoomListener(this); } - void zoomChanged() override {} // No need to do anything here. Handled by the GAction - void zoomRangeValuesChanged() override { - gtk_scale_clear_marks(slider); - auto position = gtk_orientable_get_orientation(GTK_ORIENTABLE(slider)) == GTK_ORIENTATION_HORIZONTAL ? - GTK_POS_BOTTOM : - GTK_POS_RIGHT; - gtk_scale_add_mark(slider, scaleFunction(1.0), position, nullptr); - gtk_scale_add_mark(slider, scaleFunction(zoomCtrl->getZoomFitValue() / zoomCtrl->getZoom100Value()), - position, nullptr); - } - - GtkScale* slider; ///< Parent to this data - ZoomControl* zoomCtrl; - }; - - auto data = std::make_unique(GTK_SCALE(item.get()), zoomCtrl); - data->zoomRangeValuesChanged(); // Set up the marks - - // Destroy *data if the widget is destroyed - g_object_weak_ref( - G_OBJECT(item.get()), +[](gpointer d, GObject*) { delete static_cast(d); }, data.release()); - - return item; -} - -auto ToolZoomSlider::getToolDisplayName() const -> std::string { return _("Zoom Slider"); } - -auto ToolZoomSlider::getNewToolIcon() const -> GtkWidget* { - return gtk_image_new_from_icon_name(iconName.c_str(), GTK_ICON_SIZE_SMALL_TOOLBAR); -} - -auto ToolZoomSlider::scaleFunction(double x) -> double { return std::log(x - SCALE_LOG_OFFSET); } - -auto ToolZoomSlider::scaleInverseFunction(double x) -> double { return std::exp(x) + SCALE_LOG_OFFSET; } diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolZoomSlider.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolZoomSlider.h deleted file mode 100644 index 68ac347..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/ToolZoomSlider.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for unique_ptr -#include // for string - -#include // for GdkPixbuf -#include // for GtkRange, GtkWidget - -#include "control/zoom/ZoomListener.h" // for ZoomListener -#include "gui/IconNameHelper.h" // for IconNameHelper - -#include "AbstractSliderItem.h" // for NewAbstractSliderItem - -class ZoomControl; -class ActionDatabase; - -class ToolZoomSlider: public AbstractSliderItem { -public: - ToolZoomSlider(std::string id, ZoomControl* zoom, IconNameHelper iconNameHelper, ActionDatabase& db); - ~ToolZoomSlider() override = default; - - xoj::util::WidgetSPtr createItem(bool horizontal) override; - -protected: - static constexpr bool DISPLAY_VALUE = true; - static std::string formatSliderValue(double value); - - std::string getToolDisplayName() const override; - -protected: - GtkWidget* getNewToolIcon() const override; - -protected: - /** - * @brief Function to convert from the GAction's state value to the slider's position. (e.g. for log scaling) - */ - static double scaleFunction(double x); - - /** - * @brief Function to convert from the slider's position to the GAction's state value. (e.g. for log scaling) - */ - static double scaleInverseFunction(double x); - -protected: - std::string iconName; - ZoomControl* zoomCtrl; - - template - friend class SliderItemCreationHelper; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/TooltipToolButton.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/TooltipToolButton.cpp deleted file mode 100644 index 9133123..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/TooltipToolButton.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "TooltipToolButton.h" - -#include // for move - -#include -#include - -#include "util/glib_casts.h" -#include "util/raii/GObjectSPtr.h" // for WidgetSPtr - -TooltipToolButton::TooltipToolButton(std::string id, Category cat, Action action, std::string iconName, - std::string description, std::function fetchTooltip): - ToolButton(std::move(id), cat, action, std::move(iconName), std::move(description), false), - fetchTooltip(std::move(fetchTooltip)) {} - -auto TooltipToolButton::createItem(bool horizontal) -> xoj::util::WidgetSPtr { - auto item = ToolButton::createItem(horizontal); - - gtk_widget_set_has_tooltip(item.get(), true); - - auto* cloneFetchTooltip = new std::function(this->fetchTooltip); - - g_signal_connect_data(item.get(), "query-tooltip", - G_CALLBACK(+[](GtkWidget*, gint, gint, gboolean, GtkTooltip* tooltip, gpointer d) { - auto fn = static_cast*>(d); - gtk_tooltip_set_text(tooltip, (*fn)().c_str()); - return true; - }), - cloneFetchTooltip, xoj::util::closure_notify_cb>, - GConnectFlags(0)); - - return item; -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/TooltipToolButton.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/TooltipToolButton.h deleted file mode 100644 index 1887e7c..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/TooltipToolButton.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include // for string, allocator - -#include // for GtkWidget - -#include "enums/Action.enum.h" // for Action -#include "gui/PopoverFactory.h" -#include "util/raii/GVariantSPtr.h" - -#include "ToolButton.h" - -/// ToolButton with dynamic tooltip description (overrides the GtkWidget::query-tooltip signal handler) -class TooltipToolButton: public ToolButton { -public: - TooltipToolButton(std::string id, Category cat, Action action, std::string iconName, std::string description, - std::function fetchTooltip); - ~TooltipToolButton() override = default; - - xoj::util::WidgetSPtr createItem(bool horizontal) override; - -private: - std::function fetchTooltip; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ColorIcon.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ColorIcon.cpp deleted file mode 100644 index a2e96b0..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ColorIcon.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "ColorIcon.h" - -#include // for M_PI - -#include "util/raii/CairoWrappers.h" -#include "util/raii/GObjectSPtr.h" - -namespace ColorIcon { -/** - * Create a new GtkImage with preview color - */ -auto newGtkImage(Color color, int size, bool circle, std::optional secondaryColor) -> GtkWidget* { - xoj::util::GObjectSPtr img(newGdkPixbuf(color, size, circle, secondaryColor)); - GtkWidget* w = gtk_image_new_from_pixbuf(img.get()); - gtk_widget_show(w); - return w; -} - -/** - * Create a new GdkPixbuf* with preview color - */ -auto newGdkPixbuf(Color color, int size, bool circle, std::optional secondaryColor) - -> xoj::util::GObjectSPtr { - xoj::util::CairoSurfaceSPtr buf(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size, size), xoj::util::adopt); - xoj::util::CairoSPtr cr(cairo_create(buf.get()), xoj::util::adopt); - - Util::cairo_set_source_rgbi(cr.get(), color, 1); - - constexpr double PADDING = 1; - - if (circle) { - const double mid = .5 * size; - const double radius = mid - PADDING; - cairo_arc(cr.get(), mid, mid, radius, 0, 2 * M_PI); - } else { - cairo_rectangle(cr.get(), PADDING, PADDING, size - 2 * PADDING, size - 2 * PADDING); - } - cairo_fill_preserve(cr.get()); - - cairo_set_source_rgba(cr.get(), 0, 0, 0, 1); - cairo_set_line_width(cr.get(), 1); - cairo_stroke(cr.get()); - - if (secondaryColor) { - // Draw an indicator for the secondary color - Util::cairo_set_source_rgbi(cr.get(), secondaryColor.value(), 1); - - const double indicatorMid = size - 2 * PADDING; - const double indicatorRadius = (0.5 * size) - PADDING; - // only draws the upper left quarter of the arc - cairo_arc(cr.get(), indicatorMid, indicatorMid, indicatorRadius, M_PI, M_PI / 2); - cairo_fill_preserve(cr.get()); - - cairo_set_source_rgba(cr.get(), 0, 0, 0, 1); - cairo_set_line_width(cr.get(), 1); - cairo_stroke(cr.get()); - } - - return xoj::util::GObjectSPtr(gdk_pixbuf_get_from_surface(buf.get(), 0, 0, size, size), - xoj::util::adopt); -} -}; // namespace ColorIcon diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ColorIcon.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ColorIcon.h deleted file mode 100644 index 2107e67..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ColorIcon.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Xournal++ - * - * Icon for color buttons - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for GdkPixbuf -#include // for GtkWidget - -#include "util/Color.h" // for Color -#include "util/raii/GObjectSPtr.h" - -namespace ColorIcon { -/** - * @brief Create a new GtkImage with preview color - * @return The pointer is a floating ref - */ -GtkWidget* newGtkImage(Color color, int size = 22, bool circle = true, - std::optional secondaryColor = std::nullopt); - -/** - * @brief Create a new GdkPixbuf* with preview color - */ -xoj::util::GObjectSPtr newGdkPixbuf(Color color, int size = 22, bool circle = true, - std::optional secondaryColor = std::nullopt); -}; // namespace ColorIcon diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ToolbarSeparatorImage.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ToolbarSeparatorImage.cpp deleted file mode 100644 index c18f956..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ToolbarSeparatorImage.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "ToolbarSeparatorImage.h" - -#include // for cairo_create, cairo_destroy, cairo_image_su... -#include // for gdk_pixbuf_get_from_surface -#include // for g_object_unref -#include // for Colors::red, Colors::gray -#include // for cairo_set_source_rgbi - -constexpr double LINE_WIDTH = 5.; -constexpr double MARGIN = 3.; -constexpr double TAIL_SIZE = 5.; - -auto ToolbarSeparatorImage::newImage(SeparatorType separator) -> GtkWidget* { - GdkPixbuf* pixbuf = ToolbarSeparatorImage::getNewToolPixbuf(separator); - GtkWidget* w = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - return w; -} - -auto ToolbarSeparatorImage::getNewToolPixbuf(SeparatorType separator) -> GdkPixbuf* { - constexpr auto width = 30; - constexpr auto height = 30; - cairo_surface_t* crImage = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - cairo_t* cr = cairo_create(crImage); - - Util::cairo_set_source_rgbi(cr, Colors::red); - cairo_set_line_width(cr, LINE_WIDTH); - cairo_move_to(cr, width / 2, 0); - cairo_line_to(cr, width / 2, height); - cairo_stroke(cr); - if (separator == SeparatorType::SPACER) { // add double arrow tails - Util::cairo_set_source_rgbi(cr, Colors::gray); - - cairo_move_to(cr, MARGIN + TAIL_SIZE, height / 2 - TAIL_SIZE); - cairo_line_to(cr, MARGIN, height / 2); - cairo_line_to(cr, MARGIN + TAIL_SIZE, height / 2 + TAIL_SIZE); - - cairo_move_to(cr, width - MARGIN - TAIL_SIZE, height / 2 - TAIL_SIZE); - cairo_line_to(cr, width - MARGIN, height / 2); - cairo_line_to(cr, width - MARGIN - TAIL_SIZE, height / 2 + TAIL_SIZE); - - cairo_stroke(cr); - } - cairo_destroy(cr); - GdkPixbuf* pixbuf = gdk_pixbuf_get_from_surface(crImage, 0, 0, width, height); - cairo_surface_destroy(crImage); - return pixbuf; -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ToolbarSeparatorImage.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ToolbarSeparatorImage.h deleted file mode 100644 index 57b34f6..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/icon/ToolbarSeparatorImage.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Xournal++ - * - * Toolbar icon for separator (only used for drag and drop and so) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for GdkPixbuf -#include // for GtkWidget - -enum SeparatorType { SEPARATOR, SPACER }; - -/** - * Menuitem handler - */ -namespace ToolbarSeparatorImage { - -/** - * @brief Create Seperator Widget - * This is used in the toolbar for spacing between items. - * - * @return GtkWidget* Separator - */ -GtkWidget* newImage(SeparatorType separator); - -/** - * @brief Create Separator Pixbuf - * This is used in the toolbar customization to drag the separator - * from the Customization dialog to the toolbar and vice versa. - * - * @return GdkPixbuf* Seperator - */ -GdkPixbuf* getNewToolPixbuf(SeparatorType separator); -}; // namespace ToolbarSeparatorImage diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ColorPalette.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ColorPalette.cpp deleted file mode 100644 index 142aa5b..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ColorPalette.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "ColorPalette.h" - -#include // for basic_ifstream, basic_ofstream -#include -#include // for operator<<, basic_ostream::operator<< -#include // for invalid_argument -#include // for move - -#include // for g_warning, g_error - -#include "util/StringUtils.h" // for StringUtils -#include "util/Util.h" -#include "util/XojMsgBox.h" -#include "util/i18n.h" // for FORMAT_STR, FS, _ -#include "util/serdesstream.h" // for serdes_stream - - -Palette::Palette(fs::path path): filepath{std::move(path)}, namedColors{}, header{} {} - -void Palette::load() { - if (!fs::exists(this->filepath)) - throw std::invalid_argument( - FS(FORMAT_STR("The palette file {1} does not exist.") % this->filepath.filename().u8string())); - header.clear(); - namedColors.clear(); - - - auto gplFile = serdes_stream(filepath); - gplFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); - - std::string line; - getline(gplFile, line); - int lineNumber{1}; - // parse standard header line - parseFirstGimpPaletteLine(line); - // attempt parsing line by line as either header, color, or fallback - while (!gplFile.eof() && gplFile.peek() != EOF && getline(gplFile, line)) { - lineNumber++; - parseCommentLine(line) || parseHeaderLine(line) || parseColorLine(line) || parseEmptyLine(line) || - parseLineFallback(lineNumber); - } - if (namedColors.size() < 1) { - throw std::invalid_argument("Your Palettefile has no parsable color. It needs at least one!"); - } -} - -auto Palette::load_default() -> void { - std::stringstream defaultFile{default_palette()}; - std::string line; - - getline(defaultFile, line); - if (!parseFirstGimpPaletteLine(line)) - g_error("The default file was mallformed. This should never happen!"); - while (getline(defaultFile, line)) { - parseHeaderLine(line) || parseColorLine(line); - } -} - -auto Palette::getHeader(const std::string& attr) const -> std::string { - if (header.find(attr) == header.end()) { - return std::string{}; - } - return header.at(attr); -} - -auto Palette::parseFirstGimpPaletteLine(const std::string& line) const -> bool { - if (StringUtils::trim(line) != "GIMP Palette") { - throw std::invalid_argument(".gpl file needs to start with \"GIMP Palette\" in the " - "first line"); - } - return true; -} - -auto Palette::parseHeaderLine(const std::string& line) -> bool { - Header headerEntry; - std::istringstream iss{line}; - if (iss >> headerEntry) { - header[headerEntry.getAttribute()] = headerEntry.getValue(); - return true; - } - return false; -} - -auto Palette::parseColorLine(const std::string& line) -> bool { - NamedColor color{namedColors.size()}; - std::istringstream iss{line}; - if (iss >> color) { - namedColors.emplace_back(std::move(color)); - return true; - } - return false; -} - -auto Palette::parseCommentLine(const std::string& line) const -> bool { return line.front() == '#'; } - -auto Palette::parseEmptyLine(const std::string& line) const -> bool { return line.empty(); } - -auto Palette::parseLineFallback(int lineNumber) const -> const bool { - throw std::invalid_argument(FS(FORMAT_STR("The line {1} is malformed.") % lineNumber)); -} - -auto Palette::getColorAt(size_t i) const -> NamedColor const& { - if (i >= namedColors.size()) { - i = i % namedColors.size(); - g_warning("There are more Coloritems in the Toolbar than your Palette defines.\n" - "Hence, cycling through palette from the beginning."); - } - - return namedColors.at(i); -} - -auto Palette::size() const -> size_t { return namedColors.size(); } - - -auto Palette::default_palette() -> const std::string { - auto d = serdes_stream(); - d << "GIMP Palette\n" - << "Name: Xournal Palette\n" - << "#\n" - << 0 << " " << 0 << " " << 0 << " " << NC_("Color", "Black") << "\n" - << 0 << " " << 128 << " " << 0 << " " << NC_("Color", "Green") << "\n" - << 0 << " " << 192 << " " << 255 << " " << NC_("Color", "Light Blue") << "\n" - << 0 << " " << 255 << " " << 0 << " " << NC_("Color", "Light Green") << "\n" - << 51 << " " << 51 << " " << 204 << " " << NC_("Color", "Blue") << "\n" - << 128 << " " << 128 << " " << 128 << " " << NC_("Color", "Gray") << "\n" - << 255 << " " << 0 << " " << 0 << " " << NC_("Color", "Red") << "\n" - << 255 << " " << 0 << " " << 255 << " " << NC_("Color", "Magenta") << "\n" - << 255 << " " << 128 << " " << 0 << " " << NC_("Color", "Orange") << "\n" - << 255 << " " << 255 << " " << 0 << " " << NC_("Color", "Yellow") << "\n" - << 255 << " " << 255 << " " << 255 << " " << NC_("Color", "White") << std::endl; - return d.str(); -} - -void Palette::create_default(fs::path filepath) { - auto myfile = serdes_stream(filepath); - myfile << default_palette(); -} - -auto Header::getAttribute() const -> std::string { return this->attribute; }; -auto Header::getValue() const -> std::string { return this->value; }; -auto Palette::getFilePath() const -> fs::path const& { return this->filepath; }; - -auto operator>>(std::istream& str, Header& header) -> std::istream& { - /* - * inspired by - * https://codereview.stackexchange.com/questions/38879/parsing-text-file-in-c - */ - std::string line; - Header tmp; - if (std::getline(str, line)) { - std::istringstream iss{line}; - if (getline(iss, tmp.attribute, ':') && getline(iss, tmp.value, '\n')) { - tmp.attribute = StringUtils::trim(tmp.attribute); - tmp.value = StringUtils::trim(tmp.value); - - // parsing was successful hence results can be stored permanently - header = std::move(tmp); - } else { - /* - * One operation failed. - * So set the state on the main stream - * to indicate failure. - */ - str.setstate(std::ios::failbit); - } - } - return str; -} - -auto Palette::parseErrorDialog(const std::exception& e) const -> void { - std::stringstream msg_stream{}; - msg_stream << "There has been a problem parsing the color palette file at " << char_cast(filepath.u8string()) - << "\n\n"; - msg_stream << "What happened:\n" << e.what() << "\n"; - msg_stream << "What to do:\n"; - msg_stream << "Please fix your palette file, or rename it so xournalpp creates a new default palette file " - "for you. This file can then be used as a template.\n"; - msg_stream << "Until this is fixed, the application will use the default color palette." << std::endl; - - // Call later, to make sure the main window has been set up, so the popup is displayed in front of it (and modal) - Util::execInUiThread([msg = msg_stream.str()]() { XojMsgBox::showErrorToUser(nullptr, msg); }); -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ColorPalette.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ColorPalette.h deleted file mode 100644 index 46778ce..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ColorPalette.h +++ /dev/null @@ -1,217 +0,0 @@ -#pragma once - -#include // for size_t -#include // for exception -#include // for istream -#include // for map -#include // for string, basic_string -#include // for vector - -#include "util/NamedColor.h" // for NamedColor - -#include "filesystem.h" // for path - -/** - * @brief Header entity of a gpl file - * This is simply a key value pair. The main reason to define a struct for this is to define a custom input operator. - * - */ -struct Header { - /** - * @brief Input operator for parsing Header from input string stream - * - * @param str input string stream - * @param header output for parsed Header - * @return std::istream& which is the rest of the input string stream after parsing - */ - friend std::istream& operator>>(std::istream& str, Header& header); - - std::string getAttribute() const; - std::string getValue() const; - -private: - /** - * @brief Attribute name given in gpl file - * - */ - std::string attribute; - - /** - * @brief Value for corresponding attribute in gpl file - * - */ - std::string value; - - /** - * @brief Swap all properties between two Header instances - * - * @param other other Header instance to swap properties with - */ - void swap(Header& other); -}; - -/** - * @brief ColorPalette coming from a parsed gpl file - * - */ -struct Palette { - /** - * @brief Construct a new Palette - * This does not yet parse the file. It simply sets up the class. - * - * @param path to the gpl file - */ - Palette(fs::path path); - - /** - * @brief Create default gpl file string - * Default xournalpp color scheme - * 0 0 0 Black - * 0 128 0 Green - * 0 192 255 Light Blue - * 0 255 0 Light Green - * 51 51 204 Blue - * 128 128 128 Gray - * 255 0 0 Red - * 255 0 255 Magenta - * 255 128 0 Orange - * 255 255 0 Yellow - * 255 255 255 White - * - * @return const std::string - */ - static const std::string default_palette(); - - /** - * @brief Create a default gpl file for the xournalpp color scheme - * See default_palette() for further information. - * - * @param path to write gpl file to - */ - static void create_default(fs::path path); - - /** - * @brief Parse the gpl file in filepath - * This fills the header map and the namedColors vector after clearing them first - * - * @throw exception in case of wrong formatted file - * - */ - void load(); - - /** - * @brief Load the default Palette - * - */ - void load_default(); - - /** - * @brief Show a Dialog with only an OK button - * - * @param message to be displayed in the dialog - */ - void parseErrorDialog(const std::exception& e) const; - - /** - * @brief Get the number of namedColors part of the palette - * - * @return size_t number of namedColors in palette - */ - size_t size() const; - - /** - * @brief Get a NamedColor from the palette - * - * @param i palette index - * @return NamedColor of palette at palette index - */ - NamedColor const& getColorAt(size_t i) const; - - fs::path const& getFilePath() const; - - std::string getHeader(const std::string& attr) const; - - -private: - /** - * @brief filepath to the gpl file the palette is coming from - * - */ - fs::path filepath; - - /** - * @brief Vector containing all colors of the palette - * - */ - std::vector namedColors; - - /** - * @brief Map containing the key value pairs of the gpl header - * e.g. "Palette Name", "Description" - * - */ - std::map header; - - /** - * @brief Verify if line contains the expected "GIMP Palette" string - * - * @param line first line of gpl file - * @return true if line is "GIMP Palette" - * @return false otherwise - */ - bool parseFirstGimpPaletteLine(const std::string& line) const; - - /** - * @brief Try to parse a color and add it to namedColors - * - * - * @param line line of gpl file - * @return true if line is of form "255 255 255 White" (r g b name) - * @return false otherwise - */ - bool parseColorLine(const std::string& line); - - /** - * @brief Try to parse a header key value pair and add it to header - * - * @param line line of gpl file - * @return true if line is of form "key:value" - * @return false otherwise - */ - bool parseHeaderLine(const std::string& line); - - /** - * @brief Parse a Comment line - * Every line starting with "#" will be considered a comment - * - * @param line - * @return true if line starts with "#" - * @return false else - */ - bool parseCommentLine(const std::string& line) const; - - /** - * @brief Parse an empty line - * Empty lines do not contain any characters and are ignored - * - * @param line - * @return true if line is empty - * @return false otherwise - */ - bool parseEmptyLine(const std::string& line) const; - - /** - * @brief Fallback for line parsing - * This function is the fallback in case no other parsing attempt works. - * In this case this function throws an error containing the non-parseable line number - * - * This should be used in the following way - * - * firstLineParseAttempt(line) || secondLineParseAttempt(line) || parseLineFallback(lineNumber) - * - * @param lineNumber of the erroneous line - * @return nothing as it always throws an error - * @throw invalid_argument exception if not a comment - */ - const bool parseLineFallback(int lineNumber) const; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarData.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarData.cpp deleted file mode 100644 index 9481fb1..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarData.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "ToolbarData.h" - -#include // for strcmp, strncmp -#include // for move - -#include "gui/toolbarMenubar/model/ColorPalette.h" // for Palette -#include "gui/toolbarMenubar/model/ToolbarEntry.h" // for ToolbarEntry, Too... -#include "gui/toolbarMenubar/model/ToolbarItem.h" // for ToolbarItem -#include "util/PlaceholderString.h" // for PlaceholderString -#include "util/StringUtils.h" // for StringUtils -#include "util/i18n.h" // for FC, FORMAT_STR, _F - -using std::string; - -ToolbarData::ToolbarData(bool predefined): predefined(predefined) {} - -ToolbarData::ToolbarData(const ToolbarData& data) { - *this = data; - this->predefined = false; -} - -void ToolbarData::operator=(const ToolbarData& other) { - this->id = other.id; - this->name = other.name; - this->predefined = other.predefined; - this->contents = other.contents; -} - -ToolbarData::~ToolbarData() = default; - -auto ToolbarData::getName() const -> const std::string& { return this->name; } - -void ToolbarData::setName(string name) { this->name = std::move(name); } - -auto ToolbarData::getId() const -> const std::string& { return this->id; } - -void ToolbarData::setId(string id) { this->id = std::move(id); } - -auto ToolbarData::isPredefined() const -> bool { return this->predefined; } - -void ToolbarData::load(GKeyFile* config, const char* group, const Palette& colorPalette) { - - size_t unassignedColorIndex = 0U; - auto filterDeprecatedItemNames = [&](std::string name) -> std::string { - // recognize previous name, V1.07 (Jan 2019) and earlier. - if (name == "TWO_PAGES") { - return "PAIRED_PAGES"; - } - - // recognize previous name, V1.08 (Feb 2019) and earlier. - if (name == "RECSTOP") { - return "AUDIO_RECORDING"; - } - - // recognize previous name, V1.0.19 (Dec 2020) and earlier - if (name == "HILIGHTER") { - return "HIGHLIGHTER"; - } - - // recognize previous name, V1.1.0+dev (Jan 2021) and earlier - if (name == "DRAW_CIRCLE") { - return "DRAW_ELLIPSE"; - } - - // recognize previous name, V1.1.0+dev (Nov 2022) and earlier - if (name == "PEN_FILL_OPACITY") { - return "FILL_OPACITY"; - } - - if (StringUtils::startsWith(name, "COLOR(") && StringUtils::endsWith(name, ")")) { - std::string arg = name.substr(6, name.length() - 7); - // check for old color format of toolbar.ini - if (StringUtils::startsWith(arg, "0x")) { - auto paletteIndex = colorPalette.getColorAt(unassignedColorIndex++).getIndex(); - return "COLOR(" + std::to_string(paletteIndex) + ")"; - } - } - - return name; - }; - - gsize length = 0; - gchar** keys = g_key_file_get_keys(config, group, &length, nullptr); - if (keys == nullptr) { - return; - } - - gchar* name = g_key_file_get_locale_string(config, group, "name", nullptr, nullptr); - if (name != nullptr) { - this->name = name; - g_free(name); - } - - for (gsize i = 0; i < length; i++) { - if (strcmp(keys[i], "name") == 0 || strncmp(keys[i], "name[", 5) == 0) { - continue; - } - - auto& e = contents.emplace_back(); - e.setName(keys[i]); - - gsize keyLen = 0; - gchar** list = g_key_file_get_string_list(config, group, keys[i], &keyLen, nullptr); - - for (gsize x = 0; x < keyLen; x++) { - e.addItem(filterDeprecatedItemNames(StringUtils::trim(std::string(list[x])))); - } - - g_strfreev(list); - } - - g_strfreev(keys); -} - -void ToolbarData::saveToKeyFile(GKeyFile* config) const { - string group = getId(); - - for (const ToolbarEntry& e: this->contents) { - string line{}; - - for (const auto& it: e.getItems()) { - line += ","; - line += it.getName(); - } - - if (line.length() > 2) { - g_key_file_set_string(config, group.c_str(), e.getName().c_str(), line.substr(1).c_str()); - } - } - - g_key_file_set_string(config, group.c_str(), "name", this->name.c_str()); -} - -auto ToolbarData::insertItem(const std::string& toolbar, const std::string& item, int position) -> int { - g_message("ToolbarData::insertItem(%s, %s, %d);", toolbar.data(), item.data(), position); - - g_return_val_if_fail(isPredefined() == false, -1); - - for (ToolbarEntry& e: this->contents) { - if (e.getName() == toolbar) { - g_message(" | Toolbar %s found -- Inserting element", toolbar.c_str()); - return e.insertItem(item, position); - } - } - - // No toolbar named toolbar. Adding a new one - g_message(" | Toolbar %s not found -- Creating a new one", toolbar.c_str()); - auto& newEntry = contents.emplace_back(); - newEntry.setName(toolbar); - return newEntry.addItem(item); -} - -auto ToolbarData::removeItemByID(const string& toolbar, int id) -> bool { - g_return_val_if_fail(isPredefined() == false, false); - - for (ToolbarEntry& e: contents) { - if (e.getName() == toolbar) { - return e.removeItemById(id); - } - } - - return false; -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarData.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarData.h deleted file mode 100644 index 412caa3..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarData.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Xournal++ - * - * Toolbar definitions model - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string -#include // for vector - -#include // for GKeyFile - -class ToolbarEntry; -struct Palette; - -class ToolbarData { -public: - ToolbarData(bool predefined); - ToolbarData(const ToolbarData& data); - virtual ~ToolbarData(); - - void operator=(const ToolbarData& other); - -public: - const std::string& getName() const; - void setName(std::string name); - const std::string& getId() const; - void setId(std::string id); - bool isPredefined() const; - - void load(GKeyFile* config, const char* group, const Palette& colorPalette); - void saveToKeyFile(GKeyFile* config) const; - - // Editing API - int insertItem(const std::string& toolbar, const std::string& item, int position); - bool removeItemByID(const std::string& toolbar, int id); - -private: - std::string id; - std::string name; - std::vector contents; - - bool predefined = false; - - friend class ToolbarModel; - friend class ToolMenuHandler; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarEntry.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarEntry.cpp deleted file mode 100644 index 260b7f7..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarEntry.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "ToolbarEntry.h" - -#include -#include // for move - -#include - -#include "gui/toolbarMenubar/model/ToolbarItem.h" // for ToolbarItem -#include "util/Assert.h" - -ToolbarEntry::ToolbarEntry() = default; - -ToolbarEntry::ToolbarEntry(const ToolbarEntry& e) { *this = e; } -ToolbarEntry::ToolbarEntry(ToolbarEntry&& e) { *this = std::move(e); } - -ToolbarEntry& ToolbarEntry::operator=(const ToolbarEntry& e) { - this->name = e.name; - this->entries = e.entries; - return *this; -} - -ToolbarEntry& ToolbarEntry::operator=(ToolbarEntry&& e) { - this->name = std::move(e.name); - this->entries = std::move(e.entries); - return *this; -} - -ToolbarEntry::~ToolbarEntry() = default; - -auto ToolbarEntry::getName() const -> std::string { return this->name; } - -void ToolbarEntry::setName(std::string name) { this->name = std::move(name); } - -auto ToolbarEntry::addItem(std::string item) -> int { return entries.emplace_back(std::move(item)).getId(); } - -auto ToolbarEntry::removeItemById(int id) -> bool { - auto it = std::find_if(entries.begin(), entries.end(), [id](const auto& it) { return it.getId() == id; }); - if (it != entries.end()) { - entries.erase(it); - return true; - } - g_warning("ToolbarEntry::removeItemById: Tried to remove inexistant ID"); - return false; -} - -auto ToolbarEntry::insertItem(std::string item, int position) -> int { - xoj_assert(position >= 0); - if (position >= static_cast(entries.size())) { - return entries.emplace_back(std::move(item)).getId(); - } - - return entries.emplace(std::next(entries.begin(), position), std::move(item))->getId(); -} - -auto ToolbarEntry::getItems() const -> const ToolbarItemVector& { return entries; } diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarEntry.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarEntry.h deleted file mode 100644 index 96eccf8..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarEntry.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string -#include // for vector - -class ToolbarItem; - -typedef std::vector ToolbarItemVector; - -class ToolbarEntry { -public: - ToolbarEntry(); - ToolbarEntry(const ToolbarEntry& e); - ToolbarEntry(ToolbarEntry&& e); - ~ToolbarEntry(); - - ToolbarEntry& operator=(const ToolbarEntry& e); - ToolbarEntry& operator=(ToolbarEntry&& e); - -public: - std::string getName() const; - void setName(std::string name); - - /** - * Adds a new item and return the ID of the item - */ - int addItem(std::string item); - bool removeItemById(int id); - - /** - * Insert a new item and return the ID of the item - */ - int insertItem(std::string item, int position); - - const ToolbarItemVector& getItems() const; - -private: - std::string name; - ToolbarItemVector entries; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarItem.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarItem.cpp deleted file mode 100644 index dd85d2f..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarItem.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "ToolbarItem.h" - -#include - -int ToolbarItem::sid = 0; - -ToolbarItem::ToolbarItem(std::string name) { - this->name = std::move(name); - this->id = ToolbarItem::sid++; - - if (ToolbarItem::sid < 0) { - ToolbarItem::sid = 0; - } -} - -auto ToolbarItem::getName() const -> std::string { return this->name; } - -void ToolbarItem::setName(std::string name) { this->name = std::move(name); } - -auto ToolbarItem::operator==(ToolbarItem& other) -> bool { return this->name == other.name; } - -auto ToolbarItem::getId() const -> int { return this->id; } diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarItem.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarItem.h deleted file mode 100644 index e5c72f3..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarItem.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Xournal++ - * - * Part of the customizable toolbars - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - - -class ToolbarItem { -public: - ToolbarItem(std::string name); - ToolbarItem() = default; - -public: - std::string getName() const; - void setName(std::string name); - - bool operator==(ToolbarItem& other); - - int getId() const; - -private: - /** - * @brief This is the name of the ToolbarItem - * This is also what is stored in the toolbar.ini verbatim. - * - */ - std::string name; - int id; - - static int sid; -}; diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarModel.cpp b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarModel.cpp deleted file mode 100644 index 8fb5a2a..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarModel.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "ToolbarModel.h" - -#include // for find_if -#include // for size_t - -#include "util/StringUtils.h" -#include "util/XojMsgBox.h" // for XojMsgBox -#include "util/i18n.h" // for _ -#include "util/safe_casts.h" // for as_signed - -#include "ToolbarData.h" // for ToolbarData -#include "filesystem.h" // for path - -ToolbarModel::ToolbarModel() = default; -ToolbarModel::~ToolbarModel() = default; - -auto ToolbarModel::getToolbars() const -> const std::vector>& { return this->toolbars; } - -void ToolbarModel::parseGroup(GKeyFile* config, const char* group, bool predefined, const Palette& colorPalette) { - auto data = std::make_unique(predefined); - - data->name = (predefined ? "predef_" : "custom_"); - data->id = group; - - data->load(config, group, colorPalette); - - add(std::move(data)); -} - -void ToolbarModel::remove(ToolbarData* data) { - auto it = std::find_if(toolbars.begin(), toolbars.end(), [data](const auto& tb) { return tb.get() == data; }); - if (it != this->toolbars.end()) { - this->toolbars.erase(it); - } -} - -auto ToolbarModel::add(std::unique_ptr data) -> ToolbarData* { - return this->toolbars.emplace_back(std::move(data)).get(); -} - -auto ToolbarModel::parse(fs::path const& filepath, bool predefined, const Palette& colorPalette) -> bool { - GKeyFile* config = g_key_file_new(); - g_key_file_set_list_separator(config, ','); - if (!g_key_file_load_from_file(config, char_cast(filepath.u8string().c_str()), G_KEY_FILE_NONE, nullptr)) { - g_key_file_free(config); - return false; - } - - gsize length = 0; - gchar** groups = g_key_file_get_groups(config, &length); - - for (gsize i = 0; i < length; i++) { - parseGroup(config, groups[i], predefined, colorPalette); - } - - g_strfreev(groups); - g_key_file_free(config); - return true; -} - -void ToolbarModel::initCopyNameId(ToolbarData* data) { - if (!existsId(data->getId())) { - return; - } - for (int i = 0; i < 100; i++) { - std::string id = data->getId() + " Copy"; - - if (i > 0) { - id += " "; - id += std::to_string(i); - } - - if (!existsId(id)) { - std::string filename = data->getName(); - filename += " "; - filename += C_("as a noun: a copy of", "Copy"); - - if (i > 0) { - filename += " "; - filename += std::to_string(i); - } - - data->setName(filename); - data->setId(id); - return; - } - } -} - -auto ToolbarModel::existsId(const std::string& id) const -> bool { - return std::any_of(toolbars.begin(), toolbars.end(), [&id](const auto& d) { return d->getId() == id; }); -} - -const char* TOOLBAR_INI_HEADER = - "# Xournal++ Toolbar configuration\n" - "# Here you can customize the Toolbars\n" - " Delete this file to generate a new config file with default values\n" - "\n" - " Available buttons:\n" - " File: NEW,OPEN,SAVE,SAVEPDF,PRINT\n" - "\n" - " Edit: UNDO,REDO,CUT,COPY,PASTE,SEARCH,DELETE,ROTATION_SNAPPING,GRID_SNAPPING\n" - "\n" - " View: PAIRED_PAGES,PRESENTATION_MODE,FULLSCREEN,MANAGE_TOOLBAR,CUSTOMIZE_TOOLBAR,ZOOM_OUT,ZOOM_IN,ZOOM_FIT,ZOOM_100\n" - "\n" - " Navigation: GOTO_FIRST,GOTO_BACK,GOTO_PAGE,GOTO_NEXT,GOTO_LAST,GOTO_PREVIOUS_LAYER,GOTO_NEXT_LAYER,GOTO_TOP_LAYER,\n" - " GOTO_NEXT_ANNOTATED_PAGE\n" - "\n" - " Journal: INSERT_NEW_PAGE,DELETE_CURRENT_PAGE\n" - "\n" - " Tool: PEN,PLAIN,DASHED,DASH-/ DOTTED,DOTTED,ERASER,HIGHLIGHTER,TEXT,MATH_TEX,IMAGE,DEFAULT_TOOL,SHAPE_RECOGNIZER,SELECT_PDF_TEXT_LINEAR,\n" - " SELECT_PDF_TEXT_RECT,DRAW_RECTANGLE,DRAW_ELLIPSE,DRAW_ARROW,DRAW_DOUBLE_ARROW,DRAW_COORDINATE_SYSTEM,RULER,DRAW_SPLINE,\n" - " SELECT_REGION,SELECT_RECTANGLE,SELECT_MULTILAYER_REGION,SELECT_MULTILAYER_RECTANGLE,SELECT_OBJECT,VERTICAL_SPACE,PLAY_OBJECT,\n" - " HAND,SETSQUARE,COMPASS,SELECT_FONT,AUDIO_RECORDING,AUDIO_PAUSE_PLAYBACK,AUDIO_STOP_PLAYBACK,AUDIO_SEEK_FORWARDS,AUDIO_SEEK_BACKWARDS\n" - - " Notice: ERASER and PEN also have drop down menus to select the type, SELECT are all selection tools, with drop down menu\n" - "\n" - " Footer tools: PAGE_SPIN,ZOOM_SLIDER,LAYER,TOOL_FILL,PEN_FILL_OPACITY\n" - " PAGE_SPIN: The page spiner, incl. current page label\n" - " ZOOM_SLIDER: The zoom slider\n" - " LAYER: The layer dropdown menu\n" - "\n" - " Color: " - "COLOR(0),COLOR(1),COLOR(2),COLOR(3),COLOR(4),COLOR(5),COLOR(6),COLOR(7),COLOR(8),COLOR(9),COLOR(10),COLOR_SELECT\n" - " Notice: The colors reference the respective color in the palette.gpl file.\n" - " For backwards compatibility the hex representation, e.g. COLOR(0xff8000), is still permitted. However, the hex value\n" - " will be IGNORED in favour of the \"next\" palette color. They will be automatically migrated when the user customizes\n" - " the respective toolbar configuration.\n" - "\n" - " Non-menu items: SELECT,DRAW,PDF_TOOL\n" - "\n" - " Tool configuration: VERY_FINE,FINE,MEDIUM,THICK,VERY_THICK\n" - "\n" - " Item separation: SEPARATOR,SPACER\n" - "\n"; - -void ToolbarModel::save(fs::path const& filepath) const { - GKeyFile* config = g_key_file_new(); - g_key_file_set_list_separator(config, ','); - - g_key_file_set_comment(config, nullptr, nullptr, TOOLBAR_INI_HEADER, nullptr); - - for (const auto& data: this->toolbars) { - if (!data->isPredefined()) { - data->saveToKeyFile(config); - } - } - - gsize len = 0; - char* data = g_key_file_to_data(config, &len, nullptr); - - g_key_file_free(config); - config = nullptr; - - GError* error = nullptr; - if (!g_file_set_contents(char_cast(filepath.u8string().c_str()), data, as_signed(len), &error)) { - XojMsgBox::showErrorToUser(nullptr, error->message); - g_error_free(error); - } - - g_free(data); -} diff --git a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarModel.h b/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarModel.h deleted file mode 100644 index bc3f07b..0000000 --- a/entry/src/main/cpp/src/core/gui/toolbarMenubar/model/ToolbarModel.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Xournal++ - * - * Toolbar definitions model - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include -#include - -#include - -#include "filesystem.h" - -class ToolbarData; -struct Palette; - -class ToolbarModel { -public: - ToolbarModel(); - virtual ~ToolbarModel(); - -private: - ToolbarModel(const ToolbarModel& other); - void operator=(const ToolbarModel& other); - -public: - const std::vector>& getToolbars() const; - bool parse(fs::path const& filepath, bool predefined, const Palette& colorPalette); - ToolbarData* add(std::unique_ptr data); - void remove(ToolbarData* data); - void save(const fs::path& filepath) const; - bool existsId(const std::string& id) const; - void initCopyNameId(ToolbarData* data); - -private: - void parseGroup(GKeyFile* config, const char* group, bool predefined, const Palette& colorPalette); - -private: - std::vector> toolbars; -}; diff --git a/entry/src/main/cpp/src/core/gui/widgets/SpinPageAdapter.cpp b/entry/src/main/cpp/src/core/gui/widgets/SpinPageAdapter.cpp deleted file mode 100644 index f11d985..0000000 --- a/entry/src/main/cpp/src/core/gui/widgets/SpinPageAdapter.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "SpinPageAdapter.h" - -#include // for uint64_t - -#include // for g_signal_handler_disconnect, G_CALLBACK - -#include "util/Assert.h" // for xoj_assert -#include "util/glib_casts.h" // for wrap_for_once_v -#include "util/safe_casts.h" - -auto SpinPageAdapter::pageNrSpinChangedTimerCallback(SpinPageAdapter* adapter) -> bool { - adapter->page = strict_cast(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(adapter->widget.get()))); - - adapter->firePageChanged(); - - adapter->timeout.consume(); - return false; -} - -void SpinPageAdapter::pageNrSpinChangedCallback(GtkSpinButton* spinbutton, SpinPageAdapter* adapter) { - // Nothing changed. - if (as_unsigned(gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton))) == adapter->page) { - return; - } - - // Give the spin button some time to release, if we don't do he will send new events... - adapter->timeout = g_timeout_add(100, xoj::util::wrap_for_once_v, adapter); -} - -void SpinPageAdapter::setWidget(GtkWidget* widget) { - if (this->widget && this->pageNrSpinChangedHandlerId) { - g_signal_handler_disconnect(this->widget.get(), this->pageNrSpinChangedHandlerId); - } - xoj_assert(widget); - this->widget.reset(widget, xoj::util::refsink); - this->pageNrSpinChangedHandlerId = - g_signal_connect(widget, "value-changed", G_CALLBACK(pageNrSpinChangedCallback), this); - - gtk_spin_button_set_range(GTK_SPIN_BUTTON(widget), static_cast(this->min), static_cast(this->max)); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), static_cast(this->page)); -} - -auto SpinPageAdapter::getPage() const -> size_t { return this->page; } - -void SpinPageAdapter::setPage(size_t page) { - this->page = page; - if (this->widget) { - gtk_spin_button_set_value(GTK_SPIN_BUTTON(this->widget.get()), static_cast(page)); - } -} - -void SpinPageAdapter::setMinMaxPage(size_t min, size_t max) { - this->min = min; - this->max = max; - if (this->widget) { - gtk_spin_button_set_range(GTK_SPIN_BUTTON(this->widget.get()), static_cast(min), - static_cast(max)); - } -} - -void SpinPageAdapter::addListener(SpinPageListener* listener) { this->listener = listener; } - -void SpinPageAdapter::removeListener(SpinPageListener* listener) { - xoj_assert(listener == this->listener); - this->listener = nullptr; -} - -void SpinPageAdapter::firePageChanged() { this->listener->pageChanged(this->page); } - -SpinPageListener::~SpinPageListener() = default; diff --git a/entry/src/main/cpp/src/core/gui/widgets/SpinPageAdapter.h b/entry/src/main/cpp/src/core/gui/widgets/SpinPageAdapter.h deleted file mode 100644 index 88f7bd6..0000000 --- a/entry/src/main/cpp/src/core/gui/widgets/SpinPageAdapter.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Xournal++ - * - * Handle the Page Spin Widget - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t -#include // for list - -#include // for guint, gulong -#include // for GtkWidget, GtkSpinButton - -#include "util/raii/GObjectSPtr.h" // for WidgetSPtr -#include "util/raii/GSourceURef.h" - -class SpinPageListener; - -class SpinPageAdapter final { -public: - SpinPageAdapter() = default; - ~SpinPageAdapter() = default; - -public: - /** - * Assumes ownership of widget - */ - void setWidget(GtkWidget* widget); - - size_t getPage() const; - void setPage(size_t page); - void setMinMaxPage(size_t min, size_t max); - - void addListener(SpinPageListener* listener); - void removeListener(SpinPageListener* listener); - -private: - static bool pageNrSpinChangedTimerCallback(SpinPageAdapter* adapter); - static void pageNrSpinChangedCallback(GtkSpinButton* spinbutton, SpinPageAdapter* adapter); - - void firePageChanged(); - -private: - xoj::util::WidgetSPtr widget; - gulong pageNrSpinChangedHandlerId = 0; - size_t page = 0; - - xoj::util::GSourceURef timeout; - SpinPageListener* listener; - - size_t min = 0; - size_t max = 0; -}; - -class SpinPageListener { -public: - virtual void pageChanged(size_t page) = 0; - virtual ~SpinPageListener(); -}; diff --git a/entry/src/main/cpp/src/core/gui/widgets/XournalWidget.cpp b/entry/src/main/cpp/src/core/gui/widgets/XournalWidget.cpp deleted file mode 100644 index 0435848..0000000 --- a/entry/src/main/cpp/src/core/gui/widgets/XournalWidget.cpp +++ /dev/null @@ -1,327 +0,0 @@ -#include "XournalWidget.h" - -#include // for max -#include // for NAN -#include // for optional -#include // for vector - -#include // for cairo_restore, cairo_save -#include // for GdkRectangle, GdkWindowAttr - -#include "control/Control.h" // for Control -#include "control/settings/Settings.h" // for Settings -#include "control/tools/EditSelection.h" // for EditSelection -#include "gui/Layout.h" // for Layout -#include "gui/LegacyRedrawable.h" // for Redrawable -#include "gui/PageView.h" // for XojPageView -#include "gui/Shadow.h" // for Shadow -#include "gui/XournalView.h" // for XournalView -#include "gui/inputdevices/InputContext.h" // for InputContext -#include "gui/scroll/ScrollHandling.h" // for ScrollHandling -#include "util/Color.h" // for cairo_set_source_rgbi -#include "util/Rectangle.h" // for Rectangle - -#include "config-debug.h" // for DEBUG_DRAW_WIDGET - -/* - * Declares: - * static void gtk_xournal_class_init(GtkXournalClass*); - * static void gtk_xournal_init(GtkXournal*); - * Defines - * gtk_xournal_parent_class (pointer to GtkWidgetClass instance) - * GType gtk_xournal_get_type(); - */ -G_DEFINE_TYPE(GtkXournal, gtk_xournal, GTK_TYPE_WIDGET) - -static void gtk_xournal_get_preferred_width(GtkWidget* widget, gint* minimal_width, gint* natural_width); -static void gtk_xournal_get_preferred_height(GtkWidget* widget, gint* minimal_height, gint* natural_height); -static void gtk_xournal_size_allocate(GtkWidget* widget, GtkAllocation* allocation); -static void gtk_xournal_realize(GtkWidget* widget); -static auto gtk_xournal_draw(GtkWidget* widget, cairo_t* cr) -> gboolean; -static void gtk_xournal_dispose(GObject* object); - -auto gtk_xournal_new(XournalView* view, InputContext* inputContext) -> GtkWidget* { - GtkXournal* xoj = GTK_XOURNAL(g_object_new(gtk_xournal_get_type(), nullptr)); - xoj->view = view; - xoj->scrollHandling = inputContext->getScrollHandling(); - xoj->layout = new Layout(view, inputContext->getScrollHandling()); - xoj->selection = nullptr; - xoj->input = inputContext; - - xoj->input->connect(GTK_WIDGET(xoj)); - - return GTK_WIDGET(xoj); -} - -static void gtk_xournal_class_init(GtkXournalClass* cptr) { - auto* widget_class = reinterpret_cast(cptr); - - widget_class->realize = gtk_xournal_realize; - widget_class->get_preferred_width = gtk_xournal_get_preferred_width; - widget_class->get_preferred_height = gtk_xournal_get_preferred_height; - widget_class->size_allocate = gtk_xournal_size_allocate; - - widget_class->draw = gtk_xournal_draw; - -#ifdef DEBUG_DRAW_WIDGET - widget_class->queue_draw_region = +[](GtkWidget* w, const cairo_region_t* reg) { - cairo_rectangle_int_t r; - cairo_region_get_extents(reg, &r); - auto width = gtk_widget_get_allocated_width(w); - auto height = gtk_widget_get_allocated_height(w); - - auto widthp = gtk_widget_get_allocated_width(gtk_widget_get_parent(w)); - auto heightp = gtk_widget_get_allocated_height(gtk_widget_get_parent(w)); - printf(" * queue_draw_region: %d x %d + (%d ; %d) out of %d x %d parent: %d x %d\n", r.width, r.height, r.x, - r.y, width, height, widthp, heightp); - GTK_WIDGET_CLASS(gtk_xournal_parent_class)->queue_draw_region(w, reg); - }; -#endif - - G_OBJECT_CLASS(cptr)->dispose = gtk_xournal_dispose; -} - -auto gtk_xournal_get_visible_area(GtkWidget* widget, const XojPageView* p) -> xoj::util::Rectangle* { - g_return_val_if_fail(widget != nullptr, nullptr); - g_return_val_if_fail(GTK_IS_XOURNAL(widget), nullptr); - - GtkXournal* xournal = GTK_XOURNAL(widget); - - GtkAdjustment* vadj = xournal->scrollHandling->getVertical(); - GtkAdjustment* hadj = xournal->scrollHandling->getHorizontal(); - - GdkRectangle r2; - r2.x = static_cast(gtk_adjustment_get_value(hadj)); - r2.y = static_cast(gtk_adjustment_get_value(vadj)); - r2.width = static_cast(gtk_adjustment_get_page_size(hadj)); - r2.height = static_cast(gtk_adjustment_get_page_size(vadj)); - - GdkRectangle r1; - r1.x = p->getX(); - r1.y = p->getY(); - r1.width = p->getDisplayWidth(); - r1.height = p->getDisplayHeight(); - - GdkRectangle r3 = {0, 0, 0, 0}; - gdk_rectangle_intersect(&r1, &r2, &r3); - - if (r3.width == 0 && r3.height == 0) { - return nullptr; - } - - r3.x -= r1.x; - r3.y -= r1.y; - - double zoom = xournal->view->getZoom(); - - if (r3.x < 0 || r3.y < 0) { - g_warning("XournalWidget:gtk_xournal_get_visible_area: intersection rectangle coordinates are negative which " - "should never happen"); - } - - return new xoj::util::Rectangle(std::max(r3.x, 0) / zoom, std::max(r3.y, 0) / zoom, r3.width / zoom, - r3.height / zoom); -} - -auto gtk_xournal_get_layout(GtkWidget* widget) -> Layout* { - g_return_val_if_fail(widget != nullptr, nullptr); - g_return_val_if_fail(GTK_IS_XOURNAL(widget), nullptr); - - GtkXournal* xournal = GTK_XOURNAL(widget); - return xournal->layout; -} - -static void gtk_xournal_init(GtkXournal* xournal) { - GtkWidget* widget = GTK_WIDGET(xournal); - - gtk_widget_set_can_focus(widget, true); -} - -static void gtk_xournal_get_preferred_width(GtkWidget* widget, gint* minimal_width, gint* natural_width) { - g_return_if_fail(GTK_IS_XOURNAL(widget)); - GtkXournal* xournal = GTK_XOURNAL(widget); - g_return_if_fail(xournal->layout); - *minimal_width = *natural_width = xournal->layout->getMinimalWidth(); -} - -static void gtk_xournal_get_preferred_height(GtkWidget* widget, gint* minimal_height, gint* natural_height) { - g_return_if_fail(GTK_IS_XOURNAL(widget)); - GtkXournal* xournal = GTK_XOURNAL(widget); - g_return_if_fail(xournal->layout); - *minimal_height = *natural_height = xournal->layout->getMinimalHeight(); -} - -/** - * This method is called while scrolling or after the XournalWidget size has changed - */ -static void gtk_xournal_size_allocate(GtkWidget* widget, GtkAllocation* allocation) { - g_return_if_fail(widget != nullptr); - g_return_if_fail(GTK_IS_XOURNAL(widget)); - g_return_if_fail(allocation != nullptr); - - gtk_widget_set_allocation(widget, allocation); - - if (gtk_widget_get_realized(widget)) { - gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x, allocation->y, allocation->width, - allocation->height); - } - - GtkXournal* xournal = GTK_XOURNAL(widget); - - // layout the pages in the XournalWidget - xournal->layout->layoutPages(allocation->width, allocation->height); -} - -static void gtk_xournal_realize(GtkWidget* widget) { - GdkWindowAttr attributes; - - g_return_if_fail(widget != nullptr); - g_return_if_fail(GTK_IS_XOURNAL(widget)); - - gtk_widget_set_realized(widget, true); - - gtk_widget_set_hexpand(widget, true); - gtk_widget_set_vexpand(widget, true); - - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK; - - gint attributes_mask = GDK_WA_X | GDK_WA_Y; - - gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask)); - gdk_window_set_user_data(gtk_widget_get_window(widget), widget); -} - -static void gtk_xournal_draw_shadow(GtkXournal* xournal, cairo_t* cr, int left, int top, int width, int height, - bool selected) { - if (selected) { - Shadow::drawShadow(cr, left - 2, top - 2, width + 4, height + 4); - - Settings* settings = xournal->view->getControl()->getSettings(); - - // Draw border - Util::cairo_set_source_rgbi(cr, settings->getBorderColor()); - cairo_set_line_width(cr, 2.0); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); - - cairo_rectangle(cr, left - 1, top - 1, width + 2, height + 2); - cairo_stroke(cr); - } else { - Shadow::drawShadow(cr, left, top, width, height); - } -} - -void gtk_xournal_repaint_area(GtkWidget* widget, int x1, int y1, int x2, int y2) { - g_return_if_fail(widget != nullptr); - g_return_if_fail(GTK_IS_XOURNAL(widget)); - - if (x2 < 0 || y2 < 0) { - return; // outside visible area - } - - GtkAllocation alloc = {0}; - gtk_widget_get_allocation(widget, &alloc); - - if (x1 > alloc.width || y1 > alloc.height) { - return; // outside visible area - } - - gtk_widget_queue_draw_area(widget, x1, y1, x2 - x1, y2 - y1); -} - -static auto gtk_xournal_draw(GtkWidget* widget, cairo_t* cr) -> gboolean { - g_return_val_if_fail(widget != nullptr, false); - g_return_val_if_fail(GTK_IS_XOURNAL(widget), false); - - -#ifdef DEBUG_DRAW_WIDGET - { - double x1 = NAN, x2 = NAN, y1 = NAN, y2 = NAN; - cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n" - " DRAW %d x %d + (%d ; %d)\n\n" - "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$&&&&&&&&&&&&&&&&&&&&&&\n", - round_cast(x2 - x1), round_cast(y2 - y1), round_cast(x1), round_cast(y1)); - } -#endif - - GtkXournal* xournal = GTK_XOURNAL(widget); - - double x1 = NAN, x2 = NAN, y1 = NAN, y2 = NAN; - - cairo_clip_extents(cr, &x1, &y1, &x2, &y2); - - // Draw background - Settings* settings = xournal->view->getControl()->getSettings(); - Util::cairo_set_source_rgbi(cr, settings->getBackgroundColor()); - cairo_paint(cr); - - // Add a padding for the shadow of the pages - xoj::util::Rectangle clippingRect(x1 - 10, y1 - 10, x2 - x1 + 20, y2 - y1 + 20); - - for (auto&& pv: xournal->view->getViewPages()) { - int px = pv->getX(); - int py = pv->getY(); - int pw = pv->getDisplayWidth(); - int ph = pv->getDisplayHeight(); - - if (!clippingRect.intersects(pv->getRect())) { - continue; - } - - gtk_xournal_draw_shadow(xournal, cr, px, py, pw, ph, pv->isSelected()); - - cairo_save(cr); - cairo_translate(cr, px, py); - - pv->paintPage(cr, nullptr); - cairo_restore(cr); - } - - if (xournal->selection) { - cairo_save(cr); - double zoom = xournal->view->getZoom(); - - LegacyRedrawable* red = xournal->selection->getView(); - cairo_translate(cr, red->getX(), red->getY()); - - xournal->selection->paint(cr, zoom); - cairo_restore(cr); - } - - std::optional recolor = settings->getRecolorParameters().recolorizeMainView ? - std::make_optional(settings->getRecolorParameters().recolor) : - std::nullopt; - - if (recolor) { - recolor->recolorCurrentCairoRegion(cr); - } - - return true; -} - -static void gtk_xournal_dispose(GObject* object) { - g_return_if_fail(object != nullptr); - g_return_if_fail(GTK_IS_XOURNAL(object)); - GtkXournal* xournal = GTK_XOURNAL(object); - - delete xournal->selection; - xournal->selection = nullptr; - - delete xournal->layout; - xournal->layout = nullptr; - - delete xournal->input; - xournal->input = nullptr; - - G_OBJECT_CLASS(gtk_xournal_parent_class)->dispose(object); -} diff --git a/entry/src/main/cpp/src/core/gui/widgets/XournalWidget.h b/entry/src/main/cpp/src/core/gui/widgets/XournalWidget.h deleted file mode 100644 index 0644d8a..0000000 --- a/entry/src/main/cpp/src/core/gui/widgets/XournalWidget.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Xournal++ - * - * Xournal widget which is the "View" widget - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for unique_ptr - -#include // for G_TYPE_CHECK_INSTANCE_CAST, G_TYPE_C... -#include // for G_BEGIN_DECLS, G_END_DECLS -#include // for GtkWidget, GtkWidgetClass - -namespace xoj::util { -template -class Rectangle; -} // namespace xoj::util -struct _GtkXournal; -struct _GtkXournalClass; - -G_BEGIN_DECLS - -#define GTK_XOURNAL(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, gtk_xournal_get_type(), GtkXournal) -#define GTK_XOURNAL_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gtk_xournal_get_type(), GtkXournalClass) -#define GTK_IS_XOURNAL(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, gtk_xournal_get_type()) - -class EditSelection; -class Layout; -class XojPageView; -class ScrollHandling; -class XournalView; -class InputContext; - - -typedef struct _GtkXournal GtkXournal; -typedef struct _GtkXournalClass GtkXournalClass; - -struct _GtkXournal { - GtkWidget widget; - - /** - * The view class - */ - XournalView* view; - - /** - * Scrollbars - */ - ScrollHandling* scrollHandling; - - - Layout* layout; - - - /** - * Selected content, if any - */ - EditSelection* selection; - - /** - * Input handling - */ - InputContext* input = nullptr; -}; - -struct _GtkXournalClass { - GtkWidgetClass parent_class; -}; - -GType gtk_xournal_get_type(); - -GtkWidget* gtk_xournal_new(XournalView* view, InputContext* inputContext); - -Layout* gtk_xournal_get_layout(GtkWidget* widget); - -void gtk_xournal_scroll_relative(GtkWidget* widget, double x, double y); - -void gtk_xournal_repaint_area(GtkWidget* widget, int x1, int y1, int x2, int y2); - -xoj::util::Rectangle* gtk_xournal_get_visible_area(GtkWidget* widget, const XojPageView* p); - -G_END_DECLS diff --git a/entry/src/main/cpp/src/core/gui/widgets/ZoomCallib.cpp b/entry/src/main/cpp/src/core/gui/widgets/ZoomCallib.cpp deleted file mode 100644 index a9cafad..0000000 --- a/entry/src/main/cpp/src/core/gui/widgets/ZoomCallib.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Xournal++ - * - * Control to callibrate the zoom to fit the display DPI - * - * @author Xournal Team - * http://xournal.sf.net - * - * @license GPL - */ -#include "ZoomCallib.h" - -#include // for cairo_set_source_rgb, cairo_fill, cairo_move_to -#include // for GdkWindowAttr, gdk_window_move_resize, gdk_wind... - -G_DEFINE_TYPE(ZoomCallib, zoomcallib, GTK_TYPE_WIDGET); - -static void zoomcallib_get_preferred_width(GtkWidget* widget, gint* minimal_width, gint* natural_width); -static void zoomcallib_get_preferred_height(GtkWidget* widget, gint* minimal_height, gint* natural_height); - -static void zoomcallib_size_allocate(GtkWidget* widget, GtkAllocation* allocation); -static void zoomcallib_realize(GtkWidget* widget); -static auto zoomcallib_draw(GtkWidget* widget, cairo_t* cr) -> gboolean; - -void zoomcallib_set_val(ZoomCallib* callib, gint val) { - callib->val = val; - - if (gtk_widget_is_drawable(GTK_WIDGET(callib))) { - gtk_widget_queue_draw(GTK_WIDGET(callib)); - } -} - -auto zoomcallib_new() -> GtkWidget* { return GTK_WIDGET(g_object_new(zoomcallib_get_type(), nullptr)); } - -static void zoomcallib_class_init(ZoomCallibClass* klass) { - GtkWidgetClass* widget_class = nullptr; - - widget_class = reinterpret_cast(klass); - - widget_class->realize = zoomcallib_realize; - widget_class->size_allocate = zoomcallib_size_allocate; - - widget_class->draw = zoomcallib_draw; - widget_class->get_preferred_width = zoomcallib_get_preferred_width; - widget_class->get_preferred_height = zoomcallib_get_preferred_height; -} - -static void zoomcallib_init(ZoomCallib* zc) { zc->val = 72; } - -static void zoomcallib_get_preferred_width(GtkWidget* widget, gint* minimal_width, gint* natural_width) { - *minimal_width = *natural_width = 200; -} - -static void zoomcallib_get_preferred_height(GtkWidget* widget, gint* minimal_height, gint* natural_height) { - *minimal_height = *natural_height = 75; -} - -static void zoomcallib_size_allocate(GtkWidget* widget, GtkAllocation* allocation) { - g_return_if_fail(widget != nullptr); - g_return_if_fail(IS_ZOOM_CALLIB(widget)); - g_return_if_fail(allocation != nullptr); - - gtk_widget_set_allocation(widget, allocation); - - if (gtk_widget_get_realized(widget)) { - gdk_window_move_resize(gtk_widget_get_window(widget), allocation->x, allocation->y, allocation->width, - allocation->height); - } -} - -static void zoomcallib_realize(GtkWidget* widget) { - GdkWindowAttr attributes; - GtkAllocation allocation; - - g_return_if_fail(widget != nullptr); - g_return_if_fail(IS_ZOOM_CALLIB(widget)); - - gtk_widget_set_realized(widget, true); - - attributes.window_type = GDK_WINDOW_CHILD; - - gtk_widget_get_allocation(widget, &allocation); - - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.event_mask = gtk_widget_get_events(widget) | GDK_EXPOSURE_MASK; - - gint attributes_mask = GDK_WA_X | GDK_WA_Y; - - gtk_widget_set_window(widget, gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask)); - - gdk_window_set_user_data(gtk_widget_get_window(widget), widget); -} - -static auto zoomcallib_draw(GtkWidget* widget, cairo_t* cr) -> gboolean { - if (!IS_ZOOM_CALLIB(widget)) { - g_message("zoomcallib_draw without a ZoomCallib"); - } - - cairo_text_extents_t extents; - GtkAllocation allocation; - - cairo_set_source_rgb(cr, 1, 1, 1); - cairo_paint(cr); - - gtk_widget_get_allocation(widget, &allocation); - - gdouble hafCm = (ZOOM_CALLIB(widget)->val / 2.54) / 2; - - int h = allocation.height; - int height = 50; - if (h < height) { - height = allocation.height - 10; - } - - - cairo_select_font_face(cr, "Serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); - cairo_set_font_size(cr, 13); - - auto cx = [x_base = 2, hafCm](int i) { return x_base + i * hafCm; }; - for (int i = 0; cx(i) < allocation.width; ++i) { - gdouble x = cx(i); - - int y = 0; - if (i % 2 == 0) { - cairo_set_source_rgb(cr, 0, 0, 0); - y = height - 3; - } else { - cairo_set_source_rgb(cr, 0.5, 0.5, 0.5); - y = height - 17; - } - - cairo_rectangle(cr, x, 2 + h - y, 1, y); - - cairo_fill(cr); - - if (i % 2 == 0 && i != 0 && x < allocation.width - 20) { - cairo_set_source_rgb(cr, 0, 0, 0); - - char* txt = g_strdup_printf("%i", i / 2); - cairo_text_extents(cr, txt, &extents); - - cairo_move_to(cr, x - extents.width / 2, h - y - 3); - - cairo_show_text(cr, txt); - g_free(txt); - } - } - - return true; -} diff --git a/entry/src/main/cpp/src/core/gui/widgets/ZoomCallib.h b/entry/src/main/cpp/src/core/gui/widgets/ZoomCallib.h deleted file mode 100644 index 4d5729c..0000000 --- a/entry/src/main/cpp/src/core/gui/widgets/ZoomCallib.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Xournal++ - * - * Control to callibrate the zoom to fit the display DPI - * - * @author Xournal Team - * http://xournal.sf.net - * - * @license GPL - */ -#pragma once - -#include // for G_TYPE_CHECK_INSTANCE_TYPE, G_TYPE_CHECK_IN... -#include // for gint, G_BEGIN_DECLS, G_END_DECLS -#include // for GtkWidget, GtkWidgetClass - -struct _ZoomCallib; -struct _ZoomCallibClass; - -G_BEGIN_DECLS - -#define ZOOM_CALLIB(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, zoomcallib_get_type(), ZoomCallib) -#define ZOOM_CALLIB_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, zoomcallib_get_type(), ZoomCallibClass) -#define IS_ZOOM_CALLIB(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, zoomcallib_get_type()) - -typedef struct _ZoomCallib ZoomCallib; -typedef struct _ZoomCallibClass ZoomCallibClass; - -struct _ZoomCallib { - GtkWidget widget; - - gint val; -}; - -struct _ZoomCallibClass { - GtkWidgetClass parent_class; -}; - -GType zoomcallib_get_type(void); -void zoomcallib_set_val(ZoomCallib* callib, gint val); -GtkWidget* zoomcallib_new(); - -G_END_DECLS diff --git a/entry/src/main/cpp/src/core/view/CompassView.cpp b/entry/src/main/cpp/src/core/view/CompassView.cpp deleted file mode 100644 index cb492d5..0000000 --- a/entry/src/main/cpp/src/core/view/CompassView.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "CompassView.h" - -#include // for max, min -#include // for isnan, sqrt, cos, sin, atan2 -#include -#include -#include // for move - -#include // for g_error, g_warning - -#include "model/Compass.h" // for Compass -#include "model/Stroke.h" // for Stroke -#include "util/Assert.h" // for xoj_assert -#include "util/raii/CairoWrappers.h" // for CairoSaveGuard -#include "util/safe_casts.h" // for round_cast -#include "view/Repaintable.h" // for Repaintable -#include "view/View.h" // for Context - -#include "StrokeView.h" // for StrokeView - -using namespace xoj::view; - -// all lengths are in centimeter -constexpr double FONT_SIZE = .2; -constexpr double CIRCLE_RAD = .3; -constexpr double TICK_SMALL = .1; -constexpr double TICK_LARGE = .2; -constexpr double RELATIVE_CIRCLE_POS = .8; -constexpr double RELATIVE_ANGULAR_CAPTION_POS = .3; -constexpr double OFFSET_CIRCLE_POS = .4; -constexpr const char* FONT_FAMILY = "Arial"; - -CompassView::CompassView(const Compass* compass, Repaintable* parent, ZoomControl* zoomControl): - GeometryToolView(compass, parent, zoomControl) { - this->registerToPool(compass->getViewPool()); -} - -CompassView::~CompassView() noexcept { this->unregisterFromPool(); }; - - -void CompassView::on(FlagDirtyRegionRequest, const Range& rg) { this->parent->flagDirtyRegion(rg); } - -void CompassView::on(UpdateValuesRequest, double h, double rot, cairo_matrix_t m) { - xoj_assert_message(h > 0, "Non-positive compass height"); - height = h; - rotation = rot; - matrix = m; - circlePos = height * RELATIVE_CIRCLE_POS - OFFSET_CIRCLE_POS; - angularCaptionPos = height * RELATIVE_ANGULAR_CAPTION_POS; - maxHmark = round_cast(height * 10.0); - drawRotationDisplay = height >= 2.; - drawRadialCaption = height >= 1.5; - angularOffset = (height >= 2.) ? 1 : (height >= 1.2) ? 2 : (height >= 0.8) ? 5 : 10; - angularCaptionOffset = (height >= 3.) ? 30 : (height >= 1.5) ? 45 : (height >= 1.) ? 90 : 360; -} - -void CompassView::deleteOn(CompassView::FinalizationRequest, const Range& rg) { - this->parent->drawAndDeleteToolView(this, rg); -} - -void CompassView::drawGeometryTool(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_scale(cr, CM, CM); - - cairo_set_line_width(cr, LINE_WIDTH_IN_CM); - cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); - cairo_select_font_face(cr, FONT_FAMILY, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, FONT_SIZE); - - cairo_set_source_rgb(cr, 1, 0, 0); // red - drawOutline(cr); - - cairo_set_source_rgb(cr, .0, .0, 1.); // blue - drawHorizontalMarks(cr); - - cairo_set_source_rgb(cr, .5, 0, .5); // violet - drawAngularMarks(cr); -} - -void CompassView::drawDisplays(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_transform(cr, &matrix); - cairo_set_line_width(cr, LINE_WIDTH_IN_CM); - cairo_select_font_face(cr, FONT_FAMILY, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, FONT_SIZE); - - cairo_set_source_rgb(cr, 0, .5, .5); // turquoise - drawRotation(cr); -} - -void CompassView::drawOutline(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_move_to(cr, .0, .0); - cairo_arc(cr, .0, .0, this->height, .0, 2. * M_PI); - cairo_stroke_preserve(cr); - - cairo_set_source_rgba(cr, .2, .2, .2, .1); // transparent gray - cairo_fill(cr); -} - -void CompassView::drawRotation(cairo_t* cr) const { - if (!drawRotationDisplay) { - return; - } - xoj::util::CairoSaveGuard saveGuard(cr); - // write the angle within a small circle - std::stringstream ss; - ss << std::fixed << std::setprecision(1) << std::abs(std::remainder(deg(this->rotation), 180.)); - cairo_move_to(cr, .0, -this->circlePos); - showTextCenteredAndRotated(cr, ss.str(), -deg(this->rotation)); - - cairo_move_to(cr, .0, -this->circlePos); - cairo_new_sub_path(cr); - cairo_arc(cr, .0, -this->circlePos, CIRCLE_RAD, .0, 2. * M_PI); - cairo_stroke(cr); -} - -void CompassView::drawAngularMarks(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - - for (int i = angularOffset; i < 360; i += angularOffset) { - const double cs = std::cos(rad(i)); - const double si = std::sin(rad(i)); - const double tick = (i % 5 == 0) ? TICK_LARGE : TICK_SMALL; - cairo_move_to(cr, this->height * cs, this->height * si); - if (i % angularCaptionOffset == 0) { - const double radTickEnd = (i == 270) ? (this->circlePos + 1.5 * CIRCLE_RAD) : (angularCaptionPos + 0.3); - cairo_line_to(cr, radTickEnd * cs, radTickEnd * si); - cairo_move_to(cr, angularCaptionPos * cs, angularCaptionPos * si); - showTextCenteredAndRotated(cr, std::to_string(360 - i), i + 90); - } else { - cairo_rel_line_to(cr, -tick * cs, -tick * si); - } - } - cairo_stroke(cr); -} - -void CompassView::drawHorizontalMarks(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - // BEGIN: radial measuring marks - - for (int i = 0; i <= this->maxHmark; i++) { - const double tick = (i % 5 == 0) ? TICK_LARGE : TICK_SMALL; - // draw marks - cairo_move_to(cr, static_cast(i) / 10.0, .0); - cairo_rel_line_to(cr, .0, tick); - if (i % 10 == 0 && drawRadialCaption) { - // draw numbers - cairo_rel_move_to(cr, .0, FONT_SIZE / 2.); - const auto text = std::to_string(std::abs(i / 10)); - showTextCenteredAndRotated(cr, text.c_str(), .0); - } - } - cairo_stroke(cr); - // END: radial measuring marks -} diff --git a/entry/src/main/cpp/src/core/view/CompassView.h b/entry/src/main/cpp/src/core/view/CompassView.h deleted file mode 100644 index 15c1be9..0000000 --- a/entry/src/main/cpp/src/core/view/CompassView.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Xournal++ - * - * A Compass view - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "model/Compass.h" // for Compass -#include "util/DispatchPool.h" -#include "util/safe_casts.h" // for floor_cast -#include "view/overlays/BaseStrokeToolView.h" - -#include "GeometryToolView.h" - -class Stroke; -class OverlayBase; -class ZoomControl; - -/** - * @brief A class that renders a compass - * - * The compass has vertical, horizontal and angular marks. - * The intersection angle with the x-axis is displayed as well. - * - * See the file development/documentation/Compass_Readme.md for - * details how the Compass is rendered. - * - * A temporary stroke is displayed when it is created near the - * outline of the Compass or at the marked radius (with angle 0). - */ - -namespace xoj::view { -class Repaintable; - -class CompassView: public GeometryToolView { - -public: - CompassView(const Compass* s, Repaintable* parent, ZoomControl* zoomControl); - ~CompassView() noexcept override; - - void on(FlagDirtyRegionRequest, const Range& rg) override; - void on(UpdateValuesRequest, double h, double rot, cairo_matrix_t m) override; - void deleteOn(FinalizationRequest, const Range& rg) override; - -private: - void drawGeometryTool(cairo_t* cr) const override; - void drawDisplays(cairo_t* cr) const override; - - double height = Compass::INITIAL_HEIGHT; - double rotation = 0.; - cairo_matrix_t matrix{CM, 0., 0., CM, 0., 0.}; - - /** - * @brief the distance of the circle containing the rotation angle display from the center - * of the compass - */ - double circlePos = 2.; - - /** - * @brief the distance of the angular captions (written numbers) for certain angles - */ - double angularCaptionPos = .9; - - /** - * @brief the index of the last horizontal mark to be drawn - */ - int maxHmark = floor_cast(10. * Compass::INITIAL_HEIGHT); - - /** - * @brief after how many degrees should a new small angular mark be drawn - */ - int angularOffset = 1; - - /** - * @brief after how many degrees should a new big angular mark be drawn and a number be added - */ - int angularCaptionOffset = 30; - - /** - * @brief should the numbers along the measuring marks be drawn - */ - bool drawRadialCaption = true; - - /** - * @brief should the display of the rotation be drawn - */ - bool drawRotationDisplay = true; - - void drawHorizontalMarks(cairo_t* cr) const; - void drawAngularMarks(cairo_t* cr) const; - void drawOutline(cairo_t* cr) const; - void drawRotation(cairo_t* cr) const; - -public: - static constexpr double LINE_WIDTH_IN_CM = .02; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/DebugShowRepaintBounds.h b/entry/src/main/cpp/src/core/view/DebugShowRepaintBounds.h deleted file mode 100644 index 40e40af..0000000 --- a/entry/src/main/cpp/src/core/view/DebugShowRepaintBounds.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "config-debug.h" - -#ifdef DEBUG_SHOW_REPAINT_BOUNDS -#define IF_DEBUG_REPAINT(f) f -#else -#define IF_DEBUG_REPAINT(f) -#endif diff --git a/entry/src/main/cpp/src/core/view/DocumentView.cpp b/entry/src/main/cpp/src/core/view/DocumentView.cpp deleted file mode 100644 index c6a98fb..0000000 --- a/entry/src/main/cpp/src/core/view/DocumentView.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "DocumentView.h" - -#include -#include // for __shared_ptr_access, uni... -#include // for vector - -#include // for g_message - -#include "model/Layer.h" // for Layer -#include "model/XojPage.h" // for XojPage -#include "view/DebugShowRepaintBounds.h" // for IF_DEBUG_REPAINT -#include "view/View.h" // for EditionTreatment, NORMAL... -#include "view/background/BackgroundView.h" // for BackgroundFlags, Backgro... - -#include "LayerView.h" // for LayerView - -/** - * Mark stroke with Audio - */ -void DocumentView::setMarkAudioStroke(bool markAudioStroke) { this->markAudioStroke = markAudioStroke; } - -void DocumentView::setPdfCache(PdfCache* cache) { pdfCache = cache; } - -/** - * Drawing first step - * @param page The page to draw - * @param cr Draw to this context - * @param dontRenderEditingStroke false to draw currently drawing stroke - */ -void DocumentView::initDrawing(ConstPageRef page, cairo_t* cr, bool dontRenderEditingStroke) { - this->cr = cr; - this->page = page; - this->dontRenderEditingStroke = dontRenderEditingStroke; -} - -/** - * Last step in drawing - */ -void DocumentView::finializeDrawing() { - IF_DEBUG_REPAINT({ - double minX; - double maxX; - double minY; - double maxY; - cairo_clip_extents(cr, &minX, &minY, &maxX, &maxY); - if (minX > 1 || minY > 1 || maxX < page->getWidth() - 1 || maxY < page->getHeight() - 1) { - g_message("DBG:rerender area: %6.2f < x < %6.2f ; %6.2f < y < %6.2f", minX, maxX, minY, maxY); - cairo_set_source_rgb(cr, 1, 0, 0); - cairo_set_line_width(cr, 1); - cairo_rectangle(cr, minX + 3, minY + 3, maxX - minX - 6, maxY - minY - 6); - cairo_stroke(cr); - } else { - g_message("DBG:rerender complete"); - } - }); - - this->page = nullptr; - this->cr = nullptr; -} - -/** - * Draw the background - */ -void DocumentView::drawBackground(xoj::view::BackgroundFlags bgFlags) const { - auto bgView = xoj::view::BackgroundView::createForPage(page, bgFlags, pdfCache); - bgView->draw(cr); -} - -void DocumentView::drawPage(ConstPageRef page, cairo_t* cr, bool dontRenderEditingStroke, - xoj::view::BackgroundFlags flags) { - initDrawing(page, cr, dontRenderEditingStroke); - - drawBackground(flags); - - xoj::view::Context context{cr, (xoj::view::NonAudioTreatment)this->markAudioStroke, - (xoj::view::EditionTreatment) !this->dontRenderEditingStroke, xoj::view::NORMAL_COLOR}; - for (const Layer* layer: page->getLayersView()) { - if (layer->isVisible()) { - xoj::view::LayerView layerView(layer); - layerView.draw(context); - } - } - - finializeDrawing(); -} - - -void DocumentView::drawLayersOfPage(const LayerRangeVector& layerRange, ConstPageRef page, cairo_t* cr, - bool dontRenderEditingStroke, xoj::view::BackgroundFlags flags) { - initDrawing(page, cr, dontRenderEditingStroke); - - drawBackground(flags); - - size_t layerCount = page->getLayerCount(); - std::map visibleLayers; - - for (LayerRangeEntry e: layerRange) { - auto last = e.last; - if (last >= layerCount) { - last = layerCount - 1; - } - for (size_t x = e.first; x <= last; x++) { - visibleLayers[x] = page->getLayersView()[x]; - } - } - - xoj::view::Context context{cr, (xoj::view::NonAudioTreatment)this->markAudioStroke, - (xoj::view::EditionTreatment) !this->dontRenderEditingStroke, xoj::view::NORMAL_COLOR}; - for (auto&& [_, l]: visibleLayers) { - xoj::view::LayerView layerView(l); - layerView.draw(context); - } - - finializeDrawing(); -} diff --git a/entry/src/main/cpp/src/core/view/DocumentView.h b/entry/src/main/cpp/src/core/view/DocumentView.h deleted file mode 100644 index c8df500..0000000 --- a/entry/src/main/cpp/src/core/view/DocumentView.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Xournal++ - * - * Paints a page to a cairo context - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "model/PageRef.h" // for ConstPageRef -#include "util/ElementRange.h" -#include "view/background/BackgroundFlags.h" - -class PdfCache; - -namespace xoj::view { -struct BackgroundFlags; -}; - -class DocumentView { -public: - DocumentView() = default; - virtual ~DocumentView() = default; - -public: - /** - * Draw the full page, usually you would like to call this method - * @param page The page to draw - * @param cr Draw to thgis context - * @param dontRenderEditingStroke false to draw currently drawing stroke - * @param flags show/hide various background components - */ - void drawPage(ConstPageRef page, cairo_t* cr, bool dontRenderEditingStroke, - xoj::view::BackgroundFlags flags = xoj::view::BACKGROUND_SHOW_ALL); - - /** - * Only draws the prescribed layers of the given page, regardless of the layer's current visibility. - * @param layerRange Range of layers to draw - * @param page The page to draw - * @param cr Draw to this context - * @param dontRenderEditingStroke false to draw currently drawing stroke - * @param flags show/hide various background components - */ - void drawLayersOfPage(const LayerRangeVector& layerRange, ConstPageRef page, cairo_t* cr, - bool dontRenderEditingStroke, - xoj::view::BackgroundFlags flags = xoj::view::BACKGROUND_SHOW_ALL); - - /** - * Mark stroke with Audio - */ - void setMarkAudioStroke(bool markAudioStroke); - - // API for special drawing, usually you won't call this methods -public: - void setPdfCache(PdfCache* cache); - - /** - * Drawing first step - * @param page The page to draw - * @param cr Draw to thgis context - * @param dontRenderEditingStroke false to draw currently drawing stroke - */ - void initDrawing(ConstPageRef page, cairo_t* cr, bool dontRenderEditingStroke); - - /** - * Draw the background - */ - void drawBackground(xoj::view::BackgroundFlags bgFlags) const; - - /** - * Draw background if there is no background shown, like in GIMP etc. - */ - void drawTransparentBackgroundPattern(); - - /** - * Last step in drawing - */ - void finializeDrawing(); - -private: - cairo_t* cr = nullptr; - ConstPageRef page = nullptr; - PdfCache* pdfCache = nullptr; - bool dontRenderEditingStroke = false; - bool markAudioStroke = false; - -}; diff --git a/entry/src/main/cpp/src/core/view/ElementContainerView.cpp b/entry/src/main/cpp/src/core/view/ElementContainerView.cpp deleted file mode 100644 index a9b8256..0000000 --- a/entry/src/main/cpp/src/core/view/ElementContainerView.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "ElementContainerView.h" - -#include // for unique_ptr - -#include "model/ElementContainer.h" // for ElementContainer - -#include "View.h" // for ElementView - -class Element; - -using namespace xoj::view; - -ElementContainerView::ElementContainerView(const ElementContainer* container): container(container) {} - -void ElementContainerView::draw(const Context& ctx) const { - container->forEachElement([&ctx](const Element* e) { - auto elementView = ElementView::createFromElement(e); - elementView->draw(ctx); - }); -} diff --git a/entry/src/main/cpp/src/core/view/ElementContainerView.h b/entry/src/main/cpp/src/core/view/ElementContainerView.h deleted file mode 100644 index 6649924..0000000 --- a/entry/src/main/cpp/src/core/view/ElementContainerView.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Xournal++ - * - * Displays the content of a selection - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -class ElementContainer; - -namespace xoj::view { -class Context; - -class ElementContainerView { -public: - ElementContainerView(const ElementContainer* container); - - /** - * @brief Draws the container to the given context - */ - void draw(const Context& ctx) const; - -private: - const ElementContainer* container; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/ElementView.cpp b/entry/src/main/cpp/src/core/view/ElementView.cpp deleted file mode 100644 index 4dfeef1..0000000 --- a/entry/src/main/cpp/src/core/view/ElementView.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include // for make_unique, unique_ptr - -#include "model/Element.h" // for Element, ELEMENT_IMAGE, ELEMENT_STROKE -#include "model/Image.h" // for Image -#include "model/Stroke.h" // for Stroke -#include "model/TexImage.h" // for TexImage -#include "model/Text.h" // for Text -#include "util/Assert.h" // for xoj_assert - -#include "ImageView.h" // for ImageView -#include "StrokeView.h" // for StrokeView -#include "TexImageView.h" // for TexImageView -#include "TextView.h" // for TextView -#include "View.h" // for ElementView, view - -using namespace xoj::view; - -auto ElementView::createFromElement(const Element* e) -> std::unique_ptr { - switch (e->getType()) { - case ELEMENT_STROKE: - return std::make_unique(dynamic_cast(e)); - case ELEMENT_TEXT: - return std::make_unique(dynamic_cast(e)); - case ELEMENT_IMAGE: - return std::make_unique(dynamic_cast(e)); - case ELEMENT_TEXIMAGE: - return std::make_unique(dynamic_cast(e)); - default: - xoj_assert_message(false, "ElementView::getFromElement: Unknown element type!"); - return nullptr; - } -} diff --git a/entry/src/main/cpp/src/core/view/ErasableStrokeView.cpp b/entry/src/main/cpp/src/core/view/ErasableStrokeView.cpp deleted file mode 100644 index bc5601d..0000000 --- a/entry/src/main/cpp/src/core/view/ErasableStrokeView.cpp +++ /dev/null @@ -1,309 +0,0 @@ -#include "ErasableStrokeView.h" - -#include // for ceil -#include // for ptrdiff_t -#include // for next -#include // for allocator_traits<>::value_type -#include // for vector - -#include "model/LineStyle.h" // for LineStyle -#include "model/PathParameter.h" // for PathParameter -#include "model/Point.h" // for Point -#include "model/Stroke.h" // for Stroke, StrokeTool::HIGHLIG... -#include "model/eraser/ErasableStroke.h" // for ErasableStroke, ErasableStr... -#include "util/Assert.h" // for xoj_assert -#include "util/Color.h" // for cairo_set_source_rgbi -#include "util/Interval.h" // for Interval -#include "util/Rectangle.h" // for Rectangle -#include "util/Util.h" // for cairo_set_dash_from_vector - -#include "Mask.h" // for Mask -#include "StrokeView.h" // for StrokeView, StrokeView::CAI... -#include "config-debug.h" // for DEBUG_ERASABLE_STROKE_BOXES - -using xoj::util::Rectangle; -using namespace xoj::view; - -ErasableStrokeView::ErasableStrokeView(const ErasableStroke& erasableStroke): erasableStroke(erasableStroke) {} - -void ErasableStrokeView::draw(cairo_t* cr) const { - std::vector sections = erasableStroke.getRemainingSubSectionsVector(); - - if (sections.empty()) { - return; - } - - const Stroke& stroke = this->erasableStroke.stroke; - - const auto& dashes = stroke.getLineStyle().getDashes(); - - const std::vector& data = stroke.getPointVector(); - - xoj::util::CairoSaveGuard guard(cr); - - if (stroke.hasPressure()) { - double dashOffset = 0; - for (const auto& interval: sections) { - Point p = stroke.getPoint(interval.min); - cairo_set_line_width(cr, p.z); - cairo_move_to(cr, p.x, p.y); - - const Point* lastPoint = &p; - - auto endIt = std::next(data.cbegin(), (std::ptrdiff_t)interval.max.index + 1); - for (auto it = std::next(data.cbegin(), (std::ptrdiff_t)interval.min.index + 1); it != endIt; ++it) { - if (!dashes.empty()) { - Util::cairo_set_dash_from_vector(cr, dashes, dashOffset); - dashOffset += lastPoint->lineLengthTo(*it); - lastPoint = &(*it); - } - cairo_line_to(cr, it->x, it->y); - cairo_stroke(cr); - cairo_set_line_width(cr, it->z); - cairo_move_to(cr, it->x, it->y); - } - - if (!dashes.empty()) { - Util::cairo_set_dash_from_vector(cr, dashes, dashOffset); - } - - Point q = stroke.getPoint(interval.max); - cairo_line_to(cr, q.x, q.y); - cairo_stroke(cr); - } - } else { - cairo_set_line_width(cr, stroke.getWidth()); - Util::cairo_set_dash_from_vector(cr, dashes, 0); - - bool mergeFirstAndLast = this->erasableStroke.isClosedStroke() && - stroke.getToolType() == StrokeTool::HIGHLIGHTER && sections.size() >= 2 && - sections.front().min == PathParameter(0, 0.0) && - sections.back().max == PathParameter(data.size() - 2, 1.0); - - auto sectionIt = sections.cbegin(); - auto sectionEndIt = sections.cend(); - - if (mergeFirstAndLast) { - /** - * Draw the first and last section as one - */ - const ErasableStroke::SubSection& first = sections.front(); - const ErasableStroke::SubSection& last = sections.back(); - Point p = stroke.getPoint(last.min); - cairo_move_to(cr, p.x, p.y); - - auto endIt = data.cend(); - for (auto it = std::next(data.cbegin(), (std::ptrdiff_t)last.min.index + 1); it != endIt; ++it) { - cairo_line_to(cr, it->x, it->y); - } - endIt = std::next(data.cbegin(), (std::ptrdiff_t)first.max.index + 1); - for (auto it = data.cbegin(); it != endIt; ++it) { cairo_line_to(cr, it->x, it->y); } - - Point q = stroke.getPoint(first.max); - cairo_line_to(cr, q.x, q.y); - cairo_stroke(cr); - - // Avoid drawing those sections again - ++sectionIt; - --sectionEndIt; - } - - for (; sectionIt != sectionEndIt; ++sectionIt) { - Point p = stroke.getPoint(sectionIt->min); - cairo_move_to(cr, p.x, p.y); - - auto endIt = std::next(data.cbegin(), (std::ptrdiff_t)sectionIt->max.index + 1); - for (auto it = std::next(data.cbegin(), (std::ptrdiff_t)sectionIt->min.index + 1); it != endIt; ++it) { - cairo_line_to(cr, it->x, it->y); - } - - Point q = stroke.getPoint(sectionIt->max); - cairo_line_to(cr, q.x, q.y); - cairo_stroke(cr); - } - } - -#ifdef DEBUG_ERASABLE_STROKE_BOXES - if (!this->erasableStroke.debugMask.isInitialized()) { - cairo_matrix_t matrix; - cairo_get_matrix(cr, &matrix); - - Range extents(0, 0, stroke.getElementWidth(), stroke.getElementHeight()); - extents.addPadding(5 * stroke.getWidth()); - erasableStroke.debugMask = Mask(cairo_get_target(cr), extents, matrix.xx, CAIRO_CONTENT_COLOR_ALPHA); - cairo_set_line_width(this->erasableStroke.debugMask.get(), 2); - } else { - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - this->erasableStroke.debugMask.paintTo(cr); - } -#endif -} - -void ErasableStrokeView::drawFilling(cairo_t* cr) const { - std::vector sections = erasableStroke.getRemainingSubSectionsVector(); - - if (sections.empty()) { - return; - } - - const Stroke& stroke = this->erasableStroke.stroke; - const std::vector& data = stroke.getPointVector(); - - bool mergeFirstAndLast = this->erasableStroke.isClosedStroke() && sections.size() >= 2 && - sections.front().min == PathParameter(0, 0.0) && - sections.back().max == PathParameter(data.size() - 2, 1.0); - - auto sectionIt = sections.cbegin(); - auto sectionEndIt = sections.cend(); - - if (mergeFirstAndLast) { - /** - * Draw the first and last sections as one - */ - const ErasableStroke::SubSection& first = sections.front(); - const ErasableStroke::SubSection& last = sections.back(); - Point p = stroke.getPoint(last.min); - cairo_move_to(cr, p.x, p.y); - - auto endIt = data.cend(); - for (auto it = std::next(data.cbegin(), (std::ptrdiff_t)last.min.index + 1); it != endIt; ++it) { - cairo_line_to(cr, it->x, it->y); - } - endIt = std::next(data.cbegin(), (std::ptrdiff_t)first.max.index + 1); - for (auto it = data.cbegin(); it != endIt; ++it) { cairo_line_to(cr, it->x, it->y); } - - Point q = stroke.getPoint(first.max); - cairo_line_to(cr, q.x, q.y); - cairo_fill(cr); - - // Avoid drawing those sections again - ++sectionIt; - --sectionEndIt; - } - - for (; sectionIt != sectionEndIt; ++sectionIt) { - Point p = stroke.getPoint(sectionIt->min); - cairo_move_to(cr, p.x, p.y); - - auto endIt = std::next(data.cbegin(), (std::ptrdiff_t)sectionIt->max.index + 1); - for (auto it = std::next(data.cbegin(), (std::ptrdiff_t)sectionIt->min.index + 1); it != endIt; ++it) { - cairo_line_to(cr, it->x, it->y); - } - - Point q = stroke.getPoint(sectionIt->max); - cairo_line_to(cr, q.x, q.y); - cairo_fill(cr); - } -} - -void ErasableStrokeView::paintFilledHighlighter(cairo_t* cr) const { - const Stroke& stroke = erasableStroke.stroke; - std::vector sections = erasableStroke.getRemainingSubSectionsVector(); - - if (sections.empty()) { - return; - } - - xoj::util::CairoSaveGuard guard(cr); - - const auto linecap = StrokeView::CAIRO_LINE_CAP[stroke.getStrokeCapStyle()]; - - /** - * We create a mask for each subsection, paint on it and blit them all. - * We need to rescale the mask according to the scaling of the target cairo context. - * We find out this scaling by looking at the transformation matrix - */ - cairo_matrix_t matrix; - cairo_get_matrix(cr, &matrix); - // We assume the matrix is an homothety - xoj_assert(matrix.xx == matrix.yy && matrix.xy == 0 && matrix.yx == 0); - - // Initialise the cairo context - cairo_set_operator(cr, CAIRO_OPERATOR_MULTIPLY); - Util::cairo_set_source_rgbi(cr, stroke.getColor(), static_cast(stroke.getFill()) / 255.0); - - const std::vector& data = stroke.getPointVector(); - - bool mergeFirstAndLast = erasableStroke.isClosedStroke() && sections.size() >= 2 && - sections.front().min == PathParameter(0, 0.0) && - sections.back().max == PathParameter(data.size() - 2, 1.0); - - auto sectionIt = sections.cbegin(); - auto sectionEndIt = sections.cend(); - - if (mergeFirstAndLast) { - /** - * Draw the first and last sections as one - */ - const ErasableStroke::SubSection& first = sections.front(); - const ErasableStroke::SubSection& last = sections.back(); - - /** - * Create a mask tailored to the union of the sections' bounding boxes - */ - Range box = erasableStroke.getSubSectionBoundingBox(first).unite(erasableStroke.getSubSectionBoundingBox(last)); - - Mask mask = createMask(cr, box, matrix.xx); - cairo_t* crMask = mask.get(); - cairo_set_line_cap(crMask, linecap); - - // Paint to the mask - Point p = stroke.getPoint(last.min); - cairo_move_to(crMask, p.x, p.y); - - auto endIt = data.cend(); - for (auto it = std::next(data.cbegin(), (std::ptrdiff_t)last.min.index + 1); it != endIt; ++it) { - cairo_line_to(crMask, it->x, it->y); - } - endIt = std::next(data.cbegin(), (std::ptrdiff_t)first.max.index + 1); - for (auto it = data.cbegin(); it != endIt; ++it) { cairo_line_to(crMask, it->x, it->y); } - - Point q = stroke.getPoint(first.max); - cairo_line_to(crMask, q.x, q.y); - - cairo_fill_preserve(crMask); - cairo_stroke(crMask); - - mask.blitTo(cr); - - // Avoid drawing those sections again - ++sectionIt; - --sectionEndIt; - } - - for (; sectionIt != sectionEndIt; ++sectionIt) { - // Create a mask - Mask mask = createMask(cr, erasableStroke.getSubSectionBoundingBox(*sectionIt), matrix.xx); - cairo_t* crMask = mask.get(); - cairo_set_line_cap(crMask, linecap); - - // Paint to the mask - Point p = stroke.getPoint(sectionIt->min); - cairo_move_to(crMask, p.x, p.y); - - auto endIt = std::next(data.cbegin(), (std::ptrdiff_t)sectionIt->max.index + 1); - for (auto it = std::next(data.cbegin(), (std::ptrdiff_t)sectionIt->min.index + 1); it != endIt; ++it) { - cairo_line_to(crMask, it->x, it->y); - } - - Point q = stroke.getPoint(sectionIt->max); - cairo_line_to(crMask, q.x, q.y); - - cairo_fill_preserve(crMask); - cairo_stroke(crMask); - - mask.blitTo(cr); - } -} - -auto ErasableStrokeView::createMask(cairo_t* target, const Range& box, double zoom) const -> Mask { - Mask mask(cairo_get_target(target), box, zoom); - - cairo_t* crMask = mask.get(); - cairo_set_line_join(crMask, CAIRO_LINE_JOIN_ROUND); - cairo_set_source_rgba(crMask, 1, 1, 1, 1); - cairo_set_operator(crMask, CAIRO_OPERATOR_SOURCE); - cairo_set_line_width(crMask, this->erasableStroke.stroke.getWidth()); - - return mask; -} diff --git a/entry/src/main/cpp/src/core/view/ErasableStrokeView.h b/entry/src/main/cpp/src/core/view/ErasableStrokeView.h deleted file mode 100644 index c7dea37..0000000 --- a/entry/src/main/cpp/src/core/view/ErasableStrokeView.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Xournal++ - * - * Draw stroke - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for pair - -#include // for cairo_t - -class ErasableStroke; -class Range; - -namespace xoj { -namespace view { -class Mask; - -class ErasableStrokeView { -public: - ErasableStrokeView(const ErasableStroke& erasableStroke); - ~ErasableStrokeView() = default; - - /** - * @brief Draw the erasable stroke assuming the cairo context is all set - * @param cr The cairo context to draw to - */ - void draw(cairo_t* cr) const; - - /** - * @brief Draw the filling of the erasable stroke assuming the cairo context is all set - * @param cr The cairo context - */ - void drawFilling(cairo_t* cr) const; - - /** - * @brief Paint the erasable stroke, after setting up the cairo context, assuming the stroke is filled and made with - * the highlighter tool - * @param cr The cairo context - */ - void paintFilledHighlighter(cairo_t* cr) const; - -private: - /** - * @brief Create a cairo mask for a given rectangle and sets up a context for drawing on it - * @param target A cairo context on which the mask would be used - * @param box The range delimiting the mask - * @param zoom A zoom ratio to apply to the mask - */ - xoj::view::Mask createMask(cairo_t* target, const Range& box, double zoom) const; - -private: - const ErasableStroke& erasableStroke; -}; -}; // namespace view -}; // namespace xoj diff --git a/entry/src/main/cpp/src/core/view/GeometryToolView.cpp b/entry/src/main/cpp/src/core/view/GeometryToolView.cpp deleted file mode 100644 index 0e5f2a4..0000000 --- a/entry/src/main/cpp/src/core/view/GeometryToolView.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "GeometryToolView.h" - -#include "control/zoom/ZoomControl.h" -#include "model/GeometryTool.h" // for GeometryTool -#include "model/Stroke.h" // for Stroke -#include "util/raii/CairoWrappers.h" // for CairoSaveGuard -#include "view/Repaintable.h" // for Repaintable -#include "view/View.h" // for Context - -#include "StrokeView.h" // for StrokeView - -using namespace xoj::view; - -GeometryToolView::GeometryToolView(const GeometryTool* geometryTool, Repaintable* parent, ZoomControl* zoomControl): - ToolView(parent), geometryTool(geometryTool), zoomControl(zoomControl) { - zoomControl->addZoomListener(this); -} - -GeometryToolView::~GeometryToolView() { zoomControl->removeZoomListener(this); } - -void GeometryToolView::draw(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_save(cr); - - if (!mask.isInitialized()) { - // Initialize the mask on first call, when the geometry tool changes size and when zooming - mask = createMask(cr); - this->drawGeometryTool(mask.get()); - } - cairo_translate(cr, geometryTool->getOrigin().x, geometryTool->getOrigin().y); - cairo_rotate(cr, geometryTool->getRotation()); - mask.paintTo(cr); - cairo_restore(cr); - this->drawDisplays(cr); - this->drawTemporaryStroke(cr); -} - -bool GeometryToolView::isViewOf(const OverlayBase* overlay) const { return overlay == this->geometryTool; } - -void GeometryToolView::drawTemporaryStroke(cairo_t* cr) const { - if (geometryTool->getStroke()) { - auto context = xoj::view::Context::createDefault(cr); - xoj::view::StrokeView strokeView(geometryTool->getStroke()); - strokeView.draw(context); - } -} - -auto GeometryToolView::createMask(cairo_t* targetCr) const -> Mask { - const double zoom = this->parent->getZoom(); - Range rg = geometryTool->getToolRange(false); - return Mask(cairo_get_target(targetCr), rg, zoom, CAIRO_CONTENT_COLOR_ALPHA); -} - -void GeometryToolView::on(ResetMaskRequest) { mask.reset(); } - -void GeometryToolView::showTextCenteredAndRotated(cairo_t* cr, const std::string& text, double angle) const { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_text_extents_t te; - cairo_text_extents(cr, text.c_str(), &te); - const double dx = te.x_bearing + te.width / 2.0; - const double dy = te.y_bearing + te.height / 2.0; - - cairo_rotate(cr, rad(angle)); - cairo_rel_move_to(cr, -dx, -dy); - cairo_text_path(cr, text.c_str()); -} - -void GeometryToolView::zoomChanged() { - // If zooming in, the mask needs redrawing. Otherwise it gets blurry. - mask.reset(); -} diff --git a/entry/src/main/cpp/src/core/view/GeometryToolView.h b/entry/src/main/cpp/src/core/view/GeometryToolView.h deleted file mode 100644 index 629dc8e..0000000 --- a/entry/src/main/cpp/src/core/view/GeometryToolView.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Xournal++ - * - * A GeometryTool view - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for cairo_t - -#include "control/zoom/ZoomListener.h" -#include "model/GeometryTool.h" // for GeometryTool -#include "view/overlays/BaseStrokeToolView.h" - -#include "Mask.h" - -class Stroke; -class OverlayBase; -class ZoomControl; - -/** - * @brief A class that renders a geometry tool - */ - -namespace xoj::view { -class Repaintable; - -constexpr double rad(double n) { return n * M_PI / 180.; } -constexpr double rad(int n) { return rad(static_cast(n)); } -constexpr double deg(double a) { return a * 180.0 / M_PI; } -inline double cathete(double h, double o) { return std::sqrt(std::pow(h, 2) - std::pow(o, 2)); } - -class GeometryToolView: public ToolView, public ZoomListener, public xoj::util::Listener { - -public: - GeometryToolView(const GeometryTool* geometryTool, Repaintable* parent, ZoomControl* zoomControl); - virtual ~GeometryToolView(); - - /** - * Zoom interface - */ - void zoomChanged() override; - - /** - * Listener interface - */ - static constexpr struct FlagDirtyRegionRequest { - } FLAG_DIRTY_REGION = {}; - virtual void on(FlagDirtyRegionRequest, const Range& rg) = 0; - - static constexpr struct UpdateValuesRequest { - } UPDATE_VALUES = {}; - virtual void on(UpdateValuesRequest, double h, double rot, cairo_matrix_t m) = 0; - - static constexpr struct FinalizationRequest { - } FINALIZATION_REQUEST = {}; - /** - * @brief Called before the corresponding GeometryTool's destruction - * @param rg The bounding box of the entire geometry tool - */ - virtual void deleteOn(FinalizationRequest, const Range& rg) = 0; - - static constexpr struct ResetMaskRequest { - } RESET_MASK = {}; - void on(ResetMaskRequest); - - /** - * @brief draws the geometry tool and temporary stroke to a cairo context - * @param cr the cairo context - */ - void draw(cairo_t* cr) const override; - - bool isViewOf(const OverlayBase* overlay) const override; - -private: - /** - * @brief draws the GeometryTool to a cairo context - * @param cr the cairo context drawn to - */ - virtual void drawGeometryTool(cairo_t* cr) const = 0; - - /** - * @brief draws displays (that may change with rotation and/or translation) - * of the geometry tool - * - * @param cr the cairo context drawn to - */ - virtual void drawDisplays(cairo_t* cr) const = 0; - - /** - * @brief draws the temporary stroke to a cairo context - * @param cr the cairo context drawn to - */ - void drawTemporaryStroke(cairo_t* cr) const; - - /** - * @brief Creates a mask for caching the drawing of the geometry tool (without stroke) - */ - Mask createMask(cairo_t* targetCr) const; - -protected: - /** - * @brief the underlying GeometryTool - */ - const GeometryTool* geometryTool; - - /** - * @brief The stroke drawn aligned to the longest side of the GeometryTool or ending at the midpoint of the longest - * side of the GeometryTool - */ - Stroke* stroke = nullptr; - - /** - * @brief renders text centered and possibly rotated at the current position on a cairo context - * @param cr the cairo context - * @param text the text string - * @param angle the rotation angle - */ - void showTextCenteredAndRotated(cairo_t* cr, const std::string& text, double angle) const; - -private: - mutable Mask mask; - ZoomControl* zoomControl; -}; -}; // namespace xoj::view \ No newline at end of file diff --git a/entry/src/main/cpp/src/core/view/ImageView.cpp b/entry/src/main/cpp/src/core/view/ImageView.cpp deleted file mode 100644 index d9308a9..0000000 --- a/entry/src/main/cpp/src/core/view/ImageView.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "ImageView.h" - -#include // for cairo_image_surface_get_height, cairo_image... - -#include "model/Image.h" // for Image -#include "view/View.h" // for Context, OPACITY_NO_AUDIO, view - -using namespace xoj::view; - -ImageView::ImageView(const Image* image): image(image) {} - -ImageView::~ImageView() = default; - -void ImageView::draw(const Context& ctx) const { - cairo_t* cr = ctx.cr; - - cairo_save(cr); - - cairo_surface_t* img = image->getImage(); - int width = cairo_image_surface_get_width(img); - int height = cairo_image_surface_get_height(img); - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - double xFactor = image->getElementWidth() / width; - double yFactor = image->getElementHeight() / height; - - cairo_scale(cr, xFactor, yFactor); - - cairo_set_source_surface(cr, img, image->getX() / xFactor, image->getY() / yFactor); - // make images translucent when highlighting elements with audio, as they can not have audio - if (ctx.fadeOutNonAudio) { - cairo_paint_with_alpha(cr, OPACITY_NO_AUDIO); - } else { - cairo_paint(cr); - } - - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/ImageView.h b/entry/src/main/cpp/src/core/view/ImageView.h deleted file mode 100644 index 7fa5215..0000000 --- a/entry/src/main/cpp/src/core/view/ImageView.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Xournal++ - * - * Displays a Image Element - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "View.h" - -class Image; - -class xoj::view::ImageView: public xoj::view::ElementView { -public: - ImageView(const Image* image); - virtual ~ImageView(); - - /** - * Draws an Image element - */ - void draw(const Context& ctx) const override; - -private: - const Image* image; -}; diff --git a/entry/src/main/cpp/src/core/view/LayerView.cpp b/entry/src/main/cpp/src/core/view/LayerView.cpp deleted file mode 100644 index c4d7197..0000000 --- a/entry/src/main/cpp/src/core/view/LayerView.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "LayerView.h" - -#include // for unique_ptr - -#include // for cairo_clip_extents, cairo_rectangle -#include // for g_message - -#include "model/Element.h" // for Element -#include "model/Layer.h" // for Layer - -#include "DebugShowRepaintBounds.h" // for IF_DEBUG_REPAINT -#include "View.h" // for Context, ElementView - -using namespace xoj::view; - -LayerView::LayerView(const Layer* layer): layer(layer) {} - -const Layer* LayerView::getLayer() const { return layer; } - -void LayerView::draw(const Context& ctx) const { - IF_DEBUG_REPAINT(int drawn = 0; int notDrawn = 0;); - - // Get the bounds of the mask, in page coordinates - double minX; - double maxX; - double minY; - double maxY; - cairo_clip_extents(ctx.cr, &minX, &minY, &maxX, &maxY); - - for (auto const& e: layer->getElementsView()) { - - IF_DEBUG_REPAINT({ - auto cr = ctx.cr; - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgb(cr, 0, 1, 0); - cairo_set_line_width(cr, 1); - cairo_rectangle(cr, e->getX(), e->getY(), e->getElementWidth(), e->getElementHeight()); - cairo_stroke(cr); - }); - - if (e->intersectsArea(minX, minY, maxX - minX, maxY - minY)) { - ElementView::createFromElement(e)->draw(ctx); - IF_DEBUG_REPAINT(drawn++;); - } - IF_DEBUG_REPAINT(else { notDrawn++; }); - } - IF_DEBUG_REPAINT(g_message("DBG:LayerView::draw: draw %i / not draw %i", drawn, notDrawn);); -} diff --git a/entry/src/main/cpp/src/core/view/LayerView.h b/entry/src/main/cpp/src/core/view/LayerView.h deleted file mode 100644 index e442e47..0000000 --- a/entry/src/main/cpp/src/core/view/LayerView.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Xournal++ - * - * Displays a Layer - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -class Layer; -namespace xoj::view { -class Context; - -class LayerView { -public: - LayerView(const Layer* layer); - - /** - * @brief Draws the entire Layer - */ - void draw(const Context& ctx) const; - - const Layer* getLayer() const; - -private: - const Layer* layer; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/Mask.cpp b/entry/src/main/cpp/src/core/view/Mask.cpp deleted file mode 100644 index 682812d..0000000 --- a/entry/src/main/cpp/src/core/view/Mask.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "Mask.h" - -#include - -#include - -#include "util/Assert.h" -#include "util/Range.h" -#include "util/safe_casts.h" // for ceil_cast, floor_cast - -#include "config-debug.h" - -using namespace xoj::view; - -#ifdef DEBUG_MASKS -#include -namespace { // cairo helper functions, for handling various surface types -std::string getSurfaceTypeName(cairo_surface_t*); -}; -#define IF_DBG_MASKS(f) f -#else -#define IF_DBG_MASKS(f) -#endif - -Mask::Mask(cairo_surface_t* target, const Range& extent, double zoom, cairo_content_t contentType): - xOffset(floor_cast(extent.minX * zoom)), yOffset(floor_cast(extent.minY * zoom)), zoom(zoom) { - constructorImpl(target, extent, zoom, contentType); -} - -Mask::Mask(int DPIScaling, const Range& extent, double zoom, cairo_content_t contentType): - xOffset(floor_cast(extent.minX * zoom)), yOffset(floor_cast(extent.minY * zoom)), zoom(zoom) { - constructorImpl(DPIScaling, extent, zoom, contentType); -} - -template -class SurfaceCreator {}; -template <> -class SurfaceCreator { -public: - static constexpr auto create = [](cairo_surface_t* other, cairo_content_t content, int width, - int height) -> cairo_surface_t* { - return cairo_surface_create_similar(other, content, width, height); - }; -}; -template <> -class SurfaceCreator { -public: - static cairo_surface_t* create(int DPIScaling, cairo_content_t contentType, int width, int height) { - cairo_surface_t* surf = - cairo_image_surface_create(contentType == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32, - width * DPIScaling, height * DPIScaling); - cairo_surface_set_device_scale(surf, DPIScaling, DPIScaling); - return surf; - } -}; - -template -void Mask::constructorImpl(DPIInfoType dpiInfo, const Range& extent, double zoom, cairo_content_t contentType) { - xoj_assert(dpiInfo); - xoj_assert_message(extent.isValid(), std::string("Invalid range in Mask(): X ") + std::to_string(extent.minX) + - " -- " + std::to_string(extent.maxX) + - "\n Y " + std::to_string(extent.minY) + - " -- " + std::to_string(extent.maxY)); - xoj_assert(zoom > 0.0); - - const int width = ceil_cast(extent.maxX * zoom) - xOffset; - const int height = ceil_cast(extent.maxY * zoom) - yOffset; - - /* - * Create the most suitable kind of surface. - * - * Note that width and height are in device space coordinates (i.e. before DPI scaling). - * If `dpiInfo` asks for a device scaling, then the number of pixels in the resulting surface will be multiplied - * accordingly, and the scaling is applied to the new surface. - */ - cairo_surface_t* surf = SurfaceCreator::create(dpiInfo, contentType, width, height); - - IF_DBG_MASKS({ - std::cout << "Creating mask of type: " << getSurfaceTypeName(surf) << std::endl; - std::cout << " Its size: " << width << " x " << height << " (in device space)" << std::endl; - double x; - double y; - cairo_surface_get_device_scale(surf, &x, &y); - std::cout << " Its DPI scaling: " << x << " x " << y << std::endl; - }); - - this->cr.reset(cairo_create(surf), xoj::util::adopt); - cairo_surface_destroy(surf); // surf is now owned by this->cr - - cairo_translate(this->cr.get(), -xOffset, -yOffset); - cairo_scale(this->cr.get(), zoom, zoom); - - IF_DBG_MASKS({ - xoj::util::CairoSaveGuard saveGuard(cr.get()); - cairo_set_operator(cr.get(), CAIRO_OPERATOR_OVER); - cairo_set_source_rgba(cr.get(), 1.0, 0.0, 0.0, 0.3); - cairo_paint(cr.get()); - }); -} - -auto Mask::get() -> cairo_t* { return cr.get(); } - -bool Mask::isInitialized() const { return cr; } - -void Mask::blitTo(cairo_t* targetCr) const { - xoj_assert(isInitialized()); - xoj::util::CairoSaveGuard guard(targetCr); - cairo_scale(targetCr, 1. / zoom, 1. / zoom); - cairo_mask_surface(targetCr, cairo_get_target(const_cast(cr.get())), xOffset, yOffset); -} - -void Mask::paintTo(cairo_t* targetCr) const { - xoj_assert(isInitialized()); - xoj::util::CairoSaveGuard guard(targetCr); - cairo_scale(targetCr, 1. / zoom, 1. / zoom); - cairo_set_source_surface(targetCr, cairo_get_target(const_cast(cr.get())), xOffset, yOffset); - cairo_paint(targetCr); -} - -void Mask::paintToWithAlpha(cairo_t* targetCr, uint8_t alpha) const { - xoj_assert(isInitialized()); - xoj::util::CairoSaveGuard guard(targetCr); - cairo_scale(targetCr, 1. / zoom, 1. / zoom); - cairo_set_source_surface(targetCr, cairo_get_target(const_cast(cr.get())), xOffset, yOffset); - cairo_paint_with_alpha(targetCr, alpha / 255.0); -} - -void Mask::wipe() { - xoj_assert(isInitialized()); - xoj::util::CairoSaveGuard saveGuard(cr.get()); - cairo_set_operator(cr.get(), CAIRO_OPERATOR_CLEAR); - cairo_paint(cr.get()); - IF_DBG_MASKS({ - cairo_set_operator(cr.get(), CAIRO_OPERATOR_OVER); - cairo_set_source_rgba(cr.get(), 1.0, 0.0, 0.0, 0.3); - cairo_paint(cr.get()); - }); -} - -void Mask::wipeRange(const Range& rg) { - xoj_assert(isInitialized()); - xoj::util::CairoSaveGuard saveGuard(cr.get()); - cairo_rectangle(cr.get(), rg.minX, rg.minY, rg.getWidth(), rg.getHeight()); - cairo_clip(cr.get()); - wipe(); -} - -void Mask::reset() { cr.reset(); } - -#ifdef DEBUG_MASKS -namespace { -auto getSurfaceTypeName(cairo_surface_t* surf) -> std::string { - auto surftype = cairo_surface_get_type(surf); - switch (surftype) { - // Strings from https://cairographics.org/manual/cairo-cairo-surface-t.html#cairo-surface-type-t - case CAIRO_SURFACE_TYPE_IMAGE: - return "image"; - case CAIRO_SURFACE_TYPE_PDF: - return "pdf"; - case CAIRO_SURFACE_TYPE_PS: - return "ps"; - case CAIRO_SURFACE_TYPE_XLIB: - return "xlib"; - case CAIRO_SURFACE_TYPE_XCB: - return "xcb"; - case CAIRO_SURFACE_TYPE_GLITZ: - return "glitz"; - case CAIRO_SURFACE_TYPE_QUARTZ: - return "quartz"; - case CAIRO_SURFACE_TYPE_WIN32: - return "win32"; - case CAIRO_SURFACE_TYPE_BEOS: - return "beos"; - case CAIRO_SURFACE_TYPE_DIRECTFB: - return "directfb"; - case CAIRO_SURFACE_TYPE_SVG: - return "svg"; - case CAIRO_SURFACE_TYPE_OS2: - return "os2"; - case CAIRO_SURFACE_TYPE_WIN32_PRINTING: - return "win32 printing surface"; - case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: - return "quartz_image"; - case CAIRO_SURFACE_TYPE_SCRIPT: - return "script"; - case CAIRO_SURFACE_TYPE_QT: - return "Qt"; - case CAIRO_SURFACE_TYPE_RECORDING: - return "recording"; - case CAIRO_SURFACE_TYPE_VG: - return "OpenVG surface"; - case CAIRO_SURFACE_TYPE_GL: - return "OpenGL"; - case CAIRO_SURFACE_TYPE_DRM: - return "Direct Render Manager"; - case CAIRO_SURFACE_TYPE_TEE: - return "'tee' (a multiplexing surface)"; - case CAIRO_SURFACE_TYPE_XML: - return "XML (for debugging)"; - case CAIRO_SURFACE_TYPE_SKIA: - return "CAIRO_SURFACE_TYPE_SKIA"; - case CAIRO_SURFACE_TYPE_SUBSURFACE: - return "subsurface created with cairo_surface_create_for_rectangle()"; - case CAIRO_SURFACE_TYPE_COGL: - return "Cogl"; - default: - return "Unknown surface type"; - } -} -}; // namespace -#endif diff --git a/entry/src/main/cpp/src/core/view/Mask.h b/entry/src/main/cpp/src/core/view/Mask.h deleted file mode 100644 index a6a7448..0000000 --- a/entry/src/main/cpp/src/core/view/Mask.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Xournal++ - * - * Virtual class for showing overlays (e.g. active tools, selections and so on) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include -#include - -#include "util/raii/CairoWrappers.h" - -class Range; - -namespace xoj::view { - -/** - * @brief Mask class: a cairo surface and its context to draw on, with the later purpose of blitting or using as a - * buffer. - */ -class Mask { -public: - Mask() = default; - /** - * @brief Create a mask tailored for the specified target - * @param target A cairo surface similar to that on which the mask will be used - * @param extent The extent of the mask, in local coordinates (i.e. in the coordinates of the cairo context(s) on - * which the mask will be used). - * @param zoom The local zoom ratio (zoom ratio of the cairo context(s) on which the mask will be used). - * @param contentType The intended content of the mask - */ - Mask(cairo_surface_t* target, const Range& extent, double zoom, cairo_content_t contentType = CAIRO_CONTENT_ALPHA); - - /** - * @brief Create a mask tailored for the specified target - * @param DPIScaling The DPI scaling of the targeted use monitor - * @param extent The extent of the mask, in local coordinates (i.e. in the coordinates of the cairo context(s) on - * which the mask will be used). - * @param zoom The local zoom ratio (zoom ratio of the cairo context(s) on which the mask will be used). - * @param contentType The intended content of the mask - */ - Mask(int DPIScaling, const Range& extent, double zoom, cairo_content_t contentType = CAIRO_CONTENT_ALPHA); - - cairo_t* get(); - bool isInitialized() const; - /** - * @brief Use the surface as a mask - */ - void blitTo(cairo_t* targetCr) const; - /** - * @brief Paint the content of the surface to the target cairo context - */ - void paintTo(cairo_t* targetCr) const; - /** - * @brief Paint the content of the surface to the target cairo context - */ - void paintToWithAlpha(cairo_t* targetCr, uint8_t alpha) const; - /** - * @brief Erase all the surface's content - */ - void wipe(); - - /** - * @brief Erase part the surface's content - * @param rg The part to erase, in Page coordinates - */ - void wipeRange(const Range& rg); - - /** - * @brief Delete the mask - */ - void reset(); - - inline double getZoom() const { return zoom; } - -private: - template - void constructorImpl(DPIInfoType dpiInfo, const Range& extent, double zoom, cairo_content_t contentType); - - xoj::util::CairoSPtr cr; - int xOffset = 0; - int yOffset = 0; - double zoom = 1.0; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/Repaintable.h b/entry/src/main/cpp/src/core/view/Repaintable.h deleted file mode 100644 index 14c880f..0000000 --- a/entry/src/main/cpp/src/core/view/Repaintable.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Xournal++ - * - * - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -class Range; -class ZoomControl; - -namespace xoj::util { -template -class Rectangle; -}; - -namespace xoj::view { -class OverlayView; -class ToolView; - -class Repaintable { -public: - Repaintable() = default; - virtual ~Repaintable() = default; - - Repaintable(const Repaintable&) = delete; - Repaintable(Repaintable&&) = delete; - - /** - * @brief Get the Repaintable's visible part, in local coordinates - * @return A range. It could be empty. - */ - virtual Range getVisiblePart() const = 0; - - // Get the current zoom. - virtual double getZoom() const = 0; - virtual ZoomControl* getZoomControl() const = 0; - - // Width and height, in local coordinates - virtual double getWidth() const = 0; - virtual double getHeight() const = 0; - - // Convert a rectangle from local coordinates to global coordinates - virtual xoj::util::Rectangle toWindowCoordinates(const xoj::util::Rectangle& r) const = 0; - - /** - * @brief Flag a region as dirty. Dirty regions will get redrawn at the next screen refresh. - */ - virtual void flagDirtyRegion(const Range& rg) const = 0; - - /** - * @brief Draw the ToolView to the repaintable buffer (if any), remove a tool view and repaint the given range - * Called just before the tool sequence ends and the handler is deleted. - */ - virtual void drawAndDeleteToolView(ToolView* v, const Range& rg) = 0; - - /** - * @brief Remove a overlay view and repaint the given range - * The given range is supposed to be big enough so that repainting this area will indeed erase the overlay from - * the display - */ - virtual void deleteOverlayView(OverlayView* v, const Range& rg) = 0; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/SetsquareView.cpp b/entry/src/main/cpp/src/core/view/SetsquareView.cpp deleted file mode 100644 index e599a0b..0000000 --- a/entry/src/main/cpp/src/core/view/SetsquareView.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include "SetsquareView.h" - -#include // for max, min -#include // for isnan, sqrt, cos, sin, atan2 -#include -#include -#include // for move - -#include // for g_error, g_warning - -#include "model/Setsquare.h" // for Setsquare -#include "model/Stroke.h" // for Stroke -#include "util/Assert.h" // for xoj_assert -#include "util/raii/CairoWrappers.h" // for CairoSaveGuard -#include "util/safe_casts.h" // for floor_cast -#include "view/Repaintable.h" // for Repaintable -#include "view/View.h" // for Context - -#include "StrokeView.h" // for StrokeView - -using namespace xoj::view; - -// all lengths are in centimeter -constexpr double FONT_SIZE = .2; -constexpr double CIRCLE_RAD = .3; -constexpr double TICK_SMALL = .1; -constexpr double TICK_LARGE = .2; -constexpr double MAX_HOR_POS_VMARKS = 2.5; -constexpr int MIN_OFFSET_ANG_MARKS = 2; -constexpr double RELATIVE_CIRCLE_POS = .75; -constexpr double RELATIVE_MAX_HOR_POS_VMARKS = .6; -constexpr double HMARK_POS = 2.; -constexpr double MIN_DIST_FROM_HMARK = .2; -constexpr int MIN_VMARK_SMALL = 3; -constexpr int MIN_VMARK_LARGE = 5; -constexpr int OFFSET_FROM_SEMICIRCLE = 2.; -constexpr double ZERO_MARK_TICK = .5; -constexpr int SKIPPED_HMARKS = 8; -constexpr const char* FONT_FAMILY = "Arial"; - -SetsquareView::SetsquareView(const Setsquare* setsquare, Repaintable* parent, ZoomControl* zoomControl): - GeometryToolView(setsquare, parent, zoomControl) { - this->registerToPool(setsquare->getViewPool()); -} - -SetsquareView::~SetsquareView() noexcept { this->unregisterFromPool(); }; - -void SetsquareView::on(FlagDirtyRegionRequest, const Range& rg) { this->parent->flagDirtyRegion(rg); } - -void SetsquareView::on(UpdateValuesRequest, double h, double rot, cairo_matrix_t m) { - xoj_assert_message(h > 0, "Non-positive setsquare height"); - height = h; - rotation = rot; - matrix = m; - radius = Setsquare::radiusFromHeight(height); - circlePos = height * RELATIVE_CIRCLE_POS; - horPosVmarks = std::min(MAX_HOR_POS_VMARKS, radius * RELATIVE_MAX_HOR_POS_VMARKS); - minVmark = (std::abs(horPosVmarks - HMARK_POS - TICK_SMALL / 2.) < MIN_DIST_FROM_HMARK - TICK_SMALL / 2.) ? - MIN_VMARK_LARGE : - MIN_VMARK_SMALL; - maxVmark = floor_cast(cathete(radius, horPosVmarks) * 10.0) - OFFSET_FROM_SEMICIRCLE; - - // The following computation of the angular marks offset is based on experimentation. - offset = std::max(MIN_OFFSET_ANG_MARKS, - static_cast(256.0 / std::pow(height, 2))); // larger offset for small height - if (std ::abs(radius - std::round(radius)) < .2) { // larger offset when semicircle comes close to big hmarks - offset = std::max(offset, static_cast(24.0 / radius)); - } - maxHmark = floor_cast(height * 10.0) - SKIPPED_HMARKS; -} - -void SetsquareView::deleteOn(SetsquareView::FinalizationRequest, const Range& rg) { - this->parent->drawAndDeleteToolView(this, rg); -} - -void SetsquareView::drawGeometryTool(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_scale(cr, CM, CM); - - cairo_set_line_width(cr, LINE_WIDTH_IN_CM); - cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); - cairo_select_font_face(cr, FONT_FAMILY, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, FONT_SIZE); - - // clip to slightly enlarged setsquare for performance reasons - const double enlargedHeight = this->height + LINE_WIDTH_IN_CM; - cairo_move_to(cr, enlargedHeight, -LINE_WIDTH_IN_CM); - cairo_line_to(cr, -enlargedHeight, -LINE_WIDTH_IN_CM); - cairo_line_to(cr, .0, enlargedHeight); - cairo_close_path(cr); - cairo_clip(cr); - - cairo_set_source_rgb(cr, 1., .0, .0); // red - drawOutline(cr); - - cairo_set_source_rgb(cr, .0, .0, 1.); // blue - drawHorizontalMarks(cr); - - cairo_set_source_rgb(cr, .0, .5, .0); // green - drawVerticalMarks(cr); - - cairo_set_source_rgb(cr, .5, .0, .5); // violet - drawAngularMarks(cr); -} - -void SetsquareView::drawDisplays(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_transform(cr, &matrix); - cairo_set_line_width(cr, LINE_WIDTH_IN_CM); - cairo_select_font_face(cr, FONT_FAMILY, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, FONT_SIZE); - - cairo_set_source_rgb(cr, .0, .5, .5); // turquoise - drawRotation(cr); -} - -void SetsquareView::drawOutline(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_move_to(cr, this->height, .0); - cairo_line_to(cr, -this->height, .0); - cairo_line_to(cr, .0, this->height); - cairo_close_path(cr); - cairo_stroke_preserve(cr); - - cairo_set_source_rgba(cr, .2, .2, .2, .1); // transparent gray - cairo_fill(cr); -} - -void SetsquareView::drawRotation(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - - // write the angle between hypotenuse and horizontal axis within a small circle - std::stringstream ss; - ss << std::fixed << std::setprecision(1) << std::abs(std::remainder(deg(this->rotation), 180.)); - cairo_move_to(cr, .0, this->circlePos); - showTextCenteredAndRotated(cr, ss.str(), -deg(this->rotation)); - - cairo_move_to(cr, .0, this->circlePos); - cairo_new_sub_path(cr); - cairo_arc(cr, .0, this->circlePos, CIRCLE_RAD, .0, 2. * M_PI); - cairo_stroke(cr); -} - -void SetsquareView::drawAngularMarks(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - // BEGIN: 45 degree marks - clipHorizontalStripes(cr); - clipVerticalStripes(cr); - - for (int i: {45, 135}) { - const double cs = std::cos(rad(i)); - const double si = std::sin(rad(i)); - - // inside semicircle - const double radInsideUpper = this->radius - .3; // 4.2 - cairo_move_to(cr, cs, si); - cairo_line_to(cr, radInsideUpper * cs, radInsideUpper * si); - - // outside semicircle - const double radOutsideLower = this->radius + .3; // 4.8 - const double radOutsideUpper = this->height / std::sqrt(2.) - .3; // 5.4 - cairo_move_to(cr, radOutsideLower * cs, radOutsideLower * si); - cairo_line_to(cr, radOutsideUpper * cs, radOutsideUpper * si); - } - cairo_stroke(cr); - cairo_reset_clip(cr); - // END: 45 degree marks - - // BEGIN: marks and numbers around semicircle - for (int i = 1; i < 180; i++) { - // the radius corresponding to the point with angle i on one of the short sides of the setsquare - // it is computed using the law of sines - const double radCath = this->height * std::sin(rad(45)) / std::sin(rad(i > 90 ? i - 45 : 135 - i)); - const double cs = std::cos(rad(i)); - const double si = std::sin(rad(i)); - const double tick = (i % 5 == 0) ? TICK_LARGE : TICK_SMALL; - cairo_move_to(cr, radCath * cs, radCath * si); // move to one of the short sides of the set square - if (i % 10 == 0 && i > this->offset && i < 180 - this->offset) { - // large tick near short side of set square - const double radTickEnd = (i == 90) ? (this->circlePos + .5) : (this->radius + .8); - cairo_line_to(cr, radTickEnd * cs, radTickEnd * si); - - // show increasing numbers near semi-circle - const double radInc = this->radius + 0.3; - cairo_move_to(cr, radInc * cs, radInc * si); - showTextCenteredAndRotated(cr, std::to_string(i), i + 270); - - // show decreasing numbers a bit further from semi-circle - if (i != 90) { - const double radDec = this->radius + 0.6; - cairo_move_to(cr, radDec * cs, radDec * si); - showTextCenteredAndRotated(cr, std::to_string(180 - i), i + 270); - } - } else { - cairo_rel_line_to(cr, -tick * cs, -tick * si); // just a tick near short side of set square - } - - if (i > this->offset && i < 180 - this->offset) { - // tick near semi-circle - cairo_move_to(cr, this->radius * cs, this->radius * si); - cairo_rel_line_to(cr, tick * cs, tick * si); - } - } - cairo_stroke(cr); - // END: marks and numbers around semicircle -} - -void SetsquareView::drawVerticalMarks(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - const auto max = this->maxVmark / 10; // number of full centimeters - - // BEGIN: VERTICAL marks within semicircle - clipVerticalStripes(cr); - - // draw vertical marks - for (double i = .5; i <= max; i += .5) { - const double x = cathete(this->radius - .25, i); - cairo_move_to(cr, -x, i); - cairo_line_to(cr, x, i); - cairo_stroke(cr); - } - cairo_reset_clip(cr); - // END: VERTICAL marks within circle - - - // BEGIN: vertical measuring marks with numbers - for (int i = this->minVmark; i <= this->maxVmark; i++) { - const double y = static_cast(i) / 10.; - const double tick = (i % 5 == 0) ? TICK_LARGE : TICK_SMALL; - - // marks and numbers (left and right) - for (const double sign: {-1., 1.}) { - cairo_move_to(cr, sign * this->horPosVmarks, y); - cairo_rel_line_to(cr, -sign * tick, .0); - if (i % 10 == 0) { - const auto text = std::to_string(i / 10); - cairo_rel_move_to(cr, -sign * TICK_SMALL, .0); - showTextCenteredAndRotated(cr, text, .0); - }; - } - } - cairo_stroke(cr); - // END: vertical measuring marks with numbers -} - -void SetsquareView::drawHorizontalMarks(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - const auto max = this->maxVmark / 10; // number of full centimeters - - // BEGIN: line indicating horizontal 0 - for (auto i = 1; i <= max; i++) { - cairo_move_to(cr, .0, static_cast(i) - ZERO_MARK_TICK / 2.); - cairo_rel_line_to(cr, .0, ZERO_MARK_TICK); - } - cairo_stroke(cr); - // END: line indicating horizontal 0 - - // BEGIN: measuring marks on top - for (int i = -this->maxHmark; i <= this->maxHmark; i++) { - const double tick = (i % 5 == 0) ? TICK_LARGE : TICK_SMALL; - // draw marks - cairo_move_to(cr, static_cast(i) / 10., .0); - cairo_rel_line_to(cr, .0, tick); - if (i % 10 == 0) { - // draw numbers - cairo_rel_move_to(cr, .0, FONT_SIZE / 2.); - const auto text = std::to_string(std::abs(i / 10)); - showTextCenteredAndRotated(cr, text.c_str(), .0); - } - } - cairo_stroke(cr); - // END: measuring marks on top -} - -void SetsquareView::clipVerticalStripes(cairo_t* cr) const { - // y-coordinate of the highest vertical mark - const auto y = static_cast(this->maxVmark) / 10.; - - cairo_rectangle(cr, -this->horPosVmarks - .25, .0, .75, y + .5); // left stripe - cairo_rectangle(cr, this->horPosVmarks - .5, .0, .75, y + .5); // right stripe - cairo_rectangle(cr, -.25, .0, .5, y + .5); // middle stripe - cairo_rectangle(cr, -this->height, .0, 2. * this->height, this->height); // clip to the outside - cairo_clip(cr); -} - -void SetsquareView::clipHorizontalStripes(cairo_t* cr) const { - for (auto i = .5; i <= static_cast(this->maxVmark) / 10.0; i += .5) { - double x = cathete(this->radius - .25, i); - cairo_rectangle(cr, -x, i - .15, 2. * x, .3); - } - cairo_rectangle(cr, -this->height, .0, 2. * this->height, this->height); // clip to the outside - cairo_clip(cr); -} diff --git a/entry/src/main/cpp/src/core/view/SetsquareView.h b/entry/src/main/cpp/src/core/view/SetsquareView.h deleted file mode 100644 index 84b479c..0000000 --- a/entry/src/main/cpp/src/core/view/SetsquareView.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Xournal++ - * - * A setsquare view - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include // for cairo_t - -#include "model/Setsquare.h" // for Setsquare -#include "util/DispatchPool.h" -#include "view/overlays/BaseStrokeToolView.h" - -#include "GeometryToolView.h" - -class Stroke; -class OverlayBase; -class ZoomControl; - -/** - * @brief A class that renders a setsquare - * - * The setsquare has vertical, horizontal and angular marks. - * The intersection angle with the x-axis is displayed as well. - * - * See the file development/documentation/Setsquare_Readme.md for - * details how the setsquare is rendered. - * - * A temporary stroke is displayed when it is created near the - * longest side of the setsquare or from a point to the mid point - * of the longest side of the setsquare. - */ - -namespace xoj::view { -class Repaintable; - -class SetsquareView: public GeometryToolView { - -public: - SetsquareView(const Setsquare* s, Repaintable* parent, ZoomControl* zoomControl); - ~SetsquareView() noexcept override; - - void on(FlagDirtyRegionRequest, const Range& rg) override; - void on(UpdateValuesRequest, double h, double rot, cairo_matrix_t m) override; - void deleteOn(FinalizationRequest, const Range& rg) override; - -private: - void drawGeometryTool(cairo_t* cr) const override; - void drawDisplays(cairo_t* cr) const override; - - double height = Setsquare::INITIAL_HEIGHT; - double rotation = 0.; - cairo_matrix_t matrix{CM, 0., 0., CM, 0., 0.}; - - - /** - * @brief the radius of the semi-circle for the angular marks - */ - double radius = 4.5; - - /** - * @brief the distance of the circle containing the rotation angle display from the mid point of the longest side of - * the setsquare - */ - double circlePos = 6.0; - - /** - * @brief the distance (in cm) of the vertical marks from the symmetry axis of the setsquare - */ - double horPosVmarks = 2.5; - - /** - * @brief the index of the first vertical mark which should be drawn (which should not overlap with the measuring - * marks) - */ - int minVmark = 3; - - /** - * @brief the index of the last vertical mark to be drawn - */ - int maxVmark = 35; - - /** - * @brief the number of angular marks that are left away on both ends (in order not to overlap with the measuring - * marks) - */ - int offset = 4; - - /** - * @brief the index of the last horizontal mark to be drawn - */ - int maxHmark = 70; - - void drawVerticalMarks(cairo_t* cr) const; - void drawHorizontalMarks(cairo_t* cr) const; - void drawAngularMarks(cairo_t* cr) const; - void drawOutline(cairo_t* cr) const; - void drawRotation(cairo_t* cr) const; - void clipVerticalStripes(cairo_t* cr) const; - void clipHorizontalStripes(cairo_t* cr) const; - -public: - static constexpr double LINE_WIDTH_IN_CM = .02; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/StrokeView.cpp b/entry/src/main/cpp/src/core/view/StrokeView.cpp deleted file mode 100644 index 6b20d9a..0000000 --- a/entry/src/main/cpp/src/core/view/StrokeView.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "StrokeView.h" - -#include // for max -#include // for ceil - -#include // for g_warning - -#include "model/Stroke.h" // for Stroke, StrokeTool::HIGHLIGHTER -#include "util/Assert.h" // for xoj_assert -#include "util/Color.h" // for cairo_set_source_rgbi -#include "util/Rectangle.h" // for Rectangle -#include "view/Mask.h" // for Mask -#include "view/View.h" // for Context, OPACITY_NO_AUDIO, view - -#include "ErasableStrokeView.h" // for ErasableStrokeView -#include "StrokeViewHelper.h" -#include "filesystem.h" // for path - -class ErasableStroke; - -using xoj::util::Rectangle; -using namespace xoj::view; - -StrokeView::StrokeView(const Stroke* s): s(s) {} - -void StrokeView::draw(const Context& ctx) const { - - if (s->getPointCount() < 2) { - // Should not happen - g_warning("View::StrokeView::draw empty stroke..."); - return; - } - - const bool highlighter = s->getToolType() == StrokeTool::HIGHLIGHTER; - const bool filledHighlighter = highlighter && s->getFill() != -1; - const bool drawTranslucent = ctx.fadeOutNonAudio && s->getAudioFilename().empty(); - const bool useMask = (!ctx.noColor && filledHighlighter) || drawTranslucent; - - if (ctx.showCurrentEdition && filledHighlighter && s->getErasable() != nullptr) { - // Currently being erased filled highlighter strokes need a special treatment - ErasableStrokeView erasableStrokeView(*s->getErasable()); - erasableStrokeView.paintFilledHighlighter(ctx.cr); - return; - } - - // The mask will be colorblind - const bool noColor = ctx.noColor || useMask; - - xoj::util::CairoSaveGuard saveGuard(ctx.cr); - - Mask mask; - - // If not using a mask, draw directly onto the given cairo context - cairo_t* cr = ctx.cr; - - if (useMask) { - /** - * To avoid visual glitches when different translucent cairo_stroke are painted, - * they are painted without colors to a mask which will in turn be blitted (see below) - */ - - /** - * Infer the zoom level from context. - */ - cairo_matrix_t matrix; - cairo_get_matrix(ctx.cr, &matrix); - // We assume the matrix is diagonal (i.e. only scaling, no rotation) - xoj_assert(matrix.xy == 0 && matrix.yx == 0); - - const double zoom = std::max(matrix.xx, matrix.yy); - - /** - * Create a mask tailored to the stroke's bounding box - */ - mask = Mask(cairo_get_target(ctx.cr), Range(s->boundingRect()), zoom); - cr = mask.get(); - } - - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - cairo_set_line_cap(cr, CAIRO_LINE_CAP[s->getStrokeCapStyle()]); - - if (auto fill = s->getFill(); fill != -1) { - /** - * Paint the filling - */ - if (noColor) { - // Painting on an Alpha-only mask. No need for colors. - if (filledHighlighter) { - cairo_set_source_rgba(cr, 1, 1, 1, 1); - } else { - cairo_set_source_rgba(cr, 1, 1, 1, static_cast(fill) / 255.0); - } - } else { - Util::cairo_set_source_rgbi(cr, s->getColor(), static_cast(fill) / 255.0); - } - cairo_set_operator(cr, useMask ? CAIRO_OPERATOR_SOURCE : CAIRO_OPERATOR_OVER); - - if (ErasableStroke* erasable = s->getErasable(); erasable != nullptr && ctx.showCurrentEdition) { - // don't render erasable for previews - ErasableStrokeView erasableStrokeView(*erasable); - erasableStrokeView.drawFilling(cr); - } else { - StrokeViewHelper::pathToCairo(cr, s->getPointVector()); - cairo_fill(cr); - } - } - - /** - * Picking the colors and alpha values, and the operator - */ - if (noColor) { - /** - * No color: painting onto an alpha mask. Colors will be applied upon blitting. - */ - cairo_set_source_rgba(cr, 1, 1, 1, 1); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - } else if (highlighter) { - /** - * Highlighter without filling. - */ - Util::cairo_set_source_rgbi(cr, s->getColor(), OPACITY_HIGHLIGHTER); - cairo_set_operator(cr, CAIRO_OPERATOR_MULTIPLY); - } else { - /** - * Normal pen - */ - Util::cairo_set_source_rgbi(cr, s->getColor()); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - } - - if (ErasableStroke* erasable = s->getErasable(); erasable != nullptr && ctx.showCurrentEdition) { - // don't render erasable for previews - ErasableStrokeView erasableStrokeView(*erasable); - erasableStrokeView.draw(cr); - } else if (s->hasPressure() && !highlighter) { - StrokeViewHelper::drawWithPressure(cr, s->getPointVector(), s->getLineStyle()); - } else { - StrokeViewHelper::drawNoPressure(cr, s->getPointVector(), s->getWidth(), s->getLineStyle()); - } - - if (useMask) { - /** - * Blit the mask onto the target cairo context. - */ - - /** - * Opacity for the mask's content: the base value depends on the tool: - * Pen : 1 - * Highlighter (no filling): OPACITY_HIGHLIGHTER - * Highlighter (filled) : s->getFill() / 255 - */ - double groupAlpha = - highlighter ? (filledHighlighter ? static_cast(s->getFill()) / 255.0 : OPACITY_HIGHLIGHTER) : - 1.0; - - // If the stroke has no audio attached, we draw it (even more) translucent - if (drawTranslucent) { - groupAlpha *= OPACITY_NO_AUDIO; - groupAlpha = std::max(MINIMAL_ALPHA, groupAlpha); - } - - // Blit the mask onto the given cairo context - cairo_set_operator(ctx.cr, highlighter ? CAIRO_OPERATOR_MULTIPLY : CAIRO_OPERATOR_OVER); - - Util::cairo_set_source_rgbi(ctx.cr, s->getColor(), groupAlpha); - - mask.blitTo(ctx.cr); - } -} diff --git a/entry/src/main/cpp/src/core/view/StrokeView.h b/entry/src/main/cpp/src/core/view/StrokeView.h deleted file mode 100644 index 6d18449..0000000 --- a/entry/src/main/cpp/src/core/view/StrokeView.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Xournal++ - * - * Draw stroke - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t, CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_ROUND - -#include "View.h" // for ElementView - -class Stroke; - -class xoj::view::StrokeView: public xoj::view::ElementView { -public: - StrokeView(const Stroke* s); - ~StrokeView() = default; - -public: - /** - * @brief Paint the given stroke. - * @param dontRenderEditingStroke If true, and if the stroke is currently being (partially) erased, then render only - * the not-yet-erased parts. (Typically set to true, except for previews and export jobs) - * @param markAudioStroke If true, the stroke is faded out if it has no audio playback attached. - * @param noColor If true, paint as if on a colorblind mask (only the alpha values are painted). - */ - void draw(const Context& ctx) const override; - -private: - const Stroke* s; - -public: - static constexpr double OPACITY_HIGHLIGHTER = 0.47; - static constexpr double MINIMAL_ALPHA = 0.04; - - // Must match the enum StrokeCapStyle in Stroke.h - static constexpr cairo_line_cap_t CAIRO_LINE_CAP[] = {CAIRO_LINE_CAP_ROUND, CAIRO_LINE_CAP_BUTT, - CAIRO_LINE_CAP_SQUARE}; -}; diff --git a/entry/src/main/cpp/src/core/view/StrokeViewHelper.cpp b/entry/src/main/cpp/src/core/view/StrokeViewHelper.cpp deleted file mode 100644 index ccce5e6..0000000 --- a/entry/src/main/cpp/src/core/view/StrokeViewHelper.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "StrokeViewHelper.h" - -#include "model/LineStyle.h" -#include "model/Point.h" -#include "model/StrokeContour.h" -#include "util/Assert.h" -#include "util/LoopUtil.h" -#include "util/PairView.h" -#include "util/Util.h" // for cairo_set_dash_from_vector - -void xoj::view::StrokeViewHelper::pathToCairo(cairo_t* cr, const std::vector& pts) { - for_first_then_each( - pts, [cr](auto const& first) { cairo_move_to(cr, first.x, first.y); }, - [cr](auto const& other) { cairo_line_to(cr, other.x, other.y); }); -} - -/** - * No pressure sensitivity, one line is drawn - */ -void xoj::view::StrokeViewHelper::drawNoPressure(cairo_t* cr, const std::vector& pts, const double strokeWidth, - const LineStyle& lineStyle, double dashOffset) { - cairo_set_line_width(cr, strokeWidth); - - const auto& dashes = lineStyle.getDashes(); - Util::cairo_set_dash_from_vector(cr, dashes, dashOffset); - - pathToCairo(cr, pts); - cairo_stroke(cr); -} - -/** - * Draw a stroke with pressure, for this multiple lines with different widths needs to be drawn - */ -double xoj::view::StrokeViewHelper::drawWithPressure(cairo_t* cr, const std::vector& pts, - const LineStyle& lineStyle, double dashOffset) { - const auto& dashes = lineStyle.getDashes(); - if (cairo_surface_get_type(cairo_get_target(cr)) == CAIRO_SURFACE_TYPE_PDF) { - // PDF documents have an equivalent of cairo_stroke(). We use it to get smaller PDF files - auto drawSegment = [cr](const Point& p, const Point& q) { - xoj_assert(p.z > 0.0); - cairo_set_line_width(cr, p.z); - cairo_move_to(cr, p.x, p.y); - cairo_line_to(cr, q.x, q.y); - cairo_stroke(cr); - }; - if (!dashes.empty()) { - /* - * Because the width varies, we need to call cairo_stroke() once per segment - */ - for (const auto& [p, q]: PairView(pts)) { - Util::cairo_set_dash_from_vector(cr, dashes, dashOffset); - dashOffset += p.lineLengthTo(q); - drawSegment(p, q); - } - } else { - cairo_set_dash(cr, nullptr, 0, 0.0); - for (const auto& [p, q]: PairView(pts)) { - drawSegment(p, q); - }; - } - } else { - if (pts.size() == 2 && pts.front().equalsPos(pts.back())) { - // Single dot - cairo_arc(cr, pts.front().x, pts.front().y, .5 * pts.front().z, 0, 2. * M_PI); - } else if (!dashes.empty()) { - dashOffset = StrokeContourDashes(pts, dashes).addToCairo(cr, dashOffset); - } else { - StrokeContour(pts).addToCairo(cr); - } - cairo_fill(cr); - } - return dashOffset; -} diff --git a/entry/src/main/cpp/src/core/view/StrokeViewHelper.h b/entry/src/main/cpp/src/core/view/StrokeViewHelper.h deleted file mode 100644 index f32ef9f..0000000 --- a/entry/src/main/cpp/src/core/view/StrokeViewHelper.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Xournal++ - * - * Draw stroke - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include - -class LineStyle; -class Point; - -namespace xoj::view::StrokeViewHelper { - -/** - * @brief Simply adds the points to a cairo context, as a single path - */ -void pathToCairo(cairo_t* cr, const std::vector& pts); - -/** - * @brief No pressure sensitivity, one line is drawn, with given width and line style (dashes) - */ -void drawNoPressure(cairo_t* cr, const std::vector& pts, const double strokeWidth, const LineStyle& lineStyle, - double dashOffset = 0); - -/** - * @brief Draw a stroke with pressure, for this multiple lines with different widths needs to be drawn. - * @return New dash offset, if one wants to keep on drawing the same stroke. - * Effectively, the return value equals dashOffset + length of the path. - */ -double drawWithPressure(cairo_t* cr, const std::vector& pts, const LineStyle& lineStyle, double dashOffset = 0); -}; // namespace xoj::view::StrokeViewHelper diff --git a/entry/src/main/cpp/src/core/view/TexImageView.cpp b/entry/src/main/cpp/src/core/view/TexImageView.cpp deleted file mode 100644 index 9d72ebf..0000000 --- a/entry/src/main/cpp/src/core/view/TexImageView.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "TexImageView.h" - -#include // for string - -#include // for cairo_paint_with_alpha, cairo_scale -#include // for g_warning -#include // for PopplerPage, PopplerDocument, g_clear_... - -#include "model/TexImage.h" // for TexImage -#include "view/View.h" // for Context, OPACITY_NO_AUDIO, view - -using namespace xoj::view; - -TexImageView::TexImageView(const TexImage* texImage): texImage(texImage) {} - -TexImageView::~TexImageView() = default; - -void TexImageView::draw(const Context& ctx) const { - - cairo_t* cr = ctx.cr; - cairo_save(cr); - - PopplerDocument* pdf = texImage->getPdf(); - cairo_surface_t* img = texImage->getImage(); - - if (pdf != nullptr) { - if (poppler_document_get_n_pages(pdf) < 1) { - g_warning("Got latex PDF without pages!: %s", texImage->getText().c_str()); - return; - } - - PopplerPage* page = poppler_document_get_page(pdf, 0); - - double pageWidth = 0; - double pageHeight = 0; - poppler_page_get_size(page, &pageWidth, &pageHeight); - - double xFactor = texImage->getElementWidth() / pageWidth; - double yFactor = texImage->getElementHeight() / pageHeight; - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_translate(cr, texImage->getX(), texImage->getY()); - cairo_scale(cr, xFactor, yFactor); - - auto surfType = cairo_surface_get_type(cairo_get_target(cr)); - auto pageRenderFunction = - surfType == CAIRO_SURFACE_TYPE_PDF || surfType == CAIRO_SURFACE_TYPE_PS || - surfType == CAIRO_SURFACE_TYPE_SVG || surfType == CAIRO_SURFACE_TYPE_SCRIPT || - surfType == CAIRO_SURFACE_TYPE_WIN32_PRINTING || surfType == CAIRO_SURFACE_TYPE_XML || - surfType == CAIRO_SURFACE_TYPE_RECORDING ? - poppler_page_render_for_printing : - poppler_page_render; - - // Make TeX images translucent when highlighting audio strokes as they can not have audio - if (ctx.fadeOutNonAudio) { - /** - * Switch to a temporary surface, render the page, then switch back. - * This sets the current pattern to the temporary surface. - */ - cairo_push_group(cr); - pageRenderFunction(page, cr); - cairo_pop_group_to_source(cr); - - // paint the temporary surface with opacity level - cairo_paint_with_alpha(cr, OPACITY_NO_AUDIO); - } else { - pageRenderFunction(page, cr); - } - - g_clear_object(&page); - } else if (img != nullptr) { - int width = cairo_image_surface_get_width(img); - int height = cairo_image_surface_get_height(img); - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - double xFactor = texImage->getElementWidth() / width; - double yFactor = texImage->getElementHeight() / height; - - cairo_scale(cr, xFactor, yFactor); - - cairo_set_source_surface(cr, img, texImage->getX() / xFactor, texImage->getY() / yFactor); - // Make TeX images translucent when highlighting audio strokes as they can not have audio - if (ctx.fadeOutNonAudio) { - cairo_paint_with_alpha(cr, OPACITY_NO_AUDIO); - } else { - cairo_paint(cr); - } - } - - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/TexImageView.h b/entry/src/main/cpp/src/core/view/TexImageView.h deleted file mode 100644 index 75613fa..0000000 --- a/entry/src/main/cpp/src/core/view/TexImageView.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Xournal++ - * - * Displays a TexImage Element - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include "View.h" - -class TexImage; - -class xoj::view::TexImageView: public xoj::view::ElementView { -public: - TexImageView(const TexImage* texImage); - virtual ~TexImageView(); - - /** - * Draws a TexImage model - */ - void draw(const Context& ctx) const override; - -private: - const TexImage* texImage; -}; diff --git a/entry/src/main/cpp/src/core/view/TextView.cpp b/entry/src/main/cpp/src/core/view/TextView.cpp deleted file mode 100644 index 9c3d546..0000000 --- a/entry/src/main/cpp/src/core/view/TextView.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "TextView.h" - -#include // for max -#include // for size_t - -#include "model/Text.h" // for Text -#include "util/Color.h" // for cairo_set_source_rgbi -#include "util/StringUtils.h" // for StringUtils -#include "util/raii/CairoWrappers.h" -#include "util/raii/GObjectSPtr.h" -#include "view/View.h" // for Context, OPACITY_NO_AUDIO, view - -#include "filesystem.h" // for path - -using namespace xoj::view; - -TextView::TextView(const Text* text): text(text) {} - -TextView::~TextView() = default; - -auto TextView::initPango(cairo_t* cr, const Text* t) -> xoj::util::GObjectSPtr { - auto layout = t->createPangoLayout(); - pango_cairo_update_layout(cr, layout.get()); - pango_context_set_matrix(pango_layout_get_context(layout.get()), nullptr); - - return layout; -} - -void TextView::draw(const Context& ctx) const { - if (text->isInEditing()) { - // The drawing is handled by gui/TextEditor - return; - } - - xoj::util::CairoSaveGuard saveGuard(ctx.cr); - - // make elements without audio translucent when highlighting elements with audio - if (ctx.fadeOutNonAudio && text->getAudioFilename().empty()) { - cairo_set_operator(ctx.cr, CAIRO_OPERATOR_OVER); - Util::cairo_set_source_rgbi(ctx.cr, text->getColor(), OPACITY_NO_AUDIO); - } else { - cairo_set_operator(ctx.cr, CAIRO_OPERATOR_SOURCE); - Util::cairo_set_source_rgbi(ctx.cr, text->getColor()); - } - - cairo_translate(ctx.cr, text->getX(), text->getY()); - - auto layout = initPango(ctx.cr, text); - const std::string& content = text->getText(); - pango_layout_set_text(layout.get(), content.c_str(), static_cast(content.length())); - - pango_cairo_show_layout(ctx.cr, layout.get()); -} diff --git a/entry/src/main/cpp/src/core/view/TextView.h b/entry/src/main/cpp/src/core/view/TextView.h deleted file mode 100644 index d80c15a..0000000 --- a/entry/src/main/cpp/src/core/view/TextView.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * Displays a text Element - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string -#include // for vector - -#include // for PangoLayout, cairo_t - -#include "util/raii/GObjectSPtr.h" - -#include "View.h" // for ElementView - -class Text; - -class xoj::view::TextView: public xoj::view::ElementView { -public: - TextView(const Text* t); - virtual ~TextView(); - - /** - * Draws a Text model to a cairo surface - */ - void draw(const Context& ctx) const override; - - /** - * Initialize a Pango layout - */ - static xoj::util::GObjectSPtr initPango(cairo_t* cr, const Text* t); - -private: - const Text* text; -}; diff --git a/entry/src/main/cpp/src/core/view/View.h b/entry/src/main/cpp/src/core/view/View.h deleted file mode 100644 index 87dd7c4..0000000 --- a/entry/src/main/cpp/src/core/view/View.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Xournal++ - * - * Namespace for view related classes - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include - -class Element; - -namespace xoj { -namespace view { - -enum NonAudioTreatment : bool { FADE_OUT_NON_AUDIO_ = true, NORMAL_NON_AUDIO = false }; -enum EditionTreatment : bool { SHOW_CURRENT_EDITING = true, HIDE_CURRENT_EDITING = false }; -enum ColorTreatment : bool { COLORBLIND = true, NORMAL_COLOR = false }; - -class Context { -public: - cairo_t* cr; - NonAudioTreatment fadeOutNonAudio; - EditionTreatment showCurrentEdition; - ColorTreatment noColor; - - static Context createDefault(cairo_t* cr) { return {cr, NORMAL_NON_AUDIO, HIDE_CURRENT_EDITING, NORMAL_COLOR}; } - static Context createColorBlind(cairo_t* cr) { return {cr, NORMAL_NON_AUDIO, HIDE_CURRENT_EDITING, COLORBLIND}; } -}; - -class ElementView { -public: - virtual ~ElementView() = default; - virtual void draw(const Context& ctx) const = 0; - static std::unique_ptr createFromElement(const Element* e); -}; - -class TexImageView; -class ImageView; -class StrokeView; -class TextView; - -constexpr double OPACITY_NO_AUDIO = 0.3; -}; // namespace view -}; // namespace xoj diff --git a/entry/src/main/cpp/src/core/view/background/BackgroundFlags.h b/entry/src/main/cpp/src/core/view/background/BackgroundFlags.h deleted file mode 100644 index 077b1cb..0000000 --- a/entry/src/main/cpp/src/core/view/background/BackgroundFlags.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Xournal++ - * - * Flags for background painting - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -namespace xoj::view { - -enum PDFBackgroundTreatment : bool { SHOW_PDF_BACKGROUND = true, HIDE_PDF_BACKGROUND = false }; -enum ImageBackgroundTreatment : bool { SHOW_IMAGE_BACKGROUND = true, HIDE_IMAGE_BACKGROUND = false }; -enum RulingBackgroundTreatment : bool { SHOW_RULING_BACKGROUND = true, HIDE_RULING_BACKGROUND = false }; -enum BackgroundColorTreatment : bool { FORCE_AT_LEAST_BACKGROUND_COLOR = true, DONT_FORCE_BACKGROUND_COLOR = false }; -enum VisibilityTreatment : bool { FORCE_VISIBLE = true, USE_DOCUMENT_VISIBILITY = false }; - -struct BackgroundFlags { - PDFBackgroundTreatment showPDF; - ImageBackgroundTreatment showImage; - RulingBackgroundTreatment showRuling; - BackgroundColorTreatment forceBackgroundColor = DONT_FORCE_BACKGROUND_COLOR; - VisibilityTreatment forceVisible = USE_DOCUMENT_VISIBILITY; -}; - -static constexpr BackgroundFlags BACKGROUND_SHOW_ALL = {SHOW_PDF_BACKGROUND, SHOW_IMAGE_BACKGROUND, - SHOW_RULING_BACKGROUND, DONT_FORCE_BACKGROUND_COLOR, - USE_DOCUMENT_VISIBILITY}; - -static constexpr BackgroundFlags BACKGROUND_FORCE_PAINT_BACKGROUND_COLOR_ONLY = { - HIDE_PDF_BACKGROUND, HIDE_IMAGE_BACKGROUND, HIDE_RULING_BACKGROUND, FORCE_AT_LEAST_BACKGROUND_COLOR, - FORCE_VISIBLE}; -} // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/BackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/BackgroundView.cpp deleted file mode 100644 index 3d8ae00..0000000 --- a/entry/src/main/cpp/src/core/view/background/BackgroundView.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "BackgroundView.h" - -#include // for g_warning - -#include "model/PageType.h" // for PageType, PageTy... -#include "model/XojPage.h" // for XojPage -#include "view/background/OneColorBackgroundView.h" // for OneColorBackgrou... - -#include "DottedBackgroundView.h" // for DottedBackground... -#include "GraphBackgroundView.h" // for GraphBackgroundView -#include "ImageBackgroundView.h" // for ImageBackgroundView -#include "IsoDottedBackgroundView.h" // for IsoDottedBackgro... -#include "IsoGraphBackgroundView.h" // for IsoGraphBackgrou... -#include "LinedBackgroundView.h" // for LinedBackgroundView -#include "PdfBackgroundView.h" // for PdfBackgroundView -#include "PlainBackgroundView.h" // for PlainBackgroundView -#include "RuledBackgroundView.h" // for RuledBackgroundView -#include "StavesBackgroundView.h" // for StavesBackground... -#include "TransparentCheckerboardBackgroundView.h" // for TransparentCheck... - -using namespace xoj::view; - -auto BackgroundView::createRuled(double width, double height, Color backgroundColor, const PageType& pt, - double lineWidthFactor) -> std::unique_ptr { - std::unique_ptr res; - switch (pt.format) { - case PageTypeFormat::Plain: - return std::make_unique(width, height, backgroundColor); - case PageTypeFormat::Ruled: - res = std::make_unique(width, height, backgroundColor, pt.config); - break; - case PageTypeFormat::Lined: - res = std::make_unique(width, height, backgroundColor, pt.config); - break; - case PageTypeFormat::Graph: - res = std::make_unique(width, height, backgroundColor, pt.config); - break; - case PageTypeFormat::Staves: - res = std::make_unique(width, height, backgroundColor, pt.config); - break; - case PageTypeFormat::Dotted: - res = std::make_unique(width, height, backgroundColor, pt.config); - break; - case PageTypeFormat::IsoGraph: - res = std::make_unique(width, height, backgroundColor, pt.config); - break; - case PageTypeFormat::IsoDotted: - res = std::make_unique(width, height, backgroundColor, pt.config); - break; - default: - g_warning("BackgroundView::createForPage unknowntype: %d", static_cast(pt.format)); - return nullptr; - } - // In page template previews, the line width is multiplied to make the lines actually visible. - res->multiplyLineWidth(lineWidthFactor); - return res; -} - -auto BackgroundView::createForPage(ConstPageRef page, BackgroundFlags bgFlags, PdfCache* pdfCache) - -> std::unique_ptr { - const double width = page->getWidth(); - const double height = page->getHeight(); - if (!bgFlags.forceVisible && !page->isLayerVisible(0)) { - return std::make_unique(width, height); - } - - const auto pt = page->getBackgroundType(); - if (pt.isSpecial()) { - switch (pt.format) { - case PageTypeFormat::Image: - if (bgFlags.showImage) { - return std::make_unique(width, height, page->getBackgroundImage()); - } - break; - case PageTypeFormat::Pdf: - if (bgFlags.showPDF) { - return std::make_unique(width, height, page->getPdfPageNr(), pdfCache); - } - break; - default: - g_warning("BackgroundView::createForPage unknown type: %d\n", static_cast(pt.format)); - return nullptr; - } - } else { - if (bgFlags.showRuling) { - return createRuled(width, height, page->getBackgroundColor(), pt); - } - } - - if (bgFlags.forceBackgroundColor) { - return std::make_unique(width, height, page->getBackgroundColor()); - } else { - return std::make_unique(width, height); // Dummy no-op view - } -} diff --git a/entry/src/main/cpp/src/core/view/background/BackgroundView.h b/entry/src/main/cpp/src/core/view/background/BackgroundView.h deleted file mode 100644 index 58c796c..0000000 --- a/entry/src/main/cpp/src/core/view/background/BackgroundView.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Xournal++ - * - * Displays a background - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for unique_ptr - -#include // for cairo_t - -#include "model/PageRef.h" // for ConstPageRef -#include "util/Color.h" // for Color - -#include "BackgroundFlags.h" - -class PdfCache; -class PageType; - -namespace xoj { -namespace view { -class BackgroundView { -public: - BackgroundView(double pageWidth, double pageHeight): pageWidth(pageWidth), pageHeight(pageHeight) {} - virtual ~BackgroundView() = default; - - /** - * @brief Draws the background on the entire mask represented by the cairo context cr - * - * Does nothing in the base class - used when the background drawing is suppressed. - */ - virtual void draw(cairo_t* cr) const {} - - [[nodiscard]] static std::unique_ptr createRuled(double width, double height, Color backgroundColor, - const PageType& pt, double lineWidthFactor = 1.0); - - [[nodiscard]] static std::unique_ptr createForPage(ConstPageRef page, - xoj::view::BackgroundFlags bgFlags, - PdfCache* pdfCache = nullptr); - -protected: - double pageWidth; - double pageHeight; -}; -}; // namespace view -}; // namespace xoj diff --git a/entry/src/main/cpp/src/core/view/background/BaseIsometricBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/BaseIsometricBackgroundView.cpp deleted file mode 100644 index b363e2c..0000000 --- a/entry/src/main/cpp/src/core/view/background/BaseIsometricBackgroundView.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "BaseIsometricBackgroundView.h" - -#include // for floor, sqrt -#include // for allocator - -#include "model/BackgroundConfig.h" // for BackgroundConfig -#include "util/safe_casts.h" // for floor_cast -#include "view/background/BackgroundView.h" // for view -#include "view/background/OneColorBackgroundView.h" // for OneColorBackgrou... -#include "view/background/PlainBackgroundView.h" // for PlainBackgroundView - -using namespace background_config_strings; -using namespace xoj::view; - -BaseIsometricBackgroundView::BaseIsometricBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config, double defaultLineWidth): - OneColorBackgroundView(pageWidth, pageHeight, backgroundColor, config, defaultLineWidth, DEFAULT_LINE_COLOR, - ALT_DEFAULT_LINE_COLOR) { - - config.loadValue(CFG_RASTER, triangleSize); -} - -void BaseIsometricBackgroundView::draw(cairo_t* cr) const { - // Paint the background color - PlainBackgroundView::draw(cr); - - const double xstep = std::sqrt(3.0) / 2.0 * triangleSize; - const double ystep = triangleSize / 2.0; - - // Deduce the maximum grid size - const double margin = triangleSize; - int cols = floor_cast((pageWidth - 2 * margin) / xstep); - int rows = floor_cast((pageHeight - 2 * margin) / ystep); - - // Center the grid on the page - const double contentWidth = cols * xstep; - const double contentHeight = rows * ystep; - double contentXOffset = (pageWidth - contentWidth) / 2; - double contentYOffset = (pageHeight - contentHeight) / 2; - - // Get the bounds of the mask, in page coordinates - double minX; - double maxX; - double minY; - double maxY; - cairo_clip_extents(cr, &minX, &minY, &maxX, &maxY); - - // Get the indices we need to paint (= on or near the mask) - const double halfLineWidth = 0.5 * lineWidth; - auto [indexMinX, indexMaxX] = - getIndexBounds(minX - halfLineWidth - xstep - contentXOffset, maxX + halfLineWidth + xstep - contentXOffset, - xstep, 0.0, contentWidth); - auto [indexMinY, indexMaxY] = - getIndexBounds(minY - halfLineWidth - ystep - contentYOffset, maxY + halfLineWidth + ystep - contentYOffset, - ystep, 0.0, contentHeight); - - if ((indexMinY + indexMinX) % 2) { - /** The painted area should start with \/\/\/... - * /\/\/\/.. - * - * Enlarge by 1 so that it starts with /\/\/... - * \/\/\/.. - */ - if (indexMinX) { - --indexMinX; - } else { - --indexMinY; - } - } - - // Compute the offset and the number of steps within the mask - contentXOffset += indexMinX * xstep; - contentYOffset += indexMinY * ystep; - - cols = indexMaxX - indexMinX; - rows = indexMaxY - indexMinY; - - paintGrid(cr, cols, rows, xstep, ystep, contentXOffset, contentYOffset); - - cairo_save(cr); - Util::cairo_set_source_rgbi(cr, foregroundColor); - cairo_set_line_width(cr, lineWidth); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_stroke(cr); - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/background/BaseIsometricBackgroundView.h b/entry/src/main/cpp/src/core/view/background/BaseIsometricBackgroundView.h deleted file mode 100644 index 0ff3bcb..0000000 --- a/entry/src/main/cpp/src/core/view/background/BaseIsometricBackgroundView.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Xournal++ - * - * Base class for isometric backgrounds - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "util/Color.h" // for Color - -#include "OneColorBackgroundView.h" // for OneColorBackgroundView - -class BackgroundConfig; - -namespace xoj::view { -class BaseIsometricBackgroundView: public OneColorBackgroundView { -public: - BaseIsometricBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config, double defaultLineWidth); - virtual ~BaseIsometricBackgroundView() = default; - - virtual void draw(cairo_t* cr) const override; - -protected: - virtual void paintGrid(cairo_t* cr, int cols, int rows, double xstep, double ystep, double xOffset, - double yOffset) const = 0; - -protected: - double triangleSize = 14.17; // 5mm - - constexpr static Color DEFAULT_LINE_COLOR = Colors::xopp_silver; - constexpr static Color ALT_DEFAULT_LINE_COLOR = Colors::xopp_darkslategray; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/DottedBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/DottedBackgroundView.cpp deleted file mode 100644 index b2ed67e..0000000 --- a/entry/src/main/cpp/src/core/view/background/DottedBackgroundView.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "DottedBackgroundView.h" - -#include // for allocator - -#include "model/BackgroundConfig.h" // for BackgroundConfig -#include "view/background/BackgroundView.h" // for view -#include "view/background/OneColorBackgroundView.h" // for OneColorBackgrou... -#include "view/background/PlainBackgroundView.h" // for PlainBackgroundView - -using namespace background_config_strings; -using namespace xoj::view; - -DottedBackgroundView::DottedBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config): - OneColorBackgroundView(pageWidth, pageHeight, backgroundColor, config, DEFAULT_LINE_WIDTH, DEFAULT_LINE_COLOR, - ALT_DEFAULT_LINE_COLOR) { - - config.loadValue(CFG_RASTER, squareSize); -} - -void DottedBackgroundView::draw(cairo_t* cr) const { - // Paint the background color - PlainBackgroundView::draw(cr); - - // Get the bounds of the mask, in page coordinates - double minX; - double maxX; - double minY; - double maxY; - cairo_clip_extents(cr, &minX, &minY, &maxX, &maxY); - - const double halfLineWidth = 0.5 * lineWidth; - /* 1- Add a halfLineWidth padding in case the line is just outside the mask but its thickness still makes it - * (partially) visible - * 2- Set clearance so no dot is half-drawn on the edge of the sheet - */ - auto [indexMinX, indexMaxX] = - getIndexBounds(minX - halfLineWidth, maxX + halfLineWidth, squareSize, halfLineWidth, pageWidth); - auto [indexMinY, indexMaxY] = - getIndexBounds(minY - halfLineWidth, maxY + halfLineWidth, squareSize, halfLineWidth, pageHeight); - - for (int i = indexMinX; i <= indexMaxX; ++i) { - double x = i * squareSize; - for (int j = indexMinY; j <= indexMaxY; ++j) { - double y = j * squareSize; - cairo_move_to(cr, x, y); - cairo_line_to(cr, x, y); - } - } - - cairo_save(cr); - Util::cairo_set_source_rgbi(cr, foregroundColor); - cairo_set_line_width(cr, lineWidth); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_stroke(cr); - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/background/DottedBackgroundView.h b/entry/src/main/cpp/src/core/view/background/DottedBackgroundView.h deleted file mode 100644 index 42524e5..0000000 --- a/entry/src/main/cpp/src/core/view/background/DottedBackgroundView.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Xournal++ - * - * Class for graph backgrounds - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "util/Color.h" // for Color - -#include "OneColorBackgroundView.h" // for OneColorBackgroundView - -class BackgroundConfig; - -namespace xoj::view { -class DottedBackgroundView: public OneColorBackgroundView { -public: - DottedBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, const BackgroundConfig& config); - virtual ~DottedBackgroundView() = default; - - virtual void draw(cairo_t* cr) const override; - -protected: - double squareSize = 14.17; // 5mm - - constexpr static Color DEFAULT_LINE_COLOR = Colors::xopp_silver; - constexpr static Color ALT_DEFAULT_LINE_COLOR = Colors::xopp_darkslategray; - constexpr static double DEFAULT_LINE_WIDTH = 1.5; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/GraphBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/GraphBackgroundView.cpp deleted file mode 100644 index ca8ff90..0000000 --- a/entry/src/main/cpp/src/core/view/background/GraphBackgroundView.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "GraphBackgroundView.h" - -#include // for max, min -#include // for floor -#include // for allocator - -#include "model/BackgroundConfig.h" // for BackgroundConfig -#include "view/background/BackgroundView.h" // for view -#include "view/background/OneColorBackgroundView.h" // for OneColorBackgrou... -#include "view/background/PlainBackgroundView.h" // for PlainBackgroundView - -using namespace background_config_strings; -using namespace xoj::view; - -GraphBackgroundView::GraphBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config): - OneColorBackgroundView(pageWidth, pageHeight, backgroundColor, config, DEFAULT_LINE_WIDTH, DEFAULT_LINE_COLOR, - ALT_DEFAULT_LINE_COLOR) { - - config.loadValue(CFG_RASTER, squareSize); - config.loadValue(CFG_MARGIN, margin); - config.loadValue(CFG_BOLD_LINE_INTERVAL, boldLineInterval); - config.loadValue(CFG_BOLD_LINE_WIDTH, boldLineWidth); - - if (int roundToGrid = 0; margin > 0.0 && config.loadValue(CFG_ROUND_MARGIN, roundToGrid) && roundToGrid) { - roundUpMargin = true; - } -} - -void GraphBackgroundView::draw(cairo_t* cr) const { - // Paint the background color - PlainBackgroundView::draw(cr); - - // Get the bounds of the mask, in page coordinates - double minX; - double maxX; - double minY; - double maxY; - cairo_clip_extents(cr, &minX, &minY, &maxX, &maxY); - - if (margin > 0.0) { - minX = std::max(minX, margin); - maxX = std::min(maxX, pageWidth - margin); - minY = std::max(minY, margin); - maxY = std::min(maxY, pageHeight - margin); - } - - const double halfLineWidth = 0.5 * (boldLineInterval > 0 ? boldLineWidth : lineWidth); - const double clearance = std::max(margin, halfLineWidth); - /* 1- Add a halfLineWidth padding in case the line is just outside the mask but its thickness still makes it - * (partially) visible - * 2- Set clearance so no line is drawn in the margin or to close to the edge of the sheet - */ - auto [indexMinX, indexMaxX] = - getIndexBounds(minX - halfLineWidth, maxX + halfLineWidth, squareSize, clearance, pageWidth); - auto [indexMinY, indexMaxY] = - getIndexBounds(minY - halfLineWidth, maxY + halfLineWidth, squareSize, clearance, pageHeight); - - if (roundUpMargin) { - auto [pageIndexMinX, pageIndexMaxX] = getIndexBounds(margin - halfLineWidth, pageWidth - margin + halfLineWidth, - squareSize, clearance, pageWidth); - auto [pageIndexMinY, pageIndexMaxY] = getIndexBounds( - margin - halfLineWidth, pageHeight - margin + halfLineWidth, squareSize, clearance, pageHeight); - minX = std::max(minX, squareSize * pageIndexMinX); - maxX = std::min(maxX, squareSize * pageIndexMaxX); - minY = std::max(minY, squareSize * pageIndexMinY); - maxY = std::min(maxY, squareSize * pageIndexMaxY); - } - - cairo_save(cr); - Util::cairo_set_source_rgbi(cr, foregroundColor); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); - - if (boldLineInterval > 0) { - cairo_set_line_width(cr, lineWidth); - if (minY < maxY) { - for (int i = indexMinX; i <= indexMaxX; ++i) { - if (i % boldLineInterval != 0) { - double x = i * squareSize; - cairo_move_to(cr, x, minY); - cairo_line_to(cr, x, maxY); - } - } - } - if (minX < maxX) { - for (int i = indexMinY; i <= indexMaxY; ++i) { - if (i % boldLineInterval != 0) { - double y = i * squareSize; - cairo_move_to(cr, minX, y); - cairo_line_to(cr, maxX, y); - } - } - } - cairo_stroke(cr); - - cairo_set_line_width(cr, boldLineWidth); - if (minY < maxY) { - for (int i = indexMinX; i <= indexMaxX; ++i) { - if (i % boldLineInterval == 0) { - double x = i * squareSize; - cairo_move_to(cr, x, minY); - cairo_line_to(cr, x, maxY); - } - } - } - if (minX < maxX) { - for (int i = indexMinY; i <= indexMaxY; ++i) { - if (i % boldLineInterval == 0) { - double y = i * squareSize; - cairo_move_to(cr, minX, y); - cairo_line_to(cr, maxX, y); - } - } - } - cairo_stroke(cr); - } else { - cairo_set_line_width(cr, lineWidth); - if (minY < maxY) { - for (int i = indexMinX; i <= indexMaxX; ++i) { - double x = i * squareSize; - cairo_move_to(cr, x, minY); - cairo_line_to(cr, x, maxY); - } - } - if (minX < maxX) { - for (int i = indexMinY; i <= indexMaxY; ++i) { - double y = i * squareSize; - cairo_move_to(cr, minX, y); - cairo_line_to(cr, maxX, y); - } - } - cairo_stroke(cr); - } - - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/background/GraphBackgroundView.h b/entry/src/main/cpp/src/core/view/background/GraphBackgroundView.h deleted file mode 100644 index 434cc8b..0000000 --- a/entry/src/main/cpp/src/core/view/background/GraphBackgroundView.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * Class for graph backgrounds - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "util/Color.h" // for Color - -#include "OneColorBackgroundView.h" // for OneColorBackgroundView - -class BackgroundConfig; - -namespace xoj::view { -class GraphBackgroundView: public OneColorBackgroundView { -public: - GraphBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, const BackgroundConfig& config); - virtual ~GraphBackgroundView() = default; - - virtual void draw(cairo_t* cr) const override; - -protected: - bool roundUpMargin = false; - double margin = 0.0; - double squareSize = 14.17; // 5mm - int boldLineInterval = 0; // 0 means no bold lines, otherwise every Nth line is bold - double boldLineWidth = 1.5; - - constexpr static Color DEFAULT_LINE_COLOR = Colors::xopp_silver; - constexpr static Color ALT_DEFAULT_LINE_COLOR = Colors::xopp_darkslategray; - constexpr static double DEFAULT_LINE_WIDTH = 0.5; - constexpr static double DEFAULT_BOLD_LINE_WIDTH = 1.5; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/ImageBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/ImageBackgroundView.cpp deleted file mode 100644 index 8f37e0a..0000000 --- a/entry/src/main/cpp/src/core/view/background/ImageBackgroundView.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "ImageBackgroundView.h" - -#include // for gdk_pixbuf_get_height -#include // for gdk_cairo_set_source_pixbuf - -#include "model/BackgroundImage.h" // for BackgroundImage -#include "view/background/BackgroundView.h" // for BackgroundView, view - -using namespace xoj::view; - -ImageBackgroundView::ImageBackgroundView(double pageWidth, double pageHeight, const BackgroundImage& image): - BackgroundView(pageWidth, pageHeight), image(image) {} - -void ImageBackgroundView::draw(cairo_t* cr) const { - const GdkPixbuf* pixbuff = this->image.getPixbuf(); - if (pixbuff) { - cairo_matrix_t matrix = {0}; - cairo_get_matrix(cr, &matrix); - - int width = gdk_pixbuf_get_width(pixbuff); - int height = gdk_pixbuf_get_height(pixbuff); - - double sx = this->pageWidth / width; - double sy = this->pageHeight / height; - - cairo_scale(cr, sx, sy); - - gdk_cairo_set_source_pixbuf(cr, pixbuff, 0, 0); - cairo_paint(cr); - - cairo_set_matrix(cr, &matrix); - } -} diff --git a/entry/src/main/cpp/src/core/view/background/ImageBackgroundView.h b/entry/src/main/cpp/src/core/view/background/ImageBackgroundView.h deleted file mode 100644 index 95926b4..0000000 --- a/entry/src/main/cpp/src/core/view/background/ImageBackgroundView.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Xournal++ - * - * Displays a background image - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "BackgroundView.h" // for BackgroundView - -struct BackgroundImage; - -namespace xoj::view { -class ImageBackgroundView: public BackgroundView { -public: - ImageBackgroundView(double pageWidth, double pageHeight, const BackgroundImage& image); - - /** - * @brief Draws the background on the entire mask represented by the cairo context ctx.cr - */ - virtual void draw(cairo_t* cr) const override; - -private: - const BackgroundImage& image; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/IsoDottedBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/IsoDottedBackgroundView.cpp deleted file mode 100644 index af90c48..0000000 --- a/entry/src/main/cpp/src/core/view/background/IsoDottedBackgroundView.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "IsoDottedBackgroundView.h" - -#include "model/BackgroundConfig.h" // for BackgroundC... -#include "view/background/BackgroundView.h" // for view -#include "view/background/BaseIsometricBackgroundView.h" // for BaseIsometr... - -using namespace xoj::view; - -IsoDottedBackgroundView::IsoDottedBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config): - BaseIsometricBackgroundView(pageWidth, pageHeight, backgroundColor, config, DEFAULT_LINE_WIDTH) {} - - -void IsoDottedBackgroundView::paintGrid(cairo_t* cr, int cols, int rows, double xstep, double ystep, double xOffset, - double yOffset) const { - - auto drawDot = [&](double x, double y) { - cairo_move_to(cr, xOffset + x, yOffset + y); - cairo_line_to(cr, xOffset + x, yOffset + y); - }; - - for (int col = 0; col <= cols; ++col) { - const auto x = col * xstep; - - const auto evenCol = col % 2 == 0; - const auto yoffset = evenCol ? ystep : 0.0; - const auto rowsInCol = evenCol ? rows - 2 : rows; - - for (int row = 0; row <= rowsInCol; row += 2) { - const auto y = yoffset + row * ystep; - drawDot(x, y); - } - } -} diff --git a/entry/src/main/cpp/src/core/view/background/IsoDottedBackgroundView.h b/entry/src/main/cpp/src/core/view/background/IsoDottedBackgroundView.h deleted file mode 100644 index b2adfb2..0000000 --- a/entry/src/main/cpp/src/core/view/background/IsoDottedBackgroundView.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Xournal++ - * - * Class for isometric graph backgrounds - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "util/Color.h" // for Color - -#include "BaseIsometricBackgroundView.h" // for BaseIsometricBackgroundView - -class BackgroundConfig; - -namespace xoj::view { -class IsoDottedBackgroundView: public BaseIsometricBackgroundView { -public: - IsoDottedBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, const BackgroundConfig& config); - virtual ~IsoDottedBackgroundView() = default; - -protected: - virtual void paintGrid(cairo_t* cr, int cols, int rows, double xstep, double ystep, double xOffset, - double yOffset) const override; - -protected: - constexpr static double DEFAULT_LINE_WIDTH = 1.5; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/IsoGraphBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/IsoGraphBackgroundView.cpp deleted file mode 100644 index 7f417cc..0000000 --- a/entry/src/main/cpp/src/core/view/background/IsoGraphBackgroundView.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "IsoGraphBackgroundView.h" - -#include "model/BackgroundConfig.h" // for BackgroundC... -#include "util/safe_casts.h" // for floor_cast -#include "view/background/BackgroundView.h" // for view -#include "view/background/BaseIsometricBackgroundView.h" // for BaseIsometr... - -using namespace xoj::view; - -IsoGraphBackgroundView::IsoGraphBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config): - BaseIsometricBackgroundView(pageWidth, pageHeight, backgroundColor, config, DEFAULT_LINE_WIDTH) {} - - -void IsoGraphBackgroundView::paintGrid(cairo_t* cr, int cols, int rows, double xstep, double ystep, double xOffset, - double yOffset) const { - - auto drawLine = [&](double x1, double y1, double x2, double y2) { - cairo_move_to(cr, xOffset + x1, yOffset + y1); - cairo_line_to(cr, xOffset + x2, yOffset + y2); - }; - - const auto contentWidth = cols * xstep; - const auto contentHeight = rows * ystep; - - // Draw Horizontal line on top and bottom - // NB: if we're drawing only a portion of the page that does not touch the upper or lower edge, those lines are not - // at their rightful place. They are also out of the cairo mask's clip, so the following is a no-op. - drawLine(0.0, 0.0, contentWidth, 0.0); - drawLine(0.0, contentHeight, contentWidth, contentHeight); - - for (int col = 0; col <= cols; ++col) { - const auto x = col * xstep; - drawLine(x, 0.0, x, contentHeight); - } - - // Determine the number of diagonals to draw - auto hdiags = floor_cast(cols / 2); - auto vdiags = floor_cast(rows / 2); - auto diags = hdiags + vdiags; - auto hcorr = cols - 2 * hdiags; - auto vcorr = rows - 2 * vdiags; - - // Draw diagonals starting in the top left corner (left-down) - for (int d = 0; d < diags + hcorr * vcorr; ++d) { - // Point 1 travels horizontally from top left to top right, - // then from top right to bottom right. - double x1 = contentWidth, y1 = 0.0; - if (d < hdiags) { - x1 = xstep + d * 2 * xstep; - } else { - y1 = ystep + (d - hdiags) * 2 * ystep - hcorr * ystep; - } - - // Point 2 travels vertically from top left to bottom left, - // then from bottom left to bottom right. - double x2 = 0.0, y2 = contentHeight; - if (d < vdiags) { - y2 = ystep + d * 2 * ystep; - } else { - x2 = xstep + (d - vdiags) * 2 * xstep - vcorr * xstep; - } - - drawLine(x1, y1, x2, y2); - } - - // Draw diagonals starting in the top right corner (right-down) - for (int d = 0; d < diags; ++d) { - // Point 1 travels horizontally from top right to top left, - // then from top left to bottom left. - double x1 = 0.0, y1 = 0.0; - if (d < hdiags) { - x1 = contentWidth - (xstep + d * 2 * xstep) - hcorr * xstep; - } else { - y1 = ystep + (d - hdiags) * 2 * ystep; - } - - // Point 2 travels vertically from top right to bottom right, - // then from top bottom right to bottom left. - double x2 = contentWidth, y2 = contentHeight; - if (d < vdiags) { - y2 = ystep + d * 2 * ystep + hcorr * ystep; - } else { - x2 = contentWidth - (xstep + (d - vdiags) * 2 * xstep) + (vcorr - hcorr) * xstep; - } - - drawLine(x1, y1, x2, y2); - } -} diff --git a/entry/src/main/cpp/src/core/view/background/IsoGraphBackgroundView.h b/entry/src/main/cpp/src/core/view/background/IsoGraphBackgroundView.h deleted file mode 100644 index e2da042..0000000 --- a/entry/src/main/cpp/src/core/view/background/IsoGraphBackgroundView.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Xournal++ - * - * Class for isometric graph backgrounds - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "util/Color.h" // for Color - -#include "BaseIsometricBackgroundView.h" // for BaseIsometricBackgroundView - -class BackgroundConfig; - -namespace xoj::view { -class IsoGraphBackgroundView: public BaseIsometricBackgroundView { -public: - IsoGraphBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, const BackgroundConfig& config); - virtual ~IsoGraphBackgroundView() = default; - -protected: - virtual void paintGrid(cairo_t* cr, int cols, int rows, double xstep, double ystep, double xOffset, - double yOffset) const override; - -protected: - constexpr static double DEFAULT_LINE_WIDTH = 1.0; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/LinedBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/LinedBackgroundView.cpp deleted file mode 100644 index 90a4950..0000000 --- a/entry/src/main/cpp/src/core/view/background/LinedBackgroundView.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "LinedBackgroundView.h" - -#include // for allocator - -#include "model/BackgroundConfig.h" // for BackgroundConfig -#include "view/background/BackgroundView.h" // for view -#include "view/background/RuledBackgroundView.h" // for RuledBackgroundView - -using namespace background_config_strings; -using namespace xoj::view; - -LinedBackgroundView::LinedBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config): - RuledBackgroundView(pageWidth, pageHeight, backgroundColor, config) { - - if (backgroundColor.isLight()) { - vLineColor = getColorOr(config, CFG_FOREGROUND_COLOR_2, DEFAULT_V_LINE_COLOR); - } else { - vLineColor = getColorOr(config, CFG_ALT_FOREGROUND_COLOR_2, ALT_DEFAULT_V_LINE_COLOR); - } - - config.loadValue(CFG_MARGIN, margin); - if (margin < 0) { - // A negative value puts the margin line on the right hand side - margin += pageWidth; - } -} - -void LinedBackgroundView::draw(cairo_t* cr) const { - // Paint the horizontal lines - RuledBackgroundView::draw(cr); - - // Add the vertical line - cairo_save(cr); - Util::cairo_set_source_rgbi(cr, vLineColor); - cairo_set_line_width(cr, lineWidth); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); - cairo_move_to(cr, margin, 0); - cairo_line_to(cr, margin, pageHeight); - cairo_stroke(cr); - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/background/LinedBackgroundView.h b/entry/src/main/cpp/src/core/view/background/LinedBackgroundView.h deleted file mode 100644 index 66a940a..0000000 --- a/entry/src/main/cpp/src/core/view/background/LinedBackgroundView.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Xournal++ - * - * Class for lined backgrounds (= ruled + vertical margin line) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "model/BackgroundConfig.h" // for BackgroundConfig -#include "util/Color.h" // for Color - -#include "RuledBackgroundView.h" // for RuledBackgroundView - -namespace xoj::view { -class LinedBackgroundView: public RuledBackgroundView { -public: - LinedBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, const BackgroundConfig& config); - virtual ~LinedBackgroundView() = default; - - virtual void draw(cairo_t* cr) const override; - -protected: - Color vLineColor; - double margin = 72.0; // default = 1 inch. Negative values put the margin on the right hand side. - - constexpr static Color DEFAULT_V_LINE_COLOR = Colors::xopp_deeppink; - constexpr static Color ALT_DEFAULT_V_LINE_COLOR = Colors::xopp_midnightblue; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/OneColorBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/OneColorBackgroundView.cpp deleted file mode 100644 index c8d5fd2..0000000 --- a/entry/src/main/cpp/src/core/view/background/OneColorBackgroundView.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "OneColorBackgroundView.h" - -#include // for uint32_t - -#include "model/BackgroundConfig.h" // for BackgroundConfig -#include "view/background/BackgroundView.h" // for view -#include "view/background/PlainBackgroundView.h" // for PlainBackgroundView - -using namespace background_config_strings; -using namespace xoj::view; - -OneColorBackgroundView::OneColorBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config, double defaultLineWidth, - Color defaultLineColor, Color altDefaultLineColor): - PlainBackgroundView(pageWidth, pageHeight, backgroundColor), lineWidth(defaultLineWidth) { - - config.loadValue(CFG_LINE_WIDTH, lineWidth); - - if (backgroundColor.isLight()) { - foregroundColor = getColorOr(config, CFG_FOREGROUND_COLOR_1, defaultLineColor); - } else { - foregroundColor = getColorOr(config, CFG_ALT_FOREGROUND_COLOR_1, altDefaultLineColor); - } -} - -void xoj::view::OneColorBackgroundView::multiplyLineWidth(double factor) { lineWidth *= factor; } - -Color OneColorBackgroundView::getColorOr(const BackgroundConfig& config, const std::string& str, - const Color& defaultColor) { - if (uint32_t hexColor; config.loadValueHex(str, hexColor)) { - return Color(hexColor); - } - return defaultColor; -} diff --git a/entry/src/main/cpp/src/core/view/background/OneColorBackgroundView.h b/entry/src/main/cpp/src/core/view/background/OneColorBackgroundView.h deleted file mode 100644 index e4ab39b..0000000 --- a/entry/src/main/cpp/src/core/view/background/OneColorBackgroundView.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Xournal++ - * - * Class for backgrounds with lineWidth and a line color - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for string - -#include "util/Color.h" // for Color - -#include "PlainBackgroundView.h" // for PlainBackgroundView - -class BackgroundConfig; - -namespace xoj::view { -class OneColorBackgroundView: public PlainBackgroundView { -public: - OneColorBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, const BackgroundConfig& config, - double defaultLineWidth, Color defaultLineColor, Color altDefaultLineColor); - virtual ~OneColorBackgroundView() = default; - - void multiplyLineWidth(double factor); - -protected: - /** - * @brief Get the config's Hex value associated to the config string and make it a color. - * Fallback to defaultColor if the value does not exist in config. - */ - static Color getColorOr(const BackgroundConfig& config, const std::string& str, const Color& defaultColor); - -protected: - Color foregroundColor; - double lineWidth; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/PdfBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/PdfBackgroundView.cpp deleted file mode 100644 index 32c7403..0000000 --- a/entry/src/main/cpp/src/core/view/background/PdfBackgroundView.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "PdfBackgroundView.h" - -#include // for g_warning - -#include "control/PdfCache.h" // for PdfCache -#include "util/Assert.h" // for xoj_assert -#include "view/background/BackgroundView.h" // for BackgroundView, view - -using namespace xoj::view; - -PdfBackgroundView::PdfBackgroundView(double pageWidth, double pageHeight, size_t pageNo, PdfCache* pdfCache): - BackgroundView(pageWidth, pageHeight), pageNo(pageNo), pdfCache(pdfCache) {} - -void PdfBackgroundView::draw(cairo_t* cr) const { - if (pdfCache) { - // get zoom from cairo - cairo_matrix_t matrix = {0}; - cairo_get_matrix(cr, &matrix); - xoj_assert(matrix.xx == matrix.yy && matrix.xy == 0.0 && matrix.yx == 0.0); // Homothety matrix - double scaleX; - double scaleY; - cairo_surface_get_device_scale(cairo_get_target(cr), &scaleX, &scaleY); - xoj_assert(scaleX == scaleY); - double pixelsPerPageUnit = matrix.xx * scaleX; - pdfCache->render(cr, pageNo, pixelsPerPageUnit, pageWidth, pageHeight); - } else { - g_warning("PdfBackgroundView::draw Missing pdf cache: cannot render the pdf page"); - PdfCache::renderMissingPdfPage(cr, pageWidth, pageHeight); - } -} diff --git a/entry/src/main/cpp/src/core/view/background/PdfBackgroundView.h b/entry/src/main/cpp/src/core/view/background/PdfBackgroundView.h deleted file mode 100644 index 35a4a3a..0000000 --- a/entry/src/main/cpp/src/core/view/background/PdfBackgroundView.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Xournal++ - * - * Displays a pdf background - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for size_t - -#include // for cairo_t - -#include "BackgroundView.h" // for BackgroundView - -class PdfCache; - -namespace xoj { -namespace view { - -class PdfBackgroundView: public BackgroundView { -public: - PdfBackgroundView(double pageWidth, double pageHeight, size_t pageNo, PdfCache* pdfCache = nullptr); - virtual ~PdfBackgroundView() = default; - - /** - * @brief Draws the background on the entire mask represented by the cairo context cr - */ - void draw(cairo_t* cr) const override; - -private: - size_t pageNo; - PdfCache* pdfCache = nullptr; -}; - -}; // namespace view -}; // namespace xoj diff --git a/entry/src/main/cpp/src/core/view/background/PlainBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/PlainBackgroundView.cpp deleted file mode 100644 index bbc6a9e..0000000 --- a/entry/src/main/cpp/src/core/view/background/PlainBackgroundView.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "PlainBackgroundView.h" - -#include // for max, min - -#include "util/safe_casts.h" // for ceil_cast, floor_cast -#include "view/background/BackgroundView.h" // for BackgroundView, view - -using namespace xoj::view; - -PlainBackgroundView::PlainBackgroundView(double pageWidth, double pageHeight, Color backgroundColor): - BackgroundView(pageWidth, pageHeight), backgroundColor(backgroundColor) {} - -void PlainBackgroundView::draw(cairo_t* cr) const { - Util::cairo_set_source_rgbi(cr, this->backgroundColor); - cairo_paint(cr); -} - -std::pair PlainBackgroundView::getIndexBounds(double min, double max, double step, double margin, - double length) { - return {ceil_cast(std::max(min, margin) / step), floor_cast(std::min(max, length - margin) / step)}; -} diff --git a/entry/src/main/cpp/src/core/view/background/PlainBackgroundView.h b/entry/src/main/cpp/src/core/view/background/PlainBackgroundView.h deleted file mode 100644 index 8cf584b..0000000 --- a/entry/src/main/cpp/src/core/view/background/PlainBackgroundView.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Xournal++ - * - * Class for plain backgrounds - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for pair - -#include // for cairo_t - -#include "util/Color.h" // for Color - -#include "BackgroundView.h" // for BackgroundView - -namespace xoj::view { -class PlainBackgroundView: public BackgroundView { -public: - PlainBackgroundView(double pageWidth, double pageHeight, Color backgroundColor); - virtual ~PlainBackgroundView() = default; - - virtual void draw(cairo_t* cr) const override; - -protected: - Color backgroundColor; - - static std::pair getIndexBounds(double min, double max, double step, double margin, double length); -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/RuledBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/RuledBackgroundView.cpp deleted file mode 100644 index 2b87f04..0000000 --- a/entry/src/main/cpp/src/core/view/background/RuledBackgroundView.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "RuledBackgroundView.h" - -#include // for allocator - -#include "model/BackgroundConfig.h" // for BackgroundConfig -#include "view/background/BackgroundView.h" // for view -#include "view/background/OneColorBackgroundView.h" // for OneColorBackgrou... -#include "view/background/PlainBackgroundView.h" // for PlainBackgroundView - -using namespace background_config_strings; -using namespace xoj::view; - -RuledBackgroundView::RuledBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config): - OneColorBackgroundView(pageWidth, pageHeight, backgroundColor, config, DEFAULT_LINE_WIDTH, DEFAULT_H_LINE_COLOR, - ALT_DEFAULT_H_LINE_COLOR) { - config.loadValue(CFG_RASTER, lineSpacing); -} - -void RuledBackgroundView::draw(cairo_t* cr) const { - // Paint the background color - PlainBackgroundView::draw(cr); - - // Get the bounds of the mask, in page coordinates - double minX; - double maxX; - double minY; - double maxY; - cairo_clip_extents(cr, &minX, &minY, &maxX, &maxY); - - // Add a 0.5 * lineWidth padding in case the line is just outside the mask but its thickness still makes it - // (partially) visible - auto [indexMinY, indexMaxY] = - getIndexBounds(minY - HEADER_SIZE - 0.5 * lineWidth, maxY - HEADER_SIZE + 0.5 * lineWidth, lineSpacing, 0.0, - pageHeight - HEADER_SIZE - FOOTER_SIZE); - - for (int i = indexMinY; i <= indexMaxY; ++i) { - cairo_move_to(cr, minX, HEADER_SIZE + i * lineSpacing); - cairo_line_to(cr, maxX, HEADER_SIZE + i * lineSpacing); - } - - cairo_save(cr); - Util::cairo_set_source_rgbi(cr, foregroundColor); - cairo_set_line_width(cr, lineWidth); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); - cairo_stroke(cr); - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/background/RuledBackgroundView.h b/entry/src/main/cpp/src/core/view/background/RuledBackgroundView.h deleted file mode 100644 index 1b31934..0000000 --- a/entry/src/main/cpp/src/core/view/background/RuledBackgroundView.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Xournal++ - * - * Class for ruled backgrounds - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "util/Color.h" // for Color - -#include "OneColorBackgroundView.h" // for OneColorBackgroundView - -class BackgroundConfig; - -namespace xoj::view { -class RuledBackgroundView: public OneColorBackgroundView { -public: - RuledBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, const BackgroundConfig& config); - virtual ~RuledBackgroundView() = default; - - virtual void draw(cairo_t* cr) const override; - -protected: - double lineSpacing = 24.0; // Between two horizontal lines - - constexpr static Color DEFAULT_H_LINE_COLOR = Colors::xopp_dodgerblue; - constexpr static Color ALT_DEFAULT_H_LINE_COLOR = Colors::xopp_darkslategray; - constexpr static double DEFAULT_LINE_WIDTH = 0.5; - - constexpr static double HEADER_SIZE = 80.0; - constexpr static double FOOTER_SIZE = 60.0; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/StavesBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/StavesBackgroundView.cpp deleted file mode 100644 index 638f541..0000000 --- a/entry/src/main/cpp/src/core/view/background/StavesBackgroundView.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "StavesBackgroundView.h" - -#include "model/BackgroundConfig.h" // for BackgroundConfig -#include "view/background/BackgroundView.h" // for view -#include "view/background/OneColorBackgroundView.h" // for OneColorBackgrou... -#include "view/background/PlainBackgroundView.h" // for PlainBackgroundView - -using namespace background_config_strings; -using namespace xoj::view; - -StavesBackgroundView::StavesBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, - const BackgroundConfig& config): - OneColorBackgroundView(pageWidth, pageHeight, backgroundColor, config, DEFAULT_LINE_WIDTH, DEFAULT_LINE_COLOR, - ALT_DEFAULT_LINE_COLOR) {} - -void StavesBackgroundView::draw(cairo_t* cr) const { - // Paint the background color - PlainBackgroundView::draw(cr); - - // Get the bounds of the mask, in page coordinates - double minX; - double maxX; - double minY; - double maxY; - cairo_clip_extents(cr, &minX, &minY, &maxX, &maxY); - - const double staffHeight = lineWidth + 4 * LINES_SPACING; - - // The `+ 4 * lineWidth` is here as a legacy and it does not make a lot of sense. - // Still, we must keep it so that we do not alter how staves are displayed in pre-existing documents - const double vOffsetBetweenStaves = STAVES_SPACING + staffHeight + 4 * lineWidth; - - auto [indexMinY, indexMaxY] = getIndexBounds(minY - HEADER_SIZE - staffHeight, maxY + 0.5 * lineWidth - HEADER_SIZE, - vOffsetBetweenStaves, 0.0, pageHeight - HEADER_SIZE - FOOTER_SIZE); - - auto drawStaff = [cr, w = this->pageWidth](double offset) { - for (int i = 0; i < 5; ++i) { - double y = offset + i * LINES_SPACING; - cairo_move_to(cr, MARGIN, y); - cairo_line_to(cr, w - MARGIN, y); - } - cairo_line_to(cr, w - MARGIN, offset); - cairo_move_to(cr, MARGIN, offset); - cairo_line_to(cr, MARGIN, offset + 4 * LINES_SPACING); - }; - - for (int i = indexMinY; i <= indexMaxY; ++i) { drawStaff(HEADER_SIZE + i * vOffsetBetweenStaves); } - - cairo_save(cr); - Util::cairo_set_source_rgbi(cr, foregroundColor); - cairo_set_line_width(cr, lineWidth); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); - cairo_stroke(cr); - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/background/StavesBackgroundView.h b/entry/src/main/cpp/src/core/view/background/StavesBackgroundView.h deleted file mode 100644 index ecd98d9..0000000 --- a/entry/src/main/cpp/src/core/view/background/StavesBackgroundView.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Xournal++ - * - * Class for staves backgrounds - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_t - -#include "util/Color.h" // for Color - -#include "OneColorBackgroundView.h" // for OneColorBackgroundView - -class BackgroundConfig; - -namespace xoj::view { -class StavesBackgroundView: public OneColorBackgroundView { -public: - StavesBackgroundView(double pageWidth, double pageHeight, Color backgroundColor, const BackgroundConfig& config); - virtual ~StavesBackgroundView() = default; - - virtual void draw(cairo_t* cr) const override; - -protected: - constexpr static Color DEFAULT_LINE_COLOR = Colors::black; - constexpr static Color ALT_DEFAULT_LINE_COLOR = Colors::white; - constexpr static double DEFAULT_LINE_WIDTH = 0.5; - - constexpr static double HEADER_SIZE = 80.0; - constexpr static double FOOTER_SIZE = 60.0; - constexpr static double MARGIN = 50.0; - constexpr static double STAVES_SPACING = 40.0; // Between two staves - constexpr static double LINES_SPACING = 5.0; // Between two lines within a staff -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/background/TransparentCheckerboardBackgroundView.cpp b/entry/src/main/cpp/src/core/view/background/TransparentCheckerboardBackgroundView.cpp deleted file mode 100644 index 837a36a..0000000 --- a/entry/src/main/cpp/src/core/view/background/TransparentCheckerboardBackgroundView.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "TransparentCheckerboardBackgroundView.h" - -#include "view/background/BackgroundView.h" // for BackgroundView, view - -using namespace xoj::view; - -TransparentCheckerboardBackgroundView::TransparentCheckerboardBackgroundView(double pageWidth, double pageHeight): - BackgroundView(pageWidth, pageHeight), pattern(createPattern()) {} - -TransparentCheckerboardBackgroundView::~TransparentCheckerboardBackgroundView() noexcept { - cairo_pattern_destroy(pattern); -} - -auto TransparentCheckerboardBackgroundView::createPattern() -> cairo_pattern_t* { - cairo_surface_t* surf = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 2 * CHECKER_SIZE, 2 * CHECKER_SIZE); - cairo_t* cr = cairo_create(surf); - - Util::cairo_set_source_rgbi(cr, LIGHT_GREY); - cairo_paint(cr); - - Util::cairo_set_source_rgbi(cr, DARK_GREY); - cairo_rectangle(cr, CHECKER_SIZE, 0, CHECKER_SIZE, CHECKER_SIZE); - cairo_rectangle(cr, 0, CHECKER_SIZE, CHECKER_SIZE, CHECKER_SIZE); - cairo_fill(cr); - - cairo_destroy(cr); - - cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surf); - - cairo_surface_destroy(surf); // The surface is now owned by the pattern - - cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST); - cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - - return pattern; -} - -void TransparentCheckerboardBackgroundView::draw(cairo_t* cr) const { - cairo_save(cr); - cairo_set_source(cr, this->pattern); - cairo_paint(cr); - cairo_restore(cr); -} diff --git a/entry/src/main/cpp/src/core/view/background/TransparentCheckerboardBackgroundView.h b/entry/src/main/cpp/src/core/view/background/TransparentCheckerboardBackgroundView.h deleted file mode 100644 index 9fcbe2a..0000000 --- a/entry/src/main/cpp/src/core/view/background/TransparentCheckerboardBackgroundView.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Xournal++ - * - * Class for transparent backgrounds (checkerboard pattern) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include // for cairo_pattern_t, cairo_t - -#include "util/Color.h" // for Color - -#include "BackgroundView.h" // for BackgroundView - -namespace xoj::view { -class TransparentCheckerboardBackgroundView: public BackgroundView { -public: - TransparentCheckerboardBackgroundView(double pageWidth, double pageHeight); - virtual ~TransparentCheckerboardBackgroundView() noexcept; - - void draw(cairo_t* cr) const override; - -private: - cairo_pattern_t* pattern = nullptr; - -protected: - static cairo_pattern_t* createPattern(); - static constexpr int CHECKER_SIZE = 8; - static constexpr Color DARK_GREY{Colors::gray}; - static constexpr Color LIGHT_GREY{Colors::silver}; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/BaseShapeOrSplineToolView.cpp b/entry/src/main/cpp/src/core/view/overlays/BaseShapeOrSplineToolView.cpp deleted file mode 100644 index 1fab5a2..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/BaseShapeOrSplineToolView.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "BaseShapeOrSplineToolView.h" - -#include "control/tools/InputHandler.h" -#include "model/LineStyle.h" -#include "model/Stroke.h" -#include "util/Assert.h" -#include "util/Color.h" -#include "util/Util.h" // for cairo_set_dash_from_vector - -using namespace xoj::view; - -/** - * @brief To avoid rendering artefact (due to antialiasing?) we add a padding when clearing out the mask (for filled - * highlighter only) - */ -constexpr double MASK_CLEARANCE_PADDING = 1; - -static const Stroke& safeGetStroke(const InputHandler* h) { - xoj_assert(h); - xoj_assert(h->getStroke()); - return *h->getStroke(); -} - -static double getFillingAlpha(const InputHandler* h) { - auto f = safeGetStroke(h).getFill(); - return f == -1 ? 0.0 : f / 255.0; -} - -BaseShapeOrSplineToolView::BaseShapeOrSplineToolView(const InputHandler* toolHandler, Repaintable* parent): - BaseStrokeToolView(parent, safeGetStroke(toolHandler)), - fillingAlpha(getFillingAlpha(toolHandler)), - needMask(this->fillingAlpha != 0.0 && safeGetStroke(toolHandler).getToolType() == StrokeTool::HIGHLIGHTER) {} - -BaseShapeOrSplineToolView::~BaseShapeOrSplineToolView() noexcept = default; - -cairo_t* BaseShapeOrSplineToolView::prepareContext(cairo_t* cr) const { - cairo_set_operator(cr, this->cairoOp); - - if (needMask) { - // The mask is only for filled highlighter strokes, to avoid artefacts as in - // https://github.com/xournalpp/xournalpp/issues/3709 - if (!mask.isInitialized()) { - mask = createMask(cr); - const auto& dashes = this->lineStyle.getDashes(); - Util::cairo_set_dash_from_vector(mask.get(), dashes, 0); - cairo_set_line_width(mask.get(), this->strokeWidth); - // operator is already set by createMask(). - } else { - // Clear the mask - maskWipeExtent.addPadding(MASK_CLEARANCE_PADDING); - mask.wipeRange(maskWipeExtent); - maskWipeExtent = Range(); - } - return mask.get(); - } else { - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - cairo_set_line_width(cr, this->strokeWidth); - - const auto& dashes = this->lineStyle.getDashes(); - Util::cairo_set_dash_from_vector(cr, dashes, 0.0); - return cr; - } -} - -void BaseShapeOrSplineToolView::commitDrawing(cairo_t* cr) const { - if (fillingAlpha != 0.0) { - if (mask.isInitialized()) { - cairo_fill_preserve(mask.get()); - } else { - // Not need when using a mask: transparency will be applied upon blitting. - Util::cairo_set_source_rgbi(cr, strokeColor, fillingAlpha); - cairo_fill_preserve(cr); - } - } - - Util::cairo_set_source_argb(cr, this->strokeColor); - - if (mask.isInitialized()) { - cairo_stroke(mask.get()); - mask.blitTo(cr); - } else { - cairo_stroke(cr); - } -} diff --git a/entry/src/main/cpp/src/core/view/overlays/BaseShapeOrSplineToolView.h b/entry/src/main/cpp/src/core/view/overlays/BaseShapeOrSplineToolView.h deleted file mode 100644 index 325dc46..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/BaseShapeOrSplineToolView.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Xournal++ - * - * Base view for shapes or spline tools - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include - -#include "util/Range.h" -#include "view/Mask.h" - -#include "BaseStrokeToolView.h" - -class InputHandler; - -namespace xoj::view { -class Repaintable; - -class BaseShapeOrSplineToolView: public BaseStrokeToolView { - -public: - BaseShapeOrSplineToolView(const InputHandler* handler, Repaintable* parent); - ~BaseShapeOrSplineToolView() noexcept override; - -protected: - cairo_t* prepareContext(cairo_t* cr) const; - - void commitDrawing(cairo_t* cr) const; - - const double fillingAlpha; - - // The mask is only for filled highlighter strokes, to avoid artefacts as in - // https://github.com/xournalpp/xournalpp/issues/3709 - mutable Mask mask; - const bool needMask; - /// @brief The part of the mask that needs to be wiped to ensure the filling is correctly drawn. - mutable Range maskWipeExtent; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/BaseStrokeToolView.cpp b/entry/src/main/cpp/src/core/view/overlays/BaseStrokeToolView.cpp deleted file mode 100644 index d9bb529..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/BaseStrokeToolView.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "BaseStrokeToolView.h" - -#include - -#include - -#include "model/Stroke.h" -#include "util/Range.h" -#include "view/Mask.h" -#include "view/Repaintable.h" -#include "view/overlays/OverlayView.h" - -using namespace xoj::view; - -BaseStrokeToolView::BaseStrokeToolView(Repaintable* parent, const Stroke& stroke): - ToolView(parent), - cairoOp(stroke.getToolType() == StrokeTool::HIGHLIGHTER ? CAIRO_OPERATOR_MULTIPLY : CAIRO_OPERATOR_OVER), - strokeColor(strokeColorWithAlpha(stroke)), - lineStyle(stroke.getLineStyle()), - strokeWidth(stroke.getWidth()) {} - -BaseStrokeToolView::~BaseStrokeToolView() noexcept = default; - -Color BaseStrokeToolView::strokeColorWithAlpha(const Stroke& s) { - Color c = s.getColor(); - if (s.getToolType() == StrokeTool::HIGHLIGHTER) { - c.alpha = s.getFill() == -1 ? 120U : static_cast(s.getFill()); - } else { - c.alpha = 255U; - } - return c; -} - -auto BaseStrokeToolView::createMask(cairo_t* tgtcr) const -> Mask { - const double zoom = this->parent->getZoom(); - Range visibleRange = this->parent->getVisiblePart(); - - if (!visibleRange.isValid()) { - /* - * The user might be drawing on a page that is not visible at all: - * e.g. https://github.com/xournalpp/xournalpp/pull/4158#issuecomment-1385954494 - */ - return Mask(); - } - - // Add a small padding, to avoid visual artefacts if scrolling right after finishing a stroke touching the visible - // area's border - visibleRange.addPadding(0.5 * this->strokeWidth); - - Mask mask(cairo_get_target(tgtcr), visibleRange, zoom); - cairo_t* cr = mask.get(); - - cairo_set_source_rgba(cr, 1, 1, 1, 1); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); - return mask; -} diff --git a/entry/src/main/cpp/src/core/view/overlays/BaseStrokeToolView.h b/entry/src/main/cpp/src/core/view/overlays/BaseStrokeToolView.h deleted file mode 100644 index f763355..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/BaseStrokeToolView.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Xournal++ - * - * Virtual class for showing overlays (e.g. active tools, selections and so on) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -#include "model/LineStyle.h" -#include "util/Color.h" -#include "view/overlays/OverlayView.h" - -class Stroke; - -namespace xoj::view { -class Mask; -class Repaintable; - -class BaseStrokeToolView: public ToolView { -protected: - BaseStrokeToolView(Repaintable* parent, const Stroke& stroke); - ~BaseStrokeToolView() noexcept override; - - /** - * @brief Creates a mask corresponding to the parent's visible area. - * The mask is optimized (?) to be blitted to a surface of the same type as cairo_get_target(targetCr). - * If targetCr == nullptr, the surface is of CAIRO_SURFACE_TYPE_IMAGE. - */ - Mask createMask(cairo_t* targetCr) const; - - /** - * @brief Helper function to get a color whose alpha value depends on the tool's properties - */ - static Color strokeColorWithAlpha(const Stroke& s); - - /** - * @brief All that's required to draw a stroke in cairo - */ - const cairo_operator_t cairoOp; - const Color strokeColor; - const LineStyle lineStyle; - double strokeWidth; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/ImageSizeSelectionView.cpp b/entry/src/main/cpp/src/core/view/overlays/ImageSizeSelectionView.cpp deleted file mode 100644 index 7f5acc4..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/ImageSizeSelectionView.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "ImageSizeSelectionView.h" - -#include "control/tools/ImageSizeSelection.h" // for ImageSizeSelection -#include "util/Rectangle.h" // for Rectangle -#include "util/raii/CairoWrappers.h" // for cairo_save -#include "view/Repaintable.h" // for Repaintable - -using namespace xoj::view; - - -ImageSizeSelectionView::ImageSizeSelectionView(const ImageSizeSelection* imageSizeSelection, Repaintable* parent, - Color selectionColor): - OverlayView(parent), imageSizeSelection(imageSizeSelection), selectionColor(selectionColor) { - this->registerToPool(imageSizeSelection->getViewPool()); -} - -ImageSizeSelectionView::~ImageSizeSelectionView() noexcept = default; - - -void ImageSizeSelectionView::draw(cairo_t* cr) const { - const xoj::util::Rectangle space = this->imageSizeSelection->getSelectedSpace(); - - xoj::util::CairoSaveGuard const saveGuard(cr); // cairo_save - - cairo_set_line_width(cr, BORDER_WIDTH_IN_PIXELS / this->parent->getZoom()); - cairo_set_dash(cr, DASH_PATTERN.data(), DASH_PATTERN.size(), 0); - Util::cairo_set_source_rgbi(cr, selectionColor); - - cairo_new_path(cr); - - // these lines form the outline of the space rectangle - cairo_line_to(cr, space.x, space.y); - cairo_line_to(cr, space.x, space.y + space.height); - cairo_line_to(cr, space.x + space.width, space.y + space.height); - cairo_line_to(cr, space.x + space.width, space.y); - - - cairo_close_path(cr); - - cairo_stroke_preserve(cr); - Util::cairo_set_source_rgbi(cr, selectionColor, OPACITY_FOR_FILL); - cairo_fill(cr); -} - -auto ImageSizeSelectionView::isViewOf(const OverlayBase* overlay) const -> bool { - return overlay == this->imageSizeSelection; -} - -void ImageSizeSelectionView::on(ImageSizeSelectionView::FlagDirtyRegionRequest, Range rg) { - rg.addPadding(BORDER_WIDTH_IN_PIXELS / this->parent->getZoom()); - this->parent->flagDirtyRegion(rg); -} - -void ImageSizeSelectionView::deleteOn(ImageSizeSelectionView::FinalizationRequest, Range rg) { - rg.addPadding(BORDER_WIDTH_IN_PIXELS / this->parent->getZoom()); - this->parent->deleteOverlayView(this, rg); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/ImageSizeSelectionView.h b/entry/src/main/cpp/src/core/view/overlays/ImageSizeSelectionView.h deleted file mode 100644 index 0eb4969..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/ImageSizeSelectionView.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Xournal++ - * - * Displays a Rectangle to see while selecting space for an image - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include // for std::array - -#include "util/Color.h" // for Color -#include "util/DispatchPool.h" // for Listener - -#include "OverlayView.h" // for OverlayView - -class ImageSizeSelection; -class Range; - -namespace xoj::view { -class Repaintable; - -class ImageSizeSelectionView: public OverlayView, public xoj::util::Listener { -public: - ImageSizeSelectionView(const ImageSizeSelection* imageSizeSelection, Repaintable* parent, Color selectionColor); - virtual ~ImageSizeSelectionView() noexcept; - - /** - * @brief Draws the overlay to the given context - */ - void draw(cairo_t* cr) const override; - - auto isViewOf(const OverlayBase* overlay) const -> bool override; - - // Listener - static constexpr struct FlagDirtyRegionRequest { - } FLAG_DIRTY_REGION = {}; - void on(FlagDirtyRegionRequest, Range rg); - - static constexpr struct FinalizationRequest { - } FINALIZATION_REQUEST = {}; - void deleteOn(FinalizationRequest, Range rg); - -private: - const ImageSizeSelection* imageSizeSelection; - const Color selectionColor; - - static constexpr int BORDER_WIDTH_IN_PIXELS = 1; - static constexpr double OPACITY_FOR_FILL = 0.1; - static constexpr std::array DASH_PATTERN = {6.0, 4.0}; -}; - -}; // namespace xoj::view \ No newline at end of file diff --git a/entry/src/main/cpp/src/core/view/overlays/LaserPointerView.cpp b/entry/src/main/cpp/src/core/view/overlays/LaserPointerView.cpp deleted file mode 100644 index 517033e..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/LaserPointerView.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "LaserPointerView.h" - -#include "control/tools/LaserPointerHandler.h" -#include "control/tools/StrokeHandler.h" -#include "model/Stroke.h" -#include "util/Range.h" -#include "util/raii/CairoWrappers.h" -#include "view/Repaintable.h" -#include "view/View.h" - -#include "StrokeToolView.h" - -using namespace xoj::view; - -LaserPointerView::LaserPointerView(const LaserPointerHandler* handler, Repaintable* parent): - OverlayView(parent), handler(handler) { - this->registerToPool(handler->getViewPool()); -} - -LaserPointerView::~LaserPointerView() noexcept { this->unregisterFromPool(); } - -void LaserPointerView::draw(cairo_t* cr) const { - if (this->mask.isInitialized()) { - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - this->mask.paintToWithAlpha(cr, this->alpha); - } else { - this->mask = createMask(cr); - } - if (this->activeStrokeView) { - this->activeStrokeView->draw(cr); - } -} - -bool LaserPointerView::isViewOf(const OverlayBase* overlay) const { return overlay == this->handler; } - -void xoj::view::LaserPointerView::on(StartNewStrokeRequest, StrokeHandler* handler) { - this->activeStrokeView = std::make_unique(handler, *handler->getStroke(), parent); - if (!this->extents.empty()) { - on(SET_ALPHA_REQUEST, 255); - } -} - -void xoj::view::LaserPointerView::on(SetAlphaRequest, uint8_t alpha) { - this->alpha = alpha; - this->parent->flagDirtyRegion(this->extents); -} - -void xoj::view::LaserPointerView::on(FinishStrokeRequest, const Range& strokeBox) { - xoj_assert(this->activeStrokeView); - if (this->mask.isInitialized()) { - this->activeStrokeView->draw(this->mask.get()); - } - this->activeStrokeView.reset(); - this->extents = this->extents.unite(strokeBox); -} - -void xoj::view::LaserPointerView::on(InputCancellationRequest, const Range& rg) { - this->activeStrokeView.reset(); - this->parent->flagDirtyRegion(rg); -} - -void xoj::view::LaserPointerView::deleteOn(FinalizationRequest) { - this->parent->deleteOverlayView(this, this->extents); -} - - -auto xoj::view::LaserPointerView::createMask(cairo_t* tgtcr) const -> Mask { - const double zoom = this->parent->getZoom(); - Range visibleRange = this->parent->getVisiblePart(); - - if (!visibleRange.isValid()) { - /* - * The user might be drawing on a page that is not visible at all: - * e.g. https://github.com/xournalpp/xournalpp/pull/4158#issuecomment-1385954494 - */ - return Mask(); - } - - Mask mask(cairo_get_target(tgtcr), visibleRange, zoom, CAIRO_CONTENT_COLOR_ALPHA); - cairo_t* cr = mask.get(); - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - return mask; -} diff --git a/entry/src/main/cpp/src/core/view/overlays/LaserPointerView.h b/entry/src/main/cpp/src/core/view/overlays/LaserPointerView.h deleted file mode 100644 index 9068e4b..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/LaserPointerView.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Xournal++ - * - * View active Laser pointer strokes - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include - -#include - -#include "util/DispatchPool.h" -#include "util/Range.h" -#include "view/Mask.h" -#include "view/overlays/OverlayView.h" - -class OverlayBase; -class Settings; -class ZoomControl; -class LaserPointerHandler; -class StrokeHandler; - -namespace xoj::view { -class Repaintable; -class StrokeToolView; - -class LaserPointerView final: public OverlayView, public xoj::util::Listener { - -public: - LaserPointerView(const LaserPointerHandler* handler, Repaintable* parent); - ~LaserPointerView() noexcept override; - - /** - * @brief Draws the overlay to the given context - */ - void draw(cairo_t* cr) const override; - - bool isViewOf(const OverlayBase* overlay) const override; - - /** - * Listener interface - */ - static constexpr struct InputCancellationRequest { - } INPUT_CANCELLATION_REQUEST = {}; - void on(InputCancellationRequest, const Range& rg); - - static constexpr struct StartNewStrokeRequest { - } START_NEW_STROKE_REQUEST = {}; - void on(StartNewStrokeRequest, StrokeHandler* handler); - - static constexpr struct FinishStrokeRequest { - } FINISH_STROKE_REQUEST = {}; - /// Deletes the TemporaryStrokeView and all references to the handler's StrokeHandler - void on(FinishStrokeRequest, const Range& strokeBox); - - /// For fade out - static constexpr struct SetAlphaRequest { - } SET_ALPHA_REQUEST = {}; - void on(SetAlphaRequest, uint8_t alpha); - - static constexpr struct FinalizationRequest { - } FINALIZATION_REQUEST = {}; - void deleteOn(FinalizationRequest); - -private: - Mask createMask(cairo_t* tgtcr) const; - -private: - const LaserPointerHandler* handler; - - std::unique_ptr activeStrokeView; - - mutable Mask mask; - - uint8_t alpha = 255; ///< for fadeout - Range extents; ///< for fadeout repaints -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/OverlayView.h b/entry/src/main/cpp/src/core/view/overlays/OverlayView.h deleted file mode 100644 index 9fca660..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/OverlayView.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Xournal++ - * - * Virtual class for showing overlays (e.g. active tools, selections and so on) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ - -#pragma once - -#include - -class OverlayBase; - -namespace xoj::view { -class Repaintable; -class OverlayView { -public: - OverlayView(Repaintable* parent): parent(parent) {} - virtual ~OverlayView() = default; - - /** - * @brief Draws the overlay to the given context - */ - virtual void draw(cairo_t* cr) const = 0; - - virtual bool isViewOf(const OverlayBase* overlay) const = 0; - -protected: - Repaintable* parent; -}; - -class ToolView: public OverlayView { -public: - ToolView(Repaintable* parent): OverlayView(parent) {} - - /** - * @brief Draws without putative drawing aids (e.g. spline knots and tangents, text frame) - */ - virtual void drawWithoutDrawingAids(cairo_t* cr) const { this->draw(cr); } -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/PdfElementSelectionView.cpp b/entry/src/main/cpp/src/core/view/overlays/PdfElementSelectionView.cpp deleted file mode 100644 index 77c4e16..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/PdfElementSelectionView.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "PdfElementSelectionView.h" - -#include "control/tools/PdfElemSelection.h" -#include "util/raii/CairoWrappers.h" -#include "view/Repaintable.h" - -class Range; - -using namespace xoj::view; - -PdfElementSelectionView::PdfElementSelectionView(const PdfElemSelection* selection, Repaintable* parent, - Color selectionColor): - OverlayView(parent), selection(selection), selectionColor(selectionColor) { - this->registerToPool(selection->getViewPool()); -} - -PdfElementSelectionView::~PdfElementSelectionView() noexcept { this->unregisterFromPool(); } - -void PdfElementSelectionView::draw(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - - if (auto reg = selection->getSelectedRegion(); reg && !cairo_region_is_empty(reg)) { - gdk_cairo_region(cr, reg); - Util::cairo_set_source_rgbi(cr, selectionColor, SELECTION_OPACITY); - cairo_fill(cr); - } -} - -bool PdfElementSelectionView::isViewOf(const OverlayBase* overlay) const { return overlay == this->selection; } - -void PdfElementSelectionView::on(PdfElementSelectionView::FlagDirtyRegionRequest, const Range& rg) const { - this->parent->flagDirtyRegion(rg); -} - -void PdfElementSelectionView::deleteOn(PdfElementSelectionView::CancelSelectionRequest, const Range& rg) { - this->parent->deleteOverlayView(this, rg); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/PdfElementSelectionView.h b/entry/src/main/cpp/src/core/view/overlays/PdfElementSelectionView.h deleted file mode 100644 index 2837deb..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/PdfElementSelectionView.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Xournal++ - * - * View pdf selections - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include // for cairo_t - -#include "util/Color.h" -#include "util/DispatchPool.h" // for Listener -#include "view/overlays/OverlayView.h" - -class OverlayBase; -class PdfElemSelection; -class Range; - -namespace xoj::view { -class Repaintable; - -class PdfElementSelectionView final: public OverlayView, public xoj::util::Listener { - -public: - PdfElementSelectionView(const PdfElemSelection* selection, Repaintable* parent, Color selectionColor); - ~PdfElementSelectionView() noexcept override; - - /** - * @brief Draws the overlay to the given context - */ - void draw(cairo_t* cr) const override; - - bool isViewOf(const OverlayBase* overlay) const override; - - /** - * Listener interface - */ - static constexpr struct CancelSelectionRequest { - } CANCEL_SELECTION_REQUEST = {}; - void deleteOn(CancelSelectionRequest, const Range& rg); - static constexpr struct FlagDirtyRegionRequest { - } FLAG_DIRTY_REGION_REQUEST = {}; - void on(FlagDirtyRegionRequest, const Range& rg) const; - -private: - const PdfElemSelection* selection; - const Color selectionColor; - -public: - // Opacity of the background - static constexpr double SELECTION_OPACITY = 0.3; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/SearchResultView.cpp b/entry/src/main/cpp/src/core/view/overlays/SearchResultView.cpp deleted file mode 100644 index b98e0b2..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/SearchResultView.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "SearchResultView.h" - -#include "control/SearchControl.h" -#include "util/Range.h" -#include "util/raii/CairoWrappers.h" -#include "view/Repaintable.h" - -using namespace xoj::view; - -SearchResultView::SearchResultView(const SearchControl* searchControl, Repaintable* parent, Color frameColor, - Color frameHighlightColor): - OverlayView(parent), - searchControl(searchControl), - frameColor(frameColor), - frameHighlightColor(frameHighlightColor) { - this->registerToPool(searchControl->getViewPool()); -} - -SearchResultView::~SearchResultView() noexcept { this->unregisterFromPool(); } - -void SearchResultView::draw(cairo_t* cr) const { - const XojPdfRectangle* highlightRect = this->searchControl->getHighlightRect(); - xoj::util::CairoSaveGuard saveGuard(cr); - - cairo_set_line_width(cr, BORDER_WIDTH_IN_PIXELS / this->parent->getZoom()); - - for (const XojPdfRectangle& rect: this->searchControl->getResults()) { - cairo_rectangle(cr, rect.x1, rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1); - Color color = frameColor; - if (&rect == highlightRect) { - color = frameHighlightColor; - } - Util::cairo_set_source_rgbi(cr, color); - cairo_stroke_preserve(cr); - Util::cairo_set_source_rgbi(cr, color, BACKGROUND_OPACITY); - cairo_fill(cr); - } -} - -bool SearchResultView::isViewOf(const OverlayBase* overlay) const { return overlay == this->searchControl; } - -void SearchResultView::on(SearchResultView::SearchChangedNotification) { - Range rg = this->parent->getVisiblePart(); - if (!rg.empty()) { - this->parent->flagDirtyRegion(this->parent->getVisiblePart()); - } -} diff --git a/entry/src/main/cpp/src/core/view/overlays/SearchResultView.h b/entry/src/main/cpp/src/core/view/overlays/SearchResultView.h deleted file mode 100644 index a389437..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/SearchResultView.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Xournal++ - * - * View highlighting search results - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include // for cairo_t - -#include "util/Color.h" -#include "util/DispatchPool.h" // for Listener -#include "view/overlays/OverlayView.h" - -class OverlayBase; -class SearchControl; - -namespace xoj::view { -class Repaintable; - -class SearchResultView final: public OverlayView, public xoj::util::Listener { - -public: - SearchResultView(const SearchControl* searchControl, Repaintable* parent, Color frameColor, - Color frameHighlightColor); - ~SearchResultView() noexcept override; - - /** - * @brief Draws the overlay to the given context - */ - void draw(cairo_t* cr) const override; - - bool isViewOf(const OverlayBase* overlay) const override; - - /** - * Listener interface - */ - static constexpr struct SearchChangedNotification { - } SEARCH_CHANGED_NOTIFICATION = {}; - void on(SearchChangedNotification); - -private: - const SearchControl* searchControl; - const Color frameColor; - const Color frameHighlightColor; - -public: - // Width of the line delimiting moved elements - static constexpr int BORDER_WIDTH_IN_PIXELS = 1; - // Opacity of the background - static constexpr double BACKGROUND_OPACITY = 0.3; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/SelectorView.cpp b/entry/src/main/cpp/src/core/view/overlays/SelectorView.cpp deleted file mode 100644 index fa895bc..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/SelectorView.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "SelectorView.h" - -#include - -#include "control/tools/Selector.h" -#include "util/Color.h" -#include "util/LoopUtil.h" -#include "util/Range.h" -#include "util/raii/CairoWrappers.h" -#include "view/Repaintable.h" - -using namespace xoj::view; - -SelectorView::SelectorView(const Selector* selector, Repaintable* parent, Color selectorColor): - OverlayView(parent), selector(selector), selectorColor(selectorColor) { - this->registerToPool(selector->getViewPool()); -} - -SelectorView::~SelectorView() noexcept { this->unregisterFromPool(); } - -void SelectorView::draw(cairo_t* cr) const { - auto pts = this->selector->getBoundary(); - if (pts.size() < 3) { - // To few points to draw - return; - } - - xoj::util::CairoSaveGuard saveGuard(cr); // cairo_save - - // set the line always the same size on display - cairo_set_line_width(cr, BORDER_WIDTH_IN_PIXELS / this->parent->getZoom()); - - Util::cairo_set_source_rgbi(cr, selectorColor); - - cairo_new_path(cr); - for (auto& p: pts) { - cairo_line_to(cr, p.x, p.y); - } - cairo_close_path(cr); - - cairo_stroke_preserve(cr); - Util::cairo_set_source_rgbi(cr, selectorColor, FILLING_OPACITY); - cairo_fill(cr); -} - -bool SelectorView::isViewOf(const OverlayBase* overlay) const { return overlay == this->selector; } - -void SelectorView::on(SelectorView::FlagDirtyRegionRequest, Range rg) { - rg.addPadding(BORDER_WIDTH_IN_PIXELS / this->parent->getZoom()); - this->parent->flagDirtyRegion(rg); -} - -void xoj::view::SelectorView::deleteOn(xoj::view::SelectorView::DeleteViewsRequest, Range rg) { - rg.addPadding(BORDER_WIDTH_IN_PIXELS / this->parent->getZoom()); - this->parent->deleteOverlayView(this, rg); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/SelectorView.h b/entry/src/main/cpp/src/core/view/overlays/SelectorView.h deleted file mode 100644 index cab4028..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/SelectorView.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Xournal++ - * - * Displays the content of a selection - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include "util/Color.h" -#include "util/DispatchPool.h" - -#include "OverlayView.h" -#include "cairo.h" - -class Selector; -class Range; - -namespace xoj::view { -class Repaintable; - -class SelectorView: public OverlayView, public xoj::util::Listener { -public: - SelectorView(const Selector* selector, Repaintable* parent, Color selectorColor); - virtual ~SelectorView() noexcept; - - /** - * @brief Draws the container to the given context - */ - void draw(cairo_t* cr) const override; - bool isViewOf(const OverlayBase* overlay) const override; - - static constexpr struct FlagDirtyRegionRequest { - } FLAG_DIRTY_REGION = {}; - void on(FlagDirtyRegionRequest, Range rg); - - static constexpr struct DeleteViewsRequest { - } DELETE_VIEWS_REQUEST = {}; - void deleteOn(DeleteViewsRequest, Range rg); - -private: - const Selector* selector; - Color selectorColor; - - static constexpr double BORDER_WIDTH_IN_PIXELS = 1; - static constexpr double FILLING_OPACITY = 0.3; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/ShapeToolView.cpp b/entry/src/main/cpp/src/core/view/overlays/ShapeToolView.cpp deleted file mode 100644 index fadd809..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/ShapeToolView.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "ShapeToolView.h" - -#include - -#include "control/tools/BaseShapeHandler.h" -#include "util/raii/CairoWrappers.h" -#include "view/Repaintable.h" -#include "view/StrokeViewHelper.h" - -using namespace xoj::view; - -ShapeToolView::ShapeToolView(const BaseShapeHandler* toolHandler, Repaintable* parent): - BaseShapeOrSplineToolView(toolHandler, parent), toolHandler(toolHandler) { - this->registerToPool(toolHandler->getViewPool()); -} - -ShapeToolView::~ShapeToolView() noexcept { this->unregisterFromPool(); } - -void ShapeToolView::draw(cairo_t* cr) const { - const auto& pts = this->toolHandler->getShape(); - - if (pts.empty()) { - // The input sequence has been cancelled. This view should soon be deleted - return; - } - - xoj::util::CairoSaveGuard saveGuard(cr); // cairo_save - - cairo_t* effCr = this->prepareContext(cr); - - StrokeViewHelper::pathToCairo(effCr, pts); - - this->commitDrawing(cr); -} - -bool ShapeToolView::isViewOf(const OverlayBase* overlay) const { return overlay == this->toolHandler; } - -void ShapeToolView::on(ShapeToolView::FlagDirtyRegionRequest, const Range& rg) { - maskWipeExtent = maskWipeExtent.unite(rg); - this->parent->flagDirtyRegion(rg); -} - -void ShapeToolView::deleteOn(ShapeToolView::FinalizationRequest, const Range& rg) { - this->parent->drawAndDeleteToolView(this, rg); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/ShapeToolView.h b/entry/src/main/cpp/src/core/view/overlays/ShapeToolView.h deleted file mode 100644 index 0dfd781..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/ShapeToolView.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Xournal++ - * - * View active shape tools (rectangle, ellipse and so on) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include // for cairo_t - -#include "util/DispatchPool.h" // for Listener - -#include "BaseShapeOrSplineToolView.h" - -class BaseShapeHandler; -class OverlayBase; -class Range; - -namespace xoj::view { -class Repaintable; - -class ShapeToolView final: public BaseShapeOrSplineToolView, public xoj::util::Listener { - -public: - ShapeToolView(const BaseShapeHandler* handler, Repaintable* parent); - ~ShapeToolView() noexcept override; - - /** - * @brief Draws the overlay to the given context - */ - void draw(cairo_t* cr) const override; - - bool isViewOf(const OverlayBase* overlay) const override; - - /** - * Listener interface - */ - static constexpr struct FlagDirtyRegionRequest { - } FLAG_DIRTY_REGION = {}; - void on(FlagDirtyRegionRequest, const Range& rg); - - - static constexpr struct FinalizationRequest { - } FINALIZATION_REQUEST = {}; - /** - * @brief Called before the corresponding BaseShapeHandler's destruction - * @param rg The bounding box of the entire stroke - */ - void deleteOn(FinalizationRequest, const Range& rg); - -private: - const BaseShapeHandler* toolHandler; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/SplineToolView.cpp b/entry/src/main/cpp/src/core/view/overlays/SplineToolView.cpp deleted file mode 100644 index 92fe2a1..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/SplineToolView.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "SplineToolView.h" - -#include // for for_each -#include -#include -#include -#include - -#include "control/tools/SplineHandler.h" -#include "control/zoom/ZoomControl.h" -#include "model/Point.h" -#include "model/SplineSegment.h" -#include "util/Assert.h" -#include "util/raii/CairoWrappers.h" -#include "view/Repaintable.h" - -class OverlayBase; - -using namespace xoj::view; - -SplineToolView::SplineToolView(const SplineHandler* splineHandler, Repaintable* parent): - BaseShapeOrSplineToolView(splineHandler, parent), splineHandler(splineHandler) { - this->registerToPool(splineHandler->getViewPool()); - this->parent->getZoomControl()->addZoomListener(this); -} - -SplineToolView::~SplineToolView() noexcept { - this->unregisterFromPool(); - this->parent->getZoomControl()->removeZoomListener(this); -} - -void SplineToolView::draw(cairo_t* cr) const { - auto data = this->splineHandler->getData(); - if (!data) { - return; - } - xoj_assert(!data->knots.empty() && data->knots.size() == data->tangents.size()); - - const double lineWidth = LINE_WIDTH_WITHOUT_ZOOM / this->parent->getZoom(); - - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_set_line_width(cr, lineWidth); - - const Point& firstKnot = data->knots.front(); - const Point& lastKnot = data->knots.back(); - const Point& firstTangent = data->tangents.front(); - const Point& lastTangent = data->tangents.back(); - - auto drawCircle = [cr, radius = data->knotsAttractionRadius](const Point& center) { - cairo_new_sub_path(cr); - cairo_arc(cr, center.x, center.y, radius, 0, 2 * M_PI); - }; - - // draw circles around knot points - Util::cairo_set_source_argb(cr, NODE_CIRCLE_COLOR); - std::for_each(std::next(data->knots.begin()), data->knots.end(), drawCircle); - cairo_stroke(cr); - - Util::cairo_set_source_argb(cr, FIRST_NODE_CIRCLE_COLOR); - drawCircle(firstKnot); - if (data->closedSpline) { // current point lies within the circle around the first knot - cairo_fill_preserve(cr); - } - cairo_stroke(cr); - - // draw dynamically changing segment - Util::cairo_set_source_argb(cr, DYNAMIC_OBJECTS_COLOR); - const Point& cp1 = Point(lastKnot.x + lastTangent.x, lastKnot.y + lastTangent.y); - const Point& cp2 = - data->closedSpline ? Point(firstKnot.x - firstTangent.x, firstKnot.y - firstTangent.y) : data->currPoint; - const Point& otherKnot = data->closedSpline ? firstKnot : data->currPoint; - SplineSegment(lastKnot, cp1, cp2, otherKnot).draw(cr); - cairo_stroke(cr); - - - Util::cairo_set_source_argb(cr, TANGENT_VECTOR_COLOR); - // draw dynamically changing tangent vector - cairo_move_to(cr, lastKnot.x - lastTangent.x, lastKnot.y - lastTangent.y); - cairo_line_to(cr, lastKnot.x + lastTangent.x, lastKnot.y + lastTangent.y); - - // draw other tangent vectors - for (size_t i = 0; i < data->knots.size() - 1; i++) { - cairo_move_to(cr, data->knots[i].x - data->tangents[i].x, data->knots[i].y - data->tangents[i].y); - cairo_line_to(cr, data->knots[i].x + data->tangents[i].x, data->knots[i].y + data->tangents[i].y); - } - cairo_stroke(cr); - - this->drawSpline(cr, data.value()); -} - -void SplineToolView::drawWithoutDrawingAids(cairo_t* cr) const { - auto data = this->splineHandler->getData(); - if (!data) { - return; - } - xoj_assert(!data->knots.empty() && data->knots.size() == data->tangents.size()); - - xoj::util::CairoSaveGuard saveGuard(cr); - this->drawSpline(cr, data.value()); -} - -void SplineToolView::drawSpline(cairo_t* cr, const SplineHandlerData& data) const { - if (data.knots.size() > 1) { - cairo_t* effCr = this->prepareContext(cr); - - const Point& firstKnot = data.knots.front(); - cairo_move_to(effCr, firstKnot.x, firstKnot.y); - - auto itKnot1 = data.knots.begin(); - auto itKnot2 = std::next(itKnot1); - auto itTgt1 = data.tangents.begin(); - auto itTgt2 = std::next(itTgt1); - for (; itKnot2 != data.knots.end(); ++itKnot1, ++itKnot2, ++itTgt1, ++itTgt2) { - cairo_curve_to(effCr, itKnot1->x + itTgt1->x, itKnot1->y + itTgt1->y, itKnot2->x - itTgt2->x, - itKnot2->y - itTgt2->y, itKnot2->x, itKnot2->y); - } - - this->commitDrawing(cr); - } -} - -bool SplineToolView::isViewOf(const OverlayBase* overlay) const { return overlay == this->splineHandler; } - -void SplineToolView::zoomChanged() { this->mask.reset(); } - -void SplineToolView::on(FlagDirtyRegionRequest, Range rg) { - maskWipeExtent = maskWipeExtent.unite(rg); - rg.addPadding(LINE_WIDTH_WITHOUT_ZOOM / (2.0 * this->parent->getZoom())); - this->parent->flagDirtyRegion(rg); -} - -void SplineToolView::deleteOn(SplineToolView::FinalizationRequest, Range rg) { - rg.addPadding(LINE_WIDTH_WITHOUT_ZOOM / (2.0 * this->parent->getZoom())); - this->parent->drawAndDeleteToolView(this, rg); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/SplineToolView.h b/entry/src/main/cpp/src/core/view/overlays/SplineToolView.h deleted file mode 100644 index 7625353..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/SplineToolView.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Xournal++ - * - * View active spline tool - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include - -#include "control/zoom/ZoomListener.h" -#include "util/Color.h" -#include "util/DispatchPool.h" - -#include "BaseShapeOrSplineToolView.h" - -class SplineHandler; -struct SplineHandlerData; -class OverlayBase; -class Range; -class ZoomControl; - -namespace xoj::view { -class Repaintable; - -class SplineToolView: - public BaseShapeOrSplineToolView, - public ZoomListener, - public xoj::util::Listener { - -public: - SplineToolView(const SplineHandler* splineHandler, Repaintable* parent); - virtual ~SplineToolView() noexcept; - - /** - * @brief Draws the overlay to the given context - */ - void draw(cairo_t* cr) const override; - void drawWithoutDrawingAids(cairo_t* cr) const override; - - bool isViewOf(const OverlayBase* overlay) const override; - - /** - * Zoom interface - */ - void zoomChanged() override; - - /** - * Listener interface - */ - static constexpr struct FlagDirtyRegionRequest { - } FLAG_DIRTY_REGION = {}; - void on(FlagDirtyRegionRequest, Range rg); - - /** - * @brief Called before the corresponding SplineHandler's destruction - * @param rg The bounding box of the entire spline + drawing aids, to be repainted - */ - static constexpr struct FinalizationRequest { - } FINALIZATION_REQUEST = {}; - void deleteOn(FinalizationRequest, Range rg); - -private: - void drawSpline(cairo_t* cr, const SplineHandlerData& data) const; - - const SplineHandler* splineHandler; - -public: - static constexpr double LINE_WIDTH_WITHOUT_ZOOM = 2.0; // for tangent vectors & dynamic spline seg. - static constexpr Color NODE_CIRCLE_COLOR = Colors::gray; - static constexpr Color FIRST_NODE_CIRCLE_COLOR = Colors::red; - static constexpr Color TANGENT_VECTOR_COLOR = Colors::lawngreen; - static constexpr Color DYNAMIC_OBJECTS_COLOR = Colors::gray; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledHighlighterView.cpp b/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledHighlighterView.cpp deleted file mode 100644 index 64acbc5..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledHighlighterView.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "StrokeToolFilledHighlighterView.h" - -#include - -#include "model/Point.h" -#include "util/Color.h" -#include "util/Range.h" -#include "util/raii/CairoWrappers.h" -#include "view/StrokeViewHelper.h" - -using namespace xoj::view; - -StrokeToolFilledHighlighterView::StrokeToolFilledHighlighterView(const StrokeHandler* strokeHandler, - const Stroke& stroke, Repaintable* parent): - StrokeToolFilledView(strokeHandler, stroke, parent) {} - -StrokeToolFilledHighlighterView::~StrokeToolFilledHighlighterView() noexcept = default; - -void StrokeToolFilledHighlighterView::draw(cairo_t* cr) const { - - std::vector pts = this->flushBuffer(); - if (pts.empty()) { - // The input sequence has probably been cancelled. This view should soon be deleted - return; - } - - this->filling.appendSegments(pts); - - if (!this->mask.isInitialized()) { - // Initialize mask on first call - this->mask = this->createMask(cr); - if (!mask.isInitialized()) { - /* - * The user might be drawing on a page that is not visible at all: - * e.g. https://github.com/xournalpp/xournalpp/pull/4158#issuecomment-1385954494 - */ - return; - } - } - - if (this->singleDot) { - this->drawDot(this->mask.get(), pts.back()); - } else { - /* - * Upon adding a segment, the filling can actually shrink. - * We wipe the portion of the mask that can change: the convex hull of the added points + the first point - */ - Range wipe(filling.firstPoint.x, filling.firstPoint.y); - - for (auto& p: pts) { - wipe.addPoint(p.x, p.y); - } - - if (wipe.isValid()) { - this->mask.wipeRange(wipe); - } - - - /* - * Draw both the filling and the stroke alike on the mask - */ - cairo_set_line_width(this->mask.get(), this->strokeWidth); - StrokeViewHelper::pathToCairo(this->mask.get(), this->filling.contour); - cairo_fill_preserve(this->mask.get()); - cairo_stroke(this->mask.get()); - } - - xoj::util::CairoSaveGuard saveGuard(cr); - Util::cairo_set_source_argb(cr, this->strokeColor); - cairo_set_operator(cr, this->cairoOp); - - this->mask.blitTo(cr); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledHighlighterView.h b/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledHighlighterView.h deleted file mode 100644 index 34aacf6..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledHighlighterView.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Xournal++ - * - * View active stroke tool -- for filled highlighter only - * In this case, the mask needs to be wiped at every iteration, and repainted to avoid artefacts like in - * https://github.com/xournalpp/xournalpp/issues/3709 - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include "StrokeToolFilledView.h" - -namespace xoj::view { -class StrokeToolFilledHighlighterView: public StrokeToolFilledView { -public: - StrokeToolFilledHighlighterView(const StrokeHandler* strokeHandler, const Stroke& stroke, Repaintable* parent); - virtual ~StrokeToolFilledHighlighterView() noexcept; - - void draw(cairo_t* cr) const override; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledView.cpp b/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledView.cpp deleted file mode 100644 index 175232b..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledView.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "StrokeToolFilledView.h" - -#include - -#include "model/Stroke.h" -#include "util/Assert.h" -#include "util/Color.h" -#include "util/Range.h" -#include "view/Repaintable.h" -#include "view/StrokeViewHelper.h" - -using namespace xoj::view; - -static const Point& setupFirstPoint(const Stroke& s) { - const auto& pts = s.getPointVector(); - xoj_assert(!pts.empty()); - return pts.front(); -} - -StrokeToolFilledView::StrokeToolFilledView(const StrokeHandler* strokeHandler, const Stroke& stroke, - Repaintable* parent): - StrokeToolView(strokeHandler, stroke, parent), filling(stroke.getFill() / 255.0, setupFirstPoint(stroke)) {} - -StrokeToolFilledView::~StrokeToolFilledView() noexcept = default; - -void StrokeToolFilledView::drawFilling(cairo_t* cr, const std::vector& pts) const { - this->filling.appendSegments(pts); - /* - * Draw the filling directly (not through the mask) - * Upon adding a segment, the filling can actually shrink, making it easier to redraw the filling every time. - */ - StrokeViewHelper::pathToCairo(cr, this->filling.contour); - Util::cairo_set_source_rgbi(cr, strokeColor, this->filling.alpha); - cairo_fill(cr); -} - -void StrokeToolFilledView::on(StrokeToolView::AddPointRequest, const Point& p) { - this->singleDot = false; - xoj_assert(!this->pointBuffer.empty()); - Point lastPoint = this->pointBuffer.back(); - this->pointBuffer.emplace_back(p); - auto rg = this->getRepaintRange(lastPoint, p); - // Add the first point, so that the range covers all the filling changes - rg.addPoint(this->filling.firstPoint.x, this->filling.firstPoint.y); - this->parent->flagDirtyRegion(rg); -} - -void StrokeToolFilledView::on(StrokeToolView::StrokeReplacementRequest, const Stroke& newStroke) { - StrokeToolView::on(STROKE_REPLACEMENT_REQUEST, newStroke); - this->filling.contour = this->pointBuffer; - if (!this->pointBuffer.empty()) { - const Point& fp = this->pointBuffer.front(); - this->filling.firstPoint = xoj::util::Point(fp.x, fp.y); - } -} - -void StrokeToolFilledView::FillingData::appendSegments(const std::vector& pts) { - xoj_assert(!pts.empty()); - // Add new points to the contour - // contour.back() == pts.front(), so we skip it. - std::copy(std::next(pts.begin()), pts.end(), std::back_inserter(contour)); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledView.h b/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledView.h deleted file mode 100644 index 2359106..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/StrokeToolFilledView.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Xournal++ - * - * View active stroke tool -- filled strokes, but not filled highlighter. - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include - -#include - -#include "model/Point.h" -#include "util/Point.h" - -#include "StrokeToolView.h" - -namespace xoj::view { -class StrokeToolFilledHighlighterView; - -/** - * @brief View active stroke tool -- with a filling - * - * In draw, the filling is painted directly, while the stroke itself is blitted from the mask - */ -class StrokeToolFilledView: public StrokeToolView { -public: - StrokeToolFilledView(const StrokeHandler* strokeHandler, const Stroke& stroke, Repaintable* parent); - virtual ~StrokeToolFilledView() noexcept; - - void drawFilling(cairo_t* cr, const std::vector& pts) const override; - - void on(AddPointRequest, const Point& p) override; - void on(StrokeReplacementRequest, const Stroke& newStroke) override; - -protected: - class FillingData { - public: - FillingData(double alpha, const Point& p): alpha(alpha), firstPoint(p.x, p.y), contour{p} {} - - const double alpha; - xoj::util::Point firstPoint; // Store a copy for safe concurrent access - - - void appendSegments(const std::vector& pts); - - /** - * @brief Filling contour (i.e. the stroke's entire path) - */ - std::vector contour; - }; - - mutable FillingData filling; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/StrokeToolView.cpp b/entry/src/main/cpp/src/core/view/overlays/StrokeToolView.cpp deleted file mode 100644 index d96fac5..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/StrokeToolView.cpp +++ /dev/null @@ -1,147 +0,0 @@ -#include "StrokeToolView.h" - -#include -#include -#include - -#include "control/tools/StrokeHandler.h" -#include "model/LineStyle.h" -#include "model/Stroke.h" -#include "util/Assert.h" -#include "util/Color.h" -#include "util/PairView.h" -#include "util/Range.h" -#include "util/raii/CairoWrappers.h" // for CairoSaveGuard -#include "view/Repaintable.h" -#include "view/StrokeViewHelper.h" - -using namespace xoj::view; - -StrokeToolView::StrokeToolView(const StrokeHandler* strokeHandler, const Stroke& stroke, Repaintable* parent): - BaseStrokeToolView(parent, stroke), strokeHandler(strokeHandler), pointBuffer(stroke.getPointVector()) { - this->registerToPool(strokeHandler->getViewPool()); - parent->flagDirtyRegion(Range(stroke.boundingRect())); -} - -StrokeToolView::~StrokeToolView() noexcept { this->unregisterFromPool(); } - -bool StrokeToolView::isViewOf(const OverlayBase* overlay) const { return overlay == this->strokeHandler; } - -void StrokeToolView::draw(cairo_t* cr) const { - - std::vector pts = this->flushBuffer(); - if (pts.empty()) { - // The input sequence has probably been cancelled. This view should soon be deleted - return; - } - // pts.front() is the last point we painted on the mask during the last iteration (see flushBuffer()) - - if (!mask.isInitialized()) { - // Initialize the mask on first call - mask = createMask(cr); - if (!mask.isInitialized()) { - /* - * The user might be drawing on a page that is not visible at all: - * e.g. https://github.com/xournalpp/xournalpp/pull/4158#issuecomment-1385954494 - */ - return; - } - } - - xoj::util::CairoSaveGuard saveGuard(cr); - cairo_set_operator(cr, this->cairoOp); - - this->drawFilling(cr, pts); // Noop in the base class. - - Util::cairo_set_source_argb(cr, strokeColor); - - if (pts.size() > 1) { - // Draw the new segments on the mask - if (pts.front().z == Point::NO_PRESSURE) { - StrokeViewHelper::drawNoPressure(this->mask.get(), pts, this->strokeWidth, this->lineStyle, - this->dashOffset); - if (this->lineStyle.hasDashes()) { - // Keep the offset up to date, so we do not have to redraw the entire stroke every time. - PairView segments(pts); - this->dashOffset = - std::transform_reduce(segments.begin(), segments.end(), this->dashOffset, std::plus<>(), - [](auto& seg) { return seg.front().lineLengthTo(seg.back()); }); - } - } else { - this->dashOffset = - StrokeViewHelper::drawWithPressure(this->mask.get(), pts, this->lineStyle, this->dashOffset); - } - } else if (this->singleDot) { - this->drawDot(this->mask.get(), pts.back()); - } - - this->mask.blitTo(cr); -} - -void StrokeToolView::on(StrokeToolView::AddPointRequest, const Point& p) { - this->singleDot = false; - xoj_assert(!this->pointBuffer.empty()); // front() is the last point we painted on the mask (see flushBuffer()) - Point lastPoint = this->pointBuffer.back(); - this->pointBuffer.emplace_back(p); - this->parent->flagDirtyRegion(this->getRepaintRange(lastPoint, p)); -} - -void StrokeToolView::on(StrokeToolView::ThickenFirstPointRequest, double newWidth) { - xoj_assert(newWidth > 0.0); - xoj_assert(this->pointBuffer.size() == 1); - Point& p = this->pointBuffer.back(); - xoj_assert(p.z <= newWidth); // Thicken means thicken - p.z = newWidth; - Range rg = Range(p.x, p.y); - rg.addPadding(0.5 * newWidth); - this->parent->flagDirtyRegion(rg); -} - -void StrokeToolView::deleteOn(StrokeToolView::CancellationRequest, const Range& rg) { - this->pointBuffer.clear(); - this->parent->drawAndDeleteToolView(this, rg); -} - -void StrokeToolView::on(StrokeToolView::StrokeReplacementRequest, const Stroke& newStroke) { - if (this->mask.isInitialized()) { - // only wipe mask it actually exists (the view has already been drawn at least once) - this->mask.wipe(); - } - this->pointBuffer = newStroke.getPointVector(); - this->dashOffset = 0; - this->strokeWidth = newStroke.getWidth(); - xoj_assert(this->strokeColor == strokeColorWithAlpha(newStroke)); - xoj_assert(this->lineStyle == newStroke.getLineStyle()); - xoj_assert(this->cairoOp == - (newStroke.getToolType() == StrokeTool::HIGHLIGHTER ? CAIRO_OPERATOR_MULTIPLY : CAIRO_OPERATOR_OVER)); -} - -void StrokeToolView::deleteOn(StrokeToolView::FinalizationRequest, const Range& rg) { - this->parent->drawAndDeleteToolView(this, rg); -} - -auto StrokeToolView::getRepaintRange(const Point& lastPoint, const Point& addedPoint) const -> Range { - const double width = lastPoint.z == Point::NO_PRESSURE ? this->strokeWidth : lastPoint.z; - Range rg(lastPoint.x, lastPoint.y); - rg.addPoint(addedPoint.x, addedPoint.y); - rg.addPadding(0.5 * width); - return rg; -} - -void StrokeToolView::drawDot(cairo_t* cr, const Point& p) const { - cairo_set_line_width(cr, p.z == Point::NO_PRESSURE ? this->strokeWidth : p.z); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_move_to(cr, p.x, p.y); - cairo_line_to(cr, p.x, p.y); - cairo_stroke(cr); -} - -std::vector StrokeToolView::flushBuffer() const { - std::vector pts; - std::swap(this->pointBuffer, pts); - if (!pts.empty()) { - // Keep the last point in the buffer - to be used in the next iteration - this->pointBuffer.emplace_back(pts.back()); - } - return pts; -} diff --git a/entry/src/main/cpp/src/core/view/overlays/StrokeToolView.h b/entry/src/main/cpp/src/core/view/overlays/StrokeToolView.h deleted file mode 100644 index 4ee7831..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/StrokeToolView.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Xournal++ - * - * View active stroke tool - abstract base class - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include - -#include - -#include "util/DispatchPool.h" -#include "view/Mask.h" - -#include "BaseStrokeToolView.h" - -class StrokeHandler; -class Point; -class Range; -class Stroke; -class OverlayBase; - -namespace xoj::view { -class Repaintable; - -class StrokeToolView: public BaseStrokeToolView, public xoj::util::Listener { -public: - StrokeToolView(const StrokeHandler* strokeHandler, const Stroke& stroke, Repaintable* parent); - virtual ~StrokeToolView() noexcept; - - bool isViewOf(const OverlayBase* overlay) const override; - - void draw(cairo_t* cr) const override; - - /** - * Listener interface - */ - static constexpr struct AddPointRequest { - } ADD_POINT_REQUEST = {}; - virtual void on(AddPointRequest, const Point& p); - - static constexpr struct ThickenFirstPointRequest { - } THICKEN_FIRST_POINT_REQUEST = {}; - void on(ThickenFirstPointRequest, double newPressure); - - static constexpr struct StrokeReplacementRequest { - } STROKE_REPLACEMENT_REQUEST = {}; - virtual void on(StrokeReplacementRequest, const Stroke& newStroke); - - static constexpr struct CancellationRequest { - } CANCELLATION_REQUEST = {}; - void deleteOn(CancellationRequest, const Range& rg); - - /** - * @brief Called before the corresponding StrokeHandler's destruction - */ - static constexpr struct FinalizationRequest { - } FINALIZATION_REQUEST = {}; - void deleteOn(FinalizationRequest, const Range& rg); - -protected: - /** - * @brief Compute the bounding box of the given segment, taking stroke width into account. - */ - auto getRepaintRange(const Point& lastPoint, const Point& addedPoint) const -> Range; - - void drawDot(cairo_t* cr, const Point& p) const; - - /** - * @brief (Thread-safe) Flush the communication buffer and returns its content. - */ - std::vector flushBuffer() const; - - // Nothing in the base class - virtual void drawFilling(cairo_t*, const std::vector&) const {} - -protected: - const StrokeHandler* strokeHandler; - -protected: - bool singleDot = true; - - /** - * @brief offset for drawing dashes (if any) - * In effect, this stores the length of the path already drawn to the mask. - */ - mutable double dashOffset = 0; - - /** - * @brief Controller/View communication buffer - * Those are in the same thread. Add mutex protection if this changes - */ - mutable std::vector pointBuffer; // Todo: implement a lock-free fifo? - - /** - * @brief Drawing mask. - * - * The stroke is drawn to the mask and the mask is then blitted wherever needed. - * Upon calls to draw(), the buffer is flushed and the corresponding part of stroke is added to the mask. - */ - mutable Mask mask; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/TextEditionView.cpp b/entry/src/main/cpp/src/core/view/overlays/TextEditionView.cpp deleted file mode 100644 index 9c3868c..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/TextEditionView.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "TextEditionView.h" - -#include "control/tools/TextEditor.h" -#include "model/Text.h" -#include "util/Color.h" -#include "util/raii/CairoWrappers.h" -#include "view/Repaintable.h" - -using namespace xoj::view; - -TextEditionView::TextEditionView(const TextEditor* textEditor, Repaintable* parent): - ToolView(parent), textEditor(textEditor) { - this->registerToPool(textEditor->getViewPool()); - this->on(FLAG_DIRTY_REGION, textEditor->getContentBoundingBox()); -} - -TextEditionView::~TextEditionView() noexcept { this->unregisterFromPool(); } - -void TextEditionView::draw(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - - // Draw the frame - double zoom = parent->getZoom(); - cairo_set_line_width(cr, BORDER_WIDTH_IN_PIXELS / zoom); - Util::cairo_set_source_argb(cr, this->textEditor->getSelectionColor()); - Range frame = textEditor->getContentBoundingBox(); - frame.addPadding(PADDING_IN_PIXELS / zoom); - cairo_rectangle(cr, frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight()); - cairo_stroke(cr); - - // Draw the text itself - this->drawWithoutDrawingAids(cr); - - // Draw the cursor - if (this->textEditor->isCursorVisible()) { - auto cursorBox = this->textEditor->getCursorBox(); - if (cursorBox.getWidth() == 0.0) { - const double shift = 0.5 * INSERTION_CURSOR_WIDTH_IN_PIXELS / zoom; - cursorBox.minX -= shift; - cursorBox.maxX += shift; - } - cairo_set_operator(cr, CAIRO_OPERATOR_DIFFERENCE); - cairo_set_source_rgb(cr, 1, 1, 1); - const Text* textElement = this->textEditor->getTextElement(); - cairo_rectangle(cr, cursorBox.minX + textElement->getX(), cursorBox.minY + textElement->getY(), - cursorBox.getWidth(), cursorBox.getHeight()); - cairo_fill(cr); - } -} - -void TextEditionView::drawWithoutDrawingAids(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - - const Text* textElement = this->textEditor->getTextElement(); - Util::cairo_set_source_rgbi(cr, textElement->getColor()); - - // From now on, coordinates are in textElement coordinates - cairo_translate(cr, textElement->getX(), textElement->getY()); - - // The data is owned by textEditor - PangoLayout* layout = this->textEditor->getUpToDateLayout(); - - // The cairo context might have changed. Update the pango layout - pango_cairo_update_layout(cr, layout); - - pango_context_set_matrix(pango_layout_get_context(layout), nullptr); - - pango_cairo_show_layout(cr, layout); -} - -bool TextEditionView::isViewOf(const OverlayBase* overlay) const { return overlay == this->textEditor; } - -auto TextEditionView::toWindowCoordinates(const xoj::util::Rectangle& r) const -> xoj::util::Rectangle { - auto* textElement = this->textEditor->getTextElement(); - return parent->toWindowCoordinates(r.translated(textElement->getX(), textElement->getY())); -} - -void TextEditionView::on(TextEditionView::FlagDirtyRegionRequest, Range rg) { - const double padding = std::max(BORDER_WIDTH_IN_PIXELS + PADDING_IN_PIXELS, INSERTION_CURSOR_WIDTH_IN_PIXELS) / - this->parent->getZoom(); - rg.addPadding(padding); - this->parent->flagDirtyRegion(rg); -} - -void TextEditionView::deleteOn(TextEditionView::FinalizationRequest, Range rg) { - const double padding = std::max(BORDER_WIDTH_IN_PIXELS + PADDING_IN_PIXELS, INSERTION_CURSOR_WIDTH_IN_PIXELS) / - this->parent->getZoom(); - rg.addPadding(padding); - this->parent->drawAndDeleteToolView(this, rg); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/TextEditionView.h b/entry/src/main/cpp/src/core/view/overlays/TextEditionView.h deleted file mode 100644 index 52bf13b..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/TextEditionView.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Xournal++ - * - * View active text edition - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include // for cairo_t - -#include "util/DispatchPool.h" // for Listener -#include "view/overlays/OverlayView.h" - -class OverlayBase; -class TextEditor; -class Range; - -namespace xoj::util { -template -class Rectangle; -}; - -namespace xoj::view { -class Repaintable; - -class TextEditionView final: public ToolView, public xoj::util::Listener { - -public: - TextEditionView(const TextEditor* handler, Repaintable* parent); - ~TextEditionView() noexcept override; - - /** - * @brief Draws the overlay to the given context - */ - void draw(cairo_t* cr) const override; - void drawWithoutDrawingAids(cairo_t* cr) const override; - - bool isViewOf(const OverlayBase* overlay) const override; - - xoj::util::Rectangle toWindowCoordinates(const xoj::util::Rectangle& r) const; - - /** - * Listener interface - */ - static constexpr struct FlagDirtyRegionRequest { - } FLAG_DIRTY_REGION = {}; - void on(FlagDirtyRegionRequest, Range rg); - - static constexpr struct FinalizationRequest { - } FINALIZATION_REQUEST = {}; - void deleteOn(FinalizationRequest, Range rg); - -private: - const TextEditor* textEditor; - -public: - // Padding between the text logical box and the frame - static constexpr int PADDING_IN_PIXELS = 5; - // Width of the lines making the frame - static constexpr int BORDER_WIDTH_IN_PIXELS = 1; - // Width of the cursor in insertion mode (or at the end of a line) - static constexpr int INSERTION_CURSOR_WIDTH_IN_PIXELS = 2; -}; -}; // namespace xoj::view diff --git a/entry/src/main/cpp/src/core/view/overlays/VerticalToolView.cpp b/entry/src/main/cpp/src/core/view/overlays/VerticalToolView.cpp deleted file mode 100644 index 9ad1d86..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/VerticalToolView.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include "VerticalToolView.h" - -#include "control/settings/Settings.h" -#include "control/zoom/ZoomControl.h" -#include "util/raii/CairoWrappers.h" -#include "view/ElementContainerView.h" -#include "view/Repaintable.h" -#include "view/View.h" - -using namespace xoj::view; - -VerticalToolView::VerticalToolView(const VerticalToolHandler* handler, Repaintable* parent, ZoomControl* zoomControl, - const Settings* settings): - ToolView(parent), toolHandler(handler), zoomControl(zoomControl), aidColor(settings->getSelectionColor()) { - this->registerToPool(handler->getViewPool()); - zoomControl->addZoomListener(this); -} - -VerticalToolView::~VerticalToolView() noexcept { - zoomControl->removeZoomListener(this); - this->unregisterFromPool(); -} - -void VerticalToolView::draw(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - - const double startY = toolHandler->getStartY(); - const double endY = toolHandler->getEndY(); - - cairo_rectangle(cr, 0, startY, toolHandler->getPageWidth(), endY - startY); - - cairo_set_line_width(cr, BORDER_WIDTH_IN_PIXELS / this->parent->getZoom()); - Util::cairo_set_source_rgbi(cr, this->aidColor); - cairo_stroke_preserve(cr); - - Util::cairo_set_source_rgbi(cr, this->aidColor, BACKGROUND_OPACITY); - cairo_fill(cr); - - this->drawWithoutDrawingAids(cr); -} - -void VerticalToolView::drawWithoutDrawingAids(cairo_t* cr) const { - xoj::util::CairoSaveGuard saveGuard(cr); - - if (!mask.isInitialized()) { - // Initialize the mask on first call, when changing sides or upon zoom change - mask = createMask(cr); - xoj::view::ElementContainerView v(this->toolHandler); - v.draw(xoj::view::Context::createDefault(mask.get())); - } - - cairo_translate(cr, 0, toolHandler->getEndY() - toolHandler->getStartY()); - - mask.paintTo(cr); -} - -bool VerticalToolView::isViewOf(const OverlayBase* overlay) const { return overlay == this->toolHandler; } - -void VerticalToolView::on(VerticalToolView::SetVerticalShiftRequest, double shift) { - Range rg = this->parent->getVisiblePart(); - auto side = this->toolHandler->getSide(); - - // Padding for taking into account the drawing aid line width - const double padding = 0.5 * BORDER_WIDTH_IN_PIXELS / this->parent->getZoom(); - if (side == VerticalToolHandler::Side::Above) { - rg.maxY = std::clamp(std::max(shift, this->lastShift) + padding, rg.minY, rg.maxY); - } else { - rg.minY = std::clamp(std::min(shift, this->lastShift) - padding, rg.minY, rg.maxY); - } - this->parent->flagDirtyRegion(rg); - this->lastShift = shift; -} - -void VerticalToolView::on(VerticalToolView::SwitchDirectionRequest) { - mask.reset(); - this->parent->flagDirtyRegion(this->parent->getVisiblePart()); -} - -void VerticalToolView::deleteOn(VerticalToolView::FinalizationRequest) { - double startY = toolHandler->getStartY(); - double endY = toolHandler->getEndY(); - auto [minY, maxY] = std::minmax(startY, endY); - - // Padding for taking into account the drawing aid line width - const double padding = 0.5 * BORDER_WIDTH_IN_PIXELS / this->parent->getZoom(); - - // Get a range containing exactly the drawing aid blue rectangle - Range rg(std::numeric_limits::lowest(), minY - padding, std::numeric_limits::max(), maxY + padding); - rg = rg.intersect(this->parent->getVisiblePart()); - - this->parent->drawAndDeleteToolView(this, rg); -} - -Mask VerticalToolView::createMask(cairo_t* tgtcr) const { - auto side = toolHandler->getSide(); - auto startY = toolHandler->getStartY(); - /* - * Create a mask that - * * starts at startY if side == Side::Below - * * ends at startY if side == Side::Above - * * has height and width those of the visible area - * This mask is as small as possible, and still allows the user to see all elements go up or down, as long as the - * cursor remains in the affected page. - * TODO find a way to have the mask big enough for all situations: - * * If the previous page is partially visible, the mask is to short - * * If the cursor goes into the toolbar, the mask is to short - * * If several views are implemented, the mask size should depend on the possible cursor positions - * within the acted upon view, not the current view - * (the entire page is not an option for infinite pages...) - */ - const double zoom = this->parent->getZoom(); - Range range = this->parent->getVisiblePart(); - - if (side == VerticalToolHandler::Side::Above) { - range.translate(0, startY - range.maxY); - } else { - range.translate(0, startY - range.minY); - } - - return Mask(cairo_get_target(tgtcr), range, zoom, CAIRO_CONTENT_COLOR_ALPHA); -} - -void VerticalToolView::zoomChanged() { - // If zooming in, the mask needs redrawing to get a suitable definition - // If zooming out, the mask needs redrawing to cover a bigger part of the page - mask.reset(); -} diff --git a/entry/src/main/cpp/src/core/view/overlays/VerticalToolView.h b/entry/src/main/cpp/src/core/view/overlays/VerticalToolView.h deleted file mode 100644 index fccb986..0000000 --- a/entry/src/main/cpp/src/core/view/overlays/VerticalToolView.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Xournal++ - * - * View active VerticalTool (move elements up and down) - * - * @author Xournal++ Team - * https://github.com/xournalpp/xournalpp - * - * @license GNU GPLv2 or later - */ -#pragma once - -#include // for cairo_t - -#include "control/tools/VerticalToolHandler.h" // for Side -#include "control/zoom/ZoomListener.h" -#include "util/Color.h" -#include "util/DispatchPool.h" // for Listener -#include "view/Mask.h" -#include "view/overlays/OverlayView.h" - -class OverlayBase; -class Range; -class Settings; -class ZoomControl; - -namespace xoj::view { -class Repaintable; - -class VerticalToolView final: public ToolView, public ZoomListener, public xoj::util::Listener { - -public: - VerticalToolView(const VerticalToolHandler* handler, Repaintable* parent, ZoomControl* zoomControl, - const Settings* settings); - ~VerticalToolView() noexcept override; - - /** - * @brief Draws the overlay to the given context - */ - void draw(cairo_t* cr) const override; - void drawWithoutDrawingAids(cairo_t* cr) const override; - - bool isViewOf(const OverlayBase* overlay) const override; - - /** - * Zoom interface - */ - void zoomChanged() override; - - /** - * Listener interface - */ - static constexpr struct SetVerticalShiftRequest { - } SET_VERTICAL_SHIFT_REQUEST = {}; - void on(SetVerticalShiftRequest, double shift); - - static constexpr struct SwitchDirectionRequest { - } SWITCH_DIRECTION_REQUEST = {}; - void on(SwitchDirectionRequest); - - static constexpr struct FinalizationRequest { - } FINALIZATION_REQUEST = {}; - void deleteOn(FinalizationRequest); - -private: - Mask createMask(cairo_t* tgtcr) const; - -private: - const VerticalToolHandler* toolHandler; - ZoomControl* zoomControl; - double lastShift = 0.0; - const Color aidColor; - - mutable Mask mask; - -public: - // Width of the line delimiting moved elements - static constexpr int BORDER_WIDTH_IN_PIXELS = 1; - // Opacity of the background - static constexpr double BACKGROUND_OPACITY = 0.3; -}; -}; // namespace xoj::view