rtk.Window
¶
An OS-native window that is to be the root ancestor of all other widgets.
rtk.Window
implements the rtk.Container
interface and behaves like a regular widget,
except with certain behaviors adapted for OS windows. For example, setting geometry
attributes (x
, y
, w
, h
), which normally affects widget layout, here moves and
resizes the actual window. Similarly, bg
sets the window's overall background color.
Windows can be either docked or undocked (floating), which is controlled by the docked
attribute, and which can be changed dynamically. Most of rtk.Window
's attributes
don't apply to docked windows: geometry (x
, y
, w
, h
), borderless
, opacity
, etc.
are only respected when the window is undocked.
Moreover, a considerable amount of functionality (particularly the ability to modify the window after it has opened) depends on the js_ReaScriptAPI extension. rtk itself doesn't require the extension however, so just be aware when you use some functionality that depends on it (which will be clearly explained in the APIs below). You will need to be cognizant of whether you want to impose the js_ReaScriptAPI requirement on users of your script based on the dependent functionality you use.
Due to REAPER's design there can only be one rtk.Window
per script.
-- Creates a window that defaults to 400x200 and is undocked (because the
-- docked attribute defaults to false).
local window = rtk.Window{w=400, h=200}
-- This works exactly like any other rtk.Container: this will add the
-- text widget and center it within the window.
window:add(rtk.Text{'Hello world!'}, {halign='center', valign='center'})
-- Now open the window which itself is top-center on the screen.
window:open{halign='center', valign='top'}
The geometry of the window is controlled by the x
, y
, w
, h
, minw
, maxw
,
minh
, and maxh
attributes. These attributes influence how the window should be
initially positioned and sized, but of course changes to the window's position and
size can come from external causes, such as the user resizing the window via the OS
window border, or REAPER modifying the dimensions of the window when it's docked
or undocked.
When a geometry change originates from an external cause like this, the above
attributes become passive and don't force any changes back onto the window's geometry.
The x
, y
, w
, and h
attributes are automatically updated to reflect this
externally caused change. However, minw
, maxw
, minh
, and maxh
are left the way
you set them.
After the window is opened, the minw
, maxw
, minh
, and maxh
only exert any
influence on the window geometry if any of the eight geometry-related attributes are
changed programmatically, such as via attr()
. Programmatically setting any of these
attributes will cause all the min/max constraints to be reevaluated and enforced at
that time, but thereafter become inert again when it comes to externally caused changes
to position or size.
Out of the box, undocked (i.e. floating) windows will be closed when the user hits the
escape key while the window is focused. Or, to be more precise, when there is an
unhandled rtk.Event.KEY
event with an ESCAPE
keycode and docked
is false. You can override this by
explicitly handling this event via onkeypresspost()
:
local window = rtk.Window()
window.onkeypresspost = function(self, event)
if not event.handled and event.keycode == rtk.keycodes.ESCAPE and
not window.docked then
-- Prevent default behavior of escape key closing the window
-- by marking the event as handled.
event:set_handled(self)
end
end
The window will of course also close when the user clicks on the window's OS-native
close button (for non-borderless
windows), or programmatically when you call
rtk.Window:close()
.
Used with the dock
attribute, where lowercase strings of these constants can be used
for convenience (e.g. 'bottom'
instead of rtk.Window.DOCK_BOTTOM
). These strings
are automatically converted to the appropriate numeric constants.
rtk.Window.DOCK_BOTTOM¶ | 'bottom' |
Find the first docker that is attached to the bottom of the main window. |
rtk.Window.DOCK_LEFT¶ | 'left' |
Find the first docker that is attached to the left of the main window. |
rtk.Window.DOCK_TOP¶ | 'top' |
Find the first docker that is attached to the top of the main window. |
rtk.Window.DOCK_RIGHT¶ | 'right' |
Find the first docker that is attached to the right of the main window. |
rtk.Window.DOCK_FLOATING¶ | 'floating' |
Find the first docker that that is not attached to the main window. |
x | number | read/write |
The x screen coordinate of the window when undocked (default nil) |
y | number | read/write |
Like |
w | number or nil | read/write |
The current client width of the window (default nil) |
h | number or nil | read/write |
Like |
minw | number | read/write |
Minimum allowed width for the window when undocked (default 100) |
minh | number | read/write |
Like |
maxw | number or nil | read/write |
Maximum width allowed for the undocked window when |
maxh | number or nil | read/write |
Like |
visible | boolean | read/write |
Sets the visibility of the detached window when undocked (default true) |
docked | boolean | read/write |
True if the window is docked and false otherwise (default false) |
dock | number | read/write |
The id of the docker to which this window is (or, when set, will
become) attached when |
pinned | boolean | read/write |
If true, undocked windows will be pinned (i.e. they are always on top) and if false the window ordering works as usual (default false) |
borderless | boolean | read/write |
If true, undocked windows will not show the OS-native window frame (default false) |
title | string | read/write |
The title of the window shown in the OS-native window frame (default "REAPER Application") |
opacity | number | read/write |
The opacity of the full window at the OS level, which affects how the window is composited by the OS (default 1.0) |
resizable | bool | read/write |
Controls whether undocked windows will be provided a means of resizing the window (default true) |
hwnd | userdata | read-only |
The handle of the |
in_window | boolean | read-only |
True if the mouse is positioned within the |
is_focused | boolean | read-only |
True if the |
running | boolean | read-only |
True if the window's main event loop is running |
rtk.Window() | Create a new window with the given attributes |
focus() | Focuses the window so it receives subsequent keyboard events |
open() | Opens the window and begins the main event loop |
close() | Closes the window and will end the application unless there are active user-managed deferred calls in flight to prevent REAPER from terminating us |
queue_blit() | Queues a full blit of the window from its backing store based on previously drawn state upon next update |
queue_mouse_refresh() | Queues a simulated mousemove event on next update to cause widgets to refresh the mouse hover state |
request_mouse_cursor() | Called within an event handler to ask the window to set the mouse cursor |
clear() | Clears the window's backing store to the window's background color (or the theme default) |
get_normalized_y() | Returns a normalized version of a screen-level y coordinate |
The x screen coordinate of the window when undocked (default nil). When this attribute is set the window will be moved only if it's undocked, but when an undocked window is moved by the user, this attribute is also updated to reflect the current screen position.
Setting after open()
is called requires the js_ReaScriptAPI extension.
If this attribute is nil (as is default) at the time open()
is called, the window
will be automatically horizontally centered on the primary display and this
attribute will be updated to reflect the new actual screen x coordinate. If you
wish to center the window on a display other than primary, then you'll need to
reflect the display position in the x
and y
attributes and pass the center
alignment option to open()
instead.
Tip: you can call move() to set both x
and y
at the same time.
Note that while x
reflects the current screen position of the window, the
calculated version of this attribute is always 0. This is
because the calculated value is used as the offset for drawing widgets inside the
window. If you want to offset the inner contents, you can use lpadding
or tpadding
instead.
Like x
but for the y screen coordinate (default nil).
As with x
, if this attribute is nil (as is default) at the time open()
is
called, the window will be automatically vertically centered on the system's
primary display and this attribute will be updated to reflect the new actual screen
y coordinate.
Whereas on Windows and Linux the y
coordinate is relative the top of the screen
(so y=0
refers to the top edge of the screen), on Mac this is inverted such that
y=0
refers to the bottom edge of the window positioned at the bottom edge of the
screen.
If you need a consistent representation of the y coordinate, you can use
rtk.Window:get_normalized_y()
.
The current client width of the window (default nil). Client in this context means the inner contents of the window without the OS native window frame.
If nil (default), the window's width will be automatically sized based on its
content (i.e. its child widgets). maxw
and minw
are respected and can be used
to constrain the upper and lower bounds of the width. Once the window is opened,
this attribute will be automatically updated to reflect the window's actual width,
and will continue to be updated if the window is resized due to outside influence
(e.g. the user resizing via the OS's window frame).
If the window is undocked, then this attribute is also settable. If set before
open()
then it defines the initial width of the window if undocked, but has no
effect on the width of docked windows (as REAPER doesn't allow that).
Setting a value after open()
is possible but only when the window is undocked,
and this requires the js_ReaScriptAPI extension. Setting this attribute to nil
will "shrinkwrap" the window's width to its current content size, as described
above.
On Macs with Retina displays, the OS window size is actually half the size of the
internal graphics buffer. The calculated versions of w
and h
reflect this full (double) size, but w
and h
themselves will be half the size.
This ratio is reflected by rtk.scale.framebuffer
.
Tip: you can call resize() to set both w
and h
at the same
time.
Like w
but for the window height (default nil).
As with w
, nil values will automatically fit the window's height to its contents.
And minh
and maxh
are respected.
minh
is respected and the window will not be allowed a smaller height when
set via attr()
or when borderless
is true.
Minimum allowed width for the window when undocked (default 100).
This attribute ensures that w
is not less than this value on initial open()
, or
when the window's width is set via attr()
, or when resizing when borderless
is
true.
However for bordered windows, the OS may allow the user to set a smaller width for
the window than minw
, and so in this case it is possible for w
to be smaller
than minw
. This smaller size will be reflected in the w
attribute, which
always tracks the current window width.
As with w
and h
, the calculated value for minw
is multiplied by
rtk.scale.framebuffer
. See w
for more details.
Like minw
, but is the minimum height allowed for the window when undocked
(default 30).
Maximum width allowed for the undocked window when w
is nil to autosize the width
based on the child widgets (default 800).
Unlike minw
, this attribute does not affect the window's maximum size when
setting the window's width programmatically or when resizing. It's only used to
constrain the automatic sizing ("shrinkwrap") behavior when the w
attribute is
nil.
This can be used to prevent widgets with the fillw container cell attribute set to true (which behave greedily and consume the maximum allowed width) from causing the window to become unmanageably large.
If this attribute is set to nil, then the display's width will be used as the upper
bound. In multi-monitor systems, the display that contains point based on the x
and y
attributes is used.
As with w
and h
, the calculated value for maxw
is multiplied by
rtk.scale.framebuffer
. See w
for more details.
Like maxw
but is the maximum height allowed for the undocked window when h
is
nil (default 600).
Sets the visibility of the detached window when undocked (default true). This atribute is ignored when docked.
This requires the js_ReaScriptAPI extension to be available in order to work,
otherwise setting this is a no-op. This attribute can be set directly, or you can
use the hide()
, show()
, or toggle()
convenience methods.
True if the window is docked and false otherwise (default false). This is
updated to reflect externally-caused changes to the dock state, but can also
be set to dock or undock the window, and when set to true is is combined with
dock
to decide where to dock the window.
The id of the docker to which this window is (or, when set, will
become) attached when docked
is true (default 'right'
). This is updated to
reflect the current docker id when the user moves the window between dockers, but
can also be set to cause the window to programmatically move between dockers.
The value is either a numeric docker id to target a specific docker, or one of the dock position constants which will search for a docker that's attached to the main window in the given position. If no docker can be found at that position, then then the first docker window will be used as a last resort.
If true, undocked windows will be pinned (i.e. they are always on top) and if false the window ordering works as usual (default false). This attribute is ignored when docked.
This requires js_ReaScriptAPI extension to work and without it is always false.
Note that due to a limitation with js_ReaScriptAPI, the pin button will not be visible on the window title bar. It's up to you to provide some facility for the user to pin, such as a toolbar button that toggles this attribute.
(The js_ReaScriptAPI limitation is that it provides no means of removing the pin
after it's attached, and therefore conflicts with the borderless
attribute.
You are free to call reaper.JS_Window_AttachTopmostPin()
explicitly yourself,
passing it the window's hwnd
, just be aware that the pin will persist and
render oddly if borderless
is subsequently set to true, at least on Windows. Also,
this will only work on 64-bit builds of REAPER.)
If true, undocked windows will not show the OS-native window frame (default false). This attribute is ignored when docked.
When borderless, a resize grip will be shown on the bottom right corner of the window to allow the window to be resizable, and also if the user clicks and drags along the top edge of the window it can be moved.
This requires the js_ReaScriptAPI extension and without it is always false.
Tip: if you put widgets along the top edge of the window (e.g. a row of buttons acting as a toolbar) you can prevent click-dragging of these widgets from also moving the window by attaching to those widgets a custom ondragstart handler that returns false.
The title of the window shown in the OS-native window frame (default "REAPER Application"). This attribute is ignored when docked.
Setting after open()
is called requires the js_ReaScriptAPI extension, otherwise
the change is ignored.
The opacity of the full window at the OS level, which affects how the window is composited by the OS (default 1.0). This attribute is ignored when docked.
This is distinct from alpha
, which affects how all widgets within the window are
blended on top of the background color, because opacity
can make
the entire window translucent, including the window frame (assuming borderless
is
false).
Requires the js_ReaScriptAPI extension, otherwise this attribute is entirely ignored.
Controls whether undocked windows will be provided a means of resizing the window
(default true). For borderless
windows the resize grip on the bottom right
corner is hidden, while for normal bordered windows the normal resize zones along
the window frame and and minimize/maximize/restore buttons on the window title bar
will not be available. This does not prevent programmatic resizing, or resizing
through external means (such as AutoHotkey), and in those cases onresize()
will
still be called.
Requires the js_ReaScriptAPI extension, otherwise this attribute is entirely ignored.
The handle of the rtk.Window
which is set once open()
is called.
This requires the js_ReaScriptAPI extension and is nil if it's not installed.
True if the mouse is positioned within the rtk.Window
and false otherwise.
Detecting window occlusion (i.e. where another window is above the rtk.Window)
requires the js_ReaScriptAPI extension. When the extension is available, if
the mouse cursor is positioned in the occluding window's region, in_window
will be false. However when the extension is not available, in_window
will
always be true when the cursor is within the window geometry, even if there are
other windows placed above rtk.Window.
True if the rtk.Window
currently holds keyboard focus.
This requires the js_ReaScriptAPI extension and if it's not installed will always be true.
True if the window's main event loop is running. close()
will set this to false.
Create a new window with the given attributes.
Focuses the window so it receives subsequent keyboard events.
This requires the js_ReaScriptAPI extension to be available in order to work.
Note that likewise onfocus()
and onblur()
event handlers at the rtk.Window
level require js_ReaScriptAPI as well.
(bool) | returns true the the js_ReaScriptAPI extension was available, and false otherwise. |
Opens the window and begins the main event loop. Once called, the application
will continue running until close()
is called.
The options
parameter is an optional table of fields that allows you to influence the
initial placement of undocked windows beyond the standard x
and y
attributes. The
following options are currently supported:
Field | Values | Description |
---|---|---|
halign | 'left' , 'center' , 'right' |
Controls horizontal alignment of the window. If nil, the x attribute controls the x coordinate of undocked windows, otherwise x is used to determine on which monitor the window should be horizontally aligned. |
valign | 'top ', 'center' , 'bottom' |
Controls vertical alignment of the window . If nil, the y attribute controls the y coordinate of undocked windows, otherwise y is used to determine on which monitor the window should be vertically aligned. |
align | 'center'` | Convenience field to center both horizontally and vertically, which is exactly equivalent to setting both halign and valign fields to center . |
constrain | true , false |
If true, the window's initial geometry will be modified to ensure the window fits within the current display. On multi-display systems, "current display" is the display which contains most of the window's rectangle. |
local window = rtk.Window()
window:open{align='center'}
The fields in the options table only apply to the initial placement of the window
during open, and have no further influence after that point. Notably, the
halign/valign options are unrelated to the halign
and valign
widget attributes:
the alignment options here influence position of the undocked OS-native window, while the
halign
and valign
widget attributes affect the alignment of child widgets placed within
the rtk.Window.
options | (table or nil) | an optional table of placement attributes |
Closes the window and will end the application unless there are active user-managed deferred calls in flight to prevent REAPER from terminating us.
It is possible to call open()
again after the window is closed (assuming we haven't
yet terminated obviously).
Queues a full blit of the window from its backing store based on previously drawn state upon next update.
This normally should never need to be called -- rtk internally understands when it needs to blit -- but if you're doing some low level window trickery voodoo underneath rtk (e.g. by using the js_ReaScriptAPI directly), you may find it necessary to invoke this.
Queues a simulated mousemove event on next update to cause widgets to refresh the mouse hover state.
This normally never needs to be called, but this method is needed to handle a very precise edge case:
rtk.NativeMenu
is open)Calling this function will force the injection of a simulated rtk.Event.MOUSEMOVE
event without any buttons pressed which causes the new widget under the mouse to update
its hover appearance.
If you find you need to call this method when the application isn't blocked, this should be considered a bug and reported.
Called within an event handler to ask the window to set the mouse cursor.
The word "ask" is used because this works on a first-come-first-served basis: whoever is first to call this function on each update cycle wins the race. At least unless the force parameter is true, but this should only ever be needed in very rare cases (such as touch-scrolling).
If you want a particular cursor when mousing over a widget, use the
cursor attribute rather than calling this function. Setting
cursor
on an rtk.Window
will result in it being the default cursor (when no widget
has requested a different cursor).
One use case for calling this function is switching cursors during a widget drag operation:
local img = container:add(rtk.ImageBox{icon='drag-handle'})
img.ondragstart = function(self, event)
-- Accept drags for this widget.
return true
end
img.ondragmousemove = function(self, event, dragarg)
-- Set the mouse cursor while dragging.
self.window:request_mouse_cursor(rtk.mouse.cursors.REAPER_DRAGDROP_COPY)
end
The above example requires either REAPER 6.24 or later (due to this bug) or the presence of the js_ReaScriptAPI extension (which enables us to work around the bug).
cursor | (cursorconst) | one of the mouse cursor constants |
force | (bool) | if true, force-replaces the cursor even if it was already set |
(bool) | true if the cursor was set, false if a cursor was already during this update cycle. |
Clears the window's backing store to the window's background color (or the theme default).
This is a low-level function that normally never needs to be called, but could be used in certain cases within an ondraw handler.
Returns a normalized version of a screen-level y coordinate.
On Mac, window y
coordinates are relative to the bottom of the screen, while on
Windows and Linux they are relative to the top. In other words, on Mac, y=0 represents
the bottom of the screen, while on other platforms it's the top of the screen.
This method returns a normalized version of the y
attribute so that it's always
relative to the top of the screen, regardless of platform.
(number or nil) | the normalized |
See also handlers for rtk.Widget.
onupdate() | Called on each update cycle before any reflow (if applicable), animation processing, event handling, or drawing takes place |
onreflow() | Called after one or more widgets have been reflowed (i.e. laid out) within the window |
onmove() | Called when the window changes position |
onresize() | Called when the window changes size |
ondock() | Called when the window is docked or undocked, which includes when the window is first opened |
onclose() | Called after the window is (gracefully) closed by clicking the OS-native close
button or when |
onkeypresspre() | Called when a key event occurs but before it is dispatched to any widgets |
onkeypresspost() | Called when a key event occurs after all widgets have been given a chance to handle the event |
Called on each update cycle before any reflow (if applicable), animation processing, event handling, or drawing takes place. Consequently, any actions performed by the handler that affect the interface will be reflected immediately.
(bool or nil) | if false, the normal update processing will be skipped. |
Called after one or more widgets have been reflowed (i.e. laid out) within the window.
Unlike the base class method, onreflow handlers attached
to rtk.Window
s receive an optional list of widgets. If a full reflow has
occurred (i.e. every visible widget was reflowed), then
widgets
is nil, but if specific widgets were explicitly reflowed this cycle
then widgets
is an array containing the widgets.
widgets | (table or nil) | an array of widgets that were the subset of widgets being reflowed this cycle, or if full reflow occurred then nil |
(nil) | Return value has no significance. This is a notification event only. |
Called when the window changes position.
The x
and y
attributes reflect the current position, while the lastx
and lasty
parameters hold the previous x and y values before the move occurred.
lastx | (number) | the last x value of the window before the move |
lasty | (number) | the last y value of the window before the move |
(nil) | Return value has no significance. This is a notification event only. |
Called when the window changes size.
The w
and h
attributes reflect the current size, while the lastw
and lasth
parameters hold the previous w and h values before the resize occurred.
lastw | (number) | the last width of the window before the resize |
lasth | (number) | the last height of the window before the resize |
(nil) | Return value has no significance. This is a notification event only. |
Called when the window is docked or undocked, which includes when the window is first opened.
When this handler is called, the dock
and docked
attributes reflect the
current state.
(nil) | Return value has no significance. This is a notification event only. |
Called after the window is (gracefully) closed by clicking the OS-native close
button or when close()
is called.
When the window would ungracefully close (e.g. because an exception occurred
causing program abort), the rtk.onerror
handler will be called instead.
You may wish to bind rtk.quit()
to this handler to ensure if the user closes the
window that the script terminates.
(nil) | Return value has no significance. This is a notification event only. |
Called when a key event occurs but before it is dispatched to any widgets.
The caller has the opportunity to mutate the event or set it as handled to prevent any widgets from responding to it.
event | (rtk.Event) | a |
(nil) | Return value has no significance. This is a notification event only. |
Called when a key event occurs after all widgets have been given a chance to handle the event.
event | (rtk.Event) | a |
(nil) | Return value has no significance. This is a notification event only. |