Message
| It's a good question, and something I've been planning to demonstrate for a while. Tabbed windows have three major things:
- A title bar showing the name of the currently-active tab, and which lets you drag the window around
- The "client" area which changes depending on the selected tab
- The tabs at the bottom (or top, or wherever) which let you change tabs, and also show (by the way they are drawn) what the current tab is
The plugin below implements a demonstration of that, hopefully in a modular-enough format for you to adapt to your needs.
|
To save and install the TabDemo plugin do this:
- Copy between the lines below (to the Clipboard)
- Open a text editor (such as Notepad) and paste the plugin into it
- Save to disk on your PC, preferably in your plugins directory, as TabDemo.xml
- Go to the MUSHclient File menu -> Plugins
- Click "Add"
- Choose the file TabDemo.xml (which you just saved in step 3) as a plugin
- Click "Close"
|
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
name="TabDemo"
author="Nick Gammon"
id="302097c20a726d174b9d692a"
language="Lua"
purpose="Demonstrates a tabbed miniwindow"
date_written="2018-02-06 15:24:08"
requires="5.00"
save_state="y"
version="1.0"
>
<description trim="y">
<![CDATA[
Demonstrates doing a miniwindow with tabs.
]]>
</description>
</plugin>
<!-- Script -->
<script>
<![CDATA[
-- colours
background_colour = ColourNameToRGB "lightskyblue"
frame_colour = ColourNameToRGB "mediumorchid"
title_bar_colour = ColourNameToRGB "palegoldenrod"
title_colour = ColourNameToRGB "mediumblue"
tab_colour = ColourNameToRGB "green"
tab_text_colour = ColourNameToRGB "white"
-- miniwindow size
window_width = 300
window_height = 200
-- gap between text in tabs
tab_filler = 10
-- -------------------------------------------------------------------------------
-- Handlers for drawing the contents of each tab
-- -------------------------------------------------------------------------------
function DrawCircle (left, top, right, bottom)
local circle_size = 60
WindowRectOp (win, miniwin.rect_fill, -- fill
left, top, right, bottom,
ColourNameToRGB "peachpuff")
WindowCircleOp (win, miniwin.circle_ellipse, -- circle
(right - left) / 2 - circle_size / 2, (bottom - top) / 2 - circle_size / 2, -- Left, Top,
(right - left) / 2 + circle_size / 2, (bottom - top) / 2 + circle_size / 2, -- Right, Bottom
ColourNameToRGB("blue"), miniwin.pen_solid, 2, -- pen width 2
ColourNameToRGB("cyan"), miniwin.brush_solid) -- brush
end -- DrawCircle
function DrawSquare (left, top, right, bottom)
local square_size = 80
WindowRectOp (win, miniwin.rect_fill, -- square
(right - left) / 2 - square_size / 2, (bottom - top) / 2 - square_size / 2, -- Left, Top,
(right - left) / 2 + square_size / 2, (bottom - top) / 2 + square_size / 2, -- Right, Bottom
ColourNameToRGB("lightcoral"), miniwin.pen_solid, 2, -- pen width 2
ColourNameToRGB("violet"), miniwin.brush_solid) -- brush
end -- DrawSquare
function DrawArrow (left, top, right, bottom)
WindowPolygon (win, "20,50,180,50,180,20,230,70,180,120,180,90,20,90",
ColourNameToRGB("cyan"), miniwin.pen_solid, 3, -- pen (solid, width 3)
ColourNameToRGB("yellow"), miniwin.brush_solid, -- brush (solid)
true, -- fill
false) -- alternate fill
end -- DrawArrow
function DrawPie (left, top, right, bottom)
local pie_size = 80
WindowCircleOp (win, miniwin.circle_pie, -- pie
(right - left) / 2 - pie_size / 2, (bottom - top) / 2 - pie_size / 2, -- Left, Top,
(right - left) / 2 + pie_size / 2, (bottom - top) / 2 + pie_size / 2, -- Right, Bottom
ColourNameToRGB("green"), miniwin.pen_solid, 2, -- pen width 2
ColourNameToRGB("cyan"), miniwin.brush_solid, -- brush
0, right, -- the x, y position of the pie's starting point
right, bottom) -- the x, y position of the pie's ending point
end -- DrawPie
-- -------------------------------------------------------------------------------
-- tabs - table of all available tabs
-- -------------------------------------------------------------------------------
tabs = {
{ name = "Circle", handler = DrawCircle },
{ name = "Square", handler = DrawSquare },
{ name = "Arrow", handler = DrawArrow },
{ name = "Pie", handler = DrawPie },
} -- end of tabs
active_tab = 1
-- -------------------------------------------------------------------------------
-- OnPluginInstall
-- -------------------------------------------------------------------------------
function OnPluginInstall ()
win = GetPluginID ()
font_id = "fn"
font_name = "Lucida Console" -- the font name
require "movewindow" -- load the movewindow.lua module
-- install the window movement handler, get back the window position
windowinfo = movewindow.install (win, miniwin.pos_top_left) -- default to top left
-- 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,
background_colour)
WindowFont (win, font_id, font_name, 8, false, false, false, false, 0, 0) -- normal
font_height = WindowFontInfo (win, font_id, 1) -- height
client_bottom = window_height - font_height - 8
DrawWindow (1)
end -- OnPluginInstall
-- -------------------------------------------------------------------------------
-- OnPluginSaveState
-- -------------------------------------------------------------------------------
function OnPluginSaveState ()
-- save window current location for next time
movewindow.save_state (win)
end -- function OnPluginSaveState
-- -------------------------------------------------------------------------------
-- mousedown - handle clicking on a tab
-- -------------------------------------------------------------------------------
function tab_mouse_down (flags, hotspot_id)
local whichTab = string.match (hotspot_id, "^hs(%d)$")
if not whichTab then -- tab unknown for some reason
return
end -- if
DrawWindow (tonumber (whichTab))
end -- tab_mouse_down
-- -------------------------------------------------------------------------------
-- DrawWindow - draw the tabbed window
-- -------------------------------------------------------------------------------
function DrawWindow (whichTab)
active_tab = whichTab
-- clear window
WindowRectOp (win, miniwin.rect_fill, 0, 0, 0, 0, background_colour)
WindowDeleteAllHotspots (win)
-- draw drag bar rectangle
WindowRectOp (win, miniwin.rect_fill, 1, 1, 0, font_height + 2, title_bar_colour)
-- add the drag handler so they can move the window around
movewindow.add_drag_handler (win, 0, 0, 0, font_height)
local thisTab = tabs [whichTab]
-- find title width so we can center it
title_width = WindowTextWidth (win, font_id, thisTab.name)
-- draw title
WindowText(win, font_id, thisTab.name, (window_width - title_width )/ 2 + 1, 1, 0, 0, title_colour)
-- frame window
WindowRectOp (win, miniwin.rect_frame, 0, 0, 0, 0, frame_colour)
-- draw tabs
local left = 1
for k, v in ipairs (tabs) do
local tab_width = WindowTextWidth (win, font_id, v.name)
-- tab background
WindowRectOp (win, miniwin.rect_fill, left, client_bottom, left + tab_width + tab_filler, window_height - 1, tab_colour)
-- tab text
WindowText(win, font_id, v.name, left + tab_filler / 2, client_bottom + 4, 0, 0, tab_text_colour)
-- 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,
ColourNameToRGB "lightgray", 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,
ColourNameToRGB "lightgray", miniwin.pen_solid, 1)
-- draw vertical lines
WindowLine(win, left, client_bottom + 2, left, window_height - 1,
ColourNameToRGB "lightgray", miniwin.pen_solid, 1)
WindowLine(win, left + tab_width + tab_filler, client_bottom + 2, left + tab_width + tab_filler, window_height - 1,
ColourNameToRGB "lightgray", 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
"tab_mouse_down",
"", -- cancelmousedown
"", -- mouseup
"Select " .. 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 (1, font_height + 2, window_width - 1, client_bottom)
else
ColourNote ("orange", "", "No tab handler for " .. thisTab.name)
end -- if
WindowShow (win, true)
end -- DrawWindow
]]>
</script>
</muclient>
You shouldn't need to change much of it, except the "tab handlers" which draw the contents of the tabs (only one is drawn at a time, of course) and the table of tabs, which refers to the tab handlers.
Example of it in operation:
The tab handlers are given the dimensions of the "client" area (left, top, right, bottom) which is where they should draw inside. You can use that, for example, to clear the client area as I did in the case of the circle.
You can see that the active tab looks a bit different (at the bottom) and the name of the currently-selected tab appears in the title area. |
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|