Index
The border layout manager draws a border around a widget. The grid layout manager handles containers with many elements, and also has the means to draw borders around them. The grid layout manager has many options and settings, while the border layout manager is dedicated and optimized for this specific task, and is faster than the grid layout manager for this specific use case. The LibCXX Widget Toolkit uses the border layout manager to draw buttons and keyboard input focus borders.
The border layout manager has an option of adding a title to the border. This visually frames related widgets together and gives them a title.
/* ** Copyright 2017-2021 Double Precision, Inc. ** See COPYING for distribution information. */ #include "config.h" #include <x/mpobj.H> #include <x/appid.H> #include <x/exception.H> #include <x/destroy_callback.H> #include <x/ref.H> #include <x/obj.H> #include <x/w/main_window.H> #include <x/w/gridlayoutmanager.H> #include <x/w/gridfactory.H> #include <x/w/borderlayoutmanager.H> #include <x/w/frame_appearance.H> #include <x/w/label.H> #include <string> #include <iostream> #include <sstream> #include <utility> #include "close_flag.H" std::string x::appid() noexcept { return "borderlayoutmanager.examples.w.libcxx.com"; } static void create_main_window(const x::w::main_window &mw) { auto glm=mw->gridlayout(); // Two sample containers with the border layout manager. One of them // will have a title. // // Even though the rest of the two containers are identical, the // title results in that one being slightly taller. For better // visual appearance, align all elements in row 0 at the bottom. glm->row_alignment(0, x::w::valign::bottom); x::w::gridfactory f=glm->append_row(); x::w::new_borderlayoutmanager nblm; // The creator lambda that gets passed to create_container(). // Get the creaed borderlayout() manager and call its replace() // to obtain a factory which we use to create_label() the // label inside the border. // // This is done for both sample containers, so we just define this // lambda once. auto creator=[] (const x::w::container &c) { c->borderlayout()->replace() ->create_label("Border layout manager"); }; // We're just creating a simple label inside each border. Usually // an entire container gets created inside the border, but we just // have a label. Change the default padding between the border and // its element to 10 millimeters. This makes the container bigger, // for demo purposes. nblm.appearance=nblm.appearance->modify ([] (const auto &appearance) { appearance->hpad=10; appearance->vpad=10; }); f->create_container(creator, nblm); // Create the 2nd one with the title. We can use the same // new_borderlayoutmanager, just set the title. nblm.title("Hello"); f->create_container(creator, nblm); } void borderlayoutmanager() { x::destroy_callback::base::guard guard; auto close_flag=close_flag_ref::create(); auto main_window=x::w::main_window::create(create_main_window); main_window->set_window_title("Borders!"); guard(main_window->connection_mcguffin()); main_window->on_disconnect([] { exit(1); }); main_window->on_delete ([close_flag] (ONLY IN_THREAD, const auto &ignore) { close_flag->close(); }); main_window->show_all(); x::mpcobj<bool>::lock lock{close_flag->flag}; // update_title() updates the existing border's title. const char *titles[2]={"Hello", "World"}; while (!lock.wait_for(std::chrono::seconds(1), [&] { return *lock; })) { std::swap(titles[0], titles[1]); // We want the container in row 0, column 1 of the main window's // grid. x::w::gridlayoutmanager glm=main_window->get_layoutmanager(); x::w::container frame_with_border=glm->get(0, 1); // This container uses the border layout manager. x::w::borderlayoutmanager blm= frame_with_border->get_layoutmanager(); // And update the border's title. blm->update_title(titles[0]); } } int main(int argc, char **argv) { try { borderlayoutmanager(); } catch (const x::exception &e) { e->caught(); exit(1); } return 0; }
Passing an
x::w::new_borderlayoutmanager
to a factory's create_container
()
creates a container with a
x::w::borderlayoutmanager
.
x::w::new_borderlayoutmanager
's creates
an empty container. The usual pattern is to have the creator lambda
get the constructed container's border layout manager and use
its replace
() to obtain a factory that
creates exactly one widget. But that widget can be another container
that, for example, uses the
grid layout mamanager. Thie
results in a border around an entire container of widgets:
factory->create_container( [&] (const x::w::container &c) { auto f=c->borderlayout()->replace(); x::w::new_gridlayoutmanager nglm; f->create_container([] (const x::w::container &c) { // ... }, nglm); }, x::w::new_borderlayoutmanager{} );
This is the typical way to create a border. The creator lambda uses
replace
() to get the new contain's factory.
The border layout manager always manages exactly one widget. Another
widget created by the factory replaces, and takes the place of the
previous one.
The initial replace
() installs the border
layout manager's initial widget, and
the lambda uses the factory to create a container that uses the grid
layout manager, then proceeds to initialize the grid.
The border layout manager draws a border around a single widget,
but this widget could be a container of other widgets.
After setting any needed options in the
x::w::new_borderlayoutmanager
,
create_container() creates the container with the border layout manager:
x::w::container c=f->create_container(creator, nblm);
create_container
() takes the
x::w::new_borderlayoutmanager
and constructs
a new container with the border layout manager, and calls the
lambda to create the widget with the border.
As always, create_container
()
invokes the creator lambda to initialize the contents of the new container.
In the case of the border layout manager the creator lambda typically
retrieves the borderlayout
() to create the
initial widget in the container.