387 lines
17 KiB
TeX
387 lines
17 KiB
TeX
\chapter{Creating new widgets and dialogues}
|
|
|
|
This chapter dives into the area of creating your own widgets or dialogues. For
|
|
this example we use a real widget and a dialogue under development. The widget
|
|
being developed is the progress bar and the screen the initial load screen.
|
|
|
|
First we make the widget, then the screen in order to test the widget. It
|
|
happens often that, when you need to add a new widget, you need it for a new
|
|
dialogue - so you need to create both for testing. Another option is to add the
|
|
widget as dummy item to another existing dialogue. When adding a dialogue for
|
|
which all widgets already exist this doesn't matter and you can directly dive
|
|
into generating the dialogue.
|
|
|
|
\section{Creating the widget}
|
|
\label{sec:creating_the_widget}
|
|
|
|
The widget is normally split in 7 different files. Three .cpp/.hpp files and one
|
|
WML file. Usually I start to create the new files by simply copy pasting the old
|
|
files and pick a rather small class like timage or something. Then, I start to
|
|
update the build system files, followed by creating the code for the
|
|
classes\footnote{Obviously I already thought about the design of the class
|
|
before that, but that's of less importance in this tutorial.}.
|
|
|
|
Now, we start to explain what the various files do. First, I do a general overview of
|
|
the files after which I dive more into the implementation of each file.
|
|
|
|
\begin{description}
|
|
|
|
\item[src/gui/auxiliary/widget\_definition/progress\_bar.*]
|
|
These files contain the definition of the progress bar. This mainly involves
|
|
the fixed fields for the widget. This widget has no extra fields so the copy
|
|
pasted version suffices. This file contains the \emph{static} properties for
|
|
a certain definition of a progress bar.
|
|
|
|
\begin{description}
|
|
\item[hpp] \Liref{widget_definition.hpp} contains the sample code.
|
|
\begin{description}
|
|
\item[\Lref{widget_definition.hpp:control}] Normally a
|
|
widget definition inherits from tcontrol\_definition which defines the
|
|
basic mandatory fields for a widget definition and a templated load
|
|
function for the resolution. Most widgets don't add more members to this
|
|
class.
|
|
\item[\Lref{widget_definition.hpp:resolution}] Normally a resolution
|
|
definition inherits from tresolution\_definition\_ which define the
|
|
basic mandatory fields for a resolution definition. Not all widgets use
|
|
these members, but most do. Most widgets don't add more members to this
|
|
class, except most container classes that add a grid builder
|
|
definition. Another example is are the scrollbars which define some
|
|
minimum sizes for parts of their control.
|
|
\end{description}
|
|
|
|
\item[cpp] \Liref{widget_definition.cpp} contains the sample code.
|
|
\begin{description}
|
|
\item[\Lref{widget_definition.cpp:textdomain}] Every file in the library
|
|
is inside the ``wesnoth-lib'' text domain.
|
|
\item[\Lref{widget_definition.cpp:constructor}] The constructor used is
|
|
pretty typical for all widgets.
|
|
\item[\Lref{widget_definition.cpp:resolution_constructor}] The
|
|
constructor used is semi-typical. Resolutions that have their own
|
|
members initialize them in the constructor, but also validate mandatory
|
|
fields for their existence.
|
|
|
|
Also the progress bar only has one state, most widgets have more and
|
|
thus add more states.
|
|
|
|
And maybe the most important part of this constructor is the wiki
|
|
comment. This comment is used to generate wiki pages about the widget.
|
|
These wiki pages are used by content creators to know how to create a
|
|
proper WML file for the class.
|
|
\end{description}
|
|
\end{description}
|
|
|
|
\item[data/gui/default/widget/progress\_bar\_default.cfg]
|
|
Now that the widget is defined, we can decide how it should look. Which is
|
|
done in this file. Note that in the formula we use ``percentage'' which is
|
|
the percentage of the bar to be filled.
|
|
|
|
\begin{description}
|
|
\item[\Lref{progress_bar.cfg:textdomain}] Every file in the library
|
|
is inside the ``wesnoth-lib'' text domain.
|
|
|
|
\item[\Lref{progress_bar.cfg:class}]
|
|
Beginning of the progress bar. This part is much better documented in
|
|
the wiki\footnote{\url{http://wiki.wesnoth.org/GUIWidgetDefinitionWML}}.
|
|
Since this part is aimed at WML authors, duplicating that effort here
|
|
makes no sense so just visit the wiki.
|
|
|
|
\end{description}
|
|
|
|
\item[src/gui/auxiliary/window\_builder/progress\_bar.*]
|
|
These files contain the code to build a widget from the definition described
|
|
above and a config object as defined in the window. These files contain also the
|
|
\emph{dynamic} properties of the progress bar. Since the progress bar has no
|
|
dynamic content this file is also rather short.
|
|
|
|
\begin{description}
|
|
\item[hpp] \Liref{window_builder.hpp} contains the sample code.
|
|
\begin{description}
|
|
\item[\Lref{window_builder.hpp:control}] Normally a
|
|
window builder inherits from tbuilder\_control which defines the
|
|
basic mandatory fields for a window builder.
|
|
|
|
The function also declares the build function.
|
|
|
|
Widget define their own member if they want to have some runtime
|
|
settings, e.g. the spacer defines its fixed size if needed.
|
|
\end{description}
|
|
|
|
\item[cpp] \Liref{window_builder.cpp} contains the sample code.
|
|
\begin{description}
|
|
\item[\Lref{window_builder.cpp:textdomain}] Every file in the library
|
|
is inside the ``wesnoth-lib'' text domain.
|
|
\item[\Lref{window_builder.cpp:constructor}] The constructor used is
|
|
pretty typical for all widgets.
|
|
|
|
If the constructor initializes custom members it may also add some validation.
|
|
This is also true when the widget has a grid, like the listbox or
|
|
multi\_page.
|
|
\item[\Lref{window_builder.cpp:build}]
|
|
This build() is semi-typical, it creates the widget, initializes the
|
|
default fields and returns the created object.
|
|
|
|
Widgets with their own members initialize them after initializing the
|
|
default members.
|
|
\item[\Lref{window_builder.cpp:wiki}]
|
|
At the end of the file it contains two wiki comment sections:
|
|
|
|
The first defines a macro with a short description of the widget.
|
|
|
|
The second describes the extra fields for the instance of the widget.
|
|
\end{description}
|
|
\end{description}
|
|
|
|
\item[src/gui/widgets/progress\_bar.*]
|
|
These files contain the interaction the widget has with the outer world and
|
|
how it reacts to events. Again, the progress bar is rather boring. The
|
|
interesting part is the setter of the percentage. The value of the
|
|
percentage used in the drawing routines is set here\footnote{Other classes have a
|
|
separate update canvas, but that's because the canvas in those classes is
|
|
invalidated in several functions.}.
|
|
|
|
\begin{description}
|
|
\item[hpp] \Liref{progress_bar.hpp} contains the sample code.
|
|
\begin{description}
|
|
\item[\Lref{progress_bar.hpp:class}]
|
|
Most simple widgets derive from tcontrol, which is the base class of the
|
|
visual widgets. Another common base is tcontainer or
|
|
tscrollbar\_container.
|
|
|
|
\item[\Lref{progress_bar.hpp:constructor}]
|
|
The class calls the control constructor with the number of states, which
|
|
is the number of canvases used. Other then that, it does the
|
|
initialization of its members. Some constructors do a bit more
|
|
processing, but where a lot needs to be done it's often deferred to a
|
|
finalize() function.
|
|
|
|
\item[\Lref{progress_bar.hpp:inherited}]
|
|
This section implements or overrides member functions of the base class.
|
|
Some functions are purely virtual and need to be overridden by others to
|
|
change the behaviour.\footnote{Of course, adding here a list of functions which are
|
|
common would be nice. However, the library is still too
|
|
volatile to do so - no need to create a soon out of date list.}
|
|
|
|
\item[\Lref{progress_bar.hpp:settersgetters}]
|
|
This section contains the setters and getters for the class. The
|
|
list below shows the common convention where T is the type of the
|
|
setter/getter and ``foo'' the name of the member without trailing
|
|
underscore.
|
|
|
|
\begin{description}
|
|
\item{setter}
|
|
Signature void set\_foo(const T foo); The type T can be by reference
|
|
if a larger class.
|
|
|
|
\item{getter}
|
|
Signature T get\_foo() const { return foo\_; } The type T is always
|
|
returned by value.
|
|
|
|
\item{reference}
|
|
Signature T\& foo() { return foo\_; } This version returns the value
|
|
by reference, and it should also have a const version. These
|
|
functions or at least the non-const version are often not public.
|
|
|
|
\item{pointer}
|
|
Signature T* foo() { return foo\_; } Almost the same as the
|
|
reference version and is used for members that are pointers. The
|
|
text of the reference also applies here.
|
|
\end{description}
|
|
|
|
The setter is normally available. The getter is often omitted when a
|
|
reference or pointer function are used. Especially it there is a const
|
|
version of these functions.
|
|
|
|
\item[\Lref{progress_bar.hpp:state}]
|
|
The state has the list of states available and normally has COUNT as
|
|
last value, which in turn is used in the constructor to initialize the
|
|
base class.
|
|
|
|
\end{description}
|
|
|
|
\item[cpp] \Liref{progress_bar.cpp} contains the sample code.
|
|
\begin{description}
|
|
\item[\Lref{progress_bar.cpp:textdomain}] Every file in the library
|
|
is inside the ``wesnoth-lib'' text domain.
|
|
|
|
\item[\Lref{progress_bar.cpp:logheader}]
|
|
The common headers used for logging, this makes sure the output of the
|
|
items always have the same format. Used by
|
|
LOG\_FOO \textless\textless{} LOG\_HEADER \textless\textless{} "foo.\textbackslash{}n"; or
|
|
log\_scope(foo, LOG\_SCOPE); % check function signature
|
|
|
|
\item[\Lref{progress_bar.cpp:register}]
|
|
Registers a widget, this part is really volatile and still has some
|
|
hoops and rings to jump through. Normally, it works. If not, too bad -
|
|
try to look through the other widgets to see how to fix it.
|
|
|
|
\textbf{Caveat emptor} Just when all compiles fine and you suddenly get a runtime
|
|
error about your new nice class, the builder claims your widget doesn't
|
|
exist. \emph{Don't panic}, probably you did nothing wrong. Grep TRY in
|
|
src/gui/auxiliary/window\_builder.cpp (at the moment of writing line 96)
|
|
and read the comment above, duly add your class to the list and be
|
|
happy.
|
|
|
|
\item[\Lref{progress_bar.cpp:get_control_type}]
|
|
A simple helper to get the human readable name of the class. The first
|
|
version was inlined in the header, but that seems to be an ODR
|
|
violation. At least at some point a compiler or linker complained, can't
|
|
really remember which one. % TODO git pick-axe
|
|
|
|
\end{description}
|
|
\end{description}
|
|
|
|
This completes the writing of the files for the new classes, some files need to
|
|
be modified to get things up and running. The build system files need the three
|
|
new .cpp files listed, these are:
|
|
\begin{itemize}
|
|
\item src/Makefile.am
|
|
\item src/SConstruct
|
|
\item src/CmakeLists.txt
|
|
\end{itemize}
|
|
|
|
The next step has become optional now, when most of build systems can glob the files
|
|
needed for translation, but I still add them manually as well. The file is
|
|
po/wesnoth-lib/POTFILES.IN. It holds the files for the wesnoth-lib text
|
|
domain.
|
|
|
|
The last file to be edited is src/gui/widgets/settings.cpp. Here, a wiki comment
|
|
for the new class needs to be added, this might change later. The reason is that
|
|
before automatically registering widgets this file needed more modification, so
|
|
it was done in one fell swoop.
|
|
|
|
\end{description}
|
|
|
|
This concludes the simple progress bar widget. Of course, we haven't tested it
|
|
yet, since there's no dialogue to test it in. So let's implement a dialogue.
|
|
|
|
|
|
\section{Creating the window}
|
|
\label{sec:creating_the_window}
|
|
|
|
The window is normally split in 3 files. One .cpp/.hpp file and one WML file.
|
|
The dialogue used is the unit attack dialogue, at least an initial version. This
|
|
version barely does what it needs to do, and the in game version will be more
|
|
polished. This simple version is nice as an example here since it's not too large.
|
|
|
|
Now, let's explain what the various files do. First, a general overview of
|
|
the files after which I dive more into the implementation of the file.
|
|
|
|
\begin{description}
|
|
|
|
\item[src/gui/dialogs/unit\_attack.*pp]
|
|
These files contain the code of the dialogue. This code `binds' the WML
|
|
code and allows the C++ code to show the dialogue show the right data at the
|
|
right place. In several cases this also allows the designer of the WML file
|
|
to decide which widget s/he picks.
|
|
|
|
\begin{description}
|
|
\item[hpp] \Liref{unit_attack.hpp} contains the sample code.
|
|
\begin{description}
|
|
\item[\Lref{unit_attack.hpp:class}]
|
|
Defines the class itself, which normally inherits from tdialog.
|
|
Sometimes a class inherits from another class, but this other class then
|
|
derives from tdialog; for example the wml\_dialogs have a common base and
|
|
separate classes for left and right.
|
|
|
|
\item[\Lref{unit_attack.hpp:constructor}]
|
|
Dialogues are often created and then shown once before being destroyed,
|
|
therefore the constructor often takes all the parameters needed. Since the show()
|
|
function shouldn't be overloaded, the only other alternative would be member
|
|
functions to set the members. Note that when keeping `references' to widgets these
|
|
members must be pointers and set to NULL in the constructor, this due to the
|
|
simple fact that the widgets aren't yet created at this point. Also keep in mind that
|
|
when the dialogue is shown twice (using the \emph{same} object) the widgets won't be
|
|
the same. The window owning the widgets is destroyed after being shown and
|
|
a new one created upon the next call to show().
|
|
|
|
\item[\Lref{unit_attack.hpp:settersgetters}]
|
|
As said before, there are often no setters, since all is set in the
|
|
contructor. Most members also remain hidden, since the caller has the
|
|
information. Only members that change are `exported'. The most common example in
|
|
a class with a listbox, the last selected item is made public, since this is
|
|
often used as the choice the user made.
|
|
|
|
\item[\Lref{unit_attack.hpp:window_id}]
|
|
This function is a part of the window registration and only needs to be
|
|
declared in the header, the definition will be provided by a macro.
|
|
|
|
\item[\Lref{unit_attack.hpp:pre_show}]
|
|
This function is called after the window is created, but before being
|
|
shown. This is the point to set the members that point to a widget. As said
|
|
before, every time the dialogue is shown a newly created window is shown as well, so
|
|
setting the pointers can be unconditional. This is also the place to fill the
|
|
widgets with the proper content, if needed. E.g. filling the languages in the
|
|
language selection dialogue.
|
|
|
|
\item[\Lref{unit_attack.hpp:post_show}]
|
|
Called after the dialogue is shown, this allows you to update certain
|
|
statuses. E.g. if the dialogue is closed with the OK button set the selected
|
|
language to the newly selected language. You can also update it unconditionally
|
|
and let the caller test the status.
|
|
|
|
\item[\Lref{unit_attack.hpp:members}]
|
|
At this point the list of private members start.
|
|
|
|
\end{description}
|
|
|
|
\item[cpp] \Liref{unit_attack.cpp} contains the sample code. Note some
|
|
parts are already described more verbosely in the header and thus not mentioned
|
|
here.
|
|
\begin{description}
|
|
\item[\Lref{unit_attack.cpp:textdomain}]
|
|
Like written for the widget, every file is inside the `wesnoth-lib' text
|
|
domain.
|
|
|
|
\item[\Lref{unit_attack.cpp:wiki}]
|
|
Directly after the includes (inside the gui2 namespace) the wiki
|
|
documentation starts.
|
|
|
|
\item[\Lref{unit_attack.cpp:register}]
|
|
After the wiki documentation the registration code follows, it defines
|
|
the window\_id function and does some other registration parts.
|
|
|
|
\item[\Lref{unit_attack.cpp:pre_show}]
|
|
The pre\_show is already mentioned in the header file and it the one
|
|
used here uses several static helper functions to do it's job.
|
|
|
|
\end{description}
|
|
|
|
\end{description}
|
|
|
|
\item[src/gui/dialogs/unit\_attack.cfg]
|
|
This file contains the WML that defines the widget. It should honour the
|
|
restrains set in the wiki comment like \lref{unit_attack.cpp:wiki}. These
|
|
constrains set the minimum set of needed widgets and their types, and mentions
|
|
the optional widgets. How the widgets are placed and whether only the optional
|
|
ones are set is up to the designer of the dialog. The gui toolkit wiki has more
|
|
information on the subject. Still some parts are worth mentioning.
|
|
|
|
\begin{description}
|
|
\item[\Lref{unit_attack.cfg:textdomain}]
|
|
Every file in the library is inside the ``wesnoth-lib'' text domain.
|
|
|
|
\item[\Lref{unit_attack.cfg:defines}]
|
|
With larger dialogs, I often first design them on paper and then divide the
|
|
dialog in several sections. These sections often are turned into defines in
|
|
order to keep the main dialog rather simple. WML tends to be verbose and deeply
|
|
nested, and the GUI's also tend to have a lot of nested items, these powers
|
|
combined result in deeply nested structure, where one can easily lose the way.
|
|
Also note that all local macros are prefixed with \_GUI, this is to avoid clashes
|
|
with other macros. The BIG in the names are just because I want to make a
|
|
different definition of high resolution screens (this will be the first screen
|
|
using that feature, but that will be added later).
|
|
|
|
\item[\Lref{unit_attack.cfg:window}]
|
|
Not much to tell about this part, since it's all documented in the wiki. %TODO add ref?
|
|
But do note that due to the defines above, the grid in the window itself is
|
|
rather simple.
|
|
|
|
\item[\Lref{unit_attack.cfg:undefines}]
|
|
The local macros are no longer needed so undefine them, I normally
|
|
undefine them in the oposite order of the definitions. I'm quite sure that's not
|
|
actually needed, but it feels the right way\texttrademark.
|
|
|
|
\end{description}
|
|
|
|
\end{description}
|
|
|