-- -- NoteBook Widget. -- @copyright Jefferson Gonzalez -- @license MIT -- local style = require "core.style" local Widget = require "libraries.widget" local Button = require "libraries.widget.button" local HSPACING = 2 local VSPACING = 2 ---Represents a notebook pane ---@class widget.notebook.pane ---@field public name string ---@field public tab widget.button ---@field public container widget local NoteBookPane = {} ---@class widget.notebook : widget ---@field public panes widget.notebook.pane[] ---@field public active_pane widget.notebook.pane local NoteBook = Widget:extend() ---Notebook constructor ---@param parent widget function NoteBook:new(parent) NoteBook.super.new(self, parent) self.type_name = "widget.notebook" self.panes = {} self.active_pane = nil end ---Called when a tab is clicked. ---@param pane widget.notebook.pane ---@diagnostic disable-next-line function NoteBook:on_tab_click(pane) end ---Adds a new pane to the notebook and returns a container widget where ---you can add more child elements. ---@param name string ---@param label string ---@return widget container function NoteBook:add_pane(name, label) ---@type widget.button local tab = Button(self, label) tab.border.width = 0 if #self.panes > 0 then tab:set_position(self.panes[#self.panes].tab:get_right() + HSPACING, 0) end local container = Widget(self) container.scrollable = true container:set_position(0, tab:get_bottom() + VSPACING) container:set_size( self:get_width(), self:get_height() - tab:get_height() - VSPACING ) local pane = { name = name, tab = tab, container = container } if not self.active_pane then self.active_pane = pane end tab.on_click = function() self.active_pane = pane self:on_tab_click(pane) end table.insert(self.panes, pane) return container end ---Search the pane for the given name and return it. ---@param name string ---@return widget.notebook.pane | nil function NoteBook:get_pane(name) for _, pane in pairs(self.panes) do if pane.name == name then return pane end end return nil end ---Activates the given pane. ---@param name string ---@return boolean function NoteBook:set_pane(name) local pane = self:get_pane(name) if pane then self.active_pane = pane return true end return false end ---Change the tab label of the given pane. ---@param name string ---@param label string function NoteBook:set_pane_label(name, label) local pane = self:get_pane(name) if pane then pane.tab:set_label(label) return true end return false end ---Set or remove the icon for the given pane. ---@param name string ---@param icon? string|nil ---@param color? renderer.color|nil ---@param hover_color? renderer.color|nil function NoteBook:set_pane_icon(name, icon, color, hover_color) local pane = self:get_pane(name) if pane then pane.tab:set_icon(icon, color, hover_color) return true end return false end ---Recalculate the position of the elements on resizing or position ---changes and also make changes to properly render active pane. function NoteBook:update() if not NoteBook.super.update(self) then return false end for pos, pane in pairs(self.panes) do if pos ~= 1 then pane.tab:set_position( self.panes[pos-1].tab:get_right() + HSPACING, 0 ) else pane.tab:set_position(0, 0) end if pane ~= self.active_pane then if pane.container.visible then pane.tab.background_color = style.background pane.tab.foreground_color = style.text pane.container:hide() end elseif not pane.container.visible then pane.container:show() end end if self.active_pane then self.active_pane.tab.foreground_color = style.accent self.active_pane.container:set_position( 0, self.active_pane.tab:get_bottom() + VSPACING ) self.active_pane.container:set_size( self:get_width(), self:get_height() - self.active_pane.tab:get_height() - VSPACING ) self.active_pane.container.border.color = style.divider end return true end ---Here we draw the bottom line on the tab of active pane. function NoteBook:draw() if not NoteBook.super.draw(self) then return false end if self.active_pane then local x = self.active_pane.tab.position.x local y = self.active_pane.tab.position.y + self.active_pane.tab:get_bottom() local w = self.active_pane.tab:get_width() renderer.draw_rect(x, y, w, HSPACING, style.caret) end return true end return NoteBook