From 399b8c05eae862298b40704fd0d0db35d34f5a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 28 Jan 2024 20:29:34 +0100 Subject: [PATCH 01/30] Create a separate file for ThemePreferencesDialog --- Theme Preferences/ThemePreferencesDialog.lua | 290 ++++++++++++++++ Theme Preferences/extension.lua | 331 ++++++++++--------- 2 files changed, 456 insertions(+), 165 deletions(-) create mode 100644 Theme Preferences/ThemePreferencesDialog.lua diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua new file mode 100644 index 0000000..8e4f5af --- /dev/null +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -0,0 +1,290 @@ +return function(options) + local title = "Theme Preferences: " .. options.name + local titleModified = title .. " (modified)" + + local isModified = options.isModified + local colors = options.colors + + local dialog = Dialog { + title = isModified and titleModified or title, + onclose = options.onclose + } + + function MarkThemeAsModified() + if isModified then return end + isModified = true + + dialog -- + :modify{id = "save-configuration", enabled = true} -- + :modify{title = title .. " (modified)"} + end + + function ThemeColor(widgetOptions) + dialog:color{ + id = widgetOptions.id, + label = widgetOptions.label, + color = colors[widgetOptions.id], + visible = widgetOptions.visible, + onchange = function() + local color = dialog.data[widgetOptions.id] + colors[widgetOptions.id] = color + + if widgetOptions.onchange then + widgetOptions.onchange(color) + end + + MarkThemeAsModified() + end + } + end + + dialog -- + :radio{ + id = "mode-simple", + label = "Mode", + text = "Simple", + selected = true, + onclick = function() ChangeMode() end + } -- + :radio{ + id = "mode-advanced", + text = "Advanced", + selected = false, + onclick = function() ChangeMode() end + } + + dialog:separator{text = "Text"} + + ThemeColor {label = "Active/Regular", id = "text_active", visible = true} + ThemeColor { + id = "text_regular", + visible = true, + onchange = function(color) + if dialog.data["mode-simple"] then + SetThemeColor("editor_icons", color) + end + end + } + ThemeColor {label = "Link/Separator", id = "text_link", visible = false} + ThemeColor {id = "text_separator", visible = false} + + dialog:color{ + id = "simple-link", + label = "Link/Separator", + color = colors["text_link"], + onchange = function() + local color = dialog.data["simple-link"] + + SetThemeColor("text_link", color) + SetThemeColor("text_separator", color) + + MarkThemeAsModified() + end + } + + dialog:separator{text = "Input Fields"} + + ThemeColor {label = "Highlight", id = "field_highlight", visible = true} + + -- FUTURE: Allow for separate chaning of the "field_background" + -- dialog:color{ + -- id = "simple-field", + -- label = "Background", + -- color = colors["field_background"], + -- onchange = function() + -- local color = dialog.data["simple-field"] + + -- local shadowColor = Color { + -- red = ShiftRGB(color.red, -57), + -- green = ShiftRGB(color.green, -57), + -- blue = ShiftRGB(color.blue, -57), + -- alpha = color.alpha + -- } + + -- local cornerShadowColor = Color { + -- red = ShiftRGB(color.red, -74), + -- green = ShiftRGB(color.green, -74), + -- blue = ShiftRGB(color.blue, -74), + -- alpha = color.alpha + -- } + + -- colors["field_background"] = color + -- colors["field_shadow"] = shadowColor + -- colors["field_corner_shadow"] = cornerShadowColor + -- end + -- } + + dialog:separator{text = "Editor"} + + ThemeColor { + label = "Background", + id = "editor_background", + onchange = function(color) + local shadowColor = ShiftColor(color, -36, -20, -53) + colors["editor_background_shadow"] = shadowColor + end + } + + ThemeColor {label = "Icons", id = "editor_icons", visible = false} + + ThemeColor { + label = "Tooltip", + id = "editor_tooltip", + onchange = function(color) + local shadowColor = ShiftColor(color, -100, -90, -32) + local cornerShadowColor = ShiftColor(color, -125, -152, -94) + + colors["editor_tooltip_shadow"] = shadowColor + colors["editor_tooltip_corner_shadow"] = cornerShadowColor + end + } + + dialog -- + :color{ + id = "editor_cursor", + label = "Cursor", + color = colors["editor_cursor"], + onchange = function() ChangeCursorColors() end + } -- + :color{ + id = "editor_cursor_outline", + color = colors["editor_cursor_outline"], + onchange = function() ChangeCursorColors() end + } + + dialog:separator{text = "Button"} + + ThemeColor {id = "button_highlight", visible = false} + ThemeColor {id = "button_background", visible = false} + ThemeColor {id = "button_shadow", visible = false} + + dialog:color{ + id = "simple-button", + color = colors["button_background"], + onchange = function() + local color = dialog.data["simple-button"] + local highlightColor = ShiftColor(color, 57, 57, 57) + local shadowColor = ShiftColor(color, -74, -74, -74) + + SetThemeColor("button_highlight", highlightColor) + SetThemeColor("button_background", color) + SetThemeColor("button_shadow", shadowColor) + + MarkThemeAsModified() + end + } + + ThemeColor {label = "Selected", id = "button_selected", visible = true} + + dialog:separator{text = "Tab"} + + ThemeColor {id = "tab_corner_highlight", visible = false} + ThemeColor {id = "tab_highlight", visible = false} + ThemeColor {id = "tab_background", visible = false} + ThemeColor {id = "tab_shadow", visible = false} + + dialog:color{ + id = "simple-tab", + color = colors["tab_background"], + onchange = function() + local color = dialog.data["simple-tab"] + local cornerHighlightColor = ShiftColor(color, 131, 110, 98) + local highlightColor = ShiftColor(color, 49, 57, 65) + local shadowColor = ShiftColor(color, -24, -61, -61) + + SetThemeColor("tab_corner_highlight", cornerHighlightColor) + SetThemeColor("tab_highlight", highlightColor) + SetThemeColor("tab_background", color) + SetThemeColor("tab_shadow", shadowColor) + + MarkThemeAsModified() + end + } + + dialog:separator{text = "Window"} + + ThemeColor { + id = "window_highlight", + visible = false, + onchange = function(color) + colors["window_highlight"] = color + + -- FUTURE: Remove this when setting a separate value for the "field_background" is possible + + local fieldShadowColor = ShiftColor(color, -57, -57, -57) + local filedCornerShadowColor = ShiftColor(color, -74, -74, -74) + + colors["field_background"] = color + colors["field_shadow"] = fieldShadowColor + colors["field_corner_shadow"] = filedCornerShadowColor + end + } + + ThemeColor {id = "window_background", visible = false} + + ThemeColor { + id = "window_shadow", + visible = false, + onchange = function(color) + local cornerShadowColor = ShiftColor(color, -49, -44, -20) + SetThemeColor("window_corner_shadow", cornerShadowColor) + end + } + + dialog:color{ + id = "simple-window", + color = colors["window_background"], + onchange = function() + local color = dialog.data["simple-window"] + local highlightColor = ShiftColor(color, 45, 54, 66) + local shadowColor = ShiftColor(color, -61, -73, -73) + local cornerShadowColor = ShiftColor(color, -110, -117, -93) + + SetThemeColor("window_highlight", highlightColor) + SetThemeColor("window_background", color) + SetThemeColor("window_shadow", shadowColor) + SetThemeColor("window_corner_shadow", cornerShadowColor) + + -- FUTURE: Remove this when setting a separate value for the "field_background" is possible + + local fieldShadowColor = ShiftColor(highlightColor, -57, -57, -57) + local filedCornerShadowColor = + ShiftColor(highlightColor, -74, -74, -74) + + colors["field_background"] = highlightColor + colors["field_shadow"] = fieldShadowColor + colors["field_corner_shadow"] = filedCornerShadowColor + + MarkThemeAsModified() + end + } -- + + ThemeColor {label = "Hover", id = "window_hover", visible = true} + + dialog -- + :separator() -- + :button{ + id = "save-configuration", + label = "Configuration", + text = "Save", + enabled = isModified, -- Only allows saving of a modified theme + -- TODO: Add SaveAs option + onclick = function() options.onsave() end + } -- + :button{text = "Load", onclick = function() options.onload() end} -- + :button{text = "Font", onclick = function() options.onfont() end} + + dialog -- + :separator() -- + :button{ + text = "OK", + onclick = function() + options.onok() + dialog:close() + end + } -- + :button{text = "Apply", onclick = function() options.onok() end} -- + :button{text = "Cancel", onclick = function() dialog:close() end} -- + + return dialog +end diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 9dfa915..69b36b1 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -1,6 +1,7 @@ local Template = dofile("./Template.lua") local ThemeManager = dofile("./ThemeManager.lua") local FontsProvider = dofile("./FontsProvider.lua") +local ThemePreferencesDialog = dofile("./ThemePreferencesDialog.lua") local THEME_ID = "custom" local DIALOG_WIDTH = 240 @@ -66,33 +67,30 @@ for id, parameter in pairs(Template.parameters) do end -- Dialog -local ThemePreferencesDialog = { - isModified = false, - lastRefreshState = false, - isDialogOpen = false, - onClose = nil, - dialog = nil -} +local isModified = false +local lastRefreshState = false +local isDialogOpen = false +local onClose = nil -ThemePreferencesDialog.dialog = Dialog { +local dialog = Dialog { title = DIALOG_TITLE, - onclose = function() ThemePreferencesDialog:onClose() end + onclose = function() if onClose then onClose() end end } -function ThemePreferencesDialog:SetInitialWidth() - self.dialog:show{wait = false} - self.dialog:close() +function SetInitialWidth() + dialog:show{wait = false} + dialog:close() local uiScale = app.preferences.general["ui_scale"] - local bounds = self.dialog.bounds + local bounds = dialog.bounds bounds.x = bounds.x - (DIALOG_WIDTH - bounds.width) / 2 bounds.width = DIALOG_WIDTH * uiScale - self.dialog.bounds = bounds + dialog.bounds = bounds end -function ThemePreferencesDialog:RefreshTheme(template, theme) +function RefreshTheme(template, theme) -- Prepare color lookup local Map = {} @@ -145,12 +143,12 @@ function ThemePreferencesDialog:RefreshTheme(template, theme) image:saveAs(SheetPath) -- Update the XML theme file - ThemePreferencesDialog:UpdateThemeXml(theme) + UpdateThemeXml(theme) app.command.Refresh() end -function ThemePreferencesDialog:UpdateThemeXml(theme) +function UpdateThemeXml(theme) -- Prepare theme.xml local xmlContent = ReadAll(ThemeXmlTemplatePath) @@ -176,10 +174,10 @@ function ThemePreferencesDialog:UpdateThemeXml(theme) WriteAll(ThemeXmlPath, xmlContent) end -function ThemePreferencesDialog:Refresh() - self.lastRefreshState = self.isModified +function Refresh() + lastRefreshState = isModified - self:RefreshTheme(Template, Theme) + RefreshTheme(Template, Theme) ThemeManager:SetCurrentTheme(Theme) -- Switch Aseprite to the custom theme @@ -201,25 +199,25 @@ function ShiftColor(color, redModifier, greenModifer, blueModifier) } end -function ThemePreferencesDialog:MarkThemeAsModified() - self.isModified = true +function MarkThemeAsModified() + isModified = true - self.dialog -- + dialog -- :modify{id = "save-configuration", enabled = true} -- :modify{title = DIALOG_TITLE .. ": " .. Theme.name .. " (modified)"} end -function ThemePreferencesDialog:SetThemeColor(id, color) +function SetThemeColor(id, color) Theme.colors[id] = color - if self.dialog.data[id] then self.dialog:modify{id = id, color = color} end + if dialog.data[id] then dialog:modify{id = id, color = color} end end -function ThemePreferencesDialog:ChangeMode(options) +function ChangeMode(options) -- Set default options options = options or {} options.force = options.force ~= nil and options.force or false - local isSimple = self.dialog.data["mode-simple"] + local isSimple = dialog.data["mode-simple"] if isSimple then if not options.force then @@ -230,14 +228,14 @@ function ThemePreferencesDialog:ChangeMode(options) } if confirmation == 2 then - self.dialog:modify{id = "mode-simple", selected = false} - self.dialog:modify{id = "mode-advanced", selected = true} + dialog:modify{id = "mode-simple", selected = false} + dialog:modify{id = "mode-advanced", selected = true} return end end -- Set new simple values when switching to Simple Mode - self.dialog -- + dialog -- :modify{id = "simple-link", color = Theme.colors["text_link"]} -- :modify{id = "simple-button", color = Theme.colors["button_background"]} -- :modify{id = "simple-tab", color = Theme.colors["tab_background"]} -- @@ -245,7 +243,7 @@ function ThemePreferencesDialog:ChangeMode(options) :modify{id = "editor_icons", color = Theme.colors["text_regular"]} end - self.dialog -- + dialog -- :modify{id = "simple-link", visible = isSimple} -- :modify{id = "simple-button", visible = isSimple} -- :modify{id = "simple-tab", visible = isSimple} -- @@ -259,24 +257,24 @@ function ThemePreferencesDialog:ChangeMode(options) } for _, id in ipairs(advancedWidgetIds) do - self.dialog:modify{id = id, visible = self.dialog.data["mode-advanced"]} + dialog:modify{id = id, visible = dialog.data["mode-advanced"]} end - Theme.parameters.isAdvanced = self.dialog.data["mode-advanced"] - self:MarkThemeAsModified() + Theme.parameters.isAdvanced = dialog.data["mode-advanced"] + MarkThemeAsModified() end -function ThemePreferencesDialog:LoadTheme(theme) +function LoadTheme(theme) -- Copy theme to the current theme Theme.name = theme.name Theme.parameters = theme.parameters -- Chanage mode - self.dialog -- + dialog -- :modify{id = "mode-simple", selected = not theme.parameters.isAdvanced} -- :modify{id = "mode-advanced", selected = theme.parameters.isAdvanced} - self:ChangeMode{force = true} + ChangeMode {force = true} -- Load simple versions first to then overwrite advanced colors local simpleButtons = { @@ -288,41 +286,41 @@ function ThemePreferencesDialog:LoadTheme(theme) } for id, color in pairs(simpleButtons) do - self.dialog:modify{id = id, color = color} + dialog:modify{id = id, color = color} end -- Finally, copy colors for id, color in pairs(theme.colors) do -- Copy color just in case - self:SetThemeColor(id, CopyColor(color)) + SetThemeColor(id, CopyColor(color)) end - self.dialog:modify{title = DIALOG_TITLE .. ": " .. theme.name} -- - self.dialog:modify{id = "save-configuration", enabled = false} + dialog:modify{title = DIALOG_TITLE .. ": " .. theme.name} -- + dialog:modify{id = "save-configuration", enabled = false} - self.isModified = false + isModified = false end -function ThemePreferencesDialog:ThemeColor(options) - self.dialog:color{ +function ThemeColor(options) + dialog:color{ id = options.id, label = options.label, color = Theme.colors[options.id], visible = options.visible, onchange = function() - local color = self.dialog.data[options.id] + local color = dialog.data[options.id] Theme.colors[options.id] = color if options.onchange then options.onchange(color) end - self:MarkThemeAsModified() + MarkThemeAsModified() end } end -function ThemePreferencesDialog:ChangeCursorColors() - local color = self.dialog.data["editor_cursor"] - local outlinecolor = self.dialog.data["editor_cursor_outline"] +function ChangeCursorColors() + local color = dialog.data["editor_cursor"] + local outlinecolor = dialog.data["editor_cursor_outline"] local shadowColor = Color { red = (color.red + outlinecolor.red) / 2, @@ -335,15 +333,15 @@ function ThemePreferencesDialog:ChangeCursorColors() Theme.colors["editor_cursor_shadow"] = shadowColor Theme.colors["editor_cursor_outline"] = outlinecolor - self:MarkThemeAsModified() + MarkThemeAsModified() end -function ThemePreferencesDialog:LoadCurrentTheme() +function LoadCurrentTheme() local currentTheme = ThemeManager:GetCurrentTheme() - if currentTheme then self:LoadTheme(currentTheme) end + if currentTheme then LoadTheme(currentTheme) end end -function ThemePreferencesDialog:Init() +function Init() -- Colors = Tint, Highlight, Tooltip (label as Hover) -- Link/Separator = Tint Color @@ -352,7 +350,7 @@ function ThemePreferencesDialog:Init() -- Tooltip = Tooltip -- Hover = 50/50 Tooltip/Window Background Color - self.dialog -- + dialog -- -- :radio{ -- id = "mode-tint", -- label = "Mode", @@ -365,51 +363,47 @@ function ThemePreferencesDialog:Init() label = "Mode", text = "Simple", selected = true, - onclick = function() self:ChangeMode() end + onclick = function() ChangeMode() end } -- :radio{ id = "mode-advanced", text = "Advanced", selected = false, - onclick = function() self:ChangeMode() end + onclick = function() ChangeMode() end } - self.dialog:separator{text = "Text"} + dialog:separator{text = "Text"} - self:ThemeColor{ - label = "Active/Regular", - id = "text_active", - visible = true - } - self:ThemeColor{ + ThemeColor {label = "Active/Regular", id = "text_active", visible = true} + ThemeColor { id = "text_regular", visible = true, onchange = function(color) - if self.dialog.data["mode-simple"] then - self:SetThemeColor("editor_icons", color) + if dialog.data["mode-simple"] then + SetThemeColor("editor_icons", color) end end } - self:ThemeColor{label = "Link/Separator", id = "text_link", visible = false} - self:ThemeColor{id = "text_separator", visible = false} + ThemeColor {label = "Link/Separator", id = "text_link", visible = false} + ThemeColor {id = "text_separator", visible = false} - self.dialog:color{ + dialog:color{ id = "simple-link", label = "Link/Separator", color = Theme.colors["text_link"], onchange = function() - local color = self.dialog.data["simple-link"] + local color = dialog.data["simple-link"] - self:SetThemeColor("text_link", color) - self:SetThemeColor("text_separator", color) + SetThemeColor("text_link", color) + SetThemeColor("text_separator", color) - self:MarkThemeAsModified() + MarkThemeAsModified() end } - self.dialog:separator{text = "Input Fields"} + dialog:separator{text = "Input Fields"} - self:ThemeColor{label = "Highlight", id = "field_highlight", visible = true} + ThemeColor {label = "Highlight", id = "field_highlight", visible = true} -- FUTURE: Allow for separate chaning of the "field_background" -- dialog:color{ @@ -439,9 +433,9 @@ function ThemePreferencesDialog:Init() -- end -- } - self.dialog:separator{text = "Editor"} + dialog:separator{text = "Editor"} - self:ThemeColor{ + ThemeColor { label = "Background", id = "editor_background", onchange = function(color) @@ -450,9 +444,9 @@ function ThemePreferencesDialog:Init() end } - self:ThemeColor{label = "Icons", id = "editor_icons", visible = false} + ThemeColor {label = "Icons", id = "editor_icons", visible = false} - self:ThemeColor{ + ThemeColor { label = "Tooltip", id = "editor_tooltip", onchange = function(color) @@ -464,71 +458,71 @@ function ThemePreferencesDialog:Init() end } - self.dialog -- + dialog -- :color{ id = "editor_cursor", label = "Cursor", color = Theme.colors["editor_cursor"], - onchange = function() self:ChangeCursorColors() end + onchange = function() ChangeCursorColors() end } -- :color{ id = "editor_cursor_outline", color = Theme.colors["editor_cursor_outline"], - onchange = function() self:ChangeCursorColors() end + onchange = function() ChangeCursorColors() end } - self.dialog:separator{text = "Button"} + dialog:separator{text = "Button"} - self:ThemeColor{id = "button_highlight", visible = false} - self:ThemeColor{id = "button_background", visible = false} - self:ThemeColor{id = "button_shadow", visible = false} + ThemeColor {id = "button_highlight", visible = false} + ThemeColor {id = "button_background", visible = false} + ThemeColor {id = "button_shadow", visible = false} - self.dialog:color{ + dialog:color{ id = "simple-button", color = Theme.colors["button_background"], onchange = function() - local color = self.dialog.data["simple-button"] + local color = dialog.data["simple-button"] local highlightColor = ShiftColor(color, 57, 57, 57) local shadowColor = ShiftColor(color, -74, -74, -74) - self:SetThemeColor("button_highlight", highlightColor) - self:SetThemeColor("button_background", color) - self:SetThemeColor("button_shadow", shadowColor) + SetThemeColor("button_highlight", highlightColor) + SetThemeColor("button_background", color) + SetThemeColor("button_shadow", shadowColor) - self:MarkThemeAsModified() + MarkThemeAsModified() end } - self:ThemeColor{label = "Selected", id = "button_selected", visible = true} + ThemeColor {label = "Selected", id = "button_selected", visible = true} - self.dialog:separator{text = "Tab"} + dialog:separator{text = "Tab"} - self:ThemeColor{id = "tab_corner_highlight", visible = false} - self:ThemeColor{id = "tab_highlight", visible = false} - self:ThemeColor{id = "tab_background", visible = false} - self:ThemeColor{id = "tab_shadow", visible = false} + ThemeColor {id = "tab_corner_highlight", visible = false} + ThemeColor {id = "tab_highlight", visible = false} + ThemeColor {id = "tab_background", visible = false} + ThemeColor {id = "tab_shadow", visible = false} - self.dialog:color{ + dialog:color{ id = "simple-tab", color = Theme.colors["tab_background"], onchange = function() - local color = self.dialog.data["simple-tab"] + local color = dialog.data["simple-tab"] local cornerHighlightColor = ShiftColor(color, 131, 110, 98) local highlightColor = ShiftColor(color, 49, 57, 65) local shadowColor = ShiftColor(color, -24, -61, -61) - self:SetThemeColor("tab_corner_highlight", cornerHighlightColor) - self:SetThemeColor("tab_highlight", highlightColor) - self:SetThemeColor("tab_background", color) - self:SetThemeColor("tab_shadow", shadowColor) + SetThemeColor("tab_corner_highlight", cornerHighlightColor) + SetThemeColor("tab_highlight", highlightColor) + SetThemeColor("tab_background", color) + SetThemeColor("tab_shadow", shadowColor) - self:MarkThemeAsModified() + MarkThemeAsModified() end } - self.dialog:separator{text = "Window"} + dialog:separator{text = "Window"} - self:ThemeColor{ + ThemeColor { id = "window_highlight", visible = false, onchange = function(color) @@ -545,30 +539,30 @@ function ThemePreferencesDialog:Init() end } - self:ThemeColor{id = "window_background", visible = false} + ThemeColor {id = "window_background", visible = false} - self:ThemeColor{ + ThemeColor { id = "window_shadow", visible = false, onchange = function(color) local cornerShadowColor = ShiftColor(color, -49, -44, -20) - self:SetThemeColor("window_corner_shadow", cornerShadowColor) + SetThemeColor("window_corner_shadow", cornerShadowColor) end } - self.dialog:color{ + dialog:color{ id = "simple-window", color = Theme.colors["window_background"], onchange = function() - local color = self.dialog.data["simple-window"] + local color = dialog.data["simple-window"] local highlightColor = ShiftColor(color, 45, 54, 66) local shadowColor = ShiftColor(color, -61, -73, -73) local cornerShadowColor = ShiftColor(color, -110, -117, -93) - self:SetThemeColor("window_highlight", highlightColor) - self:SetThemeColor("window_background", color) - self:SetThemeColor("window_shadow", shadowColor) - self:SetThemeColor("window_corner_shadow", cornerShadowColor) + SetThemeColor("window_highlight", highlightColor) + SetThemeColor("window_background", color) + SetThemeColor("window_shadow", shadowColor) + SetThemeColor("window_corner_shadow", cornerShadowColor) -- FUTURE: Remove this when setting a separate value for the "field_background" is possible @@ -580,13 +574,13 @@ function ThemePreferencesDialog:Init() Theme.colors["field_shadow"] = fieldShadowColor Theme.colors["field_corner_shadow"] = filedCornerShadowColor - self:MarkThemeAsModified() + MarkThemeAsModified() end } -- - self:ThemeColor{label = "Hover", id = "window_hover", visible = true} + ThemeColor {label = "Hover", id = "window_hover", visible = true} - self.dialog -- + dialog -- :separator() -- :button{ id = "save-configuration", @@ -595,11 +589,11 @@ function ThemePreferencesDialog:Init() enabled = false, onclick = function() local onsave = function(theme) - self.dialog:modify{title = DIALOG_TITLE .. ": " .. theme.name} - self.dialog:modify{id = "save-configuration", enabled = false} + dialog:modify{title = DIALOG_TITLE .. ": " .. theme.name} + dialog:modify{id = "save-configuration", enabled = false} - self.isModified = false - self.lastRefreshState = false + isModified = false + lastRefreshState = false end ThemeManager:Save(Theme, onsave) @@ -609,50 +603,50 @@ function ThemePreferencesDialog:Init() text = "Load", onclick = function() local onload = function(theme) - self:LoadTheme(theme) - self:Refresh() + LoadTheme(theme) + Refresh() end local onreset = function() - self:LoadTheme(Template) - self:Refresh() + LoadTheme(Template) + Refresh() end -- Hide the Theme Preferences dialog - ThemePreferencesDialog.dialog:close() + dialog:close() ThemeManager:Load(onload, onreset) -- Reopen the dialog - ThemePreferencesDialog.dialog:show{wait = false} + dialog:show{wait = false} end } -- :button{ text = "Font", onclick = function() - local onconfirm = function() self:Refresh() end + local onconfirm = function() Refresh() end -- Hide the Theme Preferences dialog - ThemePreferencesDialog.dialog:close() + dialog:close() FontsProvider:OpenDialog(onconfirm) -- Reopen the dialog - ThemePreferencesDialog.dialog:show{wait = false} + dialog:show{wait = false} end } - self.dialog -- + dialog -- :separator() -- :button{ text = "OK", onclick = function() - self:Refresh() - self.dialog:close() + Refresh() + dialog:close() end } -- - :button{text = "Apply", onclick = function() self:Refresh() end} -- - :button{text = "Cancel", onclick = function() self.dialog:close() end} -- + :button{text = "Apply", onclick = function() Refresh() end} -- + :button{text = "Cancel", onclick = function() dialog:close() end} -- end function init(plugin) @@ -668,64 +662,71 @@ function init(plugin) FontsProvider:Init{storage = storage} -- Initialize the diaog - ThemePreferencesDialog:Init() + Init() -- Initialize data from plugin preferences - ThemePreferencesDialog:LoadCurrentTheme() - ThemePreferencesDialog.isModified = plugin.preferences.themePreferences - .isThemeModified - if ThemePreferencesDialog.isModified then - ThemePreferencesDialog:MarkThemeAsModified() - end + LoadCurrentTheme() + isModified = plugin.preferences.themePreferences.isThemeModified + if isModified then MarkThemeAsModified() end -- Treat the "Modified" state as the last known refresh state - ThemePreferencesDialog.lastRefreshState = ThemePreferencesDialog.isModified + lastRefreshState = isModified -- Setup function to be called on close - ThemePreferencesDialog.onClose = function() - ThemePreferencesDialog:LoadCurrentTheme() + onClose = function() + LoadCurrentTheme() - ThemePreferencesDialog.isModified = - ThemePreferencesDialog.lastRefreshState - if ThemePreferencesDialog.isModified then - ThemePreferencesDialog:MarkThemeAsModified() - end + isModified = lastRefreshState + if isModified then MarkThemeAsModified() end - ThemePreferencesDialog.isDialogOpen = false + isDialogOpen = false end -- Set the initial width of the dialog - ThemePreferencesDialog:SetInitialWidth() + SetInitialWidth() plugin:newCommand{ id = "ThemePreferences", title = DIALOG_TITLE .. "...", group = "view_screen", - onenabled = function() - return not ThemePreferencesDialog.isDialogOpen - end, + onenabled = function() return not isDialogOpen end, onclick = function() -- Refreshing the UI on open to fix the issue where the dialog would keep parts of the old theme app.command.Refresh() -- Show Theme Preferences dialog - ThemePreferencesDialog.dialog:show{wait = false} + dialog:show{wait = false} -- Treat the "Modified" state as the last known refresh state - ThemePreferencesDialog.lastRefreshState = - ThemePreferencesDialog.isModified + lastRefreshState = isModified -- Update the dialog if the theme is modified - if ThemePreferencesDialog.isModified then - ThemePreferencesDialog:MarkThemeAsModified() - end + if isModified then MarkThemeAsModified() end + + isDialogOpen = true + end + } - ThemePreferencesDialog.isDialogOpen = true + plugin:newCommand{ + id = "ThemePreferencesNew", + title = DIALOG_TITLE .. " (New)...", + group = "view_screen", + onenabled = function() return not isDialogOpen end, + onclick = function() + local newDialog = ThemePreferencesDialog { + name = Theme.name, + colors = Theme.colors, + onclose = function() print("Close") end, + onsave = function() print("Save") end, + onload = function() print("Load") end, + onfont = function() print("Font") end, + onok = function() print("Ok") end + } + newDialog:show{} end } end function exit(plugin) - plugin.preferences.themePreferences.isThemeModified = - ThemePreferencesDialog.isModified + plugin.preferences.themePreferences.isThemeModified = isModified end From 8da9845fac05f4972cc1a86a62d21b3863f3f1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 28 Jan 2024 20:46:57 +0100 Subject: [PATCH 02/30] No longer overwrite passed theme in ThemePreferencesDialog --- Theme Preferences/ThemePreferencesDialog.lua | 126 ++++++++++++------- 1 file changed, 84 insertions(+), 42 deletions(-) diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 8e4f5af..a982f32 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -1,3 +1,12 @@ +function ShiftColor(color, redModifier, greenModifer, blueModifier) + return Color { + red = ShiftRGB(color.red, redModifier), + green = ShiftRGB(color.green, greenModifer), + blue = ShiftRGB(color.blue, blueModifier), + alpha = color.alpha + } +end + return function(options) local title = "Theme Preferences: " .. options.name local titleModified = title .. " (modified)" @@ -26,10 +35,8 @@ return function(options) color = colors[widgetOptions.id], visible = widgetOptions.visible, onchange = function() - local color = dialog.data[widgetOptions.id] - colors[widgetOptions.id] = color - if widgetOptions.onchange then + local color = dialog.data[widgetOptions.id] widgetOptions.onchange(color) end @@ -61,7 +68,7 @@ return function(options) visible = true, onchange = function(color) if dialog.data["mode-simple"] then - SetThemeColor("editor_icons", color) + dialog:modify{id = "editor_icons", color = color} end end } @@ -75,8 +82,8 @@ return function(options) onchange = function() local color = dialog.data["simple-link"] - SetThemeColor("text_link", color) - SetThemeColor("text_separator", color) + dialog:modify{id = "text_link", color = color} + dialog:modify{id = "text_separator", color = color} MarkThemeAsModified() end @@ -120,22 +127,31 @@ return function(options) label = "Background", id = "editor_background", onchange = function(color) - local shadowColor = ShiftColor(color, -36, -20, -53) - colors["editor_background_shadow"] = shadowColor + dialog:modify{ + id = "editor_background_shadow", + color = ShiftColor(color, -36, -20, -53) + } end } + ThemeColor {id = "editor_tooltip_shadow", visible = false} + ThemeColor {id = "editor_tooltip_corner_shadow", visible = false} + ThemeColor {id = "editor_background_shadow", visible = false} + ThemeColor {label = "Icons", id = "editor_icons", visible = false} ThemeColor { label = "Tooltip", id = "editor_tooltip", onchange = function(color) - local shadowColor = ShiftColor(color, -100, -90, -32) - local cornerShadowColor = ShiftColor(color, -125, -152, -94) - - colors["editor_tooltip_shadow"] = shadowColor - colors["editor_tooltip_corner_shadow"] = cornerShadowColor + dialog:modify{ + id = "editor_tooltip_shadow", + color = ShiftColor(color, -100, -90, -32) + } + dialog:modify{ + id = "editor_tooltip_corner_shadow", + color = ShiftColor(color, -125, -152, -94) + } end } @@ -163,12 +179,16 @@ return function(options) color = colors["button_background"], onchange = function() local color = dialog.data["simple-button"] - local highlightColor = ShiftColor(color, 57, 57, 57) - local shadowColor = ShiftColor(color, -74, -74, -74) - SetThemeColor("button_highlight", highlightColor) - SetThemeColor("button_background", color) - SetThemeColor("button_shadow", shadowColor) + dialog:modify{ + id = "button_highlight", + color = ShiftColor(color, 57, 57, 57) + } + dialog:modify{id = "button_background", color = color} + dialog:modify{ + id = "button_shadow", + color = ShiftColor(color, -74, -74, -74) + } MarkThemeAsModified() end @@ -188,14 +208,20 @@ return function(options) color = colors["tab_background"], onchange = function() local color = dialog.data["simple-tab"] - local cornerHighlightColor = ShiftColor(color, 131, 110, 98) - local highlightColor = ShiftColor(color, 49, 57, 65) - local shadowColor = ShiftColor(color, -24, -61, -61) - SetThemeColor("tab_corner_highlight", cornerHighlightColor) - SetThemeColor("tab_highlight", highlightColor) - SetThemeColor("tab_background", color) - SetThemeColor("tab_shadow", shadowColor) + dialog:modify{ + id = "tab_corner_highlight", + color = ShiftColor(color, 131, 110, 98) + } + dialog:modify{ + id = "tab_highlight", + color = ShiftColor(color, 49, 57, 65) + } + dialog:modify{id = "tab_background", color = color} + dialog:modify{ + id = "tab_shadow", + color = ShiftColor(color, -24, -61, -61) + } MarkThemeAsModified() end @@ -207,16 +233,17 @@ return function(options) id = "window_highlight", visible = false, onchange = function(color) - colors["window_highlight"] = color - -- FUTURE: Remove this when setting a separate value for the "field_background" is possible local fieldShadowColor = ShiftColor(color, -57, -57, -57) local filedCornerShadowColor = ShiftColor(color, -74, -74, -74) - colors["field_background"] = color - colors["field_shadow"] = fieldShadowColor - colors["field_corner_shadow"] = filedCornerShadowColor + dialog:modify{id = "field_background", color = color} + dialog:modify{id = "field_shadow", color = fieldShadowColor} + dialog:modify{ + id = "field_corner_shadow", + color = filedCornerShadowColor + } end } @@ -226,24 +253,34 @@ return function(options) id = "window_shadow", visible = false, onchange = function(color) - local cornerShadowColor = ShiftColor(color, -49, -44, -20) - SetThemeColor("window_corner_shadow", cornerShadowColor) + dialog:modify{ + id = "window_corner_shadow", + color = ShiftColor(color, -49, -44, -20) + } end } + ThemeColor {id = "field_background", visible = false} + ThemeColor {id = "field_shadow", visible = false} + ThemeColor {id = "field_corner_shadow", visible = false} + dialog:color{ id = "simple-window", color = colors["window_background"], onchange = function() local color = dialog.data["simple-window"] local highlightColor = ShiftColor(color, 45, 54, 66) - local shadowColor = ShiftColor(color, -61, -73, -73) - local cornerShadowColor = ShiftColor(color, -110, -117, -93) - SetThemeColor("window_highlight", highlightColor) - SetThemeColor("window_background", color) - SetThemeColor("window_shadow", shadowColor) - SetThemeColor("window_corner_shadow", cornerShadowColor) + dialog:modify{id = "window_highlight", color = highlightColor} + dialog:modify{id = "window_background", color = color} + dialog:modify{ + id = "window_shadow", + color = ShiftColor(color, -61, -73, -73) + } + dialog:modify{ + id = "window_corner_shadow", + color = ShiftColor(color, -110, -117, -93) + } -- FUTURE: Remove this when setting a separate value for the "field_background" is possible @@ -251,9 +288,12 @@ return function(options) local filedCornerShadowColor = ShiftColor(highlightColor, -74, -74, -74) - colors["field_background"] = highlightColor - colors["field_shadow"] = fieldShadowColor - colors["field_corner_shadow"] = filedCornerShadowColor + dialog:modify{id = "field_background", color = highlightColor} + dialog:modify{id = "field_shadow", color = fieldShadowColor} + dialog:modify{ + id = "field_corner_shadow", + color = filedCornerShadowColor + } MarkThemeAsModified() end @@ -268,7 +308,6 @@ return function(options) label = "Configuration", text = "Save", enabled = isModified, -- Only allows saving of a modified theme - -- TODO: Add SaveAs option onclick = function() options.onsave() end } -- :button{text = "Load", onclick = function() options.onload() end} -- @@ -288,3 +327,6 @@ return function(options) return dialog end + +-- TODO: Add SaveAs button +-- TODO: Add Reset button From 2de19887fefbed5ac55699bdfd5ab9a808fdf4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 28 Jan 2024 21:06:53 +0100 Subject: [PATCH 03/30] Reconnect simple saving to the new dialog --- Theme Preferences/ThemePreferencesDialog.lua | 4 ++-- Theme Preferences/extension.lua | 23 +++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index a982f32..dea6382 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -318,11 +318,11 @@ return function(options) :button{ text = "OK", onclick = function() - options.onok() + options.onok(dialog.data) dialog:close() end } -- - :button{text = "Apply", onclick = function() options.onok() end} -- + :button{text = "Apply", onclick = function() options.onok(dialog.data) end} -- :button{text = "Cancel", onclick = function() dialog:close() end} -- return dialog diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 69b36b1..f0b00f1 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -92,11 +92,11 @@ end function RefreshTheme(template, theme) -- Prepare color lookup - local Map = {} + local map = {} for id, templateColor in pairs(template.colors) do -- Map the template color to the theme color - Map[ColorToHex(templateColor)] = theme.colors[id] + map[ColorToHex(templateColor)] = theme.colors[id] end -- Prepare sheet.png @@ -128,7 +128,7 @@ function RefreshTheme(template, theme) pixelData = cache[pixelValueKey] end - resultColor = Map[pixelData.id] + resultColor = map[pixelData.id] if resultColor ~= nil then newColor = CopyColor(resultColor) @@ -720,9 +720,22 @@ function init(plugin) onsave = function() print("Save") end, onload = function() print("Load") end, onfont = function() print("Font") end, - onok = function() print("Ok") end + onok = function(colors, parameters) + print("Ok") + + -- Copy new colors to the theme + for key, _ in pairs(Theme.colors) do + if colors[key] then + Theme.colors[key] = colors[key] + end + end + + -- TODO: Save new parameters + + Refresh() + end } - newDialog:show{} + newDialog:show{wait = false} end } end From e5ee7696551b5e0ef95a6c53ff953cbe70a3e959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 28 Jan 2024 21:29:32 +0100 Subject: [PATCH 04/30] Reintroduce changing modes and cursor colors --- Theme Preferences/ThemePreferencesDialog.lua | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index dea6382..537f1b8 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -45,6 +45,80 @@ return function(options) } end + function ChangeCursorColors() + local color = dialog.data["editor_cursor"] + local outlinecolor = dialog.data["editor_cursor_outline"] + + dialog:modify{ + id = "editor_cursor_shadow", + color = Color { + red = (color.red + outlinecolor.red) / 2, + green = (color.green + outlinecolor.green) / 2, + blue = (color.blue + outlinecolor.blue) / 2, + alpha = color.alpha + } + } + + MarkThemeAsModified() + end + + function ChangeMode(options) + -- Set default options + options = options or {} + options.force = options.force ~= nil and options.force or false + + local isSimple = dialog.data["mode-simple"] + + if isSimple then + if not options.force then + local confirmation = app.alert { + title = "Warning", + text = "Switching to Simple Mode will modify your theme, do you want to continue?", + buttons = {"Yes", "No"} + } + + if confirmation == 2 then + dialog:modify{id = "mode-simple", selected = false} + dialog:modify{id = "mode-advanced", selected = true} + return + end + end + + -- Set new simple values when switching to Simple Mode + dialog -- + :modify{id = "simple-link", color = dialog.data["text_link"]} -- + :modify{ + id = "simple-button", + color = dialog.data["button_background"] + } -- + :modify{id = "simple-tab", color = dialog.data["tab_background"]} -- + :modify{ + id = "simple-window", + color = dialog.data["window_background"] + } -- + :modify{id = "editor_icons", color = dialog.data["text_regular"]} + end + + dialog -- + :modify{id = "simple-link", visible = isSimple} -- + :modify{id = "simple-button", visible = isSimple} -- + :modify{id = "simple-tab", visible = isSimple} -- + :modify{id = "simple-window", visible = isSimple} + + local advancedWidgetIds = { + "button_highlight", "button_background", "button_shadow", + "tab_corner_highlight", "tab_highlight", "tab_background", + "tab_shadow", "window_highlight", "window_background", + "window_shadow", "text_link", "text_separator", "editor_icons" + } + + for _, id in ipairs(advancedWidgetIds) do + dialog:modify{id = id, visible = dialog.data["mode-advanced"]} + end + + MarkThemeAsModified() + end + dialog -- :radio{ id = "mode-simple", @@ -168,6 +242,8 @@ return function(options) onchange = function() ChangeCursorColors() end } + ThemeColor {id = "editor_cursor_shadow", visible = false} + dialog:separator{text = "Button"} ThemeColor {id = "button_highlight", visible = false} @@ -248,6 +324,7 @@ return function(options) } ThemeColor {id = "window_background", visible = false} + ThemeColor {id = "window_corner_shadow", visible = false} ThemeColor { id = "window_shadow", From 9fc5f40d79a8ccaf9958f7885fc166bd75e1dce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 28 Jan 2024 21:51:24 +0100 Subject: [PATCH 05/30] Save theme parameters --- Theme Preferences/ThemePreferencesDialog.lua | 18 ++++++++++++++---- Theme Preferences/extension.lua | 12 ++++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 537f1b8..1112396 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -13,6 +13,7 @@ return function(options) local isModified = options.isModified local colors = options.colors + local parameters = options.parameters local dialog = Dialog { title = isModified and titleModified or title, @@ -124,13 +125,13 @@ return function(options) id = "mode-simple", label = "Mode", text = "Simple", - selected = true, + selected = not parameters.isAdvanced, onclick = function() ChangeMode() end } -- :radio{ id = "mode-advanced", text = "Advanced", - selected = false, + selected = parameters.isAdvanced, onclick = function() ChangeMode() end } @@ -395,13 +396,22 @@ return function(options) :button{ text = "OK", onclick = function() - options.onok(dialog.data) + options.onok(dialog.data, + {isAdvanced = dialog.data["mode-advanced"]}) dialog:close() end } -- - :button{text = "Apply", onclick = function() options.onok(dialog.data) end} -- + :button{ + text = "Apply", + onclick = function() + options.onok(dialog.data, + {isAdvanced = dialog.data["mode-advanced"]}) + end + } -- :button{text = "Cancel", onclick = function() dialog:close() end} -- + if parameters.isAdvanced then ChangeMode {force = true} end + return dialog end diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index f0b00f1..a19142d 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -716,6 +716,8 @@ function init(plugin) local newDialog = ThemePreferencesDialog { name = Theme.name, colors = Theme.colors, + parameters = Theme.parameters, + isModified = isModified, onclose = function() print("Close") end, onsave = function() print("Save") end, onload = function() print("Load") end, @@ -723,14 +725,20 @@ function init(plugin) onok = function(colors, parameters) print("Ok") - -- Copy new colors to the theme + -- Copy new colors for key, _ in pairs(Theme.colors) do if colors[key] then Theme.colors[key] = colors[key] end end - -- TODO: Save new parameters + -- Copy new parameters + for key, _ in pairs(Theme.parameters) do + if parameters[key] ~= nil then + print(key, parameters[key]) + Theme.parameters[key] = parameters[key] + end + end Refresh() end From c0ce480df84953a406fa50c6fb6739efd6c7a8d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 28 Jan 2024 23:02:14 +0100 Subject: [PATCH 06/30] Delete duplicate code --- Theme Preferences/ThemePreferencesDialog.lua | 62 +- Theme Preferences/extension.lua | 637 +++---------------- 2 files changed, 125 insertions(+), 574 deletions(-) diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 1112396..26b1b5a 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -1,3 +1,7 @@ +function ShiftRGB(value, modifier) + return math.max(math.min(value + modifier, 255), 0) +end + function ShiftColor(color, redModifier, greenModifer, blueModifier) return Color { red = ShiftRGB(color.red, redModifier), @@ -8,9 +12,16 @@ function ShiftColor(color, redModifier, greenModifer, blueModifier) end return function(options) - local title = "Theme Preferences: " .. options.name + local title = "Theme Preferences" local titleModified = title .. " (modified)" + function UpdateTitle(name) + title = "Theme Preferences: " .. name + titleModified = title .. " (modified)" + end + + UpdateTitle(options.name) + local isModified = options.isModified local colors = options.colors local parameters = options.parameters @@ -20,13 +31,21 @@ return function(options) onclose = options.onclose } - function MarkThemeAsModified() - if isModified then return end - isModified = true + function GetParameters() + return { + isAdvanced = dialog.data["mode-advanced"], + isModified = isModified + } + end + + function MarkAsModified(value) + if isModified == value then return end + + isModified = value dialog -- - :modify{id = "save-configuration", enabled = true} -- - :modify{title = title .. " (modified)"} + :modify{id = "save-configuration", enabled = value} -- + :modify{title = title .. (value and " (modified)" or "")} end function ThemeColor(widgetOptions) @@ -41,7 +60,7 @@ return function(options) widgetOptions.onchange(color) end - MarkThemeAsModified() + MarkAsModified(true) end } end @@ -60,7 +79,7 @@ return function(options) } } - MarkThemeAsModified() + MarkAsModified(true) end function ChangeMode(options) @@ -117,7 +136,7 @@ return function(options) dialog:modify{id = id, visible = dialog.data["mode-advanced"]} end - MarkThemeAsModified() + if not options.force then MarkAsModified(true) end end dialog -- @@ -160,7 +179,7 @@ return function(options) dialog:modify{id = "text_link", color = color} dialog:modify{id = "text_separator", color = color} - MarkThemeAsModified() + MarkAsModified(true) end } @@ -267,7 +286,7 @@ return function(options) color = ShiftColor(color, -74, -74, -74) } - MarkThemeAsModified() + MarkAsModified(true) end } @@ -300,7 +319,7 @@ return function(options) color = ShiftColor(color, -24, -61, -61) } - MarkThemeAsModified() + MarkAsModified(true) end } @@ -373,7 +392,7 @@ return function(options) color = filedCornerShadowColor } - MarkThemeAsModified() + MarkAsModified(true) end } -- @@ -386,7 +405,14 @@ return function(options) label = "Configuration", text = "Save", enabled = isModified, -- Only allows saving of a modified theme - onclick = function() options.onsave() end + onclick = function() + local onsuccess = function(theme) + UpdateTitle(theme.name) + MarkAsModified(false) + end + + options.onsave(dialog.data, GetParameters(), onsuccess) + end } -- :button{text = "Load", onclick = function() options.onload() end} -- :button{text = "Font", onclick = function() options.onfont() end} @@ -396,17 +422,13 @@ return function(options) :button{ text = "OK", onclick = function() - options.onok(dialog.data, - {isAdvanced = dialog.data["mode-advanced"]}) + options.onok(dialog.data, GetParameters()) dialog:close() end } -- :button{ text = "Apply", - onclick = function() - options.onok(dialog.data, - {isAdvanced = dialog.data["mode-advanced"]}) - end + onclick = function() options.onok(dialog.data, GetParameters()) end } -- :button{text = "Cancel", onclick = function() dialog:close() end} -- diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index a19142d..aa5401e 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -5,7 +5,6 @@ local ThemePreferencesDialog = dofile("./ThemePreferencesDialog.lua") local THEME_ID = "custom" local DIALOG_WIDTH = 240 -local DIALOG_TITLE = "Theme Preferences" local ExtensionsDirectory = app.fs.joinPath(app.fs.userConfigPath, "extensions") local ThemePreferencesDirectory = app.fs.joinPath(ExtensionsDirectory, @@ -66,29 +65,7 @@ for id, parameter in pairs(Template.parameters) do Theme.parameters[id] = parameter end --- Dialog -local isModified = false -local lastRefreshState = false -local isDialogOpen = false -local onClose = nil - -local dialog = Dialog { - title = DIALOG_TITLE, - onclose = function() if onClose then onClose() end end -} - -function SetInitialWidth() - dialog:show{wait = false} - dialog:close() - - local uiScale = app.preferences.general["ui_scale"] - - local bounds = dialog.bounds - bounds.x = bounds.x - (DIALOG_WIDTH - bounds.width) / 2 - bounds.width = DIALOG_WIDTH * uiScale - - dialog.bounds = bounds -end +local IsDialogOpen = false function RefreshTheme(template, theme) -- Prepare color lookup @@ -175,7 +152,7 @@ function UpdateThemeXml(theme) end function Refresh() - lastRefreshState = isModified + -- lastRefreshState = IsModified RefreshTheme(Template, Theme) ThemeManager:SetCurrentTheme(Theme) @@ -186,467 +163,11 @@ function Refresh() end end -function ShiftRGB(value, modifier) - return math.max(math.min(value + modifier, 255), 0) -end - -function ShiftColor(color, redModifier, greenModifer, blueModifier) - return Color { - red = ShiftRGB(color.red, redModifier), - green = ShiftRGB(color.green, greenModifer), - blue = ShiftRGB(color.blue, blueModifier), - alpha = color.alpha - } -end - -function MarkThemeAsModified() - isModified = true - - dialog -- - :modify{id = "save-configuration", enabled = true} -- - :modify{title = DIALOG_TITLE .. ": " .. Theme.name .. " (modified)"} -end - -function SetThemeColor(id, color) - Theme.colors[id] = color - if dialog.data[id] then dialog:modify{id = id, color = color} end -end - -function ChangeMode(options) - -- Set default options - options = options or {} - options.force = options.force ~= nil and options.force or false - - local isSimple = dialog.data["mode-simple"] - - if isSimple then - if not options.force then - local confirmation = app.alert { - title = "Warning", - text = "Switching to Simple Mode will modify your theme, do you want to continue?", - buttons = {"Yes", "No"} - } - - if confirmation == 2 then - dialog:modify{id = "mode-simple", selected = false} - dialog:modify{id = "mode-advanced", selected = true} - return - end - end - - -- Set new simple values when switching to Simple Mode - dialog -- - :modify{id = "simple-link", color = Theme.colors["text_link"]} -- - :modify{id = "simple-button", color = Theme.colors["button_background"]} -- - :modify{id = "simple-tab", color = Theme.colors["tab_background"]} -- - :modify{id = "simple-window", color = Theme.colors["window_background"]} -- - :modify{id = "editor_icons", color = Theme.colors["text_regular"]} - end - - dialog -- - :modify{id = "simple-link", visible = isSimple} -- - :modify{id = "simple-button", visible = isSimple} -- - :modify{id = "simple-tab", visible = isSimple} -- - :modify{id = "simple-window", visible = isSimple} - - local advancedWidgetIds = { - "button_highlight", "button_background", "button_shadow", - "tab_corner_highlight", "tab_highlight", "tab_background", "tab_shadow", - "window_highlight", "window_background", "window_shadow", "text_link", - "text_separator", "editor_icons" - } - - for _, id in ipairs(advancedWidgetIds) do - dialog:modify{id = id, visible = dialog.data["mode-advanced"]} - end - - Theme.parameters.isAdvanced = dialog.data["mode-advanced"] - MarkThemeAsModified() -end - -function LoadTheme(theme) - -- Copy theme to the current theme - Theme.name = theme.name - Theme.parameters = theme.parameters - - -- Chanage mode - dialog -- - :modify{id = "mode-simple", selected = not theme.parameters.isAdvanced} -- - :modify{id = "mode-advanced", selected = theme.parameters.isAdvanced} - - ChangeMode {force = true} - - -- Load simple versions first to then overwrite advanced colors - local simpleButtons = { - ["simple-link"] = theme.colors["text_link"], - ["simple-button"] = theme.colors["button_background"], - -- ["simple-field"] = Theme.colors["field_background"], - ["simple-tab"] = theme.colors["tab_background"], - ["simple-window"] = theme.colors["window_background"] - } - - for id, color in pairs(simpleButtons) do - dialog:modify{id = id, color = color} - end - - -- Finally, copy colors - for id, color in pairs(theme.colors) do - -- Copy color just in case - SetThemeColor(id, CopyColor(color)) - end - - dialog:modify{title = DIALOG_TITLE .. ": " .. theme.name} -- - dialog:modify{id = "save-configuration", enabled = false} - - isModified = false -end - -function ThemeColor(options) - dialog:color{ - id = options.id, - label = options.label, - color = Theme.colors[options.id], - visible = options.visible, - onchange = function() - local color = dialog.data[options.id] - Theme.colors[options.id] = color - - if options.onchange then options.onchange(color) end - - MarkThemeAsModified() - end - } -end - -function ChangeCursorColors() - local color = dialog.data["editor_cursor"] - local outlinecolor = dialog.data["editor_cursor_outline"] - - local shadowColor = Color { - red = (color.red + outlinecolor.red) / 2, - green = (color.green + outlinecolor.green) / 2, - blue = (color.blue + outlinecolor.blue) / 2, - alpha = color.alpha - } - - Theme.colors["editor_cursor"] = color - Theme.colors["editor_cursor_shadow"] = shadowColor - Theme.colors["editor_cursor_outline"] = outlinecolor - - MarkThemeAsModified() -end - -function LoadCurrentTheme() - local currentTheme = ThemeManager:GetCurrentTheme() - if currentTheme then LoadTheme(currentTheme) end -end - -function Init() - -- Colors = Tint, Highlight, Tooltip (label as Hover) - - -- Link/Separator = Tint Color - -- Simple Tab Color = 50/50 Tint Color/Window Background Color - -- Highlight = Highlight - -- Tooltip = Tooltip - -- Hover = 50/50 Tooltip/Window Background Color - - dialog -- - -- :radio{ - -- id = "mode-tint", - -- label = "Mode", - -- text = "Tint", - -- selected = true, - -- onclick = ChangeMode - -- } -- - :radio{ - id = "mode-simple", - label = "Mode", - text = "Simple", - selected = true, - onclick = function() ChangeMode() end - } -- - :radio{ - id = "mode-advanced", - text = "Advanced", - selected = false, - onclick = function() ChangeMode() end - } - - dialog:separator{text = "Text"} - - ThemeColor {label = "Active/Regular", id = "text_active", visible = true} - ThemeColor { - id = "text_regular", - visible = true, - onchange = function(color) - if dialog.data["mode-simple"] then - SetThemeColor("editor_icons", color) - end - end - } - ThemeColor {label = "Link/Separator", id = "text_link", visible = false} - ThemeColor {id = "text_separator", visible = false} - - dialog:color{ - id = "simple-link", - label = "Link/Separator", - color = Theme.colors["text_link"], - onchange = function() - local color = dialog.data["simple-link"] - - SetThemeColor("text_link", color) - SetThemeColor("text_separator", color) - - MarkThemeAsModified() - end - } - - dialog:separator{text = "Input Fields"} - - ThemeColor {label = "Highlight", id = "field_highlight", visible = true} - - -- FUTURE: Allow for separate chaning of the "field_background" - -- dialog:color{ - -- id = "simple-field", - -- label = "Background", - -- color = Theme.colors["field_background"], - -- onchange = function() - -- local color = dialog.data["simple-field"] - - -- local shadowColor = Color { - -- red = ShiftRGB(color.red, -57), - -- green = ShiftRGB(color.green, -57), - -- blue = ShiftRGB(color.blue, -57), - -- alpha = color.alpha - -- } - - -- local cornerShadowColor = Color { - -- red = ShiftRGB(color.red, -74), - -- green = ShiftRGB(color.green, -74), - -- blue = ShiftRGB(color.blue, -74), - -- alpha = color.alpha - -- } - - -- Theme.colors["field_background"] = color - -- Theme.colors["field_shadow"] = shadowColor - -- Theme.colors["field_corner_shadow"] = cornerShadowColor - -- end - -- } - - dialog:separator{text = "Editor"} - - ThemeColor { - label = "Background", - id = "editor_background", - onchange = function(color) - local shadowColor = ShiftColor(color, -36, -20, -53) - Theme.colors["editor_background_shadow"] = shadowColor - end - } - - ThemeColor {label = "Icons", id = "editor_icons", visible = false} - - ThemeColor { - label = "Tooltip", - id = "editor_tooltip", - onchange = function(color) - local shadowColor = ShiftColor(color, -100, -90, -32) - local cornerShadowColor = ShiftColor(color, -125, -152, -94) - - Theme.colors["editor_tooltip_shadow"] = shadowColor - Theme.colors["editor_tooltip_corner_shadow"] = cornerShadowColor - end - } - - dialog -- - :color{ - id = "editor_cursor", - label = "Cursor", - color = Theme.colors["editor_cursor"], - onchange = function() ChangeCursorColors() end - } -- - :color{ - id = "editor_cursor_outline", - color = Theme.colors["editor_cursor_outline"], - onchange = function() ChangeCursorColors() end - } - - dialog:separator{text = "Button"} - - ThemeColor {id = "button_highlight", visible = false} - ThemeColor {id = "button_background", visible = false} - ThemeColor {id = "button_shadow", visible = false} - - dialog:color{ - id = "simple-button", - color = Theme.colors["button_background"], - onchange = function() - local color = dialog.data["simple-button"] - local highlightColor = ShiftColor(color, 57, 57, 57) - local shadowColor = ShiftColor(color, -74, -74, -74) - - SetThemeColor("button_highlight", highlightColor) - SetThemeColor("button_background", color) - SetThemeColor("button_shadow", shadowColor) - - MarkThemeAsModified() - end - } - - ThemeColor {label = "Selected", id = "button_selected", visible = true} - - dialog:separator{text = "Tab"} - - ThemeColor {id = "tab_corner_highlight", visible = false} - ThemeColor {id = "tab_highlight", visible = false} - ThemeColor {id = "tab_background", visible = false} - ThemeColor {id = "tab_shadow", visible = false} - - dialog:color{ - id = "simple-tab", - color = Theme.colors["tab_background"], - onchange = function() - local color = dialog.data["simple-tab"] - local cornerHighlightColor = ShiftColor(color, 131, 110, 98) - local highlightColor = ShiftColor(color, 49, 57, 65) - local shadowColor = ShiftColor(color, -24, -61, -61) - - SetThemeColor("tab_corner_highlight", cornerHighlightColor) - SetThemeColor("tab_highlight", highlightColor) - SetThemeColor("tab_background", color) - SetThemeColor("tab_shadow", shadowColor) - - MarkThemeAsModified() - end - } - - dialog:separator{text = "Window"} - - ThemeColor { - id = "window_highlight", - visible = false, - onchange = function(color) - Theme.colors["window_highlight"] = color - - -- FUTURE: Remove this when setting a separate value for the "field_background" is possible - - local fieldShadowColor = ShiftColor(color, -57, -57, -57) - local filedCornerShadowColor = ShiftColor(color, -74, -74, -74) - - Theme.colors["field_background"] = color - Theme.colors["field_shadow"] = fieldShadowColor - Theme.colors["field_corner_shadow"] = filedCornerShadowColor - end - } - - ThemeColor {id = "window_background", visible = false} - - ThemeColor { - id = "window_shadow", - visible = false, - onchange = function(color) - local cornerShadowColor = ShiftColor(color, -49, -44, -20) - SetThemeColor("window_corner_shadow", cornerShadowColor) - end - } - - dialog:color{ - id = "simple-window", - color = Theme.colors["window_background"], - onchange = function() - local color = dialog.data["simple-window"] - local highlightColor = ShiftColor(color, 45, 54, 66) - local shadowColor = ShiftColor(color, -61, -73, -73) - local cornerShadowColor = ShiftColor(color, -110, -117, -93) - - SetThemeColor("window_highlight", highlightColor) - SetThemeColor("window_background", color) - SetThemeColor("window_shadow", shadowColor) - SetThemeColor("window_corner_shadow", cornerShadowColor) - - -- FUTURE: Remove this when setting a separate value for the "field_background" is possible - - local fieldShadowColor = ShiftColor(highlightColor, -57, -57, -57) - local filedCornerShadowColor = - ShiftColor(highlightColor, -74, -74, -74) - - Theme.colors["field_background"] = highlightColor - Theme.colors["field_shadow"] = fieldShadowColor - Theme.colors["field_corner_shadow"] = filedCornerShadowColor - - MarkThemeAsModified() - end - } -- - - ThemeColor {label = "Hover", id = "window_hover", visible = true} - - dialog -- - :separator() -- - :button{ - id = "save-configuration", - label = "Configuration", - text = "Save", - enabled = false, - onclick = function() - local onsave = function(theme) - dialog:modify{title = DIALOG_TITLE .. ": " .. theme.name} - dialog:modify{id = "save-configuration", enabled = false} - - isModified = false - lastRefreshState = false - end - - ThemeManager:Save(Theme, onsave) - end - } -- - :button{ - text = "Load", - onclick = function() - local onload = function(theme) - LoadTheme(theme) - Refresh() - end - - local onreset = function() - LoadTheme(Template) - Refresh() - end - - -- Hide the Theme Preferences dialog - dialog:close() - - ThemeManager:Load(onload, onreset) - - -- Reopen the dialog - dialog:show{wait = false} - end - } -- - :button{ - text = "Font", - onclick = function() - local onconfirm = function() Refresh() end - - -- Hide the Theme Preferences dialog - dialog:close() - - FontsProvider:OpenDialog(onconfirm) - - -- Reopen the dialog - dialog:show{wait = false} - end - } +function LoadTheme(theme, stopRefresh) + Theme = theme + IsModified = false - dialog -- - :separator() -- - :button{ - text = "OK", - onclick = function() - Refresh() - dialog:close() - end - } -- - :button{text = "Apply", onclick = function() Refresh() end} -- - :button{text = "Cancel", onclick = function() dialog:close() end} -- + if not stopRefresh then Refresh() end end function init(plugin) @@ -661,93 +182,101 @@ function init(plugin) ThemeManager:Init{storage = storage} FontsProvider:Init{storage = storage} - -- Initialize the diaog - Init() - -- Initialize data from plugin preferences - LoadCurrentTheme() - isModified = plugin.preferences.themePreferences.isThemeModified - if isModified then MarkThemeAsModified() end + local currentTheme = ThemeManager:GetCurrentTheme() + if currentTheme then LoadTheme(currentTheme, true) end - -- Treat the "Modified" state as the last known refresh state - lastRefreshState = isModified + IsModified = plugin.preferences.themePreferences.isThemeModified - -- Setup function to be called on close - onClose = function() - LoadCurrentTheme() + local CopyToTheme = function(colors, parameters) + -- Copy new colors + for key, _ in pairs(Theme.colors) do + if colors[key] then Theme.colors[key] = colors[key] end + end - isModified = lastRefreshState - if isModified then MarkThemeAsModified() end + -- Copy new parameters + for key, _ in pairs(Theme.parameters) do + if parameters[key] ~= nil then + Theme.parameters[key] = parameters[key] + end + end - isDialogOpen = false + IsModified = parameters.isModified end - -- Set the initial width of the dialog - SetInitialWidth() - plugin:newCommand{ - id = "ThemePreferences", - title = DIALOG_TITLE .. "...", + id = "ThemePreferencesNew", + title = "Theme Preferences...", group = "view_screen", - onenabled = function() return not isDialogOpen end, + onenabled = function() return not IsDialogOpen end, onclick = function() - -- Refreshing the UI on open to fix the issue where the dialog would keep parts of the old theme - app.command.Refresh() + local dialog = nil + local CreateDialog = nil + + local onsave = function(colors, parameters, onSuccessDialog) + local onsuccess = function(theme) + -- Pass the saved theme to the dialog to update the window title + onSuccessDialog(theme) + IsModified = false + end - -- Show Theme Preferences dialog - dialog:show{wait = false} + CopyToTheme(colors, parameters) + ThemeManager:Save(Theme, onsuccess) + end - -- Treat the "Modified" state as the last known refresh state - lastRefreshState = isModified + local onload = function() + local onload = function(theme) LoadTheme(theme) end + local onreset = function() LoadTheme(Template) end - -- Update the dialog if the theme is modified - if isModified then MarkThemeAsModified() end + -- Hide the Theme Preferences dialog + dialog:close() - isDialogOpen = true - end - } + ThemeManager:Load(onload, onreset) - plugin:newCommand{ - id = "ThemePreferencesNew", - title = DIALOG_TITLE .. " (New)...", - group = "view_screen", - onenabled = function() return not isDialogOpen end, - onclick = function() - local newDialog = ThemePreferencesDialog { - name = Theme.name, - colors = Theme.colors, - parameters = Theme.parameters, - isModified = isModified, - onclose = function() print("Close") end, - onsave = function() print("Save") end, - onload = function() print("Load") end, - onfont = function() print("Font") end, - onok = function(colors, parameters) - print("Ok") - - -- Copy new colors - for key, _ in pairs(Theme.colors) do - if colors[key] then - Theme.colors[key] = colors[key] - end - end - - -- Copy new parameters - for key, _ in pairs(Theme.parameters) do - if parameters[key] ~= nil then - print(key, parameters[key]) - Theme.parameters[key] = parameters[key] - end - end - - Refresh() - end - } - newDialog:show{wait = false} + -- Reopen the dialog + dialog = CreateDialog() + end + + local onfont = function() + local onconfirm = function() Refresh() end + + -- Hide the Theme Preferences dialog + dialog:close() + + FontsProvider:OpenDialog(onconfirm) + + -- Reopen the dialog + dialog = CreateDialog() + end + + local onok = function(colors, parameters) + CopyToTheme(colors, parameters) + Refresh() + end + + CreateDialog = function() + local newDialog = ThemePreferencesDialog { + name = Theme.name, + colors = Theme.colors, + parameters = Theme.parameters, + isModified = IsModified, + onclose = function() IsDialogOpen = false end, + onsave = onsave, + onload = onload, + onfont = onfont, + onok = onok + } + + newDialog:show{wait = false} + return newDialog + end + + dialog = CreateDialog() + IsDialogOpen = true end } end function exit(plugin) - plugin.preferences.themePreferences.isThemeModified = isModified + plugin.preferences.themePreferences.isThemeModified = IsModified end From ef7b048b263aba6f84ee05ec604f7d64d6f61050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 28 Jan 2024 23:14:10 +0100 Subject: [PATCH 07/30] Refactor and clean up --- Theme Preferences/Template.lua | 286 +++++++++++++++++--------------- Theme Preferences/extension.lua | 63 +++---- 2 files changed, 174 insertions(+), 175 deletions(-) diff --git a/Theme Preferences/Template.lua b/Theme Preferences/Template.lua index ed23c95..18d90c6 100644 --- a/Theme Preferences/Template.lua +++ b/Theme Preferences/Template.lua @@ -1,142 +1,154 @@ -return { - name = "Default", - colors = { - -- Button - ["button_highlight"] = Color {gray = 255, alpha = 255}, - ["button_background"] = Color {gray = 198, alpha = 255}, - ["button_shadow"] = Color {gray = 124, alpha = 255}, - ["button_selected"] = Color { - red = 120, - green = 96, - blue = 80, - alpha = 255 - }, +return function() + return { + name = "Default", + colors = { + -- Button + ["button_highlight"] = Color {gray = 255, alpha = 255}, + ["button_background"] = Color {gray = 198, alpha = 255}, + ["button_shadow"] = Color {gray = 124, alpha = 255}, + ["button_selected"] = Color { + red = 120, + green = 96, + blue = 80, + alpha = 255 + }, - -- Tab - ["tab_corner_highlight"] = Color { - red = 255, - green = 255, - blue = 254, - alpha = 255 - }, - ["tab_highlight"] = Color { - red = 173, - green = 202, - blue = 222, - alpha = 255 - }, - ["tab_background"] = Color { - red = 125, - green = 146, - blue = 158, - alpha = 255 - }, - ["tab_shadow"] = Color {red = 100, green = 84, blue = 96, alpha = 255}, + -- Tab + ["tab_corner_highlight"] = Color { + red = 255, + green = 255, + blue = 254, + alpha = 255 + }, + ["tab_highlight"] = Color { + red = 173, + green = 202, + blue = 222, + alpha = 255 + }, + ["tab_background"] = Color { + red = 125, + green = 146, + blue = 158, + alpha = 255 + }, + ["tab_shadow"] = Color { + red = 100, + green = 84, + blue = 96, + alpha = 255 + }, - -- Window - ["window_hover"] = Color { - red = 255, - green = 235, - blue = 182, - alpha = 255 - }, - ["window_highlight"] = Color { - red = 255, - green = 254, - blue = 255, - alpha = 255 - }, - ["window_background"] = Color { - red = 210, - green = 202, - blue = 189, - alpha = 255 - }, - ["window_shadow"] = Color { - red = 149, - green = 129, - blue = 116, - alpha = 255 - }, - ["window_corner_shadow"] = Color { - red = 100, - green = 85, - blue = 96, - alpha = 255 - }, + -- Window + ["window_hover"] = Color { + red = 255, + green = 235, + blue = 182, + alpha = 255 + }, + ["window_highlight"] = Color { + red = 255, + green = 254, + blue = 255, + alpha = 255 + }, + ["window_background"] = Color { + red = 210, + green = 202, + blue = 189, + alpha = 255 + }, + ["window_shadow"] = Color { + red = 149, + green = 129, + blue = 116, + alpha = 255 + }, + ["window_corner_shadow"] = Color { + red = 100, + green = 85, + blue = 96, + alpha = 255 + }, - -- Text - ["text_regular"] = Color {gray = 2, alpha = 255}, - ["text_active"] = Color {gray = 253, alpha = 255}, - ["text_link"] = Color {red = 44, green = 76, blue = 145, alpha = 255}, - ["text_separator"] = Color { - red = 44, - green = 76, - blue = 145, - alpha = 255 - }, + -- Text + ["text_regular"] = Color {gray = 2, alpha = 255}, + ["text_active"] = Color {gray = 253, alpha = 255}, + ["text_link"] = Color { + red = 44, + green = 76, + blue = 145, + alpha = 255 + }, + ["text_separator"] = Color { + red = 44, + green = 76, + blue = 145, + alpha = 255 + }, - -- Field - ["field_highlight"] = Color { - red = 255, - green = 87, - blue = 87, - alpha = 255 - }, - ["field_background"] = Color {gray = 254, alpha = 255}, - ["field_shadow"] = Color {gray = 197, alpha = 255}, - ["field_corner_shadow"] = Color {gray = 123, alpha = 255}, + -- Field + ["field_highlight"] = Color { + red = 255, + green = 87, + blue = 87, + alpha = 255 + }, + ["field_background"] = Color {gray = 254, alpha = 255}, + ["field_shadow"] = Color {gray = 197, alpha = 255}, + ["field_corner_shadow"] = Color {gray = 123, alpha = 255}, - -- Editor - ["editor_background"] = Color { - red = 101, - green = 85, - blue = 97, - alpha = 255 - }, - ["editor_background_shadow"] = Color { - red = 65, - green = 65, - blue = 44, - alpha = 255 - }, - ["editor_tooltip"] = Color { - red = 255, - green = 255, - blue = 125, - alpha = 255 - }, - ["editor_tooltip_shadow"] = Color { - red = 125, - green = 146, - blue = 157, - alpha = 255 - }, - ["editor_tooltip_corner_shadow"] = Color { - red = 100, - green = 84, - blue = 95, - alpha = 255 - }, - ["editor_cursor"] = Color { - red = 254, - green = 255, - blue = 255, - alpha = 255 - }, - ["editor_cursor_shadow"] = Color { - red = 123, - green = 124, - blue = 124, - alpha = 255 - }, - ["editor_cursor_outline"] = Color { - red = 1, - green = 0, - blue = 0, - alpha = 255 - }, - ["editor_icons"] = Color {gray = 1, alpha = 255} - }, - parameters = {isAdvanced = false} -} + -- Editor + ["editor_background"] = Color { + red = 101, + green = 85, + blue = 97, + alpha = 255 + }, + ["editor_background_shadow"] = Color { + red = 65, + green = 65, + blue = 44, + alpha = 255 + }, + ["editor_tooltip"] = Color { + red = 255, + green = 255, + blue = 125, + alpha = 255 + }, + ["editor_tooltip_shadow"] = Color { + red = 125, + green = 146, + blue = 157, + alpha = 255 + }, + ["editor_tooltip_corner_shadow"] = Color { + red = 100, + green = 84, + blue = 95, + alpha = 255 + }, + ["editor_cursor"] = Color { + red = 254, + green = 255, + blue = 255, + alpha = 255 + }, + ["editor_cursor_shadow"] = Color { + red = 123, + green = 124, + blue = 124, + alpha = 255 + }, + ["editor_cursor_outline"] = Color { + red = 1, + green = 0, + blue = 0, + alpha = 255 + }, + ["editor_icons"] = Color {gray = 1, alpha = 255} + }, + parameters = {isAdvanced = false} + } +end diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index aa5401e..6e1ec73 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -53,21 +53,12 @@ function CopyColor(originalColor) } end --- Color Definitions -local Theme = {name = "", colors = {}, parameters = {}} - --- Copy template to theme -Theme.name = Template.name - -for id, color in pairs(Template.colors) do Theme.colors[id] = CopyColor(color) end - -for id, parameter in pairs(Template.parameters) do - Theme.parameters[id] = parameter -end - +-- Start from the template +local Theme = Template() local IsDialogOpen = false -function RefreshTheme(template, theme) +function RefreshTheme(theme) + local template = Template() -- Prepare color lookup local map = {} @@ -152,9 +143,7 @@ function UpdateThemeXml(theme) end function Refresh() - -- lastRefreshState = IsModified - - RefreshTheme(Template, Theme) + RefreshTheme(Theme) ThemeManager:SetCurrentTheme(Theme) -- Switch Aseprite to the custom theme @@ -170,6 +159,22 @@ function LoadTheme(theme, stopRefresh) if not stopRefresh then Refresh() end end +function CopyToTheme(colors, parameters) + -- Copy new colors + for key, _ in pairs(Theme.colors) do + if colors[key] then Theme.colors[key] = colors[key] end + end + + -- Copy new parameters + for key, _ in pairs(Theme.parameters) do + if parameters[key] ~= nil then + Theme.parameters[key] = parameters[key] + end + end + + IsModified = parameters.isModified +end + function init(plugin) -- Do nothing when UI is not available if not app.isUIAvailable then return end @@ -179,30 +184,12 @@ function init(plugin) plugin.preferences.themePreferences or {} local storage = plugin.preferences.themePreferences - ThemeManager:Init{storage = storage} - FontsProvider:Init{storage = storage} - -- Initialize data from plugin preferences - local currentTheme = ThemeManager:GetCurrentTheme() - if currentTheme then LoadTheme(currentTheme, true) end - - IsModified = plugin.preferences.themePreferences.isThemeModified - - local CopyToTheme = function(colors, parameters) - -- Copy new colors - for key, _ in pairs(Theme.colors) do - if colors[key] then Theme.colors[key] = colors[key] end - end - - -- Copy new parameters - for key, _ in pairs(Theme.parameters) do - if parameters[key] ~= nil then - Theme.parameters[key] = parameters[key] - end - end + ThemeManager:Init{storage = storage} + Theme = ThemeManager:GetCurrentTheme() or Theme - IsModified = parameters.isModified - end + FontsProvider:Init{storage = storage} + IsModified = storage.isThemeModified plugin:newCommand{ id = "ThemePreferencesNew", From fa95ceeb1b974e43ae7f4062d53b0479000f763e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 28 Jan 2024 23:46:00 +0100 Subject: [PATCH 08/30] Minor performance improvement when saving or applying themes --- ROADMAP.md | 2 +- Theme Preferences/extension.lua | 75 +++++++++++++-------------------- 2 files changed, 30 insertions(+), 47 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 481128f..c32394c 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -15,7 +15,7 @@ Update v1.0.3. Unreleased: -- ... +- [Improvement] Minor performance improvement when saving or applying themes Update v2.0.0: diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 6e1ec73..f2502de 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -35,24 +35,6 @@ function ColorToHex(color) return string.format("#%02x%02x%02x", color.red, color.green, color.blue) end -function RgbaPixelToColor(rgbaPixel) - return Color { - red = app.pixelColor.rgbaR(rgbaPixel), - green = app.pixelColor.rgbaG(rgbaPixel), - blue = app.pixelColor.rgbaB(rgbaPixel), - alpha = app.pixelColor.rgbaA(rgbaPixel) - } -end - -function CopyColor(originalColor) - return Color { - red = originalColor.red, - green = originalColor.green, - blue = originalColor.blue, - alpha = originalColor.alpha - } -end - -- Start from the template local Theme = Template() local IsDialogOpen = false @@ -64,45 +46,46 @@ function RefreshTheme(theme) for id, templateColor in pairs(template.colors) do -- Map the template color to the theme color - map[ColorToHex(templateColor)] = theme.colors[id] + local r = templateColor.red + local g = templateColor.green + local b = templateColor.blue + + if not map[r] then map[r] = {} end + if not map[r][g] then map[r][g] = {} end + map[r][g][b] = theme.colors[id] end -- Prepare sheet.png local image = Image {fromFile = SheetTemplatePath} - local pixelValue, newColor, pixelData, pixelColor, pixelValueKey, - resultColor -- Save references to function to improve performance local getPixel, drawPixel = image.getPixel, image.drawPixel - local cache = {} - for x = 0, image.width - 1 do for y = 0, image.height - 1 do - pixelValue = getPixel(image, x, y) + local pixelValue = getPixel(image, x, y) if pixelValue > 0 then - pixelValueKey = tostring(pixelValue) - pixelData = cache[pixelValueKey] - - if not pixelData then - pixelColor = RgbaPixelToColor(pixelValue) - - cache[pixelValueKey] = { - id = ColorToHex(pixelColor), - color = pixelColor - } - - pixelData = cache[pixelValueKey] - end - - resultColor = map[pixelData.id] - - if resultColor ~= nil then - newColor = CopyColor(resultColor) - newColor.alpha = pixelData.color.alpha -- Restore the original alpha value - - drawPixel(image, x, y, newColor) + local r = app.pixelColor.rgbaR(pixelValue) + + if map[r] then + local g = app.pixelColor.rgbaG(pixelValue) + + if map[r][g] then + local b = app.pixelColor.rgbaB(pixelValue) + + if map[r][g][b] then + local themeColor = map[r][g][b] + + drawPixel(image, x, y, Color { + red = themeColor.red, + green = themeColor.green, + blue = themeColor.blue, + -- Restore the original alpha value + alpha = app.pixelColor.rgbaA(pixelValue) + }) + end + end end end end @@ -213,7 +196,7 @@ function init(plugin) local onload = function() local onload = function(theme) LoadTheme(theme) end - local onreset = function() LoadTheme(Template) end + local onreset = function() LoadTheme(Template()) end -- Hide the Theme Preferences dialog dialog:close() From 6502441648b8d05e9a9e263cbfcc323326da2d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Mon, 29 Jan 2024 00:16:52 +0100 Subject: [PATCH 09/30] Reintroduce initial dialog size --- Theme Preferences/extension.lua | 71 +++++++++++++++++---------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index f2502de..4c4a8b0 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -4,7 +4,7 @@ local FontsProvider = dofile("./FontsProvider.lua") local ThemePreferencesDialog = dofile("./ThemePreferencesDialog.lua") local THEME_ID = "custom" -local DIALOG_WIDTH = 240 +local DialogSize = Size(240, 412) local ExtensionsDirectory = app.fs.joinPath(app.fs.userConfigPath, "extensions") local ThemePreferencesDirectory = app.fs.joinPath(ExtensionsDirectory, @@ -43,16 +43,10 @@ function RefreshTheme(theme) local template = Template() -- Prepare color lookup local map = {} + local template = Template() for id, templateColor in pairs(template.colors) do - -- Map the template color to the theme color - local r = templateColor.red - local g = templateColor.green - local b = templateColor.blue - - if not map[r] then map[r] = {} end - if not map[r][g] then map[r][g] = {} end - map[r][g][b] = theme.colors[id] + map[templateColor.rgbaPixel] = theme.colors[id] end -- Prepare sheet.png @@ -60,33 +54,22 @@ function RefreshTheme(theme) -- Save references to function to improve performance local getPixel, drawPixel = image.getPixel, image.drawPixel + local rgbaA = app.pixelColor.rgbaA + local pixelValue, themeColor for x = 0, image.width - 1 do for y = 0, image.height - 1 do - local pixelValue = getPixel(image, x, y) - - if pixelValue > 0 then - local r = app.pixelColor.rgbaR(pixelValue) - - if map[r] then - local g = app.pixelColor.rgbaG(pixelValue) - - if map[r][g] then - local b = app.pixelColor.rgbaB(pixelValue) - - if map[r][g][b] then - local themeColor = map[r][g][b] - - drawPixel(image, x, y, Color { - red = themeColor.red, - green = themeColor.green, - blue = themeColor.blue, - -- Restore the original alpha value - alpha = app.pixelColor.rgbaA(pixelValue) - }) - end - end - end + pixelValue = getPixel(image, x, y) + themeColor = map[pixelValue] + + if themeColor then + drawPixel(image, x, y, Color { + red = themeColor.red, + green = themeColor.green, + blue = themeColor.blue, + -- Restore the original alpha value + alpha = rgbaA(pixelValue) + }) end end end @@ -158,6 +141,17 @@ function CopyToTheme(colors, parameters) IsModified = parameters.isModified end +function GetWindowSize() + if app.apiVersion >= 25 then return app.window end + + local dialog = Dialog() + dialog:show{wait = false} + dialog:close() + + return Size(dialog.bounds.x * 2 + dialog.bounds.width, + dialog.bounds.y * 2 + dialog.bounds.height) +end + function init(plugin) -- Do nothing when UI is not available if not app.isUIAvailable then return end @@ -237,7 +231,16 @@ function init(plugin) onok = onok } - newDialog:show{wait = false} + local window = GetWindowSize() + local bounds = Rectangle((window.width - DialogSize.width) / 2, + (window.height - DialogSize.height) / 2, + DialogSize.width, DialogSize.height) + + newDialog:show{ + wait = false, + bounds = bounds, + autoscrollbars = true + } return newDialog end From e136adc3ae182d50800a0a4b76832f4dad2a84b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Mon, 29 Jan 2024 10:33:39 +0100 Subject: [PATCH 10/30] Minor refactor --- Theme Preferences/extension.lua | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 4c4a8b0..dc9dc5a 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -39,8 +39,7 @@ end local Theme = Template() local IsDialogOpen = false -function RefreshTheme(theme) - local template = Template() +function UpdateThemeSheet(theme) -- Prepare color lookup local map = {} local template = Template() @@ -75,11 +74,6 @@ function RefreshTheme(theme) end image:saveAs(SheetPath) - - -- Update the XML theme file - UpdateThemeXml(theme) - - app.command.Refresh() end function UpdateThemeXml(theme) @@ -108,21 +102,24 @@ function UpdateThemeXml(theme) WriteAll(ThemeXmlPath, xmlContent) end -function Refresh() - RefreshTheme(Theme) - ThemeManager:SetCurrentTheme(Theme) +function RefreshTheme() + UpdateThemeSheet(Theme) + UpdateThemeXml(Theme) -- Switch Aseprite to the custom theme - if app.preferences.theme.selected ~= THEME_ID then - app.preferences.theme.selected = THEME_ID - end + app.preferences.theme.selected = THEME_ID + + -- Force refresh of the Aseprite UI to reload the theme + app.command.Refresh() + + ThemeManager:SetCurrentTheme(Theme) end function LoadTheme(theme, stopRefresh) Theme = theme IsModified = false - if not stopRefresh then Refresh() end + if not stopRefresh then RefreshTheme() end end function CopyToTheme(colors, parameters) @@ -202,7 +199,7 @@ function init(plugin) end local onfont = function() - local onconfirm = function() Refresh() end + local onconfirm = function() RefreshTheme() end -- Hide the Theme Preferences dialog dialog:close() @@ -215,7 +212,7 @@ function init(plugin) local onok = function(colors, parameters) CopyToTheme(colors, parameters) - Refresh() + RefreshTheme() end CreateDialog = function() @@ -253,3 +250,5 @@ end function exit(plugin) plugin.preferences.themePreferences.isThemeModified = IsModified end + +-- TODO: Move all of the Refresh/Update theme logic to a separate file From 4a9cf5ac3f0789289be76972cea58021743902c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Mon, 29 Jan 2024 12:19:09 +0100 Subject: [PATCH 11/30] Refactor all dialogs out of ThemeManager --- .../ExportConfigurationDialog.lua | 29 ++ Theme Preferences/GetWindowSize.lua | 10 + .../ImportConfigurationDialog.lua | 35 ++ Theme Preferences/LoadConfigurationDialog.lua | 95 ++++++ Theme Preferences/SaveConfigurationDialog.lua | 42 +++ Theme Preferences/ThemeManager.lua | 319 +++--------------- Theme Preferences/extension.lua | 19 +- 7 files changed, 271 insertions(+), 278 deletions(-) create mode 100644 Theme Preferences/ExportConfigurationDialog.lua create mode 100644 Theme Preferences/GetWindowSize.lua create mode 100644 Theme Preferences/ImportConfigurationDialog.lua create mode 100644 Theme Preferences/LoadConfigurationDialog.lua create mode 100644 Theme Preferences/SaveConfigurationDialog.lua diff --git a/Theme Preferences/ExportConfigurationDialog.lua b/Theme Preferences/ExportConfigurationDialog.lua new file mode 100644 index 0000000..3922fc4 --- /dev/null +++ b/Theme Preferences/ExportConfigurationDialog.lua @@ -0,0 +1,29 @@ +local EXPORT_DIALOG_WIDTH = 540 + +return function(name, code, onclose) + -- TODO: Simplify this using just the window size + local isFirstOpen = true + + local dialog = Dialog { + title = "Export " .. name, + onclose = function() if not isFirstOpen then onclose() end end + } + + dialog -- + :entry{label = "Code", text = code} -- + :separator() -- + :button{text = "Close"} -- + + -- Open and close to initialize bounds + dialog:show{wait = false} + dialog:close() + + isFirstOpen = false + + local bounds = dialog.bounds + bounds.x = bounds.x - (EXPORT_DIALOG_WIDTH - bounds.width) / 2 + bounds.width = EXPORT_DIALOG_WIDTH + dialog.bounds = bounds + + return dialog +end diff --git a/Theme Preferences/GetWindowSize.lua b/Theme Preferences/GetWindowSize.lua new file mode 100644 index 0000000..9238ad2 --- /dev/null +++ b/Theme Preferences/GetWindowSize.lua @@ -0,0 +1,10 @@ +return function() + if app.apiVersion >= 25 then return app.window end + + local dialog = Dialog() + dialog:show{wait = false} + dialog:close() + + return Size(dialog.bounds.x * 2 + dialog.bounds.width, + dialog.bounds.y * 2 + dialog.bounds.height) +end diff --git a/Theme Preferences/ImportConfigurationDialog.lua b/Theme Preferences/ImportConfigurationDialog.lua new file mode 100644 index 0000000..ec422e1 --- /dev/null +++ b/Theme Preferences/ImportConfigurationDialog.lua @@ -0,0 +1,35 @@ +local IMPORT_DIALOG_WIDTH = 540 + +return function(decode, onok) + local dialog = Dialog("Import") + + dialog -- + :entry{id = "code", label = "Code"} -- + :separator{id = "separator"} -- + :button{ + text = "Import", + onclick = function() + local theme = decode(dialog.data.code) + + if not theme then + dialog:modify{id = "separator", text = "Incorrect code"} + return + end + + dialog:close() + onok(theme) + end + } -- + :button{text = "Cancel"} -- + + -- Open and close to initialize bounds + dialog:show{wait = false} + dialog:close() + + local bounds = dialog.bounds + bounds.x = bounds.x - (IMPORT_DIALOG_WIDTH - bounds.width) / 2 + bounds.width = IMPORT_DIALOG_WIDTH + dialog.bounds = bounds + + return dialog +end diff --git a/Theme Preferences/LoadConfigurationDialog.lua b/Theme Preferences/LoadConfigurationDialog.lua new file mode 100644 index 0000000..08ee597 --- /dev/null +++ b/Theme Preferences/LoadConfigurationDialog.lua @@ -0,0 +1,95 @@ +local ExportConfigurationDialog = dofile("./ExportConfigurationDialog.lua") + +local ConfigurationsPerPage = 10 +local CurrentPage = 1 + +return function(themes, onload, ondelete, onimport) + local pages = math.ceil(#themes / ConfigurationsPerPage) + + local dialog = Dialog("Load Configuration") + + -- TODO: Hide tabs in older version of Aseprite, also hide them when there's only one page + + for page = 1, pages do + dialog:tab{ + id = "tab-" .. page, + text = " " .. page .. " ", + onclick = function() CurrentPage = page end + } + + for i = 1, ConfigurationsPerPage do + local index = i + (page - 1) * ConfigurationsPerPage + if index > #themes then break end + + local theme = themes[index] + + dialog -- + :button{ + label = theme.name, -- TODO: Limit the max number of characters displayed here to not make different pages have buttons of different sizes + text = "Load", + onclick = function() + local confirmation = app.alert { + title = "Loading theme " .. theme.name, + text = "Unsaved changes will be lost, do you want to continue?", + buttons = {"Yes", "No"} + } + + if confirmation == 1 then + dialog:close() + onload(theme) + end + end + } -- + :button{ + text = "Export", + enabled = index > 1, + onclick = function() + dialog:close() + local onExportDialogClose = function() + dialog:show() + end + + local exportDialog = + ExportConfigurationDialog(theme.name, theme.code, + onExportDialogClose) + exportDialog:show() + end + } -- + :button{ + text = "Delete", + enabled = index > 1, + onclick = function() + local confirmation = app.alert { + title = "Delete " .. theme.name, + text = "Are you sure?", + buttons = {"Yes", "No"} + } + + if confirmation == 1 then + dialog:close() + ondelete(index - 1) + end + end + } + end + end + + local selectedPage = math.min(pages, CurrentPage) + + dialog:endtabs{id = "tabs", selected = "tab-" .. selectedPage} + + dialog -- + :button{ + text = "Import", + onclick = function() + dialog:close() + onimport() + end + } -- + + dialog -- + :separator() -- + :button{text = "Close"} -- + + return dialog +end diff --git a/Theme Preferences/SaveConfigurationDialog.lua b/Theme Preferences/SaveConfigurationDialog.lua new file mode 100644 index 0000000..c899dfa --- /dev/null +++ b/Theme Preferences/SaveConfigurationDialog.lua @@ -0,0 +1,42 @@ +return function(theme, isImport, onConfirmation) + local title = "Save Configuration" + local okButtonText = "&OK" + + if isImport then + title = "Import Configuration" + okButtonText = "Save" + end + + local dialog = Dialog(title) + + dialog -- + :entry{ + id = "name", + label = "Name", + text = theme.name, + onchange = function() + dialog:modify{id = "ok", enabled = #dialog.data.name > 0} -- + end + } -- + :separator() -- + :button{ + id = "ok", + text = okButtonText, + enabled = #theme.name > 0, + onclick = function() onConfirmation(dialog.data.name) end + } -- + + if isImport then + dialog:button{ + text = "Save and Apply", + enabled = #theme.name > 0, + onclick = function() + onConfirmation(dialog.data.name, true) + end + } + end + + dialog:button{text = "Cancel"} + + return dialog +end diff --git a/Theme Preferences/ThemeManager.lua b/Theme Preferences/ThemeManager.lua index d907653..dc1fa27 100644 --- a/Theme Preferences/ThemeManager.lua +++ b/Theme Preferences/ThemeManager.lua @@ -1,9 +1,13 @@ -local EXPORT_DIALOG_WIDTH = 540 - local ThemeEncoder = dofile("./Base64Encoder.lua") +local LoadConfigurationDialog = dofile("./LoadConfigurationDialog.lua") +local ImportConfigurationDialog = dofile("./ImportConfigurationDialog.lua") +local SaveConfigurationDialog = dofile("./SaveConfigurationDialog.lua") local ThemeManager = {storage = nil} +local DefaultThemeEncoded = + "" + function ThemeManager:Init(options) self.storage = options.storage @@ -23,8 +27,7 @@ function ThemeManager:Init(options) "" } - self.storage.savedThemes = self.storage.savedThemes or - "" + self.storage.savedThemes = self.storage.savedThemes or DefaultThemeEncoded end function ThemeManager:SetCurrentTheme(theme) @@ -40,31 +43,24 @@ function ThemeManager:GetCurrentTheme() end end -function ThemeManager:Find(name) - for i, savedthemeCode in ipairs(self.storage.savedThemes) do - if ThemeEncoder:DecodeName(savedthemeCode) == name then return i end - end -end - function ThemeManager:Save(theme, onsave, isImport) - local title = "Save Configuration" - local okButtonText = "OK" + local dialog = nil - if isImport then - title = "Import Configuration" - okButtonText = "Save" + local getThemeIndex = function(name) + for i, encodedTheme in ipairs(self.storage.savedThemes) do + if ThemeEncoder:DecodeName(encodedTheme) == name then + return i + end + end end - local saveDialog = Dialog(title) - - local save = function(options) - local applyImmediately = options and options.apply - local isNameUsed = self:Find(saveDialog.data.name) + local onConfirm = function(name, applyImmediately) + local themeIndex = getThemeIndex(name) - if isNameUsed then + if themeIndex then local overwriteConfirmation = app.alert { title = "Configuration overwrite", - text = "Configuration with a name " .. saveDialog.data.name .. + text = "Configuration with a name " .. name .. " already exists, do you want to overwrite it?", buttons = {"Yes", "No"} } @@ -72,7 +68,7 @@ function ThemeManager:Save(theme, onsave, isImport) if overwriteConfirmation ~= 1 then return end end - theme.name = saveDialog.data.name + theme.name = name if not isImport or (isImport and applyImmediately) then onsave(theme) @@ -81,270 +77,65 @@ function ThemeManager:Save(theme, onsave, isImport) local code = ThemeEncoder:EncodeSigned(theme.name, theme.parameters, theme.colors) - if isNameUsed then - self.storage.savedThemes[isNameUsed] = code + if themeIndex then + self.storage.savedThemes[themeIndex] = code else table.insert(self.storage.savedThemes, code) end - saveDialog:close() - end - - saveDialog -- - :entry{ - id = "name", - label = "Name", - text = theme.name, - onchange = function() - saveDialog:modify{id = "ok", enabled = #saveDialog.data.name > 0} -- - end - } -- - :separator() -- - :button{ - id = "ok", - text = okButtonText, - enabled = #theme.name > 0, - onclick = function() save() end - } -- - - if isImport then - saveDialog:button{ - text = "Save and Apply", - enabled = #theme.name > 0, - onclick = function() save {apply = true} end - } + dialog:close() end - saveDialog -- - :button{text = "Cancel"} -- - :show() - + dialog = SaveConfigurationDialog(theme, isImport, onConfirm) + dialog:show() end -function ThemeManager:ShowExportDialog(name, code, onclose) - local isFirstOpen = true - - local exportDialog = Dialog { - title = "Export " .. name, - onclose = function() if not isFirstOpen then onclose() end end +function ThemeManager:GetDecodedThemes() + local encodedThemes = { + DefaultThemeEncoded, table.unpack(self.storage.savedThemes) } + local themes = {} - exportDialog -- - :entry{label = "Code", text = code} -- - :separator() -- - :button{text = "Close"} -- - - -- Open and close to initialize bounds - exportDialog:show{wait = false} - exportDialog:close() - - isFirstOpen = false + for _, encodedTheme in ipairs(encodedThemes) do + local theme = ThemeEncoder:DecodeSigned(encodedTheme) + theme.code = encodedTheme - local bounds = exportDialog.bounds - bounds.x = bounds.x - (EXPORT_DIALOG_WIDTH - bounds.width) / 2 - bounds.width = EXPORT_DIALOG_WIDTH - exportDialog.bounds = bounds + table.insert(themes, theme) + end - exportDialog:show() + return themes end -local CurrentPage = 1 -local ConfigurationsPerPage = 10 -local LoadButtonIdPrefix = "saved-theme-load-" -local ExportButtonIdPrefix = "saved-theme-export-" -local DeleteButtonIdPrefix = "saved-theme-delete-" - -function ThemeManager:Load(onload, onreset) - local pages = math.ceil(#self.storage.savedThemes / ConfigurationsPerPage) - - CurrentPage = math.min(CurrentPage, pages) - - local skip = (CurrentPage - 1) * ConfigurationsPerPage - - local browseDialog = Dialog("Load Configuration") +function ThemeManager:Load(onload) + local themes = self:GetDecodedThemes() - local updateBrowseDialog = function() - browseDialog -- - :modify{id = "button-previous", enabled = CurrentPage > 1} -- - :modify{id = "button-next", enabled = CurrentPage < pages} + local dialog = nil + local onDelete = nil + local onImport = nil - skip = (CurrentPage - 1) * ConfigurationsPerPage - - for index = 1, ConfigurationsPerPage do - local savedthemeCode = self.storage.savedThemes[skip + index] - local loadButtonId = LoadButtonIdPrefix .. tostring(index) - local exportButtonId = ExportButtonIdPrefix .. tostring(index) - local deleteButtonId = DeleteButtonIdPrefix .. tostring(index) - - if savedthemeCode then - local theme = ThemeEncoder:DecodeSigned(savedthemeCode) - - browseDialog -- - :modify{id = loadButtonId, visible = true, label = theme.name} -- - :modify{id = exportButtonId, visible = true} -- - :modify{id = deleteButtonId, visible = true} - else - browseDialog -- - :modify{id = loadButtonId, visible = false} -- - :modify{id = exportButtonId, visible = false} -- - :modify{id = deleteButtonId, visible = false} - end - end + local CreateDialog = function() + dialog = LoadConfigurationDialog(themes, onload, onDelete, onImport) + dialog:show() end - browseDialog -- - :button{ - id = "button-previous", - text = "Previous", - enabled = false, - onclick = function() - CurrentPage = CurrentPage - 1 - updateBrowseDialog() - end - } -- - :button{text = "", enabled = false} -- - :button{ - id = "button-next", - text = "Next", - enabled = pages > 1, - onclick = function() - CurrentPage = CurrentPage + 1 - updateBrowseDialog() - end - } -- - :separator() - - for index = 1, ConfigurationsPerPage do - browseDialog -- - :button{ - id = LoadButtonIdPrefix .. tostring(index), - label = "", -- Set empty label, without it it's impossible to update it later - text = "Load", - onclick = function() - local savedthemeCode = self.storage.savedThemes[skip + index] - local theme = ThemeEncoder:DecodeSigned(savedthemeCode) - - local confirmation = app.alert { - title = "Loading theme " .. theme.name, - text = "Unsaved changes will be lost, do you want to continue?", - buttons = {"Yes", "No"} - } - - if confirmation == 1 then - browseDialog:close() - onload(theme) - end - end - } -- - :button{ - id = ExportButtonIdPrefix .. tostring(index), - text = "Export", - onclick = function() - local savedthemeCode = self.storage.savedThemes[skip + index] - local theme = ThemeEncoder:DecodeSigned(savedthemeCode) - - browseDialog:close() - local onExportDialogClose = function() - browseDialog:show() - end - - self:ShowExportDialog(theme.name, savedthemeCode, - onExportDialogClose) - end - } -- - :button{ - id = DeleteButtonIdPrefix .. tostring(index), - text = "Delete", - onclick = function() - local savedthemeCode = self.storage.savedThemes[skip + index] - local theme = ThemeEncoder:DecodeSigned(savedthemeCode) - - local confirmation = app.alert { - title = "Delete " .. theme.name, - text = "Are you sure?", - buttons = {"Yes", "No"} - } - - if confirmation == 1 then - table.remove(self.storage.savedThemes, skip + index) - - browseDialog:close() - self:Load(onload, onreset) - end - end - } + onDelete = function(index) + table.remove(self.storage.savedThemes, index) + themes = self:GetDecodedThemes() + CreateDialog() end - if #self.storage.savedThemes > 0 then - browseDialog:separator{id = "separator"} - end - - -- Initialize - updateBrowseDialog() - - browseDialog -- - :button{ - text = "Import", - onclick = function() - browseDialog:close() - local importDialog = Dialog("Import") - - importDialog -- - :entry{id = "code", label = "Code"} -- - :separator{id = "separator"} -- - :button{ - text = "Import", - onclick = function() - local code = importDialog.data.code - local theme = ThemeEncoder:DecodeSigned(code) - - if not theme then - importDialog:modify{ - id = "separator", - text = "Incorrect code" - } - return - end - - importDialog:close() - - self:Save(theme, onload, true) - end - } -- - :button{text = "Cancel"} -- - - -- Open and close to initialize bounds - importDialog:show{wait = false} - importDialog:close() - - local bounds = importDialog.bounds - bounds.x = bounds.x - (EXPORT_DIALOG_WIDTH - bounds.width) / 2 - bounds.width = EXPORT_DIALOG_WIDTH - importDialog.bounds = bounds - - importDialog:show() + onImport = function() + local decode = function(code) + return ThemeEncoder:DecodeSigned(code) end - } -- - :button{ - text = "Reset to Default", - onclick = function() - local confirmation = app.alert { - title = "Resetting theme", - text = "Unsaved changes will be lost, do you want to continue?", - buttons = {"Yes", "No"} - } - if confirmation == 1 then - browseDialog:close() - onreset() - end - end - } + local onConfirm = function(theme) self:Save(theme, onload, true) end + + local importDialog = ImportConfigurationDialog(decode, onConfirm) + importDialog:show() + end - browseDialog -- - :separator() -- - :button{text = "Close"} -- - :show() + CreateDialog() end return ThemeManager diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index dc9dc5a..14b368c 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -2,6 +2,7 @@ local Template = dofile("./Template.lua") local ThemeManager = dofile("./ThemeManager.lua") local FontsProvider = dofile("./FontsProvider.lua") local ThemePreferencesDialog = dofile("./ThemePreferencesDialog.lua") +local GetWindowSize = dofile("./GetWindowSize.lua") -- TODO: This would be a good place to use "require" local THEME_ID = "custom" local DialogSize = Size(240, 412) @@ -138,17 +139,6 @@ function CopyToTheme(colors, parameters) IsModified = parameters.isModified end -function GetWindowSize() - if app.apiVersion >= 25 then return app.window end - - local dialog = Dialog() - dialog:show{wait = false} - dialog:close() - - return Size(dialog.bounds.x * 2 + dialog.bounds.width, - dialog.bounds.y * 2 + dialog.bounds.height) -end - function init(plugin) -- Do nothing when UI is not available if not app.isUIAvailable then return end @@ -186,13 +176,14 @@ function init(plugin) end local onload = function() - local onload = function(theme) LoadTheme(theme) end - local onreset = function() LoadTheme(Template()) end + local onload = function(theme) + LoadTheme(theme or Template()) + end -- Hide the Theme Preferences dialog dialog:close() - ThemeManager:Load(onload, onreset) + ThemeManager:Load(onload) -- Reopen the dialog dialog = CreateDialog() From 76301280509e475f9a1d863f84e2b15935ccc4f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Wed, 31 Jan 2024 21:38:56 +0100 Subject: [PATCH 12/30] Refactor logic for refreshing the theme into a separate file --- Theme Preferences/FontsProvider.lua | 10 +- .../ImportConfigurationDialog.lua | 4 +- Theme Preferences/RefreshTheme.lua | 113 ++++++++++ Theme Preferences/ThemePreferencesDialog.lua | 6 +- Theme Preferences/extension.lua | 204 ++++-------------- 5 files changed, 166 insertions(+), 171 deletions(-) create mode 100644 Theme Preferences/RefreshTheme.lua diff --git a/Theme Preferences/FontsProvider.lua b/Theme Preferences/FontsProvider.lua index 54a1b11..9960abb 100644 --- a/Theme Preferences/FontsProvider.lua +++ b/Theme Preferences/FontsProvider.lua @@ -2,6 +2,7 @@ local DefaultFont = { default = {name = "Aseprite", size = "9"}, mini = {name = "Aseprite Mini", size = "7"} } + local FontSizes = {"6", "7", "8", "9", "10", "11", "12"} local FontsProvider = {storage = nil, availableFonts = {}} @@ -46,13 +47,6 @@ function FontsProvider:SetMiniFontSize(fontSize) self.storage.font.mini.size = fontSize end -function FontsProvider:GetFontDeclaration(font) - if not font.type or not font.file then return "" end - - return string.format("", - font.name, font.type, font.file) -end - -- FUTURE: Revisit this, currently can cause issues and completely break the window layout rendering Aseprite unusable function FontsProvider:VerifyScaling() local currentFont = self:GetCurrentFont() @@ -297,7 +291,7 @@ function FontsProvider:OpenDialog(onconfirm) self:SetDefaultFont(dialog.data["default-font"]) self:SetMiniFont(dialog.data["mini-font"]) - onconfirm() + onconfirm(self:GetCurrentFont()) -- self:VerifyScaling() end diff --git a/Theme Preferences/ImportConfigurationDialog.lua b/Theme Preferences/ImportConfigurationDialog.lua index ec422e1..9329b78 100644 --- a/Theme Preferences/ImportConfigurationDialog.lua +++ b/Theme Preferences/ImportConfigurationDialog.lua @@ -1,6 +1,6 @@ local IMPORT_DIALOG_WIDTH = 540 -return function(decode, onok) +return function(decode, onConfirm) local dialog = Dialog("Import") dialog -- @@ -17,7 +17,7 @@ return function(decode, onok) end dialog:close() - onok(theme) + onConfirm(theme) end } -- :button{text = "Cancel"} -- diff --git a/Theme Preferences/RefreshTheme.lua b/Theme Preferences/RefreshTheme.lua new file mode 100644 index 0000000..0330bb8 --- /dev/null +++ b/Theme Preferences/RefreshTheme.lua @@ -0,0 +1,113 @@ +local Template = dofile("./Template.lua") + +local THEME_ID = "custom" + +local ExtensionsDirectory = app.fs.joinPath(app.fs.userConfigPath, "extensions") +local ThemePreferencesDirectory = app.fs.joinPath(ExtensionsDirectory, + "theme-preferences") +local SheetTemplatePath = app.fs.joinPath(ThemePreferencesDirectory, + "sheet-template.png") +local SheetPath = app.fs.joinPath(ThemePreferencesDirectory, "sheet.png") +local ThemeXmlTemplatePath = app.fs.joinPath(ThemePreferencesDirectory, + "theme-template.xml") +local ThemeXmlPath = app.fs.joinPath(ThemePreferencesDirectory, "theme.xml") + +function ColorToHex(color) + return string.format("#%02x%02x%02x", color.red, color.green, color.blue) +end + +function ReadAll(filePath) + local file = assert(io.open(filePath, "rb")) + local content = file:read("*all") + file:close() + return content +end + +function WriteAll(filePath, content) + local file = io.open(filePath, "w") + if file then + file:write(content) + file:close() + end +end + +function UpdateThemeSheet(template, theme) + -- Prepare color lookup + local map = {} + + for id, templateColor in pairs(template.colors) do + map[templateColor.rgbaPixel] = theme.colors[id] + end + + -- Prepare sheet.png + local image = Image {fromFile = SheetTemplatePath} + + -- Save references to function to improve performance + local getPixel, drawPixel = image.getPixel, image.drawPixel + local rgbaA = app.pixelColor.rgbaA + local pixelValue, themeColor + + for x = 0, image.width - 1 do + for y = 0, image.height - 1 do + pixelValue = getPixel(image, x, y) + themeColor = map[pixelValue] + + if themeColor then + drawPixel(image, x, y, Color { + red = themeColor.red, + green = themeColor.green, + blue = themeColor.blue, + -- Restore the original alpha value + alpha = rgbaA(pixelValue) + }) + end + end + end + + image:saveAs(SheetPath) +end + +function FormatFontDeclaration(font) + if not font.type or not font.file then return "" end + + return string.format("", + font.name, font.type, font.file) +end + +function UpdateThemeXml(template, theme, font) + -- Prepare theme.xml + local xmlContent = ReadAll(ThemeXmlTemplatePath) + + for id, _ in pairs(template.colors) do + xmlContent = xmlContent:gsub("<" .. id .. ">", + ColorToHex(theme.colors[id])) + end + + -- Setting fonts for these just in case it's a system font + xmlContent = xmlContent:gsub("", + FormatFontDeclaration(font.default)) + xmlContent = xmlContent:gsub("", font.default.name) + xmlContent = xmlContent:gsub("", font.default.size) + + xmlContent = xmlContent:gsub("", + FormatFontDeclaration(font.mini)) + xmlContent = xmlContent:gsub("", font.mini.name) + xmlContent = xmlContent:gsub("", font.mini.size) + + -- TODO: If using system fonts - ask user if they want to switch default scaling percentages + + WriteAll(ThemeXmlPath, xmlContent) +end + +return function(theme, font) + local template = Template() + + UpdateThemeSheet(template, theme) + UpdateThemeXml(template, theme, font) + + -- Switch Aseprite to the custom theme + app.preferences.theme.selected = THEME_ID + + -- Force refresh of the Aseprite UI to reload the theme + app.command.Refresh() +end diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 26b1b5a..94a6335 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -406,12 +406,12 @@ return function(options) text = "Save", enabled = isModified, -- Only allows saving of a modified theme onclick = function() - local onsuccess = function(theme) - UpdateTitle(theme.name) + local refreshTitle = function(name) + UpdateTitle(name) MarkAsModified(false) end - options.onsave(dialog.data, GetParameters(), onsuccess) + options.onsave(refreshTitle) end } -- :button{text = "Load", onclick = function() options.onload() end} -- diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 14b368c..007920f 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -3,142 +3,13 @@ local ThemeManager = dofile("./ThemeManager.lua") local FontsProvider = dofile("./FontsProvider.lua") local ThemePreferencesDialog = dofile("./ThemePreferencesDialog.lua") local GetWindowSize = dofile("./GetWindowSize.lua") -- TODO: This would be a good place to use "require" +local RefreshTheme = dofile("./RefreshTheme.lua") -local THEME_ID = "custom" local DialogSize = Size(240, 412) -local ExtensionsDirectory = app.fs.joinPath(app.fs.userConfigPath, "extensions") -local ThemePreferencesDirectory = app.fs.joinPath(ExtensionsDirectory, - "theme-preferences") -local SheetTemplatePath = app.fs.joinPath(ThemePreferencesDirectory, - "sheet-template.png") -local SheetPath = app.fs.joinPath(ThemePreferencesDirectory, "sheet.png") -local ThemeXmlTemplatePath = app.fs.joinPath(ThemePreferencesDirectory, - "theme-template.xml") -local ThemeXmlPath = app.fs.joinPath(ThemePreferencesDirectory, "theme.xml") - -function ReadAll(filePath) - local file = assert(io.open(filePath, "rb")) - local content = file:read("*all") - file:close() - return content -end - -function WriteAll(filePath, content) - local file = io.open(filePath, "w") - if file then - file:write(content) - file:close() - end -end - -function ColorToHex(color) - return string.format("#%02x%02x%02x", color.red, color.green, color.blue) -end - -- Start from the template -local Theme = Template() local IsDialogOpen = false -function UpdateThemeSheet(theme) - -- Prepare color lookup - local map = {} - local template = Template() - - for id, templateColor in pairs(template.colors) do - map[templateColor.rgbaPixel] = theme.colors[id] - end - - -- Prepare sheet.png - local image = Image {fromFile = SheetTemplatePath} - - -- Save references to function to improve performance - local getPixel, drawPixel = image.getPixel, image.drawPixel - local rgbaA = app.pixelColor.rgbaA - local pixelValue, themeColor - - for x = 0, image.width - 1 do - for y = 0, image.height - 1 do - pixelValue = getPixel(image, x, y) - themeColor = map[pixelValue] - - if themeColor then - drawPixel(image, x, y, Color { - red = themeColor.red, - green = themeColor.green, - blue = themeColor.blue, - -- Restore the original alpha value - alpha = rgbaA(pixelValue) - }) - end - end - end - - image:saveAs(SheetPath) -end - -function UpdateThemeXml(theme) - -- Prepare theme.xml - local xmlContent = ReadAll(ThemeXmlTemplatePath) - - for id, color in pairs(theme.colors) do - xmlContent = xmlContent:gsub("<" .. id .. ">", ColorToHex(color)) - end - - local font = FontsProvider:GetCurrentFont() - - -- Setting fonts for these just in case it's a system font - xmlContent = xmlContent:gsub("", - FontsProvider:GetFontDeclaration(font.default)) - xmlContent = xmlContent:gsub("", font.default.name) - xmlContent = xmlContent:gsub("", font.default.size) - - xmlContent = xmlContent:gsub("", - FontsProvider:GetFontDeclaration(font.mini)) - xmlContent = xmlContent:gsub("", font.mini.name) - xmlContent = xmlContent:gsub("", font.mini.size) - - -- TODO: If using system fonts - ask user if they want to switch default scaling percentages - - WriteAll(ThemeXmlPath, xmlContent) -end - -function RefreshTheme() - UpdateThemeSheet(Theme) - UpdateThemeXml(Theme) - - -- Switch Aseprite to the custom theme - app.preferences.theme.selected = THEME_ID - - -- Force refresh of the Aseprite UI to reload the theme - app.command.Refresh() - - ThemeManager:SetCurrentTheme(Theme) -end - -function LoadTheme(theme, stopRefresh) - Theme = theme - IsModified = false - - if not stopRefresh then RefreshTheme() end -end - -function CopyToTheme(colors, parameters) - -- Copy new colors - for key, _ in pairs(Theme.colors) do - if colors[key] then Theme.colors[key] = colors[key] end - end - - -- Copy new parameters - for key, _ in pairs(Theme.parameters) do - if parameters[key] ~= nil then - Theme.parameters[key] = parameters[key] - end - end - - IsModified = parameters.isModified -end - function init(plugin) -- Do nothing when UI is not available if not app.isUIAvailable then return end @@ -161,62 +32,81 @@ function init(plugin) group = "view_screen", onenabled = function() return not IsDialogOpen end, onclick = function() + local currentTheme = ThemeManager:GetCurrentTheme() + local currentFont = FontsProvider:GetCurrentFont() + local dialog = nil - local CreateDialog = nil + local CreateDialog = function() end - local onsave = function(colors, parameters, onSuccessDialog) + local onSave = function(refreshTitle) local onsuccess = function(theme) - -- Pass the saved theme to the dialog to update the window title - onSuccessDialog(theme) + refreshTitle(theme.name) + + currentTheme = theme + + ThemeManager:SetCurrentTheme(theme) IsModified = false end - CopyToTheme(colors, parameters) - ThemeManager:Save(Theme, onsuccess) + ThemeManager:Save(currentTheme, onsuccess) end - local onload = function() - local onload = function(theme) - LoadTheme(theme or Template()) - end - + local onLoad = function() -- Hide the Theme Preferences dialog dialog:close() - ThemeManager:Load(onload) + local onConfirm = function(theme) + currentTheme = theme or Template() + + ThemeManager:SetCurrentTheme(currentTheme) + IsModified = false + + RefreshTheme(currentTheme, currentFont) + end + + ThemeManager:Load(onConfirm) -- Reopen the dialog dialog = CreateDialog() end - local onfont = function() - local onconfirm = function() RefreshTheme() end - + local onFont = function() -- Hide the Theme Preferences dialog dialog:close() - FontsProvider:OpenDialog(onconfirm) + local onConfirm = function(font) + currentFont = font + RefreshTheme(currentTheme, currentFont) + end + + FontsProvider:OpenDialog(onConfirm) -- Reopen the dialog dialog = CreateDialog() end - local onok = function(colors, parameters) - CopyToTheme(colors, parameters) - RefreshTheme() + local onConfirm = function(colors, parameters) + currentTheme.colors = colors + currentTheme.parameters = parameters + + IsModified = parameters.isModified + + ThemeManager:SetCurrentTheme(currentTheme) + + RefreshTheme(currentTheme, currentFont) end CreateDialog = function() local newDialog = ThemePreferencesDialog { - name = Theme.name, - colors = Theme.colors, - parameters = Theme.parameters, + name = currentTheme.name, + colors = currentTheme.colors, + parameters = currentTheme.parameters, isModified = IsModified, onclose = function() IsDialogOpen = false end, - onsave = onsave, - onload = onload, - onfont = onfont, - onok = onok + onsave = onSave, + onload = onLoad, + onfont = onFont, + onok = onConfirm } local window = GetWindowSize() @@ -241,5 +131,3 @@ end function exit(plugin) plugin.preferences.themePreferences.isThemeModified = IsModified end - --- TODO: Move all of the Refresh/Update theme logic to a separate file From a30ef4fda025f7d15b1986af4a9fb384dad8379a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Wed, 31 Jan 2024 22:23:06 +0100 Subject: [PATCH 13/30] Refactor FontConfigurationDialog to a separate file --- Theme Preferences/DefaultFont.lua | 6 + Theme Preferences/FontConfigurationDialog.lua | 116 ++++++++++++++ Theme Preferences/FontsProvider.lua | 147 ++---------------- Theme Preferences/extension.lua | 8 +- 4 files changed, 138 insertions(+), 139 deletions(-) create mode 100644 Theme Preferences/DefaultFont.lua create mode 100644 Theme Preferences/FontConfigurationDialog.lua diff --git a/Theme Preferences/DefaultFont.lua b/Theme Preferences/DefaultFont.lua new file mode 100644 index 0000000..b4528a0 --- /dev/null +++ b/Theme Preferences/DefaultFont.lua @@ -0,0 +1,6 @@ +return function() + return { + default = {name = "Aseprite", size = "9"}, + mini = {name = "Aseprite Mini", size = "7"} + } +end diff --git a/Theme Preferences/FontConfigurationDialog.lua b/Theme Preferences/FontConfigurationDialog.lua new file mode 100644 index 0000000..a450a1c --- /dev/null +++ b/Theme Preferences/FontConfigurationDialog.lua @@ -0,0 +1,116 @@ +local DefaultFont = dofile("./DefaultFont.lua") + +local FontSizes = {"6", "7", "8", "9", "10", "11", "12"} + +function HasSize(font) return font.type ~= "spritesheet" end + +function GetFontNames(fonts) + local fontNames = {} + + for name, _ in pairs(fonts) do table.insert(fontNames, name) end + table.sort(fontNames) + + return fontNames +end + +return function(font, availableFonts, onconfirm) + local fontNames = GetFontNames(availableFonts) + + local dialog = Dialog("Font Configuration") + + local updateFonts = function() + local fontName = dialog.data["default-font"] + local defaultFont = availableFonts[fontName] + + local miniFontName = dialog.data["mini-font"] + local miniFont = availableFonts[miniFontName] + + local newFont = { + default = { + name = defaultFont.name, + type = defaultFont.type, + file = defaultFont.file, + size = dialog.data["default-font-size"] + }, + mini = { + name = miniFont.name, + type = miniFont.type, + file = miniFont.file, + size = dialog.data["mini-font-size"] + } + } + + onconfirm(newFont) + + -- self:VerifyScaling() + end + + dialog -- + :separator{text = "Default"} -- + :combobox{ + id = "default-font", + label = "Name", + option = font.default.name, + options = fontNames, + onchange = function() + local fontName = dialog.data["default-font"] + dialog:modify{ + id = "default-font-size", + enabled = HasSize(availableFonts[fontName]) + } + end + } -- + :combobox{ + id = "default-font-size", + options = FontSizes, + option = font.default.size, + enabled = HasSize(font.default) + } -- + :separator{text = "Mini"} -- + :combobox{ + id = "mini-font", + label = "Name", + option = font.mini.name, + options = fontNames, + onchange = function() + local miniFontName = dialog.data["mini-font"] + dialog:modify{ + id = "mini-font-size", + enabled = HasSize(availableFonts[miniFontName]) + } + end + } -- + :combobox{ + id = "mini-font-size", + options = FontSizes, + option = font.mini.size, + enabled = HasSize(font.mini) + } -- + :separator() -- + :button{ + text = "Reset to Default", + onclick = function() + local default = DefaultFont() + + dialog -- + :modify{id = "default-font-size", option = default.default.size} -- + :modify{id = "mini-font-size", option = default.mini.size} -- + :modify{id = "default-font", option = default.default.name} -- + :modify{id = "mini-font", option = default.mini.name} -- + + updateFonts() + end + } -- + :separator() -- + :button{ + text = "OK", + onclick = function() + updateFonts() + dialog:close() + end + } -- + :button{text = "Apply", onclick = updateFonts} -- + :button{text = "Cancel"} + + return dialog +end diff --git a/Theme Preferences/FontsProvider.lua b/Theme Preferences/FontsProvider.lua index 9960abb..4b6f3b8 100644 --- a/Theme Preferences/FontsProvider.lua +++ b/Theme Preferences/FontsProvider.lua @@ -1,50 +1,19 @@ -local DefaultFont = { - default = {name = "Aseprite", size = "9"}, - mini = {name = "Aseprite Mini", size = "7"} -} - -local FontSizes = {"6", "7", "8", "9", "10", "11", "12"} +local FontConfigurationDialog = dofile("./FontConfigurationDialog.lua") +local DefaultFont = dofile("./DefaultFont.lua") local FontsProvider = {storage = nil, availableFonts = {}} function FontsProvider:Init(options) self.storage = options.storage - self.storage.font = self.storage.font or DefaultFont + self.storage.font = self.storage.font or DefaultFont() self:_RefreshAvailableFonts() end function FontsProvider:GetCurrentFont() return self.storage.font end -function FontsProvider:SetDefaultFont(fontName) - if fontName == nil or #fontName == 0 then return end - - local newFont = self.availableFonts[fontName] - if newFont == nil then return end - - self.storage.font.default.name = newFont.name - self.storage.font.default.type = newFont.type - self.storage.font.default.file = newFont.file -end - -function FontsProvider:SetMiniFont(fontName) - - if fontName == nil or #fontName == 0 then return end - - local newFont = self.availableFonts[fontName] - if newFont == nil then return end - - self.storage.font.mini.name = newFont.name - self.storage.font.mini.type = newFont.type - self.storage.font.mini.file = newFont.file -end - -function FontsProvider:SetDefaultFontSize(fontSize) - self.storage.font.default.size = fontSize -end - -function FontsProvider:SetMiniFontSize(fontSize) - self.storage.font.mini.size = fontSize +function FontsProvider:SetCurrentFont(font) + self.storage.font = font or DefaultFont() end -- FUTURE: Revisit this, currently can cause issues and completely break the window layout rendering Aseprite unusable @@ -207,20 +176,6 @@ function FontsProvider:GetFontsFromDirectory(path, fonts) return fonts end -function FontsProvider:GetAvailableFontNames() - if not self.availableFonts then self:_RefreshAvailableFonts() end - - local fontNames = {} - - for name, _ in pairs(self.availableFonts) do - table.insert(fontNames, name) - end - - table.sort(fontNames) - - return fontNames -end - function FontsProvider:_RefreshAvailableFonts() self.availableFonts = {} @@ -276,96 +231,16 @@ function FontsProvider:_GetSystemFonts() return systemFonts end -function FontsProvider:_HasSize(font) return font.type ~= "spritesheet" end - function FontsProvider:OpenDialog(onconfirm) - local dialog = Dialog("Font Configuration") - - local fontNames = self:GetAvailableFontNames() - local currentFont = self:GetCurrentFont() - - local updateFonts = function() - self:SetDefaultFontSize(dialog.data["default-font-size"]) - self:SetMiniFontSize(dialog.data["mini-font-size"]) - - self:SetDefaultFont(dialog.data["default-font"]) - self:SetMiniFont(dialog.data["mini-font"]) - - onconfirm(self:GetCurrentFont()) + local currentFont = FontsProvider:GetCurrentFont() - -- self:VerifyScaling() + local onConfirm = function(newFont) + FontsProvider:SetCurrentFont(newFont) + onconfirm(newFont) end - dialog -- - :separator{text = "Default"} -- - :combobox{ - id = "default-font", - label = "Name", - option = currentFont.default.name, - options = fontNames, - onchange = function() - local newFont = self.availableFonts[dialog.data["default-font"]] - dialog:modify{ - id = "default-font-size", - enabled = self:_HasSize(newFont) - } - end - } -- - :combobox{ - id = "default-font-size", - options = FontSizes, - option = currentFont.default.size or DefaultFont.default.size, - enabled = self:_HasSize(currentFont.default), - onchange = function() - self:SetDefaultFontSize(dialog.data["default-font-size"]) - end - } -- - :separator{text = "Mini"} -- - :combobox{ - id = "mini-font", - label = "Name", - option = currentFont.mini.name, - options = fontNames, - onchange = function() - local newFont = self.availableFonts[dialog.data["mini-font"]] - dialog:modify{ - id = "mini-font-size", - enabled = self:_HasSize(newFont) - } - end - } -- - :combobox{ - id = "mini-font-size", - options = FontSizes, - option = currentFont.mini.size or DefaultFont.mini.size, - enabled = self:_HasSize(currentFont.mini), - onchange = function() - self:SetMiniFontSize(dialog.data["mini-font-size"]) - end - } -- - :separator() -- - :button{ - text = "Reset to Default", - onclick = function() - dialog -- - :modify{id = "default-font-size", option = DefaultFont.default.size} -- - :modify{id = "mini-font-size", option = DefaultFont.mini.size} -- - :modify{id = "default-font", option = DefaultFont.default.name} -- - :modify{id = "mini-font", option = DefaultFont.mini.name} -- - - updateFonts() - end - } -- - :separator() -- - :button{ - text = "OK", - onclick = function() - updateFonts() - dialog:close() - end - } -- - :button{text = "Apply", onclick = updateFonts} -- - :button{text = "Cancel"} + local dialog = FontConfigurationDialog(currentFont, self.availableFonts, + onConfirm) dialog:show() end diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 007920f..bfcc20f 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -33,7 +33,6 @@ function init(plugin) onenabled = function() return not IsDialogOpen end, onclick = function() local currentTheme = ThemeManager:GetCurrentTheme() - local currentFont = FontsProvider:GetCurrentFont() local dialog = nil local CreateDialog = function() end @@ -61,6 +60,8 @@ function init(plugin) ThemeManager:SetCurrentTheme(currentTheme) IsModified = false + local currentFont = FontsProvider:GetCurrentFont() + RefreshTheme(currentTheme, currentFont) end @@ -75,8 +76,7 @@ function init(plugin) dialog:close() local onConfirm = function(font) - currentFont = font - RefreshTheme(currentTheme, currentFont) + RefreshTheme(currentTheme, font) end FontsProvider:OpenDialog(onConfirm) @@ -93,6 +93,8 @@ function init(plugin) ThemeManager:SetCurrentTheme(currentTheme) + local currentFont = FontsProvider:GetCurrentFont() + RefreshTheme(currentTheme, currentFont) end From 7df2cc4c2e92db0d57a7d8b1b877c75995400e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Wed, 31 Jan 2024 22:25:37 +0100 Subject: [PATCH 14/30] Fix saving the current theme --- Theme Preferences/ThemePreferencesDialog.lua | 2 +- Theme Preferences/extension.lua | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 94a6335..6111be4 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -411,7 +411,7 @@ return function(options) MarkAsModified(false) end - options.onsave(refreshTitle) + options.onsave(dialog.data, GetParameters(), refreshTitle) end } -- :button{text = "Load", onclick = function() options.onload() end} -- diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index bfcc20f..d286de6 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -37,14 +37,15 @@ function init(plugin) local dialog = nil local CreateDialog = function() end - local onSave = function(refreshTitle) + local onSave = function(colors, parameters, refreshTitle) local onsuccess = function(theme) refreshTitle(theme.name) - currentTheme = theme + currentTheme.colors = colors + currentTheme.parameters = parameters + IsModified = false ThemeManager:SetCurrentTheme(theme) - IsModified = false end ThemeManager:Save(currentTheme, onsuccess) From e18fd1a99aaa87978cfb99ec3be27addf97d370e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Wed, 31 Jan 2024 22:36:09 +0100 Subject: [PATCH 15/30] Move the Font configuration to its own menu option --- ROADMAP.md | 1 + Theme Preferences/FontConfigurationDialog.lua | 4 +- Theme Preferences/FontsProvider.lua | 8 ++-- Theme Preferences/ThemePreferencesDialog.lua | 1 - Theme Preferences/extension.lua | 38 +++++++++++-------- 5 files changed, 29 insertions(+), 23 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index c32394c..6e4fa9d 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -16,6 +16,7 @@ Update v1.0.3. Unreleased: - [Improvement] Minor performance improvement when saving or applying themes +- [Improvement] Move the Font configuration to it's own menu option under View > Font Preferences... Update v2.0.0: diff --git a/Theme Preferences/FontConfigurationDialog.lua b/Theme Preferences/FontConfigurationDialog.lua index a450a1c..96a197d 100644 --- a/Theme Preferences/FontConfigurationDialog.lua +++ b/Theme Preferences/FontConfigurationDialog.lua @@ -13,10 +13,10 @@ function GetFontNames(fonts) return fontNames end -return function(font, availableFonts, onconfirm) +return function(font, availableFonts, onclose, onconfirm) local fontNames = GetFontNames(availableFonts) - local dialog = Dialog("Font Configuration") + local dialog = Dialog {title = "Font Configuration", onclose = onclose} local updateFonts = function() local fontName = dialog.data["default-font"] diff --git a/Theme Preferences/FontsProvider.lua b/Theme Preferences/FontsProvider.lua index 4b6f3b8..5ccaa8c 100644 --- a/Theme Preferences/FontsProvider.lua +++ b/Theme Preferences/FontsProvider.lua @@ -231,18 +231,18 @@ function FontsProvider:_GetSystemFonts() return systemFonts end -function FontsProvider:OpenDialog(onconfirm) +function FontsProvider:OpenDialog(onClose, onSuccess) local currentFont = FontsProvider:GetCurrentFont() local onConfirm = function(newFont) FontsProvider:SetCurrentFont(newFont) - onconfirm(newFont) + onSuccess(newFont) end local dialog = FontConfigurationDialog(currentFont, self.availableFonts, - onConfirm) + onClose, onConfirm) - dialog:show() + dialog:show{wait = false} end return FontsProvider diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 6111be4..7fbd694 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -415,7 +415,6 @@ return function(options) end } -- :button{text = "Load", onclick = function() options.onload() end} -- - :button{text = "Font", onclick = function() options.onfont() end} dialog -- :separator() -- diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index d286de6..dce7240 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -7,8 +7,8 @@ local RefreshTheme = dofile("./RefreshTheme.lua") local DialogSize = Size(240, 412) --- Start from the template local IsDialogOpen = false +local IsFontsDialogOpen = false function init(plugin) -- Do nothing when UI is not available @@ -72,20 +72,6 @@ function init(plugin) dialog = CreateDialog() end - local onFont = function() - -- Hide the Theme Preferences dialog - dialog:close() - - local onConfirm = function(font) - RefreshTheme(currentTheme, font) - end - - FontsProvider:OpenDialog(onConfirm) - - -- Reopen the dialog - dialog = CreateDialog() - end - local onConfirm = function(colors, parameters) currentTheme.colors = colors currentTheme.parameters = parameters @@ -108,7 +94,6 @@ function init(plugin) onclose = function() IsDialogOpen = false end, onsave = onSave, onload = onLoad, - onfont = onFont, onok = onConfirm } @@ -129,8 +114,29 @@ function init(plugin) IsDialogOpen = true end } + + plugin:newCommand{ + id = "FontPreferences", + title = "Font Preferences...", + group = "view_screen", + onenabled = function() return not IsFontsDialogOpen end, + onclick = function() + local onClose = function() IsFontsDialogOpen = false end + + local onConfirm = function(font) + local currentTheme = ThemeManager:GetCurrentTheme() + RefreshTheme(currentTheme, font) + end + + FontsProvider:OpenDialog(onClose, onConfirm) + + IsFontsDialogOpen = true + end + } end function exit(plugin) plugin.preferences.themePreferences.isThemeModified = IsModified end + +-- TODO: Consider moving the font configuration to a separate menu option - "Font Preferences..." From 7043b5594cbef119c7398cabe672140743240e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Wed, 31 Jan 2024 22:38:26 +0100 Subject: [PATCH 16/30] Rename the dialog to Font Preferences --- ...ontConfigurationDialog.lua => FontPreferencesDialog.lua} | 2 +- Theme Preferences/FontsProvider.lua | 6 +++--- Theme Preferences/extension.lua | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) rename Theme Preferences/{FontConfigurationDialog.lua => FontPreferencesDialog.lua} (97%) diff --git a/Theme Preferences/FontConfigurationDialog.lua b/Theme Preferences/FontPreferencesDialog.lua similarity index 97% rename from Theme Preferences/FontConfigurationDialog.lua rename to Theme Preferences/FontPreferencesDialog.lua index 96a197d..95e7be8 100644 --- a/Theme Preferences/FontConfigurationDialog.lua +++ b/Theme Preferences/FontPreferencesDialog.lua @@ -16,7 +16,7 @@ end return function(font, availableFonts, onclose, onconfirm) local fontNames = GetFontNames(availableFonts) - local dialog = Dialog {title = "Font Configuration", onclose = onclose} + local dialog = Dialog {title = "Font Preferences", onclose = onclose} local updateFonts = function() local fontName = dialog.data["default-font"] diff --git a/Theme Preferences/FontsProvider.lua b/Theme Preferences/FontsProvider.lua index 5ccaa8c..206c8ac 100644 --- a/Theme Preferences/FontsProvider.lua +++ b/Theme Preferences/FontsProvider.lua @@ -1,4 +1,4 @@ -local FontConfigurationDialog = dofile("./FontConfigurationDialog.lua") +local FontPreferencesDialog = dofile("./FontPreferencesDialog.lua") local DefaultFont = dofile("./DefaultFont.lua") local FontsProvider = {storage = nil, availableFonts = {}} @@ -239,8 +239,8 @@ function FontsProvider:OpenDialog(onClose, onSuccess) onSuccess(newFont) end - local dialog = FontConfigurationDialog(currentFont, self.availableFonts, - onClose, onConfirm) + local dialog = FontPreferencesDialog(currentFont, self.availableFonts, + onClose, onConfirm) dialog:show{wait = false} end diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index dce7240..e3693b6 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -138,5 +138,3 @@ end function exit(plugin) plugin.preferences.themePreferences.isThemeModified = IsModified end - --- TODO: Consider moving the font configuration to a separate menu option - "Font Preferences..." From 95e17aa88306ef4b8743bc54b45892371e95a60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Wed, 31 Jan 2024 22:49:52 +0100 Subject: [PATCH 17/30] Move the "Reset to Default" option to the main dialog window --- ROADMAP.md | 1 + Theme Preferences/LoadConfigurationDialog.lua | 2 -- Theme Preferences/ThemeManager.lua | 11 +++------- Theme Preferences/ThemePreferencesDialog.lua | 7 +++++-- Theme Preferences/extension.lua | 20 ++++++++++++++++++- 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 6e4fa9d..94a54a2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -17,6 +17,7 @@ Unreleased: - [Improvement] Minor performance improvement when saving or applying themes - [Improvement] Move the Font configuration to it's own menu option under View > Font Preferences... +- [Improvement] Move the "Reset to Default" option to the main Theme Preferences dialog window Update v2.0.0: diff --git a/Theme Preferences/LoadConfigurationDialog.lua b/Theme Preferences/LoadConfigurationDialog.lua index 08ee597..334941f 100644 --- a/Theme Preferences/LoadConfigurationDialog.lua +++ b/Theme Preferences/LoadConfigurationDialog.lua @@ -42,7 +42,6 @@ return function(themes, onload, ondelete, onimport) } -- :button{ text = "Export", - enabled = index > 1, onclick = function() dialog:close() local onExportDialogClose = function() @@ -57,7 +56,6 @@ return function(themes, onload, ondelete, onimport) } -- :button{ text = "Delete", - enabled = index > 1, onclick = function() local confirmation = app.alert { title = "Delete " .. theme.name, diff --git a/Theme Preferences/ThemeManager.lua b/Theme Preferences/ThemeManager.lua index dc1fa27..0427db4 100644 --- a/Theme Preferences/ThemeManager.lua +++ b/Theme Preferences/ThemeManager.lua @@ -5,9 +5,6 @@ local SaveConfigurationDialog = dofile("./SaveConfigurationDialog.lua") local ThemeManager = {storage = nil} -local DefaultThemeEncoded = - "" - function ThemeManager:Init(options) self.storage = options.storage @@ -27,7 +24,8 @@ function ThemeManager:Init(options) "" } - self.storage.savedThemes = self.storage.savedThemes or DefaultThemeEncoded + self.storage.savedThemes = self.storage.savedThemes or + "" end function ThemeManager:SetCurrentTheme(theme) @@ -91,12 +89,9 @@ function ThemeManager:Save(theme, onsave, isImport) end function ThemeManager:GetDecodedThemes() - local encodedThemes = { - DefaultThemeEncoded, table.unpack(self.storage.savedThemes) - } local themes = {} - for _, encodedTheme in ipairs(encodedThemes) do + for _, encodedTheme in ipairs(self.storage.savedThemes) do local theme = ThemeEncoder:DecodeSigned(encodedTheme) theme.code = encodedTheme diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 7fbd694..d7a7b96 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -415,8 +415,11 @@ return function(options) end } -- :button{text = "Load", onclick = function() options.onload() end} -- - - dialog -- + :separator() -- + :button{ + text = "Reset to Default", + onclick = function() options.onreset() end + } -- :separator() -- :button{ text = "OK", diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index e3693b6..efff188 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -5,7 +5,7 @@ local ThemePreferencesDialog = dofile("./ThemePreferencesDialog.lua") local GetWindowSize = dofile("./GetWindowSize.lua") -- TODO: This would be a good place to use "require" local RefreshTheme = dofile("./RefreshTheme.lua") -local DialogSize = Size(240, 412) +local DialogSize = Size(240, 422) local IsDialogOpen = false local IsFontsDialogOpen = false @@ -72,6 +72,23 @@ function init(plugin) dialog = CreateDialog() end + local onReset = function() + -- Hide the Theme Preferences dialog + dialog:close() + + currentTheme = theme or Template() + + ThemeManager:SetCurrentTheme(currentTheme) + IsModified = false + + local currentFont = FontsProvider:GetCurrentFont() + + RefreshTheme(currentTheme, currentFont) + + -- Reopen the dialog + dialog = CreateDialog() + end + local onConfirm = function(colors, parameters) currentTheme.colors = colors currentTheme.parameters = parameters @@ -94,6 +111,7 @@ function init(plugin) onclose = function() IsDialogOpen = false end, onsave = onSave, onload = onLoad, + onreset = onReset, onok = onConfirm } From 8f748255c59a40afdf0a1ac7f7ad303fe3e63f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Thu, 1 Feb 2024 22:18:27 +0100 Subject: [PATCH 18/30] Fix broken replacing of semi-transparent template colors --- Theme Preferences/RefreshTheme.lua | 12 ++- Theme Preferences/Template.lua | 165 ++++++----------------------- 2 files changed, 37 insertions(+), 140 deletions(-) diff --git a/Theme Preferences/RefreshTheme.lua b/Theme Preferences/RefreshTheme.lua index 0330bb8..9b3a738 100644 --- a/Theme Preferences/RefreshTheme.lua +++ b/Theme Preferences/RefreshTheme.lua @@ -44,13 +44,15 @@ function UpdateThemeSheet(template, theme) -- Save references to function to improve performance local getPixel, drawPixel = image.getPixel, image.drawPixel - local rgbaA = app.pixelColor.rgbaA - local pixelValue, themeColor + local value, themeColor + + local pc = app.pixelColor + local rgba, r, g, b, rgbaA = pc.rgba, pc.rgbaR, pc.rgbaG, pc.rgbaB, pc.rgbaA for x = 0, image.width - 1 do for y = 0, image.height - 1 do - pixelValue = getPixel(image, x, y) - themeColor = map[pixelValue] + value = getPixel(image, x, y) + themeColor = map[rgba(r(value), g(value), b(value))] if themeColor then drawPixel(image, x, y, Color { @@ -58,7 +60,7 @@ function UpdateThemeSheet(template, theme) green = themeColor.green, blue = themeColor.blue, -- Restore the original alpha value - alpha = rgbaA(pixelValue) + alpha = rgbaA(value) }) end end diff --git a/Theme Preferences/Template.lua b/Theme Preferences/Template.lua index 18d90c6..38c5af3 100644 --- a/Theme Preferences/Template.lua +++ b/Theme Preferences/Template.lua @@ -3,151 +3,46 @@ return function() name = "Default", colors = { -- Button - ["button_highlight"] = Color {gray = 255, alpha = 255}, - ["button_background"] = Color {gray = 198, alpha = 255}, - ["button_shadow"] = Color {gray = 124, alpha = 255}, - ["button_selected"] = Color { - red = 120, - green = 96, - blue = 80, - alpha = 255 - }, + ["button_highlight"] = Color {gray = 255}, + ["button_background"] = Color {gray = 198}, + ["button_shadow"] = Color {gray = 124}, + ["button_selected"] = Color {r = 120, g = 96, b = 80}, -- Tab - ["tab_corner_highlight"] = Color { - red = 255, - green = 255, - blue = 254, - alpha = 255 - }, - ["tab_highlight"] = Color { - red = 173, - green = 202, - blue = 222, - alpha = 255 - }, - ["tab_background"] = Color { - red = 125, - green = 146, - blue = 158, - alpha = 255 - }, - ["tab_shadow"] = Color { - red = 100, - green = 84, - blue = 96, - alpha = 255 - }, + ["tab_corner_highlight"] = Color {r = 255, g = 255, b = 254}, + ["tab_highlight"] = Color {r = 173, g = 202, b = 222}, + ["tab_background"] = Color {r = 125, g = 146, b = 158}, + ["tab_shadow"] = Color {r = 100, g = 84, b = 96}, -- Window - ["window_hover"] = Color { - red = 255, - green = 235, - blue = 182, - alpha = 255 - }, - ["window_highlight"] = Color { - red = 255, - green = 254, - blue = 255, - alpha = 255 - }, - ["window_background"] = Color { - red = 210, - green = 202, - blue = 189, - alpha = 255 - }, - ["window_shadow"] = Color { - red = 149, - green = 129, - blue = 116, - alpha = 255 - }, - ["window_corner_shadow"] = Color { - red = 100, - green = 85, - blue = 96, - alpha = 255 - }, + ["window_hover"] = Color {r = 255, g = 235, b = 182}, + ["window_highlight"] = Color {r = 255, g = 254, b = 255}, + ["window_background"] = Color {r = 210, g = 202, b = 189}, + ["window_shadow"] = Color {r = 149, g = 129, b = 116}, + ["window_corner_shadow"] = Color {r = 100, g = 85, b = 96}, -- Text - ["text_regular"] = Color {gray = 2, alpha = 255}, - ["text_active"] = Color {gray = 253, alpha = 255}, - ["text_link"] = Color { - red = 44, - green = 76, - blue = 145, - alpha = 255 - }, - ["text_separator"] = Color { - red = 44, - green = 76, - blue = 145, - alpha = 255 - }, + ["text_regular"] = Color {gray = 2}, + ["text_active"] = Color {gray = 253}, + ["text_link"] = Color {r = 44, g = 76, b = 145}, + ["text_separator"] = Color {r = 44, g = 76, b = 145}, -- Field - ["field_highlight"] = Color { - red = 255, - green = 87, - blue = 87, - alpha = 255 - }, - ["field_background"] = Color {gray = 254, alpha = 255}, - ["field_shadow"] = Color {gray = 197, alpha = 255}, - ["field_corner_shadow"] = Color {gray = 123, alpha = 255}, + ["field_highlight"] = Color {r = 255, g = 87, b = 87}, + ["field_background"] = Color {gray = 254}, + ["field_shadow"] = Color {gray = 197}, + ["field_corner_shadow"] = Color {gray = 123}, -- Editor - ["editor_background"] = Color { - red = 101, - green = 85, - blue = 97, - alpha = 255 - }, - ["editor_background_shadow"] = Color { - red = 65, - green = 65, - blue = 44, - alpha = 255 - }, - ["editor_tooltip"] = Color { - red = 255, - green = 255, - blue = 125, - alpha = 255 - }, - ["editor_tooltip_shadow"] = Color { - red = 125, - green = 146, - blue = 157, - alpha = 255 - }, - ["editor_tooltip_corner_shadow"] = Color { - red = 100, - green = 84, - blue = 95, - alpha = 255 - }, - ["editor_cursor"] = Color { - red = 254, - green = 255, - blue = 255, - alpha = 255 - }, - ["editor_cursor_shadow"] = Color { - red = 123, - green = 124, - blue = 124, - alpha = 255 - }, - ["editor_cursor_outline"] = Color { - red = 1, - green = 0, - blue = 0, - alpha = 255 - }, - ["editor_icons"] = Color {gray = 1, alpha = 255} + ["editor_background"] = Color {r = 101, g = 85, b = 97}, + ["editor_background_shadow"] = Color {r = 65, g = 65, b = 44}, + ["editor_tooltip"] = Color {r = 255, g = 255, b = 125}, + ["editor_tooltip_shadow"] = Color {r = 125, g = 146, b = 157}, + ["editor_tooltip_corner_shadow"] = Color {r = 100, g = 84, b = 95}, + ["editor_cursor"] = Color {r = 254, g = 255, b = 255}, + ["editor_cursor_shadow"] = Color {r = 123, g = 124, b = 124}, + ["editor_cursor_outline"] = Color {r = 1, g = 0, b = 0}, + ["editor_icons"] = Color {gray = 1} }, parameters = {isAdvanced = false} } From f522da4dfeea9b208c6b94e0e6ee6d383b80a231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Thu, 1 Feb 2024 22:36:06 +0100 Subject: [PATCH 19/30] Preload the theme sheet template file to improve performance --- ROADMAP.md | 2 +- Theme Preferences/RefreshTheme.lua | 14 ++++++-------- Theme Preferences/ThemeManager.lua | 3 +++ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 94a54a2..1119e67 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -15,7 +15,7 @@ Update v1.0.3. Unreleased: -- [Improvement] Minor performance improvement when saving or applying themes +- [Improvement] Major performance improvement when applying theme preferences - [Improvement] Move the Font configuration to it's own menu option under View > Font Preferences... - [Improvement] Move the "Reset to Default" option to the main Theme Preferences dialog window diff --git a/Theme Preferences/RefreshTheme.lua b/Theme Preferences/RefreshTheme.lua index 9b3a738..6ba1690 100644 --- a/Theme Preferences/RefreshTheme.lua +++ b/Theme Preferences/RefreshTheme.lua @@ -12,6 +12,9 @@ local ThemeXmlTemplatePath = app.fs.joinPath(ThemePreferencesDirectory, "theme-template.xml") local ThemeXmlPath = app.fs.joinPath(ThemePreferencesDirectory, "theme.xml") +-- Preload the theme sheet template file +local TemplateSheetImage = Image {fromFile = SheetTemplatePath} + function ColorToHex(color) return string.format("#%02x%02x%02x", color.red, color.green, color.blue) end @@ -40,7 +43,7 @@ function UpdateThemeSheet(template, theme) end -- Prepare sheet.png - local image = Image {fromFile = SheetTemplatePath} + local image = Image(TemplateSheetImage) -- Save references to function to improve performance local getPixel, drawPixel = image.getPixel, image.drawPixel @@ -55,13 +58,8 @@ function UpdateThemeSheet(template, theme) themeColor = map[rgba(r(value), g(value), b(value))] if themeColor then - drawPixel(image, x, y, Color { - red = themeColor.red, - green = themeColor.green, - blue = themeColor.blue, - -- Restore the original alpha value - alpha = rgbaA(value) - }) + drawPixel(image, x, y, rgba(themeColor.red, themeColor.green, + themeColor.blue, rgbaA(value))) end end end diff --git a/Theme Preferences/ThemeManager.lua b/Theme Preferences/ThemeManager.lua index 0427db4..8729232 100644 --- a/Theme Preferences/ThemeManager.lua +++ b/Theme Preferences/ThemeManager.lua @@ -2,6 +2,7 @@ local ThemeEncoder = dofile("./Base64Encoder.lua") local LoadConfigurationDialog = dofile("./LoadConfigurationDialog.lua") local ImportConfigurationDialog = dofile("./ImportConfigurationDialog.lua") local SaveConfigurationDialog = dofile("./SaveConfigurationDialog.lua") +local Template = dofile("./Template.lua") local ThemeManager = {storage = nil} @@ -39,6 +40,8 @@ function ThemeManager:GetCurrentTheme() if self.storage.currentTheme then return ThemeEncoder:DecodeSigned(self.storage.currentTheme) end + + return Template() end function ThemeManager:Save(theme, onsave, isImport) From fe2b7e5d07583ebdcf04773fe1e28789b8785382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Fri, 2 Feb 2024 00:06:16 +0100 Subject: [PATCH 20/30] Correctly size the Theme Preferences window --- Theme Preferences/DialogBounds.lua | 22 ++++++++++++++++++ .../ExportConfigurationDialog.lua | 23 ++----------------- Theme Preferences/GetWindowSize.lua | 10 -------- Theme Preferences/LoadConfigurationDialog.lua | 5 +++- Theme Preferences/extension.lua | 13 +++++------ 5 files changed, 34 insertions(+), 39 deletions(-) create mode 100644 Theme Preferences/DialogBounds.lua delete mode 100644 Theme Preferences/GetWindowSize.lua diff --git a/Theme Preferences/DialogBounds.lua b/Theme Preferences/DialogBounds.lua new file mode 100644 index 0000000..b413834 --- /dev/null +++ b/Theme Preferences/DialogBounds.lua @@ -0,0 +1,22 @@ +function GetWindowSize() + if app.apiVersion >= 25 then return app.window end + + local dialog = Dialog() + dialog:show{wait = false} + dialog:close() + + return Size(dialog.bounds.x * 2 + dialog.bounds.width, + dialog.bounds.y * 2 + dialog.bounds.height) +end + +return function(size) + local window = GetWindowSize() + + local uiScale = app.preferences.general["ui_scale"] + size = Size(size.width * uiScale, size.height * uiScale) + + local x = (window.width - size.width) / 2 + local y = (window.height - size.height) / 2 + + return Rectangle(x, y, size.width, size.height) +end diff --git a/Theme Preferences/ExportConfigurationDialog.lua b/Theme Preferences/ExportConfigurationDialog.lua index 3922fc4..6b8bb4b 100644 --- a/Theme Preferences/ExportConfigurationDialog.lua +++ b/Theme Preferences/ExportConfigurationDialog.lua @@ -1,29 +1,10 @@ -local EXPORT_DIALOG_WIDTH = 540 - -return function(name, code, onclose) - -- TODO: Simplify this using just the window size - local isFirstOpen = true - - local dialog = Dialog { - title = "Export " .. name, - onclose = function() if not isFirstOpen then onclose() end end - } +return function(name, code, onClose) + local dialog = Dialog {title = "Export " .. name, onclose = onClose} dialog -- :entry{label = "Code", text = code} -- :separator() -- :button{text = "Close"} -- - -- Open and close to initialize bounds - dialog:show{wait = false} - dialog:close() - - isFirstOpen = false - - local bounds = dialog.bounds - bounds.x = bounds.x - (EXPORT_DIALOG_WIDTH - bounds.width) / 2 - bounds.width = EXPORT_DIALOG_WIDTH - dialog.bounds = bounds - return dialog end diff --git a/Theme Preferences/GetWindowSize.lua b/Theme Preferences/GetWindowSize.lua deleted file mode 100644 index 9238ad2..0000000 --- a/Theme Preferences/GetWindowSize.lua +++ /dev/null @@ -1,10 +0,0 @@ -return function() - if app.apiVersion >= 25 then return app.window end - - local dialog = Dialog() - dialog:show{wait = false} - dialog:close() - - return Size(dialog.bounds.x * 2 + dialog.bounds.width, - dialog.bounds.y * 2 + dialog.bounds.height) -end diff --git a/Theme Preferences/LoadConfigurationDialog.lua b/Theme Preferences/LoadConfigurationDialog.lua index 334941f..b290426 100644 --- a/Theme Preferences/LoadConfigurationDialog.lua +++ b/Theme Preferences/LoadConfigurationDialog.lua @@ -1,4 +1,7 @@ local ExportConfigurationDialog = dofile("./ExportConfigurationDialog.lua") +local DialogBounds = dofile("./DialogBounds.lua") + +local ExportDialogSize = Size(540, 67) local ConfigurationsPerPage = 10 local CurrentPage = 1 @@ -51,7 +54,7 @@ return function(themes, onload, ondelete, onimport) local exportDialog = ExportConfigurationDialog(theme.name, theme.code, onExportDialogClose) - exportDialog:show() + exportDialog:show{bounds = DialogBounds(ExportDialogSize)} end } -- :button{ diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index efff188..8945d39 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -2,10 +2,11 @@ local Template = dofile("./Template.lua") local ThemeManager = dofile("./ThemeManager.lua") local FontsProvider = dofile("./FontsProvider.lua") local ThemePreferencesDialog = dofile("./ThemePreferencesDialog.lua") -local GetWindowSize = dofile("./GetWindowSize.lua") -- TODO: This would be a good place to use "require" +local DialogBounds = dofile("./DialogBounds.lua") local RefreshTheme = dofile("./RefreshTheme.lua") -local DialogSize = Size(240, 422) +local SimpleDialogSize = Size(240, 422) +local AdvancedDialogSize = Size(240, 440) local IsDialogOpen = false local IsFontsDialogOpen = false @@ -115,14 +116,12 @@ function init(plugin) onok = onConfirm } - local window = GetWindowSize() - local bounds = Rectangle((window.width - DialogSize.width) / 2, - (window.height - DialogSize.height) / 2, - DialogSize.width, DialogSize.height) + local bounds = currentTheme.parameters.isAdvanced and + AdvancedDialogSize or SimpleDialogSize newDialog:show{ wait = false, - bounds = bounds, + bounds = DialogBounds(bounds), autoscrollbars = true } return newDialog From d0666525c18bfe114130795e3b9f02997e553884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 4 Feb 2024 12:52:52 +0100 Subject: [PATCH 21/30] Restore Theme Preferences dialog position after closing Load Configuration dialog --- Theme Preferences/DialogBounds.lua | 7 ++++++- Theme Preferences/extension.lua | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Theme Preferences/DialogBounds.lua b/Theme Preferences/DialogBounds.lua index b413834..95d3724 100644 --- a/Theme Preferences/DialogBounds.lua +++ b/Theme Preferences/DialogBounds.lua @@ -9,7 +9,7 @@ function GetWindowSize() dialog.bounds.y * 2 + dialog.bounds.height) end -return function(size) +return function(size, position) local window = GetWindowSize() local uiScale = app.preferences.general["ui_scale"] @@ -18,5 +18,10 @@ return function(size) local x = (window.width - size.width) / 2 local y = (window.height - size.height) / 2 + if position then + x = position.x + y = position.y + end + return Rectangle(x, y, size.width, size.height) end diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 8945d39..5c91606 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -119,9 +119,15 @@ function init(plugin) local bounds = currentTheme.parameters.isAdvanced and AdvancedDialogSize or SimpleDialogSize + local position = nil + + if dialog then + position = Point(dialog.bounds.x, dialog.bounds.y) + end + newDialog:show{ wait = false, - bounds = DialogBounds(bounds), + bounds = DialogBounds(bounds, position), autoscrollbars = true } return newDialog From f279062354a65ba500d828f9265e2afcc79e625f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 4 Feb 2024 12:58:06 +0100 Subject: [PATCH 22/30] Encapsulate file access functions --- Theme Preferences/FileProvider.lua | 20 +++++++++++++++++ Theme Preferences/FontsProvider.lua | 10 ++------- Theme Preferences/RefreshTheme.lua | 34 ++++++++--------------------- 3 files changed, 31 insertions(+), 33 deletions(-) create mode 100644 Theme Preferences/FileProvider.lua diff --git a/Theme Preferences/FileProvider.lua b/Theme Preferences/FileProvider.lua new file mode 100644 index 0000000..6b37b72 --- /dev/null +++ b/Theme Preferences/FileProvider.lua @@ -0,0 +1,20 @@ +local FileProvider = {} + +function FileProvider:ReadAll(filePath) + local file = assert(io.open(filePath, "rb")) + local content = file:read("*all") + file:close() + + return content +end + +function FileProvider:Write(filePath, content) + local file = io.open(filePath, "w") + + if file then + file:write(content) + file:close() + end +end + +return FileProvider diff --git a/Theme Preferences/FontsProvider.lua b/Theme Preferences/FontsProvider.lua index 206c8ac..f43229a 100644 --- a/Theme Preferences/FontsProvider.lua +++ b/Theme Preferences/FontsProvider.lua @@ -1,5 +1,6 @@ local FontPreferencesDialog = dofile("./FontPreferencesDialog.lua") local DefaultFont = dofile("./DefaultFont.lua") +local FileProvider = dofile("./FileProvider.lua") local FontsProvider = {storage = nil, availableFonts = {}} @@ -57,13 +58,6 @@ function FontsProvider:VerifyScaling() end end -function FontsProvider:_ReadAll(filePath) - local file = assert(io.open(filePath, "rb")) - local content = file:read("*all") - file:close() - return content -end - function FontsProvider:_FindAll(content, patternStart, patternEnd) local results = {} local start = 0 @@ -128,7 +122,7 @@ function FontsProvider:_ParseFont(fontDescription) end function FontsProvider:_ExtractFonts(filePath) - local fileContent = self:_ReadAll(filePath) + local fileContent = FileProvider:ReadAll(filePath) fileContent = fileContent:gsub("[\n\r\t]+", " ") local fontDeclarations = self:_FindAll(fileContent, "") diff --git a/Theme Preferences/RefreshTheme.lua b/Theme Preferences/RefreshTheme.lua index 6ba1690..780a604 100644 --- a/Theme Preferences/RefreshTheme.lua +++ b/Theme Preferences/RefreshTheme.lua @@ -1,16 +1,15 @@ local Template = dofile("./Template.lua") +local FileProvider = dofile("./FileProvider.lua") local THEME_ID = "custom" local ExtensionsDirectory = app.fs.joinPath(app.fs.userConfigPath, "extensions") -local ThemePreferencesDirectory = app.fs.joinPath(ExtensionsDirectory, - "theme-preferences") -local SheetTemplatePath = app.fs.joinPath(ThemePreferencesDirectory, - "sheet-template.png") -local SheetPath = app.fs.joinPath(ThemePreferencesDirectory, "sheet.png") -local ThemeXmlTemplatePath = app.fs.joinPath(ThemePreferencesDirectory, - "theme-template.xml") -local ThemeXmlPath = app.fs.joinPath(ThemePreferencesDirectory, "theme.xml") +local BaseDirectory = app.fs.joinPath(ExtensionsDirectory, "theme-preferences") + +local SheetTemplatePath = app.fs.joinPath(BaseDirectory, "sheet-template.png") +local SheetPath = app.fs.joinPath(BaseDirectory, "sheet.png") +local XmlTemplatePath = app.fs.joinPath(BaseDirectory, "theme-template.xml") +local XmlPath = app.fs.joinPath(BaseDirectory, "theme.xml") -- Preload the theme sheet template file local TemplateSheetImage = Image {fromFile = SheetTemplatePath} @@ -19,21 +18,6 @@ function ColorToHex(color) return string.format("#%02x%02x%02x", color.red, color.green, color.blue) end -function ReadAll(filePath) - local file = assert(io.open(filePath, "rb")) - local content = file:read("*all") - file:close() - return content -end - -function WriteAll(filePath, content) - local file = io.open(filePath, "w") - if file then - file:write(content) - file:close() - end -end - function UpdateThemeSheet(template, theme) -- Prepare color lookup local map = {} @@ -76,7 +60,7 @@ end function UpdateThemeXml(template, theme, font) -- Prepare theme.xml - local xmlContent = ReadAll(ThemeXmlTemplatePath) + local xmlContent = FileProvider:ReadAll(XmlTemplatePath) for id, _ in pairs(template.colors) do xmlContent = xmlContent:gsub("<" .. id .. ">", @@ -96,7 +80,7 @@ function UpdateThemeXml(template, theme, font) -- TODO: If using system fonts - ask user if they want to switch default scaling percentages - WriteAll(ThemeXmlPath, xmlContent) + FileProvider:Write(XmlPath, xmlContent) end return function(theme, font) From 750340ef4fd3bf56ef2305f6835e6af7973e8f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 4 Feb 2024 13:29:19 +0100 Subject: [PATCH 23/30] Refactor plugin preferences use --- ...{FontsProvider.lua => FontPreferences.lua} | 36 ++++++------ ...{ThemeManager.lua => ThemePreferences.lua} | 42 +++++++------- Theme Preferences/extension.lua | 57 ++++++++++--------- 3 files changed, 68 insertions(+), 67 deletions(-) rename Theme Preferences/{FontsProvider.lua => FontPreferences.lua} (87%) rename Theme Preferences/{ThemeManager.lua => ThemePreferences.lua} (78%) diff --git a/Theme Preferences/FontsProvider.lua b/Theme Preferences/FontPreferences.lua similarity index 87% rename from Theme Preferences/FontsProvider.lua rename to Theme Preferences/FontPreferences.lua index f43229a..325110b 100644 --- a/Theme Preferences/FontsProvider.lua +++ b/Theme Preferences/FontPreferences.lua @@ -2,23 +2,23 @@ local FontPreferencesDialog = dofile("./FontPreferencesDialog.lua") local DefaultFont = dofile("./DefaultFont.lua") local FileProvider = dofile("./FileProvider.lua") -local FontsProvider = {storage = nil, availableFonts = {}} +local FontPreferences = {preferences = nil, availableFonts = {}} -function FontsProvider:Init(options) - self.storage = options.storage - self.storage.font = self.storage.font or DefaultFont() +function FontPreferences:Init(preferences) + self.preferences = preferences + self.preferences.font = self.preferences.font or DefaultFont() self:_RefreshAvailableFonts() end -function FontsProvider:GetCurrentFont() return self.storage.font end +function FontPreferences:GetCurrentFont() return self.preferences.font end -function FontsProvider:SetCurrentFont(font) - self.storage.font = font or DefaultFont() +function FontPreferences:SetCurrentFont(font) + self.preferences.font = font or DefaultFont() end -- FUTURE: Revisit this, currently can cause issues and completely break the window layout rendering Aseprite unusable -function FontsProvider:VerifyScaling() +function FontPreferences:VerifyScaling() local currentFont = self:GetCurrentFont() local isDefaultFontVector = currentFont.default.type == nil or @@ -58,7 +58,7 @@ function FontsProvider:VerifyScaling() end end -function FontsProvider:_FindAll(content, patternStart, patternEnd) +function FontPreferences:_FindAll(content, patternStart, patternEnd) local results = {} local start = 0 @@ -80,7 +80,7 @@ function FontsProvider:_FindAll(content, patternStart, patternEnd) return results end -function FontsProvider:_ParseFont(fontDescription) +function FontPreferences:_ParseFont(fontDescription) local result = {} local name = "" @@ -121,7 +121,7 @@ function FontsProvider:_ParseFont(fontDescription) return result end -function FontsProvider:_ExtractFonts(filePath) +function FontPreferences:_ExtractFonts(filePath) local fileContent = FileProvider:ReadAll(filePath) fileContent = fileContent:gsub("[\n\r\t]+", " ") @@ -137,7 +137,7 @@ function FontsProvider:_ExtractFonts(filePath) return result end -function FontsProvider:GetFontsFromDirectory(path, fonts) +function FontPreferences:GetFontsFromDirectory(path, fonts) -- Validate the path if not app.fs.isDirectory(path) then return end @@ -170,7 +170,7 @@ function FontsProvider:GetFontsFromDirectory(path, fonts) return fonts end -function FontsProvider:_RefreshAvailableFonts() +function FontPreferences:_RefreshAvailableFonts() self.availableFonts = {} local systemFonts = self:_GetSystemFonts() @@ -192,7 +192,7 @@ function FontsProvider:_RefreshAvailableFonts() end end -function FontsProvider:_GetSystemFonts() +function FontPreferences:_GetSystemFonts() -- Windows local roamingPath = os.getenv("APPDATA") local appDataPath = roamingPath and app.fs.filePath(roamingPath) @@ -225,11 +225,11 @@ function FontsProvider:_GetSystemFonts() return systemFonts end -function FontsProvider:OpenDialog(onClose, onSuccess) - local currentFont = FontsProvider:GetCurrentFont() +function FontPreferences:OpenDialog(onClose, onSuccess) + local currentFont = FontPreferences:GetCurrentFont() local onConfirm = function(newFont) - FontsProvider:SetCurrentFont(newFont) + FontPreferences:SetCurrentFont(newFont) onSuccess(newFont) end @@ -239,4 +239,4 @@ function FontsProvider:OpenDialog(onClose, onSuccess) dialog:show{wait = false} end -return FontsProvider +return FontPreferences diff --git a/Theme Preferences/ThemeManager.lua b/Theme Preferences/ThemePreferences.lua similarity index 78% rename from Theme Preferences/ThemeManager.lua rename to Theme Preferences/ThemePreferences.lua index 8729232..011fe92 100644 --- a/Theme Preferences/ThemeManager.lua +++ b/Theme Preferences/ThemePreferences.lua @@ -4,12 +4,11 @@ local ImportConfigurationDialog = dofile("./ImportConfigurationDialog.lua") local SaveConfigurationDialog = dofile("./SaveConfigurationDialog.lua") local Template = dofile("./Template.lua") -local ThemeManager = {storage = nil} +local ThemePreferences = {preferences = nil} -function ThemeManager:Init(options) - self.storage = options.storage - - self.storage.savedThemes = self.storage.savedThemes or { +function ThemePreferences:Init(preferences) + self.preferences = preferences + self.preferences.savedThemes = self.preferences.savedThemes or { "", "", "", @@ -25,30 +24,29 @@ function ThemeManager:Init(options) "" } - self.storage.savedThemes = self.storage.savedThemes or - "" + self.preferences.savedThemes = self.preferences.savedThemes or + "" end -function ThemeManager:SetCurrentTheme(theme) +function ThemePreferences:SetCurrentTheme(theme) local code = ThemeEncoder:EncodeSigned(theme.name, theme.parameters, theme.colors) - if code then self.storage.currentTheme = code end + if code then self.preferences.currentTheme = code end end -function ThemeManager:GetCurrentTheme() - if self.storage.currentTheme then - return ThemeEncoder:DecodeSigned(self.storage.currentTheme) - end +function ThemePreferences:GetCurrentTheme() + local currentTheme = self.preferences.currentTheme + if currentTheme then return ThemeEncoder:DecodeSigned(currentTheme) end return Template() end -function ThemeManager:Save(theme, onsave, isImport) +function ThemePreferences:Save(theme, onsave, isImport) local dialog = nil local getThemeIndex = function(name) - for i, encodedTheme in ipairs(self.storage.savedThemes) do + for i, encodedTheme in ipairs(self.preferences.savedThemes) do if ThemeEncoder:DecodeName(encodedTheme) == name then return i end @@ -79,9 +77,9 @@ function ThemeManager:Save(theme, onsave, isImport) theme.colors) if themeIndex then - self.storage.savedThemes[themeIndex] = code + self.preferences.savedThemes[themeIndex] = code else - table.insert(self.storage.savedThemes, code) + table.insert(self.preferences.savedThemes, code) end dialog:close() @@ -91,10 +89,10 @@ function ThemeManager:Save(theme, onsave, isImport) dialog:show() end -function ThemeManager:GetDecodedThemes() +function ThemePreferences:GetDecodedThemes() local themes = {} - for _, encodedTheme in ipairs(self.storage.savedThemes) do + for _, encodedTheme in ipairs(self.preferences.savedThemes) do local theme = ThemeEncoder:DecodeSigned(encodedTheme) theme.code = encodedTheme @@ -104,7 +102,7 @@ function ThemeManager:GetDecodedThemes() return themes end -function ThemeManager:Load(onload) +function ThemePreferences:Load(onload) local themes = self:GetDecodedThemes() local dialog = nil @@ -117,7 +115,7 @@ function ThemeManager:Load(onload) end onDelete = function(index) - table.remove(self.storage.savedThemes, index) + table.remove(self.preferences.savedThemes, index) themes = self:GetDecodedThemes() CreateDialog() end @@ -136,4 +134,4 @@ function ThemeManager:Load(onload) CreateDialog() end -return ThemeManager +return ThemePreferences diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 5c91606..7bc9f33 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -1,6 +1,6 @@ local Template = dofile("./Template.lua") -local ThemeManager = dofile("./ThemeManager.lua") -local FontsProvider = dofile("./FontsProvider.lua") +local ThemePreferences = dofile("./ThemePreferences.lua") +local FontPreferences = dofile("./FontPreferences.lua") local ThemePreferencesDialog = dofile("./ThemePreferencesDialog.lua") local DialogBounds = dofile("./DialogBounds.lua") local RefreshTheme = dofile("./RefreshTheme.lua") @@ -10,22 +10,27 @@ local AdvancedDialogSize = Size(240, 440) local IsDialogOpen = false local IsFontsDialogOpen = false +local IsModified = false function init(plugin) -- Do nothing when UI is not available if not app.isUIAvailable then return end - -- Initialize plugin preferences data for backwards compatibility - plugin.preferences.themePreferences = - plugin.preferences.themePreferences or {} - local storage = plugin.preferences.themePreferences + -- Copy plugin theme preferences data for backwards compatibility + if plugin.preferences.themePreferences then + for key, value in pairs(plugin.preferences.themePreferences) do + plugin.preferences[key] = value + end - -- Initialize data from plugin preferences - ThemeManager:Init{storage = storage} - Theme = ThemeManager:GetCurrentTheme() or Theme + plugin.preferences.themePreferences = nil + end - FontsProvider:Init{storage = storage} - IsModified = storage.isThemeModified + local preferences = plugin.preferences + + -- Initialize data from plugin preferences + ThemePreferences:Init(preferences) + FontPreferences:Init(preferences) + IsModified = preferences.isThemeModified plugin:newCommand{ id = "ThemePreferencesNew", @@ -33,7 +38,7 @@ function init(plugin) group = "view_screen", onenabled = function() return not IsDialogOpen end, onclick = function() - local currentTheme = ThemeManager:GetCurrentTheme() + local currentTheme = ThemePreferences:GetCurrentTheme() local dialog = nil local CreateDialog = function() end @@ -46,10 +51,10 @@ function init(plugin) currentTheme.parameters = parameters IsModified = false - ThemeManager:SetCurrentTheme(theme) + ThemePreferences:SetCurrentTheme(theme) end - ThemeManager:Save(currentTheme, onsuccess) + ThemePreferences:Save(currentTheme, onsuccess) end local onLoad = function() @@ -59,15 +64,15 @@ function init(plugin) local onConfirm = function(theme) currentTheme = theme or Template() - ThemeManager:SetCurrentTheme(currentTheme) + ThemePreferences:SetCurrentTheme(currentTheme) IsModified = false - local currentFont = FontsProvider:GetCurrentFont() + local currentFont = FontPreferences:GetCurrentFont() RefreshTheme(currentTheme, currentFont) end - ThemeManager:Load(onConfirm) + ThemePreferences:Load(onConfirm) -- Reopen the dialog dialog = CreateDialog() @@ -77,12 +82,12 @@ function init(plugin) -- Hide the Theme Preferences dialog dialog:close() - currentTheme = theme or Template() + currentTheme = Template() - ThemeManager:SetCurrentTheme(currentTheme) + ThemePreferences:SetCurrentTheme(currentTheme) IsModified = false - local currentFont = FontsProvider:GetCurrentFont() + local currentFont = FontPreferences:GetCurrentFont() RefreshTheme(currentTheme, currentFont) @@ -96,9 +101,9 @@ function init(plugin) IsModified = parameters.isModified - ThemeManager:SetCurrentTheme(currentTheme) + ThemePreferences:SetCurrentTheme(currentTheme) - local currentFont = FontsProvider:GetCurrentFont() + local currentFont = FontPreferences:GetCurrentFont() RefreshTheme(currentTheme, currentFont) end @@ -147,17 +152,15 @@ function init(plugin) local onClose = function() IsFontsDialogOpen = false end local onConfirm = function(font) - local currentTheme = ThemeManager:GetCurrentTheme() + local currentTheme = ThemePreferences:GetCurrentTheme() RefreshTheme(currentTheme, font) end - FontsProvider:OpenDialog(onClose, onConfirm) + FontPreferences:OpenDialog(onClose, onConfirm) IsFontsDialogOpen = true end } end -function exit(plugin) - plugin.preferences.themePreferences.isThemeModified = IsModified -end +function exit(plugin) plugin.preferences.isThemeModified = IsModified end From d5d5487656c38ce2bc3a7a8f71d1984e4bc8245e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 4 Feb 2024 13:47:06 +0100 Subject: [PATCH 24/30] Change user screen & UI scaling settings to correctly display vector fonts --- ROADMAP.md | 1 + Theme Preferences/FontPreferences.lua | 40 ++++++--------------- Theme Preferences/FontPreferencesDialog.lua | 4 +-- Theme Preferences/RefreshTheme.lua | 2 -- 4 files changed, 12 insertions(+), 35 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 1119e67..8a8c1d1 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -18,6 +18,7 @@ Unreleased: - [Improvement] Major performance improvement when applying theme preferences - [Improvement] Move the Font configuration to it's own menu option under View > Font Preferences... - [Improvement] Move the "Reset to Default" option to the main Theme Preferences dialog window +- [Improvement] Change user screen & UI scaling settings to correctly display vector fonts Update v2.0.0: diff --git a/Theme Preferences/FontPreferences.lua b/Theme Preferences/FontPreferences.lua index 325110b..58b6589 100644 --- a/Theme Preferences/FontPreferences.lua +++ b/Theme Preferences/FontPreferences.lua @@ -18,44 +18,23 @@ function FontPreferences:SetCurrentFont(font) end -- FUTURE: Revisit this, currently can cause issues and completely break the window layout rendering Aseprite unusable -function FontPreferences:VerifyScaling() - local currentFont = self:GetCurrentFont() - - local isDefaultFontVector = currentFont.default.type == nil or - currentFont.default.type ~= "spritesheet" - local isMiniFontVector = currentFont.mini.type == nil or - currentFont.mini.type == "spritesheet" - - if not isDefaultFontVector and not isMiniFontVector then return end +function FontPreferences:VerifyScaling(font) + if font.default.type == "spritesheet" and font.mini.type == "spritesheet" then + return + end local screenScale = app.preferences.general["screen_scale"] local uiScale = app.preferences.general["ui_scale"] if screenScale < uiScale then return end - local userChoice = app.alert { + app.preferences.general["screen_scale"] = uiScale + app.preferences.general["ui_scale"] = screenScale + + app.alert { title = "Warning", - text = { - "One of the selected fonts may appear blurry, switching UI and Screen Scaling may help.", - "", - "Current: Screen " .. tostring(screenScale * 100) .. "%, " .. "UI " .. - tostring(uiScale * 100) .. "%", - "Suggested: Screen " .. tostring(uiScale * 100) .. "%, " .. "UI " .. - tostring(screenScale * 100) .. "%", "", - "Would you like to switch?" - }, - buttons = {"Yes", "No"} + text = "If the fonts appear blurry, please restart Aseprite for all changes to be applied." } - - if userChoice == 1 then -- Yes = 1 - app.preferences.general["screen_scale"] = uiScale - app.preferences.general["ui_scale"] = screenScale - - app.alert { - title = "Aseprite Restart Necessary", - text = "Please restart Aseprite for the changes to be applied." - } - end end function FontPreferences:_FindAll(content, patternStart, patternEnd) @@ -231,6 +210,7 @@ function FontPreferences:OpenDialog(onClose, onSuccess) local onConfirm = function(newFont) FontPreferences:SetCurrentFont(newFont) onSuccess(newFont) + self:VerifyScaling(newFont) end local dialog = FontPreferencesDialog(currentFont, self.availableFonts, diff --git a/Theme Preferences/FontPreferencesDialog.lua b/Theme Preferences/FontPreferencesDialog.lua index 95e7be8..d8ce20b 100644 --- a/Theme Preferences/FontPreferencesDialog.lua +++ b/Theme Preferences/FontPreferencesDialog.lua @@ -41,8 +41,6 @@ return function(font, availableFonts, onclose, onconfirm) } onconfirm(newFont) - - -- self:VerifyScaling() end dialog -- @@ -105,8 +103,8 @@ return function(font, availableFonts, onclose, onconfirm) :button{ text = "OK", onclick = function() - updateFonts() dialog:close() + updateFonts() end } -- :button{text = "Apply", onclick = updateFonts} -- diff --git a/Theme Preferences/RefreshTheme.lua b/Theme Preferences/RefreshTheme.lua index 780a604..6496773 100644 --- a/Theme Preferences/RefreshTheme.lua +++ b/Theme Preferences/RefreshTheme.lua @@ -78,8 +78,6 @@ function UpdateThemeXml(template, theme, font) xmlContent = xmlContent:gsub("", font.mini.name) xmlContent = xmlContent:gsub("", font.mini.size) - -- TODO: If using system fonts - ask user if they want to switch default scaling percentages - FileProvider:Write(XmlPath, xmlContent) end From 15c886facebc7d9e3f5fb2263ef00c8d3aa066ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sun, 4 Feb 2024 14:09:31 +0100 Subject: [PATCH 25/30] Add "Save As" button for the Theme configuration --- ROADMAP.md | 1 + Theme Preferences/ThemePreferences.lua | 27 ++++++++++++-------- Theme Preferences/ThemePreferencesDialog.lua | 13 ++++++++-- Theme Preferences/extension.lua | 13 ++++++++-- 4 files changed, 40 insertions(+), 14 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 8a8c1d1..707bd8a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -19,6 +19,7 @@ Unreleased: - [Improvement] Move the Font configuration to it's own menu option under View > Font Preferences... - [Improvement] Move the "Reset to Default" option to the main Theme Preferences dialog window - [Improvement] Change user screen & UI scaling settings to correctly display vector fonts +- [Improvement] Add "Save As" button for the Theme configuration Update v2.0.0: diff --git a/Theme Preferences/ThemePreferences.lua b/Theme Preferences/ThemePreferences.lua index 011fe92..1fcaa29 100644 --- a/Theme Preferences/ThemePreferences.lua +++ b/Theme Preferences/ThemePreferences.lua @@ -42,19 +42,26 @@ function ThemePreferences:GetCurrentTheme() return Template() end -function ThemePreferences:Save(theme, onsave, isImport) - local dialog = nil - - local getThemeIndex = function(name) - for i, encodedTheme in ipairs(self.preferences.savedThemes) do - if ThemeEncoder:DecodeName(encodedTheme) == name then - return i - end - end +function ThemePreferences:GetThemeIndex(name) + for i, encodedTheme in ipairs(self.preferences.savedThemes) do + if ThemeEncoder:DecodeName(encodedTheme) == name then return i end end +end + +function ThemePreferences:Save(theme) + local themeIndex = self:GetThemeIndex(theme.name) + + local code = ThemeEncoder:EncodeSigned(theme.name, theme.parameters, + theme.colors) + + self.preferences.savedThemes[themeIndex] = code +end + +function ThemePreferences:SaveAs(theme, onsave, isImport) + local dialog = nil local onConfirm = function(name, applyImmediately) - local themeIndex = getThemeIndex(name) + local themeIndex = self:GetThemeIndex(name) if themeIndex then local overwriteConfirmation = app.alert { diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index d7a7b96..976a418 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -45,6 +45,7 @@ return function(options) dialog -- :modify{id = "save-configuration", enabled = value} -- + :modify{id = "save-as-configuration", enabled = value} -- :modify{title = title .. (value and " (modified)" or "")} end @@ -405,13 +406,22 @@ return function(options) label = "Configuration", text = "Save", enabled = isModified, -- Only allows saving of a modified theme + onclick = function() + options.onsave(dialog.data, GetParameters()) + MarkAsModified(false) + end + } -- + :button{ + id = "save-as-configuration", + text = "Save As", + enabled = isModified, -- Only allows saving of a modified theme onclick = function() local refreshTitle = function(name) UpdateTitle(name) MarkAsModified(false) end - options.onsave(dialog.data, GetParameters(), refreshTitle) + options.onsaveas(dialog.data, GetParameters(), refreshTitle) end } -- :button{text = "Load", onclick = function() options.onload() end} -- @@ -439,5 +449,4 @@ return function(options) return dialog end --- TODO: Add SaveAs button -- TODO: Add Reset button diff --git a/Theme Preferences/extension.lua b/Theme Preferences/extension.lua index 7bc9f33..b1def9c 100644 --- a/Theme Preferences/extension.lua +++ b/Theme Preferences/extension.lua @@ -43,7 +43,15 @@ function init(plugin) local dialog = nil local CreateDialog = function() end - local onSave = function(colors, parameters, refreshTitle) + local onSave = function(colors, parameters) + currentTheme.colors = colors + currentTheme.parameters = parameters + IsModified = false + + ThemePreferences:Save(currentTheme) + end + + local onSaveAs = function(colors, parameters, refreshTitle) local onsuccess = function(theme) refreshTitle(theme.name) @@ -54,7 +62,7 @@ function init(plugin) ThemePreferences:SetCurrentTheme(theme) end - ThemePreferences:Save(currentTheme, onsuccess) + ThemePreferences:SaveAs(currentTheme, onsuccess) end local onLoad = function() @@ -116,6 +124,7 @@ function init(plugin) isModified = IsModified, onclose = function() IsDialogOpen = false end, onsave = onSave, + onsaveas = onSaveAs, onload = onLoad, onreset = onReset, onok = onConfirm From f03575c1bbf95db3795c1b94bae879b042d4abee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Fri, 9 Feb 2024 23:00:51 +0100 Subject: [PATCH 26/30] Add "Outline" color and support backwards compatibility of themes --- ROADMAP.md | 1 + Theme Preferences/Base64Encoder.lua | 14 ++++++++++---- Theme Preferences/Template.lua | 5 ++++- Theme Preferences/ThemePreferencesDialog.lua | 8 ++++++-- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 707bd8a..02dadbb 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -20,6 +20,7 @@ Unreleased: - [Improvement] Move the "Reset to Default" option to the main Theme Preferences dialog window - [Improvement] Change user screen & UI scaling settings to correctly display vector fonts - [Improvement] Add "Save As" button for the Theme configuration +- [Feature] Add "Outline" color Update v2.0.0: diff --git a/Theme Preferences/Base64Encoder.lua b/Theme Preferences/Base64Encoder.lua index 292c9d3..f6229a3 100644 --- a/Theme Preferences/Base64Encoder.lua +++ b/Theme Preferences/Base64Encoder.lua @@ -1,4 +1,6 @@ -local CODE_VERSION = 1 +local Template = dofile("./Template.lua")() + +local CODE_VERSION = 2 local START_CHARACTER = "<" local LAST_CHARACTER = ">" local SPLIT_CHARACTER = ":" @@ -41,7 +43,9 @@ local Base64ThemeEncoder = { "editor_cursor", -- "editor_cursor_shadow", -- "editor_cursor_outline", -- - "editor_icons" -- + "editor_icons", -- + -- Outline + "outline" } } @@ -149,7 +153,7 @@ function Base64ThemeEncoder:EncodeColors(colors) local result = "" for _, id in ipairs(self.colorIds) do - result = result .. self:EncodeColor(colors[id]) + result = result .. self:EncodeColor(colors[id] or Template.colors[id]) end return result @@ -228,7 +232,9 @@ function Base64ThemeEncoder:DecodeColors(version, encodedColors) end local colors = {} - for i, id in ipairs(self.colorIds) do colors[id] = decodedColors[i] end + for i, id in ipairs(self.colorIds) do + colors[id] = decodedColors[i] or Template.colors[id] + end return colors end diff --git a/Theme Preferences/Template.lua b/Theme Preferences/Template.lua index 38c5af3..b1fada3 100644 --- a/Theme Preferences/Template.lua +++ b/Theme Preferences/Template.lua @@ -42,7 +42,10 @@ return function() ["editor_cursor"] = Color {r = 254, g = 255, b = 255}, ["editor_cursor_shadow"] = Color {r = 123, g = 124, b = 124}, ["editor_cursor_outline"] = Color {r = 1, g = 0, b = 0}, - ["editor_icons"] = Color {gray = 1} + ["editor_icons"] = Color {gray = 1}, + + -- Outline + ["outline"] = Color {gray = 0} }, parameters = {isAdvanced = false} } diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 976a418..255495d 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -1,3 +1,5 @@ +local Template = dofile("./Template.lua")() + function ShiftRGB(value, modifier) return math.max(math.min(value + modifier, 255), 0) end @@ -53,7 +55,8 @@ return function(options) dialog:color{ id = widgetOptions.id, label = widgetOptions.label, - color = colors[widgetOptions.id], + color = colors[widgetOptions.id] or + Template.colors[widgetOptions.id], visible = widgetOptions.visible, onchange = function() if widgetOptions.onchange then @@ -398,6 +401,7 @@ return function(options) } -- ThemeColor {label = "Hover", id = "window_hover", visible = true} + ThemeColor {label = "Outline", id = "outline", visible = true} dialog -- :separator() -- @@ -449,4 +453,4 @@ return function(options) return dialog end --- TODO: Add Reset button +-- TODO: Reset the theme on cancel, reverting all unsaved changes? From acc5a9b41beed660c7e9009eb0367d798e9509e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sat, 10 Feb 2024 11:26:06 +0100 Subject: [PATCH 27/30] Add "Title Bar" color to the Window section --- Theme Preferences/Base64Encoder.lua | 29 ++++++++++-- Theme Preferences/Template.lua | 12 ++++- Theme Preferences/ThemePreferencesDialog.lua | 47 ++++++++++++++++++- Theme Preferences/sheet-template.png | Bin 16012 -> 16023 bytes Theme Preferences/theme-template.xml | 4 +- 5 files changed, 84 insertions(+), 8 deletions(-) diff --git a/Theme Preferences/Base64Encoder.lua b/Theme Preferences/Base64Encoder.lua index f6229a3..7b48d0e 100644 --- a/Theme Preferences/Base64Encoder.lua +++ b/Theme Preferences/Base64Encoder.lua @@ -45,7 +45,12 @@ local Base64ThemeEncoder = { "editor_cursor_outline", -- "editor_icons", -- -- Outline - "outline" + "outline", -- + -- Window Title Bar + "window_title_bar_corner_highlight", -- + "window_title_bar_highlight", -- + "window_title_bar_background", -- + "window_title_bar_shadow" } } @@ -153,7 +158,9 @@ function Base64ThemeEncoder:EncodeColors(colors) local result = "" for _, id in ipairs(self.colorIds) do - result = result .. self:EncodeColor(colors[id] or Template.colors[id]) + result = result .. + self:EncodeColor( + colors[id] or self:GetDefaultColor(id, colors)) end return result @@ -233,7 +240,7 @@ function Base64ThemeEncoder:DecodeColors(version, encodedColors) local colors = {} for i, id in ipairs(self.colorIds) do - colors[id] = decodedColors[i] or Template.colors[id] + colors[id] = decodedColors[i] or self:GetDefaultColor(id, colors) end return colors @@ -257,4 +264,20 @@ function Base64ThemeEncoder:DecodeName(code) return name end +function Base64ThemeEncoder:GetDefaultColor(id, colors) + if id == "outline" then return Template.colors[id] end + + if id == "window_title_bar_corner_highlight" then + return colors["tab_corner_highlight"] + end + + if id == "window_title_bar_highlight" then return colors["tab_highlight"] end + + if id == "window_title_bar_background" then + return colors["tab_background"] + end + + if id == "window_title_bar_shadow" then return colors["tab_shadow"] end +end + return Base64ThemeEncoder diff --git a/Theme Preferences/Template.lua b/Theme Preferences/Template.lua index b1fada3..35c5785 100644 --- a/Theme Preferences/Template.lua +++ b/Theme Preferences/Template.lua @@ -45,7 +45,17 @@ return function() ["editor_icons"] = Color {gray = 1}, -- Outline - ["outline"] = Color {gray = 0} + ["outline"] = Color {gray = 0}, + + -- Window Title Bar + ["window_title_bar_corner_highlight"] = Color { + r = 255, + g = 255, + b = 253 + }, + ["window_title_bar_highlight"] = Color {r = 173, g = 202, b = 221}, + ["window_title_bar_background"] = Color {r = 125, g = 146, b = 156}, + ["window_title_bar_shadow"] = Color {r = 100, g = 85, b = 95} }, parameters = {isAdvanced = false} } diff --git a/Theme Preferences/ThemePreferencesDialog.lua b/Theme Preferences/ThemePreferencesDialog.lua index 255495d..decaaeb 100644 --- a/Theme Preferences/ThemePreferencesDialog.lua +++ b/Theme Preferences/ThemePreferencesDialog.lua @@ -116,6 +116,10 @@ return function(options) color = dialog.data["button_background"] } -- :modify{id = "simple-tab", color = dialog.data["tab_background"]} -- + :modify{ + id = "simple-window-title-bar", + color = dialog.data["window_title_bar_background"] + } -- :modify{ id = "simple-window", color = dialog.data["window_background"] @@ -127,13 +131,16 @@ return function(options) :modify{id = "simple-link", visible = isSimple} -- :modify{id = "simple-button", visible = isSimple} -- :modify{id = "simple-tab", visible = isSimple} -- - :modify{id = "simple-window", visible = isSimple} + :modify{id = "simple-window-title-bar", visible = isSimple} -- + :modify{id = "simple-window", visible = isSimple} -- local advancedWidgetIds = { "button_highlight", "button_background", "button_shadow", "tab_corner_highlight", "tab_highlight", "tab_background", "tab_shadow", "window_highlight", "window_background", - "window_shadow", "text_link", "text_separator", "editor_icons" + "window_shadow", "text_link", "text_separator", "editor_icons", + "window_title_bar_corner_highlight", "window_title_bar_highlight", + "window_title_bar_background", "window_title_bar_shadow" } for _, id in ipairs(advancedWidgetIds) do @@ -329,7 +336,42 @@ return function(options) dialog:separator{text = "Window"} + dialog:color{ + label = "Title Bar", + id = "simple-window-title-bar", + color = colors["window_title_bar_background"], + onchange = function() + local color = dialog.data["simple-window-title-bar"] + + dialog:modify{ + id = "window_title_bar_corner_highlight", + color = ShiftColor(color, 131, 110, 98) + } + dialog:modify{ + id = "window_title_bar_highlight", + color = ShiftColor(color, 49, 57, 65) + } + dialog:modify{id = "window_title_bar_background", color = color} + dialog:modify{ + id = "window_title_bar_shadow", + color = ShiftColor(color, -24, -61, -61) + } + + MarkAsModified(true) + end + } -- + + ThemeColor { + label = "Title Bar", + id = "window_title_bar_corner_highlight", + visible = false + } + ThemeColor {id = "window_title_bar_highlight", visible = false} + ThemeColor {id = "window_title_bar_background", visible = false} + ThemeColor {id = "window_title_bar_shadow", visible = false} + ThemeColor { + label = "Body", id = "window_highlight", visible = false, onchange = function(color) @@ -366,6 +408,7 @@ return function(options) ThemeColor {id = "field_corner_shadow", visible = false} dialog:color{ + label = "Body", id = "simple-window", color = colors["window_background"], onchange = function() diff --git a/Theme Preferences/sheet-template.png b/Theme Preferences/sheet-template.png index 2840d01257e8b85024e3c7f1c400ba4401207b03..f21119d8e019386e6fdeb3ef634b00fb7509c7a3 100644 GIT binary patch delta 15758 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 Z>D2_p_%;`pLCA-SqNYL(nw(|m{{dXN`zinc delta 15746 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 diff --git a/Theme Preferences/theme-template.xml b/Theme Preferences/theme-template.xml index 04b551e..a178007 100644 --- a/Theme Preferences/theme-template.xml +++ b/Theme Preferences/theme-template.xml @@ -68,9 +68,9 @@ - + - + From 3a3f568363cdf7eec0ba97a08fdf719f3b9e5396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sat, 10 Feb 2024 11:27:24 +0100 Subject: [PATCH 28/30] Load the template image on the first apply and not on start --- Theme Preferences/RefreshTheme.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Theme Preferences/RefreshTheme.lua b/Theme Preferences/RefreshTheme.lua index 6496773..bee9138 100644 --- a/Theme Preferences/RefreshTheme.lua +++ b/Theme Preferences/RefreshTheme.lua @@ -12,7 +12,7 @@ local XmlTemplatePath = app.fs.joinPath(BaseDirectory, "theme-template.xml") local XmlPath = app.fs.joinPath(BaseDirectory, "theme.xml") -- Preload the theme sheet template file -local TemplateSheetImage = Image {fromFile = SheetTemplatePath} +local TemplateSheetImage = nil function ColorToHex(color) return string.format("#%02x%02x%02x", color.red, color.green, color.blue) @@ -27,6 +27,10 @@ function UpdateThemeSheet(template, theme) end -- Prepare sheet.png + if TemplateSheetImage == nil then + TemplateSheetImage = Image {fromFile = SheetTemplatePath} + end + local image = Image(TemplateSheetImage) -- Save references to function to improve performance From a5820d459606232482a9b172c579d846be668996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sat, 10 Feb 2024 11:28:19 +0100 Subject: [PATCH 29/30] Update ROADMAP.md for Theme Preferences --- ROADMAP.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 02dadbb..49e4925 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -21,10 +21,10 @@ Unreleased: - [Improvement] Change user screen & UI scaling settings to correctly display vector fonts - [Improvement] Add "Save As" button for the Theme configuration - [Feature] Add "Outline" color +- [Feature] Add "Title Bar" Window color Update v2.0.0: -- [Test-Feature] Tint Mode where you can only edit the Tab color + optional underglow - [Improvement] A new color (set) - Window Title Bar - [Improvement] Read font names from TTF files @@ -33,8 +33,6 @@ Future: - [Feature] Add a Dark theme template - [Feature] [Blocked] Separate "field_background" when Aseprite fixes the menu shadow - [Feature] [Blocked] Add separate color for Tooltip Text (Tooltip Section?) - currently it doesn't work due to a bug -- [Feature] Generating a theme from the current color palette -- [Refactor] Add a Default model next to Template - Template is a template, default is default ## FX From 5e9aa1fa49e938a2e6d05dc5634255ea4d8b0abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Wo=C5=BAniak?= Date: Sat, 10 Feb 2024 21:57:21 +0100 Subject: [PATCH 30/30] Update ROADMAP.md for Theme Preferences --- ROADMAP.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 49e4925..e94671f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -23,13 +23,18 @@ Unreleased: - [Feature] Add "Outline" color - [Feature] Add "Title Bar" Window color -Update v2.0.0: +Update v1.0.7: -- [Improvement] A new color (set) - Window Title Bar -- [Improvement] Read font names from TTF files +- [Improvement] Rework the dialogs and menu options +- [Improvement] Update template with new elements for 1.3 and check for compatibility with 1.2 -Future: +Update v1.0.8: + +- [Fix] Make the title bar change it's height with font size +Update v2.0.0: + +- [Improvement] Read font names from TTF files - [Feature] Add a Dark theme template - [Feature] [Blocked] Separate "field_background" when Aseprite fixes the menu shadow - [Feature] [Blocked] Add separate color for Tooltip Text (Tooltip Section?) - currently it doesn't work due to a bug