home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 2 / AUCD2.iso / program / vista.arc / c / objects < prev    next >
Text File  |  1996-02-01  |  31KB  |  1,188 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. //
  29. // window objects
  30. //
  31.  
  32. #include "Vista:task.h"
  33. #include "Vista:window.h"
  34. #include <stdlib.h>
  35. #include <kernel.h>
  36. #include <swis.h>
  37. #include <string.h>
  38. #include <stdarg.h>
  39. #include <stdio.h>
  40. #include <math.h>
  41.  
  42. Object::Object (Window *w, char *name, int priority, char *menu)
  43.    {
  44.    window = w ;
  45.    if (menu == NULL)
  46.       default_menu = NULL ;
  47.    else
  48.       {
  49.       default_menu = w->task->find_menu (menu) ;
  50.       if (default_menu == NULL)
  51.          throw ("Unknown menu") ;
  52.       }
  53.    next = NULL ;
  54.    prev = NULL ;
  55.    this->priority = priority ;
  56.    strncpy (this->name, name, 32) ;
  57.    w->add_object (this) ;
  58.    }
  59.  
  60. Object::~Object ()
  61.    {
  62.    window->remove_object (this) ;
  63.    }
  64.  
  65. void Object::redraw (int x0, int y0, int x1, int y1)
  66.    {
  67.    }
  68.  
  69. void Object::update (int x0, int y0, int x1, int y1)
  70.    {
  71.    }
  72.  
  73. int Object::compare (int x, int y)
  74.    {
  75.    x = window->xtowindow(x) ; // x in window coords
  76.    y = window->ytowindow(y) ; // y in window coords
  77.    return x <= this->x1 && x >= this->x0 && y <= this->y1 && y >= this->y0 ;
  78.    }
  79.  
  80. //
  81. // move to alternative window coords
  82. //
  83.  
  84. void Object::move (int x0, int y0, int x1, int y1)
  85.    {
  86.    this->x0 = x0 ;
  87.    this->y0 = y0 ;
  88.    this->x1 = x1 ;
  89.    this->y1 = y1 ;
  90.    }
  91.  
  92. void Object::move (int dx, int dy)
  93.    {
  94.    this->x0 += dx ;
  95.    this->y0 += dy ;
  96.    this->x1 += dx ;
  97.    this->y1 += dy ;
  98.    }
  99.  
  100. void Object::drag (int mx, int my, int buttons)
  101.    {
  102.    window->task->register_object_drag (this, 1) ;
  103.    window->do_drag (5, x0 + window->x0 - window->scx, y0 + window->y1 - window->scy,
  104.                        x1 + window->x0 - window->scx, y1 + window->y1 - window->scy) ;
  105.    }
  106.  
  107. void Object::click (int mx, int my, int button)
  108.    {
  109.    }
  110.  
  111. void Object::double_click (int mx, int my, int button)
  112.    {
  113.    }
  114.  
  115. void Object::end_drag (int x0, int y0, int x1, int y1, int id)
  116.    {
  117.    int oldx0 = this->x0 ;
  118.    int oldy0 = this->y0 ;
  119.    int oldx1 = this->x1 ;
  120.    int oldy1 = this->y1 ;
  121.    move (window->xtowindow (x0), window->ytowindow(y0),
  122.          window->xtowindow (x1), window->ytowindow(y1)) ;
  123.    window->do_redraw (oldx0, oldy0, oldx1, oldy1) ;
  124.    window->do_redraw(this->x0, this->y0, this->x1, this->y1) ;
  125.    }
  126.  
  127. void Object::key (int x, int y, int height, int index, int code)
  128.    {
  129.    }
  130.  
  131. void Object::select()
  132.    {
  133.    selected = 1 ;
  134.    }
  135.  
  136. void Object::unselect()
  137.    {
  138.    selected = 0 ;
  139.    }
  140.  
  141. void Object::pointer (int entering)
  142.    {
  143.    }
  144.  
  145. void Object::mode_change()
  146.    {
  147.    }
  148.  
  149. Menu *Object::display_menu (int x, int y, int button, int icon)
  150.    {
  151.    if (default_menu == NULL)
  152.       {
  153.       char *menu_name = get_menu(x, y, button, icon) ;
  154.       if (menu_name == NULL)
  155.          return NULL ;
  156.       Menu *m = window->task->find_menu (menu_name) ;
  157.       if (m != NULL)
  158.          {
  159.          m->open (x - 40, y) ;
  160.          return m ;
  161.          }
  162.       return NULL ;       // no menu
  163.       }
  164.    else
  165.       {
  166.       pre_menu (default_menu, x,  y,  button,  icon) ;
  167.       default_menu->open (x - 40, y) ;
  168.       return default_menu ;
  169.       }
  170.    }
  171.  
  172. //
  173. // give user a chance to change the menu before display
  174. //
  175.  
  176. void Object::pre_menu (Menu *m, int x, int y, int button, int icon)
  177.    {
  178.    }
  179.  
  180. //
  181. // this window doesn't have a default menu, ask the user to provide one
  182. //
  183.  
  184.  
  185. char *Object::get_menu (int x, int y, int button, int icon)
  186.    {
  187.    return NULL ;
  188.    }
  189.  
  190.  
  191. void Object::menu (MenuItem item[])
  192.    {
  193.    }
  194.  
  195.  
  196. char *Object::help (int mx, int my, int buttons)
  197.    {
  198.    return NULL ;
  199.    }
  200.  
  201. static void move(int x, int y)
  202.    {
  203.    _kernel_swi_regs r ;
  204.    _kernel_oserror *e ;
  205.    r.r[0] = 4 ;
  206.    r.r[1] = x ;
  207.    r.r[2] = y ;
  208.    if ((e = _kernel_swi (OS_Plot, &r, &r)) != NULL)
  209.       throw (e) ;
  210.    }
  211.  
  212. static void draw_char (char ch)
  213.    {
  214.    _kernel_swi_regs r ;
  215.    _kernel_swi (OS_WriteI+ch, &r, &r) ;
  216.    }
  217.  
  218. static void set_colour (int colour)
  219.    {
  220.    _kernel_swi_regs r ;
  221.    r.r[0] = 18 ;
  222.    _kernel_swi (OS_WriteC, &r, &r) ;
  223.    r.r[0] = 0 ;
  224.    _kernel_swi (OS_WriteC, &r, &r) ;
  225.    r.r[0] = colour ;
  226.    _kernel_swi (OS_WriteC, &r, &r) ;
  227.    }
  228.  
  229.  
  230. //
  231. // icon object
  232. //
  233.  
  234. IconObject::IconObject (Window *w, char *name, Icon *icon, int priority, char *menu)
  235.    : Object (w, name, priority, menu)
  236.    {
  237.    this->icon = icon ;
  238.    }
  239.  
  240. IconObject::~IconObject ()
  241.    {
  242.    }
  243.  
  244. void IconObject::redraw (int x0, int y0, int x1, int y1)
  245.    {
  246.    Box box ;
  247.    icon->read_position (box) ;
  248.    if (x0 <= box.x1 && x1 >= box.x0 && y0 <= box.y1 && y1 >= box.y0)
  249.       icon->plot() ;
  250.    }
  251.  
  252.  
  253. //
  254. // a sprite object
  255. //
  256.  
  257. RawSpriteObject::RawSpriteObject (Window *w, char *name, char *sprite, void *area, int x, int y, int priority, char *menu)
  258.    : Object (w, name, priority, menu)
  259.    {
  260.    _kernel_swi_regs r ;
  261.    _kernel_oserror *e ;
  262.    x0 = x ;
  263.    y0 = y ;
  264.    this->sprite = sprite ;
  265.    this->area = area ;
  266.    r.r[0] = 40 + 0x100 ;           // read sprite info
  267.    r.r[1] = (int)area ;
  268.    r.r[2] = (int)sprite ;
  269.    if ((e = _kernel_swi (OS_SpriteOp, &r, &r)) != NULL)
  270.       throw (e) ;
  271.    x1 = x0 + r.r[3] ;
  272.    y1 = y0 + r.r[4] ;
  273.    }
  274.  
  275. RawSpriteObject::RawSpriteObject (Window *w, char *name, char *sprite, int x, int y, int priority, char *menu)
  276.    : Object (w, name, priority, menu)
  277.    {
  278.    x0 = x ;
  279.    y0 = y ;
  280.    this->sprite = sprite ;
  281.    this->area = 0 ;
  282.    init() ;
  283.    }
  284.  
  285. void RawSpriteObject::init()
  286.    {
  287.    _kernel_swi_regs r ;
  288.    _kernel_oserror *e ;
  289.    r.r[0] = 40 + (area == NULL ? 0 : 256) ;           // read sprite info
  290.    r.r[2] = (int)sprite ;
  291.    if ((e = _kernel_swi (area == NULL ? Wimp_SpriteOp : OS_SpriteOp, &r, &r)) != NULL)
  292.       throw (e) ;
  293.    int xsize = r.r[3] ;
  294.    int ysize = r.r[4] ;
  295.    mode = r.r[6] ;
  296.    xsize <<= window->task->xeigfactor ;
  297.    ysize <<= window->task->yeigfactor ;
  298.    x1 = x0 + xsize ;
  299.    y1 = y0 + ysize ;
  300.  
  301. // set up scale factors
  302.  
  303.    scale_factors[0] = 1  ;
  304.    scale_factors[1] = 1  ;
  305.    scale_factors[2] = 1 ;
  306.    scale_factors[3] = 1 ;
  307.  
  308. #if 0
  309.    if (area == NULL)
  310.       {
  311.       if ((e = _kernel_swi (Wimp_BaseOfSprites, &r, &r)) != NULL)
  312.          throw (e) ;
  313.       r.r[0] = r.r[1] ;
  314.       }
  315.    else
  316.       r.r[0] = (int)area ;
  317. #endif
  318.    r.r[0] = mode ;
  319.    r.r[1] = 3 ;        // NColour  (see PRM 1-710)
  320.    if ((e = _kernel_swi (OS_ReadModeVariable,&r,&r)) != NULL)
  321.       throw (e) ;
  322.    pixel_trans = new char [256] ;
  323.    if (r.r[2] < 63)           // < 256 colours
  324.       {
  325.       unsigned int palette[20] ;
  326.       r.r[1] = (int)palette ;
  327.       if ((e = _kernel_swi (Wimp_ReadPalette,&r,&r)) != NULL)
  328.          throw (e) ;
  329.       unsigned int i,p,col ;
  330.       for (i = 0 ; i < 15 ; i++)
  331.          {
  332.          p = palette[i] ;
  333.          col = p ;
  334.          col |= (p & 0xf0000000) >> 4 ;
  335.          col |= (p & 0x00f00000) >> 4 ;
  336.          col |= (p & 0x0000f000) >> 4 ;
  337.          palette[i] = p & 0xffffff00 ;
  338.          }
  339.       r.r[0] = mode ;
  340.       r.r[1] = 0 ;
  341.       r.r[2] = -1 ;
  342.       r.r[3] = (int)palette ;
  343.       r.r[4] = (int)pixel_trans ;
  344.       r.r[5] = 0 ;
  345.       if ((e = _kernel_swi (ColourTrans_GenerateTable, &r, &r)) != NULL)
  346.          throw (e) ;
  347.       }
  348.    else
  349.       {
  350.       r.r[0] = mode ;
  351.       r.r[1] = -1 ;
  352.       r.r[2] = -1 ;
  353.       r.r[3] = -1 ;
  354. //   r.r[4] = 0 ;       // read buffer size
  355. //   if ((e = _kernel_swi (ColourTrans_SelectTable, &r, &r)) != NULL)
  356. //      throw (e) ;
  357. //   pixel_trans = new char [r.r[4]] ;
  358.       r.r[4] = (int) pixel_trans ;
  359.       if ((e = _kernel_swi (ColourTrans_SelectTable, &r, &r)) != NULL)
  360.          throw (e) ;
  361.       }
  362.    }
  363.  
  364.  
  365. RawSpriteObject::~RawSpriteObject ()
  366.    {
  367.    }
  368.  
  369. void RawSpriteObject::redraw (int x0, int y0, int x1, int y1)
  370.    {
  371.    _kernel_swi_regs r ;
  372.    _kernel_oserror *e ;
  373.    int sx, sy ;
  374.    int swi ;
  375.    if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
  376.       {
  377.       sx = window->xtoscreen(this->x0) ;        // screen x
  378.       sy = window->ytoscreen(this->y0) ;        // screen y
  379. //      ::move (sx, sy) ;
  380.       r.r[0] = 52 + (area == NULL ? 0 : 256) ;          // put sprite scaled
  381.       r.r[1] = (int)area ;
  382.       r.r[2] = (int)sprite ;
  383.       r.r[3] = sx ;
  384.       r.r[4] = sy ;
  385.       r.r[5] = 8 ;        // just put on screen
  386.       r.r[6] = 0 ; // (int)scale_factors ;
  387.       r.r[7] = (int)pixel_trans ;
  388.       swi = ((area == NULL) ? Wimp_SpriteOp : OS_SpriteOp) ;
  389.       if ((e = _kernel_swi (swi, &r, &r)) != NULL)
  390.          throw (e) ;
  391.       }
  392.    }
  393.  
  394.  
  395. //
  396. // a text object
  397. //
  398.  
  399. #if 0
  400. TextObject::TextObject (Window *w, char *name, char *text, int length, int x, int y, char *menu)
  401.    : Object (w, name, priority, menu)
  402.    {
  403.    lines = NULL ;
  404.    num_lines = 0 ;
  405.    max_lines = 0 ;
  406.    max_length = 0 ;
  407.    this->text = (char*)malloc (length) ;
  408.    if (this->text == NULL)
  409.       throw ("Out of memory") ;
  410.    memcpy (this->text, text, length) ;
  411.    char *p = this->text ;
  412.    char *ch = p ;
  413.    int len ;
  414.    for (;;)
  415.       {
  416.       while (length > 0 && *ch != '\n') length--,ch++ ;    // skip to newline
  417.       len = ch - p ;
  418.       insert_line (p, len) ;
  419.       p = ++ch ;                  // skip newline
  420.       length-- ;                  // one byte less
  421.       if (length <= 0)
  422.          break ;
  423.       }
  424.    x0 = x ;
  425.    y1 = y ;
  426.    x1 = x0 + max_length ;
  427.    y0 = y1 - num_lines * 32 ;
  428.    }
  429. #endif
  430.  
  431. TextObject::TextObject (Window *w, char *name, char *text, int x, int y, int priority, char *menu)
  432.    : Object (w, name, priority, menu)
  433.    {
  434.    lines = NULL ;
  435.    num_lines = 0 ;
  436.    max_lines = 0 ;
  437.    max_length = 0 ;
  438.    int length = strlen (text) ;
  439.    this->text = (char*)malloc (length+1) ;
  440.    if (this->text == NULL)
  441.       throw ("Out of memory") ;
  442.    strcpy (this->text, text) ;
  443.    char *p = this->text ;
  444.    char *ch = p ;
  445.    int len ;
  446.    for (;;)
  447.       {
  448.       while (length > 0 && *ch != '\n') length--,ch++ ;    // skip to newline
  449.       len = ch - p ;
  450.       insert_line (p, len) ;
  451.       p = ++ch ;                  // skip newline
  452.       length-- ;                  // one byte less
  453.       if (length <= 0)
  454.          break ;
  455.       }
  456.    x0 = x ;
  457.    y1 = y ;
  458.    x1 = x0 + max_length ;
  459.    y0 = y1 - num_lines * 32 ;
  460.    }
  461.  
  462. TextObject::TextObject (Window *w, char *name, int x, int y, int priority, char *menu)
  463.    : Object (w, name, priority, menu)
  464.    {
  465.    lines = NULL ;
  466.    text = NULL ;
  467.    num_lines = 0 ;
  468.    max_lines = 0 ;
  469.    max_length = 0 ;
  470.    x0 = x ;
  471.    y1 = y ;
  472.    }
  473.  
  474.  
  475. TextObject::~TextObject()
  476.    {
  477.    if (text == NULL)                // not initialised with text
  478.       {
  479.       for (int i = 0 ; i < num_lines ; i++)
  480.          if (lines[i].text != NULL)
  481.             free (lines[i].text) ;
  482.       }
  483.    else
  484.       free (text) ;
  485.    if (lines != NULL)
  486.       free (lines) ;
  487.    }
  488.  
  489.  
  490.  
  491. void TextObject::redraw (int x0, int y0, int x1, int y1)
  492.    {
  493. #if 1
  494.    _kernel_swi_regs r ;
  495.    _kernel_oserror *e ;
  496.    int sx, sy ;              // screen x and y coords
  497.    int dx, dy ;              // delta x and y
  498.    int startx, starty ;      // line and char positions in text
  499.    int endx, endy, len ;
  500.    if (lines == NULL)        // no text?
  501.      return ;
  502.    if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
  503.       {
  504.       dy = this->y1 - y1 ;        // calculate difference in y coords
  505.       dx = x0 - this->x0 ;        // calc diff in X coords
  506.       if (dy < 0)                 // above text?
  507.          starty = 0 ;             // start at line 0
  508.       else
  509.          starty = dy / 32 ;       // start at first line in box
  510.       if (dx < 0)                 // left of text?
  511.          startx = 0 ;             // start at char 0
  512.       else
  513.          startx = dx / 16 ;       // start at first char in box
  514.       dy = y1 - y0 ;              // get difference in y coords
  515.       dx = x1 - x0 ;              // and x coords
  516.       endy = (dy / 32) + starty + 1;            // set end line count
  517.       len = (dx / 16) + startx + 1;             // set length count
  518.       if (endy >= num_lines)       // more than number of lines?
  519.          endy = num_lines ;
  520.       else
  521.          endy++ ;
  522.       sx = window->xtoscreen(this->x0) ;        // screen x
  523.       sy = window->ytoscreen(this->y1) ;        // screen y
  524.       line *l ;
  525.       int i, j ;
  526.       for (i = starty ; i < endy ; i++)        // for each line
  527.          {
  528.          ::move (sx + startx * 16, sy - i * 32) ;     // move to screen coord
  529.          l = &lines[i] ;
  530.          if (len >= l->length)
  531.             endx = l->length ;
  532.          else
  533.             endx = len + 1;
  534.          for (j = startx ; j < endx ; j++)     // for each char
  535.             {
  536.             char ch = l->text[j] ;
  537.             switch (ch)
  538.                {
  539.                case TextObject_Colour:
  540.                   {
  541.                   int colour = l->text[++j] ;
  542.                   set_colour (colour) ;
  543.                   break ;
  544.                   }
  545.                default:
  546.                   draw_char (ch) ;                // draw it
  547.                   break ;
  548.                }
  549.             }
  550.          }
  551.       }
  552. #endif
  553.    }
  554.  
  555.  
  556.  
  557. void TextObject::insert_line (char *text, int length)
  558.    {
  559.    if (num_lines == max_lines)
  560.       {
  561.       if (lines == NULL)
  562.          lines = (line*)malloc (sizeof (line) * 10) ;
  563.       else
  564.          lines = (line*)realloc (lines, sizeof (line) * (max_lines + 10)) ;
  565.       if (lines == NULL)
  566.          throw ("Out of memory") ;
  567.       max_lines += 10 ;
  568.       }
  569.    int i = num_lines++ ;
  570.    lines[i].text = text ;
  571.    lines[i].length = length ;
  572.    int len = length * 16 ;
  573.    if (len > max_length)
  574.       max_length = len ;
  575.    }
  576.  
  577.  
  578. void TextObject::insert_line (char *text)
  579.    {
  580.    if (num_lines == max_lines)
  581.       {
  582.       if (lines == NULL)
  583.          lines = (line*)malloc (sizeof (line) * 10) ;
  584.       else
  585.          lines = (line*)realloc (lines, sizeof (line) * (max_lines + 10)) ;
  586.       if (lines == NULL)
  587.          throw ("Out of memory") ;
  588.       max_lines += 10 ;
  589.       }
  590.    int i = num_lines++ ;
  591.    char *p ;
  592.    int len = strlen (text) ;
  593.    p = malloc (len+1) ;
  594.    if (p == NULL)
  595.       throw ("Out of memory") ;
  596.    strcpy (p, text) ;
  597.    lines[i].text = p ;
  598.    lines[i].length = len ;
  599.    len *= 16 ;
  600.    if (len > max_length)
  601.       max_length = len ;
  602.    x1 = x0 + max_length ;
  603.    y0 = y1 - num_lines * 32 ;
  604.    }
  605.  
  606.  
  607.  
  608. //
  609. // a line
  610. //
  611.  
  612. LineObject::LineObject (Window *w, char *name, int x1, int y1, int x2, int y2, int priority, int thickness)
  613.    : Object (w, name, priority, NULL)
  614.    {
  615.    this->x0 = x1 ;
  616.    this->y0 = y1 ;
  617.    this->x1 = x2 ;
  618.    this->y1 = y2 ;
  619.    this->thickness = thickness ;
  620.    if (thickness > 1)
  621.       {
  622.       double theta ;                      // angle from x axis
  623.       double delta ;                      // angle to perpendicular
  624.       const double ninety = 3.14159265 / 2 ;
  625.       if (x1 == x2)
  626.          theta = ninety ;                 // prevent division by zero
  627.       else
  628.          theta = atan ((y2 - y1)/(x2 - x1)) ;
  629.       delta = ninety - theta ;
  630.       dx = thickness * cos (delta) ;            // delta x
  631.       dy = thickness * sin (delta) ;            // delta y
  632.       }
  633.    }
  634.  
  635. LineObject::~LineObject ()
  636.    {
  637.    }
  638.  
  639. void LineObject::redraw (int x0, int y0, int x1, int y1)
  640.    {
  641.    _kernel_swi_regs r ;
  642.    _kernel_oserror *e ;
  643.    int sx, sy ;              // start screen x and y coords
  644.    int ex, ey ;              // end screen coords
  645.    if (x0 <= this->x1 + dx && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0 - dy)
  646.       {
  647.       sx = window->xtoscreen(this->x0) ;        // screen x
  648.       sy = window->ytoscreen(this->y0) ;        // screen y
  649.       ex = window->xtoscreen(this->x1) ;        // screen x
  650.       ey = window->ytoscreen(this->y1) ;        // screen y
  651.  
  652.       if (thickness <= 1)
  653.          {
  654.          ::move (sx, sy) ;     // move to screen coord
  655.          r.r[0] = 5 ;
  656.          r.r[1] = ex ;
  657.          r.r[2] = ey ;
  658.          _kernel_swi (OS_Plot, &r, &r) ;
  659.          }
  660.       else
  661.          {
  662.          ::move (sx, sy) ;
  663.          ::move (sx + dx, sy - dy) ;
  664.          r.r[0] = 0x55 ;
  665.          r.r[1] = ex ;
  666.          r.r[2] = ey ;
  667.          _kernel_swi (OS_Plot, &r, &r) ;
  668.          r.r[0] = 0x55 ;
  669.          r.r[1] = ex + dx ;
  670.          r.r[2] = ey - dy ;
  671.          _kernel_swi (OS_Plot, &r, &r) ;
  672.          }
  673.       }
  674.    }
  675.  
  676.  
  677. //
  678. // a font object
  679. //
  680.  
  681. FontObject::FontObject (Window *w, char *name, int fhandle, int x0, int y1, int width, int priority, char *menu)
  682.    : Object (w,name,priority, menu)
  683.    {
  684.    _kernel_swi_regs r ;
  685.    _kernel_oserror *e ;
  686.    text = NULL ;
  687.    text_length = 0 ;
  688.    max_length = 0 ;
  689.    this->x0 = x0 ;
  690.    this->y1 = y1 ;
  691.    this->x1 = x0 + width ;
  692.    lines = NULL ;
  693.    last_line = NULL ;
  694.    font_handle = fhandle ;
  695.    indent = 0 ;
  696.    }
  697.  
  698. FontObject::~FontObject ()
  699.    {
  700.    line *l, *nextl ;
  701.    for (l = lines ; l != NULL ; l = nextl)
  702.       {
  703.       nextl = l->next ;
  704.       delete l ;
  705.       }
  706.    free (text) ;
  707.    }
  708.  
  709. //
  710. // finish off the font object by working out the set of lines
  711. //
  712.  
  713. void FontObject::finish()
  714.    {
  715.    char *ch = text ;         // current char
  716.    struct
  717.       {
  718.       int axs, ays ;
  719.       int axl, ayl ;
  720.       int split_char ;         // split character
  721.       int x0, y0 ;             // x,y of bottom left
  722.       int x1,y1 ;              // x,y of top right
  723.       } coord_block ;
  724.    _kernel_swi_regs r ;
  725.    _kernel_oserror *e ;
  726.    int cy = FONT_BORDER ;
  727.    int xmax, ymax ;
  728.    r.r[1] = x1 - x0 ;
  729.    r.r[2] = 1000 ;
  730.    if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
  731.       throw (e) ;
  732.    xmax = r.r[1] - FONT_BORDER ;
  733.    ymax = 0  ;
  734.    int fhandle = font_handle ;
  735.    int indent = this->indent ;
  736.    int w ;
  737.  
  738.    while (*ch != 0)
  739.       {
  740.       coord_block.axs = coord_block.ays = 0 ;
  741.       coord_block.axl = coord_block.ayl = 0 ;
  742.       coord_block.split_char = ' ' ;
  743.  
  744.       r.r[0] = fhandle ;
  745.       r.r[1] = (int)ch ;
  746.       r.r[2] = 0x40120 ;       // return bounding box, use R5, R0
  747.       r.r[3] = xmax - indent;
  748.       r.r[4] = ymax ;
  749.       r.r[5] = (int)&coord_block ;
  750.       r.r[7] = 0 ;
  751.       if ((e = _kernel_swi (Font_ScanString, &r, &r)) != NULL)
  752.          throw (e) ;
  753.       line *l = new line ;
  754.       l->next = NULL ;
  755.       l->start = ch ;
  756.       l->length = r.r[1] - (int)ch ;
  757.       l->height = coord_block.y1 /*- coord_block.y0 */ ;
  758.       l->y = cy + l->height ;          // positive
  759.       cy = l->y + FONT_LINE_GAP ;
  760.       if (lines == NULL)
  761.          lines = last_line = l ;
  762.       else
  763.          {
  764.          last_line->next = l ;
  765.          last_line = l ;
  766.          }
  767.       ch = (char*)r.r[1] ;
  768.       r.r[1] = r.r[3] + indent ;
  769.       l->width = r.r[1] ;             // assign line width
  770.       r.r[2] = 0 ;
  771.       if ((e = _kernel_swi (Font_ConverttoOS, &r, &r)) != NULL)
  772.          throw (e) ;
  773.       end_width = r.r[1] ;         // width in OS units
  774.       if (*ch == ' ')
  775.          ch++ ;
  776.       if ((e = _kernel_swi (Font_FutureFont, &r, &r)) != NULL)
  777.          throw (e) ;
  778.       fhandle = r.r[0] ;
  779.       indent = 0 ;           // no more indent
  780.       }
  781.    r.r[1] = 0 ;
  782.    r.r[2] = cy + FONT_BORDER ;
  783.    if ((e = _kernel_swi (Font_ConverttoOS, &r, &r)) != NULL)
  784.       throw (e) ;
  785.    y0 = y1 - r.r[2] ;
  786.    if (lines == last_line)       // only one line?
  787.       x1 = x0 + end_width ;      // set width to width of only line
  788.    }
  789.  
  790. void FontObject::set_indent (int units)
  791.    {
  792.    _kernel_swi_regs r ;
  793.    _kernel_oserror *e ;
  794.    end_width = units ;         // in case of 0 size object
  795.    r.r[1] = units ;
  796.    r.r[2] = 0 ;
  797.    if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
  798.       throw (e) ;
  799.    indent = r.r[1] ;         // in millipoints
  800.    }
  801.  
  802.  
  803. void FontObject::redraw (int x0, int y0, int x1, int y1)
  804.    {
  805.    _kernel_swi_regs r ;
  806.    _kernel_oserror *e ;
  807.    line *l ;
  808.    int sx ;              // start screen x coord
  809.    int ey ;              // end screen y coord
  810.    int px, py ;
  811.    int fhandle = font_handle ;
  812.    int indent = this->indent ;
  813.    if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
  814.       {
  815.       sx = window->xtoscreen(this->x0) ;        // screen x
  816.       ey = window->ytoscreen(this->y1) ;        // screen y
  817.       r.r[1] = sx ;
  818.       r.r[2] = ey ;
  819.       if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
  820.          throw (e) ;
  821.       px = r.r[1] ;         // x in millipoints
  822.       py = r.r[2] ;         // y in millipoints
  823.       for (l = lines ; l != NULL ; l = l->next)
  824.          {
  825.          r.r[0] = fhandle ;
  826.          r.r[1] = (int)l->start ;
  827.          r.r[2] = 0x180 ;               // use R7, R0
  828.          r.r[3] = px + indent ;
  829.          r.r[4] = py - l->y ;
  830.          r.r[7] = l->length ;
  831.          if ((e = _kernel_swi (Font_Paint, &r, &r)) != NULL)
  832.             throw (e) ;
  833.          if ((e = _kernel_swi (Font_FutureFont, &r, &r)) != NULL)
  834.             throw (e) ;
  835.          fhandle = r.r[0] ;
  836.          indent = 0 ;         // no more indent
  837.          }
  838.       }
  839.    }
  840.  
  841.  
  842. void FontObject::check_buffer(int length)
  843.    {
  844.    while (text_length + length > max_length)
  845.       {
  846.       if (text == NULL)
  847.          {
  848.          text = (char*)malloc (FONT_BLOCKING_FACTOR) ;
  849.      max_length = FONT_BLOCKING_FACTOR ;
  850.      }
  851.       else
  852.          {
  853.          text = (char*)realloc (text, max_length * 2) ;
  854.          max_length *= 2 ;
  855.          }
  856.       if (text == NULL)
  857.          throw ("Out of memory") ;
  858.       }
  859.    }
  860.  
  861.  
  862.  
  863. void FontObject::add_text (char *t)
  864.    {
  865.    int length = strlen (t) + 1 ;          // allow for 0
  866.    check_buffer (length) ;
  867.    memcpy (&text[text_length], t, length) ;
  868.    text_length += length - 1 ;            // remove 0
  869.    }
  870.  
  871.  
  872. void FontObject::set_colour (int r, int g, int b, int R, int G, int B, int max)
  873.    {
  874.    check_buffer (8) ;
  875.    char *ch = &text[text_length] ;
  876.    *ch++ = 19 ;
  877.    *ch++ = r ;
  878.    *ch++ = g ;
  879.    *ch++ = b ;
  880.    *ch++ = R ;
  881.    *ch++ = G ;
  882.    *ch++ = B ;
  883.    *ch = max ;
  884.    text_length += 8 ;
  885.    }
  886.  
  887. void FontObject::begin_underline()
  888.    {
  889.    check_buffer (3) ;
  890.    char *ch = &text[text_length] ;
  891.    *ch++ = 25 ;
  892.    *ch++ = 210 ;
  893.    *ch = 20 ;
  894.    text_length += 3 ;
  895.    }
  896.  
  897. void FontObject::end_underline()
  898.    {
  899.    check_buffer (3) ;
  900.    char *ch = &text[text_length] ;
  901.    *ch++ = 25 ;
  902.    *ch++ = 210 ;
  903.    *ch = 0 ;
  904.    text_length += 3 ;
  905.    }
  906.  
  907. void FontObject::set_font (int handle)
  908.    {
  909.    check_buffer(2) ;
  910.    char *ch = &text[text_length] ;
  911.    *ch++ = 26 ;
  912.    *ch = handle ;
  913.    text_length += 2 ;
  914.    }
  915.  
  916. int FontObject::width()
  917.    {
  918.    return end_width ;
  919.    }
  920.  
  921. int FontObject::compare (int x, int y)
  922.    {
  923. // quick check first
  924.    int x1 = x + (window->scx - window->x0) ;   // x in window coords
  925.    int y1 = y + (window->scy - window->y1) ;   // y in window coords
  926.    if (x1 > this->x1 || x1 < this->x0 || y1 > this->y1 || y1 < this->y0)
  927.       return 0 ;
  928. // now try for more accuracy
  929.    _kernel_swi_regs r ;
  930.    _kernel_oserror *e ;
  931.    line *l ;
  932.    int sx ;              // start screen x coord
  933.    int ey ;              // end screen y coord
  934.    int px, py ;
  935.    int indent = this->indent ;
  936. // first convert position into millipoints
  937.    r.r[1] = x ;
  938.    r.r[2] = y ;
  939.    if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
  940.       throw (e) ;
  941.    x = r.r[1] ;
  942.    y = r.r[2] ;
  943. // get the screen position of object in os units
  944.    sx = window->x0 + this->x0 - window->scx ;        // screen x
  945.    ey = window->y1 + this->y1 - window->scy ;        // screen y
  946.    r.r[1] = sx ;
  947.    r.r[2] = ey ;
  948.    if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
  949.       throw (e) ;
  950.    px = r.r[1] ;         // sx in millipoints
  951.    py = r.r[2] ;         // ey in millipoints
  952. // now go thru the lines looking for a match
  953.    for (l = lines ; l != NULL ; l = l->next)
  954.       {
  955.       if (y > py)            // gone past possible line?
  956.          return 0 ;
  957.       if (y >= (py - l->y) &&
  958.                x <= (px + indent + l->width) &&
  959.                   x >= (px + indent))
  960.          return 1 ;
  961.       indent = 0 ;
  962.       }
  963.    return 0 ;
  964.    }
  965.  
  966.  
  967. //
  968. // Draw object (uses DrawFile module)
  969. //
  970.  
  971.  
  972. DrawObject::DrawObject (Window *w, char *name, char *data, int length, int x, int y, int priority, char *menu)
  973.    : Object (w, name, priority, menu)
  974.    {
  975.    _kernel_swi_regs r ;
  976.    _kernel_oserror *e ;
  977.    this->data = data ;
  978.    data_length = length ;
  979.    dealloc_data = false ;
  980.    max_length = length ;
  981.    init (x,y) ;
  982.    }
  983.  
  984. DrawObject::DrawObject (Window *w, char *name, char *filename, int x, int y, int priority, char *menu)
  985.    : Object (w, name, priority, menu)
  986.    {
  987.    _kernel_swi_regs r ;
  988.    _kernel_oserror *e ;
  989.    r.r[0] = 17 ;
  990.    r.r[1] = (int)filename ;
  991.    if ((e = _kernel_swi (OS_File, &r, &r)) != NULL)          // read file length
  992.       throw (e) ;
  993.    data_length = r.r[4] ;
  994.    data = malloc (data_length) ;
  995.    if (data == NULL)
  996.       throw ("Out of memory") ;
  997.    r.r[0] = 12 ;
  998.    r.r[1] = (int)filename ;
  999.    r.r[2] = (int)data ;
  1000.    r.r[3] = 0 ;
  1001.    if ((e = _kernel_swi (OS_File, &r, &r)) != NULL)         // load the file
  1002.       throw (e) ;
  1003.    dealloc_data = true ;
  1004.    max_length = data_length ;
  1005.    init(x,y) ;
  1006.    }
  1007.  
  1008.  
  1009.  
  1010. DrawObject::DrawObject(Window *w, char *name, int priority, char *menu)
  1011.    : Object (w, name, priority, menu)
  1012.    {
  1013.    data = NULL ;
  1014.    max_length = data_length = 0 ;
  1015.    dealloc_data = true ;
  1016.    }
  1017.  
  1018.  
  1019. //
  1020. // Note that the x and y passed to this are the window coords for the top left of
  1021. // the diagram.  This conflicts with the drawfile SWIs as they use the
  1022. // bottom left as the origin.  It is necessary to translate the diagram
  1023. // down by its height to get it to the correct position
  1024. //
  1025.  
  1026. void DrawObject::init(int x, int y)            // x and y are in window coords
  1027.    {
  1028.    _kernel_swi_regs r ;
  1029.    _kernel_oserror *e ;
  1030.    matrix[0] = 1<<16 ;
  1031.    matrix[1] = 0 ;
  1032.    matrix[2] = 0 ;
  1033.    matrix[3] = 1 << 16 ;
  1034.    matrix[4] = 256*(window->x0 + x - window->scx) ;        // convert to screen coords
  1035.    matrix[5] = 256*(window->y1 + y - window->scy) ;
  1036.    r.r[0] = 0 ;
  1037.    r.r[1] = (int)data ;
  1038.    r.r[2] = data_length ;
  1039.    r.r[3] = (int)matrix ;
  1040.    int buffer[4] ;
  1041.    r.r[4] = (int)buffer ;
  1042.    if ((e = _kernel_swi (DrawFile_BBox, &r, &r)) != NULL)
  1043.       throw (e) ;
  1044.    xoffset = buffer[0] - 256*(window->x0 + x - window->scx) ;
  1045.    yoffset = buffer[1] - 256*(window->y1 + y - window->scy) ;
  1046.    int height = (buffer[3] - buffer[1]) / 256 ;                  // height in OS units
  1047.    int width = (buffer[2] - buffer[0]) / 256 ;                   // width in OS units
  1048.    x0 = x ;
  1049.    y1 = y ;
  1050.    x1 = x + width ;
  1051.    y0 = y - height ;
  1052.    }
  1053.  
  1054.  
  1055. DrawObject::~DrawObject()
  1056.    {
  1057.    if (dealloc_data)
  1058.       free(data) ;
  1059.    }
  1060.  
  1061. void DrawObject::redraw (int x0, int y0, int x1, int y1)
  1062.    {
  1063.    if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
  1064.       {
  1065.      _kernel_swi_regs r ;
  1066.       _kernel_oserror *e ;
  1067.       r.r[0] = 0 ;
  1068.       r.r[1] = (int)data ;
  1069.       r.r[2] = data_length ;
  1070.       matrix[4] = 256*window->xtoscreen(this->x0) - xoffset ;
  1071.       matrix[5] = 256*window->ytoscreen(this->y0) - yoffset ;
  1072.       r.r[3] = (int)matrix ;
  1073.       int clip[4] ;
  1074.       clip[0] = window->xtoscreen(x0) ;
  1075.       clip[1] = window->ytoscreen(y0) ;
  1076.       clip[2] = window->xtoscreen(x1) ;
  1077.       clip[3] = window->ytoscreen(y1) ;
  1078.       r.r[4] = (int)clip ;
  1079.       if ((e = _kernel_swi (DrawFile_Render, &r, &r)) != NULL)
  1080.          throw (e) ;
  1081.       }
  1082.    }
  1083.  
  1084.  
  1085. void DrawObject::make_header (int width, int height)
  1086.    {
  1087.    check_space (40) ;
  1088.    int *p = (int*)&data[data_length] ;
  1089.    strncpy ((char*)p, "Draw", 4) ;
  1090.    p++ ;
  1091.    *p++ = 201 ;
  1092.    *p++ = 0 ;
  1093.    strncpy ((char*)p, "Vista       ",12) ;
  1094.    p += 3 ;
  1095.    *p++ = 0 ;
  1096.    *p++ = 0 ;
  1097.    *p++ = width ;
  1098.    *p++ = height ;
  1099.    data_length = 40 ;
  1100.    }
  1101.  
  1102. void DrawObject::insert_word (int word)
  1103.    {
  1104.    check_space (sizeof(int)) ;
  1105.    int *p = (int*)&data[data_length] ;
  1106.    *p = word ;
  1107.    data_length += sizeof(int) ;
  1108.    }
  1109.  
  1110. void DrawObject::insert_string (char *str)
  1111.    {
  1112.    int length = strlen (str) ;
  1113.    check_space (length + 1) ;
  1114.    memcpy (&data[data_length], str, length + 1) ;
  1115.    data_length += length + 1 ;
  1116.    }
  1117.  
  1118. void DrawObject::insert_data (void *s, int length)
  1119.    {
  1120.    check_space (length) ;
  1121.    memcpy (&data[data_length], s, length) ;
  1122.    data_length += length ;
  1123.    }
  1124.  
  1125. void DrawObject::insert_byte (char c)
  1126.    {
  1127.    check_space (1) ;
  1128.    char *p = &data[data_length] ;
  1129.    *p = c ;
  1130.    data_length++ ;
  1131.    }
  1132.  
  1133. void DrawObject::align()
  1134.    {
  1135.    check_space (sizeof (int)) ;
  1136.    data_length = (data_length + 3) & ~3 ;
  1137.    }
  1138.  
  1139. void DrawObject::check_space (int length)
  1140.    {
  1141.    if (data_length + length > max_length)
  1142.       {
  1143.       if (length < DRAW_BLOCKING_FACTOR)
  1144.          length = DRAW_BLOCKING_FACTOR ;
  1145.       else
  1146.          length += DRAW_BLOCKING_FACTOR ;
  1147.       if (data == NULL)
  1148.          data = (char*)malloc (length) ;
  1149.       else
  1150.          data = (char*)realloc (data, max_length + length) ;
  1151.       if (data == NULL)
  1152.          throw ("Out of memory") ;
  1153.       max_length += length ;
  1154.       }
  1155.    }
  1156.  
  1157. SpriteObject::SpriteObject (Window *w, char *name, char *sprite, int x, int y, int priority, char *menu)
  1158.    : DrawObject (w, name, priority, menu)
  1159.    {
  1160.    _kernel_swi_regs r ;
  1161.    _kernel_oserror *e ;
  1162.    void *addr = w->task->find_sprite (sprite) ;
  1163.    if (addr == NULL)
  1164.       throw ("No such sprite") ;
  1165.    int length = *((int*)addr) ;
  1166.    length = (length + 3) & ~3 ;        // align the length
  1167.    r.r[0] = 40 ;           // read sprite info
  1168.    r.r[2] = (int)sprite ;
  1169.    if ((e = _kernel_swi (Wimp_SpriteOp, &r, &r)) != NULL)
  1170.       throw (e) ;
  1171.    int width = (r.r[3] << w->task->xeigfactor) * 256 ;
  1172.    int height = (r.r[4] << w->task->yeigfactor) * 256 ;
  1173.    make_header (width, height) ;
  1174.    insert_word (5) ;             // sprite object
  1175.    insert_word (24 + length) ;  // object length
  1176.    insert_word (0) ;
  1177.    insert_word (0) ;
  1178.    insert_word (width) ;
  1179.    insert_word (height) ;
  1180.    insert_data (addr, length) ;
  1181.    init (x,y) ;
  1182.    }
  1183.  
  1184. SpriteObject::~SpriteObject()
  1185.    {
  1186.    }
  1187.  
  1188.