diff options
Diffstat (limited to 'Build/source/texk/xdvik/gui/pagesel.c')
-rw-r--r-- | Build/source/texk/xdvik/gui/pagesel.c | 1591 |
1 files changed, 1591 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/gui/pagesel.c b/Build/source/texk/xdvik/gui/pagesel.c new file mode 100644 index 00000000000..b3db730e481 --- /dev/null +++ b/Build/source/texk/xdvik/gui/pagesel.c @@ -0,0 +1,1591 @@ +/* + * Page selector for xdvi + * + * Copyright (c) 2001-2004 xdvik development team + * + * This code is derived from the page selector in xdvik-j, and + * parts of it are Copyright (c) 1993, 1995 + * MATSUURA Syun syun@fuka.info.waseda.ac.jp + * HIRAHARA Atsushi hirahara@fuka.info.waseda.ac.jp + * ONO Kouichi onono@fuka.info.waseda.ac.jp + * All rights reserved. + * + * + * (SU: I was unsure how to interpret the `All rights reserved' in the + * previous line, so emailed Ono Kouichi about this. Here's a + * verbatim quote of the relevant part of his answer (which was CC'ed + * to Hirahara Atsushi - all three of them had left Waseda university + * around '95): + * + * You can modify, embed, copy and distribute a part of or the + * entire of our source code when you specify our copyright in your + * xdvik version. + * + * IANAL, but I think this is compatible with the X consortium + * license, which follows.) + * + * 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. + * + */ + +/* + BUGS: + + - with Xaw, the highlighting for the selected page (XawListHighlight) + vanishes when mouse is dragged outside the widget and then released + (but the respective page is selected, which is IMHO the desired behaviour). + + - with Xaw, scrolling the list with PgUp/PgDown until the current page + gets `out of focus' should un-highlight the current page number + + - The ASCII-based marks are *ugly*. Pixmaps (for the marked state) + would be better. The viewer gv has one (but it's Xaw only). Some + file directory widgets like + e.g. http://ftp.xfree86.org/pub/X.Org/contrib/widgets/ListTree-3.0b3.tar.gz + also have facilities for that, but most suffer from other + inadequacies (e.g. no such ting as browseSelection) and all kinds + of bitrot ... Another alternative would be using XmContainer + (see e.g. the `filemanager' example in demos/programs/filemanagers + in the openmotif distribution), but that's available for Motif >= 2.1 only. + +*/ + +#include "xdvi-config.h" +#include "xdvi.h" + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Shell.h> + +#include "xm_toolbar.h" +#include "xm_menu.h" +#include "xaw_menu.h" + +#include "x_util.h" + +#ifdef MOTIF +# include <Xm/Xm.h> +# include <Xm/List.h> +# include <Xm/ScrollBar.h> /* for XmScrollBarGetValues */ +#else /* MOTIF */ +# include <X11/Xaw/Dialog.h> +# include <X11/Xaw/Cardinals.h> +# include <X11/Xaw/Command.h> +# include <X11/Xaw/List.h> +# include <X11/Xaw/Viewport.h> +#endif /* MOTIF */ + +#include "message-window.h" +#include "pagesel.h" +#include "util.h" +#include "string-utils.h" +#include "dvi-init.h" +#include "statusline.h" +#include "events.h" +#include "print-dialog.h" +#include "search-internal.h" +#include "pagehist.h" + +#define PAGENUMLEN 128 +#define SCROLL_LIST_SCROLLBAR 0 + +#ifndef MAX_PAGE +# define MAX_PAGE (1024) +#endif /* MAX_PAGE */ + +#define LONGESTPAGENUM 55 + + +/* for saving the GC of the pagelist widget + (when un-highlighting items in highlight_page_callback, and + drawing the `current' marker) +*/ +static struct page_gc { + GC fore; + GC back; +} m_page_gc; + +#define MOTIF_IDX_OFFSET 1 /* motif index starts at 1, not 0 */ +#if !defined(LESSTIF_VERSION) +static Boolean my_list_pos_to_bounds(Widget widget, int idx, Position *x, Position *y, Dimension *w, Dimension *h); +static void refresh_highlight_marker(Widget widget, GC gc, Position x, Position y, Dimension w, Dimension h); +#endif /* !defined(LESSTIF_VERSION) */ + + + +#ifdef MOTIF + +/* make button2 mark instead of drag&drop */ +static void xm_list_set_mark(Widget widget, XEvent *event, String *params, Cardinal *num_params); +static void xm_list_drag_mark(Widget widget, XEvent *event, String *params, Cardinal *num_params); +static XtActionsRec CustomListActions[] = { + { "ListSetMark", xm_list_set_mark }, + { "ListDragMark", xm_list_drag_mark }, +}; +static char *motif_custom_translations = + "#override \n" + "s <Btn2Down>: ListDragMark(ListButtonMotion)\n" + "<Btn2Motion>: ListSetMark(ListButtonMotion)\n" + "<Btn2Up>: ListSetMark(ListButtonMotion)\n" + "<Btn2Down>: ListSetMark(ListButtonMotion)\n" +/* /\* "s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginExtend)\n" *\/ */ +/* /\* "s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndExtend)\n" *\/ */ +/* /\* "~c ~s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginSelect)\n" *\/ */ +/* /\* "~c ~s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndSelect)\n" *\/ */ +/* /\* "c ~s ~m ~a <Btn2Down>: ListMyProcessBtn2(ListBeginToggle)\n" *\/ */ +/* /\* "c ~s ~m ~a <Btn2Up>: ListMyProcessBtn2(ListEndToggle)\n" *\/ */ +/* /\* "c ~s ~m a <Btn2Down>: ListProcessDrag()\n" *\/ */ +/* /\* "~c s ~m a <Btn2Down>: ListProcessDrag()\n" *\/ */ +; + +#define LIST_WIDGET page_list +/* motif pagenumber is a string */ +static const char* const pageno_format = "%c %s "; + +#else /* MOTIF */ + +static int view_y; +extern Widget panel_widget; +static Widget list_widget = NULL; +static Widget viewport = NULL; +#define LIST_WIDGET list_widget +/* Xaw pagenumber is an integer, and we need to left-pad it */ +static const char* const pageno_format = "%c %*d "; + +static int xaw_maybe_scroll_pagelist(int new_page, Boolean force_recenter, int old); + +#define REDRAW_CURRENT_MARKER_HACK 1 + + +/* + The following hack tries to address the following 2 bugs with the + self-made page highlighting marker: + + - the marker overlaps with the ordinary XawListHighlight marker; + when un-highlighting a page, 1 pixel (vertically) at the edge of + the ordinary marker is overdrawn. + + - When the XawListHighlight crosses the self-drawn rectangle, + the vertical bars remain visible, but the horizontal bars + are erased. + + The hack just redraws the appropriate items whenever one of + the above can happen, i.e. when the two markers are 2 or less + pages apart from each other. +*/ +#if REDRAW_CURRENT_MARKER_HACK +/* Store index of currently marked (with our own marker) list + item, or -1 if none is marked. */ +static int g_current_highlighted = -1; + +/* redraw the default Xaw list highlight (XawListHighlight()) */ +static void +xaw_maybe_redraw_highlight(int idx) +{ + XawListReturnStruct *ret; + int high; + + if (LIST_WIDGET == NULL) + return; + + ret = XawListShowCurrent(LIST_WIDGET); + high = ret->list_index; + if (high != XAW_LIST_NONE && abs(idx - (high + MOTIF_IDX_OFFSET)) <= 2) { + /* re-highlight it */ + XawListHighlight(LIST_WIDGET, high); + } + g_current_highlighted = -1; +} + +/* redraw our own rectangle highlight marker: */ +static void +xaw_maybe_redraw_current_marker(int idx) +{ + Position x, y; + Dimension w, h; + +/* fprintf(stderr, "idx: %d, high: %d; diff: %d\n", idx + MOTIF_IDX_OFFSET, g_current_highlighted, */ +/* abs(idx + MOTIF_IDX_OFFSET - g_current_highlighted)); */ + if (abs((idx + MOTIF_IDX_OFFSET) - g_current_highlighted) <= 2 + && my_list_pos_to_bounds(LIST_WIDGET, g_current_highlighted, &x, &y, &w, &h)) { + refresh_highlight_marker(LIST_WIDGET, m_page_gc.fore, x, y, w, h); + } +} +#endif /* REDRAW_CURRENT_MARKER_HACK */ + +#endif /* MOTIF */ + +/* + * Table of page offsets in DVI file, indexed by page number - 1, + * marked pages, and page sizes. + * Initialized in prepare_pages(). + */ +struct page_index { + long offset; + int number; + Boolean marked; + unsigned int pw, ph; /* page size */ + unsigned int ww, wh; /* window size */ +}; + +struct page_index_info { + struct page_index *index; /* above struct */ + size_t index_size; /* size of currently allocated index */ + char **page_labels; /* label strings */ +}; + +static struct page_index_info page_info; + +/* access functions used by dvi-draw.c and dvi-init.c */ +long +pageinfo_get_offset(int page) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); +/* fprintf(stderr, "offset for page %d is %ld\n", page, page_info.index[page].offset); */ + return page_info.index[page].offset; +} + +/* access functions used by dvi-draw.c and dvi-init.c */ +unsigned int +pageinfo_get_page_width(int page) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + return page_info.index[page].pw; +} + +unsigned int +pageinfo_get_page_height(int page) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + return page_info.index[page].ph; +} + +unsigned int +pageinfo_get_window_width(int page) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + return page_info.index[page].ww; +} + +unsigned int +pageinfo_get_window_height(int page) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + return page_info.index[page].wh; +} + +void +pageinfo_set_page_width(int page, unsigned int width) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + page_info.index[page].pw = width; +} + +void +pageinfo_set_page_height(int page, unsigned int height) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + page_info.index[page].ph = height; +} + +void +pageinfo_set_window_width(int page, unsigned int width) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + page_info.index[page].ww = width; +} + +void +pageinfo_set_window_height(int page, unsigned int height) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + page_info.index[page].wh = height; +} + +int +pageinfo_get_number(int page) +{ + ASSERT(page >= 0 && page < (int)page_info.index_size, "Page number out of range"); + return page_info.index[page].number; +} + +/* search for page with TeX number `number', and return its index, or -1 if it's not found. */ +int +pageinfo_get_index_of_number(int number) +{ + size_t i; + for (i = 0; i < page_info.index_size - 1; i++) { + if (number == page_info.index[i].number) + return i; + } + return -1; +} + +void +pageinfo_set_offset(int index, long offset) +{ + ASSERT(index >= 0 && index < (int)page_info.index_size, ""); + page_info.index[index].offset = offset; +} + +void +pageinfo_set_number(int index, int number) +{ + ASSERT(index >= 0 && index < (int)page_info.index_size, ""); + page_info.index[index].number = number; +} + +void +pageinfo_allocate(int total_pages) +{ + int i; + page_info.index = xmalloc(total_pages * sizeof *(page_info.index)); + for (i = 0; i < total_pages; i++) { + page_info.index[i].marked = False; + } + /* following initializations are handled by the respective Motif/Xaw functions */ + page_info.page_labels = NULL; + page_info.index_size = total_pages; +} + +/* + Deallocate page_info. NOTE: We mustn't free the page_labels here, + since the page list might survive quite some time (e.g. while fonts + for the new file are being generated) and needs the labels. +*/ +void +pageinfo_deallocate(void) +{ + free(page_info.index); + page_info.index_size = 0; + page_info.index = NULL; +} + +#ifdef MOTIF +void +toggle_pagelist(void) +{ + Dimension curr_w, curr_x; + XtVaGetValues(globals.widgets.main_window, + XmNwidth, &curr_w, + XmNx, &curr_x, + NULL); + + if ((resource.expert_mode & XPRT_SHOW_PAGELIST) != 0) { + XtManageChild(XtParent(page_list)); + XtManageChild(page_list); + + curr_x += resource.pagelist_width; + curr_w -= resource.pagelist_width; + XtVaSetValues(globals.widgets.main_window, + XtNwidth, curr_w, + XtNx, curr_x, + XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, XtParent(page_list), + NULL); + } + else { + XtUnmanageChild(XtParent(page_list)); + XtUnmanageChild(page_list); + + curr_x -= resource.pagelist_width; + curr_w += resource.pagelist_width; + XtVaSetValues(globals.widgets.main_window, + XmNwidth, curr_w, + XmNx, curr_x, + XmNleftAttachment, XmATTACH_FORM, + NULL); + } + +#if defined(NEW_MENU_CREATION) || defined(MOTIF) + set_menu(&resource.expert_mode, Act_set_expert_mode, check_resource_expert); +#else + set_show_pagelist_option(); +#endif +} +#endif + + +Boolean +pageinfo_have_marked_pages(void) +{ + int i; + for (i = 0; i < total_pages; i++) { + if (page_info.index[i].marked) { + return True; + } + } + return False; +} + + +/* return True if page i is marked, False else */ +Boolean +pageinfo_is_marked(int i) +{ + ASSERT(i <= (int)page_info.index_size, ""); + return page_info.index[i].marked; +} + + +typedef enum { SCROLL_UP, SCROLL_DOWN, CLICK } saveCmdT; + + +static void internal_process_button2(Widget widget, XEvent *event); +static int get_item_index(Widget w, int mouse_y); + +static int +get_page_size(void) +{ + int offset = 0; + int min_page = 0; + int max_page = 0; + int min_pageno_len = 0; + int max_pageno_len = 0; + int i; + + if (globals.dvi_file.bak_fp == NULL) + return 0; + + for (i = 0; i < total_pages; i++) { + max_page = MAX(page_info.index[i].number, max_page); + min_page = MIN(page_info.index[i].number, min_page); + } + + if (min_page >= 0) { + offset = 0; /* plus symbol is hidden */ + } else { + offset = 1; /* offset for minus symbol */ + min_page = -min_page; + } + for (min_pageno_len = offset; min_page > 0; + min_page /= 10, min_pageno_len++); + + if (max_page >= 0) { + offset = 0; /* plus symbol is hidden */ + } else { + offset = 1; /* offset for minus symbol */ + max_page = -max_page; + } + for (max_pageno_len = offset; max_page > 0; + max_page /= 10, max_pageno_len++); + + return MAX(min_pageno_len, max_pageno_len); + /* Plus 1 for minus symbol */ +} + +#if !defined(LESSTIF_VERSION) +/* draw or erase highlight marker at position x, y with widht w an height h, + using suitable offsets (for sake of consistency of the latter, and because + of the differences Xaw/Motif, this is a separate function). + */ +static void +refresh_highlight_marker(Widget widget, GC gc, + Position x, Position y, Dimension w, Dimension h) +{ + XDrawRectangle(XtDisplay(widget), XtWindow(widget), gc, +#ifdef MOTIF + x + 1, y + 1, w - 3, h - 3 +#else + x + 2, y, w - 1, h - 1 +#endif + ); +} +#endif /* !defined(LESSTIF_VERSION) */ + +#ifndef MOTIF + +/* update (redisplay) the list, saving the currently highlighted item. + * This is invoked whenever marking the page, and the re-construction of the + * entire list causes considerable flicker; but I guess that's unavoidable + * with the current simplistic labelling scheme (with changing the list items + * themselves). Gv does this considerably better (using custom widgets). + */ +static void +xaw_update_list(void) +{ + static int pagelist_width = -1; + static int total_pages_bak = -1; + + XawListReturnStruct *ret; + int idx, button_width; + + if (pagelist_width == -1 || total_pages != total_pages_bak) { + pagelist_width = xaw_get_pagelist_size(); + total_pages_bak = total_pages; + } + + /* save selected item */ + ret = XawListShowCurrent(LIST_WIDGET); + idx = ret->list_index; + button_width = get_panel_width() - 2 * (resource.btn_side_spacing + resource.btn_border_width); + /* delete and re-create list */ + ASSERT(total_pages <= (int)page_info.index_size, ""); + XawListChange(LIST_WIDGET, page_info.page_labels, 0, + MAX(button_width, pagelist_width), False); + /* restore selected item */ + if (idx != XAW_LIST_NONE) { + XawListHighlight(LIST_WIDGET, idx); + } +} + +/* + return height of a row in the list widget, and the initial offset of XtNinternalHeight + in parameters row_height and internal_h +*/ +static void +xaw_get_row_height(Widget w, Dimension *row_height, Dimension *internal_h) +{ + Dimension row_space; + XFontStruct *font; + Arg arglist[5]; + int i = 0; + + if (w == NULL || !XtIsRealized(w)) + return; + + XtSetArg(arglist[i], XtNfont, &font); ++i; + XtSetArg(arglist[i], XtNrowSpacing, &row_space); ++i; + XtSetArg(arglist[i], XtNinternalHeight, internal_h); i++; + XtGetValues(w, arglist, i); + *row_height = font->max_bounds.ascent + font->max_bounds.descent + row_space; +} + +/* + * Get pagelist width. + */ +int +xaw_get_pagelist_size(void) +{ + Widget w; + XFontStruct *font; + + w = XtVaCreateWidget("list", listWidgetClass, globals.widgets.top_level, NULL); + XtVaGetValues(w, XtNfont, &font, NULL); + XtDestroyWidget(w); + + /* have space for max. pageno + space + current-marker, + plus a few pixels for right margin */ + return (get_page_size() + 2) * get_avg_font_width(font) + 6; +} + +/* auto-scroll pagelist when mouse-1 is down and moved above top or below bottom of + page list. +*/ +static void +xaw_drag_page_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont) +{ + int y, idx, actual_idx = 0; + + UNUSED(data); + UNUSED(cont); + + if (event->xany.type == ButtonPress || ((event->xbutton.state & Button1Mask) == 0)) + return; + if (event->xany.type == MotionNotify) + y = (int)event->xmotion.y; + else + y = (int)event->xbutton.y; + + idx = get_item_index(widget, y); + + if (idx <= 0) { + idx = 1; + } + else if (idx > total_pages) { + idx = total_pages; + } + + actual_idx = xaw_maybe_scroll_pagelist(idx, False, actual_idx); + XawListHighlight(LIST_WIDGET, idx - MOTIF_IDX_OFFSET); + +/* if (event->xany.type == ButtonRelease) { */ +/* fprintf(stderr, "1\n"); */ +/* page_history_insert(idx - MOTIF_IDX_OFFSET); */ +/* goto_page(idx - MOTIF_IDX_OFFSET, resource.keep_flag ? NULL : home); */ +/* search_signal_page_changed(); */ +/* } */ +} + +static void +xaw_SendReportProc(Widget w, XtPointer closure, XtPointer call_data) +{ + XawPannerReport *rep = (XawPannerReport *) call_data; + + UNUSED(w); + UNUSED(closure); + + view_y = rep->slider_y; +} + +#endif /* not MOTIF */ + + + +/* returns the index of the current item in `Motif'-style, i.e. first item has index 1, not 0 */ +static int +get_item_index(Widget w, int mouse_y) +{ +#ifdef MOTIF + return XmListYToPos(w, mouse_y); +#else + Dimension row_height, internal_height; + + xaw_get_row_height(w, &row_height, &internal_height); + return (mouse_y - internal_height) / row_height + MOTIF_IDX_OFFSET; +#endif +} + +#if !defined(LESSTIF_VERSION) +/* idx is Motif-style index, i.e. 1 for 1st item, not 0 */ +static Boolean +my_list_pos_to_bounds(Widget widget, int idx, Position *x, Position *y, Dimension *w, Dimension *h) +{ +#ifdef MOTIF + Position x1, y1; + Dimension w1, h1; + if (XmListPosToBounds(widget, idx, &x1, &y1, &w1, &h1)) { + *x = x1; + *y = y1; + *w = w1; + *h = h1; + return True; + } + return False; +#else + Dimension row_height, internal_height; + /* FIXME: Remove this hard-coded offset! */ + const int X_OFFSET = 9; + const int RULE_OFFSET = 2; + + if (idx <= 0 || idx > total_pages) { + return False; + } + + if (viewport != NULL && XtIsRealized(viewport)) + XtVaGetValues(viewport, XtNx, x, NULL); + xaw_get_row_height(widget, &row_height, &internal_height); + XtVaGetValues(widget, XtNwidth, w, NULL); + + *x -= X_OFFSET; + *y = row_height * idx + internal_height - row_height - 1; + *w -= RULE_OFFSET; + *h = row_height + RULE_OFFSET; + + return True; +#endif +} +#endif /* !defined(LESSTIF_VERSION) */ + +/* it seems that in order to support scrolling of the page list with wheel mice, + we need to program this explicitly. + */ +static void +wheel_scroll_list_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont) +{ + int button = event->xbutton.button; + + UNUSED(widget); + UNUSED(data); + UNUSED(cont); + + if (event->xany.type == ButtonPress && (button == 4 || button == 5)) { +#if SCROLL_LIST_SCROLLBAR + Widget vert = XtNameToWidget(viewport, "vertical"); + static Dimension row_height = 0, dummy = 0; + int diff_y = 0; + + if (row_height == 0) + xaw_get_row_height(LIST_WIDGET, &row_height, &dummy); + + if (vert == NULL) { + XDVI_WARNING((stderr, "Couldn't get name of pagelist viewport widget!")); + return; + } + if (button == 5) { + diff_y = row_height; + } + else { + diff_y = -row_height; + } + XtCallCallbacks(vert, XtNscrollProc, (XtPointer)diff_y); +#else + int pageno = current_page; + if (button == 5) { + if (current_page >= total_pages - 1) { + XBell(DISP, 0); + statusline_print(STATUS_SHORT, "Last page of DVI file"); + return; + } + pageno++; + } + else { + if (current_page == 0) { + XBell(DISP, 0); + statusline_print(STATUS_SHORT, "First page of DVI file"); + return; + } + pageno--; + } + goto_page(check_goto_page(pageno), resource.keep_flag ? NULL : home, False); + search_signal_page_changed(); +#endif + } +} + + +#if !defined(LESSTIF_VERSION) +/* draw a hightlight rectangle around the page the mouse is currently over, to + make e.g. marking easier. + */ +static void +highlight_page_callback(Widget widget, XtPointer data, XEvent *event, Boolean *cont) +{ + int curr_idx = get_item_index(widget, event->xmotion.y); + Position x, y; + Dimension w, h; + static int idx_bak = -1; + + UNUSED(data); + UNUSED(cont); + + switch(event->xany.type) { + case ButtonPress: + case ButtonRelease: + case MotionNotify: + /* might need to un-highlight previous one */ + if (idx_bak >= 0 && idx_bak != curr_idx + && my_list_pos_to_bounds(widget, idx_bak, &x, &y, &w, &h)) { +/* fprintf(stderr, "index: %d, %d, h: %d, w: %d\n", x, y, h, w); */ + refresh_highlight_marker(widget, m_page_gc.back, x, y, w, h); +#if REDRAW_CURRENT_MARKER_HACK + xaw_maybe_redraw_highlight(curr_idx); +#endif + } + idx_bak = curr_idx; + /* redraw unless out of bounds (when pagelist is shorter than view area) */ + if (my_list_pos_to_bounds(widget, curr_idx, &x, &y, &w, &h)) { + refresh_highlight_marker(widget, m_page_gc.fore, x, y, w, h); +#if REDRAW_CURRENT_MARKER_HACK + g_current_highlighted = curr_idx; +#endif + } + break; + case LeaveNotify: + /* this might look overly complicated, but is neccessary to cover all + cases of 1-pixel movement up/down before leaving the list, or no + movement at all before leaving it. */ + if ((idx_bak >= 0 && idx_bak != curr_idx && my_list_pos_to_bounds(widget, idx_bak, &x, &y, &w, &h)) + || my_list_pos_to_bounds(widget, curr_idx, &x, &y, &w, &h)) { + refresh_highlight_marker(widget, m_page_gc.back, x, y, w, h); +#if REDRAW_CURRENT_MARKER_HACK + xaw_maybe_redraw_highlight(curr_idx); +#endif + } + break; + default: + break; + } +} +#endif /* !defined(LESSTIF_VERSION) */ + +/* + * invoked on Button-1 Down. + */ +static void +select_page_callback(Widget w, XtPointer closure, XtPointer call_data) +{ +#ifdef MOTIF + XmListCallbackStruct *cbs = (XmListCallbackStruct *) call_data; + int new = cbs->item_position; + + UNUSED(w); + UNUSED(closure); + + maybe_scroll_pagelist(new - MOTIF_IDX_OFFSET, False); + page_history_insert(new - MOTIF_IDX_OFFSET); + goto_page(new - MOTIF_IDX_OFFSET, resource.keep_flag ? NULL : home, False); +#else + XawListReturnStruct *item = (XawListReturnStruct *) call_data; + int new = item->list_index; + + UNUSED(w); + UNUSED(closure); + + if (globals.debug & DBG_EVENT) + fprintf(stderr, "got: button-1 for `%d'\n", new); + +#if 0 + fprintf(stderr, "select page: %d\n", new); +#endif + maybe_scroll_pagelist(new, False); + page_history_insert(new); + goto_page(new, resource.keep_flag ? NULL : home, False); +#endif + search_signal_page_changed(); +} + + +static void +init_pagelabels(int start, int end) +{ + int i; + char s[PAGENUMLEN]; +#if 0 + fprintf(stderr, "===== init_pagelabels from %d to %d\n", start, end); +#endif + ASSERT(end < (int)page_info.index_size, ""); + + page_info.page_labels = xrealloc(page_info.page_labels, sizeof *(page_info.page_labels) * (end + 2)); + for (i = start; i < end; i++) { + if (page_info.index[i].marked) + sprintf(s, "* %*d ", get_page_size(), + resource.use_tex_pages ? page_info.index[i].number : i + 1); + else + sprintf(s, " %*d ", get_page_size(), + resource.use_tex_pages ? page_info.index[i].number : i + 1); + + page_info.page_labels[i] = xstrdup(s); + } + page_info.page_labels[i] = NULL; /* terminate - important for creating the widget. */ +} + + +#ifdef MOTIF + + +static int +xm_get_top_visible(int start) +{ + int top = start; + while (top < total_pages && !XmListPosToBounds(LIST_WIDGET, top, NULL, NULL, NULL, NULL)) + top++; + return top; +} + +static int +xm_get_bottom_visible(int start) +{ + int bot = start; + while (bot < total_pages && XmListPosToBounds(LIST_WIDGET, bot, NULL, NULL, NULL, NULL)) + bot++; + bot--; + return bot; +} + +/* Scroll pagelist down or up if needed, and update top_visible and + bot_visible. List is always scrolled so that 1 element is still + visible below or above pointer, to make it possible to flip through + document by repeatedly clicking on first/last. + */ +static void +xm_maybe_scroll_pagelist(int current, saveCmdT curr_cmd, int *top_visible, int *bot_visible) +{ +#if 0 + fprintf(stderr, "topmost visible: %d, bottom: %d, current: %d, total: %d\n", + top_visible, bottom_visible, current, total_pages); +#endif + + if (current < *top_visible && curr_cmd != SCROLL_DOWN) { + XmListSetPos(LIST_WIDGET, + current < 1 + ? 1 + : current); + (*top_visible)--; + (*bot_visible)--; + } + else if (current + MOTIF_IDX_OFFSET >= *bot_visible && curr_cmd != SCROLL_UP) { + XmListSetBottomPos(LIST_WIDGET, + current + MOTIF_IDX_OFFSET >= total_pages + ? current + MOTIF_IDX_OFFSET + : current + MOTIF_IDX_OFFSET + 1); + (*top_visible)++; + (*bot_visible)++; + } +} + +static void +xm_set_page_labels(void) +{ + int i; + char buf[PAGENUMLEN]; + + XmString *motif_page_labels = xmalloc((total_pages + 2) * sizeof *motif_page_labels); + + for (i = 0; i < total_pages; ++i) { + sprintf(buf, pageno_format, ' ', page_info.page_labels[i]); + motif_page_labels[i] = XmStringCreateLocalized(buf); + } + XmListDeleteAllItems(LIST_WIDGET); + XmListAddItems(LIST_WIDGET, motif_page_labels, total_pages, 0); + + XmListSelectPos(LIST_WIDGET, current_page + MOTIF_IDX_OFFSET, False); + for (i = 0; i < total_pages; ++i) { + XmStringFree(motif_page_labels[i]); + } + free(motif_page_labels); +} + +static void +xm_toggle_label(Widget widget, int idx, Boolean update) +{ + /* TODO: use `update' to update all labels at once when toggling multiple */ + XmString str; + char *mark_font, buf[128]; + + if (widget == NULL) + return; + + UNUSED(update); + +/* ensure_labelinfo_size(idx); */ + ASSERT(idx < (int)page_info.index_size, ""); + if (!page_info.index[idx].marked) { + sprintf(buf, pageno_format, '*', page_info.page_labels[idx]); + mark_font = "MARKED"; + page_info.index[idx].marked = True; + } + else { + sprintf(buf, pageno_format, ' ', page_info.page_labels[idx]); + mark_font = "UNMARKED"; + page_info.index[idx].marked = False; + } +/* str = XmStringCreateLocalized(buf); */ + str = XmStringCreateLtoR(buf, mark_font); + XmListReplaceItemsPos(widget, &str, 1, idx + MOTIF_IDX_OFFSET); + XmStringFree(str); +} + + +#else /* MOTIF */ + +static void +mark_page_callback(Widget w, XtPointer data, XEvent *event, Boolean *cont) +{ + UNUSED(data); + UNUSED(cont); + + /* moving button2 generates MotionNotify events for button0 */ + if (event->type == MotionNotify || event->xbutton.button == Button2) + internal_process_button2(w, event); + + if (pageinfo_have_marked_pages()) { + notify_print_dialog_have_marked(True); + } + else { + notify_print_dialog_have_marked(False); + } + +} + +void +xaw_create_pagelist_widgets(Dimension height, Dimension width, Position y, Widget parent) +{ + viewport = XtVaCreateWidget("viewport", + viewportWidgetClass, parent, + XtNallowVert, True, + /* this is not related to the scroll bar: */ + /* XtNforceBars, True, */ + XtNx, resource.btn_side_spacing, + XtNy, y, + XtNheight, height, + XtNwidth, width, + NULL); + LIST_WIDGET = XtVaCreateWidget("list", + listWidgetClass, viewport, + XtNlist, page_info.page_labels, + XtNdefaultColumns, 1, + XtNforceColumns, True, + XtNx, 10, + XtNy, 10, + XtNheight, height, + XtNwidth, width - 10, + XtNlongest, LONGESTPAGENUM, + XtNverticalList, True, + NULL); + XtManageChild(LIST_WIDGET); + XtManageChild(viewport); + XtAddCallback(LIST_WIDGET, XtNcallback, select_page_callback, + (XtPointer) NULL); + /* for scrolling the list */ + XtAddCallback(viewport, XtNreportCallback, xaw_SendReportProc, + (XtPointer) NULL); + XtAddEventHandler(LIST_WIDGET, + ButtonPressMask | ButtonReleaseMask | Button2MotionMask, + False, mark_page_callback, (XtPointer)NULL); + + if (resource.pagelist_highlight_current) + XtAddEventHandler(LIST_WIDGET, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask | LeaveWindowMask, + False, highlight_page_callback, (XtPointer)NULL); + + + XtAddEventHandler(LIST_WIDGET, ButtonPressMask | ButtonReleaseMask, + False, wheel_scroll_list_callback, (XtPointer)NULL); + + + XtAddEventHandler(LIST_WIDGET, + /* FIXME: We should add PointerMotionMask here, but handling PointerMotionMask + currently doesn't work with the Xaw list widget: the auto-scrolling code doesn't + realize when the mouse direction of the pointer movement changes, and continues + to scroll into the same direction. This will be rather annoying for users, so + we disabled PointerMotionMask for the time being. + */ + ButtonReleaseMask /* | PointerMotionMask */ | Button1MotionMask, + False, xaw_drag_page_callback, (XtPointer)NULL); +} + +static void +xaw_toggle_label(Widget w, int idx, Boolean update) +{ + if (w == NULL) + return; + +/* ensure_labelinfo_size(idx); */ + ASSERT(idx < (int)page_info.index_size, ""); + if (!page_info.index[idx].marked) { +/* sprintf(toc[idx], "* %*d ", get_page_size(), page_index[idx].number); */ + sprintf(page_info.page_labels[idx], pageno_format, '*', get_page_size(), + resource.use_tex_pages ? page_info.index[idx].number : idx + 1); + page_info.index[idx].marked = True; + } + else { + sprintf(page_info.page_labels[idx], pageno_format, ' ', get_page_size(), + resource.use_tex_pages ? page_info.index[idx].number : idx + 1); +/* sprintf(toc[idx], " %*d ", get_page_size(), page_index[idx].number); */ + page_info.index[idx].marked = False; + } + + if (update) + xaw_update_list(); +} + +static int +xaw_maybe_scroll_pagelist(int new_page, Boolean force_recenter, int idx_bak) +{ + Position x; + Position y, new_y, bot_y; + Dimension view_height, row_height, internal_height; + /* Dimension clip_height; */ + /* static Widget list_clip = 0; */ + + if (LIST_WIDGET == NULL || (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) + return idx_bak; + +/* if (list_clip == 0) { */ +/* list_clip = XtNameToWidget(viewport, "clip"); */ +/* } */ +/* if (XtIsRealized(list_clip)) */ +/* XtVaGetValues(list_clip, XtNheight, &clip_height, XtNx, &cx, XtNy, &y1, NULL); */ + if (viewport != NULL && XtIsRealized(viewport)) + XtVaGetValues(viewport, XtNheight, &view_height, XtNx, &x, NULL); +/* fprintf(stderr, "diff: %d, %d, %d, %d, %d\n", cx - x, clip_height, view_height, y1, (int)y2); */ + xaw_get_row_height(LIST_WIDGET, &row_height, &internal_height); + y = row_height * new_page; + +#if DEBUG + fprintf(stderr, "###### xaw_maybe_scroll_pagelist: y %d, view_y %d, view_height %d, row_height %d, internal_height %d; actual %d\n", + y, view_y, view_height, row_height, internal_height, idx_bak); +#endif + /*FIXME: when page list is destroyed, view_y will be 0 until user scrolls page list */ + bot_y = view_y + view_height; + if (force_recenter || ((y >= bot_y - row_height))) { +#if DEBUG + fprintf(stderr, "scrolled below bottom; incrementing %d to %d\n", view_y, view_y + row_height); +#endif + y += row_height; + XawViewportSetCoordinates(viewport, x, y - view_height > 0 ? y - view_height : 0); + return new_page + 1; + } + else if (force_recenter || ((y <= view_y + row_height + internal_height))) { +#if DEBUG + fprintf(stderr, "scrolled over top; new_y: %d\n", y - row_height); +#endif + new_y = y - 2 * row_height; + XawViewportSetCoordinates(viewport, x, new_y); + return new_page - 1; + } + /* not scrolled */ + return -2; +} + +#endif /* MOTIF */ + + +/* idx is C-style index (0-based), not Motif one (1-based) */ +static void +toggle_label(Widget widget, int idx, Boolean update) +{ + if (idx >= total_pages) + return; + ASSERT(idx < total_pages, ""); + ASSERT(idx >= 0, ""); +#ifdef MOTIF + xm_toggle_label(widget, idx, update); +#else + xaw_toggle_label(widget, idx, update); +#endif +} + + +void +list_toggle_marks(int arg) +{ + + int i; + + if (arg < 0) { /* mark all */ + for (i = 0; i < total_pages; i++) { + ASSERT(i < (int)page_info.index_size, ""); +/* ensure_labelinfo_size(i); */ + if (!page_info.index[i].marked) { + toggle_label(LIST_WIDGET, i, False); + } + } + } + else if (arg == 0) { /* unmark all */ + for (i = 0; i < total_pages; i++) { + ASSERT(i < (int)page_info.index_size, ""); +/* ensure_labelinfo_size(i); */ + if (page_info.index[i].marked) { + toggle_label(LIST_WIDGET, i, False); + } + } + } + else { /* toggle odd/even */ + if (arg == 2) /* toggle even */ + arg = 0; + for (i = 0; i < total_pages; i++) { + if ((i + 1) % 2 == arg) { + toggle_label(LIST_WIDGET, i, False); + } + } + } + /* TODO: update widget once for Motif as well! */ +#ifndef MOTIF + xaw_update_list(); +#endif +} + +static Boolean PagelistInitialized = False; + +#ifndef MOTIF +void +handle_pagelist_resize(void) +{ + /* TODO: the following will mess up the geometry of the list + (doesn't increase height, and incrementally decreases width): + if (list_widget) { + Dimension height; + --- without the (un)manage, I get an X Error: + XtMakeGeometryRequest - parent has no geometry manager + --- + XtUnmanageChild(viewport); + XtUnmanageChild(LIST_WIDGET); + XtVaGetValues(globals.widgets.clip_widget, XtNheight, &height, NULL); + height -= resource.btn_top_spacing + resource.btn_border_width + global_y_pos; + XtVaSetValues(viewport, XtNheight, height, NULL); + XtManageChild(LIST_WIDGET); + XtManageChild(viewport); + } + ... so we use brute force instead: */ + handle_destroy_pagelist(LIST_WIDGET, NULL, NULL); + create_pagelist(); +} + +void +handle_destroy_pagelist(Widget w, XtPointer client_data, XtPointer call_data) +{ + UNUSED(w); + UNUSED(client_data); + UNUSED(call_data); + + if (viewport != NULL) { + XtDestroyWidget(viewport); + viewport = NULL; + LIST_WIDGET = NULL; + } + PagelistInitialized = False; +} +#endif /* MOTIF */ + +void +create_pagelist(void) +{ + Pixel background, foreground; +#ifdef MOTIF + +/* items = xrealloc(items, sizeof *items * (total_pages + 2)); */ + init_pagelabels(0, total_pages); + xm_set_page_labels(); + if (!PagelistInitialized) { + XtAppContext app; + + XtVaGetValues(LIST_WIDGET, XmNforeground, &foreground, XmNbackground, &background, NULL); + m_page_gc.back = set_or_make_gc(NULL, GXcopy, background, foreground); + m_page_gc.fore = set_or_make_gc(NULL, GXcopy, foreground, background); + XtManageChild(LIST_WIDGET); + + XtAddCallback(LIST_WIDGET, XmNbrowseSelectionCallback, select_page_callback, NULL); +#if !defined(LESSTIF_VERSION) + /* + Don't use the highlighting hack with LessTif, since its XmListPosToBounds() + is too broken to be usable (as of 0.93.36): + - it returns generally too low values, apparently it doesn't take + XmNlistSpacing into account; + - it doesn't take scrollbar position into account. + */ + if (resource.pagelist_highlight_current) + XtAddEventHandler(LIST_WIDGET, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask | LeaveWindowMask, + False, highlight_page_callback, (XtPointer)NULL); +#endif /* !defined(LESSTIF_VERSION) */ + XtAddEventHandler(LIST_WIDGET, ButtonPressMask | ButtonReleaseMask, + False, wheel_scroll_list_callback, (XtPointer)NULL); + + app = XtWidgetToApplicationContext(globals.widgets.top_level); + XtAppAddActions(app, CustomListActions, XtNumber(CustomListActions)); + XtOverrideTranslations(LIST_WIDGET, XtParseTranslationTable(motif_custom_translations)); + PagelistInitialized = True; + } +#else /* MOTIF */ + if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) { + PagelistInitialized = False; /* might need to re-create widgets in this case */ + return; + } + + if (globals.debug & DBG_GUI) + fprintf(stderr, "allocating list with %d pages\n", total_pages); + + init_pagelabels(0, total_pages); + if (!PagelistInitialized) { + xaw_create_pagelist(); + XtVaGetValues(LIST_WIDGET, XtNforeground, &foreground, XtNbackground, &background, NULL); + m_page_gc.back = set_or_make_gc(NULL, GXcopy, background, foreground); + m_page_gc.fore = set_or_make_gc(NULL, GXcopy, foreground, background); + PagelistInitialized = True; + } +#endif /* MOTIF */ + /* scroll to the current page if needed */ + maybe_scroll_pagelist(current_page, False); +} + +#ifndef MOTIF +static void +free_pagelabels(void) +{ + int i; + for (i = 0; page_info.page_labels != NULL && page_info.page_labels[i] != NULL; i++) { + free(page_info.page_labels[i]); + } + free(page_info.page_labels); + page_info.page_labels = NULL; +} +#endif /* not MOTIF */ + + +void +refresh_pagelist(int newsize, int newpage) +{ + if ( +#ifndef MOTIF + (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0 || +#endif + !XtIsRealized(globals.widgets.top_level)) + return; + +#ifdef DEBUG + fprintf(stderr, "=== refresh_pagelist: newsize %d, newpage %d\n", newsize, newpage); +#endif +#ifdef MOTIF +/* items = xrealloc(items, sizeof *items * (newsize + 2)); */ + init_pagelabels(0, newsize); + xm_set_page_labels(); +#else /* MOTIF */ + if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) + return; + + /* FIXME - is this really neccessary?? The alternative: + XawListChange(LIST_WIDGET, page_info.page_labels, newsize, 0, True); + has problems when freeing the page labels afterwards. + */ + handle_destroy_pagelist(LIST_WIDGET, NULL, NULL); + + free_pagelabels(); + init_pagelabels(0, newsize); + + xaw_create_pagelist(); +#endif /* MOTIF */ + /* `True' since the pagelist is newly created */ + maybe_scroll_pagelist(newpage, True); +} + +void +maybe_scroll_pagelist(int newpage, Boolean force_recenter) +{ +#ifdef MOTIF + int top_visible, bot_visible; + UNUSED(force_recenter); +#endif + + if ( +#ifndef MOTIF + (resource.expert_mode & XPRT_SHOW_BUTTONS) == 0 || +#endif + !XtIsRealized(globals.widgets.top_level)) + return; + +#ifdef MOTIF + XmListSelectPos(LIST_WIDGET, newpage + MOTIF_IDX_OFFSET, False); + + top_visible = xm_get_top_visible(1); + bot_visible = xm_get_bottom_visible(top_visible); + + xm_maybe_scroll_pagelist(newpage, CLICK, &top_visible, &bot_visible); +#if HAVE_XPM + tb_check_navigation_sensitivity(current_page); +#endif +#else + + if (LIST_WIDGET == NULL) + return; + + (void)xaw_maybe_scroll_pagelist(newpage + 1, force_recenter, 0); + + XawListHighlight(LIST_WIDGET, newpage); +#if REDRAW_CURRENT_MARKER_HACK + /* if the XawListHighlight happens adjacent to the page that was + last highlighted with our home-made `current selected' + rectangle, it might overdraw that rectangle. In this case, + restore it: + */ + xaw_maybe_redraw_current_marker(newpage); +#endif +#endif +} + +#ifdef MOTIF +static void +set_all_marks(int from, int to) +{ + int i; + for (i = from; i < to; i++) { +/* ensure_labelinfo_size(i); */ + page_info.index[i].marked = True; + toggle_label(LIST_WIDGET, i, False); + } +} + +static void +internal_process_button2_drag(Widget widget, XEvent *event) +{ + int i, idx, min = total_pages, max = 0; + idx = get_item_index(widget, event->xbutton.y); + + for (i = 0; i < total_pages; i++) { +/* ensure_labelinfo_size(i); */ + if (page_info.index[i].marked && i > max) + max = i; + } + for (i = total_pages; i > 0; i--) { +/* ensure_labelinfo_size(i); */ + if (page_info.index[i].marked && i < min) + min = i; + } + + if (min == total_pages) + min = 0; + if (max == 0) + max = total_pages; + + if (idx < min) { + set_all_marks(idx, min); + } + else if (idx > max) { + set_all_marks(max + 1, idx); + } + else { + set_all_marks(0, idx); + } +} +#endif /* MOTIF */ + +static void +internal_process_button2(Widget widget, XEvent *event) +{ + int curr_idx; + static int prev_idx = 0; +#ifndef MOTIF + static int actual_idx = -2; +#endif + static int top_visible = 0, bot_visible = 0; + static int prev_y = 0, curr_y = 0; + static saveCmdT prev_cmd = 0; /* previous command (CLICK/SCROLL_UP/SCROLL_DOWN) */ + static saveCmdT curr_cmd = 0; /* current command (CLICK/SCROLL_UP/SCROLL_DOWN) */ + static saveCmdT bak_cmd = 0; /* last command that started inside the pagelist (CLICK/SCROLL_UP/SCROLL_DOWN) */ + static Boolean change_scroll_direction = False; + + switch(event->xany.type) { + case ButtonPress: + prev_y = event->xbutton.y; + prev_idx = curr_idx = get_item_index(widget, prev_y); +#ifdef MOTIF + top_visible = xm_get_top_visible(1); + bot_visible = xm_get_bottom_visible(top_visible); +#endif + toggle_label(widget, curr_idx - 1, True); + prev_cmd = CLICK; +#ifdef MOTIF + xm_maybe_scroll_pagelist(curr_idx - 1, CLICK, &top_visible, &bot_visible); +#else + actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx); +#endif + break; + case ButtonRelease: + prev_cmd = CLICK; + break; + case MotionNotify: + curr_y = (int)event->xmotion.y; + curr_idx = get_item_index(widget, event->xmotion.y); +#ifndef MOTIF + if (actual_idx > 0) { + curr_idx = actual_idx; + } +#endif + + if (curr_y < prev_y) + curr_cmd = SCROLL_UP; + else if (curr_y > prev_y) + curr_cmd = SCROLL_DOWN; + prev_y = curr_y; + + if (prev_cmd != CLICK && curr_cmd != prev_cmd) + change_scroll_direction = True; + + if ((curr_idx != prev_idx && !change_scroll_direction) + || (change_scroll_direction + /* last or first visible are always spared, unless they are really + the first or last page; this way, always 1 more page is visible + than is currently marked/selected + */ + && !(curr_idx == top_visible) && !(curr_idx == bot_visible))) { + if (curr_idx <= 0) { + /* When user has scrolled off, mark this by setting curr_idx to 1 more or less + than the pagelist has so that the last/first page don't oscillate between + marked/unmarked state when user continues to scroll. + Also, we continue scrolling as long as user drags in the same direction as + the last `real' scrolling event (saved as bak_cmd). + */ + if (curr_cmd == SCROLL_DOWN && bak_cmd == SCROLL_DOWN && prev_idx <= total_pages) { + curr_idx = prev_idx + 1; + } + else if (curr_cmd == SCROLL_UP && bak_cmd == SCROLL_UP && prev_idx > 0) { + curr_idx = prev_idx - 1; + } + } + + + if (curr_idx > 0 && curr_idx <= total_pages) { + toggle_label(widget, curr_idx - 1, True); +#ifdef MOTIF + xm_maybe_scroll_pagelist(curr_idx - 1, curr_cmd, &top_visible, &bot_visible); +#else + actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx); +#endif + prev_idx = curr_idx; + bak_cmd = curr_cmd; + change_scroll_direction = False; + } + else { +#ifndef MOTIF + if (curr_idx > total_pages) + actual_idx = -2; + else + actual_idx = xaw_maybe_scroll_pagelist(curr_idx, False, actual_idx); +#endif + } + prev_cmd = curr_cmd; + } + break; + default: + break; + } +} + +void +list_toggle_current(int arg) +{ + toggle_label(LIST_WIDGET, arg, True); + + if (pageinfo_have_marked_pages()) { + notify_print_dialog_have_marked(True); + } + else { + notify_print_dialog_have_marked(False); + } +} + +#ifdef MOTIF + +static void +xm_list_set_mark(Widget widget, + XEvent *event, + String *params, + Cardinal *num_params) +{ + UNUSED(params); + + if ((*num_params != 1) || !XmIsList(widget)) + return; + + internal_process_button2(widget, event); + + if (pageinfo_have_marked_pages()) { + notify_print_dialog_have_marked(True); + } + else { + notify_print_dialog_have_marked(False); + } +} + +static void +xm_list_drag_mark(Widget widget, + XEvent *event, + String *params, + Cardinal *num_params) +{ + UNUSED(params); + + if ((*num_params != 1) || !XmIsList(widget)) + return; + + internal_process_button2_drag(widget, event); + + if (pageinfo_have_marked_pages()) { + notify_print_dialog_have_marked(True); + } + else { + notify_print_dialog_have_marked(False); + } +} + +#endif /* MOTIF */ |