better controls over themed scrollbars
This commit is contained in:
@@ -133,6 +133,7 @@
|
|||||||
---@field scrollbarPadding number? -- Scrollbar padding from edges
|
---@field scrollbarPadding number? -- Scrollbar padding from edges
|
||||||
---@field scrollSpeed number? -- Scroll speed multiplier
|
---@field scrollSpeed number? -- Scroll speed multiplier
|
||||||
---@field scrollBarStyle string? -- Scrollbar style name from theme (selects from theme.scrollbars)
|
---@field scrollBarStyle string? -- Scrollbar style name from theme (selects from theme.scrollbars)
|
||||||
|
---@field scrollbarKnobOffset number|table? -- Scrollbar knob/handle offset (number or {x, y} or {horizontal, vertical})
|
||||||
---@field _overflowX boolean? -- Internal: whether content overflows horizontally
|
---@field _overflowX boolean? -- Internal: whether content overflows horizontally
|
||||||
---@field _overflowY boolean? -- Internal: whether content overflows vertically
|
---@field _overflowY boolean? -- Internal: whether content overflows vertically
|
||||||
---@field _contentWidth number? -- Internal: total content width
|
---@field _contentWidth number? -- Internal: total content width
|
||||||
@@ -1444,6 +1445,7 @@ function Element.new(props)
|
|||||||
scrollSpeed = props.scrollSpeed,
|
scrollSpeed = props.scrollSpeed,
|
||||||
smoothScrollEnabled = props.smoothScrollEnabled,
|
smoothScrollEnabled = props.smoothScrollEnabled,
|
||||||
scrollBarStyle = props.scrollBarStyle,
|
scrollBarStyle = props.scrollBarStyle,
|
||||||
|
scrollbarKnobOffset = props.scrollbarKnobOffset,
|
||||||
hideScrollbars = props.hideScrollbars,
|
hideScrollbars = props.hideScrollbars,
|
||||||
_scrollX = props._scrollX,
|
_scrollX = props._scrollX,
|
||||||
_scrollY = props._scrollY,
|
_scrollY = props._scrollY,
|
||||||
@@ -1460,6 +1462,7 @@ function Element.new(props)
|
|||||||
self.scrollbarPadding = self._scrollManager.scrollbarPadding
|
self.scrollbarPadding = self._scrollManager.scrollbarPadding
|
||||||
self.scrollSpeed = self._scrollManager.scrollSpeed
|
self.scrollSpeed = self._scrollManager.scrollSpeed
|
||||||
self.scrollBarStyle = self._scrollManager.scrollBarStyle
|
self.scrollBarStyle = self._scrollManager.scrollBarStyle
|
||||||
|
self.scrollbarKnobOffset = self._scrollManager.scrollbarKnobOffset
|
||||||
self.hideScrollbars = self._scrollManager.hideScrollbars
|
self.hideScrollbars = self._scrollManager.hideScrollbars
|
||||||
|
|
||||||
-- Initialize state properties (will be synced from ScrollManager)
|
-- Initialize state properties (will be synced from ScrollManager)
|
||||||
|
|||||||
@@ -900,6 +900,20 @@ function Renderer:drawScrollbars(element, x, y, w, h, dims)
|
|||||||
local frameComponent = scrollbarComponent.frame or scrollbarComponent
|
local frameComponent = scrollbarComponent.frame or scrollbarComponent
|
||||||
local barComponent = scrollbarComponent.bar or scrollbarComponent
|
local barComponent = scrollbarComponent.bar or scrollbarComponent
|
||||||
|
|
||||||
|
-- Calculate knob offset (element overrides theme)
|
||||||
|
local knobOffsetX = 0
|
||||||
|
local knobOffsetY = 0
|
||||||
|
|
||||||
|
-- Use element offset if provided, otherwise use theme offset
|
||||||
|
if element.scrollbarKnobOffset then
|
||||||
|
knobOffsetX = element.scrollbarKnobOffset.x or 0
|
||||||
|
knobOffsetY = element.scrollbarKnobOffset.vertical or 0
|
||||||
|
elseif barComponent and barComponent.knobOffset then
|
||||||
|
local themeOffset = self._utils.normalizeOffsetTable(barComponent.knobOffset, 0)
|
||||||
|
knobOffsetX = themeOffset.x
|
||||||
|
knobOffsetY = themeOffset.vertical
|
||||||
|
end
|
||||||
|
|
||||||
-- Draw track (frame) if component exists
|
-- Draw track (frame) if component exists
|
||||||
if frameComponent and frameComponent._loadedAtlas and frameComponent.regions then
|
if frameComponent and frameComponent._loadedAtlas and frameComponent.regions then
|
||||||
self._NinePatch.draw(
|
self._NinePatch.draw(
|
||||||
@@ -917,8 +931,8 @@ function Renderer:drawScrollbars(element, x, y, w, h, dims)
|
|||||||
self._NinePatch.draw(
|
self._NinePatch.draw(
|
||||||
barComponent,
|
barComponent,
|
||||||
barComponent._loadedAtlas,
|
barComponent._loadedAtlas,
|
||||||
trackX,
|
trackX + knobOffsetX,
|
||||||
trackY + dims.vertical.thumbY,
|
trackY + dims.vertical.thumbY + knobOffsetY,
|
||||||
element.scrollbarWidth,
|
element.scrollbarWidth,
|
||||||
dims.vertical.thumbHeight
|
dims.vertical.thumbHeight
|
||||||
)
|
)
|
||||||
@@ -961,6 +975,20 @@ function Renderer:drawScrollbars(element, x, y, w, h, dims)
|
|||||||
local frameComponent = scrollbarComponent.frame or scrollbarComponent
|
local frameComponent = scrollbarComponent.frame or scrollbarComponent
|
||||||
local barComponent = scrollbarComponent.bar or scrollbarComponent
|
local barComponent = scrollbarComponent.bar or scrollbarComponent
|
||||||
|
|
||||||
|
-- Calculate knob offset (element overrides theme)
|
||||||
|
local knobOffsetX = 0
|
||||||
|
local knobOffsetY = 0
|
||||||
|
|
||||||
|
-- Use element offset if provided, otherwise use theme offset
|
||||||
|
if element.scrollbarKnobOffset then
|
||||||
|
knobOffsetX = element.scrollbarKnobOffset.horizontal or 0
|
||||||
|
knobOffsetY = element.scrollbarKnobOffset.y or 0
|
||||||
|
elseif barComponent and barComponent.knobOffset then
|
||||||
|
local themeOffset = self._utils.normalizeOffsetTable(barComponent.knobOffset, 0)
|
||||||
|
knobOffsetX = themeOffset.horizontal
|
||||||
|
knobOffsetY = themeOffset.y
|
||||||
|
end
|
||||||
|
|
||||||
-- Draw track (frame) if component exists
|
-- Draw track (frame) if component exists
|
||||||
if frameComponent and frameComponent._loadedAtlas and frameComponent.regions then
|
if frameComponent and frameComponent._loadedAtlas and frameComponent.regions then
|
||||||
self._NinePatch.draw(
|
self._NinePatch.draw(
|
||||||
@@ -978,8 +1006,8 @@ function Renderer:drawScrollbars(element, x, y, w, h, dims)
|
|||||||
self._NinePatch.draw(
|
self._NinePatch.draw(
|
||||||
barComponent,
|
barComponent,
|
||||||
barComponent._loadedAtlas,
|
barComponent._loadedAtlas,
|
||||||
trackX + dims.horizontal.thumbX,
|
trackX + dims.horizontal.thumbX + knobOffsetX,
|
||||||
trackY,
|
trackY + knobOffsetY,
|
||||||
dims.horizontal.thumbWidth,
|
dims.horizontal.thumbWidth,
|
||||||
element.scrollbarWidth
|
element.scrollbarWidth
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
---@field scrollbarPadding number -- Padding around scrollbar
|
---@field scrollbarPadding number -- Padding around scrollbar
|
||||||
---@field scrollSpeed number -- Scroll speed for wheel events (pixels per wheel unit)
|
---@field scrollSpeed number -- Scroll speed for wheel events (pixels per wheel unit)
|
||||||
---@field scrollBarStyle string? -- Scrollbar style name from theme (selects from theme.scrollbars)
|
---@field scrollBarStyle string? -- Scrollbar style name from theme (selects from theme.scrollbars)
|
||||||
|
---@field scrollbarKnobOffset table -- {x: number, y: number, horizontal: number, vertical: number} -- Offset for scrollbar knob/handle position
|
||||||
---@field hideScrollbars table -- {vertical: boolean, horizontal: boolean}
|
---@field hideScrollbars table -- {vertical: boolean, horizontal: boolean}
|
||||||
---@field touchScrollEnabled boolean -- Enable touch scrolling
|
---@field touchScrollEnabled boolean -- Enable touch scrolling
|
||||||
---@field momentumScrollEnabled boolean -- Enable momentum scrolling
|
---@field momentumScrollEnabled boolean -- Enable momentum scrolling
|
||||||
@@ -84,6 +85,9 @@ function ScrollManager.new(config, deps)
|
|||||||
self.scrollSpeed = config.scrollSpeed or 20
|
self.scrollSpeed = config.scrollSpeed or 20
|
||||||
self.scrollBarStyle = config.scrollBarStyle -- Theme scrollbar style name (nil = use default)
|
self.scrollBarStyle = config.scrollBarStyle -- Theme scrollbar style name (nil = use default)
|
||||||
|
|
||||||
|
-- scrollbarKnobOffset can be number or table {x, y} or {horizontal, vertical}
|
||||||
|
self.scrollbarKnobOffset = self._utils.normalizeOffsetTable(config.scrollbarKnobOffset, 0)
|
||||||
|
|
||||||
-- hideScrollbars can be boolean or table {vertical: boolean, horizontal: boolean}
|
-- hideScrollbars can be boolean or table {vertical: boolean, horizontal: boolean}
|
||||||
self.hideScrollbars = self._utils.normalizeBooleanTable(config.hideScrollbars, false)
|
self.hideScrollbars = self._utils.normalizeBooleanTable(config.hideScrollbars, false)
|
||||||
|
|
||||||
@@ -656,6 +660,7 @@ function ScrollManager:getState()
|
|||||||
_scrollbarHoveredVertical = self._scrollbarHoveredVertical or false,
|
_scrollbarHoveredVertical = self._scrollbarHoveredVertical or false,
|
||||||
_scrollbarHoveredHorizontal = self._scrollbarHoveredHorizontal or false,
|
_scrollbarHoveredHorizontal = self._scrollbarHoveredHorizontal or false,
|
||||||
scrollBarStyle = self.scrollBarStyle,
|
scrollBarStyle = self.scrollBarStyle,
|
||||||
|
scrollbarKnobOffset = self.scrollbarKnobOffset,
|
||||||
_overflowX = self._overflowX,
|
_overflowX = self._overflowX,
|
||||||
_overflowY = self._overflowY,
|
_overflowY = self._overflowY,
|
||||||
_contentWidth = self._contentWidth,
|
_contentWidth = self._contentWidth,
|
||||||
@@ -730,6 +735,10 @@ function ScrollManager:setState(state)
|
|||||||
self.scrollBarStyle = state.scrollBarStyle
|
self.scrollBarStyle = state.scrollBarStyle
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if state.scrollbarKnobOffset ~= nil then
|
||||||
|
self.scrollbarKnobOffset = self._utils.normalizeOffsetTable(state.scrollbarKnobOffset, 0)
|
||||||
|
end
|
||||||
|
|
||||||
if state._overflowX ~= nil then
|
if state._overflowX ~= nil then
|
||||||
self._overflowX = state._overflowX
|
self._overflowX = state._overflowX
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -322,6 +322,7 @@ end
|
|||||||
---@field contentAutoSizingMultiplier {width:number?, height:number?}? -- Optional: multiplier for auto-sized content dimensions
|
---@field contentAutoSizingMultiplier {width:number?, height:number?}? -- Optional: multiplier for auto-sized content dimensions
|
||||||
---@field scaleCorners number? -- Optional: scale multiplier for non-stretched regions (corners/edges). E.g., 2 = 2x size. Default: nil (no scaling)
|
---@field scaleCorners number? -- Optional: scale multiplier for non-stretched regions (corners/edges). E.g., 2 = 2x size. Default: nil (no scaling)
|
||||||
---@field scalingAlgorithm "nearest"|"bilinear"? -- Optional: scaling algorithm for non-stretched regions. Default: "bilinear"
|
---@field scalingAlgorithm "nearest"|"bilinear"? -- Optional: scaling algorithm for non-stretched regions. Default: "bilinear"
|
||||||
|
---@field knobOffset number|table? -- Optional: offset for scrollbar knob/handle (number or {x, y} or {horizontal, vertical})
|
||||||
---@field _loadedAtlas string|love.Image? -- Internal: cached loaded atlas image
|
---@field _loadedAtlas string|love.Image? -- Internal: cached loaded atlas image
|
||||||
---@field _loadedAtlasData love.ImageData? -- Internal: cached loaded atlas ImageData for pixel access
|
---@field _loadedAtlasData love.ImageData? -- Internal: cached loaded atlas ImageData for pixel access
|
||||||
---@field _ninePatchData {insets:table, contentPadding:table, stretchX:table, stretchY:table}? -- Internal: parsed 9-patch data with stretch regions and content padding
|
---@field _ninePatchData {insets:table, contentPadding:table, stretchX:table, stretchY:table}? -- Internal: parsed 9-patch data with stretch regions and content padding
|
||||||
@@ -569,6 +570,10 @@ function Theme.new(definition)
|
|||||||
if type(scrollbarDef.bar) == "string" then
|
if type(scrollbarDef.bar) == "string" then
|
||||||
-- Convert string path to ThemeComponent structure
|
-- Convert string path to ThemeComponent structure
|
||||||
local barComponent = { atlas = scrollbarDef.bar }
|
local barComponent = { atlas = scrollbarDef.bar }
|
||||||
|
-- Copy knobOffset from parent scrollbarDef if it exists
|
||||||
|
if scrollbarDef.knobOffset then
|
||||||
|
barComponent.knobOffset = scrollbarDef.knobOffset
|
||||||
|
end
|
||||||
loadAtlasWithNinePatch(barComponent, scrollbarDef.bar, "for scrollbar '" .. scrollbarName .. ".bar'")
|
loadAtlasWithNinePatch(barComponent, scrollbarDef.bar, "for scrollbar '" .. scrollbarName .. ".bar'")
|
||||||
if barComponent.insets then
|
if barComponent.insets then
|
||||||
createRegionsFromInsets(barComponent, barComponent._loadedAtlas or self.atlas)
|
createRegionsFromInsets(barComponent, barComponent._loadedAtlas or self.atlas)
|
||||||
@@ -576,6 +581,10 @@ function Theme.new(definition)
|
|||||||
scrollbarDef.bar = barComponent
|
scrollbarDef.bar = barComponent
|
||||||
elseif type(scrollbarDef.bar) == "table" then
|
elseif type(scrollbarDef.bar) == "table" then
|
||||||
-- Already a ThemeComponent structure, process it
|
-- Already a ThemeComponent structure, process it
|
||||||
|
-- Copy knobOffset from parent if bar component doesn't have one
|
||||||
|
if scrollbarDef.knobOffset and not scrollbarDef.bar.knobOffset then
|
||||||
|
scrollbarDef.bar.knobOffset = scrollbarDef.knobOffset
|
||||||
|
end
|
||||||
if scrollbarDef.bar.atlas and type(scrollbarDef.bar.atlas) == "string" then
|
if scrollbarDef.bar.atlas and type(scrollbarDef.bar.atlas) == "string" then
|
||||||
loadAtlasWithNinePatch(scrollbarDef.bar, scrollbarDef.bar.atlas, "for scrollbar '" .. scrollbarName .. ".bar'")
|
loadAtlasWithNinePatch(scrollbarDef.bar, scrollbarDef.bar.atlas, "for scrollbar '" .. scrollbarName .. ".bar'")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ local AnimationProps = {}
|
|||||||
---@field scrollSpeed number? -- Pixels per wheel notch (default: 20)
|
---@field scrollSpeed number? -- Pixels per wheel notch (default: 20)
|
||||||
---@field smoothScrollEnabled boolean? -- Enable smooth scrolling animation for wheel events (default: false)
|
---@field smoothScrollEnabled boolean? -- Enable smooth scrolling animation for wheel events (default: false)
|
||||||
---@field scrollBarStyle string? -- Scrollbar style name from theme (selects from theme.scrollbars, default: uses first scrollbar or fallback rendering)
|
---@field scrollBarStyle string? -- Scrollbar style name from theme (selects from theme.scrollbars, default: uses first scrollbar or fallback rendering)
|
||||||
|
---@field scrollbarKnobOffset number|{x:number, y:number}|{horizontal:number, vertical:number}? -- Offset for scrollbar knob/handle position in pixels (number for both axes, or table for per-axis control, default: 0, adds to theme offset)
|
||||||
---@field hideScrollbars boolean|{vertical:boolean, horizontal:boolean}? -- Hide scrollbars (boolean for both, or table for individual control, default: false)
|
---@field hideScrollbars boolean|{vertical:boolean, horizontal:boolean}? -- Hide scrollbars (boolean for both, or table for individual control, default: false)
|
||||||
---@field imagePath string? -- Path to image file (auto-loads via ImageCache)
|
---@field imagePath string? -- Path to image file (auto-loads via ImageCache)
|
||||||
---@field image love.Image? -- Image object to display
|
---@field image love.Image? -- Image object to display
|
||||||
|
|||||||
@@ -546,6 +546,36 @@ local function normalizeBooleanTable(value, defaultValue)
|
|||||||
return { vertical = defaultValue, horizontal = defaultValue }
|
return { vertical = defaultValue, horizontal = defaultValue }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Normalize an offset value to {x, y} or {horizontal, vertical} format
|
||||||
|
---@param value number|table|nil Input value (number applies to both, table for individual control)
|
||||||
|
---@param defaultValue number Default value if nil (default: 0)
|
||||||
|
---@return table Normalized table with x/y or horizontal/vertical fields
|
||||||
|
local function normalizeOffsetTable(value, defaultValue)
|
||||||
|
defaultValue = defaultValue or 0
|
||||||
|
|
||||||
|
if value == nil then
|
||||||
|
return { x = defaultValue, y = defaultValue, horizontal = defaultValue, vertical = defaultValue }
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(value) == "number" then
|
||||||
|
return { x = value, y = value, horizontal = value, vertical = value }
|
||||||
|
end
|
||||||
|
|
||||||
|
if type(value) == "table" then
|
||||||
|
-- Support both {x, y} and {horizontal, vertical} formats
|
||||||
|
local x = value.x or value.horizontal or defaultValue
|
||||||
|
local y = value.y or value.vertical or defaultValue
|
||||||
|
return {
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
horizontal = x,
|
||||||
|
vertical = y,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return { x = defaultValue, y = defaultValue, horizontal = defaultValue, vertical = defaultValue }
|
||||||
|
end
|
||||||
|
|
||||||
-- Text sanitization utilities
|
-- Text sanitization utilities
|
||||||
|
|
||||||
--- Sanitize text to prevent security vulnerabilities
|
--- Sanitize text to prevent security vulnerabilities
|
||||||
@@ -1187,6 +1217,7 @@ return {
|
|||||||
brightenColor = brightenColor,
|
brightenColor = brightenColor,
|
||||||
resolveImagePath = resolveImagePath,
|
resolveImagePath = resolveImagePath,
|
||||||
normalizeBooleanTable = normalizeBooleanTable,
|
normalizeBooleanTable = normalizeBooleanTable,
|
||||||
|
normalizeOffsetTable = normalizeOffsetTable,
|
||||||
resolveFontPath = resolveFontPath,
|
resolveFontPath = resolveFontPath,
|
||||||
getFont = getFont,
|
getFont = getFont,
|
||||||
applyContentMultiplier = applyContentMultiplier,
|
applyContentMultiplier = applyContentMultiplier,
|
||||||
|
|||||||
@@ -1027,6 +1027,54 @@ function TestScrollManagerEdgeCases:testIsMomentumScrolling()
|
|||||||
luaunit.assertTrue(sm:isMomentumScrolling())
|
luaunit.assertTrue(sm:isMomentumScrolling())
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Test scrollbarKnobOffset configuration
|
||||||
|
function TestScrollManagerEdgeCases:testScrollbarKnobOffsetNumber()
|
||||||
|
local sm = createScrollManager({ scrollbarKnobOffset = 5 })
|
||||||
|
luaunit.assertNotNil(sm.scrollbarKnobOffset)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.x, 5)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.y, 5)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.horizontal, 5)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.vertical, 5)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TestScrollManagerEdgeCases:testScrollbarKnobOffsetTableXY()
|
||||||
|
local sm = createScrollManager({ scrollbarKnobOffset = { x = 10, y = 20 } })
|
||||||
|
luaunit.assertNotNil(sm.scrollbarKnobOffset)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.x, 10)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.y, 20)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.horizontal, 10)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.vertical, 20)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TestScrollManagerEdgeCases:testScrollbarKnobOffsetTableHorizontalVertical()
|
||||||
|
local sm = createScrollManager({ scrollbarKnobOffset = { horizontal = 15, vertical = 25 } })
|
||||||
|
luaunit.assertNotNil(sm.scrollbarKnobOffset)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.x, 15)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.y, 25)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.horizontal, 15)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.vertical, 25)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TestScrollManagerEdgeCases:testScrollbarKnobOffsetDefault()
|
||||||
|
local sm = createScrollManager({})
|
||||||
|
luaunit.assertNotNil(sm.scrollbarKnobOffset)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.x, 0)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.y, 0)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.horizontal, 0)
|
||||||
|
luaunit.assertEquals(sm.scrollbarKnobOffset.vertical, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TestScrollManagerEdgeCases:testScrollbarKnobOffsetStatePersistence()
|
||||||
|
local sm = createScrollManager({ scrollbarKnobOffset = { x = 5, y = 10 } })
|
||||||
|
local state = sm:getState()
|
||||||
|
luaunit.assertNotNil(state.scrollbarKnobOffset)
|
||||||
|
|
||||||
|
local sm2 = createScrollManager({})
|
||||||
|
sm2:setState(state)
|
||||||
|
luaunit.assertEquals(sm2.scrollbarKnobOffset.x, 5)
|
||||||
|
luaunit.assertEquals(sm2.scrollbarKnobOffset.y, 10)
|
||||||
|
end
|
||||||
|
|
||||||
if not _G.RUNNING_ALL_TESTS then
|
if not _G.RUNNING_ALL_TESTS then
|
||||||
os.exit(luaunit.LuaUnit.run())
|
os.exit(luaunit.LuaUnit.run())
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ return {
|
|||||||
v1 = {
|
v1 = {
|
||||||
bar = "themes/metal/Button/Button01a_1.9.png",
|
bar = "themes/metal/Button/Button01a_1.9.png",
|
||||||
frame = "themes/metal/Frame/Frame01a.9.png",
|
frame = "themes/metal/Frame/Frame01a.9.png",
|
||||||
|
knobOffset = { x = 4, y = 4 }, -- 0, 0 is default
|
||||||
},
|
},
|
||||||
v2 = {
|
v2 = {
|
||||||
bar = "themes/metal/Button/Button01a_1.9.png",
|
bar = "themes/metal/Button/Button01a_1.9.png",
|
||||||
frame = "themes/metal/Frame/Frame01a.9.png",
|
frame = "themes/metal/Frame/Frame01a.9.png",
|
||||||
|
knobOffset = { x = 4, y = 4 }, -- 0, 0 is default
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components = {
|
components = {
|
||||||
|
|||||||
Reference in New Issue
Block a user