313 lines
11 KiB
Lua
313 lines
11 KiB
Lua
-- tabbed_window.lua
|
|
|
|
--[[
|
|
|
|
Author: Nick Gammon
|
|
Date: 7th February 2018
|
|
|
|
Generic tabbed miniwindow drawer.
|
|
|
|
Exposed functions:
|
|
|
|
init (context) -- call once (from OnPluginInstall), supply:
|
|
|
|
context.win -- window ID for this tabbed window
|
|
context.tabfont -- table of font info for non-active tabs (name, size, unicode, bold, italic)
|
|
context.activefont -- table of font info for the selected tab (name, size, unicode, bold, italic)
|
|
context.titlefont -- table of font info for the title bar (name, size, unicode, bold, italic)
|
|
context.colours -- table of assorted colours (see below for examples)
|
|
context.window -- table (width and height) of the desired window size
|
|
context.tab_filler -- gap between tabs
|
|
context.can_move -- can window be dragged around?
|
|
context.active_tab -- the currently active tab
|
|
context.tabs -- table of tables - one per tab (name, handler)
|
|
|
|
draw_window (context, which_tab) -- draws the window with which_tab as the active tab
|
|
hide_window (context) -- hides this window
|
|
save_state (context) -- for saving the window position (call from OnPluginSaveState)
|
|
|
|
Exposed variables:
|
|
|
|
VERSION -- version of this module
|
|
|
|
--]]
|
|
|
|
module (..., package.seeall)
|
|
|
|
VERSION = 1.1 -- -- for querying by plugins
|
|
|
|
require "movewindow" -- load the movewindow.lua module
|
|
|
|
local default_context = {
|
|
|
|
-- window ID
|
|
win = "tabbed_window_" .. GetUniqueID (),
|
|
|
|
-- font for inactive tab text
|
|
tabfont = {
|
|
id = "fn",
|
|
name = "Lucida Console",
|
|
size = 10, -- points
|
|
unicode = false, -- Unicode?
|
|
bold = false, -- make bold?
|
|
italic = false, -- make italic?
|
|
}, -- end of tabfont
|
|
|
|
-- font for active tab text
|
|
activefont = {
|
|
id = "fa",
|
|
name = "Lucida Console",
|
|
size = 10, -- points
|
|
unicode = false, -- Unicode?
|
|
bold = false, -- make bold?
|
|
italic = false, -- make italic?
|
|
}, -- end of activefont
|
|
|
|
-- font for title text
|
|
titlefont = {
|
|
id = "ft",
|
|
name = "Lucida Console",
|
|
size = 12, -- points
|
|
unicode = false, -- Unicode?
|
|
bold = true, -- make bold?
|
|
italic = false, -- make italic?
|
|
}, -- end of titlefont
|
|
|
|
colours = {
|
|
background = ColourNameToRGB ("lightskyblue"), -- entire window background
|
|
frame = ColourNameToRGB ("mediumorchid"), -- frame around window
|
|
title_bar = ColourNameToRGB ("palegoldenrod"), -- behind the title
|
|
title = ColourNameToRGB ("mediumblue"), -- title text
|
|
tab = ColourNameToRGB ("green"), -- tab background
|
|
tab_text = ColourNameToRGB ("white"), -- inactive tab text
|
|
active_tab_text = ColourNameToRGB ("lightgreen"), -- active tab text
|
|
upper_line = ColourNameToRGB ("lightgray"), -- line above tab text
|
|
lower_line = ColourNameToRGB ("lightgray"), -- line below tab text
|
|
vertical_line = ColourNameToRGB ("lightgray"), -- line between tabs
|
|
}, -- end of colours
|
|
|
|
-- miniwindow size
|
|
window = {
|
|
width = 300,
|
|
height = 200,
|
|
}, -- end of window info
|
|
|
|
-- gap between text in tabs
|
|
tab_filler = 10,
|
|
|
|
-- can it be moved?
|
|
can_move = true,
|
|
|
|
-- which tab is active
|
|
active_tab = 1,
|
|
|
|
-- tabs
|
|
-- table of tabs. For each one supply a table containing a name and a handler,
|
|
-- eg. { name = "Circle", handler = DrawCircle },
|
|
|
|
tabs = { },
|
|
|
|
|
|
} -- end of default_context
|
|
|
|
-- -------------------------------------------------------------------------------
|
|
-- init - initialize this module ready for use (do once)
|
|
-- -------------------------------------------------------------------------------
|
|
function init (context)
|
|
|
|
-- make copy of colours, sizes etc.
|
|
assert (type (context) == "table", "No 'context' table supplied to tabbed_window.")
|
|
|
|
-- force some context defaults if not supplied
|
|
for k, v in pairs (default_context) do
|
|
|
|
-- some context items are tables so copy the table entries
|
|
if type (v) == 'table' then
|
|
if type (context [k]) ~= 'table' then
|
|
assert (context [k] == nil, "tabbed window context item '" .. k .. "' should be a table or nil")
|
|
context [k] = { } -- make table if required
|
|
end -- not having a table there
|
|
for k1, v1 in pairs (v) do
|
|
context [k] [k1] = context [k] [k1] or v1
|
|
end -- for each sub-table item
|
|
else
|
|
context [k] = context [k] or v
|
|
end -- if table or not
|
|
end -- for
|
|
|
|
if next (context.tabs) == nil then
|
|
ColourNote ("orange", "", "Warning: no tabs define for tabbed window")
|
|
end -- if
|
|
|
|
-- install the window movement handler, get back the window position
|
|
context.windowinfo = movewindow.install (context.win, miniwin.pos_top_left, 0) -- default to top left
|
|
|
|
-- save a bit of typing
|
|
local windowinfo = context.windowinfo
|
|
local win = context.win
|
|
local tabfont = context.tabfont
|
|
local activefont = context.activefont
|
|
local titlefont = context.titlefont
|
|
local window = context.window
|
|
local colours = context.colours
|
|
|
|
-- make window so I can grab the font info
|
|
WindowCreate (win,
|
|
windowinfo.window_left,
|
|
windowinfo.window_top,
|
|
window.width,
|
|
window.height,
|
|
windowinfo.window_mode,
|
|
windowinfo.window_flags,
|
|
colours.background)
|
|
|
|
WindowFont (win, tabfont.id, tabfont.name, tabfont.size, tabfont.bold, tabfont.italic, false, false, 0, 0)
|
|
tabfont.height = WindowFontInfo (win, tabfont.id, 1) -- height
|
|
WindowFont (win, activefont.id, activefont.name, activefont.size, activefont.bold, activefont.italic, false, false, 0, 0)
|
|
activefont.height = WindowFontInfo (win, activefont.id, 1) -- height
|
|
WindowFont (win, titlefont.id, titlefont.name, titlefont.size, titlefont.bold, titlefont.italic, false, false, 0, 0)
|
|
titlefont.height = WindowFontInfo (win, titlefont.id, 1) -- height
|
|
|
|
context.client_bottom = context.window.height - context.tabfont.height - 8
|
|
|
|
end -- init
|
|
|
|
function save_state (context)
|
|
-- save window current location for next time
|
|
movewindow.save_state (context.win)
|
|
end -- save_state
|
|
|
|
-- -------------------------------------------------------------------------------
|
|
-- draw_window - draw the tabbed window
|
|
-- -------------------------------------------------------------------------------
|
|
function draw_window (context, whichTab)
|
|
|
|
context.active_tab = whichTab
|
|
|
|
-- save a bit of typing
|
|
local windowinfo = context.windowinfo
|
|
local win = context.win
|
|
local tabfont = context.tabfont
|
|
local activefont = context.activefont
|
|
local titlefont = context.titlefont
|
|
local window = context.window
|
|
local colours = context.colours
|
|
local tabs = context.tabs
|
|
local client_bottom = context.client_bottom
|
|
local tab_filler = context.tab_filler
|
|
|
|
-- clear window
|
|
WindowRectOp (win, miniwin.rect_fill, 0, 0, 0, 0, colours.background)
|
|
WindowDeleteAllHotspots (win)
|
|
|
|
-- draw drag bar rectangle
|
|
WindowRectOp (win, miniwin.rect_fill, 1, 1, 0, titlefont.height + 2, colours.title_bar)
|
|
|
|
-- add the drag handler so they can move the window around
|
|
if context.can_move then
|
|
movewindow.add_drag_handler (win, 0, 0, 0, titlefont.height)
|
|
end -- if can move the window
|
|
|
|
local thisTab = tabs [whichTab]
|
|
|
|
if not thisTab then
|
|
ColourNote ("orange", "", "Tab " .. whichTab .. " does not exist")
|
|
return
|
|
end -- no such tab
|
|
|
|
-- find title width so we can center it
|
|
local title_width = WindowTextWidth (win, titlefont.id, thisTab.name, titlefont.unicode)
|
|
|
|
-- draw title
|
|
WindowText(win, titlefont.id, thisTab.name, (window.width - title_width )/ 2 + 1, 1, 0, 0, colours.title, titlefont.unicode)
|
|
|
|
-- frame window
|
|
WindowRectOp (win, miniwin.rect_frame, 0, 0, 0, 0, colours.frame)
|
|
|
|
-- draw tabs
|
|
|
|
local left = 1
|
|
|
|
-- we have to make a function to handle each tabbed window, so its
|
|
-- name must include the window ID
|
|
local mouse_down_function_name = "tabbed_window_mouse_down_handler_" .. win
|
|
|
|
-- the function will have the context as a closure
|
|
getfenv () [mouse_down_function_name] = function (flags, hotspot_id)
|
|
local whichTab = string.match (hotspot_id, "^hs(%d)$")
|
|
if not whichTab then -- tab unknown for some reason
|
|
ColourNote ("orange", "", "Mousedown tab unknown " .. hotspot_id)
|
|
return
|
|
end -- if
|
|
|
|
draw_window (context, tonumber (whichTab))
|
|
|
|
end -- mouse_down_function_name
|
|
|
|
for k, v in ipairs (tabs) do
|
|
local tab_width
|
|
|
|
if k == whichTab then
|
|
tab_width = WindowTextWidth (win, activefont.id, v.name, activefont.unicode)
|
|
else
|
|
tab_width = WindowTextWidth (win, tabfont.id, v.name, tabfont.unicode)
|
|
end -- if
|
|
|
|
-- tab background
|
|
WindowRectOp (win, miniwin.rect_fill, left, client_bottom, left + tab_width + tab_filler, window.height - 1, colours.tab)
|
|
|
|
-- tab text
|
|
if k == whichTab then
|
|
WindowText(win, activefont.id, v.name, left + tab_filler / 2, client_bottom + 4, 0, 0, colours.active_tab_text, activefont.unicode)
|
|
else
|
|
WindowText(win, tabfont.id, v.name, left + tab_filler / 2, client_bottom + 4, 0, 0, colours.tab_text, tabfont.unicode)
|
|
end -- if
|
|
|
|
-- draw upper line if not active tab
|
|
if k ~= whichTab then
|
|
WindowLine(win, left, client_bottom + 2, left + tab_width + tab_filler, client_bottom + 2,
|
|
colours.upper_line, miniwin.pen_solid, 2)
|
|
end -- if not active
|
|
|
|
-- draw lower line
|
|
WindowLine(win, left, window.height - 1, left + tab_width + tab_filler, window.height - 1,
|
|
colours.lower_line, miniwin.pen_solid, 1)
|
|
|
|
-- draw vertical lines
|
|
WindowLine(win, left, client_bottom + 2, left, window.height - 1,
|
|
colours.vertical_line, miniwin.pen_solid, 1)
|
|
WindowLine(win, left + tab_width + tab_filler, client_bottom + 2, left + tab_width + tab_filler, window.height - 1,
|
|
colours.vertical_line, miniwin.pen_solid, 1)
|
|
|
|
-- now add a hotspot for this tab
|
|
WindowAddHotspot(win, "hs" .. k,
|
|
left, client_bottom, left + tab_width + tab_filler, window.height - 1, -- rectangle
|
|
"", -- mouseover
|
|
"", -- cancelmouseover
|
|
"tabbed_window." .. mouse_down_function_name,
|
|
"", -- cancelmousedown
|
|
"", -- mouseup
|
|
"Show " .. v.name .. " tab", -- tooltip text
|
|
miniwin.cursor_hand, 0) -- hand cursor
|
|
|
|
left = left + tab_width + tab_filler
|
|
|
|
end -- for each tab
|
|
|
|
-- call handler to draw rest of window
|
|
local handler = thisTab.handler
|
|
if handler then
|
|
handler (win, 1, titlefont.height + 2, window.width - 1, client_bottom, context)
|
|
else
|
|
ColourNote ("orange", "", "No tab handler for " .. thisTab.name)
|
|
end -- if
|
|
|
|
WindowShow (win, true)
|
|
end -- draw_window
|
|
|
|
-- -------------------------------------------------------------------------------
|
|
-- hide_window - hide the tabbed window
|
|
-- -------------------------------------------------------------------------------
|
|
function hide_window (context)
|
|
WindowShow (context.win, false)
|
|
end -- hide_window |