|
DefineClass.XButton = { |
|
__parents = { "XContextControl" }, |
|
|
|
properties = { |
|
{ category = "General", id = "RepeatStart", name = "Start repeating time", editor = "number", default = 0, }, |
|
{ category = "General", id = "RepeatInterval", name = "Repeat interval", editor = "number", default = 0, }, |
|
{ category = "General", id = "OnPressEffect", editor = "choice", default= "", items = {"", "close", "action"}, }, |
|
{ category = "General", id = "OnPressParam", editor = "text", default = "" }, |
|
{ category = "General", id = "OnPress", name = "On press", editor = "func", params = "self, gamepad" }, |
|
{ category = "General", id = "AltPress", name = "Allow alternative press", editor = "bool", default = false, }, |
|
{ category = "General", id = "OnAltPress", name = "On alt press", editor = "func", params = "self, gamepad" }, |
|
|
|
{ category = "Visual", id = "RolloverBackground", name = "Rollover background", editor = "color", default = RGBA(255, 255, 255, 255), }, |
|
{ category = "Visual", id = "RolloverBorderColor", name = "Rollover border color", editor = "color", default = RGBA(0, 0, 0, 0), }, |
|
{ category = "Visual", id = "PressedBackground", name = "Pressed background", editor = "color", default = RGBA(255, 255, 255, 255), }, |
|
{ category = "Visual", id = "PressedBorderColor", name = "Pressed border color", editor = "color", default = RGBA(0, 0, 0, 0), }, |
|
{ category = "Visual", id = "PressedOffset", name = "Pressed offset", editor = "number", default = 1, }, |
|
}, |
|
|
|
Background = RGBA(255, 255, 255, 255), |
|
FocusedBackground = RGBA(255, 255, 255, 255), |
|
MouseCursor = "CommonAssets/UI/HandCursor.tga", |
|
state = "mouse-out", |
|
ChildrenHandleMouse = false, |
|
RolloverOnFocus = true, |
|
action = false, |
|
touch_press_dist = 20*20, |
|
|
|
AltPressButton = "ButtonX", |
|
AltPressButtonUp = "-ButtonX", |
|
AltPressButtonDown = "+ButtonX", |
|
} |
|
|
|
function XButton:Open(...) |
|
local host = GetActionsHost(self, true) |
|
if not self.action and self.OnPressEffect == "action" then |
|
self.action = host and host:ActionById(self.OnPressParam) or nil |
|
end |
|
if self:IsActionDisabled(host) then |
|
self:SetEnabled(false) |
|
end |
|
if self.action and self.action.ActionGamepadHold and self.action.ActionGamepad then |
|
host.action_hold_buttons = host.action_hold_buttons or {} |
|
host.action_hold_buttons[self.action.ActionId] = self |
|
end |
|
|
|
if self.action and self.action.OnAltAction then |
|
self.AltPress = true |
|
end |
|
XContextControl.Open(self, ...) |
|
end |
|
|
|
function XButton:IsActionDisabled(host, ...) |
|
return self.action and self.action:ActionState(host, ...) == "disabled" |
|
end |
|
|
|
function XButton:Press(alt, force, gamepad) |
|
if alt and not self.AltPress then return end |
|
self:PlayActionFX(force) |
|
if not self.enabled and not force then |
|
return |
|
end |
|
if alt then |
|
self:OnAltPress(gamepad) |
|
else |
|
self:OnPress(gamepad) |
|
end |
|
if self.window_state ~= "destroying" then |
|
local host = GetActionsHost(self, true) |
|
if self:IsActionDisabled(host) then |
|
self:SetEnabled(false) |
|
end |
|
end |
|
end |
|
|
|
function XButton:OnPress(gamepad) |
|
local effect = self.OnPressEffect |
|
if effect == "close" then |
|
local win = self.parent |
|
while win and not win:IsKindOf("XDialog") do |
|
win = win.parent |
|
end |
|
if win then |
|
win:Close(self.OnPressParam ~= "" and self.OnPressParam or nil) |
|
end |
|
elseif self.action then |
|
local host = GetActionsHost(self, true) |
|
if host then |
|
host:OnAction(self.action, self, gamepad) |
|
end |
|
end |
|
end |
|
|
|
function XButton:OnAltPress(gamepad) |
|
if self.action and self.action.OnAltAction then |
|
local host = GetActionsHost(self, true) |
|
if host then |
|
self.action:OnAltAction(host, self, gamepad) |
|
end |
|
end |
|
end |
|
|
|
function XButton:OnButtonDown(alt, mouse) |
|
if alt and not self.AltPress then return end |
|
if not self.enabled then |
|
self:Press(alt, nil, not mouse) |
|
return "break" |
|
end |
|
if self.state == "mouse-in" or self.state == "mouse-out" then |
|
self.state = "pressed-in" |
|
if mouse then |
|
self.desktop:SetMouseCapture(self) |
|
end |
|
self:Invalidate() |
|
if self.RepeatStart > 0 then |
|
self:DeleteThread("repeat") |
|
self:CreateThread("repeat", function(self, alt) |
|
Sleep(self.RepeatStart) |
|
while self.state == "pressed-in" or self.state == "pressed-out" do |
|
self:Press(alt, nil, not mouse) |
|
Sleep(self.RepeatInterval) |
|
end |
|
end, self, alt) |
|
end |
|
end |
|
return "break" |
|
end |
|
|
|
function XButton:OnButtonUp(alt, mouse) |
|
if alt and not self.AltPress then return end |
|
if self.state == "pressed-in" then |
|
self.state = "mouse-in" |
|
self:Invalidate() |
|
if mouse then |
|
self.desktop:SetMouseCapture() |
|
end |
|
self:Press(alt, nil, not mouse) |
|
elseif self.state == "pressed-out" then |
|
self.state = "mouse-out" |
|
self:Invalidate() |
|
if mouse then |
|
self.desktop:SetMouseCapture() |
|
end |
|
end |
|
return "break" |
|
end |
|
|
|
function XButton:OnMouseButtonDown(pt, button) |
|
if button == "L" then |
|
return self:OnButtonDown(false, true) |
|
elseif button == "R" then |
|
return self:OnButtonDown(true, true) |
|
end |
|
end |
|
|
|
function XButton:OnMouseButtonUp(pt, button) |
|
if button == "L" then |
|
return self:OnButtonUp(false, true) |
|
elseif button == "R" then |
|
return self:OnButtonUp(true, true) |
|
end |
|
end |
|
|
|
function XButton:OnSetRollover(rollover) |
|
XControl.OnSetRollover(self, rollover) |
|
if rollover then |
|
if self.state == "mouse-out" then |
|
self.state = "mouse-in" |
|
elseif self.state == "pressed-out" then |
|
self.state = "pressed-in" |
|
end |
|
else |
|
if self.state == "mouse-in" then |
|
self.state = "mouse-out" |
|
elseif self.state == "pressed-in" then |
|
self.state = "pressed-out" |
|
end |
|
end |
|
self:Invalidate() |
|
end |
|
|
|
function XButton:OnCaptureLost() |
|
if self.state == "pressed-in" then |
|
self.state = "mouse-in" |
|
elseif self.state == "pressed-out" then |
|
self.state = "mouse-out" |
|
end |
|
self:Invalidate() |
|
end |
|
|
|
|
|
function XButton:OnTouchBegan(id, pos, touch) |
|
if self.state == "mouse-in" or self.state == "mouse-out" then |
|
touch.start_pos = pos |
|
touch.start_time = RealTime() |
|
self.state = "pressed-out" |
|
self:OnTouchMoved(id, pos, touch) |
|
return "capture" |
|
end |
|
end |
|
|
|
function XButton:OnTouchMoved(id, pos, touch) |
|
if touch.capture == self then |
|
local dist_diff = pos:Dist2D2(touch.start_pos) |
|
if dist_diff > self.touch_press_dist then |
|
|
|
local scroll_area = GetParentOfKind(self, "XScrollArea") |
|
if scroll_area then |
|
self:OnTouchCancelled(id, pos, touch) |
|
touch.capture = nil |
|
touch.target = scroll_area |
|
return scroll_area:OnTouchBegan(id, pos, touch) |
|
end |
|
end |
|
if self.state == "pressed-in" and not self:PointInWindow(pos) then |
|
self.state = "pressed-out" |
|
self:Invalidate() |
|
self:PlayHoverFX(false) |
|
elseif self.state == "pressed-out" and self:PointInWindow(pos) then |
|
self.state = "pressed-in" |
|
self:Invalidate() |
|
self:PlayHoverFX(true) |
|
end |
|
return "break" |
|
end |
|
end |
|
|
|
function XButton:OnTouchEnded(id, pos, touch) |
|
self:OnTouchMoved(id, pos, touch) |
|
if self.state == "pressed-in" then |
|
self:Press(false) |
|
end |
|
return self:OnTouchCancelled(id, pos, touch) |
|
end |
|
|
|
function XButton:OnTouchCancelled(id, pos, touch) |
|
if self.state ~= "mouse-out" then |
|
if self.state == "pressed-in" then |
|
self:PlayHoverFX(false) |
|
end |
|
self.state = "mouse-out" |
|
self:Invalidate() |
|
return "break" |
|
end |
|
end |
|
|
|
function XButton:OnShortcut(shortcut, source, ...) |
|
if shortcut == "Enter" or shortcut == "Space" or shortcut == "ButtonA" then |
|
self:Press(false) |
|
return "break" |
|
elseif self.AltPress and (shortcut == "Alt-Enter" or shortcut == "Alt-Space" or shortcut == self.AltPressButton) then |
|
self:Press(true) |
|
return "break" |
|
elseif shortcut == "+ButtonA" then |
|
return self:OnButtonDown(false) |
|
elseif shortcut == self.AltPressButtonDown then |
|
return self:OnButtonDown(true) |
|
elseif shortcut == "-ButtonA" then |
|
return self:OnButtonUp(false) |
|
elseif shortcut == self.AltPressButtonUp then |
|
return self:OnButtonUp(true) |
|
end |
|
end |
|
|
|
function XButton:CalcBackground() |
|
if not self.enabled then return self.DisabledBackground end |
|
if self.state == "pressed-in" or self.state == "pressed-out" then |
|
return self.PressedBackground |
|
end |
|
if self.state == "mouse-in" then |
|
return self.RolloverBackground |
|
end |
|
local FocusedBackground, Background = self.FocusedBackground, self.Background |
|
if FocusedBackground == Background then return Background end |
|
return self:IsFocused() and FocusedBackground or Background |
|
end |
|
|
|
function XButton:CalcBorderColor() |
|
if not self.enabled then return self.DisabledBorderColor end |
|
if self.state == "pressed-in" or self.state == "pressed-out" then |
|
return self.PressedBorderColor |
|
end |
|
if self.state == "mouse-in" then |
|
return self.RolloverBorderColor |
|
end |
|
local FocusedBorderColor, BorderColor = self.FocusedBorderColor, self.BorderColor |
|
if FocusedBorderColor == BorderColor then return BorderColor end |
|
return self:IsFocused() and FocusedBorderColor or BorderColor |
|
end |
|
|
|
function XButton:GetRolloverTemplate() |
|
local template = self.RolloverTemplate |
|
if template ~= "" then return template end |
|
local action = self.action |
|
return action and action:GetRolloverTemplate() or "" |
|
end |
|
|
|
function XButton:GetRolloverText() |
|
local enabled = self:GetEnabled() |
|
local text = not enabled and self.RolloverDisabledText ~= "" and self.RolloverDisabledText or self.RolloverText |
|
if text ~= "" then return text end |
|
local action = self.action |
|
local disabled_text = action and action:GetRolloverDisabledText() |
|
return action and (not enabled and disabled_text ~= "" and disabled_text or action:GetRolloverText()) or "" |
|
end |
|
|
|
function OnMsg.ClassesPostprocess() |
|
if not config.GamepadAltPressUseButtonY then return end |
|
ClassDescendants("XButton", function(class_name, class) |
|
class.AltPressButton = "ButtonY" |
|
class.AltPressButtonUp = "-ButtonY" |
|
class.AltPressButtonDown = "+ButtonY" |
|
end) |
|
XButton.AltPressButton = "ButtonY" |
|
XButton.AltPressButtonUp = "-ButtonY" |
|
XButton.AltPressButtonDown = "+ButtonY" |
|
end |
|
|
|
|
|
|
|
DefineClass.XTextButton = { |
|
__parents = { "XButton", "XFrame", "XEmbedIcon", "XEmbedLabel" }, |
|
properties = { |
|
{ category = "Image", id = "ColumnsUse", editor = "text", default = "aaaaa", }, |
|
{ category = "Image", id = "ShowGamepadShortcut", editor = "bool", default = false, }, |
|
{ category = "Visual", id = "ShowKeyboardShortcut", editor = "bool", default = false, }, |
|
{ category = "Visual", id = "KeyboardShortcutTextStyle", editor = "text", default = "", }, |
|
}, |
|
ContextUpdateOnOpen = true, |
|
LayoutMethod = "HList", |
|
LayoutHSpacing = 2, |
|
HandleMouse = true, |
|
SqueezeX = false, |
|
SqueezeY = false, |
|
} |
|
|
|
function XTextButton:Init() |
|
self.idLabel:SetHAlign("center") |
|
self:SetColumnsUse(self.ColumnsUse) |
|
end |
|
|
|
function XTextButton:OnHoldButtonTick(i, shortcut) |
|
if not self.action or not self.action.ActionGamepadHold then return end |
|
self.idHoldShortcut:SetVisible(not not i) |
|
|
|
if i then |
|
self.idHoldShortcut:SetImage("UI/DesktopGamepad/hold" .. i) |
|
end |
|
end |
|
|
|
function XTextButton:Open() |
|
XButton.Open(self) |
|
local action = self.action |
|
if action then |
|
local action_ui_style = action.ActionUIStyle |
|
if self.ShowGamepadShortcut and (action_ui_style == "auto" and GetUIStyleGamepad() or action_ui_style == "gamepad") and action.ActionGamepad ~= "" then |
|
local keys = SplitShortcut(action.ActionGamepad) |
|
for i = 1, #keys do |
|
local image_path, scale = GetPlatformSpecificImagePath(keys[i]) |
|
local img = XImage:new({ |
|
Id = "idActionShortcut", |
|
Image = image_path, |
|
ZOrder = 0, |
|
ImageScale = point(scale, scale), |
|
enabled = self.enabled, |
|
}, self) |
|
if action.ActionGamepadHold then |
|
local over_img = XImage:new({ |
|
Id = "idHoldShortcut", |
|
Image = "UI/DesktopGamepad/hold0", |
|
ZOrder = 0, |
|
ImageScale = point(scale, scale), |
|
enabled = self.enabled, |
|
}, self) |
|
end |
|
img:Open() |
|
if action.ActionGamepadHold then |
|
over_img:Open() |
|
end |
|
end |
|
elseif self.ShowKeyboardShortcut and (action_ui_style == "auto" and not GetUIStyleGamepad() or action_ui_style == "keyboard") and action.ActionShortcut ~= "" then |
|
local label = XLabel:new({ |
|
Id = "idActionShortcut", |
|
ZOrder = 0, |
|
TextStyle = self.KeyboardShortcutTextStyle ~= "" and self.KeyboardShortcutTextStyle or self.TextStyle, |
|
VAlign = "center", |
|
Translate = true, |
|
enabled = self.enabled, |
|
}, self):Open() |
|
local name = KeyNames[VKStrNamesInverse[action.ActionShortcut]] |
|
label:SetText(T{629765447024, "<name>", name = name}) |
|
end |
|
end |
|
end |
|
|
|
function XTextButton:SetText(text) |
|
self.Text = text |
|
local label = self:ResolveId("idLabel") |
|
if label then |
|
label:SetDock(text == "" and "ignore" or false) |
|
label:SetText(text) |
|
end |
|
end |
|
|
|
local a_charcode = string.byte("a") |
|
function XTextButton:SetColumnsUse(columns_use) |
|
local max = 1 |
|
for i = 1, #columns_use do |
|
max = Max(max, string.byte(columns_use, i)) |
|
end |
|
self.ColumnsUse = columns_use |
|
self.Columns = max - a_charcode + 1 |
|
self:Invalidate() |
|
end |
|
|
|
function XTextButton:SetColumn() |
|
assert(false) |
|
end |
|
|
|
function XTextButton:SetRollover(rollover) |
|
XButton.SetRollover(self, rollover) |
|
local label = self:ResolveId("idLabel") |
|
if label then |
|
label:SetRollover(rollover) |
|
end |
|
end |
|
|
|
function XTextButton:OnSetRollover(rollover) |
|
XButton.OnSetRollover(self, rollover) |
|
end |
|
|
|
local state_to_column = { |
|
["mouse-out" ] = 1, |
|
["mouse-in" ] = 2, |
|
["pressed-out"] = 3, |
|
["pressed-in" ] = 4, |
|
["disabled" ] = 5, |
|
} |
|
|
|
function XTextButton:GetColumn() |
|
local column = state_to_column[self.enabled and self.state or "disabled"] |
|
return (string.byte(self.ColumnsUse, column) or a_charcode) - a_charcode + 1 |
|
end |
|
|
|
do |
|
local columns_use_prop = table.find_value(XTextButton.properties, "id", "ColumnsUse") |
|
local column_to_state = table.invert(state_to_column) |
|
columns_use_prop.help = "" |
|
for i=1,#column_to_state do |
|
columns_use_prop.help = string.format("%s%d - %s\n", columns_use_prop.help, i, column_to_state[i]) |
|
end |
|
end |
|
|
|
|
|
|
|
DefineClass.XStateButton = { |
|
__parents = { "XTextButton" }, |
|
TextColor = RGB(32, 32, 32), |
|
IconColor = RGB(32, 32, 32), |
|
DisabledTextColor = RGBA(32, 32, 32, 128), |
|
DisabledIconColor = RGBA(32, 32, 32, 128), |
|
Icon = "CommonAssets/UI/check-40.tga", |
|
IconScale = point(480, 480), |
|
IconRows = 2, |
|
} |
|
|
|
function XStateButton:OnRowChange(row) |
|
end |
|
|
|
function XStateButton:OnPress() |
|
local row = self.IconRow + 1 |
|
if row > self.IconRows then |
|
row = 1 |
|
end |
|
self:SetIconRow(row) |
|
self:OnRowChange(row) |
|
XTextButton.OnPress(self) |
|
end |
|
|
|
|
|
|
|
|
|
DefineClass.XCheckButton = { |
|
__parents = { "XStateButton" }, |
|
properties = { |
|
{ category = "General", id = "Check", editor = "bool", default = false, }, |
|
{ category = "General", id = "OnChange", name = "On change", editor = "func", params = "self, check" }, |
|
}, |
|
Background = RGBA(0, 0, 0, 0), |
|
RolloverBackground = RGBA(0, 0, 0, 0), |
|
FocusedBackground = RGBA(0, 0, 0, 0), |
|
PressedBackground = RGBA(0, 0, 0, 0), |
|
} |
|
|
|
function XCheckButton:SetCheck(check) |
|
self:SetIconRow(check and 2 or 1) |
|
end |
|
|
|
function XCheckButton:GetCheck() |
|
return self.IconRow ~= 1 |
|
end |
|
|
|
XCheckButton.SetToggled = XCheckButton.SetCheck |
|
|
|
function XCheckButton:OnChange(check) |
|
end |
|
|
|
function XCheckButton:OnRowChange(state) |
|
self:OnChange(state ~= 1) |
|
end |
|
|
|
|
|
|
|
|
|
DefineClass.XToggleButton = { |
|
__parents = { "XTextButton" }, |
|
|
|
properties = { |
|
{ category = "General", id = "Toggled", editor = "bool", default = false, }, |
|
{ category = "General", id = "OnChange", name = "On change", editor = "func", params = "self, toggled" }, |
|
{ category = "Visual", id = "ToggledBackground", name = "Toggled background", editor = "color", default = RGBA(0, 0, 0, 0), }, |
|
{ category = "Visual", id = "ToggledBorderColor", name = "Toggled border color", editor = "color", default = RGBA(0, 0, 0, 0), }, |
|
}, |
|
} |
|
|
|
function XToggleButton:OnPress() |
|
self:SetToggled(not self.Toggled) |
|
XTextButton.OnPress(self) |
|
end |
|
|
|
function XToggleButton:SetToggled(toggled) |
|
toggled = toggled or false |
|
if self.Toggled ~= toggled then |
|
self.Toggled = toggled |
|
self:OnChange(self.Toggled) |
|
self:Invalidate() |
|
end |
|
end |
|
|
|
function XToggleButton:OnChange(toggled) |
|
end |
|
|
|
function XToggleButton:CalcBackground() |
|
return self.Toggled and self.ToggledBackground or XTextButton.CalcBackground(self) |
|
end |
|
|
|
function XToggleButton:CalcBorderColor() |
|
return self.Toggled and self.ToggledBorderColor or XTextButton.CalcBorderColor(self) |
|
end |
|
|