Easy DIY Miniwindows - fiendish/aardwolfclientpackage GitHub Wiki
Note: This is still experimental. Elements may change or improve. Watch this space.
The Aardwolf MUSHclient Package now includes special Lua code modules to bypass most or all of the horrible complexity of making miniwindows for your plugins.
Instructions
First, your plugin must be written in Lua. If you don't like Lua, I'm sorry.
Prefer learning by example? Explore the aard_ingame_help_window.xml plugin.
Step 1: Add require "themed_miniwindows"
at the top of your plugin's script section.
To make a basic miniwindow, call:
my_window = ThemedBasicWindow(
id, -- string, required, a unique identifier for this window
default_left_position, -- integer, required, where to put it if the player hasn't moved it
default_top_position, -- integer, required, where to put it if the player hasn't moved it
default_width, -- integer, required, how big to make it if the player hasn't moved it
default_height, -- integer, required, how big to make it if the player hasn't moved it
title, -- string, optional (nil means no titlebar), text to put into the title
title_alignment, -- string, optional (default is "center"), "left", "center", or "right"
is_temporary, -- boolean, optional (default is false), true adds a close button in the top left
resizer_type, -- nil/integer, optional (default is nil), nil for non-resizeable, 1 for demi, 2 for full
do_while_resizing, -- function, optional (default is nil), display function to call while resizing
do_after_resizing, -- function, optional (default is nil), display function to call after resizing is done
do_on_delete, -- function, optional (default is nil), cleanup function to call when closed/deleted
title_font_name, -- string, optional (default is Dina), override the default font name
title_font_size, -- integer, optional (default is 10), override the default font size
defer_showing, -- boolean, optional (default is false), true will prevent the window from appearing until you call :show() on it
body_is_transparent -- boolean, optional (default is false), if true, pixels the same color as Theme.PRIMARY_BODY will be transparent
)
Then draw whatever you want within the bounds of my_window.bodyleft
, my_window.bodytop
, my_window.bodyright
, and my_window.bodybottom
using the standard miniwindow drawing functions. There is no protection against you drawing on top of the window frame (titlebar, border, etc). You must protect yourself and stay within the lines. Get your magnifying glass out and make sure you don't accidentally draw over the edges.
As a best practice, put all of your custom drawing code into one function. If your miniwindow is resizable, assign that function as do_after_resizing
and do_while_resizing
above. If your drawing is too slow for smooth resizing, make a smaller faster function and assign that as do_while_resizing
instead.
Normally changing color themes (see: Miniwindow-Color-Themes) restarts all plugins. This may not be desirable. To prevent your plugin from being restarted and instead just redraw your miniwindows when the player switches color themes, add this function to your plugin:
function OnPluginThemeChange()
if WindowInfo(my_window_id, 1) ~= nil then
-- Miniwindow color themes are applied at their creation, so create
-- existing windows again here if the theme changes.
end
end
Drawing to miniwindows does not automatically update the screen, so after your custom drawing code is finished, you may want to do CallPlugin("abc1a0944ae4af7586ce88dc", "BufferedRepaint")
. This code will handle it for you during resizing, but not necessarily at other times.
If you need to paint over the body of a basic window with the background color, call
my_window:blank()
This does not remove any custom hotspots you might have added yourself.
If you need to reapply the window dressing (maybe you want to paint content partially behind the resizer widget), call
my_window:dress_window()
Or to change the window's title, call dress_window with the new title information
my_window:dress_window(new_title)
To delete my_window, call
my_window:delete()
Creating a new easy miniwindow with the same unique identifier as an existing one will automatically delete the previous one, so if you're just re-creating an existing one, there's no need to call delete() on it first. Setting is_temporary
to true during window creation will add a button to the top-left corner of the window that deletes the window when clicked.
To reset my_window to its default position and size, call
my_window:reset()
Easy miniwindows will remember their size and location automatically if the player moves them around or resizes them.
To programmatically resize my_window without dragging the corner, call
my_window:resize(width, height)
To show/hide my_window, call
my_window:show()
or
my_window:hide()
If you created my_window with defer_showing
set to true, you will need to call my_window:show() for it to be visible.
To get my_window's special WindowMenu objects, call
my_window:get_menu_items()
Easy miniwindows come pre-made with a right-click menu with commands to move the window to the front/back. If you want to override the hotspot that creates the right-click menu, you can optionally use these to migrate the built-in menu options into your own custom menu. This function returns a string and a numerically-indexed table of functions. You are expected to always prefix your WindowMenu strings with "!" in order to use the numeric indexes. If you don't know what this means or are confused, feel free to ask Fiendish in-game.
To change Z-order (front/back placement) of my_window without using the right-click menu, call
my_window:bring_to_front()
or
my_window:send_to_back()
To add clickable buttons to easy miniwindows, call
right, bottom = my_window:add_button(
id, -- string, required, a unique identifier for this button
left, -- integer, optional (default is my_window.bodyleft), where to put it in the window
top, -- integer, optional (default is my_window.bodytop), where to put it in the window
text, -- string, optional (default is nothing), what to write on the button
utf8, -- boolean, optional (default is false), whether the text should be interpreted as utf8
tooltip, -- string, optional (default is none), mouseover tooltip
mousedown_callback, -- function, optional (default is none), function to call when the button is pressed down
mouseup_callback, -- function, optional (default is none), function to call when the pressed button is released
font, -- string, optional (default is my_win.title_font), which font to use
x_padding, -- integer, optional, how much space between the button text and the edge of the button
y_padding, -- integer, optional, how much space between the button text and the edge of the button
width, -- integer, optional, negates x_padding, manually set the button width
height, -- integer, optional, negates y_padding, manually set the button height
style -- string, optionally one of Theme.STYLE_3D, Theme.STYLE_FLAT, Theme.STYLE_TRANSPARENT (default is flat), chooses the style of button (body_is_transparent must be set on the window for the transparent style to work)
)
(right
and bottom
are the bottom-right corner of the created button so you know how big the button is if you let it automatically set its own size from your text)
To make a text miniwindow, call:
my_window = ThemedTextWindow(
id, -- string, required, a unique identifier for this window
default_left_position, -- integer, required, where to put it if the player hasn't moved it
default_top_position, -- integer, required, where to put it if the player hasn't moved it
default_width, -- integer, required, how big to make it if the player hasn't moved it
default_height, -- integer, required, how big to make it if the player hasn't moved it
title, -- string, optional (nil means no titlebar), text to put into the title
title_alignment, -- string, optional (default is "center"), "left", "center", or "right"
is_temporary, -- boolean, optional (default is false), true adds a close button in the top left
resizeable, -- boolean, optional (default is false), make the window resizeable
text_scrollable, -- boolean, optional (default is false), add a scrollbar and mousewheel scrolling
text_selectable, -- boolean, optional (default is false), make the text selectable
text_copyable, -- boolean, optional (default is false), make the text copyable via right-click
url_hyperlinks, -- boolean, optional (default is false), turn detected URLs into clickable links
autowrap, -- boolean, optional (default is false), automatically wrap text lines that are too wide
title_font_name, -- string, optional (default is Dina), override the title font name
title_font_size, -- integer, optional (default is 10), override the title font size
text_font_name, -- string, optional (default is Dina), override the body text font name
text_font_size, -- integer, optional (default is 10), override the body text font size
text_max_lines, -- integer, optional (default is 1000), maximum number of text lines to keep
text_padding, -- integer, optional (default is 5 pixels), space between text and miniwindow frame
defer_showing, -- boolean, optional (default is false), true will prevent the window from appearing until you call :show() on it
body_is_transparent -- boolean, optional (default is false), if true, pixels the same color as Theme.PRIMARY_BODY will be transparent
)
In addition to all of the functions from ThemedBasicWindow, ThemedTextWindow also has:
To add text to a ThemedTextWindow, call
my_window:add_text(
string_or_styles, -- string or table, required, text string with Aardwolf color codes or table of MUSHclient style tables
draw_after, -- boolean, optional (default is true), set to false to not immediately draw the new condition of the window
links, -- table, optional, set as shown below to add clickable links within the line text
)
Links structure:
{
{
label=<tooltip text to show>,
start=<index on line where link begins>,
stop=<index on line where link ends>,
text=<script text to perform>,
},
...
}
See example of use down below.
This also accepts multiple lines at once either by embedding "\n" in your text string or nesting multiple stylerun tables in an enclosing table. (There are demos of this below.)
To clear the text contents of a ThemedTextWindow, call
my_window:clear(
draw_after -- boolean, optional (default is true), set to false to not immediately draw the new condition of the window
)
If you set draw_after to false and later want to draw the additions, call
my_window:draw()
To return the contents of a ThemedTextWindow in styles table format, call
my_styles = my_window:get_styles()
To return the contents of a ThemedTextWindow in color-coded text format, call
my_text = my_window:get_text()
To determine how much horizontal space is needed to display some text in a ThemedTextWindow, call
my_window:text_width(
string_or_styles -- string or table, required, text string with Aardwolf color codes or table of MUSHclient style tables
)
To scroll a ThemedTextWindow to a certain line, call
my_window:set_scroll(
line_number -- integer, required, which wrapped line of text to scroll to (the first line is 1, second line is 2, etc)
)
To resize a ThemedTextWindow to fit certain content metrics without needing to know the size of the window dressing, call
my_window:fit_size(
content_width, -- integer, optional, how wide you want the text content area to be not including the window dressing
num_content_lines, -- integer, optional, how many lines you want the text content area to hold
max_width, -- integer, optional, upper limit on window width if the content width plus the window dressing would be too wide
max_height -- integer, optional, upper limit on window height if the height of the lines plus the window dressing would be too wide
)
To resize a ThemedTextWindow to fit its current contents, call
my_window:fit_contents(
max_width, -- integer, optional, upper limit on window width
max_height -- integer, optional, upper limit on window height
)
Examples
Basic Window Example
require "themed_miniwindows"
my_window = ThemedBasicWindow("testwindow", 100, 100, 200, 150, "Hello", "center", true, 1)
Multiline Title With Colors Example
You can have colorized window titles with multiple lines (use $C to set color back to the theme default).
require "themed_miniwindows"
my_window = ThemedBasicWindow(
"testwindow", 100, 100, 200, 150, "He@x123llo\n@GHe$Cllo", "center", true, 1
)
Title From Styles Table Example
Titles can also be one or more lines of styles.
require "themed_miniwindows"
title_styles = {
{
{
bold=false,
backcolour=0,
length=11,
textcolour=12632256,
text="Hello"
}
},{
{
bold=true,
backcolour=0,
length=10,
textcolour=255,
text="Hello"
}
}
}
my_window = ThemedBasicWindow("testwindow", 100, 100, 200, 150, title_styles, "center", true, 1)
Resizer Style and Title Alignment
Alternate resizer style and title aligned to the left.
require "themed_miniwindows"
my_window = ThemedBasicWindow("testwindow", 100, 100, 200, 150, "Hello", "left", false, 2)
This is just a demo. Don't actually use resizer type 2 without a scrollbar. It's ugly.
Basic Drawing Example
You can draw whatever you want on the window as long as you follow a few rules like staying within the body boundaries. Because this window is resizable, we're going to put all of our drawing code into a special drawing function that will get run during and immediately after resizing.
require "themed_miniwindows"
function my_draw()
my_window:blank()
WindowRectOp(
my_window.id, 2, my_window.bodyleft+20, my_window.bodytop+20,
my_window.bodyright-20, my_window.bodybottom-20, ColourNameToRGB("green")
)
end
my_window = ThemedBasicWindow(
"testwindow", 100, 100, 200, 150, "Hello", "center", true, 1, my_draw, my_draw
)
-- Draw our stuff manually the first time.
my_draw()
-- While the resize routine re-dresses the window after calling my_draw automatically,
-- calling my_draw manually doesn't.
-- And since my_draw draws over the area where the resize widget is, calling dress_window
-- once manually here draws the resize widget again.
my_window:dress_window()
Clickable Buttons Example
Need clickable 3D buttons? There's a special function for adding them. This window isn't resizable so here we don't need to use a special drawing function.
require "themed_miniwindows"
my_window = ThemedBasicWindow("testwindow", 100, 100, 200, 150, "Hello", "center", true)
my_window:add_button(
"testbutton",
my_window.bodyleft + 20,
my_window.bodytop + 20,
"BUTTON GO ZOOM",
false,
nil,
function(flags, button_id) print("CLICKED", button_id) end,
function(flags, button_id) print("RELEASED", button_id) end,
nil,
5,
5,
nil,
nil,
Theme.STYLE_3D
)
Clicking the button prints:
CLICKED testbutton
RELEASED testbutton
Text Capturing Example
If all you want is to simply capture text, ThemedTextWindow is a specialized window just for that.
require "themed_miniwindows"
my_window = ThemedTextWindow("testwindow", 200, 200, 200, 200, "Hello Hello", "center", false, true, false)
for i=1,10 do
my_window:add_text(tostring(i).."@WFoo@RFoo@MFoo@CFoo")
end
Scrollable Text Example
To make the text scrollable, activate scrolling.
require "themed_miniwindows"
my_window = ThemedTextWindow("testwindow", 200, 200, 200, 200, "Hello Hello", "center", false, true, true)
for i=1,100 do
my_window:add_text(tostring(i).."@WFoo@RFoo@MFoo@CFoo")
end
Links In Text Example
require "themed_miniwindows"
my_window = ThemedTextWindow("testwindow", 200, 200, 200, 200, "Hello Hello", "center", false, true, false)
my_window:add_text(
"test test test",
true,
{
{label="First", start=1, stop=4, text="a='look';Execute(a)"},
{label="Second", start=6, stop=9, text="a='scan';Execute(a)"}
}
)
Multiline Text Example
Added text doesn't have to be one line. You can include "\n" newlines too or use a sequence of lines of styles instead.
require "themed_miniwindows"
my_window = ThemedTextWindow("testwindow", 200, 200, 200, 200, "Hello Hello", "center", false, true, true)
for i=1,100 do
my_window:add_text("@w1234567890\n@R09876@G54321") -- \n means new line
end
or
require "themed_miniwindows"
my_window = ThemedTextWindow("testwindow", 200, 200, 200, 200, "Hello Hello", "center", false, true, true)
styles = { -- begin multiple lines
{ -- begin line
{ -- begin style in line
bold=false,
backcolour=0,
length=5,
textcolour=12632256,
text="1234567890"
}, -- end style in line
},{ -- end line, begin new line
{ -- begin style in line
bold=true,
backcolour=0,
length=10,
textcolour=255,
text="09876"
}, -- end style in line
{ -- begin another style in same line
bold=true,
backcolour=0,
length=10,
textcolour=65280,
text="54321"
} -- end style in line
} -- end line
} -- end multiple lines
for i=1,100 do
my_window:add_text(styles)
end