\documentclass[a4paper,11pt]{report} % Define the title \author{Graeme Geldenhuys} \title{fpGUI - A technical reference} \setlength{\parindent}{0pt} \setlength{\parskip}{1ex plus 0.5ex minus 0.2ex} \begin{document} % generates the title \maketitle \newpage % insert the table of contents \tableofcontents \newpage % ******************************************************************* \chapter{Introduction} After developing many cross platform applications with Kylix and Delphi I started getting very frustrated with the differences between the look and behaviour of the applications under Linux and Windows. The code was also riddled with IFDEF statements. Then I stumbled across the Free Pascal and Lazarus projects. I thought this is it, the answer to all my cross platform development problems. Unfortunately after working with Lazarus for a few months I started finding more and more issues with the widget sets, though the IDE was great. The Lazarus LCL is a wrapper for each platforms native widget set. This brought with it the same issues I experienced with Kylix and Delphi. This got me thinking about how I could resolve this issue. Then it hit me - implement the widget set myself using Free Pascal! Painting the widgets myself to get a consistent look and implementing a consistent behaviour. Instead of reinventing the wheel, I thought I would do some searching to see if there is another project I can contribute to or help by giving me a head start. The first version of my widget set was based around a heavily modified version of the Light Pascal Toolkit\footnote{http://sourceforge.net/projects/lptk}. I then discovered the discontinued fpGUI and fpGFX projects. I tried to contact the original author to no avail. The fpGUI code hasn't been touched in four years (since early 2002). After studying the code for a few weeks, I came to the conclusion that fpGUI is much closer to what I strived to accomplish with my modified LPTK. A lot was still missing from fpGUI though. After thinking long and hard, I decided to start my widget set again, but this time based on the work done in fpGUI and fpGFX. I also added to the mix some good ideas I saw in Qt 4.1. So far I have completed quite a few things missing in fpGUI, but I still need to do a lot to get to the point where I can test drive it in a commercial application. I set myself a list of things outstanding which should get it to a usable level. I also added a lot of documentation as I went as there was no documentation included with the original fpGUI and fpGFX projects. Documentation is important to attract other developers in using the widget set. % ******************************************************************* \chapter{GUI and Events} This chapter is currently a copy and paste of an email I wrote explaining how the events work. The difference between the GFX events and the GUI events. Soon I will rewrite this chapter and add a lot more detail. Here follows the email text for now. The GFX part gets events from the windowing system, be that X11 or GDI. That means that TFCustomWindow gets all the events from the windowing system. Now the GUI part. Every widget is \emph{not} a TFCustomWindow, so every widget doesn't have a Handle. The GUI is implemented with only one handle per Form (TFForm). All widgets are just painted onto the canvas of the TFForm. If you look at the TFCustomForm you will see it has a instance of TFCustomWindow stored in FWnd. That instance gets all the events from the windowing system. So to let the widgets also get events we have to implement our own event system. The TFCustomForm will then send those custom events (TEventObj descendants) by translating the windowing events into our custom GUI events. For example:\\ Lets say we have a Form with a Button on it. Now we want to handle a OnMouseMove event on the Button. The flow of events will go as follows: \begin{itemize} \item TFCustomForm.Wnd will receive the OnMouseMove from the windowing system and process it in the WndMouseMoved() method. \item WndMouseMoved() will translate that windowing system event into whatever GUI events are needed and start sending them. \item Any TWidget descendant handles events in the ProcessEvent() method. TWidget being the big one. \item Because TFCustomForm is a TFContainerWidget descendant, it means it can contain other widgets. So it starts distributing the GUI events to the children. Distribution is done by the DistributeEvent() method. \item If TFCustomButton needed to do any special processing with the GUI event, it would handle it in its ProcessEvent() method. TWidget.ProcessEvent normally does most of the generic work. \item As an example of a widget that does custom processing, have a look at the TFMenuItem.ProcessEvent(). In this case it handles the TMouseEnterEventObj and TMouseLeaveEventObj events so it can changes it's look when the mouse enters a menu item or leaves a menu item. \end{itemize} So as a summary:\\ TFCustomForm contains a instance of a GFX window. Translates all the GFX events (underlying windowing events) to GUI events (TEventObj descendants) and distributes them to the children of the Form. % ******************************************************************* \chapter{Layout Algorithm} \section{Initialisation of a window (form)} If a window presents itself for the first time, and no standard size was given, then it must compute these. This is a recursive process, with which the event TCalcSizesEventObj is set for all children of the window from top to bottom in the Widget tree (beginning with the window). TWidget reacts to the receipt of this event as follows (in TWidget.EvCalcSizes): \begin{itemize} \item The event is passed on with TWidget.DistributeEvent to all children. \item The virtual protected method TWidget.DoCalcSizes is called. Again derived Widgets overwrites this method, in order to compute its sizes of (minimum, maximum, optimum). \item The results of DoCalcSizes are if necessary corrected, e.g. the maximum size may not be smaller than the minimum size. \item If the code for the window finished the dispatch of this event, all Widgets in the window has valid statements of size. Now it can do its own, initials size sets (this is the before computed optimum size of the window). This is accomplished by TWidget.SetBounds. \end{itemize} ... to be continued ... % ******************************************************************* \chapter{Database Components} ... to be continued ... \end{document}