Miniwindows in MUSHclient - Hotspots
Written by Nick Gammon - July 2008. Updated September 2010.
On this page:
- Introduction
- Example of adding a hotspot
- WindowAddHotspot
- WindowDeleteAllHotspots
- WindowDeleteHotspot
- WindowDragHandler
- WindowHotspotInfo
- WindowHotspotList
- WindowHotspotTooltip
- WindowMoveHotspot
- WindowScrollwheelHandler
See also:
- Introduction
- Creating miniwindows
- Drawing shapes
- Drawing text
- Drawing images
- Helpful graphics functions
- Blending images
Hotspots
In order to allow you to interact with the miniwindows, you can designate hotspots (really, "hot rectangles"). When the mouse is moved inside these designated areas (of which there can be any number per miniwindow), script functions in your plugin can be called. These functions can handle:
- Mouse over the hotspot - this lets you pop up an "information box" if you want to, or make the area change colour to indicate it is important in some way. For example, a hyperlink might change colour.
- Mouse moved away from a hotspot - this lets you cancel the information box, or change the colour back to what it normally is.
- Mouse down in a hotspot - this is to "prime" a mouse-click. Most Windows programs, if you watch carefully, do not actually do anything important on a mouse-down - they do it on the corresponding mouse-up. However a mouse-down event is a good time to redraw a button in a "pushed" state, as a visual cue that letting the mouse go will have some effect.
- Mouse up in a hotspot - generally this is when you react to the mouse click. For example, on a hyperlink, you do the hyperlinked action. On a button, you carry out the button-press action.
- Mouse-down cancel - this is when they have clicked on a hotspot, but moved the mouse away, and let go, effectively cancelling the mouse down. Here is where you might redraw the button in a non-pressed state, to indicate the button is no longer pressed.
In addition, you can specify tooltip text, which automatically appears if the mouse hovers over a hotspot, after a short delay. This can be used to provide short help messages.
You can also add support for mouse dragging (from version 4.40 onwards) using WindowDragHandler, and for the player moving the mouse scroll-wheel with WindowScrollwheelHandler.
Add a hotspot
Each miniwindow can have any number of hotspots (including zero). Each one designates a rectangle which has some significance if you mouse over it, or click inside it. You should take care not to overlap hotspot rectangles or they may not behave as you expect. When checking for mouse clicks, hotspots are evaluated in ascending alphabetic order by hotspot id.
Hotspots are not, in themselves, visible graphic elements. You would normally associate them with a piece of text (for a hyperlink) or a graphical element such as a button or checkbox. For example, when drawing text, you know the starting point of the text, the height of the text, and the width of the text. This can be used to create a hotspot over the same place the text appeared.
Most of the functionality of hotspots is provided by script plugin "callbacks" - that is, when you mouse over a hotspot, a function in your plugin is called (if you nominate one). Thus hotspots would generally be implemented inside plugins.
In addition to the callbacks defined here, you can also use WindowDragHandler to add callbacks for dragging with the mouse, and WindowScrollwheelHandler for if the scroll-wheel on the mouse is moved.
WindowAddHotspot function prototype:
long WindowAddHotspot(BSTR Name, BSTR HotspotId, long Left, long Top, long Right, long Bottom, BSTR MouseOver, BSTR CancelMouseOver, BSTR MouseDown, BSTR CancelMouseDown, BSTR MouseUp, BSTR TooltipText, long Cursor, long Flags);
This create a hotspot in the miniwindow, and remembers it by the nominated "hotspot id".
- Name - the name of an existing miniwindow. Names are case-sensitive.
- HotspotId - the hotspot id to be associated with this particular hotspot.
- Left, Top, Right, Bottom - describes the hotspot rectangle. This can be changed later with WindowMoveHotspot.
- MouseOver - the script function to be called when you mouse over the hotspot rectangle
- CancelMouseOver - the script function to be called when you move the mouse away from the hotspot rectangle
- MouseDown - the script function to be called when you mouse down in the hotspot rectangle
- CancelMouseDown - the script function to be called when you release the mouse not in the hotspot rectangle that the mouse-down occurred in
- MouseUp - the script function to be called when you release the mouse in the hotspot rectangle that the mouse-down occurred in
- TooltipText - the text here is shown automatically if you "hover" the mouse over the hotspot for about a second. It is then removed after a few seconds. This is intended for informational messages (maximum 999 characters). This can be changed later with WindowHotspotTooltip. The tooltip can have a bold "heading line" if you have the tab character in the text. eg. "Weapon \t Sword"
- Cursor - a number which indicates what shape the mouse pointer is to take when over the hotspot, as follows:
Value Purpose Lua symbol -1 No cursor miniwin.cursor_none 0 Arrow miniwin.cursor_arrow 1 Hand miniwin.cursor_hand 2 I-beam miniwin.cursor_ibeam 3 + symbol miniwin.cursor_plus 4 Wait (hour-glass) miniwin.cursor_wait 5 Up arrow miniwin.cursor_up 6 Arrow nw-se miniwin.cursor_nw_se_arrow 7 Arrow ne-sw miniwin.cursor_ne_sw_arrow 8 Arrow e-w miniwin.cursor_ew_arrow 9 Arrow n-s miniwin.cursor_ns_arrow 10 Arrow - all ways miniwin.cursor_both_arrow 11 (X) cannot do action miniwin.cursor_x 12 Help (? symbol) miniwin.cursor_help You can use SetCursor to change the cursor shape when you want.
- Flags - flags to modify hotspot behaviour.
Value Purpose Lua symbol 1 If set, all mouse-overs (not just the first) are sent to the mouse-over function. miniwin.hotspot_report_all_mouseovers
Example of making a hotspot
WindowAddHotspot(win, "hs1",
10, 10, 60, 20, -- rectangle
"mouseover",
"cancelmouseover",
"mousedown",
"cancelmousedown",
"mouseup",
"Click here to be healed", -- tooltip text
miniwin.cursor_hand, 0) -- hand cursor
Hotspot callback functions
The functions specified for WindowAddHotspot do not have to exist - use an empty string if you don't want a particular action to cause a function call. However if the callback function name is not empty it must be a valid function name. There is no error message if the function cannot be found, however if you turn Trace on (Game menu -> Trace) then messages will appear in the output window to warn you about missing (non-empty) functions.
The callback function should look like this:
function mouseover (flags, hotspot_id)
Note ("we moused over hotspot " .. hotspot_id)
return 0 -- needed for some languages
end -- mouseover
Since the hotspot ID is passed to the callback function, you can share the same function amongst all your hotspots. For example, a "mouse down" function could handle all the hyperlinks in a miniwindow - by using the hotspot ID, it could look up in a table what action to perform for this particular hotspot.
The function return code is ignored, however for some languages, like PHP, you should return 0, otherwise you will get a runtime error.
The flags parameter is a bit mask as follows:
| Value | Purpose | Lua symbol |
|---|---|---|
| 0x01 (1) | Shift key down | |
| 0x02 (2) | Control key down | |
| 0x04 (4) | Alt key down | |
| 0x10 (16) | LH mouse | |
| 0x20 (32) | RH mouse | |
| 0x40 (64) | Double-click | |
| 0x80 (128) | Not first mouse-over in hotspot | |
| 0x100 (256) | Scroll wheel scrolled down (towards you) |
So, for example, if the left-hand mouse was double-clicked whilst the shift and control keys were held down, the flags would be:
flags = 0x01 + 0x02 + 0x10 + 0x40 --> namely 0x53 (83 in decimal)
-- that is:
flags = miniwin.hotspot_got_shift + miniwin.hotspot_got_control +
miniwin.hotspot_got_lh_mouse + miniwin.hotspot_got_dbl_click
-- in Lua you might test for a LH mouse click like this:
if bit.band (flags, miniwin.hotspot_got_lh_mouse) ~= 0 then
-- LH mouse clicked
end -- if
Sequence of callback function calls
Mouse over
- If you mouse-over a hotspot, and the mouse is not presently "captured" (in other words, if the mouse is not already down when you mouse-over), then a single call will be made to the "MouseOver" function. Further movement of the mouse inside the hotspot will not cause further function calls unless you set the flag miniwin.hotspot_report_all_mouseovers, in which case all movements will be reported. You can test the flag miniwin.hotspot_got_not_first to see if this is the first or subsequent mouse-over.
- Once the "MouseOver" function is called, you are guaranteed that the "CancelMouseOver" function will be called if one of the following happens:
- The mouse moves away from the hotspot, but is still inside the miniwindow; or
- The mouse button is clicked (ie. a mousedown); or
- The mouse moves to a different miniwindow; or
- The mouse moves away from the miniwindow entirely.
If the mouse is clicked inside the hotspot, the "CancelMouseOver" function is called before any "MouseDown" function for the same hotspot.
If the mouse moves over a hotspot, after about half a second the TooltipText string is displayed in a tooltip window (if any is specified). This tool tip will disappear after a few seconds.
The moment the mouse moves over a hotspot the mouse cursor is changed to be the shape specified for the hotspot (Cursor argument).
Suggestions
The MouseOver event (with the corresponding CancelMouseOver where required) can be used to:
- Play a "rollover" sound
- Highlight a button or checkbox in a way that indicates it is something you can click on
- Pop up a help window (eg. describing what an inventory item does)
- Put help information into a "help box" near the bottom of the window, or in the MUSHclient status bar.
The CancelMouseOver event should be used, if necessary to:
- Un-highlight any buttons you highlighted
- Remove any help windows you may have drawn
Mouse down
- If you mouse-down over a hotspot, then a single call will be made to the "MouseDown" function (possibly after calling CancelMouseOver for the same hotspot). Further movement of the mouse inside the hotspot will not cause further function calls. You can move the mouse away from the hotspot, and back again, without letting go, and no further function calls will be made.
- Once the "MouseDown" function is called, you are guaranteed that either the "CancelMouseDown", or the "MouseUp" function will be called when the following happens:
- The mouse is released over the same hotspot it went down in (MouseUp function)
- The mouse button is released anywhere else (CancelMouseDown function)
Suggestions
The MouseDown event (with the corresponding CancelMouseOver or MouseUp where required) can be used to:
- Play a "click" sound
- Highlight a button or checkbox in a way that indicates it has been clicked on (for example, drawing it slightly to one side, as if it was pushed)
- Draw text under the hotspot in a different way
The CancelMouseDown event should be used, if necessary to:
- Un-highlight any buttons you highlighted
- Redraw any text you changed back in the original colours
The MouseUp event should be used, if necessary to:
- Un-highlight any buttons you highlighted
- Redraw any text you changed back in the original colours
- Perform the requested action (eg. do what the hyperlink promised), check a checkbox (or uncheck it), close the window (if it was a close button), and so on.
Delete a hotspot
If you no longer require a hotspot it can be deleted by calling WindowDeleteHotspot.
WindowDeleteHotspot function prototype:
long WindowDeleteHotspot(BSTR Name, BSTR HotspotId);
This deletes the hotspot from the miniwindow.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- HotspotId - the hotspot id to be deleted.
Example of deleting a hotspot
WindowDeleteHotspot (win, "hs1");
Delete all hotspots
If you no longer require your hotspots (perhaps after clearing the window and starting again), you can call WindowDeleteAllHotspots.
WindowDeleteAllHotspots function prototype:
long WindowDeleteAllHotspots(BSTR Name);
This deletes all hotspots from the miniwindow.
- Name - the name of an existing miniwindow. Names are case-sensitive.
Example of deleting all hotspots
WindowDeleteAllHotspots (win);
Note - when WindowCreate is called, all existing hotspots are automatically deleted, if the window previously existed, unless the flag miniwin.create_keep_hotspots was used when calling WindowCreate.
Move a hotspot
If you need to move a hotspot around you can do it with WindowMoveHotspot.
WindowMoveHotspot function prototype:
long WindowMoveHotspot(BSTR Name, BSTR HotspotId, long Left, long Top, long Right, long Bottom);
This moves a hotspot from one place to another. You might use this in a resize callback function.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- HotspotId - the hotspot id to be moved.
- Left, Top, Right, Bottom - describes the new hotspot rectangle.
Example of moving a hotspot
WindowMoveHotspot (win, "hs1", 20, 20, 40, 40);
List all hotspots
WindowHotspotList function prototype:
VARIANT WindowHotspotList(BSTR Name);
This returns a list of all hotspots loaded into this miniwindow. You could use this to find which hotspots have been created, and then use WindowHotspotInfo to find information about each one.
Example:
-- show all hotspots
hotspots = WindowHotspotList(win)
if hotspots then
for _, v in ipairs (hotspots) do
Note (v)
end
end -- if any
Get information about a hotspot
WindowHotspotInfo function prototype:
VARIANT WindowHotspotInfo(BSTR Name, BSTR HotspotId, long InfoType);
This returns information about a hotspot. You need to specify the name of the miniwindow, and the hotspot id you used when creating the hotspot.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- HotspotId - the hotspot id you used when you created the hotspot.
- InfoType - the information you want:
- 1: Rectangle: Left
- 2: Rectangle: Top
- 3: Rectangle: Right
- 4: Rectangle: Bottom
- 5: MouseOver function name
- 6: CancelMouseOver function name
- 7: MouseDown function name
- 8: CancelMouseDown function name
- 9: MouseUp function name
- 10: TooltipText
- 11: Cursor
- 12: Flags
- 13: Drag and drop move callback function name
- 14: Drag and drop release callback function name
- 15: Drag and drop flags
Change the tooltip text for a hotspot
WindowHotspotTooltip function prototype:
long WindowHotspotTooltip(BSTR Name, BSTR HotspotId, BSTR TooltipText);
This changes the tooltip text for a hotspot (shown if the mouse hovers over the hotspot for a second or so).
- Name - the name of an existing miniwindow. Names are case-sensitive.
- HotspotId - the hotspot id you used when you created the hotspot.
- TooltipText - the new tooltip text - maximum 999 characters. The tooltip can have a bold "heading line" if you have the tab character in the text. eg. "Weapon \t Sword"
Example of adding a hotspot
function hyperlink_configure_background ()
local new_colour = PickColour (background_colour) -- colour picker
if new_colour ~= -1 then -- if dialog not dismissed
background_colour = new_colour
Display_Map ()
end -- new colour
end -- hyperlink_configure_background
function hyperlink_configure_title ()
local new_colour = PickColour (title_colour) -- colour picker
if new_colour ~= -1 then -- if dialog not dismissed
title_colour = new_colour
Display_Map ()
end -- new colour
end -- hyperlink_configure_title
-- here if they click on the hyperlink
function mousedown (flags, hotspotid)
local f = hyperlink_functions [hotspotid]
if f then
f ()
end -- function found
end -- mousedown
hyperlink_functions = {}
function make_hyperlink (text, id, left, top, action, hint)
-- work out text rectangle size
local height = WindowFontInfo (win, font_id, 1)
local right = left + WindowTextWidth (win, font_id, text)
local bottom = top + height
-- add the hotspot
WindowAddHotspot(win, id,
left, top, right, bottom,
"", -- mouseover (do nothing)
"", -- cancelmouseover (do nothing)
"mousedown",
"", -- cancelmousedown (do nothing)
"", -- mouseup (do nothing)
hint, -- hint text if they hover over it
miniwin.cursor_hand, 0)
-- draw the hyperlink text in the rectangle
WindowText (win, font_id, text, left, top, right, bottom, hyperlink_colour)
-- remember action function
hyperlink_functions [id] = action
end -- make_hyperlink
-- further down, where we draw the map ....
-- hyperlink for title colour
make_hyperlink ("?", "back_colour", width - 15, height - 5 - font_height,
hyperlink_configure_background, "Choose background colour")
-- hyperlink for map body colour
make_hyperlink ("?", "title_colour", width - 15, font_height + 5,
hyperlink_configure_title, "Choose title colour")
With the above code in place, you see the "?" characters in the specified locations. These are the hyperlinks:

Now if you click on one, it opens the colour picker, so you can choose the colour you want:

Set up a mouse-drag handler
WindowDragHandler function prototype:
long WindowDragHandler(BSTR Name, BSTR HotspotId, BSTR MoveCallback, BSTR ReleaseCallback, long Flags);
This adds a "mouse drag handler" to the designated hotspot. You need to specify the name of the miniwindow, and the hotspot id you used when creating the hotspot. This provides extra functionality which applies after there is a mouse-down in that hotspot.
- Name - the name of an existing miniwindow. Names are case-sensitive.
- HotspotId - the hotspot id you used when you created the hotspot.
- MoveCallback - the script function to be called when you move the mouse away from the hotspot rectangle
- ReleaseCallback - the script function to be called when you mouse down in the hotspot rectangle
- Flags - flags to modify dragging behaviour. Leave as zero, these are not currently used.
The flags passed to the drag handler will be a bit mask as follows:
| Value | Purpose | Lua symbol |
|---|---|---|
| 0x01 (1) | Shift key down | |
| 0x02 (2) | Control key down | |
| 0x04 (4) | Alt key down |
Example of adding a drag handler
function dragmove(flags, hotspot_id)
local posx, posy = WindowInfo (win, 17),
WindowInfo (win, 18)
print ("moved to position", posx, posy)
-- move the window to the new location
WindowPosition(win, posx - startx, posy - starty,
miniwin.pos_stretch_to_view,
miniwin.create_absolute_location);
-- change the mouse cursor shape appropriately
if posx < 0 or posx > GetInfo (281) or
posy < 0 or posy > GetInfo (280) then
check (SetCursor (miniwin.cursor_x)) -- X cursor
else
check (SetCursor (miniwin.cursor_hand)) -- hand cursor
end -- if
end -- dragmove
function dragrelease(flags, hotspot_id)
print ("mouse drag release for " .. hotspot_id)
print ("released at position", WindowInfo (win, 17), WindowInfo (win, 18))
end -- dragrelease
WindowDragHandler(win, "hs1", "dragmove", "dragrelease", 0)
Set up a scroll-wheel handler
WindowScrollwheelHandler function prototype:
long WindowScrollwheelHandler(BSTR WindowName, BSTR HotspotId, BSTR MoveCallback);
Adds a scroll-wheel handler callback to the nominated hotspot. If:
- The user moves the scroll wheel over a miniwindow hotspot; and
- There is a MoveCallback function defined (by using this function)
- Name - the name of an existing miniwindow. Names are case-sensitive.
- HotspotId - the hotspot id you used when you created the hotspot.
- MoveCallback - the script function to be called when you scroll the mouse-wheel over the hotspot
The callback function should look like this:
function wheel_move (flags, hotspot_id)
if bit.band (flags, miniwin.wheel_scroll_back) ~= 0 then
-- wheel scrolled down (towards you)
else
-- wheel scrolled up (away from you)
end -- if
return 0 -- needed for some languages
end -- wheel_move
Since the hotspot ID is passed to the callback function, you can share the same function amongst all your hotspots.
The function return code is ignored, however for some languages, like PHP, you should return 0, otherwise you will get a runtime error.
The flags parameter passed to the move function is a bit mask as follows:
| Value | Purpose | Lua symbol |
|---|---|---|
| 0x01 (1) | Shift key down | |
| 0x02 (2) | Control key down | |
| 0x04 (4) | Altkey down | |
| 0x100 (256) | Scroll wheel scrolled down (towards you) |
Other pages about miniwindows
- Introduction
- Creating miniwindows
- Drawing shapes
- Drawing text
- Drawing images
- Helpful graphics functions
- Blending images