📄 menu.c
字号:
#ifndef lint#ifdef sccsstatic char sccsid[] = "@(#)menu.c 1.1 92/07/30 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_sizeimage_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 */staticimage_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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -