From 6da140a22af40a1ff73f541fef57b445c6d60260 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Wed, 9 Feb 2011 19:15:22 +0000 Subject: [PATCH] Seperate gui2 design document in several files. --- doc/design/CMakeLists.txt | 14 + doc/design/gui2.sty | 19 + doc/design/gui2.tex | 1027 +---------------- doc/design/gui2/abstract.tex | 21 + .../gui2/creating_widgets_and_dialogs.tex | 388 +++++++ doc/design/gui2/design_details.tex | 182 +++ doc/design/gui2/files_for_the_widget.tex | 51 + doc/design/gui2/files_for_the_window.tex | 21 + doc/design/gui2/introduction.tex | 105 ++ doc/design/gui2/overall_design.tex | 228 ++++ 10 files changed, 1038 insertions(+), 1018 deletions(-) create mode 100644 doc/design/gui2.sty create mode 100644 doc/design/gui2/abstract.tex create mode 100644 doc/design/gui2/creating_widgets_and_dialogs.tex create mode 100644 doc/design/gui2/design_details.tex create mode 100644 doc/design/gui2/files_for_the_widget.tex create mode 100644 doc/design/gui2/files_for_the_window.tex create mode 100644 doc/design/gui2/introduction.tex create mode 100644 doc/design/gui2/overall_design.tex diff --git a/doc/design/CMakeLists.txt b/doc/design/CMakeLists.txt index 1a2848c70d3..7fc6963c3ba 100644 --- a/doc/design/CMakeLists.txt +++ b/doc/design/CMakeLists.txt @@ -13,6 +13,20 @@ if(ENABLE_DESIGN_DOCUMENTS) ADD_LATEX_DOCUMENT( gui2.tex INPUTS + # + # LaTeX files + # + gui2.sty + gui2/abstract.tex + gui2/introduction.tex + gui2/overall_design.tex + gui2/design_details.tex + gui2/creating_widgets_and_dialogs.tex + gui2/files_for_the_widget.tex + gui2/files_for_the_window.tex + # + # Source files. + # gui2/progress_bar.cpp gui2/unit_attack.cpp gui2/widget_definition.cpp diff --git a/doc/design/gui2.sty b/doc/design/gui2.sty new file mode 100644 index 00000000000..463cc25dc8b --- /dev/null +++ b/doc/design/gui2.sty @@ -0,0 +1,19 @@ +\usepackage{listings} +\lstset{ + numbers = left + , showstringspaces = false + , tabsize = 4 + , frame = single + , xrightmargin = -7em + , xleftmargin = -7em +} + +\lstdefinestyle{C++}{ + language = C++ + , escapeinside = {/*@}{@*/}} + +\lstdefinelanguage{WML}{} +\lstdefinestyle{WML}{ + language = WML + , escapeinside = {\#*@}{@*\#}} + diff --git a/doc/design/gui2.tex b/doc/design/gui2.tex index 28271eb8268..559ebbba7b2 100644 --- a/doc/design/gui2.tex +++ b/doc/design/gui2.tex @@ -1,28 +1,12 @@ \documentclass[a4paper,notitlepage]{report} \usepackage[english]{babel} -\usepackage{listings} -\lstset{ - numbers = left - , showstringspaces = false - , tabsize = 4 - , frame = single - , xrightmargin = -7em - , xleftmargin = -7em -} - -\lstdefinestyle{C++}{ - language = C++ - , escapeinside = {/*@}{@*/}} - -\lstdefinelanguage{WML}{} -\lstdefinestyle{WML}{ - language = WML - , escapeinside = {\#*@}{@*\#}} \usepackage{verbatim} \usepackage {hyperref} +\usepackage{gui2} + \author{M.~de Wever} \title{Gui2 design document} @@ -33,1010 +17,17 @@ \tableofcontents -\begin{abstract} - -Late 2007 I started to rewrite the gui engine of Wesnoth, this project is called -the gui2 project. A lot of code and documentation has been written since. The -documentation is available at: -\begin{itemize} -\item \url{http://wiki.wesnoth.org/GUIToolkit} The general information - regarding the project and documentation regarding the WML used. -\item \url{http://devdocs.wesnoth.org} The general doxygen information. -\item \url{http://devdocs.wesnoth.org/pages.html} Contains some links to more - gui2 specific information. -\end{itemize} - -This documentation describes a lot of the details and the wiki describes some of -the design from the WML side. Doxygen contains some information regarding the -design of the C++ side but it misses the overall design. This paper tries to -fill that gap, trying to explain more of the overall design and some of the -design choices. - -\end{abstract} - - -\chapter{Introduction} - -This paper describes the general design of the gui2 project. The paper is -divided in several chapters: -\begin{description} -\item[Chapter 1] Explains why yet another document is added instead of using the - doxygen and a short history of the gui2 project. -\item[Chapter 2] Goes into the general design and structure of the gui2 project. -\item[Chapter 3] Dives deeper into certain parts of the design of certain - classes and algorithms. -\end{description} - -A omission in this paper is the simple story of how to add your own widgets in -the C++ code\footnote{The WML part is described in the wiki.}. I have a slightly -outdated paper on the subject, but decided not to add it; the paper needs -polishing and updates, but I've some design changes planned for the 1.9 -development series. These changes will also change the way of adding new -widgets, so that paper needs to be rewritten and added after the rewrite is -complete. - -\section{Why why why?} - -Why is this document written in \LaTeX{} instead of doxygen? The reason is -simple; during the development of the iterator class I felt I had to write a -lot. Writing much documentation in doxygen feels awkward. A lot of time is spend -on formatting, the number of subsections is limited (too low in my opinion). -Also it's not possible to document why certain functions aren't implemented, a -solution would be to make the function private and declared only, but that feels -like an ugly hack. - -Why is the document needed? In my opinion most manuals written in doxygen are -great as reference manuals but fail to explain how to do certain things with the -library and fail to explain why certain things are implemented in the way it is. -Writing a separate document separated from the code has the disadvantage of -getting earlier out of sync when an implementation details differs, but this can -be used as an advantage as well. Since it's hard to keep the details in sync, -it's a good reason not to dive into these details. This makes a natural -separation between which part should be in doxygen and which part in this -manual. - -Why after the above, are some parts of gui2 documented in separate pages in -doxygen? This indeed seems a contradiction, but it's not. Remember the first -paragraph stating it's annoying to write this kind of documentation in doxygen? -These parts are where I realized it's annoying to do it in doxygen and haven't -been incorporated in this document\footnote{These parts are still mentioned in -this paper, but they refer to the doxygen documentation.}. - -\section{History} - -The gui2 project was started late in 2007 to fix several problems I had with the -current gui at that time. The problems I had were: -\begin{enumerate} -\item When using small resolutions the gui started to look bad, since widgets - simply left their container and were drawn outside it. -\item Most of the gui was hard-coded in the C++ code and thus not configurable - for normal users. -\item ThemeWML, the part that allows the user to configure the layout, is not - well understood by the current developers. -\end{enumerate} - -This let to the following design goals: - -\begin{enumerate} -\item The gui should look well at every possible resolution and automatically - fit well. -\item Everything, or at least as much as possible should be configurable by WML. -\item The project needed more documentation as the current ThemeWML, and explain - how to create your own guis. -\end{enumerate} - -At the time of this writing the project is still work in progress\footnote{It -was never expected to be a short during project.} and will still take while to -finish. This initial goals were pretty clear, and still are. On the other hand -how to implement certain parts provided to be less clear. - -The library is the first time I designed a gui toolkit and like with all larger -projects, you need to learn from mistakes; preferably of others, but your doomed -to make your own as well. The design process is an iterative one, causing some -parts of the design to be changed several times. At the time of -writing\footnote{Shortly before the 1.8 release.} a lot of areas feel stable, -but others are still planned to be rewritten. Mainly the handling of scrollbar -widgets feels awkward and hacky and are slated for a redesign. - -Other parts of the gui are still in the planning stage and not implemented yet, -but the project moves along at a steady pace and more features will be added in -the future. - -\paragraph{} - -The history of this document also goes back a long time, it's mostly build from -various scraps of notes I have on my system. The plan was to change these notes -to doxygen format some day put it in the source. The problem was to find a nice -place in the source to do so. - -This lead to the fact the notes just stayed on my system and the number of -notes accumulated. During travelling to work I started to design some things for -the 1.9 development series and for the iterator class I needed a new kind of -document. I decided that was the final straw and started to work on writing this -document while travelling. - -Since you read this document it's uploaded in the Wesnoth source tree, this -doesn't mean the document is complete. In fact it more means the opposite, the -draft is uploaded and I can start to work on finishing the document by adding -the missing information. - - -\chapter{Overall design} - -This chapter takes a deeper look into the overall design of the library. Before -we can explain how things work, we'll have a look at the features; both -implemented and planned for the future. Once we know what the gui should be able -to do I'll explain how these goals are achieved. The chapter ends with a short -explanation of the directory structure so you'll be able to find the parts of -the library. - -\section{Features} - -Wesnoth runs on a large amount of devices, with an even larger amount of display -resolutions, from $320\times 240$ on hand-held devices to $2560\times 1600$ on -large 30" screens. The gui should look appealing on all these devices. Therefore -there are three resolution groups: -\begin{description} -\item[hand-held devices] For these devices the code needs to be compiled with -\textbf{TINY\_GUI}. This forces all images to be scaled down by a factor two. - The typical resolutions on these devices are $320\times 240$ -- $640\times - 480$. -\item[PC] For the usage on PC's Wesnoth offers the resolutions $800\times 600$ - -- $2560\times 1600$\footnote{And larger once screens that size become - available.}. -\item[Netbooks] When the first netbooks were introduced the normal resolution - was $800\times 480$, which is slightly smaller as the minimum PC resolution. - Therefore a start option \textsc{--smallgui} was added making minimal - modifications to the layout\footnote{Actually this is gui1 only.}. -\end{description} - -In order to facilitate this range of resolutions the gui2 code allows several -definitions of a window, tuned for a specific resolution. The reason is twofold; -first to make a difference between the hand-held devices and PCs, second allow -different views for different resolutions. - -The main example of this feature\footnote{Not yet implemented, but one of the -main reasons to add this feature.} is the attack dialogue. The dialogue has a -button to show the damage calculation, which shows a new dialogue with the -calculation overview. From an UI point of view I consider that rather ugly and -rather have tabs to switch between the view. But when I have a larger screen the -dialogue only fills a small part and I need to switch between tabs to see the -info, in that case I rather have one dialogue without tabs, which directly shows -all information. When the user changes the resolution the dialogue should switch -between these two views, depending on the current resolution. - -\paragraph{} - -The gui should be able to adapt to the size actually needed, the current gui -uses fixed sizes at some places. This leads to problems that when the screen -resolution is reduced widgets end up outside the dialogue or get truncated. The -same for some translated texts, where the translation is much longer as the -English original. Gui2 solves this problem by dynamically determining the size -of a widget and adjust the layout until it fits. This has the disadvantage that -dialogues with a lot of dynamic content, resize at random times and changing the -layout of the dialogue slightly. Another disadvantage is that when a dialogue -doesn't fit Wesnoth terminates. This problem can be fixed by adding scrollbars -to every window. When the dialogue doesn't fit the scrollbars are used and the -dialogue fits again, might be a bit ugly but at least everything fits again. - -\paragraph{} - -It must be possible for WML designers to change the entire gui of Wesnoth with -their own version. For example Spacenoth\footnote{That project is dead, but -that doesn't matter for this example.} is Wesnoth is a space setting, so the -project might want to use a more fitting user interface. - -Adding a new gui is a lot of work and can't be done in one fell swoop, so the -code needs to support a gradual conversion. Therefore when you select your own -theme\footnote{Support for this selection and the entire fall-back haven't been -added yet. Obviously I want to add support, but it remains low priority until -somebody really wants to add their own gui.} the engine first searches in the -new theme for items\footnote{A widget or window.}. When an item is not found it -uses that item from the default theme. Therefore it's mandatory that every item -is defined for the default gui, which the engine validates at -startup\footnote{That causes the problem that Wesnoth sometimes refused to start -when the source and data are out-of-sync.}. - -\section{The big picture} - -First we dive into the components that define the gui. - -\subsection{Widget} - -A widget is the basic user interface element, like a label, a button or a text -entry. Every widget has its own behaviour, which sometimes can be influenced by -certain settings, but the main behaviour is fixed per widget. Next to behaviour -a widget also has a visual representation so the user can see and interact with -the widget. - -Before the widget is shown to the user it needs to be created first, the -creation happens in the window builder class. This class reads the definition of -a widget and fills in the blanks et voil\`a the widget is there. Let's go over -this part in more slow-motion. - -\paragraph{The definition} -The definition determines how a widget looks and some basic properties, these -properties are the same for all instances of that widget. For example a button -has a minimum size so the decoration can be drawn. It's possible to make -multiple definitions of a button. These different definitions, can look -different have different minimum sizes and other properties. - -These definitions are written in WML and a small loader class loads and -validates the definition. The definition is then added to the list of known -widgets of this type. - -The definition of the widget depends on the resolution, this is for example used -in the button. It has a minimum size depending on the decoration used, in -\textbf{TINY\_GUI} mode the decoration is scaled down, so the minimum size can -also be reduced. - -\paragraph{The builder} -The builder is started from the C++ code, started while building a window. This -window definition contains a list of widget to build with more instance specific -values. For example a label builder has the text to show to the user as -parameter. - -These builder ``scripts'' are also written in WML and loaded by as small loader -class that does the validation and build the needed widget. - -\paragraph{Widget} -The widget itself is written in a larger C++ class and it defines the behaviour -and provide various hooks to modify the properties of that widget. These hooks -are used by the builder, but can also be modified later by the engine. - -Other hooks provide bindings to react to events. The bindings are now rather -static, but with the new event handling added late in the 1.8 release series -more things are possible. The plan is to enhance this part during the 1.9 -release series and deprecate and remove the current interface. - -Of course the question ``why wait until 1.9'' raises. The reason is simple it -was added late in the 1.8 cycle to fix certain issues with the MP lobby at that -time I had no time to convert the rest of the code, since I was working on the -MP lobby instead. - -\subsection{Window} - -A window can mean two things, the window widget and the window definition. In -this section the window definition is meant. Already discussed before, but a bit -more verbose this time. - -The window definition defines a window and which widgets are placed in the -window. This window definition also depends on the resolution. This allows the -window to look different depending on the resolution. The changes can be small -or the window can look completely different. - -\subsection{Dialogue} - -A dialogue is a pure C++ thing. A dialogue shows a window, but is not a window. -So what's the difference\footnote{These are the definitions used in the gui2 -code and not the definition of other window toolkits.}? A window is a dumb -combination of widgets created depending on the definitions in a WML file. After -the window is created it often needs extra content and react to certain events. -For example the language dialogue after building has an empty list of languages. -This is where the dialogue comes into play. The user asks for the language -selection dialogue. The code creates and shows a dialogue. The dialogue code -builds a window, then fills the language list with the available languages and -selects the current language and then shows it to the user. - -In other dialogues the code also needs to wire in event handlers or build other -structures. It searches the wanted widget by id, in some cases it doesn't even -care what kind of widget is used. In other cases it needs to be of a certain -class or ``concept''. This allows a flexible design and let the user select the -kind of widget used in some cases. - -So the dialogue is the sugar between the WML window and an interactive dialogue -shown in the game. - -\section{Directory structure} - -This section describes the directories available, instead of listing them in -alphabetic order I list them in a order that makes explaining them more natural. - -\begin{description} -\item[src/gui] The general source code directory with all parts used for the gui. - -\begin{description} -\item[dialogs] This directory contains all dialogues used in Wesnoth, in - general every file contains one dialogue, the name of the file being the - logical name of what the dialogue does. Some dialogues have a helper - dialogue, which is sometimes embedded in the same file. -\item[widgets] This directory contains all widgets used in the library. Every - file contains one widget. Also base classes or concepts of widgets are - stored in this directory. During the development it also accumulated some - helper files, which don't fit in the aforementioned descriptions, this lead - to the creation of the auxiliary directory. Some files haven't been moved to - this new directory yet. -\item[auxiliary] This directory contains items auxiliary classes. Some helper - parts are so large that they got their own subdirectory. - -\begin{description} -\item[event] Contains all event handling code, the translation from SDL events - to the internal events and their dispatching. -\item[widget\_definition] Contains the code to serialize the WML to an internal - data structure, needed to define that kind of widget. The names of the files - match the widget names. (Most files are rather small, but I prefer small - single tasked files over huge files controlling a lot of code\footnote{Some - might remember I started with a single file, which did exactly that, but the - file got too large to maintain efficiently.}. -\item[window\_builder] Contains the code to create a widget object, from the - widget definition and the data supplied in the window definition. Again the - name of the file matches the name of widget they build. (These files are - also mostly small.) -\end{description} - -\end{description} - -\item[data/gui] The general data directory with all parts used for the gui. All - guis shipped with Wesnoth should be in a sub-directory of this one, with a - config file with the name of the directory as main entry point and include - the sub-directory. At the time of writing only one gui is shipped, the - default one. - -\begin{description} -\item[default] This directory is the bases for the default gui. - -\begin{description} -\item[macro] This directory contains some helper macros, for default font sizes. -\item[widget] This directory contains the definitions of widgets. Since there - can be multiple definitions of a widget their name is the name of the widget - with a suffix. The suffix for the default widgets is, \textsc{default} for - the others an appropriate name is picked. -\item[window] Contains the definitions of windows, the name of the files is the - name of the dialogue they represent. -\end{description} - -\end{description} - -\end{description} - - -\chapter{Design details} - -Now that the big picture regarding the library is known, I dive into parts of -the code that can use more explanation. A part not explained here, doesn't mean -the code is obvious or simple, lack of time to document it properly is more -likely the excuse. - -\section{Boot strapping the library} - -Before the library can be started the available widgets and windows need to -be registered. This registering is done before \textsc{main()} is started. -The registering is done by some small static classes that do the registering -of the item\footnote{Widget or Window.} in its constructor. Since this -involves some redundant typing there are REGISTER\_XXX macros written. - -After all items are register the library can be started, which is simply -done by \textsc{gui2::init()}. This function does all required steps to get -the library up and running. - -\section{Layout algorithm} - -An important part of the gui engine is to properly layout the widgets in the -available space. The documentation of that algorithm is written in -doxygen\footnote{\url{http://devdocs.wesnoth.org/layout\_algorihm.html}}. - -\section{Event handling and dispatching} -\label{event_handling} - -The event handling translates the ``raw'' SDL events to an event structure -specific to gui2, effectively decoupling the interface. This also allows adding -frameworks to fake events. The documentation of that code is written in doxygen -doxygen\footnote{\url{http://devdocs.wesnoth.org/event_dispatching.html}} - -\section{Iterator} - -The iterator class is written\footnote{The code hasn't been written yet only -designed how it should look. Still I feel the design is rather finished and I -can update this paper if details change too much.} to alleviate certain -problems. The scrollbar containers have their own grid and a grid for it's -content. The implantation makes the looping over all children tricky. This has -been solved, but the design of the solution is rather awkward. Obviously fixing -the design is the right thing to do, but that breaks the iteration. - -By first writing an iteration class the interface for iteration can be kept -cleaner and the classes can easily be refactored. - -\subsection{Design} - -There are two basic kind of iterators in the design, the simple ones that can -only travel themselves and their direct children. This type will be referred to -as basic iterator hereafter. - -This basic iterator is a superclass for several specific subclasses. The -superclass is a concrete class, which can be instantiated. This class acts as a -sentinel iterator, signalling the end of a list. - -Every widget has it's own creation function returning a pointer to a subclass -object, allowing the main iterator to keep pointers to basic iterators, which it -uses for travelling. - -\paragraph{} - -The other kind is called the main iterator. This iterator is the type the user -normally creates and uses. The class is a template class, where a policy designs -how the travelling should go\footnote{For now only one policy is planned, but I -can think of more kinds}. - -When the main iterator is created it's possible to add a predicate to the -constructor. The predicate determines what the travelling routine does with a -candidate widget. - -Now that we know the players in the game look further about the implementation -details and the decisions made. - -\subsubsection{Travelling} - -A widget can have several ``layers'' namely: - -\begin{description} -\item[self] The widget itself. -\item[grid] Container widget have a grid which is another layer, note that for a - grid widget, its grid and self layer are the same. -\item[content] Scrollbar containers have a grid, containing their scrollbars and - a dummy content spacer. Their real content is stored in a separate internal - node, which is used as content layer. -\end{description} - -The travel policy decides in which order these layers are visited, and when a -node from a ``grid'' or ``content'' is returned, which direction to travel? -Travel over them first and then into their children or children first? These -decisions are coded in the travelling policy. - -While travelling, the policy finds a candidate widget to travel to. This widget is -offered for evaluation to the predicate, which returns one of the following -values: - -\begin{description} -\item[return] The widget referred by the iterator is accepted and the algorithm - found its target. -\item[continue] The widget is skipped and the next candidate is sought. -\item[break] The widget is not allowed and the travelling at this layer stops. - This doesn't mean the algorithm gives up. This layer is cancelled but the - travelling path might have more options, which are used. At the moment there's - no way to tell that the candidate has failed and that the searching should stop - altogether, a ``exit'' result might be added for that case. -\end{description} - -Obviously these names are inspired by the C++ keywords. - -\subsubsection{Copying} - -The basic iterators are copyable since their state can easily be copied. - -\paragraph{} - -The main iterator can't be copied, it would involve copying the state -and copying the iterator is deemed not to be needed. - -\subsubsection{Operator++(int) (postfix increment)} - -The postfix increment operator hasn't been added to either widget type. For the -basic iterators, there's the problem that the type iterator returned after -iteration might not be the original type. This works properly on the prefix -increment operator since it's a virtual function, using the covariant return -type. - -The postfix version needs to return an object and that would involve slicing the -returned object instead of binding it to a reference. - -\paragraph{} - -The main iterator has no postfix increment operator since it's not copyable. -This of course is a bit the chicken and the egg problem, since I wanted to -prevent the postfix increment operator I made the class not copyable. - -For most (standard) iterator classes the overhead of copying isn't too high -since those iterators carry little state. This iterator carries a lot of state, -so you don't want to copy it. The cost of copying is $O(n)$ where $n$ is the -depth in the widget tree the iterator is\footnote{This might depend on the -travelling policy, but it won't get cheap}. So in the same spirit that the -standard library doesn't add operator[] for std::list I omitted the postfix -increment operator. - - -\section{Callbacks} - -\S~\ref{event_handling} describes the generic event handling for the widgets but -in some cases a widget wants to notify other widgets of a state change. Parts of -gui2 use simple C-style callbacks for that purpose, but using boost::function -makes better replacement. Therefore the code was analysed closer and another -problem should be rectified; The callback causes a binding between two objects, -but they are not notified of the deletion of the object leaving a hole for -calling a destroyed object. - -In order to fix the problem two classes are defined: - -\begin{description} -\item[tnotifier] The class sending the wanted notification. -\item[tnotifiee] The class to manage the lifetime of the connection. -\end{description} - -The tnotifiee is a small class that holds a pointer to the receiver its -connected to, upon destruction it uses this pointer to deregister itself by the -receiver. There after the callback function will no longer be called. - -The class should be used as member of a class so it can manage the lifetime of -the connection with the tnotifier. - -\paragraph{} - -The tnotifier is the main class, when a callback is registered it stores the -callbacks in an internal list and updates the pointer in the tnotifiee to -itself. - -Upon destruction it clears the pointer in all tnotifiees that point to use, that -way upon destruction of the tnotifiee it won't try to deregister itself with -this destroyed object. - -Subclasses of the tnotifier should add an notification function so the notifier -can call all callbacks in the list. The notifier should take care of this -calling. - - -\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 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, this -happens often when you need to add a new widget that 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 a general overview of -the files after which I dive more into the implementation of the 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] Listing \ref{widget_definition.hpp} contains the sample code. - \begin{description} - \item[Line \ref{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[Line \ref{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] Listing \ref{widget_definition.cpp} contains the sample code. - \begin{description} - \item[Line \ref{widget_definition.cpp:textdomain}] Every file in the library - is inside the ``wesnoth-lib'' text domain. - \item[Line \ref{widget_definition.cpp:constructor}] The constructor used is - pretty typical for all widgets. - \item[Line \ref{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[Line \ref{progress_bar.cfg:textdomain}] Every file in the library - is inside the ``wesnoth-lib'' text domain. - - \item[Line \ref{progress_bar.cfg:class}] - Beginning of the progress bar, this part is much better documented in - the wiki %TODO ref - 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. This file contains 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] Listing \ref{window_builder.hpp} contains the sample code. - \begin{description} - \item[Line \ref{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] Listing \ref{window_builder.cpp} contains the sample code. - \begin{description} - \item[Line \ref{window_builder.cpp:textdomain}] Every file in the library - is inside the ``wesnoth-lib'' text domain. - \item[Line \ref{window_builder.cpp:constructor}] The constructor used is - pretty typical for all widgets. - - If the constructor initialize custom members it may add some validation. - This is also true when the widget has a grid, like the listbox or - multi\_page. - \item[Line \ref{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[Line \ref{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, here the value of the - percentage use in the drawing routines is set\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] Listing \ref{progress_bar.hpp} contains the sample code. - \begin{description} - \item[Line \ref{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[Line \ref{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[Line \ref{progress_bar.hpp:inherited}] - This section implements or overrides member functions of the base class. - Some functions are pure virtual and need to be overridden others to - change behaviour.\footnote{Of course a list of which functions are - common the add here would be nice, however the library is still too - volatile to do so, no need to create a soon out of date list.} - - \item[Line \ref{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. - - Furthermore this version often has no normal getter but may have a - setter. - \end{description} - - \item[Line \ref{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] Listing \ref{progress_bar.cpp} contains the sample code. - \begin{description} - \item[Line \ref{progress_bar.cpp:textdomain}] Every file in the library - is inside the ``wesnoth-lib'' text domain. - - \item[Line \ref{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[Line \ref{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 and - look through the other widgets to see how to fix it. - - \textbf{Caveat emptor} just when all compiles fine you 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, dully add your class to the list and be - happy. - - \item[Line \ref{progress_bar.cpp:get_control_type}] - 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 that most 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 which 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. The reason is that -before automatically registering widgets this file needed more modification so -it was done in one fell swoop. - -\end{description} - -This completes 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 example here since it's not too large. - -Now we start to 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] Listing \ref{unit_attack.hpp} contains the sample code. - \begin{description} - \item[Line \ref{unit_attack.hpp:class}] - Defines the class itself, which normally inherits from tdialog. - Sometimes a class inherits from another class, but that class then -derives from tdialog, for example the wml\_dialogs have a common base and -separate classes for left and right. - - \item[Line \ref{unit_attack.hpp:constructor}] - Dialogues are often created and then shown once before being destroyed, -therefore the constructor often takes all parameters needed. Since the show -function shouldn't be overloaded the only other alternative would be member -functions to set the members. Note when keeping `references' to widgets these -member must be pointers and set to NULL in the constructor, this due to the -simple fact that the widgets aren't created at this point. Also keep in mind -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[Line \ref{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 choice the user made. - - \item[Line \ref{unit_attack.hpp:window_id}] - This function is part of the window registration and only needs to be -declared in the header, the definition will be provided by a macro. - - \item[Line \ref{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, so -setting the pointers can be unconditional. This is also the place to fill the -widgets with the proper content, if needed. Eg filling the languages in the -language selection dialogue. - - \item[Line \ref{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[Line \ref{unit_attack.hpp:member}] - At this point the list of private members start. - - \end{description} - -\item[cpp] Listing \ref{unit_attack.cpp} contains the sample code. Note some -parts are already described more verbose in the header and thus not mentioned -here. - \begin{description} - \item[Line \ref{unit_attack.cpp:textdomain}] - Like written for the widget, every file is inside the `wesnoth-lib' text -domain. - - \item[Line \ref{unit_attack.cpp:wiki}] - Directly after the includes (inside the gui2 namespace) the wiki -documentation starts. - - - \item[Line \ref{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[Line \ref{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 \ref{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[Line \ref{unit_attack.cfg:textdomain}] - Every file in the library is inside the ``wesnoth-lib'' text domain. - - \item[Line \ref{unit_attack.cfg:defines}] - With larger dialogs I often 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 not that all local macros are prefixed with \_GUI, this 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[Line \ref{unit_attack.cfg:window}] - Not much to tell about this part, since it's all documented in the wiki. -But do note that due to the defines above the grid in the window itself is -rather simple. - - \item[Line \ref{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} +\include{gui2/abstract} +\include{gui2/introduction} +\include{gui2/overall_design} +\include{gui2/design_details} +\include{gui2/creating_widgets_and_dialogs} \appendix - -\chapter{Files for creating the widget} - -This chapter contains the files created in \S~\ref{sec:creating_the_widget}, these -files aren't the real files added, but a slightly modified version; The -copyright headers are stripped to avoid taking up useless space. Some extra -comments are added to make referencing possible. This also means the files here -will get out of date with the real files when fixes are committed, that's also -fine since it doesn't change how the files are structured. The label still -mentions the original filename, but might over time differ from the listings -below. - -\lstinputlisting[style=C++ - , caption={src/gui/auxiliary/widget\_definition/progress\_bar.hpp} - , label=widget_definition.hpp] - {gui2/widget_definition.hpp} - -\pagebreak -\lstinputlisting[style=C++ - , caption={src/gui/auxiliary/widget\_definition/progress\_bar.cpp} - , label=widget_definition.cpp] - {gui2/widget_definition.cpp} - -\pagebreak -\lstinputlisting[style=WML - , caption={data/gui/default/widget/progress\_bar\_default.cfg} - , label=progress_bar.cfg] - {gui2/progress_bar.cfg} - -\pagebreak -\lstinputlisting[style=C++ - , caption={src/gui/auxiliary/window\_builder/progress\_bar.hpp} - , label=window_builder.hpp] - {gui2/window_builder.hpp} - -\lstinputlisting[style=C++ - , caption={src/gui/auxiliary/window\_builder/progress\_bar.cpp} - , label=window_builder.cpp] - {gui2/window_builder.cpp} - -\lstinputlisting[style=C++ - , caption={src/gui/widgets/progress\_bar.hpp} - , label=progress_bar.hpp] - {gui2/progress_bar.hpp} - -\pagebreak -\lstinputlisting[style=C++ - , caption={src/gui/widgets/progress\_bar.cpp} - , label=progress_bar.cpp] - {gui2/progress_bar.cpp} - - -\chapter{Files for creating the window} - -This chapter like the previous one contains listings of files, this time for -\S~\ref{sec:creating_the_window}. About the same is true for these files, except -we know the originals will change in the future. - -\lstinputlisting[style=C++ - , caption={src/gui/dialogs/unit\_attack.hpp} - , label=unit_attack.hpp] - {gui2/unit_attack.hpp} - -\lstinputlisting[style=C++ - , caption={src/gui/dialogs/unit\_attack.cpp} - , label=unit_attack.cpp] - {gui2/unit_attack.cpp} - -\lstinputlisting[style=WML - , caption={src/gui/dialogs/unit\_attack.cfg} - , label=unit_attack.cfg] - {gui2/unit_attack.cfg} - +\include{gui2/files_for_the_widget} +\include{gui2/files_for_the_window} \end{document} diff --git a/doc/design/gui2/abstract.tex b/doc/design/gui2/abstract.tex new file mode 100644 index 00000000000..8d67247eaca --- /dev/null +++ b/doc/design/gui2/abstract.tex @@ -0,0 +1,21 @@ +\begin{abstract} + +Late 2007 I started to rewrite the gui engine of Wesnoth, this project is called +the gui2 project. A lot of code and documentation has been written since. The +documentation is available at: +\begin{itemize} +\item \url{http://wiki.wesnoth.org/GUIToolkit} The general information + regarding the project and documentation regarding the WML used. +\item \url{http://devdocs.wesnoth.org} The general doxygen information. +\item \url{http://devdocs.wesnoth.org/pages.html} Contains some links to more + gui2 specific information. +\end{itemize} + +This documentation describes a lot of the details and the wiki describes some of +the design from the WML side. Doxygen contains some information regarding the +design of the C++ side but it misses the overall design. This paper tries to +fill that gap, trying to explain more of the overall design and some of the +design choices. + +\end{abstract} + diff --git a/doc/design/gui2/creating_widgets_and_dialogs.tex b/doc/design/gui2/creating_widgets_and_dialogs.tex new file mode 100644 index 00000000000..33c79a3be87 --- /dev/null +++ b/doc/design/gui2/creating_widgets_and_dialogs.tex @@ -0,0 +1,388 @@ +\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 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, this +happens often when you need to add a new widget that 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 a general overview of +the files after which I dive more into the implementation of the 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] Listing \ref{widget_definition.hpp} contains the sample code. + \begin{description} + \item[Line \ref{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[Line \ref{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] Listing \ref{widget_definition.cpp} contains the sample code. + \begin{description} + \item[Line \ref{widget_definition.cpp:textdomain}] Every file in the library + is inside the ``wesnoth-lib'' text domain. + \item[Line \ref{widget_definition.cpp:constructor}] The constructor used is + pretty typical for all widgets. + \item[Line \ref{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[Line \ref{progress_bar.cfg:textdomain}] Every file in the library + is inside the ``wesnoth-lib'' text domain. + + \item[Line \ref{progress_bar.cfg:class}] + Beginning of the progress bar, this part is much better documented in + the wiki %TODO ref + 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. This file contains 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] Listing \ref{window_builder.hpp} contains the sample code. + \begin{description} + \item[Line \ref{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] Listing \ref{window_builder.cpp} contains the sample code. + \begin{description} + \item[Line \ref{window_builder.cpp:textdomain}] Every file in the library + is inside the ``wesnoth-lib'' text domain. + \item[Line \ref{window_builder.cpp:constructor}] The constructor used is + pretty typical for all widgets. + + If the constructor initialize custom members it may add some validation. + This is also true when the widget has a grid, like the listbox or + multi\_page. + \item[Line \ref{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[Line \ref{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, here the value of the + percentage use in the drawing routines is set\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] Listing \ref{progress_bar.hpp} contains the sample code. + \begin{description} + \item[Line \ref{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[Line \ref{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[Line \ref{progress_bar.hpp:inherited}] + This section implements or overrides member functions of the base class. + Some functions are pure virtual and need to be overridden others to + change behaviour.\footnote{Of course a list of which functions are + common the add here would be nice, however the library is still too + volatile to do so, no need to create a soon out of date list.} + + \item[Line \ref{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. + + Furthermore this version often has no normal getter but may have a + setter. + \end{description} + + \item[Line \ref{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] Listing \ref{progress_bar.cpp} contains the sample code. + \begin{description} + \item[Line \ref{progress_bar.cpp:textdomain}] Every file in the library + is inside the ``wesnoth-lib'' text domain. + + \item[Line \ref{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[Line \ref{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 and + look through the other widgets to see how to fix it. + + \textbf{Caveat emptor} just when all compiles fine you 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, dully add your class to the list and be + happy. + + \item[Line \ref{progress_bar.cpp:get_control_type}] + 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 that most 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 which 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. The reason is that +before automatically registering widgets this file needed more modification so +it was done in one fell swoop. + +\end{description} + +This completes 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 example here since it's not too large. + +Now we start to 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] Listing \ref{unit_attack.hpp} contains the sample code. + \begin{description} + \item[Line \ref{unit_attack.hpp:class}] + Defines the class itself, which normally inherits from tdialog. + Sometimes a class inherits from another class, but that class then +derives from tdialog, for example the wml\_dialogs have a common base and +separate classes for left and right. + + \item[Line \ref{unit_attack.hpp:constructor}] + Dialogues are often created and then shown once before being destroyed, +therefore the constructor often takes all parameters needed. Since the show +function shouldn't be overloaded the only other alternative would be member +functions to set the members. Note when keeping `references' to widgets these +member must be pointers and set to NULL in the constructor, this due to the +simple fact that the widgets aren't created at this point. Also keep in mind +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[Line \ref{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 choice the user made. + + \item[Line \ref{unit_attack.hpp:window_id}] + This function is part of the window registration and only needs to be +declared in the header, the definition will be provided by a macro. + + \item[Line \ref{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, so +setting the pointers can be unconditional. This is also the place to fill the +widgets with the proper content, if needed. Eg filling the languages in the +language selection dialogue. + + \item[Line \ref{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[Line \ref{unit_attack.hpp:member}] + At this point the list of private members start. + + \end{description} + +\item[cpp] Listing \ref{unit_attack.cpp} contains the sample code. Note some +parts are already described more verbose in the header and thus not mentioned +here. + \begin{description} + \item[Line \ref{unit_attack.cpp:textdomain}] + Like written for the widget, every file is inside the `wesnoth-lib' text +domain. + + \item[Line \ref{unit_attack.cpp:wiki}] + Directly after the includes (inside the gui2 namespace) the wiki +documentation starts. + + + \item[Line \ref{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[Line \ref{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 \ref{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[Line \ref{unit_attack.cfg:textdomain}] + Every file in the library is inside the ``wesnoth-lib'' text domain. + + \item[Line \ref{unit_attack.cfg:defines}] + With larger dialogs I often 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 not that all local macros are prefixed with \_GUI, this 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[Line \ref{unit_attack.cfg:window}] + Not much to tell about this part, since it's all documented in the wiki. +But do note that due to the defines above the grid in the window itself is +rather simple. + + \item[Line \ref{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} + diff --git a/doc/design/gui2/design_details.tex b/doc/design/gui2/design_details.tex new file mode 100644 index 00000000000..eede7261fd1 --- /dev/null +++ b/doc/design/gui2/design_details.tex @@ -0,0 +1,182 @@ +\chapter{Design details} + +Now that the big picture regarding the library is known, I dive into parts of +the code that can use more explanation. A part not explained here, doesn't mean +the code is obvious or simple, lack of time to document it properly is more +likely the excuse. + +\section{Boot strapping the library} + +Before the library can be started the available widgets and windows need to +be registered. This registering is done before \textsc{main()} is started. +The registering is done by some small static classes that do the registering +of the item\footnote{Widget or Window.} in its constructor. Since this +involves some redundant typing there are REGISTER\_XXX macros written. + +After all items are register the library can be started, which is simply +done by \textsc{gui2::init()}. This function does all required steps to get +the library up and running. + +\section{Layout algorithm} + +An important part of the gui engine is to properly layout the widgets in the +available space. The documentation of that algorithm is written in +doxygen\footnote{\url{http://devdocs.wesnoth.org/layout\_algorihm.html}}. + +\section{Event handling and dispatching} +\label{event_handling} + +The event handling translates the ``raw'' SDL events to an event structure +specific to gui2, effectively decoupling the interface. This also allows adding +frameworks to fake events. The documentation of that code is written in doxygen +doxygen\footnote{\url{http://devdocs.wesnoth.org/event_dispatching.html}} + +\section{Iterator} + +The iterator class is written\footnote{The code hasn't been written yet only +designed how it should look. Still I feel the design is rather finished and I +can update this paper if details change too much.} to alleviate certain +problems. The scrollbar containers have their own grid and a grid for it's +content. The implantation makes the looping over all children tricky. This has +been solved, but the design of the solution is rather awkward. Obviously fixing +the design is the right thing to do, but that breaks the iteration. + +By first writing an iteration class the interface for iteration can be kept +cleaner and the classes can easily be refactored. + +\subsection{Design} + +There are two basic kind of iterators in the design, the simple ones that can +only travel themselves and their direct children. This type will be referred to +as basic iterator hereafter. + +This basic iterator is a superclass for several specific subclasses. The +superclass is a concrete class, which can be instantiated. This class acts as a +sentinel iterator, signalling the end of a list. + +Every widget has it's own creation function returning a pointer to a subclass +object, allowing the main iterator to keep pointers to basic iterators, which it +uses for travelling. + +\paragraph{} + +The other kind is called the main iterator. This iterator is the type the user +normally creates and uses. The class is a template class, where a policy designs +how the travelling should go\footnote{For now only one policy is planned, but I +can think of more kinds}. + +When the main iterator is created it's possible to add a predicate to the +constructor. The predicate determines what the travelling routine does with a +candidate widget. + +Now that we know the players in the game look further about the implementation +details and the decisions made. + +\subsubsection{Travelling} + +A widget can have several ``layers'' namely: + +\begin{description} +\item[self] The widget itself. +\item[grid] Container widget have a grid which is another layer, note that for a + grid widget, its grid and self layer are the same. +\item[content] Scrollbar containers have a grid, containing their scrollbars and + a dummy content spacer. Their real content is stored in a separate internal + node, which is used as content layer. +\end{description} + +The travel policy decides in which order these layers are visited, and when a +node from a ``grid'' or ``content'' is returned, which direction to travel? +Travel over them first and then into their children or children first? These +decisions are coded in the travelling policy. + +While travelling, the policy finds a candidate widget to travel to. This widget is +offered for evaluation to the predicate, which returns one of the following +values: + +\begin{description} +\item[return] The widget referred by the iterator is accepted and the algorithm + found its target. +\item[continue] The widget is skipped and the next candidate is sought. +\item[break] The widget is not allowed and the travelling at this layer stops. + This doesn't mean the algorithm gives up. This layer is cancelled but the + travelling path might have more options, which are used. At the moment there's + no way to tell that the candidate has failed and that the searching should stop + altogether, a ``exit'' result might be added for that case. +\end{description} + +Obviously these names are inspired by the C++ keywords. + +\subsubsection{Copying} + +The basic iterators are copyable since their state can easily be copied. + +\paragraph{} + +The main iterator can't be copied, it would involve copying the state +and copying the iterator is deemed not to be needed. + +\subsubsection{Operator++(int) (postfix increment)} + +The postfix increment operator hasn't been added to either widget type. For the +basic iterators, there's the problem that the type iterator returned after +iteration might not be the original type. This works properly on the prefix +increment operator since it's a virtual function, using the covariant return +type. + +The postfix version needs to return an object and that would involve slicing the +returned object instead of binding it to a reference. + +\paragraph{} + +The main iterator has no postfix increment operator since it's not copyable. +This of course is a bit the chicken and the egg problem, since I wanted to +prevent the postfix increment operator I made the class not copyable. + +For most (standard) iterator classes the overhead of copying isn't too high +since those iterators carry little state. This iterator carries a lot of state, +so you don't want to copy it. The cost of copying is $O(n)$ where $n$ is the +depth in the widget tree the iterator is\footnote{This might depend on the +travelling policy, but it won't get cheap}. So in the same spirit that the +standard library doesn't add operator[] for std::list I omitted the postfix +increment operator. + + +\section{Callbacks} + +\S~\ref{event_handling} describes the generic event handling for the widgets but +in some cases a widget wants to notify other widgets of a state change. Parts of +gui2 use simple C-style callbacks for that purpose, but using boost::function +makes better replacement. Therefore the code was analysed closer and another +problem should be rectified; The callback causes a binding between two objects, +but they are not notified of the deletion of the object leaving a hole for +calling a destroyed object. + +In order to fix the problem two classes are defined: + +\begin{description} +\item[tnotifier] The class sending the wanted notification. +\item[tnotifiee] The class to manage the lifetime of the connection. +\end{description} + +The tnotifiee is a small class that holds a pointer to the receiver its +connected to, upon destruction it uses this pointer to deregister itself by the +receiver. There after the callback function will no longer be called. + +The class should be used as member of a class so it can manage the lifetime of +the connection with the tnotifier. + +\paragraph{} + +The tnotifier is the main class, when a callback is registered it stores the +callbacks in an internal list and updates the pointer in the tnotifiee to +itself. + +Upon destruction it clears the pointer in all tnotifiees that point to use, that +way upon destruction of the tnotifiee it won't try to deregister itself with +this destroyed object. + +Subclasses of the tnotifier should add an notification function so the notifier +can call all callbacks in the list. The notifier should take care of this +calling. + diff --git a/doc/design/gui2/files_for_the_widget.tex b/doc/design/gui2/files_for_the_widget.tex new file mode 100644 index 00000000000..2735dc2d07b --- /dev/null +++ b/doc/design/gui2/files_for_the_widget.tex @@ -0,0 +1,51 @@ +\chapter{Files for creating the widget} + +This chapter contains the files created in \S~\ref{sec:creating_the_widget}, these +files aren't the real files added, but a slightly modified version; The +copyright headers are stripped to avoid taking up useless space. Some extra +comments are added to make referencing possible. This also means the files here +will get out of date with the real files when fixes are committed, that's also +fine since it doesn't change how the files are structured. The label still +mentions the original filename, but might over time differ from the listings +below. + +\lstinputlisting[style=C++ + , caption={src/gui/auxiliary/widget\_definition/progress\_bar.hpp} + , label=widget_definition.hpp] + {gui2/widget_definition.hpp} + +\pagebreak +\lstinputlisting[style=C++ + , caption={src/gui/auxiliary/widget\_definition/progress\_bar.cpp} + , label=widget_definition.cpp] + {gui2/widget_definition.cpp} + +\pagebreak +\lstinputlisting[style=WML + , caption={data/gui/default/widget/progress\_bar\_default.cfg} + , label=progress_bar.cfg] + {gui2/progress_bar.cfg} + +\pagebreak +\lstinputlisting[style=C++ + , caption={src/gui/auxiliary/window\_builder/progress\_bar.hpp} + , label=window_builder.hpp] + {gui2/window_builder.hpp} + +\lstinputlisting[style=C++ + , caption={src/gui/auxiliary/window\_builder/progress\_bar.cpp} + , label=window_builder.cpp] + {gui2/window_builder.cpp} + +\lstinputlisting[style=C++ + , caption={src/gui/widgets/progress\_bar.hpp} + , label=progress_bar.hpp] + {gui2/progress_bar.hpp} + +\pagebreak +\lstinputlisting[style=C++ + , caption={src/gui/widgets/progress\_bar.cpp} + , label=progress_bar.cpp] + {gui2/progress_bar.cpp} + + diff --git a/doc/design/gui2/files_for_the_window.tex b/doc/design/gui2/files_for_the_window.tex new file mode 100644 index 00000000000..a4893d74cc8 --- /dev/null +++ b/doc/design/gui2/files_for_the_window.tex @@ -0,0 +1,21 @@ +\chapter{Files for creating the window} + +This chapter like the previous one contains listings of files, this time for +\S~\ref{sec:creating_the_window}. About the same is true for these files, except +we know the originals will change in the future. + +\lstinputlisting[style=C++ + , caption={src/gui/dialogs/unit\_attack.hpp} + , label=unit_attack.hpp] + {gui2/unit_attack.hpp} + +\lstinputlisting[style=C++ + , caption={src/gui/dialogs/unit\_attack.cpp} + , label=unit_attack.cpp] + {gui2/unit_attack.cpp} + +\lstinputlisting[style=WML + , caption={src/gui/dialogs/unit\_attack.cfg} + , label=unit_attack.cfg] + {gui2/unit_attack.cfg} + diff --git a/doc/design/gui2/introduction.tex b/doc/design/gui2/introduction.tex new file mode 100644 index 00000000000..6ba6f4832dd --- /dev/null +++ b/doc/design/gui2/introduction.tex @@ -0,0 +1,105 @@ +\chapter{Introduction} + +This paper describes the general design of the gui2 project. The paper is +divided in several chapters: +\begin{description} +\item[Chapter 1] Explains why yet another document is added instead of using the + doxygen and a short history of the gui2 project. +\item[Chapter 2] Goes into the general design and structure of the gui2 project. +\item[Chapter 3] Dives deeper into certain parts of the design of certain + classes and algorithms. +\end{description} + +A omission in this paper is the simple story of how to add your own widgets in +the C++ code\footnote{The WML part is described in the wiki.}. I have a slightly +outdated paper on the subject, but decided not to add it; the paper needs +polishing and updates, but I've some design changes planned for the 1.9 +development series. These changes will also change the way of adding new +widgets, so that paper needs to be rewritten and added after the rewrite is +complete. + +\section{Why why why?} + +Why is this document written in \LaTeX{} instead of doxygen? The reason is +simple; during the development of the iterator class I felt I had to write a +lot. Writing much documentation in doxygen feels awkward. A lot of time is spend +on formatting, the number of subsections is limited (too low in my opinion). +Also it's not possible to document why certain functions aren't implemented, a +solution would be to make the function private and declared only, but that feels +like an ugly hack. + +Why is the document needed? In my opinion most manuals written in doxygen are +great as reference manuals but fail to explain how to do certain things with the +library and fail to explain why certain things are implemented in the way it is. +Writing a separate document separated from the code has the disadvantage of +getting earlier out of sync when an implementation details differs, but this can +be used as an advantage as well. Since it's hard to keep the details in sync, +it's a good reason not to dive into these details. This makes a natural +separation between which part should be in doxygen and which part in this +manual. + +Why after the above, are some parts of gui2 documented in separate pages in +doxygen? This indeed seems a contradiction, but it's not. Remember the first +paragraph stating it's annoying to write this kind of documentation in doxygen? +These parts are where I realized it's annoying to do it in doxygen and haven't +been incorporated in this document\footnote{These parts are still mentioned in +this paper, but they refer to the doxygen documentation.}. + +\section{History} + +The gui2 project was started late in 2007 to fix several problems I had with the +current gui at that time. The problems I had were: +\begin{enumerate} +\item When using small resolutions the gui started to look bad, since widgets + simply left their container and were drawn outside it. +\item Most of the gui was hard-coded in the C++ code and thus not configurable + for normal users. +\item ThemeWML, the part that allows the user to configure the layout, is not + well understood by the current developers. +\end{enumerate} + +This let to the following design goals: + +\begin{enumerate} +\item The gui should look well at every possible resolution and automatically + fit well. +\item Everything, or at least as much as possible should be configurable by WML. +\item The project needed more documentation as the current ThemeWML, and explain + how to create your own guis. +\end{enumerate} + +At the time of this writing the project is still work in progress\footnote{It +was never expected to be a short during project.} and will still take while to +finish. This initial goals were pretty clear, and still are. On the other hand +how to implement certain parts provided to be less clear. + +The library is the first time I designed a gui toolkit and like with all larger +projects, you need to learn from mistakes; preferably of others, but your doomed +to make your own as well. The design process is an iterative one, causing some +parts of the design to be changed several times. At the time of +writing\footnote{Shortly before the 1.8 release.} a lot of areas feel stable, +but others are still planned to be rewritten. Mainly the handling of scrollbar +widgets feels awkward and hacky and are slated for a redesign. + +Other parts of the gui are still in the planning stage and not implemented yet, +but the project moves along at a steady pace and more features will be added in +the future. + +\paragraph{} + +The history of this document also goes back a long time, it's mostly build from +various scraps of notes I have on my system. The plan was to change these notes +to doxygen format some day put it in the source. The problem was to find a nice +place in the source to do so. + +This lead to the fact the notes just stayed on my system and the number of +notes accumulated. During travelling to work I started to design some things for +the 1.9 development series and for the iterator class I needed a new kind of +document. I decided that was the final straw and started to work on writing this +document while travelling. + +Since you read this document it's uploaded in the Wesnoth source tree, this +doesn't mean the document is complete. In fact it more means the opposite, the +draft is uploaded and I can start to work on finishing the document by adding +the missing information. + diff --git a/doc/design/gui2/overall_design.tex b/doc/design/gui2/overall_design.tex new file mode 100644 index 00000000000..1c95431a929 --- /dev/null +++ b/doc/design/gui2/overall_design.tex @@ -0,0 +1,228 @@ +\chapter{Overall design} + +This chapter takes a deeper look into the overall design of the library. Before +we can explain how things work, we'll have a look at the features; both +implemented and planned for the future. Once we know what the gui should be able +to do I'll explain how these goals are achieved. The chapter ends with a short +explanation of the directory structure so you'll be able to find the parts of +the library. + +\section{Features} + +Wesnoth runs on a large amount of devices, with an even larger amount of display +resolutions, from $320\times 240$ on hand-held devices to $2560\times 1600$ on +large 30" screens. The gui should look appealing on all these devices. Therefore +there are three resolution groups: +\begin{description} +\item[hand-held devices] For these devices the code needs to be compiled with +\textbf{TINY\_GUI}. This forces all images to be scaled down by a factor two. + The typical resolutions on these devices are $320\times 240$ -- $640\times + 480$. +\item[PC] For the usage on PC's Wesnoth offers the resolutions $800\times 600$ + -- $2560\times 1600$\footnote{And larger once screens that size become + available.}. +\item[Netbooks] When the first netbooks were introduced the normal resolution + was $800\times 480$, which is slightly smaller as the minimum PC resolution. + Therefore a start option \textsc{--smallgui} was added making minimal + modifications to the layout\footnote{Actually this is gui1 only.}. +\end{description} + +In order to facilitate this range of resolutions the gui2 code allows several +definitions of a window, tuned for a specific resolution. The reason is twofold; +first to make a difference between the hand-held devices and PCs, second allow +different views for different resolutions. + +The main example of this feature\footnote{Not yet implemented, but one of the +main reasons to add this feature.} is the attack dialogue. The dialogue has a +button to show the damage calculation, which shows a new dialogue with the +calculation overview. From an UI point of view I consider that rather ugly and +rather have tabs to switch between the view. But when I have a larger screen the +dialogue only fills a small part and I need to switch between tabs to see the +info, in that case I rather have one dialogue without tabs, which directly shows +all information. When the user changes the resolution the dialogue should switch +between these two views, depending on the current resolution. + +\paragraph{} + +The gui should be able to adapt to the size actually needed, the current gui +uses fixed sizes at some places. This leads to problems that when the screen +resolution is reduced widgets end up outside the dialogue or get truncated. The +same for some translated texts, where the translation is much longer as the +English original. Gui2 solves this problem by dynamically determining the size +of a widget and adjust the layout until it fits. This has the disadvantage that +dialogues with a lot of dynamic content, resize at random times and changing the +layout of the dialogue slightly. Another disadvantage is that when a dialogue +doesn't fit Wesnoth terminates. This problem can be fixed by adding scrollbars +to every window. When the dialogue doesn't fit the scrollbars are used and the +dialogue fits again, might be a bit ugly but at least everything fits again. + +\paragraph{} + +It must be possible for WML designers to change the entire gui of Wesnoth with +their own version. For example Spacenoth\footnote{That project is dead, but +that doesn't matter for this example.} is Wesnoth is a space setting, so the +project might want to use a more fitting user interface. + +Adding a new gui is a lot of work and can't be done in one fell swoop, so the +code needs to support a gradual conversion. Therefore when you select your own +theme\footnote{Support for this selection and the entire fall-back haven't been +added yet. Obviously I want to add support, but it remains low priority until +somebody really wants to add their own gui.} the engine first searches in the +new theme for items\footnote{A widget or window.}. When an item is not found it +uses that item from the default theme. Therefore it's mandatory that every item +is defined for the default gui, which the engine validates at +startup\footnote{That causes the problem that Wesnoth sometimes refused to start +when the source and data are out-of-sync.}. + +\section{The big picture} + +First we dive into the components that define the gui. + +\subsection{Widget} + +A widget is the basic user interface element, like a label, a button or a text +entry. Every widget has its own behaviour, which sometimes can be influenced by +certain settings, but the main behaviour is fixed per widget. Next to behaviour +a widget also has a visual representation so the user can see and interact with +the widget. + +Before the widget is shown to the user it needs to be created first, the +creation happens in the window builder class. This class reads the definition of +a widget and fills in the blanks et voil\`a the widget is there. Let's go over +this part in more slow-motion. + +\paragraph{The definition} +The definition determines how a widget looks and some basic properties, these +properties are the same for all instances of that widget. For example a button +has a minimum size so the decoration can be drawn. It's possible to make +multiple definitions of a button. These different definitions, can look +different have different minimum sizes and other properties. + +These definitions are written in WML and a small loader class loads and +validates the definition. The definition is then added to the list of known +widgets of this type. + +The definition of the widget depends on the resolution, this is for example used +in the button. It has a minimum size depending on the decoration used, in +\textbf{TINY\_GUI} mode the decoration is scaled down, so the minimum size can +also be reduced. + +\paragraph{The builder} +The builder is started from the C++ code, started while building a window. This +window definition contains a list of widget to build with more instance specific +values. For example a label builder has the text to show to the user as +parameter. + +These builder ``scripts'' are also written in WML and loaded by as small loader +class that does the validation and build the needed widget. + +\paragraph{Widget} +The widget itself is written in a larger C++ class and it defines the behaviour +and provide various hooks to modify the properties of that widget. These hooks +are used by the builder, but can also be modified later by the engine. + +Other hooks provide bindings to react to events. The bindings are now rather +static, but with the new event handling added late in the 1.8 release series +more things are possible. The plan is to enhance this part during the 1.9 +release series and deprecate and remove the current interface. + +Of course the question ``why wait until 1.9'' raises. The reason is simple it +was added late in the 1.8 cycle to fix certain issues with the MP lobby at that +time I had no time to convert the rest of the code, since I was working on the +MP lobby instead. + +\subsection{Window} + +A window can mean two things, the window widget and the window definition. In +this section the window definition is meant. Already discussed before, but a bit +more verbose this time. + +The window definition defines a window and which widgets are placed in the +window. This window definition also depends on the resolution. This allows the +window to look different depending on the resolution. The changes can be small +or the window can look completely different. + +\subsection{Dialogue} + +A dialogue is a pure C++ thing. A dialogue shows a window, but is not a window. +So what's the difference\footnote{These are the definitions used in the gui2 +code and not the definition of other window toolkits.}? A window is a dumb +combination of widgets created depending on the definitions in a WML file. After +the window is created it often needs extra content and react to certain events. +For example the language dialogue after building has an empty list of languages. +This is where the dialogue comes into play. The user asks for the language +selection dialogue. The code creates and shows a dialogue. The dialogue code +builds a window, then fills the language list with the available languages and +selects the current language and then shows it to the user. + +In other dialogues the code also needs to wire in event handlers or build other +structures. It searches the wanted widget by id, in some cases it doesn't even +care what kind of widget is used. In other cases it needs to be of a certain +class or ``concept''. This allows a flexible design and let the user select the +kind of widget used in some cases. + +So the dialogue is the sugar between the WML window and an interactive dialogue +shown in the game. + +\section{Directory structure} + +This section describes the directories available, instead of listing them in +alphabetic order I list them in a order that makes explaining them more natural. + +\begin{description} +\item[src/gui] The general source code directory with all parts used for the gui. + +\begin{description} +\item[dialogs] This directory contains all dialogues used in Wesnoth, in + general every file contains one dialogue, the name of the file being the + logical name of what the dialogue does. Some dialogues have a helper + dialogue, which is sometimes embedded in the same file. +\item[widgets] This directory contains all widgets used in the library. Every + file contains one widget. Also base classes or concepts of widgets are + stored in this directory. During the development it also accumulated some + helper files, which don't fit in the aforementioned descriptions, this lead + to the creation of the auxiliary directory. Some files haven't been moved to + this new directory yet. +\item[auxiliary] This directory contains items auxiliary classes. Some helper + parts are so large that they got their own subdirectory. + +\begin{description} +\item[event] Contains all event handling code, the translation from SDL events + to the internal events and their dispatching. +\item[widget\_definition] Contains the code to serialize the WML to an internal + data structure, needed to define that kind of widget. The names of the files + match the widget names. (Most files are rather small, but I prefer small + single tasked files over huge files controlling a lot of code\footnote{Some + might remember I started with a single file, which did exactly that, but the + file got too large to maintain efficiently.}. +\item[window\_builder] Contains the code to create a widget object, from the + widget definition and the data supplied in the window definition. Again the + name of the file matches the name of widget they build. (These files are + also mostly small.) +\end{description} + +\end{description} + +\item[data/gui] The general data directory with all parts used for the gui. All + guis shipped with Wesnoth should be in a sub-directory of this one, with a + config file with the name of the directory as main entry point and include + the sub-directory. At the time of writing only one gui is shipped, the + default one. + +\begin{description} +\item[default] This directory is the bases for the default gui. + +\begin{description} +\item[macro] This directory contains some helper macros, for default font sizes. +\item[widget] This directory contains the definitions of widgets. Since there + can be multiple definitions of a widget their name is the name of the widget + with a suffix. The suffix for the default widgets is, \textsc{default} for + the others an appropriate name is picked. +\item[window] Contains the definitions of windows, the name of the files is the + name of the dialogue they represent. +\end{description} + +\end{description} + +\end{description} +