wordwraplabel.C
gives an example of using so-called “appearance objects”
to adjust a widget's visual appearance. The visual appearance
of LibCXXW's widgets defaults to the
current display theme.
wordwraplabel.C
overrides the default window
background color to light yellow for showing text
in blue and black colors.
An appearance object is a
reference-counted object
accessed using LibCXX's
smart pointers.
The appearance objects are constant objects, and their smart pointer
handles follow the default LibCXX naming conventions. A main window's
appearance object handle is named
x::w::const_main_window_appearance
.
Each LibCXXW's class that gets used to create a widget
has an appearance object attached to it, and the appearance object
remains attached to the widget for the duration of its
existence.
The connection thread uses appearance objects for rendering.
The appearance objects are thread-safe by the virtue of them being
constant objects.
An existing appearance object never gets modified directly.
Each appearance object's modify
() method
creates a duplicate copy of the
original appearance object which then gets
modified, and modify
() returns a new, constant, appearance object.
A new main window gets created using a
x::w::main_window_config
whose appearance
member specifies the main window's
default visual appearance. This is a design pattern that's universally
shared by all widgets.
For example,
an x::w::new_listlayoutmanager
's
appearance
object specifies the visual appearance
of a new list.
The appearance
is always a
x::const_ref
.
It gets dereferenced to a constant object that cannot be modified.
The initial, default appearance
is always a
cached, constant object that sets the visual appearance from the
current display theme.
Implementing a custom appearance involves using the appearance
object's modify
() to create a modifiable copy
of itself. The resulting object gets modified, and placed back into
the original object where the appearance came from:
#include <x/w/main_window_appearance.H> #include <x/w/rgb.H> x::w::main_window_config config; x::w::const_main_window_appearance appearance=config.appearance; appearance=appearance->modify ([] (const x::w::main_window_appearance &appearance) { appearance->background_color=x::w::white; }); config.appearance=appearance;
x::w::main_window_config
's default
constructor installs the default, cached, appearance
reflecting the current display theme.
Its handle name is
x::w::const_main_window_appearance
reflecting that it's a reference to a const
object.
An appearance object's modify
() method takes
a callable object, or a closure, as its parameter. The closure
receives a modifiable copy of the original appearance object,
an
x::w::main_window_appearance
.
The closure makes changes to the appearance object, and
modify
() returns a new constant
appearance object that replaces
x::w::main_window_config
's original one.
Appearance-objects, like all other library objects, are reference-counted objects. This convention ensures by contract that appearance objects referenced by active widgets are always constant and thread-safe. This approach makes appearance objects modifiable only after they're copied from an existing constant object, and the modified appearance objects remain constant thereafter.
Each call to an existing appearance object's
modify
() creates a new object. It is more
efficient to use the same appearance object with multiple widgets that should have the same visual appearance.
If all widgets with the same appearance get created together, it's simple enough to create their common appearance object and use them when creating each one. When widgets get created in different places, taking advantage of static local function scope is a basic, thread-safe singleton implementation:
#include <x/w/progressbar_appearance.H> static x::w::const_progressbar_appearance create_custom_appearance() { return x::w::progressbar_appearance::base::theme()->modify ([] (const auto &appearance) { appearance->label_font=x::w::font{"liberation mono; point_size=24"}; }); } static x::w::const_progressbar_appearance &custom_progressbar() { static const x::w::const_progressbar_appearance obj= create_custom_appearance(); return obj; } // ... x::w::progressbar_config config; config.appearance=custom_progressbar(); factory->create_progressbar ([] (const LIBCXX_NAMESPACE::w::progressbar &container) { // ... }, config);
custom_progressbar
() returns a native reference
to the same appearance object, that gets automatically constructed
in a thread-safe manner. All progress
bars will share, efficiently, the same appearance object.
It is also possible to create a new appearance object from an XML stylesheet. See Appendix B, LibCXXW theme files for more information.