|
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, |
|
all_panels = false, |
|
interactive_panels = false, |
|
actions_toggled = false, |
|
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, |
|
blink_border_color = RGBA(0, 0, 0, 0), |
|
progress_text = false, |
|
progress_bar = false, |
|
|
|
|
|
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 |
|
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) |
|
|
|
|
|
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 |
|
|
|
|
|
if panel then |
|
|
|
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 |
|
|
|
|
|
if sel_read_only == nil then |
|
sel_read_only = true |
|
end |
|
|
|
|
|
if not panel.read_only and sel_read_only then |
|
|
|
if (id ~= "Copy" and id ~= "Paste") or config.ModdingToolsInUserMode then |
|
return "disabled" |
|
end |
|
|
|
elseif panel.read_only and sel_read_only then |
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
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 |
|
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 |
|
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) |
|
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, ...) |
|
self.connection:Send("rfnRunGlobal", rfunc_name, ...) |
|
end |
|
|
|
function GedApp:Call(rfunc_name, ...) |
|
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, ...) |
|
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() |
|
local question = self.ui_questions and self.ui_questions[1] |
|
if question then |
|
question:Close("delete") |
|
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 |
|
|
|
|
|
|
|
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)) |
|
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 |
|
|
|
|
|
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 |
|
|
|
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 |
|
|
|
|
|
|
|
|
|
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 |
|
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 |
|
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 |