Major upgrade for alpha testers
This commit is contained in:
+657
-100
@@ -14,7 +14,7 @@ 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
|
||||
|
||||
|
||||
--]=]
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ local _
|
||||
--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_attribute
|
||||
---@field name string
|
||||
---@field label string
|
||||
---@field name string?
|
||||
---@field label string?
|
||||
---@field widget string
|
||||
---@field default any
|
||||
---@field default any?
|
||||
---@field minvalue number?
|
||||
---@field maxvalue number?
|
||||
---@field step number?
|
||||
@@ -55,12 +55,15 @@ local attributes = {
|
||||
name = "font",
|
||||
label = "Font",
|
||||
widget = "fontdropdown",
|
||||
setter = function(widget, value) widget:SetFont(value, select(2, widget:GetFont())) end
|
||||
setter = function(widget, value)
|
||||
local font = LibStub:GetLibrary("LibSharedMedia-3.0"):Fetch("font", value)
|
||||
widget:SetFont(font, select(2, widget:GetFont()))
|
||||
end
|
||||
},
|
||||
{
|
||||
name = "color",
|
||||
label = "Color",
|
||||
widget = "colordropdown",
|
||||
widget = "color",
|
||||
setter = function(widget, value) widget:SetTextColor(unpack(value)) end
|
||||
},
|
||||
{
|
||||
@@ -69,6 +72,7 @@ local attributes = {
|
||||
widget = "range",
|
||||
setter = function(widget, value) widget:SetAlpha(value) end
|
||||
},
|
||||
{widget = "blank"},
|
||||
{
|
||||
name = "shadow",
|
||||
label = "Draw Shadow",
|
||||
@@ -78,7 +82,7 @@ local attributes = {
|
||||
{
|
||||
name = "shadowcolor",
|
||||
label = "Shadow Color",
|
||||
widget = "colordropdown",
|
||||
widget = "color",
|
||||
setter = function(widget, value) widget:SetShadowColor(unpack(value)) end
|
||||
},
|
||||
{
|
||||
@@ -103,6 +107,7 @@ local attributes = {
|
||||
widget = "outlinedropdown",
|
||||
setter = function(widget, value) widget:SetFont(widget:GetFont(), select(2, widget:GetFont()), value) end
|
||||
},
|
||||
{widget = "blank"},
|
||||
{
|
||||
name = "anchor",
|
||||
label = "Anchor",
|
||||
@@ -113,16 +118,16 @@ local attributes = {
|
||||
name = "anchoroffsetx",
|
||||
label = "Anchor X Offset",
|
||||
widget = "range",
|
||||
minvalue = -20,
|
||||
maxvalue = 20,
|
||||
minvalue = -100,
|
||||
maxvalue = 100,
|
||||
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
||||
},
|
||||
{
|
||||
name = "anchoroffsety",
|
||||
label = "Anchor Y Offset",
|
||||
widget = "range",
|
||||
minvalue = -20,
|
||||
maxvalue = 20,
|
||||
minvalue = -100,
|
||||
maxvalue = 100,
|
||||
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
||||
},
|
||||
{
|
||||
@@ -134,56 +139,59 @@ local attributes = {
|
||||
maxvalue = math.pi*2,
|
||||
setter = function(widget, value) widget:SetRotation(value) end
|
||||
},
|
||||
{
|
||||
name = "scale",
|
||||
label = "Scale",
|
||||
widget = "range",
|
||||
usedecimals = true,
|
||||
minvalue = 0.65,
|
||||
maxvalue = 2.5,
|
||||
setter = function(widget, value) widget:SetScale(value) end
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
local profileTable = {
|
||||
spellname_text_size = 10,
|
||||
spellname_text_font = "Arial Narrow",
|
||||
spellname_text_color = {1, 1, 1, 1},
|
||||
spellname_text_outline = "NONE",
|
||||
spellname_text_shadow_color = {0, 0, 0, 1},
|
||||
spellname_text_shadow_color_offset = {1, -1},
|
||||
spellname_text_anchor = {side = 9, x = 0, y = 0},
|
||||
}
|
||||
|
||||
--create a map table for the profile table
|
||||
local mapTable = {
|
||||
text = "text test",
|
||||
size = "spellname_text_size",
|
||||
font = "spellname_text_font",
|
||||
color = "spellname_text_color",
|
||||
outline = "spellname_text_outline",
|
||||
shadowcolor = "spellname_text_shadow_color",
|
||||
shadowoffsetx = "spellname_text_shadow_color_offset[1]",
|
||||
shadowoffsety = "spellname_text_shadow_color_offset[2]",
|
||||
anchor = "spellname_text_anchor.side",
|
||||
anchoroffsetx = "spellname_text_anchor.x",
|
||||
anchoroffsety = "spellname_text_anchor.y",
|
||||
}
|
||||
|
||||
local table_path = {
|
||||
shadowWidth = "text_settings[1].width",
|
||||
shadowHeight = "text_settings[1].height",
|
||||
shadowEnabled = "text_settings.settings.enabled",
|
||||
text = "text_settings.settings.text.current_text",
|
||||
}
|
||||
|
||||
local text_settings = {
|
||||
shadowWidth = {{width = 100}},
|
||||
shadowHeight = {{height = 100}},
|
||||
shadowEnabled = {settings = {enabled = true}},
|
||||
text = {settings = {text = {current_text = "hellow world"}}},
|
||||
}
|
||||
|
||||
---@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 EditObject fun(self:df_editor, object:uiobject, profileTable:table, profileKeyMap:table, callback:function)
|
||||
---@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)
|
||||
|
||||
---@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
|
||||
|
||||
---@type df_editobjectoptions
|
||||
local editObjectDefaultOptions = {
|
||||
use_colon = true,
|
||||
can_move = true,
|
||||
use_guide_lines = true,
|
||||
}
|
||||
|
||||
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
|
||||
@@ -191,6 +199,18 @@ detailsFramework.EditorMixin = {
|
||||
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)
|
||||
@@ -207,28 +227,117 @@ detailsFramework.EditorMixin = {
|
||||
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,
|
||||
|
||||
---@param self df_editor
|
||||
---@param object uiobject
|
||||
---@param profileTable table
|
||||
---@param profileKeyMap table
|
||||
---@param callback function calls when an attribute is changed with the payload: editingObject, optionName, newValue, profileTable, profileKey
|
||||
EditObject = function(self, object, profileTable, profileKeyMap, callback)
|
||||
assert(type(object) == "table", "EditObject(object) expects an UIObject on first parameter.")
|
||||
assert(type(profileTable) == "table", "EditObject(object) expects a table on second parameter.")
|
||||
assert(object.GetObjectType, "EditObject(object) expects an UIObject on first parameter.")
|
||||
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 profileTable = registeredObject.profiletable
|
||||
local profileKeyMap = registeredObject.profilekeymap
|
||||
local extraOptions = registeredObject.extraoptions
|
||||
local callback = registeredObject.callback
|
||||
local options = registeredObject.options
|
||||
|
||||
--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.onEditCallback = callback
|
||||
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)
|
||||
--get the object and its profile table with the current values
|
||||
local object = self:GetEditingObject()
|
||||
@@ -243,56 +352,135 @@ detailsFramework.EditorMixin = {
|
||||
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:BuildMenu()
|
||||
local menuOptions = {}
|
||||
for i = 1, #attributeList do
|
||||
local option = attributeList[i]
|
||||
|
||||
--get the key to be used on profile table
|
||||
local profileKey = profileMap[option.name]
|
||||
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)
|
||||
if (option.widget == "blank") then
|
||||
menuOptions[#menuOptions+1] = {type = "blank"}
|
||||
else
|
||||
value = profileTable[profileKey]
|
||||
end
|
||||
--get the key to be used on profile table
|
||||
local profileKey = profileMap[option.name]
|
||||
local value
|
||||
|
||||
--if no value is found, attempt to get a default
|
||||
value = value or option.default
|
||||
--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 (value) then
|
||||
menuOptions[#menuOptions+1] = {
|
||||
type = option.widget,
|
||||
name = option.label,
|
||||
get = function() return value end,
|
||||
set = function(widget, fixedValue, newValue)
|
||||
if (profileKey and (profileKey:match("%.") or profileKey:match("%["))) then
|
||||
detailsFramework.table.setfrompath(profileTable, profileKey, value)
|
||||
else
|
||||
profileTable[profileKey] = value
|
||||
end
|
||||
--if no value is found, attempt to get a default
|
||||
if (type(value) == "nil") then
|
||||
value = option.default
|
||||
end
|
||||
|
||||
if (self:GetOnEditCallback()) then
|
||||
self:GetOnEditCallback()(object, option.name, newValue, profileTable, profileKey)
|
||||
end
|
||||
local bHasValue = type(value) ~= "nil"
|
||||
|
||||
if (option.name == "anchor" or option.name == "anchoroffsetx" or option.name == "anchoroffsety") then
|
||||
local anchorTable = detailsFramework.table.getfrompath(profileTable, profileKey:gsub("%.[^.]*$", ""))
|
||||
option.setter(object, anchorTable)
|
||||
else
|
||||
option.setter(object, newValue)
|
||||
end
|
||||
end,
|
||||
min = option.minvalue,
|
||||
max = option.maxvalue,
|
||||
step = option.step,
|
||||
usedecimals = option.usedecimals,
|
||||
}
|
||||
local minValue = option.minvalue
|
||||
local maxValue = option.maxvalue
|
||||
|
||||
if (option.name == "anchoroffsetx") then
|
||||
minValue = -object:GetParent():GetWidth()/2
|
||||
maxValue = object:GetParent():GetWidth()/2
|
||||
elseif (option.name == "anchoroffsety") then
|
||||
minValue = -object:GetParent():GetHeight()/2
|
||||
maxValue = object:GetParent():GetHeight()/2
|
||||
end
|
||||
|
||||
if (option.name == "classcolor") then print("", value) end
|
||||
|
||||
if (bHasValue) then
|
||||
if (option.name == "classcolor") then print("HERE", value) end
|
||||
|
||||
local parentTable = getParentTable(profileTable, profileKey)
|
||||
|
||||
if (option.name == "anchor" or option.name == "anchoroffsetx" or option.name == "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 == "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
|
||||
else
|
||||
detailsFramework.table.setfrompath(profileTable, profileKey, newValue)
|
||||
end
|
||||
|
||||
if (self:GetOnEditCallback()) then
|
||||
self:GetOnEditCallback()(object, option.name, newValue, profileTable, profileKey)
|
||||
end
|
||||
|
||||
--update the widget visual
|
||||
--anchoring uses SetAnchor() which require the anchorTable to be passed
|
||||
if (option.name == "anchor" or option.name == "anchoroffsetx" or option.name == "anchoroffsety") then
|
||||
anchorSettings = parentTable
|
||||
|
||||
if (option.name == "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.name,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -303,7 +491,9 @@ detailsFramework.EditorMixin = {
|
||||
|
||||
local optionsFrame = self:GetOptionsFrame()
|
||||
local canvasScrollBox = self:GetCanvasScrollBox()
|
||||
local bUseColon = true
|
||||
|
||||
local bUseColon = editingOptions.use_colon
|
||||
|
||||
local bSwitchIsCheckbox = true
|
||||
local maxHeight = 5000
|
||||
|
||||
@@ -318,25 +508,361 @@ detailsFramework.EditorMixin = {
|
||||
local options_slider_template = detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE")
|
||||
local options_button_template = detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")
|
||||
|
||||
detailsFramework:BuildMenu(optionsFrame, menuOptions, 0, -2, maxHeight, bUseColon, options_text_template, options_dropdown_template, options_switch_template, bSwitchIsCheckbox, options_slider_template, options_button_template)
|
||||
detailsFramework:BuildMenuVolatile(optionsFrame, menuOptions, 0, -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()
|
||||
|
||||
--self:UpdateGuideLinesAnchors()
|
||||
|
||||
--update guidelines
|
||||
if (self:GetEditingOptions().use_guide_lines) then
|
||||
--show all four guidelines
|
||||
for side, texture in pairs(self.moverGuideLines) do
|
||||
texture:Show()
|
||||
end
|
||||
end
|
||||
|
||||
local optionsFrame = self:GetOptionsFrame()
|
||||
|
||||
moverFrame:EnableMouse(true)
|
||||
moverFrame:SetMovable(true)
|
||||
moverFrame:ClearAllPoints()
|
||||
moverFrame:Show()
|
||||
|
||||
--update the mover frame size to match the object size
|
||||
if (object:GetObjectType() == "FontString") then
|
||||
---@cast object fontstring
|
||||
local width = object:GetStringWidth()
|
||||
local height = object:GetStringHeight()
|
||||
moverFrame:SetSize(width, height)
|
||||
else
|
||||
local width, height = object:GetSize()
|
||||
moverFrame:SetSize(width, height)
|
||||
end
|
||||
|
||||
for i = 1, object:GetNumPoints() do
|
||||
local point, relativeTo, relativePoint, x, y = object:GetPoint(i)
|
||||
moverFrame:SetPoint(point, relativeTo, relativePoint, x, y)
|
||||
end
|
||||
|
||||
local currentPosX, currentPosY
|
||||
|
||||
moverFrame:SetScript("OnMouseDown", function()
|
||||
object:ClearAllPoints()
|
||||
object:SetPoint("topleft", moverFrame, "topleft", 0, 0)
|
||||
currentPosX, currentPosY = moverFrame:GetCenter()
|
||||
moverFrame:SetBackdropBorderColor(1, 1, 0, 0)
|
||||
|
||||
for i = 1, object:GetNumPoints() do
|
||||
local point, relativeTo, relativePoint, x, y = object:GetPoint(i)
|
||||
moverFrame:SetPoint(point, relativeTo, relativePoint, x, y)
|
||||
end
|
||||
|
||||
moverFrame:StartMoving()
|
||||
moverFrame.bIsMoving = true
|
||||
end)
|
||||
|
||||
moverFrame:SetScript("OnMouseUp", function()
|
||||
moverFrame:StopMovingOrSizing()
|
||||
moverFrame.bIsMoving = false
|
||||
|
||||
object:ClearAllPoints()
|
||||
detailsFramework:SetAnchor(object, anchorSettings, object:GetParent())
|
||||
|
||||
moverFrame:ClearAllPoints()
|
||||
for i = 1, object:GetNumPoints() do
|
||||
local point, relativeTo, relativePoint, x, y = object:GetPoint(i)
|
||||
moverFrame:SetPoint(point, relativeTo, relativePoint, x, y)
|
||||
end
|
||||
end)
|
||||
|
||||
--detailsFramework:SetAnchor(moverFrame, anchorSettings)
|
||||
--detailsFramework:SetAnchor(object, anchorSettings, moverFrame)
|
||||
|
||||
moverFrame:SetScript("OnUpdate", function()
|
||||
--if the object isn't moving, make the mover follow the object position
|
||||
if (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
|
||||
|
||||
--[=[
|
||||
--update the mover frame size to match the object size
|
||||
if (object:GetObjectType() == "FontString") then
|
||||
---@cast object fontstring
|
||||
local width = object:GetStringWidth()
|
||||
local height = object:GetStringHeight()
|
||||
moverFrame:SetSize(width, height)
|
||||
else
|
||||
local width, height = object:GetSize()
|
||||
moverFrame:SetSize(width, height)
|
||||
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,
|
||||
|
||||
RegisterObject = function(self, object, localizedLabel, id, profileTable, 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"
|
||||
|
||||
---@type df_editor_objectinfo
|
||||
local objectRegistered = {
|
||||
object = object,
|
||||
label = localizedLabel,
|
||||
id = id,
|
||||
profiletable = profileTable,
|
||||
profilekeymap = profileKeyMap,
|
||||
extraoptions = extraOptions or {},
|
||||
callback = callback,
|
||||
options = options,
|
||||
}
|
||||
|
||||
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
|
||||
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:SetTexture([[Interface\AnimCreate\AnimCreateIcons]])
|
||||
line.Icon:SetTexCoord(1/4, 2/4, 1/4, 2/4)
|
||||
|
||||
elseif (objectRegistered.object:GetObjectType() == "Texture") then
|
||||
line.Icon:SetTexture([[Interface\AnimCreate\AnimCreateIcons]])
|
||||
line.Icon:SetTexCoord(2/4, 3/4, 0, 1/4)
|
||||
end
|
||||
|
||||
line.Label:SetText(objectRegistered.label)
|
||||
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:Mixin(line, detailsFramework.HeaderFunctions)
|
||||
|
||||
--line:SetScript("OnEnter", lineOnEnter)
|
||||
--line:SetScript("OnLeave", lineOnLeave)
|
||||
|
||||
line:SetScript("OnClick", function(self)
|
||||
local objectRegistered = editorFrame:GetObjectByIndex(self.index)
|
||||
editorFrame:EditObject(objectRegistered)
|
||||
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)
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
---@class df_editor_defaultoptions : table
|
||||
---@field width number
|
||||
---@field height 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
|
||||
|
||||
---@class df_editor_defaultoptions
|
||||
local editorDefaultOptions = {
|
||||
width = 400,
|
||||
height = 600,
|
||||
create_object_list = true,
|
||||
object_list_width = 200,
|
||||
object_list_height = 420,
|
||||
object_list_lines = 20,
|
||||
object_list_line_height = 20,
|
||||
}
|
||||
|
||||
---@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_objectinfo : table
|
||||
---@field object uiobject
|
||||
---@field label string
|
||||
---@field id any
|
||||
---@field profiletable table
|
||||
---@field profilekeymap table
|
||||
---@field extraoptions table
|
||||
---@field callback function
|
||||
---@field options df_editobjectoptions
|
||||
|
||||
function detailsFramework:CreateEditor(parent, name, options)
|
||||
name = name or ("DetailsFrameworkEditor" .. math.random(100000, 10000000))
|
||||
local editorFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
||||
@@ -344,10 +870,25 @@ function detailsFramework:CreateEditor(parent, name, options)
|
||||
detailsFramework:Mixin(editorFrame, detailsFramework.EditorMixin)
|
||||
detailsFramework:Mixin(editorFrame, detailsFramework.OptionsFunctions)
|
||||
|
||||
editorFrame.registeredObjects = {}
|
||||
editorFrame.registeredObjectsByID = {}
|
||||
|
||||
editorFrame:BuildOptionsTable(editorDefaultOptions, options)
|
||||
|
||||
editorFrame:SetSize(editorFrame.options.width, editorFrame.options.height)
|
||||
|
||||
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, "topright", 2, 0)
|
||||
editorFrame.objectSelector = objectSelector
|
||||
objectSelector:RefreshMe()
|
||||
end
|
||||
|
||||
--options frame is the frame that holds the options for the editing object, it is used as the parent frame for BuildMenuVolatile()
|
||||
local optionsFrame = CreateFrame("frame", name .. "OptionsFrame", editorFrame, "BackdropTemplate")
|
||||
optionsFrame:SetSize(editorFrame.options.width, 5000)
|
||||
@@ -355,6 +896,22 @@ function detailsFramework:CreateEditor(parent, name, options)
|
||||
local canvasFrame = detailsFramework:CreateCanvasScrollBox(editorFrame, optionsFrame, name .. "CanvasScrollBox")
|
||||
canvasFrame:SetAllPoints()
|
||||
|
||||
--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)
|
||||
moverFrame:SetBackdrop({
|
||||
edgeFile = "Interface\\Buttons\\WHITE8x8",
|
||||
edgeSize = 1,
|
||||
})
|
||||
editorFrame.moverFrame = moverFrame
|
||||
|
||||
editorFrame:CreateMoverGuideLines()
|
||||
|
||||
editorFrame.optionsFrame = optionsFrame
|
||||
editorFrame.canvasScrollBox = canvasFrame
|
||||
|
||||
|
||||
Reference in New Issue
Block a user