home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
zip
/
program
/
gempp15b.zoo
/
src
/
gemhf.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-25
|
15KB
|
585 lines
/////////////////////////////////////////////////////////////////////////////
//
// This file is Copyright 1992,1993 by Warwick W. Allison.
// This file is part of the gem++ library.
// You are free to copy and modify these sources, provided you acknowledge
// the origin by retaining this notice, and adhere to the conditions
// described in the file COPYING.LIB.
//
/////////////////////////////////////////////////////////////////////////////
#include <aesbind.h>
#include <values.h>
#include "gemhf.h"
#include "gemrawo.h"
#include "grect.h"
static int FindEdit(GEMrawobject* o, int i)
{
return o[i].Editable() ? i : -1;
}
GEMhotform::GEMhotform(const GEMrsc& in, int RSCindex) :
GEMform(in,RSCindex)
{
curedit=Map(FindEdit);
Zooms(FALSE);
}
int GEMhotform::DoKey(int meta, int key)
{
return Ignore;
}
int GEMhotform::DoOff()
{
return NoObject;
}
int GEMhotform::DoHot(int ob, bool inside)
{
static void objc_toggle(GEMrawobject* tree, int obj);
objc_toggle(Obj,ob);
// Could use this, but G_STRING objects are transparent, so do not
// Redraw well when selected.
//
// Obj[ob].Selected(inside);
// RedrawObject(ob);
return Ignore;
}
// "Hot" version from Profesional GEM, by Tim Oren.
//
// The following code is based on the file "gemcl13.c" in the
// source code provided with the Professional GEM series.
// Available in the /atari/Programming directory of atari.archive.umich.edu.
//
// Changes include:
//
// - Ported to C++ (ie. uses ANSI prototypes).
// - Uses current bindings.
// - Added "machine" macros #defines at start.
// - Clicking off form detected.
#define NIL -1
#define M1_ENTER 0x0000
#define M1_EXIT 0x0001
#define BS 0x0008
#define TAB 0x0009
#define CR 0x000D
#define ESC 0x001B
#define BTAB 0x0f00
#define UP 0x4800
#define DOWN 0x5000
#define DEL 0x5300
/* Global variables used by */
/* 'mapped' functions */
static GRect br_rect; /* Current break rectangle */
static int br_mx, br_my, br_togl; /* Break mouse posn & flag */
static int fn_obj; /* Found tabable object */
static int fn_last; /* Object tabbing from */
static int fn_prev; /* Last EDITABLE obj seen */
static int fn_dir; /* 1 = TAB, 0 = BACKTAB */
/************* Utility routines for new forms manager ***************/
/* Return the object's GRect through 'p' */
static void objc_xywh(GEMrawobject* tree, int obj, GRect *p)
{
objc_offset(tree, obj, &p->g_x, &p->g_y);
p->g_w = tree[obj].Width();
p->g_h = tree[obj].Height();
}
/* Reverse the SELECT state */
static void objc_toggle(GEMrawobject* tree, int obj)
{
int state, newstate;
GRect root;
objc_xywh(tree, ROOT, &root);
state = tree[obj].States();
newstate = state ^ SELECTED;
objc_change(tree, obj, 0, root.g_x, root.g_y,
root.g_w, root.g_h, newstate, 1);
}
/* If the object is not already SELECTED, make it so. */
static void objc_sel(GEMrawobject* tree, int obj)
{
if ( !(tree[obj].States() & SELECTED) )
objc_toggle(tree, obj);
}
/* If the object is SELECTED, deselect it. */
static void objc_dsel(GEMrawobject* tree, int obj)
{
if (tree[obj].States() & SELECTED)
objc_toggle(tree, obj);
}
/* Non-cursive traverse of an object tree. */
static void map_tree(GEMrawobject* tree, int this1, int last, int routine(GEMrawobject*,int))
{
int tmp1;
tmp1 = this1; /* Initialize to impossible value: */
/* TAIL won't point to self! */
/* Look until final node, or off */
/* the end of tree */
while (this1 != last && this1 != NIL)
/* Did we 'pop' into this1 node */
/* for the second time? */
if (tree[this1].Tail() != tmp1)
{
tmp1 = this1; /* This is a new node */
this1 = NIL;
/* Apply operation, testing */
/* for rejection of sub-tree */
if (!tree[tmp1].HideTree())
if (routine(tree, tmp1))
this1 = tree[tmp1].Head();
/* Subtree path not taken, */
/* so traverse right */
if (this1 == NIL)
this1 = tree[tmp1].Next();
}
else /* Revisiting parent: */
/* No operation, move right */
{
tmp1 = this1;
this1 = tree[tmp1].Next();
}
}
/* Find the parent of an object of by traversing right */
static int get_parent(GEMrawobject* tree, int obj)
{
int pobj;
if (obj == NIL)
return (NIL);
pobj = tree[obj].Next();
if (pobj != NIL)
{
while( tree[pobj].Tail() != obj )
{
obj = pobj;
pobj = tree[obj].Next();
}
}
return(pobj);
}
/* determine if x,y is in rectangle */
static int inside(int x, int y, GRect *pt)
{
if ( (x >= pt->g_x) && (y >= pt->g_y) &&
(x < pt->g_x + pt->g_w) && (y < pt->g_y + pt->g_h) )
return(TRUE);
else
return(FALSE);
}
/************* "Hot-spot" manager and subroutines ***************/
static int break_x(int *pxy)
{ /* Breaking object is right of */
if (br_mx < pxy[0]) /* mouse. Reduce width of */
{ /* bounding rectangle. */
br_rect.g_w = pxy[0] - br_rect.g_x;
return (TRUE);
}
if (br_mx > pxy[2]) /* Object to left. Reduce width*/
{ /* and move rect. to right */
br_rect.g_w += br_rect.g_x - pxy[2] - 1;
br_rect.g_x = pxy[2] + 1;
return (TRUE);
}
return (FALSE); /* Mouse within object segment. */
} /* Break attempt fails. */
static int break_y(int *pxy)
{
if (br_my < pxy[1]) /* Object below mouse. Reduce */
{ /* height of bounding rect. */
br_rect.g_h = pxy[1] - br_rect.g_y;
return (TRUE);
}
if (br_my > pxy[3]) /* Object above mouse. Reduce */
{ /* height and shift downward. */
br_rect.g_h += br_rect.g_y - pxy[3] - 1;
br_rect.g_y = pxy[3] + 1;
return (TRUE);
}
/* Emergency escape test! Protection vs. turkeys who nest */
/* non-selectable objects inside of selectables. */
if (br_mx >= pxy[0] && br_mx <= pxy[1])
{ /* Will X break fail? */
br_rect.g_x = br_mx; /* If so, punt! */
br_rect.g_y = br_my;
br_rect.g_w = br_rect.g_h = 1;
return (TRUE);
}
return (FALSE);
}
/* Called once per object to */
static int break_obj(GEMrawobject* tree, int obj)
{
GRect s;
int flags, broken, pxy[4];
objc_xywh(tree, obj, &s);
grect_to_array(&s, pxy);
if (!rc_intersect(&br_rect, &s))
return (FALSE); /* Trivial rejection case */
flags = tree[obj].Flags(); /* Is this1 object a potential */
if (flags & HIDETREE) /* hot-spot? */
return (FALSE);
if ( !(flags & SELECTABLE) )
return (TRUE);
if (tree[obj].States() & DISABLED)
return (TRUE);
for (broken = FALSE; !broken; ) /* This could take two passes */
{ /* if the first break fails. */
if (br_togl)
broken = break_x(pxy);
else
broken = break_y(pxy);
br_togl = !br_togl;
}
return (TRUE);
}
/* Manages mouse rectangle events */
static int form_hot(GEMrawobject* tree, int hot_obj, int mx, int my, GRect *rect, int *mode)
{
GRect root;
int state;
objc_xywh(tree, ROOT, &root); /* If there is already a hot-spot */
if (!(inside(mx, my, &root)) ) /* Mouse has moved outside of */
{ /* the dialog. Wait for return. */
*mode = M1_ENTER;
rc_copy(&root, rect);
return (NIL);
}
/* What object is mouse over? */
/* (Hit is guaranteed.) */
hot_obj = objc_find(tree, ROOT, MAX_DEPTH, mx, my);
/* Is this object a hot-spot? */
state = tree[hot_obj].States();
if (tree[hot_obj].Flags() & SELECTABLE)
if ( !(state & DISABLED) )
{ /* Yes! Set up wait state. */
*mode = M1_EXIT;
objc_xywh(tree, hot_obj, rect);
if (state & SELECTED) /* But only toggle if it's not */
return (NIL); /* already SELECTED! */
else
{
return (hot_obj);
}
}
rc_copy(&root, &br_rect); /* No hot object, so compute */
br_mx = mx; /* mouse bounding rectangle. */
br_my = my;
br_togl = 0;
map_tree(tree, ROOT, NIL, break_obj);
rc_copy(&br_rect, rect); /* Then return to wait state. */
*mode = M1_EXIT;
return (NIL);
}
/************* Keyboard manager and subroutines ***************/
/* Check if the object is DEFAULT */
static int find_def(GEMrawobject* tree, int obj)
{ /* Is sub-tree hidden? */
if (HIDETREE & tree[obj].Flags())
return (FALSE);
/* Must be DEFAULT and not DISABLED */
if (DEFAULT & tree[obj].Flags())
if ( !(DISABLED & tree[obj].States()) )
fn_obj = obj; /* Record object number */
return (TRUE);
}
/* Look for target of TAB operation. */
static int find_tab(GEMrawobject* tree, int obj)
{ /* Check for hiddens subtree. */
if (HIDETREE & tree[obj].Flags())
return (FALSE);
/* If not EDITABLE, who cares? */
if ( !(EDITABLE & tree[obj].Flags()) )
return (TRUE);
/* Check for forward tab match */
if (fn_dir && fn_prev == fn_last)
fn_obj = obj;
/* Check for backward tab match */
if (!fn_dir && obj == fn_last)
fn_obj = fn_prev;
fn_prev = obj; /* Record object for next call. */
return (TRUE);
}
static int form_keyboard(GEMrawobject* tree, int edit_obj, int next_obj, int kr, int *out_obj, int *okr)
{
if (kr&0xff) /* If lower byte valid, mask out */
kr &= 0xff; /* extended code byte. */
fn_dir = 0; /* Default tab direction if backward. */
switch (kr) {
case CR: /* Zap character. */
*okr = 0;
/* Look for a DEFAULT object. */
fn_obj = NIL;
map_tree(tree, ROOT, NIL, find_def);
/* If found, SELECT and force exit. */
if (fn_obj != NIL)
{
objc_sel(tree, fn_obj);
*out_obj = fn_obj;
return (FALSE);
} /* Falls through to */
case TAB: /* tab if no default */
case DOWN:
fn_dir = 1; /* Set fwd direction */
case BTAB:
case UP:
*okr = 0; /* Zap character */
fn_last = edit_obj;
fn_prev = fn_obj = NIL; /* Look for TAB object */
map_tree(tree, ROOT, NIL, find_tab);
if (fn_obj == NIL) /* try to wrap around */
map_tree(tree, ROOT, NIL, find_tab);
if (fn_obj != NIL)
*out_obj = fn_obj;
break;
default: /* Pass other chars */
return (TRUE);
}
return (TRUE);
}
/************* Mouse button manager and subroutines ***************/
static void do_radio(GEMrawobject* tree, int obj)
{
GRect root;
int pobj, sobj;
objc_xywh(tree, ROOT, &root);
pobj = get_parent(tree, obj); /* Get the object's parent */
for (sobj = tree[pobj].Head(); sobj != pobj;
sobj = tree[sobj].Next() )
{ /* Deselect all but... */
if (sobj != obj)
objc_dsel(tree, sobj);
}
objc_sel(tree, obj); /* the one being SELECTED */
}
/* Mouse button handler */
static int form_butn(GEMrawobject* tree, int obj, int clicks, int *next_obj, int *hot_obj)
{
int flags, state, hibit, texit, sble, dsbld, edit;
int in_state;
flags = tree[obj].Flags(); /* Get flags and states */
state = tree[obj].States();
texit = flags & TOUCHEXIT;
sble = flags & SELECTABLE;
dsbld = state & DISABLED;
edit = flags & EDITABLE;
if (!texit && (!sble || dsbld) && !edit) /* This is not an */
{ /* interesting object */
*next_obj = 0;
return (TRUE);
}
if (texit && clicks == 2) /* Preset special flag */
hibit = 0x8000;
else
hibit = 0x0;
if (sble && !dsbld) /* Hot stuff! */
{
if (flags & RBUTTON) /* Process radio buttons*/
do_radio(tree, obj); /* immediately! */
else if (!texit)
{
in_state = (obj == *hot_obj)? /* Already toggled ? */
state: state ^ SELECTED;
if (!graf_watchbox(tree, obj, in_state,
in_state ^ SELECTED))
{ /* He gave up... */
*next_obj = 0;
*hot_obj = NIL;
return (TRUE);
}
}
else /* if (texit) */
if (obj != *hot_obj) /* Force SELECTED */
objc_toggle(tree, obj);
}
if (obj == *hot_obj) /* We're gonna do it! So don't */
*hot_obj = NIL; /* turn it off later. */
if (texit || (flags & EXIT) ) /* Exit conditions. */
{
*next_obj = obj | hibit;
return (FALSE); /* Time to leave! */
}
else if (!edit) /* Clear object unless tabbing */
*next_obj = 0;
return (TRUE);
}
static int to_find;
static int FindToFind(GEMrawobject* o, int i)
{
return i==to_find ? i : -1;
}
/************* New forms manager: main loop *************/
int GEMhotform::FormDo()
{
int edit_obj;
int next_obj, hot_obj, hot_mode;
int which, cont;
int idx;
int mx, my, mb, meta, kr, br;
GRect hot_rect;
wind_update(BEG_MCTRL);
/* Init. editing */
to_find=curedit;
if (Map(FindToFind)!=to_find) // Is it hidden?
curedit=Map(FindEdit);
next_obj = curedit;
edit_obj = 0;
/* Initial hotspot cndx */
hot_obj = NIL; hot_mode = M1_ENTER;
objc_xywh(Obj, ROOT, &hot_rect);
/* Main event loop */
cont = TRUE;
while (cont) {
/* position cursor on */
/* the selected */
/* editting field */
if (edit_obj!=next_obj && next_obj!=0) {
edit_obj = next_obj;
next_obj = 0;
objc_edit(Obj, edit_obj, 0, idx, EDINIT, &idx);
}
/* wait for button or */
/* key or rectangle */
which = evnt_multi(MU_KEYBD | MU_BUTTON | MU_M1,
0x01, // WWA - Only single click - else race can occur between clicks
0x01, 0x01,
hot_mode, hot_rect.g_x, hot_rect.g_y,
hot_rect.g_w, hot_rect.g_h,
0, 0, 0, 0, 0,
0x0L,
0,
&mx, &my, &mb, &meta, &kr, &br);
if (which & MU_M1) { /* handle rect. event */
if (hot_obj != NIL) {
int h=DoHot(hot_obj,FALSE);
if (h!=Ignore) {
next_obj=h;
cont=FALSE;
}
}
if (cont) {
hot_obj = form_hot(Obj, hot_obj, mx, my, &hot_rect, &hot_mode);
if (hot_obj != NIL) {
int h=DoHot(hot_obj,TRUE);
if (h!=Ignore) {
next_obj=h;
cont=FALSE;
}
}
}
}
if (which & MU_KEYBD) { /* handle keyboard event*/
/* Control char filter */
cont = form_keyboard(Obj, edit_obj, next_obj, kr, &next_obj, &kr);
if (kr) {
int k=DoKey(meta,kr);
if (k!=Ignore) {
next_obj=k;
cont=FALSE;
} else {
if (edit_obj>0) {
objc_edit(Obj, edit_obj, kr, idx, EDCHAR, &idx);
}
}
}
}
/* handle button event */
if (which & MU_BUTTON) {
/* Which object hit? */
next_obj = objc_find(Obj, ROOT, MAX_DEPTH, mx, my);
if (next_obj == NIL) {
next_obj = DoOff();
if (next_obj==NoObject) {
cont = FALSE; // We want non-form click to cancel form
}
} else {
/* Process a click */
// UnHot the object, rather than expecting form_butn to deal with it.
if (hot_obj != NIL) {
DoHot(hot_obj,FALSE);
hot_obj=NIL;
}
cont = form_butn(Obj, next_obj, br, &next_obj, &hot_obj);
}
}
/* handle end of field */
/* clean up */
if (!cont || (next_obj != edit_obj && next_obj != 0))
if (edit_obj != 0)
objc_edit(Obj, edit_obj, 0, idx, EDEND, &idx);
}
/* If defaulted, may */
/* need to clear hotspot*/
if (hot_obj != (next_obj & 0x7fff))
if (hot_obj != NIL)
DoHot(hot_obj,FALSE);
/* return exit object */
/* hi bit may be set */
/* if exit obj. was */
/* double-clicked */
curedit = edit_obj;
wind_update(END_MCTRL);
return(next_obj);
}