Download CommonLua/Ged/GedApp.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 52 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Ged/GedApp.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/CommonLua/Ged/GedApp.lua
-
curl -L -o GedApp.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Ged/GedApp.lua
52 kB
| function OnMsg.SystemActivate() | |
| if rawget(_G, "g_GedApp") and Platform.ged then | |
| g_GedApp.connection:Send("rfnGedActivated", false) | |
| end | |
| end | |
| GedDisabledOp = "(disabled)" | |
| GedCommonOps = { | |
| { Id = "MoveUp", Name = "Move up", Icon = "CommonAssets/UI/Ged/up.tga", Shortcut = "Alt-Up", }, | |
| { Id = "MoveDown", Name = "Move down", Icon = "CommonAssets/UI/Ged/down.tga", Shortcut = "Alt-Down", }, | |
| { Id = "MoveOut", Name = "Move out", Icon = "CommonAssets/UI/Ged/left.tga", Shortcut = "Alt-Left", }, | |
| { Id = "MoveIn", Name = "Move in", Icon = "CommonAssets/UI/Ged/right.tga", Shortcut = "Alt-Right", }, | |
| { Id = "Delete", Name = "Delete", Icon = "CommonAssets/UI/Ged/delete.tga", Shortcut = "Delete", Split = true, }, | |
| { Id = "Cut", Name = "Cut", Icon = "CommonAssets/UI/Ged/cut.tga", Shortcut = "Ctrl-X", }, | |
| { Id = "Copy", Name = "Copy", Icon = "CommonAssets/UI/Ged/copy.tga", Shortcut = "Ctrl-C", }, | |
| { Id = "Paste", Name = "Paste", Icon = "CommonAssets/UI/Ged/paste.tga", Shortcut = "Ctrl-V", }, | |
| { Id = "Duplicate", Name = "Duplicate", Icon = "CommonAssets/UI/Ged/duplicate.tga", Shortcut = "Ctrl-D", Split = true, }, | |
| { Id = "DiscardEditorChanges", Name = "Discard editor changes", Icon = "CommonAssets/UI/Ged/cleaning_brush.png", Shortcut = "Ctrl-Alt-D", }, | |
| { Id = "Undo", Name = "Undo", Icon = "CommonAssets/UI/Ged/undo.tga", Shortcut = "Ctrl-Z", }, | |
| { Id = "Redo", Name = "Redo", Icon = "CommonAssets/UI/Ged/redo.tga", Shortcut = "Ctrl-Y", Split = true, }, | |
| } | |
| DefineClass.GedApp = { | |
| __parents = { "XActionsHost", "XDarkModeAwareDialog" }, | |
| properties = { | |
| { category = "GedApp", id = "HasTitle", editor = "bool", default = true, }, | |
| { category = "GedApp", id = "Title", editor = "text", default = "", no_edit = function(obj) return not obj:GetProperty("HasTitle") end }, | |
| { category = "GedApp", id = "AppId", editor = "text", default = "", }, | |
| { category = "GedApp", id = "ToolbarTemplate", editor = "choice", default = "GedToolBar", items = XTemplateCombo("XToolBar"), }, | |
| { category = "GedApp", id = "MenubarTemplate", editor = "choice", default = "GedMenuBar", items = XTemplateCombo("XMenuBar"), }, | |
| { category = "GedApp", id = "CommonActionsInMenubar", editor = "bool", default = true, }, | |
| { category = "GedApp", id = "CommonActionsInToolbar", editor = "bool", default = true, }, | |
| { category = "GedApp", id = "InitialWidth", editor = "number", default = 1600, }, | |
| { category = "GedApp", id = "InitialHeight", editor = "number", default = 900, }, | |
| { category = "GedApp", id = "DiscardChangesAction", editor = "bool", default = true, }, | |
| }, | |
| LayoutMethod = "HPanel", | |
| LayoutHSpacing = 0, | |
| IdNode = true, | |
| Background = RGB(160, 160, 160), | |
| connection = false, | |
| in_game = false, | |
| settings = false, | |
| first_update = true, -- used by GedListPanel/GedTreePanel | |
| all_panels = false, | |
| interactive_panels = false, -- mapping context => panel | |
| actions_toggled = false, -- mapping actionid => toggled (only for Toggled actions) | |
| ui_status = false, | |
| ui_update_time = 0, | |
| ui_questions = false, | |
| ui_status_delay_time = 0, | |
| ui_status_delay_thread = false, | |
| last_focused_panel = false, | |
| last_focused_tree_or_list_panel = false, | |
| blink_thread = false, -- see GedOpError | |
| blink_border_color = RGBA(0, 0, 0, 0), | |
| progress_text = false, | |
| progress_bar = false, | |
| -- support for next/previous match when a search with "Search in properties and sub-objects" is active | |
| search_value_filter_text = false, | |
| search_value_results = false, | |
| search_value_panel = false, | |
| search_result_idx = 1, | |
| display_search_result = false, | |
| } | |
| function GedApp:Init(parent, context) | |
| if Platform.ged then rawset(_G, "g_GedApp", self) end | |
| for k, v in pairs(context) do | |
| rawset(self, k, v) | |
| end | |
| if Platform.ged and self.connection then | |
| self.connection:Send("rfnGedActivated", true) | |
| end | |
| self.connection.app = self | |
| self.actions_toggled = {} | |
| self.ui_status = {} | |
| self:SetHasTitle(true) | |
| if not self.in_game then | |
| self.HAlign = "stretch" | |
| self.VAlign = "stretch" | |
| if self.ui_scale then | |
| self:SetScaleModifier(point(self.ui_scale * 10, self.ui_scale * 10)) | |
| end | |
| end | |
| hr.MaxFps = Min(60, self.max_fps) | |
| ShowMouseCursor("GedApp") | |
| XAction:new({ | |
| ActionId = "idSearch", | |
| ActionToolbar = false, | |
| ActionShortcut = "Ctrl-F", | |
| ActionContexts = {}, | |
| ActionMenubar = false, | |
| ActionName = "Search", | |
| ActionTranslate = false, | |
| OnAction = function(action, ged_app, src) | |
| local panel = ged_app.last_focused_panel | |
| if panel and IsKindOf(panel, "GedPanel") then | |
| panel:OpenSearch() | |
| end | |
| end | |
| }, self) | |
| XAction:new({ | |
| ActionId = "idExpandCollapseNode", | |
| ActionToolbar = false, | |
| ActionShortcut = "Alt-C", | |
| ActionContexts = {}, | |
| ActionMenubar = false, | |
| ActionName = "Expand/collapse selected node's children", | |
| ActionTranslate = false, | |
| OnAction = function(action, ged_app, src) | |
| local panel = ged_app.last_focused_panel | |
| if panel and IsKindOf(panel, "GedTreePanel") then | |
| panel.idContainer:ExpandNodeByPath(panel.idContainer:GetFocusedNodePath() or empty_table) | |
| panel.idContainer:ExpandCollapseChildren(panel.idContainer:GetFocusedNodePath() or empty_table, not "recursive", "user_initiated") | |
| end | |
| end | |
| }, self) | |
| XAction:new({ | |
| ActionId = "idExpandCollapseTree", | |
| ActionToolbar = false, | |
| ActionShortcut = "Shift-C", | |
| ActionContexts = {}, | |
| ActionMenubar = false, | |
| ActionName = "Expand/collapse tree", | |
| ActionTranslate = false, | |
| OnAction = function(action, ged_app, src) | |
| local panel = ged_app.last_focused_panel | |
| if IsKindOf(panel, "GedTreePanel") then | |
| panel.idContainer:ExpandCollapseChildren({}, "recursive", "user_initiated") | |
| elseif IsKindOf(panel, "GedPropPanel") then | |
| panel:ExpandCollapseCategories() | |
| end | |
| end | |
| }, self) | |
| if self.MenubarTemplate ~= "" then XTemplateSpawn(self.MenubarTemplate, self) end | |
| if self.ToolbarTemplate ~= "" then XTemplateSpawn(self.ToolbarTemplate, self) end | |
| if not self.in_game then | |
| self.status_ui = StdStatusDialog:new({}, self.desktop, { dark_mode = self.dark_mode }) | |
| self.status_ui:SetVisible(false) | |
| self.status_ui:Open() | |
| end | |
| self:SetContext("root") | |
| end | |
| function GedApp:AddCommonActions() | |
| if not self.interactive_panels then return end | |
| if self.CommonActionsInMenubar then | |
| if not self:ActionById("File") then | |
| XAction:new({ | |
| ActionId = "File", | |
| ActionName = "File", | |
| ActionMenubar = "main", | |
| ActionTranslate = false, | |
| ActionSortKey = "1", | |
| OnActionEffect = "popup", | |
| }, self) | |
| end | |
| if not self:ActionById("Edit") then | |
| XAction:new({ | |
| ActionId = "Edit", | |
| ActionName = "Edit", | |
| ActionMenubar = "main", | |
| ActionTranslate = false, | |
| ActionSortKey = "1", | |
| OnActionEffect = "popup", | |
| }, self) | |
| end | |
| end | |
| local has_undo = false -- if at least one panel with ActionsClass set | |
| for _, panel in pairs(self.interactive_panels) do | |
| has_undo = has_undo or panel.ActionsClass ~= "None" | |
| end | |
| local needs_separator = false | |
| for _, data in ipairs(GedCommonOps) do | |
| local id = data.Id | |
| local is_undo = id == "Undo" or id == "Redo" or id == "DiscardEditorChanges" | |
| local contexts = {} | |
| for _, panel in pairs(self.interactive_panels) do | |
| if not is_undo and panel[id] ~= "" and panel[id] ~= GedDisabledOp then | |
| if panel:IsKindOf("GedListPanel") then | |
| table.insert(contexts, panel.ItemActionContext) | |
| elseif panel:IsKindOf("GedTreePanel") then | |
| if panel.EnableForRootLevelItems or id == "Paste" then | |
| table.insert(contexts, panel.RootActionContext) | |
| end | |
| table.insert(contexts, panel.ChildActionContext) | |
| elseif panel:IsKindOf("GedPropPanel") then | |
| table.insert(contexts, panel.PropActionContext) | |
| end | |
| end | |
| end | |
| if is_undo and has_undo or next(contexts) then | |
| XAction:new({ | |
| ActionId = id, | |
| ActionMenubar = self.CommonActionsInMenubar and "Edit", | |
| ActionToolbar = self.CommonActionsInToolbar and "main", | |
| ActionToolbarSplit = data.Split, | |
| ActionTranslate = false, | |
| ActionName = data.Name, | |
| ActionIcon = data.Icon, | |
| ActionShortcut = data.Shortcut, | |
| ActionSortKey = "1", | |
| ActionContexts = contexts, | |
| ActionState = function(self, host) return host:CommonActionState(self.ActionId) end, | |
| OnAction = function(self, host, source) host:CommonAction(self.ActionId) end, | |
| }, self) | |
| needs_separator = true | |
| end | |
| if data.Split and needs_separator then | |
| XAction:new({ | |
| ActionMenubar = "Edit", | |
| ActionName = "-----", | |
| ActionTranslate = false, | |
| ActionSortKey = "1", | |
| }, self) | |
| needs_separator = false | |
| end | |
| end | |
| end | |
| function GedApp:FindPropPanelForPropertyPaste(panel) | |
| -- look for a GedPropPanel where the object from the current panel is displayed (and it supports paste) | |
| -- allow pasting properties in this case even if the current panel has no ops | |
| if panel and panel:HasMember("SelectionBind") then | |
| local panel_bindings = panel.SelectionBind:split(",") | |
| for _, prop_panel in pairs(self.interactive_panels) do | |
| if prop_panel:IsKindOf("GedPropPanel") and prop_panel.Paste ~= "" and prop_panel.Paste ~= GedDisabledOp and | |
| table.find(panel_bindings, prop_panel.context) then | |
| return prop_panel | |
| end | |
| end | |
| end | |
| end | |
| local reCommaList = "([%w_]+)%s*,%s*" | |
| function GedApp:CommonActionState(id) | |
| if id == "DiscardEditorChanges" then | |
| return (not rawget(self, "PresetClass") or not self.DiscardChangesAction or config.ModdingToolsInUserMode) and "hidden" | |
| elseif id ~= "Undo" and id ~= "Redo" then | |
| local panel = self:GetLastFocusedPanel() | |
| if IsKindOf(panel, "GedTreePanel") and not panel.EnableForRootLevelItems then | |
| local selection = panel:GetSelection() | |
| if selection and #selection == 1 and id ~= "Paste" then | |
| return "disabled" | |
| end | |
| end | |
| -- Disable most common operations for read-only presets/objects | |
| if panel then | |
| -- Check if selection obj is read-only | |
| local sel_read_only | |
| if panel.SelectionBind then | |
| for bind in string.gmatch(panel.SelectionBind .. ",", reCommaList) do | |
| sel_read_only = sel_read_only or self.connection:Obj(bind .. "|read_only") | |
| if sel_read_only then | |
| break | |
| end | |
| end | |
| else | |
| sel_read_only = self.connection:Obj(panel.context .. "|read_only") | |
| end | |
| -- "sel_read_only == nil" means the binding object is changing, so actions should be disabled | |
| if sel_read_only == nil then | |
| sel_read_only = true | |
| end | |
| -- Panel context IS NOT read-only but the selection bind IS read-only (ex. Leftmost preset tree panel) | |
| if not panel.read_only and sel_read_only then | |
| -- Disable all operations when Modding, otherwise leave only Copy and Paste | |
| if (id ~= "Copy" and id ~= "Paste") or config.ModdingToolsInUserMode then | |
| return "disabled" | |
| end | |
| -- Panel context IS read-only but the selection bind IS read-only (ex. Middle preset panel (container items panel)) | |
| elseif panel.read_only and sel_read_only then | |
| -- Disable all operations except Copy | |
| if id ~= "Copy" then | |
| return "disabled" | |
| end | |
| end | |
| end | |
| if not panel or not IsKindOf(panel, "GedPanel") or panel[id] == "" or panel[id] == GedDisabledOp then | |
| if id ~= "Paste" or not self:FindPropPanelForPropertyPaste(panel) then | |
| return "disabled" | |
| end | |
| end | |
| end | |
| end | |
| function GedApp:CommonAction(id) | |
| if id == "Undo" then | |
| self:Undo() | |
| elseif id == "Redo" then | |
| self:Redo() | |
| elseif id == "DiscardEditorChanges" then | |
| self:DiscardEditorChanges() | |
| else | |
| local panel = self:GetLastFocusedPanel() | |
| local op = panel[id] | |
| if panel:IsKindOf("GedPropPanel") then | |
| if id == "Copy" then | |
| self:Op(op, panel.context, panel:GetSelectedProperties(), panel.context) | |
| elseif id == "Paste" then | |
| self:Op(op, panel.context, panel:GetSelectedProperties(), panel.context) | |
| else | |
| assert(false, "Unknown common action " .. id .. "; prop panels only have Copy & Paste common actions") | |
| end | |
| elseif id == "MoveUp" or id == "MoveDown" or id == "MoveIn" or id == "MoveOut" or id == "Delete" then | |
| self:Op(op, panel.context, panel:GetMultiSelection()) | |
| elseif id == "Cut" or id == "Copy" or id == "Paste" or id == "Duplicate" then | |
| if id == "Paste" and (op == "" or op == GedDisabledOp) then | |
| panel = self:FindPropPanelForPropertyPaste(panel) | |
| self:Op(panel[id], panel.context) | |
| else | |
| self:Op(op, panel.context, panel:GetMultiSelection(), panel.ItemClass(self)) | |
| end | |
| else | |
| assert(false, "Unknown common action " .. id) | |
| end | |
| end | |
| end | |
| function GedApp:SetHasTitle(has_title) | |
| self.HasTitle = has_title | |
| if self.in_game and self.HasTitle then | |
| if not self:HasMember("idTitleContainer") then | |
| XMoveControl:new({ | |
| Id = "idTitleContainer", | |
| Dock = "top", | |
| }, self) | |
| XLabel:new({ | |
| Id = "idTitle", | |
| Dock = "left", | |
| Margins = box(4, 2, 4, 2), | |
| TextStyle = "GedTitle", | |
| }, self.idTitleContainer) | |
| XTextButton:new({ | |
| Dock = "right", | |
| OnPress = function(n) | |
| self:Exit() | |
| end, | |
| Text = "X", | |
| LayoutHSpacing = 0, | |
| Padding = box(1, 1, 1, 1), | |
| Background = RGBA(0, 0, 0, 0), | |
| RolloverBackground = RGB(204, 232, 255), | |
| PressedBackground = RGB(121, 189, 241), | |
| VAlign = "center", | |
| TextStyle = "GedTitle", | |
| }, self.idTitleContainer) | |
| end | |
| elseif self:HasMember("idTitleContainer") then | |
| self.idTitleContainer:Done() | |
| end | |
| end | |
| function GedApp:UpdateUiStatus(force) | |
| if self.in_game then return end | |
| if not force and now() - self.ui_update_time < 250 then | |
| CreateRealTimeThread(function() | |
| Sleep(now() - self.ui_update_time) | |
| self:UpdateUiStatus(true) | |
| end) | |
| return | |
| end | |
| self.ui_update_time = now() | |
| if #self.ui_status == 0 then | |
| self.status_ui:SetVisible(false) | |
| return | |
| end | |
| local texts = {} | |
| for _, status in ipairs(self.ui_status) do | |
| texts[#texts + 1] = status.text | |
| end | |
| self.status_ui.idText:SetText(table.concat(texts, "\n")) | |
| self.status_ui:SetVisible(true) | |
| end | |
| function GedApp:Open(...) | |
| self:CreateProgressStatusText() | |
| XActionsHost.Open(self, ...) | |
| self:AddCommonActions() | |
| if self.AppId ~= "" then | |
| self:ApplySavedSettings() | |
| end | |
| self:SetDarkMode(GetDarkModeSetting()) | |
| self:OnContextUpdate(self.context, nil) | |
| end | |
| function GedApp:CreateProgressStatusText() | |
| if not self.interactive_panels then return end | |
| -- find first interactive panel, add the progress status text on its bottom | |
| for _, panel in ipairs(self.all_panels) do | |
| if self.interactive_panels[panel.context or false] then | |
| local parent = XWindow:new({ | |
| Dock = "bottom", | |
| FoldWhenHidden = true, | |
| Margins = box(2, 1, 2, 1), | |
| }, panel) | |
| self.progress_bar = XWindow:new({ | |
| DrawContent = function(self, clip_box) | |
| local bbox = self.content_box | |
| local sizex = MulDivRound(bbox:sizex(), self.progress, self.total_progress) | |
| UIL.DrawSolidRect(sizebox(bbox:min(), bbox:size():SetX(sizex)), RGBA(128, 128, 128, 128)) | |
| end, | |
| }, parent) | |
| self.progress_text = XText:new({ | |
| Background = RGBA(0, 0, 0, 0), | |
| TextStyle = "GedDefault", | |
| TextHAlign = "center", | |
| }, parent) | |
| parent:SetVisible(false) | |
| break | |
| end | |
| end | |
| end | |
| function GedApp:SetProgressStatus(text, progress, total_progress) | |
| if not self.progress_text then return end | |
| if not text then | |
| self.progress_text.parent:SetVisible(false) | |
| return | |
| end | |
| rawset(self.progress_bar, "progress", progress) | |
| rawset(self.progress_bar, "total_progress", total_progress) | |
| self.progress_bar:Invalidate() | |
| self.progress_text:SetText(text) | |
| self.progress_text.parent:SetVisible(true) | |
| end | |
| function GedApp:GedDefaultBox() | |
| local ret = sizebox(20, 20, self.InitialWidth, self.InitialHeight) | |
| return ret + (self.in_game and GetDevUIViewport().box:min() or point(30, 30)) | |
| end | |
| function GedApp:ApplySavedSettings() | |
| self.settings = io.exists(self:SettingsPath()) and LoadLuaTableFromDisk(self:SettingsPath()) or {} | |
| self:SetWindowBox(self.settings.box or self:GedDefaultBox()) | |
| if self.settings.resizable_panel_sizes then | |
| self:SetSizeOfResizablePanels() | |
| end | |
| local search_values = self.settings.search_in_props | |
| if search_values then | |
| for context, panel in pairs(self.interactive_panels) do | |
| local setting_value = search_values[context] | |
| if panel.SearchValuesAvailable and setting_value ~= nil and panel.search_values ~= setting_value then | |
| panel:ToggleSearchValues("no_settings_update") | |
| end | |
| end | |
| end | |
| local collapsed_categories = self.settings.collapsed_categories or empty_table | |
| for context, panel in pairs(self.interactive_panels) do | |
| panel.collapsed_categories = collapsed_categories[context] or {} | |
| end | |
| end | |
| function GedApp:SetWindowBox(box) | |
| if self.in_game then | |
| local viewport = GetDevUIViewport().box:grow(-20) | |
| if viewport:Intersect2D(box) ~= const.irInside then | |
| box = self:GedDefaultBox() | |
| end | |
| self:SetDock("ignore") | |
| self:SetBox(box:minx(), box:miny(), box:sizex(), box:sizey()) | |
| else | |
| terminal.OverrideOSWindowPos(box:min()) | |
| ChangeVideoMode(box:sizex(), box:sizey(), 0, true, false) | |
| end | |
| end | |
| function GedApp:SetSizeOfResizablePanels() | |
| if not self.settings.resizable_panel_sizes then return end | |
| for id, data in pairs(self.settings.resizable_panel_sizes) do | |
| local panel = self:ResolveId(id) | |
| if panel then | |
| panel:SetMaxWidth(data.MaxWidth) | |
| panel:SetMaxHeight(data.MaxHeight) | |
| end | |
| end | |
| end | |
| function GedApp:Exit() | |
| self.connection:delete() | |
| end | |
| function GedApp:Close(...) | |
| self:SaveSettings() | |
| XActionsHost.Close(self, ...) | |
| end | |
| function GedApp:SettingsPath() | |
| local subcategory = "" | |
| if rawget(self, "PresetClass") then subcategory = "-" .. self.PresetClass end | |
| local filename = string.format("AppData/Ged/%s%s%s.settings", self.in_game and "ig_" or "", self.AppId, subcategory) | |
| return filename | |
| end | |
| function GedApp:SaveSettings() | |
| if not self.settings then return end | |
| self.settings.box = self:GetWindowBox() | |
| self:SavePanelSize() | |
| local filename = self:SettingsPath() | |
| local path = SplitPath(filename) | |
| AsyncCreatePath(path) | |
| return SaveLuaTableToDisk(self.settings, filename) | |
| end | |
| function GedApp:SavePanelSize() | |
| if not self.settings["resizable_panel_sizes"] then | |
| self.settings["resizable_panel_sizes"] = {} | |
| end | |
| for _, child in ipairs(self) do | |
| if not child:IsKindOf("XPanelSizer") and not child.Dock then | |
| self.settings.resizable_panel_sizes[child.Id] = { | |
| MaxHeight = child.MaxHeight, | |
| MaxWidth = child.MaxWidth | |
| } | |
| end | |
| end | |
| end | |
| function GedApp:Activate(context) | |
| for k, v in pairs(context) do | |
| rawset(self, k, v) | |
| end | |
| if rawget(terminal, "BringToTop") then | |
| return terminal.BringToTop() | |
| end | |
| return false | |
| end | |
| function GedApp:GetWindowBox() | |
| if self.in_game then | |
| return self.box | |
| end | |
| return sizebox(terminal.GetOSWindowPos(), self.box:size()) | |
| end | |
| function GedApp:OnContextUpdate(context, view) | |
| if not view then | |
| if self.HasTitle then | |
| local title = self.Title | |
| title = _InternalTranslate(IsT(title) and title or T{title}, self, false) | |
| if self.in_game then | |
| self.idTitle:SetText(title) | |
| else | |
| terminal.SetOSWindowTitle(title) | |
| end | |
| end | |
| -- fetch global data, as needed | |
| if self.WarningsUpdateRoot then | |
| self.connection:BindObj("root|warnings_cache", "root", "GedGetCachedDiagnosticMessages") | |
| end | |
| if #GetChildrenOfKind(self, "GedPropPanel") > 0 then | |
| self.connection:BindObj("root|categories", "root", "GedGlobalPropertyCategories") | |
| end | |
| if self.PresetClass then | |
| self.connection:BindObj("root|prop_stats", "root", "GedPresetPropertyUsageStats", self.PresetClass) | |
| end | |
| if self.PresetClass or self.AppId == "ModEditor" then | |
| self.connection:BindObj("root|dirty_objects", "root", "GedGetDirtyObjects") | |
| end | |
| end | |
| if view == "prop_stats" then | |
| for _, panel in ipairs(self.all_panels) do | |
| if panel.context and IsKindOf(panel, "GedPropPanel") then | |
| panel:UpdatePropertyNames(panel.ShowInternalNames) | |
| end | |
| end | |
| end | |
| self:CheckUpdateItemTexts(view) | |
| end | |
| function GedApp:CheckUpdateItemTexts(view) | |
| if view == "warnings_cache" or view == "dirty_objects" then | |
| for _, panel in ipairs(self.all_panels) do | |
| if panel.context then -- cached detached panels as property editors get recreated by GedPropPanel:RebuildControls | |
| panel:UpdateItemTexts() | |
| end | |
| end | |
| end | |
| end | |
| function GedApp:SetTitle(title) | |
| self.Title = title | |
| self:OnContextUpdate(self.context, nil) | |
| end | |
| function GedApp:AddPanel(context, panel) | |
| self.all_panels = self.all_panels or {} | |
| self.all_panels[#self.all_panels + 1] = panel | |
| if panel.Interactive and not panel.Embedded then | |
| self.interactive_panels = self.interactive_panels or {} | |
| if not self.interactive_panels[context] then | |
| local focus_column = 1 | |
| for _, panel in pairs(self.interactive_panels) do | |
| focus_column = Max(focus_column, panel.focus_column + 1000) | |
| end | |
| panel.focus_column = focus_column | |
| self.interactive_panels[context] = panel | |
| end | |
| end | |
| end | |
| function GedApp:RemovePanel(panel) | |
| table.remove_value(self.all_panels, panel) | |
| for id, obj in pairs(self.interactive_panels or empty_table) do | |
| if obj == panel then | |
| self.interactive_panels[id] = nil | |
| return | |
| end | |
| end | |
| end | |
| function GedApp:SetSelection(panel_context, selection, multiple_selection, notify, restoring_state, focus) | |
| local panel = self.interactive_panels[panel_context] | |
| if not panel then return end | |
| if selection and (notify or restoring_state) then | |
| panel:CancelSearch("dont_select") | |
| end | |
| panel:SetSelection(selection, multiple_selection, notify, restoring_state) | |
| if not restoring_state then | |
| panel:SetPanelFocused() | |
| end | |
| if focus then | |
| self.last_focused_panel = panel -- will suppress GedPanelBase:OnSetFocus() which binds the object, selected in the panel | |
| self.last_focused_tree_or_list_panel = panel | |
| self:ActionsUpdated() | |
| panel.idContainer:SetFocus() | |
| end | |
| end | |
| function GedApp:SetSearchString(panel_context, search_string) | |
| local panel = self.interactive_panels[panel_context] | |
| if not panel then return end | |
| if not search_string then | |
| panel:CancelSearch() | |
| return | |
| end | |
| if panel.idSearchEdit then | |
| panel.idSearchEdit:SetText(search_string) | |
| panel:UpdateFilter() | |
| end | |
| end | |
| function GedApp:SelectSiblingsInFocusedPanel(selection, selected) | |
| local panel = self.last_focused_panel | |
| if panel then | |
| local first_selected, all_selected = panel:GetSelection() | |
| for _, idx in ipairs(selection) do | |
| if selected then | |
| table.insert_unique(all_selected, idx) | |
| else | |
| table.remove_value(all_selected, idx) | |
| end | |
| end | |
| panel:SetSelection(first_selected, all_selected, not "notify") | |
| end | |
| end | |
| function GedApp:SetPropSelection(context, prop_list) -- list with id's to select | |
| if not context or not self.interactive_panels[context] then return end | |
| self.interactive_panels[context]:SetSelection(prop_list) | |
| end | |
| function GedApp:SetLastFocusedPanel(panel) | |
| if self.last_focused_panel ~= panel then | |
| self.last_focused_panel = panel | |
| if IsKindOfClasses(panel, "GedTreePanel", "GedListPanel") then | |
| self.last_focused_tree_or_list_panel = panel | |
| end | |
| self:ActionsUpdated() | |
| return true | |
| end | |
| end | |
| function GedApp:GetLastFocusedPanel() | |
| return self.last_focused_panel | |
| end | |
| function GedApp:GetState() | |
| local state = {} | |
| if self.interactive_panels and self.window_state ~= "destroying" then | |
| for context, panel in pairs(self.interactive_panels) do | |
| state[context] = panel:GetState() | |
| end | |
| end | |
| state.focused_panel = self.last_focused_tree_or_list_panel and self.last_focused_tree_or_list_panel.context | |
| return state | |
| end | |
| function GedApp:OnMouseButtonDown(pt, button) | |
| if button == "L" then | |
| if self.last_focused_panel then | |
| self.last_focused_panel:SetPanelFocused() | |
| end | |
| return "break" | |
| end | |
| end | |
| function GedApp:OnMouseWheelForward() | |
| return "break" | |
| end | |
| function GedApp:OnMouseWheelBack() | |
| return "break" | |
| end | |
| function GedApp:SetActionToggled(action_id, toggled) | |
| self.actions_toggled[action_id] = toggled | |
| self:ActionsUpdated() | |
| end | |
| function GedApp:Op(op_name, obj, ...) | |
| self.connection:Send("rfnOp", self:GetState(), op_name, obj, ...) | |
| end | |
| function GedApp:OnSaving() | |
| local focus = self.desktop.keyboard_focus | |
| if focus then | |
| local prop_editor = GetParentOfKind(focus, "GedPropEditor") | |
| if prop_editor and not prop_editor.prop_meta.read_only then | |
| prop_editor:SendValueToGame() | |
| end | |
| end | |
| end | |
| function GedApp:Send(rfunc_name, ...) -- for calls that don't modify objects | |
| self.connection:Send("rfnRunGlobal", rfunc_name, ...) | |
| end | |
| function GedApp:Call(rfunc_name, ...) -- for calls that return a value | |
| return self.connection:Call("rfnRunGlobal", rfunc_name, ...) | |
| end | |
| function GedApp:InvokeMethod(obj_name, func_name, ...) | |
| self.connection:Send("rfnInvokeMethod", obj_name, func_name, ...) | |
| end | |
| function GedApp:InvokeMethodReturn(obj_name, func_name, ...) -- for calls that return a value | |
| return self.connection:Call("rfnInvokeMethod", obj_name, func_name, ...) | |
| end | |
| function GedApp:Undo() | |
| self.connection:Send("rfnUndo") | |
| end | |
| function GedApp:Redo() | |
| self.connection:Send("rfnRedo") | |
| end | |
| function GedApp:StoreAppState() | |
| self.connection:Send("rfnStoreAppState", self:GetState()) | |
| end | |
| function GedApp:SelectAndBindObj(name, obj_address, func_name, ...) | |
| self.connection:Send("rfnSelectAndBindObj", name, obj_address, func_name, ...) | |
| end | |
| function GedApp:SelectAndBindMultiObj(name, obj_address, all_indexes, func_name, ...) | |
| self.connection:Send("rfnSelectAndBindMultiObj", name, obj_address, all_indexes, func_name, ...) | |
| end | |
| function GedApp:DiscardEditorChanges() | |
| self:Send("GedDiscardEditorChanges") | |
| end | |
| function GedApp:GetGameError() | |
| local error_text, error_time = self.connection:Call("rfnGetLastError") | |
| return error_text, error_time and (error_time - self.game_real_time) | |
| end | |
| function GedApp:ShowMessage(title, text) | |
| StdMessageDialog:new({}, self.desktop, { title = title, text = text, dark_mode = self.dark_mode }):Open() | |
| end | |
| function GedApp:WaitQuestion(title, text, ok_text, cancel_text) | |
| local dialog = StdMessageDialog:new({}, self.desktop, { | |
| title = title or "", | |
| text = text or "", | |
| ok_text = ok_text ~= "" and ok_text, | |
| cancel_text = cancel_text ~= "" and cancel_text, | |
| translate = false, | |
| question = true, | |
| dark_mode = self.dark_mode, | |
| }) | |
| dialog:Open() | |
| self.ui_questions = self.ui_questions or {} | |
| table.insert(self.ui_questions, dialog) | |
| local result, win = dialog:Wait() | |
| if self.ui_questions then | |
| table.remove_value(self.ui_questions, dialog) | |
| end | |
| return result | |
| end | |
| function GedApp:DeleteQuestion() -- cancel is already taken as the default "answer" | |
| local question = self.ui_questions and self.ui_questions[1] | |
| if question then | |
| question:Close("delete") -- the waiting thread should remove it form the list | |
| end | |
| end | |
| function GedApp:WaitUserInput(title, default, items) | |
| local dialog = StdInputDialog:new({}, self.desktop, { title = title, default = default, items = items, dark_mode = self.dark_mode }) | |
| dialog:Open() | |
| local result, win = dialog:Wait() | |
| return result | |
| end | |
| function GedApp:WaitListChoice(items, caption, start_selection, lines) | |
| local dialog = StdInputDialog:new({}, terminal.desktop, { title = caption, default = start_selection, items = items, lines = lines } ) | |
| dialog:Open() | |
| local result, win = dialog:Wait() | |
| return result | |
| end | |
| function GedApp:SetUiStatus(id, text, delay) | |
| local idx = table.find(self.ui_status, "id", id) or (#self.ui_status + 1) | |
| if not text then | |
| table.remove(self.ui_status, idx) | |
| else | |
| self.ui_status[idx] = { id = id, text = text } | |
| end | |
| self:UpdateUiStatus() | |
| if delay then | |
| self.ui_status_delay_time = RealTime() + delay | |
| if not self.ui_status_delay_thread then | |
| self.ui_status_delay_thread = CreateRealTimeThread(function() | |
| while self.ui_status_delay_time - RealTime() > 0 do | |
| Sleep(self.ui_status_delay_time - RealTime()) | |
| end | |
| self:SetUiStatus(id) | |
| self.ui_status_delay_thread = nil | |
| end) | |
| end | |
| end | |
| end | |
| function GedApp:WaitBrowseDialog(folder, filter, create, multiple) | |
| return OpenBrowseDialog(folder, filter or "", not not create, not not multiple) | |
| end | |
| function GedApp:GedOpError(error_message) | |
| if not self.blink_thread then | |
| self.blink_thread = CreateRealTimeThread(function() | |
| for i = 1, 3 do | |
| self.blink_border_color = RGB(220, 0, 0) | |
| self:Invalidate() | |
| Sleep(50) | |
| self.blink_border_color = RGBA(0, 0, 0, 0) | |
| self:Invalidate() | |
| Sleep(50) | |
| end | |
| self.blink_border_color = nil | |
| self.blink_thread = nil | |
| self:Invalidate() | |
| end) | |
| end | |
| if type(error_message) == "string" and error_message ~= "error" and error_message ~= "" then | |
| self:ShowMessage("Error", error_message) | |
| end | |
| end | |
| function GedApp:DrawChildren(clip_box) | |
| XActionsHost.DrawChildren(self, clip_box) | |
| if self.blink_border_color ~= RGBA(0, 0, 0, 0) then | |
| local box = (self:GetLastFocusedPanel() or self).box | |
| UIL.DrawBorderRect(box, 2, 2, self.blink_border_color, RGBA(0, 0, 0, 0)) | |
| end | |
| end | |
| function GedApp:GetDisplayedSearchResultData() | |
| return self.display_search_result and self.search_value_results and self.search_value_results[self.search_result_idx] | |
| end | |
| function GedApp:TryHighlightSearchMatchInChildPanels(parent_panel) | |
| if not parent_panel.SelectionBind then return end | |
| for bind in string.gmatch(parent_panel.SelectionBind .. ",", reCommaList) do | |
| local bind_dot = bind .. "." | |
| for _, panel in ipairs(self.all_panels) do | |
| local context = panel.context | |
| if panel.window_state ~= "destroying" and context and (context == bind or context:starts_with(bind_dot)) then | |
| panel:TryHighlightSearchMatch() | |
| end | |
| end | |
| end | |
| end | |
| function GedApp:FocusProperty(panel_id, prop_id) | |
| local panel = self.interactive_panels[panel_id] | |
| local prop_editor = panel and panel:LocateEditorById(prop_id) | |
| if prop_editor then | |
| local focus = prop_editor:GetRelativeFocus(point(0, 0), "next") or prop_editor | |
| focus:SetFocus() | |
| end | |
| end | |
| function GedApp:OpenContextMenu(action_context, anchor_pt) | |
| if not action_context or not anchor_pt or action_context == "" then return end | |
| local menu = XPopupMenu:new({ | |
| ActionContextEntries = action_context, | |
| Anchor = anchor_pt, | |
| AnchorType = "mouse", | |
| MaxItems = 12, | |
| GetActionsHost = function() return self end, | |
| popup_parent = self, | |
| RebuildActions = function(menu, host) | |
| XPopupMenu.RebuildActions(menu, host) | |
| for _, entry in ipairs(menu.idContainer) do | |
| if entry.action.OnActionEffect == "popup" then | |
| XLabel:new({ | |
| Dock = "right", | |
| ZOrder = -1, | |
| Margins = box(5, 0, 0, 0), | |
| }, entry):SetText(">") | |
| end | |
| end | |
| end, | |
| }, terminal.desktop) | |
| menu:Open() | |
| return menu | |
| end | |
| ----- Dark Mode support | |
| function GetDarkModeSetting() | |
| local setting = rawget(_G, "g_GedApp") and g_GedApp.dark_mode | |
| if setting == "Follow system" then | |
| return GetSystemDarkModeSetting() | |
| else | |
| return setting and setting ~= "Light" | |
| end | |
| end | |
| local menubar = RGB(64, 64, 64) | |
| local l_menubar = RGB(255, 255, 255) | |
| local menu_selection = RGB(100, 100, 100) | |
| local l_menu_selection = RGB(204, 232, 255) | |
| local toolbar = RGB(64, 64, 64) | |
| local l_toolbar = RGB(255, 255, 255) | |
| local panel = RGB(42, 41, 41) | |
| local panel_title = RGB(64, 64, 64) | |
| local panel_background_tab = RGB(96, 96, 96) | |
| local panel_rollovered_tab = RGB(110, 110, 110) | |
| local panel_child = RGBA(0, 0, 0, 0) | |
| local panel_focused_border = RGB(100, 100, 100) | |
| local l_panel = RGB(255, 255, 255) | |
| local l_panel_title = RGB(220, 220, 220) | |
| local l_panel_background_tab = RGB(196, 196, 196) | |
| local l_panel_rollovered_tab = RGB(240, 240, 240) | |
| local l_panel_child = RGBA(0, 0, 0, 0) | |
| local l_panel_focused_border = RGB(0, 0, 0) | |
| local l_prop_button_focused = RGB(24, 123, 197) | |
| local l_prop_button_rollover = RGB(24, 123, 197) | |
| local l_prop_button_pressed = RGB(38, 146, 227) | |
| local l_prop_button_disabled = RGB(128, 128, 128) | |
| local l_prop_button_background = RGB(38, 146, 227) | |
| local prop_button_focused = RGB(193, 193, 193) | |
| local prop_button_rollover = RGB(100, 100, 100) | |
| local prop_button_pressed = RGB(105, 105, 105) | |
| local prop_button_disabled = RGB(93, 93, 93) | |
| local prop_button_background = RGB(105, 105, 105) | |
| local scroll = RGB(131, 131, 131) | |
| local scroll_pressed = RGB(211, 211, 211) | |
| local scroll_rollover = RGB(170, 170, 170) | |
| local scroll_background = RGB(64, 64, 64) | |
| local button_divider = RGB(100, 100, 100) | |
| local l_scroll = RGB(169, 169, 169) | |
| local l_scroll_pressed = RGB(100, 100, 100) | |
| local l_scroll_rollover = RGB(128, 128, 128) | |
| local l_scroll_background = RGB(240, 240, 240) | |
| local l_button_divider = RGB(169, 169, 169) | |
| local edit_box = RGB(54, 54, 54) | |
| local edit_box_border = RGB(130, 130, 130) | |
| local edit_box_focused = RGB(42, 41, 41) | |
| local l_edit_box = RGB(240, 240, 240) | |
| local l_edit_box_border = RGB(128, 128, 128) | |
| local l_edit_box_focused = RGB(255, 255, 255) | |
| local propitem_selection = RGB(20, 109, 171) | |
| local subobject_selection = RGB(40, 50, 70) | |
| local panel_item_selection = RGB(70, 70, 70) | |
| local l_propitem_selection = RGB(121, 189, 241) | |
| local l_subobject_selection = RGB(204, 232, 255) | |
| local l_panel_item_selection = RGB(204, 232, 255) | |
| local button_border = RGB(130, 130, 130) | |
| local button_pressed_background = RGB(191, 191, 191) | |
| local button_toggled_background = RGB(150, 150, 150) | |
| local button_rollover = RGB(70, 70, 70) | |
| local l_button_border = RGB(240, 240, 240) | |
| local l_button_pressed_background = RGB(121, 189, 241) | |
| local l_button_toggled_background = RGB(35, 97, 171) | |
| local l_button_rollover = RGB(204, 232, 255) | |
| local checkbox_color = RGB(128, 128, 128) | |
| local checkbox_disabled_color = RGBA(128, 128, 128, 128) | |
| function GedApp:UpdateChildrenDarkMode(win) | |
| if win.window_state ~= "destroying" then | |
| self:UpdateControlDarkMode(win) | |
| if not IsKindOfClasses(win, "XMenuBar", "XToolBar", "GedPanelBase", "GedPropSet") then | |
| for _, child in ipairs(win or self) do | |
| self:UpdateChildrenDarkMode(child) | |
| end | |
| end | |
| end | |
| end | |
| local function SetUpTextStyle(control, dark_mode) | |
| local new_style = GetTextStyleInMode(rawget(control, "TextStyle"), dark_mode) | |
| if new_style then | |
| control:SetTextStyle(new_style) | |
| elseif control.TextStyle:starts_with("GedDefault") then | |
| control:SetTextStyle(dark_mode and "GedDefaultDark" or "GedDefault") | |
| elseif control.TextStyle:starts_with("GedSmall") then | |
| control:SetTextStyle(dark_mode and "GedSmallDark" or "GedSmall") | |
| end | |
| end | |
| local function SetUpDarkModeButton(button, dark_mode) | |
| SetUpTextStyle(button, dark_mode) | |
| button:SetBackground(dark_mode and prop_button_background or l_prop_button_background) | |
| button:SetFocusedBackground(dark_mode and prop_button_focused or l_prop_button_focused) | |
| button:SetRolloverBackground(dark_mode and prop_button_rollover or l_prop_button_rollover) | |
| button:SetPressedBackground(dark_mode and prop_button_pressed or l_prop_button_pressed) | |
| button:SetDisabledBackground(dark_mode and prop_button_disabled or l_prop_button_disabled) | |
| end | |
| local function SetUpDarkModeSetItem(button, dark_mode) | |
| SetUpTextStyle(button, dark_mode) | |
| button:SetBackground(RGBA(0, 0, 0, 0)) | |
| if dark_mode and not button:GetEnabled() then | |
| button:SetToggledBackground(dark_mode and prop_button_disabled or l_propitem_selection) | |
| button:SetDisabledBackground(dark_mode and RGBA(0, 0, 0, 0) or l_prop_button_disabled) | |
| else | |
| button:SetFocusedBackground(dark_mode and prop_button_focused or l_prop_button_focused) | |
| button:SetPressedBackground(dark_mode and propitem_selection or l_propitem_selection) | |
| button:SetToggledBackground(dark_mode and propitem_selection or l_propitem_selection) | |
| button:SetDisabledBackground(dark_mode and prop_button_disabled or l_prop_button_disabled) | |
| end | |
| end | |
| local function SetUpIconButton(button, dark_mode) | |
| button.idIcon:SetImageColor(dark_mode and RGB(210, 210, 210) or button.parent.Id == "idNumberEditor" and RGB(0, 0, 0) or nil) | |
| button:SetBackground(RGBA(0, 0, 0, 1)) -- 1 is used as alpha because we don't touch control with color == 0 | |
| if IsKindOf(button, "XCheckButton") then | |
| button:SetBorderColor(RGBA(0, 0, 0, 0)) | |
| button:SetIconColor(dark_mode and checkbox_color or RGB(0, 0, 0)) | |
| button:SetDisabledIconColor(checkbox_disabled_color) | |
| else | |
| button:SetRolloverBorderColor(dark_mode and button_border or l_button_border) | |
| button:SetRolloverBackground(dark_mode and button_rollover or l_button_rollover) | |
| button:SetPressedBackground(dark_mode and button_pressed_background or l_button_pressed_background) | |
| if IsKindOf(button, "XToggleButton") and button:GetToggledBackground() == button:GetDefaultPropertyValue("ToggledBackground") then | |
| button:SetToggledBackground(dark_mode and button_toggled_background or l_button_toggled_background) | |
| end | |
| -- Set border color if it hasn't been manually set | |
| local border_color = button:GetBorderColor() | |
| local other_mode_border_color = not dark_mode and button_border or l_button_border | |
| if border_color == button:GetDefaultPropertyValue("BorderColor") or border_color == other_mode_border_color then | |
| button:SetBorderColor(dark_mode and button_border or l_button_border) | |
| end | |
| end | |
| end | |
| function GedApp:UpdateControlDarkMode(control) | |
| local dark_mode = self.dark_mode | |
| local new_style = GetTextStyleInMode(rawget(control, "TextStyle"), dark_mode) | |
| if IsKindOf(control, "XRolloverWindow") and IsKindOf(control[1], "XText") then | |
| control[1].invert_colors = true | |
| end | |
| if control.Id == "idPopupBackground" then | |
| control:SetBackground(dark_mode and RGB(54, 54, 54) or RGB(240, 240, 240)) | |
| end | |
| if IsKindOf(control, "GedApp") then | |
| control:SetBackground(dark_mode and button_divider or nil) | |
| end | |
| if IsKindOf(control, "GedPropEditor") then | |
| control.SelectionBackground = dark_mode and panel_item_selection or l_panel_item_selection | |
| end | |
| if IsKindOf(control, "XList") then | |
| control:SetBorderColor(dark_mode and edit_box_border or l_edit_box_border) | |
| control:SetFocusedBorderColor(dark_mode and edit_box_border or l_edit_box_border) | |
| control:SetBackground(dark_mode and panel or l_panel) | |
| control:SetFocusedBackground(dark_mode and panel or l_panel) | |
| end | |
| if IsKindOf(control, "XListItem") then | |
| local prop_editor = GetParentOfKind(control, "GedPropEditor") | |
| if prop_editor and not IsKindOfClasses(prop_editor, "GedPropPrimitiveList", "GedPropEmbeddedObject") then | |
| control:SetSelectionBackground(dark_mode and propitem_selection or l_propitem_selection) | |
| else | |
| control:SetSelectionBackground(dark_mode and panel_item_selection or l_panel_item_selection) | |
| end | |
| control:SetFocusedBorderColor(dark_mode and panel_focused_border or l_panel_focused_border) | |
| end | |
| if IsKindOf(control, "XMenuBar") then | |
| control:SetBackground(dark_mode and menubar or l_menubar) | |
| for _, menu_item in ipairs(control) do | |
| SetUpTextStyle(menu_item.idLabel, dark_mode) | |
| menu_item:SetRolloverBackground(dark_mode and menu_selection or l_menu_selection) | |
| menu_item:SetPressedBackground(dark_mode and menu_selection or l_menu_selection) | |
| end | |
| return | |
| end | |
| if IsKindOf(control, "ShortcutEditor") then | |
| control:SetBackground(dark_mode and menubar or l_menubar) | |
| control:SetFocusedBackground(dark_mode and menubar or l_menubar) | |
| for _, win in ipairs(control.idContainer.idModifiers) do | |
| if IsKindOf(win, "XToggleButton") then | |
| SetUpDarkModeSetItem(win, dark_mode) | |
| end | |
| end | |
| return | |
| end | |
| if IsKindOf(control, "XPopup") then | |
| control:SetBackground(dark_mode and menubar or l_menubar) | |
| control:SetFocusedBackground(dark_mode and menubar or l_menubar) | |
| for _, entry in ipairs(control.idContainer) do | |
| if entry:IsKindOf("XButton") then | |
| entry:SetRolloverBackground(dark_mode and menu_selection or l_menu_selection) | |
| end | |
| end | |
| return | |
| end | |
| if IsKindOf(control, "XToolBar") then | |
| control:SetBackground(dark_mode and toolbar or l_toolbar) | |
| for _, toolbar_item in ipairs(control) do | |
| -- divider line betweeen action buttons | |
| if not IsKindOf(toolbar_item, "XTextButton") and not IsKindOf(toolbar_item, "XToggleButton") then | |
| toolbar_item:SetBackground(dark_mode and button_divider or l_button_divider) | |
| else | |
| SetUpIconButton(toolbar_item, dark_mode) | |
| end | |
| end | |
| return | |
| end | |
| if IsKindOf(control, "GedPropSet") then | |
| self:UpdateChildrenDarkMode(control.idLabelHost) | |
| control.idContainer:SetBorderColor(dark_mode and edit_box_border or l_edit_box_border) | |
| for _, win in ipairs(control.idContainer) do | |
| if IsKindOf(win, "XToggleButton") then | |
| SetUpDarkModeSetItem(win, dark_mode) | |
| else | |
| self:UpdateChildrenDarkMode(win) | |
| end | |
| end | |
| return | |
| end | |
| if IsKindOf(control, "GedPropScript") then | |
| control.idEditHost:SetBorderColor(dark_mode and edit_box_border or l_edit_box_border) | |
| return | |
| end | |
| if IsKindOf(control, "XCurveEditor") then | |
| control:SetCurveColor(dark_mode and l_scroll or nil) | |
| control:SetControlPointColor(dark_mode and l_scroll or nil) | |
| control:SetControlPointHoverColor(dark_mode and button_divider or nil) | |
| control:SetControlPointCaptureColor(dark_mode and scroll_background or nil) | |
| control:SetGridColor(dark_mode and scroll_background or nil) | |
| return | |
| end | |
| if IsKindOf(control, "GedPanelBase") then | |
| if control.Id == "idStatusBar" then | |
| control:SetBackground(dark_mode and panel_title or l_panel_title) | |
| else | |
| control:SetBackground(dark_mode and panel or l_panel) | |
| end | |
| if control:ResolveId("idTitleContainer") then | |
| control.idTitleContainer:SetBackground(dark_mode and panel_title or l_panel_title) | |
| control.idTitleContainer:ResolveId("idTitle"):SetTextStyle(new_style or GetTextStyleInMode(control.Embedded and "GedDefault" or "GedTitleSmall", dark_mode)) | |
| end | |
| if control:ResolveId("idSearchResultsText") then | |
| control:ResolveId("idSearchResultsText"):SetTextStyle(GetTextStyleInMode("GedDefault", dark_mode)) | |
| end | |
| for _, child_control in ipairs(control) do | |
| if child_control.Id == "idContainer" then | |
| if child_control:HasMember("TextStyle") then | |
| SetUpTextStyle(child_control, dark_mode) | |
| end | |
| if child_control:HasMember("FocusedBackground") then | |
| child_control:SetFocusedBackground(dark_mode and panel_child or l_panel_child) | |
| end | |
| if child_control:HasMember("SelectionBackground") then | |
| child_control:SetSelectionBackground(dark_mode and panel_item_selection or l_panel_item_selection) | |
| child_control:SetFocusedBorderColor(dark_mode and panel_focused_border or l_panel_focused_border) | |
| end | |
| child_control:SetBackground(dark_mode and panel_child or l_panel_child) | |
| if IsKindOfClasses(control, "GedPropPanel", "GedTreePanel") then | |
| local noProps = control.idContainer:ResolveId("idNoPropsToShow") | |
| if noProps then | |
| SetUpTextStyle(noProps, dark_mode) | |
| else | |
| control:SetFocusedBackground(dark_mode and panel or l_panel) | |
| local container = control.idContainer | |
| for _, prop_win in ipairs(container) do | |
| for _, prop_child in ipairs(prop_win) do | |
| if IsKindOf(prop_child, "XTextButton") then | |
| SetUpDarkModeButton(prop_child, dark_mode) | |
| else | |
| self:UpdateChildrenDarkMode(prop_child) | |
| end | |
| end | |
| end | |
| for _, control in ipairs(control.idTitleContainer) do | |
| if IsKindOf(control, "XTextButton") then | |
| SetUpIconButton(control, dark_mode) | |
| end | |
| end | |
| end | |
| elseif IsKindOf(control, "GedBreadcrumbPanel") then | |
| local container = control.idContainer | |
| for _, win in ipairs(container) do | |
| if IsKindOf(win, "XButton") then | |
| win:SetRolloverBackground(dark_mode and RGB(72, 72, 72) or l_button_rollover) | |
| SetUpTextStyle(win[1], dark_mode) | |
| end | |
| end | |
| elseif IsKindOf(control, "GedTextPanel") then | |
| control.idContainer:SetTextStyle(new_style or GetTextStyleInMode("GedTextPanel", dark_mode)) | |
| else | |
| self:UpdateChildrenDarkMode(child_control) | |
| end | |
| elseif child_control.Id == "idTitleContainer" then | |
| local search = control:ResolveId("idSearchContainer") | |
| search:SetBackground(RGBA(0, 0, 0, 0)) | |
| search:SetBorderColor(dark_mode and panel_focused_border or l_panel_focused_border) | |
| local edit = control:ResolveId("idSearchEdit") | |
| self:UpdateEditControlDarkMode(edit, dark_mode) | |
| edit:SetTextStyle(new_style or GetTextStyleInMode("GedDefault", dark_mode)) | |
| edit:SetBackground(dark_mode and edit_box_focused or l_edit_box_focused) | |
| edit:SetHintColor(dark_mode and RGBA(210, 210, 210, 128) or nil) | |
| SetUpIconButton(control:ResolveId("idToggleSearch"), dark_mode) | |
| SetUpIconButton(control:ResolveId("idCancelSearch"), dark_mode) | |
| SetUpDarkModeButton(control:ResolveId("idSearchHistory"), dark_mode) | |
| for _, tab_button in ipairs(control.idTabContainer) do | |
| tab_button:SetToggledBackground(dark_mode and panel or l_panel) | |
| tab_button:SetToggledBorderColor(dark_mode and panel or l_panel) | |
| tab_button:SetBackground(dark_mode and panel_background_tab or l_panel_background_tab) | |
| tab_button:SetPressedBackground(dark_mode and panel_rollovered_tab or l_panel_rollovered_tab) | |
| tab_button:SetRolloverBackground(dark_mode and panel_rollovered_tab or l_panel_rollovered_tab) | |
| tab_button:SetBorderColor(dark_mode and panel_title or l_panel_title) | |
| tab_button:SetRolloverBorderColor(dark_mode and panel_title or l_panel_title) | |
| tab_button:SetTextStyle(dark_mode and "GedButton" or "GedDefault") | |
| end | |
| elseif IsKindOf(child_control, "XSleekScroll") then | |
| child_control.idThumb:SetBackground(dark_mode and scroll or l_scroll) | |
| child_control:SetBackground(dark_mode and scroll_background or l_scroll_background) | |
| elseif child_control.Id ~= "idViewErrors" and child_control.Id ~= "idPauseResume" then | |
| self:UpdateChildrenDarkMode(child_control) | |
| end | |
| end | |
| return | |
| end | |
| if control.Id == "idPanelDockedButtons" then | |
| control:SetBackground(dark_mode and panel_title or l_panel_title) | |
| return | |
| end | |
| if IsKindOf(control, "XRangeScroll") then | |
| control:SetThumbBackground(dark_mode and scroll or l_scroll) | |
| control:SetThumbRolloverBackground(dark_mode and scroll_rollover or l_scroll_rollover) | |
| control:SetThumbPressedBackground(dark_mode and scroll_pressed or l_scroll_pressed) | |
| control.idThumbLeft:SetBackground(dark_mode and scroll or l_scroll) | |
| control.idThumbRight:SetBackground(dark_mode and scroll or l_scroll) | |
| control:SetScrollColor(dark_mode and scroll or l_scroll) | |
| control:SetBackground(dark_mode and scroll_background or l_scroll_background) | |
| end | |
| if IsKindOf(control, "XTextButton") then | |
| SetUpIconButton(control, dark_mode) | |
| end | |
| if IsKindOf(control, "XFontControl") then | |
| if control.Id == "idWarningText" then | |
| return | |
| end | |
| SetUpTextStyle(control, dark_mode) | |
| end | |
| if IsKindOf(control, "XCombo") or IsKindOf(control, "XCheckButtonCombo") then | |
| control:SetBackground(dark_mode and edit_box or l_edit_box) | |
| control:SetFocusedBackground(dark_mode and edit_box or l_edit_box) | |
| control:SetBorderColor(dark_mode and edit_box_border or l_edit_box_border) | |
| control:SetFocusedBorderColor(dark_mode and edit_box_border or l_edit_box_border) | |
| if IsKindOf(control, "XCombo") and (control:GetListItemTemplate() == "XComboListItemDark" or control:GetListItemTemplate() == "XComboListItemLight") then | |
| control:SetListItemTemplate(dark_mode and "XComboListItemDark" or "XComboListItemLight") | |
| control.PopupBackground = dark_mode and panel or l_panel | |
| end | |
| end | |
| if IsKindOf(control, "XComboButton") then | |
| SetUpDarkModeButton(control, dark_mode) | |
| end | |
| if IsKindOf(control, "XScrollArea") and not IsKindOf(control, "XMultiLineEdit") and not IsKindOf(control, "XList") then | |
| control:SetBackground(dark_mode and panel or l_panel) | |
| end | |
| if IsKindOf(control, "XMultiLineEdit") then | |
| if GetParentOfKind(control, "GedMultiLinePanel") then | |
| control:SetTextStyle(new_style or GetTextStyleInMode("GedMultiLine", dark_mode)) | |
| else | |
| control:SetTextStyle(new_style or GetTextStyleInMode("GedDefault", dark_mode)) | |
| if control.parent.Id == "idEditHost" then | |
| control.parent:SetBorderColor(dark_mode and edit_box_border or l_edit_box_border) | |
| end | |
| end | |
| self:UpdateEditControlDarkMode(control, dark_mode) | |
| end | |
| if IsKindOf(control, "XEdit") then | |
| control:SetTextStyle(new_style or GetTextStyleInMode("GedDefault", dark_mode)) | |
| self:UpdateEditControlDarkMode(control, dark_mode) | |
| end | |
| if IsKindOf(control, "XTextEditor") then | |
| control:SetHintColor(dark_mode and RGBA(210, 210, 210, 128) or nil) | |
| end | |
| if IsKindOf(control, "XSleekScroll") then | |
| control.idThumb:SetBackground(dark_mode and scroll or l_scroll) | |
| control:SetBackground(dark_mode and scroll_background or l_scroll_background) | |
| end | |
| if IsKindOf(control, "XToggleButton") and control.Id == "idInputListener" then | |
| control:SetPressedBackground(dark_mode and propitem_selection or l_propitem_selection) | |
| control:SetToggledBackground(dark_mode and propitem_selection or l_propitem_selection) | |
| end | |
| end | |
| function OnMsg.GedPropertyUpdated(property) | |
| if IsKindOf(property, "GedPropSet") then | |
| GetParentOfKind(property, "GedApp"):UpdateChildrenDarkMode(property) | |
| end | |
| end | |
| ----- GedBindView | |
| DefineClass.GedBindView = { | |
| __parents = { "XContextWindow" }, | |
| Dock = "ignore", | |
| visible = false, | |
| properties = { | |
| { category = "General", id = "BindView", editor = "text", default = "", }, | |
| { category = "General", id = "BindRoot", editor = "text", default = "", }, | |
| { category = "General", id = "BindField", editor = "text", default = "", }, | |
| { category = "General", id = "BindFunc", editor = "text", default = "", }, | |
| { category = "General", id = "ControlId", editor = "text", default = "", }, | |
| { category = "General", id = "GetBindParams", editor = "expression", params = "self, control", }, | |
| { category = "General", id = "OnViewChanged", editor = "func", params = "self, value, control", }, | |
| }, | |
| MinWidth = 0, | |
| MinHeight = 0, | |
| } | |
| function GedBindView:Open(...) | |
| XContextWindow.Open(self, ...) | |
| self.app = GetParentOfKind(self.parent, "GedApp") | |
| end | |
| function GedBindView:Done() | |
| local connection = self.app and self.app.connection | |
| if connection then | |
| connection:UnbindObj(self.context .. "|" .. self.BindView) | |
| end | |
| end | |
| function GedBindView:GetBindParams(control) | |
| end | |
| function GedBindView:OnContextUpdate(context, view) | |
| self.app = self.app or GetParentOfKind(self.parent, "GedApp") | |
| local connection = self.app and self.app.connection | |
| if not connection then return end | |
| if not view and self.BindView ~= "" then -- obj changed | |
| local path = self.BindRoot == "" and context or self.BindRoot | |
| if self.BindField ~= "" then | |
| path = {path, self.BindField} | |
| end | |
| connection:BindObj(context .. "|" .. self.BindView, path, self.BindFunc ~= "" and self.BindFunc, self:GetBindParams(self:ResolveId(self.ControlId))) | |
| end | |
| if view == self.BindView or (self.BindView == "") then -- view changed | |
| local name = self.BindView ~= "" and context .. "|" .. self.BindView or context | |
| local value = connection.bound_objects[name] | |
| self:OnViewChanged(value, self:ResolveId(self.ControlId)) | |
| end | |
| end | |
| function GedBindView:OnViewChanged(value, control) | |
| end | |
| function RebuildSubItemsActions(panel, actions_def, default_submenu, toolbar, menubar) | |
| local host = GetActionsHost(panel) | |
| local actions = host:GetActions() | |
| for i = #(actions or ""), 1, -1 do | |
| local action = actions[i] | |
| if action.ActionId:starts_with("NewItemEntry_") or action.ActionId:starts_with("NewSubitemMenu_") then | |
| host:RemoveAction(action) | |
| end | |
| end | |
| if type(actions_def) == "table" and #actions_def > 0 then | |
| local submenus = {} | |
| for _, def in ipairs(actions_def) do | |
| local submenu = def.EditorSubmenu or default_submenu | |
| if submenu ~= "" then | |
| submenus[submenu] = true | |
| XAction:new({ | |
| ActionId = "NewItemEntry_" .. def.Class, | |
| ActionMenubar = "NewSubitemMenu_" .. submenu, | |
| ActionToolbar = def.EditorIcon and toolbar, | |
| ActionIcon = def.EditorIcon, | |
| ActionName = def.EditorName or def.Class, | |
| ActionTranslate = false, | |
| ActionShortcut = def.EditorShortcut, | |
| OnActionParam = def.Class, | |
| OnAction = function(self, host, source) | |
| if panel:IsKindOf("GedTreePanel") then | |
| host:Op("GedOpTreeNewItemInContainer", panel.context, panel:GetSelection(), self.OnActionParam) | |
| else | |
| host:Op("GedOpListNewItem", panel.context, panel:GetSelection(), self.OnActionParam) | |
| end | |
| end, | |
| }, host) | |
| end | |
| end | |
| for submenu in sorted_pairs(submenus) do | |
| XAction:new({ | |
| ActionId = "NewSubitemMenu_" .. submenu, | |
| ActionMenubar = menubar, | |
| ActionName = submenu, | |
| ActionTranslate = false, | |
| ActionSortKey = "2", | |
| OnActionEffect = "popup", | |
| ActionContexts = { "ContentPanelAction", "ContentRootPanelAction", "ContentChildPanelAction" }, | |
| }, host) | |
| end | |
| end | |
| end |