Classes Extending the Dyalog GUI

Dick Bowman

August 2006 (updated October 2006 - August 2007)

Continuing the explorations of the Dyalog APL/W OOP extensions started with component files, this paper shows some code used to define extensions to the Dyalog APL/W GUI.

The APL/W GUI has been around for some years now and proven quite capable as a framework for constructing reasonably-behaved Windows applications (I know nothing of its portability and usefulness in a Unix/Linux environment).  There's been the implication that customised controls could be built and used, but until the OOP extensions of Version 11 were introduced this seemed (at least to this author) more trouble than it was worth - the OOP extensions make a difference.

The code shown here may be used freely (with attribution to Dogon Research), but should not be regarded as necessarily bug-free (developing these classes has been one of my approaches to learning about Dyalog's OOP facilities - as such the code is not necessarily optimal, and may show various areas of misunderstanding).

Note that the code shown here represents a snapshot of various times; current "live" code usually has been made more flexible/complex.

DogClasses

The table shows which classes are currently available.

NameDescriptionComments
DogButtonButton
DogComboCombo with attached label
DogDateDate-only DateTimePicker with attached labelAdded April 2007
DogEditEdit field with attached label
DogFileEdit field for file specificationAdded November 2006
DogFormForm
DogListListboxAdded March 2007
DogMenuTable-driven menubar menu
DogModalModal FormAdded November 2006
DogPopupTable-driven popup menu
DogRadiosRadio buttons in an implied group
DogTickCheck-style buttonAdded November 2006
DogTimeTime-only DateTimePicker with attached labelAdded April 2007
DogToolTable-driven toolbarAdded December 2006
DogTreeMutation of TreeViewAdded August 2007

Old and New Vernacular

APL/W 11 introduces new syntax to handle the OOP paradigm, and - as the GUI is aligned with this new model - we can (and should?) use this syntax to de-clutter code handling GUI objects.  Principally this comes down to using  ⎕NEW to create GUI objects instead of  ⎕WC ( ⎕WG and  ⎕WS were consigned to your dustbin years ago, weren't they?) and referencing objects directly rather than by name.  I'm finding that this new syntax rather alters my coding style, and may write more on it as and when I settle down.

Old New
'f' ⎕wc 'Form' 'I am a form' ('Coord' 'Pixel')('Size' 100 100)
'f.l' ⎕wc 'Label' 'Hello There' ('Posn' 10 10)('Size' 20 80)
'f.ok' ⎕wc 'Button' 'Press Me' ('Posn' 50 20)('Size' 25 60)
f.Wait
fn←⎕NEW'Form'(('Caption' 'I am a New Form')('Coord' 'Pixel')('Size'(100 100)))
fn.l←fn.⎕new 'Label' (('Caption' 'Hello There')('Posn' (10 10))('Size' (20 80)))
fn.ok←fn.⎕new 'Button'(('Caption' 'Press Me')('Posn' (50 20))('Size' (25 60)))
fn.Wait

The new code is a little more verbose, partly because Dyalog are (here) rather stricter about identity/value pair syntax than used to be the case.

Something that's good about the new syntax is that it's more self-consistent and APLish in the sense that things are made by assignment and we don't have the "sometimes use the name, sometimes use the thing" flavour of arbitrariness that's in the old code.

Design Goals

Having GUI controls defined within code is "good" in so far as it allows the application programmer flexibility - adding, removing, redefining controls on the fly (but these things lead to trouble when overdone), but there are downsides:
The DogControl classes are intended to address these issues; they also implement "compound controls" (where edit controls, for example, are supposed always to be accompanied by a label)

DogButton

:Class DogButton : 'Button' 
⍝ Standardised buttons
⍝ Argument is Caption Posn
    :Field Caption←'Dogon Button'
    ∇ Create args
      :Access Public
      args←(⊂¨(⍴args)↑'Caption' 'Posn'),∘⊂¨args
      :Implements Constructor :Base args,⊂ ('Size' (23 75))
      ⎕DF'[DogForm: ',Caption,']'
    ∇
:EndClass


Makes it easier to create buttons that are all the same size, and to change the standard size if the desire arises (but won't do anything to make sure that form layouts remain usable, of course).

DogCombo

:Class DogCombo : 'SubForm'
⍝ Standardised label/combo
⍝ Argument is Caption Posn Items 
   
    ⎕io←0
    :Field Caption←'Dogon Combo'
   
    :Property Value
    :Access Public
        ∇ z←get
          z←combo.Text
        ∇
    :endProperty
   
    ∇ Create args;size
      :Access Public
      size←50 180
      args←(⊂¨(⍴args)↑'Caption' 'Posn' 'Items'),∘⊂¨args
      :Implements Constructor :Base (1⌷args), ('Size' size)('EdgeStyle' 'Dialog')
      label←⎕NEW'Label'((↑args)('Posn'(10 0))('Size'(20 180)))
      combo←⎕NEW'Combo'((2⌷args),('Posn'(30 0))('Size'(20 180))('Style' 'DropEdit')('SelItems'(1↑⍨⍴2 1⊃args)))
      combo.onKeyPress←'keypress'
      ⎕DF'[DogCombo: ',Caption,']'
    ∇
   
    ∇ z←keypress msg;new;sel
      :If (⊂2⊃msg)∊∪∊(↑msg).Items
          new←(↑msg).Text,2⊃msg
      :AndIf 1=+/sel←(⊂new)≡¨(⍴new)↑¨(↑msg).Items
          (↑msg).Text←∊sel/(↑msg).Items
          (↑msg).SelItems←sel
          z←0
      :Else
          z←1
      :EndIf
    ∇
:EndClass


Again, a little more complex and/or specialised.

DogDate

:Class DogDate : 'SubForm'
⍝:Dogon Research Date-only date/time picker with label
⍝ Argument is Caption Posn Style Date
⍝             Caption Posn Style Date Attach
    :Field Caption←'Dogon Date'
   
    :Property Value
    :Access Public
        ∇ z←get
          z←#.IDNToDate↑dtp.DateTime
        ∇
        ∇ set w
          dtp.DateTime←3↑#.DateToIDN w.NewValue
        ∇
    :endProperty
   
    ∇ Create w;size
      :Access Public
      size←50 180
      :Select ⍬⍴⍴w
      :Case 4
          w,←⊂'nnnn'
      :EndSelect
      (3⊃w)←(#.DateToIDN 3⊃w),0 0 0
      (4⊃w)←translateAttach 4⊃w
      w←(⊂¨(⍴w)↑'Caption' 'Posn' 'Style' 'DateTime' 'Attach'),∘⊂¨w
      :Implements Constructor :Base (1 4⊃¨⊂w), ('Size' size)('EdgeStyle' 'Dialog')
      label←⎕NEW'Label'((↑w)('Posn'(10 0))('Size'(20 180)))
      dtp←⎕NEW'DateTimePicker'(('FieldType' 'Date')(2⊃w)(3⊃w)('Posn'(30 0))('Size'(20 100)))
      ⎕DF'[DogDate: ',Caption,']'
    ∇
   
⍝:Created ⋄ 2007 4 4 14 1 23 921 ⋄ dick ⋄ .\scheduler
⍝:Saved ⋄ 2007 4 4 15 7 3 796 ⋄ dick ⋄ .\scheduler
:EndClass

A straightforward simplification of the DateTimePicker which is part of the APL/W GUI, taking and returning values as year-month-day triplets.

DogEdit

 :Class DogEdit : 'SubForm'
⍝ Standardised label/edit
⍝ Argument is Caption Posn Value Callback
    :Field Caption←'Dogon Edit'
   
    :Property Value
    :Access Public
        ∇ z←get
          z←edit.Value
        ∇
    :endProperty
   
    ∇ Create args;size
      :Access Public
      size←50 180
      args←(⊂¨(⍴args)↑'Caption' 'Posn' 'Value' 'Event'),∘⊂¨args
      :Implements Constructor :Base (1⌷args), ('Size' size)('EdgeStyle' 'Dialog')
      label←⎕NEW'Label'((↑args)('Posn'(10 0))('Size'(20 180)))
      edit←⎕NEW'Edit'((2⌷args),('Posn'(30 0))('Size'(20 180)))
      edit.onChange←'Change'(3 1⊃args)
      ⎕DF'[DogEdit: ',Caption,']'
    ∇
   
    ∇ opt Change msg
      ⍎opt,' 0'
    ∇
:EndClass


A little more ambitious with this one...

DogFile

:Class DogFile : 'SubForm'
⍝ ⍝ Standardised label/edit/button for file selection
⍝ ⍝ Argument is Caption Posn Value
    :Field Caption←'Dogon File'
   
    :Property Value
    :Access Public
        ∇ z←get
          z←edit.Value
        ∇
        ∇ set w
          edit.Value←w.NewValue
        ∇
    :endProperty
   
    ∇ Create args;size;⎕IO;⎕ML
    ⍝ Create the contained controls
      :Access Public
      ⎕IO ⎕ML←0 3
      size←50 280
      args←(⊂¨(⍴args)↑'Caption' 'Posn' 'Value' 'Event'),∘⊂¨args
      :Implements Constructor :Base (1⌷args), ('Size' size)('EdgeStyle' 'Dialog')
      label←⎕NEW'Label'((↑args)('Posn'(10 0))('Size'(20 250)))
      edit←⎕NEW'Edit'((2⌷args),('Posn'(30 0))('Size'(20 250)))
      button←⎕NEW'Button'(('Caption' '...')('Posn'(30 250))('Size'(20 30)))
      button.onSelect←'select'(2 1⊃args)
      ⎕DF'[DogFile: ',Caption,']'
    ∇
   
    ∇ old select msg;file;folder;⎕IO;⎕ML
    ⍝ File selection callback
      ⎕IO ⎕ML←0 3
      folder←↑SplitName old
      file←FileBox'#' 'Output filename'folder'Single' 'Write'(FileFilters'csv')
      :If ×⍴file
          edit.Value←file
      :EndIf
    ∇
:EndClass


DogFile combines an edit field with label and a browse button used to open a file selection dialogue.  Code within the select callback uses external utilities; one of those areas where there's a judgement call to be made whether classes should be self-contained - at this time I'm not using the :Include keyword, maybe that will change (at present these classes are mostly being used within enhancements to older applications and wholesale re-engineering isn't within my horizons).

Inspection of the code shows that some further generalisation is required (at present the class has - as you can see - only been used in one context).

DogForm

 :Class DogForm   : 'Form' 
⍝ Standardised form
⍝ Argument is Caption Size
    :Field Caption←'Dogon Form'
    ∇ Create args
      :Access Public
      args←(⊂¨'Caption' 'Size'),∘⊂¨args
      :Implements Constructor :Base args,⊂ ('Coord' 'Pixel')
      ⎕DF'[DogForm: ',Caption,']'
    ∇
:EndClass

Since my preference is to work in pixel coordinates, this saves the bother of having write it explicitly when defining a form

DogList

:Class DogList : 'SubForm'
⍝ Standardised label/listbox
⍝ Argument is Caption Posn Size Value Callback
⍝             Caption Posn Size Value Callback Attach
    :Field Caption←'Dogon Listbox'
   
    :Property Items
    :Access Public
        ∇ set w
          list.Items←w.NewValue
        ∇
    :endProperty
   
    ∇ Create args
      :Access Public
      :Select ⍬⍴⍴args
      :Case 5
          args,←⊂translateAttach'nnnn'
      :Case 6
          (5⊃args)←translateAttach 4⊃args
      :EndSelect
      args←(⊂¨(⍴args)↑'Caption' 'Posn' 'Size' 'Value' 'Event' 'Attach'),∘⊂¨args
      :Implements Constructor :Base  (1 5⊃¨⊂args),⊂('EdgeStyle' 'Dialog')
      label←⎕NEW'Label'((↑args)('Posn'(10 0))('Size'(20 180)))
      list←⎕NEW'List'((2⌷args),('Posn'(30 0))('Size'((2 1⊃args)-30 0)))
      ⎕DF'[DogList: ',Caption,']'
    ∇
 
:EndClass

Somewhat similar to DogEdit, but (at the time of writing) only supports <set> and has no callback support - easily changed as and when applications begin to need more functionality.
translateAttach is a trivial utility which expands Attach parameters to their full form (l becomes Left, for example)

DogMenu

Askoolum [0] describes an approach to menu construction which is table-driven; this is clearly advantageous in terms of taking form-building out of code and into the realm of data - here's a first cut in implementing something similar as an APL/W class...

Note that DogMenu is new and may be subject to significant redesign - in particular I'm not at all sure that having a base class of MenuBar is correct (developing DogPopup has led me to this supposition)

:Class DogMenu : 'MenuBar'
⍝ Standardised menu
⍝ Argument is  [0] ←→ form
⍝              [1] ←→ matrix of name type caption (callback function) (callback arguments)
    ⎕io←0
    :Field Caption←'Dogon Menu'
   
    ∇ Create args;size
      :Access Public
      form specs←args
      specs←⊂[1]specs
      :Implements Constructor :Base
      :For spec :In specs
          :Select 1⊃spec
          :Case 'Menu'
              ⍎(↑spec),'←⎕NEW''Menu''(,⊂(''Caption''(2⊃spec)))'
          :Case 'Item'
              ⍎(↑spec),'←',({(⍵⍳'.')↑⍵}↑spec),'.⎕NEW''MenuItem''(,⊂(''Caption''(2⊃spec)))'
              ⍎(↑spec),'.onSelect←''Select''(((⊂form.Name),4⊃spec) (3⊃spec))'
          :Case 'Separator'
              ⍎(↑spec),'←',({(⍵⍳'.')↑⍵}↑spec),'.⎕NEW''Separator'' '''''
          :EndSelect
      :EndFor
      ⎕DF'[DogMenu: ',Caption,']'
    ∇
   
    ∇ opt Select msg;arg
      arg←enparen enquote¨↑opt
      ⍎(⍕arg),(1⊃opt),' 0'
    ∇
      enparen←{
          '(',¨(⍕¨⍵),¨')'}
   
      enquote←{
          2=≡⍵:⍵
          0=1↑0⍴⍵:⍵
          '''',⍵,''''}
:EndClass

Which can be driven by a menu specification like this...

.→-6 5------------------------------------------------------------------------------------------------------------------------------.
↓ .→-7----.       .→-4-.      .→-5--.  .⊖.                          .⊖.                                                             |
| |mnuHelp|       |Menu|      |&Help|  | |                          | |                                                             |
| '-------'       '----'      '-----'  '-'                          '-'                                                             |
| .→-13---------. .→-4-.      .→-6---. .→-21-----------------.      .→-3----------------------------------------------------------. |
| |mnuHelp.About| |Item|      |&About| |#.UTIL.HELP.HelpAbout|      | .→-23-------------------. .→-23-------------------. .→-5--. | |
| '-------------' '----'      '------' '---------------------'      | |Dogon Class Maintenance| |Dogon Class Maintenance| |class| | |
|                                                                   | '-----------------------' '-----------------------' '-----' | |
|                                                                   '∊------------------------------------------------------------' |
| .→-12--------.  .→-4-.      .→-5--.  .→-16------------.           .→-10------.                                                    |
| |mnuHelp.Help|  |Item|      |&Help|  |#.UTIL.HELP.Help|           |class.html|                                                    |
| '------------'  '----'      '-----'  '----------------'           '----------'                                                    |
| .→-13---------. .→-9------. .⊖.      .⊖.                          .⊖.                                                             |
| |mnuHelp.Sep10| |Separator| | |      | |                          | |                                                             |
| '-------------' '---------' '-'      '-'                          '-'                                                             |
| .→-13---------. .→-9------. .⊖.      .⊖.                          .⊖.                                                             |
| |mnuHelp.sep10| |Separator| | |      | |                          | |                                                             |
| '-------------' '---------' '-'      '-'                          '-'                                                             |
| .→-12--------.  .→-4-.      .→-6---. .→-26----------------------. .→-2---------------.                                            |
| |mnuHelp.ToDo|  |Item|      |&To Do| |#.UTIL.TODO.ReviewToDoList| | .→-11-------.    |                                            |
| '------------'  '----'      '------' '--------------------------' | |config.dycf| 11 |                                            |
|                                                                   | '-----------'    |                                            |
|                                                                   '∊-----------------'                                            |
'∊----------------------------------------------------------------------------------------------------------------------------------'

DogModal

:Class DogModal : 'Form'
⍝ Standardised modal dialogue
⍝ Argument is Caption Size IconObj
    :Field Private caption←'Dogon Modal Form'
    ∇ Create args
      :Access Public
      args←(⊂¨'Caption' 'Size'),∘⊂¨args
      args,←('Coord' 'Pixel')('EdgeStyle' 'Dialog')('Border' 2)
      :Implements Constructor :Base args
      ⎕DF'[DogModal: ',caption,']'
    ∇   
:EndClass

DogModal is similar in purpose to DogForm, but appropriately bordered for modal use.

DogPopup

DogPopup has a similar goal to DogMenu, but is intended for creation of popup menus

:Class DogPopup : 'Menu'
⍝ Standardised popup menu
⍝ Argument is  [0] ←→ form
⍝              [1] ←→ matrix of name type caption
    ⎕io←0
    :Field Caption←'Dogon Popup Menu'
   
    ∇ Create args;size;specs;spec;form
      :Access Public
      form specs←args
      specs←⊂[1]specs
      :Implements Constructor :Base
      :For spec :In specs
          :Select 1⊃spec
          :Case 'Item'
              ⍎(↑spec),'←⎕NEW''MenuItem''(,⊂(''Caption''(2⊃spec)))'
              ⍎(↑spec),'.Id←''',(↑spec),''''
              ⍎(↑spec),'.onSelect←1'
          :Case 'Separator'
              ⍎(↑spec),'←⎕NEW''Separator'' '''''
          :EndSelect
      :EndFor
      ⎕DF'[DogPopup: ',Caption,']'
    ∇
   
⍝:Saved 2006 10 10 15 57 23 765
:EndClass


Not only have I caught on to local variables, this class may be better defined in terms of a base class of Menu (compare to DogMenu).  The driving table is relatively simpler (because popup menus don't use callback functions)

.→-8 3------------------------------------.
↓ .→-8-----.  .→-4-.      .→-13---------. |
| |InsAbove|  |Item|      |Insert &Above| |
| '--------'  '----'      '-------------' |
| .→-8-----.  .→-4-.      .→-13---------. |
| |InsBelow|  |Item|      |Insert &Below| |
| '--------'  '----'      '-------------' |
| .→-9------. .→-4-.      .→-10------.    |
| |Duplicate| |Item|      |D&uplicate|    |
| '---------' '----'      '----------'    |
| .→-6---.    .→-4-.      .→-7----.       |
| |Delete|    |Item|      |&Delete|       |
| '------'    '----'      '-------'       |
| .→-5--.     .→-9------. .⊖.             |
| |Sep10|     |Separator| | |             |
| '-----'     '---------' '-'             |
| .→-3.       .→-4-.      .→-4-.          |
| |Run|       |Item|      |&Run|          |
| '---'       '----'      '----'          |
| .→-5--.     .→-9------. .⊖.             |
| |Sep20|     |Separator| | |             |
| '-----'     '---------' '-'             |
| .→-6---.    .→-4-.      .→-7----.       |
| |Cancel|    |Item|      |&Cancel|       |
| '------'    '----'      '-------'       |
'∊----------------------------------------'

And, to show how it's used...

form.popSample←form.⎕NEW #.UTIL.DogPopup(form popmenu)

DogRadios

:Class DogRadios : 'Group'
⍝ Group of radio buttons
⍝ Argument is Posn Captions State
    ⎕io ⎕ml←0 3
   
    :Field Caption←'Dogon Radio Buttons'
   
    :Property State
    :Access Public
        ∇ z←Get
          z←(⍎¨¯1↓(⊂[1]⎕NL 9)~¨' ').State
        ∇
    :endProperty
   
    ∇ Create args;posn;labels;count;button;bargs;states
      :Access Public
      posn labels states←args
      count←⍴labels
      :Implements Constructor :Base ('Posn' posn) ('Size' ((20+20×count), 150))
      :For button :In ⍳count
          bargs←'''Button''((''Caption''(button⊃labels))(''Style'' ''Radio'')(''Posn''((10+20×button),10))(''State'' (button⊃states)))'
          ⍎'b',(⍕button),'←⎕new ',bargs
      :EndFor
      ⎕DF'[DogRadios: ',Caption,']'
    ∇
:EndClass


Radio buttons are tedious, because they need to be encapsulated within a Group (which is otherwise of little value to the application), so DogRadios lets the complete set of buttons, with their group, be defined in a single statement.

DogTick

:Class DogTick : 'Button'
⍝ Standardised Checkbox button
⍝ Argument is Caption Posn
    :Field Caption←'Dogon Checkbox Button'   
   
    ∇ Create args
      :Access Public
      args←(⊂¨(⍴args)↑'Caption' 'Posn'),∘⊂¨args
      :Implements Constructor :Base args, ('Size' (20 200))('Style' 'Check')
      ⎕DF'[DogTick: ',Caption,']'
    ∇
:EndClass

DogTick is a single checkbox, note that all properties of the base Button class are available, so that once created the application can include statements like  fex.Titles.State←↑parms, there's no need for explicit declarations within the DogTick code.

DogTime

:Class DogTime : 'SubForm'
⍝:Dogon Research Time-only date/time picker with label
⍝ Argument is Caption Posn Time
⍝             Caption Posn Time Attach
    :Field Caption←'Dogon Time'
   
    :Property Value
    :Access Public
        ∇ z←get
          z←¯3↑dtp.DateTime
        ∇
        ∇ set w
          dtp.DateTime←0,w.NewValue
        ∇
    :endProperty
   
    ∇ Create w;size
      :Access Public
      size←50 180
      :Select ⍬⍴⍴w
      :Case 3
          w,←⊂'nnnn'
      :EndSelect
      (2⊃w)←0,2⊃w
      (3⊃w)←translateAttach 3⊃w
      w←(⊂¨(⍴w)↑'Caption' 'Posn' 'DateTime' 'Attach'),∘⊂¨w
      :Implements Constructor :Base (1 3⊃¨⊂w), ('Size' size)('EdgeStyle' 'Dialog')
      label←⎕NEW'Label'((↑w)('Posn'(10 0))('Size'(20 180)))
      dtp←⎕NEW'DateTimePicker'(('FieldType' 'Time')(2⊃w)('Style' 'UpDown')('Posn'(30 0))('Size'(20 100)))
      ⎕DF'[DogTime: ',Caption,']'
    ∇
⍝:Created ⋄ 2007 4 4 14 40 58 0 ⋄ dick ⋄ .\scheduler
⍝:Saved ⋄ 2007 4 4 14 57 1 906 ⋄ dick ⋄ .\scheduler
:EndClass

As with DogDate, a simplification of the supplied DateTimePicker for times only, taking and returning values as hour-minute-second triplets.

DogTool

:Class DogTool : 'ToolControl'
⍝ Standardised toolbar class   
⍝ Argument is [0] ←→ form   
⍝             [1] ←→ list of image objects
⍝             [2] ←→ matrix of name type caption image hint tip (callback function) (call back arguments)
   
    :Field tc Private
   
    ∇ Create(form images specs);⎕IO;⎕ML;spec;opts
      ⎕IO ⎕ML←0 3
      :Access Public
      :Implements Constructor :Base
      specs←⊂[1]specs
      tc←form.cbrMain.cbd3.⎕NEW'ToolControl'(('ImageListObj'images)('Divider' 0))
      :For spec :In specs
          :Select 1⊃spec
          :Case 'Button'
              opts←'((''Caption''(2⊃spec))(''ImageIndex''(3⊃spec))(''Hint''(4⊃spec))(''Tip''(5⊃spec)))'
              ⍎'tc.',(↑spec),'←tc.⎕new ''ToolButton'' ',opts
              ⍎'tc.',(↑spec),'.onSelect←''Select''(((⊂form.Name),7⊃spec) (6⊃spec))'    
          :Case 'Separator'
              ⍎'tc.',(↑spec),'←tc.⎕new ''ToolButton'' (,⊂(''Style'' ''Separator''))'
          :EndSelect
      :EndFor
    ∇
   
    ∇ opt Select msg;arg
      arg←enparen enquote¨↑opt
      ⍎(⍕arg),(1⊃opt),' 0'
    ∇
   
      enparen←{
          '(',¨(⍕¨⍵),¨')'}
   
      enquote←{
          2=≡⍵:⍵
          0=1↑0⍴⍵:⍵
          '''',⍵,''''}
   
⍝:Saved 2006 12 28 15 43 51 625
:EndClass


DogTool is somewhat similar to DogMenu, with some extra columns in the definition matrix; the internal code of both is rather unruly, with too much in the way of executed enquoted text (although I suppose this does show how the OOP approach can conceal  underlying code nastiness).  Both classes are rather similar, suggesting a further layer of abstraction at some future time,

Here's DogTool in use...

 folder DefineMainCoolBarToolBar form;⎕IO;⎕ML;junk;this;tools
⍝ Define Main form toolbar structure
 ⎕IO ⎕ML←0 3
 ilnorm←⎕NEW'ImageList'(('Masked' 0)('MapCols' 1))
 junk←ilnorm.⎕NEW'BitMap'(,⊂('File'(folder,'htmlnorm.bmp')))
 ilhot←⎕NEW'ImageList'(('Masked' 0)('MapCols' 1))
 junk←ilhot.⎕NEW'BitMap'(,⊂('File'(folder,'htmlhot.bmp')))
 iloff←⎕NEW'ImageList'(('Masked' 0)('MapCols' 1))
 junk←iloff.⎕NEW'BitMap'(,⊂('File'(folder,'htmloff.bmp')))
 this←⍕⎕THIS
 tools←ToolBarItems''
 form.cbrMain.cbd3←form.cbrMain.⎕NEW'CoolBand'(('Size'(⍬ 82))('NewLine' 1))
 form.cbrMain.cbd3.tcl0←form.cbrMain.cbd3.⎕NEW #.UTIL.DogTool(form((⊂this),¨'.ilnorm' '.ilhot' '.iloff')tools)


where the definition matrix is constructed  by...

 z←ToolBarItems w;⎕IO;⎕ML
⍝ Toolbar Items
 ⎕IO ⎕ML←0 3
 z←1 8⍴'btnExit' 'Button' 'Exit' 4 'Exit' 'Exit' '#.HTMLTOOLS.HTMLExit' 0
 z,[0]←8↑'sep10' 'Separator'
 z,[0]←'btnOpenFile' 'Button' 'Open File' 3 'Open File' 'Open File' '#.HTMLTOOLS.OpenFile' 0
 z,[0]←'btnOpenWeb' 'Button' 'Open Web' 0 'Open Web' 'Open Web' '#.HTMLTOOLS.OpenWeb' 0

DogTree

:Class DogTree : 'TreeView'
⍝:Dogon Research TreeView
⍝ Argument is Posn Size Items [Attach]
   
    :Property items
    :Access Public
        ∇ z←get
          z←Items
        ∇
        ∇ set w;state;s
          state←GetItemState¨⍳⍴Items
          s←(⍴Items)=⍴w.NewValue
          Items←w.NewValue
          :If s
              SetItemState(⍳⍴state)state
          :EndIf
        ∇
    :endProperty  
   
    ∇ Create w;size
      :Access Public
      :Select ⍬⍴⍴w
      :Case 3
          w,←⊂'nnnn'
      :EndSelect
      (3⊃w)←translateAttach 3⊃w
      w←(⊂¨(⍴w)↑'Posn' 'Size' 'Items' 'Attach'),∘⊂¨w
      :Implements Constructor :Base w
      ⎕DF'[DogTree:]'
    ∇
   
⍝:Created ⋄ 2007 8 7 14 1 23 921 ⋄ dick ⋄ .\htmltools
⍝:Saved ⋄ 2007 8 7 15 37 23 78 ⋄ dick ⋄ .\htmltools
⍝:Loaded ⋄ 2007 8 7 15 37 29 859 ⋄ dick ⋄ .\htmltools
:EndClass

DogTree has (at this writing) one objective - that when the text of the TreeView items is changed, but the number of items stays the same, then the state of the tree should be retained.  It's a specialised requirement, and perhaps DogTree won't stay like this for very long.

An Example Using DogControls

Here are some of them being used...

 z←DogExample w;⎕IO;⎕ML;df;PressMe;doginfo;CheckEdit
⍝ Example of using Dogon GUI classes
 ⎕IO ⎕ML←0 3
 PressMe←{⎕←'Ouch'}
 CheckEdit←{⎕←'Checking DogEdit'}
 df←#.⎕NEW DogForm('Dog Form'(500 200))
 df.rg←df.⎕NEW DogRadios((10 10)('Button A' 'Button B' 'Button C')(1 0 0))
 df.de←df.⎕NEW DogEdit('DogEdit Here'(100 10)'This is the value' '#.CheckEdit')
 df.dc←df.⎕NEW DogCombo('DogCombo Here'(150 10)('abacus' 'banana' 'bandana' 'banyan' 'cucumber'))
 df.db←df.⎕NEW DogButton('OK'(450 10))
 df.onClose←'GetFormInfo'
 df.db.onSelect←'PressMe'
 ⎕DQ'df' ⍝ df.Wait
 z←⊃doginfo

GetFormInfo msg;⎕IO;⎕ML
⍝ Collect form info
 ⎕IO ⎕ML←0 3
 doginfo←''
 doginfo,←⊂'DogRadio State ←→ 'df.rg.State
 doginfo,←⊂'DogEdit Value  ←→ 'df.de.Value
 doginfo,←⊂'DogCombo Value ←→ 'df.dc.Value
 
PressMe and CheckEdit would obviously(?) be replaced by something more sophisticated in the real world.

Use of ⎕DQ rather than Wait is (I hope) due to problems in the APL/W beta version used when this code was written.

And Finally...

Hopefully this paper has shown how easy it is to extend the APL/W GUI to reduce code verbosity and make customised controls.  Many more instances of similar extensions are possible - the code shown here will be extended over time as and when needs and circumstances combine.  As these classes are used in applications their functionality (and internal code) is likely to change - if you are interested in using them you can find more about current status by sending email to Dogon Research.

References:

[0] Askoolum; System Building with APL+Win; Wiley; 2006; ISBN 0-470-03020-8

Page updated 7 August 2007

Copyright © Dogon Research, 2006-2007.  Material from the Dogon Research Music and APL Pages may be freely redistributed, but copyright is retained and attribution to Dogon Research is requested.