Files
Mush-Soundpack/cosmic rage/lua/mw.lua
2025-07-01 23:28:00 +03:00

480 lines
16 KiB
Lua

-- mw.lua
-- Helper functions for miniwindows
--
-- Author: Nick Gammon - 8th September 2008
--[[
Exposed functions are:
mw.colourtext - show a string with imbedded colour codes
mw.colour_conversion - table with colour codes in it - add more if you want
mw.strip_colours - remove colour codes from a string
mw.popup - make a popup window
mw.tooltip - make a tooltip window
EXAMPLE OF MAKING A POPUP WINDOW:
require "mw"
-- SET UP FOR POPUP WINDOWS - define colours, add fonts, make window id
-- (DO THIS ONCE ONLY, eg. in OnPluginInstall)
-- our window frame/background colours
border_colour = 0xCCD148
background_colour = 0x222222
-- a unique ID
infowin = GetPluginID () .. ":info"
-- font IDs
font_id = "popup_font"
heading_font_id = "popup_heading_font"
font_size = 8
-- use 8 pt Dina or 10 pt Courier
local fonts = utils.getfontfamilies ()
-- choose a font that exists
if fonts.Dina then
font_name = "Dina"
elseif fonts ["Lucida Sans Unicode"] then
font_name = "Lucida Sans Unicode"
else
font_size = 10
font_name = "Courier"
end -- if
-- load fonts
WindowCreate (infowin, 0, 0, 0, 0, 0, 0, 0) -- make initial window
-- install the fonts
WindowFont (infowin, font_id, font_name, font_size, false, false, false, false,
miniwin.font_charset_ansi,
miniwin.font_family_modern + miniwin.font_pitch_fixed)
WindowFont (infowin, heading_font_id, font_name, font_size + 2, false, false, false, false,
miniwin.font_charset_ansi,
miniwin.font_family_modern + miniwin.font_pitch_fixed)
-- NOW DISPLAY A WINDOW
-- what to say - one line per table entry, with imbedded colour codes
info = { "@Ctesting 1 2 3",
"@GThis is a heading",
"Line @Mwith @Bmultiple @Rcolours",
}
heading = "@MHello, @Yworld"
left, top = 40, 50
align_right = false
align_bottom = false
capitalize = true
-- show it
mw.popup (infowin, -- window name to use
heading_font_id, -- font to use for the heading
font_id, -- font to use for each line
heading, -- heading text
info, -- table of lines to show (with colour codes)
left, top, -- where to put it
border_colour, -- colour for round rectangle line
background_colour, -- colour for background
capitalize, -- if true, force the first letter to upper case
align_right, -- if true, align right side on "Left" parameter
align_bottom) -- if true, align bottom side on "Top" parameter
EXAMPLE OF MAKING A TOOLTIP WINDOW:
-- SET UP FOR TOOLTIP WINDOWS - define colours, add fonts, make window id
-- (DO THIS ONCE ONLY, eg. in OnPluginInstall)
-- Example setup code:
require "mw"
-- get ready for tooltips
win_tooltip = GetPluginID () .. "_tooltip"
font_tooltip = "tf"
bold_font_tooltip = "tfb"
-- make the window
WindowCreate (win_tooltip, 0, 0, 0, 0, 0, 0, 0)
-- load some fonts into it
WindowFont (win_tooltip, font_tooltip, "Tahoma", 8)
WindowFont (win_tooltip, bold_font_tooltip, "Tahoma", 8, true)
-- NOW DISPLAY A tooltip (Put bold lines inside asterisks)
mw.tooltip (win_tooltip, -- window name to use
font_tooltip, -- font to use for each line
bold_font_tooltip, -- bold font
"*Info*\nHello, world!\nHave fun.", -- tooltip text
45, 75, -- where to put it (x, y)
0, -- colour for text (black)
0, -- colour for border (black)
ColourNameToRGB ("#FFFFE1")) -- colour for background
--]]
module (..., package.seeall)
DEFAULT_COLOUR = "@w"
TRANSPARENCY_COLOUR = 0x080808
BORDER_WIDTH = 2
local BLACK = 1
local RED = 2
local GREEN = 3
local YELLOW = 4
local BLUE = 5
local MAGENTA = 6
local CYAN = 7
local WHITE = 8
-- colour styles (eg. @r is normal red, @R is bold red)
-- @- is shown as ~
-- @@ is shown as @
-- This table uses the colours as defined in the MUSHclient ANSI tab, however the
-- defaults are shown on the right if you prefer to use those.
colour_conversion = {
k = GetNormalColour (BLACK) , -- 0x000000
r = GetNormalColour (RED) , -- 0x000080
g = GetNormalColour (GREEN) , -- 0x008000
y = GetNormalColour (YELLOW) , -- 0x008080
b = GetNormalColour (BLUE) , -- 0x800000
m = GetNormalColour (MAGENTA) , -- 0x800080
c = GetNormalColour (CYAN) , -- 0x808000
w = GetNormalColour (WHITE) , -- 0xC0C0C0
K = GetBoldColour (BLACK) , -- 0x808080
R = GetBoldColour (RED) , -- 0x0000FF
G = GetBoldColour (GREEN) , -- 0x00FF00
Y = GetBoldColour (YELLOW) , -- 0x00FFFF
B = GetBoldColour (BLUE) , -- 0xFF0000
M = GetBoldColour (MAGENTA) , -- 0xFF00FF
C = GetBoldColour (CYAN) , -- 0xFFFF00
W = GetBoldColour (WHITE) , -- 0xFFFFFF
-- add custom colours here
} -- end conversion table
-- displays text with colour codes imbedded
--
-- win: window to use
-- font_id : font to use
-- Text : what to display
-- Left, Top, Right, Bottom : where to display it
-- Capitalize : if true, turn the first letter into upper-case
function colourtext (win, font_id, Text, Left, Top, Right, Bottom, Capitalize, utf8)
if Text:match ("@") then
local x = Left -- current x position
local need_caps = Capitalize
Text = Text:gsub ("@%-", "~") -- fix tildes
Text = Text:gsub ("@@", "\0") -- change @@ to 0x00
-- make sure we start with @ or gsub doesn't work properly
if Text:sub (1, 1) ~= "@" then
Text = DEFAULT_COLOUR .. Text
end -- if
for colour, text in Text:gmatch ("@(%a)([^@]+)") do
text = text:gsub ("%z", "@") -- put any @ characters back
if need_caps then
local count
text, count = text:gsub ("%a", string.upper, 1)
need_caps = count == 0 -- if not done, still need to capitalize yet
end -- if
if #text > 0 then
x = x + WindowText (win, font_id, text, x, Top, Right, Bottom,
colour_conversion [colour] or GetNormalColour (WHITE), utf8)
end -- some text to display
end -- for each colour run
return x
end -- if
if Capitalize then
Text = Text:gsub ("%a", string.upper, 1)
end -- if leading caps wanted
return WindowText (win, font_id, Text, Left, Top, Right, Bottom,
colour_conversion [DEFAULT_COLOUR] or GetNormalColour (WHITE))
end -- colourtext
-- converts text with colour styles in it into style runs
function ColoursToStyles (Text)
if Text:match ("@") then
astyles = {}
Text = Text:gsub ("@%-", "~") -- fix tildes
Text = Text:gsub ("@@", "\0") -- change @@ to 0x00
-- make sure we start with @ or gsub doesn't work properly
if Text:sub (1, 1) ~= "@" then
Text = DEFAULT_COLOUR .. Text
end -- if
for colour, text in Text:gmatch ("@(%a)([^@]+)") do
text = text:gsub ("%z", "@") -- put any @ characters back
if #text > 0 then
table.insert (astyles, { text = text,
length = #text,
textcolour = colour_conversion [colour] or GetNormalColour (WHITE),
backcolour = GetNormalColour (BLACK) })
end -- if some text
end -- for each colour run.
return astyles
end -- if any colour codes at all
-- No colour codes, create a single style.
return { { text = Text,
length = #Text,
textcolour = GetNormalColour (WHITE),
backcolour = GetNormalColour (BLACK) } }
end -- function ColoursToStyles
-- take a string, and remove colour codes from it (eg. "@Ghello" becomes "hello"
function strip_colours (s)
s = s:gsub ("@%-", "~") -- fix tildes
s = s:gsub ("@@", "\0") -- change @@ to 0x00
s = s:gsub ("@%a([^@]*)", "%1")
return (s:gsub ("%z", "@")) -- put @ back
end -- strip_colours
function popup (win, -- window name to use
heading_font_id, -- font to use for the heading
font_id, -- font to use for each line
heading, -- heading text
info, -- table of lines to show (with colour codes)
Left, Top, -- where to put it
border_colour, -- colour for round rectangle line
background_colour, -- colour for background
capitalize, -- if true, force the first letter to be upper case
align_right, -- if true, align right side on "Left" parameter
align_bottom) -- if true, align bottom side on "Top" parameter
assert (WindowInfo (win, 1), "Window " .. win .. " must already exist")
assert (WindowFontInfo (win, heading_font_id, 1), "No font " .. heading_font_id .. " in " .. win)
assert (WindowFontInfo (win, font_id, 1), "No font " .. font_id .. " in " .. win)
local font_height = WindowFontInfo (win, font_id, 1)
local font_leading = WindowFontInfo (win, font_id, 4) + WindowFontInfo (win, font_id, 5)
local heading_font_height = WindowFontInfo (win, heading_font_id, 1)
-- find text width - minus colour codes
local infowidth = 0
local infoheight = 0
-- calculate heading width and height
if heading and #heading > 0 then
infowidth = WindowTextWidth (win, heading_font_id, strip_colours (heading))
infoheight = heading_font_height
end -- have a heading
-- calculate remaining width and height
for _, v in ipairs (info) do
infowidth = math.max (infowidth, WindowTextWidth (win, font_id, strip_colours (v)))
infoheight = infoheight + font_height
end -- for
infowidth = infowidth + (2 * BORDER_WIDTH) + -- leave room for border
WindowFontInfo (win, font_id, 6) -- one character width extra
infoheight = infoheight + (2 * BORDER_WIDTH) + -- leave room for border
font_leading + -- plus leading below bottom line,
10 -- and 5 pixels top and bottom
if align_right then
Left = Left - infowidth
end -- if align_right
if align_bottom then
Top = Top - infoheight
end -- if align_bottom
WindowCreate (win,
Left, Top, -- where
infowidth, -- width (gap of 5 pixels per side)
infoheight, -- height
miniwin.pos_top_left, -- position mode: can't be 0 to 3
miniwin.create_absolute_location + miniwin.create_transparent,
TRANSPARENCY_COLOUR) -- background (transparent) colour
WindowCircleOp (win, miniwin.circle_round_rectangle,
BORDER_WIDTH, BORDER_WIDTH, -BORDER_WIDTH, -BORDER_WIDTH, -- border inset
border_colour, miniwin.pen_solid, BORDER_WIDTH, -- line
background_colour, miniwin.brush_solid, -- fill
5, 5) -- diameter of ellipse
local x = BORDER_WIDTH + WindowFontInfo (win, font_id, 6) / 2 -- start 1/2 character in
local y = BORDER_WIDTH + 5 -- skip border, and leave 5 pixel gap
-- heading if wanted
if heading and #heading > 0 then
colourtext (win, heading_font_id, heading, x, y, 0, 0, capitalize)
y = y + heading_font_height
end -- have a heading
-- show each line
for _, v in ipairs (info) do
colourtext (win, font_id, v, x, y, 0, 0, capitalize)
y = y + font_height
end -- for
-- display popup window
WindowShow (win, true)
end -- popup
-- --------------------------------------------------------------
-- Displays a tooltip (small box with "arrow" pointing to something of interest)
-- Bold lines are surrounded by asterisks (eg. *Info*)
-- --------------------------------------------------------------
function tooltip (win, -- window name to use
font_id, -- font to use for each line
bold_font_id, -- font to use for bold lines
text, -- tooltip text
Left, Top, -- where to put it (x, y)
text_colour, -- colour for text
border_colour, -- colour for border
background_colour) -- colour for background
assert (WindowInfo (win, 1), "Window " .. win .. " must already exist")
assert (WindowFontInfo (win, font_id, 1), "No font " .. font_id .. " in " .. win)
assert (WindowFontInfo (win, bold_font_id, 1), "No font " .. bold_font_id .. " in " .. win)
local font_height = WindowFontInfo (win, font_id, 1)
local bold_font_height = WindowFontInfo (win, bold_font_id, 1)
local MARGIN = 8
local TIPSIZE = 12
-- break text into lines
local t = utils.split (text, "\n")
-- tooltip height
local height = MARGIN * 2 -- margin at top and bottom
-- tooltip width
local width = TIPSIZE * 2 -- must be at least large enough for the tip part
for k, v in ipairs (t) do
-- bold lines start and end with an asterisk
local boldText = string.match (v, "^%*(.*)%*$")
if boldText then
width = math.max (width, WindowTextWidth (win, bold_font_id, boldText, true))
height = height + bold_font_height
else
width = math.max (width, WindowTextWidth (win, font_id, v, true))
height = height + font_height
end -- if
end -- for
width = width + (MARGIN * 2) -- margin per side
-- the tooltip pointer starts TIPSIZE pixels to the right and descends TIPSIZE pixels
WindowCreate (win,
Left - TIPSIZE, Top - height - TIPSIZE,
width + 2, height + TIPSIZE + 2, -- 2 pixels margin to allow for border + TIPSIZE downwards for the tip
miniwin.pos_top_left, -- position
miniwin.create_absolute_location + miniwin.create_transparent + miniwin.create_ignore_mouse,
TRANSPARENCY_COLOUR)
-- mucking around here to get rounded rectangle
local points = {
-- top LH corner
1, 6,
2, 6,
2, 4,
3, 4,
3, 3,
4, 3,
4, 2,
6, 2,
6, 1,
-- top RH corner
width - 5, 1,
width - 5, 2,
width - 3, 2,
width - 3, 3,
width - 2, 3,
width - 2, 4,
width - 1, 4,
width - 1, 6,
width, 6,
-- bottom RH corner
width, height - 5,
width - 1, height - 5,
width - 1, height - 3,
width - 2, height - 3,
width - 2, height - 2,
width - 3, height - 2,
width - 3, height - 1,
width - 5, height - 1,
width - 5, height,
(TIPSIZE * 2) + 1, height, -- RH side of tip
TIPSIZE + 1, height + TIPSIZE, -- bottom of tip
TIPSIZE + 1, height, -- LH side of tip
-- bottom LH corner
6, height,
6, height - 1,
4, height - 1,
4, height - 2,
3, height - 2,
3, height - 3,
2, height - 3,
2, height - 5,
1, height - 5,
}
-- make the tooltip polygon
WindowPolygon(win, table.concat (points, ","),
border_colour, -- pen colour
miniwin.pen_solid, 1, -- pen (1 pixel wide)
background_colour, -- brush colour
miniwin.brush_solid, -- brush
true) -- close it
-- put the text into it
local top = MARGIN + 1
for _, v in ipairs (t) do
-- bold lines start and end with an asterisk
local boldText = string.match (v, "^%*(.*)%*$")
if boldText then
WindowText (win, bold_font_id, boldText, MARGIN + 1, top, 0, 0, text_colour, true)
top = top + bold_font_height
else
WindowText (win, font_id, v, MARGIN + 1, top, 0, 0, text_colour, true)
top = top + font_height
end -- if
end -- for
WindowShow (win, true)
end -- tooltip