PreviousUpNext

15.4.1329  src/lib/tk/src/toolkit/tests+examples/simpleinst.pkg

## simpleinst.pkg
## (C) 1996, Bremen Institute for Safe Systems, Universitaet Bremen
## Author: cxl (Last modification by $Author: 2cxl $)
 
# Compiled by:
#     src/lib/tk/src/toolkit/tests+examples/sources.sublib



# ***************************************************************************
#
# Test and example program for generate_gui_g.
#
# This example only knows two object types, texts and numbers. Numbers have
# four different subtypes, corresponding to the four riders of the apocalypse,
# or rather the four basic arithmetic operations. 
#
#
# Texts can be concatened by dropping one onto the other, or they can
# be edited in the construction area. Numbers can added, subtracted
# etc. by dropping them onto each other. If you drag a number object into the 
# con area, a textual representation of the number is appended to the text
# currently under construction. 
#
# There is also the possibility to import a text by calling up the
# file browser and dragging one file into the construction system. 
#
# Use SimpleInst::go() to start. 
#
# $Date: 2001/03/30 13:40:03 $
# $Revision: 3.0 $
#
#
# **************************************************************************



package simple_inst_appl #  : Application 

{
    stipulate
        include package   tk;
        include package   basic_utilities;
    herein     

      #  Instantiating the utility windows 

      # We have text objects and numbers. Numbers have different modes,
      # namely plus, minus, times or div.

       Objtype0 = TEXT | NUM;

       Mode    = PLUS_M | MINUS_M | TIMES_M | DIV_M;

       Part_Type = (Objtype0, Null_Or( Mode ));

      fun mode (_, m)
          =
          the m; 

       Name
           =
           String Ref;

      fun mode_name plus_m  => "Add me";
         mode_name minus_m => "Subtract me";
         mode_name times_m => "Multiply me";
         mode_name div_m   => "Divide me"; end;


       Part_Ilk   = TEXTOBJ  (String, Ref( String ))
                      | NUMBER   (Int, Ref( Mode ), Ref( String ));

      fun ord (textobj x, number y)  => LESS;
         ord (textobj (_, x), textobj (_, x')) => string::compare (*x,*x');
         ord (number (_, _, x), number (_, _, x')) => string::compare (*x,*x');
         ord (number x, textobj y)  => GREATER; end;

      fun name_of (textobj (_, x)) => x;
         name_of (number (_, _, x)) => x; end;

      fun rename s (textobj (_, x)) => (x:=s);
         rename s (number (_, _, x)) => (x:=s); end;

      fun reset_name _
          =
          ();

      fun string_of_name s t
          =
          *s;

      fun part_type (textobj _)         => (text, NULL);
          part_type (number (_, m, _))  => (num, THE *m);
      end;

      fun modes (text, _) => [];
         modes (num, _)  => [plus_m, minus_m, times_m, div_m]; end;

      fun sel_mode (textobj _) => plus_m;  #  Disnae matter what we return here 
         sel_mode (number(_, m, _))=> *m; end;

      fun set_mode (textobj _, _)=> ();
         set_mode (number(_, m, _), nu)=>  m:= nu; end;


      fun objlist_type ls
          = 
          {   fun forall p
                  =
                  not o (list::exists (not o p));

              if (forall (\\ oo = fst (part_type oo) == text) ls )
                   THE (text, NULL);
              elif (forall (\\ oo => fst (part_type oo) == num; end ) ls )
                        THE (num, THE plus_m);
              else NULL;
              fi;
          };

       Objectlist = Void -> List( Part_Ilk );
       Cb_Objects = Objectlist;

      fun  cb_objects_abs x = x;
      fun  cb_objects_rep x = x;

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

      fun is_constructed (text, _)  => TRUE;
         is_constructed (num, _)   => FALSE; end;

      fun get_name (textobj(_, nm))    => *nm;
         get_name (number(_, _, nm)) => *nm; end;

      fun sel_name ob
          =
          THE (get_name ob);

      fun label_action { obj, cc }
          =
          { fun set (textobj(_, nm)) nuname   => { nm:= nuname; cc nuname;};
                 set (number(_, _, nm)) nuname => { nm:= nuname; cc nuname;}; end;
            uw::enter_line { title=>"Renaming object", default=>"",
                           prompt=>"Please enter new name: ",
                           width=> 20, cc=>set obj };
          };

      fun set_name (textobj(_, nm), nuname) => nm:= nuname;
         set_name (number(_, _, nm), nuname)  => nm:= nuname; end;

      fun sel_text   (textobj (t, _))= t;
      fun sel_number (number (m, _, _)) = m;

      fun outline _
          =
          FALSE; #  never outline 

      fun icon (ot, m)
          =
          {
              fun iconnm (text, _)     => "note.gif";
                 iconnm (num, THE plus_m)  => "number.gif";
                 iconnm (num, THE minus_m) => "nummin.gif";
                 iconnm (num, THE times_m) => "numtim.gif";
                 iconnm (num, THE div_m)   => "numdiv.gif"; end;

              icons::get_icon (get_lib_path()$"/tests+examples/icons", 
                            iconnm (ot, m));
          };

     #  Configuring generate_gui_g 

     package conf
         = 
         package {                                                              my
             width         = 500;                                              my
             height        = 300;                                              my
             ca_width       = 350;                                              my
             ca_height      = 300;                                              my
             ca_xy          = THE (50, 470);

             fun ca_title nm
                 =
                 "Edit text: " $ nm;
                                                                              my
             icon_name_width = 60;                                               my
             icon_name_font  = tk::SANS_SERIF [tk::SMALL];
                                                                              my
             background    = GREY;
                                                                              my
             move_opaque    = TRUE;
                                                                              my
             one_window     = TRUE;

             fun trashcan_icon ()
                 =
                 icons::get_icon (get_lib_path()$"/icons",
                                                  "trashcan.gif");
                                                                              my
             trashcan_coord = (width - 50, (height div 2) - 50);         
                                                                              my
             delta         = 70;

         };

      #  The standard operations: show & info 

      fun show (textobj (tx, nm))
              => 
              uw::display { title=> *nm, width=> 40, height=> 20,
                         text=> string_to_livetext tx, cc=> \\ _ => (); end  };

          show (number (n, _, nm))
              =>
              uw::display { title=> *nm, width=> 6, height=> 3,
                         text=> string_to_livetext ("Value:  " $ (int::to_string n)),
                         cc=> \\ _ = ()  };
      end;

      fun stat   (textobj (tx, nm))
          => 
          { fun count p = list::length o (list::filter p);
                                                                              my
              tc = explode tx;                                                  my
              nl = count string_util::is_linefeed tc;                           my
              nc = list::length tc;                                             my
              nspc = count char::is_space tc;                                   my
              na = ((count char::is_alpha tc) * 100) div nc;                    my
              st = "\nNumber of lines:  " $ (int::to_string nl) $
                       "\nNumber of chars:  " $ (int::to_string nc) $
                       "\nNumber of spaces: " $ (int::to_string nspc) $
                       "\nPercentage of alphanumerical char's: " $
                          (int::to_string na)$"\n";

              uw::display {
                  title  =>  "Statistics for " + *nm,
                  width  =>  40,
                  height =>  20,
                  text   =>  string_to_livetext st,
                  cc     =>  \\ _ = ()
              };
          };

         stat  (number (n, _, nm))
          => 
          {                                                                 my
              st= "The number has " + (int::to_string ((size (int::to_string n))-1)) + 
                                         " digits.\n";

              uw::display {
                  title  =>  "Statistics for " + *nm,
                  width  =>  40,
                  height =>  20,
                  text   =>  string_to_livetext st,
                  cc     =>  \\ _ = ()
              };
          }; end;


      fun std_ops _
          =
          [   (show, "Show"), 
              (stat, "Info")
          ];


      fun delete _
          =
          ();


      #  Initially appearing objects. 

      fun init ()
          =
          [(number (2, REF plus_m, REF "2"), ((10, 10), SOUTH)),
           (number (4, REF plus_m, REF "4"), ((10, 10), EAST)),
           (number (5, REF plus_m, REF "5"), ((10, 10), SOUTH)),
           (textobj("Bring me my bow of burning gold!\n" + 
                    "Bring me my arrows of desire!\n" + 
                    "Bring me my spear! O clouds unfold!\n" + 
                    "Bring me my chariot of fire!\n", 
                    REF "Jer'lem 1"), ((100, 10), CENTER)),
           (textobj("I will not cease from mental fight\n" + 
                    "Nor shall my sword sleep in my hand\n" + 
                    "Till we have built Jerusalem\n" + 
                    "In England's green and pleasant land\n",
                    REF "Jer'lem 2"), ((100, 10), SOUTH))];

      fun mon_ops _
          =
          [];
                                                                              my
      create_actions = [];

      # For texts, there is just one binary operation: concatenation:

      fun tconc (t1, wh, [], cc_newop) => cc_newop (t1, (wh, SOUTH));
         tconc (t1, wh, t,  cc_newop) => 
                     cc_newop (textobj (string::join "\n" 
                                              (map sel_text (t1 . t)),
                                         REF  (string::join " and " 
                                              (map get_name (t1 . t)))),
                               (wh, SOUTH)); end;

      fun numop (number (n, m, _), wh, ls, cc_newop)
          =
          { fun appl_op [] => n;
                 appl_op ((number (n, m, _)) . ns) => 
                  case *m    plus_m  => (appl_op ns)+n;
                            minus_m => (appl_op ns)-n;
                            times_m => (appl_op ns)*n;
                            div_m   => (appl_op ns) div n; esac; end;
              nunum = appl_op ls; 

              cc_newop (number (nunum, m, REF (int::to_string nunum)), (wh, SOUTH));
          };


      fun bin_ops ((text, _), (text, _)) => THE tconc;
         bin_ops ((num, _), (num, _))   => THE numop;
         bin_ops (_, _)               => NULL; end;

      # The Construction Area.
      # 
      # The Construction Area essentially consists of a text widget
      # which can be used to edit the text. If another text is dragged
      # down from the manipulation area, it will appended at the end.

      fun tx_id ws_id
          =
          make_sub_widget_id (ws_id, "xTxEd");

      Ca = Widget_Id;


      join_cr = string::join "\n"; 

      fun area_ops (text, _) wid ls
          => 
          tk::set_text_end (tx_id wid) (join_cr (map sel_text ls)); 

         area_ops (num, _) wid ls
          =>
          tk::set_text_end (tx_id wid) (join_cr (map (int::to_string o sel_number) ls)); end;



      fun area_open (window, textobj (tx, nm), cc)
          = 
          {
              ws_wid = make_widget_id();

              title = LABEL {
                          widget_id => make_widget_id(), 
                          packing_hints => [PACK_AT TOP, FILL ONLY_X], 
                          traits => [RELIEF GROOVE, BORDER_THICKNESS 2,
                                         TEXT *nm],
                          event_callbacks => []
                      };

              txwid = TEXT_WIDGET {
                          widget_id => tx_id ws_wid,
                          scrollbars => AT_RIGHT, 
                          live_text => string_to_livetext tx,
                          packing_hints => [FILL XY], 
                          traits => [],
                          event_callbacks => []
                      };

              fun close txid cc nm ()
                  = 
                  cc (textobj (tk::get_tcl_text txid, nm));

              quit  = BUTTON {
                          widget_id    => make_widget_id(),
                          packing_hints => [PACK_AT RIGHT, PACK_AT BOTTOM],
                          traits  => [ TEXT "Close",
                                                CALLBACK (close (tx_id ws_wid) cc nm)
                                              ],
                          event_callbacks => []
                      };

              widgs  = [quit, txwid];                       


              (   ws_wid,

                  if (conf::one_window)  title . widgs;
                                      else widgs;fi,
                  k0
              );
          };

      area_init
          =
          \\ ()=> (); end ; #  no init necessary 


     # Communicating with the Filer:
     #  
     # First, we need to instantiate the clipboard: 
     #
     package clipboard = clipboard_g ( Part = Void -> List( Part_Ilk ); );

     # Instantiate the filer.
     # We need to provide it with a function to convert files to 
     # texts (file_to_part below); we'll do so by reading the file's contents
     # into the text of the object.
     #
     package filer
         =
         filer_g (package options = 
               package {
                 exception NO_FILE  String;
                 fun icons_path () = winix__premicrothread::path::cat (tk::get_lib_path(),
                                                    "icons/filer");
                 icons_size = (40, 10);
                 default_pattern = NULL;
                 fun root () = NULL;
                 default_filter = NULL;

                 package conf= filer_default_config;    # filer_default_config  is from   src/lib/tk/src/toolkit/filer_default_config.pkg

                 package clipboard= 
                     package { #  we have to insert a closure here 
                          Part = List( Part_Ilk );
                         fun  put obs ev cb = 
                             clipboard::put (\\ ()=> obs; end ) ev cb;
                     };

                 filetypes
                     =
                     {
                       fun file_to_part { dir:   String,
                                       file:  String  } =
                       {
                         filenm= "/" + winix__premicrothread::path::make_path_from_dir_and_file { dir, file };
                         objnm = REF ("File: " + file);
                         txt  =
                         {
                           fun read_file si
                               = 
                               if (file::end_of_stream si)
                                    "";
                               else (the_else((file::read_line si), "")) + (read_file si);fi;

                           is  = file::open_for_read filenm;
                           txt = read_file is;
                           file::close_input is;

                           txt;
                         }
                         except
                             NO_FILE f => "NoFile: " + f; end ;

                         [textobj (txt, objnm)];
                       };

                       [ { ext     => [""],
                           display => THE { comment => "Default filetype",
                                            icon    => "unknown_Icon.gif",
                                            preview => NULL:   Null_Or( { dir:   String,
                                                                file:  String }
                                                              -> Void),
                                            file_to_obj => THE file_to_part } } ];
                     };
               };); 
         end;
  };

package simple_inst 
  #  Begin_api my go: Void -> Void end  
{

    include package   tk;

    package simple_gui = generate_gui_g (package appl= simple_inst_appl;);

    exception RESULT  simple_gui::Gui_State;

    fun quit_button window
        =
        { fun confirm_quit ()
                = 
                uw::confirm("Do you really want to quit?",
                           (\\()=> { st= simple_gui::state();
                                     { close_window window;
                                        raise exception RESULT st;};
                                   }; end ));

            BUTTON {
                widget_id => make_widget_id(),
                packing_hints => [PACK_AT BOTTOM, FILL ONLY_X, EXPAND TRUE],
                traits => [RELIEF RIDGE, BORDER_THICKNESS 2,
                             TEXT "Quit", CALLBACK confirm_quit],
                event_callbacks => []
            }; 
        };


    fun filer_button window
        = 
        BUTTON {
            widget_id => make_widget_id(),
            packing_hints => [PACK_AT BOTTOM, FILL ONLY_X, EXPAND TRUE],
            event_callbacks => [],
            traits => [RELIEF RIDGE, BORDER_THICKNESS 2,
                         TEXT "Import File",
                         CALLBACK (\\ _ => simple_inst_appl::filer::enter_file(); end )]
        };

    main_window
        =
        {   wid = make_window_id ();

            make_window {
                window_id => wid, 
                traits => [WINDOW_TITLE "tk Office 2000",
                             WIDE_HIGH_X_Y (NULL, THE (50, 50))],
                subwidgets => PACKED [simple_gui::main_wid wid, 
                                   quit_button wid, filer_button wid],
                event_callbacks => [],
                init => (\\ ()=> simple_gui::init (simple_gui::initial_state()); end )
            };
        };

    fun go ()
        =  
        {   tk::start_tcl [ main_window ];
            simple_gui::initial_state ();
        }
        except
            simple_gui::GENERATE_GUI_FN err
                => 
                {   debug::print 19 ("GenGUI error: " + err);
                    simple_gui::initial_state();
                };

            RESULT state => state;
        end; 
};


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext