Google

CHAPTER 3 - CREATING NEW VIEW-OBJECTS

3.1 INTRODUCTION

This chapter gives some advice on how to code a new XDL_VIEW view-object. Though the fundamental requirements are few it is recommended that any new view-objects should be coded in the same style as those which already exist. It is also desirable to follow the internal documentation style so that documentation may be extracted automatically from the source file using the 'extract_doc' program.

List of sections:

Writing Code for a New View-Object
General Layout of the Code
The View-object Template File
View-objects without an Active Strip
View-objects with Keyboard Input
Layout Considerations
Library Window Routines

3.2 WRITING CODE FOR A NEW VIEW-OBJECT

A single source code file should be provided for each view-object. This will contain the code used to set up the object, code to handle event callbacks etc. and additional application callable routines if required. Fortran interfaces should be provided to the application callable routines in a manner which will cope with a range of different computer types.

The fundamental requirements for coding a view-object are few. The routine for creating the view-object must have a view-object handle as one of its parameters. A top level window must be created and a call must be made to the routine xdl_new_view_object to add the view-object to the list of view-objects. For any additional windows created, entries must be added to the view-object's list of windows by calling the routine xdl_add_window (or xdl_add_libwin) for each added window.

It is desirable, however, to follow the presentation and coding style of the original set of view-objects such as xdl_menu_area, xdl_param_table, xdl_io_window and xdl_film_image. Some basic requirements are common to almost all view-objects. To describe the recommended coding layout and to assist with the writing of new view-objects, a template file xdl_template.c has been prepared to act as a starting point. This contains the essential skeleton for a view-object which has at least one paint window and which returns some data to the application program when required. Thus the basic coding for including an active strip window is included. Keyboard input is not included in this template file but an alternative file which includes code for handling the keyboard focus is available as xdl_template_kbd.c. Some details of how to cope with other requirements are given following the description of the template code and reference is made to some of the original view-objects where appropriate.

Where possible, the layout should allow for font specifications of any size. However, the small font size may be used with 'hard wired' sizes and may be assumed not to exceed 7x13 pixels in size. The five fonts (normal or bold) may also be assumed to be in ascending order of size. The size of a normal font and the corresponding bold font may be assumed not to differ by more than one pixel in width and two in height.

3.3 GENERAL LAYOUT OF THE CODE

The general layout of the coding is as follows:

  1. Header Information for routine creating the view-object:

    • Routine Header
    • Description of Fortran call
    • Inclusion of xdl_view_extern.h and other header files
    • Parameter definitions for the view-object
    • Definition of the global data structure for the view-object
    • Definition of the routine types
    • Definition of the Fortran binding names (for LINKTYP options)
    • Definition of the Fortran binding routines

  2. The code for the view-object creation routine.

  3. The code for the Fortran binding of the view-object creation routine.

  4. Private service routines as follows:

    • Repaint routine for the active strip (if present)
    • Repaint routines for the view-object's windows
    • Event handling routines for the view-object's windows
    • View-object on_off routine
    • View-object tidy_up routine
    • Other service routines as needed
    • Panel item callback routines if needed

  5. Application callable routines:

    • Routines to change the state of the view-object (+ Fortran bindings)
    • Routines to return data to the application (+ Fortran bindings)

      (Each should have a section of documentation in its header)

It is suggested in particular that the following be preserved:

  • The general style of the existing view-objects appearance should be followed where possible (e.g. use of active strip, restrained use of colour, border width and height around the main inner window of BORDER_WIDTH and BORDER_HEIGHT).

  • The view_object should be given a name e.g. with two parts separated by an underscore (e.g. menu_area, film_image).

  • The name of the routine for creating the view-object should be of the form xdl_view_name (e.g. xdl_menu_area) and the equivalent fortran binding name be xdlf_view_name.

  • All routines within the view-object source code file should start with the above name e.g. for xdl_param_table, xdl_param_table_rp1, xdl_param_table_ep1, xdl_param_table_on_off, xdl_param_table_tidy_up, xdl_param_table_getvalue etc.

  • The on/off routine name should be of the form xdl_view_name_on_off and the tidy up routine name should be of the form xdl_view_name_tidy_up.

  • The name of the global data structure should be of the form XDl_view_name e.g. XDl_param_table.

  • The use of the variable 'gd' as a temporary pointer to the global data structure.

  • The way of setting up the top level window and handling the presence or absence of a parent view-object.

  • The handling of the Fortran/C interface (Especially with respect to character strings and link names).

  • The handling of the call checking in the application callable routines for modifying the view-object state or returning data from the view-object.

Also, it is desirable to follow the documentation scheme as indicated in the template files as a program (extrac_doc) is available to extract this documentation from the files. The documentation sections are as follows:

  • A title line enclosed by:

    /*-Title: ...
    -end*.
    

  • An introductory section enclosed by:

    /*-Intro:
    ...
    -end*/
    

  • A header section for each set of routines to be documented enclosed by:

    /*-Section: ...section_title...
    ...
    -end*/
    

  • The main routine header and each application routine header should be laid out with the calls described as indicated. The document extraction program will be searching for Routine header sections:

    /*-Routine: ...brief_description... - ...routine_name...
    ...
    ... (description)
    ...
    -end*/
    

  • Also sections describing the Fortran call:

    /*-Fortran:
        ...subroutine_call_syntax...
    -end*/
    

    /*-Parameters: ... ... (description of parameters) ... -end*/

  • Also sections describing the 'C' call:

    /*-C:*/
         ...function_definition...
    /*end*/
    

    /*-Parameters:*/ ... ... (parameter specifications - different form may be adopted if parameters ... defined in definition (see extract_doc program documentation) ... /*end*/

    /*-Doc:

    Return: ...description_of_the_function_return(s)...

    -end*/

For further details, see the documentation of the extract_doc program.

Each new view-object coded must be assigned a unique integer which is used in checking that application routines called are for the correct type of view-object. The user wishing to create his/her own routines should use numbers greater than 100000. If a view-object is included in the distribution set then it will be reassigned a number less than 100000. The assignment of the same number to more than one view-object does not prevent anything working correctly if the correct routines are called with the correct view-object handles; it just removes a safety net.

3.4 THE VIEW-OBJECT TEMPLATE FILE

When using the template file as a starting point for the code for a new view-object, the text 'view_name' must be replaced by the name of the new routine (preferably again a two part name linked with an underscore). Places where an ellipsis (...) occurs will need altering or filling out with code specific to the new view-object.

The template file is reproduced below with added comments following exclamation marks. These comments are designed to explain the coding in the template and to help the programmer to add the code required for the new view-object. Reference is made to existing view-objects for examples where appropriate.

/*-Title: ...    ! Title for this set of routines
-end*/

/*-Intro: ... ! General description of the view object -end*/

/*Routines List: ... ! Names and very brief descriptions of user callable routines ! (not used in extracted documentation) */

! Code starts with a standard format of header

/*-Routine: ... - ... ! Brief description and routine name ... ! Description of the routine -end*/

/* ************************ ** xdl_view_name ** ************************

Purpose: ! Brief description of the view-object given here

Author: ...

! Fortran call described next /*-Fortran: CALL XDLF_VIEW_NAME (IVH, IVHPARENT, IX, IY, ICSET, ... , IERR) -end*/

/*-Parameters: IVH (R) View-object handle (see vh) IVHPARENT (R) View-object handle for parent 0=none (see vh_parent) IX (R) X position if parent given (see x) IY (R) Y position if parent given (see y) ICSET (R) Colorset number (see cset) ... ! Add other parameters here as needed IERR (W) Returns status from xdl_view_name call -end*/

/* Include XDL external data and headers */

! The following header file is always included #include "xdl_view_ext.h" ! Other header files may be required e.g. xdl_panel_items.h ! (see xdl_param_table, xdl_film_image for examples)

#define ... ! Put any parameter definitions here (see xdl_film_image for ! examples)

/* Define structure for the global data for the view-object */

! The global data area for the view-object is now defined. This ! must contain all data items which are required for communication ! between the routines for the view object an which are specific to ! a particular instance of the view-object. A few items (or very ! similar ones are always included) typedef struct { Window wframe; /* Primary window id */ Window wpaint; /* Paint window id */ Window wact; /* Active strip window */ GC paint_gc; /* GC for paint window */ int on_off; /* Program awaiting input =1, not =0 */ ... ! Add other items specific to the view-object here } XDl_view_name; ! Name based on view-object name

/* Define routine types */

int xdl_view_name(); ! Define all routines for the view-object void xdl_view_name_rps(); ! (Fortran bindings will be defined below) void xdl_view_name_rp1(); void xdl_view_name_ep1(); void xdl_view_name_on_off(); void xdl_view_name_tidy_up(); int xdl_view_name_getdata();

/* Define Fortran binding names */ ! Application callable routines

#if LINKTYP == 1

#define xdlf_view_name xdlf_view_name_ #define xdlf_view_name_getdata xdlf_view_name_getdata_ ! Add additional routines here and below

#elif LINKTYP == 2

#define xdlf_view_name XDLF_view_name #define xdlf_view_name_getdata XDLF_VIEW_NAME_GETDATA ! Add additional routines here and below

#endif

! Define fortran binding routines void xdlf_view_name(); void xdlf_view_name_getdata(); ! Add additional routines here

! View-object creation routine follows /*-C:*/ int xdl_view_name (vh, vh_parent, x, y, cset, ... ) /*end*/

/*Parameters:*/ int vh; /* User selected view-object handle (R)*/ int vh_parent; /* View-object handle for the parent base frame, if 0 then a base level frame is created to enclose the view-object (R)*/ int x; /* x coordinate for the view-object If no parent may be -1 to give default x (R)*/ int y; /* y coordinate for the view-object If no parent may be -1 to give default y (R)*/ int cset; /* Number of the colorset to be used (R) */ ... /*end*/

/*-Doc: Return: Status flag =0 OK, >0 error bit 0 set: Requested parent not found in the view-objects list ... ! Add other conditions as required -end*/ { Window wframe; /* Top level window id*/ Window wparent; /* Parent window id */ XDl_view_name * gd; /* Pointer to view-object's global data structure */ int err; /* Error return flag */ int iv; /* Offset into XDL_view_objects array */ int width; /* View-object width */ int height; /* View-object height */ int area_width; /* Paint area width */ int area_height; /* Paint area height */ int x_area; /* x position of paint area within the view-object*/ int y_area; /* y position of paint area within the view-object */

err = 0;

/* Get size requirements */ ! e.g for the top level window and the ! paint window width = ... ; height = ... ; area_width = ... ; area_height = ... ; x_area = ... ; y_area = ...;

/* Create the top level frame (or base frame) window for the routine */

! The following section will be appropriate for most view-objects. It ! has been used in xdl_menu_area, xdl_param_table, xdl_film_image etc. /* Check that parent_vh present if requested */

if (vh_parent>0) { iv = xdl_getiv (vh_parent); if (iv<0) /* Create frame window as parent window was given */ { err |= 1; return err; } wparent = XDL_view_objects[iv]->wid; wframe = xdl_create_frame_window (wparent, x, y, width, height, cset); }else{ /* Create base frame window as no parent frame window was specified */ wframe = xdl_create_base_frame_window ("xdl_view_name", "xdl_view", x, y, width, height); }

/* Create structure for the routines' global data */

gd = (XDl_view_name *) malloc (sizeof(XDl_view_name)); ! gd has been generally used as a temporary pointer to the global data ! for a view-object

/* Add new view-object to the list of view-objects */

xdl_new_view_object (vh, wframe, vh_parent, gd, 999..., xdl_view_name_on_off, xdl_view_name_tidy_up); ! The fifth parameter is an integer which should be unique to a particular ! type of view-object. It is used to check that, when an application calls ! one of the other routines associated with the view-object (e.g. ! xdl_view_name_getdata in this template file), the view-object accessed ! via the view-object handle is of the correct type. ! Note definition of on_off and tidy_up routines

/* Some initialisations */

gd->wframe = wframe; gd->on_off = 0; ! Set on/off flag to 'inactive' state. This will ! subsequently be set on or off via the on-off ! routine defined in the xdl_new_view_object call ! above ! Initialise other items in the global data structure as needed

/* Create active strip window */

gd->wact = xdl_create_active_strip (gd->wframe, vh, area_width..., xdl_view_name_rps); ! Check the required width in the above call ! Note definition of active strip repaint routine

/* Create paint window */ ! Note that the window is added to the ! windows list

gd->wpaint = xdl_create_paint_window (wframe, x_area, y_area, 1, area_width, area_height, cset);

xdl_add_window (vh, gd->wpaint, xdl_view_name_rp1, xdl_view_name_ep1); ! Note definition of repaint and event handling routines

/* Prepare for event handling */

XSelectInput (XDL_display, gd->wpaint, ExposureMask|StructureNotifyMask| ... ); ! Add other event inputs as required

/* Create and initialise GC */ ! Remember to free any GCs created ! in the tidy_up routine

gd->paint_gc = XCreateGC (XDL_display, gd->wpaint, 0, NULL);

XSetForeground (XDL_display, gd->paint_gc, XDL_blackpixel);

XSetFont (XDL_display, gd->paint_gc, ... ); ! Set a font if needed

return 0; }

! Fortran binding routine follows. ! Add extra parameters as needed. ! For an example of passing a character string using the xdlstr function ! see the xdlf_param_table subroutine

/* Fortran binding: xdlf_view_name */

void xdlf_view_name (ivh, ivhparent, ix, iy, icset, ... , ierr)

int *ivh, *ivhparent, *ix, *iy, *icset, *ierr; ... { *ierr = xdl_view_name (*ivh, *ivhparent, *ix, *iy, *icset, ... ); return; }

/*==================================================*/ /* 'Private' SERVICE ROUTINES */ /*==================================================*/

/* ********************************* ** xdl_view_name_rps ** *********************************

PURPOSE: Repaint active strip window

RETURN: None

AUTHOR: ...

*/

void xdl_view_name_rps (wid, event, iv, global, callback)

Window wid; XEvent *event; int iv; char * global; void (*callback)();

{ XDl_view_name * gd; /* Pointer to global data area */

gd = (XDl_view_name *) global; if (gd->on_off==0) { xdl_active_strip_off (wid); } else { xdl_active_strip_on (wid, "...", 0); } ! Note that the final parameter of the xdl_active_strip_on call indicates ! the status of the keyboard focus when this is relevant to the ! view-object. In this case it is not and a value of 0 is given. }

! A window repaint routine follows; there will normally be one such routine ! for each window associated with the view-object. /* ********************************* ** xdl_view_name_rp1 ** *********************************

Purpose: Repaint paint window

Return: None

Author: ...

*/

void xdl_view_name_rp1 (wid, event, iv, global, callback)

Window wid; XEvent *event; int iv; char * global; void (*callback)();

{ XDl_view_name * gd; /* Pointer to global data area */

gd = (XDl_view_name *) global;

/* Repaint code */

... ! This must be added as needed for the particular view-object ! See for example xdl_param_table_rp1, xdl_film_image_rp1 etc.

return; }

! A general event handling routine follows; there will normally be one ! such routine for each window associated with the view-object. /* ********************************* ** xdl_view_name_ep1 ** *********************************

Purpose: Event handling from paint window

Return: None

Author: ...

*/

void xdl_view_name_ep1 (wid, event, iv, global, callback)

Window wid; XEvent *event; int iv; char * global; void (*callback)();

{ XDl_view_name *gd; /* Pointer to the global data area */

gd = (XDl_view_name *) global;

... ! This must be added as needed for the particular view-object ! See for example xdl_param_table_ep1, xdl_film_image_ep1 etc.

return; }

! The following is the routine which will be called by the routine ! xdl_get_events to switch a view-object into its input 'active' or ! 'inactive' state /* *********************************** ** xdl_view_name_on_off ** ***********************************

Purpose: Routine called when switching application input on/off

Return: None

Author: ...

*/

void xdl_view_name_on_off (iv, i)

int iv; /* Offset in XDL_view_objects array */ int i; /* flag =1 on, =0 off */

{ XDl_view_name *gd; /* Pointer to global data area */

gd = (XDl_view_name *) XDL_view_objects[iv]->gd; if (i==1) { gd->on_off = 1; ... ! This must be added as needed for the particular view-object ! See for example xdl_menu_area_on_off etc. xdl_active_strip_on (gd->wact, "...", 0); ! The last parameter in the above call may be different for view-objects ! with keyboard input (see for example xdl_io_window_on_off routine) } else { gd->on_off = 0; ... ! This must be added as needed for the particular view-object ! See for example xdl_menu_area_on_off etc. xdl_active_strip_off (gd->wact); } return; }

! The following routine will be called when the view-object is deleted /* ************************************ ** xdl_view_name_tidy_up ** ************************************

Purpose: Routine called to tidy up before view-object is deleted

Return: None

Author: ...

*/

void xdl_view_name_tidy_up (global)

char * global; /* Pointer to global data area */

{ XDl_view_name *gd; /* Pointer to the global data area */

gd = (XDl_view_name *) global; ... ! Free any areas of memory allocated by the view-object (except ! for the global data area which will automatically be freed by ! the xdl_delete_view_object routine). Free any other resources ! allocated. (see for example xdl_film_image_tidy_up) XFreeGC (XDL_display, gd->paint_gc); return; }

/*===========================================================*/ /* 'Public' APPLICATION CALLABLE ROUTINES */ /*===========================================================*/

! Example of layout of a routine to return the data from a view-object ! (see for example xdl_param_table_getvalue) /*Routine: ... - ... ! Brief description and name ... ! Purpose, name and description of the routine ... -end*/

/* *********************************** ** xdl_view_name_getdata ** ***********************************

Purpose: Get returned data ... from the view_name

Author: ... /*-Fortran: CALL XDLF_VIEW_NAME_GETDATA (IVH, ..., IERR) -end*/

/*-Parameters: IVH (R) View-object handle (see vh) ... IERR (W) Returns status from xdl_view_name_gedata call

-end*/

/*-C:*/ int xdl_view_name_getdata (vh, ... ) /*end*/

/*Parameters:*/ int vh; /* View-object handle (R)*/ ... ! Add parameters here as needed /*end*/

/*-Doc: Return: Status = 0 OK, >0 error bit 0 set: View-object handle not found bit 1 set: View handle does not match view object ... -end*/ { int iv; /* Offset in XDL_view_objects array */ XDl_view_name *gd; /* pointer to the global data area */

iv = xdl_getiv (vh);

/* Check validity of the call */

if (iv<0) {xdl_view_iv_errmsg ("xdl_view_name_getdata",vh); return 1;} if (XDL_view_objects[iv]->type!=999...) { xdl_view_type_errmsg ("xdl_view_name_getdata", vh, "xdl_view_name"); return 2; }

gd = (XDl_view_name *) XDL_view_objects[iv]->gd;

/* Return the required data */

... ! The code here will normally access data items from the global ! data area (pointed to by gd) and return the relevant information ! through the parameter list for this function

return 0; }

/* Fortran binding xdlf_view_name_getdata */

void xdlf_view_name_getdata (ivh, ..., ierr) int *ivh, *ierr; ... { *ierr = xdl_view_name_getdata (*ivh, ... ); ! Examples of returning parameter values including text string values ! may be found in xdlf_menu_area_getitem and xdlf_param_table_getvalue return; }

3.5 VIEW-OBJECTS WITHOUT AN ACTIVE STRIP

In some cases the view-object will not require to return data to the calling application program (e.g. progress bar view-object). In this case the code for including an active strip as given in the template file may be omitted.

The following changes would be made:

  1. Remove the call to create the active strip

    gd->wact = xdl_create_active_strip (gd->wframe......

  2. Remove the routine xdl_view_name_rps and references to it

  3. Remove the routine xdl_view_name_on_off and references to it; in the xdl_new_view_object call, replace its name with a NULL.

  4. Remove references to the on_off item from the XDl_view_name structure (e.g. gd->on_off)

3.6 VIEW-OBJECTS WITH KEYBOARD INPUT

In view objects with keyboard input, the question of keyboard focus has to be considered. When an active strip is included and the view-object is in its active state, the message in the active strip should be in bold print when the view-object has the keyboard focus and be in normal print when it has lost the keyboard focus. The following additions/changes are required to the template code described above (a file including such changes is available as xdl_template_kbd.c):

  1. Add the integer item kbd_focus to the XDl_view_name structure.

  2. Initialise this flag to zero when the global data area has been allocated.

  3. In the xdl_view_name_rps routine, use the flag gd->kbd_focus as the final parameter in calling the routine xdl_active_strip_on. (normal/bold print flag)

  4. In the xdl_view_name_on_off routine, when called to set the 'active' state, get the keyboard focus if possible and set the gd->kbd_focus flag as appropriate.

  5. In the event handling routine, check for keyboard focus gained or keyboard focus lost events. If gained, set gd->kbd_focus to 1 and re-draw the active strip with the message in bold print if the view-object is in its active state (gd->on_off == 1). If lost, set gd->kbd_focus to 0 and re-draw the active strip with the message in normal print if the view-object is in its active state. Also, if the view-object is in its active state, get the keyboard focus if Button1 of the mouse was pressed.

Examples of view-objects with keyboard input include the I/O window view-object and the parameter table view-object.

3.7 LAYOUT CONSIDERATIONS

When a view-object has an active strip, then this is situated just below the top of the top-level window. It's origin pixel is situated at x = BORDER_WIDTH, y = BORDER_HEIGHT. If w is the width of the top-level window for the view-object then the width of the active strip will normally be (w - 2*BORDER_WIDTH - 2). The total height of the active strip plus the top border is given by ACT_STRIP_HEIGHT. The window of a view-object situated immediately below the active strip will normally have its origin at x = BORDER_WIDTH, y = ACT_STRIP_HEIGHT + BORDER_HEIGHT (leaving a border of height BORDER_HEIGHT between the active strip and the window). Thus, where appropriate, top and bottom borders will be of height BORDER_HEIGHT and side borders will be of width BORDER_WIDTH. Examples of view-objects using these border sizes are the menu area view-object, the parameter table view-object and the I/O window view-object.

The parameters BORDER_WIDTH, BORDER_HEIGHT and ACT_STRIP_HEIGHT are defined in the header file xdl_view_extern.h.

Where appropriate, a routine should be provided to calculate the size of a view-object given a set of set-up parameters. Examples are the xdl_menu_area_getsize, xdl_io_window_getsize, xdl_param_table_getsize and xdl_film_image_getsize routines.

3.8 LIBRARY WINDOW ROUTINES

Routines, such as those for creating and manipulating the panel items, provide standard window items which may be used within the coding of view-objects. They differ from the main view-objects in that they are used to serve the internal needs of a view-object rather than directly serving the needs of the application program. As a consequence they do not have view-object handles. They create windows which belong to the view-object in a manner similar to that of other windows created within the view-object's own code. Because, however, they are library routines, which may be shared by many view-objects, they normally require a separate global data area to be set up for each instance created. Also, as they are not identified by view-object handles, they return data to the view-object via a callback mechanism. When the window from a library window routine is added to the windows list of a view-object, the routine xdl_add_libwin is used instead of xdl_add_window. This allows three extra items to be added to the stored window data namely:

  1. A pointer to the library routine's global data area

  2. A pointer to the callback routine to be used

  3. A pointer to a tidy_up routine to be called when the library routine window item is deleted.

When an event is processed (xdl_get_events or xdl_flush_events), it is a pointer to the library routine's own global data area that is passed as a parameter to the event handling routine rather than a pointer to the global data for the view-object and a pointer to the callback routine is passed as the final parameter rather than a NULL. When a view-object is deleted then the tidy_up routines, associated with any library window routines used, will be called.



John W. Campbell
CCLRC Daresbury Laboratory
Last update 4 Feb 1998