Files
Arquivotheca.SunOS-4.1.4/usr.lib/libsuntool/misc/menu.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

615 lines
15 KiB
C

#ifndef lint
#ifdef sccs
static char sccsid[] = "@(#)menu.c 1.1 94/10/31 Copyr 1984 Sun Micro";
#endif
#endif
/*
* Copyright (c) 1984 by Sun Microsystems, Inc.
*/
/*
* Implement the menu interface described in menu.h.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <errno.h>
#include <stdio.h>
#include <strings.h>
#include <pixrect/pixrect.h>
#include <pixrect/pixfont.h>
#include <pixrect/pr_util.h>
#include <pixrect/memvar.h>
#include <sunwindow/rect.h>
#include <sunwindow/rectlist.h>
#include <sunwindow/cms.h>
#include <sunwindow/pixwin.h>
#include <sunwindow/cms_mono.h>
#include <sunwindow/win_input.h>
#include <sunwindow/win_cursor.h>
#include <sunwindow/win_struct.h>
#include <sunwindow/win_screen.h> /* to satisfy win_ioctl.h */
#include <sunwindow/win_ioctl.h> /* for journaling */
#include "sunwindow/sv_malloc.h"
#include <suntool/menu.h>
#include <suntool/fullscreen.h>
extern errno;
#define MD(m) ((struct menudata *)(LINT_CAST((m)->m_data)))
#define stripe_height (stripe_v_bound-MENU_BORDER)
struct menudata {
short md_width; /* width of menu */
};
static int _menu_windowfd;
static struct inputevent *_menu_event;
static struct pixfont *_menu_font;
static struct fullscreen *_menu_fs;
static struct pr_size image_size();
int type; /* MENU_IMAGESTRING or MENU_GRAPHIC */
/*
* Menu global data
*/
static short stripe_v_bound ;
static int menu_count;
static int items_top, cur_item, promotemenuno;
static struct menu *menu_list;
static struct rect menu_rect;
static short _menu_butcode;
static Pw_pixel_cache *pixel_cache;
/*
* Cursor data
*/
extern struct cursor menu_cursor;
/*
* journaling
*/
extern int sv_journal;
extern void win_sync();
struct menuitem *
menu_display(menuptr, inputevent, iowindowfd)
struct menu **menuptr;
struct inputevent *inputevent;
int iowindowfd;
{
int initx = inputevent->ie_locx, inity = inputevent->ie_locy;
struct inputmask im;
/*
* Grab all input and disable anybody but windowfd from writing
* to screen while we are violating window overlapping.
*/
_menu_windowfd = iowindowfd;
_menu_fs = fullscreen_init(iowindowfd);
/*
* Setup global data
*/
(void)_menu_init(*menuptr, inputevent);
/*
* Set menu cursor
*/
(void)win_setcursor(_menu_windowfd, &menu_cursor);
/*
* Make sure input mask allows menu package to track cursor motion
*/
im = _menu_fs->fs_cachedim;
im.im_flags |= IM_NEGEVENT;
win_setinputcodebit(&im, LOC_MOVEWHILEBUTDOWN);
win_setinputcodebit(&im, MS_LEFT);
win_setinputcodebit(&im, _menu_butcode);
(void)win_setinputmask(_menu_windowfd, &im, (struct inputmask *)0,
WIN_NULLLINK);
Repaint:
if (_menu_putup(&initx, &inity) == FALSE)
goto Done;
/*
* if journaling, send sync point.
*/
if (sv_journal)
win_sync(WIN_SYNC_STACK, iowindowfd);
(void)track_mouse_over_menu();
(void)menu_click();
(void)remove_menus();
if (promotemenuno) {
(void)promote_menu(promotemenuno);
promotemenuno = 0;
if (!(event_action(_menu_event) == _menu_butcode &&
win_inputnegevent(_menu_event)))
goto Repaint;
}
Done:
*menuptr = menu_list;
(void)fullscreen_destroy(_menu_fs);
(void)pw_pfsysclose();
if (cur_item==-1)
return(0);
else
return(menu_list->m_items+cur_item);
}
_menu_putup(initx, inity)
int *initx, *inity;
{
struct rect stripe_rect;
register int i;
register struct menuitem *mip;
register struct menu *wmp;
/*
* lay out menu space, adjusted for screen boundaries
*/
if (_menu_computerect(&menu_rect, initx, inity) == FALSE) {
return(FALSE);
}
if ((pixel_cache = pw_save_pixels(fsglobal->fs_pixwin, &menu_rect)) ==
PW_PIXEL_CACHE_NULL)
return(FALSE);
/*
* Lock at outer level so every write operation doesn't have too.
*/
(void)pw_lock(_menu_fs->fs_pixwin, &menu_rect);
/*
* paint the items for the topmost menu
*/
stripe_rect.r_left = menu_rect.r_left;
stripe_rect.r_top = items_top;
stripe_rect.r_width = MD(menu_list)->md_width;
stripe_rect.r_height = stripe_v_bound;
for (mip = menu_list->m_items,i=0;i < menu_list->m_itemcount;i++) {
image_stripe(mip[i].mi_imagetype, mip[i].mi_imagedata,
&stripe_rect, FALSE);
stripe_rect.r_top += stripe_height;
}
/*
* add header for topmost menu
*/
stripe_rect.r_height = stripe_height;
stripe_rect.r_top = items_top - stripe_height;
wmp = menu_list;
image_stripe(wmp->m_imagetype, wmp->m_imagedata, &stripe_rect, TRUE);
/*
* add the headers for each remaining menu on menu_list
*/
while (wmp = wmp->m_next) {
stripe_rect.r_top -= stripe_height;
stripe_rect.r_left += 4*MENU_BORDER;
image_stripe(wmp->m_imagetype, wmp->m_imagedata,
&stripe_rect, TRUE);
(void)header_separator(&stripe_rect);
(void)fake_RL_edge(stripe_rect.r_left + stripe_rect.r_width,
stripe_rect.r_top + stripe_height);
}
(void)pw_unlock(_menu_fs->fs_pixwin);
return(TRUE);
}
_menu_computerect(new, initx, inity)
register struct rect *new;
register int *initx, *inity;
{
register int s_w = _menu_fs->fs_screenrect.r_width,
s_h = _menu_fs->fs_screenrect.r_height;
int XINITOFFSET = 2;
new->r_width = MD(menu_list)->md_width +
4*MENU_BORDER * (menu_count - 1);
new->r_height = ( (menu_list->m_itemcount + menu_count)
* stripe_height) + MENU_BORDER;
if (new->r_width > s_w || new->r_height > s_h) {
(void)fprintf(stderr, "win_menu: menu doesn't fit!\n");
return(FALSE);
}
items_top = stripe_height * menu_count;
new->r_left = *initx + XINITOFFSET;
new->r_top = *inity - items_top;
/*
* Constrain to be on screen. Note: need utility rect_constrain.
*/
(void)wmgr_constrainrect(new, &_menu_fs->fs_screenrect, 0, 0);
/*
* Change inity so when click thru menu stack the top of the top
* menu doesn't appear to migrate unless needed.
*/
*inity = new->r_top + items_top;
items_top += new->r_top;
return(TRUE);
}
fake_RL_edge(x, y)
register x, y;
{
register w = 4*MENU_BORDER;
register h = menu_list->m_itemcount * stripe_height;
struct rect r;
x -= w;
rect_construct(&r, x, y, w, h);
(void)pw_preparesurface(_menu_fs->fs_pixwin, &r);
(void)pw_writebackground(_menu_fs->fs_pixwin, x, y, w, h, PIX_SET);
w -= MENU_BORDER; h -= MENU_BORDER;
(void)pw_writebackground(_menu_fs->fs_pixwin, x, y, w, h, PIX_CLR);
}
remove_menus() /* restore bitmap under */
{
pw_restore_pixels(_menu_fs->fs_pixwin, pixel_cache);
pixel_cache = PW_PIXEL_CACHE_NULL;
}
_menu_init(menustart, initevent)
struct menu *menustart;
struct inputevent *initevent;
{
int i;
struct menu *menu;
struct menuitem *mi;
struct pr_size size;
extern struct pixfont *pw_pfsysopen();
_menu_butcode = event_action(initevent);
/*
* Open font
*/
_menu_font = pw_pfsysopen();
/*
* Setup global menu invocation data
*/
menu_count = 0;
/*
stripe_v_bound = _menu_font->pf_defaultsize.y+8;
*/
stripe_v_bound = 0;
items_top = 0;
cur_item = -1;
promotemenuno = 0;
menu_list = menustart;
menu_rect = rect_null;
_menu_event = initevent;
/*
* Do per menu initialization
*/
for (menu=(menu_list);menu;menu=menu->m_next) {
/*
* Allocate implementation private/individual menu specific data
*/
if (menu->m_data==0) {
menu->m_data = (caddr_t) (LINT_CAST(
sv_calloc(1, sizeof (struct menudata))));
}
/*
* Find width & height of menu
*/
menu_count++;
size = image_size(menu->m_imagetype, menu->m_imagedata);
stripe_v_bound = max(stripe_v_bound, size.y);
MD(menu)->md_width = size.x;
for (i=0;i<menu->m_itemcount;i++) {
mi = menu->m_items+i;
size = image_size(mi->mi_imagetype, mi->mi_imagedata);
stripe_v_bound = max(stripe_v_bound, size.y);
MD(menu)->md_width = max(size.x, MD(menu)->md_width);
}
MD(menu)->md_width += (2*MENU_BORDER)+2;
}
stripe_v_bound += 8;
}
get_mouse_raw()
{
for (;;) {
if (input_readevent(_menu_windowfd, _menu_event)==-1) {
perror("menu: error reading input");
return;
}
switch(event_action(_menu_event)) {
case MS_LEFT: break;
case LOC_MOVEWHILEBUTDOWN:
if (win_inputnegevent(_menu_event))
continue;
else
break;
default:
if (event_action(_menu_event) == _menu_butcode)
break;
else
continue;
}
break;
}
return;
}
track_mouse_over_menu() /* compute new item:
* outside item list ? -1
* else y-offset in item list
* mod stripe r_height
*/
{
register int new_item, loop = 1;
int firsttime = 1;
do {
if (firsttime)
goto MaybeMoved;
/*
* Get and choose only inputevent interested in
*/
(void)get_mouse_raw();
switch(event_action(_menu_event)) {
case MS_LEFT:
if (win_inputnegevent(_menu_event)) {
loop = 0;
break;
}
continue;
case LOC_MOVEWHILEBUTDOWN:
if (win_inputposevent(_menu_event))
break;
continue;
default:
if (event_action(_menu_event) == _menu_butcode &&
win_inputnegevent(_menu_event)) {
loop = 0;
break;
} else
continue;
}
MaybeMoved:
firsttime = 0;
/*
* See if over menu item
*/
if (menu_rect.r_left <= _menu_event->ie_locx &&
_menu_event->ie_locx <
menu_rect.r_left+MD(menu_list)->md_width &&
items_top <= _menu_event->ie_locy &&
_menu_event->ie_locy <
menu_rect.r_top + menu_rect.r_height) {
new_item = (_menu_event->ie_locy - items_top)/
stripe_height;
if (new_item == menu_list->m_itemcount) {
new_item -= 1; /* in bottom border */
}
} else {
new_item = -1;
}
/*
* invert appropriate stripes if over new item
*/
if (new_item != cur_item) {
if (cur_item != -1) (void)invert_stripe(cur_item);
cur_item = new_item;
if (new_item != -1) (void)invert_stripe(new_item);
}
} while (loop);
return;
}
menu_click()
{
register int menu_no;
/*
* cur_item has just been set to the item which contains
* the mouse (or -1 if none).
*/
if (cur_item != -1)
return;
/*
* in header region, button means promote a different menu to r_top
*/
if (_menu_event->ie_locy < menu_rect.r_top ||
items_top <= _menu_event->ie_locy ) {
return;
}
menu_no = menu_count - ((_menu_event->ie_locy - menu_rect.r_top)
/ stripe_height) - 1;
if (menu_rect.r_left + (menu_no * 4*MENU_BORDER)
<= _menu_event->ie_locx
&& _menu_event->ie_locx
< menu_rect.r_left + menu_rect.r_width
- ((menu_count - menu_no - 1) * 4*MENU_BORDER))
promotemenuno = menu_no;
return;
}
text_stripe(str, r, invert)
register char *str;
struct rect *r;
{
#define MENU_STRMAX 100
char buf[MENU_STRMAX+1];
int max_len = min((r->r_width -
(2 * MENU_BORDER) - 2)/_menu_font->pf_defaultsize.x,
MENU_STRMAX);
/*
* Clip string for rear menu titles (sometimes)
*/
if (max_len < strlen(str)) {
(void)strncpy(buf, str, max_len);
buf[max_len] = '\0';
str = buf;
}
(void)pw_preparesurface(_menu_fs->fs_pixwin, r);
(void)pw_writebackground(_menu_fs->fs_pixwin, r->r_left, r->r_top,
r->r_width, r->r_height, PIX_SET);
if(!invert)
(void)pw_writebackground(_menu_fs->fs_pixwin,
r->r_left+MENU_BORDER, r->r_top+MENU_BORDER,
r->r_width-2*MENU_BORDER, r->r_height-2*MENU_BORDER,
PIX_CLR);
if (str == '\0')
return;
(void)pw_text(_menu_fs->fs_pixwin,
r->r_left+MENU_BORDER+1-_menu_font->pf_char[str[0]].pc_home.x,
r->r_top+MENU_BORDER+1-_menu_font->pf_char[str[0]].pc_home.y,
(invert ? PIX_NOT(PIX_SRC) : PIX_SRC), _menu_font, str);
}
invert_stripe(n)
{
struct rect r;
if (n > menu_list->m_itemcount || n < 0) {
(void)fprintf(stderr, "win_menu: invert_stripe n=%d\n", n);
return;
}
r.r_left = menu_rect.r_left + MENU_BORDER;
r.r_top = items_top + n*stripe_height + MENU_BORDER;
r.r_width = MD(menu_list)->md_width - 2 * MENU_BORDER;
r.r_height = stripe_height - MENU_BORDER;
(void)pw_writebackground(_menu_fs->fs_pixwin,
r.r_left, r.r_top, r.r_width, r.r_height, PIX_NOT(PIX_DST));
}
/*
* Menu promotion routine
*/
promote_menu(n)
{
register struct menu *new, *prev;
if (n==0) return;
if (n >= menu_count) {
(void)fprintf(stderr, "Menu Manager error: selected non-active menu.\n");
return;
}
prev = menu_list;
while (--n) if (prev->m_next) prev = prev->m_next;
if (prev->m_next == 0) {
(void)fprintf(stderr, "Menu Manager error: menu list too short.\n");
return;
}
new = prev->m_next; prev->m_next = new->m_next;
new->m_next = menu_list; menu_list = new;
}
struct pixrect *
save_bits(pixwin, r) /* save underlying bits */
struct pixwin *pixwin;
struct rect *r;
{
struct pixrect *mpr = mem_create(r->r_width, r->r_height,
pixwin->pw_pixrect->pr_depth);
if (mpr == 0) {
(void)fprintf(stderr, "Couldn't allocate memory in save_bits\n");
return((struct pixrect *) 0);
}
/*
* Subvert the pixwin interface, because pw_read requires
* a PIX_DONTCLIP|PIX_SRC to not clip to the src (the window)
* but the PIX_DONTCLIP flags makes the call unsafe if try to read
* from off the screen.
*/
(void)pw_lock(pixwin, r);
(void)pr_rop(mpr, 0, 0, r->r_width, r->r_height, PIX_SRC, pixwin->pw_pixrect,
r->r_left-fsglobal->fs_screenrect.r_left,
r->r_top-fsglobal->fs_screenrect.r_top);
(void)pw_unlock(pixwin);
/*
* Ignore pixwin->pw_rlfixup
*/
return(mpr);
}
restore_bits(pixwin, r, mpr) /* restore saved underlying bits */
struct pixwin *pixwin;
struct rect *r;
struct pixrect *mpr;
{
(void)pw_write(pixwin, r->r_left, r->r_top, r->r_width, r->r_height,
PIX_SRC, mpr, 0, 0);
mem_destroy(mpr);
}
header_separator(r)
register struct rect *r;
{
(void)pw_writebackground(_menu_fs->fs_pixwin,
r->r_left+MENU_BORDER, r->r_top+r->r_height-MENU_BORDER,
r->r_width-2*MENU_BORDER, MENU_BORDER, PIX_CLR);
}
static struct pr_size
image_size(menu_type, data)
int menu_type; /* MENU_IMAGESTRING or MENU_GRAPHIC */
caddr_t data; /* char * or pixrect * */
/* image_size returns the size of data given its type. Global _menu_font
is used if type is MENU_IMAGESTRING.
*/
{
extern struct pr_size pf_textwidth();
switch (menu_type) {
case MENU_IMAGESTRING:
return (pf_textwidth(strlen((char *)data), _menu_font, (char *)data));
case MENU_GRAPHIC:
return (((struct pixrect *)LINT_CAST(data))->pr_size);
}
/*NOTREACHED*/
} /* image_size */
static
image_stripe(menu_type, data, r, invert)
int menu_type;
register caddr_t data;
struct rect *r;
int invert;
/* image_stripe stripes data within the rect r.
*/
{
switch (menu_type) {
case MENU_IMAGESTRING:
(void)text_stripe((char *)data, r, invert);
break;
case MENU_GRAPHIC:
(void)pw_preparesurface(_menu_fs->fs_pixwin, r);
(void)pw_writebackground(_menu_fs->fs_pixwin, r->r_left, r->r_top,
r->r_width, r->r_height, PIX_SET);
if(!invert)
(void)pw_writebackground(_menu_fs->fs_pixwin,
r->r_left+MENU_BORDER, r->r_top+MENU_BORDER,
r->r_width-2*MENU_BORDER, r->r_height-2*MENU_BORDER,
PIX_CLR);
/* center the pixrect vertically in the enclosing rect */
(void)pw_write(_menu_fs->fs_pixwin,
r->r_left+MENU_BORDER + 1,
r->r_top + MENU_BORDER + 1 +
(r->r_height - ((struct pixrect *)(LINT_CAST(data)))->pr_height -
2 * MENU_BORDER) / 2,
min(r->r_width, ((struct pixrect *)(LINT_CAST(data)))->pr_width),
r->r_height,
(invert ? PIX_NOT(PIX_SRC) : PIX_SRC),
(struct pixrect *)(LINT_CAST(data)), 0, 0);
break;
}
} /* image_stripe */