Professional GEM - Part IV - Resource structure

From Atari Wiki
Revision as of 12:07, 13 September 2006 by Zorro 2 (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search


        Professional GEM                                               24


                                    P�PA�AR�RT�T -�- I�IV�V

                            R�Re�es�so�ou�ur�rc�ce�e S�St�tr�ru�uc�ct�tu�ur�re�e      


             Welcome to  the  fourth  installment  of ST PRO GEM.  We are
        about  to delve into the mysteries of GEM resource structure, and
        then  use  this  knowledge  to  create  some useful utilities for
        handling  dialogs.  As with the past columns, there is once again
        a  download  file.   You  will find it under the name GEMCL4.C in
        the ATARI 16-bit Forum (GO PCS-58).  

             The first  and  largest  part  of  the download contains a C
        image  of a sample resource file.  To create this listing, I used
        the  GEM  Resource   Construction  Set to create a dummy resource
        with  three  dialogs including examples of all object types, then
        enabled  the  C  output  option  and saved  the resource.  If you
        have  access  to  a  copy of RCS, I suggest that you  create your
        own  listing  in  order  to  get  a  feel for the results.  Then,
        using   either  listing  as  a  roadmap  to the resource, you can
        follow along as  we enter...  


        A�A M�MA�AZ�ZE�E O�OF�F T�TW�WI�IS�ST�TY�Y L�LI�IT�TT�TL�LE�E P�PA�AS�SS�SA�AG�GE�ES�S.�.    

             While a  GEM  resource  is  loaded  as  a  block  of  binary
        information,  it  is  actually  composed of a number of different
        data  structures.   These  structures  are  linked  together in a
        rather  tangled  hierarchy.  Our first job is to map this linkage
        system.  

             The topmost  structure  in  a  resource file is the resource
        header.  This is an array of words containing the size and offset
        within  the  resource of the other structures which follow.  This
        information  is  used  by   GEM during the resource load process,
        and  you  should  never  need  to access it. (The resource header
        does  not  appear  in  the  C output file; it is generated by the
        RSCREATE   utility  if  the  C  file  is  used  to  recreate  the
        resource.) 

             The next  structure  of interest is the tree index.  This is
        an  array of long pointers, each of which addresses the beginning
        of  an  object  tree.  Again,  you  wouldn't normally access this
        structure  directly.   The  GEM   rsrcgaddr  call  uses  it  when
        finding  trees'  addresses.  This structure is called "rstrindex"
        in the C output.  

             If you  look  at  the  contents of rstrindex you will notice
        that   the  values  are  integers,  instead  of  the  pointers  I
        described.   What  has  happened  is  that  RCS has converted the
        pointers  to indices into the object array. (If you actually used
        the  C  file  to  recreate  the resource file, then the  pointers


        


        Professional GEM             Part IV                           25


        would be regenerated by RSCREATE.) 

             Now you  can  follow  the link from rstrindex to the objects
        stored  in  rsobject.   Take  (for  instance) the second entry in
        rstrindex  and  count  down  that  many  lines  in rsobject.  The
        following  line  (object) should start with a -1.  This indicates
        that  it  is  the  root  object of a tree.  The following objects
        down  to  the  next root belong to that tree. We'll pass over the
        details  of  inter-object linkage for now, leaving it for a later
        column.  

             There are  a  number  of  different fields in an object, but
        right  now  we'll  concentrate on two of them: OBTYPE and OBSPEC.
        The  OBTYPE  is  the  field which contains mnemonics like GSTRING
        and  GBOX  indicating  the type of the object.  The OBSPEC is the
        only  field  in each object which  is a LONG - you can tell it by
        the L after the number.  

             What's in  OBSPEC  depends on the object type, so we need to
        talk  about  what  kinds of objects are available, what you might
        use them for, and finally how they use the OBSPEC field.  

             The box  type objects are GBOX, GIBOX, and GBOXCHAR.  A GBOX
        is  an  opaque  rectangle, with an optional border.  It's used to
        create  a solid patch of color or pattern on which to place other
        objects.  For instance, the background of a dialog is a GBOX.  

             A GIBOX  is  a  hollow box which has only a border.  (If the
        border  has  no thickness, then the box is "invisible", hence the
        name.)   The  favorite  use  for IBOXes is to hold radio buttons.
        There  is  also one neat trick you can play with an IBOX.  If you
        have  more  than one object (say an image and a string) which you
        would  like  to have selected all at once, you can insert them in
        a  dialog,  then  cover  them  with  an  IBOX.  Since  the box is
        transparent,  they  will  show  through.  If you now make the box
        selectable,  clicking  on  it  will  highlight  the whole area at
        once! 

             The GBOXCHAR  is  just  like  a  GBOX,  except that a single
        character  is  drawn  in  its  center.   They  are mostly used as
        "control  points":  the  FULLER, CLOSER, SIZER, and arrows in GEM
        windows  are  BOXCHARs,  as  are   the  components  of  the color
        selection gadgets in the RCS.  

             The OBSPEC  for box type objects is a packed bit array.  Its
        various  fields  contain  the  background  color and pattern, the
        border  thickness  and  color, and the optional character and its
        color.  

             The string  type  objects  are GSTRING, GBUTTON, and GTITLE.
        GSTRINGs  (in  addition  to  being  a bad pun) are for setting up
        static  explanatory  text  within  dialogs.   The  characters are


        


        Professional GEM             Part IV                           26


        always  written  in  the "system font": full size, black, with no
        special effects.  

             We have  already  discussed  many  of  the uses of GBUTTONs.
        They  add a border around the text.  The thickness of a GBUTTON's
        border  is  determined by what flags are set for the object.  All
        buttons  start  out  with  a  border thickness of one pixel.  One
        pixel  is  added  if  the  EXIT attribute is set, and one more is
        added if the DEFAULT attribute is set.  

             The GTITLE  type  is  a specially formatted text string used
        only  in  the  title  bar  of menus.  This type is needed to make
        sure  that the menus redraw correctly.  The Resource Construction
        Set  automatically  handles inserting GTITLEs, so you will seldom
        use them directly.  

             In a  resource,  the OBSPEC for all string objects is a long
        pointer  to  a  null terminated ASCII string.  The string data in
        the  C file is shown in the BYTE array rsstrings.  Again you will
        notice  that   the  OBSPECs  in the C file have been converted to
        indices  into  rsstring.  To  find  the  string which matches the
        object,  take  the value of OBSPEC and count down that many lines
        in rsstrings.  The next line is the correct string.  

             The formatted   text   object  types  are  GTEXT,  GBOXTEXT,
        GFTEXT,  and  GFBOXTEXT.   GTEXTs  are a lot like strings, except
        that  you can specify a color, different sizes, and a positioning
        rule  for  the  text.    Since  they  require  more  memory  than
        GSTRINGs,  GTEXTs  should be used  sparingly to draw attention to
        important  information  within a dialog.   GTEXTs are also useful
        for  automatic  centering  of  dialog  text  which is  changed at
        run-time.  I will describe this technique in detail later on.  

             The GBOXTEXT  type adds a solid background and border to the
        GTEXT  type.   These  objects  are  occasionally used in place of
        GBUTTONs  when  their  color  will draw attention to an important
        object.  

             The GFTEXT  object  is an editable text field.  You are able
        to  specify  a  constant  "template"  of characters, a validation
        field  for  those  characters  which  are  to be typed in, and an
        initial  value  for  the  input  characters.  You may also select
        color,  size,  and  positioning  rule for GFTEXTs.  We'll discuss
        text editing at length below.  

             The GFBOXTEXT  object,  as you might suspect, is the same as
        GFTEXT  with the addition of background and border.  This type is
        seldom  used:  the  extra  appearance  details distract attention
        from the text being edited.  

             The OBSPEC  for  a formatted text object is a pointer to yet
        another  type  of  structure: a TEDINFO.  In the C file, you will


        


        Professional GEM             Part IV                           27


        find  these  in  rstedinfo.  Take the OBSPEC value from each text
        type  object  and  count  down  that  many  entries in rstedinfo,
        finding  the  matching  TEDINFO  on the next line.  Each contains
        pointers  to  ASCII  strings  for  the  template, validation, and
        initialization.   You  can  find these strings in rsstrings, just
        as above.  

             There are  also  fields  for  the  optional  background  and
        border  details, and for the length of the template and text.  As
        we  will see when discussing  editing, the most important TEDINFO
        fields  are  the  TEPTEXT  pointer  to   initialized text and the
        TETXTLEN field which gives its length.  

             The GIMAGE  object  type  is  the  only  one of its kind.  A
        GIMAGE  is  a monochrome bit image.  For examples, see the images
        within  the  various  GEM alert boxes.  Note that monochrome does
        not  necessarily mean black.  The image may be any color, but all
        parts  of it are the SAME color.  GIMAGEs are used as visual cues
        in  dialogs.   They  are  seldom used as selectable items because
        their  entire  rectangle is inverted when they are clicked.  This
        effect  is seldom visually pleasing, particularly if the image is
        colored.  

             GIMAGE objects  have  an  OBSPEC  which  is  a  pointer to a
        further  structure  type:  the  BITBLK.  By now, you should guess
        that  you  will find it in the C file in the array rsbitblk.  The
        BITBLK  contains  fields  describing  the height and width of the
        image  in pixels, its color,nd it also contains a long pointer to
        the  actual  bits  which  make  up the image.  In the C file, the
        images  are  encoded  as  hexadecimal  words and stored in arrays
        named IMAG0, IMAG1, and so on.  

             The last  type of object is the GICON.  Like the GIMAGE, the
        GICON  is  a  bit  image,  but it adds a mask array which selects
        what  portions  of  the  image  will  be  drawn,  as  well  as an
        explanatory  text  field.   A  GICON  may  also specify different
        colors  for  its  "foreground" pixels (the ones that are normally
        black), and its "background" pixels (which are normally white).  

             The pictures  which  you  see in Desktop windows are GICONs,
        and  so  are the disks and trashcan on the desktop surface.  With
        the  latter you will notice the effects of the mask.  The desktop
        shows  through  right  up  to the edge of the GICON, and only the
        icon  itself  (not  a  rectangle)  is  inverted  when  a  disk is
        selected.  

             The OBSPEC  of an icon points to another structure called an
        ICONBLK.   It  is  shown in the C file as rsiconblk.  The ICONBLK
        contains  long  pointers to its foreground bit array, to the mask
        bit  array, and to the ASCII string of explanatory text.  It also
        has  the foreground and background colors as well as the location
        of  the  text  area  from  the  upper left of the icon.  The most


        


        Professional GEM             Part IV                           28


        common  use  of  GICONs  and ICONBLKs  is not in dialogs, instead
        they  are  used  frequently in trees which are build at run-time,
        such  as Desktop windows.  In a future article, we will return to
        a discussion of building such "on-the-fly" trees with GICONs.  

             Now, let's  recap the hierarchy of resource structures:  The
        highest  level  structures  are the resource header, and then the
        tree  index.   The  tree  index  points  to the beginning of each
        object  tree.  The  objects  making  up  the  tree are of several
        types,  and  depending on that type, they may contain pointers to
        ASCII  strings,  or  to  TEDINFO,  ICONBLK, or BITBLK structures.
        TEDINFOs  contain  further  pointers  to  strings;  BITBLKs  have
        pointers to bit images; and ICONBLKs have both.  


        P�PU�UT�TT�TI�IN�NG�G I�IT�T T�TO�O W�WO�OR�RK�K      

             The most  common  situations  requiring  you  to  understand
        resource  structures  involve  the  use of text and editable text
        objects in dialogs.  We'll look at two such techniques.  

             Often an  application requires two or more dialogs which are
        very  similar  except  for  one  or  two  title  lines.   In this
        circumstance,  you  can  save  a  good  deal of resource space by
        building only one dialog, and changing the title at run time.  

             It is  easy to go wrong with this practice, however, because
        the  obvious  tactic of using a GSTRING and writing over its text
        at  run  time  can  go wrong.  The first problem is that you must
        know  in  advance  the longest title to be used, and put a string
        that  long  into the resource. If you don't you will damage other
        objects  in  the  resource  as you copy in characters.  The other
        problem  is that a GSTRING is always drawn at the same place in a
        dialog.   If  the  length of the title changes from time to time,
        the dialog will have an unbalanced and sloppy appearance.  

             A better  way  to  do  this  is  to exploit the GTEXT object
        type,  and  the  TEDINFO structure.  The settext() routine in the
        download  shows  how.   The  parameters  provided  are  the  tree
        address,  the object number, and the 32-bit address of the string
        to  be  substituted.   For  this  to  work, the object referenced
        should  be  defined  as  a GTEXT type object.   Additionally, the
        Centered  text  type should be chosen, and the object should have
        been  "stretched"  so  that  it fills the dialog box from side to
        side.  

             In the  code, the first action is to get the OBSPEC from the
        object  which was referenced.  Since we know that the object is a
        GTEXT,  the  OBSPEC  must  point to a TEDINFO.  We need to change
        two  fields  in the TEDINFO.  The TEPTEXT field is the pointer to
        the  actual  string  to  be  displayed;  we  replace  it with the
        address  of our new string. The TETXTLEN field is loaded with the


        


        Professional GEM             Part IV                           29


        new  string's length.  Since the Centered attribute was specified
        for  the  object,  changing the TETXTLEN will cause the string to
        be correctly positioned in the middle of the dialog! 

             Editing text   also   requires   working  with  the  TEDINFO
        structure.  One  way of doing this is shown in the download.  The
        object  to  be  used  (EDITOBJ)  is  assumed  to  be  a GFTEXT or
        GFBOXTEXT.   Since  we  will  replace the initialized text at run
        time,  that  field  may be left empty when building the object in
        the RCS.  

             The basic  trick  of  this  code  is  to point the TEDINFO's
        TEPTEXT  at  a  string  which  is  defined  in  your code's local
        stack.   The  advantages  of  this  technique  are  that you save
        resource  space,  save  static  data  by  putting  the  string in
        reusable  stack memory, and automatically create a scratch string
        which may be discarded if the dialog is cancelled.  

             The text  string  shown  is  arbitrarily 41 characters long.
        You  should  give yours a length equal to the number of blanks in
        the  object's  template  field  plus  one.  Note that the code is
        shown  as a segment,  rather than a subroutine.  This is required
        because  the  text string must be allocated within the context of
        dialog  handling  routine itself,  rather than a routine which it
        calls! 

             After the  tree  address is found, the code proceeds to find
        the  TEDINFO and modify its TEPTEXT as described above.  However,
        the  length  which  is inserted into TETXTLEN must be the maximum
        string length,  including the null! 

             The final  line  of  code  inserts  a  null  into  the first
        character  of  the  uninitialized  string.   This will produce an
        empty  editing  field  when the dialog is displayed.  If there is
        an  existing  value  for   the  object,  you  should  instead use
        strcpy()  to  move  it  into text[]. Once the dialog is complete,
        you  should  check  its  final  status  as  described in the last
        article.   If  an  "OK"  button  was  clicked,  you will then use
        strcpy()  to  move  the  value  in  text[]  back  to  its  static
        location.  

             Although I  prefer  this  method  of handling editable text,
        another  method  deserves mention also.  This procedure allocates
        a  full  length  text string of blanks when creating the editable
        object  in the RCS. At  run-time, the TEPTEXT link is followed to
        find   this   string's   location   in   the  resource,  and  any
        pre-existing  value  is  copied  in. After the dialog is run, the
        resulting  value  is  copied  back  out  if  the dialog completed
        successfully.  

             Note that  in  both editing techniques a copy of the current
        string   value  is  kept  within  the  application's  data  area.


        


        Professional GEM             Part IV                           30


        Threading  the  resource  whenever  you  need to check a string's
        value is extremely wasteful.  

             One final  note on editable text objects:  GEM's editor uses
        the  commercial  at sign '@' as a "meta-character".  If it is the
        first  byte  of the initialized text, then the field is displayed
        blank  no  matter  what  follows.   This  can  be  useful, but is
        sometimes  confusing when a user in all innocence enters an @ and
        has his text disappear the next time the dialog is drawn! 


        L�LE�ET�TT�TE�ER�RS�S W�WE�E G�GE�ET�T L�LE�ET�TT�TE�ER�RS�S      

             The Feedback  section  on  ANTIC ST ONLINE is now functional
        and  is  producing  a  gratifying volume of response. A number of
        requests  were  made  for topics such as ST hardware and ST BASIC
        which  are  beyond the intended scope of this column.  These have
        been referred to ANTIC's editorial staff for action.  

             So many  good GEM questions were received that I will devote
        part   of  the  next  column  to  answering  several  of  general
        interest.   Also,  your   requests  have  resulting in scheduling
        future  columns  on  VDI  text  output  and on the principles (or
        mythology)  of  designing  GEM application interfaces. Finally, a
        tip  of  the  hat to the anonymous reader who suggested including
        the  actual  definitions  of  all  macro  symbols,  so that those
        without  the  appropriate  H files can follow along.  As a result
        of  this  suggestion,  the  definitions  for  this column and the
        previous  three  are included at the end of the download.  Future
        articles will continue this practice.  


        S�ST�TR�RA�AW�W P�PO�OL�LL�L!�!        

             I'd like  to  make  a  practice of using the Feedback to get
        your  opinions  on  the  column's  format.  As a first trial, I'd
        like  to  know your feelings about my use of "portability macros"
        in  the  sample  code.  These macros, LLGET for example, are used
        for  compatibility between 68K GEM systems like the ST, and Intel
        based  systems  like  the  IBM PC.  This may be important to many
        developers.  On  the  other  hand,  omitting them results in more
        natural  looking  C code.  For instance, in the download you will
        find  a  second  version  of  settext()  as  described above, but
        without  the portability macros.  So, I would like to know if you
        think  we  should  (A) Keep the macros - portability is important
        to  serious  developers,  (B)  Get  rid of them - who cares about
        Intel  chips  anyway,  or  (C) Who cares? I'll tally the votes in
        two weeks and announce the results here.  






        

Back to Professional_GEM