diff --git a/share/icons/Dash/symbolic/actions/object-recolor-art-symbolic.svg b/share/icons/Dash/symbolic/actions/object-recolor-art-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..b078cf421c5c1beec4852445a720247bf9c2827c --- /dev/null +++ b/share/icons/Dash/symbolic/actions/object-recolor-art-symbolic.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/share/icons/Dash/symbolic/actions/reset-colors-symbolic.svg b/share/icons/Dash/symbolic/actions/reset-colors-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..7d47572893ed89f875798b4b0e353615b756fc70 --- /dev/null +++ b/share/icons/Dash/symbolic/actions/reset-colors-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/share/icons/Dash/symbolic/actions/reset-symbolic.svg b/share/icons/Dash/symbolic/actions/reset-symbolic.svg deleted file mode 100644 index 09c40a1e3021e4ad13a7d5a0086ef0a972d948e6..0000000000000000000000000000000000000000 --- a/share/icons/Dash/symbolic/actions/reset-symbolic.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/share/icons/hicolor/symbolic/actions/reset-colors-symbolic.svg b/share/icons/hicolor/symbolic/actions/reset-colors-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..7d47572893ed89f875798b4b0e353615b756fc70 --- /dev/null +++ b/share/icons/hicolor/symbolic/actions/reset-colors-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/share/icons/hicolor/symbolic/actions/reset-symbolic.svg b/share/icons/hicolor/symbolic/actions/reset-symbolic.svg deleted file mode 100644 index 7dcef2b3f70fffc0d4e14bd1fdd4381979bf9177..0000000000000000000000000000000000000000 --- a/share/icons/hicolor/symbolic/actions/reset-symbolic.svg +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - diff --git a/share/icons/multicolor/symbolic/actions/object-recolor-art-symbolic.svg b/share/icons/multicolor/symbolic/actions/object-recolor-art-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..b078cf421c5c1beec4852445a720247bf9c2827c --- /dev/null +++ b/share/icons/multicolor/symbolic/actions/object-recolor-art-symbolic.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/share/icons/multicolor/symbolic/actions/reset-colors-symbolic.svg b/share/icons/multicolor/symbolic/actions/reset-colors-symbolic.svg new file mode 100644 index 0000000000000000000000000000000000000000..7d47572893ed89f875798b4b0e353615b756fc70 --- /dev/null +++ b/share/icons/multicolor/symbolic/actions/reset-colors-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/share/icons/multicolor/symbolic/actions/reset-symbolic.svg b/share/icons/multicolor/symbolic/actions/reset-symbolic.svg deleted file mode 100644 index 7dcef2b3f70fffc0d4e14bd1fdd4381979bf9177..0000000000000000000000000000000000000000 --- a/share/icons/multicolor/symbolic/actions/reset-symbolic.svg +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - - diff --git a/share/ui/recolor-art.glade b/share/ui/recolor-art.glade new file mode 100644 index 0000000000000000000000000000000000000000..d1488022ed8302538aa164968871c2dcc6fb9896 --- /dev/null +++ b/share/ui/recolor-art.glade @@ -0,0 +1,181 @@ + + + + + recolor-art + vertical + true + true + + + list-wheel-box + top + false + + + original-recolor-colors-list-box + vertical + true + true + + + original-reset-recolor + horizontal + center + center + 85 + + + Original + fill + + + + + reset + true + false + false + center + 18 + + + reset-settings + normal + + + + + + + New + center + + + + + + + true + true + true + centre + never + false + + + colors-list + vertical + true + fill + fill + + + false + fill + true + fill + 250 + + + + + + + + + + + horizontal + 6 + center + true + + + hamburger-menu + normal + + + + + Color List + center + center + + + + + + + + color-wheel-page + vertical + true + true + + + + Color Wheel Content Goes Here + + + + + + + + horizontal + 6 + center + true + + + color-wheel-symbolic + normal + + + + + Color Wheel + center + center + + + + + + + + + + + vertical + true + + + + + + liveP-apply + horizontal + 300 + + + liveP + Live Preview + end + start + + + + + + + + \ No newline at end of file diff --git a/share/ui/style.css b/share/ui/style.css index 5a9f9d2bf1d470bd221d55214edf8cb1777ab482..6500c1e2986369acf1cdf14237d7236d55ea85dc 100644 --- a/share/ui/style.css +++ b/share/ui/style.css @@ -67,7 +67,7 @@ * "..combobright" Combo bright */ -*{ +* { font-feature-settings: "tnum"; } @@ -75,9 +75,11 @@ .view.image { color: @theme_fg_color; } + .view.image:backdrop { color: @theme_unfocused_fg_color; } + .view.image:disabled { color: @insensitive_fg_color; } @@ -102,7 +104,7 @@ -gtk-icon-style: symbolic; } -.titlebutton > image { +.titlebutton>image { -gtk-icon-style: requested; } @@ -118,32 +120,58 @@ .highlight { color: @theme_fg_color; - background-color: alpha(@theme_selected_bg_color,0.5); - background-image: image(alpha(@theme_selected_bg_color,0.5)); + background-color: alpha(@theme_selected_bg_color, 0.5); + background-image: image(alpha(@theme_selected_bg_color, 0.5)); caret-color: @theme_bg_color; - border-radius:4px; + border-radius: 4px; -gtk-secondary-caret-color: @theme_fg_color; } -.noborder{ - border-width:0; +.noborder { + border-width: 0; } /* blinking animation for dialogs reopen*/ @keyframes blink_border { - 0% { border-color: @theme_selected_fg_color;} - 90% { border-color: @theme_selected_bg_color; } - 100% { border-color: @theme_selected_fg_color; } + 0% { + border-color: @theme_selected_fg_color; + } + + 90% { + border-color: @theme_selected_bg_color; + } + + 100% { + border-color: @theme_selected_fg_color; + } } + @keyframes blink_background { - 0% { background-color: @theme_bg_color; } - 90% { background-color: @theme_selected_bg_color; } - 100% { background-color: @theme_bg_color; } + 0% { + background-color: @theme_bg_color; + } + + 90% { + background-color: @theme_selected_bg_color; + } + + 100% { + background-color: @theme_bg_color; + } } + @keyframes blink_background_img { - 0% { background-image: image(@theme_bg_color); } - 90% { background-image: image(@theme_selected_bg_color); } - 100% { background-image: image(@theme_bg_color); } + 0% { + background-image: image(@theme_bg_color); + } + + 90% { + background-image: image(@theme_selected_bg_color); + } + + 100% { + background-image: image(@theme_bg_color); + } } button.blink { @@ -151,11 +179,11 @@ button.blink { } notebook.blink { - animation: 0.5s blink_border 0.1s ease 1; + animation: 0.5s blink_border 0.1s ease 1; } -notebook.blink > header > tabs > tab:checked { - animation: 0.5s blink_background 0.1s ease 1; +notebook.blink>header>tabs>tab:checked { + animation: 0.5s blink_background 0.1s ease 1; } .inverted :not(menuitem):not(.rawstyle):not(overshoot):not(undershoot):not(selection), @@ -167,17 +195,19 @@ notebook.blink > header > tabs > tab:checked { } .dark .combobright .combo, -.dark .combobright menu{ +.dark .combobright menu { background-color: @theme_text_color; background-image: linear-gradient(to top, @theme_text_color, @theme_fd_color); caret-color: @theme_base_color; -gtk-secondary-caret-color: @theme_base_color; } -.dark .combobright box *{ + +.dark .combobright box * { color: @theme_base_color; } + .dark .combobright .combo *, -.dark .combobright menu *{ +.dark .combobright menu * { color: inherit; } @@ -225,10 +255,10 @@ iconview *:hover { border-color: @theme_bg_color; } -#startscreennotebook iconview *:hover{ - background-color:@theme_selected_bg_color; - border-radius:5px; - border-width:0; +#startscreennotebook iconview *:hover { + background-color: @theme_selected_bg_color; + border-radius: 5px; + border-width: 0; } .inksmall { @@ -255,7 +285,8 @@ iconview *:hover { } #CommandPaletteBase { - background-color: @theme_base_color; /* some themes don't seem to have a background color for list rows defined and would end up transparent otherwise */ + background-color: @theme_base_color; + /* some themes don't seem to have a background color for list rows defined and would end up transparent otherwise */ border: 5px solid @theme_bg_color; border-radius: 5px; } @@ -308,18 +339,18 @@ iconview *:hover { border-width: 0; } -#SelectorsAndStyleDialog #StyleDialog treeview button *{ - font-size:5px; - min-height:1px; - padding:0; - margin:0; +#SelectorsAndStyleDialog #StyleDialog treeview button * { + font-size: 5px; + min-height: 1px; + padding: 0; + margin: 0; } #SelectorsAndStyleDialog #StyleDialog treeview button { - padding:0; - min-height:1px; - border-left-width:4px; - border-color:@success_color; + padding: 0; + min-height: 1px; + border-left-width: 4px; + border-color: @success_color; } /* ink-ruler */ @@ -346,25 +377,28 @@ iconview *:hover { /* Ensure ui/themes.cpp excludes these classes on applying overridebasecolor: */ .bright #InkRuler.shadow { - color: rgba(0,0,0,0.3); + color: rgba(0, 0, 0, 0.3); } + .dark #InkRuler.shadow { - color: rgba(0,0,0,0.5); + color: rgba(0, 0, 0, 0.5); } .bright #InkRuler.page { color: @theme_base_color; } + .dark #InkRuler.page { color: shade(@theme_base_color, 0.666); } .bright #InkRuler.selection.border, -.dark #InkRuler.selection.border { +.dark #InkRuler.selection.border { color: @theme_selected_bg_color; } + .bright #InkRuler.selection.background, -.dark #InkRuler.selection.background { +.dark #InkRuler.selection.background { color: transparent; } @@ -374,7 +408,9 @@ SPCanvas { } /* Those are three buttons in canvas corners; their size dictates how large scrollbars are */ -#QuickActions, #LockGuides, #CMS_Adjust { +#QuickActions, +#LockGuides, +#CMS_Adjust { padding: 0; margin: 0; outline: none; @@ -383,10 +419,14 @@ SPCanvas { min-width: 22px; min-height: 22px; } + /* Don't let images inside those buttons inflate their sizes */ -#QuickActions *, #LockGuides *, #CMS_Adjust * { +#QuickActions *, +#LockGuides *, +#CMS_Adjust * { padding: 0; } + #QuickActions image { margin-top: 1px; } @@ -433,13 +473,15 @@ SPCanvas { #InkSpinScale scale { padding: 0px; - margin:0; + margin: 0; } #InkSpinScale trough { min-height: 25px; - padding: 0; /* remove padding to make inkspinscale the same height as spinbutton */ + padding: 0; + /* remove padding to make inkspinscale the same height as spinbutton */ } + #InkSpinScale trough highlight { margin: 0; } @@ -451,7 +493,7 @@ SPCanvas { #InkSpinScale spinbutton { box-shadow: none; min-height: 10px; - border-left:0; + border-left: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; } @@ -470,10 +512,11 @@ SPCanvas { outline-width: 5px; outline-color: alpha(@theme_fg_color, 0.1); } + #Objects .search { - padding: 2px 4px; - min-height: 16px; - font-size: smaller; + padding: 2px 4px; + min-height: 16px; + font-size: smaller; } #SimpleFilterModifier #InkSpinScale { @@ -484,6 +527,7 @@ SPCanvas { border-top-right-radius: 0; border-bottom-right-radius: 0; } + #CompletionPopup button { border-top-left-radius: 0; border-bottom-left-radius: 0; @@ -509,7 +553,7 @@ treeview.view:drop(active).before { border-radius: 10px; } -button.close-button{ +button.close-button { background-image: none; padding: 0px; min-height: 1px; @@ -519,7 +563,7 @@ button.close-button{ box-shadow: none; } -button.close-button:hover{ +button.close-button:hover { box-shadow: none; opacity: 1; } @@ -528,27 +572,29 @@ button.close-button:hover{ * Inkscape start dialog styles */ -#start-screen-window .titlebar stack { /* banner-stack */ +#start-screen-window .titlebar stack { + /* banner-stack */ padding: 0; /* opaque bg at bottom corners, rather than having gap, which in GTK3 glitches in transition */ background: linear-gradient(to bottom, transparent 0%, transparent 50%, @theme_bg_color); } #start-screen-window .combo { - padding:1px 10px; + padding: 1px 10px; } + #start-screen-window .combo * { - padding:2px; + padding: 2px; } #start-screen-window grid label { - font-size:small; - margin:12px; + font-size: small; + margin: 12px; } #start-screen-window * { - outline:0; + outline: 0; } button.link:hover image { @@ -558,6 +604,7 @@ button.link:hover image { .marker-item-box { padding: 1px; } + .marker-separator { padding: 0; } @@ -592,6 +639,7 @@ stackswitcher button { margin: 0; min-width: 16px; } + .color-palette-main-box flowbox, .color-palette-main-box scrolledwindow { padding: 0; @@ -600,6 +648,7 @@ stackswitcher button { min-width: 1px; min-height: 1px; } + /* remove padding/margins from FlowBoxChild widgets, * so previews can be adjacent to each other */ .color-palette-main-box flowboxchild { @@ -609,6 +658,7 @@ stackswitcher button { min-width: 1px; min-height: 1px; } + /*removes dashed line (scrolling indicator) on color palette for all themes */ .color-palette-main-box scrolledwindow undershoot.top, .color-palette-main-box scrolledwindow undershoot.right, @@ -624,33 +674,36 @@ stackswitcher button { } @keyframes pulse { - 0% { - opacity: 0.3; - } - 50% { - opacity: 0.9; - } - 100% { - opacity: 0.3; - } + 0% { + opacity: 0.3; + } + + 50% { + opacity: 0.9; + } + + 100% { + opacity: 0.3; + } } .backgnd-active { - animation-name: pulse; - background-color: @theme_selected_bg_color; - animation-duration: 1s; - animation-timing-function: ease; - animation-iteration-count: infinite; + animation-name: pulse; + background-color: @theme_selected_bg_color; + animation-duration: 1s; + animation-timing-function: ease; + animation-iteration-count: infinite; } -.nb-highlight > header.top { - background-color: @theme_selected_bg_color; +.nb-highlight>header.top { + background-color: @theme_selected_bg_color; } .tight-flowbox flowboxchild { margin: 0; padding: 0px; } + .tight-flowbox button { margin: 0; padding: 4px; @@ -690,7 +743,8 @@ button.square-button image { } .tag-box label { - min-width: 2em; /* don't let it collapse */ + min-width: 2em; + /* don't let it collapse */ margin-right: 1px; margin-left: 8px; } @@ -701,11 +755,10 @@ button.square-button image { } /* Give layer selector button label a highlight color */ -#LayerSelector label -{ +#LayerSelector label { padding-left: 6px; border-left-style: solid; - border-left-width: 3px ; + border-left-width: 3px; /* Color is set in src/ui/widget/layer-selector.cpp */ } @@ -714,17 +767,18 @@ button.square-button image { padding-right: 3px; } -#DialogNotebook #Swatches #ColorItem.group + label { +#DialogNotebook #Swatches #ColorItem.group+label { font-weight: bold; } -#DialogNotebook #Swatches #ColorItem.paint-none + label { +#DialogNotebook #Swatches #ColorItem.paint-none+label { font-style: italic; } #StyleSwatch { font-size: smaller; } + #StyleSwatch.vertical { line-height: 0.8; /* Extra height for text descenders (?) makes style swatch bounding box too tall enlarging toolbars; @@ -748,17 +802,21 @@ button.square-button image { /* heading label in dialogs */ .heading { font-weight: bold; - font-size: 1.1em; /* make it optically comparable with non-bold */ + font-size: 1.1em; + /* make it optically comparable with non-bold */ margin-top: 0.5em; } + /* topmost heading in dialogs */ .heading.top { margin-top: 0.2em; } + /* slightly smaller (sub)heading label in dialogs */ .heading1 { font-weight: bold; - font-size: 1em; /* make it optically comparable with non-bold */ + font-size: 1em; + /* make it optically comparable with non-bold */ margin-top: 0.5em; } @@ -774,18 +832,22 @@ button.square-button image { .inkscape-toolbar { margin: 4px; } -.inkscape-toolbar > * { + +.inkscape-toolbar>* { margin-right: 2px; margin-left: 2px; } -.inkscape-toolbar > box > image, -.inkscape-toolbar > box > label { + +.inkscape-toolbar>box>image, +.inkscape-toolbar>box>label { margin-right: 2px; } -.inkscape-toolbar popover content > * { + +.inkscape-toolbar popover content>* { margin-right: 2px; margin-left: 2px; } + /* Revise for gtk4: There's no box in popover */ /*.inkscape-toolbar > popover > box {*/ /* margin: 4px 3px;*/ @@ -823,15 +885,18 @@ button.menu-btn-tight { #DesktopStatusBar { margin-right: 1em; } + /* * Inkscape Export Dialog */ -#ExportDialog #export_selection{ +#ExportDialog #export_selection { border-radius: 0px; } + #ExportDialog #export_preview_single { border: 1px solid; } + #ExportDialog #export_preview_batch { border: 1px solid; } @@ -848,29 +913,33 @@ combobox.flat-combobox button { background-image: image(transparent); } -.filter-effects, .effects-params { +.filter-effects, +.effects-params { min-height: 50px; } /* Defeat standard darker background color on views: use popoverʼs background */ popover.background.filter-effects-info textview, -popover.background.filter-effects-info textview > text { +popover.background.filter-effects-info textview>text { background: none; } .dark .symbolsoverlay iconview:not(:selected) { - background-color: #f0f0f0; /* bright background color for typically black symbols */ + background-color: #f0f0f0; + /* bright background color for typically black symbols */ /* background-color: @theme_fg_color; - this doesn't work for some themes (like MonoThemeDark) */ - color:@theme_bg_color; /* symbol text labels */ + color: @theme_bg_color; + /* symbol text labels */ } .dark .symbolsoverlay { - color: @theme_bg_color; /* this is for overlay widget's children */ + color: @theme_bg_color; + /* this is for overlay widget's children */ } /* LPE Dialog add */ #LPEScrolled { - border:none; + border: none; } #LPESelectorFlowBox GtkFlowBoxChild, @@ -934,12 +1003,12 @@ popover.background.filter-effects-info textview > text { margin: 0px 0px 10px 0px; border-radius: 0px; border-width: 0 0 1px 0; - padding:5px; + padding: 5px; } -#LPESelectorFlowBox image{ - background-color:@theme_bg_color; - border-color:transparent; +#LPESelectorFlowBox image { + background-color: @theme_bg_color; + border-color: transparent; } #LPEExperimental image { @@ -953,29 +1022,29 @@ popover.background.filter-effects-info textview > text { } #LPEDialogSelector.LPEPackMore flowboxchild { -margin:5px 1px 0px; -padding:3px 3px 10px 3px; + margin: 5px 1px 0px; + padding: 3px 3px 10px 3px; } #LPEDialogSelector.LPEList .lpename { margin-bottom: 1px; - font-weight:bold; + font-weight: bold; } #LPEDialogSelector.LPEList flowboxchild { - padding:3px 1px 3px 10px; - margin:1px 0px 1px; - border-radius:0; - border-style:dotted; - border-color:@theme_fg_color; + padding: 3px 1px 3px 10px; + margin: 1px 0px 1px; + border-radius: 0; + border-style: dotted; + border-color: @theme_fg_color; border-width: 0 0 1px 0; } #LPEDialogSelector.LPEList flowboxchild:selected { - border-style:none; - margin:-3px 0px 0px; - padding:4px 1px 4px 10px; + border-style: none; + margin: -3px 0px 0px; + padding: 4px 1px 4px 10px; } #LPEDialogSelector.LPEList #LPESelectorFlowBox *:selected #LPESelectorEffectFavTop, @@ -984,132 +1053,139 @@ padding:3px 3px 10px 3px; } #LivePathEffect { - padding-top:5px; + padding-top: 5px; } -#LivePathEffect expander:focus, #LivePathEffect expander > label:focus{ - outline-width:0; +#LivePathEffect expander:focus, +#LivePathEffect expander>label:focus { + outline-width: 0; } -#LivePathEffect list{ - margin:5px 5px 0 5px; +#LivePathEffect list { + margin: 5px 5px 0 5px; } -#LivePathEffect list row{ - margin:0; - padding:0; - border-width:0; - border-style:none; - outline-width:0; +#LivePathEffect list row { + margin: 0; + padding: 0; + border-width: 0; + border-style: none; + outline-width: 0; } -#LivePathEffect list row > box{ - margin:0; - padding:1px; - border-width:1px; - border-radius:4px; - margin-bottom:5px; - border-style:solid; - border-color:@borders; - outline-width:0; + +#LivePathEffect list row>box { + margin: 0; + padding: 1px; + border-width: 1px; + border-radius: 4px; + margin-bottom: 5px; + border-style: solid; + border-color: @borders; + outline-width: 0; } -#LivePathEffect list row:last-child > box{ - margin-bottom:0px; +#LivePathEffect list row:last-child>box { + margin-bottom: 0px; } -#LPEEffectItem{ - border-radius:3px; - padding:2px; - outline:0; +#LPEEffectItem { + border-radius: 3px; + padding: 2px; + outline: 0; } #LPEEffectItem .minbutton { - padding:0; - margin:0; - outline:0; - border-color:@borders; + padding: 0; + margin: 0; + outline: 0; + border-color: @borders; } #LPEEffectItem expander title label { - min-height:26px; + min-height: 26px; } -#LPEEffectItem expander, +#LPEEffectItem expander, #LPEEffectItem expander *, -#LPEEffectItem expander:focus, +#LPEEffectItem expander:focus, #LPEEffectItem expander *:focus { - outline:0; + outline: 0; } -.LPEDrag,.LPEDrag:active,.LPEDrag:focus,.LPEDrag:hover { - margin:0; - padding:0; - border-style:none; - opacity:0.7; - background-color:transparent; - background-image:none; - outline:0; +.LPEDrag, +.LPEDrag:active, +.LPEDrag:focus, +.LPEDrag:hover { + margin: 0; + padding: 0; + border-style: none; + opacity: 0.7; + background-color: transparent; + background-image: none; + outline: 0; } .LPEDrag:hover { - opacity:1; - background-color:transparent; - background-image:none; + opacity: 1; + background-color: transparent; + background-image: none; } -#LivePathEffect list#LPEParentBox row{ - border-style:none; - outline:0; +#LivePathEffect list#LPEParentBox row { + border-style: none; + outline: 0; } -#LivePathEffect list#LPEParentBox row > button { - padding:2px; - margin:0; +#LivePathEffect list#LPEParentBox row>button { + padding: 2px; + margin: 0; } #LPEContainer:drop(active) { - box-shadow:none; + box-shadow: none; } -#LPECurrentItem *{ - color:@theme_fg_color; +#LPECurrentItem * { + color: @theme_fg_color; } -#LPEContainer #LPEListBox{ +#LPEContainer #LPEListBox { border-style: solid none solid none; border-color: @theme_base_color; - border-width:0; - padding:0; + border-width: 0; + padding: 0; } -#LPEListBox row:drop(active){ - box-shadow:none; + +#LPEListBox row:drop(active) { + box-shadow: none; } -#LPEContainer:drop(active).before row:first-child > box, -#LPEListBox row:drop(active).before > box{ - border-width:6px 1px 1px 1px; + +#LPEContainer:drop(active).before row:first-child>box, +#LPEListBox row:drop(active).before>box { + border-width: 6px 1px 1px 1px; border-color: @theme_selected_bg_color @borders @borders @borders; - box-shadow:none; - border-radius:6px 6px 0 0; + box-shadow: none; + border-radius: 6px 6px 0 0; } -#LPEContainer:drop(active).after row:last-child > box, -#LPEListBox row:drop(active).after > box{ - border-width:1px 1px 6px 1px; +#LPEContainer:drop(active).after row:last-child>box, +#LPEListBox row:drop(active).after>box { + border-width: 1px 1px 6px 1px; border-color: @borders @borders @theme_selected_bg_color @borders; - border-radius:0 0 6px 6px; - box-shadow:none; + border-radius: 0 0 6px 6px; + box-shadow: none; } #LPEEffectItem expander title label { - min-height:34px; + min-height: 34px; } #LPEMenu menuitem:not(.menu-category):disabled { - color:alpha(@theme_text_color,0.4); + color: alpha(@theme_text_color, 0.4); } -#LPEListBox row > *:disabled * { - color:@theme_text_color; +#LPEListBox row>*:disabled * { + color: @theme_text_color; } @@ -1121,44 +1197,49 @@ padding:3px 3px 10px 3px; #LivePathEffect list row .drag-icon, #LPEListBox row.activatable .drag-icon:hover { background-color: @theme_base_color; - border-width:1px; - border-radius:0; - margin:0; - padding:5px; - border-style:solid; - border-color:@borders; - outline-width:0; + border-width: 1px; + border-radius: 0; + margin: 0; + padding: 5px; + border-style: solid; + border-color: @borders; + outline-width: 0; } #LivePathEffect list row .drag-icon * { - outline:0; + outline: 0; } -#LPEActionButtons #eventbutton:nth-child(1) button{ - border-radius:3px 0 0 3px; - border-width:1px 0 1px 1px; +#LPEActionButtons #eventbutton:nth-child(1) button { + border-radius: 3px 0 0 3px; + border-width: 1px 0 1px 1px; } -#LPEActionButtons #eventbutton:nth-child(2) button{ - border-radius:0; - border-width:1px 0 1px 1px; +#LPEActionButtons #eventbutton:nth-child(2) button { + border-radius: 0; + border-width: 1px 0 1px 1px; } + #LPECurrentItem * { - border-width:0; - border-style:none; + border-width: 0; + border-style: none; } + #LPECurrentItem { - margin-top:0; + margin-top: 0; } -#LPECurrentItem image{ - margin-right:6px; + +#LPECurrentItem image { + margin-right: 6px; } + #LPECurrentItem { - margin-top:0; + margin-top: 0; } -#LPEParentBox{ - margin:10px 4px; - padding:0; + +#LPEParentBox { + margin: 10px 4px; + padding: 0; } /* min size for an angle slider in gradient editor */ @@ -1168,24 +1249,30 @@ padding:3px 3px 10px 3px; /* Gtk::PopoverMenu and Inkscape::UI::Widget::PopoverMenu */ /* Make it look basically like GtkMenu; see comments @ original merge request */ -popover.menu, /* GTK sets .menu/make_menuized_popover() sets .menuize */ -popover.popover-menu { /* Inkscape::UI::Widget::PopoverMenu */ +popover.menu, +/* GTK sets .menu/make_menuized_popover() sets .menuize */ +popover.popover-menu { + /* Inkscape::UI::Widget::PopoverMenu */ /* Rounded corners can glitch in GTK3 with submenus, and GtkMenu was square anyway = emulate */ border-radius: 0; border-color: @borders; padding: 0; } + popover.popover-menu contents { padding: 1px 0; } + popover.popover-menu menu { background: none; border: none; } + popover.popover-menu .menu-category { min-height: 16px; padding: 2px 10px; } + /* popover.menu modelbutton, */ popover.popover-menu .regular-item { border-radius: 0; @@ -1193,21 +1280,26 @@ popover.popover-menu .regular-item { min-height: 23px; padding: 2px 10px; } + popover.popover-menu menuitem:hover { background-color: @theme_selected_bg_color; color: @theme_selected_fg_color; } + popover.popover-menu menuitem:hover image { background-color: @theme_selected_bg_color; color: @theme_selected_fg_color; } + popover.popover-menu separator { margin: 1px 0; } + /* Defeat defaulting to having more spacing between RadioButtons than GtkMenu */ popover.popover-menu radiobutton { padding: 0; } + /* Emulate GtkMenu theming in absence of ability to change CSS node name, unlike our PopoverMenu */ /* popover.menu modelbutton:focus, popover.menu modelbutton:hover { @@ -1215,18 +1307,22 @@ popover.menu modelbutton:hover { color: @theme_selected_fg_color; } */ /* UGH! GtkMenuSectionBox has Widget:margin = 10px. Counteract to look like popover.popover-menu */ -popover.menu > stack > box { +popover.menu>stack>box { margin: -2px -6px; } + /* Detect submenu headings & replicate GTK .dim-label, looks nicer than leaving normal fg colour */ -popover.menu > stack > box > modelbutton:first-child > * /* Affect children not bgcolour */ -{ +popover.menu>stack>box>modelbutton:first-child>* + +/* Affect children not bgcolour */ + { opacity: 0.55; } /* regular popover that has no arrow and pretends to be a dropdown menu */ popover.popup-menu contents { - margin-top: 1px; /* distance from the bottom of the button above this menu */ + margin-top: 1px; + /* distance from the bottom of the button above this menu */ } /* darker background for extensions gallery due to fixed-color thumbnails (white background + drop shadow) */ @@ -1239,20 +1335,22 @@ popover.popup-menu contents { margin-top: 1px; margin-bottom: 1px; } + #tool-toolbar button { margin-left: 1px; margin-right: 1px; } + #tool-toolbar { - margin: 1px; /* toolbar box itself, so it has some breathing space; other toolbars have much larger margins */ + margin: 1px; + /* toolbar box itself, so it has some breathing space; other toolbars have much larger margins */ } /* used @ ui/themes to get correct foreground color; get_color() can be wrong */ /* Asterisks & stuff in the selectors are just to ensure sufficient priority. */ *.theme_fg_color, *.theme_fg_color:not(:backdrop), -*.theme_fg_color:backdrop -{ +*.theme_fg_color:backdrop { color: @theme_fg_color; } @@ -1261,21 +1359,20 @@ popover.popup-menu contents { Asterisks & stuff in the selectors are just to ensure sufficient priority. */ *.theme_bg_color, *.theme_bg_color:not(:backdrop), -*.theme_bg_color:backdrop -{ +*.theme_bg_color:backdrop { color: @theme_bg_color; } + *.theme_selected_bg_color, *.theme_selected_bg_color:not(:backdrop), -*.theme_selected_bg_color:backdrop -{ +*.theme_selected_bg_color:backdrop { color: @theme_selected_bg_color; } /* ColorSlider */ #ColorSlider { - min-width : 96px; - min-height: 8px; + min-width: 96px; + min-height: 8px; } #ColorPicker { @@ -1283,24 +1380,28 @@ popover.popup-menu contents { min-width: 24px; min-height: 24px; } -#ColorPicker > button { + +#ColorPicker>button { border-width: 0; padding: 0; } -#ColorPicker > .toggle { + +#ColorPicker>.toggle { border-width: 0; padding: 0; } /* ColorPreview */ #ColorPreview { - min-width : 16px; + min-width: 16px; min-height: 16px; } + #ColorPreview.simple { - min-width : 32px; + min-width: 32px; min-height: 12px; } + #ColorPreview:hover:not(.simple) { border-radius: 3px; border: solid @theme_selected_bg_color 1px; @@ -1308,32 +1409,35 @@ popover.popup-menu contents { /* GradientImage */ #GradientImage { - min-width : 54px; + min-width: 54px; min-height: 12px; } /* GradientWithStops */ #GradientEdit { - min-width : 60px; + min-width: 60px; /* widget's height; it should take stop template's height into account * current value is fine-tuned to make stop handles overlap gradient image * just the right amount */ min-height: 33px; } + /* focus outline, emulates style of GTKʼs Adwaita/Default CSS themeʼs outline */ #GradientEdit { - border: 1px dashed transparent; /* reserve space but donʼt draw til focus */ + border: 1px dashed transparent; + /* reserve space but donʼt draw til focus */ border-radius: 3px; padding: 3px; } + #GradientEdit:focus-within { border-color: alpha(@theme_fg_color, 0.3); } /* Canvas */ #InkscapeCanvas { - min-width : 256px; + min-width: 256px; min-height: 256px; } @@ -1346,8 +1450,9 @@ popover.popup-menu contents { frame.icon-preview { border-radius: 0; } + button.icon-preview { - min-width : 0; + min-width: 0; min-height: 0; padding: 5px; } @@ -1358,9 +1463,9 @@ frame.flat { } /*we dont want higlight with tab order only want checked ones */ -#ToolToolbar flowboxchild:selected { - background-color:transparent; - background-image:image(@theme_bg_color); +#ToolToolbar flowboxchild:selected { + background-color: transparent; + background-image: image(@theme_bg_color); } /* Adding some margins for popup dialogs, so the content is not touching the window borders */ @@ -1369,86 +1474,107 @@ frame.flat { } /* Tabs widget */ -#DocumentTab { padding: 3px; } +#DocumentTab { + padding: 3px; +} #DocumentTab:hover { - background-color:shade(@theme_bg_color, 0.97); + background-color: shade(@theme_bg_color, 0.97); } #DocumentTab.tab_active { box-shadow: inset 0 -2px @theme_selected_bg_color; - background-color:@theme_bg_color; + background-color: @theme_bg_color; } -#DocumentTabsWidget { box-shadow: none; } +#DocumentTabsWidget { + box-shadow: none; +} @keyframes pulse-border { - 0% { - box-shadow: inset alpha(@theme_selected_bg_color, 0.4) 0px 0px 2px 1px; - } - 50% { - box-shadow: inset @theme_selected_bg_color 0px 0px 6px 2px; - } - 100% { - box-shadow: inset alpha(@theme_selected_bg_color, 0.4) 0px 0px 2px 1px; - } + 0% { + box-shadow: inset alpha(@theme_selected_bg_color, 0.4) 0px 0px 2px 1px; + } + + 50% { + box-shadow: inset @theme_selected_bg_color 0px 0px 6px 2px; + } + + 100% { + box-shadow: inset alpha(@theme_selected_bg_color, 0.4) 0px 0px 2px 1px; + } } -#DocumentTabsWidget.drop-highlight > #Overlay { - box-shadow: inset @theme_selected_bg_color 0px 0px 5px 1px; - animation-name: pulse-border; - animation-duration: 1s; - animation-timing-function: ease; - animation-iteration-count: infinite; +#DocumentTabsWidget.drop-highlight>#Overlay { + box-shadow: inset @theme_selected_bg_color 0px 0px 5px 1px; + animation-name: pulse-border; + animation-duration: 1s; + animation-timing-function: ease; + animation-iteration-count: infinite; } /*helper info in popover menu*/ -.menu_search{ - background-color:alpha(@theme_fg_color,0.1); - margin:0 0 -8px -8px; +.menu_search { + background-color: alpha(@theme_fg_color, 0.1); + margin: 0 0 -8px -8px; } /* limit height of list view items */ -columnview.list-view-small > listview > row > cell { +columnview.list-view-small>listview>row>cell { padding: 5px; } /* gridview items with smaller margins */ -gridview.grid-view-small > child box.item-box { +gridview.grid-view-small>child box.item-box { padding: 0; margin: 8px; border-spacing: 8px; } /* list view with items based on labels need some extra vertical space */ -listview.list-view-small > row > box.item-box { +listview.list-view-small>row>box.item-box { margin-top: 3px; margin-bottom: 3px; } -listview.list-view-small > row > box.item-box.separator { +listview.list-view-small>row>box.item-box.separator { margin: 1px; } /* About screen slide show transitions >>>>>>>>>>>>>>>>>>>>>>>>> */ @keyframes fade_in_opacity { - 0% { opacity: 0; } - 100% { opacity: 1; } + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } } + @keyframes fade_out_opacity { - 0% { opacity: 1; } - 100% { opacity: 0; } + 0% { + opacity: 1; + } + + 100% { + opacity: 0; + } } + .fade-in { animation: 1.2s fade_in_opacity 0s both; } + .fade-out { animation: 1.2s fade_out_opacity 0s both; } + .background-transition { transition-property: background-color; transition-duration: 1.2s; } + /* <<<<<<<<<<<<<<<<<<<<<<<< About screen slide show transitions */ /* Grid definition panel/box in document properties dialog */ @@ -1484,6 +1610,7 @@ separator.faint { #ColorPlate.rectangular { min-height: 160px; } + #ColorPlate.circular { min-height: 300px; } @@ -1497,17 +1624,18 @@ separator.faint { /* Simple decorators for resizing handles giving them borders */ #MultipanedHandle.horizontal { background-image: linear-gradient(to right, - alpha(@theme_fg_color, 0.25) 0%, - @theme_bg_color 10%, - @theme_bg_color 90%, - alpha(@theme_fg_color, 0.25) 100%); + alpha(@theme_fg_color, 0.25) 0%, + @theme_bg_color 10%, + @theme_bg_color 90%, + alpha(@theme_fg_color, 0.25) 100%); } + #MultipanedHandle.vertical { background-image: linear-gradient(to bottom, - alpha(@theme_fg_color, 0.25) 0%, - @theme_bg_color 10%, - @theme_bg_color 90%, - alpha(@theme_fg_color, 0.25) 100%); + alpha(@theme_fg_color, 0.25) 0%, + @theme_bg_color 10%, + @theme_bg_color 90%, + alpha(@theme_fg_color, 0.25) 100%); } /* Adds an exception to StartScreen recent files tab @@ -1544,31 +1672,69 @@ listview row.top-separator { min-height: calc(2em + 4px); padding: 0 4px; } + #SimpleTab { min-width: 4em; min-height: calc(2em + 4px); } + #SimpleTab:hover { box-shadow: inset 0 -3px alpha(@theme_fg_color, 0.15); } + #SimpleTab.tab-active { background-color: @theme_base_color; box-shadow: inset 0 -3px @theme_selected_bg_color, inset -1px 0 alpha(@theme_fg_color, 0.10), - inset 1px 0 alpha(@theme_fg_color, 0.10); + inset 1px 0 alpha(@theme_fg_color, 0.10); } + #SimpleTab.tab-active:hover { /*border-bottom-color: @theme_selected_bg_color;*/ } + #NewTabButton { margin-left: 3px; } + #DialogMenuButton { margin-left: 3px; } /* Some themes add color decoration for active drop targets; we use our own highlight, so disable them */ -#MultipanedDropZone:drop(active), #MultipanedDropZone:drop(active):focus, - #DialogMultipaned:drop(active), #DialogMultipaned:drop(active):focus { +#MultipanedDropZone:drop(active), +#MultipanedDropZone:drop(active):focus, +#DialogMultipaned:drop(active), +#DialogMultipaned:drop(active):focus { box-shadow: none; } + +/* +********************** +* Recolor Art class * +********************** +*/ + + +#recolor-art #original, +#recolored { + min-height: 6px; + border-radius: 4px; + border: 2px solid transparent; +} + +#original-recolor-box button#original:hover, +button#recolored:hover { + border-color: @theme_fq_color; +} + +#recolor-art listview row:selected { + background-color: transparent; + border: 2px solid @theme_selected_bg_color; + border-radius: 4px; +} + +#recolor-art { + min-width: 400px; + min-height: 500px; +} \ No newline at end of file diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index df176e03431ccbf30a5b47adb1941b7a8799563c..5d4f2108ceb642401946898a7384cb437703d60c 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -285,10 +285,10 @@ set(ui_SRC widget/unit-tracker.cpp widget/widget-vfuncs-class-init.cpp widget/xml-treeview.cpp + widget/recolor-art.cpp view/svg-view-widget.cpp - # ------- # Headers builder-utils.h @@ -597,7 +597,8 @@ set(ui_SRC widget/unit-tracker.h widget/widget-vfuncs-class-init.h widget/xml-treeview.h - + widget/recolor-art.h + view/svg-view-widget.h ) diff --git a/src/ui/dialog/fill-and-stroke.cpp b/src/ui/dialog/fill-and-stroke.cpp index a3736bae318004ddef8d59b2d620843806c00a30..02de1d41d0c7b72ee93f5e713e0415af08f7e919 100644 --- a/src/ui/dialog/fill-and-stroke.cpp +++ b/src/ui/dialog/fill-and-stroke.cpp @@ -23,15 +23,17 @@ #include #include -#include "desktop.h" #include "desktop-style.h" +#include "desktop.h" #include "preferences.h" +#include "selection.h" #include "ui/icon-loader.h" #include "ui/icon-names.h" #include "ui/pack.h" #include "ui/widget/fill-style.h" -#include "ui/widget/stroke-style.h" #include "ui/widget/notebook-page.h" +#include "ui/widget/recolor-art.h" +#include "ui/widget/stroke-style.h" namespace Inkscape::UI::Dialog { @@ -40,12 +42,9 @@ FillAndStroke::FillAndStroke() , _page_fill(Gtk::make_managed(1, 1)) , _page_stroke_paint(Gtk::make_managed(1, 1)) , _page_stroke_style(Gtk::make_managed(1, 1)) - , _composite_settings(INKSCAPE_ICON("dialog-fill-and-stroke"), - "fillstroke", - UI::Widget::SimpleFilterModifier::ISOLATION | - UI::Widget::SimpleFilterModifier::BLEND | - UI::Widget::SimpleFilterModifier::BLUR | - UI::Widget::SimpleFilterModifier::OPACITY) + , _composite_settings(INKSCAPE_ICON("dialog-fill-and-stroke"), "fillstroke", + UI::Widget::SimpleFilterModifier::ISOLATION | UI::Widget::SimpleFilterModifier::BLEND | + UI::Widget::SimpleFilterModifier::BLUR | UI::Widget::SimpleFilterModifier::OPACITY) , fillWdgt(nullptr) , strokeWdgt(nullptr) { @@ -54,7 +53,8 @@ FillAndStroke::FillAndStroke() _notebook.append_page(*_page_fill, _createPageTabLabel(_("_Fill"), INKSCAPE_ICON("object-fill"))); _notebook.append_page(*_page_stroke_paint, _createPageTabLabel(_("Stroke _paint"), INKSCAPE_ICON("object-stroke"))); - _notebook.append_page(*_page_stroke_style, _createPageTabLabel(_("Stroke st_yle"), INKSCAPE_ICON("object-stroke-style"))); + _notebook.append_page(*_page_stroke_style, + _createPageTabLabel(_("Stroke st_yle"), INKSCAPE_ICON("object-stroke-style"))); _notebook.set_vexpand(true); _switch_page_conn = _notebook.signal_switch_page().connect(sigc::mem_fun(*this, &FillAndStroke::_onSwitchPage)); @@ -62,7 +62,6 @@ FillAndStroke::FillAndStroke() _layoutPageFill(); _layoutPageStrokePaint(); _layoutPageStrokeStyle(); - UI::pack_end(*this, _composite_settings, UI::PackOptions::shrink); _composite_settings.setSubject(&_subject); @@ -80,6 +79,7 @@ FillAndStroke::~FillAndStroke() void FillAndStroke::selectionChanged(Selection *selection) { + if (!page_changed) { changed_fill = true; changed_stroke = true; @@ -94,6 +94,7 @@ void FillAndStroke::selectionChanged(Selection *selection) if (strokeStyleWdgt && npage == 2) { strokeStyleWdgt->selectionChangedCB(); } + } void FillAndStroke::selectionModified(Selection *selection, guint flags) @@ -110,6 +111,7 @@ void FillAndStroke::selectionModified(Selection *selection, guint flags) if (strokeStyleWdgt && npage == 2) { strokeStyleWdgt->selectionModifiedCB(flags); } + } void FillAndStroke::desktopReplaced() @@ -126,10 +128,11 @@ void FillAndStroke::desktopReplaced() if (strokeStyleWdgt) { strokeStyleWdgt->setDesktop(getDesktop()); } + _subject.setDesktop(getDesktop()); } -void FillAndStroke::_onSwitchPage(Gtk::Widget * page, guint pagenum) +void FillAndStroke::_onSwitchPage(Gtk::Widget *page, guint pagenum) { npage = pagenum; if (page->is_visible()) { @@ -153,65 +156,55 @@ void FillAndStroke::_onSwitchPage(Gtk::Widget * page, guint pagenum) _savePagePref(pagenum); } -void -FillAndStroke::_savePagePref(guint page_num) +void FillAndStroke::_savePagePref(guint page_num) { // remember the current page Inkscape::Preferences *prefs = Inkscape::Preferences::get(); prefs->setInt("/dialogs/fillstroke/page", page_num); } -void -FillAndStroke::_layoutPageFill() +void FillAndStroke::_layoutPageFill() { fillWdgt = Gtk::make_managed(FILL); _page_fill->table().attach(*fillWdgt, 0, 0, 1, 1); } -void -FillAndStroke::_layoutPageStrokePaint() +void FillAndStroke::_layoutPageStrokePaint() { strokeWdgt = Gtk::make_managed(STROKE); _page_stroke_paint->table().attach(*strokeWdgt, 0, 0, 1, 1); } -void -FillAndStroke::_layoutPageStrokeStyle() +void FillAndStroke::_layoutPageStrokeStyle() { strokeStyleWdgt = Gtk::make_managed(); strokeStyleWdgt->set_hexpand(); strokeStyleWdgt->set_halign(Gtk::Align::START); _page_stroke_style->table().attach(*strokeStyleWdgt, 0, 0, 1, 1); } - -void -FillAndStroke::showPageFill() +void FillAndStroke::showPageFill() { blink(); _notebook.set_current_page(0); _savePagePref(0); - } -void -FillAndStroke::showPageStrokePaint() +void FillAndStroke::showPageStrokePaint() { blink(); _notebook.set_current_page(1); _savePagePref(1); } -void -FillAndStroke::showPageStrokeStyle() +void FillAndStroke::showPageStrokeStyle() { blink(); _notebook.set_current_page(2); _savePagePref(2); - } -Gtk::Box& -FillAndStroke::_createPageTabLabel(const Glib::ustring& label, const char *label_image) + +Gtk::Box &FillAndStroke::_createPageTabLabel(Glib::ustring const &label, char const *label_image) { auto const _tab_label_box = Gtk::make_managed(Gtk::Orientation::HORIZONTAL, 4); diff --git a/src/ui/dialog/fill-and-stroke.h b/src/ui/dialog/fill-and-stroke.h index 0a918df2f0af4d1b9ec2a65a397ca69653e66a77..29c3ba92b4eb2e9efb668d6d36628c24be0c37ae 100644 --- a/src/ui/dialog/fill-and-stroke.h +++ b/src/ui/dialog/fill-and-stroke.h @@ -24,6 +24,7 @@ namespace Gtk { class Box; +class Popover; } // namespace Gtk namespace Inkscape::UI { @@ -32,6 +33,7 @@ namespace Widget { class FillNStroke; class NotebookPage; class StrokeStyle; +class RecolorArt; } // namespace Widget namespace Dialog { @@ -78,6 +80,7 @@ private: UI::Widget::FillNStroke *fillWdgt = nullptr; UI::Widget::FillNStroke *strokeWdgt = nullptr; UI::Widget::StrokeStyle *strokeStyleWdgt = nullptr; + sigc::scoped_connection _switch_page_conn; }; diff --git a/src/ui/widget/paint-selector.cpp b/src/ui/widget/paint-selector.cpp index 5ad356bd70b23474f5b7816466c7b594282bde39..d3a34ead5bec22d962946baf5fd5911bc4bce789 100644 --- a/src/ui/widget/paint-selector.cpp +++ b/src/ui/widget/paint-selector.cpp @@ -57,6 +57,7 @@ #include "ui/widget/gradient-editor.h" #include "ui/widget/gradient-selector.h" #include "ui/widget/pattern-editor.h" +#include "ui/widget/recolor-art.h" #include "ui/widget/swatch-selector.h" #include "widgets/widget-sizes.h" #include "xml/repr.h" @@ -135,6 +136,9 @@ GradientSelectorInterface *PaintSelector::getGradientFromData() const PaintSelector::PaintSelector(FillOrStroke kind, std::shared_ptr colors) : _selected_colors(std::move(colors)) + ,recolorArtWdgt(Gtk::make_managed()) + ,recolorButtonTriger(Gtk::make_managed()) + , recolorPopOver(Gtk::make_managed()) { set_orientation(Gtk::Orientation::VERTICAL); @@ -205,6 +209,16 @@ PaintSelector::PaintSelector(FillOrStroke kind, std::shared_ptrsignal_released.connect(sigc::mem_fun(*this, &PaintSelector::onSelectedColorReleased)); _selected_colors->signal_changed.connect(sigc::mem_fun(*this, &PaintSelector::onSelectedColorChanged)); + recolorButtonTriger->set_label("Recolor Selection"); + recolorButtonTriger->set_hexpand(false); + recolorButtonTriger->signal_clicked().connect([this]() { + recolorPopOver->popup(); + recolorArtWdgt->performUpdate(); + }); + recolorPopOver->set_parent(*recolorButtonTriger); + recolorPopOver->set_child(*recolorArtWdgt); + recolorPopOver->set_position(Gtk::PositionType::LEFT); + _frame->append(*recolorButtonTriger); // from _new function setMode(PaintSelector::MODE_MULTIPLE); diff --git a/src/ui/widget/paint-selector.h b/src/ui/widget/paint-selector.h index f76eda68f6cfa78a5620674edaf59896fcf29e63..41a0e4a674acef444d661eca5401cfe282610b7b 100644 --- a/src/ui/widget/paint-selector.h +++ b/src/ui/widget/paint-selector.h @@ -42,6 +42,7 @@ class SPStyle; namespace Gtk { class Label; class ToggleButton; +class Popover; } // namespace Gtk namespace Inkscape::UI::Widget { @@ -50,6 +51,7 @@ class FillRuleRadioButton; class GradientEditor; class PatternEditor; class StyleToggleButton; +class RecolorArt; /** * Generic paint selector widget. @@ -103,6 +105,10 @@ class PaintSelector : public Gtk::Box { SwatchSelector *_selector_swatch = nullptr; PatternEditor* _selector_pattern = nullptr; + UI::Widget::RecolorArt *recolorArtWdgt = nullptr; + Gtk::Button *recolorButtonTriger = nullptr; + Gtk::Popover* recolorPopOver=nullptr; + Gtk::Label *_label; GtkWidget *_patternmenu = nullptr; bool _patternmenu_update = false; diff --git a/src/ui/widget/recolor-art.cpp b/src/ui/widget/recolor-art.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b66164d0b8751132d9e8d6a181b9f0ba92b639fe --- /dev/null +++ b/src/ui/widget/recolor-art.cpp @@ -0,0 +1,529 @@ +#include "recolor-art.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #include +#include +#include + +#include "actions/actions-tools.h" +#include "canvas.h" +#include "color-notebook.h" +#include "desktop-style.h" +#include "desktop.h" +#include "document-undo.h" +#include "document.h" +#include "gradient-chemistry.h" +#include "inkscape.h" +#include "object/sp-defs.h" +#include "object/sp-gradient.h" +#include "object/sp-linear-gradient.h" +#include "object/sp-mesh-gradient.h" +#include "object/sp-object.h" +#include "object/sp-pattern.h" +#include "object/sp-radial-gradient.h" +#include "object/sp-stop.h" +#include "object/sp-text.h" +#include "object/sp-use.h" +#include "pattern-manipulation.h" +#include "selection.h" +#include "style-internal.h" +#include "style.h" +#include "ui/builder-utils.h" +#include "ui/dialog/dialog-base.h" +#include "ui/icon-names.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +RecolorArt::RecolorArt() + : Gtk::Box() + , _builder(create_builder("recolor-art.glade")) + , _solid_colors(std::make_shared()) +{ + set_name("RecolorArt"); + append(get_widget(_builder, "recolor-art")); + _solid_colors->set(Color(0x000000ff)); + + layoutColorPicker(); + _color_list = _builder->get_widget("colors-list"); + _live_preview = _builder->get_widget("liveP"); + _live_preview->signal_toggled().connect(sigc::mem_fun(*this, &RecolorArt::onLivePreviewToggled)); + _live_preview->set_active(true); + _reset = _builder->get_widget("reset"); + _reset->signal_clicked().connect(sigc::mem_fun(*this, &RecolorArt::onResetClicked)); + + _notebook = _builder->get_widget("list-wheel-box"); + _color_wheel_page = _builder->get_widget("color-wheel-page"); + _notebook->signal_switch_page().connect([this](Gtk::Widget *page, guint page_num) { + int wheel_index = _notebook->page_num(*_color_wheel_page); + + if (static_cast(page_num) == wheel_index) { + _color_picker_wdgt->set_visible(false); + // std::cout << "Color Wheel tab is active.\n"; + } else { + _color_picker_wdgt->set_visible(true); + // std::cout << "Color Wheel tab is NOT active.\n"; + } + }); + + _list_view = _builder->get_widget("recolor-art-list"); + _color_model = Gio::ListStore::create(); + _selection_model = Gtk::SingleSelection::create(_color_model); + _color_factory = Gtk::SignalListItemFactory::create(); + + _color_factory->signal_setup().connect([](Glib::RefPtr const &list_item) { + auto box = Gtk::make_managed(Gtk::Orientation::HORIZONTAL); + auto original = Gtk::make_managed(); + auto arrow = Gtk::make_managed(); + auto recolored = Gtk::make_managed(); + + original->set_hexpand(true); + + recolored->set_hexpand(true); + + arrow->set_use_markup(true); + arrow->set_width_chars(6); + arrow->set_markup(""); + arrow->set_halign(Gtk::Align::CENTER); + arrow->set_valign(Gtk::Align::CENTER); + arrow->set_margin_top(3); + + box->set_name("original-recolor-box"); + box->append(*original); + box->append(*arrow); + box->append(*recolored); + list_item->set_child(*box); + }); + + _color_factory->signal_bind().connect([this](Glib::RefPtr const &list_item) { + auto item = std::dynamic_pointer_cast(list_item->get_item()); + if (!item) + return; + + auto box = dynamic_cast(list_item->get_child()); + if (!box || box->get_first_child() == nullptr || box->get_last_child() == nullptr) + return; + + auto original = dynamic_cast(box->get_first_child()); + auto recolored = dynamic_cast(box->get_last_child()); + + if (original && recolored) { + colorButtons(original, item->old_color); + colorButtons(recolored, item->new_color); + + original->set_name("original"); + recolored->set_name("recolored"); + original->signal_clicked().connect([this, item, index = list_item->get_position()] { + _selection_model->set_selected(index); + onOriginalColorClicked(item->key); + }); + + recolored->signal_clicked().connect([this, item, index = list_item->get_position()] { + _selection_model->set_selected(index); + onOriginalColorClicked(item->key); + }); + buttons[item->key] = {original, recolored}; + } + }); + + _list_view->set_model(_selection_model); + _list_view->set_factory(_color_factory); + auto lm = _list_view->get_layout_manager(); + if (auto grid_layout = std::dynamic_pointer_cast(lm)) { + grid_layout->set_row_spacing(0); + } + _list_view->set_hexpand(false); + _list_view->set_vexpand(false); + + _selection_model->signal_selection_changed().connect([this](guint pos, guint n_items) { + int index = _selection_model->get_selected(); + if (index < 0) + return; + + auto item = _color_model->get_item(index); + auto color_item = std::dynamic_pointer_cast(item); + if (!color_item) + return; + + onOriginalColorClicked(color_item->key); + }); + _desktop = SP_ACTIVE_DESKTOP; + // _apply = _builder->get_widget("apply"); + // _apply->signal_clicked().connect(sigc::mem_fun(*this, &RecolorArt::_onApplyButtonClicked)); +} +RecolorArt::~RecolorArt() {} + +void RecolorArt::setDesktop(SPDesktop *desktop) +{ + if (_desktop != desktop) { + _desktop = desktop; + } + g_message("setDesktop\n"); +} +void RecolorArt::collectColors(std::vector items) +{ + _selected_colors.clear(); + for (auto item : items) { + extractItemColors(item); + } +} +void RecolorArt::extractItemColors(SPItem *item) +{ + if (item) { + extractItemStyle(item); + } + if (auto group = dynamic_cast(item)) { + for (SPObject &child : group->children) { + if (auto childItem = dynamic_cast(&child)) { + extractItemColors(childItem); + } + } + } +} +void RecolorArt::extractGradientStops(SPItem *item, std::string kind, bool isFill) +{ + SPPaintServer *paint_server = isFill ? item->style->getFillPaintServer() : item->style->getStrokePaintServer(); + if (paint_server && dynamic_cast(paint_server)) { + SPGradient *gradient = dynamic_cast(paint_server); + SPGradient *vectorGradient = gradient->getVector(); + if (vectorGradient) { + if (vectorGradient->hasPatches()) { + vectorGradient->ensureArray(); + std::unique_ptr nodeArray; + if (auto mesh = dynamic_cast(gradient)) { + nodeArray = std::make_unique(mesh); + extractMeshStops(nodeArray->nodes, item, kind); + } + + } else { + vectorGradient->ensureVector(); + // int stopCount = vectorGradient->getStopCount(); + // std::cout << "Stops count : " << stopCount << std::endl; + // std::cout << "has patches : " << vectorGradient->hasPatches() << std::endl; + populateStopsMap(vectorGradient->getFirstStop()); + } + } + for (auto stop : vectorGradient->getGradientVector().stops) { + if (stop.color.has_value()) { + populateMap(stop.color.value(), item, kind); + } + } + } +} +void RecolorArt::extractMeshStops(std::vector> mesh_nodes, SPItem *item, std::string kind) +{ + for (auto nodes : mesh_nodes) { + for (auto node : nodes) { + populateStopsMap(node->stop); + if (node->color.has_value()) { + populateMap(node->color.value(), item, kind); + } + } + } +} +void RecolorArt::populateStopsMap(SPStop *stop) +{ + g_message("populateStopsMap in"); + while (stop) { + std::string color = stop->getColor().toString(); + _gradient_stops[color].push_back(stop); + stop = stop->getNextStop(); + } +} +void RecolorArt::populateMap(Color color, SPItem *item, std::string kind) +{ + ColorRef ref = ColorRef(item, kind); + ColorPair pair = ColorPair(color, color); + if (_selected_colors.count(color.toString())) { + _selected_colors[color.toString()].first.push_back(ref); + } else { + _selected_colors.emplace(color.toString(), std::make_pair(std::vector{ref}, pair)); + } +} +void RecolorArt::extractItemStyle(SPItem *item) +{ + // check item style + if (!item || !item->style) + return; + + SPStyle *style = item->style; + // get flat fills + if (style->fill.isColor()) { + auto color = style->fill.getColor(); + populateMap(color, item, "fill"); + } + // get gradient stops strokes + else if (style->fill.isPaintserver()) { + extractGradientStops(item, "stop", true); + } + + if (style->stroke.isColor()) { + auto color = style->stroke.getColor(); + populateMap(color, item, "stroke"); + } + // get gradient stops strokes + else if (style->stroke.isPaintserver()) { + extractGradientStops(item, "stop", false); + } +} +void RecolorArt::generateVisualList() +{ + _color_model->remove_all(); + buttons.clear(); + for (auto &[key, value] : _selected_colors) { + auto old_color = value.second.value().old_color.toString(); + auto new_color = value.second.value().new_color.toString(); + _color_model->append(ColorItem::create(key, old_color, new_color)); + } + _color_list->append(*_list_view); +} +void RecolorArt::layoutColorPicker(std::shared_ptr updated_color) +{ + if (updated_color) + _solid_colors = updated_color; + _color_picker_wdgt = Gtk::make_managed(_solid_colors); + _color_picker_wdgt->set_visible(true); + _color_picker_wdgt->set_label(_("Selected Color")); + _solid_colors->signal_changed.connect(sigc::mem_fun(*this, &RecolorArt::onColorPickerChanged)); + + auto container = _builder->get_widget("color-picker"); + if (container) { + for (auto child : container->get_children()) + container->remove(*child); + container->append(*_color_picker_wdgt); + } else { + g_warning("color picker not found"); + } +} +void RecolorArt::colorButtons(Gtk::Button *button, std::string color) +{ + if (color.empty() || color.size() < 7 || color[0] != '#') { + g_warning("Invalid color string: %s", color.c_str()); + return; + } + + if (button) { + auto css_provider = Gtk::CssProvider::create(); + Glib::ustring css = "button { background-color: " + Glib::ustring(color) + "; background-image: none;}"; + css_provider->load_from_data(css); + auto style_context = button->get_style_context(); + style_context->add_provider(css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER); + } else { + g_message("button not found"); + } +} +// void RecolorArt::colorBorderOnClick(Gtk::Button *button, bool kind) +// { +// auto &_last_button = kind == 1 ? _last_original_button : _last_recolored_button; +// if (_last_button && _last_button != button) { +// auto style_context = _last_button->get_style_context(); +// style_context->remove_class("selected-button"); +// } +// if (button) { +// auto style_context = button->get_style_context(); +// style_context->add_class("selected-button"); +// _last_button = button; +// } else { +// g_warning("button not found for border coloring"); +// } +// } +void RecolorArt::onOriginalColorClicked(std::string color_id) +{ + _current_color_id = color_id; + auto it = _selected_colors.find(color_id); + auto btns = buttons.find(color_id); + if (it != _selected_colors.end() && it->second.second.has_value() && btns != buttons.end()) { + Color color = it->second.second.value().new_color; + std::shared_ptr updated_color = std::make_shared(); + updated_color->set(color); + layoutColorPicker(updated_color); + // colorBorderOnClick(btns->second.first, 1); + // colorBorderOnClick(btns->second.second, 0); + // g_message("original color selected at color %s", color_id.c_str()); + } +} +void RecolorArt::onColorPickerChanged() +{ + auto it = buttons.find(_current_color_id); + if (it == buttons.end()) { + g_message("couldn't find the color id \" %s \" ", _current_color_id.c_str()); + return; + } + Gtk::Button *_current_recolor_button = it->second.second; + std::optional new_color = _solid_colors->get(); + if (!new_color.has_value()) { + g_message("there is no color"); + return; + } + std::string _color_string = new_color.value().toString(); + colorButtons(_current_recolor_button, _color_string); + auto _selected = _selected_colors.find(_current_color_id); + if (_selected != _selected_colors.end()) + _selected->second.second.value().new_color = new_color.value(); + if (_live_preview && _live_preview->property_active()) { + lpChecked(); + } + guint index = _selection_model->get_selected(); + auto item = _color_model->get_item(index); + auto color_item = std::dynamic_pointer_cast(item); + color_item->new_color = _color_string; + g_message("color picker changed"); +} +void RecolorArt::lpChecked() +{ + auto _selected = _selected_colors.find(_current_color_id); + std::optional new_color = _solid_colors->get(); + if (!new_color.has_value()) { + g_message("there is no color"); + return; + } + std::string _color_string = new_color.value().toString(); + if (_selected == _selected_colors.end()) { + g_message("no items found"); + return; + } + _selected->second.second.value().new_color = new_color.value(); + for (auto &item : _selected->second.first) { + if (item.kind == "stop") + continue; + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property_string(css, item.kind.c_str(), _color_string); + sp_desktop_apply_css_recursive(item.item, css, true); + sp_repr_css_attr_unref(css); + } + recolorStops(_selected->first, new_color.value()); + DocumentUndo::done(_desktop->getDocument(), _("Recolored items"), INKSCAPE_ICON("object-recolor-art")); +} +void RecolorArt::onResetClicked() +{ + for (auto [key, btns] : buttons) { + colorButtons(btns.second, key); + } + + for (auto i = 0; i < _color_model->get_n_items(); i++) { + auto item = _color_model->get_item(i); + auto color_item = std::dynamic_pointer_cast(item); + color_item->new_color = color_item->key; + } + revertToOriginalColors(); + onOriginalColorClicked(buttons.begin()->first); +} +void RecolorArt::revertToOriginalColors() +{ + for (auto [key, items] : _selected_colors) { + for (auto &item : items.first) { + if (item.kind == "stop") + continue; + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property_string(css, item.kind.c_str(), key); + sp_desktop_apply_css_recursive(item.item, css, true); + sp_repr_css_attr_unref(css); + } + recolorStops(key, items.second.value().old_color); + } +} +void RecolorArt::convertToRecoloredColors() +{ + for (auto [key, items] : _selected_colors) { + if (items.second.has_value()) { + std::string new_color = items.second.value().new_color.toString(); + for (auto &item : items.first) { + if (item.kind == "stop") + continue; + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_set_property_string(css, item.kind.c_str(), new_color); + sp_desktop_apply_css_recursive(item.item, css, true); + sp_repr_css_attr_unref(css); + } + recolorStops(key, items.second.value().new_color); + } + } +} +void RecolorArt::recolorStops(std::string old_color, Color new_color) +{ + auto stops_vector = _gradient_stops.find(old_color); + if (stops_vector != _gradient_stops.end()) { + for (auto stop : stops_vector->second) { + stop->setColor(new_color); + } + } +} +void RecolorArt::onLivePreviewToggled() +{ + _is_preview = _live_preview->property_active(); + if (_is_preview) { + convertToRecoloredColors(); + } else { + revertToOriginalColors(); + } + g_message(_is_preview ? "is true" : "is false"); + g_message("LP toggled"); +} +void RecolorArt::performUpdate() +{ + for (auto child : _color_list->get_children()) { + _color_list->remove(*child); + } + buttons.clear(); + _gradient_stops.clear(); + _last_original_button = nullptr; + _last_recolored_button = nullptr; + // _current_color_id = ""; + if (_desktop) { + if (auto selection = _desktop->getSelection()) { + std::vector vec(selection->items().begin(), selection->items().end()); + collectColors(vec); + if (!_selected_colors.empty()) { + generateVisualList(); + auto first_button_id = buttons.begin()->first; + onOriginalColorClicked(first_button_id); + } + } + g_message("Performing Update\n"); + } + else + g_message("Desktop is NULL in Performupdate in recolor widegt\n"); +} +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +// void RecolorArt::_onApplyButtonClicked() +// { +// for (auto [key, items] : _selected_colors) { +// std::string _color_string = items.second.value().new_color.toString(); +// for (auto &item : items.first) { +// SPCSSAttr *css = sp_repr_css_attr_new(); +// sp_repr_css_set_property_string(css, item.kind.c_str(), _color_string); +// sp_desktop_apply_css_recursive(item.item, css, true); +// sp_repr_css_attr_unref(css); +// } +// } +// g_message("apply clicked"); +// } +// if (!_gradient_stops.empty()) { +// for (auto [key, value] : _gradient_stops) { +// std::cout << key << " : "; +// for (auto stop : value) +// std::cout << stop << " "; +// std::cout << std::endl; +// } +// g_message("filled stops map"); + +// } else { +// g_message("empty stops map"); +// } \ No newline at end of file diff --git a/src/ui/widget/recolor-art.h b/src/ui/widget/recolor-art.h new file mode 100644 index 0000000000000000000000000000000000000000..0c9e9eda6a34a5815b094a8612ff24b2ea054106 --- /dev/null +++ b/src/ui/widget/recolor-art.h @@ -0,0 +1,144 @@ + + +#ifndef SEEN_DIALOGS_SP_RECOLOR_ART_H +#define SEEN_DIALOGS_SP_RECOLOR_ART_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "canvas.h" +#include "style-internal.h" +#include "style.h" +#include "ui/widget/paint-selector.h" + +using namespace Inkscape::Colors; + +namespace Inkscape::Colors { +class Color; +class ColorSet; +namespace Space { +class AnySpace; +} +} // namespace Inkscape::Colors + +namespace Gtk { +class Widget; +class Builder; +class ListStore; +class Notebook; +} // namespace Gtk + +class SPDesktop; + +namespace Inkscape { +namespace UI { +namespace Tools { +class ToolBase; +} + +namespace Widget { +class ColorNotebook; + +struct ColorRef +{ + SPItem *item; + std::string kind; +}; + +struct ColorPair +{ + Color old_color; + Color new_color; +}; + +struct ColorItem : public Glib::Object +{ + Glib::ustring key; + Glib::ustring old_color; + Glib::ustring new_color; + + static Glib::RefPtr create(Glib::ustring const &k, Glib::ustring const &old_c, + Glib::ustring const &new_c) + { + auto item = Glib::make_refptr_for_instance(new ColorItem()); + item->key = k; + item->old_color = old_c; + item->new_color = new_c; + return item; + } +}; +class RecolorArt : public Gtk::Box +{ +private: + SPDesktop *_desktop = nullptr; + std::shared_ptr _solid_colors; + std::map, std::optional>> _selected_colors; + Inkscape::UI::Widget::ColorNotebook *_color_picker_wdgt = nullptr; + Gtk::Box *_color_list = nullptr; + Gtk::ListView *_list_view = nullptr; + Gtk::Button *_reset = nullptr; + Gtk::CheckButton *_live_preview = nullptr; + std::string _current_color_id; + std::map> buttons; // color_id : {original , recolored} + bool _is_preview = false; + + Glib::RefPtr> _color_model; + Glib::RefPtr _color_factory; + Glib::RefPtr _selection_model; + + Gtk::Button *_last_original_button = nullptr; + Gtk::Button *_last_recolored_button = nullptr; + + std::map> _gradient_stops; + + Gtk::Notebook *_notebook = nullptr; + Gtk::Box *_color_wheel_page = nullptr; + + // Gtk::Button *_apply = nullptr; + + Glib::RefPtr _builder; + void populateMap(Color color, SPItem *style, std::string kind); + void collectColors(std::vector items); + void extractGradientStops(SPItem *item, std::string kind, bool isFill); + void extractMeshStops(std::vector> mesh_nodes, SPItem *item, std::string kind); + void extractItemColors(SPItem *item); + void extractItemStyle(SPItem *item); + void generateVisualList(); + void layoutColorPicker(std::shared_ptr updated_color = nullptr); + void colorButtons(Gtk::Button *button, std::string color); + // void colorBorderOnClick(Gtk::Button *button, bool kind); + + // signals handelrs + void onOriginalColorClicked(std::string color_id); + void onResetClicked(); + void onColorPickerChanged(); + void onLivePreviewToggled(); + void lpChecked(); + void revertToOriginalColors(); + void convertToRecoloredColors(); + // void _onApplyButtonClicked(); + + void populateStopsMap(SPStop *stop); + void recolorStops(std::string old_color, Color new_color); + +public: + RecolorArt(); + ~RecolorArt(); + void performUpdate(); + bool isInPreviewMode() { return _is_preview; } + void setDesktop(SPDesktop *desktop); +}; + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif // SEEN_DIALOGS_SP_RECOLOR_ART_H