Module Bogue.Layout
Source
The main, all-purpose graphics container.
A layout is a "box" (a rectangle) whose purpose is to place onscreen the various elements composing the GUI. It can contain a single widget, or a list of sub-layouts (recursively). In Bogue, we use the housing metaphor: a layout is a house that contains either a single resident, or several rooms. Each room can be seen as a sub-house, and can contain a resident or sub-rooms. Houses and rooms have the type t
, while a resident has the type Widget.t
.
Technically, the usual metaphor in computer science is a Tree. A layout is a tree, each vertex (or node) has any number of branches (or children). A leaf (terminal node: without any child) is either empty or contains a widget. However, the tree is upside-down (as often): we think of the trunk (or top-layout) to be a the top, and the leaves at the bottom.
Sourceexception Fatal_error of t * string
Sourcetype adjust =
| Fit
| Width
| Height
| Nothing
Backgrounds
Warning, the background
type corresponds actually to the Style.t
type, which means it includes color backgrounds, image patterns, corner and shadow styles.
Construct a background from an RGBA color.
Construct a background from an RGB (ie non-transparent) color.
Construct a background from the given Style
.
This is the background constructed from the current theme's BG_COLOR.
Sourceval unload_background : t -> unit
Free the texture associated with the background (if any). This can be used to force recreating it.
Creation of layouts
Remark: all layouts have an optional name
property, which is used only for debugging.
Sourceval empty :
?name:string ->
?background:background ->
w:int ->
h:int ->
unit ->
t
An empty layout can reserve some space without stealing focus.
Sourceval resident :
?name:string ->
?x:int ->
?y:int ->
?w:int ->
?h:int ->
?background:background ->
?draggable:bool ->
?canvas:Draw.canvas ->
?keyboard_focus:bool ->
Widget.t ->
t
Create a layout (=room) from a single Widget (=resident). The content of such a layout cannot be modified.
Horizontal arrangement of widgets. See flat
.
Vertical arrangement of widgets. See tower
.
Create layouts from other layouts
Create a horizontal arrangement from a list of rooms.
sep
= horizontal space between two rooms (except on the right hand side of a room of zero width).hmargin
= horizontal margin (left and right).vmargin
= vertical margin (top and bottom).- if
margins
is set, then sep, hmargin and vmargin are all set to this value.
Create a vertical arrangement from a list of rooms. See flat
.
Sourceval superpose :
?w:int ->
?h:int ->
?name:string ->
?background:background ->
?canvas:Draw.canvas ->
?center:bool ->
?scale_content:bool ->
t list ->
t
Create a new layout by superposing a list of layouts without changing their (x,y) position. Warning: if a room in a superpose
layout is later moved out of the bounding box, it will never get mouse focus.
Remark: when creating a house (a layout) with flat*
, tower*
, or superpose
, the size of the inner rooms will be automatically updated whenever the size of the house is modified. However, as soon as one manually sets the size or the position of a room inside this house with set_width
, setx
and likes, then the room will stop reacting to changes of the house size.
Some useful layout combinations
Sourceval make_clip :
?w:int ->
?scrollbar:bool ->
?scrollbar_inside:bool ->
?scrollbar_width:int ->
?on_scroll:(int -> unit) ->
h:int ->
t ->
t
Clip a layout inside a smaller container and make it scrollable, and optionally add a scrollbar widget. The on_scroll
function is called anytime the scroll is modified, with the vertical offset as parameter.
Currently, only vertical scrolling is implemented. The ?w
variable is not used.
Get layout attributes
get current absolute x position of the layout (relative to the top-left corner of the window). Not necessarily up-to-date.
Sourceval get_size : t -> int * int
get_size l
is equivalent to (width l, height l)
Sourceval get_physical_size : t -> int * int
multiplies get_size
by the Theme scaling factor. This gives in principle the correct size in physical pixels, up to an error of +/- 1pixel, due to rounding error.
Compute the relative x position of the room with respect to its house, using animations if any. Because of this, this function should not be called by the animation itself! Use get_oldx
instead.
Return the last computed value for the relative x position of the layout.
Return the resident widget, or
Return the top of the layout tree (the "house" that contains the given layout and that is not contained in another layout). It is the only layout that is directly attached to a "physical" (SDL) window.
Modify existing layouts
Layouts should be modified only by the main Thread. If you want to modify a Layout within a Widget.connection
without Main
priority, you should use Sync.push
, or properly lock it using lock
/unlock
.
Set the layout to automatically scale its inner rooms when the layout size is modified.
Sourceval resize_keep_margins :
?margin:int ->
?min_width:int ->
?min_height:int ->
?max_width:int ->
?max_height:int ->
t ->
unit
When asked to resize, the layout will keep the initial 4 margins with respect to its house.
Sourceval disable_resize : t -> unit
This makes sure that nothing is executed when someone tries to resize the layout (that is, when the size of the layout's house changes). Warning; working with resize functions is tricky. disable_resize
should in general be called after the layout has been installed in a house, see comments for on_resize
.
Sourceval on_resize : t -> (unit -> unit) -> unit
on_resize room f
will execute f ()
upon resizing the room's house (or the room's window, in case the room is the top house, see top_house
), in addition to the already registered resize functions. Warning: placing the room in another layout will likely reset the resize function (unless you set the resize
flag to Keep
, see eg. flat
and the remark below that). Hence on_resize
should be called after the room is hosted in its house.
Sourceval set_width :
?keep_resize:bool ->
?check_window:bool ->
?update_bg:bool ->
t ->
int ->
unit
set_width
and similar functions will not work if there is an animation running acting of the variable we want to set (here, the width). Most of these functions will stop the automatic resizing mechanism of the room. Use auto_scale
to reactivate it.
Sourceval set_height :
?keep_resize:bool ->
?check_window:bool ->
?update_bg:bool ->
t ->
int ->
unit
Sourceval set_size :
?keep_resize:bool ->
?check_window:bool ->
?update_bg:bool ->
?w:int ->
?h:int ->
t ->
unit
Sourceval setx : ?keep_resize:bool -> t -> int -> unit
Sourceval sety : ?keep_resize:bool -> t -> int -> unit
Sourceval set_show : t -> bool -> unit
Sourceval fix_content : t -> unit
Disable automatic resizing of the rooms inside this layout.
Sourceval fit_content : ?sep:int -> t -> unit
Adapt the size of the layout (and their houses) to the disposition of the contained rooms.
Sourceval set_rooms : t -> ?sync:bool -> t list -> unit
Modify the layout content by replacing the former content by a new list of rooms. Use sync=true
(the default) as much as possible in order to avoid multi-threading problems. Then the changes will be applied by the main thread at next frame (see Sync
).
Sourceval replace_room : by:t -> t -> bool
Replace room
by by
inside its "house" in lieu and place of the initial room. No size adjustments are made.
Using replace_room
can be dangerous, because it modifies both the room
's house and by
. Beware of circular dependencies...
This function cannot be used for the top_house
(the window layout) because that layout has no house. Also, the function not accept to proceed if by
already belongs to a house.
Sourceval set_enabled : t -> bool -> unit
Disable or enable a layout and all its rooms recursively. A disabled layout will not accept any mouse or keyboard focus.
Sourceval iter_unload_textures : t -> unit
Use this to free the textures stored by the layout (and its children) for reducing memory. The layout can still be used without any impact, the textures will be recreated on the fly.
In general, modifying a layout should by done by the main Thread or by using a Sync.push
. However, in case you need a layout to be modified by different threads, you should lock it with lock
. Once a layout is locked, another lock
statement from another thread will wait for the previous lock to be removed by unlock
. Locking twice by the same thread is allowed, and will not block, which allows recursive locking, but this practice should be avoided because it is difficult to debug. If you need a higher level locking API, wrap the layout in a Var.t
variable.
Animations
Position, size, alpha channel, and rotation of Layouts use Avar
variables and hence can be easily animated. Most predefined animations have a default duration of 300ms.
Generic animations
These functions assign an animated variable if type Avar.t
to one of the properties of the layout (position, width, etc.)
Assign an Avar to the layout x position.
Stop animations of the variables x and y.
Predefined animations
Does nothing if the layout is already fully displayed. Only the Avar.Top
and Avar.Bottom
directions are currently implemented. For these directions, hide
and show
do not modify the position variables (x,y) of the layout, they use a special variable called voffset
.
Sourceval fade_in :
?duration:int ->
?from_alpha:float ->
?to_alpha:float ->
t ->
unit
Animate the alpha channel of the layout. Can be combined with animations involving the other animated variables. Does not modify the show
status of the layout. By default, from_alpha=0.
(transparent) and to_alpha=1.
(opaque).
Sourceval fade_out :
?duration:int ->
?from_alpha:float ->
?to_alpha:float ->
?hide:bool ->
t ->
unit
See fade_in
. WARNING: fading out to alpha=0 results in a completely transparent layout, but the layout is still there (it's not "hidden"). Which means it can still get mouse focus. If you want to hide it, then use hide=true
. By default, hide=false
, from_alpha
is the current alpha of the layout, and to_alpha=0.
Sourceval rotate : ?duration:int -> ?from_angle:float -> angle:float -> t -> unit
Rotate all widgets inside the layout around their respective centers. For a global rotation, use a Snapshot
.
Sourceval slide_to : ?duration:int -> t -> (int * int) -> unit
slide_to room (x0,y0)
will translate the room
to the position (x0,y0)
.
Sourceval follow_mouse :
?dx:int ->
?dy:int ->
?modifierx:(int -> int) ->
?modifiery:(int -> int) ->
t ->
unit
Sourceval oscillate : ?duration:int -> ?frequency:float -> int -> t -> unit
Sourceval zoom : ?duration:int -> from_factor:float -> to_factor:float -> t -> unit
Sourceval reflat :
?align:Draw.align ->
?hmargin:int ->
?vmargin:int ->
?margins:int ->
?duration:int ->
t ->
unit
Adjust an existing layout to arrange its rooms in a "flat" fashion, as if they were created by Layout.flat
. Will be animated if duration <> 0
.
Sourceval retower :
?align:Draw.align ->
?hmargin:int ->
?vmargin:int ->
?margins:int ->
?duration:int ->
t ->
unit
Windows
An SDL window is created for each Layout in the list sent to Main.create
.
Return the SDL window containing the layout. It will return None
if the window was not created yet, or was previously destroyed. Note that SDL windows are created by Main.run
, not before.
Make the window containing the layout appear onscreen, using set_show
and Sdl.show_window
. (If the layout was hidden at startup, Sdl.show_window
is not enough to display the layout: use this function instead.)
Hide the window containing the layout.
Sourceval set_window_pos : t -> (int * int) -> unit
set_window_pos layout x y
sets the position of the window containing layout
to (x,y), in physical pixels. (0,0) is top-left. This should be run after Main.create
.
Sourceval get_window_pos : t -> int option * int option
Return the window position within the desktop, in physical pixels.
Emit the close-window event to the window containing the layout, as if the user clicked on the close button. This should close the window at the next graphics frame, or execute the function registered by Window.on_close
.
Sourceval destroy_window : t -> unit
Emit the destroy_window event to ask Bogue to destroy the SDL window containing the layout.
Misc
Sourceval inside : t -> (int * int) -> bool
Sourceval claim_keyboard_focus : t -> unit
Sourceval set_cursor : t option -> unit
Set the current cursor to the default value for this layout.
Search for the room containing the widget, if any.