MODULE ObxControls;
(**

   project   = "BlackBox"
   organization   = "www.oberon.ch"
   contributors   = "Oberon microsystems"
   version   = "System/Rsrc/About"
   copyright   = "System/Rsrc/About"
   license   = "Docu/BB-License"
   changes   = ""
   issues   = ""

**)

   IMPORT Dialog, Ports, Properties, Views;

   CONST beginner = 0; advanced = 1; expert = 2; guru = 3;   (* user classes *)

   TYPE

      View = POINTER TO RECORD (Views.View)
         size: INTEGER   (* border size in mm *)
      END;
   VAR

      data*: RECORD
         class*: INTEGER;   (* current user class *)
         list*: Dialog.List;   (* list of currently available sizes, derived from class *)
         width*: INTEGER   (* width of next view to be opened. Derived from
                              class, or entered through a text entry field *)
      END;
      predef: ARRAY 6 OF INTEGER;   (* table of predefined sizes *)

   PROCEDURE SetList;


   BEGIN
      IF data.class = beginner THEN
         data.list.SetLen(1);
         data.list.SetItem(0, "default")
      ELSIF data.class = advanced THEN
         data.list.SetLen(4);
         data.list.SetItem(0, "default");
         data.list.SetItem(1, "small");
         data.list.SetItem(2, "medium");
         data.list.SetItem(3, "large");
      ELSE
         data.list.SetLen(6);
         data.list.SetItem(0, "default");
         data.list.SetItem(1, "small");
         data.list.SetItem(2, "medium");
         data.list.SetItem(3, "large");
         data.list.SetItem(4, "tiny");
         data.list.SetItem(5, "huge");
      END
   END SetList;
   (* View *)

   PROCEDURE (v: View) CopyFromSimpleView (source: Views.View);

   BEGIN
      v.size := source(View).size
   END CopyFromSimpleView;
   PROCEDURE (v: View) Restore (f: Views.Frame; l, t, r, b: INTEGER);

   BEGIN   (* fill view with a red square of size v.size *)
      IF v.size = 0 THEN v.size := predef[0] END;   (* lazy initialization of size *)
      f.DrawRect(0, 0, v.size, v.size, Ports.fill, Ports.red)
   END Restore;
   PROCEDURE (v: View) HandlePropMsg (VAR msg: Views.PropMessage);

   BEGIN
      WITH msg: Properties.SizePref DO
         IF v.size = 0 THEN v.size := predef[0] END;   (* lazy initialization of size *)
         msg.w := v.size; msg.h := v.size   (* tell environment about desired width and height *)
      ELSE   (* ignore other messages *)
      END
   END HandlePropMsg;
   (* notifiers *)

   
   PROCEDURE ClassNotify* (op, from, to: INTEGER);
   BEGIN   (* react to change in data.class *)
      IF op = Dialog.changed THEN
         IF (to = beginner) OR (to = advanced) & (data.list.index > 3) THEN
            (* if class is reduced, make sure that selection contains legal elements *)
            data.list.index := 0; data.width := predef[0];   (* modify interactor *)
            Dialog.Update(data)   (* redraw controls where necessary *)
         END;
         SetList;
         Dialog.UpdateList(data.list)   (* reconstruct list box contents *)
      END
   END ClassNotify;
   PROCEDURE ListNotify* (op, from, to: INTEGER);

   BEGIN   (* reacto to change in data.list (index to was selected) *)
      IF op = Dialog.changed THEN
         data.width := predef[to];   (* modify interactor *)
         Dialog.Update(data)   (* redraw controls where necessary *)
      END
   END ListNotify;
   (* guards *)

   PROCEDURE ListGuard* (VAR par: Dialog.Par);

   BEGIN   (* disable list box for a beginner *)
      par.disabled := data.class = beginner
   END ListGuard;
   PROCEDURE WidthGuard* (VAR par: Dialog.Par);

   BEGIN   (* make text entry field read-only if user is not guru *)
      par.readOnly := data.class # guru
   END WidthGuard;
   (* commands *)

   PROCEDURE Open*;

      VAR v: View;
   BEGIN
      NEW(v);   (* create and initialize a new view *)
      v.size := data.width * Ports.mm;   (* define view's size in function of class *)
      Views.OpenAux(v, "Example")   (* open the view in a window *)
   END Open;
BEGIN   (* initialization of global variables *)

   predef[0] := 40; predef[1] := 30; predef[2] := 50;   (* predefined sizes *)
   predef[3] := 70; predef[4] := 20; predef[5] := 100;
   data.class := beginner;   (* default values *)
   data.list.index := 0;
   data.width := predef[0];
   SetList
END ObxControls.