summaryrefslogtreecommitdiff
path: root/fluid/documentation/src/page_tutorial.dox
diff options
context:
space:
mode:
authorMatthias Melcher <github@matthiasm.com>2024-04-17 17:51:32 +0200
committerGitHub <noreply@github.com>2024-04-17 17:51:32 +0200
commitfd791a068e39e06785adc44693f4c533d3d6c903 (patch)
treeef7ff684b38f646165e80c142e454cd7ef077e2e /fluid/documentation/src/page_tutorial.dox
parentb4cf1a9824f2c4ba9596044962d3af36e3ca3d99 (diff)
Separate FLUID user documentation, screen shot automation (#936)
* CMake integration, no autotiools * alignment panel is now correctly renamed to setting panel * source view is now correctly renamed to code view * Merge FLTK FLUID docs into FLUID user manual. * Add two simple entry tutorials * Remove FLUID chapter form FLTK docs. * GitHub action to generate HTML and PDF docs and make the available as artefacts
Diffstat (limited to 'fluid/documentation/src/page_tutorial.dox')
-rw-r--r--fluid/documentation/src/page_tutorial.dox534
1 files changed, 534 insertions, 0 deletions
diff --git a/fluid/documentation/src/page_tutorial.dox b/fluid/documentation/src/page_tutorial.dox
new file mode 100644
index 000000000..3f0d48cae
--- /dev/null
+++ b/fluid/documentation/src/page_tutorial.dox
@@ -0,0 +1,534 @@
+/**
+
+ \page page_tutorial Tutorials
+
+ \tableofcontents
+
+<!-- ---------------------------------------------------------------------- -->
+
+ \section fluid_hello_world_tutorial Hello, World!
+
+ The first FLUID tutorial explains the FLUID basics. It creates a single
+ `main()` function that opens an application window with a static text box
+ inside.
+
+ After launching FLUID we want to make sure that two very useful tool windows
+ are open.
+ The "Widget Bin" gives quick access to all available widgets and functional
+ types. It can be opened via the main menu: __Edit > Show Widget Bin__, or
+ using the shortcut __Alt-B__.
+
+ The second very helpful tool box is the "Code View". The Code View gives
+ a preview of the code as it will be generated by FLUID. All changes in the
+ layout or in attributes are reflected immediately in the Code View.
+ Choose __Edit > Show Code View__ or press __Alt-C__ to get this
+ toolbox. Make sure that _Auto-Refresh_ and _Auto-Position_ are active in
+ the Code View.
+
+ Let's start Hello World from scratch. If there is already a previous project
+ loaded, select __File > New__ or __Ctrl-N__.
+
+ Before we can create a window, we need a "C" function that can be called
+ when we run the program. Select __New > Code > Function/Method...__ or click on
+ the
+ \image{inline} html flFunction.png "Function/Method"
+ \image{inline} latex flFunction.png
+ image in the widget bin.
+
+ A function is added as a first line to the widget tree in the main window,
+ and a "Function/Method Properties" dialog box will pop up. For our Hello World
+ program, delete all text in the top "Name(args)" text field. If this field
+ is left empty, FLUID will generate a `main(argc, argv)` function for us.
+
+ \image html fluid4.png "Function/Method Properties Dialog"
+ \image latex fluid4.png "Function/Method Properties Dialog" width=7cm
+
+ Click OK to apply the changes you made in the Function Properties dialog.
+ You can get this dialog back at any time by selecting the function in the
+ main window and pressing __F1__, or by double-clicking it.
+
+ Note that the function will not show up in the Code View yet. FLUID will
+ not generate code for functions that don't have any content, and only create
+ a forward declaration in the header file, assuming that the function will
+ be implemented inside another module.
+
+ Keep the `main` function selected and add an `Fl_Window` to the function by
+ selecting __New > Group > Window...__, by clicking the
+ \image{inline} html flWindow.png "Group/Window"
+ \image{inline} latex flWindow.png
+ image in the Widget Bin, or by dragging the Group/Window image from the
+ Widget Bin onto the desktop.
+
+ A new application window will open up on the desktop. The thin red outline
+ around the window indicates that it is selected. Dragging the red line will
+ resize the window. Take a look at the Code View: the main function
+ is now generated, including code to instantiate our `Fl_Window`.
+
+ To edit all the attributes of our window, make sure it is selected and press
+ __F1__, or double-click the entry in the main FLUID window, or double-click
+ the window itself. The "Widget Properties" dialog box will pop up. Enter
+ some text in the "Label:" text box and see how the label is updated immediately
+ in the window itself, in the widget list, and in the Code View.
+
+ Adding a static text to our window is just as easy. Put an `Fl_Box` into our
+ window by selecting __New > Other > Box__, or by clicking on the
+ \image{inline} html flBox.png "Other/Box"
+ \image{inline} latex flBox.png
+ image in the Widget Bin, or by dragging the Other/Box image from the
+ Widget Bin into our newly created window.
+
+ Most importantly, enter the text "Hello, World!" in the "Label:" field
+ of the Box Widget Properties panel to achieve the goal of this tutorial. Now
+ is also a great time to experiment with label styles, label fonts, sizes,
+ colors, etc. .
+
+ Finally, we should save our project as an `.fl` project file somewhere. Once
+ the project is saved, select __File > Write Code__ or press __Shift-Ctrl-C__
+ to write our source code and header file to the same directory.
+
+ Compile the program using a Makefile, CMake file, or fltk-config as described
+ in the FLTK manual and the `README.txt` files in the FLTK source tree.
+
+<!-- ---------------------------------------------------------------------- -->
+
+ \section fluid_1of7guis_tutorial 7GUIs, Task 1
+
+ In the first "Hello World" tutorial, we built an entire application in FLUID.
+ It's a boring application though that does nothing except quitting when the
+ close button in the window border is clicked.
+
+ \image html 1of7GUIs.png "Task 1 of 7GUIs"
+ \image latex 1of7GUIs.png "Task 1 of 7GUIs" width=5cm
+
+ The second tutorial will introduce callbacks by implementing task 1, "Counter",
+ of 7GUIs. 7GUIs has been created as a spin-off of my master’s thesis
+ Comparison of Object-Oriented and Functional Programming for GUI Development
+ at the Human-Computer Interaction group of the Leibniz Universität Hannover
+ in 2014. 7GUIs defines seven tasks that represent typical challenges in GUI
+ programming. https://eugenkiss.github.io/7guis/ .
+
+ Task 1 requires "Understanding the basic ideas of a language/toolkit. The
+ task is to build a frame containing a label or read-only textfield T and a
+ button B. Initially, the value in T is “0” and each click of B increases the
+ value in T by one."
+
+ Our knowledge from tutorial 1 is enough to generate the `main()` function, and
+ add an `Fl_Window`, an `Fl_Output`, and an `Fl_Button`. To make life easy,
+ FLUID comes with a built-in template for this tutorial. Just select
+ __File > New from Template...__ and double-click "1of7GUIs" in the Template
+ Panel.
+
+ We will need to reference the output widget in our callback, so let's assign a
+ pointer to the widget to a global variable and give that variable a name.
+ Open the Widget Properties dialog by double-clicking the output widget.
+ Change to the "C++" tab, and enter "`counter_widget`" in the "Name:" field.
+
+ The "Count" button is the active element in our application. To tell the
+ app what to do when the user clicks the button, we create a callback function
+ for that button. Open the widget properties dialog for the button.
+ In the "C++" tab, we find the input field "Callback:".
+
+ The callback is called exactly once every time the user clicks the button. Our
+ strategy here is to read the current value from the `counter_widget`,
+ increment it by 1, and write it back to `counter_widget`.
+ The FLTK documentation tells us that we can use `Fl_Output::ivalue()` to get
+ text in `Fl_Output` as an integer, and we can write it back by calling
+ `Fl_Output::value(int)`. When the value is changed, FLTK will automatically
+ redraw the output widget for us. So here is the callback code:
+
+ ```
+ int i = counter_widget->ivalue();
+ i++;
+ counter_widget->value(i);
+ ```
+
+ That's it. This is a complete interactive desktop application. Compile, link,
+ run, and test it to see how it works.
+
+<!-- ---------------------------------------------------------------------- -->
+
+\section fluid_cubeview_tutorial Cube View
+
+This tutorial will show you how to generate a complete user interface
+class with FLUID that is used for the CubeView program provided with FLTK.
+
+\image html cubeview.png "CubeView demo"
+\image latex cubeview.png "CubeView demo" width=7cm
+
+The window is of class CubeViewUI, and is completely generated by FLUID,
+including class member functions. The central display of the cube is a
+separate subclass of Fl_Gl_Window called CubeView. CubeViewUI manages
+CubeView using callbacks from the various sliders and rollers to
+manipulate the viewing angle and zoom of CubeView.
+
+At the completion of this tutorial you will (hopefully) understand how to:
+
+-# Use FLUID to create a complete user interface class, including
+ constructor and any member functions necessary.
+-# Use FLUID to set callback member functions of custom widget classes.
+-# Subclass an Fl_Gl_Window to suit your purposes.
+
+\subsection fluid_cubeview The CubeView Class
+
+The CubeView class is a subclass of Fl_Gl_Window. It has methods for
+setting the zoom, the \e x and \e y pan, and the rotation angle
+about the \e x and \e y axes.
+
+You can safely skip this section as long as you realize that CubeView
+is a sublass of Fl_Gl_Window and will respond to calls from
+CubeViewUI, generated by FLUID.
+
+\par The CubeView Class Definition
+
+Here is the CubeView class definition, as given by its header file
+"test/CubeView.h":
+<br>
+
+<!-- Code copied from test/CubeView.h -->
+\code
+#include <FL/Fl.H>
+#include <FL/Fl_Gl_Window.H>
+#include <FL/gl.h>
+
+class CubeView : public Fl_Gl_Window {
+
+public:
+ CubeView(int x, int y, int w, int h, const char *l = 0);
+
+ // This value determines the scaling factor used to draw the cube.
+ double size;
+
+ /* Set the rotation about the vertical (y) axis.
+ *
+ * This function is called by the horizontal roller in
+ * CubeViewUI and the initialize button in CubeViewUI.
+ */
+ void v_angle(double angle) { vAng = angle; }
+
+ // Return the rotation about the vertical (y) axis.
+ double v_angle() const { return vAng; }
+
+ /* Set the rotation about the horizontal (x) axis.
+ *
+ * This function is called by the vertical roller in
+ * CubeViewUI and the initialize button in CubeViewUI.
+ */
+
+ void h_angle(double angle) { hAng = angle; }
+
+ // The rotation about the horizontal (x) axis.
+ double h_angle() const { return hAng; }
+
+ /* Sets the x shift of the cube view camera.
+ *
+ * This function is called by the slider in CubeViewUI
+ * and the initialize button in CubeViewUI.
+ */
+ void panx(double x) { xshift = x; }
+
+ /* Sets the y shift of the cube view camera.
+ *
+ * This function is called by the slider in CubeViewUI
+ * and the initialize button in CubeViewUI.
+ */
+ void pany(double y) { yshift = y; }
+
+ /* The widget class draw() override.
+ *
+ * The draw() function initializes Gl for another round of
+ * drawing, then calls specialized functions for drawing each
+ * of the entities displayed in the cube view.
+ */
+ void draw();
+
+private:
+ /* Draw the cube boundaries.
+ *
+ * Draw the faces of the cube using the boxv[] vertices,
+ * using GL_LINE_LOOP for the faces.
+ */
+ void drawCube();
+
+ double vAng, hAng;
+ double xshift, yshift;
+
+ float boxv0[3]; float boxv1[3];
+ float boxv2[3]; float boxv3[3];
+ float boxv4[3]; float boxv5[3];
+ float boxv6[3]; float boxv7[3];
+};
+\endcode
+
+\par The CubeView Class Implementation
+
+Here is the CubeView implementation. It is very similar to the
+"CubeView" demo included with FLTK.
+<br>
+
+<!-- Code copied from test/CubeView.cxx -->
+\code
+#include "CubeView.h"
+#include <math.h>
+
+CubeView::CubeView(int x, int y, int w, int h, const char *l)
+ : Fl_Gl_Window(x, y, w, h, l)
+{
+ Fl::use_high_res_GL(1);
+ vAng = 0.0;
+ hAng = 0.0;
+ size = 10.0;
+ xshift = 0.0;
+ yshift = 0.0;
+
+ /* The cube definition. These are the vertices of a unit cube
+ * centered on the origin.*/
+
+ boxv0[0] = -0.5; boxv0[1] = -0.5; boxv0[2] = -0.5;
+ boxv1[0] = 0.5; boxv1[1] = -0.5; boxv1[2] = -0.5;
+ boxv2[0] = 0.5; boxv2[1] = 0.5; boxv2[2] = -0.5;
+ boxv3[0] = -0.5; boxv3[1] = 0.5; boxv3[2] = -0.5;
+ boxv4[0] = -0.5; boxv4[1] = -0.5; boxv4[2] = 0.5;
+ boxv5[0] = 0.5; boxv5[1] = -0.5; boxv5[2] = 0.5;
+ boxv6[0] = 0.5; boxv6[1] = 0.5; boxv6[2] = 0.5;
+ boxv7[0] = -0.5; boxv7[1] = 0.5; boxv7[2] = 0.5;
+}
+
+void CubeView::drawCube() {
+/* Draw a colored cube */
+#define ALPHA 0.5
+ glShadeModel(GL_FLAT);
+
+ glBegin(GL_QUADS);
+ glColor4f(0.0, 0.0, 1.0, ALPHA);
+ glVertex3fv(boxv0);
+ glVertex3fv(boxv1);
+ glVertex3fv(boxv2);
+ glVertex3fv(boxv3);
+
+ glColor4f(1.0, 1.0, 0.0, ALPHA);
+ glVertex3fv(boxv0);
+ glVertex3fv(boxv4);
+ glVertex3fv(boxv5);
+ glVertex3fv(boxv1);
+
+ glColor4f(0.0, 1.0, 1.0, ALPHA);
+ glVertex3fv(boxv2);
+ glVertex3fv(boxv6);
+ glVertex3fv(boxv7);
+ glVertex3fv(boxv3);
+
+ glColor4f(1.0, 0.0, 0.0, ALPHA);
+ glVertex3fv(boxv4);
+ glVertex3fv(boxv5);
+ glVertex3fv(boxv6);
+ glVertex3fv(boxv7);
+
+ glColor4f(1.0, 0.0, 1.0, ALPHA);
+ glVertex3fv(boxv0);
+ glVertex3fv(boxv3);
+ glVertex3fv(boxv7);
+ glVertex3fv(boxv4);
+
+ glColor4f(0.0, 1.0, 0.0, ALPHA);
+ glVertex3fv(boxv1);
+ glVertex3fv(boxv5);
+ glVertex3fv(boxv6);
+ glVertex3fv(boxv2);
+ glEnd();
+
+ glColor3f(1.0, 1.0, 1.0);
+ glBegin(GL_LINES);
+ glVertex3fv(boxv0);
+ glVertex3fv(boxv1);
+
+ glVertex3fv(boxv1);
+ glVertex3fv(boxv2);
+
+ glVertex3fv(boxv2);
+ glVertex3fv(boxv3);
+
+ glVertex3fv(boxv3);
+ glVertex3fv(boxv0);
+
+ glVertex3fv(boxv4);
+ glVertex3fv(boxv5);
+
+ glVertex3fv(boxv5);
+ glVertex3fv(boxv6);
+
+ glVertex3fv(boxv6);
+ glVertex3fv(boxv7);
+
+ glVertex3fv(boxv7);
+ glVertex3fv(boxv4);
+
+ glVertex3fv(boxv0);
+ glVertex3fv(boxv4);
+
+ glVertex3fv(boxv1);
+ glVertex3fv(boxv5);
+
+ glVertex3fv(boxv2);
+ glVertex3fv(boxv6);
+
+ glVertex3fv(boxv3);
+ glVertex3fv(boxv7);
+ glEnd();
+} // drawCube
+
+void CubeView::draw() {
+ if (!valid()) {
+ glLoadIdentity();
+ glViewport(0, 0, pixel_w(), pixel_h());
+ glOrtho(-10, 10, -10, 10, -20050, 10000);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+
+ glTranslatef((GLfloat)xshift, (GLfloat)yshift, 0);
+ glRotatef((GLfloat)hAng, 0, 1, 0);
+ glRotatef((GLfloat)vAng, 1, 0, 0);
+ glScalef(float(size), float(size), float(size));
+
+ drawCube();
+
+ glPopMatrix();
+}
+\endcode
+
+\subsection fluid_cubeview_ui The CubeViewUI Class
+
+We will completely construct a window to display and control the
+CubeView defined in the previous section using FLUID.
+
+\par Defining the CubeViewUI Class
+
+Once you have started FLUID, the first step in defining a class is to
+create a new class within FLUID using the <b>New->Code->Class</b>
+menu item. Name the class "CubeViewUI" and leave the subclass blank.
+We do not need any inheritance for this window. You should see the
+new class declaration in the FLUID browser window.
+
+\image html fluid1.png "FLUID file for CubeView"
+\image latex fluid1.png "FLUID file for CubeView" width=7cm
+
+\par Adding the Class Constructor
+
+Click on the CubeViewUI class in the FLUID window and add a new method
+by selecting <b>New->Code->Function/Method.</b> The name of the
+function will also be CubeViewUI. FLUID will understand that this will
+be the constructor for the class and will generate the appropriate
+code. Make sure you declare the constructor public.
+
+Then add a window to the CubeViewUI class. Highlight the name of
+the constructor in the FLUID browser window and click on
+<b>New->Group->Window</b>. In a similar manner add the
+following to the CubeViewUI constructor:
+
+\li A horizontal roller named \p hrot
+\li A vertical roller named \p vrot
+\li A horizontal slider named \p xpan
+\li A vertical slider named \p ypan
+\li A horizontal value slider named \p zoom
+
+None of these additions need be public. And they shouldn't be
+unless you plan to expose them as part of the interface for
+CubeViewUI.
+
+When you are finished you should have something like this:
+
+\image html fluid2.png "FLUID window containing CubeView demo"
+\image latex fluid2.png "FLUID window containing CubeView demo" width=7cm
+
+We will talk about the \p show() method that is highlighted
+shortly.
+
+\par Adding the CubeView Widget
+
+What we have is nice, but does little to show our cube. We have already
+defined the CubeView class and we would like to show it within the
+CubeViewUI.
+
+The CubeView class inherits the Fl_Gl_Window class, which
+is created in the same way as an Fl_Box widget. Use
+<b>New->Other->Box</b> to add a square box to the main window.
+This will be no ordinary box, however.
+
+The Box properties window will appear. The key to letting CubeViewUI
+display CubeView is to enter CubeView in the <b>Class:</b> text
+entry box. This tells FLUID that it is not an Fl_Box, but a
+similar widget with the same constructor.
+
+In the <b>Extra Code:</b> field enter <tt>\#include "CubeView.h"</tt>
+
+This \p \#include is important, as we have just included
+CubeView as a member of CubeViewUI, so any public CubeView methods are
+now available to CubeViewUI.
+
+\image html fluid3-cxx.png "CubeView methods"
+\image latex fluid3-cxx.png "CubeView methods" width=7cm
+
+\par Defining the Callbacks
+
+Each of the widgets we defined before adding CubeView can have
+callbacks that call CubeView methods. You can call an external
+function or put a short amount of code in the <b>Callback</b>
+field of the widget panel. For example, the callback for the
+\p ypan slider is:
+
+\code
+cube->pany(((Fl_Slider *)o)->value());
+cube->redraw();
+\endcode
+
+We call <tt>cube->redraw()</tt> after changing the value to update
+the CubeView window. CubeView could easily be modified to do this, but
+it is nice to keep this exposed. In the case where you may want to do
+more than one view change only redrawing once saves a lot of time.
+
+There is no reason to wait until after you have added CubeView to
+enter these callbacks. FLUID assumes you are smart enough not to refer
+to members or functions that don't exist.
+
+\par Adding a Class Method
+
+You can add class methods within FLUID that have nothing to do with the
+GUI. As an example add a show function so that CubeViewUI can actually
+appear on the screen.
+
+Make sure the top level CubeViewUI is selected and select
+<b>New->Code->Function/Method</b>. Just use the name
+\p show(). We don't need a return value here, and since we will
+not be adding any widgets to this method FLUID will assign it a return
+type of \p void.
+
+\image html fluid4.png "CubeView constructor"
+\image latex fluid4.png "CubeView constructor" width=7cm
+
+Once the new method has been added, highlight its name and select
+<b>New->Code->Code.</b> Enter the method's code in the code window.
+
+\subsection fluid_addconst Adding Constructor Initialization Code
+
+If you need to add code to initialize a class, for example setting
+initial values of the horizontal and vertical angles in the
+CubeView, you can simply highlight the constructor and select
+<b>New->Code->Code</b>. Add any required code.
+
+\subsection fluid_gencode Generating the Code
+
+Now that we have completely defined the CubeViewUI, we have to generate
+the code. There is one last trick to ensure this all works. Open the
+preferences dialog from <b>Edit->Preferences</b>.
+
+At the bottom of the preferences dialog box is the key:
+<b>"Include Header from Code"</b>.
+Select that option and set your desired file
+extensions and you are in business. You can include the CubeViewUI.h
+(or whatever extension you prefer) as you would any other C++ class.
+
+*/