Download CommonLua/X/XDialog.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 14.7 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/X/XDialog.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/CommonLua/X/XDialog.lua
-
curl -L -o XDialog.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/X/XDialog.lua
14.7 kB
| if FirstLoad then | |
| Dialogs = {} | |
| end | |
| function OpenDialog(template, parent, context, reason, id, prop_preset) | |
| id = id or template | |
| local dialog = GetDialog(id) | |
| if dialog then | |
| if context then | |
| dialog:SetContext(context) | |
| end | |
| local mode = ResolveValue(context, "Mode") | |
| if mode ~= nil then | |
| dialog:SetMode(mode) | |
| end | |
| else | |
| assert(Dialogs[id] == nil) | |
| dialog = XTemplateSpawn(template, parent, context) | |
| assert(IsKindOf(dialog, "XDialog")) | |
| if not dialog then | |
| return | |
| end | |
| dialog.XTemplate = XTemplates[template] and template or nil | |
| Dialogs[id] = dialog | |
| Dialogs[dialog] = id | |
| if not parent or parent.window_state == "open" then | |
| if prop_preset then | |
| dialog:CopyProperties(prop_preset, prop_preset:GatherTemplateProperties()) | |
| end | |
| dialog:Open() | |
| end | |
| end | |
| if IsKindOf(dialog, "XDialog") then | |
| dialog:AddOpenReason(reason) | |
| end | |
| return dialog | |
| end | |
| function CloseDialog(id, result, reason) | |
| local dialog = GetDialog(id) | |
| if dialog then | |
| if IsKindOf(dialog, "XDialog") then | |
| dialog:RemoveOpenReason(reason, result) | |
| else | |
| dialog:Close(result) | |
| end | |
| return dialog | |
| end | |
| end | |
| function ListDialogs() | |
| local dlgs = {} | |
| for k,v in pairs(Dialogs) do | |
| if type(k)=="string" then | |
| dlgs[#dlgs + 1] = k | |
| end | |
| end | |
| table.sort(dlgs) | |
| return dlgs | |
| end | |
| function ListAllDialogs() | |
| return PresetsCombo("XTemplate", nil, "InGameInterface")() | |
| end | |
| function RemoveOpenReason(reason, result) | |
| for dialog in pairs(Dialogs) do | |
| if IsKindOf(dialog, "XDialog") then | |
| dialog:RemoveOpenReason(reason, result) | |
| end | |
| end | |
| end | |
| function GetDialog(id_or_win) | |
| if type(id_or_win) == "table" and IsKindOf(id_or_win, "XWindow") then | |
| return GetParentOfKind(id_or_win, "XDialog") | |
| end | |
| return Dialogs[id_or_win] | |
| end | |
| function WaitDialog(...) | |
| local dialog = OpenDialog(...) | |
| if dialog then | |
| return dialog:Wait() | |
| end | |
| end | |
| function EnsureDialog(dlg) | |
| local dialog = GetDialog(dlg) | |
| if not dialog then | |
| local t = GetInGameInterface() | |
| if not t then | |
| ShowInGameInterface(true) | |
| t = GetInGameInterface() | |
| end | |
| dialog = OpenDialog(dlg, t) | |
| end | |
| return dialog | |
| end | |
| function GetDialogMode(id_or_win) | |
| local dlg = GetDialog(id_or_win) | |
| return dlg and dlg.Mode | |
| end | |
| function GetDialogModeParam(id_or_win) | |
| local dlg = GetDialog(id_or_win) | |
| return dlg and dlg.mode_param | |
| end | |
| function SetDialogMode(id_or_win, mode, mode_param) | |
| local dlg = GetDialog(id_or_win) | |
| if dlg then | |
| dlg:SetMode(mode, mode_param) | |
| end | |
| end | |
| function SetBackDialogMode(id_or_win) | |
| local dlg = GetDialog(id_or_win) | |
| if dlg then | |
| local mode = table.remove(dlg.mode_log) | |
| if mode then | |
| dlg:SetMode(mode[1], mode[2]) | |
| table.remove(dlg.mode_log) | |
| end | |
| end | |
| end | |
| function GetDialogContext(id_or_win) | |
| local dlg = GetDialog(id_or_win) | |
| return dlg and dlg.context | |
| end | |
| function _GetUIPath(win, parent) | |
| win = win or (parent or terminal.desktop):GetMouseTarget(terminal:GetMousePos()) | |
| parent = parent or false | |
| local wins = {} | |
| local w = win | |
| local f | |
| while w and w ~= parent do | |
| local name = Dialogs[w] or rawget(w, "XTemplate") or w.class | |
| local id = rawget(w, "Id") | |
| if id and name ~= id and id ~= "" then | |
| name = name .. "(" .. id .. ")" | |
| end | |
| local z = w.ZOrder ~= 1 and w.ZOrder | |
| if z then | |
| name = name .. "[" .. z .. "]" | |
| end | |
| if not w:IsVisible() then | |
| name = name .. "|X|" | |
| end | |
| if not f and w:IsFocused() then | |
| f = w | |
| name = name .. "*" | |
| end | |
| table.insert(wins, 1, name) | |
| w = w.parent or false | |
| end | |
| return table.concat(wins, " - ") | |
| end | |
| function _PrintDialogs(print_func, indent, except) | |
| except = except or {} | |
| indent = indent or "" | |
| print_func = print_func or print | |
| local texts = {} | |
| for name, dlg in pairs(Dialogs) do | |
| if type(name) == "string" and type(dlg) == "table" and not table.find(except,name) then | |
| texts[#texts + 1] = _GetUIPath(dlg, terminal.desktop) | |
| if dlg:IsKindOf("BaseLoadingScreen") then | |
| texts[#texts + 1] = "\t" .. ValueToLuaCode(dlg:GetOpenReasons()) | |
| end | |
| end | |
| end | |
| table.sort(texts) | |
| local indents = {} | |
| for i=1,#texts do | |
| local txt = texts[i] | |
| for j=i+1,#texts do | |
| local t = texts[j] | |
| local b, e = string.find(t, txt, 1, true) | |
| if b then | |
| indents[j] = (indents[j] or 0) + 1 | |
| texts[j] = string.sub(t, e+1) | |
| end | |
| end | |
| end | |
| for i=1,#texts do | |
| local txt = texts[i] | |
| if indents[i] then | |
| txt = string.rep("\t", indents[i]) .. txt | |
| end | |
| print_func(indent, txt) | |
| end | |
| end | |
| function OnMsg.BugReportStart(print_func) | |
| print_func("Screen size: ", UIL.GetScreenSize()) | |
| if next(Dialogs) ~= nil then | |
| print_func("Opened dialogs: (notation: (n) = Id, [n] = ZOrder, |X| = Invisible, * = Focused)") | |
| _PrintDialogs(print_func, "\t") | |
| print_func("") | |
| end | |
| end | |
| function CloseAllDialogs(except, force_loading_screens) | |
| if Platform.xbox then | |
| AsyncOpCancel(ActiveVirtualKeyboard) | |
| end | |
| CloseAllMessagesAndQuestions() | |
| local dialogs = ListDialogs() | |
| for i = 1, #dialogs do | |
| local dialog = dialogs[i] | |
| if except and except[dialog] then | |
| print("Skipping dialog " .. dialog) | |
| elseif not force_loading_screens and (IsKindOf(GetDialog(dialog), "BaseLoadingScreen") or IsKindOf(GetDialog(dialog), "BaseSavingScreen")) then | |
| -- should be closed by the code that opened them | |
| else | |
| CloseDialog(dialog) | |
| end | |
| end | |
| end | |
| function CloseDialogs(id, ...) | |
| if not id then return end | |
| CloseDialog(id) | |
| return CloseDialogs(...) | |
| end | |
| ----- XDialog | |
| DefineClass.XDialog = { | |
| __parents = { "XActionsHost" }, | |
| properties = { | |
| { category = "General", id = "InitialMode", editor = "text", default = "" }, | |
| { category = "General", id = "Mode", editor = "text", default = "", read_only = true, }, | |
| { category = "General", id = "InternalModes", name = "Internal modes", editor = "text", default = "", help = "A list of internal modes. When present, any mode outside of the list will be propagated to the parent dialog."}, | |
| { category = "General", id = "gamestate", Name = "Game state", editor = "text", default = "" }, | |
| { category = "General", id = "FocusOnOpen", editor = "choice", default = "self", items = {"", "self", "child"}, }, | |
| { category = "Visual", id = "HideInScreenshots", editor = "bool", default = false }, | |
| }, | |
| XTemplate = false, | |
| Translate = true, | |
| IdNode = true, | |
| open_reasons = false, | |
| result = false, | |
| close_controller_id = false, -- which controller was used to close the dialog | |
| mode_log = false, | |
| mode_param = false, | |
| } | |
| function XDialog:Init(parent, context) | |
| self.InitialMode = ResolveValue(context, "Mode") or self.InitialMode | |
| self.mode_log = ResolveValue(context, "mode_log") or {} | |
| end | |
| function XDialog:Close(reason, source, controller_id, ...) | |
| if source == "gamepad" then | |
| self.close_controller_id = controller_id | |
| end | |
| XActionsHost.Close(self, reason, source, controller_id, ...) | |
| end | |
| function XDialog:Done(result) | |
| Msg("DialogClose", self, result) | |
| local id = Dialogs[self] | |
| Dialogs[self] = nil | |
| if id and Dialogs[id] == self then | |
| Dialogs[id] = nil | |
| if self.gamestate ~= "" then | |
| ChangeGameState(self.gamestate, false) | |
| end | |
| end | |
| self.result = result | |
| Msg(self) | |
| end | |
| function XDialog:Open(...) | |
| if not self.HostInParent then | |
| self:ResolveRelativeFocusOrder() | |
| end | |
| self:SetFocus_OnOpen(self.FocusOnOpen) | |
| XActionsHost.Open(self, ...) | |
| Msg("DialogOpen", self, self.InitialMode) | |
| if self.InitialMode ~= "" then | |
| self:SetMode(self.InitialMode) | |
| end | |
| if self.gamestate ~= "" then | |
| ChangeGameState(self.gamestate, true) | |
| end | |
| end | |
| function XDialog:SetFocus_OnOpen(focus) | |
| focus = focus or self.FocusOnOpen | |
| if focus == "self" then | |
| self:SetFocus() | |
| elseif focus == "child" then | |
| local child = self:GetRelativeFocus(point(1, 1), "nearest") | |
| if child then | |
| child:SetFocus() | |
| end | |
| end | |
| end | |
| function XDialog:Wait() | |
| assert(IsAsyncCode()) | |
| if self.window_state == "open" then | |
| assert(not self:GetThreadName(), "The window thread will be deleted before self:Wait() returns") | |
| WaitMsg(self) | |
| end | |
| return self.result, self, self.close_controller_id | |
| end | |
| function XDialog:AddOpenReason(reason) | |
| self.open_reasons = self.open_reasons or {} | |
| self.open_reasons[reason or true] = true | |
| end | |
| function XDialog:RemoveOpenReason(reason, result) | |
| local open_reasons = self.open_reasons | |
| reason = reason or true | |
| if open_reasons and open_reasons[reason] then | |
| open_reasons[reason] = nil | |
| if next(open_reasons) == nil and self.window_state ~= "destroying" then | |
| self:Close(result) | |
| return true | |
| end | |
| end | |
| end | |
| function XDialog:GetOpenReasons() | |
| return self.open_reasons or empty_table | |
| end | |
| local function callOnModeChange(win, mode, dialog) | |
| if win == dialog or not IsKindOf(win, "XDialog") then | |
| for _, win in ipairs(win or empty_table) do | |
| callOnModeChange(win, mode, dialog) | |
| end | |
| end | |
| win:OnDialogModeChange(mode, dialog) | |
| end | |
| function MatchDialogMode(mode, list) | |
| if not list or list == "" then return end | |
| if mode == "" then | |
| return list:starts_with(",") -- the first mode in the list can be "" | |
| end | |
| if mode == list then | |
| return true | |
| end | |
| if not list:find(mode, 1, true) then | |
| return | |
| end | |
| for m in list:gmatch("([%w%-_]+)") do | |
| if m == mode then | |
| return true | |
| end | |
| end | |
| end | |
| function XDialog:GetModes(list) | |
| list = list or self.InternalModes or "" | |
| local arr = { list:starts_with(",") and "" or nil } | |
| for m in list:gmatch("([%w%-_]+)") do | |
| arr[#arr + 1] = m | |
| end | |
| return arr | |
| end | |
| function XDialog:SetMode(mode, mode_param) | |
| if not MatchDialogMode(mode, self.InternalModes) then | |
| local dlg = GetParentOfKind(self.parent, "XDialog") | |
| if dlg then | |
| dlg:SetMode(mode, mode_param) | |
| return | |
| end | |
| end | |
| self.mode_log[#self.mode_log + 1] = { self.Mode, self.mode_param } | |
| local old_mode = self.Mode | |
| self.Mode = mode | |
| self.mode_param = mode_param | |
| Msg("DialogSetMode", self, mode, mode_param, old_mode) | |
| self:CallOnModeChange() | |
| end | |
| function XDialog:CallOnModeChange() | |
| callOnModeChange(self, self.Mode, self) | |
| end | |
| ----- XLayer | |
| DefineClass.XLayer = { | |
| __parents = { "XDialog" }, | |
| FocusOnOpen = "", | |
| } | |
| ----- XOpenLayer | |
| DefineClass.XOpenLayer = { | |
| __parents = { "XWindow" }, | |
| properties = { | |
| { category = "General", id = "Layer", editor = "combo", default = "", items = function() return XTemplateCombo("XLayer") end, }, | |
| { category = "General", id = "LayerId", editor = "text", default = "", }, | |
| { category = "General", id = "Mode", editor = "text", default = false, }, | |
| }, | |
| Dock = "ignore", | |
| visible = false, | |
| dialog = false, | |
| xtemplate = false, | |
| } | |
| function XOpenLayer:Open() | |
| if self.Layer ~= "" then | |
| local context = self:GetContext() | |
| if self.Mode then | |
| context = SubContext(context, { Mode = self.Mode }) | |
| end | |
| local id = self.LayerId ~= "" and self.LayerId or nil | |
| self.dialog = OpenDialog(self.Layer, nil, context, self, id, self.xtemplate) | |
| end | |
| end | |
| function XOpenLayer:Done() | |
| if self.dialog then | |
| CreateRealTimeThread(self.dialog.RemoveOpenReason, self.dialog, self) | |
| end | |
| end | |
| ----- XContentTemplate | |
| DefineClass.XContentTemplate = { | |
| __parents = { "XActionsHost" }, | |
| properties = { | |
| { category = "Template", id = "RespawnOnContext", name = "Respawn on context update", editor = "bool", default = true, }, | |
| { category = "Template", id = "RespawnOnDialogMode", name = "Respawn on mode change", editor = "bool", default = true, }, | |
| { category = "Template", id = "RespawnExpression", name = "Respawn on expression change", editor = "expression", default = empty_func, params = "self, context", | |
| dont_save = function(self) return self.RespawnOnContext end }, | |
| }, | |
| IdNode = true, | |
| HostInParent = true, | |
| xtemplate = false, | |
| respawn_value = false, | |
| } | |
| function XContentTemplate:Init(parent, context, xtemplate) | |
| self.xtemplate = xtemplate | |
| self.respawn_value = self:RespawnExpression(context) | |
| end | |
| function XContentTemplate:OnContextUpdate(context, ...) | |
| if self.RespawnOnContext then | |
| if self.window_state == "open" then | |
| self:RespawnContent() | |
| end | |
| else | |
| local respawn_value = self:RespawnExpression(context) | |
| if rawget(self, "respawn_value") ~= respawn_value then | |
| self.respawn_value = respawn_value | |
| if self.window_state == "open" then | |
| self:RespawnContent() | |
| end | |
| end | |
| end | |
| end | |
| function XContentTemplate:OnDialogModeChange(mode, dialog) | |
| if self.RespawnOnDialogMode then | |
| self:RespawnContent() | |
| end | |
| end | |
| function XContentTemplate:RespawnContent() | |
| local xtemplate = self.xtemplate | |
| if xtemplate then | |
| local desktop = self.desktop | |
| local focus = desktop.keyboard_focus | |
| local focus_order = focus and focus:IsWithin(self) and focus:GetFocusOrder() | |
| local gamepad_rollover = RolloverControl and RolloverControl == focus and RolloverGamepad | |
| local mouse_rollover = RolloverControl and RolloverControl == desktop.last_mouse_target and RolloverControl:IsWithin(self) | |
| self:DeleteChildren() | |
| self:ClearActions() | |
| xtemplate:EvalChildren(self, self.context) | |
| for _, win in ipairs(self) do | |
| win:Open() | |
| end | |
| self:InvalidateMeasure() | |
| self:InvalidateLayout() | |
| local host = GetActionsHost(self, true) | |
| if not host or host == self then | |
| self:ResolveRelativeFocusOrder() | |
| elseif host and not host:GetThread("resolve_focus") then | |
| host:CreateThread("resolve_focus", host.ResolveRelativeFocusOrder, host) | |
| end | |
| self:DeleteThread("rollover") | |
| self:CreateThread("rollover", function(self, focus_order, gamepad_rollover, mouse_rollover) | |
| local focus = self:GetRelativeFocus(focus_order, "nearest") | |
| if focus then | |
| focus:SetFocus() | |
| end | |
| if focus and gamepad_rollover then | |
| XCreateRolloverWindow(focus, true, true) | |
| elseif mouse_rollover then | |
| local win = XGetRolloverControl() | |
| if win and win:IsWithin(self) then | |
| XCreateRolloverWindow(win, false, true) | |
| end | |
| end | |
| end, self, focus_order, gamepad_rollover, mouse_rollover) | |
| Msg("XWindowRecreated", self) | |
| end | |
| end | |
| ----- XContentTemplateScrollArea | |
| DefineClass.XContentTemplateScrollArea = { | |
| __parents = { "XScrollArea", "XContentTemplate" }, | |
| } | |
| ----- XContentTemplateList | |
| DefineClass.XContentTemplateList = { | |
| __parents = { "XList", "XContentTemplate" }, | |
| MouseScroll = false, | |
| properties = { | |
| { category = "General", id = "KeepSelectionOnRespawn", editor = "bool", default = false }, | |
| }, | |
| } | |
| function XContentTemplateList:OnShortcut(shortcut, source, ...) | |
| if XList.OnShortcut(self, shortcut, source, ...) == "break" then | |
| return "break" | |
| end | |
| return XActionsHost.OnShortcut(self, shortcut, source, ...) | |
| end | |
| function XContentTemplateList:Open(...) | |
| self:GenerateItemHashTable() | |
| XContentTemplate.Open(self, ...) | |
| self:CreateThread("SetInitialSelection", self.SetInitialSelection, self) | |
| end | |
| function XContentTemplateList:RespawnContent() | |
| local last_selection | |
| if self.KeepSelectionOnRespawn and next(self.selection) then | |
| last_selection = self.selection[1] | |
| end | |
| XContentTemplate.RespawnContent(self) | |
| self:GenerateItemHashTable() | |
| self:DeleteThread("SetInitialSelection") | |
| self:CreateThread("SetInitialSelection", self.SetInitialSelection, self, last_selection) | |
| end |