tree_node.anubis 6.71 KB

                                  The Anubis Project. 
   
                              A Widget System (4th version). 
                                  The 'tree node' widget.
   
                             Copyright (c) Alain Proute' 2005. 
   
   
   Authors: Alain Proute'

read tools/basis.anubis
   
read widget.anubis
   

   A 'tree node'  is made of a main widget  and a list of widgets,  which are displayed in
   one of the following two ways:
   
       folded:                                unfolded:
   
       + main_widget                          - main_widget
                                                  widget_1
                                                  widget_2
                                                  ...
                                                  widget_n
   
   
public type WidgetFolded:
   folded,
   unfolded. 
   
   
   When the user clicks on the '+' he unfolds  the tree node. When he clicks on the '-' he
   folds the tree node.
   
   
public define Widget
   tree_node
     (
       Widget        main, 
       List(Widget)  items,
       Int32         down,        // moves '+' and '-' that number of pixels down
       WidgetFolded  folded       // starts either folded or unfolded
     ). 

   --- That's all for the public part ! --------------------------------------------------
   
   
read tools.anubis   

   
define Int32 mw = 6.
   
   
   *** [] Computing the size of the tree node. 
      
   
define (Int32,Int32)
   stack_size
     (
       List(Widget) l
     ) =
   if l is 
     {
       [ ] then (0,0), 
       [h . t] then 
         if size(h) is (w,h) then 
         if stack_size(t) is (iw,ih) then 
           (max(w,iw),h+ih)
     }.
   
   
   
define One -> (Int32,Int32)
   size
     (
       Var(Bool)      folded_v,
       Widget         main, 
       List(Widget)   items,
       Int32          down
     ) =
   with mw2 = mw+mw, mw4 = mw2+mw2, 
   (One u) |-> if *folded_v is
     {
       false then 
         if size(main) is (w,h) then 
         if stack_size(items) is (iw,ih) then 
           (max(mw2 + w, mw4 + iw), h + ih),
   
       true then 
         if size(main) is (w,h) then 
           (mw2 + w, max(mw2,h))
     }.
   
   
   
   *** [] The draw method. 
   
   
define One
   draw_items
     (
       WidgetDrawToolBox      dtb, 
       List(Widget)           items, 
       Int32                  h,
       Int32                  down, 
       Int32                  mw, 
       Int32                  mw4
     ) =
   if items is 
     {
       [ ] then unique, 
       [item_1 . others] then 
         if size(item_1) is (_,h1) then
           draw(dtb)(rect(mw,h,mw+1,h+(if others is [] then mw+down else h1)),rgb(0,0,0));
           draw(dtb)(rect(mw,h+mw+down,mw4+1,h+mw+down+1),rgb(0,0,0));
           draw(dtb)(item_1,mw4,h); 
           draw_items(dtb,others,h+h1,down,mw,mw4)
     }.
   
define WidgetDrawToolBox -> One
   draw_method
     (
       Var(Bool)        folded_v, 
       Widget           main, 
       List(Widget)     items,
       Int32            down
     ) =
   with black = rgb(0,0,0), mw2 = mw+mw, mw4 = mw2+mw2, 
   (WidgetDrawToolBox dtb) |-> 
     draw_relief_edge(dtb,1,rect(1,1+down,mw2-1,mw2-1+down),black,black); // draw the small square
     draw(dtb)(main,mw2,0);
     if items is 
       {
         [ ] then unique, 
         [_._] then 
           draw(dtb)(rect(3,mw-1+down,mw2-3,mw+1+down),black); // draw the '-' sign
           (if *folded_v then draw(dtb)(rect(mw-1,3+down,mw+1,mw2-3+down),black) else unique); // '+' sign
           (if *folded_v then unique else 
              if size(main) is (_,h) then 
              draw(dtb)(rect(mw,mw2-1+down,mw+1,h),rgb(0,0,0)); // start of line down
              draw_items(dtb,items,h,down,mw,mw4)) // items
       }.
   
   
   
   
   
   
   *** [] The event handler. 
   
   
define WidgetAnswer
   merge_answers
     (
       WidgetAnswer  a1, 
       WidgetAnswer  a2
     ) =
   if a1 is 
     {
       not_handled(area1) then if a2 is 
         {
           not_handled(area2)            then not_handled(area1+area2), 
           handled(area2)                then handled(area1+area2), 
           resized                       then resized,
           ignored                       then a1
           want_to_capture_mouse(_,_,_)  then a2,
           want_to_capture_keyboard(_,_) then a2
         },
   
       handled(area1) then if a2 is 
         {
           not_handled(area2)            then handled(area1+area2), 
           handled(area2)                then handled(area1+area2), 
           resized                       then resized,
           ignored                       then a1,
           want_to_capture_mouse(_,_,_)  then a2,
           want_to_capture_keyboard(_,_) then a2
         }, 
   
       resized                           then resized,
       ignored                           then a2,
       want_to_capture_mouse(v,cf,area)  then a1,
       want_to_capture_keyboard(v,area)  then a1,
     }. 
   
     
define WidgetAnswer   
   transmit
     (
       WidgetEventToolBox       etb, 
       List(Widget)             items, 
       Int32                    h,
       WidgetEvent              e,
       Int32                    mw4
     ) =
   if items is 
     {
       [ ] then ignored, 
       [first . others] then 
         if size(first) is (_,h1) then 
         merge_answers(transmit(etb)(first,mw4,h,e),
                       transmit(etb,others,h+h1,e,mw4))
     }.
   
   
define (WidgetEventToolBox,WidgetEvent) -> WidgetAnswer
   event_handler
     (
       Var(Bool)         folded_v, 
       Widget            main, 
       List(Widget)      items,
       Int32             down
     ) =
   with mw2 = mw+mw, mw4 = mw2+mw2, 
   (WidgetEventToolBox etb, WidgetEvent e) |->
     if size(main) is (w,h) then 
     if e is mouse_click(ks,mc,x,y) 
     then 
       (
         if (down =< x & x =< mw2+down & down =< y & y =< mw2+down & mc = left_down)
         then 
           (
             folded_v <- (if *folded_v then false else true); 
             resized
           )
         else 
         merge_answers(transmit(etb)(main,mw2,0,e), 
                       transmit(etb,items,h,e,mw4))
       )
     else
       (
         merge_answers(transmit(etb)(main,mw2,0,e), 
                       transmit(etb,items,h,e,mw4))
       ). 
   

   *** [] Creating the tree node. 
   
public define Widget
   tree_node
     (
       Widget        main, 
       List(Widget)  items,
       Int32         down,
       WidgetFolded  fld
     ) =
   with    folded_v = var((Bool)fld=folded), 
     create_widget
       (
         size(folded_v,main,items,down),
         draw_method(folded_v,main,items,down), 
         event_handler(folded_v,main,items,down),
         (One u) |-> []
       ).