PreviousUpNext

15.4.1314  src/lib/tk/src/toolkit/generate-tree-gui-g.pkg

## generate-tree-gui-g.pkg
## (C) 2000, Albert Ludwigs Universität Freiburg
## Author: bu

# Compiled by:
#     src/lib/tk/src/toolkit/sources.sublib



# ***************************************************************************
# A generic graphical user interface.
# including a navigation pad, but still generic
# in the construction area. 
#  
# See <a href=file:../../doc/manual.html>the documentation</a> for more
# details.  
# "tests+examples/tsimpleinst.pkg" contains a small example of how to
# use this package.
# **************************************************************************



###           "To business that we love,
###               we rise betime
###                  and go to't with delight."
###
###                      -- William Shakespeare



api Tgen_Gui_Api {
     #
     include api Generated_Gui;                         # Generated_Gui is from   src/lib/tk/src/toolkit/generated-gui.api
     #
     package tree_obj:  Ptree_Part_Class;               # Ptree_Part_Class      is from   src/lib/tk/src/toolkit/tree_object_class.api
     create_folder:  tk::Coordinate -> Void;
  };
     

generic package generate_tree_gui_g (package appl: Application;)                # Application   is from   src/lib/tk/src/toolkit/appl.api
# : Tgen_Gui_Api          # XXX BUGGO FIXME why is api not used?

{
    
    stipulate

        include package   tk;
        include package   basic_utilities;
    herein


    default_printmode= { mode       => print::long,
                           printdepth => 100,
                           height     => NULL,
                           width      => NULL };  #  the value is temporary 

    fun debugmsg msg = debug::print 11 ("GenGUI: " + msg);

    fun bool2string TRUE  => "TRUE";
       bool2string FALSE => "FALSE"; end;

#  ************************************************************************ 
#                                                                           
#  Pumping the data-model of APPL (the object_class) on object_class_trees  
#                                                                           
#  ************************************************************************ 

   package m: (weak)  Part_Class                # Part_Class    is from   src/lib/tk/src/toolkit/object_class.api
            =  appl;            # Take just appl, reduce it to its
                                #  Objectclass, and bind it to m

    # I'm not that sure if folder names should remain strings.
    # We must assure uniqueness here - and the string-solution
    # would require that update-operations check this constraint
    # as invariant. Alternative: unique key's... 
    # I'll think about it

   package n: (weak)  Folder_Info               # Folder_Info   is from   src/lib/tk/src/toolkit/tree_object_class.api
            = 
                 package { 
                      Node_Info =  (Ref (String), ((tk::Coordinate, 
                                                    tk::Anchor_Kind)));
                      Subnode_Info = (tk::Coordinate, tk::Anchor_Kind);
                     fun  ord_node ((x, _), (y, _)) = string::compare (*x,*y); 
                     fun  string_of_name_node (s, _) _ = *s;
                     fun  rename_node s (t, _)   = (t:=s);
                     fun  reset_name_node (s, _) = (s:="...");
                 };
  
   package tree_obj
       =
       object_to_tree_object_g (package n = n also m = m;);

   fun name2string x = tree_obj::string_of_name 
                          (tree_obj::path2name x)
                             default_printmode;

   include package   tree_obj;       /* From now on, we'll have treeobjects as objects */ 

#  ************************************************************************ 
#                                                                           
#  TGengui-State                                                            
#                                                                           
#  ************************************************************************ 


   exception GENERATE_GUI_FN  String;

   #  the state comprises a focus and a list of (tree)-objects 
    Gui_State = (Path, List( Part_Ilk ));
    New_Part= Part_Ilk; # Distinction no longer necessary 

   root      = ([]:List( Node_Info ), NULL: Null_Or( basic::Part_Ilk ));

   gui_state = REF (root,[]:List( Part_Ilk ));

   folder_id = REF (0);

   fun select_object_from_guistate path
       = 
       select_from_path (snd *gui_state) path;

   fun eq x y
       =
       case (ord (x, y))
          
            EQUAL => TRUE;
            _     => FALSE;
       esac;

   # Merging into state is useful to keep orders of objects whenever possible.
   # Keeps the presentation og navi-board smooth - notepad::state() yields
   # the state in quite arbitrary orders . . .
   fun  merge s' s''
        =
        {   b =   (list::map_partial_fn (\\ x => list::find (\\ y => eq x y; end ) s''; end ) s'); 
            c =   (list::filter (\\ x => not (list::exists (\\ y => eq x y; end ) s'); end ) s'');
            b @ c;
        };


   fun  update_object_in_guistate ([], NULL) objs
            =>
            gui_state := (fst *gui_state, merge (snd *gui_state) objs);

        update_object_in_guistate path [obj]
            =>
            { my (p, objs) = *gui_state;
              gui_state:=(p, update_at_path objs path obj);
              #  except INCONSIST_PATH => () 
            };
   end;


   #  hooks, refreshManagement; ah, the joys of linear visibility 
                                                                                my
    elim_ob_hook     = REF( NULL: Null_Or( Part_Ilk -> Void ) );                 my
    intro_ob_hook
        =
        REF (NULL: Null_Or( (Part_Ilk, ((tk::Coordinate, tk::Anchor_Kind))) -> Void) );
                                                                                my
    refresh_lab_hook = REF (NULL: Null_Or( (Void -> Void) ));                            my
    sync_hook        = REF (NULL: Null_Or( (Bool -> Void) ));                            my
    sync_back_hook   = REF (NULL: Null_Or( (Void -> Void) ));                            my
    refocus_hook     = REF (NULL: Null_Or( (tree_obj::Path -> Void) ));

   /* used in order to delay sync's, for example for drag-Drop-Actions.
      For efficiency reasons. Could be made easily mor eager . . . 
    */                                                                          my
    force_refresh = REF FALSE;


#  ************************************************************************ 
#                                                                           
#  The common state: the clipboard                                          
#                                                                           
#  ************************************************************************ 

# The application clipboard-class (appl::clipboard) is a flat clipboard - 
# it must be adapted to the above clipboard with tree-objects.


    package canvas_clipboard = appl::clipboard; /* external clipboard for 
                                  communication with ca */

     Objectlist = Void -> List( Part_Ilk );

    package notepad_navigator_clipboard = clipboard_g ( Part = Objectlist;);         
                               /* internal clipboard for communication
                                  between navigation and notepad */     


    fun treeobj2obj x
        =
        if (is_folder x   ) list::cat (list::map treeobj2obj (snd (get_folder x)));
                        else [fst (get_content x)];fi;

    package clipboard  #  sort of "joined clipboard" 
        =
        package {  Part = notepad_navigator_clipboard::Part;

               exception EMPTY = notepad_navigator_clipboard::EMPTY;

               fun put it ev cb
                   =
                   {   notepad_navigator_clipboard::put it ev cb;
                       canvas_clipboard::put (appl::cb_objects_abs
                                                   (\\ ()=> list::cat (list::map 
                                                         treeobj2obj (it())); end )) ev cb;};

               fun get ev
                   =
                   if (notepad_navigator_clipboard::is_empty ev)

                       \\ ()
                           =
                           (list::map
                               (\\ x =  content (x, ((10, 10), CENTER)))
                               (appl::cb_objects_rep (canvas_clipboard::get ev)())
                           )
                           except
                               canvas_clipboard::EMPTY =  raise exception EMPTY;

                   else
                        notepad_navigator_clipboard::get ev;
                   fi;

               fun copy ev
                   =
                   if (notepad_navigator_clipboard::is_empty ev)

                       \\ ()
                           =
                           list::map
                               (\\ x
                                   =
                                   content (x, ((10, 10), CENTER))
                               )
                               (appl::cb_objects_rep
                                    (canvas_clipboard::copy ev)()
                               )
                               except
                                   canvas_clipboard::EMPTY
                                       =
                                       raise exception EMPTY;
                   else
                        notepad_navigator_clipboard::copy ev;
                   fi;
 

               fun is_empty ev
                   =
                   notepad_navigator_clipboard::is_empty ev
                   and
                   canvas_clipboard::is_empty ev;
        };


#  ************************************************************************ 
#                                                                           
#  Instantiate Navigation Board                                             
#                                                                           
#  ************************************************************************ 

   #  the navigationboard 

   package navi_board_actions: (weak)  Treelist_Callbacks               # Treelist_Callbacks    is from   src/lib/tk/src/toolkit/tree-list-g.pkg
   =
   package {
        Part_Ilk       = tree_obj::Part_Ilk;
        Node_Info    = tree_obj::Node_Info;
        Subnode_Info = tree_obj::Subnode_Info;
        Path         = tree_obj::Path;

       fun  content_label_action { path, was, cc } = 
            uw::enter_line { title=>"enter label:",
                         prompt=>"", default=>was, width=>30, 
                         cc=> \\ s => { cc s; the *refresh_lab_hook ();}; end  };

       fun  objtree_change_notifier { changed_at: Path }
            =
            {   debugmsg ( "general change notifier at :" $
                          (name2string changed_at) + "\n");
               the *sync_back_hook ();};



       fun  focus_change_notifier { changed_at: List( Path ) } = 
              { debugmsg ( "notifier activated at :" + 
                       (string::cat 
                       (map name2string changed_at)) +
                       "\n");
               the *refocus_hook (hd (changed_at));};

       fun  open_close_notifier { is_open: Bool, 
                                 changed_at: List( Path ) } = 
              { debugmsg ( "open/close notifier activated at :" + 
                       (string::cat 
                       (map name2string changed_at)) + 
                       " is_open:" +
                       (bool2string is_open) +
                       "\n");
               #  sync just for subtree . . . >>> 
               if (is_prefix (hd changed_at, fst *gui_state))
                    the *sync_hook FALSE;
               fi;
              };


       fun  error_action          s = (uw::error "ERROR" );
   };

    package navi_board
        = 
        tree_list_g (package s = package {
                                 package m  = tree_obj;
                                 package a  = navi_board_actions;
                                  Objlist = Void -> List( Part_Ilk );
                                 package clipboard = clipboard;
                               };);

                                                                                my _ = 
    (.width (navi_board::my_config) := 120);

    fun navi_board window objs
        =
        navi_board::create_canvas objs;


#  ************************************************************************ 
#                                                                           
#  Instantiate notepad_g                                                      
#                                                                           
#  ************************************************************************ 


    #  the construction area frame widget id 
    ca_frame_id  = make_tagged_widget_id("ca");
    #  the widget id of the canvas all the items are placed on 

    #  flag indicating wether the construction area is currently open 
    ca_open     = REF (NULL: Null_Or( Part_Ilk ));

    #  And a function to check that 
    fun is_open ob = case *ca_open    
                       NULL => FALSE; 
                      THE ob2 => case (ord (ob, ob2))   
                                     EQUAL => TRUE;
                                    _     => FALSE; esac; esac;


    fun fst (x, _) = x;
    fun snd (_, x) = x;
    fun justx x y = x;

    # split:  (Node_Info * List( Part_Ilk ) -> X) * 
    #         (Data::Part_Ilk * Subnode_Info -> X)
    #         -> Part_Ilk -> X

    fun split (f, g) obj
        = 
        if (is_folder obj ) f (get_folder obj);
                        else g (get_content obj);fi;

    fun object2newobject ob
        =
        (ob, split (snd o fst, snd) ob);

    fun newobject2object (ob, pos)
        =
        split (\\((n, _), ol)=>folder((n, pos), ol); end, 
                                          \\ (ob, _)=>content (ob, pos); end ) ob;


    #  This could be done generically:  

                                                                                my
    label_action
        =
        (\\ { obj, cc } => 
              (if (is_folder obj )
                  uw::enter_line { title=>"Renaming folder", 
                                   default=>"",
                                   prompt=>"Please enter new name: ",
                                   width=> 20, 
                                   cc=> \\ txt => { rename_node txt (fst (get_folder obj));
                                                    force_refresh:=TRUE; #  shut up optimize !!! 
                                                    navi_board::refresh_label();
                                                  };
                                        end 
                                 };
               else appl::label_action { obj => fst (get_content obj),
                                         cc  => (\\ txt => { cc txt;
                                                             navi_board::refresh_label();
                                                           };
                                                 end
                                                )
                                       };
               fi
              );
         end
        );


    fun is_constructed ot
        =
        if (is_folder_type ot)  FALSE;
        else                    appl::is_constructed (get_content_type ot);
        fi;

     Mode = Null_Or( appl::Mode );

    fun mode ot
        =
        if (is_folder_type ot)  NULL;
        else                    THE (appl::mode (get_content_type ot));
        fi;

    fun modes ot
        =
        if (is_folder_type ot)  [];
        else                    map THE (appl::modes (get_content_type ot));
        fi;

    #  much better ... 
    fun objlist_type [] => NULL;
        objlist_type [a] => THE (part_type a);
        objlist_type (a . r) => 
            if (list::exists (\\ oo => not (part_type a == part_type oo); end ) r ) NULL;
            else THE (part_type a);fi;
    end;

    fun mode_name NULL => "Folder";
        mode_name (THE x) => appl::mode_name x;
    end;

    fun set_mode (ob, m)
        = 
        split (justx (), \\ (ob', _) => appl::set_mode (ob', the m); end ) ob;
                                                                                my
    outline = split (justx FALSE, appl::outline o fst);

    fun delete ob
        = 
        {   fun rem ob ob_s
                =
                list::filter (\\ x => not (ord (x, ob) == EQUAL); end ) ob_s;

            ss = rem ob (snd *gui_state);

            p = fst *gui_state;

            split (justx (), appl::delete o fst) ob;    #  logical delete in application 

            case p 
                #              
                ([], NULL) => { gui_state:=(p, ss);
                              navi_board::upd_guistate p (ss);
                              navi_board::refresh p;};

                (m, NULL) =>  ({ my (n, ss) = get_folder (select_from_path 
                                                             (snd *gui_state) p);
                                 nu_fol = [folder (n, rem ob ss)]; 
                                 update_object_in_guistate p nu_fol;
                                 navi_board::upd_guistate p nu_fol;
                                 navi_board::refresh p;
                               });
            esac;
         };

     fun create_folder (x, y)
         = 
         {   folder_id:= *folder_id + 1;

             fol = folder((REF("Folder " + (int::to_string *folder_id)),
                                   ((x, y), CENTER)), /* will be overwritten by 
                                                         placing . . . */
                                   []);
             (the *intro_ob_hook) (object2newobject fol);  /* Doesn't work well 
                                                               does not acticate 
                                                               "findNicePlace" for 
                                                               some reason XXX BUGGO FIXME */
             (the *sync_hook) TRUE;

         };

    fun show_folder x
        = 
        { my ((nm, _), ol) = get_folder x;
            tx = "This is a folder with " +
                      (int::to_string (length ol)) + " subjects";
          uw::display { title=> *nm, width=> 40, height=> 20,
                   text=> string_to_livetext tx, cc=> \\ _ => (); end  };
        };

    fun stat_folder t_o
        =
        show_folder t_o; #  preliminary HACK ! 



    fun std_ops ot
        = 
        if (is_folder_type ot )

             [ (show_folder, "Show"), 
               (stat_folder, "Info")
             ];
        else
             map (\\ (f, s) =  (split (justx(), f o fst), s)) 
                 (appl::std_ops (get_content_type ot));
        fi;

    fun mon_ops ot
        = 
        if (is_folder_type ot)

             []; #  so far 
        else
             fun conv (h)(ob, c)(f)
                 =
                 h (fst (get_content ob), c)
                                        (\\ (x, y)=(f (content (x, y), y)));

              map (\\ (h, s)= (conv h, s))
                  (appl::mon_ops (get_content_type ot));
        fi;



    fun bin_ops (ot1, ot2)
        = 
        if (is_folder_type ot1)
             #  moving >>> 
             ({ fun hhh (ob, coord, ob_s, f) = { apply (the *elim_ob_hook) ob_s;
                                           #  <<< delete items from Notepad 
                                           the *sync_hook TRUE; 
                                           #  <<< sync notepad with state and redisplay 
                                           /* <<< extremely EXPENSIVE. Could be replaced 
                                              by something that just deletes CITEMS -- 
                                              commenting out results just in WARNINGS like:
                                              WARNING: Exception CANVAS_ITEM: item: anocid115xIcon 
                                              not found */

                                           #  update substate in gui_state und nv-board 
                                           { pp = join_path((fst *gui_state),
                                                                    (name_of ob));
                                               my (n, ss) = get_folder (select_from_path 
                                                                         (snd *gui_state)
                                                                         (pp));
                                            update_object_in_guistate pp [folder (n, ss@ob_s)];
                                              navi_board::upd_guistate pp [folder (n, ss@ob_s)];
                                              navi_board::refresh pp;
                                              /* replace tree-object on note-pad - 
                                                 otherwise correspondence of all three 
                                                 states violated (data-invariant) and
                                                 sync will not work in future >>> */
                                              (the *elim_ob_hook) ob;
                                              (the *intro_ob_hook) 
                                                  (folder (n, ss@ob_s), (coord, CENTER));
                                           } 
                                          ;};
               THE hhh; }); 
        else ({ fun loc_refresh (p as ([], NULL)) ob => ({ ss =snd *gui_state; 
                                                          gui_state:=(p, ss @ [ob]);
                                                            navi_board::upd_guistate p (ss @ [ob]);
                                                            navi_board::refresh p;
                                                         });
                     loc_refresh (p as (m, NULL)) ob => ({ my (n, ss) = get_folder
                                                                         (select_from_path 
                                                                         (snd *gui_state)
                                                                         (p));
                                                            nu_fol = [folder (n, ss @ [ob])]; 
                                                         update_object_in_guistate p nu_fol;
                                                           navi_board::upd_guistate p nu_fol;
                                                           navi_board::refresh p;
                                                        }); end;
                                                         
                  prior = split (justx NULL, THE o fst);
                                          #  filtering folder objects 
                  fun hhh (h)(ob, c, ob_s, f) = h (fst (get_content ob), c,
                                           list::map_partial_fn prior ob_s,
                                           (\\ (x, y)=>{ loc_refresh (fst *gui_state) 
                                                                  (content (x, y));
                                                      f (content (x, y), y);}; end ));
               if   (is_folder_type  ot2)
                   
                    NULL;              #  Dragging folders on basic objs: not considered useful! 
               else
                    case (appl::bin_ops (get_content_type ot1, get_content_type ot2))
                      
                         THE f => THE (hhh f);
                         NULL   => NULL;
                    esac;
               fi;
              });fi;


    fun open_con_area { window, obj, replace_object_action, outline_object_action }
        =
        {
            #  id of the window holding the con/area widgets 

            cawin = if (appl::conf::one_window)
                         window; 
                    else make_window_id ();
                    fi;

            # Event_Callbacks for the con area while open:

            fun ca_enter wsp ev
                =
                {   dropobs = appl::cb_objects_rep (appl::clipboard::copy ev)();
                    oot     = appl::objlist_type dropobs;
                
                    case oot
                      
                         THE ot => appl::area_ops ot wsp dropobs;
                         NULL => ();
                    esac; 
                }
                except
                    appl::clipboard::EMPTY => (); end ;

            fun ca_namings wsp
                = 
                [EVENT_CALLBACK (ENTER, ca_enter wsp)];

            # Event_Callbacks for the con/area while closed:

            ca_closed_namings
                =
                [EVENT_CALLBACK (ENTER, k0)];

            fun close_con_area nu_ob
                =
                {   ca_open := NULL;
                    replace_object_action nu_ob;

                    if (appl::conf::one_window)
                         
                        apply (delete_widget o get_widget_id) 
                            (get_subwidgets (get_widget ca_frame_id));
                    else 
                        close_window cawin;
                    fi;
                };
        
            if (   (is_constructed (part_type obj)) 
               and not (null_or::not_null *ca_open)
               )


                #  get the con/area widgets from the application: 
                my (bobj, _) = get_content obj; /* Folder are never 
                                                 constrcution objects...*/
                my (wsp, wwidgs, init) = appl::area_open (cawin, bobj, 
                                                         close_con_area);
                #  Add con/area event_callbacks to widgets: 
                wwidgs = map (\\ w=> update_widget_event_callbacks w 
                                           ((ca_namings wsp)@
                                            (get_widget_event_callbacks w)); end )
                                             wwidgs;                     

                 outline_object_action ();
                 #  set flag 
                 ca_open := THE obj;

                 if appl::conf::one_window

                      apply (add_widget window ca_frame_id) wwidgs;
                      add_event_callbacks ca_frame_id (ca_namings wsp);
                      init ();
                 else
                       open_window
                           (make_window
                               {
                                   window_id => cawin, 
                                   traits => [WINDOW_TITLE (appl::conf::ca_title 
                                                      (appl::string_of_name
                                                              (appl::name_of bobj)
                                                              (default_printmode))),
                                            WIDE_HIGH_X_Y (THE (appl::conf::ca_width,
                                                              appl::conf::ca_height),
                                                         appl::conf::ca_xy),
                                            WINDOW_GROUP window], 
                                   subwidgets => PACKED wwidgs, 
                                   event_callbacks => [], init
                               }
                           );
                fi;


            else
                debugmsg "Not a primary object, or ConArea already open.";fi;
     };
 
     fun object_action { obj, window,
                       outline_object_action,
                       replace_object_action }
         =
         {   fun name2path_app (p, m) a
                 =
                 (a @ p,  m);

              if (is_folder_type (part_type obj)) 
                  
                   the *refocus_hook
                         (name2path_app (name_of obj) 
                         (fst (fst *gui_state)));
              else
                   open_con_area
                       {
                         obj,
                         window,
                         outline_object_action,
                         replace_object_action
                             =>
                             \\ x
                                 =
                                 replace_object_action (content (x, ((10, 10), CENTER)))
                       };
              fi;
         };

    
     package notepadappl = 
         package { 
            include package   tree_obj;

             Mode = Mode;
            mode = mode;
            modes= modes;
            mode_name = mode_name;
            set_mode  = set_mode;
            outline   = outline;
            std_ops   = std_ops;
            mon_ops   = mon_ops;
            bin_ops   = bin_ops;  
            delete    = delete;

             New_Part = (Part_Ilk, ((tk::Coordinate, tk::Anchor_Kind)));

            objlist_type = objlist_type;

            is_constructed = is_constructed;
            
            object_action = object_action;
                
            label_action  = label_action;

            create_actions = [(\\ { pos=>(x, y), tag=>str } => create_folder (x, y); end, "folder")]; 
            
            is_locked_object = is_open;
            fun init () = map (\\ x=> (content x, snd x); end ) (appl::init()); 

            package conf = appl::conf;

             Objectlist = Void -> List( Part_Ilk );

            package clipboard = clipboard;

         };

    package notepad = notepad_g (package appl = notepadappl;);



#  ************************************************************************ 
#                                                                           
#  sync'ing and refresh                                                     
#                                                                           
#  ************************************************************************ 



    #  sync - routines = synchronize distributed state + refresh. 
    #  implemented unidirectional for efficiency reasons 
    #  here: sync notepad-content with gui_state, and gui_state with 
    #  navi-board-state. 
    fun sync_notepad_with_guistate refresh_naviboard
        = 
        {   path  = fst *gui_state;
            my () = debugmsg("sync: path >" + (name2string path) + "<\n");
             
            case path    
                #
                # Sync at root position:
                #
                ([], NULL)  =>  {   update_object_in_guistate path (map newobject2object (notepad::state()));
                                    navi_board::upd_guistate path (snd *gui_state);
                                    debugmsg "sync root refresh\n";
                                };

                # Sync somewhere deep inside:
                #
                (_, NULL)   =>  {   (get_folder (select_object_from_guistate path))
                                        ->
                                        (n, s');

                                    s'' = map newobject2object (notepad::state());
                                    fol = folder (n, merge s' s'');
                                    update_object_in_guistate path [fol];
                                    navi_board::upd_guistate path [fol];
                                    debugmsg "sync inside refresh\n";
                                };
            esac;

            if refresh_naviboard  navi_board::refresh path; fi;
        };

    fun sync_naviboard_into_guistate ()
        = 
        {   my (ap, st) = *gui_state;
            my ()      = gui_state := (ap, navi_board::get_guistate());

            newobs  =   case ap   
                            ([], NULL) => snd *gui_state;
                            (_, NULL) => snd (get_folder(
                                                   select_object_from_guistate
                                                   ap));
                        esac;
           notepad::init (map object2newobject newobs);
         };

         /* necessary for sync'ing name-changes and moves from
            the naviboard with the notepad (done since names are shared)
            and rearrangements within the naviboard. Thats not implemented 
            so far. . . */ 
                              
   /*        
     fun  create_folder (x, y)
          = 
          (let my ()  = folder_id:= *folder_id + 1;
               fol = Folder((REF("Folder " + (int::to_string *folder_id)),
                                   ((x, y), CENTER)), /* will be overwritten by 
                                                         placing . . . */
                                   [])
           in  notepad::intro (object2newobject fol);  /* doesn't work well 
                                                         does not acticate 
                                                         "findNicePlace" for 
                                                         some reason */
               sync_notepad_with_guistate TRUE
           end);
    */                      




    fun refocus_notepad (path as (m, NULL)) 
            => 
            {   (*gui_state) ->  (act_path, act_state);
                #
                debugmsg("focus: act_path " + (name2string act_path) + 
                               "\n           path " + (name2string path) + "\n");

                fun do_it ()
                    =
                    {   sync_notepad_with_guistate TRUE;
                        #
                        gui_state := (path, snd *gui_state);

                        {   newobs = 
                                       case path    
                                         ([], NULL) => snd *gui_state;
                                        (_, NULL) => snd (get_folder(
                                                      select_object_from_guistate
                                                      path)); esac;
                               notepad::init (map object2newobject newobs);
                        };
                    };

                case (ord_path (path, act_path))   
                    #
                    EQUAL => (if *force_refresh  do_it(); fi);
                    _     => do_it();
                esac;

                force_refresh := FALSE;
         }; 

        refocus_notepad (m, THE _ )
            =>
            refocus_notepad (m, NULL);
    end;


#  ************************************************************************ 
#                                                                           
#  export                                                                   
#                                                                           
#  ************************************************************************ 
   
  
    fun main_wid window
        =
        {   ass_area
                =
                FRAME
                    { widget_id=> make_widget_id(),
                      subwidgets => PACKED [ notepad::main_wid window ],
                      packing_hints => [EXPAND TRUE, FILL XY, PACK_AT RIGHT],
                      traits => [],
                      event_callbacks=> []
                    };

            navi    =  FRAME { widget_id=> make_widget_id(),
                                 subwidgets => PACKED [navi_board window []],
                                 packing_hints => [ EXPAND TRUE, FILL XY, PACK_AT LEFT ],
                                 traits => [], event_callbacks=> [] };
            ass_area_nnavi =  FRAME { widget_id=> make_widget_id(),
                                      subwidgets => PACKED [ass_area, navi],
                                      packing_hints => [ EXPAND TRUE, FILL XY, PACK_AT TOP ],
                                      traits => [],
                                      event_callbacks=> [] };
        
           if (appl::conf::one_window)
               
                FRAME {
                    widget_id=> make_widget_id(),
                    subwidgets => PACKED [ass_area_nnavi,
                                  FRAME { widget_id=>ca_frame_id, 
                                        subwidgets => PACKED [], 
                                        packing_hints => [ FILL ONLY_X, PACK_AT BOTTOM],
                                        traits=> [HEIGHT appl::conf::ca_height],
                                        event_callbacks => [] }
                                ], 
                    packing_hints=> [],
                    event_callbacks=> [],
                    traits=> []
                };
           else
                ass_area_nnavi;
           fi;
        };
    


     #  my init:   gui_state -> Void
     #  Call that as init action of main window

     fun init ((s, NULL), objs)
         => 
         {   fun distinct eq [] => TRUE;
                 distinct eq (a . r) => (not (list::exists (eq a) r))
                                       and (distinct eq r);
             end;
                                       #  too naiv. should be recursively 

             fun eq x y
                 =
                 case (ord (x, y))
                   
                      EQUAL => TRUE;
                      _     => FALSE;
                 esac;

             my () = {  elim_ob_hook     := THE notepad::elim;
                        intro_ob_hook    := THE notepad::intro;
                        refresh_lab_hook := THE (\\ _ => notepad::init (
                                                                  notepad::state()); end ); 
                                                 /* does a complete refresh; a more
                                                    local refresh of labels would increase
                                                    EFFICIENCY here */
                        sync_hook        := THE sync_notepad_with_guistate;
                        sync_back_hook   := THE sync_naviboard_into_guistate;
                        refocus_hook     := THE refocus_notepad;
                     };

             if (distinct eq objs) 
                 
                  gui_state:=((s, NULL), objs);
                  navi_board::upd_guistate (s, NULL) objs;
                  navi_board::refresh (s, NULL);

                  if (null s)            #  focus at root 
                       notepad::init (map object2newobject objs);
                  else refocus_notepad (s, NULL);
                  fi;

                  ca_open   := NULL;
                  appl::area_init();
             else
                  raise exception GENERATE_GUI_FN "generate_tree_gui_g init: objects must be distinct";
             fi;
         };

        init ((s, THE _), objs) => 
         raise exception GENERATE_GUI_FN "generate_tree_gui_g init: path must point to folder"; end;
      

     #  my state:  Void -> gui_state 

     # This is the initial state which only has those objects as given
     # by the application's init() function (see above). 

     fun state ()
         =
         {   sync_notepad_with_guistate TRUE;
             *gui_state;
         };

     # introduce (not "create" really) a new object into the
     # manipulation area
     #     my intro:  New_Part -> Void
     fun intro obj = notepad::intro (object2newobject obj);
         #  NOT YET: probably sync with state and naviboard necessary !!!

     #  my initial_state:  Void -> gui_state 
     fun initial_state () = (([], NULL), map content (appl::init()));
     #  Builds a (flat) gui_state just from appl::init 
     #  Quite old-fashioned, I guess. 


     # Resynchronize all icons, e.g. if objects have changed their mode.
     # (Unfortunately, we cinnae change icons of single objects, since
     #  we can't identify objects...)
     #
     # my redisplay_icons:  (Part_Ilk -> Bool) -> Void

     redisplay_icons = notepad::redisplay_icons;


     end;
};





Comments and suggestions to: bugs@mythryl.org

PreviousUpNext