Class ui.Custom
Custom widget.
When the none of the standard widgets suits you, you can build your own custom widget.
You yourself decide how to draw it on the screen and how it will respond to keyboard and mouse events.
For a sample script that uses a custom widget, see ui_canvas.mcs.
Misc event handlers
ui.Custom:on_cursor(self) handler | Cursor positioning handler. |
ui.Custom:on_draw(self) handler | Draw handler. |
ui.Custom:on_focus(self) handler | Focus handler. |
ui.Custom:on_hotkey(self, keycode) handler | Global keypress handler. |
ui.Custom:on_key(self, keycode) handler | Keypress handler. |
ui.Custom:on_unfocus(self) handler | Unfocus handler. |
Mouse event handlers
ui.Custom:on_click(self, x, y, buttons, count) handler | Mouse click handler. |
ui.Custom:on_mouse_down(self, x, y, buttons, count) handler | Mouse down handler. |
ui.Custom:on_mouse_drag(self, x, y, buttons) handler | Mouse drag handler. |
ui.Custom:on_mouse_move(self, x, y) handler | Mouse move handler. |
ui.Custom:on_mouse_scroll_down(self, x, y) handler | Mouse scroll down handler. |
ui.Custom:on_mouse_scroll_up(self, x, y) handler | Mouse scroll up handler. |
ui.Custom:on_mouse_up(self, x, y, buttons, count) handler | Mouse up handler. |
Misc event handlers
- ui.Custom:on_cursor(self) handler
-
Cursor positioning handler.
This handler is called to position the cursor. It is only called for widgets that have the focus.
wdg.on_cursor = function() wgt:get_canvas():goto_xy(point.x, point.y) end -- To make our widget focusable, we must also do: wdg.on_focus = function() return true end
You'll always want to implement this handler for focusable widgets or else the cursor will remain at its last arbitrary position.
- ui.Custom:on_draw(self) handler
-
Draw handler.
This is where you draw the contents of your widget. Typically you fetch a canvas object and use its drawing methods:
wdg.on_draw = function(self) local c = self:get_canvas() c:erase() c:draw_string("hi!") end
See more examples in the page on ui.Canvas.
Right before this handler is called the current style is set to MC’s normal dialog color (appropriate for the active colorset) and the cursor is positioned at the widget’s top-left corner.
- ui.Custom:on_focus(self) handler
-
Focus handler.
Called when a widget is about to receive the focus. You must return true here if you want your widget to receive the focus. Otherwise the widget will be skipped over when the user tries to tab to it.
wdg.on_focus = function() return true end
You will most probably also want to implement on_cursor.
- ui.Custom:on_hotkey(self, keycode) handler
-
Global keypress handler.
This is where you respond to a key pressed when your widget doesn’t necessarily have the focus. (You may alternatively use ui.Dialog:on_key.)
The interface is identical to that of on_key: the handler gets a keycode, and should return true for handled keys.
- ui.Custom:on_key(self, keycode) handler
-
Keypress handler.
This is where you respond to a key pressed when your widget has the focus.
The handler gets as argument the keycode. It should return true if the key was handled.
local K_LEFT = tty.keyname_to_keycode('left') local K_RIGHT = tty.keyname_to_keycode('right') ... wgt.on_key = function(self, keycode) if keycode == K_LEFT then pos.x = pos.x - 1 elseif keycode == K_RIGHT then pos.x = pos.x + 1 ... else return false end self:redraw() return true end
The above bulky code can be made to look more friendly:
local K = utils.magic.memoize(tty.keyname_to_keycode) wgt.on_key = function(self, keycode) if keycode == K'left' then pos.x = pos.x - 1 elseif keycode == K'right' then pos.x = pos.x + 1 elseif keycode == K'up' then pos.y = pos.y - 1 elseif keycode == K'down' then pos.y = pos.y + 1 else return false end self:redraw() return true end
Or you can use a dispatch table:
local K = utils.magic.memoize(tty.keyname_to_keycode) local navigation = { [K'left'] = wgt.go_left, [K'right'] = wgt.go_right, [K'up'] = wgt.go_up, [K'down'] = wgt.go_down, } wgt.on_key = function(self, keycode) if navigation[keycode] then navigation[keycode](self) self:redraw() return true end end
- ui.Custom:on_unfocus(self) handler
-
Unfocus handler.
Called when a widget is about to lose the focus. If you implement this handler, you must return true here if you want your widget to lose the focus; otherwise the user won’t be able to leave the widget.
If you don’t implement this handler, it’s as if you returned true: the user will be able to always leave the widget.
wdg.on_unfous = function() if some_data_is_missing then tty.beep() return false else return true end end
Mouse event handlers
- ui.Custom:on_click(self, x, y, buttons, count) handler
-
Mouse click handler.
Called when a mouse button is pressed down and then released inside the widget. According to conventions, this is the desired sequence before taking an action in a UI application. E.g., firing a button’s action or changing a checkbox state should be done in on_click, not in on_mouse_down.
wgt.on_click = function() os.execute('firefox') end
buttons reports the button that was clicked:
wgt.on_click = function(self, x, y, buttons, count) if buttons.left and count == 'double' then alert(T'You double-clicked the left button.') else end
- ui.Custom:on_mouse_down(self, x, y, buttons, count) handler
-
Mouse down handler.
Called when a mouse button is pressed down inside the widget.
wgt.on_mouse_down = function() wgt:focus() end
The buttons table reports which buttons are pressed after the event. Valid button names are “left”, “middle”, “right”.
count indicates whether this is part of a double-click or triple-click. It is either “single”, “double”, or “triple”.
- ui.Custom:on_mouse_drag(self, x, y, buttons) handler
-
Mouse drag handler.
Called when the mouse pointer, after a mouse button was pressed down inside the widget, is moved (either inside or outside the widget).
local function test2() local wgt = ui.Custom{cols=80, rows=5} local function draw_point(x, y) local c = wgt:get_canvas() c:set_style(tty.style('white, red')) c:goto_xy(x, y) c:draw_string('*') end wgt.on_mouse_down = function(self, x, y, buttons, count) draw_point(x, y) end wgt.on_mouse_drag = function(self, x, y, ...) -- If we remove these checks we'll be able to draw outside the widget. if x >= 0 and x < self.cols and y >= 0 and y < self.rows then draw_point(x, y) end end ui.Dialog():add(wgt):run() end
- ui.Custom:on_mouse_move(self, x, y) handler
- Mouse move handler.
- ui.Custom:on_mouse_scroll_down(self, x, y) handler
-
Mouse scroll down handler.
Called when the mouse wheel is rotated towards the user.
wgt.on_mouse_scroll_down = function() wgt.top_line = wgt.top_line + 1 wgt:redraw() end
- ui.Custom:on_mouse_scroll_up(self, x, y) handler
-
Mouse scroll up handler.
Called when the mouse wheel is rotated away from the user.
wgt.on_mouse_scroll_up = function() wgt.top_line = wgt.top_line - 1 wgt:redraw() end
- ui.Custom:on_mouse_up(self, x, y, buttons, count) handler
-
Mouse up handler.
Called when a mouse button, that was pressed down inside the widget, is now released (either inside or outside the widget).
buttons reports the button that was released.