Download CommonLua/X/XActions.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 27.5 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/X/XActions.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/CommonLua/X/XActions.lua
-
curl -L -o XActions.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/X/XActions.lua
27.5 kB
| --[[@@@ | |
| @class XAction | |
| Defines a UI action, which can be bound to buttons or used on its own. | |
| Always initialize it with a parent or if that is not possible, call RegisterInHost afterwards with the correct XActionsHost | |
| ]] | |
| DefineClass.XAction = { | |
| __parents = { "XRollover" }, | |
| properties = { | |
| { category = "Action", id = "ActionId", editor = "text", default = "" }, | |
| { category = "Action", id = "ActionMode", editor = "text", default = "" }, | |
| { category = "Action", id = "InheritedActionModes", editor = "text", default = "", read_only = true, help = "ActionModes inherited from parent if ActionMode is empty", dont_save = true }, | |
| { category = "Action", id = "ActionSortKey", editor = "text", default = "", | |
| buttons = { { name = "Rebuild", func = "RebuildSortKeys" } }, | |
| }, | |
| { category = "Action", id = "ActionTranslate", editor = "bool", default = true, }, | |
| { category = "Action", id = "ActionName", editor = "text", default = "", translate = function(obj) return obj:GetProperty("ActionTranslate") end, }, | |
| { category = "Action", id = "ActionDescription", editor = "text", default = "", translate = function(obj) return obj:GetProperty("ActionTranslate") end, }, | |
| { category = "Action", id = "ActionIcon", editor = "ui_image", default = "", }, | |
| { category = "Action", id = "ActionMenubar", editor = "text", default = "", }, | |
| { category = "Action", id = "ActionToolbar", editor = "text", default = "" }, | |
| { category = "Action", id = "ActionToolbarSplit", editor = "bool", default = false }, | |
| { category = "Action", id = "ActionToolbarSection", editor = "text", default = "" }, | |
| { category = "Action", id = "ActionUIStyle", editor = "choice", default = "auto", items = {"auto", "gamepad", "keyboard"}, }, | |
| { category = "Action", id = "ActionShortcut", editor = "shortcut", default = "" }, | |
| { category = "Action", id = "ActionShortcut2", editor = "shortcut", default = "" }, | |
| { category = "Action", id = "ActionGamepad", editor = "shortcut", shortcut_type = "gamepad", default = "" }, | |
| { category = "Action", id = "ActionGamepadHold", editor = "bool", default = false }, | |
| { category = "Action", id = "ActionBindable", editor = "bool", default = false }, | |
| { category = "Action", id = "ActionMouseBindable", editor = "bool", default = true }, | |
| { category = "Action", id = "ActionBindSingleKey", editor = "bool", default = false }, | |
| { category = "Action", id = "BindingsMenuCategory", editor = "text", default = "Default" }, | |
| { category = "Action", id = "ActionButtonTemplate", editor = "choice", default = false, items = function() return XTemplateCombo("XButton") end, }, | |
| { category = "Action", id = "ActionToggle", editor = "bool", default = false }, | |
| { category = "Action", id = "ActionToggled", editor = "func", params = "self, host", read_only = function(self) return not self:GetProperty("ActionToggle") end, }, | |
| { category = "Action", id = "ActionToggledIcon", editor = "ui_image", default = "", read_only = function(self) return not self:GetProperty("ActionToggle") end, }, | |
| { category = "Action", id = "ActionState", editor = "func", params = "self, host" }, | |
| { category = "Action", id = "OnActionEffect", editor = "choice", default = "", items = {"", "popup", "back", "close", "mode"}, }, | |
| { category = "Action", id = "OnActionParam", editor = "text", default = "" }, | |
| { category = "Action", id = "OnAction", editor = "func", params = "self, host, source, ...", }, | |
| { category = "Action", id = "OnShortcutUp", editor = "func", params = "self, host, source, ...", default = false }, | |
| { category = "Action", id = "OnAltAction", editor = "func", params = "self, host, source, ...", default = false}, | |
| { category = "Action", id = "IgnoreRepeated", editor = "bool", default = false }, | |
| { category = "Action", id = "ActionContexts", editor = "string_list", default = false }, | |
| { category = "FX", id = "FXMouseIn", editor = "text", default = "", }, | |
| { category = "FX", id = "FXPress", editor = "text", default = "", }, | |
| { category = "FX", id = "FXPressDisabled", editor = "text", default = "", }, | |
| -- properties of XRollover should regard ActionTranslate | |
| { category = "Rollover", id = "RolloverTranslate", editor = false }, | |
| { category = "Rollover", id = "RolloverAnchor", editor = false }, | |
| { category = "Rollover", id = "RolloverText", editor = "text", default = "", translate = function(obj) return obj:GetProperty("ActionTranslate") end, lines = 3, }, | |
| { category = "Rollover", id = "RolloverDisabledText", editor = "text", default = "", translate = function(obj) return obj:GetProperty("ActionTranslate") end, lines = 3, }, | |
| }, | |
| -- the default values are needed when saving and loading from AccountStorage | |
| default_ActionShortcut = false, | |
| default_ActionShortcut2 = false, | |
| default_ActionGamepad = false, | |
| shortcut_up_thread = false, | |
| host = false, | |
| multi_mode_cache = false | |
| } | |
| function XAction:RegisterInHost(host, replace_matching_id) | |
| self.host = host | |
| if host then host:_InternalAddAction(self, replace_matching_id) end | |
| self:BindShortcuts() | |
| if self.OnShortcutUp and host and self.OnAction ~= XAction.OnAction then | |
| local oldAction = self.OnAction | |
| self.OnAction = function(self, ...) | |
| oldAction(self, ...) | |
| local keyOne = self.ActionShortcut and VKStrNamesInverse[self.ActionShortcut] | |
| local keyTwo = self.ActionShortcut2 and VKStrNamesInverse[self.ActionShortcut2] | |
| local downKey = (keyOne and terminal.IsKeyPressed(keyOne) and keyOne) or (keyTwo and terminal.IsKeyPressed(keyTwo) and keyTwo) | |
| if IsValidThread(self.shortcut_up_thread) then | |
| DeleteThread(self.shortcut_up_thread) | |
| end | |
| self.shortcut_up_thread = CreateRealTimeThread(function(self, ...) | |
| while downKey and terminal.IsKeyPressed(downKey) and not terminal.desktop.inactive do | |
| Sleep(16) | |
| end | |
| self.OnShortcutUp(self, ...) | |
| end, self, ...) | |
| end | |
| end | |
| end | |
| function XAction:Init(parent, context, replace_matching_id) | |
| self:RegisterInHost(GetActionsHost(parent), replace_matching_id) | |
| end | |
| function XAction:BindShortcuts() | |
| self.default_ActionShortcut = self.ActionShortcut | |
| self.default_ActionShortcut2 = self.ActionShortcut2 | |
| self.default_ActionGamepad = self.ActionGamepad | |
| if self.ActionBindable then | |
| local bindings = AccountStorage and AccountStorage.Shortcuts[self.ActionId] | |
| if bindings then | |
| self:SetActionShortcuts(bindings[1] or self.ActionShortcut, bindings[2] or self.ActionShortcut2, bindings[3] or self.ActionGamepad) | |
| end | |
| end | |
| end | |
| local function RemoveShortcut(action, name, shortcut) | |
| shortcut = shortcut or "" | |
| local old_shortcut = action[name] | |
| if shortcut == old_shortcut then | |
| -- no change | |
| return | |
| end | |
| action[name] = nil | |
| local host = action.host | |
| if not host then return end | |
| -- unregister old shortcut | |
| host:CallHostParents("RemoveShortcutToAction", action, old_shortcut) | |
| end | |
| local function AddShortcut(action, name, shortcut) | |
| shortcut = shortcut or "" | |
| local old_shortcut = action[name] | |
| if shortcut == old_shortcut then | |
| -- no change | |
| return | |
| end | |
| action[name] = shortcut | |
| local host = action.host | |
| if not host then return end | |
| -- register new one | |
| host:CallHostParents("AddShortcutToAction", action, shortcut) | |
| end | |
| function XAction:SetActionShortcuts(shortcut, shortcut2, shortcut_gamepad) | |
| -- remove old shortcuts before adding any of the new ones | |
| RemoveShortcut(self, "ActionShortcut", shortcut) | |
| RemoveShortcut(self, "ActionShortcut2", shortcut2) | |
| RemoveShortcut(self, "ActionGamepad", shortcut_gamepad) | |
| -- add new shortcuts | |
| AddShortcut(self, "ActionShortcut", shortcut) | |
| AddShortcut(self, "ActionShortcut2", shortcut2) | |
| AddShortcut(self, "ActionGamepad", shortcut_gamepad) | |
| end | |
| function XAction:SetActionMenubar(menubar) | |
| local host = self.host | |
| if host and self.ActionMenubar ~= menubar then | |
| host:CallHostParents("RemoveMenubarAction", self) | |
| end | |
| self.ActionMenubar = menubar | |
| if not host then return end | |
| host:CallHostParents("AddMenubarAction", self) | |
| end | |
| function XAction:SetActionToolbar(toolbar) | |
| local host = self.host | |
| if host and self.ActionToolbar ~= toolbar then | |
| host:CallHostParents("RemoveToolbarAction", self) | |
| end | |
| self.ActionToolbar = toolbar | |
| if not host then return end | |
| host:CallHostParents("AddToolbarAction", self) | |
| end | |
| function XAction:SetActionSortKey(sort_key) | |
| self.ActionSortKey = sort_key | |
| if not self.host then return end | |
| self.host:InvalidateActionSortKey(self) | |
| end | |
| function XAction:ActionState(host) | |
| end | |
| function XAction:ActionToggled(host) | |
| end | |
| function XAction:OnAction(host, source, ...) | |
| local effect = self.OnActionEffect | |
| local param = self.OnActionParam | |
| if effect == "close" and host and host.window_state ~= "destroying" then | |
| host:Close(param ~= "" and param or nil, source, ...) | |
| elseif effect == "mode" and host then | |
| assert(IsKindOf(host, "XDialog")) | |
| host:SetMode(param) | |
| elseif effect == "back" and host then | |
| assert(IsKindOf(host, "XDialog")) | |
| SetBackDialogMode(host) | |
| elseif effect == "popup" then | |
| local actions_view = GetParentOfKind(source, "XActionsView") | |
| if actions_view then | |
| actions_view:PopupAction(self.ActionId, host, source) | |
| else | |
| XShortcutsTarget:OpenPopupMenu(self.ActionId, terminal.GetMousePos()) | |
| end | |
| else | |
| --print(self.ActionId, "activated") | |
| end | |
| end | |
| function XAction:OnXTemplateSetProperty(prop_id, old_value) | |
| -- toggle text properties between Ts and strings when ActionTranslate is edited | |
| if prop_id == "ActionTranslate" then | |
| self:UpdateLocalizedProperty("ActionName", self.ActionTranslate) | |
| self:UpdateLocalizedProperty("RolloverText", self.ActionTranslate) | |
| self:UpdateLocalizedProperty("RolloverDisabledText", self.ActionTranslate) | |
| ObjModified(self) | |
| end | |
| if prop_id == "ActionSortKey" and self.ActionSortKey ~= "" then | |
| local preset = GetParentTableOfKind(self, "XTemplate") | |
| preset.RequireActionSortKeys = true | |
| end | |
| end | |
| function XAction:EnabledInMode(mode) | |
| local myMode = self.ActionMode | |
| if myMode == "" then return true end | |
| if mode == myMode then return true end | |
| if not self.multi_mode_cache or self.multi_mode_cache.strsrc ~= myMode then | |
| local modeCache = { strsrc = myMode } | |
| for str in string.gmatch(myMode, "([%w%-_]+)") do | |
| modeCache[str] = true | |
| end | |
| self.multi_mode_cache = modeCache | |
| end | |
| return self.multi_mode_cache[mode] | |
| end | |
| local function assign_sortkeys(node, sortkey) | |
| if node:IsKindOf("XTemplateAction") and node.ActionId ~= "" then | |
| if node.ActionSortKey ~= "" then | |
| print("Overwriting SortKey of", node.ActionId, "to", node.ActionSortKey) | |
| end | |
| node:SetActionSortKey(tostring(sortkey * 10)) | |
| sortkey = sortkey + 1 | |
| end | |
| for _, item in ipairs(node) do | |
| sortkey = assign_sortkeys(item, sortkey) | |
| end | |
| return sortkey | |
| end | |
| function XAction:RebuildSortKeys(root, prop_id, ged, btn_param) | |
| if ged:WaitQuestion("Rebuild SortKeys", "This will assign SortKeys to each Action in the current file, in the order\nthey appear, overwriting existing ones.\n\nContinue?", "OK", "Cancel") ~= "ok" then | |
| return | |
| end | |
| assign_sortkeys(root, 100) -- start from 100 so that alphabetical order and numerical order coincide | |
| root.RequireActionSortKeys = true | |
| ObjModified(self) | |
| ObjModified(root) | |
| end | |
| ----- XActionsHost | |
| DefineClass.XActionsHost = { | |
| __parents = { "XContextWindow", "XHoldButton" }, | |
| properties = { | |
| { category = "Actions", id = "ActionsMode", editor = "text", default = "", }, | |
| { category = "Actions", id = "Translate", editor = "bool", default = false, }, | |
| { category = "Actions", id = "HostInParent", editor = "bool", default = false, }, | |
| }, | |
| actions = false, | |
| shortcut_to_actions = false, | |
| menubar_actions = false, | |
| toolbar_actions = false, | |
| action_hold_buttons = false, | |
| dirty_actions_order = false, | |
| dirty_menubars = false, | |
| dirty_toolbars = false, | |
| dirty_shortcuts = false, | |
| } | |
| function XActionsHost:Init() | |
| self.actions = self.actions or {} | |
| self.shortcut_to_actions = {} | |
| self.menubar_actions = {} | |
| self.toolbar_actions = {} | |
| self.dirty_menubars = {} | |
| self.dirty_toolbars = {} | |
| self.dirty_shortcuts = {} | |
| -- register already created actions in the host | |
| for _, action in ipairs(self.actions) do | |
| action:RegisterInHost(self) | |
| end | |
| end | |
| function XActionsHost:ClearActions() | |
| if self.HostInParent then | |
| local host = GetActionsHost(self.parent) | |
| if host then | |
| for _, action in ipairs(host and self.actions) do | |
| host:RemoveAction(action) | |
| end | |
| end | |
| end | |
| table.clear(self.actions) | |
| table.clear(self.shortcut_to_actions) | |
| table.clear(self.menubar_actions) | |
| table.clear(self.toolbar_actions) | |
| end | |
| function XActionsHost:Done() | |
| self:ClearActions() | |
| end | |
| function XActionsHost:ActionsUpdated() | |
| if not self:GetThread("UpdateActionViews") then | |
| self:CreateThread("UpdateActionViews", self.UpdateActionViews, self, self) | |
| end | |
| end | |
| function XActionsHost:SetActionsMode(mode) | |
| if self.ActionsMode ~= mode then | |
| self.ActionsMode = mode | |
| self:ActionsUpdated() | |
| end | |
| end | |
| function XActionsHost:InvalidateActionSortKey(action) | |
| self.dirty_actions_order = true | |
| if action.ActionMenubar ~= "" then | |
| self.dirty_menubars[action.ActionMenubar] = true | |
| end | |
| if action.ActionToolbar ~= "" then | |
| self.dirty_toolbars[action.ActionToolbar] = true | |
| end | |
| if action.ActionShortcut ~= "" then | |
| self.dirty_shortcuts[action.ActionShortcut] = true | |
| end | |
| if action.ActionShortcut2 ~= "" then | |
| self.dirty_shortcuts[action.ActionShortcut2] = true | |
| end | |
| if action.ActionGamepad ~= "" then | |
| self.dirty_shortcuts[action.ActionGamepad] = true | |
| end | |
| end | |
| local function sort_actions(actions) | |
| table.stable_sort(actions, function(a,b) | |
| return a.ActionSortKey < b.ActionSortKey | |
| end) | |
| end | |
| function XActionsHost:GetActions() | |
| if self.dirty_actions_order then | |
| sort_actions(self.actions) | |
| self.dirty_actions_order = nil | |
| end | |
| return self.actions | |
| end | |
| function XActionsHost:GetMenubarActions(menubar) | |
| if self.dirty_menubars[menubar] then | |
| sort_actions(self.menubar_actions[menubar]) | |
| self.dirty_menubars[menubar] = nil | |
| end | |
| return self.menubar_actions[menubar] | |
| end | |
| function XActionsHost:GetToolbarActions(toolbar) | |
| if self.dirty_toolbars[toolbar] then | |
| sort_actions(self.toolbar_actions[toolbar]) | |
| self.dirty_toolbars[toolbar] = nil | |
| end | |
| return self.toolbar_actions[toolbar] | |
| end | |
| function XActionsHost:GetShortcutActions(shortcut) | |
| if self.dirty_shortcuts[shortcut] then | |
| sort_actions(self.shortcut_to_actions[shortcut]) | |
| self.dirty_shortcuts[shortcut] = nil | |
| end | |
| return self.shortcut_to_actions[shortcut] | |
| end | |
| function XActionsHost:CallHostParents(func, ...) | |
| self[func](self, ...) | |
| if self.HostInParent then | |
| local host = GetActionsHost(self.parent) | |
| if host then | |
| host:CallHostParents(func, ...) | |
| return | |
| end | |
| end | |
| end | |
| local function add_sorted(actions, action) | |
| actions = actions or {} | |
| local i = 1 | |
| local key = action.ActionSortKey | |
| local skip_add | |
| while i <= #actions and actions[i].ActionSortKey <= key do | |
| if actions[i] == action then | |
| -- don't duplicate actions | |
| skip_add = true | |
| break | |
| end | |
| i = i + 1 | |
| end | |
| if not skip_add then | |
| table.insert(actions, i, action) | |
| end | |
| return actions | |
| end | |
| function XActionsHost:AddShortcutToAction(action, shortcut) | |
| if (shortcut or "") == "" then return end | |
| -- insert in list based on ActionSortKey | |
| self.shortcut_to_actions[shortcut] = add_sorted(self.shortcut_to_actions[shortcut], action) | |
| end | |
| function XActionsHost:RemoveShortcutToAction(action, shortcut) | |
| if (shortcut or "") == "" then return end | |
| local actions = self.shortcut_to_actions[shortcut] | |
| if not actions then return end | |
| table.remove_value(actions, action) | |
| end | |
| function XActionsHost:AddMenubarAction(action) | |
| local menubar = action.ActionMenubar | |
| if (menubar or "") == "" then return end | |
| self.menubar_actions[menubar] = add_sorted(self.menubar_actions[menubar], action) | |
| end | |
| function XActionsHost:RemoveMenubarAction(action) | |
| table.remove_entry(self.menubar_actions[action.ActionMenubar], action) | |
| end | |
| function XActionsHost:AddToolbarAction(action) | |
| local toolbar = action.ActionToolbar | |
| if (toolbar or "") == "" then return end | |
| self.toolbar_actions[toolbar] = add_sorted(self.toolbar_actions[toolbar], action) | |
| end | |
| function XActionsHost:RemoveToolbarAction(action) | |
| table.remove_entry(self.toolbar_actions[action.ActionToolbar], action) | |
| end | |
| function XActionsHost:_InternalAddAction(action, replace_matching_id) | |
| local actions = self.actions | |
| local key = action.ActionSortKey | |
| local old_idx = replace_matching_id and self:RemoveAction(self:ActionById(action.ActionId)) | |
| -- is the new action still on a correct place at the old index? | |
| if old_idx and (old_idx == 1 or actions[old_idx - 1].ActionSortKey <= key) and | |
| (old_idx > #actions or actions[old_idx].ActionSortKey >= key) then | |
| table.insert(actions, old_idx, action) | |
| else | |
| -- insert in list based on ActionSortKey | |
| add_sorted(actions, action) | |
| end | |
| -- add action to menubar and toolbar mappings | |
| self:AddMenubarAction(action) | |
| self:AddToolbarAction(action) | |
| -- add action to shortcuts mapping | |
| self:AddShortcutToAction(action, action.ActionShortcut) | |
| self:AddShortcutToAction(action, action.ActionShortcut2) | |
| self:AddShortcutToAction(action, action.ActionGamepad) | |
| if self.HostInParent then | |
| local host = GetActionsHost(self.parent) | |
| if host then | |
| host:_InternalAddAction(action, replace_matching_id) | |
| return | |
| end | |
| end | |
| self:ActionsUpdated() | |
| --assert(action.ActionName == "" or (IsT(action.ActionName) or false) == self.Translate) | |
| end | |
| function XActionsHost:RemoveAction(action) | |
| if not action then return end | |
| local actions = self.actions | |
| local idx = table.remove_entry(self.actions, action) | |
| -- remove action from menubar and toolbar mappings | |
| self:RemoveMenubarAction(action) | |
| self:RemoveToolbarAction(action) | |
| -- remove action from shortcuts mapping | |
| self:RemoveShortcutToAction(action, action.ActionShortcut) | |
| self:RemoveShortcutToAction(action, action.ActionShortcut2) | |
| self:RemoveShortcutToAction(action, action.ActionGamepad) | |
| if self.HostInParent then | |
| local host = GetActionsHost(self.parent) | |
| if host then | |
| host:RemoveAction(action) | |
| return | |
| end | |
| end | |
| self:ActionsUpdated() | |
| return idx | |
| end | |
| function XActionsHost:SetHostInParent(host_in_parent) | |
| if self.HostInParent == host_in_parent then return end | |
| self.HostInParent = host_in_parent | |
| local host = GetActionsHost(self.parent) | |
| if host then | |
| for _, action in ipairs(self.actions) do | |
| if host_in_parent then | |
| host:_InternalAddAction(action) | |
| else | |
| host:RemoveAction(action) | |
| end | |
| end | |
| end | |
| end | |
| function XActionsHost:ActionsSanityCheck() | |
| --[[local ids, shortcuts = {}, {} | |
| for _, action in ipairs(self.actions) do | |
| if action.ActionId ~= "" then | |
| assert(not ids[action.ActionId], string.format("Conflicting action Id %s", action.ActionId)) | |
| ids[action.ActionId] = action | |
| end | |
| local mode = action.ActionMode | |
| if not shortcuts[mode] then | |
| shortcuts[mode] = {} | |
| end | |
| local mode_actions = shortcuts[mode] | |
| if action.ActionShortcut ~= "" then | |
| local other = mode_actions[action.ActionShortcut] | |
| assert(not other, string.format("Conflicting shortcut %s (between actions %s & %s)", action.ActionShortcut, other and other.ActionId or "", action.ActionId)) | |
| mode_actions[action.ActionShortcut] = action | |
| end | |
| if action.ActionShortcut2 ~= "" then | |
| local other = mode_actions[action.ActionShortcut2] | |
| assert(not other, string.format("Conflicting shortcut %s (between actions %s & %s)", action.ActionShortcut2, other and other.ActionId or "", action.ActionId)) | |
| mode_actions[action.ActionShortcut2] = action | |
| end | |
| end]] | |
| end | |
| function XActionsHost:UpdateActionViews(win) | |
| if Platform.developer then | |
| self:ActionsSanityCheck() | |
| end | |
| for _, win in ipairs(win) do | |
| if IsKindOf(win, "XActionsView") then | |
| win:OnUpdateActions() | |
| end | |
| if not IsKindOf(win, "XActionsHost") or win.HostInParent then | |
| self:UpdateActionViews(win) | |
| end | |
| end | |
| end | |
| function XActionsHost:ShowActionBar(bShow) | |
| local action_bar = self:HasMember("idActionBar") and self.idActionBar | |
| if action_bar then | |
| action_bar:SetVisible(bShow) | |
| end | |
| end | |
| function XActionsHost:FilterAction(action, action_context) | |
| if not action_context then | |
| return action:EnabledInMode(self.ActionsMode) and self:ActionState(action) ~= "hidden" | |
| end | |
| for _, context in ipairs(action.ActionContexts) do | |
| if context == action_context and self:ActionState(action) ~= "hidden" then | |
| return true | |
| end | |
| end | |
| return false | |
| end | |
| function XActionsHost:ActionState(action) | |
| local action_id = action.ActionId | |
| if action.OnActionEffect == "popup" and action.OnAction == XAction.OnAction and | |
| not self:HasMenubarActions(action_id) and not self:HasToolbarActions(action_id) then | |
| return "hidden" -- hide menu entries with no children actions, that would result in an empty popup | |
| end | |
| return action:ActionState(self) | |
| end | |
| function XActionsHost:HasMenubarActions(action_id) | |
| return next(self.menubar_actions[action_id]) | |
| end | |
| function XActionsHost:HasToolbarActions(action_id) | |
| return next(self.toolbar_actions[action_id]) | |
| end | |
| function XActionsHost:OnAction(action, ctrl, ...) | |
| local hasFx = ctrl and ctrl.FXPress | |
| local ret = action:OnAction(self, ctrl, ...) | |
| if #(action.FXPress or "") ~= 0 and not hasFx then PlayFX(action.FXPress, "start", action) end | |
| if action.ActionToggle then | |
| self:ActionsUpdated() | |
| end | |
| Msg("XActionActivated", self, action, ctrl, ...) | |
| return ret | |
| end | |
| function XActionsHost:ActionById(id) | |
| return table.find_value(self.actions, "ActionId", id) | |
| end | |
| function XActionsHost:IsActionShortcut(id, shortcut) | |
| local action = self:ActionById(id) | |
| if not action then return end | |
| return action.ActionShortcut == shortcut or action.ActionShortcut2 == shortcut or action.ActionGamepad == shortcut | |
| end | |
| function XActionsHost:ActionByShortcut(shortcut, input, controller_id, repeated, ...) | |
| local found | |
| for _, action in ipairs(self:GetShortcutActions(shortcut)) do | |
| if (not action.IgnoreRepeated or not repeated) then | |
| if self:FilterAction(action) then | |
| local state = action:ActionState(self) | |
| if state ~= "disabled" and state ~= "hidden" then | |
| found = action | |
| break | |
| end | |
| end | |
| end | |
| end | |
| return found | |
| end | |
| function XActionsHost:GamepadHoldActionByShortcut(shortcut) | |
| local found | |
| for _, action in ipairs(self:GetShortcutActions(shortcut)) do | |
| if action.ActionGamepadHold and self:FilterAction(action) then | |
| local state = action:ActionState(self) | |
| if state ~= "disabled" and state ~= "hidden" then | |
| found = action | |
| break | |
| end | |
| end | |
| end | |
| return found | |
| end | |
| if FirstLoad then | |
| KbdShortcutToRelation = { | |
| ["Tab"] = "next", | |
| ["Shift-Tab"] = "prev", | |
| ["Up"] = "up", | |
| ["Down"] = "down", | |
| ["Left"] = "left", | |
| ["Right"] = "right", | |
| } | |
| XShortcutToRelation = { | |
| ["LeftThumbLeft"] = "left", ["LeftThumbDownLeft"] = "left", ["LeftThumbUpLeft"] = "left", | |
| ["LeftThumbRight"] = "right", ["LeftThumbDownRight"] = "right", ["LeftThumbUpRight"] = "right", | |
| ["LeftThumbUp"] = "up", | |
| ["LeftThumbDown"] = "down", | |
| ["DPadLeft"] = "left", | |
| ["DPadRight"] = "right", | |
| ["DPadUp"] = "up", | |
| ["DPadDown"] = "down", | |
| } | |
| end | |
| function XActionsHost:OnHoldDown(pt, button) | |
| local action = self:GamepadHoldActionByShortcut(button) | |
| action:OnAction(self,button) | |
| end | |
| function XActionsHost:OnHoldButtonTick(i, shortcut) | |
| local action = self:GamepadHoldActionByShortcut(shortcut) | |
| if not action then | |
| return | |
| end | |
| local ctrl = self.action_hold_buttons and self.action_hold_buttons[action.ActionId] | |
| if ctrl and ctrl:HasMember("OnHoldButtonTick") then | |
| ctrl:OnHoldButtonTick(i) | |
| else | |
| XHoldButton.OnHoldButtonTick(self, i, shortcut) | |
| end | |
| end | |
| function XActionsHost:OnXButtonRepeat(shortcut, controller_id,...) | |
| if self.HostInParent then return end | |
| if not RepeatableXButtons[shortcut] then | |
| local found = self:GamepadHoldActionByShortcut(shortcut) | |
| if found then | |
| XHoldButton.OnHoldButtonRepeat(self,shortcut, controller_id) | |
| return "break" | |
| end | |
| end | |
| end | |
| function XActionsHost:OnShortcut(shortcut, source, controller_id, ...) | |
| if self.HostInParent then return end | |
| local found | |
| if source=="gamepad" then | |
| if shortcut:starts_with("-") then | |
| local org_shortcut = shortcut:gsub("-", "") | |
| found = self:GamepadHoldActionByShortcut(org_shortcut) | |
| if found then | |
| found = XHoldButton.OnHoldButtonUp(self, org_shortcut, controller_id) | |
| if found then | |
| return "break" | |
| end | |
| end | |
| elseif shortcut:starts_with("+") then | |
| local org_shortcut = shortcut:gsub("+", "") | |
| found = self:GamepadHoldActionByShortcut(org_shortcut) | |
| if found then | |
| XHoldButton.OnHoldButtonDown(self,org_shortcut, controller_id) | |
| end | |
| else | |
| found = self:GamepadHoldActionByShortcut(shortcut) | |
| if found then | |
| XHoldButton.OnHoldButtonRepeat(self,shortcut, controller_id) | |
| end | |
| end | |
| end | |
| local action = not found and self:ActionByShortcut(shortcut, source, controller_id, ...) | |
| if action then | |
| self:OnAction(action, source, controller_id, ...) | |
| return "break" | |
| end | |
| if source ~= "mouse" then | |
| local relation = (source == "keyboard") and KbdShortcutToRelation[shortcut] or XShortcutToRelation[shortcut] | |
| if relation then | |
| local focus = self.desktop and self.desktop.keyboard_focus | |
| local order = focus and focus:IsWithin(self) and focus:GetFocusOrder() or point(0, 0) | |
| focus = self:GetRelativeFocus(order, relation) | |
| if focus then | |
| -- the thread prevents Tab keys to be processed in OnKbdChar of the new focus | |
| CreateRealTimeThread(function() | |
| if focus.window_state ~= "destroying" then | |
| focus:SetFocus() | |
| if source == "gamepad" and RolloverControl ~= focus then | |
| XCreateRolloverWindow(focus, true) | |
| end | |
| end | |
| end) | |
| return "break" | |
| end | |
| end | |
| end | |
| end | |
| function XActionsHost: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, | |
| }, terminal.desktop) | |
| menu:Open() | |
| return menu | |
| end | |
| function XActionsHost:OpenPopupMenu(menubar_id, anchor_pt) | |
| local menu = XPopupMenu:new({ | |
| MenuEntries = menubar_id, | |
| Anchor = anchor_pt, | |
| AnchorType = "mouse", | |
| MaxItems = 12, | |
| GetActionsHost = function() return self end, | |
| popup_parent = self, | |
| }, terminal.desktop) | |
| menu:Open() | |
| return menu | |
| end | |
| ----- XActionsView | |
| DefineClass.XActionsView = { | |
| __parents = { "XContextWindow" }, | |
| properties = { | |
| { category = "General", id = "HideWithoutActions", name = "Hide without actions", editor = "bool", default = false }, | |
| } | |
| } | |
| function XActionsView:GetActionsHost() | |
| return GetActionsHost(self, true) | |
| end | |
| function XActionsView:Open(...) | |
| XContextWindow.Open(self, ...) | |
| self:OnUpdateActions() | |
| end | |
| function XActionsView:PopupAction(action_id, host, source) | |
| assert(false) | |
| end | |
| function XActionsView:OnUpdateActions() | |
| local host = self:GetActionsHost() | |
| if not host or self.window_state == "new" then return end | |
| self:RebuildActions(host) | |
| if self.HideWithoutActions then | |
| self:SetVisible(#self > 0) | |
| end | |
| Msg("XWindowRecreated", self) | |
| end | |
| function XActionsView:RebuildActions(host) | |
| end | |
| ----- globals | |
| function GetActionsHost(win, final) | |
| while win and (not win:IsKindOf("XActionsHost") or win.HostInParent and final) do | |
| win = win.parent | |
| if final and win and win:IsKindOf("XActionsView") then | |
| return win:GetActionsHost() | |
| end | |
| end | |
| return win | |
| end | |
| function EnabledInModes(givenModes, modes) | |
| if givenModes == "" or modes == "" or modes == givenModes then return true end | |
| for givenMode in string.gmatch(givenModes, "([%w%-_]+)") do | |
| for mode in string.gmatch(modes, "([%w%-_]+)") do | |
| if givenMode == mode or givenMode == "ForwardToC" or mode == "ForwardToC" then | |
| return true | |
| end | |
| end | |
| end | |
| return false | |
| end | |