diff options
Diffstat (limited to 'Build/source/texk/xdvik/gui/menu.c')
-rw-r--r-- | Build/source/texk/xdvik/gui/menu.c | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/gui/menu.c b/Build/source/texk/xdvik/gui/menu.c new file mode 100644 index 00000000000..575ef162f9b --- /dev/null +++ b/Build/source/texk/xdvik/gui/menu.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2003-2004 the xdvik development team + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/* + * Common code for Xaw and Motif menu bar creation. + */ + +#include "xdvi-config.h" +#include "xdvi.h" +#include "events.h" +#include "menu.h" +#include "util.h" + +#if defined(NEW_MENU_CREATION) || defined(MOTIF) + +#ifdef MOTIF +# include <Xm/RowColumn.h> +# include <Xm/ToggleB.h> +#else +# include <X11/Intrinsic.h> +# include <X11/Xatom.h> +# include <X11/StringDefs.h> +# include <X11/Xaw/Label.h> +#endif + + +/* translate string argument into corresponding buttonTypeT */ +static buttonTypeT +get_type(const char *str) +{ + if (strcmp(str, "PUSH") == 0) + return BT_PUSH; + else if (strcmp(str, "RADIO") == 0) + return BT_RADIO; + else if (strcmp(str, "CHECK") == 0) + return BT_CHECK; + else if (strcmp(str, "SEP") == 0) + return BT_SEP; + else + return BT_INVALID; +} + +static struct button_info *m_button_info = NULL; /* toplevel node of pulldown menu structure */ + + +static void +set_menu_info(void *val, XtActionProc proc, Boolean (*cmp)(), struct button_info *item) +{ + size_t i; + ASSERT(item != NULL, "item in set_menu_info musn't be NULL!"); + for (i = 0; i < item->size; i++) { + if ((item->elems[i].type == BT_RADIO || item->elems[i].type == BT_CHECK) + && item->elems[i].action != NULL + && item->elems[i].action->proc != NULL + && item->elems[i].action->proc == proc + && item->elems[i].action->param != NULL) { + Boolean on; + ASSERT(cmp != NULL, "comparison function musn't be NULL!"); + on = cmp(val, item->elems[i].action->param); +#ifdef MOTIF + ASSERT(item->elems[i].widget != 0, "Widget musn't be NULL!"); + XmToggleButtonSetState(item->elems[i].widget, on, False); +#else +#ifdef NEW_MENU_CREATION + ASSERT(item->elems[i].widget != 0, "Widget musn't be NULL!"); + xaw_set_button_state(item->elems + i, on); +#else + static Arg args = { XtNleftBitmap, (XtArgVal) 0 }; + if (on) + args.value = (XtArgVal) menu_check_bitmap; + else + args.value = (XtArgVal) menu_uncheck_bitmap; + XtSetValues(item->elems[i].widget, &args, 1); +#endif /* NEW_MENU_CREATION */ +#endif + } + if (item->elems[i].submenu != NULL) { /* invoke it recursively */ + set_menu_info(val, proc, cmp, item->elems[i].submenu); + } + } +} + + +/* set a menu according to val and the compare function cmp */ +void +set_menu(void *val, XtActionProc proc, Boolean (*cmp)()) +{ + /* non-standard cast function ptr -> void ptr */ + /* TRACE_GUI((stderr, "set_menu_info: %d, %p, %p", *(int *)val, (void *)proc, (void *)cmp)); */ + set_menu_info(val, proc, cmp, m_button_info); +} + +static void +initialize_menus(void) +{ + int use_gs; + int shrinkval; + + /* initialize tickmarks for all possible actions */ + use_gs = resource.postscript; +#ifdef PS_GS + if (!resource.useGS) + use_gs = 0; +#endif + + set_menu(&use_gs, Act_set_ps, check_int); + set_menu(&resource.gs_alpha, Act_set_gs_alpha, check_toggle); + set_menu(&resource.keep_flag, Act_set_keep_flag, check_toggle); + shrinkval = resource.pixels_per_inch / mane.shrinkfactor; + set_menu(&shrinkval, Act_shrink_to_dpi, check_int); + set_menu(&mane.shrinkfactor, Act_set_shrink_factor, check_int); + set_menu(&resource.use_tex_pages, Act_use_tex_pages, check_toggle); + set_menu((char *)resource.paper, Act_set_paper_landscape, check_paper_landscape); + set_menu((char *)resource.paper, Act_set_papersize, check_papersize); + set_menu(&resource.mouse_mode, Act_switch_mode, check_int); + set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert); +} + +static void +free_items(char **items, size_t len) +{ + size_t curr = 0; + while(curr < len) { + free(items[curr++]); + } + free(items); +} + +#if 0 +static void +show_items(char *descr, char **items, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) { + fprintf(stderr, "%s %d: |%s|\n", descr, i, items[i]); + } +} +#endif + +static void +add_info(struct button_info **info, buttonTypeT bt_type, + char mnemonic, const char *title, + const char *accelerator, struct xdvi_action *action) +{ +/* fprintf(stderr, "creating new item for info %p: |%s|\n", *info, title); */ + size_t idx = (*info)->size++; + (*info)->elems = xrealloc((*info)->elems, (*info)->size * sizeof *((*info)->elems)); + (*info)->elems[idx].title = xstrdup(title); + (*info)->elems[idx].type = bt_type; + if (accelerator == NULL || accelerator[0] == '\0') + (*info)->elems[idx].accelerator = NULL; + else + (*info)->elems[idx].accelerator = xstrdup(accelerator); + (*info)->elems[idx].mnemonic = mnemonic; + (*info)->elems[idx].action = action; + (*info)->elems[idx].widget = 0; + (*info)->elems[idx].submenu = NULL; +} + +static void +insert_items(struct button_info **info, char **items, size_t num_items, + const char *button_type, const char *accelerator, const char *action) +{ + const char ENTRY_SEP = '|'; + size_t i = 0; + size_t entry_len; + size_t entry_count = 0; + char **entry_items = NULL; + size_t idx; + + Boolean found = False; + Boolean have_error = False; + +/* fprintf(stderr, "------ insert_items called for |%s|, %p, |%s|\n", *items, *info, action); */ + + if (*items == NULL) { + /* should be a separator, which is treated as a special case since + there's no menu title: */ + if (strcmp (button_type, "SEP") == 0) + add_info(info, BT_SEP, '\0', "SEP", NULL, NULL); + else + XDVI_WARNING((stderr, "Shouldn't happen: items == NULL!")); + return; + } + + entry_len = strlen(items[0]); + entry_items = split_line(items[0], ENTRY_SEP, 0, entry_len, &entry_count); + + if (entry_count < 2) { + XDVI_WARNING((stderr, "Missing Mnemonic in button info `%s'\n", items[0])); + entry_count++; + entry_items = xrealloc(entry_items, entry_count * sizeof *entry_items); + entry_items[1] = xstrdup(""); + entry_items[2] = NULL; + } + + for (i = 0; i < (*info)->size; i++) { + if (strcmp(entry_items[0], (*info)->elems[i].title) == 0) { + found = true; + break; + } + } + + idx = i; + + if (!found) { /* new item, resize info and add this item */ + struct xdvi_action *my_action = NULL; + buttonTypeT my_type = BT_NONE; + + /* if it's a `leaf' in the menu hierarchy, compile the action and set the button type */ + if (num_items == 1) { +/* fprintf(stderr, "button_type: |%s|\n", button_type); */ + + char *fmt = strchr(entry_items[0], '$'); + if (fmt != NULL + && (fmt == entry_items[0] || (fmt > entry_items[0] && *(fmt - 1) != '\\')) + && (fmt[1] == '#' || fmt[1] == '%' ||fmt[1] == '_')) { + XDVI_WARNING((stderr, "Xdvik doesn't support format characters in button labels; " + "skipping button \"%s\"", items[0])); + have_error = True; + } + + if (strlen(action) == 0 + || (my_action = compile_action(action)) == NULL) { + XDVI_WARNING((stderr, "Invalid action \"%s\" for button \"%s\" (skipping this line).", + action, items[0])); + have_error = True; + } + + if ((my_type = get_type(button_type)) == BT_INVALID) { + XDVI_WARNING((stderr, "Invalid type \"%s\" for button \"%s\" (skipping this line).", + button_type, items[0])); + have_error = True; + } + } + + if (!have_error) { + add_info(info, my_type, entry_items[1][0], entry_items[0], accelerator, my_action); + } + } + free_items(entry_items, entry_count); + + if (num_items > 1 || (num_items == 1 && strcmp(button_type, "SEP") == 0)) { /* not a leaf, invoke recursivly for next level */ +/* fprintf(stderr, "invoking recursively for %d, %p\n", idx, (*info)->elems[idx].submenu); */ + if ((*info)->elems[idx].submenu == NULL) { /* submenu didn't exist yet, create it */ + struct button_info *new_submenu = xmalloc(sizeof *new_submenu); + new_submenu->elems = NULL; + new_submenu->size = 0; + (*info)->elems[idx].submenu = new_submenu; + } + insert_items(&((*info)->elems[idx].submenu), items + 1, num_items - 1, button_type, accelerator, action); + } +} + +static void +show_button_info(int depth, struct button_info *info) +{ + size_t i; + for (i = 0; i < info->size; i++) { + TRACE_GUI((stderr, "%*c-->%s; type=%d; mnemonic=%c; accel=%s; submenu=%p; w=%lu; action: %p", + depth, ' ', + info->elems[i].title, + info->elems[i].type, + info->elems[i].mnemonic, + info->elems[i].accelerator ? info->elems[i].accelerator : "<NULL>", + (void *)info->elems[i].submenu, + (unsigned long)info->elems[i].widget, + (void *)info->elems[i].action)); + if (info->elems[i].submenu != NULL) { + show_button_info(depth + 3, info->elems[i].submenu); + } + } +} + +static void +parse_button_translations(struct button_info **info) +{ + const char *curr_p, *end_p; + + const char LINE_SEP = ':'; + const char MENU_SEP = '>'; + + for (curr_p = resource.menu_translations; + curr_p != NULL && *curr_p != '\0'; + curr_p = end_p + 1) { + end_p = strchr(curr_p, '\n'); + if (end_p != NULL) { + size_t line_len = end_p - curr_p; + size_t line_count = 0; + char **line_items; + line_items = split_line(curr_p, LINE_SEP, 0, line_len, &line_count); +/* fprintf(stderr, "length of line: %d; %d items\n", line_len, line_count); */ +/* show_items("LINE", line_items, line_count); */ + if (line_count != 4) { /* error */ + XDVI_WARNING((stderr, "Wrong number of items (%lu) in translations line:\n\"%.*s\" " + "(skipping this line).\n", + (unsigned long)line_count, (int)line_len, curr_p)); + free_items(line_items, line_count); + continue; + } + else { /* split first elem into menu description */ + size_t menu_len = strlen(line_items[0]); + size_t menu_count = 0; + char **menu_items; + if (menu_len == 0) { /* error */ + XDVI_WARNING((stderr, "Menu description (1st item) mustn't be empty:\n\"%.*s\" " + "(skipping this line).\n", + (int)line_len, curr_p)); + free_items(line_items, line_count); + continue; + } + menu_items = split_line(line_items[0], MENU_SEP, 0, menu_len, &menu_count); +/* show_items(" MENU", menu_items, menu_count); */ + + insert_items(info, menu_items, menu_count, line_items[1], line_items[2], line_items[3]); + free_items(menu_items, menu_count); + } + free_items(line_items, line_count); + } + } + show_button_info(0, *info); +} + +/* + Top-level routine: creates the pulldown menu buttons for Motif and Xaw. + For Motif, sets *globals.widgets.menu_bar to the address of the new widget created, + for Xaw, sets *width to the width of the button panel created. +*/ +void +create_menu_buttons(Widget parent, +#ifdef MOTIF + Widget *menu_bar +#else + int *width +#endif + ) +{ +#ifdef MOTIF + Widget menu = 0; +#else /* MOTIF */ + Widget panel = 0; + Boolean first_time = True; + int menu_depth = 0; +#endif + size_t i; + + m_button_info = xmalloc(sizeof *m_button_info); + m_button_info->elems = NULL; + m_button_info->size = 0; + +#ifdef MOTIF + *menu_bar = XmCreateMenuBar(parent, "menuBar", NULL, 0); + parse_button_translations(&m_button_info); +/* menu = xm_create_menu(*menu_bar, m_button_info); */ + for (i = 0; i < m_button_info->size; i++) { + menu = xm_create_menu(*menu_bar, + m_button_info->elems[i].title, + m_button_info->elems[i].mnemonic, + m_button_info->elems[i].submenu); + } + if (menu != 0) { + XtVaSetValues(*menu_bar, XmNmenuHelpWidget, menu, NULL); + } +#else /* MOTIF */ + if (first_time) { + first_time = False; + xaw_initialize_menu_bitmaps(); + panel = xaw_create_menu_widgets(parent); + parse_button_translations(&m_button_info); + } + xaw_create_menu(m_button_info, panel, menu_depth, width); +#endif /* MOTIF */ + initialize_menus(); +} +#endif /* NEW_MENU_CREATION || MOTIF */ |