PreviousUpNext

15.4.1445  src/lib/x-kit/widget/gui/guiboss-widget-layout.pkg

## guiboss-widget-layout.pkg
#
# A support library for 
#
#     src/lib/x-kit/widget/gui/guiboss-imp.pkg
#
# Here we handle the problem of assigning widgets specific
# pixmap sites on which to draw themselves.  Our inputs
# are the Guipane tree describing the abstract layout
# together with the Widget_Layout_Hint information encoding
# preferences for the size and stretchiness of individual
# widgets.


# 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 ap  =  client_to_atom;                              # client_to_atom                        is from   src/lib/x-kit/xclient/src/iccc/client-to-atom.pkg
#   package au  =  authentication;                              # authentication                        is from   src/lib/x-kit/xclient/src/stuff/authentication.pkg
#   package cpm =  cs_pixmap;                                   # cs_pixmap                             is from   src/lib/x-kit/xclient/src/window/cs-pixmap.pkg
#   package cpt =  cs_pixmat;                                   # cs_pixmat                             is from   src/lib/x-kit/xclient/src/window/cs-pixmat.pkg
#   package dy  =  display;                                     # display                               is from   src/lib/x-kit/xclient/src/wire/display.pkg
#   package fil =  file__premicrothread;                        # file__premicrothread                  is from   src/lib/std/src/posix/file--premicrothread.pkg
#   package fti =  font_index;                                  # font_index                            is from   src/lib/x-kit/xclient/src/window/font-index.pkg
#   package r2k =  xevent_router_to_keymap;                     # xevent_router_to_keymap               is from   src/lib/x-kit/xclient/src/window/xevent-router-to-keymap.pkg
#   package mtx =  rw_matrix;                                   # rw_matrix                             is from   src/lib/std/src/rw-matrix.pkg
#   package rop =  ro_pixmap;                                   # ro_pixmap                             is from   src/lib/x-kit/xclient/src/window/ro-pixmap.pkg
#   package rw  =  root_window;                                 # root_window                           is from   src/lib/x-kit/widget/lib/root-window.pkg
#   package rwv =  rw_vector;                                   # rw_vector                             is from   src/lib/std/src/rw-vector.pkg
#   package sep =  client_to_selection;                         # client_to_selection                   is from   src/lib/x-kit/xclient/src/window/client-to-selection.pkg
#   package shp =  shade;                                       # shade                                 is from   src/lib/x-kit/widget/lib/shade.pkg
#   package sj  =  socket_junk;                                 # socket_junk                           is from   src/lib/internet/socket-junk.pkg
#   package x2s =  xclient_to_sequencer;                        # xclient_to_sequencer                  is from   src/lib/x-kit/xclient/src/wire/xclient-to-sequencer.pkg
#   package tr  =  logger;                                      # logger                                is from   src/lib/src/lib/thread-kit/src/lib/logger.pkg
#   package tsr =  thread_scheduler_is_running;                 # thread_scheduler_is_running           is from   src/lib/src/lib/thread-kit/src/core-thread-kit/thread-scheduler-is-running.pkg
#   package u1  =  one_byte_unt;                                # one_byte_unt                          is from   src/lib/std/one-byte-unt.pkg
#   package v1u =  vector_of_one_byte_unts;                     # vector_of_one_byte_unts               is from   src/lib/std/src/vector-of-one-byte-unts.pkg
#   package v2w =  value_to_wire;                               # value_to_wire                         is from   src/lib/x-kit/xclient/src/wire/value-to-wire.pkg
#   package wg  =  widget;                                      # widget                                is from   src/lib/x-kit/widget/old/basic/widget.pkg
#   package wi  =  window;                                      # window                                is from   src/lib/x-kit/xclient/src/window/window.pkg
#   package wme =  window_map_event_sink;                       # window_map_event_sink                 is from   src/lib/x-kit/xclient/src/window/window-map-event-sink.pkg
#   package wpp =  client_to_window_watcher;                    # client_to_window_watcher              is from   src/lib/x-kit/xclient/src/window/client-to-window-watcher.pkg
#   package wy  =  widget_style;                                # widget_style                          is from   src/lib/x-kit/widget/lib/widget-style.pkg
#   package xc  =  xclient;                                     # xclient                               is from   src/lib/x-kit/xclient/xclient.pkg
#   package xj  =  xsession_junk;                               # xsession_junk                         is from   src/lib/x-kit/xclient/src/window/xsession-junk.pkg
#   package xtr =  xlogger;                                     # xlogger                               is from   src/lib/x-kit/xclient/src/stuff/xlogger.pkg
    #

    #
    package evt =  gui_event_types;                             # gui_event_types                       is from   src/lib/x-kit/widget/gui/gui-event-types.pkg
    package gts =  gui_event_to_string;                         # gui_event_to_string                   is from   src/lib/x-kit/widget/gui/gui-event-to-string.pkg
    package gt  =  guiboss_types;                               # guiboss_types                         is from   src/lib/x-kit/widget/gui/guiboss-types.pkg
    package gtj =  guiboss_types_junk;                          # guiboss_types_junk                    is from   src/lib/x-kit/widget/gui/guiboss-types-junk.pkg

    package a2r =  windowsystem_to_xevent_router;               # windowsystem_to_xevent_router         is from   src/lib/x-kit/xclient/src/window/windowsystem-to-xevent-router.pkg

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

    package pp  =  standard_prettyprinter;                      # standard_prettyprinter                is from   src/lib/prettyprint/big/src/standard-prettyprinter.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 bt  =  gui_to_sprite_theme;                         # gui_to_sprite_theme                   is from   src/lib/x-kit/widget/theme/sprite/gui-to-sprite-theme.pkg
    package ct  =  gui_to_object_theme;                         # gui_to_object_theme                   is from   src/lib/x-kit/widget/theme/object/gui-to-object-theme.pkg
    package wt  =  widget_theme;                                # widget_theme                          is from   src/lib/x-kit/widget/theme/widget/widget-theme.pkg

    package boi =  spritespace_imp;                             # spritespace_imp                       is from   src/lib/x-kit/widget/space/sprite/spritespace-imp.pkg
    package cai =  objectspace_imp;                             # objectspace_imp                       is from   src/lib/x-kit/widget/space/object/objectspace-imp.pkg
    package pai =  widgetspace_imp;                             # widgetspace_imp                       is from   src/lib/x-kit/widget/space/widget/widgetspace-imp.pkg

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

    package b2s =  spritespace_to_sprite;                       # spritespace_to_sprite                 is from   src/lib/x-kit/widget/space/sprite/spritespace-to-sprite.pkg
    package c2o =  objectspace_to_object;                       # objectspace_to_object                 is from   src/lib/x-kit/widget/space/object/objectspace-to-object.pkg

    package s2s =  sprite_to_spritespace;                       # sprite_to_spritespace                 is from   src/lib/x-kit/widget/space/sprite/sprite-to-spritespace.pkg
    package o2o =  object_to_objectspace;                       # object_to_objectspace                 is from   src/lib/x-kit/widget/space/object/object-to-objectspace.pkg

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

#   package frm =  frame;                                       # frame                                 is from   src/lib/x-kit/widget/leaf/frame.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 is  =  int_red_black_set;                           # int_red_black_set                     is from   src/lib/src/int-red-black-set.pkg

    package r8  =  rgb8;                                        # rgb8                                  is from   src/lib/x-kit/xclient/src/color/rgb8.pkg
    package r64 =  rgb;                                         # rgb                                   is from   src/lib/x-kit/xclient/src/color/rgb.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 ebi =  millboss_imp;                                # millboss_imp                          is from   src/lib/x-kit/widget/edit/millboss-imp.pkg
    package e2g =  millboss_to_guiboss;                         # millboss_to_guiboss                   is from   src/lib/x-kit/widget/edit/millboss-to-guiboss.pkg

    package gxi =  translate_guipane_to_guipith;                # translate_guipane_to_guipith                  is from   src/lib/x-kit/widget/gui/translate-guipane-to-guipith.pkg
    package gpj =  guiboss_popup_junk;                          # guiboss_popup_junk                    is from   src/lib/x-kit/widget/gui/guiboss-popup-junk.pkg

    tracefile   =  "widget-unit-test.trace.log";

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

Dummy1 = ebi::Millboss_Option;                          # XXX SUCKO DELETEME. This is a quick hack to make sure the package compiles during early development of it.
dummy2 = gxi::guipanes_to_guipiths;                     # XXX SUCKO DELETEME. This is a quick hack to make sure the package compiles during early development of it.

herein

    package guiboss_widget_layout
    :       Guiboss_Widget_Layout                                                                                       # Guiboss_Widget_Layout         is from   src/lib/x-kit/widget/gui/guiboss-widget-layout.api
    {
        Dummy = Int;

        Widget_Site_Info
          =
          { id:                 Id,
            subwindow_or_view:  gt::Subwindow_Or_View,                                                                  # A widget can be located either directly on a subwindow, or via a scrollport (which is ultimately visible on a subwindow, possibly via aother scrollports).
            site:               g2d::Box
          };

        fun gather_widget_layout_hints
              { me:                             gt::Guiboss_State,
                guipane:                        gt::Guipane
              }
            : idm::Map( gt::Widget_Layout_Hint)
            =
            {   result =  REF (idm::empty:      idm::Map( gt::Widget_Layout_Hint));
                #
                gtj::guipane_apply  (guipane,  [ gtj::RG_WIDGET_FN  rg_widget_fn ])
                    where
                        fun rg_widget_fn  (rg_widget: gt::Rg_Widget)
                            =
                            {   widget_layout_hint =  rg_widget.guiboss_to_widget.get_widget_layout_hint ();
                                #
                                result :=  idm::set( *result,
                                                     rg_widget.guiboss_to_widget.id,
                                                     widget_layout_hint
                                                   );
                            };
                    end;

                *result;
            };


        fun lay_out_guipane                                                                                             # Assign to each widget in given widget-tree a pixel-rectangle on which to draw itself, in window coordinates.
              {                                                                                                         # lay_out_widgets is called from   restart_gui'  in  src/lib/x-kit/widget/gui/guiboss-imp.pkg
                site:                   g2d::Box,                                                                       # This is the available window rectangle to divide between our widgets.
                rg_widget:              gt::Rg_Widget_Type,                                                             # This is the tree of widgets -- possibly a single leaf widget.
                subwindow_info:         gt::Subwindow_Data,
                widget_layout_hints:    idm::Map( gt::Widget_Layout_Hint ),
                me:                     gt::Guiboss_State
              }
            : idm::Map( Widget_Site_Info )                                                                              # Our result is a map from widget ids to assigned sites.
            =
            {   subwindow_info -> gt::SUBWINDOW_DATA subwindow_info;
                subwindow_info =  gt::SUBWINDOW_INFO subwindow_info;

                compute_size_preferences_for_rg_widget_tree  rg_widget;

                assign_sites_to_all_widgets (site, subwindow_info, rg_widget);

                *sites;
            }
            where
                #
                Sized_Widget
                  =
                  { rg_widget:          gt::Rg_Widget_Type,
                    size_prefs:         gt::Widget_Layout_Hint,
                    col_number:         Int,
                    row_number:         Int
                  };

                # Establish our result map:
                #
                sites = (REF idm::empty): Ref( idm::Map( Widget_Site_Info ) );                                          # Index is  (id_to_int guiboss_to_gadget.id).

                fun grid_dimensions (grid:      List( List( Sized_Widget ) )):   g2d::Size
                    =
                    {   high =  list::length grid;
                        wide =  int::list_max (map list::length grid);
                        #
                        { high, wide };
                    };

                fun nth_grid_row
                      (
                        grid:   List( List( Sized_Widget ) ),
                        row:    Int
                      )
                    :           List( Sized_Widget )
                    =
                    list::nth (grid, row);

                fun nth_grid_col
                      (
                        grid:   List( List( Sized_Widget ) ),
                        col:    Int
                      )
                    :           List( Sized_Widget )
                    =
                    map  get_colth  grid
                    where
                        fun get_colth (row: List( Sized_Widget ))
                            =
                            list::nth (row, col);
                    end;

                fun grid_cols (grid:    List( List( Sized_Widget ) ))                                                   # Return all columns in grid.
                    =
                    {   (grid_dimensions grid) ->  { high, wide };
                        #
                        grid_cols' (wide - 1, [])
                        where
                            fun grid_cols' (-1, result)
                                    =>
                                    result;

                                grid_cols' (i, result)
                                    =>
                                    grid_cols'  (i - 1,  (nth_grid_col (grid, i))  !  result);
                            end;
                        end;
                    };


                fun get_widget_layout_hint (r: gt::Rg_Widget)
                    =
                    {   id =  r.guiboss_to_widget.id;
#                       i  =  id_to_int id;

                        case (idm::get (widget_layout_hints, id))
                            #
                            THE hint    => hint;
                            #
                            NULL        => gt::default_widget_layout_hint;                                      # This is not expected to happen; possibly we should log something here.
                        esac;
                    };

                fun get__pixels_high_cut (widget: Sized_Widget) =  widget.size_prefs.pixels_high_cut;
                fun get__pixels_wide_cut (widget: Sized_Widget) =  widget.size_prefs.pixels_wide_cut;
                #
                fun get__pixels_high_min (widget: Sized_Widget) =  widget.size_prefs.pixels_high_min;
                fun get__pixels_wide_min (widget: Sized_Widget) =  widget.size_prefs.pixels_wide_min;

                fun find_max_of_pixels_high_mins (widgets:  List( Sized_Widget )) =    int::list_max (map  get__pixels_high_min  widgets);
                fun find_max_of_pixels_wide_mins (widgets:  List( Sized_Widget )) =    int::list_max (map  get__pixels_wide_min  widgets);
                #
                fun find_max_of_pixels_high_cuts (widgets:  List( Sized_Widget )) =  float::list_max (map  get__pixels_high_cut  widgets);
                fun find_max_of_pixels_wide_cuts (widgets:  List( Sized_Widget )) =  float::list_max (map  get__pixels_wide_cut  widgets);

                fun compute_size_preferences_for_grid_rows ([]: List( List( gt::Rg_Widget_Type )), row_number, result_rows): List(List(Sized_Widget))   # A little helper fn used in the gt::RG_GRID cases of both  fun compute_size_preferences_for_rg_widget_tree  and  assign_sites_to_all_widgets.
                        =>
                        reverse result_rows;

                    compute_size_preferences_for_grid_rows (row ! rest, row_number, result)
                        =>
                        compute_size_preferences_for_grid_rows (rest, row_number + 1,  compute_size_preferences_for_grid_row (row, 0, []) ! result)
                        where
                            fun compute_size_preferences_for_grid_row ([]: List(gt::Rg_Widget_Type), col_number, result_row)
                                    =>
                                    reverse result_row;

                                compute_size_preferences_for_grid_row (rg_widget ! rest, col_number, result_row)
                                    =>
                                    {
                                        entry   = { rg_widget,
                                                    size_prefs => compute_size_preferences_for_rg_widget_tree  rg_widget,
                                                    row_number,
                                                    col_number
                                                  };

                                        compute_size_preferences_for_grid_row (rest, col_number + 1, entry ! result_row);
                                    };
                            end;
                        end;
                end

                also
                fun compute_size_preferences_for_rg_widget_tree
                      # 
                      (rg_widget:       gt::Rg_Widget_Type)                                                             # This is the tree of widgets -- possibly a single leaf widget.
                    =
                    case rg_widget
                        #
                        gt::RG_ROW r
                            =>
                            {   do_row (r.widgets, 0, 0, 1.0, 1.0)
                                where
                                    fun do_row ([], pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut)
                                            =>
                                            {   result = { pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut };
                                                #
                                                r.widget_layout_hint := result;

                                                result;
                                            };

                                        do_row ((widget: gt::Rg_Widget_Type) ! rest,  pixels_high_min', pixels_wide_min', pixels_high_cut', pixels_wide_cut')
                                            =>
                                            {   (compute_size_preferences_for_rg_widget_tree  widget)                                                   # This widget may be (for example) a nested ROW, COL or GRID:  If so, process it recursively.
                                                    ->
                                                    { pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut };


                                                pixels_high_min = max (pixels_high_min,  pixels_high_min');
                                                pixels_high_cut = max (pixels_high_cut,  pixels_high_cut');
                                                #
                                                pixels_wide_min =     (pixels_wide_min + pixels_wide_min');
                                                pixels_wide_cut = max (pixels_wide_cut,  pixels_wide_cut');


                                                do_row (rest,  pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut);
                                            };
                                    end;
                                end;
                            };

                        gt::RG_COL r
                            =>
                            {   do_col (r.widgets, 0, 0, 1.0, 1.0)
                                where
                                    fun do_col ([], pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut)
                                            =>
                                            {   result = { pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut };
                                                #
                                                r.widget_layout_hint := result;

                                                result;
                                            };

                                        do_col ((widget: gt::Rg_Widget_Type) ! rest,  pixels_high_min', pixels_wide_min', pixels_high_cut', pixels_wide_cut')
                                            =>
                                            {   (compute_size_preferences_for_rg_widget_tree widget)                                                    # This widget may be (for example) a nested ROW, COL or GRID:  If so, process it recursively.
                                                    ->
                                                    { pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut };


                                                pixels_high_min =     (pixels_high_min + pixels_high_min');
                                                pixels_high_cut = max (pixels_high_cut,  pixels_high_cut');
                                                #
                                                pixels_wide_min = max (pixels_wide_min,  pixels_wide_min');
                                                pixels_wide_cut = max (pixels_wide_cut,  pixels_wide_cut');


                                                do_col (rest,  pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut);
                                            };
                                    end;
                                end;
                            };

                        gt::RG_GRID r
                            =>
                            {   grid =  compute_size_preferences_for_grid_rows (r.widgets, 0, []);
                                #
                                rows =             grid;
                                cols =  grid_cols  grid;                                                                        # Columns of grid, so we can compute column-by-column values conveniently.
                                
                                row_high_mins =  map  find_max_of_pixels_high_mins  rows;                                       # The min height for each row is the max of the min-heights of the widgets in that row.
                                col_wide_mins =  map  find_max_of_pixels_wide_mins  cols;                                       # The min width  for each col is the max of the min-widths  of the widgets in that col.
 
                                pixels_high_min =  int::sum  row_high_mins;                                                     # The min height for the grid widget is the sum of the row min-heights.
                                pixels_wide_min =  int::sum  col_wide_mins;                                                     # The min width  for the grid widget is the sum of the col min-widths.
 
                                all_widgets   =  list::cat  grid;
 
                                pixels_high_cut =  float::list_max  (map  get__pixels_high_cut  all_widgets);                   # The grid high-cut is max height-cut over all widgets in the grid.
                                pixels_wide_cut =  float::list_max  (map  get__pixels_wide_cut  all_widgets);                   # The grid high-cut is max height-cut over all widgets in the grid.

                                { pixels_high_min,
                                  pixels_wide_min,
                                  #
                                  pixels_high_cut,
                                  pixels_wide_cut
                                };
                            };

                        gt::RG_MARK r
                            =>
                            {   (compute_size_preferences_for_rg_widget_tree  r.widget)                                         # This widget may be (for example) a nested ROW, COL or GRID:  If so, process it recursively.
                                    ->
                                    { pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut };
                                h = { pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut };

                                r.widget_layout_hint := h;

                                h;
                            };

                        gt::RG_FRAME r
                            =>
                            {   (compute_size_preferences_for_rg_widget_tree  r.widget)                                         # This widget may be (for example) a nested ROW, COL or GRID:  If so, process it recursively.
                                    ->
                                    { pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut };


                                frame_indent_hint
                                    =
                                    case r.frame_widget
                                        #
                                        gt::RG_WIDGET { guiboss_to_widget, ... }
                                            =>
                                            guiboss_to_widget.get_frame_indent_hint ();

                                        _   => gt::default_frame_indent_hint;
                                    esac;


                                pixels_high_min = pixels_high_min
                                                + frame_indent_hint.pixels_for_top_of_frame
                                                + frame_indent_hint.pixels_for_bottom_of_frame
                                                ;

                                pixels_wide_min = pixels_wide_min
                                                + frame_indent_hint.pixels_for_left_of_frame
                                                + frame_indent_hint.pixels_for_right_of_frame
                                                ;

                                h = { pixels_high_min, pixels_wide_min, pixels_high_cut, pixels_wide_cut };

                                r.widget_layout_hint := h;

                                h;
                            };

                        gt::RG_SCROLLPORT r
                            =>
                            {                                                                                                   # Supply default layout parameters.
                                { pixels_high_min =>  0,
                                  pixels_wide_min =>  0,
                                  #
                                  pixels_high_cut =>  1.0,
                                  pixels_wide_cut =>  1.0
                                };
                            };

                        gt::RG_TABPORT r
                            =>
                            {                                                                                                   # Supply default layout parameters.
                                { pixels_high_min =>  0,
                                  pixels_wide_min =>  0,
                                  #
                                  pixels_high_cut =>  1.0,
                                  pixels_wide_cut =>  1.0
                                };
                            };

                        gt::RG_WIDGET r
                            =>
                            get_widget_layout_hint r;

                        gt::RG_OBJECTSPACE r
                            =>
                            {
msg = sprintf "do_re_site_widget_tree/pass1/OBJECTSPACE unimplemented";
nb {. msg; };
raise exception DIE msg;
                            };
                        gt::RG_SPRITESPACE r
                            =>
                            {
msg = sprintf "do_re_site_widget_tree/pass1/SPRITESPACE unimplemented";
nb {. msg; };
raise exception DIE msg;
                            };

                        gt::RG_NULL_WIDGET /* r */
                            =>
                            { pixels_wide_min => 0, pixels_high_min => 0, pixels_wide_cut => 0.0, pixels_high_cut => 0.0 };
                    esac;


                fun wide_min_for_widget ( widget as gt::RG_WIDGET r                                : gt::Rg_Widget_Type) =>  (get_widget_layout_hint r).pixels_wide_min;
                    wide_min_for_widget ( widget as gt::RG_ROW    { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_min;
                    wide_min_for_widget ( widget as gt::RG_COL    { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_min;
                    wide_min_for_widget ( widget as gt::RG_GRID   { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_min;
                    wide_min_for_widget ( widget as gt::RG_MARK   { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_min;
                    wide_min_for_widget ( widget as gt::RG_FRAME  { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_min;
                    wide_min_for_widget _                                                                                =>   0;
                end;

                fun high_min_for_widget ( widget as gt::RG_WIDGET r                                : gt::Rg_Widget_Type) =>  (get_widget_layout_hint r).pixels_high_min;
                    high_min_for_widget ( widget as gt::RG_ROW    { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_min;
                    high_min_for_widget ( widget as gt::RG_COL    { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_min;
                    high_min_for_widget ( widget as gt::RG_GRID   { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_min;
                    high_min_for_widget ( widget as gt::RG_MARK   { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_min;
                    high_min_for_widget ( widget as gt::RG_FRAME  { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_min;
                    high_min_for_widget  _                                                                               =>   0;
                end;

                fun wide_cut_for_widget ( widget as gt::RG_WIDGET r                                : gt::Rg_Widget_Type) =>  (get_widget_layout_hint r).pixels_wide_cut;
                    wide_cut_for_widget ( widget as gt::RG_ROW    { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_cut;
                    wide_cut_for_widget ( widget as gt::RG_COL    { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_cut;
                    wide_cut_for_widget ( widget as gt::RG_GRID   { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_cut;
                    wide_cut_for_widget ( widget as gt::RG_MARK   { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_cut;
                    wide_cut_for_widget ( widget as gt::RG_FRAME  { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_wide_cut;
                    wide_cut_for_widget _                                                                                =>  1.0;
                end;

                fun high_cut_for_widget ( widget as gt::RG_WIDGET r                                : gt::Rg_Widget_Type) =>   (get_widget_layout_hint r).pixels_high_cut;
                    high_cut_for_widget ( widget as gt::RG_ROW    { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_cut;
                    high_cut_for_widget ( widget as gt::RG_COL    { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_cut;
                    high_cut_for_widget ( widget as gt::RG_GRID   { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_cut;
                    high_cut_for_widget ( widget as gt::RG_MARK   { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_cut;
                    high_cut_for_widget ( widget as gt::RG_FRAME  { widget_layout_hint => h,  ... }: gt::Rg_Widget_Type) =>  (*h).pixels_high_cut;
                    high_cut_for_widget  _                                                                               =>  1.0;
                end;

                fun assign_sites_to_all_widgets
                      ( site:                           g2d::Box,                                                       # This is the available window rectangle to divide between our widgets.
                        subwindow_or_view:              gt::Subwindow_Or_View,                                          # This is the pixmap on which our site is located.
                        rg_widget:                      gt::Rg_Widget_Type                                              # This is the tree of widgets -- possibly a single leaf widget.
                      )
                    =
                    case rg_widget
                        #
                        gt::RG_MARK r
                            =>
                            {
                                r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
                                #
                                min_widths =    wide_min_for_widget  r.widget;                                          # Compute total pixels needed by fixed-width widgets.  Fixed-width widgets get first call on available space; variable-width widgets divide up what is left.
                                total_cut  =    wide_cut_for_widget  r.widget;                                          # Sum cut values of all widgets. Each variable-width widget will get widget.share/total_cut of sharable_pixels.  Which might be zero.

                                total_cut  =    if (total_cut > 0.0)    total_cut;
                                                else                    1.0;                                            # Prevent divide-by-zero in subsequent logic.
                                                fi;

                                site -> { row, col, high, wide };

                                sharable_pixels                                                                         # Compute pixels remaining after all fixed-width widgets have been given their cut.
                                    =
                                    if (wide > min_widths)      float::from_int  (wide - min_widths);                   #
                                    else                        0.0;                                                    # No pixels left after giving fixed-width widgets their allotments.
                                    fi;

                                wide_min = wide_min_for_widget  r.widget;
                                wide_cut = wide_cut_for_widget  r.widget;

                                pixels_for_this_widget
                                    #
                                    =                wide_min
                                    + float::floor ((wide_cut / total_cut) * sharable_pixels);

                                site = { row, col, high, wide => pixels_for_this_widget };

                                assign_sites_to_all_widgets                                                             # This widget may be a nested ROW, COL, GRID, SCROALLBLE_VIEW (...) so assign sites recursively within it.
                                  (
                                    site,
                                    subwindow_or_view,
                                    r.widget
                                  );
                            };

                        gt::RG_ROW r
                            =>
                            {   r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
                                #
                                widgets    =  r.widgets;

                                fun assign_sites_to_widgets  (widgets, site, dry_run, first_widget, extra_pixels_left, total_pixels_allocated)
                                    =
                                    {
                                        my (site, widgets, widget1_pixels)
                                            =
                                            case (r.first_cut, widgets)
                                                #
                                                (THE fraction, first_widget ! remaining_widgets)                                # If RG_ROW.first_cut is set  *and*  we have at least two widgets in the ROW
                                                    =>                                                                          # then 'fraction' overrides our usual pixel-allocation formula.  We use this mechanism to support  "C-x ^"  in our emacs-ish editor.
                                                    {   site -> { row, col, high, wide };
                                                        #
                                                        pixels_for_first_widget
                                                            =
                                                            float::floor (fraction * (float::from_int wide));

                                                        if (not dry_run)                                                        # Allocate pixels to first_widget specially.
                                                            #
                                                            site1 = { row, col, high, wide => pixels_for_first_widget };

                                                            assign_sites_to_all_widgets                                         # This widget may be a nested ROW, COL, GRID, SCROALLBLE_VIEW (...) so assign sites recursively within it.
                                                              (
                                                                site1,
                                                                subwindow_or_view,
                                                                first_widget
                                                              );
                                                        fi;

                                                        site =  { row,   col  => col  + pixels_for_first_widget,                # Allocate pixels to the remaining widgets normally.
                                                                  high,  wide => wide - pixels_for_first_widget
                                                                };

                                                        (site, remaining_widgets, pixels_for_first_widget);
                                                    };

                                                _ => (site, widgets, 0);                                                        # Normal case:  All widgets get allocated space by same logic.
                                            esac;

                                        min_widths =    int::sum  (map  wide_min_for_widget  widgets);                          # Compute total pixels needed by fixed-width widgets.  Fixed-width widgets get first call on available space; variable-width widgets divide up what is left.
                                        total_cut  =  float::sum  (map  wide_cut_for_widget  widgets);                          # Sum cut values of all widgets. Each variable-width widget will get widget.share/total_cut of sharable_pixels.  Which might be zero.

                                        total_cut  =    if (total_cut > 0.0)    total_cut;
                                                        else                    1.0;                                            # Prevent divide-by-zero in subsequent logic.
                                                        fi;

                                        site -> { row, col, high, wide };

                                        sharable_pixels                                                                         # Compute pixels remaining after all fixed-width widgets have been given their cut.
                                            =
                                            if (wide > min_widths)      float::from_int  (wide - min_widths);                   #
                                            else                        0.0;                                                    # No pixels left after giving fixed-width widgets their allotments.
                                            fi;


                                        fun assign_sites_to_widgets' ([], col, dry_run, first_widget, extra_pixels_left, total_pixels_allocated)
                                                =>
                                                total_pixels_allocated;

                                            assign_sites_to_widgets'
                                                  (
                                                    (w as (widget: gt::Rg_Widget_Type))  !  rest,
                                                    col,
                                                    dry_run,
                                                    first_widget,
                                                    extra_pixels_left,
                                                    total_pixels_allocated
                                                  )
                                                =>
                                                {
                                                    pixels_for_this_widget
                                                        #
                                                        =
                                                        {   wide_min = wide_min_for_widget  w;
                                                            wide_cut = wide_cut_for_widget  w;

                                                                             wide_min
                                                            + float::floor ((wide_cut / total_cut) * sharable_pixels);
                                                        };

                                                    my (pixels_for_this_widget, extra_pixels_left)
                                                        =
                                                        if (extra_pixels_left == 0)  (pixels_for_this_widget,     extra_pixels_left    );
                                                        else                         (pixels_for_this_widget + 1, extra_pixels_left - 1);
                                                        fi;

                                                    site = { row, col, high, wide => pixels_for_this_widget };

                                                    if (not dry_run)
                                                        #
                                                        assign_sites_to_all_widgets                                             # This widget may be a nested ROW, COL, GRID, SCROALLBLE_VIEW (...) so assign sites recursively within it.
                                                          (
                                                            site,
                                                            subwindow_or_view,
                                                            widget
                                                          );
                                                    fi;

                                                    assign_sites_to_widgets'                                                    # Do remaining widgets in this ROW.
                                                      (
                                                        rest,
                                                        col + pixels_for_this_widget,
                                                        dry_run,
                                                        FALSE,                                                                  # first_widget
                                                        extra_pixels_left,
                                                        pixels_for_this_widget + total_pixels_allocated
                                                      );
                                                };
                                        end;

                                        total_pixels_allocated
                                            =
                                            assign_sites_to_widgets'  (widgets, col, dry_run, first_widget, extra_pixels_left, total_pixels_allocated)
                                            +
                                            widget1_pixels;

                                        (total_pixels_allocated, sharable_pixels, min_widths);
                                    };

                                (assign_sites_to_widgets (widgets, site, TRUE, TRUE, 0, 0))
                                    ->
                                    (total_pixels_allocated, sharable_pixels, min_widths);

                                extra_pixels_left
                                    =
                                    (min_widths + (float::floor sharable_pixels)) - total_pixels_allocated;

                                assign_sites_to_widgets (widgets, site, FALSE, TRUE, extra_pixels_left, 0);

                                ();
                            };

                        gt::RG_COL r
                            =>
                            {   r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
                                #
                                widgets    =  r.widgets;

                                fun assign_sites_to_widgets  (widgets, site, dry_run, first_widget, extra_pixels_left, total_pixels_allocated)
                                    =
                                    {
                                        my (site, widgets, widget1_pixels)
                                            =
                                            case (r.first_cut, widgets)
                                                #
                                                (THE fraction, first_widget ! remaining_widgets)                                # If RG_ROW.first_cut is set  *and*  we have at least two widgets in the ROW
                                                    =>                                                                          # then 'fraction' overrides our usual pixel-allocation formula.  We use this mechanism to support  "C-x ^"  in our emacs-ish editor.
                                                    {   site -> { row, col, high, wide };
                                                        #
                                                        pixels_for_first_widget
                                                            =
                                                            float::floor (fraction * (float::from_int high));

                                                        if (not dry_run)                                                        # Allocate pixels to first_widget specially.
                                                            #
                                                            site1 = { row, col, wide, high => pixels_for_first_widget };

                                                            assign_sites_to_all_widgets                                         # This widget may be a nested ROW, COL, GRID, SCROALLBLE_VIEW (...) so assign sites recursively within it.
                                                              (
                                                                site1,
                                                                subwindow_or_view,
                                                                first_widget
                                                              );
                                                        fi;

                                                        site =  { col,   row  => row  + pixels_for_first_widget,                # Allocate pixels to the remaining widgets normally.
                                                                  wide,  high => high - pixels_for_first_widget
                                                                };

                                                        (site, remaining_widgets, pixels_for_first_widget);
                                                    };

                                                _ => (site, widgets, 0);                                                        # Normal case:  All widgets get allocated space by same logic.
                                            esac;

                                        min_heights =    int::sum  (map  high_min_for_widget  widgets);                         # Compute total pixels needed by fixed-height widgets.  Fixed-height widgets get first call on available space; variable-height widgets divide up what is left.
                                        total_cut   =  float::sum  (map  high_cut_for_widget  widgets);                         # Sum cut values of all widgets. Each variable-height widget will get widget.share/total_cut of sharable_pixels.  Which might be zero.

                                        total_cut  =    if (total_cut > 0.0)    total_cut;
                                                        else                    1.0;                                            # Prevent divide-by-zero in subsequent logic.
                                                        fi;

                                        site -> { row, col, high, wide };

                                        sharable_pixels                                                                         # Compute pixels remaining after all fixed-width widgets have been given their cut.
                                            =
                                            if (high > min_heights)     float::from_int  (high - min_heights);                  #
                                            else                        0.0;                                                    # No pixels left after giving fixed-width widgets their allotments.
                                            fi;


                                        fun assign_sites_to_widgets' ([], row, dry_run, first_widget, extra_pixels_left, total_pixels_allocated)
                                                =>
                                                total_pixels_allocated;

                                            assign_sites_to_widgets'
                                                  (
                                                    (w as (widget: gt::Rg_Widget_Type))  !  rest,
                                                    row,
                                                    dry_run,
                                                    first_widget,
                                                    extra_pixels_left,
                                                    total_pixels_allocated
                                                  )
                                                =>
                                                {
                                                    pixels_for_this_widget
                                                        #
                                                        =
                                                        {   high_min = high_min_for_widget  w;
                                                            high_cut = high_cut_for_widget  w;

                                                                             high_min
                                                            + float::floor ((high_cut / total_cut) * sharable_pixels);
                                                        };

                                                    my (pixels_for_this_widget, extra_pixels_left)
                                                        =
                                                        if (extra_pixels_left == 0)  (pixels_for_this_widget,     extra_pixels_left    );
                                                        else                         (pixels_for_this_widget + 1, extra_pixels_left - 1);
                                                        fi;

                                                    site = { row, col, wide, high => pixels_for_this_widget };

                                                    if (not dry_run)
                                                        #
                                                        assign_sites_to_all_widgets                                             # This widget may be a nested ROW, COL, GRID, SCROALLBLE_VIEW (...) so assign sites recursively within it.
                                                          (
                                                            site,
                                                            subwindow_or_view,
                                                            widget
                                                          );
                                                    fi;

                                                    assign_sites_to_widgets'                                                    # Do remaining widgets in this ROW.
                                                      (
                                                        rest,
                                                        row + pixels_for_this_widget,
                                                        dry_run,
                                                        FALSE,                                                                  # first_widget
                                                        extra_pixels_left,
                                                        pixels_for_this_widget + total_pixels_allocated
                                                      );
                                                };
                                        end;

                                        total_pixels_allocated
                                            =
                                            assign_sites_to_widgets'  (widgets, row, dry_run, first_widget, extra_pixels_left, total_pixels_allocated)
                                            +
                                            widget1_pixels;

                                        (total_pixels_allocated, sharable_pixels, min_heights);
                                    };

                                (assign_sites_to_widgets (widgets, site, TRUE, TRUE, 0, 0))
                                    ->
                                    (total_pixels_allocated, sharable_pixels, min_heights);

                                extra_pixels_left
                                    =
                                    (min_heights + (float::floor sharable_pixels)) - total_pixels_allocated;

                                assign_sites_to_widgets (widgets, site, FALSE, TRUE, extra_pixels_left, 0);

                                ();
                            };

                        gt::RG_GRID r
                            =>
                            {   r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
                                #
                                grid =  compute_size_preferences_for_grid_rows (r.widgets, 0, []);

                                rows            =             grid;                                                     # Rows    of grid, so we can compute column-by-row    values conveniently.
                                cols            =  grid_cols  grid;                                                     # Columns of grid, so we can compute column-by-column values conveniently.

                                row_high_mins   =  map  find_max_of_pixels_high_mins  rows;                             # The min height for each row is the max of the min-heights of the widgets in that row.
                                col_wide_mins   =  map  find_max_of_pixels_wide_mins  cols;                             # The min width  for each col is the max of the min-widths  of the widgets in that col.

                                row_high_cuts   =  map  find_max_of_pixels_high_cuts  rows;                             # 
                                col_wide_cuts   =  map  find_max_of_pixels_wide_cuts  cols;                             # 

                                row_highs       =  pl::zip (row_high_mins, row_high_cuts);
                                col_wides       =  pl::zip (col_wide_mins, col_wide_cuts);

                                total_high_min  =  int::sum  row_high_mins;                                             # The min height for the grid widget is the sum of the row min-heights.
                                total_wide_min  =  int::sum  col_wide_mins;                                             # The min width  for the grid widget is the sum of the col min-widths.

                                total_high_cut  =  float::sum  row_high_cuts;                                           # The grid high-cut is max high-cut over all rows in the grid.
                                total_wide_cut  =  float::sum  col_wide_cuts;                                           # The grid wide-cut is max wide-cut over all cols in the grid.

                                total_high_cut  =  if (total_high_cut > 0.0)    total_high_cut;
                                                   else                         1.0;                                    # Prevent divide-by-zero in subsequent logic.
                                                   fi;

                                total_wide_cut  =  if (total_wide_cut > 0.0)    total_wide_cut;
                                                   else                         1.0;                                    # Prevent divide-by-zero in subsequent logic.
                                                   fi;

                                site -> { row, col, high, wide };

                                sharable_vertical_pixels                                                                # Compute pixels remaining after all fixed-height widgets have been given their cut.
                                    =
                                    if (high > total_high_min)  float::from_int  (high - total_high_min);               #
                                    else                        0.0;                                                    # No pixels left after giving fixed-height widgets their allotments.
                                    fi;

                                sharable_horizontal_pixels                                                              # Compute pixels remaining after all fixed-height widgets have been given their cut.
                                    =
                                    if (high > total_wide_min)  float::from_int  (wide - total_wide_min);               #
                                    else                        0.0;                                                    # No pixels left after giving fixed-height widgets their allotments.
                                    fi;

                                col_wides                                                                               # For each column, its width in pixels.
                                    = 
                                    map  assign_width_to_column  col_wides
                                    where
                                        fun assign_width_to_column (col_wide_min, col_wide_cut)
                                            =
                                            {
                                                pixels_for_this_col     =                col_wide_min
                                                                        + float::floor ((col_wide_cut / total_wide_cut) * sharable_horizontal_pixels);

                                                pixels_for_this_col;
                                            };
                                    end;                                                                                # NB: The 'floor' op results in fractional pixels being discarded.
                                                                                                                        #     We should distribute them among the widgets instead -- see
                                                                                                                        #     the RG_ROW and RG_COL logic for guidance. XXX SUCKO FIXME.

                                row_highs                                                                               # For each row, its height in pixels.
                                    = 
                                    map  assign_width_to_row  row_highs
                                    where
                                        fun assign_width_to_row (row_high_min, row_high_cut)
                                            =
                                            {
                                                pixels_for_this_row     =                row_high_min
                                                                        + float::floor ((row_high_cut / total_high_cut) * sharable_vertical_pixels);

                                                pixels_for_this_row;
                                            };
                                    end;

                                assign_sites_to_grid_widget_rows  (grid, row, col)
                                    where
                                        fun assign_sites_to_grid_widget_rows
                                              (
                                                []:             List(List(Sized_Widget)),                               # We need to assign window sites to all these widgets
                                                row:            Int,                                                    # This tracks which   vertical window pixel on which current widget should be located.
                                                col:            Int                                                     # This tracks which horizontal window pixel on which current widget should be located.
                                              )
                                                =>
                                                ();

                                            assign_sites_to_grid_widget_rows (widget_row ! rest,  row,  col)
                                                =>
                                                {   high = assign_sites_to_grid_widget_row  (widget_row, row, col);
                                                    #
                                                    assign_sites_to_grid_widget_rows (rest, row + high, col);
                                                }
                                                where
                                                    fun assign_sites_to_grid_widget_row
                                                          (
                                                            []:                 List(Sized_Widget),
                                                            row:                Int,                                    # Which pixel row in window coordinates should current widget be located at?
                                                            col:                Int                                     # Which pixel col in window coordinates should current widget be located at?
                                                          )
                                                            =>
                                                            0;

                                                        assign_sites_to_grid_widget_row (widget ! rest,  row,  col)
                                                            =>
                                                            {   wide = list::nth (col_wides, widget.col_number);
                                                                high = list::nth (row_highs, widget.row_number);

                                                                site = { row, col, wide, high };

                                                                assign_sites_to_all_widgets                             # This widget may be a nested ROW, COL, GRID, SCROALLBLE_VIEW (...) so assign sites recursively within it.
                                                                  (
                                                                    site,
                                                                    subwindow_or_view,
                                                                    widget.rg_widget
                                                                  );

                                                                assign_sites_to_grid_widget_row (rest, row, col + wide);

                                                                high;
                                                            };
                                                    end;
                                                end;
                                        end;
                                    end;
                            };

                        gt::RG_SCROLLPORT r
                            =>
                            {
                                r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
                                #
                                # Now to do recursive layout of this view:

                                subwidget       =  *r.rg_widget;
                                pixmap_size     =   r.pixmap.size;

                                subsite = { row  => 0,  high => pixmap_size.high,                                       # Initially we have the entire subwindow_or_view for the view available for assignment to widgets.
                                            col  => 0,  wide => pixmap_size.wide
                                          };

                                subpixmap = gt::SCROLLABLE_INFO r;

                                assign_sites_to_all_widgets (subsite, subpixmap, subwidget);                            # Recursively lay out the view's widget-tree on its pixmap.
                            };

                        gt::RG_TABPORT r
                            =>
                            {
                                r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
                                #
############
# This is untested, immature code.  'pixmap_size' is inherited from
# scrollport, where it makes sense, since the size of the scrollable
# area visible through the viewport bears no necessary relation to
# scrollport.
#
# But the tabs all have the same size at the tabport, so either we
# should resize our pixmaps dynamically once we know what our site
# size is, or else maybe we shouldn't have per-tab pixmaps at all,
# and should just render our widgets directly onto our parent.
#
# This needs thought.  For now, the below code is at least a placeholder
# and a zero-th order approximation to what we need.
#
# The following magic constant is also buried in
#     pg_widget__to__rg_widget/do_pg_widget/gt::RG_TABPORT in src/lib/x-kit/widget/gui/guiboss-imp.pkg
############
                                pixmap_size = { high => 400, wide => 800 }:     g2d::Size;

                                apply   do_tab   r.tabs                                                                 # 
                                        #                                                                               # 
                                        where
                                            fun do_tab (subpixmap: gt::Tabbable_Info)
                                                =
                                                {   subpixmap ->  { rg_widget => subwidget, pixmap => view_pixmap, ... };

                                                    # Now to do recursive layout of this view:
                                                    #
                                                    subsite = { row  => 0,  high => pixmap_size.high,                   # Initially we have the entire subwindow_or_view for the view available for assignment to widgets.
                                                                col  => 0,  wide => pixmap_size.wide
                                                              };

                                                    subpixmap =  gt::TABBABLE_INFO subpixmap;

                                                    assign_sites_to_all_widgets (subsite, subpixmap, subwidget);        # Recursively lay out the view's widget-tree on its pixmap.
                                                };
                                        end;
                            };

                        gt::RG_FRAME r
                            =>
                            {
                                r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
                                #
                                assign_sites_to_all_widgets (site, subwindow_or_view, r.frame_widget);                  # Assign full site to frame_widget, which will almost always be   src/lib/x-kit/widget/leaf/frame.pkg
                                                                                                                        #                                                            or   src/lib/x-kit/widget/leaf/popupframe.pkg
                                frame_indent_hint
                                    =
                                    case r.frame_widget
                                        #
                                        gt::RG_WIDGET { guiboss_to_widget, ... }
                                            =>
                                            guiboss_to_widget.get_frame_indent_hint ();

                                        _   => gt::default_frame_indent_hint;
                                    esac;

                                indented_site =  gtj::make_nested_box (site, frame_indent_hint);

                                assign_sites_to_all_widgets (indented_site, subwindow_or_view, r.widget);               # Recursively lay out the framed widgets. We expect r.widget to typically be a ROW, COL or GRID compound widget.
                            };

                        gt::RG_WIDGET (r as { guiboss_to_widget, ... })
                            =>
                            {
                                r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
                                #
                                widget_site_info
                                  =
                                  { id                  =>  guiboss_to_widget.id,
                                    subwindow_or_view   =>  subwindow_or_view,
                                    site
                                  };

                                sites := idm::set (*sites,  guiboss_to_widget.id, widget_site_info);
                            };

                        gt::RG_OBJECTSPACE r
                            =>
                            {
                                r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
msg = sprintf "do_re_site_widget_tree/pass2/OBJECTSPACE unimplemented";
nb {. msg; };
raise exception DIE msg;
                            };
                        gt::RG_SPRITESPACE r
                            =>
                            {
                                r.site    :=  site;                                                                     # Remember this widget's assigned site on its home pixmap.
msg = sprintf "do_re_site_widget_tree/pass2/SPRITESPACE unimplemented";
nb {. msg; };
raise exception DIE msg;
                            };

                        gt::RG_NULL_WIDGET /* r */
                            =>
                            ();
                    esac;       
            end;



#       fun lay_out_subwindow
#             (
#               subwindow_info:                 gt::Subwindow_Data,                                                     # 
#               hostwindow_for_gui:             gtg::Guiboss_To_Hostwindow,                                             # This provides redraw_all_guipanes with the window on which to do the redraw.
#               me:                             gt::Guiboss_State,
#               to:                             Replyqueue
#             )
#           =
#           {
#               hostwindow_for_gui.pass_window_site  to
#                   #
#                   (\\ ({ size => { high => hostwindow_high, wide => hostwindow_wide }, ... }: g2d::Window_Site)               # hostwindow_high and hostwindow_wide are currently unused, but you'd think we'd need them eventually.
#                       =
#                       {
#                           subwindow_info
#                               =
#                               case subwindow_info
#                                   #
#                                   gt::SUBWINDOW_DATA r
#                                       =>
#                                       r;
#                               esac;

# #     gwl::lay_out_widgets                                                                                            # Assign to each widget in given widget-tree a pixel-rectangle on which to draw itself, in window coordinates.
# #       :
# #       { site:                       g2d::Box,                                                                       # This is the available window rectangle to divide between our widgets.
# #         rg_widget:                  gt::Rg_Widget_Type,                                                                     # This is the tree of widgets -- possibly a single leaf widget.
# #         subwindow_info:             gt::Subwindow_Data,
# #         widget_layout_hints:        im::Map( gt::Widget_Layout_Hint ),
# #         me:                         gt::Guiboss_State
# #       }
# #       -> im::Map( Widget_Site_Info );                                                                               # Our result is a map from widget ids to assigned sites.

#                           subwindow_info
#                             ->
#                             { guipane:        Ref( Null_Or( gt::Guipane ) ),
#                               pixmap:         Ref( g2p::Gadget_To_Rw_Pixmap ),                                        # Main backing store for this running gui.
#                               popups:         Ref(List(gt::Subwindow_Data)),                                          # These will all be SUBWINDOW_INFO, so 'Ref(List(gt::Subwindow_Info))' would be a better type here.
#                               parent:         Null_Or( gt::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.
#                             };

#                           case *guipane
#                               #
#                               NULL => ();
#                               THE guipane
#                                   =>
#                                   {
#                                       hostwindow_info = idm::get_or_raise_exception_not_found (*me.hostwindows, hostwindow_for_gui.id)
#                                                        except
#                                                            NOT_FOUND = {   printf                "*me.hostwindows contains no entry for hostwindow %d?!   -- restart_gui' in guiboss-imp.pkg\n" (id_to_int hostwindow_for_gui.id);
#                                                                            log::fatal (sprintf "*me.hostwindows contains no entry for hostwindow %d?!   -- restart_gui' in guiboss-imp.pkg" (id_to_int hostwindow_for_gui.id));
#                                                                            raise exception NOT_FOUND;                                 # Execution will never reach this point, but the compiler doesn't know that log::fatal doesn't return.
#                                                                        };
#                                       (*pixmap).size -> { high, wide };

#                                       site =  { col => 0,  high,                                                                              # Allocate all of window pixel area to widgets in guipane.rg_widget widget-tree.
#                                                 row => 0,  wide
#                                               }
#                                               : g2d::Box;

# #                                                         guipane.guiboss_to_widgetspace.pass_re_siting_done_flag                                             # Ask widgetspace-imp to re-do widget layout for this gui (either the base gui for this hostwindow or else a popup gui for this hostwindow).
# #                                                             ( site,
# #                                                               guipane.subwindow_info,
# #                                                               guipane.rg_widget,
# #                                                               *me.widget_layout_hints
# #                                                             )
# #                                                             to
# #                                                             {.
# # # The code hereabouts was adapted from  restart_gui'
# # # which does the following, but if this is needed at
# # # all it seems like it should be done in redraw_all_guipanes
# # # (below) rather than here, so I've commented it out for now: -- 2015-01-17 CrT
# # #
# # #                                                               gtj::guipane_postorder_apply                                                        # If a view pixmap is too small to fill its scrollport there will be undefined pixels showing in the scrollport.
# # #                                                                 (                                                                                 # By setting the upperleft to its default 0,0 we trigger the logic to black out these undefined areas.
# # #                                                                   guipane,                                                                        # Does doing so result in a double-draw of views at GUI startup?  If so, that might someday prove problematic: XXX QUERO FIXME
# # #                                                                   [ gt::RG_SCROLLPORT_FN
# # #                                                                       \\ (scrollable_view: gt::Scrollable_View)
# # #                                                                           =
# # #                                                                           (*scrollable_view.scroller).set_scrollport_upperleft
# #                                                                                 #
# # #                                                                               *scrollable_view.upperleft
# # #                                                                   ]
# # #                                                                 );
# # 
# #                                                                 ();
# #                                                             }; 

#                                       gwl::lay_out_widgets                                                                    # Assign to each widget in given widget-tree a pixel-rectangle on which to draw itself, in window coordinates.
#                                         {
#                                           me,
#                                           site,                                                                                       # This is the available window rectangle to divide between our widgets.
#                                           rg_widget,                                                                          # This is the tree of widgets -- possibly a single leaf widget.
#                                           subwindow_info,
#                                           widget_layout_hints,
#                                           note_widget_site'
#                                         };

# # # The code hereabouts was adapted from  restart_gui'
# # # which does the following, but if this is needed at
# # # all it seems like it should be done in redraw_all_guipanes
# # # (below) rather than here, so I've commented it out for now: -- 2015-01-17 CrT
# # #
# # #                                                               gtj::guipane_postorder_apply                                                        # If a view pixmap is too small to fill its scrollport there will be undefined pixels showing in the scrollport.
# # #                                                                 (                                                                                 # By setting the origin to its default 0,0 we trigger the logic to black out these undefined areas.
# # #                                                                   guipane,                                                                        # Does doing so result in a double-draw of views at GUI startup?  If so, that might someday prove problematic: XXX QUERO FIXME
# # #                                                                   [ gt::RG_SCROLLPORT_FN
# # #                                                                       \\ (scrollable_view: gt::Scrollable_View)
# # #                                                                           =
# # #                                                                           (*scrollable_view.scroller).set_scrollport_upperleft
# #                                                                                 #
# # #                                                                               *scrollable_view.upperleft
# # #                                                                   ]
# # #                                                                 );
# # 
# #                                                                 ();
# #                                                             }; 
#                                   };  
#                           esac;
#                       }
#                   );
#           };

#       fun lay_out_all_guipanes                                                                                        # This fn is intended to re-layout all running guis for one hostwindow.  Untested but should be at least approximately right. -- 2015-01-17 CrT
#             (                                                                                                         # 
#               subwindow_info:                 gt::Subwindow_Data,                                                     # This provides redraw_all_guipanes an entrypoint into the remaining Subwindow_Or_View tree. Any Subwindow_Or_View in the tree would do.
#               hostwindow_for_gui:             gtg::Guiboss_To_Hostwindow,                                             # This provides redraw_all_guipanes with the window on which to do the redraw.
#               me:                             gt::Guiboss_State,
#               to:                             Replyqueue
#             )
#           =
#           {
#               subwindow_datas_to_lay_out
#                   =
#                   gtj::find_all_subwindow_datas_above_given_stacking_order
#                       #
#                       (subwindow_info, 0);                                                                            # 'stacking_order' fields are always positive, so searching for all Subwindow_Or_View instances with stacking_order > 0 gets us everything.     

#               apply   lay_out_one_subwindow  subwindow_datas_to_lay_out;
#                       where
#                           fun lay_out_one_subwindow (subwindow: gt::Subwindow_Data)
#                               =
#                               lay_out_subwindow (subwindow, hostwindow_for_gui, me, to);
#                       end;
#           };  

                                                                                                                        # This is actually operational, currently called (only) from  kill_gui'  in  src/lib/x-kit/widget/gui/guiboss-imp.pkg
        fun redraw_all_guipanes                                                                                         # Intended to be called after changing the popup structure -- killing a popup, moving a popup, whatever. (Not needed after just creating a new popup.)
              (                                                                                                         # For our purposes here the base window is just one more popup, which happens to never go away.  I.e., for us, "popup" == "gt::SUBWINDOW_INFO".
                subwindow_info:                 gt::Subwindow_Data,                                                     # This provides redraw_all_guipanes an entrypoint into the remaining Subwindow_Or_View tree. Any Subwindow_Or_View in the tree would do.
                hostwindow_for_gui:             gtg::Guiboss_To_Hostwindow                                              # This provides redraw_all_guipanes with the window on which to do the redraw.
              )
            =
            {
                subwindow_infos_to_redraw
                    =
                    gtj::find_all_subwindow_datas_above_given_stacking_order
                        #
                        (subwindow_info, 0);                                                                            # 'stacking_order' fields are always positive, so searching for all Subwindow_Or_View instances with stacking_order > 0 gets us everything.     

                apply   redraw_subwindow_info  subwindow_infos_to_redraw
                        where
                            fun redraw_subwindow_info
                                  (
                                    subwindow_info:     gt::Subwindow_Data
                                  )
                                =
                                {
                                    subwindow_info    -> gt::SUBWINDOW_DATA subwindow_info;
                                    subwindow_or_view =  gt::SUBWINDOW_INFO subwindow_info;

                                    size      =  (*subwindow_info.pixmap).size;                                         # Redraw all of running gui.
                                    upperleft =  g2d::point::zero;                                                      # We need from_box to be in subwindow_or_view coordinate system, so upperleft will always be zero.
                                    #
                                    from_box  =  g2d::box::make (upperleft, size);                                      # Our from_box covers the entire popup pixmap, so as to redraw all of it.

                                    gpj::update_offscreen_parent_pixmaps_and_then_hostwindow                            # Redraw all visible parts of popup. (In our situation there is no offscreen updating to be done.)
                                        #
                                        (subwindow_or_view, from_box, hostwindow_for_gui);
                                };
                        end;
            };  


    };
end;





Comments and suggestions to: bugs@mythryl.org

PreviousUpNext