Refactor for documentation

This commit is contained in:
Eduardo Bart
2012-06-25 19:13:30 -03:00
parent 2c7ae6e521
commit 98a1b611bf
106 changed files with 654 additions and 780 deletions

View File

@@ -1,6 +1,7 @@
Effects = {}
-- @docclass
g_effects = {}
function Effects.fadeIn(widget, time, elapsed)
function g_effects.fadeIn(widget, time, elapsed)
if not elapsed then elapsed = 0 end
if not time then time = 300 end
widget:setOpacity(math.min(elapsed/time, 1))
@@ -8,14 +9,14 @@ function Effects.fadeIn(widget, time, elapsed)
if elapsed < time then
removeEvent(widget.fadeEvent)
widget.fadeEvent = scheduleEvent(function()
Effects.fadeIn(widget, time, elapsed + 30)
g_effects.fadeIn(widget, time, elapsed + 30)
end, 30)
else
widget.fadeEvent = nil
end
end
function Effects.fadeOut(widget, time, elapsed)
function g_effects.fadeOut(widget, time, elapsed)
if not elapsed then elapsed = 0 end
if not time then time = 300 end
elapsed = math.max((1 - widget:getOpacity()) * time, elapsed)
@@ -23,14 +24,14 @@ function Effects.fadeOut(widget, time, elapsed)
widget:setOpacity(math.max((time - elapsed)/time, 0))
if elapsed < time then
widget.fadeEvent = scheduleEvent(function()
Effects.fadeOut(widget, time, elapsed + 30)
g_effects.fadeOut(widget, time, elapsed + 30)
end, 30)
else
widget.fadeEvent = nil
end
end
function Effects.cancelFade(widget)
function g_effects.cancelFade(widget)
removeEvent(widget.fadeEvent)
widget.fadeEvent = nil
end

View File

@@ -1,4 +1,5 @@
ToolTip = {}
-- @docclass
g_tooltip = {}
-- private variables
local toolTipLabel
@@ -21,13 +22,13 @@ end
local function onWidgetHoverChange(widget, hovered)
if hovered then
if widget.tooltip and not Mouse.isPressed() then
ToolTip.display(widget.tooltip)
if widget.tooltip and not g_mouse.isPressed() then
g_tooltip.display(widget.tooltip)
currentHoveredWidget = widget
end
else
if widget == currentHoveredWidget then
ToolTip:hide()
g_tooltip.hide()
currentHoveredWidget = nil
end
end
@@ -40,12 +41,12 @@ local function onWidgetStyleApply(widget, styleName, styleNode)
end
-- public functions
function ToolTip.init()
function g_tooltip.init()
connect(UIWidget, { onStyleApply = onWidgetStyleApply,
onHoverChange = onWidgetHoverChange})
addEvent(function()
toolTipLabel = createWidget('UILabel', rootWidget)
toolTipLabel = g_ui.createWidget('UILabel', rootWidget)
toolTipLabel:setId('toolTip')
toolTipLabel:setBackgroundColor('#111111cc')
toolTipLabel:setTextAlign(AlignCenter)
@@ -54,7 +55,7 @@ function ToolTip.init()
end)
end
function ToolTip.terminate()
function g_tooltip.terminate()
disconnect(UIWidget, { onStyleApply = onWidgetStyleApply,
onHoverChange = onWidgetHoverChange })
@@ -62,10 +63,10 @@ function ToolTip.terminate()
toolTipLabel:destroy()
toolTipLabel = nil
ToolTip = nil
g_tooltip = nil
end
function ToolTip.display(text)
function g_tooltip.display(text)
if text == nil then return end
if not toolTipLabel then return end
@@ -75,14 +76,17 @@ function ToolTip.display(text)
toolTipLabel:show()
toolTipLabel:raise()
toolTipLabel:enable()
Effects.fadeIn(toolTipLabel, 100)
g_effects.fadeIn(toolTipLabel, 100)
moveToolTip(toolTipLabel)
end
function ToolTip.hide()
Effects.fadeOut(toolTipLabel, 100)
function g_tooltip.hide()
g_effects.fadeOut(toolTipLabel, 100)
end
-- @docclass UIWidget @{
-- UIWidget extensions
function UIWidget:setTooltip(text)
self.tooltip = text
@@ -92,5 +96,7 @@ function UIWidget:getTooltip()
return self.tooltip
end
ToolTip.init()
connect(g_app, { onTerminate = ToolTip.terminate })
-- @}
g_tooltip.init()
connect(g_app, { onTerminate = g_tooltip.terminate })

View File

@@ -0,0 +1,8 @@
-- @docclass
UIButton = extends(UIWidget)
function UIButton.create()
local button = UIButton.internalCreate()
button:setFocusable(false)
return button
end

View File

@@ -0,0 +1,13 @@
-- @docclass
UICheckBox = extends(UIWidget)
function UICheckBox.create()
local checkbox = UICheckBox.internalCreate()
checkbox:setFocusable(false)
checkbox:setTextAlign(AlignLeft)
return checkbox
end
function UICheckBox:onClick()
self:setChecked(not self:isChecked())
end

View File

@@ -0,0 +1,71 @@
-- @docclass
UIComboBox = extends(UIWidget)
function UIComboBox.create()
local combobox = UIComboBox.internalCreate()
combobox.options = {}
combobox.currentIndex = -1
return combobox
end
function UIComboBox:setCurrentOption(text)
if not self.options then return end
for i,v in ipairs(self.options) do
if v.text == text and self.currentIndex ~= i then
self.currentIndex = i
self:setText(text)
self:onOptionChange(text, v.data)
return
end
end
end
function UIComboBox:setCurrentIndex(index)
if index >= 1 and index <= #self.options then
local v = self.options[index]
self.currentIndex = index
self:setText(v.text)
self:onOptionChange(v.text, v.data)
end
end
function UIComboBox:addOption(text, data)
table.insert(self.options, { text = text, data = data })
local index = #self.options
if index == 1 then self:setCurrentOption(text) end
return index
end
function UIComboBox:onMousePress(mousePos, mouseButton)
local menu = g_ui.createWidget(self:getStyleName() .. 'PopupMenu')
menu:setId(self:getId() .. 'PopupMenu')
for i,v in ipairs(self.options) do
menu:addOption(v.text, function() self:setCurrentOption(v.text) end)
end
menu:setWidth(self:getWidth())
menu:display({ x = self:getX(), y = self:getY() + self:getHeight() })
connect(menu, { onDestroy = function() self:setOn(false) end })
self:setOn(true)
return true
end
function UIComboBox:onMouseWheel(mousePos, direction)
if direction == MouseWheelUp and self.currentIndex > 1 then
self:setCurrentIndex(self.currentIndex - 1)
elseif direction == MouseWheelDown and self.currentIndex < #self.options then
self:setCurrentIndex(self.currentIndex + 1)
end
return true
end
function UIComboBox:onStyleApply(styleName, styleNode)
if styleNode.options then
for k,option in pairs(styleNode.options) do
self:addOption(option)
end
end
end
function UIComboBox:onOptionChange(optionText, optionData)
-- nothing todo
end

View File

@@ -0,0 +1,10 @@
-- @docclass
UILabel = extends(UIWidget)
function UILabel.create()
local label = UILabel.internalCreate()
label:setPhantom(true)
label:setFocusable(false)
label:setTextAlign(AlignLeft)
return label
end

View File

@@ -0,0 +1,68 @@
if not UIWindow then dofile 'uiwindow' end
-- @docclass
UIMessageBox = extends(UIWindow)
MessageBoxOk = 1
MessageBoxCancel = 2
-- messagebox cannot be created from otui files
UIMessageBox.create = nil
function UIMessageBox.display(title, message, flags)
local messagebox = UIMessageBox.internalCreate()
rootWidget:addChild(messagebox)
messagebox:setStyle('MessageBoxWindow')
messagebox:setText(title)
local messageLabel = g_ui.createWidget('MessageBoxLabel', messagebox)
messageLabel:setText(message)
messageLabel:resizeToText()
messagebox:setWidth(math.max(messageLabel:getWidth() + 48, messagebox:getTextSize().width + 20))
messagebox:setHeight(math.max(messageLabel:getHeight() + 64, messagebox:getHeight()))
-- setup messagebox first button
local buttonRight = g_ui.createWidget('MessageBoxRightButton', messagebox)
if flags == MessageBoxOk then
buttonRight:setText('Ok')
connect(buttonRight, { onClick = function(self) self:getParent():ok() end })
connect(messagebox, { onEnter = function(self) self:ok() end })
connect(messagebox, { onEscape = function(self) self:ok() end })
elseif flags == MessageBoxCancel then
buttonRight:setText('Cancel')
connect(buttonRight, { onClick = function(self) self:getParent():cancel() end })
connect(messagebox, { onEnter = function(self) self:cancel() end })
connect(messagebox, { onEscape = function(self) self:cancel() end })
end
messagebox:lock()
return messagebox
end
function displayInfoBox(title, message)
return UIMessageBox.display(title, message, MessageBoxOk)
end
function displayErrorBox(title, message)
return UIMessageBox.display(title, message, MessageBoxOk)
end
function displayCancelBox(title, message)
return UIMessageBox.display(title, message, MessageBoxCancel)
end
function UIMessageBox:ok()
signalcall(self.onOk, self)
self.onOk = nil
self:destroy()
end
function UIMessageBox:cancel()
signalcall(self.onCancel, self)
self.onCancel = nil
self:destroy()
end

View File

@@ -0,0 +1,248 @@
-- @docclass
UIMiniWindow = extends(UIWindow)
function UIMiniWindow.create()
local miniwindow = UIMiniWindow.internalCreate()
return miniwindow
end
function UIMiniWindow:getClassName()
return 'UIMiniWindow'
end
function UIMiniWindow:open(dontSave)
self:setVisible(true)
if not dontSave then
self:setSettings({closed = false})
end
signalcall(self.onOpen, self)
end
function UIMiniWindow:close(dontSave)
self:setVisible(false)
if not dontSave then
self:setSettings({closed = true})
end
signalcall(self.onClose, self)
end
function UIMiniWindow:minimize(dontSave)
self:setOn(true)
self:getChildById('contentsPanel'):hide()
self:getChildById('miniwindowScrollBar'):hide()
self:getChildById('bottomResizeBorder'):hide()
self:getChildById('minimizeButton'):setOn(true)
self.savedHeight = self:getHeight()
self:setHeight(self.minimizedHeight)
if not dontSave then
self:setSettings({minimized = true})
end
signalcall(self.onMinimize, self)
end
function UIMiniWindow:maximize(dontSave)
self:setOn(false)
self:getChildById('contentsPanel'):show()
self:getChildById('miniwindowScrollBar'):show()
self:getChildById('bottomResizeBorder'):show()
self:getChildById('minimizeButton'):setOn(false)
self:setHeight(self.savedHeight)
if not dontSave then
self:setSettings({minimized = false})
end
signalcall(self.onMaximize, self)
end
function UIMiniWindow:onSetup()
self:getChildById('closeButton').onClick =
function()
self:close()
end
self:getChildById('minimizeButton').onClick =
function()
if self:isOn() then
self:maximize()
else
self:minimize()
end
end
local oldParent = self:getParent()
local settings = g_settings.getNode('MiniWindows')
if settings then
local selfSettings = settings[self:getId()]
if selfSettings then
if selfSettings.parentId then
local parent = rootWidget:recursiveGetChildById(selfSettings.parentId)
if parent then
if parent:getClassName() == 'UIMiniWindowContainer' and selfSettings.index and parent:isOn() then
self.miniIndex = selfSettings.index
parent:scheduleInsert(self, selfSettings.index)
elseif selfSettings.position then
self:setParent(parent)
self:setPosition(topoint(selfSettings.position))
self:bindRectToParent()
end
end
end
if selfSettings.minimized then
self:minimize(true)
end
if selfSettings.closed then
self:close(true)
end
end
end
local newParent = self:getParent()
self.miniLoaded = true
if oldParent and oldParent:getClassName() == 'UIMiniWindowContainer' then
oldParent:order()
end
if newParent and newParent:getClassName() == 'UIMiniWindowContainer' and newParent ~= oldParent then
newParent:order()
end
end
function UIMiniWindow:onDragEnter(mousePos)
local parent = self:getParent()
if not parent then return false end
if parent:getClassName() == 'UIMiniWindowContainer' then
local containerParent = parent:getParent()
parent:removeChild(self)
containerParent:addChild(self)
parent:saveChildren()
end
local oldPos = self:getPosition()
self.movingReference = { x = mousePos.x - oldPos.x, y = mousePos.y - oldPos.y }
self:setPosition(oldPos)
self.free = true
return true
end
function UIMiniWindow:onDragMove(mousePos, mouseMoved)
local oldMousePosY = mousePos.y - mouseMoved.y
local children = rootWidget:recursiveGetChildrenByMarginPos(mousePos)
local overAnyWidget = false
for i=1,#children do
local child = children[i]
if child:getParent():getClassName() == 'UIMiniWindowContainer' then
overAnyWidget = true
local childCenterY = child:getY() + child:getHeight() / 2
if child == self.movedWidget and mousePos.y < childCenterY and oldMousePosY < childCenterY then
break
end
if self.movedWidget then
self.setMovedChildMargin(0)
self.setMovedChildMargin = nil
end
if mousePos.y < childCenterY then
self.setMovedChildMargin = function(v) child:setMarginTop(v) end
self.movedIndex = 0
else
self.setMovedChildMargin = function(v) child:setMarginBottom(v) end
self.movedIndex = 1
end
self.movedWidget = child
self.setMovedChildMargin(self:getHeight())
break
end
end
if not overAnyWidget and self.movedWidget then
self.setMovedChildMargin(0)
self.movedWidget = nil
end
return UIWindow.onDragMove(self, mousePos, mouseMoved)
end
function UIMiniWindow:onMousePress()
local parent = self:getParent()
if not parent then return false end
if parent:getClassName() ~= 'UIMiniWindowContainer' then
self:raise()
return true
end
end
function UIMiniWindow:onDragLeave(droppedWidget, mousePos)
if self.movedWidget then
self.setMovedChildMargin(0)
self.movedWidget = nil
self.setMovedChildMargin = nil
self.movedIndex = nil
end
local parent = self:getParent()
if parent then
if parent:getClassName() == 'UIMiniWindowContainer' then
parent:saveChildren()
else
self:saveParentPosition(parent:getId(), self:getPosition())
end
end
end
function UIMiniWindow:onFocusChange(focused)
-- miniwindows only raises when its outside MiniWindowContainers
if not focused then return end
local parent = self:getParent()
if parent and parent:getClassName() ~= 'UIMiniWindowContainer' then
self:raise()
end
end
function UIMiniWindow:setSettings(data)
if not self.save then return end
local settings = g_settings.getNode('MiniWindows')
if not settings then
settings = {}
end
local id = self:getId()
if not settings[id] then
settings[id] = {}
end
for key,value in pairs(data) do
settings[id][key] = value
end
g_settings.setNode('MiniWindows', settings)
end
function UIMiniWindow:saveParentPosition(parentId, position)
local selfSettings = {}
selfSettings.parentId = parentId
selfSettings.position = pointtostring(position)
self:setSettings(selfSettings)
end
function UIMiniWindow:saveParentIndex(parentId, index)
local selfSettings = {}
selfSettings.parentId = parentId
selfSettings.index = index
self:setSettings(selfSettings)
end

View File

@@ -0,0 +1,103 @@
-- @docclass
UIMiniWindowContainer = extends(UIWidget)
function UIMiniWindowContainer.create()
local container = UIMiniWindowContainer.internalCreate()
container.scheduledWidgets = {}
container:setFocusable(false)
container:setPhantom(true)
return container
end
function UIMiniWindowContainer:onDrop(widget, mousePos)
if widget:getClassName() == 'UIMiniWindow' then
local oldParent = widget:getParent()
if oldParent == self then
return true
end
if oldParent then
oldParent:removeChild(widget)
end
if widget.movedWidget then
local index = self:getChildIndex(widget.movedWidget)
self:insertChild(index + widget.movedIndex, widget)
else
self:addChild(widget)
end
return true
end
end
function UIMiniWindowContainer:swapInsert(widget, index)
local oldParent = widget:getParent()
local oldIndex = self:getChildIndex(widget)
if oldParent == self and oldIndex ~= index then
local oldWidget = self:getChildByIndex(index)
self:removeChild(oldWidget)
self:insertChild(oldIndex, oldWidget)
self:removeChild(widget)
self:insertChild(index, widget)
end
end
function UIMiniWindowContainer:scheduleInsert(widget, index)
if index - 1 > self:getChildCount() then
if self.scheduledWidgets[index] then
warning('replacing scheduled widget id ' .. widget:getId())
end
self.scheduledWidgets[index] = widget
else
local oldParent = widget:getParent()
if oldParent ~= self then
oldParent:removeChild(widget)
self:insertChild(index, widget)
while true do
local placed = false
for nIndex,nWidget in pairs(self.scheduledWidgets) do
if nIndex - 1 <= self:getChildCount() then
self:insertChild(nIndex, nWidget)
self.scheduledWidgets[nIndex] = nil
placed = true
break
end
end
if not placed then break end
end
end
end
end
function UIMiniWindowContainer:order()
local children = self:getChildren()
for i=1,#children do
if not children[i].miniLoaded then return end
end
for i=1,#children do
if children[i].miniIndex then
self:swapInsert(children[i], children[i].miniIndex)
end
end
end
function UIMiniWindowContainer:saveChildren()
local children = self:getChildren()
local ignoreIndex = 0
for i=1,#children do
if children[i].save then
children[i]:saveParentIndex(self:getId(), i - ignoreIndex)
else
ignoreIndex = ignoreIndex + 1
end
end
end
function UIMiniWindowContainer:getClassName()
return 'UIMiniWindowContainer'
end

View File

@@ -0,0 +1,80 @@
-- @docclass
UIPopupMenu = extends(UIWidget)
local currentMenu
function UIPopupMenu.create()
local menu = UIPopupMenu.internalCreate()
local layout = UIVerticalLayout.create(menu)
layout:setFitChildren(true)
menu:setLayout(layout)
return menu
end
function UIPopupMenu:display(pos)
-- don't display if not options was added
if self:getChildCount() == 0 then
self:destroy()
return
end
if currentMenu then
currentMenu:destroy()
end
rootWidget:addChild(self)
self:setPosition(pos)
self:grabMouse()
self:grabKeyboard()
currentMenu = self
end
function UIPopupMenu:onGeometryChange()
self:bindRectToParent()
end
function UIPopupMenu:addOption(optionName, optionCallback)
local optionWidget = g_ui.createWidget(self:getStyleName() .. 'Button', self)
local lastOptionWidget = self:getLastChild()
optionWidget.onClick = function(self)
optionCallback()
self:getParent():destroy()
end
optionWidget:setText(optionName)
local width = optionWidget:getTextSize().width + optionWidget:getMarginLeft() + optionWidget:getMarginRight() + 6
self:setWidth(math.max(self:getWidth(), width))
end
function UIPopupMenu:addSeparator()
g_ui.createWidget(self:getStyleName() .. 'Separator', self)
end
function UIPopupMenu:onDestroy()
if currentMenu == self then
currentMenu = nil
end
end
function UIPopupMenu:onMousePress(mousePos, mouseButton)
-- clicks outside menu area destroys the menu
if not self:containsPoint(mousePos) then
self:destroy()
end
return true
end
function UIPopupMenu:onKeyPress(keyCode, keyboardModifiers)
if keyCode == KeyEscape then
self:destroy()
return true
end
return false
end
-- close all menus when the window is resized
local function onRootGeometryUpdate()
if currentMenu then
currentMenu:destroy()
end
end
connect(rootWidget, { onGeometryChange = onRootGeometryUpdate} )

View File

@@ -0,0 +1,36 @@
-- @docclass
UIProgressBar = extends(UIWidget)
function UIProgressBar.create()
local progressbar = UIProgressBar.internalCreate()
progressbar:setFocusable(false)
progressbar:setPhantom(true)
progressbar.percent = 0
progressbar:updateBackground()
return progressbar
end
function UIProgressBar:setPercent(percent)
self.percent = math.max(math.min(percent, 100), 0)
self:updateBackground()
end
function UIProgressBar:getPercent()
return self.percent
end
function UIProgressBar:getPercentPixels()
return 100 / self:getWidth()
end
function UIProgressBar:updateBackground()
local width = math.round(math.max((self.percent * self:getWidth())/100, 1))
local height = self:getHeight()
self:setBackgroundSize({width=width, height=height})
end
function UIProgressBar:onGeometryChange(oldRect, newRect)
self:updateBackground()
end

View File

@@ -1,24 +1,25 @@
RadioGroup = newclass()
-- @docclass
UIRadioGroup = newclass()
function RadioGroup.create()
local radiogroup = RadioGroup.internalCreate()
function UIRadioGroup.create()
local radiogroup = UIRadioGroup.internalCreate()
radiogroup.widgets = {}
return radiogroup
end
function RadioGroup:destroy()
function UIRadioGroup:destroy()
for k,widget in pairs(self.widgets) do
widget.onClick = nil
end
self.widgets = {}
end
function RadioGroup:addWidget(widget)
function UIRadioGroup:addWidget(widget)
table.insert(self.widgets, widget)
widget.onClick = function(widget) self:selectWidget(widget) end
end
function RadioGroup:removeWidget(widget)
function UIRadioGroup:removeWidget(widget)
if self.selectedWidget == widget then
self:selectWidget(nil)
end
@@ -26,7 +27,7 @@ function RadioGroup:removeWidget(widget)
table.removevalue(self.widgets, widget)
end
function RadioGroup:selectWidget(selectedWidget)
function UIRadioGroup:selectWidget(selectedWidget)
if selectedWidget == self.selectedWidget then return end
local previousSelectedWidget = self.selectedWidget

View File

@@ -0,0 +1,105 @@
-- @docclass
UIResizeBorder = extends(UIWidget)
function UIResizeBorder.create()
local resizeborder = UIResizeBorder.internalCreate()
resizeborder:setFocusable(false)
resizeborder.minimum = 0
resizeborder.maximum = 1000
return resizeborder
end
function UIResizeBorder:onHoverChange(hovered)
if hovered then
if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end
if self:getWidth() > self:getHeight() then
g_mouse.setVerticalCursor()
self.vertical = true
else
g_mouse.setHorizontalCursor()
self.vertical = false
end
self.hovering = true
if not self:isPressed() then
g_effects.fadeIn(self)
end
else
if not self:isPressed() and self.hovering then
g_mouse.restoreCursor()
g_effects.fadeOut(self)
self.hovering = false
end
end
end
function UIResizeBorder:onMouseMove(mousePos, mouseMoved)
if self:isPressed() then
if self.vertical then
local delta = mousePos.y - self:getY() - self:getHeight()/2
local parent = self:getParent()
local newsize = math.min(math.max(parent:getHeight() + delta, self.minimum), self.maximum)
if newsize ~= currentMargin then
self.newsize = newsize
if not self.event or self.event:isExecuted() then
self.event = addEvent(function()
parent:setHeight(self.newsize)
end)
end
end
else
local delta = mousePos.x - self:getX() - self:getWidth()/2
local parent = self:getParent()
local newsize = math.min(math.max(parent:getWidth() + delta, self.minimum), self.maximum)
if newsize ~= currentMargin then
self.newsize = newsize
if not self.event or self.event:isExecuted() then
self.event = addEvent(function()
parent:setWidth(self.newsize)
end)
end
end
end
return true
end
end
function UIResizeBorder:onMouseRelease(mousePos, mouseButton)
if not self:isHovered() then
g_mouse.restoreCursor()
g_effects.fadeOut(self)
self.hovering = false
end
end
function UIResizeBorder:onStyleApply(styleName, styleNode)
for name,value in pairs(styleNode) do
if name == 'maximum' then
self:setMaximum(tonumber(value))
elseif name == 'minimum' then
self:setMinimum(tonumber(value))
end
end
end
function UIResizeBorder:onVisibilityChange(visible)
if visible and self.maximum == self.minimum then
self:hide()
end
end
function UIResizeBorder:setMaximum(maximum)
self.maximum = maximum
if self.maximum == self.minimum then
self:hide()
end
end
function UIResizeBorder:setMinimum(minimum)
self.minimum = minimum
if self.maximum == self.minimum then
self:hide()
end
end
function UIResizeBorder:getMaximum() return self.maximum end
function UIResizeBorder:getMinimum() return self.minimum end

View File

@@ -0,0 +1,101 @@
-- @docclass
UIScrollArea = extends(UIWidget)
-- public functions
function UIScrollArea.create()
local scrollarea = UIScrollArea.internalCreate()
scrollarea:setClipping(true)
scrollarea.inverted = false
return scrollarea
end
function UIScrollArea:onStyleApply(styleName, styleNode)
for name,value in pairs(styleNode) do
if name == 'vertical-scrollbar' then
addEvent(function()
self:setVerticalScrollBar(self:getParent():getChildById(value))
end)
elseif name == 'horizontal-scrollbar' then
addEvent(function()
self:setHorizontalScrollBar(self:getParent():getChildById(value))
end)
elseif name == 'inverted-scroll' then
self:setInverted(value)
end
end
end
function UIScrollArea:updateScrollBars()
local offset = { x = 0, y = 0 }
local scrollheight = math.max(self:getChildrenRect().height - self:getPaddingRect().height, 0)
local scrollwidth = math.max(self:getChildrenRect().width - self:getPaddingRect().width, 0)
local scrollbar = self.verticalScrollBar
if scrollbar then
if self.inverted then
scrollbar:setMinimum(-scrollheight)
scrollbar:setMaximum(0)
else
scrollbar:setMinimum(0)
scrollbar:setMaximum(scrollheight)
end
end
local scrollbar = self.horizontalScrollBar
if scrollbar then
if self.inverted then
scrollbar:setMinimum(-scrollwidth)
else
scrollbar:setMaximum(scrollwidth)
end
end
end
function UIScrollArea:setVerticalScrollBar(scrollbar)
self.verticalScrollBar = scrollbar
self.verticalScrollBar.onValueChange = function(scrollbar, value)
local virtualOffset = self:getVirtualOffset()
virtualOffset.y = value
self:setVirtualOffset(virtualOffset)
end
self:updateScrollBars()
end
function UIScrollArea:setHorizontalScrollBar(scrollbar)
self.horizontalScrollBar = scrollbar
self:updateScrollBars()
end
function UIScrollArea:setInverted(inverted)
self.inverted = inverted
end
function UIScrollArea:onLayoutUpdate()
self:updateScrollBars()
end
function UIScrollArea:onMouseWheel(mousePos, mouseWheel)
if self.verticalScrollBar then
if mouseWheel == MouseWheelUp then
self.verticalScrollBar:decrement()
else
self.verticalScrollBar:increment()
end
end
return true
end
function UIScrollArea:onChildFocusChange(focusedChild, oldFocused, reason)
if focusedChild and (reason == MouseFocusReason or reason == KeyboardFocusReason) then
local paddingRect = self:getPaddingRect()
local delta = paddingRect.y - focusedChild:getY()
if delta > 0 then
self.verticalScrollBar:decrement(delta)
end
delta = (focusedChild:getY() + focusedChild:getHeight()) - (paddingRect.y + paddingRect.height)
if delta > 0 then
self.verticalScrollBar:increment(delta)
end
end
end

View File

@@ -0,0 +1,208 @@
-- @docclass
UIScrollBar = extends(UIWidget)
-- private functions
local function calcValues(self)
local slider = self:getChildById('sliderButton')
local decrementButton = self:getChildById('decrementButton')
local incrementButton = self:getChildById('incrementButton')
local pxrange, center
if self.orientation == 'vertical' then
pxrange = (self:getHeight() - decrementButton:getHeight() - decrementButton:getMarginTop() - decrementButton:getMarginBottom()
- incrementButton:getHeight() - incrementButton:getMarginTop() - incrementButton:getMarginBottom())
center = self:getY() + math.floor(self:getHeight() / 2)
else -- horizontal
pxrange = (self:getWidth() - decrementButton:getWidth() - decrementButton:getMarginLeft() - decrementButton:getMarginRight()
- incrementButton:getWidth() - incrementButton:getMarginLeft() - incrementButton:getMarginRight())
center = self:getX() + self:getWidth() / 2
end
local range = self.maximum - self.minimum + 1
local proportion
if self.pixelsScroll then
proportion = pxrange/(range+pxrange)
else
proportion = math.min(math.max(self.step, 1), range)/range
end
local px = math.max(proportion * pxrange, 10)
px = px - px % 2 + 1
local offset = 0
if range == 0 or self.value == self.minimum then
if self.orientation == 'vertical' then
offset = -math.floor((self:getHeight() - px) / 2) + decrementButton:getMarginRect().height
else
offset = -math.floor((self:getWidth() - px) / 2) + decrementButton:getMarginRect().width
end
elseif range > 1 and self.value == self.maximum then
if self.orientation == 'vertical' then
offset = math.ceil((self:getHeight() - px) / 2) - incrementButton:getMarginRect().height
else
offset = math.ceil((self:getWidth() - px) / 2) - incrementButton:getMarginRect().width
end
elseif range > 1 then
offset = (((self.value - self.minimum) / (range - 1)) - 0.5) * (pxrange - px)
end
return range, pxrange, px, offset, center
end
local function updateSlider(self)
local slider = self:getChildById('sliderButton')
if slider == nil then return end
local range, pxrange, px, offset, center = calcValues(self)
if self.orientation == 'vertical' then
slider:setHeight(px)
slider:setMarginTop(offset)
else -- horizontal
slider:setWidth(px)
slider:setMarginLeft(offset)
end
local status = (self.maximum ~= self.minimum)
self:setOn(status)
for _i,child in pairs(self:getChildren()) do
child:setEnabled(status)
end
end
local function parseSliderPos(self, pos)
local point
if self.orientation == 'vertical' then
point = pos.y
else
point = pos.x
end
local range, pxrange, px, offset, center = calcValues(self)
offset = math.min(math.max(point - center, -pxrange/2), pxrange/2)
local newvalue = math.floor(((offset / (pxrange - px)) + 0.5) * (range - 1)) + self.minimum
self:setValue(newvalue)
end
-- public functions
function UIScrollBar.create()
local scrollbar = UIScrollBar.internalCreate()
scrollbar:setFocusable(false)
scrollbar.value = 0
scrollbar.minimum = -999999
scrollbar.maximum = 999999
scrollbar.step = 1
scrollbar.orientation = 'vertical'
scrollbar.pixelsScroll = false
return scrollbar
end
function UIScrollBar:onSetup()
self.setupDone = true
signalcall(self.onValueChange, self, self.value)
g_mouse.bindAutoPress(self:getChildById('decrementButton'), function() self:decrement() end)
g_mouse.bindAutoPress(self:getChildById('incrementButton'), function() self:increment() end)
g_mouse.bindPressMove(self:getChildById('sliderButton'), function(mousePos, mouseMoved) parseSliderPos(self, mousePos) end)
updateSlider(self)
end
function UIScrollBar:onStyleApply(styleName, styleNode)
for name,value in pairs(styleNode) do
if name == 'maximum' then
self:setMaximum(tonumber(value))
elseif name == 'minimum' then
self:setMinimum(tonumber(value))
elseif name == 'step' then
self:setStep(tonumber(value))
elseif name == 'orientation' then
self:setOrientation(value)
elseif name == 'value' then
self:setValue(value)
elseif name == 'pixels-scroll' then
self.pixelsScroll = true
end
end
end
function UIScrollBar:decrement(count)
count = count or self.step
self:setValue(self.value - count)
end
function UIScrollBar:increment(count)
count = count or self.step
self:setValue(self.value + count)
end
function UIScrollBar:setMaximum(maximum)
if maximum == self.maximum then return end
self.maximum = maximum
if self.value > maximum then
self:setValue(maximum)
else
updateSlider(self)
end
end
function UIScrollBar:setMinimum(minimum)
if minimum == self.minimum then return end
self.minimum = minimum
if self.value < minimum then
self:setValue(minimum)
else
updateSlider(self)
end
end
function UIScrollBar:setRange(minimum, maximum)
self:setMinimum(minimum)
self:setMaximum(maximum)
end
function UIScrollBar:setValue(value)
value = math.max(math.min(value, self.maximum), self.minimum)
if self.value == value then return end
local delta = value - self.value
self.value = value
updateSlider(self)
if self.setupDone then
signalcall(self.onValueChange, self, value, delta)
end
end
function UIScrollBar:setStep(step)
self.step = step
end
function UIScrollBar:setOrientation(orientation)
self.orientation = orientation
end
function UIScrollBar:onGeometryChange()
updateSlider(self)
end
function UIScrollBar:onMouseWheel(mousePos, mouseWheel)
if mouseWheel == MouseWheelUp then
if self.orientation == 'vertical' then
self:decrement()
else
self:increment()
end
else
if self.orientation == 'vertical' then
self:increment()
else
self:decrement()
end
end
return true
end
function UIScrollBar:getMaximum() return self.maximum end
function UIScrollBar:getMinimum() return self.minimum end
function UIScrollBar:getValue() return self.value end
function UIScrollBar:getStep() return self.step end
function UIScrollBar:getOrientation() return self.orientation end

View File

@@ -0,0 +1,76 @@
-- @docclass
UISpinBox = extends(UITextEdit)
function UISpinBox.create()
local spinbox = UISpinBox.internalCreate()
spinbox:setValidCharacters('0123456789')
spinbox.minimum = 0
spinbox.maximum = 0
spinbox.value = 0
spinbox:setText("0")
return spinbox
end
function UISpinBox:onMouseWheel(mousePos, direction)
if direction == MouseWheelUp then
self:setValue(self.value + 1)
elseif direction == MouseWheelDown then
self:setValue(self.value - 1)
end
return true
end
function UISpinBox:onTextChange(text, oldText)
if text:len() == 0 then
self:setValue(self.minimum)
return
end
local number = tonumber(text)
if not number or number > self.maximum or number < self.minimum then
self:setText(oldText)
return
end
self:setValue(number)
end
function UISpinBox:onValueChange(value)
-- nothing todo
end
function UISpinBox:onStyleApply(styleName, styleNode)
for name, value in pairs(styleNode) do
if name == 'maximum' then
self:setMaximum(value)
elseif name == 'minimum' then
self:setMinimum(value)
end
end
end
function UISpinBox:setValue(value)
value = math.max(math.min(self.maximum, value), self.minimum)
if value == self.value then return end
if self:getText():len() > 0 then
self:setText(value)
end
self.value = value
signalcall(self.onValueChange, self, value)
end
function UISpinBox:setMinimum(minimum)
self.minimum = minimum
if self.value < minimum then
self:setValue(minimum)
end
end
function UISpinBox:setMaximum(maximum)
self.maximum = maximum
if self.value > maximum then
self:setValue(maximum)
end
end
function UISpinBox:getValue() return self.value end

View File

@@ -0,0 +1,82 @@
-- @docclass
UISplitter = extends(UIWidget)
function UISplitter.create()
local splitter = UISplitter.internalCreate()
splitter:setFocusable(false)
splitter.relativeMargin = 'bottom'
return splitter
end
function UISplitter:onHoverChange(hovered)
if hovered then
if g_mouse.isCursorChanged() or g_mouse.isPressed() then return end
if self:getWidth() > self:getHeight() then
g_mouse.setVerticalCursor()
self.vertical = true
else
g_mouse.setHorizontalCursor()
self.vertical = false
end
self.hovering = true
if not self:isPressed() then
g_effects.fadeIn(self)
end
else
if not self:isPressed() and self.hovering then
g_mouse.restoreCursor()
g_effects.fadeOut(self)
self.hovering = false
end
end
end
function UISplitter:onMouseMove(mousePos, mouseMoved)
if self:isPressed() then
--local currentmargin, newmargin, delta
if self.vertical then
local delta = mousePos.y - self:getY() - self:getHeight()/2
local newMargin = self:canUpdateMargin(self:getMarginBottom() - delta)
local currentMargin = self:getMarginBottom()
if newMargin ~= currentMargin then
self.newMargin = newMargin
if not self.event or self.event:isExecuted() then
self.event = addEvent(function()
self:setMarginBottom(self.newMargin)
end)
end
end
else
local delta = mousePos.x - self:getX() - self:getWidth()/2
local newMargin = self:canUpdateMargin(self:getMarginRight() - delta)
local currentMargin = self:getMarginRight()
if newMargin ~= currentMargin then
self.newMargin = newMargin
if not self.event or self.event:isExecuted() then
self.event = addEvent(function()
self:setMarginRight(self.newMargin)
end)
end
end
end
return true
end
end
function UISplitter:onMouseRelease(mousePos, mouseButton)
if not self:isHovered() then
g_mouse.restoreCursor()
g_effects.fadeOut(self)
self.hovering = false
end
end
function UISplitter:onStyleApply(styleName, styleNode)
if styleNode['relative-margin'] then
self.relativeMargin = styleNode['relative-margin']
end
end
function UISplitter:canUpdateMargin(newMargin)
return newMargin
end

View File

@@ -0,0 +1,132 @@
-- @docclass
UITabBar = extends(UIWidget)
-- private functions
local function onTabClick(tab)
tab.tabBar:selectTab(tab)
end
local function tabBlink(tab)
if not tab.blinking then return end
tab:setOn(not tab:isOn())
tab.blinkEvent = scheduleEvent(function() tabBlink(tab) end, 500)
end
-- public functions
function UITabBar.create()
local tabbar = UITabBar.internalCreate()
tabbar:setFocusable(false)
tabbar.tabs = {}
return tabbar
end
function UITabBar:setContentWidget(widget)
self.contentWidget = widget
if #self.tabs > 0 then
self.contentWidget:addChild(self.tabs[1].tabPanel)
end
end
function UITabBar:addTab(text, panel)
if panel == nil then
panel = g_ui.createWidget(self:getStyleName() .. 'Panel')
panel:setId('tabPanel')
end
local tab = g_ui.createWidget(self:getStyleName() .. 'Button', self)
panel.isTab = true
tab.tabPanel = panel
tab.tabBar = self
tab:setId('tab')
tab:setText(text)
tab:setWidth(tab:getTextSize().width + tab:getPaddingLeft() + tab:getPaddingRight())
tab.onClick = onTabClick
tab.onDestroy = function() tab.tabPanel:destroy() end
table.insert(self.tabs, tab)
if #self.tabs == 1 then
self:selectTab(tab)
end
return tab
end
function UITabBar:removeTab(tab)
local index = table.find(self.tabs, tab)
if index == nil then return end
if self.currentTab == tab then
self:selectPrevTab()
end
table.remove(self.tabs, index)
if tab.blinkEvent then
removeEvent(tab.blinkEvent)
end
tab:destroy()
end
function UITabBar:getTab(text)
for k,tab in pairs(self.tabs) do
if tab:getText():lower() == text:lower() then
return tab
end
end
end
function UITabBar:selectTab(tab)
if self.currentTab == tab then return end
if self.contentWidget then
local selectedWidget = self.contentWidget:getLastChild()
if selectedWidget and selectedWidget.isTab then
self.contentWidget:removeChild(selectedWidget)
end
self.contentWidget:addChild(tab.tabPanel)
tab.tabPanel:fill('parent')
end
if self.currentTab then
self.currentTab:setChecked(false)
end
signalcall(self.onTabChange, self, tab)
self.currentTab = tab
tab:setChecked(true)
tab:setOn(false)
tab.blinking = false
end
function UITabBar:selectNextTab()
if self.currentTab == nil then return end
local index = table.find(self.tabs, self.currentTab)
if index == nil then return end
local nextTab = self.tabs[index + 1] or self.tabs[1]
if not nextTab then return end
self:selectTab(nextTab)
end
function UITabBar:selectPrevTab()
if self.currentTab == nil then return end
local index = table.find(self.tabs, self.currentTab)
if index == nil then return end
local prevTab = self.tabs[index - 1] or self.tabs[#self.tabs]
if not prevTab then return end
self:selectTab(prevTab)
end
function UITabBar:blinkTab(tab)
if tab:isChecked() or tab.blinking then return end
tab.blinking = true
tabBlink(tab)
end
function UITabBar:getTabPanel(tab)
return tab.tabPanel
end
function UITabBar:getCurrentTabPanel()
if self.currentTab then
return self.currentTab.tabPanel
end
end
function UITabBar:getCurrentTab()
return self.currentTab
end

View File

@@ -0,0 +1,21 @@
-- @docclass UIWidget
function UIWidget:setMargin(...)
local params = {...}
if #params == 1 then
self:setMarginTop(params[1])
self:setMarginRight(params[1])
self:setMarginBottom(params[1])
self:setMarginLeft(params[1])
elseif #params == 2 then
self:setMarginTop(params[1])
self:setMarginRight(params[2])
self:setMarginBottom(params[1])
self:setMarginLeft(params[2])
elseif #params == 4 then
self:setMarginTop(params[1])
self:setMarginRight(params[2])
self:setMarginBottom(params[3])
self:setMarginLeft(params[4])
end
end

View File

@@ -0,0 +1,39 @@
-- @docclass
UIWindow = extends(UIWidget)
function UIWindow.create()
local window = UIWindow.internalCreate()
window:setTextAlign(AlignTopCenter)
window:setDragable(true)
return window
end
function UIWindow:onKeyDown(keyCode, keyboardModifiers)
if keyboardModifiers == KeyboardNoModifier then
if keyCode == KeyEnter then
signalcall(self.onEnter, self)
elseif keyCode == KeyEscape then
signalcall(self.onEscape, self)
end
end
end
function UIWindow:onFocusChange(focused)
if focused then self:raise() end
end
function UIWindow:onDragEnter(mousePos)
self:breakAnchors()
self.movingReference = { x = mousePos.x - self:getX(), y = mousePos.y - self:getY() }
return true
end
function UIWindow:onDragLeave(droppedWidget, mousePos)
-- TODO: auto detect and reconnect anchors
end
function UIWindow:onDragMove(mousePos, mouseMoved)
local pos = { x = mousePos.x - self.movingReference.x, y = mousePos.y - self.movingReference.y }
self:setPosition(pos)
self:bindRectToParent()
end