UIML (XML for user interfaces)



I really liked the XML idea for user-interface specification.
I have fleshed out the design by specifying a complete notepad-type
application using UIML -- the User Interface Markup Language, based
on XML.

A UIML "browser" would render the interface, interacting with the user.
The browser communicates with the application code in client-server
fashion.  (The browser is the client, the actual application code is
the server.)

Separation of user interface and application code is assured.  Assuming
a browser is implemented for all popular platforms, portability
depends only on writing the (non-gui) application code in an
environment-independent way.  (The application code may be written in
any language.)

Here is the uiml specification for the notepad application:
(This is the uncommented version, to show the small size of a spec;
 see below for a fully-commented version that will make more sense!
 (seek down to "*******" if you want)
)

---- begin notepad.uiml

// xml headers and such go here

<dialog name="find">
  <label>Find:  </label>  <entry name="findText"/>
  <br/>
  <checkbox name="strictCase">case sensitive</checkbox>
  <hr/>
  <button click="find $findText $strictCase" default=yes>^Find
next</button>
  <button click=".close" escape=yes>^Close</button>
</dialog>

<dialog name="replace">
  <label width=15>Find:  </label>
  <entry name="findText"/>
  <br/>
  <label width=15>Replace with:  </label>
  <entry name="replaceText"/>
  <br/>
  <checkbox name="strictCase">case sensitive</checkbox>
  <hr/>
  <button click="find $findText $strictCase" default=yes>^Find
next</button>
  <button click="replace $replaceText; find $findText $strictCase">
    ^Replace</button>
  <button click="replaceAll $findText $strictCase $replaceText">
    Replace ^all</button>
  <button click=".close" escape=yes>^Close</button>
</dialog>

<menu name="main">Notepad Menu
  <menu>^File
    <item cmd="file.new">^New</item>
    <cmenu name="fileOpenHistory" cmd="file.open">^Open...
      <init cmd="createFileOpenHistory fileOpenHistory"/>
    </cmenu>
    <item cmd="file.save">^Save</item>
    <item cmd="file.save">Save ^as...</item>
    <hr/>
    <item cmd="app.exit">E^xit</item>
  </menu>
  <menu>^Edit
    <item cmd="edit.cut">C^ut</item>
    <item cmd="edit.copy">^Copy</item>
    <item cmd="edit.paste">^Paste</item>
  </menu>
  <menu name="search">^Search
    <item cmd=".dialog find" hotkey="search.find">^Find...</item>
    <item cmd=".dialog replace"
hotkey="search.replace">^Replace...</item>
    <item cmd="search.repeat">Repe^at</item>
  </menu>
  <helpmenu/>  // help menu is auto-populated by the <help/> section
</menu>

<menu name="context.editor">
  <item cmd="file.save">^Save</item>
  <hr/>
  <item cmd="edit.cut">C^ut</item>
  <item cmd="edit.copy">^Copy</item>
  <item cmd="edit.paste">^Paste</item>
  <hr/>
  <submenu name="search"/>
</menu>

<toolbar name="toolbar">Toolbar
  <item cmd="file.new" icon="file.new">^New</item>
  <item cmd="file.open" icon="file.open">^Open...</item>
  <item cmd="file.save" icon="file.save">^Save</item>
  <br/>
  <item cmd="edit.cut">C^ut</item>
  <item cmd="edit.copy">^Copy</item>
  <item cmd="edit.paste">^Paste</item>
</toolbar>

<toolbar name="status">Status
  <button name="status.modified" width=2 click="file.save"/>
  <button name="status.row" width=4 losefocus="seek $status.row
$status.col"/>
  <button name="status.col" width=3 losefocus="seek $status.row
$status.col"/>
</toolbar>

<tooltip name="status.modified">
  "*" indicates file has been modified; click to save it
</tooltip>
  
// other tooltips go here

<help>
  html help file text goes here (topics are extracted for help menu, 
  probably using a specified header tag, such as <h2>
</help>

<app code="applicationExecutableFileName" icon="notepad" decor="wm
hints"
  name="aNameToStoreSettingsUnder" 
  tools="main, toolbar, status"
>
  <entry multiline=yes name="editor" capture="K:*, M:*"/>
</app>

  ---- end notepad.uiml

****************************************


Here it is again, with embedded c++-style commentary:

  ----
// xml headers and such go here

<dialog name="find" 
// other possible attributes:
//   decor="wm hints" 
//   geometry="30%x30%"
//   placement="parent.center"
//   style="styleName" ... 
                                >
  <label>Find:  </label>  <entry name="findText"/>
  <br/>
  <checkbox name="strictCase">case sensitive</checkbox>
// could have included value=yes to start "checked" (default is no)
  <hr/>
  <button click="find $findText $strictCase" default=yes>^Find
next</button>
// notes:
// when this button is clicked (or enter is pressed (default button)),
// the command is sent to the application code (suppose strictCase is
checked
// and the findText entry contains 'foo'  the application receives the 
// command:  'find "foo" 1')
// The "^" in "^Find" indicates that F is the mnemonic (underlined or
// highlighted, depending on platform).
// (If "find one, then close dialog" were desired, the click command
// would have read "find $findText $strictCase; .close")
  <button click=".close" escape=yes>^Close</button>
// when clicked or escape is pressed, the browser closes the dialog
// (".CMD" means browser executes CMD; nothing is sent to application)
</dialog>

<dialog name="replace">
  <label width=15>Find:  </label>
// width is in units of average-characer-width (based on curret font)
// alternatively, width may be specified as percentage of dialog size:
// width="30%"
  <entry name="findText"/>
  <br/>
  <label width=15>Replace with:  </label>
  <entry name="replaceText"/>
  <br/>
  <checkbox name="strictCase">case sensitive</checkbox>
  <hr/>
  <button click="find $findText $strictCase" default=yes>^Find
next</button>
  <button click="replace $replaceText; find $findText $strictCase">
    ^Replace</button>
  <button click="replaceAll $findText $strictCase $replaceText">
    Replace ^all</button>
  <button click=".close" escape=yes>^Close</button>
</dialog>

<dialog name="exit">
// This dialog will be invoked by the application code on exit with
unsaved
// modifications.  The application will pass the filename as $1.
  <live>
    <label>The file ;&quote$1;&quote has unsaved modifications.</label>
  </live>
// <live> indicates that the item(s) within must be recreated each time
the
// dialog is displayed (so that the $1 substitution is "live")
  <hr/>
  <radio name="exitChoice">
    <rbutton default=1 value="file.save; app.exit">
      ^Save the file and exit</rbutton>
    <rbutton value="app.exit force">
      ^Discard the changes and exit</rbutton>
    <rbutton value="">
      Don't exit; ^return to application</rbutton>
  </radio>
  <hr/>
  <button click=".close; $exitChoice" default=yes>O^K</button>
  <hotkey hotkey="escape" cmd=".close"/>
// not sure if this one is a good idea or not (hotkey with no
corresponding
// visual element), but it makes sense to be able to press esc here, I
think
</dialog>

<menu name="main">Notepad Menu
  <menu>^File
// <menu>'s may be nested to any level (cascading submenus)
    <item cmd="file.new">^New</item>
    <cmenu name="fileOpenHistory" cmd="file.open">^Open...
      <init cmd="createFileOpenHistory fileOpenHistory"/>
// init tags just send cmd to application (once) as browser parses uiml
file
// cmenu is a conditional-cascade menu (i.e. clicking Open launches an
open
// dialog (or whatever the application wants to do), while clicking on
the
// arrow button to the right of "Open" brings up the file history
submenu)
    </cmenu>
    <item cmd="file.save">^Save</item>
    <item cmd="file.save">Save ^as...</item>
    <hr/>
    <item cmd="app.exit">E^xit</item>
  </menu>
  <menu>^Edit
    <item cmd="edit.cut">C^ut</item>
    <item cmd="edit.copy">^Copy</item>
    <item cmd="edit.paste">^Paste</item>
  </menu>
  <menu name="search">^Search
// we have named the search menu so that we can use it elsewhere, too
    <item cmd=".dialog find" hotkey="search.find">^Find...</item>
// by default, hotkey==cmd, but we want the browser to launch the find
dialog
//   while still using the standard hotkey
    <item cmd=".dialog replace"
hotkey="search.replace">^Replace...</item>
    <item cmd="search.repeat">Repe^at</item>
  </menu>
  <helpmenu/>  // help menu is auto-populated by the <help/> section
</menu>

<menu name="context.editor">
  <item cmd="file.save">^Save</item>
  <hr/>
  <item cmd="edit.cut">C^ut</item>
  <item cmd="edit.copy">^Copy</item>
  <item cmd="edit.paste">^Paste</item>
  <hr/>
  <submenu name="search"/>  // use the previously defined search menu
</menu>

<toolbar name="toolbar">Toolbar
// toolbars are like menus, but they may be displayed as icon/text/both
// and they may accept other controls besides menu items
  <item cmd="file.new" icon="file.new">^New</item>
// icon name expands to <icon>.<size>.xpm for unix
// (tries preferred size, then tries other sizes and scales),
// <icon>.ico then <icon>.<size>.bmp for win
// Note:  I really should put the icon=... tags in the main menu, too
  <item cmd="file.open" icon="file.open">^Open...</item>
  <item cmd="file.save" icon="file.save">^Save</item>
  <br/>
  <item cmd="edit.cut">C^ut</item>
  <item cmd="edit.copy">^Copy</item>
  <item cmd="edit.paste">^Paste</item>
</toolbar>

<toolbar name="status">Status
  <button name="status.modified" width=2 click="file.save"/>
  <button name="status.row" width=4 losefocus="seek $status.row
$status.col"/>
    // a full range of events are available, including click,
doubleclick,
    //   contextmenu, dragstart, drop, gainfocus, losefocus, keypress,
etc.
  <button name="status.col" width=3 losefocus="seek $status.row
$status.col"/>
</toolbar>

<tooltip name="status.modified">
  "*" indicates file has been modified; click to save it
</tooltip>
  
// other tooltips go here

<help>
  html help file text goes here (topics are extracted for help menu, 
  probably using a specified header tag, such as <h2>
</help>
// alternatively, external help file may be used with <help file="..."/>

<app code="applicationExecutableFileName" icon="notepad" decor="wm
hints"
// the wm hints will be in a portable format usable by mwm-like and
'doze
  name="aNameToStoreSettingsUnder" 
  tools="main, toolbar, status"
// inserts toolbars into window
// optionally, prefix with [tblrf]: to specify insertion point (default
t:)
// (top, bottom, left, right, floating)
// example:  tools="t:main, f:toolbar, b:status"
>
  <entry multiline=yes name="editor" capture="K:*, M:*"
// other avail attributes:  readonly, password (shows *'s), html
// capture is a portable event mask string that specifies events to
capture
//  and pass on to app (ex. mouse click, dblclick, keypress, move,
resize)
// Here, we want to capture keypresses and mouse clicks so we can update
// row/col/modified in status bar.  (We could also add undo support)
  />
</app>

  ----

Now, the application code consists of a simple parser and interpretter
for commands sent from the UI.

Comments, please.


Paul



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]