home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari FTP
/
ATARI_FTP_0693.zip
/
ATARI_FTP_0693
/
Mint
/
toswinsc.zoo
/
winmenu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-27
|
8KB
|
401 lines
/*
* Copyright 1992 Eric R. Smith. All rights reserved.
* Redistribution is permitted only if the distribution
* is not for profit, and only if all documentation
* (including, in particular, the file "copying")
* is included in the distribution in unmodified form.
* THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
* EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
* RISK.
*/
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <osbind.h>
#include <gemfast.h>
#include "xgem.h"
#include "twdefs.h"
#define FM_COPY 3
/* given a mouse x and y coordinate
* (msx, msy) and the x, y coordinate
* of a menu bar, find which of the
* bar's menus should be displayed
* (if any), On return, the (x,y)
* coordinate at which the drop-down
* should be placed is put in *xp and
* *yp
*/
/* if we're *way* outside of the menu area,
* make the menu go away
*/
#define GOAWAY ((MENU *)-1L)
static MENU *
whichmenu(bar, barx, bary, msx, msy, xp, yp)
MENU *bar;
int barx, bary, msx, msy;
int *xp, *yp;
{
MENU *m;
int xpixel;
int leftx;
if (msx < barx || msy < bary)
return GOAWAY;
if (msy > bary+gl_hbox)
return 0;
xpixel = barx;
m = bar;
while(m) {
leftx = xpixel;
xpixel += gl_wchar * (strlen(m->title)+2);
if (msx < xpixel) {
*xp = leftx+1;
*yp = bary+gl_hbox;
return m;
}
m = m->next;
}
return 0;
}
/*
* create an object for a drop down menu, with
* upper corner (x, y)
*/
static OBJECT *
makemenu(m, x, y)
MENU *m;
int x, y;
{
extern int entrylen __PROTO(( ENTRY * ));
extern char *entrystr __PROTO(( ENTRY *, int ));
OBJECT *popobj;
ENTRY *e;
int numobjects, wide, i;
numobjects = 1;
wide = 0;
for (e = m->contents; e; e = e->next) {
numobjects++;
if ( (i = entrylen(e)) > wide)
wide = i;
}
popobj = malloc(numobjects * sizeof(OBJECT));
if (!popobj) return 0;
/* first, create the box around the menu */
popobj[0].ob_next = -1;
popobj[0].ob_head = 1;
popobj[0].ob_tail = numobjects - 1;
popobj[0].ob_type = G_BOX;
popobj[0].ob_flags = LASTOB; popobj[0].ob_state = NORMAL;
popobj[0].ob_spec = 0x00ff1100L;
popobj[0].ob_x = x/gl_wchar; popobj[0].ob_y = y/gl_hchar;
popobj[0].ob_width = wide;
popobj[0].ob_height = numobjects - 1;
i = 1;
for (e = m->contents; e; e = e->next) {
popobj[i].ob_next = (e->next) ? i+1 : 0;
popobj[i].ob_head = popobj[i].ob_tail = -1;
popobj[i].ob_type = G_STRING;
popobj[i].ob_flags = NONE;
popobj[i].ob_state = e->state;
popobj[i].ob_spec = (long)entrystr(e, wide);
if (!popobj[i].ob_spec) return 0;
popobj[i].ob_x = 0; popobj[i].ob_y = i - 1;
popobj[i].ob_width = wide; popobj[i].ob_height = 1;
i++;
}
popobj[i-1].ob_flags = LASTOB;
/* now, fix up the object tree */
for (i = 0; i < numobjects; i++)
rsrc_obfix(popobj, i);
popobj[0].ob_x = x;
popobj[0].ob_y = y;
return popobj;
}
static void
freeobj(obj)
OBJECT *obj;
{
int i;
for (i = 1; i; i++) {
free((void *)obj[i].ob_spec);
if (obj[i].ob_flags & LASTOB)
break;
}
free(obj);
}
#define screen_planes gl_screenplanes
static MFDB scr_mfdb;
static void
savearea(mfdb, x, y, w, h)
MFDB *mfdb;
int x, y, w, h;
{
int blitrec[8];
blitrec[0] = x;
blitrec[1] = y;
blitrec[2] = x + w - 1;
blitrec[3] = y + h - 1;
blitrec[4] = 0;
blitrec[5] = 0;
blitrec[6] = w - 1;
blitrec[7] = h - 1;
/* mfdb->fd_addr is assumed to be set already */
mfdb->fd_w = w;
mfdb->fd_h = h;
mfdb->fd_wdwidth = ((w+15)/16);
mfdb->fd_stand = 0;
mfdb->fd_nplanes = screen_planes;
hide_mouse();
set_clip(x, y, w, h);
vro_cpyfm(vdi_handle, FM_COPY, blitrec, &scr_mfdb, mfdb);
show_mouse();
}
static void
restorearea(mfdb, x, y, w, h)
MFDB *mfdb;
int x, y, w, h;
{
int blitrec[8];
blitrec[0] = 0;
blitrec[1] = 0;
blitrec[2] = w-1;
blitrec[3] = h-1;
blitrec[4] = x;
blitrec[5] = y;
blitrec[6] = x+w-1;
blitrec[7] = y+h-1;
hide_mouse();
set_clip(x, y, w, h);
vro_cpyfm(vdi_handle, FM_COPY, blitrec, mfdb, &scr_mfdb);
show_mouse();
}
/*
* deal with user interactions with a drop-down menu bar
* (x,y) is the upper left hand corner of the region
* containing the bar
*/
void
dropdown_menu(bar, x, y)
MENU *bar;
int x,y;
{
OBJECT *popobj = 0;
MENU *m, *lastm, *tmpm;
ENTRY *e;
int i;
int w, h;
int event, msx, msy, mbutton, mbreturn, keycode, dummy;
int curobj = -1;
int newobj;
unsigned lowbyte, hibyte;
int barx, bary;
long blitbuf;
MFDB blit_mfdb;
int newx, newy;
int drawn = 0;
int winhandle;
int winowner;
wind_update(BEG_MCTRL);
/* check to see that we have the right top window */
wind_get(0, WF_TOP, &winhandle, &winowner, &dummy, &dummy);
if (!gl_topwin ||
gl_topwin->wi_handle != winhandle) {
wind_update(END_MCTRL);
return;
}
barx = x;
bary = y;
msx = msy = 0;
event = evnt_multi(MU_M1,
2, 0x0001, 0x0001,
1, msx, msy, 1, 1,
0, 0, 0, 0, 0,
0L, 0L,
&msx, &msy, &mbutton, &dummy,
&keycode, &mbreturn);
wind_get(0, WF_SCREEN, &hibyte, &lowbyte, &dummy, &dummy);
blitbuf = ((long)hibyte << 16L) | lowbyte;
blit_mfdb.fd_addr = blitbuf;
/*
* find which (if any) menu should be displayed
*/
m = whichmenu(bar, barx, bary, msx, msy, &newx, &newy);
if (!m || m == GOAWAY) {
wind_update(END_MCTRL);
return;
}
lastm = 0;
w = h = 0;
/* display the tree and interact with it */
for(;;) {
if (m != lastm) {
if (popobj) {
freeobj(popobj);
popobj = 0;
}
if (drawn) {
restorearea(&blit_mfdb, x, y, w, h);
drawn = 0;
}
if (!m || (m == GOAWAY)) {
break;
}
lastm = m;
x = newx;
y = newy;
/* create a new object tree */
popobj = makemenu(m, x, y);
if (!popobj) {
break;
}
/* "-1" takes care of the bordering box */
x = popobj[0].ob_x - 1;
y = popobj[0].ob_y - 1;
if (x >= xdesk+wdesk)
x = xdesk+wdesk-1;
if (y >= ydesk+hdesk) {
break;
};
w = popobj[0].ob_width + 2;
h = popobj[0].ob_height + 2;
if (x + w > xdesk + wdesk) {
w = xdesk + wdesk - x;
}
if (y + h > ydesk + hdesk)
h = ydesk + hdesk - y;
/* save the area we're about to draw over */
savearea(&blit_mfdb, x, y, w, h);
/* now actually draw the object */
objc_draw(popobj, 0, 1, x, y, w, h);
drawn = 1;
}
event = evnt_multi(MU_BUTTON|MU_M1|MU_KEYBD,
2, 0x0001, 0x0001,
1, msx, msy, 1, 1,
0, 0, 0, 0, 0,
0L, 0L,
&msx, &msy, &mbutton, &dummy,
&keycode, &mbreturn);
if (event & MU_M1) {
if (msx >= x && msx <= x+w && msy >= y && msy <= y+h) {
newobj = objc_find(popobj, 0, 1, msx, msy);
} else {
newobj = -1;
tmpm = whichmenu(bar, barx, bary, msx, msy, &newx, &newy);
if (tmpm)
m = tmpm;
else if (msy - y > h + gl_hbox)
m = GOAWAY;
else if (msx - x > w + gl_wbox)
m = GOAWAY;
}
if (curobj > 0 && curobj != newobj) {
objc_change(popobj, curobj, 0, x, y, w, h,
NORMAL, 1);
}
curobj = newobj;
if (curobj > 0 && popobj[curobj].ob_state != DISABLED) {
objc_change(popobj, curobj, 0,x,y,w,h,
SELECTED, 1);
} else {
curobj = -1;
}
}
if (event & MU_KEYBD) {
lowbyte = keycode & 0x00ff;
i = 1;
for (e = m->contents; e; e = e->next) {
if ((lowbyte && e->keycode == lowbyte) ||
e->keycode == keycode) {
curobj = i;
break;
} else i++;
}
}
if (event & MU_BUTTON) {
break;
}
}
/* free memory allocated by `entrystr' */
if (popobj) {
freeobj(popobj);
}
if (drawn)
restorearea(&blit_mfdb, x, y, w, h);
wind_update(END_MCTRL);
if (curobj > 0) {
for (e = m->contents; e; e = e->next) {
--curobj;
if (curobj == 0) {
(*e->func)(e->arg);
break;
}
}
}
}
char *
menustr(bar)
MENU *bar;
{
static char buf[80];
char *s = buf;
buf[0] = 0;
while(bar) {
strcat(s, " ");
strcat(s, bar->title);
strcat(s, " ");
bar = bar->next;
}
return buf[0] ? buf : 0;
}