widget.anubis 28.1 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724

                                  The Anubis Project. 
   
                              A Widget System (4th version). 
   
                             Copyright (c) Alain Proute' 2005. 
   
   
   Authors: Alain Proute'
   
   
   
   This file is the  entry point of this widget system if you want  to create new sorts of
   widgets.  If   you  just  want   to  use  already   existing  widgets,  see   the  file
   'host_window.anubis' in the same directory.
   
   
   
   ------------------------------------ Table of Contents --------------------------------
   
   *** (1) How widgets are working. 
   
   *** (1) Geometry. 
      *** (1.1) Absolute and relative coordinates. 
      *** (1.2) Absolute and relative rectangles. 
      *** (1.3) Widgets are rectangular. 
   
   *** (2) Drawing. 
      *** (2.1) The draw tool box. 
      *** (2.2) The 'draw method'. 
      *** (2.3) Drawing tools. 
         *** (2.3.1) Drawing a child widget. 
         *** (2.3.2) Drawing rectangles.
         *** (2.3.3) Drawing images.
         *** (2.3.4) Drawing character strings.
   
   *** (3) Handling events. 
      *** (3.1) Classification of events.
         *** (3.1.1) 'mouse_move' and 'mouse_click'. 
         *** (3.1.2) 'mouse_gone'. 
         *** (3.1.3) 'captured_mouse_move' and 'captured_mouse_liberated'. 
         *** (3.1.4) 'key_down'. 
         *** (3.1.5) 'changed'.
      *** (3.2) Classification of answers. 
         *** (3.2.1) 'not_handled' and 'handled'. 
         *** (3.2.2) 'resized'. 
         *** (3.2.3) 'want_to_capture_mouse' and 'want_to_capture_keyboard'. 
      *** (3.3) Transmitting events to childs. 
      *** (3.4) Manipulating areas. 
         *** (3.4.1) Creating areas. 
         *** (3.4.2) Making the union of two areas. 
         *** (3.4.3) Transmitting areas between widgets. 
   
   *** (4) Monitoring dynamic variables. 
   
   *** (5) Creating your widget.
   
   ---------------------------------------------------------------------------------------
   
   
   *** (1) How widgets are working. 
   
   A widget is  an 'object' (in the sens  of the Object Oriented Methodology)  by its very
   nature.   This essentially  means that  a widget  has an  internal state,  and contains
   methods (which are functions, more  precisely 'commands', because their execution is in
   general non deterministic).
   
   A widget may have  'child' widgets, so that widgets are organized  in tree form. When a
   host window  is opened, it receives  a widget which  is called the 'root'  widget. This
   widget may  have childs which may  themself have childs,  and so on. Hence,  the window
   always contains a tree or hierarchy of widgets.
   
   Widgets have two main  methods: the 'draw method' and the 'event  handler'. The role of
   the first one is to redraw the widget on  the screen, and the role of the second one is
   to handle events. Each widget is responsible of its own childs. When a widget receive a
   redraw order,  i.e. when  the draw  method of this  widget is  called, the  widget must
   redraw itself and also call the draw  methods of its childs.  Similarily, when a widget
   receives an event, it has the responsability  to decide if it should transmit the event
   to its childs or not.
   
   It is  important to  understand that  theses two methods  are completely  disjoint. The
   widget system transmits  an event (mouse event, keyboard event and  other event) to the
   root widget  which eventually transmits it  to its childs  and so on. Each  widget must
   decide if the  event has been handled or not  (by itself or by one  of its childs), and
   must return  an answer.  The  widget may  have to combine  the answers returned  by its
   childs  in order  to  make its  own  answer. Handling  an event  does  not produce  any
   redrawing,  but  the  answer contains  informations  on  the  area  which needs  to  be
   redrawn. When  the widget  system receives this  answer, it  optimizes the area  into a
   disjoint union  of rectangles and calls  the draw method  of the root widget  with this
   area as one of the arguments.
   
   Despite the  fact that widgets are  objects, their position  in the host window  is not
   part of their internal state. When a widget  needs to redraw a child widget, it calls a
   method which takes the relative position of the child widget (relative to itself) as an
   argument.  The same  is true for the  transmission of events.  Hence, a  widget has the
   responsability to know the positions of its childs relative to itself. If getting these
   positions require heavy computation, the  widget may store them into dynamic variables,
   but in this case, the widget also  has the responsability of keeping these variables up
   to date.
   
   Another  consequence of the  fact that  the position  of a  widget is  not part  of its
   internal state, is that widgets are  'ubiquitous'.  This means that the same widget may
   appear  at several  different  positions in  a host  window  or even  in distinct  host
   windows.   In order  to preserve  this  property, you  should never  violate the  rules
   explained below, in particular concerning absolute and relative coordinates.
   
   An  important  feature  is  the  possibility  of capturing  either  the  mouse  or  the
   keyboard. For  example, when a 'text input'  widget is clicked upon,  it should capture
   the  keyboard. To  that  end, the  widget creates  a  'capture ticket'  and returns  an
   appropriate 'keyboard  capture' answer, containing  this ticket.  The widget  must also
   keep the  ticket.  Later, when  a keyboard event  arrives, the widget  system transmits
   this event  in the form of  a function taking this  ticket as an  argument. Each widget
   which is supposed to be able to capture the keyboard, should apply this function to the
   ticket it has created. The function  returns either 'failure' if the ticket is invalid,
   or 'success(e)' if it is valid, where 'e' is the actual captured event. This event must
   be handled, and an answer must be returned, which will eventually induce a redrawing.

   
   
   
   *** (1) Geometry. 
   
   
      *** (1.1) Absolute and relative coordinates. 
   
   We use two  sorts of coordinates: absolute cordinates, which refer  to the host window,
   and relative  coordinates which refer to a  particular widget. In this  file, you learn
   how to  create a new  widget. This  widget will be  called 'your widget',  and relative
   coordinates are always relative to your widget.
   
   The 'x' coordinate grows  from left to right, and the 'y'  coordinate grows from top to
   bottom (the unit of mesure is the pixel):
   
   
      +------------------------> x
      |
      |
      |
      |
      |
      |
      |
      |
      V
      y

   
   The  leftmost-topmost pixel  of  the (client  part  of the)  host  window has  absolute
   coordinates (0,0). The  leftmost-topmost pixel of your widget  has relative coordinates
   (0,0). You don't  have to worry about  absolute coordinates. All the tools  you have to
   provide or  use for creating a  new widget use  coordinates which are relative  to your
   widget.
   
   
   
      *** (1.2) Absolute and relative rectangles. 
   
   As  for coordinates,  rectangles are  of two  sorts: absolute  rectangles  and relative
   rectangles.  Absolute  rectangles are  represented by the  type 'Rectangle'  defined in
   'predefined.anubis'. Relative rectangle (i.e.  relative to your widget) are represented
   by the type:
   
public type WidgetRectangle:
   rect(Int32    x, 
        Int32    y, 
        Int32    u,
        Int32    v). 
   
   
   A  point   of  relative   coordinates  '(a,b)'  belongs   to  the   relative  rectangle
   'rect(x,y,u,v)' if and only if:
   
                                 x =< a < u   &   y =< b < v
   
   
   
   
      *** (1.3) Widgets are rectangular. 
   
   Widgets are rectangular.  Hence,  each widget has a width and a  height (which may vary
   during the lifetime of the widget). When a  widget of width 'w' and height 'h' is drawn
   at  some position  '(x,y)' in  the host  window, the  drawing is  performed  within the
   absolute rectangle:
   
                                     rect(x,y,x+w,y+h)
   
   Equivalently,  if  this widget  has  relative  coordinates  '(a,b)' (relative  to  your
   widget), the drawing occurs in  the relative rectangle 'rect(a,b,a+w,b+h)' (relative to
   your widget).
   
   As already mentioned,  your widget must know the relative positions  of its childs. The
   computation  of these  positions  will  in most  cases  make use  of  the  size of  the
   childs. To that end, this system provides a tool for getting the size (width,height) of
   a child widget:
   
public define (Int32 width, Int32 height)
   get_size
     (
       Widget w
     ). 
   
   
   

   *** (2) Drawing. 
   
      *** (2.1) The draw tool box. 
   
   Your widget must be able to redraw itself. This means that when you create your widget,
   you provide  a 'draw method'. When  it is called,  this method receives an  argument of
   type:
   
public type WidgetDrawToolBox:...
   
   This  is an  opaque  type. Data  of this  type  are used  to  hide all  the details  of
   conversions between  absolute and relative  coordinates, and several other  things that
   you dont need to manipulate directly.
   
   
   
      *** (2.2) The 'draw method'. 
   
   The draw method of your widget is a function of type:
   
                                 WidgetDrawToolBox -> One
   
   This means that when your widget receives  the order to redraw itself, it also receives
   an appropriate draw  tool box. A set of  tools are provided in this draw  tool box. All
   these tools have the same name: 'draw'. They are distinguished by their type. 
   
   So for example, if  the draw tool box is 'dtb', you can draw  a pink rectangle of width
   100 pixel and  height 20 pixels at  relative position (10,10) in your  widget, with the
   following command:
   
                             draw(dtb)(rect(10,10,110,30),pink)
   
   (which returns 'unique' of type 'One'). 
   
   There are similar  tools for drawing child widgets, images  and character strings. Here
   they are.
   
   
   
      *** (2.3) Drawing tools. 
   
   Now we  describe the tools that  you can use in  order to construct the  draw method of
   your widget.  All  these tools have the  same name: 'draw', and they  must be extracted
   from the draw tool box as follows:
   
                                             draw(dtb)
   
   if 'dtb' is the name of the draw tool box. 
   
   
   
         *** (2.3.1) Drawing a child widget. 
   
   When it is asked to redraw itself, your widget must also redraw its childs (if any). To
   redraw a child, use the following tool:
   
public define (Widget child, Int32 x, Int32 y) -> One
   draw
     (
       WidgetDrawToolBox dtb
     ). 
   
   For example,  in order to redraw  the child 'c'  at position '(x,y)' (relative  to your
   widget), you must execute:
   
                                        draw(dtb)(c,x,y)
   
   
      
         *** (2.3.2) Drawing rectangles.
   
   If you want to draw a colored rectangle in your widget, use the following tool:
   
public define (WidgetRectangle,RGB) -> One   
   draw 
     (
       WidgetDrawToolBox dtb
     ). 
   
   For example, write:
   
                         draw(dtb)(rect(10,10,20,20),rgb(0,0,0))

   for drawing  a black  square 10 pixels  wide at  position (10,10). The  coordinates are
   relative to your widget as usual.
   
   
   
   
         *** (2.3.3) Drawing images.
   
   If you want to draw an image into your widget, use the following tool:
   
public define (HostImage, Int32 x, Int32 y) -> One
   draw
     (
       WidgetDrawToolBox dtb
     ). 
   
   
   For example, 
   
                                       draw(dtb)(image,x,y)
   
   where 'image' is of type 'HostImage', where and 'x' and 'y' are of type Int32 will draw
   the image at  position (x,y) in your widget.  This means that the upper  left corner of
   the image will be drawn at (x,y). As usual, coordinates are relative to your widget. 

   You may also want to clip the image  before drawing it. In this case, use the following
   variant:
   
public define (HostImage, Int32 x, Int32 y, WidgetRectangle clip) -> One
   draw
     (
       WidgetDrawToolBox dtb
     ). 
   
   Again the rectangle 'clip' is relative to your widget. 
   
   
   
         *** (2.3.4) Drawing character strings.
   
   If you want to draw a character string into your widget, use the following tool:
   
public define (String s, SystemFont f, RGB c, Int32 x, Int32 y) -> Int32
   draw
     (
       WidgetDrawToolBox dtb
     ). 
   
   For example the command:
   
                              draw(dtb)("gabuzomeu",f,c,10,10)
   
   will draw  the string "gabuzomeu"  at position (10,10)  in your widget using  the given
   font  'f' and  color 'c'.   Note that  (x,y) represents  the upper  left corner  of the
   drawing. If the height  of the font is 'h', the base point  of the first character will
   be at position (x,y+h).
   
   The value returned is the width of  the printed string in pixels. Notice also that this
   command does not draw  any background. Only the pixels which belong  to the body of the
   characters are drawn.
   
   You may also want to clip that drawing. In this case, use the following variant: 
   
public define (String s, SystemFont f, RGB c, Int32 x, Int32 y, 
               WidgetRectangle clip) -> Int32
   draw
     (
       WidgetDrawToolBox dtb
     ). 
   
   
   

   *** (3) Handling events. 
   
   Widgets must also handle events. We will have to use the following types:
   
public type WidgetEventToolBox:...
public type WidgetEvent:...
public type WidgetAnswer:...
   
   The first one is opaque, and  plays a role analogous to 'WidgetDrawToolBox'. The others
   are not opaque, and are discussed below.
   
   The event handler of your widget is a function of type:
   
                        (WidgetEventToolBox, WidgetEvent) -> WidgetAnswer
   
   That your widget 'receives' an event just  means that this function has been called (by
   its father widget, or  by the widget system itself if there is  no father, i.e. if your
   widget is the root widget).
   
   The  answer (of  type 'WidgetAnswer')  gives  informations on  how the  event has  been
   handled, and on which area of the host window should be redrawn as a consequence of the
   event.
   
   
   
      *** (3.1) Classification of events.
   
   The following type describes all the events a widget may have to handle.
   
public type WidgetEvent:
   mouse_move                  (KeyboardState ks, Int32 x, Int32 y), 
   mouse_click                 (KeyboardState ks, MouseClick mc, Int32 x, Int32 y), 
   mouse_gone, 
   captured_mouse_move         (Var(One) -> Maybe((Int32 x, Int32 y))), 
   captured_mouse_liberated    (Var(One) -> Maybe((Int32 x, Int32 y))),
   key_down                    (Var(One) -> Maybe((KeyboardState ks, KeyboardKey kk))),
   changed                     (Int32 n). 
   
   The   types   'KeyboardState',   'KeyboardKey'   and  'MouseClick'   are   defined   in
   'predefined.anubis'.
   
   Recall that  your widget must eventually  transmit events to its  childs, and construct
   its answer  depending on  the answers received  from its  childs.  We now  describe the
   meanings of these events.
   
   
   
         *** (3.1.1) 'mouse_move' and 'mouse_click'. 
   
    A  widget is concerned  by a  'mouse_move' or  'mouse_click' event  only if  the mouse
   pointer lies  inside the rectangle of  the widget. This is  a rule of  this system that
   your  widget  must  respect.   Hence,  when  your widget  receives  a  'mouse_move'  or
   'mouse_click' event, you may rely on  the hypothesis that the mouse pointer lies inside
   the rectangle of your widget.
   
   As  a consequence,  if your  widget has  one or  several childs,  it should  in general
   transmit  such events  to a  given child  only  if the  mouse pointer  lies within  the
   rectangle  of this child.   However, you  don't have  to worry  about that  in general,
   because the  widget system  checks this condition  before allowing the  transmission of
   'mouse_move'  and 'mouse_click'  events.  Hence,  you  may either  check the  condition
   yourself, or just  transmit such events to all childs.  Nevertheless, there are widgets
   which need to check  this condition, as for example the desktop  widget, because it may
   have  several childs whose  rectangles overlap.  The desktop  widget must  decide which
   child should  receive the event (using the  z-order), because the widget  system is not
   able to do it since it does not know anything about the z-order.
   
   Notice that if  the widget system blocks the  transmission of such an event  to a given
   child, it replaces it by a 'mouse_gone' event.
   
   
   
         *** (3.1.2) 'mouse_gone'. 

   If your  widget receives a  'mouse_gone' event, you  can deduce that the  mouse pointer
   does not  lie within the rectangle  of your widget. This  may be useful  for example to
   change the visual aspect of the widget when the mouse pointer is leaving the widget.
   
   Now, if  your widget has  child widgets, it  is responsible of  generating 'mouse_gone'
   event for its childs. Your widget must send at least one 'mouse_gone' event to a child,
   if the mouse pointer was within the rectangle  of the child at the time of the previous
   mouse event, and if this condition is no more true.  Hence, your widget must eventually
   keep that  information that  some child  contains the mouse  pointer in  some variable.
   This variable  may be for  example of type  'Maybe(Widget)'. If it  contains 'failure',
   this means that  no child contains the mouse pointer. If  it contains 'success(c)' this
   means that the child 'c' contains the mouse pointer. While you keep this variable up to
   date, you must also generate appropriate 'mouse_gone' events for your childs.
   
   Generating extra  'mouse_gone' events  (i.e. sending several  'mouse_gone' events  to a
   child  consecutively) is of  course a  waste of  time.  Nevertheless,  it has  no other
   inconvenient.   Also remember that  the system  replace 'mouse_move'  and 'mouse_click'
   events by 'mouse_gone'  events if they are transmitted to widgets  which do not contain
   the mouse pointer. This fact may simplify  the programming of the event handler of your
   widget.
   
   
  
         *** (3.1.3) 'captured_mouse_move' and 'captured_mouse_liberated'. 

   If your  widget has  captured the  mouse (how to  capture the  mouse will  be explained
   later),  it may  receive 'captured_mouse_move'  and  'captured_mouse_liberated' events.
   Such events are  not submitted to the same rules as  the 'mouse_move' and 'mouse_click'
   events.
   
   Your widget captured  the mouse using a  'ticket', which is a dynamic  variable of type
   'Var(One)'. When  a 'captured_mouse_move' or  'captured_mouse_liberated' event arrives,
   what you get is  just a function taking such a ticket as  its unique argument. The only
   thing you can do with this event is to apply the function to your ticket.
   
   If  the result  is 'failure',  this means  that your  widget is  not concerned  by this
   event. Actually, this  also implies that the capture your widget  initiated is over. If
   the result is 'success(p)', this means that  your widget is concerned by the event (the
   capture is still valid),  and that 'p' is the pair of  coordinats for the mouse pointer
   (relative to your widget as usual).
   
   If your  widget is not concerned by  such an event, it  must transmit it to  all of its
   childs.
   
   
         *** (3.1.4) 'key_down'. 
   
   This event works like  'captured_mouse_move' and 'captured_mouse_liberated' events. You
   must apply  the function to your  ticket in order to  know if you are  concerned by the
   event. If it  is the case you get  the keyboard state and the character  which has been
   entered.
   
   If your widget is not concerned by this event it must transmit it to all of its childs.
   
      
   
         *** (3.1.5) 'changed'.
   
   This event is generated  by the widget system when a dynamic  variable registred at the
   widget system is reassigned. See below for more explanations. 
   
   
   
   
      *** (3.2) Classification of answers. 
   
   When a  widget receives an  event, it may  handle or not handle  the event, but  in all
   cases it must return  an answer.  An answer may contain an  'area' which represents the
   part of the host window which needs to be redrawn. Areas are represented as follows:
   
public type WidgetArea:...   
   
   This is  a opaque type, because  we want to  hide all conversions between  absolute and
   relative  coordinates.  As  far  as you  are  concerned, you  manipulate only  relative
   coordinates (and  relative rectangles).  This is  an important rule  that you  must not
   violate.
 
   Answers are the following:
   
public type WidgetAnswer:
   not_handled               (WidgetArea), 
   handled                   (WidgetArea),
   resized, 
   want_to_capture_mouse     (Var(One),WidgetArea), 
   want_to_capture_keyboard  (Var(One),WidgetArea). 
   
   We will give later several tools for manipulating areas. Now, we discuss the meaning of
   these answers.
   
   
  
         *** (3.2.1) 'not_handled' and 'handled'. 
   
   If your  widget handles  the event,  it should normally  return a  'handled(a)' answer,
   where 'a'  is the area within  which redrawing must occur.  'not_handled(l)' is similar
   but means that your widget did not handle the event. Nevertheless, even if the event is
   not handled, the redrawing of several rectangles may be needed.
   
   If your  widget has transmitted  the event  to one or  several childs, it  will receive
   answers from  these childs, and  must construct  its own answer  to be returned  to its
   father. How the answer  of your widget is constructed from the  answers returned by the
   childs may vary  depending on the behavior  of your widget. This is  actually a central
   point of  widget programming  and you  should pay much  attention to  it. Nevertheless,
   there is no special rule for this. This is up to you. 
   
   
   
         *** (3.2.2) 'resized'. 
   
   This answer means that the event has been handled, and that it induced a change of size
   of the widget. If your widget receives such  an answer from one of its childs, it knows
   that the sier of a childs has changed. This may induce a change of size of your widget,
   but not necessarily. For example, the size of the 'window' widget is independent of the
   size of its content.
   
   
   
   
         *** (3.2.3) 'want_to_capture_mouse' and 'want_to_capture_keyboard'. 
   
   Your widget must return one of these answers if it wants to capture either the mouse or
   the keyboard.   This answer requires  a component of  type 'Var(One)' that we  call the
   'capture ticket'. Your widget  may either create a new such ticket  at each capture, or
   use alway  the same one  (for example, it  may be created  before the creation  of your
   widget and be accessible to the event handler). 
   
   The  widget  system  generates  'captured_mouse_move',  'captures_mouse_liberated'  and
   'key_down' events which are able to recognize your ticket.
   
   These two  answers also contain  the list of  widget rectangles within  which redrawing
   must occur.
   
   
   
      *** (3.3) Transmitting events to childs. 
   
   Events are transmitted to childs using a tool extracted from the event tool box:
   
public define (Widget child, Int32 x, Int32 y, WidgetEvent) -> WidgetAnswer   
   transmit
     (
       WidgetEventToolBox etb
     ). 
   
   If your event tool box is 'etb', and if you want to transmit the event 'e' to the child
   'c', whose position relative to your widget is '(x,y)', use the following:
   
                                        transmit(etb)(c,x,y,e)
   
   The returned value is the answer of the child. 
   
   

   
      *** (3.4) Manipulating areas. 
   
   As explained above the type 'WidgetArea' is opaque.
   
   
         *** (3.4.1) Creating areas. 
   
   Nevertheless you need to construct areas. This may be done as follows:
   
public define List(WidgetRectangle) -> WidgetArea
   area
     (
       WidgetEventToolBox etb
     ). 
   
   For example if the width of your widget is  'w', and its height is 'h', and if you want
   to redraw the whole widget after some event, you may construct its area as follows:
   
                               area(etb)([rect(0,0,w,h)])
   
   
   
         *** (3.4.2) Making the union of two areas. 
   
   You may also need to  make the union of two areas. This may for  example be the case if
   several the childs  of your widget return answers containing  areas. The following tool
   computes the union of two areas (the event tool box is not required):
   
public define WidgetArea
   WidgetArea a + WidgetArea b. 
   
   
   
         *** (3.4.3) Transmitting areas between widgets. 
   
   Areas (of type 'WidgetArea') contain only  absolute coordinates. This is the reason why
   the  type 'WidgetArea'  is  opaque.  This  has also  the  advantage that  areas may  be
   transmitted from one widget to another  one without any conversion. This possibility is
   used for example by the menu manager widget.
   
   
   
   
   
   
   *** (4) Monitoring dynamic variables. 
   
   Widgets need in general to monitor  dynamic variables, simply because they are by their
   very   nature   the  graphical   representation   of   the   current  state   of   some
   'machine'. However,  a widget has  no mean  to send a  message for redrawing  itself. A
   widget may  be redrawn only as  the consequence of  an event. For this  reason, widgets
   should not monitor variables themself, but should  ask the widget system to do it.
   
   If the widget system has been asked  to monitor a dynamic variable 'v', it generates an
   event 'changed(n)', whenever  this variable is reassigned, where  'n' is the identifier
   of the  dynamic variable. When  your widget receives  this event, it must  compare this
   integer  'n' with  the  identifier  of the  variable  (say 'v')  it  depends on.   This
   comparison may be done as follows:
   
       if n = var_id(v)
       then ... I do depend on this variable ...
       else ... I don't depend on this variable ...
   
   Of course, if your widget does not  depend on the variable, nothing should be done. But
   if it depends on the variable, it  may return an answer like 'handled(a)', where 'a' is
   the area to be redrawn. Needless to say, this test must be done with all variables your
   widget depends on.
   
   Several  widgets may  depend on  the same  variable. As  a consequence,  an  event like
   'changed(n)' must always be transmitted to all childs.
   
   Now, a widget asks the system to monitor  a dynamic variable at the time this widget is
   created. The type:
   
public type WidgetRegistration:...
   
   which is  opaque, is use for  representing 'registrations' of dynamic  variables at the
   widget system. In order to register a  variable at the widget system, use the following
   tool:
   
public define WidgetRegistration
   register
     (
       Var($T)  v
     ). 
   
   By applying this tool  to a dynamic variable, you get a  registration. When your widget
   is created, you just provide the list of all these registrations. That's all. 
   
   
    

   
   *** (5) Creating your widget.
   
   Widgets are of type:
   
public type Widget:...
   
   This is an opaque type, but here is the tool which enables to create a widget. 
   
public define Widget
   create_widget
     (
       One -> (Int32,Int32)                                  get_size, 
       (WidgetDrawToolBox) -> One                            redraw, 
       (WidgetEventToolBox,WidgetEvent) -> WidgetAnswer      event_handler,
       List(WidgetRegistration)                              registrations
     ). 
   
   The  function  'get_size'  must  return  the  current  size  '(width,height)'  of  your
   widget. Be careful that, if this size  is going to change, the function must return the
   current size, not the initial size.
   
   The other arguments have already been explained. 
   
   
   
   
   
   
   --- That's all for the public part ! --------------------------------------------------