Commit 344585a84f8d17c5ec647986673fa7882ae89fc0

Authored by Alain Prouté
1 parent 6d42d3d6

*** empty log message ***

Showing 1 changed file with 712 additions and 0 deletions   Show diff stats
anubis_dev/library/widgets4/widget.anubis 0 → 100644
  1 +
  2 + The Anubis Project.
  3 +
  4 + A Widget System (4th version).
  5 +
  6 + Copyright (c) Alain Proute' 2005.
  7 +
  8 +
  9 + Authors: Alain Proute'
  10 +
  11 +
  12 +
  13 + This file is the entry point of this widget system if you want to create new sorts of
  14 + widgets. If you just want to use already existing widgets, see the file
  15 + 'host_window.anubis' in the same directory.
  16 +
  17 +
  18 +
  19 + ------------------------------------ Table of Contents --------------------------------
  20 +
  21 + *** (1) How widgets are working.
  22 +
  23 + *** (1) Geometry.
  24 + *** (1.1) Absolute and relative coordinates.
  25 + *** (1.2) Absolute and relative rectangles.
  26 + *** (1.3) Widgets are rectangular.
  27 +
  28 + *** (2) Drawing.
  29 + *** (2.1) The draw tool box.
  30 + *** (2.2) The 'draw method'.
  31 + *** (2.3) Drawing tools.
  32 + *** (2.3.1) Drawing a child widget.
  33 + *** (2.3.2) Drawing rectangles.
  34 + *** (2.3.3) Drawing images.
  35 + *** (2.3.4) Drawing character strings.
  36 +
  37 + *** (3) Handling events.
  38 + *** (3.1) Classification of events.
  39 + *** (3.1.1) 'mouse_move' and 'mouse_click'.
  40 + *** (3.1.2) 'mouse_gone'.
  41 + *** (3.1.3) 'captured_mouse_move' and 'captured_mouse_liberated'.
  42 + *** (3.1.4) 'key_down'.
  43 + *** (3.1.5) 'changed'.
  44 + *** (3.2) Classification of answers.
  45 + *** (3.2.1) 'not_handled' and 'handled'.
  46 + *** (3.2.2) 'resized'.
  47 + *** (3.2.3) 'want_to_capture_mouse' and 'want_to_capture_keyboard'.
  48 + *** (3.3) Transmitting events to childs.
  49 + *** (3.4) Manipulating areas.
  50 + *** (3.4.1) Creating areas.
  51 + *** (3.4.2) Making the union of two areas.
  52 + *** (3.4.3) Transmitting areas between widgets.
  53 +
  54 + *** (4) Monitoring dynamic variables.
  55 +
  56 + *** (5) Creating your widget.
  57 +
  58 + ---------------------------------------------------------------------------------------
  59 +
  60 +
  61 + *** (1) How widgets are working.
  62 +
  63 + A widget is an 'object' (in the sens of the Object Oriented Methodology) by its very
  64 + nature. This essentially means that a widget has an internal state, and contains
  65 + methods (which are functions, more precisely 'commands', because their execution is in
  66 + general non deterministic).
  67 +
  68 + A widget may have 'child' widgets, so that widgets are organized in tree form. When a
  69 + host window is opened, it receives a widget which is called the 'root' widget. This
  70 + widget may have childs which may themself have childs, and so on. Hence, the window
  71 + always contains a tree or hierarchy of widgets.
  72 +
  73 + Widgets have two main methods: the 'draw method' and the 'event handler'. The role of
  74 + the first one is to redraw the widget on the screen, and the role of the second one is
  75 + to handle events. Each widget is responsible of its own childs. When a widget receive a
  76 + redraw order, i.e. when the draw method of this widget is called, the widget must
  77 + redraw itself and also call the draw methods of its childs. Similarily, when a widget
  78 + receives an event, it has the responsability to decide if it should transmit the event
  79 + to its childs or not.
  80 +
  81 + It is important to understand that theses two methods are completely disjoint. The
  82 + widget system transmits an event (mouse event, keyboard event and other event) to the
  83 + root widget which eventually transmits it to its childs and so on. Each widget must
  84 + decide if the event has been handled or not (by itself or by one of its childs), and
  85 + must return an answer. The widget may have to combine the answers returned by its
  86 + childs in order to make its own answer. Handling an event does not produce any
  87 + redrawing, but the answer contains informations on the area which needs to be
  88 + redrawn. When the widget system receives this answer, it optimizes the area into a
  89 + disjoint union of rectangles and calls the draw method of the root widget with this
  90 + area as one of the arguments.
  91 +
  92 + Despite the fact that widgets are objects, their position in the host window is not
  93 + part of their internal state. When a widget needs to redraw a child widget, it calls a
  94 + method which takes the relative position of the child widget (relative to its father
  95 + widget) as an argument. The same is true for the transmission of events. Hence, a
  96 + widget has the responsability to know the positions of its childs relative to
  97 + itself. If getting these positions require heavy computation, the widget may store them
  98 + into dynamic variables, but in this case, the widget also has the responsability of
  99 + keeping these variables up to date.
  100 +
  101 + An important feature is the possibility of capturing either the mouse or the
  102 + keyboard. For example, when a 'text input' widget is clicked upon, it should capture
  103 + the keyboard. To that end, the widget uses a function which creates a 'capture ticket'
  104 + and returns an appropriate 'keyboard capture' answer, containing this ticket. The
  105 + widget must also keep the ticket. Later, when a keyboard event arrives, the widget
  106 + system transmits this event in the form of a function taking this ticket as an
  107 + argument. Each widget which is supposed to be able to capture the keyboard, should
  108 + apply this function to the ticket it has created. The function returns either 'failure'
  109 + if then ticket is invalid, or 'success(e)' if it is valid, where 'e' is the actual
  110 + captured event. This event must be handled, and an answer must be returned, which will
  111 + eventually induce a redrawing.
  112 +
  113 +
  114 +
  115 +
  116 + *** (1) Geometry.
  117 +
  118 +
  119 + *** (1.1) Absolute and relative coordinates.
  120 +
  121 + We use two sorts of coordinates: absolute cordinates, which referer to the host window,
  122 + and relative coordinates which refer to a particular widget. In this file, you learn
  123 + how to create a new widget. This widget will be called 'your widget', and relative
  124 + coordinates are always relative to your widget.
  125 +
  126 + The 'x' coordinate grows from left to right, and the 'y' coordinate grows from top to
  127 + bottom (the unit of mesure is the pixel):
  128 +
  129 +
  130 + +------------------------> x
  131 + |
  132 + |
  133 + |
  134 + |
  135 + |
  136 + |
  137 + |
  138 + |
  139 + V
  140 + y
  141 +
  142 + The leftmost-topmost pixel of the (client part of the) host window has absolute
  143 + coordinates (0,0). The leftmost-topmost pixel of your widget has relative coordinates
  144 + (0,0). You don't have to worry about absolute coordinates. All the tools you have to
  145 + provide for creating a new widget use coordinates which are relative to your widget.
  146 +
  147 +
  148 +
  149 + *** (1.2) Absolute and relative rectangles.
  150 +
  151 + As for coordinates, rectangles are of two sorts: absolute rectangles and relative
  152 + rectangles. Absolute rectangles are represented by the type 'Rectangle' defined in
  153 + 'predefined.anubis'. Relative rectangle (i.e. relative to your widget) are represented
  154 + by the type:
  155 +
  156 +public type WidgetRectangle:
  157 + rect(Int32 x,
  158 + Int32 y,
  159 + Int32 u,
  160 + Int32 v).
  161 +
  162 +
  163 + A point of relative coordinates '(a,b)' belongs to the relative rectangle
  164 + 'rect(x,y,u,v)' if and only if:
  165 +
  166 + x =< a < u & y =< b < v
  167 +
  168 +
  169 +
  170 +
  171 + *** (1.3) Widgets are rectangular.
  172 +
  173 + Widgets are rectangular. Hence, each widget has a width and a height (which may vary
  174 + during the lifetime of the widget). When a widget of width 'w' and height 'h' is drawn
  175 + at some position '(x,y)' in the host window, the drawing is performed within the
  176 + absolute rectangle:
  177 +
  178 + rect(x,y,xw,y+h)
  179 +
  180 + Equivalently, if this widget has relative coordinates '(a,b)' (relative to your
  181 + widget), the drawing occurs in the relative rectangle 'rect(a,b,a+w,b+h)' (relative to
  182 + your widget).
  183 +
  184 + As already mentioned, your widget must know the relative positions of its childs. The
  185 + computation of these positions will in most cases make use of the size of the
  186 + childs. To that end, this system provides a tool for getting the size (width,height) of
  187 + a child widget.
  188 +
  189 +
  190 +
  191 +
  192 + *** (2) Drawing.
  193 +
  194 + *** (2.1) The draw tool box.
  195 +
  196 + Your widget must be able to redraw itself. This means that when you create your widget,
  197 + you provide a 'draw method'. When it is called, this method receives an argument of
  198 + type:
  199 +
  200 +public type WidgetDrawToolBox:...
  201 +
  202 + This is an opaque type. Data of this type are used to hide all the details of
  203 + conversions between absolute and relative coordinates, and several other things that
  204 + you dont need to manipulate directly.
  205 +
  206 +
  207 +
  208 + *** (2.2) The 'draw method'.
  209 +
  210 + The draw method of your widget is a function of type:
  211 +
  212 + WidgetDrawToolBox -> One
  213 +
  214 + This means that when your widget receives the order to redraw itself, it also receives
  215 + an appropriate draw tool box. A set of tools are provided in this draw tool box. All
  216 + these tools have the same name 'draw'. There are distinguished by their type.
  217 +
  218 + So for example, if the draw tool box is 'dtb', you can draw a pink rectangle of width
  219 + 100 pixel and height 20 pixels at relative position (10,10) in your widget, with the
  220 + following command:
  221 +
  222 + draw(dtb)(rect(10,10,110,30),pink)
  223 +
  224 + (which returns 'unique' of type 'One').
  225 +
  226 + There are similar tools for drawing child widgets, images and character strings. Here
  227 + they are.
  228 +
  229 +
  230 +
  231 + *** (2.3) Drawing tools.
  232 +
  233 + Now we describe the tools that you can use in order to construct the draw method of
  234 + your widget. All these tools have the same name: 'draw', and they must be extracted
  235 + from the draw tool box as follows:
  236 +
  237 + draw(dtb)
  238 +
  239 + if 'dtb' is the name of the draw tool box.
  240 +
  241 +
  242 +
  243 + *** (2.3.1) Drawing a child widget.
  244 +
  245 + When it is asked to redraw itself, your widget must also redraw its childs (if any). To
  246 + redraw a child, use the following tool:
  247 +
  248 +public define (Widget child, Int32 x, Int32 y) -> One
  249 + draw
  250 + (
  251 + WidgetDrawToolBox dtb
  252 + ).
  253 +
  254 + For example, in order to redraw the child 'c' at position '(x,y)' (relative to your
  255 + widget), you must execute:
  256 +
  257 + draw(dtb)(c,x,y)
  258 +
  259 +
  260 +
  261 + *** (2.3.2) Drawing rectangles.
  262 +
  263 + If you want to draw a colored rectangle in your widget, use the following tool:
  264 +
  265 +public define (WidgetRectangle,RGB) -> One
  266 + draw
  267 + (
  268 + WidgetDrawToolBox dtb
  269 + ).
  270 +
  271 + For example, write:
  272 +
  273 + draw(dtb)(rect(10,10,20,20),rgb(0,0,0))
  274 +
  275 + for drawing a black square 10 pixels wide at position (10,10). The coordinates are
  276 + relative to your widget as usual.
  277 +
  278 +
  279 +
  280 +
  281 + *** (2.3.3) Drawing images.
  282 +
  283 + If you want to draw an image into your widget, use the following tool:
  284 +
  285 +public define (HostImage, Int32 x, Int32 y) -> One
  286 + draw
  287 + (
  288 + WidgetDrawToolBox dtb
  289 + ).
  290 +
  291 +
  292 + For example,
  293 +
  294 + draw(dtb)(image,x,y)
  295 +
  296 + where 'image' is of type 'HostImage', where and 'x' and 'y' are of type Int32 will draw
  297 + the image at position (x,y) in your widget. This means that the upper left corner of
  298 + the image will be drawn at (x,y). As usual, coordinates are relative to your widget.
  299 +
  300 + You may aslo want to clip the image before drawing it. In this case, use the following
  301 + variant:
  302 +
  303 +public define (HostImage, Int32 x, Int32 y, WidgetRectangle clip) -> One
  304 + draw
  305 + (
  306 + WidgetDrawToolBox dtb
  307 + ).
  308 +
  309 + Again the rectabngle 'clip' is relative to your widget.
  310 +
  311 +
  312 +
  313 + *** (2.3.4) Drawing character strings.
  314 +
  315 + If you want to draw a character string into your widget, use the following tool:
  316 +
  317 +public define (String s, SystemFont f, RGB c, Int32 x, Int32 y) -> Int32
  318 + draw
  319 + (
  320 + WidgetDrawToolBox dtb
  321 + ).
  322 +
  323 + For example the command:
  324 +
  325 + draw(dtb)("gabuzomeu",f,c,10,10)
  326 +
  327 + will draw the string "gabuzomeu" at position (10,10) in your widget using the given
  328 + font 'f' and color 'c'. Note that (x,y) represents the upper left corner of the
  329 + drawing. If the height of the font is 'h', the base point of the first character will
  330 + be at position (x,y+h).
  331 +
  332 + The value returned is the width of the printed string in pixels. Notice also that this
  333 + command does not draw any background. Only the pixels which belong to the body of the
  334 + characters are drawn.
  335 +
  336 + You may also want to clip that drawing. In this case, use the following variant:
  337 +
  338 +public define (String s, SystemFont f, RGB c, Int32 x, Int32 y,
  339 + WidgetRectangle clip) -> Int32
  340 + draw
  341 + (
  342 + WidgetDrawToolBox dtb
  343 + ).
  344 +
  345 +
  346 +
  347 +
  348 + *** (3) Handling events.
  349 +
  350 + Widgets must also handle events. We will have to use the following types:
  351 +
  352 +public type WidgetEventToolBox:...
  353 +public type WidgetEvent:...
  354 +public type WidgetAnswer:...
  355 +
  356 + The first one is opaque, and plays a role analogous to 'WidgetDrawToolBox'. The others
  357 + are not opaque, and are discussed below.
  358 +
  359 + The event handler of your widget is a function of type:
  360 +
  361 + (WidgetEventToolBox, WidgetEvent) -> WidgetAnswer
  362 +
  363 + That your widget 'receives' an event just means that this function has been called (by
  364 + its father widget, or by the widget system itself if here is no father, i.e. if your
  365 + widget is the root widget).
  366 +
  367 + The answer (of type 'WidgetAnswer') gives informations on how the event has been
  368 + handled, and on which area of the host window should be redrawn as a consequence of the
  369 + event.
  370 +
  371 +
  372 +
  373 + *** (3.1) Classification of events.
  374 +
  375 + The following type describes all the events a widget may have to handle.
  376 +
  377 +public type WidgetEvent:
  378 + mouse_move (KeyboardState ks, Int32 x, Int32 y),
  379 + mouse_click (KeyboardState ks, MouseClick mc, Int32 x, Int32 y),
  380 + mouse_gone,
  381 + captured_mouse_move (Var(One) -> Maybe((Int32 x, Int32 y))),
  382 + captured_mouse_liberated (Var(One) -> Maybe((Int32 x, Int32 y))),
  383 + key_down (Var(One) -> Maybe((KeyboardState ks, KeyboardKey kk))),
  384 + changed (Int32 n).
  385 +
  386 + The types 'KeyboardState' and 'MouseClick' are defined in 'predefined.anubis'.
  387 +
  388 + Recall that your widget must eventually transmit events to its childs, and construct
  389 + its answer depending on the answers received from its childs. We now describe the
  390 + meanings of these events.
  391 +
  392 +
  393 +
  394 + *** (3.1.1) 'mouse_move' and 'mouse_click'.
  395 +
  396 + A widget is concerned by a 'mouse_move' or 'mouse_click' event only if the mouse
  397 + pointer lies inside the rectangle of the widget. This is a rule of this system that
  398 + your widget must respect. Hence, when your widget receives a 'mouse_move' or
  399 + 'mouse_click' event, you may rely on the hypothesis that the mouse pointer lies inside
  400 + the rectangle of your widget.
  401 +
  402 + As a consequence, if your widget has one or several childs, it should transmit such
  403 + events to a given child only if the mouse pointer lies within the rectangle of this
  404 + child. However, you don't have to worry about that in general, because the widget
  405 + system checks this condition before allowing the transmission of 'mouse_move' and
  406 + 'mouse_click' events. Hence, you may either check the condition yourself, or just
  407 + transmit such events to all childs. Nevertheless, there are widgets which need to check
  408 + this condition, as for example the desktop widget, because it may have several childs
  409 + whose rectangles overlap. The desktop widget must decide which child should receive the
  410 + event (using the z-order), because the widget system is not able to do it since it does
  411 + not know anything about the z-order.
  412 +
  413 + Notice that if the widget system blocks the transmission of such an event to a given
  414 + child, it replaces it by a 'mouse_gone' event.
  415 +
  416 +
  417 +
  418 + *** (3.1.2) 'mouse_gone'.
  419 +
  420 + If your widget receives a 'mouse_gone' event, you can deduce that the mouse pointer
  421 + does not lie within the rectangle of your widget. This may be useful for example to
  422 + change the visual aspect of the widget when the mouse pointer is leaving the widget.
  423 +
  424 + Now, if your widget has child widgets, it is responsible of generating 'mouse_gone'
  425 + event for its childs. Your widget must send at least one 'mouse_gone' event to a child,
  426 + if the mouse pointer was within the rectangle of the child at the time of the previous
  427 + mouse event, and if this condition is no more true. Hence, your widget must eventually
  428 + keep that information that some child contains the mouse pointer in some variable.
  429 + This variable may be for example of type 'Maybe(Widget)'. If it contains 'failure',
  430 + this means that no child contains the mouse pointer. If it contains 'success(c)' this
  431 + means that the child 'c' contains the mouse pointer. While you keep this variable up to
  432 + date, you must also generate appropriate 'mouse_gone' events for your childs.
  433 +
  434 + Generating extra 'mouse_gone' events (i.e. sending several 'mouse_gone' events to a
  435 + child consecutively) is of course a waste of time. Nevertheless, it has no other
  436 + inconvenient. Also remember that the system replace 'mouse_move' and 'mouse_click'
  437 + events by 'mouse_gone' events if they are transmitted to widgets which do not contain
  438 + the mouse pointer. This fact may simplify the programming of the event handler of your
  439 + widget.
  440 +
  441 +
  442 +
  443 +
  444 +
  445 + *** (3.1.3) 'captured_mouse_move' and 'captured_mouse_liberated'.
  446 +
  447 + If your widget has captured the mouse (how to capture the mouse will be explained
  448 + later), it may receive 'captured_mouse_move' and 'captured_mouse_liberated' events.
  449 + Such events are not submitted to the same rules as the 'mouse_move' and 'mouse_click'
  450 + events.
  451 +
  452 + Your widget captured the mouse using a 'ticket', which is a dynamic variable of type
  453 + 'Var(One)'. When a 'captured_mouse_move' and 'captured_mouse_liberated' event arrives,
  454 + what you get is just a function taking such a ticket as its unique argument. The only
  455 + thing you can do with this event is to apply the function to your ticket.
  456 +
  457 + If the result is 'failure', this means that your widget is not concerned by this
  458 + event. Actually, this also implies that the capture your widget initiated is over. If
  459 + the result is 'success(p)', this means that your widget is concerned by the event (the
  460 + capture is still valid), and that 'p' is the pair of coordinats for the mouse pointer
  461 + (relative to your widget as usual).
  462 +
  463 + If your widget is not concerned by such an event, it must transmit it to all of its
  464 + childs.
  465 +
  466 +
  467 + *** (3.1.4) 'key_down'.
  468 +
  469 + This event works like 'captured_mouse_move' and 'captured_mouse_liberated' events. You
  470 + must apply the function to your ticket in order to know if you are concerned by the
  471 + event. If it is the case you get the keyboard state and the character which has been
  472 + entered.
  473 +
  474 + If your widget is not concerned by this event it must transmit it to all of its childs.
  475 +
  476 +
  477 +
  478 + *** (3.1.5) 'changed'.
  479 +
  480 + This event is generated by the widget system when a dynamic variable registred at the
  481 + widget system is reassigned.
  482 +
  483 +
  484 +
  485 +
  486 + *** (3.2) Classification of answers.
  487 +
  488 + When a widget receives an event, it may handle or not handle the event, but in all
  489 + cases it must return an answer. An answer may contain an 'area' which represents the
  490 + part of the host window which needs to be redrawn. Areas are represented as follows:
  491 +
  492 +public type WidgetArea:...
  493 +
  494 + This is a opaque type, because we want to hide all conversions between absolute and
  495 + relative coordinates. As far as your are concerned, you manipulate only relative
  496 + coordinates (and relative rectangles).
  497 +
  498 + Answers are the following:
  499 +
  500 +public type WidgetAnswer:
  501 + not_handled (WidgetArea),
  502 + handled (WidgetArea),
  503 + resized,
  504 + want_to_capture_mouse (Var(One),WidgetArea),
  505 + want_to_capture_keyboard (Var(One),WidgetArea).
  506 +
  507 + We will give later several tools for manipulating areas. Now, we discuss the meaning of
  508 + these answers.
  509 +
  510 +
  511 +
  512 + *** (3.2.1) 'not_handled' and 'handled'.
  513 +
  514 + If your widget handles the event, it should normally return a 'handled(l)' answer,
  515 + where 'l' is the list of the rectangles (relative to your widget) within which
  516 + redrawing must occur. 'not_handled(l)' is similar but means that your widget did not
  517 + handle the event. Nevertheless, even if the event is not handled, the redrawing of
  518 + several rectangles may be needed.
  519 +
  520 + If your widget has transmitted the event to one or several childs, it will receive
  521 + answers from these childs, and must construct its own answer to be returned to its
  522 + father. How the answer of your widget is constructed from the answers returned by the
  523 + childs may vary depending on the behavior of your widget. This is actually a central
  524 + point of widget programming and you should pay much attention to it. Nevertheless,
  525 + there is no special rule for this. This is up to you.
  526 +
  527 +
  528 +
  529 + *** (3.2.2) 'resized'.
  530 +
  531 + This answer means that the event has been handled, and that it induced a change of size
  532 + of the widget. If your widget receives such an answer from one of its childs, it knows
  533 + that the sier of a childs has changed. This may induce a change of size of your widget,
  534 + but not necessarily. For example, the size of the 'window' widget is independent of the
  535 + size of its content.
  536 +
  537 +
  538 +
  539 +
  540 + *** (3.2.3) 'want_to_capture_mouse' and 'want_to_capture_keyboard'.
  541 +
  542 + Your widget must return one of these answers if it wants to capture either the mouse or
  543 + the keyboard. This answer requires a component of type 'Var(One)' that we call the
  544 + 'capture ticket'. Your widget may either create a new such ticket at each capture, or
  545 + use alway the same one (for example, it may be created before the creation of your
  546 + widget and be accessible to the event handler).
  547 +
  548 + The widget system generates 'captured_mouse_move', 'captures_mouse_liberated' and
  549 + 'key_down' events which are able to recognize your ticket.
  550 +
  551 + These two answers also contain the list of widget rectangles within which redrawing
  552 + must occur.
  553 +
  554 +
  555 +
  556 + *** (3.3) Transmitting events to childs.
  557 +
  558 + Events are transmitted to childs using a tool extracted from the event tool box:
  559 +
  560 +public define (Widget child, Int32 x, Int32 y, WidgetEvent) -> WidgetAnswer
  561 + transmit
  562 + (
  563 + WidgetEventToolBox etb
  564 + ).
  565 +
  566 + If your event tool box is 'etb', and if you want to transmit the event 'e' to the child
  567 + 'c', whose position relative to your widget is '(x,y)', use the following:
  568 +
  569 + transmit(etb)(c,x,y,e)
  570 +
  571 + The returned value is the answer of the child.
  572 +
  573 +
  574 +
  575 +
  576 + *** (3.4) Manipulating areas.
  577 +
  578 + As explained above the type 'WidgetArea' is opaque.
  579 +
  580 +
  581 + *** (3.4.1) Creating areas.
  582 +
  583 + Nevertheless you need to construct areas. This may be done as follows:
  584 +
  585 +public define List(WidgetRectangle) -> WidgetArea
  586 + area
  587 + (
  588 + WidgetEventToolBox etb
  589 + ).
  590 +
  591 + For example if the width of your widget is 'w', and its height is 'h', and if you want
  592 + to redraw the whole widget after some event, you may construct its area as follows:
  593 +
  594 + area(etb)([rect(0,0,w,h)])
  595 +
  596 +
  597 +
  598 + *** (3.4.2) Making the union of two areas.
  599 +
  600 + You may also need to make the union of two areas. This may for example be the case if
  601 + several the childs of your widget return answers containing areas. The following tool
  602 + computes the union of two areas (the event tool box is not required):
  603 +
  604 +public define WidgetArea
  605 + WidgetArea a + WidgetArea b.
  606 +
  607 +
  608 +
  609 + *** (3.4.3) Transmitting areas between widgets.
  610 +
  611 + Areas (of type 'WidgetArea') contain only absolute coordinates. This is the reason why
  612 + the type 'WidgetArea' is opaque. This has also the advantage that areas may be
  613 + transmitted from one widget to another one without any conversion. This possibility is
  614 + used for example by the menu manager widget.
  615 +
  616 +
  617 +
  618 +
  619 +
  620 +
  621 + *** (4) Monitoring dynamic variables.
  622 +
  623 + Widgets need in general to monitor dynamic variables, simply because they are by their
  624 + very nature the graphical representation of the current state of some
  625 + 'machine'. However, a widget has no mean to send a message for redrawing itself. A
  626 + widget may be redrawn only as the consequence of an event. For this reason, widgets
  627 + should not monitor variables themself, but should ask the widget system to do it.
  628 +
  629 + If the widget system has been asked to monitor a dynamic variable 'v', it generates an
  630 + event 'changed(n)', whenever this variable is reassigned, where 'n' is the identifier
  631 + of the dynamic variable. When your widget receives this event, it must compare this
  632 + integer 'n' with the identifier of the variable (say 'v') it depends on. This
  633 + comparison may be done as follows:
  634 +
  635 + if n = var_id(v)
  636 + then ... I do depend on this variable ...
  637 + else ... I don't depend on this variable ...
  638 +
  639 + Of course, if your widget does not depend on the variable, nothing should be done. But
  640 + if it depends on the variable, it may return an answer like 'handled(a)', where 'a' is
  641 + the area to be redrawn. Needless to say, this test must be done with all variables your
  642 + widget depends on.
  643 +
  644 + Several widgets may depend on the same variable. As a consequence, an event like
  645 + 'changed(n)' must always be transmitted to all childs.
  646 +
  647 + Now, a widget asks the system to monitor a dynamic variable at the time this widget is
  648 + created. The type:
  649 +
  650 +public type WidgetRegistration:...
  651 +
  652 + which is opaque, is use for representing 'registrations' of dynamic variables at the
  653 + widget system. In order to register a variable at the widget system, use the following
  654 + tool:
  655 +
  656 +public define WidgetRegistration
  657 + register
  658 + (
  659 + Var($T) v
  660 + ).
  661 +
  662 + By applying this tool to a dynamic variable, you get a registration. When your widget
  663 + is created, you just provide the list of all these registrations. That's all.
  664 +
  665 +
  666 +
  667 +
  668 +
  669 + *** (5) Creating your widget.
  670 +
  671 + Widgets are of type:
  672 +
  673 +public type Widget:...
  674 +
  675 + This is an opaque type, but here is the tool which enables to create a widget.
  676 +
  677 +public define Widget
  678 + create_widget
  679 + (
  680 + One -> (Int32,Int32) get_size,
  681 + (WidgetDrawToolBox) -> One redraw,
  682 + (WidgetEventToolBox,WidgetEvent) -> WidgetAnswer event_handler,
  683 + List(WidgetRegistration) registrations
  684 + ).
  685 +
  686 + The function 'get_size' must return the current size '(width,height)' of your
  687 + widget. Be careful that, if this size is going to change, the function must return the
  688 + current size, not the initial size.
  689 +
  690 + The other arguments have already been explained.
  691 +
  692 +
  693 +
  694 +
  695 +
  696 +
  697 + --- That's all for the public part ! --------------------------------------------------
  698 +
  699 +
  700 +
  701 +
  702 +
  703 +
  704 +
  705 +
  706 +
  707 +
  708 +
  709 +
  710 +
  711 +
  712 +
0 713 \ No newline at end of file
... ...