ee0b350aba
- Dungeon followers now correctly show into the damage done section. - Fixed an error while statusbar plugin options. - Framework update. - Mythic Dungeon Plus code has been separated into six files (was just 2), this will help with the organization and maintenance of the code.
1017 lines
38 KiB
Lua
1017 lines
38 KiB
Lua
|
|
local detailsFramework = _G["DetailsFramework"]
|
|
if (not detailsFramework or not DetailsFrameworkCanLoad) then
|
|
return
|
|
end
|
|
|
|
---@cast detailsFramework detailsframework
|
|
|
|
local CreateFrame = CreateFrame
|
|
local unpack = unpack
|
|
local wipe = table.wipe
|
|
local _
|
|
|
|
--[=[
|
|
file description: this file has the code for the object editor
|
|
the object editor itself is a frame and has a scrollframe as canvas showing another frame where there's the options for the editing object
|
|
|
|
--]=]
|
|
|
|
|
|
--the editor doesn't know which key in the profileTable holds the current value for an attribute, so it uses a map table to find it.
|
|
--the mapTable is a table with the attribute name as a key, and the value is the profile key. For example, {["size"] = "text_size"} means profileTable["text_size"] = 10.
|
|
|
|
---@class df_editor : frame, df_optionsmixin, df_editormixin
|
|
---@field options table
|
|
---@field registeredObjects df_editor_objectinfo[]
|
|
---@field registeredObjectsByID table<any, df_editor_objectinfo>
|
|
---@field editingObject uiobject
|
|
---@field editingProfileTable table
|
|
---@field editingProfileMap table
|
|
---@field editingOptions df_editobjectoptions
|
|
---@field editingExtraOptions table
|
|
---@field moverGuideLines table<string, texture>
|
|
---@field onEditCallback function
|
|
---@field optionsFrame frame
|
|
---@field overTheTopFrame frame
|
|
---@field objectSelector df_scrollbox
|
|
---@field moverFrame frame
|
|
---@field canvasScrollBox df_canvasscrollbox
|
|
|
|
---@class df_editor_attribute
|
|
---@field key string?
|
|
---@field label string?
|
|
---@field widget string
|
|
---@field default any?
|
|
---@field minvalue number?
|
|
---@field maxvalue number?
|
|
---@field step number?
|
|
---@field usedecimals boolean?
|
|
---@field subkey string?
|
|
|
|
---@class df_editor_objectinfo : table
|
|
---@field object uiobject
|
|
---@field label string
|
|
---@field id any
|
|
---@field profiletable table
|
|
---@field profilekeymap table
|
|
---@field subtablepath string?
|
|
---@field extraoptions table
|
|
---@field callback function?
|
|
---@field options df_editobjectoptions
|
|
---@field selectButton button
|
|
|
|
--which object attributes are used to build the editor menu for each object type
|
|
local attributes = {
|
|
---@type df_editor_attribute[]
|
|
FontString = {
|
|
{
|
|
key = "text",
|
|
label = "Text",
|
|
widget = "textentry",
|
|
default = "font string text",
|
|
setter = function(widget, value) widget:SetText(value) end,
|
|
},
|
|
{
|
|
key = "size",
|
|
label = "Size",
|
|
widget = "range",
|
|
minvalue = 5,
|
|
maxvalue = 120,
|
|
setter = function(widget, value) widget:SetFont(widget:GetFont(), value, select(3, widget:GetFont())) end
|
|
},
|
|
{
|
|
key = "font",
|
|
label = "Font",
|
|
widget = "fontdropdown",
|
|
setter = function(widget, value)
|
|
local font = LibStub:GetLibrary("LibSharedMedia-3.0"):Fetch("font", value)
|
|
widget:SetFont(font, select(2, widget:GetFont()))
|
|
end
|
|
},
|
|
{
|
|
key = "color",
|
|
label = "Color",
|
|
widget = "color",
|
|
setter = function(widget, value) widget:SetTextColor(unpack(value)) end
|
|
},
|
|
{
|
|
key = "alpha",
|
|
label = "Alpha",
|
|
widget = "range",
|
|
setter = function(widget, value) widget:SetAlpha(value) end
|
|
},
|
|
{widget = "blank"},
|
|
{
|
|
key = "shadow",
|
|
label = "Draw Shadow",
|
|
widget = "toggle",
|
|
setter = function(widget, value) widget:SetShadowColor(widget:GetShadowColor(), select(2, widget:GetShadowColor()), select(3, widget:GetShadowColor()), value and 0.5 or 0) end
|
|
},
|
|
{
|
|
key = "shadowcolor",
|
|
label = "Shadow Color",
|
|
widget = "color",
|
|
setter = function(widget, value) widget:SetShadowColor(unpack(value)) end
|
|
},
|
|
{
|
|
key = "shadowoffsetx",
|
|
label = "Shadow X Offset",
|
|
widget = "range",
|
|
minvalue = -10,
|
|
maxvalue = 10,
|
|
setter = function(widget, value) widget:SetShadowOffset(value, select(2, widget:GetShadowOffset())) end
|
|
},
|
|
{
|
|
key = "shadowoffsety",
|
|
label = "Shadow Y Offset",
|
|
widget = "range",
|
|
minvalue = -10,
|
|
maxvalue = 10,
|
|
setter = function(widget, value) widget:SetShadowOffset(widget:GetShadowOffset(), value) end
|
|
},
|
|
{
|
|
key = "outline",
|
|
label = "Outline",
|
|
widget = "outlinedropdown",
|
|
setter = function(widget, value) widget:SetFont(widget:GetFont(), select(2, widget:GetFont()), value) end
|
|
},
|
|
{widget = "blank"},
|
|
{
|
|
key = "anchor",
|
|
label = "Anchor",
|
|
widget = "anchordropdown",
|
|
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
|
},
|
|
{
|
|
key = "anchoroffsetx",
|
|
label = "Anchor X Offset",
|
|
widget = "range",
|
|
minvalue = -100,
|
|
maxvalue = 100,
|
|
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
|
},
|
|
{
|
|
key = "anchoroffsety",
|
|
label = "Anchor Y Offset",
|
|
widget = "range",
|
|
minvalue = -100,
|
|
maxvalue = 100,
|
|
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
|
},
|
|
{
|
|
key = "rotation",
|
|
label = "Rotation",
|
|
widget = "range",
|
|
usedecimals = true,
|
|
minvalue = 0,
|
|
maxvalue = math.pi*2,
|
|
setter = function(widget, value) widget:SetRotation(value) end
|
|
},
|
|
{
|
|
key = "scale",
|
|
label = "Scale",
|
|
widget = "range",
|
|
usedecimals = true,
|
|
minvalue = 0.65,
|
|
maxvalue = 2.5,
|
|
setter = function(widget, value) widget:SetScale(value) end
|
|
},
|
|
}
|
|
}
|
|
|
|
---@class df_editormixin : table
|
|
---@field GetAllRegisteredObjects fun(self:df_editor):df_editor_objectinfo[]
|
|
---@field GetEditingObject fun(self:df_editor):uiobject
|
|
---@field GetEditingOptions fun(self:df_editor):df_editobjectoptions
|
|
---@field GetExtraOptions fun(self:df_editor):table
|
|
---@field GetEditingProfile fun(self:df_editor):table, table
|
|
---@field GetOnEditCallback fun(self:df_editor):function
|
|
---@field GetOptionsFrame fun(self:df_editor):frame
|
|
---@field GetCanvasScrollBox fun(self:df_editor):df_canvasscrollbox
|
|
---@field GetObjectSelector fun(self:df_editor):df_scrollbox
|
|
---@field EditObject fun(self:df_editor, object:uiobject, profileTable:table?, profileKeyMap:table?, extraOptions:table?, callback:function?, options:df_editobjectoptions?)
|
|
---@field PrepareObjectForEditing fun(self:df_editor)
|
|
---@field CreateMoverGuideLines fun(self:df_editor)
|
|
---@field GetOverTheTopFrame fun(self:df_editor):frame
|
|
---@field GetMoverFrame fun(self:df_editor):frame
|
|
---@field StartObjectMovement fun(self:df_editor, anchorSettings:df_anchor)
|
|
---@field StopObjectMovement fun(self:df_editor)
|
|
---@field RegisterObject fun(self:df_editor, object:uiobject, localizedLabel:string, id:any, profileTable:table, subTablePath:string, profileKeyMap:table, extraOptions:table?, callback:function?, options:df_editobjectoptions?):df_editor_objectinfo
|
|
---@field UnregisterObject fun(self:df_editor, object:uiobject)
|
|
---@field EditObjectById fun(self:df_editor, id:any)
|
|
---@field EditObjectByIndex fun(self:df_editor, index:number)
|
|
---@field UpdateGuideLinesAnchors fun(self:df_editor)
|
|
---@field GetObjectByRef fun(self:df_editor, object:uiobject):df_editor_objectinfo
|
|
---@field GetObjectByIndex fun(self:df_editor, index:number):df_editor_objectinfo
|
|
---@field GetObjectById fun(self:df_editor, id:any):df_editor_objectinfo
|
|
---@field CreateObjectSelectionList fun(self:df_editor, scroll_width:number, scroll_height:number, scroll_lines:number, scroll_line_height:number):df_scrollbox
|
|
---@field OnHide fun(self:df_editor)
|
|
---@field UpdateProfileTableOnAllRegisteredObjects fun(self:df_editor, profileTable:table)
|
|
---@field GetProfileTableFromObject fun(self:df_editor, object:df_editor_objectinfo):table
|
|
|
|
---@class df_editobjectoptions : table
|
|
---@field use_colon boolean if true a colon is shown after the option name
|
|
---@field can_move boolean if true the object can be moved
|
|
---@field use_guide_lines boolean if true guide lines are shown when the object is being moved
|
|
---@field text_template table
|
|
|
|
---@type df_editobjectoptions
|
|
local editObjectDefaultOptions = {
|
|
use_colon = false,
|
|
can_move = true,
|
|
use_guide_lines = true,
|
|
text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE"),
|
|
}
|
|
|
|
local getParentTable = function(profileTable, profileKey)
|
|
local parentPath
|
|
if (profileKey:match("%]$")) then
|
|
parentPath = profileKey:gsub("%s*%[.*%]%s*$", "")
|
|
else
|
|
parentPath = profileKey:gsub("%.[^.]*$", "")
|
|
end
|
|
|
|
local parentTable = detailsFramework.table.getfrompath(profileTable, parentPath)
|
|
return parentTable
|
|
end
|
|
|
|
detailsFramework.EditorMixin = {
|
|
---@param self df_editor
|
|
GetEditingObject = function(self)
|
|
return self.editingObject
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@return df_editobjectoptions
|
|
GetEditingOptions = function(self)
|
|
return self.editingOptions
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@return table
|
|
GetExtraOptions = function(self)
|
|
return self.editingExtraOptions
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@return table, table
|
|
GetEditingProfile = function(self)
|
|
return self.editingProfileTable, self.editingProfileMap
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@return function
|
|
GetOnEditCallback = function(self)
|
|
return self.onEditCallback
|
|
end,
|
|
|
|
GetOptionsFrame = function(self)
|
|
return self.optionsFrame
|
|
end,
|
|
|
|
GetOverTheTopFrame = function(self)
|
|
return self.overTheTopFrame
|
|
end,
|
|
|
|
GetMoverFrame = function(self)
|
|
return self.moverFrame
|
|
end,
|
|
|
|
GetCanvasScrollBox = function(self)
|
|
return self.canvasScrollBox
|
|
end,
|
|
|
|
GetObjectSelector = function(self)
|
|
return self.objectSelector
|
|
end,
|
|
|
|
EditObjectById = function(self, id)
|
|
---@type df_editor_objectinfo
|
|
local objectRegistered = self:GetObjectById(id)
|
|
assert(type(objectRegistered) == "table", "EditObjectById() object not found.")
|
|
self:EditObject(objectRegistered)
|
|
end,
|
|
|
|
EditObjectByIndex = function(self, index)
|
|
---@type df_editor_objectinfo
|
|
local objectRegistered = self:GetObjectByIndex(index)
|
|
assert(type(objectRegistered) == "table", "EditObjectById() object not found.")
|
|
self:EditObject(objectRegistered)
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@param registeredObject df_editor_objectinfo
|
|
EditObject = function(self, registeredObject)
|
|
--clear previous values
|
|
self.editingObject = nil
|
|
self.editingProfileMap = nil
|
|
self.editingProfileTable = nil
|
|
self.editingOptions = nil
|
|
self.editingExtraOptions = nil
|
|
self.onEditCallback = nil
|
|
|
|
local object = registeredObject.object
|
|
local profileKeyMap = registeredObject.profilekeymap
|
|
local extraOptions = registeredObject.extraoptions
|
|
local callback = registeredObject.callback
|
|
local options = registeredObject.options
|
|
|
|
local profileTable = self:GetProfileTableFromObject(registeredObject)
|
|
assert(type(profileTable) == "table", "EditObject() profileTable is invalid.")
|
|
|
|
--as there's no other place which this members are set, there is no need to create setter functions
|
|
self.editingObject = object
|
|
self.editingProfileMap = profileKeyMap
|
|
self.editingProfileTable = profileTable
|
|
self.editingOptions = options
|
|
self.editingExtraOptions = extraOptions
|
|
|
|
if (type(callback) == "function") then
|
|
self.onEditCallback = callback
|
|
end
|
|
|
|
self:PrepareObjectForEditing()
|
|
end,
|
|
|
|
---@param self df_editor
|
|
CreateMoverGuideLines = function(self)
|
|
local overTheTopFrame = self:GetOverTheTopFrame()
|
|
local moverFrame = self:GetMoverFrame()
|
|
|
|
self.moverGuideLines = {
|
|
left = overTheTopFrame:CreateTexture(nil, "overlay"),
|
|
right = overTheTopFrame:CreateTexture(nil, "overlay"),
|
|
top = overTheTopFrame:CreateTexture(nil, "overlay"),
|
|
bottom = overTheTopFrame:CreateTexture(nil, "overlay"),
|
|
}
|
|
|
|
for side, texture in pairs(self.moverGuideLines) do
|
|
texture:SetColorTexture(.8, .8, .8, 0.1)
|
|
texture:SetSize(1, 1)
|
|
texture:SetDrawLayer("overlay", 7)
|
|
texture:Hide()
|
|
|
|
if (side == "left" or side == "right") then
|
|
texture:SetHeight(1)
|
|
texture:SetWidth(GetScreenWidth())
|
|
else
|
|
texture:SetWidth(1)
|
|
texture:SetHeight(GetScreenHeight())
|
|
end
|
|
end
|
|
end,
|
|
|
|
UpdateGuideLinesAnchors = function(self)
|
|
local object = self:GetEditingObject()
|
|
|
|
for side, texture in pairs(self.moverGuideLines) do
|
|
texture:ClearAllPoints()
|
|
if (side == "left" or side == "right") then
|
|
if (side == "left") then
|
|
texture:SetPoint("right", object, "left", -2, 0)
|
|
else
|
|
texture:SetPoint("left", object, "right", 2, 0)
|
|
end
|
|
else
|
|
if (side == "top") then
|
|
texture:SetPoint("bottom", object, "top", 0, 2)
|
|
else
|
|
texture:SetPoint("top", object, "bottom", 0, -2)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
|
|
PrepareObjectForEditing = function(self) --~edit
|
|
--get the object and its profile table with the current values
|
|
local object = self:GetEditingObject()
|
|
local profileTable, profileMap = self:GetEditingProfile()
|
|
profileMap = profileMap or {}
|
|
|
|
if (not object or not profileTable) then
|
|
return
|
|
end
|
|
|
|
--get the object type
|
|
local objectType = object:GetObjectType()
|
|
local attributeList
|
|
|
|
--get options and extra options
|
|
local editingOptions = self:GetEditingOptions()
|
|
local extraOptions = self:GetExtraOptions()
|
|
|
|
--get the attribute list for the object type
|
|
if (objectType == "FontString") then
|
|
---@cast object fontstring
|
|
attributeList = attributes[objectType]
|
|
end
|
|
|
|
--if there's extra options, add the attributeList to a new table and right after the extra options
|
|
if (extraOptions and #extraOptions > 0) then
|
|
local attributeListWithExtraOptions = {}
|
|
|
|
for i = 1, #attributeList do
|
|
attributeListWithExtraOptions[#attributeListWithExtraOptions+1] = attributeList[i]
|
|
end
|
|
|
|
attributeListWithExtraOptions[#attributeListWithExtraOptions+1] = {widget = "blank", default = true}
|
|
|
|
for i = 1, #extraOptions do
|
|
attributeListWithExtraOptions[#attributeListWithExtraOptions+1] = extraOptions[i]
|
|
end
|
|
|
|
attributeList = attributeListWithExtraOptions
|
|
end
|
|
|
|
local anchorSettings
|
|
|
|
--table to use on DF:BuildMenuVolatile()
|
|
local menuOptions = {}
|
|
for i = 1, #attributeList do
|
|
local option = attributeList[i]
|
|
|
|
if (option.widget == "blank") then
|
|
menuOptions[#menuOptions+1] = {type = "blank"}
|
|
else
|
|
--get the key to be used on profile table
|
|
local profileKey = profileMap[option.key]
|
|
local value
|
|
|
|
--if the key contains a dot or a bracket, it means it's a table path, example: "text_settings[1].width"
|
|
if (profileKey and (profileKey:match("%.") or profileKey:match("%["))) then
|
|
value = detailsFramework.table.getfrompath(profileTable, profileKey)
|
|
else
|
|
value = profileTable[profileKey]
|
|
end
|
|
|
|
--if no value is found, attempt to get a default
|
|
if (type(value) == "nil") then
|
|
value = option.default
|
|
end
|
|
|
|
local bHasValue = type(value) ~= "nil"
|
|
|
|
local minValue = option.minvalue
|
|
local maxValue = option.maxvalue
|
|
|
|
if (option.key == "anchoroffsetx") then
|
|
minValue = -object:GetParent():GetWidth()/2
|
|
maxValue = object:GetParent():GetWidth()/2
|
|
elseif (option.key == "anchoroffsety") then
|
|
minValue = -object:GetParent():GetHeight()/2
|
|
maxValue = object:GetParent():GetHeight()/2
|
|
end
|
|
|
|
if (bHasValue) then
|
|
local parentTable = getParentTable(profileTable, profileKey)
|
|
|
|
if (option.key == "anchor" or option.key == "anchoroffsetx" or option.key == "anchoroffsety") then
|
|
anchorSettings = parentTable
|
|
end
|
|
|
|
menuOptions[#menuOptions+1] = {
|
|
type = option.widget,
|
|
name = option.label,
|
|
get = function() return value end,
|
|
set = function(widget, fixedValue, newValue, ...)
|
|
--color is a table with 4 indexes for each color plus alpha
|
|
if (option.widget == "range" or option.widget == "slider") then
|
|
if (not option.usedecimals) then
|
|
newValue = math.floor(newValue)
|
|
end
|
|
|
|
elseif (option.widget == "color") then
|
|
--calor callback sends the red color in the fixedParameter slot
|
|
local r, g, b, alpha = fixedValue, newValue, ...
|
|
--need to use the same table from the profile table
|
|
parentTable[1] = r
|
|
parentTable[2] = g
|
|
parentTable[3] = b
|
|
parentTable[4] = alpha
|
|
|
|
newValue = parentTable
|
|
end
|
|
|
|
detailsFramework.table.setfrompath(profileTable, profileKey, newValue)
|
|
|
|
if (self:GetOnEditCallback()) then
|
|
self:GetOnEditCallback()(object, option.key, newValue, profileTable, profileKey)
|
|
end
|
|
|
|
--update the widget visual
|
|
--anchoring uses SetAnchor() which require the anchorTable to be passed
|
|
if (option.key == "anchor" or option.key == "anchoroffsetx" or option.key == "anchoroffsety") then
|
|
anchorSettings = parentTable
|
|
|
|
if (option.key == "anchor") then
|
|
anchorSettings.x = 0
|
|
anchorSettings.y = 0
|
|
end
|
|
|
|
self:StopObjectMovement()
|
|
|
|
option.setter(object, parentTable)
|
|
|
|
if (editingOptions.can_move) then
|
|
self:StartObjectMovement(anchorSettings)
|
|
end
|
|
else
|
|
option.setter(object, newValue)
|
|
end
|
|
end,
|
|
min = minValue,
|
|
max = maxValue,
|
|
step = option.step,
|
|
usedecimals = option.usedecimals,
|
|
id = option.key,
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
--at this point, the optionsTable is ready to be used on DF:BuildMenuVolatile()
|
|
menuOptions.align_as_pairs = true
|
|
menuOptions.align_as_pairs_length = 150
|
|
menuOptions.widget_width = 180
|
|
menuOptions.slider_buttons_to_left = true
|
|
|
|
local optionsFrame = self:GetOptionsFrame()
|
|
local canvasScrollBox = self:GetCanvasScrollBox()
|
|
|
|
local bUseColon = editingOptions.use_colon
|
|
|
|
local bSwitchIsCheckbox = true
|
|
local maxHeight = 5000
|
|
|
|
local amountOfOptions = #menuOptions
|
|
local optionsFrameHeight = amountOfOptions * 20
|
|
optionsFrame:SetHeight(optionsFrameHeight)
|
|
|
|
--templates
|
|
local options_text_template = self.options.text_template or detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")
|
|
local options_dropdown_template = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")
|
|
local options_switch_template = detailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_TEMPLATE")
|
|
local options_slider_template = detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE")
|
|
local options_button_template = detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")
|
|
|
|
--~build ~menu ~volatile
|
|
detailsFramework:BuildMenuVolatile(optionsFrame, menuOptions, 2, -2, maxHeight, bUseColon, options_text_template, options_dropdown_template, options_switch_template, bSwitchIsCheckbox, options_slider_template, options_button_template)
|
|
|
|
if (editingOptions.can_move) then
|
|
self:StartObjectMovement(anchorSettings)
|
|
end
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@param anchorSettings df_anchor
|
|
StartObjectMovement = function(self, anchorSettings)
|
|
local object = self:GetEditingObject()
|
|
|
|
local moverFrame = self:GetMoverFrame()
|
|
moverFrame:EnableMouse(true)
|
|
moverFrame:SetMovable(true)
|
|
moverFrame:ClearAllPoints()
|
|
moverFrame:Show()
|
|
|
|
--update guidelines
|
|
if (self:GetEditingOptions().use_guide_lines) then
|
|
--self:UpdateGuideLinesAnchors()
|
|
--show all four guidelines
|
|
for side, texture in pairs(self.moverGuideLines) do
|
|
texture:Show()
|
|
end
|
|
end
|
|
|
|
local optionsFrame = self:GetOptionsFrame()
|
|
|
|
--getting the size this way due to the cascade of different scales that are applyed to unitFrame objects
|
|
moverFrame:ClearAllPoints()
|
|
moverFrame:SetPoint("topleft", object, "topleft", -5, 5)
|
|
moverFrame:SetPoint("bottomright", object, "bottomright", 5, -5)
|
|
local moverWidth, moverHeight = moverFrame:GetSize()
|
|
|
|
local objectWidth, objectHeight = object:GetSize()
|
|
moverFrame:SetSize(moverWidth, moverHeight)
|
|
detailsFramework:SetAnchor(moverFrame, anchorSettings, object:GetParent())
|
|
local currentPosX, currentPosY
|
|
|
|
moverFrame:SetScript("OnMouseDown", function()
|
|
object:ClearAllPoints()
|
|
object:SetPoint("topleft", moverFrame, "topleft", 0, 0)
|
|
|
|
currentPosX, currentPosY = moverFrame:GetCenter()
|
|
moverFrame.bIsMoving = true
|
|
moverFrame:StartMoving()
|
|
end)
|
|
|
|
moverFrame:SetScript("OnMouseUp", function()
|
|
moverFrame:StopMovingOrSizing()
|
|
moverFrame.bIsMoving = false
|
|
|
|
--0.64 UIParent
|
|
--0.96 object
|
|
--local scale = object:GetEffectiveScale() / UIParent:GetEffectiveScale() --1.5
|
|
|
|
local originX = anchorSettings.x
|
|
local originY = anchorSettings.y
|
|
|
|
local newPosX, newPosY = moverFrame:GetCenter()
|
|
|
|
local xOffset = newPosX - currentPosX
|
|
local yOffset = newPosY - currentPosY
|
|
|
|
xOffset = xOffset
|
|
yOffset = yOffset
|
|
|
|
anchorSettings.x = (originX + xOffset)
|
|
anchorSettings.y = (originY + yOffset)
|
|
|
|
local anchorXSlider = optionsFrame:GetWidgetById("anchoroffsetx")
|
|
anchorXSlider:SetValueNoCallback(anchorSettings.x)
|
|
|
|
local anchorYSlider = optionsFrame:GetWidgetById("anchoroffsety")
|
|
anchorYSlider:SetValueNoCallback(anchorSettings.y)
|
|
|
|
object:ClearAllPoints()
|
|
detailsFramework:SetAnchor(object, anchorSettings, object:GetParent())
|
|
|
|
--save the new position
|
|
local profileTable, profileMap = self:GetEditingProfile()
|
|
local profileKey = profileMap.anchor
|
|
local parentTable = getParentTable(profileTable, profileKey)
|
|
parentTable.x = anchorSettings.x
|
|
parentTable.y = anchorSettings.y
|
|
|
|
if (self:GetOnEditCallback()) then
|
|
self:GetOnEditCallback()(object, "x", anchorSettings.x, profileTable, profileKey)
|
|
self:GetOnEditCallback()(object, "y", anchorSettings.x, profileTable, profileKey)
|
|
end
|
|
end)
|
|
|
|
--detailsFramework:SetAnchor(moverFrame, anchorSettings)
|
|
--detailsFramework:SetAnchor(object, anchorSettings, moverFrame)
|
|
|
|
moverFrame:SetScript("OnUpdate", function() --not in use
|
|
--if the object isn't moving, make the mover follow the object position
|
|
if (false and moverFrame.bIsMoving) then
|
|
--object:ClearAllPoints()
|
|
--object:SetPoint("topleft", moverFrame, "topleft", 0, 0)
|
|
|
|
--if the object is moving, check if the moverFrame has moved
|
|
local newPosX, newPosY = moverFrame:GetCenter()
|
|
|
|
--did the frame moved?
|
|
if (newPosX ~= currentPosX) then
|
|
local xOffset = newPosX - currentPosX
|
|
anchorSettings.x = anchorSettings.x + xOffset
|
|
local anchorXSlider = optionsFrame:GetWidgetById("anchoroffsetx")
|
|
anchorXSlider:SetValueNoCallback(anchorSettings.x)
|
|
end
|
|
|
|
if (newPosY ~= currentPosY) then
|
|
local yOffset = newPosY - currentPosY
|
|
anchorSettings.y = anchorSettings.y + yOffset
|
|
local anchorYSlider = optionsFrame:GetWidgetById("anchoroffsety")
|
|
anchorYSlider:SetValueNoCallback(anchorSettings.y)
|
|
end
|
|
|
|
currentPosX, currentPosY = newPosX, newPosY
|
|
end
|
|
end)
|
|
end,
|
|
|
|
---@param self df_editor
|
|
StopObjectMovement = function(self)
|
|
local moverFrame = self:GetMoverFrame()
|
|
|
|
moverFrame:EnableMouse(false)
|
|
moverFrame:SetScript("OnUpdate", nil)
|
|
|
|
--hide all four guidelines
|
|
for side, texture in pairs(self.moverGuideLines) do
|
|
texture:Hide()
|
|
end
|
|
|
|
moverFrame:Hide()
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@param object df_editor_objectinfo
|
|
GetProfileTableFromObject = function(self, object)
|
|
local profileTable = object.profiletable
|
|
local subTablePath = object.subtablepath
|
|
|
|
if (type(subTablePath) == "string" and subTablePath ~= "") then
|
|
local subTable = detailsFramework.table.getfrompath(profileTable, subTablePath)
|
|
assert(type(subTable) == "table", "GetProfileTableFromObject() subTablePath is invalid.")
|
|
return subTable
|
|
end
|
|
|
|
return profileTable
|
|
end,
|
|
|
|
UpdateProfileTableOnAllRegisteredObjects = function(self, profileTable)
|
|
assert(type(profileTable) == "table", "UpdateProfileTableOnAllRegisteredObjects() expects a table on #1 parameter.")
|
|
|
|
local registeredObjects = self:GetAllRegisteredObjects()
|
|
|
|
for i = 1, #registeredObjects do
|
|
local objectRegistered = registeredObjects[i]
|
|
objectRegistered.profiletable = profileTable
|
|
end
|
|
|
|
local objectSelector = self:GetObjectSelector()
|
|
objectSelector:RefreshMe()
|
|
end,
|
|
|
|
RegisterObject = function(self, object, localizedLabel, id, profileTable, subTablePath, profileKeyMap, extraOptions, callback, options)
|
|
assert(type(object) == "table", "RegisterObjectToEdit() expects an UIObject on #1 parameter.")
|
|
assert(object.GetObjectType, "RegisterObjectToEdit() expects an UIObject on #1 parameter.")
|
|
assert(type(profileTable) == "table", "RegisterObjectToEdit() expects a table on #4 parameter.")
|
|
assert(type(id) ~= "nil" and type(id) ~= "boolean", "RegisterObjectToEdit() expects an ID on parameter #3.")
|
|
assert(type(callback) == "function" or callback == nil, "RegisterObjectToEdit() expects a function or nil as the #7 parameter.")
|
|
|
|
local registeredObjects = self:GetAllRegisteredObjects()
|
|
|
|
--is object already registered?
|
|
for i = 1, #registeredObjects do
|
|
local objectRegistered = registeredObjects[i]
|
|
if (objectRegistered.object == object) then
|
|
error("RegisterObjectToEdit() object already registered.")
|
|
end
|
|
end
|
|
|
|
--deploy the options table
|
|
options = type(options) == "table" and options or {}
|
|
detailsFramework.table.deploy(options, editObjectDefaultOptions)
|
|
|
|
localizedLabel = type(localizedLabel) == "string" and localizedLabel or "invalid label"
|
|
|
|
--a button to select the widget
|
|
local selectButton = CreateFrame("button", "$parentSelectButton" .. id, object:GetParent())
|
|
selectButton:SetAllPoints(object)
|
|
|
|
---@type df_editor_objectinfo
|
|
local objectRegistered = {
|
|
object = object,
|
|
label = localizedLabel,
|
|
id = id,
|
|
profiletable = profileTable,
|
|
subtablepath = subTablePath,
|
|
profilekeymap = profileKeyMap,
|
|
extraoptions = extraOptions or {},
|
|
callback = callback,
|
|
options = options,
|
|
selectButton = selectButton,
|
|
}
|
|
|
|
selectButton:SetScript("OnClick", function()
|
|
self:EditObject(objectRegistered)
|
|
end)
|
|
|
|
registeredObjects[#registeredObjects+1] = objectRegistered
|
|
self.registeredObjectsByID[id] = objectRegistered
|
|
|
|
local objectSelector = self:GetObjectSelector()
|
|
objectSelector:RefreshMe()
|
|
|
|
--what to do after an object is registered?
|
|
return objectRegistered
|
|
end,
|
|
|
|
UnregisterObject = function(self, object)
|
|
local registeredObjects = self:GetAllRegisteredObjects()
|
|
|
|
for i = 1, #registeredObjects do
|
|
local objectRegistered = registeredObjects[i]
|
|
if (objectRegistered.object == object) then
|
|
self.registeredObjectsByID[objectRegistered.id] = nil
|
|
table.remove(registeredObjects, i)
|
|
break
|
|
end
|
|
end
|
|
|
|
local objectSelector = self:GetObjectSelector()
|
|
objectSelector:RefreshMe()
|
|
|
|
--stop editing the object
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@return df_editor_objectinfo[]
|
|
GetAllRegisteredObjects = function(self)
|
|
return self.registeredObjects
|
|
end,
|
|
|
|
---@param self df_editor
|
|
---@return df_editor_objectinfo?
|
|
GetObjectByRef = function(self, object)
|
|
local registeredObjects = self:GetAllRegisteredObjects()
|
|
for i = 1, #registeredObjects do
|
|
local objectRegistered = registeredObjects[i]
|
|
if (objectRegistered.object == object) then
|
|
return objectRegistered
|
|
end
|
|
end
|
|
end,
|
|
|
|
GetObjectByIndex = function(self, index)
|
|
local registeredObjects = self:GetAllRegisteredObjects()
|
|
return registeredObjects[index]
|
|
end,
|
|
|
|
GetObjectById = function(self, id)
|
|
return self.registeredObjectsByID[id]
|
|
end,
|
|
|
|
CreateObjectSelectionList = function(self, scroll_width, scroll_height, scroll_lines, scroll_line_height)
|
|
local editorFrame = self
|
|
|
|
local refreshFunc = function(self, data, offset, totalLines) --~refresh
|
|
self.SelectionTexture:Hide()
|
|
self.SelectionTexture:ClearAllPoints()
|
|
local objectCurrentBeingEdited = editorFrame:GetEditingObject()
|
|
|
|
for i = 1, totalLines do
|
|
local index = i + offset
|
|
---@type df_editor_objectinfo
|
|
local objectRegistered = data[index]
|
|
|
|
if (objectRegistered) then
|
|
local line = self:GetLine(i)
|
|
line.index = index
|
|
|
|
if (objectRegistered.object:GetObjectType() == "Texture") then
|
|
line.Icon:SetAtlas("AnimCreate_Icon_Texture")
|
|
|
|
elseif (objectRegistered.object:GetObjectType() == "FontString") then
|
|
line.Icon:SetAtlas("AnimCreate_Icon_Text")
|
|
end
|
|
|
|
line.Label:SetText(objectRegistered.label)
|
|
|
|
if (objectRegistered.object == objectCurrentBeingEdited) then
|
|
self.SelectionTexture:SetAllPoints(line)
|
|
self.SelectionTexture:Show()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local createLineFunc = function(self, index) -- ~createline --~line
|
|
local line = CreateFrame("button", "$parentLine" .. index, self, "BackdropTemplate")
|
|
line:SetPoint("topleft", self, "topleft", 1, -((index-1)*(scroll_line_height+1)) - 1)
|
|
line:SetSize(scroll_width - 2, scroll_line_height)
|
|
|
|
line:SetBackdrop({bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
|
if (index % 2 == 0) then
|
|
line:SetBackdropColor(.1, .1, .1, .1)
|
|
else
|
|
line:SetBackdropColor(.1, .1, .1, .4)
|
|
end
|
|
|
|
detailsFramework:CreateHighlightTexture(line, "HighlightTexture")
|
|
detailsFramework:Mixin(line, detailsFramework.HeaderFunctions)
|
|
|
|
line:SetScript("OnClick", function(self)
|
|
local objectRegistered = editorFrame:GetObjectByIndex(self.index)
|
|
editorFrame:EditObject(objectRegistered)
|
|
editorFrame.objectSelector:RefreshMe()
|
|
end)
|
|
|
|
--icon
|
|
local objectIcon = line:CreateTexture("$parentIcon", "overlay")
|
|
objectIcon:SetSize(scroll_line_height - 2, scroll_line_height - 2)
|
|
|
|
--object label
|
|
local objectLabel = line:CreateFontString("$parentLabel", "overlay", "GameFontNormal")
|
|
|
|
objectIcon:SetPoint("left", line, "left", 2, 0)
|
|
objectLabel:SetPoint("left", objectIcon, "right", 2, 0)
|
|
|
|
line.Icon = objectIcon
|
|
line.Label = objectLabel
|
|
|
|
return line
|
|
end
|
|
|
|
local selectObjectScrollBox = detailsFramework:CreateScrollBox(self:GetParent(), "$parentSelectObjectScrollBox", refreshFunc, editorFrame:GetAllRegisteredObjects(), scroll_width, scroll_height, scroll_lines, scroll_line_height)
|
|
detailsFramework:ReskinSlider(selectObjectScrollBox)
|
|
|
|
local selectionTexture = selectObjectScrollBox:CreateTexture(nil, "overlay")
|
|
selectionTexture:SetColorTexture(1, 1, 0, 0.2)
|
|
selectObjectScrollBox.SelectionTexture = selectionTexture
|
|
|
|
function selectObjectScrollBox:RefreshMe()
|
|
selectObjectScrollBox:SetData(editorFrame:GetAllRegisteredObjects())
|
|
selectObjectScrollBox:Refresh()
|
|
end
|
|
|
|
--create lines
|
|
for i = 1, scroll_lines do
|
|
selectObjectScrollBox:CreateLine(createLineFunc)
|
|
end
|
|
|
|
return selectObjectScrollBox
|
|
end,
|
|
|
|
OnHide = function(self)
|
|
self:StopObjectMovement()
|
|
end,
|
|
}
|
|
|
|
---@class df_editor_defaultoptions : table
|
|
---@field width number
|
|
---@field height number
|
|
---@field options_width number
|
|
---@field create_object_list boolean
|
|
---@field object_list_width number
|
|
---@field object_list_height number
|
|
---@field object_list_lines number
|
|
---@field object_list_line_height number
|
|
---@field text_template table
|
|
|
|
--editorFrame.options.text_template
|
|
|
|
---@type df_editor_defaultoptions
|
|
local editorDefaultOptions = {
|
|
width = 400,
|
|
height = 548,
|
|
options_width = 340,
|
|
create_object_list = true,
|
|
object_list_width = 200,
|
|
object_list_height = 420,
|
|
object_list_lines = 20,
|
|
object_list_line_height = 20,
|
|
text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE"),
|
|
}
|
|
|
|
function detailsFramework:CreateEditor(parent, name, options)
|
|
name = name or ("DetailsFrameworkEditor" .. math.random(100000, 10000000))
|
|
local editorFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
|
|
|
detailsFramework:Mixin(editorFrame, detailsFramework.EditorMixin)
|
|
detailsFramework:Mixin(editorFrame, detailsFramework.OptionsFunctions)
|
|
|
|
editorFrame:SetScript("OnHide", editorFrame.OnHide)
|
|
|
|
editorFrame.registeredObjects = {}
|
|
editorFrame.registeredObjectsByID = {}
|
|
|
|
editorFrame:BuildOptionsTable(editorDefaultOptions, options)
|
|
|
|
editorFrame:SetSize(editorFrame.options.width, editorFrame.options.height)
|
|
|
|
--The options frame holds the options for the object being edited. It is used as the parent frame for the BuildMenuVolatile() function.
|
|
local optionsFrame = CreateFrame("frame", name .. "OptionsFrame", editorFrame, "BackdropTemplate")
|
|
optionsFrame:SetSize(editorFrame.options.options_width, 5000)
|
|
|
|
local canvasScrollBoxOptions = {
|
|
width = editorFrame.options.options_width,
|
|
height = 400,
|
|
reskin_slider = true,
|
|
}
|
|
local canvasFrame = detailsFramework:CreateCanvasScrollBox(editorFrame, optionsFrame, name .. "CanvasScrollBox", canvasScrollBoxOptions)
|
|
|
|
if (editorFrame.options.create_object_list) then
|
|
local scrollWidth = editorFrame.options.object_list_width
|
|
local scrollHeight = editorFrame.options.object_list_height
|
|
local scrollLinesAmount = editorFrame.options.object_list_lines
|
|
local scrollLineHeight = editorFrame.options.object_list_line_height
|
|
|
|
local objectSelector = editorFrame:CreateObjectSelectionList(scrollWidth, scrollHeight, scrollLinesAmount, scrollLineHeight)
|
|
objectSelector:SetPoint("topleft", editorFrame, "topleft", 0, -2)
|
|
objectSelector:SetBackdropBorderColor(0, 0, 0, 0)
|
|
editorFrame.objectSelector = objectSelector
|
|
objectSelector:RefreshMe()
|
|
|
|
local nScrollBarWidth = 30
|
|
canvasFrame:SetPoint("topleft", objectSelector, "topright", nScrollBarWidth, 0)
|
|
canvasFrame:SetPoint("bottomleft", objectSelector, "bottomright", -nScrollBarWidth, 0)
|
|
else
|
|
canvasFrame:SetPoint("topleft", editorFrame, "topleft", 2, -2)
|
|
canvasFrame:SetPoint("bottomleft", editorFrame, "bottomleft", 2, 0)
|
|
end
|
|
|
|
--over the top frame is a frame that is always on top of everything else
|
|
local OTTFrame = CreateFrame("frame", "$parentOTTFrame", UIParent)
|
|
OTTFrame:SetFrameStrata("TOOLTIP")
|
|
editorFrame.overTheTopFrame = OTTFrame
|
|
|
|
--frame that is used to move the object
|
|
local moverFrame = CreateFrame("frame", "$parentMoverFrame", OTTFrame, "BackdropTemplate")
|
|
moverFrame:SetClampedToScreen(true)
|
|
detailsFramework:ApplyStandardBackdrop(moverFrame)
|
|
moverFrame:SetBackdropColor(.10, .10, .10, 0)
|
|
moverFrame.__background:SetAlpha(0.1)
|
|
editorFrame.moverFrame = moverFrame
|
|
|
|
editorFrame:CreateMoverGuideLines()
|
|
|
|
editorFrame.optionsFrame = optionsFrame
|
|
editorFrame.canvasScrollBox = canvasFrame
|
|
|
|
return editorFrame
|
|
end
|