PreviousUpNext

15.4.1444  src/lib/x-kit/widget/gui/guiboss-types.pkg

## guiboss-types.pkg
#
# Private and public types for   src/lib/x-kit/widget/gui/guiboss-imp.pkg
# Support code may be found in   src/lib/x-kit/widget/gui/guiboss-types-junk.pkg
#
# This file contains a great recursive black hole:                                      # Originally this was a flock of separate files, but the natural recursive
# No type or function which enters it can ever escape.                                  # relationships proved just too difficult to avoid, so they all moved into
#                                                                                       # this file where they can recursively refer to each other to their heart's
# We use three representations for a GUI with transition diagram                        # content.  Sometimes it is best to just accept the inevitable...
#
#     Guiplan                                                                           # Public definition of GUI constructed by client and then passed to guiboss_imp via Client_To_Guiboss.start_gui or Gadget_To_Guiboss.make_popup.
#         |                                                                             #
#         v                                                                             # 
#     Guipane                                                                           # Primary representation of a running gui.  This is private to guiboss_imp and its private support packages.
#       |   ^                                                                           #
#       v   |                                                                           #
#     Guipith                                                                           # Public summary of a running gui.  Its purpose is to allow client code to morph Guipane(s) by generating a Guipith (Gadget_To_Guiboss.get_guipiths), editing it, and submitting it (Gadget_To_Guiboss.install_updated_guipiths).
#
# The application programmers passes guiboss_imp a Guiplan
# to define the GUI, which is then converted to a running
# Guipane which is then abstracted on request into a Guipith
# via Gadget_To_Guiboss.get_guipiths for application massaging and
# via Gadget_To_Guiboss.install_updated_guipiths conversion back
# into running-GUI form:  This is the main application tool for
# restructing a running GUI.
#
# In addition to defining the three GUI representations, this
# file defines most (but not all) of the major ports between
# guiboss_imp and other imps:                                                           # "gadget" refers to any of "widget", "sprite" or "object".  (Most frequently, "widget".)
#
#       Guiboss_To_Gadget                                                               # The general guiboss_imp -> gadget interface, used for forwarding user mouseclicks etc.  Most frequently used guiboss_imp -> widget_imp, but also to sprite_imp and object_imp.
#       Gadget_To_Guiboss                                                               # The general gadget -> guiboss_imp interface, used for forwarding draw operations  etc.
#       #
#       Guiboss_To_Widgetspace                                                          # The guiboss_imp -> widgetspace_imp, used to manage layout of widgets on windows.  Not yet of much importance in practice.
#       Guiboss_To_Objectspace                                                          # The guiboss_imp -> objectspace_imp, used to manage layout of objects on windows.  Not yet of much importance in practice.
#       Guiboss_To_Spritespace                                                          # The guiboss_imp -> spritespace_imp, used to manage layout of sprites on windows.  Not yet of much importance in practice.
#     
# Support code including iterators over these datastructures may be found in:
#
#     src/lib/x-kit/widget/gui/guiboss-types-junk.pkg
#
# See also:
#
#     src/lib/x-kit/widget/edit/millboss-types.pkg

# Compiled by:
#     src/lib/x-kit/widget/xkit-widget.sublib


stipulate
    include package   threadkit;                                                        # threadkit                             is from   src/lib/src/lib/thread-kit/src/core-thread-kit/threadkit.pkg
    #
    package g2d =  geometry2d;                                                          # geometry2d                            is from   src/lib/std/2d/geometry2d.pkg
    package g2j =  geometry2d_junk;                                                     # geometry2d_junk                       is from   src/lib/std/2d/geometry2d-junk.pkg

    package wt  =  widget_theme;                                                        # widget_theme                          is from   src/lib/x-kit/widget/theme/widget/widget-theme.pkg
    package evt =  gui_event_types;                                                     # gui_event_types                       is from   src/lib/x-kit/widget/gui/gui-event-types.pkg

    package o2c =  object_to_objectspace;                                               # object_to_objectspace                 is from   src/lib/x-kit/widget/space/object/object-to-objectspace.pkg
    package c2o =  objectspace_to_object;                                               # objectspace_to_object                 is from   src/lib/x-kit/widget/space/object/objectspace-to-object.pkg

    package s2b =  sprite_to_spritespace;                                               # sprite_to_spritespace                 is from   src/lib/x-kit/widget/space/sprite/sprite-to-spritespace.pkg
    package b2s =  spritespace_to_sprite;                                               # spritespace_to_sprite                 is from   src/lib/x-kit/widget/space/sprite/spritespace-to-sprite.pkg

    package g2p =  gadget_to_pixmap;                                                    # gadget_to_pixmap                      is from   src/lib/x-kit/widget/theme/gadget-to-pixmap.pkg

    package idm =  id_map;                                                              # id_map                                is from   src/lib/src/id-map.pkg
    package im  =  int_red_black_map;                                                   # int_red_black_map                     is from   src/lib/src/int-red-black-map.pkg
    package sm  =  string_map;                                                          # string_map                            is from   src/lib/src/string-map.pkg

    package gtg =  guiboss_to_guishim;                                                  # guiboss_to_guishim                    is from   src/lib/x-kit/widget/theme/guiboss-to-guishim.pkg

    package pp  =  standard_prettyprinter;                                              # standard_prettyprinter                is from   src/lib/prettyprint/big/src/standard-prettyprinter.pkg

    package lms =  list_mergesort;                                                      # list_mergesort                        is from   src/lib/src/list-mergesort.pkg

    package err =  compiler::error_message;                                             # compiler                              is from   src/lib/core/compiler/compiler.pkg
                                                                                        # error_message                         is from   src/lib/compiler/front/basics/errormsg/error-message.pkg

    package gd  =  gui_displaylist;                                                     # gui_displaylist                       is from   src/lib/x-kit/widget/theme/gui-displaylist.pkg

    package a2c =  app_to_compileimp;                                                   # app_to_compileimp                     is from   src/lib/x-kit/widget/edit/app-to-compileimp.pkg

    nb = log::note_on_stderr;                                                           # log                                   is from   src/lib/std/src/log.pkg

herein

    package guiboss_types
    {

        # Some abbreviations because line length was getting out of hand below:
        #
        Once(X) = Oneshot_Maildrop(X);


        Site = Ref( g2d::Box );                                                                                         # Pixel-rectangle assigned to the widget, in backing-pixmap coordinates.

        #########################################################################################
        ### preliminary types

        Scroller                                                                                                        # Client controller for scrolling a viewable around in a scrollport.
          =
          { get_scrollport_upperleft: Void -> g2d::Point,
            set_scrollport_upperleft: g2d::Point -> Void                                                                # Shouldn't this be 'pass_scrollport_upperleft'?
          };

        Scroller_Callback                                                                                               # Used in Gp_Widget_Type.SCROLLPORT     in   src/lib/x-kit/widget/gui/guiboss-types.pkg
          =
          Null_Or( Scroller ) -> Void;


        Tab_Picker                                                                                                      # Client controller for which tab is visible in given tabport.
          =
          { get_active_tab: Void -> Int,
            set_active_tab: Int -> Void
          };

        Tab_Picker_Callback                                                                                             # Used in Gp_Widget_Type.TABBED_VIEWS   in   src/lib/x-kit/widget/gui/guiboss-types.pkg
          =
          Null_Or( Tab_Picker ) -> Void;


        #########################################################################################
        ### Preliminary running-gui types

        # Storing instances of
        #     guiboss_to_spritespace, 
        #     guiboss_to_objectspace, 
        # or  guiboss_to_widgetspace
        # directly in Guipane leads to package circularity,
        # so instead we store their integer id here, and
        # in guiboss-imp.pkg look them up as needed in
        # (respectively):       
        #     spritespaces
        #     objectspaces
        #     widgetspaces
        # 
        Spritespace_Id = Id;
        Objectspace_Id = Id;
        Widgetspace_Id = Id;



        #########################################################################################
        ### gadget-to-guiboss types


        Gadget_Mode                                                                                                     # We use this mostly to control how a widget draws itself.
          =                                                                                                             # To avoid a package cycle this def is duplicated in   src/lib/x-kit/widget/theme/widget/widget-theme.pkg
          {                                                                                                             # We probably should find/make another home for this def. XXX SUCKO FIXME
            is_active:                          Bool,                                                                   # An inactive gadget is passed no user input. Inactive widgets are typically drawn "grayed-out".
            has_mouse_focus:                    Bool,                                                                   # A widget which has the mouse cursor on it may want to draw itself brigher or such.
            has_keyboard_focus:                 Bool                                                                    # A widget which has the keyboard focus will often      draw a black outline around its text-entry rectangle.
          };


        Wakeup_Arg
          =
          { frame_number:                       Int                                                                     # 1,2,3,... Purely for convenience of widget, guiboss-imp makes no use of this.
          };

        Wake_Me_Option
          #
          = AT_FRAME_N                          Null_Or( (Int,   Wakeup_Arg -> Void) )                                  # Call gadget.wakeup once, during frame N, and pass given arg in call. NULL arg turns this wakeup off.
          | EVERY_N_FRAMES                      Null_Or( (Int,   Wakeup_Arg -> Void) )                                  # Call gadget.wakeup every N frames,       and pass given arg in call. NULL arg turns this wakeup off.
#
# I'm too lazy to implement these two right
# now but I expect we'll want them eventually:   -- CrT 2015-01-05      

#         | IN_S_SECONDS                        Null_Or( (Float, Wakeup_Arg -> Void) )                                  # Call gadget.wakeup once after s seconds, and pass given arg in call. NULL arg turns this wakeup off.
#         | EVERY_S_SECONDS                     Null_Or( (Float, Wakeup_Arg -> Void) )                                  # Call gadget.wakeup every      s seconds, and pass given arg in call. NULL arg turns this wakeup off.
          ;



        Widget_Layout_Hint
          =
          { pixels_high_min:            Int,                                                                            # Minimum            vertical   pixels to allocate for this widget.      Used in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
            pixels_wide_min:            Int,                                                                            # Minimum            horizontal pixels to allocate for this widget.      Used in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
            #
            pixels_high_cut:            Float,                                                                          # Share of remaining vertical   pixels to allocate to  this widget.      Used in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
            pixels_wide_cut:            Float                                                                           # Share of remaining horizontal pixels to allocate to  this widget.      Used in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
          };

        default_widget_layout_hint
          =
          { pixels_high_min =>          0,
            pixels_wide_min =>          0,
            #
            pixels_high_cut =>          1.0,
            pixels_wide_cut =>          1.0
          };



        Frame_Indent_Hint                                                                                               # Used to format RG_FRAME nodes in src/lib/x-kit/widget/gui/guiboss-widget-layout.pkg
          =                                                                                                             # I expect to use this facility very rarely, so I'm favoring verbose-and-clear here in choice of fieldnames:
          { pixels_for_top_of_frame:    Int,                                                                            # Vertical   pixels to allocate for top    side of frame.
            pixels_for_bottom_of_frame: Int,                                                                            # Vertical   pixels to allocate for bottom side of frame.
            #
            pixels_for_left_of_frame:   Int,                                                                            # Horizontal pixels to allocate for left   side of frame.
            pixels_for_right_of_frame:  Int                                                                             # Horizontal pixels to allocate for right  side of frame.
          };

        default_frame_indent_hint
          =
          { pixels_for_top_of_frame     =>      9,
            pixels_for_bottom_of_frame  =>      9,
            #
            pixels_for_left_of_frame    =>      9,
            pixels_for_right_of_frame   =>      9
          };



        #########################################################################################
        ### Guiplan datatypes
        ###
        ### A Guiplan is a public definition of GUI constructed by client and then passed
        ### to guiboss_imp via Client_To_Guiboss.start_gui or Gadget_To_Guiboss.make_popup.

        Gp_Sprite                                                                                                       # Nomenclature: "Gp_" and "GP_" are mnemonic for "Gui Plan".
            #
            = SPRITE            Sprite_Start_Fn                                                                         # Intended to support 2-D animated pinball sprites (Pac-man type stuff) initially, 3-D OpenGL animated avatars eventually.  Not yet supported.

        also
        Gp_Object                                                                                                       # Intended to support overlapping non-rectangular non-tiled stuff like multiple x-y curves graphed in 2D with mouse-interaction support.   Not yet supported.
            #
            = WIDGETSPACE       Gp_Widgetspace
            #
            | OBJECT            Object_Start_Fn

        also
        Gp_Widget_Type                                                                                                  # "_Type" because for consistency we need "Gp_Widget" for WIDGET.
            #
            = ROW               Gp_Row                                                                                  # Horizontal row of widgets. A ROW of less than two widgets may be optimized away.
            | COL               Gp_Col                                                                                  # Vertical   col of widgets. A COL of less than two widgets may be optimized away.
            | GRID              Gp_Grid                                                                                 # Grid of widgets; outer list goes by rows, inner lists go by columns.  A GRID of less than two widgets may be optimized away.
            | MARK              Gp_Mark                                                                                 # Single widget whose 'id' field provides a way to identify a point in a guiplan. These are never optimized away.
            #
            | ROW'              Gp_Row'                                                                                 # Same as ROW  except 'id' field is explicitly provided instead of implicitly generated.
            | COL'              Gp_Col'                                                                                 # Same as COL  except 'id' field is explicitly provided instead of implicitly generated.
            | GRID'             Gp_Grid'                                                                                # Same as GRID except 'id' field is explicitly provided instead of implicitly generated.
            | MARK'             Gp_Mark'                                                                                # Same as MARK except 'id' field is explicitly provided instead of implicitly generated.
            #   
            | SCROLLPORT        Gp_Scrollport                                                                           # Support for scrollable viewports holding arbitrary widgets.
            | TABPORT           Gp_Tabport                                                                              # Support for tab-selectable ports holding arbitrary widgets on each tab.

            | FRAME             Gp_Frame                                                                                # For drawing a customizable frame around a widget subtree.

            | WIDGET            Gp_Widget                                                                               # Actual leaf widgets like buttons and text-entry fields.  These values are created by   make_widget_start_fn   in   src/lib/x-kit/widget/xkit/theme/widget/default/look/widget-imp.pkg 
            #
            | OBJECTSPACE       Gp_Objectspace                                                                          # Intended to support free-form (non-tiled) layout of bubble-and-arrow graphs, widgets etc.  Also drawing and painting.  Not yet supported.
            | SPRITESPACE       Gp_Spritespace                                                                          # Intended to support 2-D pinball animation initially and 3-D OpenGL animation eventually.                               Not yet supported.
            #
            | NULL_WIDGET                                                                                               # Note[1]


        also
        Frame_Option
            #
            = FRAME_WIDGET      Gp_Widget_Type



        #########################################################################################
        ### running-gui datatypes
        ###
        ### A Guipane is the primary representation of a running gui.
        ### This is private to guiboss_imp and its private support packages.

                                                                                                                        # Nomenclature: "Rg_" and "RG_" are mnemonic for "Running Gui".
        also
        Rg_Sprite_Type                                                                                                  # "_Type" because for consistency we need "Rg_Sprite" for RG_SPRITE.
            #                                                                                                           # This datatype has only one alternative, but will presumably eventually have multiple variants just like Rg_Object_Type and Rg_Widget_Type, so converting it to a simple type is probably a bad idea.
            = RG_SPRITE       Rg_Sprite
                        
        also
        Rg_Object_Type                                                                                                  # "_Type" because for consistency we need "Rg_Object" for RG_OBJECT.
            #
            = RG_WIDGETSPACE    Rg_Widgetspace                                                                          # A widget space embedded in a object, to allow all widgetspace widgets to be used also on a object.
            | RG_OBJECT         Rg_Object
                        
        also
        Rg_Widget_Type                                                                                                  # "_Type" because for consistency we need "Rg_Widget" for RG_WIDGET.
            #
            = RG_ROW              Rg_Row                                                                                # A horizontal  row  of widgets.
            | RG_COL              Rg_Col                                                                                # A vertical    col  of widgets.
            | RG_GRID             Rg_Grid                                                                               # A rectangular grid of widgets.
            | RG_MARK             Rg_Mark                                                                               # A single              widget. Used to mark a spot in widget-tree for later reference, typically between  Gadget_To_Guiboss get_guipiths() and install_updated_guipiths() calls.

| RG_CUSTOM_LAYOUT here might be a good idea by and by. Semantics TBD

            | RG_SCROLLPORT       Rg_Scrollport                                                                         # Here we provide support for widgets visible through a scrollable scrollport.  Actually providing scrollbars happens at a higher level; here we handle pixmap state maintenance and redraw support.
            | RG_TABPORT          Rg_Tabport                                                                            # Here we provide support for selection between alternate views in    tabport.  Actually providing tabs       happens at a higher level; here we handle pixmap state maintenance and redraw support.
            #
            | RG_FRAME            Rg_Frame
            | RG_WIDGET           Rg_Widget                                                                             # An actual leaf widget like an arrowbutton or label or text-entry box. These are all customizations of src/lib/x-kit/widget/xkit/theme/widget/default/look/widget-imp.pkg
            #
            | RG_OBJECTSPACE      Rg_Objectspace                                                                        # This is intended to allow editing of bubble-and-arrow graphs, arbitrary placement of widgets etc. Not yet supported.
            | RG_SPRITESPACE      Rg_Spritespace                                                                        # This is intended to allow 2-D pinball animation (and eventually 3-D OpenGL animation).            Not yet supported.
            #
            | RG_NULL_WIDGET                                                                                            # We need this because Guipane requires an Rg_Widget_Type value, and sometimes we may not have anything else.


        #########################################################################################
        ### guiboss-to-widgetspace datatypes
        #
        # Communication from    src/lib/x-kit/widget/gui/guiboss-imp.pkg
        # to                    src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg

        also
        Widgetspace_Option
            #
            = PS_MICROTHREAD_NAME       String                                                                          # 
            | PS_ID                     Id                                                                              # Unique ID for imp, issued by issue_unique_id::issue_unique_id().
            | PS_CALLBACK               Guiboss_To_Widgetspace -> Void



        #########################################################################################
        ### guiboss-to-objectpace datatypes
        #
        # Communication from    src/lib/x-kit/widget/gui/guiboss-imp.pkg
        # to                    src/lib/x-kit/widget/space/object/objectspace-imp.pkg

        also
        Objectspace_Option
          #
          = CS_MICROTHREAD_NAME         String                                                                          # 
          | CS_ID                       Id                                                                              # Unique ID for imp, issued by issue_unique_id::issue_unique_id().
          | CS_OBJECTSPACE_CALLBACK     Guiboss_To_Objectspace -> Void


        #########################################################################################
        ### guiboss-to-spritespace datatypes
        #
        # Communication from    src/lib/x-kit/widget/gui/guiboss-imp.pkg
        # to                    src/lib/x-kit/widget/space/sprite/spritespace-imp.pkg

        also
        Spritespace_Option
          #
          = OS_MICROTHREAD_NAME         String                                                                          # 
          | OS_ID                       Id                                                                              # Unique ID for imp, issued by issue_unique_id::issue_unique_id().
          | OS_SPRITESPACE_CALLBACK     Guiboss_To_Spritespace -> Void


        #########################################################################################
        ### gadget-to-guiboss datatypes





        #########################################################################################
        ### guiboss-to-gadget datatypes

        also
        Gadget_Transit                                                                                                  # This protocol is intended to support (e.g.) highlighting a gadget while the mouse is over it.
            #                                                                                                           # The intended semantics here is that:
            = CAME                                                                                                      #  o  A widget should always see an  CAME before anything else when the mouse cursor enters its space.   CAME events are NOT sent during a drag. A MOVE is always sent immediately after an CAME, with the same mouse coordinate.
            | MOVE                                                                                                      #  o  A widget can see any number of MOVE events between a CAME and LEFT; all will be in its space.      MOVE events are NOT sent during a drag.
            | LEFT                                                                                                      #  o  A widget should always see a   LEFT after  everything else when the mouse cursor exits  its space. LEFT events are NOT sent during a drag.
                                                                                                                        #  o  Thus, a widget is not guaranteed to see an CAME every time the mouse cursor enters it (due to drag exception). But if it sees anything at all, an CAME will be first, and a LEFT will be last.

        also
        Drag_Phase                                                                                                      # This protocol is intended to support dragging a slider or scrollbar thumb.
            #                                                                                                           # The intended semantics here is that:
            = OPEN                                                                                                      #  o  Every drag sequence begins with exactly one OPEN.
            | DRAG                                                                                                      #  o  Every drag sequence has zero or more        DRAG phases.
            | DONE                                                                                                      #  o  Every drag sequence ends   with exactly one DONE.
                                                                                                                        # 

        also
        Key_Event                                                                                                       # This protocol is intended to support keyboard text entry.
            #
            = KEY_PRESS
            | KEY_RELEASE

        also
        Mousebutton_Event                                                                                               # This protocol is intended to support mouse button processing.  Double-clicks are not supported here.  I dislike them because they inherently add latency, and half of GUI framework design is about minimizing latency.
            #
            = MOUSEBUTTON_PRESS
            | MOUSEBUTTON_RELEASE


        #########################################################################################
        ### Sprite_Start_Fn datatype

        also
        Sprite_Start_Fn                                                                                                 # Converting this to a simple type does not work due to mutual recursion between Sprite_Start_Fn and Sprite_Imports.
          =
          SPRITE_START_FN  (Sprite_Imports -> Sprite_Exports)



        #########################################################################################
        ### Object_Start_Fn datatype

        also
        Object_Start_Fn                                                                                                 # Converting this to a simple type does not work due to mutual recursion between Object_Start_Fn and Object_Imports.
          =
          OBJECT_START_FN  (Object_Imports -> Object_Exports)



        #########################################################################################
        ### Widget_Start_Fn datatype

        also    
        Widget_Start_Fn                                                                                                 # Converting this to a simple type does not work due to mutual recursion between Widget_Start_Fn and Widget_Imports.
          =                                                                                                             # This type is the critical interface between the widget world and src/lib/x-kit/widget/gui/guiboss-imp.pkg
          WIDGET_START_FN  (Widget_Imports -> Widget_Exports)                                                           # In particular quiplan__to__guipane() in guiboss_imp calls the widget_start_fn built in   src/lib/x-kit/widget/xkit/theme/widget/default/look/widget-imp.pkg
              


        #########################################################################################
        ### Subwindow_Or_View datatype                                                                                  # This is used mainly for the home of a gadget, since a gadget may live either directly on a subwindow or else in a scrollport visible ultimately on a subwindow.
                                                                                                                        # 
        also                                                                                                            # 
        Subwindow_Or_View                                                                                               # 
          #                                                                                                             # 
          = SUBWINDOW_INFO  Subwindow_Info                                                                              # 
          #     
          | SCROLLABLE_INFO Rg_Scrollport                                                                               
          | TABBABLE_INFO   Tabbable_Info                                                                               


        also                                                                                                            # 
        Subwindow_Data                                                                                                  # This is used in Hostwindow_Info and Guipane because they are always located directly on a subwindow, not on a scrollport within a subwindow.
          #                                                                                                             # Unfortunately we can NOT just replace Subwindow_Data everywhere by Subwindow_Info because then Subwindow_Info contains fields of type Subwindow_Info, which is not allowed by the type system.
          = SUBWINDOW_DATA  Subwindow_Info                                                                              # 


        #########################################################################################
        ### Guipith datatypes                                                                                           # Nomenclature: "Xi_" and "XI_" are mnemonic for "eXport/Import".
        ###
        ### A Guipith is a public summary of a running gui.  Its purpose is to
        ### allow client code to morph Guipane(s) by generating Guipith
        ### summaries of running Guipanes via Gadget_To_Guiboss.get_guipiths,
        ### editing them (often via the guiboss_types_junk::guipith_map                                                 # guiboss_types_junk    is from   src/lib/x-kit/widget/gui/guiboss-types-junk.pkg
        ### facility), and submitting them back to guiboss_imp via
        ### Gadget_To_Guiboss.install_updated_guipiths, which which converts
        ### them back into a full Guipanes using information from the
        ### pre-existing Guipanes and then installs ttem as the new running
        ### Guipanes, doing re-sites + re-draws as needed to appropriately
        ### update the visible screen image of the affected running GUIs.
        ###
        ### This facility is motivated by a desire to allow (for example)
        ### emacs-style editors to add new (sub)windows onto new files without
        ### having to completely shut down the existing GUI, together with a
        ### desire to keep the Guipane types private to guiboss_imp for
        ### implementation hiding / separation of concerns, and also to
        ### minimize the amount of validation needed in
        ###     Gadget_To_Guiboss.install_updated_guipiths
        ### by minimizing the amount of superfluous information passed
        ### to install_updated_guipiths.

                                                                                                                        # 
        also
        Xi_Sprite                                                                                                       # This datatype has only one alternative, but will presumably eventually have multiple variants just like Rg_Object_Type and Rg_Widget_Type, so converting it to a simple type is probably a bad idea.
            #
            = XI_SPRITE       {
                                sprite_id:              Id
                              }
                        
        also
        Xi_Object
            #
            = XI_WIDGETSPACE  { widgetspace_id:         Id,                                                             # 
                                xi_widget:              Xi_Widget_Type
                              }
            | XI_OBJECT       {
                                object_id:              Id
                              }

        also
        Xi_Widget_Type                                                                                                  # "_Type" because for consistency we need "Xi_Widget" for XI_WIDGET.
            #
            = XI_ROW                Xi_Row
            | XI_COL                Xi_Col
            | XI_GRID               Xi_Grid                                                                             # A rectangular grid of widget widgets.
            | XI_MARK               Xi_Mark                                                                             # A single                     widget.
            #
            | XI_SCROLLPORT         Xi_Scrollport                                                                       # Here we provide support for widgets visible through a scrollable scrollport.  Actually providing scrollbars happens at a higher level; here we handle pixmap state maintenance and redraw support.
            | XI_TABPORT            Xi_Tabport                                                                          # Here we provide support for selection between alternate views in scrollport.  Actually providing tabs happens at a higher level; here we handle pixmap state maintenance and redraw support.
            #
            | XI_FRAME              Xi_Frame
            | XI_WIDGET             Xi_Widget                                                                           # An actual leaf widget like an arrowbutton or label or text-entry box. These are all customizations of src/lib/x-kit/widget/xkit/theme/widget/default/look/widget-imp.pkg
            #
            | XI_OBJECTSPACE        Xi_Objectspace
            | XI_SPRITESPACE        Xi_Spritespace
            #
            | XI_NULL_WIDGET                                                                                            # We need this because Guipane requires an Rg_Widget_Type value, and sometimes we may not have anything else.
            | XI_GUIPLAN            Guiplan                                                                             # To allow starting up new widgets as part of a running-gui update.


        also                                                                                                            # 
        Xi_Subwindow_Or_View                                                                                            # 
          #                                                                                                             # 
          = XI_SUBWINDOW_INFO  Xi_Subwindow_Info                                                                        # 
          #     
          | XI_SCROLLABLE_INFO                                                                                          

        also
        Xi_Subwindow_Data
          #
          = XI_SUBWINDOW_DATA  Xi_Subwindow_Info


        withtype
        Keystroke_Info
          =
          { key_event:              Key_Event,                                                                          # KEY_PRESS or KEY_RELEASE.
            keycode:                evt::Keycode,                                                                       # Keyboard key just pressed/released.
            keysym:                 evt::Keysym,                                                                        # Keysym  of the key.  This is not present in the X version of Key_Kevtinfo; added for widget-code convenience.
            keystring:              String,                                                                             # Ascii  for the key.  This is not present in the X version of Key_Kevtinfo; added for widget-code convenience.
            keychar:                Char,                                                                               # First char of 'string' ('\0' if string-length != 1).
            modifier_keys_state:    evt::Modifier_Keys_State,                                                           # State of the modifier keys (shift, ctrl...).
            mousebuttons_state:     evt::Mousebuttons_State                                                             # State of mouse buttons as a bool record.
          }

        also
        Note_Mouse_Drag_Event_Arg
          =
          { phase:                  Drag_Phase,                                                                         # We guarantee that the gadget that sees the OPEN (downclick) for a drag also sees all the DRAGs and the DONE for that drag, and that no other gadget sees drag or transit events during that time period.
            button:                 evt::Mousebutton,                                                                   # Mouse button lack clicked down. Range is 1-13 or more.  Typically 1=left, 2=middle, 3=right, 4=mousewheel-forward, 5=mousewheel-back.
            modifier_keys_state:    evt::Modifier_Keys_State,                                                           # State of the modifier keys (shift, ctrl...).
            mousebuttons_state:     evt::Mousebuttons_State,                                                            # State of mouse buttons as a bool record.
            event_point:            g2d::Point,                                                                         # 'event_point' is the current   point the window's coordinate system.
            start_point:            g2d::Point,                                                                         # 'start_point' is the downclick point the window's coordinate system.
            last_point:             g2d::Point,                                                                         # 'last_point'  is the event_point from the preceding ntoe_mouse_drag_event call.
            site:                   g2d::Box,                                                                           # Gadget's assigned area in window coordinates.
            theme:                  wt::Widget_Theme                                                                    #
          }                                                                                                             # DONE is sent when last mousebutton is released, no matter where that happnes.

        also
        Note_Mouse_Transit_Arg
          =
          { transit:                Gadget_Transit,
            modifier_keys_state:  evt::Modifier_Keys_State,                                                             # State of the modifier keys (shift, ctrl...).
            event_point:            g2d::Point,                                                                         # 'event_point'  is the click point the window's coordinate system.
            site:                   g2d::Box,                                                                           # Gadget's assigned area in window coordinates.
            theme:                  wt::Widget_Theme                                                                    #
          }                                                                                                             # CAME/MOVE/LEFT are never sent during drag operations.

        also
        Note_Key_Event_Arg
          =
          { keystroke:              Keystroke_Info,
            site:                   g2d::Box,                                                                           # Gadget's assigned area in window coordinates.
            theme:                  wt::Widget_Theme
          }

        also
        Note_Mousebutton_Event_Arg
          =
          { mousebutton_event:      Mousebutton_Event,                                                                  # MOUSEBUTTON_PRESS or MOUSEBUTTON_RELEASE. These go to the gadget under the mouse pointer, hence a gadget may not see both if the pointer moves between them. Use note_mouse_drag_event if this is a problem.
            mouse_button:           evt::Mousebutton,                                                                   # Mouse button just clicked down. Range is 1-13 or more.  Typically 1=left, 2=middle, 3=right, 4=mousewheel-forward, 5=mousewheel-back.
            modifier_keys_state:    evt::Modifier_Keys_State,                                                           # State of the modifier keys (shift, ctrl...).
            mousebuttons_state:     evt::Mousebuttons_State,                                                            # State of mouse buttons as a bool record, BEFORE THE EVENT -- so a MOUSEBUTTON_RLEASE will always show at least one button down.
            event_point:            g2d::Point,                                                                         # 'point'  is the click point the window's coordinate system.
            site:                   g2d::Box,                                                                           # Gadget's assigned area in window coordinates.
            theme:                  wt::Widget_Theme                                                                    #
          }                                                                                                             # Normally MOUSEBUTTON_PRESS or MOUSEBUTTON_RELEASE are sent if they occur within the gadget's assigned site.

        also
        Xi_Row                                                                                                          # Used in XI_ROW
          =
          {                                                                                                             # A horizontal row of widget widgets.
            id:                         Id,
            widgets:                    List( Xi_Widget_Type ),                                                         # The list of widgets to be laid out and displayed in this row.
            first_cut:                  Null_Or( Float )                                                                # Normally NULL; if non-NULL (and at least two widgets in row/col), gives fraction of row/col space to allocate to first widget, overriding the regular bottom-up sizing mechanism.
          }

        also
        Xi_Col = Xi_Row

        also
        Xi_Grid                                                                                                         # Used in XI_GRID
          =
          { id:                         Id,                                                                             # A grid of widgets.
            widgets:                    List( List( Xi_Widget_Type ) )
          }

        also
        Xi_Mark                                                                                                         # Used inX I_GRID
          =
          { id:                         Id,                                                                             # A widget.
            doc:                        String,
            widget:                     Xi_Widget_Type
          }

        also
        Xi_Scrollport                                                                                                   # 
          =
          { id:                         Id,                                                                             #  
            xi_widget:                  Xi_Widget_Type                                                                  # Tree of widgets partially visible in scrollport.
          }

        also
        Xi_Tabport                                                                                                      # 
          =
          { id:                         Id,                                                                             # 
            widgets:                    List( Xi_Widget_Type )
          }

        also
        Xi_Frame
          =
          { id:                         Id,
            frame_widget:               Xi_Widget_Type,                                                                 # Widget which will draw the frame surround.
            widget:                     Xi_Widget_Type                                                                  # Widget-tree to draw surrounded by frame.
          }

        also
        Xi_Widget                                                                                                       # An actual leaf widget like an arrowbutton or label or text-entry box. These are all customizations of src/lib/x-kit/widget/xkit/theme/widget/default/look/widget-imp.pkg
          =                                                                                                             # Used in XI_WIDGET
          { widget_id:                  Id,
            widget_layout_hint:         Widget_Layout_Hint,
            doc:                        String                                                                          # Debugging support: Allow XI_WIDGETs to be distinguishable for debug-display purposes.
          }

        also
        Xi_Guipane
          =
          { id:                         Id,
            guiboss_to_widgetspace_id:  Id,
            xi_widget:                  Xi_Widget_Type                                                                  # The widget (or more commonly, tree of widgets) managed by the gui-tree's toplevel widgetspace-imp.
          }

        also
        Xi_Subwindow_Info                                                                                               # Used in SUBWINDOW_INFO.
          =
          { id:                         Id,                                                                             # From (*Subwindow_Info.pixmap).id
            guipane:                    Null_Or( Xi_Guipane ),
            popups:                     List(Xi_Subwindow_Data)                                                         # 
          }

        also
        Xi_Hostwindow_Info
          =
          { id:                         Id,                                                                             # From hostwindow_info.guiboss_to_hostwindow.id
            subwindow_info:             Null_Or( Xi_Subwindow_Data )
          }

        also
        Xi_Objectspace
          =
          { guiboss_to_objectspace_id:  Id,     
            xi_objects:                 List(Xi_Object)
          }

        also
        Xi_Spritespace
          =
          { guiboss_to_spritespace_id:  Id,     
            xi_sprites:                 List(Xi_Sprite)
          }


        #########################################################################################
        ### More Subwindow_Or_View types

        also      Spritespace_Arg =  List(Spritespace_Option)                                                           # Currently no required component.
        also      Objectspace_Arg =  List(Objectspace_Option)                                                           # Currently no required component.
        also      Widgetspace_Arg =  List(Widgetspace_Option)                                                           # Currently no required component.

        also
        Space_To_Gui                                                                                                    # This may eventually need to move to   src/lib/x-kit/widget/gui/guiboss-types.pkg
          =                                                                                                             # so it can be mutually recursive with everything else there, but for the moment it is working as a standalone definition.
          { id:                         Id,                                                                             # Unique id to facilitate storing space_to_gui ports in indexed datastructures like red-black trees.
            #
            note_widget_site:         { id:                     Id,
                                        site:                   g2d::Box,
                                        subwindow_or_view:      Subwindow_Or_View
                                      }
                                      -> Void
          }

        also
        Client_To_Guiwindow
          =
          { id:                         Id,                                                                             # Unique id to facilitate storing guiboss instances in indexed datastructures like red-black trees.
            kill_gui:                   Void -> Void                                                                    # Stop gui and recycle  its state and Xserver-side resources.  This invokes exactly the same code as Gadget_To_Guiboss.kill_popup.
          }

        also    Guiplan =  Gp_Widget_Type                                                                               # Synonym for improved readability.
#       also    Guipith =  Xi_Widget_Type                                                                               # Synonym for improved readability.

        also
        Make_Popup_Fn                                                                                                   # Create popup pane on given window in given site.  Given site is adjusted to lie entirely within parent (if necessary) and returned.
          =
          (
            g2d::Box,                                                                                                   # Requested site for popup, in basewindow coordinates.
            Guiplan                                                                                                     # 
          )
          ->
          (
            g2d::Box,                                                                                                   # Actual site for popup, in basewindow coordinates. It differs from requested site only if requested site does not lie entirely within basewindow site.
            Client_To_Guiwindow
          )

        also
        Guiboss_To_Objectspace                                                                                          # 
            =
              { id:                     Id,                                                                             # Unique id to facilitate storing guiboss_to_objectspace instances in indexed datastructures like red-black trees.
                #
                pass_something:         Replyqueue -> (Int -> Void) -> Void,
                do_something:           Int  -> Void,
                die:                    Void -> Void                                                                    # Equivalent to firing end_gun', but affects only one objectspace imp.
              }

        also
        Guiboss_To_Spritespace                                                                                          # 
            =
              { id:                     Id,                                                                             # Unique id to facilitate storing guiboss_to_spritespace instances in indexed datastructures like red-black trees.
                #
                pass_something:         Replyqueue -> (Int -> Void) -> Void,
                do_something:           Int  -> Void,
                die:                    Void -> Void                                                                    # Equivalent to firing end_gun', but affects only one spritespace imp.
              }

        also
        Guiboss_To_Widgetspace                                                                                          # 
          =
            { id:                       Id,                                                                             # Unique id to facilitate storing guiboss_to_widgetspace instances in indexed datastructures like red-black trees.
              #
              pass_something:           Replyqueue -> (Int -> Void) -> Void,

              do_something:             Int  -> Void,
              die:                      Void -> Void                                                                    # Equivalent to firing end_gun', but affects only one widgetspace imp.
            }

        also
        Gadget_To_Guiboss                                                                                               # 
            =
              { id:                             Id,                                                                     # Unique id to facilitate storing Gadget_To_Guiboss ports in indexed datastructures like red-black trees.
                #
                needs_redraw_gadget_request:    Id      -> Void,                                                        # Inform guiboss_imp that the gadget's appearance needs refreshing. Without this, it may not get a redraw_gadget_request call.
                                                                                                                        # This should be called any time the gadget's state changes in a way that would visibly affect its appearance. See Note[3] in   src/lib/x-kit/widget/gui/guiboss-imp.pkg
                                                                                                                        # 
                redraw_gadget                                                                                           # Update gadget appearance in response to a guiboss_to_gadget.redraw_gadget_request {...} call.
                  :                                                                                                     # This can also be called spontaneously in the absence of a redraw_gadget_request call,
                  { id:                         Id,                                                                     # but if the gadget state gets updated frequently (say, 10,000 times/sec) this may overwhelm the display subsystem.
                    site:                       g2d::Box,                                                               # This should be the 'site' value handed to Guiboss_To_Gadget.redraw_gadget_request: guiboss_imp uses this value to detect (and discard) stale redraw_gadget messages.
                    displaylist:                gd::Gui_Displaylist,
                    point_in_gadget:            Null_Or( g2d::Point -> Bool )                                           # Optional fn to decide if a mouseclick actually hit the gadget itself, or just somewhere near it in the screenspace assigned to it.
                  }
                  ->
                  Void,

                request_keyboard_focus:         Id -> Void,                                                             # This should result in us getting Guiboss_To_Gadget.note_keyboard_focus(TRUE)  from  src/lib/x-kit/widget/gui/guiboss-imp.pkg
                release_keyboard_focus:         Id -> Void,                                                             # This should result in us getting Guiboss_To_Gadget.note_keyboard_focus(FALSE) from  src/lib/x-kit/widget/gui/guiboss-imp.pkg

                note_changed_gadget_activity:   { id: Id, is_active:  Bool } -> Void,                                   # is_active is FALSE if gadget should be insensitive to input and perhaps drawn grayed-out.  Controlled by application logic.

                wake_me:                        { id: Id, options:      List(Wake_Me_Option) } -> Void,                 # Used to schedule guiboss_to_gadget.wakeup calls.

                make_popup:                     Make_Popup_Fn,                                                          # Create popup pane at given site.  Given site is adjusted to lie entirely within parent (if necessary) and returned.
                kill_popup:                     Void -> Void,                                                           # Stop guipane containing this gadget (and all its descendent popups) and recycle  its state and Xserver-side resources.  This invokes exactly the same code as Client_To_Guiwindow.kill_gui.

                note_global:                    Crypt  -> Void,                                                         # These three implement a general registry which gadget and app code can use as a blackboard for communication and coordination.
                find_global:                    String -> Null_Or(Crypt),                                               # 'String' should be the Crypt.type field for the desired Crypt.
                drop_global:                    String -> Void,                                                         # 'String' should be the Crypt.type field for the desired Crypt.  This is a no-op if no such Crypt is registered.

                set_guipane_upperleft:         (Id,   g2d::Point)   -> Void,                                            # Ask guiboss-imp to  change  value of Subwindow_Info.upperleft for guipane containing gadget.
                pass_guipane_upperleft:         Id                                                                      # Ask guiboss-imp to  pass    value of Subwindow_Info.upperleft for guipane containing gadget to given handler.
                                                 -> Replyqueue                                                          #
                                                 -> (g2d::Point -> Void)                                                #
                                                 -> Void,                                                               # 

                set_guipane_size:              (Id,   g2d::Size)   -> Void,                                             # Ask guiboss-imp to  change  value of Subwindow_Info.size for guipane containing gadget.
                pass_guipane_size:              Id                                                                      # Ask guiboss-imp to  pass    value of Subwindow_Info.size for guipane containing gadget to given handler.
                                                 -> Replyqueue                                                          #
                                                 -> (g2d::Size -> Void)                                                 #
                                                 -> Void,                                                               # 

                shut_down_guiboss:              Void -> Void,                                                           # Set Client_To_Guiboss.guiboss_done' and then terminate guiboss_imp microthread.  Nothing else.

                app_to_compileimp:              a2c::App_To_Compileimp,

                get_guipiths:                   Void -> (Int, idm::Map( Xi_Hostwindow_Info )),                          # Export abstract version of guiboss_imp's current set of running guis (Guipane instances). 'Int' is gui version, needed to trap bad concurrent updates.  
                install_updated_guipiths:       (Int, idm::Map( Xi_Hostwindow_Info )) -> Bool                           # Update guiboss_imp's running gui per supplied Guipith instances, which should be a suitably edited version of return value from get_guipiths.  See Note[1] in src/lib/x-kit/widget/gui/translate-guipane-to-guipith.pkg
                                                                                                                        #
                                                                                                                        # The Int values are Guiboss_State.gui_update_count: If the value supplied with install_updated_guipiths does not match, guiboss returns FALSE and does nothing, and client must
                                                                                                                        # start the get_guipiths -> mutate -> install_updated_guipiths.  This is insurance against two concurrent clients attempting overlapping updates to the GUI topology.
                                                                                                                        #
                                                                                                                        # The idiom to use here is:
                                                                                                                        #
                                                                                                                        #     do_while_not {.
                                                                                                                        #         (get_guipiths ()) -> (gui_version, guipiths);                 # Get current GUI layout.
                                                                                                                        #         guipiths =  gtj::guipith_map (guipiths, options);             # Modify it to produce new GUI layout.
                                                                                                                        #         install_updated_guipiths (gui_version, guipiths);             # Install new GUI layout.
                                                                                                                        #     };                                                                # If someone else modified the current GUI layout out from under us, retry.
                                                                                                                        #
                                                                                                                        # Worked examples of doing this may be found in (e.g.)
                                                                                                                        #     src/lib/x-kit/widget/edit/fundamental-mode.pkg
                                                                                                                        #
                                                                                                                        # Limitations of install_updated_guipiths:
                                                                                                                        #  o  Revised guipane may move widgets around but no individual widget may be present more than once. (Ditto for all other guipith entities.)  This restruction is fundamental to the design.
                                                                                                                        #  o  Popup hierarchy may not be modified.  Use make_popup()/kill_popup() for that.  This restriction is pure implementation laziness: we'll presumbly lift it eventually.
                                                                                                                        #  o  Tabports and Scrollports may not be modified beyond substituting widgets.      This restriction is pure implementation laziness: we'll presumbly lift it eventually.
                                                                                                                        # As a convenience, XI_ROW, XI_COL and XI_GRID instances may be freely created and inserted. (In general guipith values may be only re-arranged or dropped, outside of XI_GUIPLAN.)
# XXX QUERO FIXME I think maybe we should have call(s) here to subscribe to events like garbage collection, disk-full, low-on-ram etc.
# Having method(s) here to register a fn to be called for a given event is a simple, effective way to implement that functionality.
# One could argue that such events have little to do with GUIs and hence should not be the purvue of guiboss-imp, but guiboss-imp
# is the established architecture apps will be using to process the dominant event streams (mouseclicks + keypresses), so piggybacking
# on that takes advantage of established app architecture as well as established internal guiboss_imp architecture.  We need at least
# DISK_FULL and RAM_FULL in order to write robust apps that deal gracefully with resource exhaustion.  CPU_FULL would be a logical
# correlate, so apps can cut back on background processing when CPU cycles are in short supply. It might be worth just running through
# the list of standard Unix signals and thinking about which of them might also be best coupled to the Mythryl GUI-app world by turning
# them into events delivered through this mechanism.  SIGPWR and SIGHUP might make sense...?

#   Gadget_To_Guiboss should maybe export the log.pkg fns, as futureproofing
#   against distributed-computation situations where the GUI runs remote from
#   the application and we want logging to be centralized in the application.
              }

        also
        Widget_To_Guiboss
          =
          { id:                         Id,                                                                             # Unique id to facilitate storing guiboss instances in indexed datastructures like red-black trees.
            #
            g:                          Gadget_To_Guiboss,

            note_widget_layout_hint:    { id:                   Id,
                                          widget_layout_hint:   Widget_Layout_Hint
                                        }
                                        -> Void                                                                         # 
          }



        also
        Guiboss_To_Gadget                                                                                               # 
          =
            {   id:                     Id,                                                                             # Unique id to facilitate storing Guiboss_To_Gadget ports in indexed datastructures like red-black trees.
                doc:                    String,
                #
# These two may be a mistake,
# I'm not sure they are used
# or even potentially useful:
                wants_keystrokes:       Bool,                                                                           # TRUE iff guiboss_imp should send keyboard events to this gadget.  This might need to become a Ref(Bool)...?
                wants_mouseclicks:      Bool,                                                                           # TRUE iff guiboss_imp should send mouse    events to this gadget.  This is about correctness not efficiency: We might have two nested candidate gadgets where this flag decides which one gets the event.

                #
                initialize_gadget: {                                                                                    # Before the first redraw_gadget_request call every widget-imp/sprite-imp/object-imp gets this call from   src/lib/x-kit/widget/gui/guiboss-imp.pkg
                                      #                                                                                 # If its appearance has changed it should call needs_redraw_gadget_request().
                                      site:             g2d::Box,                                                       # Window rectangle in which to draw.
                                      theme:            wt::Widget_Theme,
                                      #
                                      get_font:         List(String) ->  evt::Font,                                     # Accepts a list of font names which are tried in order; returns font 'ascent' and 'descent' in pixels -- sum them to get  font height.
                                      pass_font:        List(String) -> Replyqueue                                      #
                                                                     -> ( evt::Font -> Void )                           #
                                                                     -> Void,                                           # Nonblocking version of previous, for use in imps.

                                      make_rw_pixmap:   g2d::Size -> g2p::Gadget_To_Rw_Pixmap
                                    }
                                    ->
                                    Void,


                redraw_gadget_request:      {                                                                           # This is a request to the gadget to redraw itself, made by    src/lib/x-kit/widget/gui/guiboss-imp.pkg
                                              #                                                                         # Gadget should always respond by calling gadget_to_guiboss.redraw_gadget(), even if appearance is unchanged. (guiboss might be refreshing screen after an EXPOSE event, say.)
                                              frame_number:             Int,                                            # 1,2,3,... Purely for convenience of gadget -- guiboss-imp makes no use of this.
                                              site:                     g2d::Box,                                       # Window rectangle in which to draw.
                                              duration_in_seconds:      Float,                                          # If state has changed look-imp should call redraw_gadget() before this time is up. Also useful for motionblur.
                                              gadget_mode:              Gadget_Mode,
                                              theme:                    wt::Widget_Theme,
                                              popup_nesting_depth:      Int                                             # 0 for gadgets on basewindow, 1 for gadgets on popup on basewindow, 2 for gadgets on popup on popup, etc.
                                            }
                                            ->
                                            Void,

                wakeup:                     {                                                                           # These calls are set up by calling gadget_to_guiboss.wake_me[].
                                              wakeup_arg:               Wakeup_Arg,                                     # 
                                              wakeup_fn:                Wakeup_Arg -> Void                              # Gadget thunk registered via gadget_to_guiboss.wake_me[].
                                            }
                                            ->
                                            Void,


                note_keyboard_focus:        (Bool, wt::Widget_Theme)    -> Void,                                        # TRUE means we now have keyboard focus, FALSE means we no longer have it.  Allows gadget to visually display focus locus, typically via a black outline and/or dis/abling cursor. See also Gadget_To_Guiboss.request_keyboard_focus
                note_mouse_drag_event:      Note_Mouse_Drag_Event_Arg   -> Void,                                        # Intended to support dragging sliders and scrollbar thumbs etc.  Not intended for drag-and-drop.
                note_mouse_transit:         Note_Mouse_Transit_Arg      -> Void,                                        # Mouse entering or leaving window site assigned to gadget.  Intended to support tooltips, active-widget highlighting etc. Note that buttons are always all up in a mouse transit -- otherwise it is a mouse-drag event.
                note_key_event:             Note_Key_Event_Arg          -> Void,                                        # Note keyboard KEY_PRESS or KEY_RELEASE at 'point'. Intended for textfield text entry etc.
                note_mousebutton_event:     Note_Mousebutton_Event_Arg  -> Void,                                        # Note mousebutton click at 'point'.  Intended for pushbuttons etc.

                die:                        Void -> Void                                                                # Equivalent to firing end_gun', but affects only one gadget.
              }

        also
        Guiboss_To_Widget
          =
          { id:                         Id,                                                                             # Unique id to facilitate storing guiboss_to_widget instances in indexed datastructures like red-black trees.
            doc:                        String,
            g:                          Guiboss_To_Gadget,                                                              # We're extending this generic widget/sprite/object interface with widget-specific functionality.
            #
            get_widget_layout_hint:     Void -> Widget_Layout_Hint,                                                     # We require this call to be O(1) and nonblocking.
            get_frame_indent_hint:      Void -> Frame_Indent_Hint,                                                      # We require this call to be O(1) and nonblocking.
            #
            pass_something:             Replyqueue ->  (Int -> Void) -> Void,
            do_something:               Int     -> Void
          }

        also
        Spritespace_Imp_Info
          =
# Looks like we don't need this record at all any more...?
# All this info is now in Rg_Spritespace, excepting
# the oneshot which is about to die.  So Spritespace_Imps
# can be just an index of Rg_Spritespace records.
          { sprite_to_spritespace:      s2b::Sprite_To_Spritespace,                                                     # 
            guiboss_to_spritespace:     Guiboss_To_Spritespace,
            shutdown_oneshot:           Oneshot_Maildrop( Void )
          }

        also
        Objectspace_Imp_Info
          =
# Looks like we don't need this record at all any more...?
# All this info is now in Rg_Objectspace, excepting
# the oneshot which is about to die.  So Objectspace_Imps
# can be just an index of Rg_Objectspace records.
          { object_to_objectspace:      o2c::Object_To_Objectspace,                                                     # 
            guiboss_to_objectspace:     Guiboss_To_Objectspace,
            shutdown_oneshot:           Oneshot_Maildrop( Void )
          }

        also
        Widgetspace_Imp_Info
          =
# Looks like we don't need this record at all any more...?
# All this info is now in Rg_Widgetspace, excepting
# the oneshot which is about to die.  So Widgetspace_Imps
# can be just an index of Rg_Widgetspace records.
          {
            guiboss_to_widgetspace:     Guiboss_To_Widgetspace,
            shutdown_oneshot:           Oneshot_Maildrop( Void )
          }

        also
        Gadget_Imp_Info                                                                                                 # The per-gadget information we track.  (This is private to guiboss-imp.)
          =                                                                                                             # Here 'gadget' refers indifferently to widget-imps, sprite-imps and object-imps.
          { site:                       Ref( g2d::Box ),                                                                # Where to draw this gadget, in hostwindow coordinates.
            subwindow_or_view:          Ref(Subwindow_Or_View),
            #
            guiboss_to_gadget:          Guiboss_To_Gadget,                                                              # We use this to make requests of gadgets.
            gadget_mode:                Ref( Gadget_Mode ),                                                             # Tracks whether this gadget currently has the mouse focus (etc).
            #
            needs_redraw_request:       Ref( Bool ),                                                                    # 
            sent__initialize_gadget:    Ref( Bool ),
            #
            point_in_gadget:            Ref( Null_Or( g2d::Point -> Bool )),                                            # Optional fn to decide if a mouseclick actually hit the gadget itself, or just somewhere near it in the screenspace assigned to it.
            #
            pixmaps:                    Ref( im::Map( g2p::Gadget_To_Rw_Pixmap )),                                      # This tracks all X-server pixmaps created by this particular gadget. We need this so that we can reliably recycle them all when killing the gadget -- otherwise we're leaking memory in the X server.

            at_frame_n:                 Ref (   Null_Or                                                                 # Call gadget.wakeup once, during frame N, and pass wakeup_fn in call. NULL means this wakeup is off.
                                                  { at_frame:   Int,
                                                    wakeup_fn:  Wakeup_Arg -> Void
                                                  }
                                            ),
            every_n_frames:             Ref (   Null_Or                                                                 # Call gadget.wakeup every N frames,       and pass wakeup_fn in call. NULL means this wakeup is off.
                                                  { n:          Int,
                                                    next:       Ref(Int),
                                                    wakeup_fn:  Wakeup_Arg -> Void
                                                  }
                                            )
          }  

        also    Spritespace_Imps    = Ref( idm::Map( Spritespace_Imp_Info    ) )                                        # 
        also    Objectspace_Imps    = Ref( idm::Map( Objectspace_Imp_Info    ) )                                        #
        also    Widgetspace_Imps    = Ref( idm::Map( Widgetspace_Imp_Info    ) )                                        #
        also    Gadget_Imps         = Ref( idm::Map(      Gadget_Imp_Info    ) )                                        # Index is  guiboss_to_gadget.id.
        also    Widget_Layout_Hints = Ref( idm::Map( Widget_Layout_Hint      ) )                                        # Index is  guiboss_to_gadget.id.

        also
        Guipane =             { id:                             Id,
                                rg_widget:                      Rg_Widget_Type,                                         # The widget (or more commonly, tree of widgets) managed by the gui-tree's toplevel widgetspace-imp.
                                guiboss_to_widgetspace:         Guiboss_To_Widgetspace,
                                widget_to_guiboss:              Widget_To_Guiboss,
                                space_to_gui:                   Space_To_Gui,
                                hostwindow:                     gtg::Guiboss_To_Hostwindow,                             # The hostwindow on which to draw our widgets. This represents the X-server window holding our tree of running guis.
                                subwindow_info:                 Subwindow_Data,                                         # The subwindow on which this running gui is drawn. This will be a sub-rectangle of the hostwindow, except for the root running gui of the popups tree. It hosts the actual backing pixmap on which rg_widget will be drawn first.
                                needs_layout_and_redraw:        Ref( Bool )
                              }
        also
        Subwindow_Info                                                                                                  # Used in SUBWINDOW_INFO.
          =
          { id:                 Id,
            guipane:            Ref( Null_Or( Guipane ) ),
            pixmap:             Ref( g2p::Gadget_To_Rw_Pixmap ),                                                        # Main backing store for this running gui.
            popups:             Ref(List(Subwindow_Data)),                                                              # These will all be SUBWINDOW_INFO, so 'Ref(List(Subwindow_Info))' would be a better type here.
            parent:             Null_Or( Subwindow_Data ),                                                              # For popups this points to the parent; for the original non-popup window it is NULL.
            stacking_order:     Int,                                                                                    # Assigned in increasing order starting at 1;  these determine who overlies who visually on the screen in case of overlaps. (Popups must be entirely within parent, but sibling popups can overlap.)
            upperleft:          Ref(g2d::Point)                                                                         # If we have a parent, this gives our location on it. Note that pixmap.size gives our size.
          }

        also
        Tabbable_Info                                                                                                   # 
          =                                                                                                             # 
          {
            rg_widget:                  Rg_Widget_Type,                                                                 # Widget-tree visible in this tabport, which gets rendered onto 'pixmap' here.
            #                                                                                                           # 
            pixmap:                     g2p::Gadget_To_Rw_Pixmap,                                                       # Tabbable_Info values appear only in RG_SCROLLPORT.scrollable_info,
                                                                                                                        #                                     RG_TABPORT.tabs
                                                                                                                        #                                     
            parent_subwindow_or_view:   Subwindow_Or_View,                                                              # This can be a SCROLLABLE_INFO if we have a tabportport located on a scrollport, for example.
            site:                       Ref(g2d::Box),                                                                  # Size and location of subwindow scrollport in parent Subwindow_Or_View coordinates.
            #
            is_visible:                 Ref( Bool )                                                                     # 
                                                                                                                        # This value is implied by *Rg_Tabport.visible_tab but as a convenience we maintain this redundant explicit version.
                                                                                                                        # We need this so that   update_offscreen_parent_pixmaps_and_then_hostwindow()   in   src/lib/x-kit/widget/gui/guiboss-imp.pkg
                                                                                                                        # can know when to stop propagating widget updates up the tabport tree.
          }



        also Gp_Row     =            List( Gp_Widget_Type )
        also Gp_Col     =            List( Gp_Widget_Type )
        also Gp_Grid    =      List( List( Gp_Widget_Type ))
        also Gp_Mark    =                  Gp_Widget_Type
        also Gp_Row'    = (Id, List( Gp_Widget_Type ))
        also Gp_Col'    = (Id, List( Gp_Widget_Type ))
        also Gp_Grid'   = (Id, List( List( Gp_Widget_Type )))
        also Gp_Mark'   = (Id, String,     Gp_Widget_Type   )
        #
        also Gp_Scrollport   = { scroller_callback: Scroller_Callback,  pixmap_size: g2d::Size,  widget: Gp_Widget_Type }
        also Gp_Tabport      = (Tab_Picker_Callback,    Gp_Widget_Type, List( Gp_Widget_Type ))                         # "Gp_Widget_Type, List(Gp_Widget_Type)" is a technical trick to specify via the type system that the list must be at least one entry long. (We subsequently just use Gp_Widget_Type ! List(Gp_Widget_Type).)
        also Gp_Frame        = (List(Frame_Option),  Gp_Widget_Type )
        also Gp_Widget       = Widget_Start_Fn
        also Gp_Objectspace  = (List(Objectspace_Option),  List(Gp_Object))
        also Gp_Spritespace  = (List(Spritespace_Option),  List(Gp_Sprite))
        also Gp_Widgetspace  = (List(Widgetspace_Option),  Gp_Widget_Type)

        #########################################################################################
        ### More guiboss-to-widgetspace types



        #########################################################################################
        ### More guiboss-to-objectspace types



        #########################################################################################
        ### More guiboss-to-spritespace types



        #########################################################################################
        ### More gui-plan types


        #########################################################################################
        ### Recursive running-gui types

        also
        Rg_Row                                                                                                          # Used in RG_ROW
          =                                                                                                             # A horizontal row of widget widgets.
          { id:                         Id,
            widgets:                    List( Rg_Widget_Type ),                                                         # The list of widgets to be laid out and displayed in this row.
            widget_layout_hint:         Ref( Widget_Layout_Hint ),                                                      # Derived ultimately from Rg_Widget layout hints.  This gets computed and set in   src/lib/x-kit/widget/gui/guiboss-widget-layout.pkg
            site:                       Ref( g2d::Box ),                                                                # Current assigned site on pixmap.  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
            first_cut:                  Null_Or( Float )                                                                # Normally NULL; if non-NULL (and at least two widgets in row/col), gives fraction of row/col space to allocate to first widget, overriding the regular bottom-up sizing mechanism.
          }

        also
        Rg_Col = Rg_Row                                                                                                 # Used in RG_COL.  Synonym to allow better code readability.

        also
        Rg_Grid                                                                                                         # Used in RG_GRID
          =                                                                                                             # A grid widget widgets.
          { id:                         Id,
            widgets:                    List(   List( Rg_Widget_Type )   ),                                             # The list lists of widgets to be laid out and displayed in this grid.
            widget_layout_hint:         Ref( Widget_Layout_Hint ),                                                      # Derived ultimately from Rg_Widget layout hints.  This gets computed and set in   src/lib/x-kit/widget/gui/guiboss-widget-layout.pkg
            site:                       Ref(g2d::Box)                                                                   # Current assigned site on pixmap.  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
          }

        also
        Rg_Mark                                                                                                         # Used in RG_MARK
          =                                                                                                             # A single widget.
          { id:                         Id,
            doc:                        String,
            widget:                     Rg_Widget_Type,                                                                 # The widget to be displayed.
            widget_layout_hint:         Ref( Widget_Layout_Hint ),                                                      # Derived ultimately from Rg_Widget layout hints.  This gets computed and set in   src/lib/x-kit/widget/gui/guiboss-widget-layout.pkg
            site:                       Ref(g2d::Box)                                                                   # Current assigned site on pixmap.  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
          }


        also
        Rg_Scrollport                                                                                                   # Used in RG_SCROLLPORT
          =                                                                                                             # 
          { id:                         Id,
            upperleft:                  Ref(g2d::Point),                                                                # Upperleft of scrollport's contents in scrollport coordinates, used for scrolling pixmap in scrollport.
            scroller:                   Ref(Scroller),                                                                  # Client-code interface for controlling 'upperleft' and thus scrolling scrollport contents. This is a ref to resolve mutual recursion issues at creation, not because we expect to update it.
            callback:                   Scroller_Callback,                                                              # This is how we pass our Scroller to app client code, which basically lets it set 'upperleft' above.
            site:                       Ref(g2d::Box),                                                                  # Our scrollport's current assigned site on parent pixmap (NOT 'pixmap').  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg

            rg_widget:                  Ref( Rg_Widget_Type ),                                                          # Widget-tree visible in this viewable, which gets rendered onto 'pixmap' here.
            #                                                                                                           # rg_widget is a Ref not because we intend to change it, but to work around a technical difficulty in guiboss-imp.pkg:do_pg_widget:PG_SCROLLPORT where  rg_scrollport and rg_widget each want to be created first.
            pixmap:                     g2p::Gadget_To_Rw_Pixmap,                                                       # 
                                                                                                                        # 
            parent_subwindow_or_view:   Subwindow_Or_View                                                               # Used when propagating redraws up the pixmap hierachy.  This can be a SCROLLABLE_INFO if we have a scrollport located on a scrollport.
          }                     

        also
        Rg_Tabport                                                                                                      # Used in RG_TABPORT
          =                                                                                                             # Here we provide support for selection between alternate views in scrollport.  Actually providing tabs happens at a higher level; here we handle pixmap state maintenance and redraw support.
          { id:                         Id,
            visible_tab:                Ref ( Int ),                                                                    # Which of 'tabs' is currently visible?  This refcell references one element from 'tabs';  it supports switching between the tabbed views.
            callback:                   Tab_Picker_Callback,                                                            # This is how we pass our Tab_Picker to app client code, which basically lets it set 'visible_tab' above.
            tabs:                       List( Tabbable_Info ),                                                          # This record holds one of the alternate views which may be made visible in the scrollport.  *** WE REQUIRE AT LEAST ONE ENTRY IN THE LIST! *** 
            site:                       Ref(g2d::Box)                                                                   # Current assigned site on pixmap.  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
                                                                                                                        # NOTE: We specifically depend on tab.site == rg_tabport.site for all tabs (i.e., all point to the same refcell).
          }

        also
        Rg_Frame
          =
          { id:                         Id,
            frame_widget:               Rg_Widget_Type,                                                                 # Widget which will draw the frame surround.
            widget:                     Rg_Widget_Type,                                                                 # Widget-tree to draw surrounded by frame.
            widget_layout_hint:         Ref( Widget_Layout_Hint ),
            site:                       Ref(g2d::Box)                                                                   # Current assigned site on pixmap.  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
          }

        also
        Rg_Widget                                                                                                       # Used in RG_WIDGET.  An actual leaf widget like an arrowbutton or label or text-entry box. These are all customizations of src/lib/x-kit/widget/xkit/theme/widget/default/look/widget-imp.pkg
          =
          {                                                                                                             # We don't need an 'id' field here because guiboss_to_widget.id serves the purpose.
            guiboss_to_widget:          Guiboss_To_Widget,                                                              # The command end of a port for communication to a widget-imp from a   src/lib/x-kit/widget/gui/guiboss-imp.pkg
            shutdown_oneshot:           Once( Void ),                                                                   # The widget-imp will fire this when shutting down due to die() call. Used by guiboss-imp.
            site:                       Ref(g2d::Box)                                                                   # Current assigned site on pixmap.  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
#           doc:                        String                                                                          # Debugging support: Allow RG_WIDGETs to be distinguishable for debug-display purposes.
          }

        also
        Rg_Widgetspace
          = 
          {                                                                                                             # We don't need an 'id' field here because guiboss_to_widgetspace.id serves the purpose.
            guiboss_to_widgetspace:     Guiboss_To_Widgetspace,                                                         # Layout imp for this widgetspace.
            rg_widget:                  Rg_Widget_Type                                                                  # Widgettree displayed in this widgetspace.     
          }

        also
        Rg_Objectspace                                                                                                  # Used in RG_OBJECTSPACE
          =
          {                                                                                                             # We don't need an 'id' field here because guiboss_to_objectspace.id serves the purpose.
            guiboss_to_objectspace:     Guiboss_To_Objectspace,
            object_to_objectspace:      o2c::Object_To_Objectspace,                                                     # 
            objects:                    List( Rg_Object_Type ),                                                         # The list of objects to be drawn. These can be placed arbitrarily, including possible overlaps.
            site:                       Ref(g2d::Box)                                                                   # Current assigned site on pixmap.  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
          }

        also
        Rg_Object
          =
          {                                                                                                             # We don't need an 'id' field here because guiboss_to_gadget.id serves the purpose.
            objectspace_to_object:      c2o::Objectspace_To_Object,                                                     # 
            guiboss_to_gadget:          Guiboss_To_Gadget,                                                              # 
            shutdown_oneshot:           Once( Void )                                                                    # The sprite-imp will fire this one-shot when shutting down due to die(). Used by guiboss-imp.
          }

        also
        Rg_Sprite
          =
          {                                                                                                             # We don't need an 'id' field here because guiboss_to_gadget.id serves the purpose.
            spritespace_to_sprite:      b2s::Spritespace_To_Sprite,                                                     # 
            guiboss_to_gadget:          Guiboss_To_Gadget,                                                              # 
            shutdown_oneshot:           Once( Void )                                                                    # The sprite-imp will fire this one-shot when shutting down due to die(). Used by guiboss-imp.
          }

        also
        Rg_Spritespace                                                                                                  # Used in RG_SPRITESPACE
          =
          {                                                                                                             # We don't need an 'id' field here because guiboss_to_spritespace.id serves the purpose.
            guiboss_to_spritespace:     Guiboss_To_Spritespace,
            sprite_to_spritespace:      s2b::Sprite_To_Spritespace,                                                     # 
            sprites:                    List( Rg_Sprite_Type ),                                                         # The list of widgets to be drawn on the spritespace. These can be placed arbitrarily.
            site:                       Ref(g2d::Box)                                                                   # Current assigned site on pixmap.  Set by  assign_sites_to_all_widgets()     in   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg
          }


        #########################################################################################
        ### Recursive  Widget_Start_Fn  types


        also
        Widget_Imports
          =
          {
            widget_to_guiboss:          Widget_To_Guiboss,                                                              # 
            run_gun':                   Run_Gun,                                                                        #
            shutdown_oneshot:           Oneshot_Maildrop( Void )
          }


        also
        Widget_Exports
          =
          { guiboss_to_widget:          Guiboss_To_Widget                                                               # 
          }



        #########################################################################################
        ### Recursive  Object_Start_Fn  types

        also
        Object_Imports
          =
          { gadget_to_guiboss:          Gadget_To_Guiboss,                                                              # 
            object_to_objectspace:      o2c::Object_To_Objectspace,                                                     # 
            run_gun':                   Run_Gun,                                                                        #
            shutdown_oneshot:           Oneshot_Maildrop( Void )
          }

        also
        Object_Exports
          =
          { guiboss_to_gadget:          Guiboss_To_Gadget,                                                              # 
            objectspace_to_object:      c2o::Objectspace_To_Object                                                      # 
          }



        #########################################################################################
        ### Recursive  Sprite_Start_Fn  types

        also
        Sprite_Imports
          =
          { gadget_to_guiboss:          Gadget_To_Guiboss,                                                              # 
            sprite_to_spritespace:      s2b::Sprite_To_Spritespace,                                                     # 
            run_gun':                   Run_Gun,                                                                        #
            shutdown_oneshot:           Oneshot_Maildrop( Void )                                                        #
          }

        also
        Sprite_Exports
          =
          { guiboss_to_gadget:          Guiboss_To_Gadget,                                                              # 
            spritespace_to_sprite:      b2s::Spritespace_To_Sprite                                                      # 
          };





        Mouse_Is                                                                                                        # Support for mouse drag operations.
          #
          = CROSSING_NONGADGET                                                                                          # Mouse is not currently to be on any gadget.
          #
          | CROSSING_GADGET                                                                                             # Mouse is currently on a gadget. Eventually we should issue ENTER and LEAVE events based on this.      
              { gadget_imp_info:        Gadget_Imp_Info                                                                 # This is the gadget on which the mouse is currently located. We send a LEAVE event when the mouse leaves it.
              }
          #
          | DRAGGING                                                                                                    # Mouse is being dragged on this gadget.
              { gadget_imp_info:        Gadget_Imp_Info,                                                                # This is the gadget on which the drag started.  It gets all the motion events until drag terminates, even if mouse leaves the window area owned by the gadget.
                start_point:            g2d::Point,                                                                     # This is the window coordinate of the downclick which started this drag.
                last_point:             g2d::Point,                                                                     # This is the window coordinate of the last motion event for this drag.
                guipane_offset:         g2d::Point                                                                      # Add this to points in basewindow coordinate system to convert them to guipane coordinate system that the gadget expects.
              }
          ;

        Hostwindow_Info
          =
          { guiboss_to_hostwindow:                      gtg::Guiboss_To_Hostwindow,
            current_frame_number:                       Ref(Int),                                                       # We count frames for convenience of widgets and debugging.
            seconds_per_frame:                          Ref(Float),                                                     # Primarily so widgets can do motion blurring if they wish.

            done_extra_redraw_request_this_frame:       Ref(Bool),                                                      # See Note[3].

            next_stacking_order:                        Ref(Int),                                                       # Next Subwindow_Or_View.stacking_order value to issue.
            

                                                                                                                        # The remainder are valid only while a gui is running,
                                                                                                                        # which is to say, between start_gui' and kill_gui'.


            subwindow_info:                             Ref( Null_Or( Subwindow_Data ) )
          };

        Guiboss_State                                                                                                   # 
          =
          {
            gui_update_count:                   Ref( Int ),                                                             # Counts the number of times that install_updated_guipiths() has been called (or gui topology otherwise modified).
            hostwindows:                                Ref( idm::Map( Hostwindow_Info ) ),                                     # Each call to client_to_guiboss.make_hostwindow() adds one entry to this.  Indexed by guiboss_to_hostwindow.id.
            mouse_is:                           Ref( Mouse_Is ),                                                        # Support for mouse drag operations.
            last_button_changed:                Ref( evt::Mousebutton ),                                                # So we can tell drag_fn clients which button is dragging. (evt::Motion_Xevtinfo values do not include a 'button' arg, unlike evt::Button_Xevtinfo values.)
            keyboard_focus:                     Ref( Null_Or( Gadget_Imp_Info ) ),                                      # Gadget currently holding keyboard focus, if any.
            #
            gadget_imps:                        Gadget_Imps,                                                            # Holds info on our Gadget_Imp_Info        instances -- basically, all running widgets, sprites and objects in hostwindow.
            widget_layout_hints:                Widget_Layout_Hints,                                                    # Holds         our Widget_Layout_Hint     instances for all widget-imp.pkg instances     for this hostwindow.
            spritespace_imps:                   Spritespace_Imps,                                                       # Holds info on our Guiboss_To_Spritespace instances -- all spritespace-imp.pkg instances for this hostwindow.
            objectspace_imps:                   Objectspace_Imps,                                                       # Holds info on our Guiboss_To_Objectspace instances -- all objectspace-imp.pkg instances for this hostwindow.
            widgetspace_imps:                   Widgetspace_Imps                                                        # Holds info on our Guiboss_To_Widgetspace instances -- all widgetspace-imp.pkg instances for this hostwindow.
          };
    };
end;

##########################################################################
# Note[1]
#
# We need a NULL_WIDGET but not a NULL_SPRITE or NULL_OBJECT
# because Guiplans are required arguments to guiboss-imp and
# Gp_Widget_Type is a required component of a Guiplan, but
# sprite and object spaces are always optional.


##########################################################################
# Note[2]
#
#           "Simple  things should be simple.
#            Complex things should be possible."
#                             -- Alan Kay
#
# The purpose of the Rg_Widget_Type facilities generally and
# of RG_ROW RG_COL RG_GRID specifically is to make simple GUI
# layout problems simple.
#
# In general, complex widget layout issues should be handled by
# writing custom code which lays out widgets (etc) on a object,
# not by cluttering Rg_Widget_Type with special cases.
#
# Trying to make complex things simple will always fail;
# the result will be instead to make simple things complex.



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext