Init
This commit is contained in:
936
usr.lib/libsuntool/menu/walkmenu_render.c
Normal file
936
usr.lib/libsuntool/menu/walkmenu_render.c
Normal file
@@ -0,0 +1,936 @@
|
||||
#ifndef lint
|
||||
#ifdef sccs
|
||||
static char sccsid[] = "@(#)walkmenu_render.c 1.1 94/10/31 Copyright 1985 Sun Micro";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Copyright (c) 1985 by Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
/*-
|
||||
WALKING MENU PACKAGE
|
||||
|
||||
walkmenu_render.c, Sun Jun 30 15:38:39 1985
|
||||
|
||||
Craig Taylor,
|
||||
Sun Microsystems
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <varargs.h>
|
||||
|
||||
#include <pixrect/pixrect.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/win_screen.h>
|
||||
#include <sunwindow/win_input.h>
|
||||
#include <sunwindow/win_cursor.h>
|
||||
#include <sunwindow/win_struct.h>
|
||||
#include <sunwindow/win_ioctl.h>
|
||||
|
||||
#include <suntool/fullscreen.h>
|
||||
#include <suntool/window.h>
|
||||
|
||||
#include <suntool/walkmenu_impl.h>
|
||||
|
||||
#define PIXRECT_NULL ((struct pixrect *)0)
|
||||
#define SCREEN_MARGIN 10 /* Minimum number of pixels away
|
||||
* from the edge of the screen a menu's
|
||||
* left and top sides should be.
|
||||
* (to enable backing out of
|
||||
* pullright menus
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Public
|
||||
*/
|
||||
/* None */
|
||||
|
||||
/*
|
||||
* Package private
|
||||
*/
|
||||
Pkg_extern struct pixrect menu_arrow_pr; /* in walkmenu_create.c */
|
||||
Pkg_extern struct fullscreen *menu_fs; /* in walkmenu_public.c */
|
||||
|
||||
Pkg_extern int menu_curitem();
|
||||
Pkg_private int menu_render();
|
||||
|
||||
|
||||
/*
|
||||
* Private
|
||||
*/
|
||||
Private int compute_item_size();
|
||||
Private int compute_dimensions();
|
||||
Private void compute_rects();
|
||||
Private void render_items();
|
||||
Private int render_pullright();
|
||||
Private void paint_shadow();
|
||||
Private void paint_menu();
|
||||
Private void feedback();
|
||||
Private void constrainrect();
|
||||
Private void destroy_gen_items();
|
||||
|
||||
/*
|
||||
* Private defs
|
||||
*/
|
||||
#define MENU_SHADOW 6 /* Width of menu shadow */
|
||||
#define MENU_BORDER 1 /* Width of menu border */
|
||||
#define STANDOFF 3 /* 1/2 the number of active pixels left of the menu */
|
||||
|
||||
extern int sv_journal;
|
||||
extern void win_sync();
|
||||
|
||||
static int old_mousex, old_mousey;
|
||||
int menu_count;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Menu_render modifies the inputevent parameter iep.
|
||||
* It should contain the last active inputevent read for the fd.
|
||||
*/
|
||||
Pkg_private int
|
||||
menu_render(menu, dynamic, parent, subrect, reenter, fd)
|
||||
struct menu *menu;
|
||||
struct menu_info *dynamic;
|
||||
struct menu_item *parent;
|
||||
struct rectnode *subrect;
|
||||
int fd;
|
||||
{
|
||||
register struct menu *m;
|
||||
register struct menu_item *mi;
|
||||
register curitem, item_width, item_height;
|
||||
register struct inputevent *iep;
|
||||
register short menu_button, locx;
|
||||
struct image *std_image;
|
||||
struct menu *(*gen_proc)();
|
||||
struct rect menurect, activerect, saverect, itemrect;
|
||||
struct pixrect *menu_image, *items_image;
|
||||
Pw_pixel_cache *pixel_cache;
|
||||
int stand_off, status, gen_items;
|
||||
int margin, right_margin, ncols, nrows;
|
||||
|
||||
/*
|
||||
* Initial setup: Pull out dynamic information.
|
||||
*/
|
||||
menu->dynamic_info = dynamic, menu->parent = parent;
|
||||
dynamic->depth++;
|
||||
iep = dynamic->last_iep;
|
||||
menu_button = iep->ie_code;
|
||||
stand_off = reenter == FALSE && menu->stand_off;
|
||||
pixel_cache = PW_PIXEL_CACHE_NULL, gen_items = FALSE, gen_proc = NULL;
|
||||
|
||||
/*
|
||||
* Dynamically create the menu if requested.
|
||||
*/
|
||||
if (gen_proc = menu->gen_proc) {
|
||||
m = (gen_proc)(menu, MENU_DISPLAY);
|
||||
if (m == NULL) {
|
||||
(void) fprintf(stderr,
|
||||
"menu_show: menu's gen_proc failed to generate a menu.\n");
|
||||
goto error_exit;
|
||||
}
|
||||
m->dynamic_info = dynamic, m->parent = parent;
|
||||
} else {
|
||||
m = menu;
|
||||
}
|
||||
|
||||
/*
|
||||
* No items, return to parent menu
|
||||
*/
|
||||
if (m->nitems == 0) {
|
||||
status = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the current menu item
|
||||
*/
|
||||
if (reenter) { /* Based on default selection */
|
||||
curitem = menu_curitem(m, m->default_selection, 1);
|
||||
} else { /* Based on initial selection */
|
||||
curitem = menu_curitem(m, m->initial_selection, 1);
|
||||
if (!curitem) {
|
||||
status = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the size of an item.
|
||||
*/
|
||||
std_image = &m->default_image;
|
||||
gen_items = compute_item_size(m, std_image);
|
||||
item_width = std_image->width;
|
||||
item_height = std_image->height;
|
||||
margin = std_image->margin;
|
||||
right_margin = std_image->right_margin;
|
||||
|
||||
/*
|
||||
* Automatically compute the elided dimension.
|
||||
*/
|
||||
if (!compute_dimensions(m, item_width, item_height,
|
||||
&menurect, &ncols, &nrows))
|
||||
goto error_exit;
|
||||
|
||||
/*
|
||||
* Compute the rects:
|
||||
* menurect - represents the area of the menu including its borders.
|
||||
* activerect - extends the left edge of the menurect. Cursor motion
|
||||
* is mapped to its associated menu with this rect.
|
||||
* saverect - extended menurect with includes the menu shadow.
|
||||
*/
|
||||
compute_rects(m, iep, stand_off, curitem,
|
||||
item_width, item_height, ncols, nrows,
|
||||
&menurect, &activerect, &saverect);
|
||||
|
||||
/*
|
||||
* Save the mouse position so that after selecting, it will return
|
||||
* to the same place
|
||||
*/
|
||||
if (menu_count++ == 0){
|
||||
old_mousex = win_get_vuid_value(fd, LOC_X_ABSOLUTE);
|
||||
old_mousey = win_get_vuid_value(fd, LOC_Y_ABSOLUTE);
|
||||
}
|
||||
/*
|
||||
* Save image under menu, generate menu and display it.
|
||||
*/
|
||||
if (((pixel_cache = pw_save_pixels(menu_fs->fs_pixwin, &saverect)) ==
|
||||
PW_PIXEL_CACHE_NULL) ||
|
||||
(pw_primary_cached_mpr(menu_fs->fs_pixwin, pixel_cache) ==
|
||||
(struct pixrect *)0))
|
||||
goto error_exit;
|
||||
|
||||
/*
|
||||
* Create pixrect w/menu image.
|
||||
* For now assume that the menu is monochrome.
|
||||
*/
|
||||
menu_image = mem_create(saverect.r_width, saverect.r_height, 1);
|
||||
items_image = pr_region(menu_image, MENU_BORDER, MENU_BORDER,
|
||||
item_width * ncols, item_height * nrows);
|
||||
|
||||
paint_shadow(menu_image, m->shadow_pr,
|
||||
pw_primary_cached_mpr(menu_fs->fs_pixwin, pixel_cache));
|
||||
render_items(m, std_image, items_image, ncols, nrows);
|
||||
|
||||
/*
|
||||
* Display the menu and provide item highlighting.
|
||||
*/
|
||||
(void) pw_lock(menu_fs->fs_pixwin, &saverect);
|
||||
|
||||
paint_menu(menu_image, &saverect, (m->shadow_pr)? 1: 0);
|
||||
|
||||
if (!stand_off)
|
||||
feedback(m, &menurect, curitem, ncols, nrows, MENU_PROVIDE_FEEDBACK);
|
||||
(void) pw_unlock(menu_fs->fs_pixwin);
|
||||
mem_destroy(items_image);
|
||||
mem_destroy(menu_image);
|
||||
|
||||
if (sv_journal) {
|
||||
win_sync(WIN_SYNC_MENU, fd);
|
||||
}
|
||||
|
||||
/* From here on any returns from this procedure should go thru exit: */
|
||||
|
||||
/*
|
||||
* Handle initial selection expansion
|
||||
*/
|
||||
if (!reenter && !m->display_one_level) {
|
||||
mi = m->item_list[curitem - 1];
|
||||
if (mi->pullright && !mi->inactive && !mi->selected &&
|
||||
(mi->value || mi->gen_pullright))
|
||||
{
|
||||
if (!mi->gen_pullright) { /* FIXME: Should handle gen pullright */
|
||||
struct menu *mn = (struct menu *)LINT_CAST(mi->value);
|
||||
if (!menu_curitem(mn, mn->initial_selection, 0))
|
||||
goto enter_input_loop;
|
||||
}
|
||||
|
||||
if (stand_off) {
|
||||
feedback(m, &menurect,
|
||||
curitem, ncols, nrows, MENU_PROVIDE_FEEDBACK);
|
||||
}
|
||||
|
||||
locx = menurect.r_left;
|
||||
if (m->column_major)
|
||||
locx += ((curitem - 1) / nrows + 1) * item_width + MENU_BORDER;
|
||||
else
|
||||
locx += ((curitem - 1) % ncols + 1) * item_width + MENU_BORDER;
|
||||
itemrect.r_width = locx;
|
||||
locx -= margin + right_margin + mi->image->right_pr->pr_width;
|
||||
locx -= stand_off ? STANDOFF : -STANDOFF;
|
||||
iep->ie_locx = locx;
|
||||
|
||||
iep->ie_locy = menurect.r_top + MENU_BORDER;
|
||||
if (m->column_major)
|
||||
iep->ie_locy += (curitem - 1) % nrows * item_height
|
||||
+ item_height / 2;
|
||||
else
|
||||
iep->ie_locy += (curitem - 1) / ncols * item_height
|
||||
+ item_height / 2;
|
||||
|
||||
itemrect.r_left = locx;
|
||||
itemrect.r_width -= locx;
|
||||
itemrect.r_top = iep->ie_locy - item_height / 2;
|
||||
itemrect.r_height = item_height;
|
||||
|
||||
(void) win_setmouseposition(menu_fs->fs_windowfd,
|
||||
iep->ie_locx, iep->ie_locy);
|
||||
|
||||
event_set_id(iep, menu_button);
|
||||
status = render_pullright(mi, subrect, &menurect, &itemrect, FALSE,fd);
|
||||
if (status == 0 || --status != 0) goto exit;
|
||||
stand_off = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
enter_input_loop:
|
||||
if (stand_off) curitem = 0;
|
||||
locx = iep->ie_locx;
|
||||
/*
|
||||
* Track the mouse.
|
||||
*/
|
||||
for (;;) {
|
||||
register int itemx, itemy, newitem;
|
||||
int arrow_bdry;
|
||||
|
||||
if (rect_includespoint(&activerect, iep->ie_locx, iep->ie_locy)) {
|
||||
/*
|
||||
* Check if cursor is in the current menu
|
||||
*/
|
||||
itemx = iep->ie_locx - menurect.r_left - MENU_BORDER;
|
||||
if (itemx < 0) itemx = m->nitems; /* Outside menu proper */
|
||||
else {
|
||||
itemx = itemx / item_width;
|
||||
if (itemx >= ncols) itemx = ncols - 1;
|
||||
}
|
||||
|
||||
itemy = (iep->ie_locy - menurect.r_top - MENU_BORDER) / item_height;
|
||||
if (itemy < 0) itemy = 0;
|
||||
else if (itemy >= nrows) itemy = nrows - 1;
|
||||
|
||||
newitem = m->column_major ?
|
||||
itemx * nrows + itemy + 1 : itemy * ncols + itemx + 1;
|
||||
|
||||
if (newitem > m->nitems) newitem = 0;
|
||||
} else {
|
||||
register struct rectnode *rp;
|
||||
if (subrect && !rect_includespoint(&subrect->rn_rect,
|
||||
iep->ie_locx, iep->ie_locy)) {
|
||||
if ((rect_includesrect(&menurect,&subrect->rn_next->rn_rect)) &&
|
||||
iep->ie_locx < menurect.r_left) {
|
||||
/*
|
||||
* cursor is to the left of pullright, and
|
||||
* parent is obscured by the child menu, so we
|
||||
* pop back to the parent menu.
|
||||
*/
|
||||
status = 1;
|
||||
goto exit;
|
||||
}
|
||||
/*
|
||||
* Check if cursor is in a parent menu
|
||||
*/
|
||||
|
||||
status = 1;
|
||||
for (rp = subrect->rn_next; rp;
|
||||
rp = rp->rn_next ? rp->rn_next->rn_next : NULL, status++) {
|
||||
if (rect_includespoint(&rp->rn_rect,
|
||||
iep->ie_locx, iep->ie_locy))
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
newitem = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Provide feedback for new item.
|
||||
*/
|
||||
if (newitem != curitem) { /* revert item to normal state */
|
||||
if (curitem)
|
||||
feedback(m, &menurect,
|
||||
curitem, ncols, nrows, MENU_REMOVE_FEEDBACK);
|
||||
curitem = newitem; /* invert new item */
|
||||
if (curitem) {
|
||||
feedback(m, &menurect,
|
||||
curitem, ncols, nrows, MENU_PROVIDE_FEEDBACK);
|
||||
locx = iep->ie_locx;
|
||||
}
|
||||
}
|
||||
|
||||
if (locx >= iep->ie_locx) locx = iep->ie_locx;
|
||||
|
||||
if (newitem) {
|
||||
/*
|
||||
* If item is a menu, recurse.
|
||||
*/
|
||||
mi = m->item_list[newitem - 1];
|
||||
if (mi->pullright)
|
||||
arrow_bdry = menurect.r_left + MENU_BORDER + STANDOFF
|
||||
+ (itemx * item_width) + item_width
|
||||
- (margin + (mi->image->string?right_margin:0)
|
||||
+ mi->image->right_pr->pr_width);
|
||||
if (mi->pullright && !mi->inactive
|
||||
&& (iep->ie_locx > arrow_bdry
|
||||
|| iep->ie_locx >= locx + m->pullright_delta)
|
||||
&& (mi->value || mi->gen_pullright))
|
||||
{
|
||||
if (iep->ie_locx > arrow_bdry) iep->ie_locx = arrow_bdry;
|
||||
|
||||
iep->ie_locy = (menurect.r_top + MENU_BORDER
|
||||
+ itemy * item_height
|
||||
+ (item_height / 2));
|
||||
event_set_id(iep, menu_button);
|
||||
/* Recurse */
|
||||
itemrect.r_left = iep->ie_locx;
|
||||
itemrect.r_width = menurect.r_left + MENU_BORDER + STANDOFF
|
||||
+ itemx * item_width + item_width - iep->ie_locx;;
|
||||
itemrect.r_top = iep->ie_locy - item_height / 2;
|
||||
itemrect.r_height = item_height;
|
||||
|
||||
status =
|
||||
render_pullright(mi, subrect, &menurect, &itemrect, TRUE,fd);
|
||||
|
||||
if (status == 0 || --status != 0) goto exit;
|
||||
locx = iep->ie_locx;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get next input event.
|
||||
*/
|
||||
do {
|
||||
if (input_readevent(menu_fs->fs_windowfd, iep) == -1) {
|
||||
(void) fprintf(stderr, "menu_show: failed to track cursor.\n");
|
||||
perror("menu_show");
|
||||
status = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* If button up is the menu button then
|
||||
* an item has been selected, return it.
|
||||
*/
|
||||
if (menu_button == iep->ie_code && win_inputnegevent(iep)) {
|
||||
if (curitem == 0 || m->item_list[curitem-1]->inactive)
|
||||
m->dynamic_info->depth = 0, curitem = NULL;
|
||||
status = 0;
|
||||
goto exit;
|
||||
}
|
||||
else if (event_action(iep) == ACTION_HELP &&
|
||||
win_inputposevent(iep)) {
|
||||
if (curitem == 0 || !m->item_list[curitem-1]->help_data)
|
||||
m->dynamic_info->help = m->help_data;
|
||||
else
|
||||
m->dynamic_info->help = m->item_list[curitem-1]->help_data;
|
||||
m->dynamic_info->depth = 0, curitem = NULL;
|
||||
status = 0;
|
||||
goto exit;
|
||||
}
|
||||
} while (iep->ie_code != LOC_MOVEWHILEBUTDOWN &&
|
||||
iep->ie_code != LOC_STILL && iep->ie_code != LOC_MOVE);
|
||||
}
|
||||
|
||||
/* Entry states at the next higher level:
|
||||
* status<0 abort menu chain (error or null selection),
|
||||
* status=0 valid selection save selected item,
|
||||
* status>0 cursor has entered a parent menu.
|
||||
*/
|
||||
|
||||
exit:
|
||||
if (status == 0 && curitem)
|
||||
m->selected_position = curitem;
|
||||
if (status > 0) --m->dynamic_info->depth;
|
||||
|
||||
/*
|
||||
* set the mouse back to the position where it was first clicked
|
||||
*/
|
||||
if(--menu_count == 0)
|
||||
win_setmouseposition(menu_fs->fs_windowfd, old_mousex, old_mousey);
|
||||
|
||||
pw_restore_pixels(menu_fs->fs_pixwin, pixel_cache); /* Checks for null */
|
||||
if (gen_items) destroy_gen_items(m);
|
||||
m->dynamic_info = NULL;
|
||||
if (gen_proc) {
|
||||
(gen_proc)(m, MENU_DISPLAY_DONE);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
error_exit:
|
||||
status = -1;
|
||||
m->dynamic_info->depth = 0;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compute max item size. Only zero sized items have to be recomputed
|
||||
*/
|
||||
Private int
|
||||
compute_item_size(menu, std_image)
|
||||
struct menu *menu;
|
||||
struct image *std_image;
|
||||
{
|
||||
register int width, height, nitems, recompute;
|
||||
register struct menu_item *mi, **mip;
|
||||
int gen_items = FALSE;
|
||||
|
||||
nitems = menu->nitems;
|
||||
width = height = 0;
|
||||
recompute = std_image->width == 0;
|
||||
|
||||
/*
|
||||
* This causes the menu to shrink around the items.
|
||||
* When the std_image is available at the client interface zeroing the
|
||||
* size of std_image should be rethought.
|
||||
*/
|
||||
std_image->width = std_image->height = 0;
|
||||
|
||||
/* Compute max size if any of the items have changed */
|
||||
for (mip = menu->item_list;mi = *mip, nitems--; mip++) {
|
||||
|
||||
mi->parent = menu;
|
||||
|
||||
if (mi->gen_proc) {
|
||||
*mip = mi = (mi->gen_proc)(mi, MENU_DISPLAY);
|
||||
gen_items = TRUE;
|
||||
}
|
||||
|
||||
/* This is an untested (unnecessary?) optimization */
|
||||
if (recompute) mi->image->width = 0; /* This forces the size to be
|
||||
* recompute inside image_get() */
|
||||
if (mi->image->width == 0) {
|
||||
width = imax(image_get(mi->image, std_image, IMAGE_WIDTH), width);
|
||||
height = imax((int)image_get(mi->image, std_image, IMAGE_HEIGHT),
|
||||
height);
|
||||
} else {
|
||||
width = imax(mi->image->width, width);
|
||||
height = imax(mi->image->height, height);
|
||||
}
|
||||
}
|
||||
std_image->width = width;
|
||||
std_image->height = height;
|
||||
|
||||
return gen_items;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compute the dimensions of the menu.
|
||||
*/
|
||||
Private int
|
||||
compute_dimensions(menu, iwidth, iheight, rect, ncolp, nrowp)
|
||||
register struct menu *menu;
|
||||
int iwidth, iheight;
|
||||
register Rect *rect;
|
||||
int *ncolp, *nrowp;
|
||||
{
|
||||
register int ncols, nrows;
|
||||
|
||||
ncols = menu->ncols;
|
||||
nrows = menu->nrows;
|
||||
|
||||
/* Fix 1015167: subtract SCREEN_MARGIN everywhere */
|
||||
|
||||
if (!(ncols && nrows)) {
|
||||
if (ncols) { /* case: ncols=n, nrows=to fit */
|
||||
rect->r_width = (ncols * iwidth) +
|
||||
2*MENU_BORDER + (menu->shadow_pr ? MENU_SHADOW : 0);
|
||||
if (rect->r_width > menu_fs->fs_screenrect.r_width
|
||||
-SCREEN_MARGIN) {
|
||||
ncols = (menu_fs->fs_screenrect.r_width - SCREEN_MARGIN
|
||||
- 2*MENU_BORDER + (menu->shadow_pr ? MENU_SHADOW : 0))
|
||||
/ iwidth;
|
||||
}
|
||||
nrows = (menu->nitems - 1) / ncols + 1;
|
||||
} else { /* case: nrows=n, ncols=to fit */
|
||||
if (!nrows) nrows = menu->nitems; /* Both zero, fit cols */
|
||||
rect->r_height = (nrows * iheight) +
|
||||
2*MENU_BORDER + (menu->shadow_pr ? MENU_SHADOW : 0);
|
||||
if (rect->r_height > menu_fs->fs_screenrect.r_height - SCREEN_MARGIN) {
|
||||
nrows = (menu_fs->fs_screenrect.r_height - SCREEN_MARGIN
|
||||
- 2*MENU_BORDER - (menu->shadow_pr ? MENU_SHADOW : 0))
|
||||
/ iheight;
|
||||
|
||||
ncols = (menu->nitems - 1) / nrows + 1;
|
||||
nrows = (menu->nitems - 1) / ncols + 1;
|
||||
} else {
|
||||
ncols = (menu->nitems - 1) / nrows + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
rect->r_width = (ncols * iwidth) +
|
||||
2*MENU_BORDER + (menu->shadow_pr ? MENU_SHADOW : 0);
|
||||
rect->r_height = (nrows * iheight) +
|
||||
2*MENU_BORDER + (menu->shadow_pr ? MENU_SHADOW : 0);
|
||||
if (rect->r_width > menu_fs->fs_screenrect.r_width - SCREEN_MARGIN
|
||||
|| rect->r_height > menu_fs->fs_screenrect.r_height - SCREEN_MARGIN) {
|
||||
(void) fprintf(stderr, "menu_show: Menu too large for screen.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*ncolp = ncols;
|
||||
*nrowp = nrows;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Compute 3 rects:
|
||||
* mrect = menu_image;
|
||||
* srect = mrect + shadow
|
||||
* irect = input region = menu_rect + stand_off region
|
||||
*/
|
||||
Private void
|
||||
compute_rects(menu, iep, stand_off, curitem,
|
||||
item_width, item_height, ncols, nrows,
|
||||
mrect, irect, srect)
|
||||
struct menu *menu;
|
||||
struct inputevent *iep;
|
||||
int stand_off, curitem, item_width, item_height, ncols, nrows;
|
||||
Rect *mrect, *irect, *srect;
|
||||
{
|
||||
int left, top;
|
||||
|
||||
left = item_width * (menu->column_major ?
|
||||
(curitem - 1) / nrows : (curitem - 1) % ncols);
|
||||
top = item_height * (menu->column_major ?
|
||||
(curitem - 1) % nrows : (curitem - 1) / ncols);
|
||||
mrect->r_left = iep->ie_locx - left - MENU_BORDER;
|
||||
mrect->r_top = iep->ie_locy - top - MENU_BORDER - item_height / 2;
|
||||
|
||||
if (left != 0) stand_off = FALSE; /* Not on the edge */
|
||||
|
||||
/* Move the menu under the cursor so that it is outside/inside the item */
|
||||
mrect->r_left += stand_off ? STANDOFF : -STANDOFF;
|
||||
|
||||
left = mrect->r_left, top = mrect->r_top;
|
||||
|
||||
constrainrect(mrect, &menu_fs->fs_screenrect);
|
||||
|
||||
if (left != mrect->r_left || top != mrect->r_top) {
|
||||
iep->ie_locx -= left - mrect->r_left;
|
||||
iep->ie_locy -= top - mrect->r_top;
|
||||
(void) win_setmouseposition(menu_fs->fs_windowfd,
|
||||
iep->ie_locx, iep->ie_locy);
|
||||
}
|
||||
|
||||
*srect = *mrect; /* Remember total size of affected area */
|
||||
|
||||
if (menu->shadow_pr) {
|
||||
mrect->r_width -= MENU_SHADOW;
|
||||
mrect->r_height -= MENU_SHADOW;
|
||||
}
|
||||
|
||||
*irect = *mrect;
|
||||
if (stand_off) {
|
||||
irect->r_left -= STANDOFF;
|
||||
irect->r_width += STANDOFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Rop items into supplied pixrect
|
||||
*/
|
||||
Private void
|
||||
render_items(menu, std_image, pr, ncols, nrows)
|
||||
struct menu *menu;
|
||||
struct image *std_image;
|
||||
struct pixrect *pr;
|
||||
{
|
||||
register int top, left, n, i, j;
|
||||
register struct menu_item **mip;
|
||||
int item_width, item_height;
|
||||
register total_height, total_width;
|
||||
|
||||
item_width = std_image->width;
|
||||
item_height = std_image->height;
|
||||
mip = menu->item_list;
|
||||
|
||||
n = 0;
|
||||
total_height = item_height * nrows;
|
||||
total_width = item_width * ncols;
|
||||
if (menu->column_major) {
|
||||
for (j = left = 0; j < ncols; j++) {
|
||||
for (i = top = 0; i < nrows; i++) {
|
||||
if (++n > menu->nitems) break;
|
||||
if ((*mip)->inactive) {
|
||||
image_render((*mip)->image, std_image,
|
||||
LINT_CAST(IMAGE_REGION), pr, left, top,
|
||||
IMAGE_INACTIVE,
|
||||
0);
|
||||
} else {
|
||||
image_render((*mip)->image, std_image,
|
||||
LINT_CAST(IMAGE_REGION), pr, left, top,
|
||||
0);
|
||||
}
|
||||
if (menu->h_line || (*mip)->h_line) {
|
||||
image_vector(0,top+item_height,total_width-1,top+item_height);
|
||||
}
|
||||
if (menu->v_line || (*mip)->v_line) {
|
||||
image_vector(left+item_width,0,left+item_width,total_height-1);
|
||||
}
|
||||
top += item_height;
|
||||
mip++;
|
||||
}
|
||||
left += item_width;
|
||||
}
|
||||
} else {
|
||||
for (i = top = n = 0; i < nrows; i++) {
|
||||
for (j = left = 0; j < ncols; j++) {
|
||||
if (++n > menu->nitems) break;
|
||||
if ((*mip)->inactive)
|
||||
image_render((*mip)->image, std_image,
|
||||
LINT_CAST(IMAGE_REGION), pr, left, top,
|
||||
IMAGE_INACTIVE,
|
||||
0);
|
||||
else {
|
||||
image_render((*mip)->image, std_image,
|
||||
LINT_CAST(IMAGE_REGION), pr, left, top,
|
||||
0);
|
||||
}
|
||||
if (menu->h_line || (*mip)->h_line) {
|
||||
image_vector(0,top+item_height,total_width-1,top+item_height);
|
||||
}
|
||||
if (menu->v_line || (*mip)->v_line) {
|
||||
image_vector(left+item_width,0,left+item_width,total_height-1);
|
||||
}
|
||||
left += item_width;
|
||||
mip++;
|
||||
}
|
||||
top += item_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Handle recursive calls for pullright items
|
||||
*/
|
||||
Private int
|
||||
render_pullright(mi, subrect, menurect, itemrect, reenter, fd)
|
||||
register struct menu_item *mi;
|
||||
Rectnode *subrect;
|
||||
Rect *menurect, *itemrect;
|
||||
int fd;
|
||||
{
|
||||
register struct menu *m, *(*gen_proc)();
|
||||
struct rectnode menu_node, active_node;
|
||||
int status;
|
||||
|
||||
|
||||
if (gen_proc = mi->gen_pullright) {
|
||||
m = (gen_proc)(mi, MENU_DISPLAY);
|
||||
if (!m) {
|
||||
(void) fprintf(stderr,
|
||||
"menu_show: gen_proc failed to generate a pullright menu.\n");
|
||||
return -1;
|
||||
}
|
||||
mi->value = (caddr_t)m;
|
||||
} else {
|
||||
m = (struct menu *)LINT_CAST(mi->value);
|
||||
}
|
||||
|
||||
menu_node.rn_next = subrect, menu_node.rn_rect = *menurect;
|
||||
active_node.rn_next = &menu_node, active_node.rn_rect = *itemrect;
|
||||
|
||||
status =
|
||||
menu_render(m, mi->parent->dynamic_info, mi, &active_node, reenter, fd);
|
||||
|
||||
if (gen_proc)
|
||||
mi->value = (caddr_t)(gen_proc)(mi, MENU_DISPLAY_DONE);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
Private void
|
||||
paint_shadow(pr, shadow_pr, save_pr)
|
||||
register struct pixrect *pr, *shadow_pr, *save_pr;
|
||||
{
|
||||
if (shadow_pr) {
|
||||
/* Draw borders with shadows */
|
||||
(void) pr_rop(pr, 0, 0, pr->pr_width - MENU_SHADOW, MENU_BORDER,
|
||||
PIX_SET, PIXRECT_NULL, 0, 0);
|
||||
(void) pr_rop(pr, 0, MENU_BORDER,
|
||||
MENU_BORDER, pr->pr_height - MENU_SHADOW - 2*MENU_BORDER,
|
||||
PIX_SET, PIXRECT_NULL, 0, 0);
|
||||
(void) pr_rop(pr,
|
||||
pr->pr_width - MENU_SHADOW - MENU_BORDER, MENU_BORDER,
|
||||
MENU_BORDER, pr->pr_height - MENU_SHADOW - 2*MENU_BORDER,
|
||||
PIX_SET, PIXRECT_NULL, 0, 0);
|
||||
(void) pr_rop(pr, 0, pr->pr_height - MENU_SHADOW - MENU_BORDER,
|
||||
pr->pr_width - MENU_SHADOW, MENU_BORDER,
|
||||
PIX_SET, PIXRECT_NULL, 0, 0);
|
||||
/* Fill in with background */
|
||||
(void) pr_rop(pr, pr->pr_width - MENU_SHADOW, 0,
|
||||
MENU_SHADOW, pr->pr_height,
|
||||
PIX_SRC, save_pr, pr->pr_width - MENU_SHADOW, 0);
|
||||
(void) pr_rop(pr, 0, pr->pr_height - MENU_SHADOW,
|
||||
pr->pr_width - MENU_SHADOW, MENU_SHADOW,
|
||||
PIX_SRC, save_pr, 0, pr->pr_height - MENU_SHADOW);
|
||||
/* Rop shadow over background */
|
||||
(void) pr_replrop(pr, pr->pr_width - MENU_SHADOW, MENU_SHADOW,
|
||||
MENU_SHADOW, pr->pr_height - MENU_SHADOW,
|
||||
PIX_SRC /* |PIX_DST opaque shadow */, shadow_pr,
|
||||
pr->pr_width - MENU_SHADOW, MENU_SHADOW);
|
||||
(void) pr_replrop(pr, MENU_SHADOW, pr->pr_height - MENU_SHADOW,
|
||||
pr->pr_width - 2 * MENU_SHADOW, MENU_SHADOW,
|
||||
PIX_SRC /* |PIX_DST */, shadow_pr,
|
||||
MENU_SHADOW, pr->pr_height - MENU_SHADOW);
|
||||
} else {
|
||||
/* Draw borders without shadows */
|
||||
(void) pr_rop(pr, 0, 0, pr->pr_width, MENU_BORDER, PIX_SET,
|
||||
PIXRECT_NULL, 0, 0);
|
||||
(void) pr_rop(pr, 0, MENU_BORDER - 1,
|
||||
MENU_BORDER, pr->pr_height - 2*MENU_BORDER,
|
||||
PIX_SET, PIXRECT_NULL, 0, 0);
|
||||
(void) pr_rop(pr, pr->pr_width - MENU_BORDER - 1, MENU_BORDER - 1,
|
||||
MENU_BORDER, pr->pr_height - 2*MENU_BORDER, PIX_SET,
|
||||
PIXRECT_NULL, 0, 0);
|
||||
(void) pr_rop(pr, 0, pr->pr_height - MENU_BORDER - 1,
|
||||
pr->pr_width, MENU_BORDER,
|
||||
PIX_SET, PIXRECT_NULL, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Private void
|
||||
paint_menu(image, rect, shadow)
|
||||
register struct pixrect *image;
|
||||
register Rect *rect;
|
||||
register int shadow;
|
||||
{
|
||||
if (menu_fs->fs_pixwin->pw_pixrect->pr_depth > 1 && shadow) {
|
||||
rect->r_width -= MENU_SHADOW;
|
||||
rect->r_height -= MENU_SHADOW;
|
||||
}
|
||||
|
||||
(void) pw_preparesurface_full(menu_fs->fs_pixwin, rect, 1);
|
||||
(void) pw_write(menu_fs->fs_pixwin,
|
||||
rect->r_left, rect->r_top, rect->r_width, rect->r_height,
|
||||
PIX_SRC, image, 0, 0);
|
||||
|
||||
if (menu_fs->fs_pixwin->pw_pixrect->pr_depth > 1 && shadow) {
|
||||
Rect shadow_rect;
|
||||
|
||||
shadow_rect.r_left = rect->r_left + rect->r_width;
|
||||
shadow_rect.r_top = rect->r_top + MENU_SHADOW;
|
||||
shadow_rect.r_width = MENU_SHADOW;
|
||||
shadow_rect.r_height = rect->r_height;
|
||||
|
||||
(void) pw_preparesurface_full(menu_fs->fs_pixwin, &shadow_rect, 1);
|
||||
(void) pw_write(menu_fs->fs_pixwin,
|
||||
shadow_rect.r_left,
|
||||
shadow_rect.r_top,
|
||||
MENU_SHADOW, rect->r_height,
|
||||
PIX_SRC /* | PIX_DST opaque shadow */, image,
|
||||
image->pr_width - MENU_SHADOW, MENU_SHADOW);
|
||||
|
||||
shadow_rect.r_left = rect->r_left + MENU_SHADOW;
|
||||
shadow_rect.r_top = rect->r_top + rect->r_height;
|
||||
shadow_rect.r_width = rect->r_width - MENU_SHADOW;
|
||||
shadow_rect.r_height = MENU_SHADOW;
|
||||
(void)pw_preparesurface_full(menu_fs->fs_pixwin, &shadow_rect, 1);
|
||||
(void) pw_write(menu_fs->fs_pixwin,
|
||||
shadow_rect.r_left,
|
||||
shadow_rect.r_top,
|
||||
shadow_rect.r_width, MENU_SHADOW,
|
||||
PIX_SRC /* | PIX_DST opaque shadow */, image,
|
||||
MENU_SHADOW, image->pr_height - MENU_SHADOW);
|
||||
rect->r_width += MENU_SHADOW;
|
||||
rect->r_height += MENU_SHADOW;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Provide feedback directly to the pixwin.
|
||||
* Someday this should be a client settable option.
|
||||
*/
|
||||
Private void
|
||||
feedback(m, r, n, ncols, nrows, state)
|
||||
register struct menu *m;
|
||||
struct rect *r;
|
||||
int n, ncols, nrows;
|
||||
Menu_feedback state;
|
||||
{
|
||||
struct menu_item *mi = m->item_list[n - 1];
|
||||
int max_width = m->default_image.width;
|
||||
int max_height = m->default_image.height;
|
||||
|
||||
if (!mi->no_feedback && !m->feedback_proc && !mi->inactive) {
|
||||
int left, top;
|
||||
register int margin = m->default_image.margin;
|
||||
|
||||
n--; /* Convert to zero origin */
|
||||
left = (r->r_left + MENU_BORDER + margin
|
||||
+ (m->column_major ? n / nrows : n % ncols) * max_width);
|
||||
top = (r->r_top + MENU_BORDER + margin
|
||||
+ (m->column_major ? n % nrows : n / ncols) * max_height);
|
||||
(void) pw_writebackground(menu_fs->fs_pixwin, left, top,
|
||||
max_width - 2 * margin,
|
||||
max_height - 2 * margin,
|
||||
PIX_NOT(PIX_DST));
|
||||
} else if (m->feedback_proc)
|
||||
(m->feedback_proc)(mi, state); /* FIXME: Pass rect or region? */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Menu must be completely on the screen.
|
||||
*/
|
||||
Private void
|
||||
constrainrect(rconstrain, rbound)
|
||||
register struct rect *rconstrain, *rbound;
|
||||
{
|
||||
/*
|
||||
* Bias algorithm to have too big rconstrain fall off right/bottom.
|
||||
*/
|
||||
if (rect_right(rconstrain) > rect_right(rbound)) {
|
||||
rconstrain->r_left = rbound->r_left + rbound->r_width
|
||||
- rconstrain->r_width;
|
||||
}
|
||||
if (rconstrain->r_left < rbound->r_left) {
|
||||
rconstrain->r_left = rbound->r_left + SCREEN_MARGIN;
|
||||
}
|
||||
if (rect_bottom(rconstrain) > rect_bottom(rbound)) {
|
||||
rconstrain->r_top = rbound->r_top + rbound->r_height
|
||||
- rconstrain->r_height;
|
||||
}
|
||||
if (rconstrain->r_top < rbound->r_top) {
|
||||
rconstrain->r_top = rbound->r_top + SCREEN_MARGIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Clean up any client generated items
|
||||
*/
|
||||
Private void
|
||||
destroy_gen_items(menu)
|
||||
struct menu *menu;
|
||||
{
|
||||
register int nitems;
|
||||
register struct menu_item *mi, **mip;
|
||||
|
||||
nitems = menu->nitems;
|
||||
/* Give client a chance to clean up any generated items */
|
||||
for (mip = menu->item_list;mi = *mip, nitems--; mip++)
|
||||
if (mi->gen_proc) *mip = (mi->gen_proc)(mi, MENU_DISPLAY_DONE);
|
||||
}
|
||||
Reference in New Issue
Block a user