mirror of
				https://github.com/ErikasKontenis/SabrehavenServer.git
				synced 2025-10-31 03:56:22 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			506 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			506 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -- @docclass
 | |
| UIMoveableTabBar = extends(UIWidget, "UIMoveableTabBar")
 | |
| 
 | |
| -- private functions
 | |
| local function onTabClick(tab)
 | |
|   tab.tabBar:selectTab(tab)
 | |
| end
 | |
| 
 | |
| local function updateMargins(tabBar)
 | |
|   if #tabBar.tabs == 0 then return end
 | |
| 
 | |
|   local currentMargin = 0
 | |
|   for i = 1, #tabBar.tabs do
 | |
|     tabBar.tabs[i]:setMarginLeft(currentMargin)
 | |
|     currentMargin = currentMargin + tabBar.tabSpacing + tabBar.tabs[i]:getWidth()
 | |
|   end
 | |
| end
 | |
| 
 | |
| local function updateNavigation(tabBar)
 | |
|   if tabBar.prevNavigation then
 | |
|     if #tabBar.preTabs > 0 or table.find(tabBar.tabs, tabBar.currentTab) ~= 1 then
 | |
|       tabBar.prevNavigation:enable()
 | |
|     else
 | |
|       tabBar.prevNavigation:disable()
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   if tabBar.nextNavigation then
 | |
|     if #tabBar.postTabs > 0 or table.find(tabBar.tabs, tabBar.currentTab) ~= #tabBar.tabs then
 | |
|       tabBar.nextNavigation:enable()
 | |
|     else
 | |
|       tabBar.nextNavigation:disable()
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| local function updateIndexes(tabBar, tab, xoff)
 | |
|   local tabs = tabBar.tabs
 | |
|   local currentMargin = 0
 | |
|   local prevIndex = table.find(tabs, tab)
 | |
|   local newIndex = prevIndex
 | |
|   local xmid = xoff + tab:getWidth()/2
 | |
|   for i = 1, #tabs do
 | |
|     local nextTab = tabs[i]
 | |
|     if xmid >= currentMargin + nextTab:getWidth()/2 then
 | |
|       newIndex = table.find(tabs, nextTab)
 | |
|     end
 | |
|     currentMargin = currentMargin + tabBar.tabSpacing * (i - 1) + tabBar.tabs[i]:getWidth()
 | |
|   end
 | |
|   if newIndex ~= prevIndex then
 | |
|     table.remove(tabs, table.find(tabs, tab))
 | |
|     table.insert(tabs, newIndex, tab)
 | |
|   end
 | |
|   updateNavigation(tabBar)
 | |
| end
 | |
| 
 | |
| local function getMaxMargin(tabBar, tab)
 | |
|   if #tabBar.tabs == 0 then return 0 end
 | |
| 
 | |
|   local maxMargin = 0
 | |
|   for i = 1, #tabBar.tabs do
 | |
|     if tabBar.tabs[i] ~= tab then
 | |
|       maxMargin = maxMargin + tabBar.tabs[i]:getWidth()
 | |
|     end
 | |
|   end
 | |
|   return maxMargin + tabBar.tabSpacing * (#tabBar.tabs - 1)
 | |
| end
 | |
| 
 | |
| local function updateTabs(tabBar)
 | |
|   if #tabBar.postTabs > 0 then
 | |
|     local i = 1
 | |
|     while i <= #tabBar.postTabs do
 | |
|       local tab = tabBar.postTabs[i]
 | |
|       if getMaxMargin(tabBar) + tab:getWidth() > tabBar:getWidth() then
 | |
|         break
 | |
|       end
 | |
| 
 | |
|       table.remove(tabBar.postTabs, i)
 | |
|       table.insert(tabBar.tabs, tab)
 | |
|       tab:setVisible(true)
 | |
|     end
 | |
|   end
 | |
|   if #tabBar.preTabs > 0 then
 | |
|     for i = #tabBar.preTabs, 1, -1 do
 | |
|       local tab = tabBar.preTabs[i]
 | |
|       if getMaxMargin(tabBar) + tab:getWidth() > tabBar:getWidth() then
 | |
|         break
 | |
|       end
 | |
| 
 | |
|       table.remove(tabBar.preTabs, i)
 | |
|       table.insert(tabBar.tabs, 1, tab)
 | |
|       tab:setVisible(true)
 | |
|     end
 | |
|   end
 | |
|   updateNavigation(tabBar)
 | |
|   updateMargins(tabBar)
 | |
|   if not tabBar.currentTab and #tabBar.tabs > 0 then
 | |
|     tabBar:selectTab(tabBar.tabs[1])
 | |
|   end
 | |
| end
 | |
| 
 | |
| local function hideTabs(tabBar, fromBack, toArray, width)
 | |
|   while #tabBar.tabs > 0 and getMaxMargin(tabBar) + width > tabBar:getWidth() do
 | |
|     local index = fromBack and #tabBar.tabs or 1
 | |
|     local tab = tabBar.tabs[index]
 | |
|     table.remove(tabBar.tabs, index)
 | |
|     if fromBack then
 | |
|       table.insert(toArray, 1, tab)
 | |
|     else
 | |
|       table.insert(toArray, tab)
 | |
|     end
 | |
|     if tabBar.currentTab == tab then
 | |
|       if #tabBar.tabs > 0 then
 | |
|         tabBar:selectTab(tabBar.tabs[#tabBar.tabs])
 | |
|       else
 | |
|         tabBar.currentTab:setChecked(false)
 | |
|         tabBar.currentTab = nil
 | |
|       end
 | |
|     end
 | |
|     tab:setVisible(false)
 | |
|   end
 | |
| end
 | |
| 
 | |
| local function showPreTab(tabBar)
 | |
|   if #tabBar.preTabs == 0 then
 | |
|     return nil
 | |
|   end
 | |
| 
 | |
|   local tmpTab = tabBar.preTabs[#tabBar.preTabs]
 | |
|   hideTabs(tabBar, true, tabBar.postTabs, tmpTab:getWidth())
 | |
| 
 | |
|   table.remove(tabBar.preTabs, #tabBar.preTabs)
 | |
|   table.insert(tabBar.tabs, 1, tmpTab)
 | |
|   tmpTab:setVisible(true)
 | |
|   return tmpTab
 | |
| end
 | |
| 
 | |
| local function showPostTab(tabBar)
 | |
|   if #tabBar.postTabs == 0 then
 | |
|     return nil
 | |
|   end
 | |
| 
 | |
|   local tmpTab = tabBar.postTabs[1]
 | |
|   hideTabs(tabBar, false, tabBar.preTabs, tmpTab:getWidth())
 | |
| 
 | |
|   table.remove(tabBar.postTabs, 1)
 | |
|   table.insert(tabBar.tabs, tmpTab)
 | |
|   tmpTab:setVisible(true)
 | |
|   return tmpTab
 | |
| end
 | |
| 
 | |
| local function onTabMousePress(tab, mousePos, mouseButton)
 | |
|   if mouseButton == MouseRightButton then
 | |
|     if tab.menuCallback then tab.menuCallback(tab, mousePos, mouseButton) end
 | |
|     return true
 | |
|   end
 | |
| end
 | |
| 
 | |
| local function onTabDragEnter(tab, mousePos)
 | |
|   tab:raise()
 | |
|   tab.hotSpot = mousePos.x - tab:getMarginLeft()
 | |
|   tab.tabBar.selected = tab
 | |
|   return true
 | |
| end
 | |
| 
 | |
| local function onTabDragLeave(tab)
 | |
|   updateMargins(tab.tabBar)
 | |
|   tab.tabBar.selected = nil
 | |
|   return true
 | |
| end
 | |
| 
 | |
| local function onTabDragMove(tab, mousePos, mouseMoved)
 | |
|   if tab == tab.tabBar.selected then
 | |
|     local xoff = mousePos.x - tab.hotSpot
 | |
| 
 | |
|     -- update indexes
 | |
|     updateIndexes(tab.tabBar, tab, xoff)
 | |
|     updateIndexes(tab.tabBar, tab, xoff)
 | |
| 
 | |
|     -- update margins
 | |
|     updateMargins(tab.tabBar)
 | |
|     xoff = math.max(xoff, 0)
 | |
|     xoff = math.min(xoff, getMaxMargin(tab.tabBar, tab))
 | |
|     tab:setMarginLeft(xoff)
 | |
|   end
 | |
| end
 | |
| 
 | |
| local function tabBlink(tab, step)
 | |
|   local step = step or 0
 | |
|   tab:setOn(not tab:isOn())
 | |
| 
 | |
|   removeEvent(tab.blinkEvent)
 | |
|   if step < 4 then
 | |
|     tab.blinkEvent = scheduleEvent(function() tabBlink(tab, step+1) end, 500)
 | |
|   else
 | |
|     tab:setOn(true)
 | |
|     tab.blinkEvent = nil
 | |
|   end
 | |
| end
 | |
| 
 | |
| -- public functions
 | |
| function UIMoveableTabBar.create()
 | |
|   local tabbar = UIMoveableTabBar.internalCreate()
 | |
|   tabbar:setFocusable(false)
 | |
|   tabbar.tabs = {}
 | |
|   tabbar.selected = nil  -- dragged tab
 | |
|   tabbar.tabSpacing = 0
 | |
|   tabbar.tabsMoveable = false
 | |
|   tabbar.preTabs = {}
 | |
|   tabbar.postTabs = {}
 | |
|   tabbar.prevNavigation = nil
 | |
|   tabbar.nextNavigation = nil
 | |
|   tabbar.onGeometryChange = function()
 | |
|                               hideTabs(tabbar, true, tabbar.postTabs, 0)
 | |
|                               updateTabs(tabbar)
 | |
|                             end
 | |
|   return tabbar
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:onDestroy()
 | |
|   if self.prevNavigation then
 | |
|     self.prevNavigation:disable()
 | |
|   end
 | |
| 
 | |
|   if self.nextNavigation then
 | |
|     self.nextNavigation:disable()
 | |
|   end
 | |
| 
 | |
|   self.nextNavigation = nil
 | |
|   self.prevNavigation = nil
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:setContentWidget(widget)
 | |
|   self.contentWidget = widget
 | |
|   if #self.tabs > 0 then
 | |
|     self.contentWidget:addChild(self.tabs[1].tabPanel)
 | |
|   end
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:setTabSpacing(tabSpacing)
 | |
|   self.tabSpacing = tabSpacing
 | |
|   updateMargins(self)
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:addTab(text, panel, menuCallback)
 | |
|   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:setDraggable(self.tabsMoveable)
 | |
|   tab:setText(text)
 | |
|   tab:setWidth(tab:getTextSize().width + tab:getPaddingLeft() + tab:getPaddingRight())
 | |
|   tab.menuCallback = menuCallback or nil
 | |
|   tab.onClick = onTabClick
 | |
|   tab.onMousePress = onTabMousePress
 | |
|   tab.onDragEnter = onTabDragEnter
 | |
|   tab.onDragLeave = onTabDragLeave
 | |
|   tab.onDragMove = onTabDragMove
 | |
|   tab.onDestroy = function() tab.tabPanel:destroy() end
 | |
| 
 | |
|   if #self.tabs == 0 then
 | |
|     self:selectTab(tab)
 | |
|     tab:setMarginLeft(0)
 | |
|     table.insert(self.tabs, tab)
 | |
|   else
 | |
|     local newMargin = self.tabSpacing * #self.tabs
 | |
|     for i = 1, #self.tabs do
 | |
|       newMargin = newMargin + self.tabs[i]:getWidth()
 | |
|     end
 | |
|     tab:setMarginLeft(newMargin)
 | |
| 
 | |
|     hideTabs(self, true, self.postTabs, tab:getWidth())
 | |
|     table.insert(self.tabs, tab)
 | |
|     if #self.tabs == 1 then
 | |
|       self:selectTab(tab)
 | |
|     end
 | |
|     updateMargins(self)
 | |
|   end
 | |
| 
 | |
|   updateNavigation(self)
 | |
|   return tab
 | |
| end
 | |
| 
 | |
| -- Additional function to move the tab by lua
 | |
| function UIMoveableTabBar:moveTab(tab, units)
 | |
|   local index = table.find(self.tabs, tab)
 | |
|   if index == nil then return end
 | |
| 
 | |
|   local focus = false
 | |
|   if self.currentTab == tab then
 | |
|     self:selectPrevTab()
 | |
|     focus = true
 | |
|   end
 | |
| 
 | |
|   table.remove(self.tabs, index)
 | |
| 
 | |
|   local newIndex = math.min(#self.tabs+1, math.max(index + units, 1))
 | |
|   table.insert(self.tabs, newIndex, tab)
 | |
|   if focus then self:selectTab(tab) end
 | |
|   updateMargins(self)
 | |
|   return newIndex
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:onStyleApply(styleName, styleNode)
 | |
|   if styleNode['movable'] then
 | |
|     self.tabsMoveable = styleNode['movable']
 | |
|   end
 | |
|   if styleNode['tab-spacing'] then
 | |
|     self:setTabSpacing(styleNode['tab-spacing'])
 | |
|   end
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:clearTabs()
 | |
|   while #self.tabs > 0 do
 | |
|     self:removeTab(self.tabs[#self.tabs])
 | |
|   end
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:removeTab(tab)
 | |
|   local tabTables = {self.tabs, self.preTabs, self.postTabs}
 | |
|   local index = nil
 | |
|   local tabTable = nil
 | |
|   for i = 1, #tabTables do
 | |
|     index = table.find(tabTables[i], tab)
 | |
|     if index ~= nil then
 | |
|       tabTable = tabTables[i]
 | |
|       break
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   if tabTable == nil then
 | |
|     return
 | |
|   end
 | |
|   table.remove(tabTable, index)
 | |
|   if self.currentTab == tab then
 | |
|     self:selectPrevTab()
 | |
|     if #self.tabs == 1 then
 | |
|       self.currentTab = nil
 | |
|     end
 | |
|   end
 | |
|   if tab.blinkEvent then
 | |
|     removeEvent(tab.blinkEvent)
 | |
|   end
 | |
|   updateTabs(self)
 | |
|   tab:destroy()
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:getTab(text)
 | |
|   for k,tab in pairs(self.tabs) do
 | |
|     if tab:getText():lower() == text:lower() then
 | |
|       return tab
 | |
|     end
 | |
|   end
 | |
|   for k,tab in pairs(self.preTabs) do
 | |
|     if tab:getText():lower() == text:lower() then
 | |
|       return tab
 | |
|     end
 | |
|   end
 | |
|   for k,tab in pairs(self.postTabs) do
 | |
|     if tab:getText():lower() == text:lower() then
 | |
|       return tab
 | |
|     end
 | |
|   end
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar: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
 | |
| 
 | |
|   if tab.blinkEvent then
 | |
|     removeEvent(tab.blinkEvent)
 | |
|     tab.blinkEvent = nil
 | |
|   end
 | |
| 
 | |
|   local parent = tab:getParent()
 | |
|   parent:focusChild(tab, MouseFocusReason)
 | |
|   updateNavigation(self)
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:selectNextTab()
 | |
|   if self.currentTab == nil then
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   local index = table.find(self.tabs, self.currentTab)
 | |
|   if index == nil then
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   local newIndex = index + 1
 | |
|   if newIndex > #self.tabs then
 | |
|     if #self.postTabs > 0 then
 | |
|       local widget = showPostTab(self)
 | |
|       self:selectTab(widget)
 | |
|     else
 | |
|       if #self.preTabs > 0 then
 | |
|         for i = 1, #self.preTabs do
 | |
|           showPreTab(self)
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       self:selectTab(self.tabs[1])
 | |
|     end
 | |
|     updateTabs(self)
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   local nextTab = self.tabs[newIndex]
 | |
|   if not nextTab then
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   self:selectTab(nextTab)
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:selectPrevTab()
 | |
|   if self.currentTab == nil then
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   local index = table.find(self.tabs, self.currentTab)
 | |
|   if index == nil then
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   local newIndex = index - 1
 | |
|   if newIndex <= 0 then
 | |
|     if #self.preTabs > 0 then
 | |
|       local widget = showPreTab(self)
 | |
|       self:selectTab(widget)
 | |
|     else
 | |
|       if #self.postTabs > 0 then
 | |
|         for i = 1, #self.postTabs do
 | |
|           showPostTab(self)
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       self:selectTab(self.tabs[#self.tabs])
 | |
|     end
 | |
|     updateTabs(self)
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   local prevTab = self.tabs[newIndex]
 | |
|   if not prevTab then
 | |
|     return
 | |
|   end
 | |
| 
 | |
|   self:selectTab(prevTab)
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:blinkTab(tab)
 | |
|   if tab:isChecked() then return end
 | |
|   tab.blinking = true
 | |
|   tabBlink(tab)
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:getTabPanel(tab)
 | |
|   return tab.tabPanel
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:getCurrentTabPanel()
 | |
|   if self.currentTab then
 | |
|     return self.currentTab.tabPanel
 | |
|   end
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:getCurrentTab()
 | |
|   return self.currentTab
 | |
| end
 | |
| 
 | |
| function UIMoveableTabBar:setNavigation(prevButton, nextButton)
 | |
|   self.prevNavigation = prevButton
 | |
|   self.nextNavigation = nextButton
 | |
| 
 | |
|   if self.prevNavigation then
 | |
|     self.prevNavigation.onClick = function() self:selectPrevTab() end
 | |
|   end
 | |
|   if self.nextNavigation then
 | |
|     self.nextNavigation.onClick = function() self:selectNextTab() end
 | |
|   end
 | |
|   updateNavigation(self)
 | |
| end
 | 
