myspace / CommonLua /Ged /GedApp.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
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