📄 menu.c
字号:
/* menu.c - proper 3D menus Copyright (C) 1996-2000 Paul Sheer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */#include <config.h>#include <stdio.h>#include <my_string.h>#include <stdlib.h>#include <stdarg.h>#include <X11/Intrinsic.h>#include "lkeysym.h"#include "stringtools.h"#include "app_glob.c"#include "coolwidget.h"#include "coollocal.h"#include "mad.h"extern struct look *look;CWidget *current_pulled_button = 0;int menu_grabbed = 0;int eh_menu (CWidget * w, XEvent * xevent, CEvent * cwevent);void CMenuSelectionDialog (CWidget * button);static void render_menu_button (CWidget * wdt);void destroy_menu (CWidget * w){ int i; if (!w) return; if (!w->menu) return; for (i = 0; i < w->numlines; i++) if (w->menu[i].text) free (w->menu[i].text); free (w->menu);}/* Gets y1 and y2 of the entry of a menu (i.e. a menu item). x1, y1, x2, y2 would describe the rectangle that encloses that entry, relative to the top left corner of the pulled-down menu window. */void get_menu_item_extents (int n, int j, struct menu_item m[], int *border, int *relief, int *y1, int *y2){ (*look->get_menu_item_extents) (n, j, m, border, relief, y1, y2);}/* Returns 0-(n-1) where n is the number of entries in that menu. Returns which menu item the pointer is in if (x,y) is the pointer pos. Returns -1 if out of bounds or between menu items. */int whereis_pointer (int x, int y, int w, int n, struct menu_item m[]){ int i, y1, y2, border, relief; for (i = 0; i < n; i++) { if (!m[i].text[2]) continue; get_menu_item_extents (n, i, m, &border, &relief, &y1, &y2); if (y >= y1) { if (y < y2 && x >= border && x < w - border) return i; } else break; } return -1;}int find_menu_hotkey (struct menu_item m[], int this, int num){ unsigned char used_keys[256]; int n = 0, j; if (!num) return 0; for (j = 0; j < num; j++) if (m[j].hot_key && j != this) used_keys[n++] = my_lower_case (m[j].hot_key); return find_letter_at_word_start ((unsigned char *) m[this].text + 1, used_keys, n);}void menu_draw (Window win, int w, int h, struct menu_item m[], int n, int light){ (*look->menu_draw) (win, w, h, m, n, light);}void render_menu (CWidget * w){ int n, border, relief, y1, y2, i; unsigned new_width, new_height; if (!w) return; n = w->numlines; get_menu_item_extents (n, n - 1, w->menu, &border, &relief, &y1, &y2); new_height = y2 + border; new_width = 0; for (i = 0; i < n; i++) { int t; t = CImageStringWidth (w->menu[i].text); t += CImageStringWidth ("W"); if (new_width < t) new_width = t; } new_width += (border + relief) * 2; if (w->width != new_width || w->height != new_height) { w->width = new_width; w->height = new_height; XResizeWindow (CDisplay, w->winid, w->width, w->height); }#if 0 if (w->y + w->height > HeightOfScreen (DefaultScreenOfDisplay (CDisplay))) { int y; y = HeightOfScreen (DefaultScreenOfDisplay (CDisplay)) - w->height; if (y < 0) y = 0; XMoveWindow (CDisplay, w->winid, w->x, y); }#endif#define BOUND_LIMITS 50 get_menu_item_extents (n, w->current, w->menu, &border, &relief, &y1, &y2); if (w->current >= 0) { if (y2 + w->y + BOUND_LIMITS >= HeightOfScreen (DefaultScreenOfDisplay (CDisplay))) CSetWidgetPosition (w->ident, w->x, HeightOfScreen (DefaultScreenOfDisplay (CDisplay)) - y2 - BOUND_LIMITS); if (y1 + w->y < BOUND_LIMITS) CSetWidgetPosition (w->ident, w->x, BOUND_LIMITS - y1); } w->droppedmenu->current = w->current; menu_draw (w->winid, w->width, w->height, w->menu, w->numlines, w->current);}/* gets a windows position relative to the origin if some ancestor windows, window can be of a widget or not */void CGetWindowPosition (Window win, Window ancestor, int *x_return, int *y_return){ CWidget *w = (CWidget *) 1; int x = 0, y = 0; Window root, parent, *children; unsigned int nchildren, width, height, bd, depth; *x_return = *y_return = 0; if (win == ancestor) return; for (;;) { if (w) w = CWidgetOfWindow (win); if (w) if (w->parentid == CRoot) w = 0; if (w) { parent = w->parentid; x = w->x; y = w->y; } else { if (!XQueryTree (CDisplay, win, &root, &parent, &children, &nchildren)) return; if (children) XFree ((char *) children); XGetGeometry (CDisplay, win, &root, &x, &y, &width, &height, &bd, &depth); } *x_return += x; *y_return += y; if (parent == ancestor || parent == CRoot) break; win = parent; }}void focus_stack_remove_window (Window w);void pull_up (CWidget * button){ if (!button) return; if (button->kind != C_MENU_BUTTON_WIDGET) return; if (button->droppedmenu) { current_pulled_button = 0; CDestroyWidget (button->droppedmenu->ident); button->droppedmenu = 0; } focus_stack_remove_window (button->winid); render_menu_button (button);}static CWidget *last_menu = 0;void CSetLastMenu (CWidget *button){ last_menu = button;}CWidget *CGetLastMenu (void){ return last_menu;}void menu_hand_cursor (Window win);static CWidget *pull_down (CWidget * button) /* must create a new widget */{ CWidget *menu; CWidget *sib; int width, height, n; int x, y; if(button->droppedmenu) return 0; sib = CGetLastMenu (); if (sib) if (strcmp (button->ident, sib->ident)) pull_up (sib); /* pull up last menu if different */ sib = button; while((sib = CNextFocus (sib)) != button) /* pull up any other sibling menus */ pull_up (sib); CSetLastMenu (button); n = button->numlines; CGetWindowPosition (button->winid, CRoot, &x, &y); height = 2; /* don't know what these are yet */ width = 2; x += button->firstcolumn; menu = CSetupWidget (catstrs (button->ident, ".pull", 0), CRoot, x, y + button->height, width, height, C_MENU_WIDGET, INPUT_KEY, COLOR_FLAT, 0); menu->options |= (button->options & MENU_AUTO_PULL_UP); menu_hand_cursor (menu->winid);/* no destroy 'cos gets ->menu gets destroyed by other menu-button-widget */ menu->numlines = n; menu->menu = button->menu; menu->eh = eh_menu; menu->droppedmenu = button; button->droppedmenu = menu; current_pulled_button = button; render_menu_button (button); return menu;}void CPullDown (CWidget * button){ pull_down (button);}CWidget *get_pulled_menu (void){ return current_pulled_button;}void CPullUp (CWidget * button){ pull_up (button);}int execute_item (CWidget * menu, int item){ int r = 0; char ident[33]; strcpy (ident, menu->ident); menu->droppedmenu->current = item; XUngrabPointer (CDisplay, CurrentTime); XUnmapWindow (CDisplay, menu->winid); if (item >= 0 && item < menu->numlines) if (menu->menu[item].call_back) { menu->droppedmenu->current = item; (*(menu->menu[item].call_back)) (menu->menu[item].data); r = 1; } menu = CIdent (ident); /* menu may not exists anymore */ if (menu) pull_up (menu->droppedmenu); CFocusLast (); return r;}static void render_menu_button (CWidget * wdt){ (*look->render_menu_button) (wdt);}int is_focus_change_key (KeySym k, int command);int is_focus_prev_key (KeySym k, int command, unsigned int state);int eh_menubutton (CWidget * w, XEvent * xevent, CEvent * cwevent){ int c; CWidget *f; switch (xevent->type) { case FocusOut: case FocusIn: render_menu_button (w); CExposeWindowArea (w->parentid, 0, w->x - WIDGET_FOCUS_RING, w->y - WIDGET_FOCUS_RING, w->width + WIDGET_FOCUS_RING * 2, w->height + WIDGET_FOCUS_RING * 2); break; case KeyPress: c = CKeySym (xevent); if (!w->droppedmenu) { if (c == XK_space || c == XK_Return || c == XK_KP_Enter || cwevent->command == CK_Down) { CMenuSelectionDialog (w); return 1; } } if (c == XK_Escape) { pull_up (w); CFocusLast (); return 1; } if (cwevent->command == CK_Up && w->droppedmenu) { if (w->droppedmenu->numlines < 1) return 1; if (w->droppedmenu->current == -1) w->droppedmenu->current = 0; do { w->droppedmenu->current = (w->droppedmenu->current + w->droppedmenu->numlines - 1) % w->droppedmenu->numlines; } while (w->droppedmenu->menu[w->droppedmenu->current].text[2] == 0); render_menu (w->droppedmenu); return 1; } if (cwevent->command == CK_Down && w->droppedmenu) { if (w->droppedmenu->numlines < 1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -