#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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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); }