home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 2 / AUCD2.iso / program / vista.arc / c / wins < prev   
Text File  |  1996-02-01  |  26KB  |  1,052 lines

  1. // **************************************************************************
  2. //                     Copyright 1996 David Allison
  3. //
  4. //             VV    VV    IIIIII     SSSSS     TTTTTT       AA
  5. //             VV    VV      II      SS           TT       AA  AA
  6. //             VV    VV      II        SSSS       TT      AA    AA
  7. //              VV  VV       II           SS      TT      AAAAAAAA
  8. //                VV       IIIIII     SSSS        TT      AA    AA
  9. //
  10. //                    MULTI-THREADED C++ WIMP CLASS LIBRARY
  11. //                                for RISC OS
  12. // **************************************************************************
  13. //
  14. //             P U B L I C    D O M A I N    L I C E N C E
  15. //             -------------------------------------------
  16. //
  17. //     This library is copyright. You may not sell the library for
  18. //     profit, but you may sell products which use it providing
  19. //     those products are presented as executable code and are not
  20. //     libraries themselves.  The library is supplied without any
  21. //     warranty and the copyright owner cannot be held responsible for
  22. //     damage resulting from failure of any part of this library.
  23. //
  24. //          See the User Manual for details of the licence.
  25. //
  26. // *************************************************************************
  27.  
  28. #include "Vista:task.h"
  29. #include "Vista:wins.h"
  30. #include <kernel.h>
  31. #include <swis.h>
  32. #include "icon.h"
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <stdarg.h>
  37.  
  38. #ifndef __EASY_C
  39. #include "Vista:myargs.h"
  40. #endif
  41.  
  42. //
  43. // An IconGrid
  44. //
  45.  
  46. // this has a window with a vertical scroll bar and can be resized.
  47. // It traps the open event from the Wimp and checks the current size
  48. // of the window.  If it can rearrange the icons it will.
  49. //
  50.  
  51. IconGrid::IconGrid (Task *task, char *tname, int ticon, char *menu)
  52.  : Window (task, tname, menu)
  53.    {
  54.    init (ticon) ;
  55.    }
  56.  
  57. IconGrid::IconGrid (Window *w, char *tname, int ticon, char *menu)
  58.  : Window (w, tname, 0, menu)
  59.    {
  60.    init (ticon) ;
  61.    }
  62.  
  63.  
  64. IconGrid::~IconGrid()
  65.    {
  66.    }
  67.  
  68. void IconGrid::init (int ticon)
  69.    {
  70.    _kernel_swi_regs r ;
  71.    _kernel_oserror *e ;
  72.    int block[40] ;
  73.  
  74.    template_icon = new Icon (this, ticon) ;
  75.    template_icon->move_to (-1000,1000) ;     // move the icon out of sight
  76.    block[0] = handle ;
  77.    block[1] = ticon ;
  78.    r.r[1] = (int)block ;
  79.    if ((e = _kernel_swi (Wimp_GetIconState, &r, &r)) != NULL)
  80.       throw (e) ;
  81.    template_button_type = (Icon::buttontype)((block[6] & 0xf000) >> 12) ;
  82.    Box *box = (Box*)&block[2] ;
  83.    icon_height = box->y1 - box->y0 ;
  84.    icon_width = box->x1 - box->x0 ;
  85.    num_rows = 0 ;
  86.    num_icons = 0 ;
  87.    current_column = 0 ;
  88.    current_row = 0 ;
  89.    num_columns = (x1 - x0 - ICONGRID_LEFT_MARGIN) / (icon_width + ICONGRID_HOR_GAP) ;
  90.    if (num_columns == 0)
  91.       num_columns = 1 ;
  92.    flag_set = NONE ;
  93.    Window::Info *inf = info() ;
  94.    min_height = inf->extent.y1 - inf->extent.y0 ;
  95.    }
  96.  
  97.  
  98. void IconGrid::set_flag (flags flag)
  99.    {
  100. #ifndef __EASY_C
  101.    int f = (int)flag_set ;
  102.    f |= (int)flag ;
  103.    flag_set = (flags)f ;
  104. #else
  105.    flag_set |= (flags)flag ;
  106. #endif
  107.    }
  108.  
  109. void IconGrid::clear_flag (flags flag)
  110.    {
  111. #ifndef __EASY_C
  112.    int f = (int)flag_set ;
  113.    f &= ~(int)flag ;
  114.    flag_set = (flags)f ;
  115. #else
  116.    flag_set |= (flags)flag ;
  117. #endif
  118.    }
  119.  
  120. //
  121. // add a new icon into the window.  This will fill up the window from
  122. // left to right taking a new row when a row is full.
  123. //
  124.  
  125. Icon *IconGrid::insert_icon(char *text, void *ref)
  126.    {
  127.    int x, y ;
  128.  
  129.    x = current_column * (icon_width + ICONGRID_HOR_GAP) + ICONGRID_LEFT_MARGIN ;
  130.    y = current_row * (icon_height + ICONGRID_VERT_GAP) + icon_height +ICONGRID_TOP_MARGIN ;
  131.  
  132.    Icon *icon = new Icon (this, template_icon, x, -y, ref) ;
  133.    Box pos ;
  134.    icon->read_position (pos) ;
  135.    do_redraw (pos.x0, pos.y0, pos.x1, pos.y1) ;    // redraw the window
  136.    icon->print (text) ;
  137.    num_icons++ ;
  138.    current_column++ ;
  139.    if (current_column == num_columns)
  140.       {
  141.       current_column = 0 ;
  142.       current_row++ ;
  143.       int new_height = current_row * (icon_height + ICONGRID_VERT_GAP) + icon_height +ICONGRID_TOP_MARGIN ;
  144.       if (new_height > min_height)
  145.          set_height (new_height) ;
  146.       }
  147.    if (flag_set & SORTED)
  148.       sort() ;
  149.    return icon ;
  150.    }
  151.  
  152. Icon *IconGrid::insert_icon(char *text, char *sprite, void *ref)
  153.    {
  154.    int x, y ;
  155.  
  156.    x = current_column * (icon_width + ICONGRID_HOR_GAP) + ICONGRID_LEFT_MARGIN ;
  157.    y = current_row * (icon_height + ICONGRID_VERT_GAP) + icon_height +ICONGRID_TOP_MARGIN ;
  158.  
  159.    Icon *icon = new Icon (this, template_icon, x, -y, ref) ;
  160.    Box pos ;
  161.    icon->read_position (pos) ;
  162.    do_redraw (pos.x0, pos.y0, pos.x1, pos.y1) ;    // redraw the window
  163.    icon->print (text) ;
  164.    icon->change_sprite (sprite) ;
  165.    num_icons++ ;
  166.    current_column++ ;
  167.    if (current_column == num_columns)
  168.       {
  169.       current_column = 0 ;
  170.       current_row++ ;
  171.       int new_height = current_row * (icon_height + ICONGRID_VERT_GAP) + icon_height +ICONGRID_TOP_MARGIN ;
  172.       if (new_height > min_height)
  173.          set_height (new_height) ;
  174.       }
  175.    if (flag_set & SORTED)
  176.       sort() ;
  177.    return icon ;
  178.    }
  179.  
  180.  
  181. void IconGrid::remove_icon(Icon *icon)
  182.    {
  183.    Window::remove_icon (icon) ;
  184.    if (!deleting)
  185.       {
  186.       num_icons-- ;
  187.       if (flag_set & SORTED)
  188.          sort() ;
  189.       }
  190.    }
  191.  
  192. void IconGrid::delete_icon (void *ref)
  193.    {
  194.    for (Icon *icon = icons ; icon != NULL ; icon = icon->next)
  195.       if (ref == icon->user_ref)
  196.          {
  197.          delete icon ;
  198.          break ;
  199.          }
  200.    }
  201.  
  202. //
  203. // sort the icons in the grid using qsort
  204. //
  205.  
  206.  
  207. static int sort_compare (const void *i1, const void *i2)
  208.    {
  209.    const Icon **x = (const Icon**)i1 ;
  210.    const Icon **y = (const Icon**)i2 ;
  211. #ifdef __EASY_C
  212.    return (*x)->compare(*y) ;
  213. #else
  214.    Icon *i = (Icon*)*x ;
  215.    Icon *j = (Icon*)*y ;
  216.    return i->compare(j) ;
  217. #endif
  218.    }
  219.  
  220.  
  221. void IconGrid::sort()
  222.    {
  223.    int i ;
  224.    Icon *icon ;
  225.    Icon **buffer = new Icon *[num_icons] ;
  226.    for (icon = icons, i = 0 ; icon != NULL ; icon = icon->next)
  227.       if (icon != template_icon)
  228.          buffer[i++] = icon ;
  229.    qsort (buffer, num_icons, sizeof (Icon *), sort_compare) ;
  230.    icons = NULL ;               // reset icons list
  231.    add_icon (template_icon) ;   // add the template again
  232.    for (i = 0 ; i < num_icons ; i++)     // put all the icons back
  233.       add_icon (buffer[i]) ;
  234.    rearrange() ;
  235.    delete [] buffer ;
  236.    }
  237.  
  238.  
  239. void IconGrid::open(int x0, int y0, int x1, int y1, int scx, int scy, int behind)
  240.   {
  241.   Window::open (x0,y0,x1,y1,scx,scy,behind) ;   // open the window
  242.   int nc = (x1 - x0 - ICONGRID_LEFT_MARGIN) / (icon_width + ICONGRID_HOR_GAP) ;
  243.   if (nc == 0)
  244.     nc = 1 ;
  245.   if (num_icons != 0 && nc != num_columns)
  246.      {
  247.      num_columns = nc ;
  248.      rearrange() ;
  249.      }
  250.   num_columns = nc ;
  251.   }
  252.  
  253.  
  254. void IconGrid::click(int mx, int my, int buttons, int icon)
  255.    {
  256.    int click_factor ;
  257.    int double_factor ;
  258.    int drag_factor ;
  259.    switch (template_button_type)
  260.       {
  261.       case Icon::BCLICKDEBOUNCE:
  262.          click_factor = 1 ;
  263.          double_factor = 0 ;
  264.          drag_factor = 0 ;
  265.          break ;
  266.       case Icon::BDEBOUNCEDRAG:
  267.       default:
  268.          click_factor = 1 ;
  269.          double_factor = 0 ;
  270.          drag_factor = 16 ;
  271.          break ;
  272.       case Icon::BCLICKDRAGDOUBLE:
  273.          click_factor = 256 ;
  274.          double_factor = 1 ;
  275.          drag_factor = 16 ;
  276.          break ;
  277.       }
  278.    if (icon >= 0)
  279.       {
  280.       Icon *ic = Window::find_icon (icon) ;
  281.       if (buttons & (4 * drag_factor))
  282.          {
  283.          int count = 0 ;
  284.          int minx = 30000, maxx = 0, miny = 0, maxy = -30000;
  285.          Box pos ;
  286.          for (Icon *i = icons ; i != NULL ; i = i->next)
  287.             if (i->is_selected())
  288.                {
  289.                count++ ;
  290.                i->read_position(pos) ;
  291.                if (pos.x0 < minx) minx = pos.x0 ;
  292.                if (pos.x1 > maxx) maxx = pos.x1 ;
  293.                if (pos.y0 < miny) miny = pos.y0 ;
  294.                if (pos.y1 > maxy) maxy = pos.y1 ;
  295.                }
  296.          minx += x0 ;
  297.          miny += y1 ;
  298.          maxx += x0 ;
  299.          maxy += y1 ;
  300.          if (count > 1)
  301.             drag_selection (mx, my, buttons, minx, miny, maxx, maxy) ;
  302.          else
  303.             drag_icon (mx, my, buttons, ic) ;
  304.          return ;
  305.          }
  306.       if (buttons & (4 * double_factor))
  307.          {
  308.          double_click (mx, my, buttons, ic) ;
  309.          if (!(flag_set & NODESELECT))
  310.             {
  311.             if (ic->is_selected())
  312.                ic->unselect() ;
  313.             }
  314.          return ;
  315.          }
  316.       if (flag_set & NOSELECT)
  317.          return ;
  318.       if (buttons & (4 * click_factor))
  319.          {
  320.          if (!ic->is_selected())
  321.             {
  322.             clear_selection() ;
  323.             ic->select() ;
  324.             }
  325.          }
  326.       else
  327.          if (buttons & (1 | 256))
  328.             if (ic->is_selected())
  329.                ic->unselect() ;
  330.             else
  331.                ic->select() ;
  332.       }
  333.    else
  334.       if (flag_set & NOSELECT)
  335.          return ;
  336.       else if (buttons & (4 * 16))
  337.          {
  338.          int block[16] ;
  339.          _kernel_swi_regs r ;
  340.          _kernel_oserror *e ;
  341.  
  342.          block[0] = handle ;
  343.          block[1] = 6 ;           // user rotating dash box
  344.          block[2] = mx ;
  345.          block[3] = my ;
  346.          block[4] = mx + 1 ;
  347.          block[5] = my + 1 ;
  348.          if (parent == NULL)
  349.             {
  350.             block[6] = x0 ;
  351.             block[7] = y0 ;
  352.             block[8] = x1 ;
  353.             block[9] = y1 ;
  354.             }
  355.          else
  356.             {
  357.             block[6] = parent->x0 + x0 ;
  358.             block[7] = parent->y0 + y0 ;
  359.             block[8] = parent->x1 + x1 ;
  360.             block[9] = parent->y1 + y1 ;
  361.             }
  362.          r.r[1] = (int)block ;
  363.          if ((e = _kernel_swi (Wimp_DragBox, &r, &r)) != NULL)
  364.             throw (e) ;
  365.          task->register_drag (this,0) ;
  366.          clear_selection() ;
  367.          }
  368.       else
  369.          if (buttons & (4 * click_factor))            // click outside icons
  370.             clear_selection() ;
  371.    }
  372.  
  373.  
  374. void IconGrid::double_click(int mx, int my, int buttons, Icon *icon)
  375.    {
  376.    }
  377.  
  378. void IconGrid::drag_icon(int mx, int my, int buttons, Icon *icon)
  379.    {
  380.    }
  381.  
  382. void IconGrid::drag_selection(int mx, int my, int buttons, int x0, int y0, int x1, int y1)
  383.    {
  384.    }
  385.  
  386. void IconGrid::drag (int dx0, int dy0, int dx1, int dy1, int id)
  387.    {
  388.    Icon *icon ;
  389.    Box box ;
  390. //   ::print ("dx0:%d dy0:%d Dx1:%d dy1:%d x0:%d y0:%d x1:%d y1:%d",dx0,dy0,dx1,dy1,x0,y0,x1,y1) ;
  391.    int tmp ;
  392.    int xdiff, ydiff ;
  393.    if (dx0 > dx1)          // strange - shouldn't have to do this surely
  394.       {
  395.       tmp = dx0 ;
  396.       dx0 = dx1 ;
  397.       dx1 = tmp ;
  398.       }
  399.    if (dy0 > dy1)
  400.       {
  401.       tmp = dy0 ;
  402.       dy0 = dy1 ;
  403.       dy1 = tmp ;
  404.       }
  405.    xdiff = x0 - scx ;
  406.    ydiff = y1 - scy ;
  407.    if (parent == NULL)
  408.       {
  409.       dx0 -= xdiff ;
  410.       dx1 -= xdiff ;
  411.       dy0 -= ydiff ;
  412.       dy1 -= ydiff ;
  413.       }
  414.    else
  415.       {
  416.       dx0 -= parent->x0 + xdiff ;
  417.       dx1 -= parent->x0 + xdiff ;
  418.       dy0 -= parent->y0 + ydiff ;
  419.       dy1 -= parent->y0 + ydiff ;
  420.       }
  421. //   ::print ("%d %d %d %d", dx0, dy0, dx1, dy1) ;
  422.    for (icon = icons ; icon != NULL ; icon = icon->next)
  423.       if (icon != template_icon)
  424.          {
  425.          icon->read_position(box) ;
  426. //         ::print ("%d %d %d %d",box.x0, box.y0, box.x1, box.y1) ;
  427.          if (dx0 <= box.x1 && dx1 >= box.x0 && dy1 >= box.y0 && dy0 <= box.y1)
  428.             icon->select() ;
  429.          }
  430.  
  431.    }
  432.  
  433.  
  434. Icon *IconGrid::find_icon (int icon)
  435.    {
  436.    return NULL ;                  // want window to deal with icon clicks
  437.    }
  438.  
  439.  
  440. void IconGrid::select_all()
  441.    {
  442.    Icon *icon ;
  443.    for (icon = icons ; icon != NULL ; icon = icon->next)
  444.       if (icon != template_icon)
  445.          if (!icon->is_selected())
  446.             icon->select() ;
  447.    }
  448.  
  449. void IconGrid::clear_selection()
  450.    {
  451.    Icon *icon ;
  452.    for (icon = icons ; icon != NULL ; icon = icon->next)
  453.       if (icon != template_icon)
  454.          if (icon->is_selected())
  455.             icon->unselect() ;
  456.    }
  457.  
  458.  
  459. void IconGrid::rearrange()
  460.    {
  461.    Icon *icon ;
  462.  
  463.    current_column = 0 ;
  464.    current_row = 0 ;
  465.    for (icon = icons ; icon != NULL ; icon = icon->next)
  466.       {
  467.       if (icon != template_icon)
  468.          {
  469.          int x = current_column * (icon_width + ICONGRID_HOR_GAP) + ICONGRID_LEFT_MARGIN ;
  470.          int y = current_row * (icon_height + ICONGRID_VERT_GAP) + icon_height + ICONGRID_TOP_MARGIN ;
  471.          icon->move_to (x,-y) ;
  472.          current_column++ ;
  473.          if (current_column == num_columns)
  474.             {
  475.             current_column = 0 ;
  476.             current_row++ ;
  477.             }
  478.          }
  479.       }
  480.    Window::Info *inf = info() ;
  481.    min_height = inf->extent.y1 - inf->extent.y0 ;
  482.    int new_height = current_row * (icon_height + ICONGRID_VERT_GAP) + icon_height + ICONGRID_TOP_MARGIN ;
  483.    if (new_height > min_height)
  484.       set_height (new_height) ;
  485.    do_redraw() ;             // whole window
  486.    }
  487.  
  488.  
  489. //
  490. // a dialogue box
  491. //
  492.  
  493.  
  494. DialogueBox::DialogueBox (Task *t, char *tname, int cancel, int ok, char *menu)
  495.    : Window (t, tname, menu), Thread (tname)
  496.    {
  497.    attributes = NULL ;
  498.    cancel_icon = NULL ;
  499.    ok_icon = NULL ;
  500.    cancelled = false ;
  501.    if (cancel != -1)
  502.       cancel_icon = new CancelButton (this, cancel) ;
  503.    if (ok != -1)
  504.       ok_icon = new OKButton (this, ok) ;
  505.    waiting = new ThreadSemaphore ;
  506.    }
  507.  
  508. DialogueBox::~DialogueBox ()
  509.    {
  510.    if (cancel_icon != NULL)
  511.       delete cancel_icon ;
  512.    if (ok_icon != NULL)
  513.       delete ok_icon ;
  514.    delete waiting ;
  515.    Attribute *a, *nexta ;
  516.    for (a = attributes ; a != NULL ; a = nexta)
  517.       {
  518.       nexta = a->next ;
  519.       delete a ;
  520.       }
  521.    }
  522.  
  523. void DialogueBox::show()
  524.    {
  525.    ok_or_cancel_pressed = false ;
  526.    for (Attribute *attr = attributes ; attr != NULL ; attr = attr->next)
  527.       attr->set() ;
  528.    from_menu = false ;
  529.    if (task->last_event == Task::ESEND && task->last_event_data[4] == Task::Message_MenuWarning)
  530.       {
  531.       from_menu = true ;
  532.       _kernel_swi_regs r ;
  533.       _kernel_oserror *e ;
  534.       r.r[1] = handle ;
  535.       r.r[2] = task->last_event_data[6] ;
  536.       r.r[3] = task->last_event_data[7] ;
  537.       if ((e = _kernel_swi (Wimp_CreateSubMenu, &r, &r)) != NULL)
  538.          throw (e) ;
  539.       }
  540.    else
  541.       do_open() ;
  542.    if (attributes != NULL)
  543.       {
  544.       Attribute *attr = attributes ;
  545.       while (attr != NULL && !attr->is_writeable())
  546.          attr = attr->next ;
  547.       if (attr != NULL)
  548.          attr->set_caret() ;
  549.       }
  550.    start() ;                // start the thread running
  551.    }
  552.  
  553. //
  554. // this is complicated by the fact that the WIMP doesn't tell the task anything
  555. // when a window is opened from a menu (menu warning) and the mouse is moved
  556. // back onto the menu thus closing the window.  In this case we
  557. // loop reading the window state until the WOPEN flag is clear signifying
  558. // that the window has been closed.
  559. //
  560. // If we are not from a menu then we just sleep until the 'waiting' semaphore is
  561. // set.
  562. //
  563.  
  564. void DialogueBox::run()
  565.    {
  566.    if (from_menu)                   // are we from a menu?
  567.       {
  568.       Window::State *s = Window::state() ;
  569.       while (s->flags & WOPEN)       // wait until we are not open
  570.          {
  571.          yield() ;
  572.          s = Window::state() ;
  573.          }
  574.       }
  575.    else
  576.       sleep (waiting) ;             // sleep until no longer waiting
  577.    }
  578.  
  579. void DialogueBox::hide()
  580.    {
  581.    if (from_menu)
  582.       {
  583.       _kernel_swi_regs r ;
  584.       _kernel_oserror *e ;
  585.       r.r[1] = -1  ;
  586.       r.r[2] = 0 ;
  587.       r.r[3] = 0 ;
  588.       if ((e = _kernel_swi (Wimp_CreateMenu, &r, &r)) != NULL)
  589.          throw (e) ;
  590.       }
  591.    else
  592.       close() ;
  593.    }
  594.  
  595. void DialogueBox::next_attribute(int icon)
  596.    {
  597.    Attribute *attr ;
  598.    for (attr = attributes ; attr != NULL ; attr = attr->next)
  599.       if (attr->icon->handle == icon)
  600.          {
  601.          if (attr->next == NULL)
  602.             attr = attributes ;
  603.          else
  604.             attr = attr->next ;
  605.          while (!attr->is_writeable())
  606.             {
  607.             attr = attr->next ;
  608.             if (attr == NULL)
  609.                attr = attributes ;
  610.             }
  611.          attr->set_caret() ;
  612.          break ;
  613.          }
  614.    }
  615.  
  616. void DialogueBox::prev_attribute(int icon)
  617.    {
  618.    Attribute *attr ;
  619.    for (attr = attributes ; attr != NULL ; attr = attr->next)
  620.       if (attr->icon->handle == icon)
  621.          {
  622.          if (attr->prev == NULL)
  623.             attr = last_attribute ;
  624.          else
  625.             attr = attr->prev ;
  626.          while (!attr->is_writeable())
  627.             {
  628.             attr = attr->prev ;
  629.             if (attr == NULL)
  630.                attr = last_attribute ;
  631.             }
  632.          attr->set_caret() ;
  633.          break ;
  634.          }
  635.    }
  636.  
  637. void DialogueBox::click (int mx, int my, int buttons, int icon)
  638.    {
  639.    Icon *i = Window::find_icon (icon) ;
  640.    if (i != NULL)
  641.       i->click (mx, my, buttons, icon) ;
  642.    }
  643.  
  644. void DialogueBox::key (int icon, int x, int y, int height, int index, int code)
  645.    {
  646. //   ::print ("key %d",code) ;
  647.    switch (code)
  648.       {
  649.       case 13:                    // cr
  650.          ok(4) ;
  651.          break ;
  652.       case 27:                    // esc
  653.          cancel(4) ;
  654.          break ;
  655.       case 394:                   // tab
  656.       case 398:                   // down arrow
  657.          next_attribute (icon) ;
  658.          break ;
  659.       case 399:                   // up arrow
  660.       case 410:                   // shift-tab
  661.          prev_attribute(icon) ;
  662.          break ;
  663.       }
  664.    }
  665.  
  666. // if the window is closed without the user pressing OK or cancel, the
  667. // cancelled flag is set.
  668.  
  669. void DialogueBox::close()
  670.    {
  671.    if (!ok_or_cancel_pressed)       // was the OK or cancel buttons pressed?
  672.       cancelled = true ;            // no, so must have been closed by close button etc.
  673.    waiting->set() ;
  674.    if (from_menu)
  675.       {
  676.       _kernel_swi_regs r ;
  677.       _kernel_oserror *e ;
  678.       r.r[1] = -1  ;
  679.       r.r[2] = 0 ;
  680.       r.r[3] = 0 ;
  681.       if ((e = _kernel_swi (Wimp_CreateMenu, &r, &r)) != NULL)
  682.          throw (e) ;
  683.       }
  684.    Window::do_close() ;
  685.    }
  686.  
  687.  
  688. void DialogueBox::cancel(int button)
  689.    {
  690.    waiting->set() ;
  691.    cancelled = true ;
  692.    ok_or_cancel_pressed = true ;
  693.    hide() ;
  694.    }
  695.  
  696. void DialogueBox::ok(int button)
  697.    {
  698.    waiting->set() ;
  699.    ok_or_cancel_pressed = true ;
  700.    cancelled = false ;
  701.    for (Attribute *attr = attributes ; attr != NULL ; attr = attr->next)
  702.       attr->get() ;
  703.    hide() ;
  704.    }
  705.  
  706. void DialogueBox::add_attribute (Attribute *attr)
  707.    {
  708.    if (attributes == NULL)
  709.       attributes = last_attribute = attr ;
  710.    else
  711.       {
  712.       attr->prev = last_attribute ;
  713.       last_attribute->next = attr ;
  714.       last_attribute = attr ;
  715.       }
  716.    }
  717.  
  718. void DialogueBox::create_attribute (int iconnum, char *str)
  719.    {
  720.    StringAttribute *attr = new StringAttribute (this, str, iconnum) ;
  721.    }
  722.  
  723. void DialogueBox::create_attribute (int iconnum, int &number)
  724.    {
  725.    IntegerAttribute *attr = new IntegerAttribute (this, number, iconnum) ;
  726.    }
  727.  
  728. void DialogueBox::create_attribute (int iconnum, bool &value)
  729.    {
  730.    BoolAttribute *attr = new BoolAttribute (this, value, iconnum) ;
  731.    }
  732.  
  733. void DialogueBox::create_attribute (int num_values, bool *values ...)
  734.    {
  735.    va_list ap ;
  736.    va_start (ap, values) ;
  737.    SetAttribute *attr = new SetAttribute (this, values, num_values, ap) ;
  738.    va_end (ap) ;
  739.    }
  740.  
  741. void DialogueBox::create_attribute (Icon *icon, int &value)
  742.    {
  743.    IntegerAttribute *attr = new IntegerAttribute (this, value, icon) ;
  744.    }
  745.  
  746. void DialogueBox::create_attribute (Icon *icon, char *value)
  747.    {
  748.    StringAttribute *attr = new StringAttribute (this, value, icon) ;
  749.    }
  750.  
  751. void DialogueBox::create_attribute (Icon *icon, bool &value)
  752.    {
  753.    BoolAttribute *attr = new BoolAttribute (this, value, icon) ;
  754.    }
  755.  
  756.  
  757. Attribute::Attribute (DialogueBox *d, int iconnum, char *menu)
  758.    {
  759.    icon = new Icon (d, iconnum) ;
  760.    next = NULL ;
  761.    prev = NULL ;
  762.    default_menu = menu ;
  763.    d->add_attribute (this) ;
  764.    my_icon = 1 ;
  765.    }
  766.  
  767. Attribute::Attribute (DialogueBox *d, Icon *icon, char *menu)
  768.    {
  769.    this->icon = icon ;
  770.    next = NULL ;
  771.    prev = NULL ;
  772.    default_menu = menu ;
  773.    d->add_attribute (this) ;
  774.    my_icon = 0 ;
  775.    }
  776.  
  777. Attribute::Attribute (DialogueBox *d)
  778.    {
  779.    this->icon = NULL ;
  780.    next = NULL ;
  781.    prev = NULL ;
  782.    default_menu = NULL ;
  783.    d->add_attribute (this) ;
  784.    my_icon = 0 ;
  785.    }
  786.  
  787. Attribute::~Attribute()
  788.    {
  789.    if (my_icon)
  790.       delete icon ;
  791.    }
  792.  
  793. void Attribute::set_caret()
  794.    {
  795.    icon->set_caret() ;
  796.    }
  797.  
  798. int Attribute::is_writeable()
  799.    {
  800.    if (icon == NULL)
  801.       return 0 ;
  802.    return icon->is_writeable() ;
  803.    }
  804.  
  805. StringAttribute::StringAttribute (DialogueBox *d, char *str, int iconnum, char *menu)
  806.    : Attribute (d, iconnum, menu)
  807.    {
  808.    string = str ;
  809.    }
  810.  
  811. StringAttribute::StringAttribute (DialogueBox *d, char *str, Icon *icon, char *menu)
  812.    : Attribute (d, icon, menu)
  813.    {
  814.    string = str ;
  815.    }
  816.  
  817. StringAttribute::~StringAttribute()
  818.    {
  819.    }
  820.  
  821. void StringAttribute::get()
  822.    {
  823.    icon->read (string) ;
  824.    }
  825.  
  826. void StringAttribute::set()
  827.    {
  828.    icon->write (string) ;
  829.    }
  830.  
  831.  
  832. IntegerAttribute::IntegerAttribute (DialogueBox *d, int &number, int iconnum,  char *menu)
  833.    : Attribute (d, iconnum, menu)
  834.    {
  835.    num = &number ;
  836.    }
  837.  
  838. IntegerAttribute::IntegerAttribute (DialogueBox *d, int &number, Icon *icon, char *menu)
  839.    : Attribute (d, icon, menu)
  840.    {
  841.    num = &number ;
  842.    }
  843.  
  844. IntegerAttribute::~IntegerAttribute()
  845.    {
  846.    }
  847.  
  848. void IntegerAttribute::get()
  849.    {
  850.    icon->read (*num) ;
  851.    }
  852.  
  853. void IntegerAttribute::set()
  854.    {
  855.    icon->write (*num) ;
  856.    }
  857.  
  858.  
  859. BoolAttribute::BoolAttribute (DialogueBox *d, bool &value, int iconnum, char *menu)
  860.    : Attribute (d, iconnum, menu)
  861.    {
  862.    this->value = &value ;
  863.    }
  864.  
  865. BoolAttribute::BoolAttribute (DialogueBox *d, bool &value, Icon *icon, char *menu)
  866.    : Attribute (d, icon, menu)
  867.    {
  868.    this->value = &value ;
  869.    }
  870.  
  871. BoolAttribute::~BoolAttribute()
  872.    {
  873.    }
  874.  
  875. void BoolAttribute::get()
  876.    {
  877.    *value = icon->is_selected() ? true : false ;
  878.    }
  879.  
  880. void BoolAttribute::set()
  881.    {
  882.    if (*value)
  883.       icon->select() ;
  884.    else
  885.       icon->unselect() ;
  886.    }
  887.  
  888.  
  889. SetAttribute::SetAttribute (DialogueBox *d, bool *values, int num_values, int iconnum ...)
  890.    : Attribute (d)
  891.    {
  892.    va_list arg ;
  893.    this->values = values ;
  894.    this->num_values = num_values ;
  895.    va_start (arg, iconnum) ;
  896.    icons = new Icon* [num_values] ;
  897.    for (int i = 0 ; i < num_values ; i++)
  898.       icons[i] = new Icon (d, va_arg (arg, int)) ;
  899.    va_end (arg) ;
  900.    }
  901.  
  902. SetAttribute::SetAttribute (DialogueBox *d, bool *values, int num_values, Icon *icon ...)
  903.    : Attribute (d)
  904.    {
  905.    va_list arg ;
  906.    this->values = values ;
  907.    this->num_values = num_values ;
  908.    va_start (arg, icon) ;
  909.    icons = new Icon* [num_values] ;
  910.    for (int i = 0 ; i < num_values ; i++)
  911.       icons[i] = va_arg (arg, Icon *) ;
  912.    va_end (arg) ;
  913.    }
  914.  
  915. SetAttribute::SetAttribute (DialogueBox *d, bool *values, int num_values, va_list arg)
  916.    : Attribute (d)
  917.    {
  918.    this->values = values ;
  919.    this->num_values = num_values ;
  920.    icons = new Icon* [num_values] ;
  921.    for (int i = 0 ; i < num_values ; i++)
  922.       icons[i] = new Icon (d, va_arg (arg, int)) ;
  923.    }
  924.  
  925.  
  926. SetAttribute::~SetAttribute()
  927.    {
  928.    for (int i = 0 ; i < num_values ; i++)
  929.       delete icons[i] ;
  930.    delete icons ;
  931.    }
  932.  
  933. void SetAttribute::get()
  934.    {
  935.    for (int i = 0 ; i < num_values ; i++)
  936.       values[i] = icons[i]->is_selected() ? true : false ;
  937.    }
  938.  
  939. void SetAttribute::set()
  940.    {
  941.    for (int i = 0 ; i < num_values ; i++)
  942.       {
  943.       if (values[i])
  944.          icons[i]->select() ;
  945.       else
  946.          icons[i]->unselect() ;
  947.       }
  948.    }
  949.  
  950.  
  951. SaveBox::SaveBox (Task *t, char *tname, char *path, char *leafname, int type, DataSave *saver)
  952.    : DialogueBox (t, tname, 3, 0)
  953.    {
  954.    if (leafname[0] == 0)
  955.       throw ("Supply leaf name for save box") ;
  956.    this->saver = saver ;
  957.    if (path[0] == 0)
  958.       strcpy (this->path, leafname) ;
  959.    else
  960.       strcpy (this->path, path) ;
  961.    file_icon = new SaverFile (this, type) ;
  962.    name = new StringAttribute (this, this->path, 1) ;
  963.    }
  964.  
  965.  
  966. SaveBox::~SaveBox()
  967.    {
  968.    delete file_icon ;
  969.    delete name ;
  970.    }
  971.  
  972. void SaveBox::drag (int x0, int y0, int x1, int y1, int id)
  973.    {
  974.    char *leafname ;
  975.    name->get() ;                                  // read name typed by user
  976.    if ((leafname = strrchr (path, '.')) != NULL)
  977.       leafname++ ;
  978.    else
  979.       leafname = path ;
  980.    int block[5] ;
  981.    _kernel_swi_regs r ;
  982.    _kernel_oserror *e ;
  983.    r.r[1] = (int)block ;
  984.    if ((e = _kernel_swi (Wimp_GetPointerInfo, &r, &r)) != NULL)
  985.       throw (e) ;
  986.    hide() ;
  987.    saver->save (block[3], block[4], block[0], block[1], leafname) ;
  988.    }
  989.  
  990. void SaveBox::ok(int button)
  991.    {
  992.    name->get() ;                           // read path typed in by user
  993.    if (strchr (path, '.') == NULL)
  994. #ifdef __EASY_C
  995.       throw "To save, drag icon to a window" ;
  996. #else
  997.       werr (0,"To save, drag icon to a window") ;
  998. #endif
  999.    else
  1000.       {
  1001.       waiting->set() ;
  1002.       hide() ;
  1003.       saver->save (path) ;
  1004.       }
  1005.    }
  1006.  
  1007. SaverFile::SaverFile (SaveBox *box, int type)
  1008.    : Icon (box, 2)
  1009.    {
  1010.    sprite = new char [32] ;
  1011.    sprintf (sprite, "file_%x",type) ;
  1012.    change_sprite (sprite) ;
  1013.    save_box = box ;
  1014.    }
  1015.  
  1016. SaverFile::~SaverFile()
  1017.    {
  1018.    delete [] sprite ;
  1019.    }
  1020.  
  1021. void SaverFile::click (int mx, int my, int button, int icon)
  1022.    {
  1023.    _kernel_swi_regs r ;
  1024.    if (button & (4 * 16))       // drag?
  1025.       {
  1026.       save_box->read_position() ;                // may have moved, so reread position
  1027.       r.r[0] = 161 ;
  1028.       r.r[1] = 28 ;
  1029.       _kernel_swi (OS_Byte, &r, &r) ;              // does user want sprite dragged?
  1030.       save_box->task->register_drag (save_box, 0, (r.r[2] & 2)? true : false) ;
  1031.       drag (mx, my, button) ;
  1032.       }
  1033.  
  1034.    }
  1035.  
  1036. //
  1037. // ProgramInfo dialogue box
  1038. //
  1039.  
  1040. ProgramInfo::ProgramInfo (Task *t, int vicon, char *v)
  1041.    : DialogueBox (t, "ProgInfo")
  1042.    {
  1043.    version = new Icon (this, vicon) ;
  1044.    version->print (v) ;
  1045.    }
  1046.  
  1047. ProgramInfo::~ProgramInfo()
  1048.    {
  1049.    delete version ;
  1050.    }
  1051.  
  1052.