diff --git a/bmButtonHandlers.lua b/bmButtonHandlers.lua index 3c4807f..50f7854 100644 --- a/bmButtonHandlers.lua +++ b/bmButtonHandlers.lua @@ -150,8 +150,8 @@ function BMButtonHandlers.RenderButtonIcon(Button, cursorScreenPos, size) local draw_list = ImGui.GetWindowDrawList() - local iconId = Button.Icon - local iconType = Button.IconType + local iconId = Button.Icon or -1 + local iconType = Button.IconType or '' if Button.IconLua and Button.IconLua:len() > 0 then local success @@ -164,10 +164,11 @@ function BMButtonHandlers.RenderButtonIcon(Button, cursorScreenPos, size) end local renderIconAnim = animItems - if iconType == nil or iconType == "Spell" then + + if iconType == "Spell" then animSpellIcons:SetTextureCell(tonumber(iconId) or 0) renderIconAnim = animSpellIcons - else + elseif iconType == "Item" then animItems:SetTextureCell(tonumber(iconId) or 0) end diff --git a/bmEditButtonPopup.lua b/bmEditButtonPopup.lua index cfdf4dd..85bab9a 100644 --- a/bmEditButtonPopup.lua +++ b/bmEditButtonPopup.lua @@ -16,7 +16,11 @@ BMButtonEditor.tmpButton = nil BMButtonEditor.selectedTimerType = 1 BMButtonEditor.selectedUpdateRate = 1 - +-- ---@diagnostic disable-next-line:undefined-field +-- BMButtonEditor.textEditor = ImGui.TextEditor.new("##TextEditor") +-- BMButtonEditor.textEditor:SetSyntax('lua') +-- ---@diagnostic disable-next-line:undefined-global +-- BMButtonEditor.textEditor.windowFlags = bit32.bor(TextEditorWindowFlags.ShowLineNumbers, TextEditorWindowFlags.WrapText, TextEditorWindowFlags.ShowIndicators) function BMButtonEditor:RenderEditButtonPopup() if not self.editButtonPopupOpen then picker:SetClosed() @@ -71,7 +75,7 @@ function BMButtonEditor:RenderEditButtonPopup() elseif attachmentType == "social" then self.tmpButton.Label = buttonText if cursorIndex + 1 > 120 then - self.tmpButton.Cmd = string.format("/alt act %d", cursorIndex - 120) + self.tmpButton.Cmd = string.format("/alt act %d", cursorIndex) self.tmpButton.Icon = nil self.tmpButton.Cooldown = buttonText self.tmpButton.TimerType = "AA" @@ -81,8 +85,7 @@ function BMButtonEditor:RenderEditButtonPopup() for i = 0, 4 do local cmd = mq.TLO.Social(cursorIndex + 1).Cmd(i)() or "" if cmd:len() > 0 then - self.tmpButton.Cmd = string.format("%s%s%s", self.tmpButton.Cmd, - self.tmpButton.Cmd:len() > 0 and "\n" or "", cmd) + self.tmpButton.Cmd = string.format("%s%s%s", self.tmpButton.Cmd, self.tmpButton.Cmd:len() > 0 and "\n" or "", cmd) end end end @@ -108,8 +111,9 @@ function BMButtonEditor:RenderEditButtonPopup() ButtonKey -- add the button key for this button set index BMSettings:GetSettings().Buttons[ButtonKey] = btnUtils.shallowcopy(self.tmpButton) -- store the tmp button into the settings table BMSettings:GetSettings().Buttons[ButtonKey].Unassigned = nil -- clear the unassigned flag - BMSettings:SaveSettings(true) + BMSettings:updateButtonDB(btnUtils.shallowcopy(self.tmpButton), ButtonKey) + BMSettings:updateSetDB(self.editButtonSet, self.editButtonIndex, ButtonKey) self.editButtonUIChanged = false else btnUtils.Output("\arSave failed. Button Label cannot be empty.") @@ -140,6 +144,8 @@ function BMButtonEditor:RenderEditButtonPopup() BMSettings:GetSettings().Buttons[ButtonKey].Unassigned = nil -- clear the unassigned flag BMSettings:SaveSettings(true) + BMSettings:updateButtonDB(btnUtils.shallowcopy(self.tmpButton), ButtonKey) + BMSettings:updateSetDB(self.editButtonSet, self.editButtonIndex, ButtonKey) self.editButtonUIChanged = false else btnUtils.Output("\arSave failed. Button Label cannot be empty.") @@ -152,6 +158,7 @@ end function BMButtonEditor:CloseEditPopup() picker:SetClosed() + -- self.textEditor:Clear() self.editButtonPopupOpen = false self.editButtonIndex = 0 self.editButtonSet = "" @@ -163,6 +170,7 @@ function BMButtonEditor:OpenEditPopup(Set, Index) self.editButtonSet = Set self.selectedTimerType = 1 self.selectedUpdateRate = 1 + local button = BMSettings:GetButtonBySetIndex(Set, Index) self.tmpButton = btnUtils.shallowcopy(button) @@ -180,6 +188,7 @@ function BMButtonEditor:OpenEditPopup(Set, Index) end end end + -- self.textEditor:Clear() end function BMButtonEditor:CreateButtonFromCursor(Set, Index) @@ -201,14 +210,12 @@ function BMButtonEditor:RenderButtonEditUI(renderButton, enableShare, enableEdit local colorChanged = false -- color pickers - colorChanged = btnUtils.RenderColorPicker(string.format("##ButtonColorPicker1_%s", renderButton.Label), 'Button', - renderButton, + colorChanged = btnUtils.RenderColorPicker(string.format("##ButtonColorPicker1_%s", renderButton.Label), 'Button', renderButton, 'ButtonColorRGB') self.editButtonUIChanged = self.editButtonUIChanged or colorChanged ImGui.SameLine() - colorChanged = btnUtils.RenderColorPicker(string.format("##TextColorPicker1_%s", renderButton.Label), 'Text', - renderButton, 'TextColorRGB') + colorChanged = btnUtils.RenderColorPicker(string.format("##TextColorPicker1_%s", renderButton.Label), 'Text', renderButton, 'TextColorRGB') self.editButtonUIChanged = self.editButtonUIChanged or colorChanged ImGui.SameLine() @@ -265,8 +272,7 @@ function BMButtonEditor:RenderButtonEditUI(renderButton, enableShare, enableEdit btnUtils.Tooltip( "Dynamically override the IconID with this Lua function. \nNote: This MUST return number, string : IconId, IconType") - self.selectedUpdateRate, _ = ImGui.Combo("Update Rate", self.selectedUpdateRate, - function(idx) return BMSettings.Constants.UpdateRates[idx].Display end, + self.selectedUpdateRate, _ = ImGui.Combo("Update Rate", self.selectedUpdateRate, function(idx) return BMSettings.Constants.UpdateRates[idx].Display end, #BMSettings.Constants.UpdateRates) renderButton.UpdateRate = BMSettings.Constants.UpdateRates[self.selectedUpdateRate].Value self.editButtonUIChanged = self.editButtonUIChanged or textChanged @@ -284,6 +290,13 @@ function BMButtonEditor:RenderButtonEditUI(renderButton, enableShare, enableEdit ImGui.PushFont(ImGui.ConsoleFont) renderButton.Cmd, textChanged = ImGui.InputTextMultiline("##_Cmd_Edit", renderButton.Cmd or "", ImVec2(ImGui.GetWindowWidth() * 0.98, editHeight), ImGuiInputTextFlags.AllowTabInput) + -- self.textEditor:Render(ImVec2(ImGui.GetWindowWidth() * 0.98, editHeight)) + -- local textContents = self.textEditor.text ~= '' and self.textEditor.text or (renderButton.Cmd and renderButton.Cmd or "") + -- self.textEditor:LoadContents(textContents) + -- if self.textEditor.text ~= renderButton.Cmd then + -- textChanged = true + -- renderButton.Cmd = self.textEditor.text + -- end ImGui.PopFont() self.editButtonUIChanged = self.editButtonUIChanged or textChanged end diff --git a/bmHotbarClass.lua b/bmHotbarClass.lua index 5f8dd65..4bd37b0 100644 --- a/bmHotbarClass.lua +++ b/bmHotbarClass.lua @@ -62,6 +62,7 @@ function BMHotbarClass.new(id, createFresh) newBMHotbar.newY = 500 BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end BMSettings:GetCharConfig().Windows[id].Sets = BMSettings:GetCharConfig().Windows[id].Sets or {} @@ -79,6 +80,7 @@ function BMHotbarClass:ToggleVisible() BMSettings:GetCharacterWindow(self.id).Visible = not BMSettings:GetCharacterWindow(self.id).Visible self.openGUI = BMSettings:GetCharacterWindow(self.id).Visible BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end function BMHotbarClass:IsVisible() @@ -247,6 +249,7 @@ function BMHotbarClass:RenderTabs() --ImGuiWindowFlags.NoMove BMSettings:GetCharacterWindow(self.id).Locked = not BMSettings:GetCharacterWindow(self.id).Locked BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (iconPadding)) @@ -277,6 +280,7 @@ function BMHotbarClass:RenderTabs() --ImGuiWindowFlags.NoMove BMSettings:GetCharacterWindow(self.id).Locked = not BMSettings:GetCharacterWindow(self.id).Locked BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end ImGui.SameLine() @@ -380,6 +384,7 @@ function BMHotbarClass:RenderTabContextMenu() if ImGui.MenuItem(k) then table.insert(BMSettings:GetCharacterWindowSets(self.id), k) BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) break end end @@ -392,6 +397,7 @@ function BMHotbarClass:RenderTabContextMenu() if ImGui.MenuItem(v) then table.remove(BMSettings:GetCharConfig().Windows[self.id].Sets, i) BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) break end end @@ -413,6 +419,8 @@ function BMHotbarClass:RenderTabContextMenu() end BMSettings:GetSettings().Sets[k] = nil BMSettings:SaveSettings(true) + BMSettings:deleteSetFromDB(k) + BMSettings:deleteSetFromCharacterDB(BMSettings.CharConfig, k) break end end @@ -439,6 +447,7 @@ function BMHotbarClass:RenderTabContextMenu() end BMSettings:GetSettings().Buttons[buttonData.id] = nil BMSettings:SaveSettings(true) + BMSettings:deleteButtonFromDB(buttonData.id) break end end @@ -458,6 +467,7 @@ function BMHotbarClass:RenderTabContextMenu() BMSettings:GetCharacterWindow(self.id).ButtonSize = i self.buttonSizeDirty = true BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) break end end @@ -489,6 +499,7 @@ function BMHotbarClass:RenderTabContextMenu() if ImGui.MenuItem(v.label, nil, checked) then BMSettings:GetCharacterWindow(self.id).Font = v.size BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) break end end @@ -500,12 +511,15 @@ function BMHotbarClass:RenderTabContextMenu() if ImGui.MenuItem("Default", nil, checked) then BMSettings:GetCharacterWindow(self.id).Theme = nil BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end for n, _ in pairs(themes) do checked = (BMSettings:GetCharacterWindow(self.id).Theme or "") == n if ImGui.MenuItem(n, nil, checked) then BMSettings:GetCharacterWindow(self.id).Theme = n BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) + break end end @@ -514,6 +528,8 @@ function BMHotbarClass:RenderTabContextMenu() if ImGui.MenuItem(n, nil, checked) then BMSettings:GetCharacterWindow(self.id).Theme = n BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) + break end end @@ -548,7 +564,9 @@ function BMHotbarClass:RenderTabContextMenu() table.sort(charList, function(a, b) return a.key < b.key end) for _, value in ipairs(charList) do if ImGui.MenuItem(value.displayName) then - CopyLocalSet(value.key) + -- CopyLocalSet(value.key) + BMCopy = true + BMCopyKey = value.key end end ImGui.EndMenu() @@ -561,26 +579,31 @@ function BMHotbarClass:RenderTabContextMenu() BMSettings:GetCharacterWindow(self.id).HideTitleBar = not BMSettings:GetCharacterWindow(self.id) .HideTitleBar BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end if ImGui.MenuItem((BMSettings:GetCharacterWindow(self.id).CompactMode and "Normal" or "Compact") .. " Mode") then BMSettings:GetCharacterWindow(self.id).CompactMode = not BMSettings:GetCharacterWindow(self.id) .CompactMode BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end if ImGui.MenuItem((BMSettings:GetCharacterWindow(self.id).AdvTooltips and "Disable" or "Enable") .. " Advanced Tooltips") then BMSettings:GetCharacterWindow(self.id).AdvTooltips = not BMSettings:GetCharacterWindow(self.id) .AdvTooltips BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end if ImGui.MenuItem((BMSettings:GetCharacterWindow(self.id).HideScrollbar and "Show" or "Hide") .. " Scrollbar") then BMSettings:GetCharacterWindow(self.id).HideScrollbar = not BMSettings:GetCharacterWindow(self.id) .HideScrollbar BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end if ImGui.MenuItem((BMSettings:GetCharacterWindow(self.id).ShowSearch and "Disable" or "Enable") .. " Search") then BMSettings:GetCharacterWindow(self.id).ShowSearch = not BMSettings:GetCharacterWindow(self.id) .ShowSearch BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end local fps_scale = { { @@ -607,6 +630,8 @@ function BMHotbarClass:RenderTabContextMenu() if ImGui.MenuItem(v.label, nil, checked) then BMSettings:GetCharacterWindow(self.id).FPS = v.fps BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) + break end end @@ -751,6 +776,7 @@ function BMHotbarClass:RenderContextMenu(Set, Index, buttonID) if ImGui.MenuItem(BMButtonHandlers.ResolveButtonLabel(value, true)) then BMSettings:GetSettings().Sets[Set][Index] = key BMSettings:SaveSettings(true) + BMSettings:deleteButtonFromSetDB(Set, Index) break end end @@ -771,6 +797,7 @@ function BMHotbarClass:RenderContextMenu(Set, Index, buttonID) if ImGui.MenuItem("Unassign") then BMSettings:GetSettings().Sets[Set][Index] = nil BMSettings:SaveSettings(true) + BMSettings:deleteButtonFromSetDB(Set, Index) end if ImGui.MenuItem(Icons.MD_SHARE) then BMButtonHandlers.ExportButtonToClipBoard(button) @@ -842,6 +869,7 @@ function BMHotbarClass:RenderButtons(Set, searchText) BMSettings:GetSettings().Sets[Set][ButtonIndex], BMSettings:GetSettings().Sets[Set][num] BMSettings:SaveSettings(true) + BMSettings:convertConfigToDB('sets') end ImGui.EndDragDropTarget() end @@ -955,6 +983,8 @@ function BMHotbarClass:RenderCreateTab() table.insert(BMSettings:GetCharConfig().Windows[self.id].Sets, self.newSetName) BMSettings:GetSettings().Sets[self.newSetName] = {} BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) + BMSettings:updateSetDB(self.newSetName, 1, '') else btnUtils.Output("\arError Saving Set: A set with this name already exists!\ax") end @@ -990,6 +1020,7 @@ function BMHotbarClass:GiveTime() if not BMSettings:GetCharacterWindow(self.id).FPS then BMSettings:GetCharacterWindow(self.id).FPS = 0 BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) end local fps = BMSettings:GetCharacterWindow(self.id).FPS / 10 diff --git a/bmSettings.lua b/bmSettings.lua index 944aac0..1bf1f19 100644 --- a/bmSettings.lua +++ b/bmSettings.lua @@ -1,9 +1,13 @@ -local mq = require('mq') -local btnUtils = require('lib.buttonUtils') - -local settings_base = mq.configDir .. '/ButtonMaster' -local settings_path = settings_base .. '.lua ' +local mq = require('mq') +local btnUtils = require('lib.buttonUtils') +local PackageMan = require('mq.PackageMan') +local sqlite3 = PackageMan.Require('lsqlite3') +local BATCH_SIZE = 500 +local settings_base = mq.configDir .. '/ButtonMaster' +local settings_path = settings_base .. '.lua ' +local dbPath = string.format('%s/ButtonMaster.db', mq.configDir) +local configFile = mq.configDir .. '/ButtonMaster.lua' local BMSettings = {} BMSettings.__index = BMSettings @@ -12,7 +16,7 @@ BMSettings.CharConfig = string.format("%s_%s", mq.TLO.EverQuest.Serve BMSettings.Constants = {} BMSettings.Globals = {} -BMSettings.Globals.Version = 7 +BMSettings.Globals.Version = 8 BMSettings.Globals.CustomThemes = {} BMSettings.Constants.TimerTypes = { @@ -34,6 +38,369 @@ BMSettings.Constants.UpdateRates = { { Display = "20 per second", Value = 0.05, }, } +function BMSettings:InitializeDB() + local db = sqlite3.open(dbPath) + db:exec([[ + CREATE TABLE IF NOT EXISTS settings ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + server TEXT NOT NULL, + character TEXT NOT NULL, + settings_version INTEGER NOT NULL, + settings_last_backup INTEGER NOT NULL, + UNIQUE(server, character) + ); + CREATE TABLE IF NOT EXISTS sets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + set_name TEXT NOT NULL, + button_number INTEGER NOT NULL, + button_id TEXT NOT NULL + ); + CREATE TABLE IF NOT EXISTS buttons ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + button_number TEXT NOT NULL, + button_label TEXT NOT NULL, + button_render INTEGER NOT NULL, + button_text_color TEXT, + button_button_color TEXT, + button_cached_countdown INTEGER, + button_cached_cooldown INTEGER, + button_cached_toggle_locked INTEGER, + button_cached_last_run NUMERIC, + button_label_mid_x INTEGER, + button_label_mid_y INTEGER, + button_cached_label TEXT, + button_cmd TEXT, + button_evaluate_label INTEGER, + button_show_label INTEGER, + button_icon INTEGER, + button_icon_type TEXT, + button_icon_lua TEXT, + button_timer_type TEXT, + button_cooldown TEXT + ); + CREATE TABLE IF NOT EXISTS windows ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + server TEXT NOT NULL, + character TEXT NOT NULL, + window_id INTEGER NOT NULL, + window_fps INTEGER NOT NULL, + window_button_size INTEGER NOT NULL, + window_advtooltip INTEGER NOT NULL, + window_compact INTEGER NOT NULL, + window_hide_title INTEGER NOT NULL, + window_width INTEGER NOT NULL, + window_height INTEGER NOT NULL, + window_x INTEGER NOT NULL, + window_y INTEGER NOT NULL, + window_visible INTEGER NOT NULL, + window_font_size INTEGER NOT NULL, + window_locked INTEGER NOT NULL, + window_theme TEXT NOT NULL, + window_set_id INTEGER NOT NULL, + window_set_name TEXT NOT NULL + ); + CREATE TABLE IF NOT EXISTS characters ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + character TEXT NOT NULL, + character_locked INTEGER NOT NULL, + character_hide_title INTEGER NOT NULL + ); + ]]) + return db +end + +function BMSettings:saveToDB(db, query, ...) + local stmt = db:prepare(query) + stmt:bind_values(...) + stmt:step() + stmt:finalize() +end + +function BMSettings:loadFromDB(db, query, ...) + local stmt = db:prepare(query) + stmt:bind_values(...) + local data = {} + for row in stmt:nrows() do + table.insert(data, row) + end + stmt:finalize() + return data +end + +function BMSettings:updateButtonDB(buttonData, id) + local db = self:InitializeDB() + local icon = tonumber(buttonData.Icon) or 0 + local showLabel = icon == 0 and true or buttonData.ShowLabel ~= nil and buttonData.ShowLabel or true + self:saveToDB(db, [[ + INSERT OR REPLACE INTO buttons ( + button_number, button_label, button_render, button_text_color, button_button_color, + button_cached_countdown, button_cached_cooldown, button_cached_toggle_locked, + button_cached_last_run, button_label_mid_x, button_label_mid_y, button_cached_label, + button_cmd, button_evaluate_label, button_show_label, button_icon, + button_icon_type, button_icon_lua, button_timer_type, button_cooldown + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]], + id, buttonData.Label or "", buttonData.highestRenderTime or 0, buttonData.TextColorRGB or "", buttonData.ButtonColorRGB or "", + buttonData.CachedCountDown or 0, buttonData.CachedCoolDownTimer or 0, buttonData.CachedToggleLocked or 0, + buttonData.CachedLastRan or 0, buttonData.labelMidX or 0, buttonData.labelMidY or 0, buttonData.CachedLabel or "", + buttonData.Cmd or "", buttonData.EvaluateLabel and 1 or 0, showLabel and 1 or 0, icon, + buttonData.IconType or "Item", buttonData.IconLua or "", buttonData.TimerType or "", buttonData.Cooldown or "" + ) + db:close() +end + +function BMSettings:updateSetDB(setName, buttonNumber, buttonID) + local db = self:InitializeDB() + + self:saveToDB(db, "INSERT OR REPLACE INTO sets (set_name, button_number, button_id) VALUES (?, ?, ?)", + setName, buttonNumber, buttonID) + db:close() +end + +function BMSettings:updateCharacterDB(charName, charData) + local db = self:InitializeDB() + + self:saveToDB(db, "INSERT INTO characters (character, character_locked, character_hide_title) VALUES (?, ?, ?)", + charName, charData.Locked and 1 or 0, charData.HideTitleBar and 1 or 0) + + if charData.Windows then + for windowID, windowData in ipairs(charData.Windows or {}) do + windowData.Pos = windowData.Pos or { x = 0, y = 0, } -- Default position + for setIndex, setName in ipairs(windowData.Sets or {}) do + self:saveToDB(db, [[ + INSERT OR REPLACE INTO windows ( + server, character, window_id, window_fps, window_button_size, window_advtooltip, + window_compact, window_hide_title, window_width, window_height, window_x, window_y, + window_visible, window_font_size, window_locked, window_theme, window_set_id, window_set_name + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]], + mq.TLO.EverQuest.Server(), charName, windowID, windowData.FPS or 0, windowData.ButtonSize or 0, windowData.AdvTooltips and 1 or 0, + windowData.CompactMode and 1 or 0, windowData.HideTitleBar and 1 or 0, windowData.Width or 0, windowData.Height or 0, + windowData.Pos.x or 0, windowData.Pos.y or 0, windowData.Visible and 1 or 0, windowData.Font or 0, + windowData.Locked and 1 or 0, windowData.Theme or "", setIndex, setName + ) + end + end + end + db:close() +end + +function BMSettings:deleteButtonFromDB(id) + local db = self:InitializeDB() + self:saveToDB(db, "DELETE FROM buttons WHERE button_number = ?", id) + db:close() +end + +function BMSettings:deleteSetFromDB(setName) + local db = self:InitializeDB() + self:saveToDB(db, "DELETE FROM sets WHERE set_name = ?", setName) + db:close() +end + +function BMSettings:deleteButtonFromSetDB(setName, buttonNumber) + local db = self:InitializeDB() + self:saveToDB(db, "DELETE FROM sets WHERE set_name = ? AND button_number = ?", setName, buttonNumber) + db:close() +end + +function BMSettings:deleteSetFromCharacterDB(charName, SetName) + local db = self:InitializeDB() + self:saveToDB(db, "DELETE FROM windows WHERE character = ? AND window_set_name = ?", charName, SetName) + db:close() +end + +-- Main Function to Convert Config to DB +function BMSettings:convertConfigToDB(table_name) + if table_name == nil then table_name = "all" end + local db = self:InitializeDB() + local config, err = loadfile(configFile) + if err or not config then + print("Error loading config file:", err) + return + end + + local settings = config() + + -- Save Global Settings + if table_name == "all" or table_name == "global" then + self:saveToDB(db, "INSERT OR REPLACE INTO settings (server, character, settings_version, settings_last_backup) VALUES (?, ?, ?, ?)", + "global", "global", self.Globals.Version, settings.LastBackup or 0) + end + + -- Save Sets with batching + if table_name == "all" or table_name == "sets" then + db:exec("BEGIN TRANSACTION") + local count = 0 + for setName, buttons in pairs(settings.Sets) do + for buttonNumber, buttonID in pairs(buttons) do + self:saveToDB(db, "INSERT OR REPLACE INTO sets (set_name, button_number, button_id) VALUES (?, ?, ?)", setName, buttonNumber, buttonID) + count = count + 1 + if count % BATCH_SIZE == 0 then + db:exec("COMMIT") + db:exec("BEGIN TRANSACTION") + end + end + end + db:exec("COMMIT") + end + + -- Save Buttons with batching + if table_name == "all" or table_name == "buttons" then + db:exec("BEGIN TRANSACTION") + local count = 0 + for buttonID, buttonData in pairs(settings.Buttons) do + local icon = tonumber(buttonData.Icon) or -1 + local showLabel = icon <= 0 or buttonData.ShowLabel == true + self:saveToDB(db, [[ + INSERT OR REPLACE INTO buttons ( + button_number, button_label, button_render, button_text_color, button_button_color, + button_cached_countdown, button_cached_cooldown, button_cached_toggle_locked, + button_cached_last_run, button_label_mid_x, button_label_mid_y, button_cached_label, + button_cmd, button_evaluate_label, button_show_label, button_icon, + button_icon_type, button_icon_lua, button_timer_type, button_cooldown + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]], + buttonID, buttonData.Label or "", buttonData.highestRenderTime or 0, buttonData.TextColorRGB or "", buttonData.ButtonColorRGB or "", + buttonData.CachedCountDown or 0, buttonData.CachedCoolDownTimer or 0, buttonData.CachedToggleLocked or 0, + buttonData.CachedLastRan or 0, buttonData.labelMidX or 0, buttonData.labelMidY or 0, buttonData.CachedLabel or "", + buttonData.Cmd or "", buttonData.EvaluateLabel and 1 or 0, showLabel and 1 or 0, icon, + buttonData.IconType or "Item", buttonData.IconLua or "", buttonData.TimerType or "", buttonData.Cooldown or "" + ) + count = count + 1 + if count % BATCH_SIZE == 0 then + db:exec("COMMIT") + db:exec("BEGIN TRANSACTION") + end + end + db:exec("COMMIT") + + -- Save Characters with batching + if table_name == "all" or table_name == "characters" then + db:exec("BEGIN TRANSACTION") + local count = 0 + for charName, charData in pairs(settings.Characters or {}) do + self:saveToDB(db, "INSERT INTO characters (character, character_locked, character_hide_title) VALUES (?, ?, ?)", + charName, charData.Locked and 1 or 0, charData.HideTitleBar and 1 or 0) + count = count + 1 + if count % BATCH_SIZE == 0 then + db:exec("COMMIT") + db:exec("BEGIN TRANSACTION") + end + + -- Save character's windows + if charData.Windows then + for windowID, windowData in ipairs(charData.Windows or {}) do + windowData.Pos = windowData.Pos or { x = 0, y = 0, } -- Default position + for setIndex, setName in ipairs(windowData.Sets or {}) do + self:saveToDB(db, [[ + INSERT OR REPLACE INTO windows ( + server, character, window_id, window_fps, window_button_size, window_advtooltip, + window_compact, window_hide_title, window_width, window_height, window_x, window_y, + window_visible, window_font_size, window_locked, window_theme, window_set_id, window_set_name + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]], + mq.TLO.EverQuest.Server(), charName, windowID, windowData.FPS or 0, windowData.ButtonSize or 0, windowData.AdvTooltips and 1 or 0, + windowData.CompactMode and 1 or 0, windowData.HideTitleBar and 1 or 0, windowData.Width or 0, windowData.Height or 0, + windowData.Pos.x or 0, windowData.Pos.y or 0, windowData.Visible and 1 or 0, windowData.Font or 0, + windowData.Locked and 1 or 0, windowData.Theme or "", setIndex, setName + ) + count = count + 1 + if count % BATCH_SIZE == 0 then + db:exec("COMMIT") + db:exec("BEGIN TRANSACTION") + end + end + end + end + end + db:exec("COMMIT") + end + db:close() + print("Conversion complete!") + end +end + +-- Retrieve and Deserialize Data +function BMSettings:retrieveDataFromDB() + local db = self:InitializeDB() + self.settings = { + Global = {}, + Version = 8, + LastBackup = os.time(), + Sets = {}, + Buttons = {}, + Characters = {}, + } + + local globalSettingsData = self:loadFromDB(db, "SELECT settings_version, settings_last_backup FROM settings WHERE server='global' AND character='global'") + if globalSettingsData[1] then + -- self.settings.Global = { + -- ButtonSize = globalSettingsData[1].settings_button_size, + -- } + self.settings.Version = globalSettingsData[1].settings_version + self.settings.LastBackup = globalSettingsData[1].settings_last_backup + end + + local setsData = self:loadFromDB(db, "SELECT set_name, button_number, button_id FROM sets") + for _, set in ipairs(setsData) do + self.settings.Sets[set.set_name] = self.settings.Sets[set.set_name] or {} + self.settings.Sets[set.set_name][set.button_number] = set.button_id + end + + local buttonsData = self:loadFromDB(db, "SELECT * FROM buttons") + for _, button in ipairs(buttonsData) do + self.settings.Buttons[button.button_number] = { + Label = button.button_label, + highestRenderTime = button.button_render, + TextColorRGB = button.button_text_color ~= "" and button.button_text_color or nil, + ButtonColorRGB = button.button_button_color ~= "" and button.button_button_color or nil, + CachedCountDown = button.button_cached_countdown, + CachedCoolDownTimer = button.button_cached_cooldown, + CachedToggleLocked = button.button_cached_toggle_locked, + CachedLastRan = button.button_cached_last_run, + labelMidX = button.button_label_mid_x, + labelMidY = button.button_label_mid_y, + CachedLabel = button.button_cached_label, + Cmd = button.button_cmd, + EvaluateLabel = button.button_evaluate_label == 1, + ShowLabel = button.button_show_label == 1, + Icon = tonumber(button.button_icon) > 0 and tonumber(button.button_icon) or nil, + IconType = button.button_icon_type ~= "" and button.button_icon_type or "Item", + IconLua = button.button_icon_lua, + TimerType = button.button_timer_type, + Cooldown = button.button_cooldown, + } + end + + local charactersData = self:loadFromDB(db, "SELECT character, character_locked, character_hide_title FROM characters") + for _, char in ipairs(charactersData) do + self.settings.Characters[char.character] = { + Locked = char.character_locked == 1, + HideTitleBar = char.character_hide_title == 1, + Windows = {}, + } + end + + local windowsData = self:loadFromDB(db, "SELECT * FROM windows ") + for _, window in ipairs(windowsData) do + local character = self.settings.Characters[window.character] + character.Windows[window.window_id] = character.Windows[window.window_id] or { + Sets = {}, + } + local win = character.Windows[window.window_id] + win.FPS = window.window_fps + win.ButtonSize = window.window_button_size + win.AdvTooltips = window.window_advtooltip == 1 + win.CompactMode = window.window_compact == 1 + win.HideTitleBar = window.window_hide_title == 1 + win.Width = window.window_width + win.Height = window.window_height + win.Pos = { x = window.window_x, y = window.window_y, } + win.Visible = window.window_visible == 1 + win.Font = window.window_font_size + win.Locked = window.window_locked == 1 + win.Theme = window.window_theme + win.Sets[window.window_set_id] = window.window_set_name + end + + return self.settings +end function BMSettings.new() local newSettings = setmetatable({}, BMSettings) @@ -56,7 +423,6 @@ function BMSettings:SaveSettings(doBroadcast) mq.pickle(mq.configDir .. "/Buttonmaster-Backups/ButtonMaster-backup-" .. os.date("%m-%d-%y-%H-%M-%S") .. ".lua", self.settings) end - mq.pickle(settings_path, self.settings) if doBroadcast and mq.TLO.MacroQuest.GameState() == "INGAME" then @@ -149,6 +515,7 @@ function BMSettings:ImportButtonAndSave(button, save) self.settings.Buttons[key] = button if save then self:SaveSettings(true) + self:updateButtonDB(button, key) end return key end @@ -179,12 +546,14 @@ function BMSettings:ImportSetAndSave(sharableSet, windowId) for index, btnName in pairs(sharableSet.Set) do local newButtonName = self:ImportButtonAndSave(sharableSet.Buttons[btnName], false) self.settings.Sets[setName][index] = newButtonName + self:updateSetDB(setName, index, newButtonName) end -- add set to user table.insert(self.settings.Characters[self.CharConfig].Windows[windowId].Sets, setName) self:SaveSettings(true) + self:updateCharacterDB(self.CharConfig, self.settings.Characters[self.CharConfig]) end function BMSettings:ConvertToLatestConfigVersion() @@ -353,6 +722,11 @@ function BMSettings:ConvertToLatestConfigVersion() btnUtils.Output("\atUpgraded to \amv%d\at!", BMSettings.Globals.Version) end end + + if self.settings.Version or 0 < 8 then + self:convertConfigToDB() + self.settings = self:retrieveDataFromDB() + end end function BMSettings:InvalidateButtonCache() @@ -362,50 +736,54 @@ function BMSettings:InvalidateButtonCache() end function BMSettings:LoadSettings() - local config, err = loadfile(settings_path) - if err or not config then - local old_settings_path = settings_path:gsub(".lua", ".ini") - printf("\ayUnable to load global settings file(%s), creating a new one from legacy ini(%s) file!", - settings_path, old_settings_path) - if btnUtils.file_exists(old_settings_path) then - self.settings = btnUtils.loadINI(old_settings_path) - self:SaveSettings(true) - else - printf("\ayUnable to load legacy settings file(%s), creating a new config!", old_settings_path) - self.settings = { - Version = BMSettings.Globals.Version, - Sets = { - ['Primary'] = { 'Button_1', 'Button_2', 'Button_3', }, - ['Movement'] = { 'Button_4', }, - }, - Buttons = { - Button_1 = { - Label = 'Burn (all)', - Cmd = '/bcaa //burn\n/timed 500 /bcaa //burn', - }, - Button_2 = { - Label = 'Pause (all)', - Cmd = '/bcaa //multi ; /twist off ; /mqp on', + if not io.open(dbPath, "r") then + local config, err = loadfile(settings_path) + if err or not config then + local old_settings_path = settings_path:gsub(".lua", ".ini") + printf("\ayUnable to load global settings file(%s), creating a new one from legacy ini(%s) file!", + settings_path, old_settings_path) + if btnUtils.file_exists(old_settings_path) then + self.settings = btnUtils.loadINI(old_settings_path) + self:SaveSettings(true) + else + printf("\ayUnable to load legacy settings file(%s), creating a new config!", old_settings_path) + self.settings = { + Version = BMSettings.Globals.Version, + Sets = { + ['Primary'] = { 'Button_1', 'Button_2', 'Button_3', }, + ['Movement'] = { 'Button_4', }, }, - Button_3 = { - Label = 'Unpause (all)', - Cmd = '/bcaa //mqp off', + Buttons = { + Button_1 = { + Label = 'Burn (all)', + Cmd = '/bcaa //burn\n/timed 500 /bcaa //burn', + }, + Button_2 = { + Label = 'Pause (all)', + Cmd = '/bcaa //multi ; /twist off ; /mqp on', + }, + Button_3 = { + Label = 'Unpause (all)', + Cmd = '/bcaa //mqp off', + }, + Button_4 = { + Label = 'Nav Target (bca)', + Cmd = '/bca //nav id ${Target.ID}', + }, }, - Button_4 = { - Label = 'Nav Target (bca)', - Cmd = '/bca //nav id ${Target.ID}', + Characters = { + [self.CharConfig] = { + Windows = { [1] = { Visible = true, Pos = { x = 10, y = 10, }, Sets = {}, Locked = false, }, }, + }, }, - }, - Characters = { - [self.CharConfig] = { - Windows = { [1] = { Visible = true, Pos = { x = 10, y = 10, }, Sets = {}, Locked = false, }, }, - }, - }, - } - self:SaveSettings(true) + } + self:SaveSettings(true) + end + else + self.settings = config() end else - self.settings = config() + self.settings = self:retrieveDataFromDB() end -- if we need to upgrade anyway then bail after the load. diff --git a/init.lua b/init.lua index db6754d..37b88ae 100644 --- a/init.lua +++ b/init.lua @@ -26,7 +26,8 @@ local BMButtonHandlers = require('bmButtonHandlers') BMHotbars = {} BMReloadSettings = false BMUpdateSettings = false - +BMCopy = false +BMCopyKey = nil -- [[ UI ]] -- local openGUI = true @@ -38,10 +39,60 @@ local function BindBtn(num) end end +-- function CopyLocalSet(key) +-- local newTable = btnUtils.deepcopy(BMSettings:GetSettings().Characters[key]) +-- BMSettings:GetSettings().Characters[BMSettings.CharConfig] = newTable +-- BMSettings:SaveSettings(true) +-- BMSettings:UpdateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) +-- BMUpdateSettings = true +-- end + function CopyLocalSet(key) - local newTable = btnUtils.deepcopy(BMSettings:GetSettings().Characters[key]) - BMSettings:GetSettings().Characters[BMSettings.CharConfig] = newTable + local db = BMSettings:InitializeDB() + local newCharacterData = { + Locked = false, + HideTitleBar = false, + Windows = {}, + } + + -- Retrieve character data from the `characters` table + local charData = BMSettings:loadFromDB(db, "SELECT character_locked, character_hide_title FROM characters WHERE character = ?", key) + if #charData > 0 then + newCharacterData.Locked = charData[1].character_locked == 1 + newCharacterData.HideTitleBar = charData[1].character_hide_title == 1 + end + + -- Retrieve window data from the `windows` table for the specified character + local windowsData = BMSettings:loadFromDB(db, "SELECT * FROM windows WHERE character = ?", key) + for _, window in ipairs(windowsData) do + local windowID = window.window_id + newCharacterData.Windows[windowID] = newCharacterData.Windows[windowID] or { Sets = {}, } + local win = newCharacterData.Windows[windowID] + + -- Populate window properties + win.FPS = window.window_fps + win.ButtonSize = window.window_button_size + win.AdvTooltips = window.window_advtooltip == 1 + win.CompactMode = window.window_compact == 1 + win.HideTitleBar = window.window_hide_title == 1 + win.Width = window.window_width + win.Height = window.window_height + win.Pos = { x = window.window_x, y = window.window_y, } + win.Visible = window.window_visible == 1 + win.Font = window.window_font_size + win.Locked = window.window_locked == 1 + win.Theme = window.window_theme + win.Sets[window.window_set_id] = window.window_set_name + end + + db:close() + + -- Deep-copy the retrieved data into the current character settings + BMSettings:GetSettings().Characters[BMSettings.CharConfig] = btnUtils.deepcopy(newCharacterData) + + -- Save and update the settings in the database BMSettings:SaveSettings(true) + BMSettings:updateCharacterDB(BMSettings.CharConfig, BMSettings:GetCharConfig()) BMUpdateSettings = true end @@ -55,7 +106,9 @@ local function BindBtnCopy(server, character) return end - CopyLocalSet(key) + -- CopyLocalSet(key) + BMCopy = true + BMCopyKey = key end local function BindBtnExec(set, index) @@ -89,18 +142,25 @@ local function ButtonGUI() -- Set this way up here so the theme can override. ImGui.PushStyleColor(ImGuiCol.ButtonHovered, 0.9, 0.9, 0.9, 0.5) ImGui.PushStyleColor(ImGuiCol.HeaderHovered, 0.9, 0.9, 0.9, 0.0) - for hotbarId, bmHotbar in ipairs(BMHotbars) do - local flags = ImGuiWindowFlags.NoFocusOnAppearing - if BMSettings:GetCharacterWindow(hotbarId).HideTitleBar then - flags = bit32.bor(flags, ImGuiWindowFlags.NoTitleBar) - end - if BMSettings:GetCharacterWindow(hotbarId).Locked then - flags = bit32.bor(flags, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoResize) - end - if BMSettings:GetCharacterWindow(hotbarId).HideScrollbar then - flags = bit32.bor(flags, ImGuiWindowFlags.NoScrollbar) + if BMHotbars ~= nil then + for hotbarId, bmHotbar in ipairs(BMHotbars) do + if BMSettings:GetCharacterWindow(hotbarId) ~= nil then + local hideTitleBar = BMSettings:GetCharacterWindow(hotbarId).HideTitleBar ~= nil and BMSettings:GetCharacterWindow(hotbarId).HideTitleBar or false + local locked = BMSettings:GetCharacterWindow(hotbarId).Locked ~= nil and BMSettings:GetCharacterWindow(hotbarId).Locked or false + local hideScrollbar = BMSettings:GetCharacterWindow(hotbarId).HideScrollbar ~= nil and BMSettings:GetCharacterWindow(hotbarId).HideScrollbar or false + local flags = ImGuiWindowFlags.NoFocusOnAppearing + if hideTitleBar then + flags = bit32.bor(flags, ImGuiWindowFlags.NoTitleBar) + end + if locked then + flags = bit32.bor(flags, ImGuiWindowFlags.NoMove, ImGuiWindowFlags.NoResize) + end + if hideScrollbar then + flags = bit32.bor(flags, ImGuiWindowFlags.NoScrollbar) + end + bmHotbar:RenderHotbar(flags) + end end - bmHotbar:RenderHotbar(flags) end BMEditPopup:RenderEditButtonPopup() ImGui.PopStyleColor(2) @@ -132,6 +192,12 @@ end local function GiveTime() while mq.TLO.MacroQuest.GameState() == "INGAME" do mq.delay(10) + if BMCopy then + BMCopy = false + CopyLocalSet(BMCopyKey) + BMCopyKey = nil + end + if BMReloadSettings then BMReloadSettings = false BMSettings:LoadSettings() diff --git a/lib/IconPicker.lua b/lib/IconPicker.lua index 288a1cc..4bbad12 100644 --- a/lib/IconPicker.lua +++ b/lib/IconPicker.lua @@ -74,7 +74,7 @@ function IconPicker:RenderIconPicker() if not self.Open then return end self.Open, self.Draw = ImGui.Begin('Icon Picker', self.Open, ImGuiWindowFlags.None) if self.Draw then - self.Page = ImGui.InputInt("Page", self.Page, 1) + self.Page = ImGui.SliderInt("Page", self.Page,1, 26) if self.Page < 1 then self.Page = 1 end if ImGui.BeginTabBar("IconTabs") then diff --git a/lib/buttonUtils.lua b/lib/buttonUtils.lua index 81ab2cb..83b3071 100644 --- a/lib/buttonUtils.lua +++ b/lib/buttonUtils.lua @@ -169,7 +169,16 @@ function ButtonUtils.RenderColorPicker(id, buttonTypeName, renderButton, key) if renderButton[key] ~= nil then local tColors = ButtonUtils.split(renderButton[key], ",") - for i, v in ipairs(tColors) do btnColor[i] = tonumber(v / 255) end + for i, v in ipairs(tColors) do + if tonumber(v) then + btnColor[i] = tonumber(v / 255) + else + btnColor[1] = 0 + btnColor[2] = 0 + btnColor[3] = 0 + break + end + end else btnColor[1] = 0 btnColor[2] = 0