John Shahbazian - 2013-06-21

Instructions (v0.3.x and up)

June 21st, 2013

Note: Through this document, the term 'function' is used to describe what in Fortran could be either a subroutine or a function. In most of the code, subroutines are used. Please excuse the lack of formality.

ForGE is a static library. To compile, include it in your library directory and add '-lforge' to the linker arguments. A preprocessor define is included to make code more readable, but it is unnecessary. To use it, add '-cpp' to the Fortran compiler arguments.

Theory of Design

ForGE was created to address a failing in the available GUI frameworks for the latest versions of Fortran. The existing frameworks are either expensive or complex. ForGE aims to be neither. To achieve these goals, the Fortran port |of GTK+, gtk-fortran, was used as a base for the GUI function calls. They were wrapped up and put into a form that even an inexperienced programmer could use.

The basic visual structure for any window in ForGE is a grid. Widgets are placed within sections of that grid and are designated by column and row values. Please see the diagram below.

             Columns
          1     2     3
     1 |-----|-----|-----|
Rows 2 |-----|-----|-----|
     3 |-----|-----|-----|

Within the function calls of ForGE, the location and span of each widget is required. For instance, a call to create a label widget could be written as:

call create_label(guiwindow,"label1",1,2,1,"Menu Example")

The first argument specifies the window object that the widget is placed in, the second specifies the name of the widget, and the final argument specifies the text to display for the label. The third, fourth, and fifth arguments are all location and span information. In every widget function call, they will be in the following order: column, row, and span. So, for the above function call, the label1 widget will be placed in Column 1, Row 2, and it will have a span of 1 (meaning it will only fill one grid spot).

The first argument in the above label example is the window object, which is the basic code structure for any window in ForGE. It is created with the following declaration:

type(window) :: guiwindow

Once that object is declared, nothing can be done to the window until the create_window() function is called. This function is demonstrated below:

call create_window(guiwindow,"window1",3,3,"Title",event(event_destroy))

The guiwindow object is passed in as the first argument. The second argument is the name of the window, which is only used internally. The third and fourth arguments are the column and row size for the window's grid (see the earlier diagram for an example of a 3,3 grid). The fifth argument is the text displayed across the title of the window, and the sixth argument is the event (function) to call when the window is closed.

The create_window() function must be called before any widgets are assigned to the window, otherwise it simply won't work. Aside from that, the only other required function for the window to properly work is:

call show_window(guiwindow)

The argument is the window object itself, which was created earlier.

In any ForGE program, there are 3 main subroutines which must run for the whole thing to work. After the window object(s) is/are created, the following three functions must be called in order:

call init()
call setup()
call run()

The init() and run() functions are off-limits to the programmer (at least for now) and are contained within the ForGE library.. The setup() function is where all the ForGE function calls go and needs to be placed in the main program.

While it lacks event handling (for the event(event_destroy) argument), below is a very basic example of a program to run ForGE:

program test
  use forge

  type(window) :: guiwindow

  call init()
  call setup()
  call run()
contains
  subroutine setup
    call create_window(guiwindow,"window1",3,3,"Title",event(event_destroy))
    call show_window(guiwindow)
  end subroutine setup
end program test
~~~~~~~~~~~~~~~~~~~~~~~~~

As stated, the above code doesn't include the event_functions module that handles events produced by the window.  That will be covered next.

In order for the widgets to interact with code, event functions will need to be called.  To use events, another module must be created and included in the main program.  Below is a very simple of example of a module that will handle the events for the above program example:

module event_functions
use iso_c_binding
use forge

contains

subroutine event_destroy(widget_ptr, data_ptr) bind(c)
    type(c_ptr), value :: widget_ptr, data_ptr

    call gtk_main_quit()
end subroutine event_destroy

end module event_functions

The name of module can be whatever the programmer chooses, but it must be called in the main program (in the earlier program example, a line of 'use event_functions' right above 'use forge' would make it work).  The 'use iso_c_binding' and 'use forge' are both required and cannot be left out.  The only procedure in this module is event_destroy(), which is called in the earlier create_window() procedure.  For every event, two variables are always passed to the function and should be placed there even if not used.  widget_ptr is a type(c_ptr) that points to the widget itself.  data_ptr is a pointer to data that may be passed from the widget.  If such data is passed, a note of it will be made within the widget creation function definition in these instructions.  For this example, no data is passed.  The only actual code that is being executed is 'call gtk_main_quit()', which is required to shut the window down.  The 'bind(c)' that comes after the 'event_destroy(widget_ptr, data_ptr)' is required for all event functions.  It won't change, so just place it after the name of every function and forget about it.

One final note that should probably have been mentioned earlier: The event() function that is used in the create_window() function above is actually just a preprocessor definition that replaces c_funloc().  The following line is required to be placed at the top of the file to use this:

define event(x) c_funloc(x)

~~~~~~~~~~~~~~~~~~~~

And in the Fortran compiler arguments, -cpp must be added to enable the pre-processor. This will add a little bit of time to the compilation, but I think that it will make the code easier to read for someone not familiar with iso_c_binding functions. If you want to remove it, then all event(...) calls must be turned into c_funloc(...)

At the moment, there is a good amount of lower-level code exposed in the function calls for events. That may change in the future. For now, it isn't too much I hope.

Widgets

The following widgets are currently available in the ForGE framework:

Widget Subroutine (i.e. preface with 'call')
Menu bar (File, Edit, View, About, etc) create_menu_bar(window_object,widget_name,grid_x,grid_y,span)
Sub-Menu create_sub_menu(window_object,widget_name)
Label create_label(window_object,widget_name,grid_x,grid_y,span,text)
Combo box (dropdown list) create_combo_box(window_object,widget_name,combo_options,grid_x,grid_y,span,event_ptr)
Progress bar create_progress_bar(window_object,widget_name,grid_x,grid_y,span,text)
Update progress bar set_progress_bar(window_object,widget_name,progress_bar_value)
Button create_button(window_object,widget_name,grid_x,grid_y,span,text,event_ptr)
Text Entry (single line to enter text into) create_text_entry(window_object,widget_name,grid_x,grid_y,span,text,event_ptr)
Text View (multiple lines to enter text into) create_text_view(window_object,widget_name,grid_x,grid_y,size_x,size_y,event_ptr)
File Chooser (brings up a dialog to select files) create_file_chooser(window_object,widget_name,grid_x,grid_y,span,text,filters,event_ptr)

Please note that the sub-menu widget is still in development and doesn't do anything

More will be added as time goes on.

Widget Function Arguments

window_object = the window object itself (guiwindow in the earlier examples)
widget_name = an internal text name (must be in single quotes) that must be unique for each widget (there isn't a check for this yet)
grid_x = the COLUMN that this widget will be in
grid_y = the ROW that this widget will be in
span = how many grid sections the widget will span
text = the text that will be displayed (must be in single quotes)
event_ptr = the event function that will be called when the widget is used (must be surrounded by event(...))
combo_options = a text array with each option in each spot (see example)
progress_bar_value = Decimal value between 0 and 1.0 for the progress bar to display
filters = a text array with each member being a filter for the files in the chooser (see example)
size_x = pixel size of the x dimension of the text view
size_y = pixel size of the y dimension of the text view

 

Last edit: John Shahbazian 2013-06-25