home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 2
/
AUCD2.iso
/
program
/
vista.arc
/
c
/
objects
< prev
next >
Wrap
Text File
|
1996-02-01
|
31KB
|
1,188 lines
// **************************************************************************
// Copyright 1996 David Allison
//
// VV VV IIIIII SSSSS TTTTTT AA
// VV VV II SS TT AA AA
// VV VV II SSSS TT AA AA
// VV VV II SS TT AAAAAAAA
// VV IIIIII SSSS TT AA AA
//
// MULTI-THREADED C++ WIMP CLASS LIBRARY
// for RISC OS
// **************************************************************************
//
// P U B L I C D O M A I N L I C E N C E
// -------------------------------------------
//
// This library is copyright. You may not sell the library for
// profit, but you may sell products which use it providing
// those products are presented as executable code and are not
// libraries themselves. The library is supplied without any
// warranty and the copyright owner cannot be held responsible for
// damage resulting from failure of any part of this library.
//
// See the User Manual for details of the licence.
//
// *************************************************************************
//
// window objects
//
#include "Vista:task.h"
#include "Vista:window.h"
#include <stdlib.h>
#include <kernel.h>
#include <swis.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <math.h>
Object::Object (Window *w, char *name, int priority, char *menu)
{
window = w ;
if (menu == NULL)
default_menu = NULL ;
else
{
default_menu = w->task->find_menu (menu) ;
if (default_menu == NULL)
throw ("Unknown menu") ;
}
next = NULL ;
prev = NULL ;
this->priority = priority ;
strncpy (this->name, name, 32) ;
w->add_object (this) ;
}
Object::~Object ()
{
window->remove_object (this) ;
}
void Object::redraw (int x0, int y0, int x1, int y1)
{
}
void Object::update (int x0, int y0, int x1, int y1)
{
}
int Object::compare (int x, int y)
{
x = window->xtowindow(x) ; // x in window coords
y = window->ytowindow(y) ; // y in window coords
return x <= this->x1 && x >= this->x0 && y <= this->y1 && y >= this->y0 ;
}
//
// move to alternative window coords
//
void Object::move (int x0, int y0, int x1, int y1)
{
this->x0 = x0 ;
this->y0 = y0 ;
this->x1 = x1 ;
this->y1 = y1 ;
}
void Object::move (int dx, int dy)
{
this->x0 += dx ;
this->y0 += dy ;
this->x1 += dx ;
this->y1 += dy ;
}
void Object::drag (int mx, int my, int buttons)
{
window->task->register_object_drag (this, 1) ;
window->do_drag (5, x0 + window->x0 - window->scx, y0 + window->y1 - window->scy,
x1 + window->x0 - window->scx, y1 + window->y1 - window->scy) ;
}
void Object::click (int mx, int my, int button)
{
}
void Object::double_click (int mx, int my, int button)
{
}
void Object::end_drag (int x0, int y0, int x1, int y1, int id)
{
int oldx0 = this->x0 ;
int oldy0 = this->y0 ;
int oldx1 = this->x1 ;
int oldy1 = this->y1 ;
move (window->xtowindow (x0), window->ytowindow(y0),
window->xtowindow (x1), window->ytowindow(y1)) ;
window->do_redraw (oldx0, oldy0, oldx1, oldy1) ;
window->do_redraw(this->x0, this->y0, this->x1, this->y1) ;
}
void Object::key (int x, int y, int height, int index, int code)
{
}
void Object::select()
{
selected = 1 ;
}
void Object::unselect()
{
selected = 0 ;
}
void Object::pointer (int entering)
{
}
void Object::mode_change()
{
}
Menu *Object::display_menu (int x, int y, int button, int icon)
{
if (default_menu == NULL)
{
char *menu_name = get_menu(x, y, button, icon) ;
if (menu_name == NULL)
return NULL ;
Menu *m = window->task->find_menu (menu_name) ;
if (m != NULL)
{
m->open (x - 40, y) ;
return m ;
}
return NULL ; // no menu
}
else
{
pre_menu (default_menu, x, y, button, icon) ;
default_menu->open (x - 40, y) ;
return default_menu ;
}
}
//
// give user a chance to change the menu before display
//
void Object::pre_menu (Menu *m, int x, int y, int button, int icon)
{
}
//
// this window doesn't have a default menu, ask the user to provide one
//
char *Object::get_menu (int x, int y, int button, int icon)
{
return NULL ;
}
void Object::menu (MenuItem item[])
{
}
char *Object::help (int mx, int my, int buttons)
{
return NULL ;
}
static void move(int x, int y)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
r.r[0] = 4 ;
r.r[1] = x ;
r.r[2] = y ;
if ((e = _kernel_swi (OS_Plot, &r, &r)) != NULL)
throw (e) ;
}
static void draw_char (char ch)
{
_kernel_swi_regs r ;
_kernel_swi (OS_WriteI+ch, &r, &r) ;
}
static void set_colour (int colour)
{
_kernel_swi_regs r ;
r.r[0] = 18 ;
_kernel_swi (OS_WriteC, &r, &r) ;
r.r[0] = 0 ;
_kernel_swi (OS_WriteC, &r, &r) ;
r.r[0] = colour ;
_kernel_swi (OS_WriteC, &r, &r) ;
}
//
// icon object
//
IconObject::IconObject (Window *w, char *name, Icon *icon, int priority, char *menu)
: Object (w, name, priority, menu)
{
this->icon = icon ;
}
IconObject::~IconObject ()
{
}
void IconObject::redraw (int x0, int y0, int x1, int y1)
{
Box box ;
icon->read_position (box) ;
if (x0 <= box.x1 && x1 >= box.x0 && y0 <= box.y1 && y1 >= box.y0)
icon->plot() ;
}
//
// a sprite object
//
RawSpriteObject::RawSpriteObject (Window *w, char *name, char *sprite, void *area, int x, int y, int priority, char *menu)
: Object (w, name, priority, menu)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
x0 = x ;
y0 = y ;
this->sprite = sprite ;
this->area = area ;
r.r[0] = 40 + 0x100 ; // read sprite info
r.r[1] = (int)area ;
r.r[2] = (int)sprite ;
if ((e = _kernel_swi (OS_SpriteOp, &r, &r)) != NULL)
throw (e) ;
x1 = x0 + r.r[3] ;
y1 = y0 + r.r[4] ;
}
RawSpriteObject::RawSpriteObject (Window *w, char *name, char *sprite, int x, int y, int priority, char *menu)
: Object (w, name, priority, menu)
{
x0 = x ;
y0 = y ;
this->sprite = sprite ;
this->area = 0 ;
init() ;
}
void RawSpriteObject::init()
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
r.r[0] = 40 + (area == NULL ? 0 : 256) ; // read sprite info
r.r[2] = (int)sprite ;
if ((e = _kernel_swi (area == NULL ? Wimp_SpriteOp : OS_SpriteOp, &r, &r)) != NULL)
throw (e) ;
int xsize = r.r[3] ;
int ysize = r.r[4] ;
mode = r.r[6] ;
xsize <<= window->task->xeigfactor ;
ysize <<= window->task->yeigfactor ;
x1 = x0 + xsize ;
y1 = y0 + ysize ;
// set up scale factors
scale_factors[0] = 1 ;
scale_factors[1] = 1 ;
scale_factors[2] = 1 ;
scale_factors[3] = 1 ;
#if 0
if (area == NULL)
{
if ((e = _kernel_swi (Wimp_BaseOfSprites, &r, &r)) != NULL)
throw (e) ;
r.r[0] = r.r[1] ;
}
else
r.r[0] = (int)area ;
#endif
r.r[0] = mode ;
r.r[1] = 3 ; // NColour (see PRM 1-710)
if ((e = _kernel_swi (OS_ReadModeVariable,&r,&r)) != NULL)
throw (e) ;
pixel_trans = new char [256] ;
if (r.r[2] < 63) // < 256 colours
{
unsigned int palette[20] ;
r.r[1] = (int)palette ;
if ((e = _kernel_swi (Wimp_ReadPalette,&r,&r)) != NULL)
throw (e) ;
unsigned int i,p,col ;
for (i = 0 ; i < 15 ; i++)
{
p = palette[i] ;
col = p ;
col |= (p & 0xf0000000) >> 4 ;
col |= (p & 0x00f00000) >> 4 ;
col |= (p & 0x0000f000) >> 4 ;
palette[i] = p & 0xffffff00 ;
}
r.r[0] = mode ;
r.r[1] = 0 ;
r.r[2] = -1 ;
r.r[3] = (int)palette ;
r.r[4] = (int)pixel_trans ;
r.r[5] = 0 ;
if ((e = _kernel_swi (ColourTrans_GenerateTable, &r, &r)) != NULL)
throw (e) ;
}
else
{
r.r[0] = mode ;
r.r[1] = -1 ;
r.r[2] = -1 ;
r.r[3] = -1 ;
// r.r[4] = 0 ; // read buffer size
// if ((e = _kernel_swi (ColourTrans_SelectTable, &r, &r)) != NULL)
// throw (e) ;
// pixel_trans = new char [r.r[4]] ;
r.r[4] = (int) pixel_trans ;
if ((e = _kernel_swi (ColourTrans_SelectTable, &r, &r)) != NULL)
throw (e) ;
}
}
RawSpriteObject::~RawSpriteObject ()
{
}
void RawSpriteObject::redraw (int x0, int y0, int x1, int y1)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
int sx, sy ;
int swi ;
if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
{
sx = window->xtoscreen(this->x0) ; // screen x
sy = window->ytoscreen(this->y0) ; // screen y
// ::move (sx, sy) ;
r.r[0] = 52 + (area == NULL ? 0 : 256) ; // put sprite scaled
r.r[1] = (int)area ;
r.r[2] = (int)sprite ;
r.r[3] = sx ;
r.r[4] = sy ;
r.r[5] = 8 ; // just put on screen
r.r[6] = 0 ; // (int)scale_factors ;
r.r[7] = (int)pixel_trans ;
swi = ((area == NULL) ? Wimp_SpriteOp : OS_SpriteOp) ;
if ((e = _kernel_swi (swi, &r, &r)) != NULL)
throw (e) ;
}
}
//
// a text object
//
#if 0
TextObject::TextObject (Window *w, char *name, char *text, int length, int x, int y, char *menu)
: Object (w, name, priority, menu)
{
lines = NULL ;
num_lines = 0 ;
max_lines = 0 ;
max_length = 0 ;
this->text = (char*)malloc (length) ;
if (this->text == NULL)
throw ("Out of memory") ;
memcpy (this->text, text, length) ;
char *p = this->text ;
char *ch = p ;
int len ;
for (;;)
{
while (length > 0 && *ch != '\n') length--,ch++ ; // skip to newline
len = ch - p ;
insert_line (p, len) ;
p = ++ch ; // skip newline
length-- ; // one byte less
if (length <= 0)
break ;
}
x0 = x ;
y1 = y ;
x1 = x0 + max_length ;
y0 = y1 - num_lines * 32 ;
}
#endif
TextObject::TextObject (Window *w, char *name, char *text, int x, int y, int priority, char *menu)
: Object (w, name, priority, menu)
{
lines = NULL ;
num_lines = 0 ;
max_lines = 0 ;
max_length = 0 ;
int length = strlen (text) ;
this->text = (char*)malloc (length+1) ;
if (this->text == NULL)
throw ("Out of memory") ;
strcpy (this->text, text) ;
char *p = this->text ;
char *ch = p ;
int len ;
for (;;)
{
while (length > 0 && *ch != '\n') length--,ch++ ; // skip to newline
len = ch - p ;
insert_line (p, len) ;
p = ++ch ; // skip newline
length-- ; // one byte less
if (length <= 0)
break ;
}
x0 = x ;
y1 = y ;
x1 = x0 + max_length ;
y0 = y1 - num_lines * 32 ;
}
TextObject::TextObject (Window *w, char *name, int x, int y, int priority, char *menu)
: Object (w, name, priority, menu)
{
lines = NULL ;
text = NULL ;
num_lines = 0 ;
max_lines = 0 ;
max_length = 0 ;
x0 = x ;
y1 = y ;
}
TextObject::~TextObject()
{
if (text == NULL) // not initialised with text
{
for (int i = 0 ; i < num_lines ; i++)
if (lines[i].text != NULL)
free (lines[i].text) ;
}
else
free (text) ;
if (lines != NULL)
free (lines) ;
}
void TextObject::redraw (int x0, int y0, int x1, int y1)
{
#if 1
_kernel_swi_regs r ;
_kernel_oserror *e ;
int sx, sy ; // screen x and y coords
int dx, dy ; // delta x and y
int startx, starty ; // line and char positions in text
int endx, endy, len ;
if (lines == NULL) // no text?
return ;
if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
{
dy = this->y1 - y1 ; // calculate difference in y coords
dx = x0 - this->x0 ; // calc diff in X coords
if (dy < 0) // above text?
starty = 0 ; // start at line 0
else
starty = dy / 32 ; // start at first line in box
if (dx < 0) // left of text?
startx = 0 ; // start at char 0
else
startx = dx / 16 ; // start at first char in box
dy = y1 - y0 ; // get difference in y coords
dx = x1 - x0 ; // and x coords
endy = (dy / 32) + starty + 1; // set end line count
len = (dx / 16) + startx + 1; // set length count
if (endy >= num_lines) // more than number of lines?
endy = num_lines ;
else
endy++ ;
sx = window->xtoscreen(this->x0) ; // screen x
sy = window->ytoscreen(this->y1) ; // screen y
line *l ;
int i, j ;
for (i = starty ; i < endy ; i++) // for each line
{
::move (sx + startx * 16, sy - i * 32) ; // move to screen coord
l = &lines[i] ;
if (len >= l->length)
endx = l->length ;
else
endx = len + 1;
for (j = startx ; j < endx ; j++) // for each char
{
char ch = l->text[j] ;
switch (ch)
{
case TextObject_Colour:
{
int colour = l->text[++j] ;
set_colour (colour) ;
break ;
}
default:
draw_char (ch) ; // draw it
break ;
}
}
}
}
#endif
}
void TextObject::insert_line (char *text, int length)
{
if (num_lines == max_lines)
{
if (lines == NULL)
lines = (line*)malloc (sizeof (line) * 10) ;
else
lines = (line*)realloc (lines, sizeof (line) * (max_lines + 10)) ;
if (lines == NULL)
throw ("Out of memory") ;
max_lines += 10 ;
}
int i = num_lines++ ;
lines[i].text = text ;
lines[i].length = length ;
int len = length * 16 ;
if (len > max_length)
max_length = len ;
}
void TextObject::insert_line (char *text)
{
if (num_lines == max_lines)
{
if (lines == NULL)
lines = (line*)malloc (sizeof (line) * 10) ;
else
lines = (line*)realloc (lines, sizeof (line) * (max_lines + 10)) ;
if (lines == NULL)
throw ("Out of memory") ;
max_lines += 10 ;
}
int i = num_lines++ ;
char *p ;
int len = strlen (text) ;
p = malloc (len+1) ;
if (p == NULL)
throw ("Out of memory") ;
strcpy (p, text) ;
lines[i].text = p ;
lines[i].length = len ;
len *= 16 ;
if (len > max_length)
max_length = len ;
x1 = x0 + max_length ;
y0 = y1 - num_lines * 32 ;
}
//
// a line
//
LineObject::LineObject (Window *w, char *name, int x1, int y1, int x2, int y2, int priority, int thickness)
: Object (w, name, priority, NULL)
{
this->x0 = x1 ;
this->y0 = y1 ;
this->x1 = x2 ;
this->y1 = y2 ;
this->thickness = thickness ;
if (thickness > 1)
{
double theta ; // angle from x axis
double delta ; // angle to perpendicular
const double ninety = 3.14159265 / 2 ;
if (x1 == x2)
theta = ninety ; // prevent division by zero
else
theta = atan ((y2 - y1)/(x2 - x1)) ;
delta = ninety - theta ;
dx = thickness * cos (delta) ; // delta x
dy = thickness * sin (delta) ; // delta y
}
}
LineObject::~LineObject ()
{
}
void LineObject::redraw (int x0, int y0, int x1, int y1)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
int sx, sy ; // start screen x and y coords
int ex, ey ; // end screen coords
if (x0 <= this->x1 + dx && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0 - dy)
{
sx = window->xtoscreen(this->x0) ; // screen x
sy = window->ytoscreen(this->y0) ; // screen y
ex = window->xtoscreen(this->x1) ; // screen x
ey = window->ytoscreen(this->y1) ; // screen y
if (thickness <= 1)
{
::move (sx, sy) ; // move to screen coord
r.r[0] = 5 ;
r.r[1] = ex ;
r.r[2] = ey ;
_kernel_swi (OS_Plot, &r, &r) ;
}
else
{
::move (sx, sy) ;
::move (sx + dx, sy - dy) ;
r.r[0] = 0x55 ;
r.r[1] = ex ;
r.r[2] = ey ;
_kernel_swi (OS_Plot, &r, &r) ;
r.r[0] = 0x55 ;
r.r[1] = ex + dx ;
r.r[2] = ey - dy ;
_kernel_swi (OS_Plot, &r, &r) ;
}
}
}
//
// a font object
//
FontObject::FontObject (Window *w, char *name, int fhandle, int x0, int y1, int width, int priority, char *menu)
: Object (w,name,priority, menu)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
text = NULL ;
text_length = 0 ;
max_length = 0 ;
this->x0 = x0 ;
this->y1 = y1 ;
this->x1 = x0 + width ;
lines = NULL ;
last_line = NULL ;
font_handle = fhandle ;
indent = 0 ;
}
FontObject::~FontObject ()
{
line *l, *nextl ;
for (l = lines ; l != NULL ; l = nextl)
{
nextl = l->next ;
delete l ;
}
free (text) ;
}
//
// finish off the font object by working out the set of lines
//
void FontObject::finish()
{
char *ch = text ; // current char
struct
{
int axs, ays ;
int axl, ayl ;
int split_char ; // split character
int x0, y0 ; // x,y of bottom left
int x1,y1 ; // x,y of top right
} coord_block ;
_kernel_swi_regs r ;
_kernel_oserror *e ;
int cy = FONT_BORDER ;
int xmax, ymax ;
r.r[1] = x1 - x0 ;
r.r[2] = 1000 ;
if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
throw (e) ;
xmax = r.r[1] - FONT_BORDER ;
ymax = 0 ;
int fhandle = font_handle ;
int indent = this->indent ;
int w ;
while (*ch != 0)
{
coord_block.axs = coord_block.ays = 0 ;
coord_block.axl = coord_block.ayl = 0 ;
coord_block.split_char = ' ' ;
r.r[0] = fhandle ;
r.r[1] = (int)ch ;
r.r[2] = 0x40120 ; // return bounding box, use R5, R0
r.r[3] = xmax - indent;
r.r[4] = ymax ;
r.r[5] = (int)&coord_block ;
r.r[7] = 0 ;
if ((e = _kernel_swi (Font_ScanString, &r, &r)) != NULL)
throw (e) ;
line *l = new line ;
l->next = NULL ;
l->start = ch ;
l->length = r.r[1] - (int)ch ;
l->height = coord_block.y1 /*- coord_block.y0 */ ;
l->y = cy + l->height ; // positive
cy = l->y + FONT_LINE_GAP ;
if (lines == NULL)
lines = last_line = l ;
else
{
last_line->next = l ;
last_line = l ;
}
ch = (char*)r.r[1] ;
r.r[1] = r.r[3] + indent ;
l->width = r.r[1] ; // assign line width
r.r[2] = 0 ;
if ((e = _kernel_swi (Font_ConverttoOS, &r, &r)) != NULL)
throw (e) ;
end_width = r.r[1] ; // width in OS units
if (*ch == ' ')
ch++ ;
if ((e = _kernel_swi (Font_FutureFont, &r, &r)) != NULL)
throw (e) ;
fhandle = r.r[0] ;
indent = 0 ; // no more indent
}
r.r[1] = 0 ;
r.r[2] = cy + FONT_BORDER ;
if ((e = _kernel_swi (Font_ConverttoOS, &r, &r)) != NULL)
throw (e) ;
y0 = y1 - r.r[2] ;
if (lines == last_line) // only one line?
x1 = x0 + end_width ; // set width to width of only line
}
void FontObject::set_indent (int units)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
end_width = units ; // in case of 0 size object
r.r[1] = units ;
r.r[2] = 0 ;
if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
throw (e) ;
indent = r.r[1] ; // in millipoints
}
void FontObject::redraw (int x0, int y0, int x1, int y1)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
line *l ;
int sx ; // start screen x coord
int ey ; // end screen y coord
int px, py ;
int fhandle = font_handle ;
int indent = this->indent ;
if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
{
sx = window->xtoscreen(this->x0) ; // screen x
ey = window->ytoscreen(this->y1) ; // screen y
r.r[1] = sx ;
r.r[2] = ey ;
if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
throw (e) ;
px = r.r[1] ; // x in millipoints
py = r.r[2] ; // y in millipoints
for (l = lines ; l != NULL ; l = l->next)
{
r.r[0] = fhandle ;
r.r[1] = (int)l->start ;
r.r[2] = 0x180 ; // use R7, R0
r.r[3] = px + indent ;
r.r[4] = py - l->y ;
r.r[7] = l->length ;
if ((e = _kernel_swi (Font_Paint, &r, &r)) != NULL)
throw (e) ;
if ((e = _kernel_swi (Font_FutureFont, &r, &r)) != NULL)
throw (e) ;
fhandle = r.r[0] ;
indent = 0 ; // no more indent
}
}
}
void FontObject::check_buffer(int length)
{
while (text_length + length > max_length)
{
if (text == NULL)
{
text = (char*)malloc (FONT_BLOCKING_FACTOR) ;
max_length = FONT_BLOCKING_FACTOR ;
}
else
{
text = (char*)realloc (text, max_length * 2) ;
max_length *= 2 ;
}
if (text == NULL)
throw ("Out of memory") ;
}
}
void FontObject::add_text (char *t)
{
int length = strlen (t) + 1 ; // allow for 0
check_buffer (length) ;
memcpy (&text[text_length], t, length) ;
text_length += length - 1 ; // remove 0
}
void FontObject::set_colour (int r, int g, int b, int R, int G, int B, int max)
{
check_buffer (8) ;
char *ch = &text[text_length] ;
*ch++ = 19 ;
*ch++ = r ;
*ch++ = g ;
*ch++ = b ;
*ch++ = R ;
*ch++ = G ;
*ch++ = B ;
*ch = max ;
text_length += 8 ;
}
void FontObject::begin_underline()
{
check_buffer (3) ;
char *ch = &text[text_length] ;
*ch++ = 25 ;
*ch++ = 210 ;
*ch = 20 ;
text_length += 3 ;
}
void FontObject::end_underline()
{
check_buffer (3) ;
char *ch = &text[text_length] ;
*ch++ = 25 ;
*ch++ = 210 ;
*ch = 0 ;
text_length += 3 ;
}
void FontObject::set_font (int handle)
{
check_buffer(2) ;
char *ch = &text[text_length] ;
*ch++ = 26 ;
*ch = handle ;
text_length += 2 ;
}
int FontObject::width()
{
return end_width ;
}
int FontObject::compare (int x, int y)
{
// quick check first
int x1 = x + (window->scx - window->x0) ; // x in window coords
int y1 = y + (window->scy - window->y1) ; // y in window coords
if (x1 > this->x1 || x1 < this->x0 || y1 > this->y1 || y1 < this->y0)
return 0 ;
// now try for more accuracy
_kernel_swi_regs r ;
_kernel_oserror *e ;
line *l ;
int sx ; // start screen x coord
int ey ; // end screen y coord
int px, py ;
int indent = this->indent ;
// first convert position into millipoints
r.r[1] = x ;
r.r[2] = y ;
if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
throw (e) ;
x = r.r[1] ;
y = r.r[2] ;
// get the screen position of object in os units
sx = window->x0 + this->x0 - window->scx ; // screen x
ey = window->y1 + this->y1 - window->scy ; // screen y
r.r[1] = sx ;
r.r[2] = ey ;
if ((e = _kernel_swi (Font_Converttopoints, &r, &r)) != NULL)
throw (e) ;
px = r.r[1] ; // sx in millipoints
py = r.r[2] ; // ey in millipoints
// now go thru the lines looking for a match
for (l = lines ; l != NULL ; l = l->next)
{
if (y > py) // gone past possible line?
return 0 ;
if (y >= (py - l->y) &&
x <= (px + indent + l->width) &&
x >= (px + indent))
return 1 ;
indent = 0 ;
}
return 0 ;
}
//
// Draw object (uses DrawFile module)
//
DrawObject::DrawObject (Window *w, char *name, char *data, int length, int x, int y, int priority, char *menu)
: Object (w, name, priority, menu)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
this->data = data ;
data_length = length ;
dealloc_data = false ;
max_length = length ;
init (x,y) ;
}
DrawObject::DrawObject (Window *w, char *name, char *filename, int x, int y, int priority, char *menu)
: Object (w, name, priority, menu)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
r.r[0] = 17 ;
r.r[1] = (int)filename ;
if ((e = _kernel_swi (OS_File, &r, &r)) != NULL) // read file length
throw (e) ;
data_length = r.r[4] ;
data = malloc (data_length) ;
if (data == NULL)
throw ("Out of memory") ;
r.r[0] = 12 ;
r.r[1] = (int)filename ;
r.r[2] = (int)data ;
r.r[3] = 0 ;
if ((e = _kernel_swi (OS_File, &r, &r)) != NULL) // load the file
throw (e) ;
dealloc_data = true ;
max_length = data_length ;
init(x,y) ;
}
DrawObject::DrawObject(Window *w, char *name, int priority, char *menu)
: Object (w, name, priority, menu)
{
data = NULL ;
max_length = data_length = 0 ;
dealloc_data = true ;
}
//
// Note that the x and y passed to this are the window coords for the top left of
// the diagram. This conflicts with the drawfile SWIs as they use the
// bottom left as the origin. It is necessary to translate the diagram
// down by its height to get it to the correct position
//
void DrawObject::init(int x, int y) // x and y are in window coords
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
matrix[0] = 1<<16 ;
matrix[1] = 0 ;
matrix[2] = 0 ;
matrix[3] = 1 << 16 ;
matrix[4] = 256*(window->x0 + x - window->scx) ; // convert to screen coords
matrix[5] = 256*(window->y1 + y - window->scy) ;
r.r[0] = 0 ;
r.r[1] = (int)data ;
r.r[2] = data_length ;
r.r[3] = (int)matrix ;
int buffer[4] ;
r.r[4] = (int)buffer ;
if ((e = _kernel_swi (DrawFile_BBox, &r, &r)) != NULL)
throw (e) ;
xoffset = buffer[0] - 256*(window->x0 + x - window->scx) ;
yoffset = buffer[1] - 256*(window->y1 + y - window->scy) ;
int height = (buffer[3] - buffer[1]) / 256 ; // height in OS units
int width = (buffer[2] - buffer[0]) / 256 ; // width in OS units
x0 = x ;
y1 = y ;
x1 = x + width ;
y0 = y - height ;
}
DrawObject::~DrawObject()
{
if (dealloc_data)
free(data) ;
}
void DrawObject::redraw (int x0, int y0, int x1, int y1)
{
if (x0 <= this->x1 && x1 >= this->x0 && y0 <= this->y1 && y1 >= this->y0)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
r.r[0] = 0 ;
r.r[1] = (int)data ;
r.r[2] = data_length ;
matrix[4] = 256*window->xtoscreen(this->x0) - xoffset ;
matrix[5] = 256*window->ytoscreen(this->y0) - yoffset ;
r.r[3] = (int)matrix ;
int clip[4] ;
clip[0] = window->xtoscreen(x0) ;
clip[1] = window->ytoscreen(y0) ;
clip[2] = window->xtoscreen(x1) ;
clip[3] = window->ytoscreen(y1) ;
r.r[4] = (int)clip ;
if ((e = _kernel_swi (DrawFile_Render, &r, &r)) != NULL)
throw (e) ;
}
}
void DrawObject::make_header (int width, int height)
{
check_space (40) ;
int *p = (int*)&data[data_length] ;
strncpy ((char*)p, "Draw", 4) ;
p++ ;
*p++ = 201 ;
*p++ = 0 ;
strncpy ((char*)p, "Vista ",12) ;
p += 3 ;
*p++ = 0 ;
*p++ = 0 ;
*p++ = width ;
*p++ = height ;
data_length = 40 ;
}
void DrawObject::insert_word (int word)
{
check_space (sizeof(int)) ;
int *p = (int*)&data[data_length] ;
*p = word ;
data_length += sizeof(int) ;
}
void DrawObject::insert_string (char *str)
{
int length = strlen (str) ;
check_space (length + 1) ;
memcpy (&data[data_length], str, length + 1) ;
data_length += length + 1 ;
}
void DrawObject::insert_data (void *s, int length)
{
check_space (length) ;
memcpy (&data[data_length], s, length) ;
data_length += length ;
}
void DrawObject::insert_byte (char c)
{
check_space (1) ;
char *p = &data[data_length] ;
*p = c ;
data_length++ ;
}
void DrawObject::align()
{
check_space (sizeof (int)) ;
data_length = (data_length + 3) & ~3 ;
}
void DrawObject::check_space (int length)
{
if (data_length + length > max_length)
{
if (length < DRAW_BLOCKING_FACTOR)
length = DRAW_BLOCKING_FACTOR ;
else
length += DRAW_BLOCKING_FACTOR ;
if (data == NULL)
data = (char*)malloc (length) ;
else
data = (char*)realloc (data, max_length + length) ;
if (data == NULL)
throw ("Out of memory") ;
max_length += length ;
}
}
SpriteObject::SpriteObject (Window *w, char *name, char *sprite, int x, int y, int priority, char *menu)
: DrawObject (w, name, priority, menu)
{
_kernel_swi_regs r ;
_kernel_oserror *e ;
void *addr = w->task->find_sprite (sprite) ;
if (addr == NULL)
throw ("No such sprite") ;
int length = *((int*)addr) ;
length = (length + 3) & ~3 ; // align the length
r.r[0] = 40 ; // read sprite info
r.r[2] = (int)sprite ;
if ((e = _kernel_swi (Wimp_SpriteOp, &r, &r)) != NULL)
throw (e) ;
int width = (r.r[3] << w->task->xeigfactor) * 256 ;
int height = (r.r[4] << w->task->yeigfactor) * 256 ;
make_header (width, height) ;
insert_word (5) ; // sprite object
insert_word (24 + length) ; // object length
insert_word (0) ;
insert_word (0) ;
insert_word (width) ;
insert_word (height) ;
insert_data (addr, length) ;
init (x,y) ;
}
SpriteObject::~SpriteObject()
{
}