scrolling groups, take 2
Bert Wesarg
wesarg at informatik.uni-halle.de
Wed Jul 4 00:18:47 CEST 2007
Hello,
this morning I had the idea to group not on the WindowInfo level, instead
to group on the TextWidget level. This brings two changes: 1) there is no
link between TextWidget and WindowInfo internals, that removes at least
the hack character. 2) it is now possible to put different panes from one
window in a group. Or mix panes from other windows. The little drawback
with 2) is, that the usability is reduced (all panes a in the dialog list).
I must admit that Tony has objections with this approach. He suggest a
callback for a "have scrolled" event from the TextWidget. But this must be
carefully implemented to avoid endless callback firings, when other
windows from the same group are scrolled 'by hand'.
In the end, here is code to discuss this issue.
Regards
Bert
PS: I bumped the version number to 3 and renamed this from sync scrolling
to scroll groups.
-------------- next part --------------
diff -ur nedit.orig/doc/help.etx nedit.syncscroll/doc/help.etx
--- nedit.orig/doc/help.etx 2007-07-02 18:26:15.663198719 +0200
+++ nedit.syncscroll/doc/help.etx 2007-07-03 22:25:01.514574712 +0200
@@ -2464,6 +2464,9 @@
**$show_line_numbers**
Whether line numbers are shown next to the text.
+**$scroll_group**
+ True if this text pane is in an syncronized scroll group;
+
**$show_matching**
Contains the current preference for showing matching pairs,
such as "[]" and "{}" pairs. Can be "off", "delimiter", or "range".
@@ -3254,6 +3257,13 @@
A value of 0 turns it off and a value of 1 turns it on.
If no parameters are supplied the option is toggled.
+**set_scroll_group( [window_name] [, paneIndex] )**
+ Include this window to the same sync scroll group as window_name and
+ possibly remove this window from the previously group.
+ If no window_name is given or window_name is the empty string remove
+ this window from any group. If paneIndex is not given or paneIndex == -1
+ use the last focused pane from the window, else a valid pane index.
+
**set_show_line_numbers( [0 | 1] )**
Show or hide line numbers for the current window.
A value of 0 turns it off and a value of 1 turns it on.
diff -ur nedit.orig/source/highlightData.c nedit.syncscroll/source/highlightData.c
--- nedit.orig/source/highlightData.c 2007-07-02 18:26:16.497269298 +0200
+++ nedit.syncscroll/source/highlightData.c 2007-07-03 22:26:03.701987020 +0200
@@ -550,10 +550,10 @@
README:\"NEdit Macro syntax highlighting patterns, version 2.6, maintainer Thorsten Haude, nedit at thorstenhau.de\":::Flag::D\n\
Comment:\"#\":\"$\"::Comment::\n\
Built-in Misc Vars:\"(?<!\\Y)\\$(?:active_pane|args|calltip_ID|column|cursor|display_width|empty_array|file_name|file_path|language_mode|line|locked|max_font_width|min_font_width|modified|n_display_lines|n_panes|rangeset_list|read_only|selection_(?:start|end|left|right)|server_name|text_length|top_line)>\":::Identifier::\n\
- Built-in Pref Vars:\"(?<!\\Y)\\$(?:auto_indent|em_tab_dist|file_format|font_name|font_name_bold|font_name_bold_italic|font_name_italic|highlight_syntax|incremental_backup|incremental_search_line|make_backup_copy|match_syntax_based|overtype_mode|show_line_numbers|show_matching|statistics_line|tab_dist|use_tabs|wrap_margin|wrap_text)>\":::Identifier2::\n\
+ Built-in Pref Vars:\"(?<!\\Y)\\$(?:auto_indent|em_tab_dist|file_format|font_name|font_name_bold|font_name_bold_italic|font_name_italic|highlight_syntax|incremental_backup|incremental_search_line|make_backup_copy|match_syntax_based|overtype_mode|show_line_numbers|show_matching|statistics_line|scroll_group|tab_dist|use_tabs|wrap_margin|wrap_text)>\":::Identifier2::\n\
Built-in Special Vars:\"(?<!\\Y)\\$(?:[1-9]|list_dialog_button|n_args|read_status|search_end|shell_cmd_status|string_dialog_button|sub_sep)>\":::String1::\n\
Built-in Subrs:\"<(?:append_file|beep|calltip|clipboard_to_string|dialog|focus_window|get_character|get_pattern_(by_name|at_pos)|get_range|get_selection|get_style_(by_name|at_pos)|getenv|kill_calltip|length|list_dialog|max|min|rangeset_(?:add|create|destroy|get_by_name|includes|info|invert|range|set_color|set_mode|set_name|subtract)|read_file|replace_in_string|replace_range|replace_selection|replace_substring|search|search_string|select|select_rectangle|set_cursor_pos|set_language_mode|set_locked|shell_command|split|string_compare|string_dialog|string_to_clipboard|substring|t_print|tolower|toupper|valid_number|write_file)>\":::Subroutine::\n\
- Menu Actions:\"<(?:new|open|open-dialog|open_dialog|open-selected|open_selected|close|save|save-as|save_as|save-as-dialog|save_as_dialog|revert-to-saved|revert_to_saved|revert_to_saved_dialog|include-file|include_file|include-file-dialog|include_file_dialog|load-macro-file|load_macro_file|load-macro-file-dialog|load_macro_file_dialog|load-tags-file|load_tags_file|load-tags-file-dialog|load_tags_file_dialog|unload_tags_file|load_tips_file|load_tips_file_dialog|unload_tips_file|print|print-selection|print_selection|exit|undo|redo|delete|select-all|select_all|shift-left|shift_left|shift-left-by-tab|shift_left_by_tab|shift-right|shift_right|shift-right-by-tab|shift_right_by_tab|find|find-dialog|find_dialog|find-again|find_again|find-selection|find_selection|find_incremental|start_incremental_find|replace|replace-dialog|replace_dialog|replace-all|replace_all|replace-in-selection|replace_in_selection|replace-again|replace_again|replace_find|replace_find_same|replace_find_again|goto-line-number|goto_line_number|goto-line-number-dialog|goto_line_number_dialog|goto-selected|goto_selected|mark|mark-dialog|mark_dialog|goto-mark|goto_mark|goto-mark-dialog|goto_mark_dialog|match|select_to_matching|goto_matching|find-definition|find_definition|show_tip|split-window|split_window|close-pane|close_pane|uppercase|lowercase|fill-paragraph|fill_paragraph|control-code-dialog|control_code_dialog|filter-selection-dialog|filter_selection_dialog|filter-selection|filter_selection|execute-command|execute_command|execute-command-dialog|execute_command_dialog|execute-command-line|execute_command_line|shell-menu-command|shell_menu_command|macro-menu-command|macro_menu_command|bg_menu_command|post_window_bg_menu|beginning-of-selection|beginning_of_selection|end-of-selection|end_of_selection|repeat_macro|repeat_dialog|raise_window|focus_pane|set_statistics_line|set_incremental_search_line|set_show_line_numbers|set_auto_indent|set_wrap_text|set_wrap_margin|set_highlight_syntax|set_make_backup_copy|set_incremental_backup|set_show_matching|set_match_syntax_based|set_overtype_mode|set_locked|set_tab_dist|set_em_tab_dist|set_use_tabs|set_fonts|set_language_mode)(?=\\s*\\()\":::Subroutine::\n\
+ Menu Actions:\"<(?:new|open|open-dialog|open_dialog|open-selected|open_selected|close|save|save-as|save_as|save-as-dialog|save_as_dialog|revert-to-saved|revert_to_saved|revert_to_saved_dialog|include-file|include_file|include-file-dialog|include_file_dialog|load-macro-file|load_macro_file|load-macro-file-dialog|load_macro_file_dialog|load-tags-file|load_tags_file|load-tags-file-dialog|load_tags_file_dialog|unload_tags_file|load_tips_file|load_tips_file_dialog|unload_tips_file|print|print-selection|print_selection|exit|undo|redo|delete|select-all|select_all|shift-left|shift_left|shift-left-by-tab|shift_left_by_tab|shift-right|shift_right|shift-right-by-tab|shift_right_by_tab|find|find-dialog|find_dialog|find-again|find_again|find-selection|find_selection|find_incremental|start_incremental_find|replace|replace-dialog|replace_dialog|replace-all|replace_all|replace-in-selection|replace_in_selection|replace-again|replace_again|replace_find|replace_find_same|replace_find_again|goto-line-number|goto_line_number|goto-line-number-dialog|goto_line_number_dialog|goto-selected|goto_selected|mark|mark-dialog|mark_dialog|goto-mark|goto_mark|goto-mark-dialog|goto_mark_dialog|match|select_to_matching|goto_matching|find-definition|find_definition|show_tip|split-window|split_window|close-pane|close_pane|uppercase|lowercase|fill-paragraph|fill_paragraph|control-code-dialog|control_code_dialog|filter-selection-dialog|filter_selection_dialog|filter-selection|filter_selection|execute-command|execute_command|execute-command-dialog|execute_command_dialog|execute-command-line|execute_command_line|shell-menu-command|shell_menu_command|macro-menu-command|macro_menu_command|bg_menu_command|post_window_bg_menu|beginning-of-selection|beginning_of_selection|end-of-selection|end_of_selection|repeat_macro|repeat_dialog|raise_window|focus_pane|set_statistics_line|set_incremental_search_line|set_show_line_numbers|set_auto_indent|set_wrap_text|set_wrap_margin|set_highlight_syntax|set_make_backup_copy|set_incremental_backup|set_show_matching|set_match_syntax_based|set_overtype_mode|set_scroll_group|set_locked|set_tab_dist|set_em_tab_dist|set_use_tabs|set_fonts|set_language_mode)(?=\\s*\\()\":::Subroutine::\n\
Text Actions:\"<(?:self-insert|self_insert|grab-focus|grab_focus|extend-adjust|extend_adjust|extend-start|extend_start|extend-end|extend_end|secondary-adjust|secondary_adjust|secondary-or-drag-adjust|secondary_or_drag_adjust|secondary-start|secondary_start|secondary-or-drag-start|secondary_or_drag_start|process-bdrag|process_bdrag|move-destination|move_destination|move-to|move_to|move-to-or-end-drag|move_to_or_end_drag|end_drag|copy-to|copy_to|copy-to-or-end-drag|copy_to_or_end_drag|exchange|process-cancel|process_cancel|paste-clipboard|paste_clipboard|copy-clipboard|copy_clipboard|cut-clipboard|cut_clipboard|copy-primary|copy_primary|cut-primary|cut_primary|newline|newline-and-indent|newline_and_indent|newline-no-indent|newline_no_indent|delete-selection|delete_selection|delete-previous-character|delete_previous_character|delete-next-character|delete_next_character|delete-previous-word|delete_previous_word|delete-next-word|delete_next_word|delete-to-start-of-line|delete_to_start_of_line|delete-to-end-of-line|delete_to_end_of_line|forward-character|forward_character|backward-character|backward_character|key-select|key_select|process-up|process_up|process-down|process_down|process-shift-up|process_shift_up|process-shift-down|process_shift_down|process-home|process_home|forward-word|forward_word|backward-word|backward_word|forward-paragraph|forward_paragraph|backward-paragraph|backward_paragraph|beginning-of-line|beginning_of_line|end-of-line|end_of_line|beginning-of-file|beginning_of_file|end-of-file|end_of_file|next-page|next_page|previous-page|previous_page|page-left|page_left|page-right|page_right|toggle-overstrike|toggle_overstrike|scroll-up|scroll_up|scroll-down|scroll_down|scroll_left|scroll_right|scroll-to-line|scroll_to_line|select-all|select_all|deselect-all|deselect_all|focusIn|focusOut|process-return|process_return|process-tab|process_tab|insert-string|insert_string|mouse_pan)>\":::Subroutine::\n\
Keyword:\"<(?:break|continue|define|delete|else|for|if|in|return|while)>\":::Keyword::\n\
Braces:\"[{}\\[\\]]\":::Keyword::\n\
diff -ur nedit.orig/source/macro.c nedit.syncscroll/source/macro.c
--- nedit.orig/source/macro.c 2007-07-02 18:26:16.529272006 +0200
+++ nedit.syncscroll/source/macro.c 2007-07-03 22:31:32.708538832 +0200
@@ -297,6 +297,8 @@
DataValue *result, char **errMsg);
static int overTypeModeMV(WindowInfo *window, DataValue *argList, int nArgs,
DataValue *result, char **errMsg);
+static int scrollGroupMV(WindowInfo *window, DataValue *argList, int nArgs,
+ DataValue *result, char **errMsg);
static int readOnlyMV(WindowInfo *window, DataValue *argList, int nArgs,
DataValue *result, char **errMsg);
static int lockedMV(WindowInfo *window, DataValue *argList, int nArgs,
@@ -449,7 +451,7 @@
statisticsLineMV, incSearchLineMV, showLineNumbersMV,
autoIndentMV, wrapTextMV, highlightSyntaxMV,
makeBackupCopyMV, incBackupMV, showMatchingMV,
- overTypeModeMV, readOnlyMV, lockedMV, fileFormatMV,
+ overTypeModeMV, scrollGroupMV, readOnlyMV, lockedMV, fileFormatMV,
fontNameMV, fontNameItalicMV,
fontNameBoldMV, fontNameBoldItalicMV, subscriptSepMV,
minFontWidthMV, maxFontWidthMV, topLineMV, numDisplayLinesMV,
@@ -467,7 +469,7 @@
"$statistics_line", "$incremental_search_line", "$show_line_numbers",
"$auto_indent", "$wrap_text", "$highlight_syntax",
"$make_backup_copy", "$incremental_backup", "$show_matching",
- "$overtype_mode", "$read_only", "$locked", "$file_format",
+ "$overtype_mode", "$scroll_group", "$read_only", "$locked", "$file_format",
"$font_name", "$font_name_italic",
"$font_name_bold", "$font_name_bold_italic", "$sub_sep",
"$min_font_width", "$max_font_width", "$top_line", "$n_display_lines",
@@ -4298,6 +4300,15 @@
return True;
}
+static int scrollGroupMV(WindowInfo *window, DataValue *argList, int nArgs,
+ DataValue *result, char **errMsg)
+{
+ result->tag = INT_TAG;
+ result->val.n = !TextScrollGroupIsSingle((TextWidget)window->lastFocus);
+
+ return True;
+}
+
static int readOnlyMV(WindowInfo *window, DataValue *argList, int nArgs,
DataValue *result, char **errMsg)
{
diff -ur nedit.orig/source/menu.c nedit.syncscroll/source/menu.c
--- nedit.orig/source/menu.c 2007-07-02 18:26:16.812295955 +0200
+++ nedit.syncscroll/source/menu.c 2007-07-04 00:15:16.892885244 +0200
@@ -311,6 +311,12 @@
Cardinal *nArgs);
static void moveDocumentDialogAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs);
+static void scrollGroupDetachAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs);
+static void scrollGroupDetachDialogAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs);
+static void scrollGroupDialogAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs);
static void nextDocumentAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs);
static void prevDocumentAP(Widget w, XEvent *event, String *args,
@@ -407,6 +413,8 @@
Cardinal *nArgs);
static void setOvertypeModeAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs);
+static void setScrollGroupAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs);
static void setLockedAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs);
static void setUseTabsAP(Widget w, XEvent *event, String *args,
@@ -527,6 +535,9 @@
{"detach_document", detachDocumentAP},
{"detach_document_dialog", detachDocumentDialogAP},
{"move_document_dialog", moveDocumentDialogAP},
+ {"scroll_group_detach", scrollGroupDetachAP},
+ {"scroll_group_detach_dialog", scrollGroupDetachDialogAP},
+ {"scroll_group_dialog", scrollGroupDialogAP},
{"next_document", nextDocumentAP},
{"previous_document", prevDocumentAP},
{"last_document", lastDocumentAP},
@@ -577,6 +588,7 @@
{"set_show_matching", setShowMatchingAP},
{"set_match_syntax_based", setMatchSyntaxBasedAP},
{"set_overtype_mode", setOvertypeModeAP},
+ {"set_scroll_group", setScrollGroupAP},
{"set_locked", setLockedAP},
{"set_tab_dist", setTabDistAP},
{"set_em_tab_dist", setEmTabDistAP},
@@ -1222,6 +1234,14 @@
window->moveDocumentItem = createMenuItem(menuPane, "moveDocument",
"Move Tab To...", 'M', doActionCB, "move_document_dialog", SHORT);
XtSetSensitive(window->moveDocumentItem, False);
+
+ btn = createMenuSeparator(menuPane, "sep02", SHORT);
+ XtVaSetValues(btn, XmNuserData, PERMANENT_MENU_ITEM, NULL);
+ window->scrollGroupDetachItem = createMenuItem(menuPane, "scrollGroupDetach",
+ "Detach from Scroll Group", 'g', doActionCB, "scroll_group_document_detach", SHORT);
+ window->scrollGroupItem = createMenuItem(menuPane, "scrollGroupDialog",
+ "Join Document To Scroll Group...", 'G', doActionCB, "scroll_group_document_dialog", SHORT);
+
btn = createMenuSeparator(menuPane, "sep1", SHORT);
XtVaSetValues(btn, XmNuserData, PERMANENT_MENU_ITEM, NULL);
@@ -3531,6 +3551,41 @@
MoveDocumentDialog(WidgetToWindow(w));
}
+static void scrollGroupDetachDialogAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs)
+{
+ WindowInfo *window = WidgetToWindow(w);
+ TextWidget text = (TextWidget)window->lastFocus;
+ int resp;
+
+ if (TextScrollGroupIsSingle(text))
+ return;
+
+ resp = DialogF(DF_QUES, window->shell, 2, "Detach %s from Scroll Group?",
+ "Detach", "Cancel", window->filename);
+
+ if (resp == 1)
+ TextScrollGroupDetach(text);
+}
+
+static void scrollGroupDetachAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs)
+{
+ WindowInfo *window = WidgetToWindow(w);
+ TextWidget text = (TextWidget)window->lastFocus;
+
+ if (TextScrollGroupIsSingle(text))
+ return;
+
+ TextScrollGroupDetach(text);
+}
+
+static void scrollGroupDialogAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs)
+{
+ ScrollGroupDialog(WidgetToWindow(w), -1);
+}
+
static void nextDocumentAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
@@ -4182,6 +4237,85 @@
SetOverstrike(window, newState);
}
+static void setScrollGroupAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs)
+{
+ WindowInfo *window = WidgetToWindow(w);
+ WindowInfo *win;
+ TextWidget text, targetText = NULL;
+
+ if (*nArgs > 2) {
+ fprintf(stderr, "NEdit: set_scroll_group too many arguments\n");
+ return;
+ }
+
+ text = (TextWidget)window->lastFocus;
+
+ TextScrollGroupDetach(text);
+
+ win = NULL;
+ if (*nArgs == 0 || !strcmp(args[0], "")) {
+ return;
+ }
+ else if (!strcmp(args[0], "last")) {
+ win = WindowList;
+ }
+ else if (!strcmp(args[0], "next")) {
+ win = window->next;
+ }
+ else if (strlen(args[0]) >= MAXPATHLEN) {
+ fprintf(stderr, "NEdit: Pathname too long in set_scroll_group()\n");
+ return;
+ }
+ else {
+ char fullname[MAXPATHLEN];
+ char normalizedString[MAXPATHLEN];
+ /* just use the plain name as supplied */
+ for (win = WindowList; win != NULL; win = win->next) {
+ sprintf(fullname, "%s%s", win->path, win->filename);
+ if (!strcmp(args[0], fullname)) {
+ break;
+ }
+ }
+ /* didn't work? try normalizing the string passed in */
+ if (win == NULL) {
+ strncpy(normalizedString, args[0], MAXPATHLEN);
+ normalizedString[MAXPATHLEN-1] = '\0';
+ if (1 == NormalizePathname(normalizedString)) {
+ /* Something is broken with the input pathname. */
+ fprintf(stderr, "NEdit: Pathname broken in set_scroll_group()\n");
+ return;
+ }
+ for (win = WindowList; win != NULL; win = win->next) {
+ sprintf(fullname, "%s%s", win->path, win->filename);
+ if (!strcmp(normalizedString, fullname))
+ break;
+ }
+ }
+ }
+
+ if (!win)
+ return;
+
+ targetText = NULL;
+ if (*nArgs > 1) {
+ int paneIndex = atoi(args[1]);
+ if (paneIndex >= 0) {
+ targetText = (TextWidget)GetPaneByIndex(win, paneIndex);
+ if (NULL == targetText) {
+ fprintf(stderr, "NEdit: set_scroll_group wrong argument for 2nd parameter\n");
+ return;
+ }
+ }
+ }
+ if (NULL == targetText) {
+ targetText = (TextWidget)win->lastFocus;
+ }
+
+ if (text != targetText)
+ TextScrollGroupJoinWith(text, targetText);
+}
+
static void setLockedAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
diff -ur nedit.orig/source/nedit.h nedit.syncscroll/source/nedit.h
--- nedit.orig/source/nedit.h 2007-07-02 18:26:16.618279538 +0200
+++ nedit.syncscroll/source/nedit.h 2007-07-03 22:09:34.528709431 +0200
@@ -443,6 +443,8 @@
Widget moveDocumentItem;
Widget contextMoveDocumentItem;
Widget contextDetachDocumentItem;
+ Widget scrollGroupDetachItem;
+ Widget scrollGroupItem;
Widget bgMenuUndoItem;
Widget bgMenuRedoItem;
#ifdef SGI_CUSTOM
diff -ur nedit.orig/source/text.c nedit.syncscroll/source/text.c
--- nedit.orig/source/text.c 2007-07-02 18:26:16.302252796 +0200
+++ nedit.syncscroll/source/text.c 2007-07-03 22:33:54.153727988 +0200
@@ -80,6 +80,10 @@
/* Length of delay in milliseconds for vertical autoscrolling */
#define VERTICAL_SCROLL_DELAY 50
+typedef void (textActionProcCall)(Widget, XEvent*, String*, Cardinal*);
+
+static void syncScrollAP(textActionProcCall actionProc, Widget w,
+ XEvent *event, String *args, Cardinal *nArgs);
static void initialize(TextWidget request, TextWidget new);
static void handleHidePointer(Widget w, XtPointer unused,
XEvent *event, Boolean *continue_to_dispatch);
@@ -877,6 +881,9 @@
XtAddEventHandler((Widget)new, NEDIT_HIDE_CURSOR_MASK, False,
handleHidePointer, (Opaque)NULL);
}
+
+ new->nextScrollGroup = new;
+ new->prevScrollGroup = new;
}
/* Hide the pointer while the user is typing */
@@ -953,6 +960,8 @@
XtRemoveAllCallbacks((Widget)w, textNdragStartCallback);
XtRemoveAllCallbacks((Widget)w, textNdragEndCallback);
+ TextScrollGroupDetach(w);
+
#ifndef NO_XMIM
/* Unregister the widget from the input manager */
XmImUnregister((Widget)w);
@@ -2910,7 +2919,7 @@
}
}
-static void nextPageAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
+static void _nextPageAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
{
textDisp *textD = ((TextWidget)w)->text.textD;
textBuffer *buf = textD->buffer;
@@ -3007,7 +3016,12 @@
}
}
-static void previousPageAP(Widget w, XEvent *event, String *args,
+static void nextPageAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
+{
+ _nextPageAP(w, event, args, nArgs);
+}
+
+static void _previousPageAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
textDisp *textD = ((TextWidget)w)->text.textD;
@@ -3092,6 +3106,12 @@
}
}
+static void previousPageAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
+{
+ _previousPageAP(w, event, args, nArgs);
+
+}
+
static void pageLeftAP(Widget w, XEvent *event, String *args, Cardinal *nArgs)
{
textDisp *textD = ((TextWidget)w)->text.textD;
@@ -3183,7 +3203,25 @@
}
}
-static void scrollUpAP(Widget w, XEvent *event, String *args,
+/*
+** do synchronous scroll for this action.
+*/
+static void syncScrollAP(textActionProcCall actionProc, Widget w,
+ XEvent *event, String *args, Cardinal *nArgs)
+{
+ TextWidget text = (TextWidget)w;
+ TextWidget t;
+
+ actionProc(w, event, args, nArgs);
+
+ if (text == text->nextScrollGroup)
+ return;
+
+ for (t = text->nextScrollGroup; t != text; t = t->nextScrollGroup)
+ actionProc((Widget)t, event, args, nArgs);
+}
+
+static void _scrollUpAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
textDisp *textD = ((TextWidget)w)->text.textD;
@@ -3204,7 +3242,13 @@
TextDSetScroll(textD, topLineNum-nLines, horizOffset);
}
-static void scrollDownAP(Widget w, XEvent *event, String *args,
+static void scrollUpAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs)
+{
+ syncScrollAP(_scrollUpAP, w, event, args, nArgs);
+}
+
+static void _scrollDownAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
textDisp *textD = ((TextWidget)w)->text.textD;
@@ -3225,6 +3269,12 @@
TextDSetScroll(textD, topLineNum+nLines, horizOffset);
}
+static void scrollDownAP(Widget w, XEvent *event, String *args,
+ Cardinal *nArgs)
+{
+ syncScrollAP(_scrollDownAP, w, event, args, nArgs);
+}
+
static void scrollLeftAP(Widget w, XEvent *event, String *args,
Cardinal *nArgs)
{
@@ -4232,3 +4282,29 @@
if (!silent)
XBell(XtDisplay(w), 0);
}
+
+void TextScrollGroupJoinWith(TextWidget new, TextWidget prev)
+{
+ TextWidget next = prev->nextScrollGroup;
+
+ next->prevScrollGroup = new;
+ prev->nextScrollGroup = new;
+ new->nextScrollGroup = next;
+ new->prevScrollGroup = prev;
+}
+
+void TextScrollGroupDetach(TextWidget old)
+{
+ TextWidget next = old->nextScrollGroup;
+ TextWidget prev = old->prevScrollGroup;
+
+ next->prevScrollGroup = prev;
+ prev->nextScrollGroup = next;
+ old->nextScrollGroup = old;
+ old->prevScrollGroup = old;
+}
+
+Boolean TextScrollGroupIsSingle(TextWidget text)
+{
+ return (text == text->nextScrollGroup);
+}
diff -ur nedit.orig/source/textDisp.c nedit.syncscroll/source/textDisp.c
--- nedit.orig/source/textDisp.c 2007-07-02 18:26:16.355257281 +0200
+++ nedit.syncscroll/source/textDisp.c 2007-07-03 22:35:09.685088728 +0200
@@ -2902,11 +2902,35 @@
textDisp *textD = (textDisp *)clientData;
int newValue = ((XmScrollBarCallbackStruct *)callData)->value;
int lineDelta = newValue - textD->topLineNum;
-
+ TextWidget text, t;
+
if (lineDelta == 0)
return;
setScroll(textD, newValue, textD->horizOffset, False, True);
+
+ text = (TextWidget)textD->w;
+
+ if (text == text->nextScrollGroup)
+ return;
+
+ /* do synchronous scroll */
+ for (t = text->nextScrollGroup; t != text; t= t->nextScrollGroup) {
+ int newLine;
+ textDisp *tD = t->text.textD;
+ if (lineDelta > 0) {
+ newLine = tD->topLineNum +
+ min(lineDelta, tD->nBufferLines -
+ tD->topLineNum -
+ tD->nVisibleLines + 2);
+ }
+ else {
+ newLine = tD->topLineNum + lineDelta;
+ }
+
+ setScroll(tD, newLine < 1 ? 1 : newLine, 0, True, True);
+ }
}
+
static void hScrollCB(Widget w, XtPointer clientData, XtPointer callData)
{
textDisp *textD = (textDisp *)clientData;
diff -ur nedit.orig/source/text.h nedit.syncscroll/source/text.h
--- nedit.orig/source/text.h 2007-07-02 18:26:16.199244079 +0200
+++ nedit.syncscroll/source/text.h 2007-07-03 21:52:41.955650466 +0200
@@ -169,6 +169,10 @@
void ShowHidePointer(TextWidget w, Boolean hidePointer);
void ResetCursorBlink(TextWidget textWidget, Boolean startsBlanked);
+void TextScrollGroupJoinWith(TextWidget new, TextWidget prev);
+void TextScrollGroupDetach(TextWidget text);
+Boolean TextScrollGroupIsSingle(TextWidget text);
+
#ifdef VMS /* VMS linker doesn't like long names (>31 chars) */
#define HandleAllPendingGraphicsExposeNoExposeEvents HandlePendingExpNoExpEvents
#endif /* VMS */
diff -ur nedit.orig/source/textP.h nedit.syncscroll/source/textP.h
--- nedit.orig/source/textP.h 2007-07-02 18:26:16.247248141 +0200
+++ nedit.syncscroll/source/textP.h 2007-07-03 18:21:21.917827744 +0200
@@ -133,6 +133,8 @@
CorePart core;
XmPrimitivePart primitive;
TextPart text;
+ struct _TextRec *nextScrollGroup;
+ struct _TextRec *prevScrollGroup;
} TextRec;
#endif /* NEDIT_TEXTP_H_INCLUDED */
diff -ur nedit.orig/source/window.c nedit.syncscroll/source/window.c
--- nedit.orig/source/window.c 2007-07-02 18:26:16.256248903 +0200
+++ nedit.syncscroll/source/window.c 2007-07-03 22:37:26.165358925 +0200
@@ -195,6 +195,7 @@
static WindowInfo *inFocusDocument = NULL; /* where we are now */
static WindowInfo *lastFocusDocument = NULL; /* where we came from */
static int DoneWithMoveDocumentDialog;
+static int DoneWithScrollGroupDialog;
static void updateLineNumDisp(const WindowInfo* window);
static int max(const int i1, const int i2);
static void setGutterWidth(const WindowInfo* window, const unsigned reqCols);
@@ -1032,6 +1033,7 @@
}
}
+ TextScrollGroupDetach((TextWidget)window->textArea);
/* remove the window from the global window list, update window menus */
removeFromWindowList(window);
InvalidateWindowMenus();
@@ -4200,6 +4202,9 @@
textD->selectFGPixel, textD->selectBGPixel,
textD->highlightFGPixel,textD->highlightBGPixel,
textD->lineNumFGPixel, textD->cursorFGPixel);
+
+ TextScrollGroupJoinWith((TextWidget)window->textPanes[i],
+ (TextWidget)orgWin->textPanes[i]);
}
/* Set the minimum pane height in the new pane */
@@ -4351,10 +4356,13 @@
window->inode = orgWin->inode;
window->fileClosedAtom = orgWin->fileClosedAtom;
orgWin->fileClosedAtom = None;
-
+
/* copy the text/split panes settings, cursor pos & selection */
cloneTextPanes(window, orgWin);
-
+
+ TextScrollGroupJoinWith((TextWidget)window->textArea,
+ (TextWidget)orgWin->textArea);
+
/* copy undo & redo list */
window->undo = cloneUndoItems(orgWin->undo);
window->redo = cloneUndoItems(orgWin->redo);
@@ -4639,6 +4647,133 @@
XtDestroyWidget(dialog);
}
+static void scrollGroupDocumentCB(Widget dialog, WindowInfo *window,
+ XtPointer call_data)
+{
+ XmSelectionBoxCallbackStruct *cbs = (XmSelectionBoxCallbackStruct *) call_data;
+ DoneWithScrollGroupDialog = cbs->reason;
+}
+
+/*
+** present dialog for selecting a target window to sync this document
+** with. Do nothing if there is only one shell window opened.
+*/
+void ScrollGroupDialog(WindowInfo *window, int paneIndex)
+{
+ WindowInfo *win;
+ TextWidget text, targetText, *textList;
+ int i, nList = 0, nPanes = 0, ac;
+ char tmpStr[MAXPATHLEN + 64];
+ Widget parent, dialog, listBox;
+ XmString *list = NULL;
+ XmString popupTitle, s1;
+ Arg csdargs[20];
+ int *position_list, position_count;
+
+ if (paneIndex < 0)
+ text = (TextWidget)window->lastFocus;
+ else
+ text = (TextWidget)GetPaneByIndex(window, paneIndex);
+
+ nPanes = 0;
+ for (win = WindowList; win; win = win->next)
+ nPanes += win->nPanes + 1;
+ list = (XmStringTable)XtMalloc(nPanes * sizeof(XmString *));
+ textList = (TextWidget *)XtMalloc(nPanes * sizeof(TextWidget *));
+
+ for (win = WindowList; win; win = win->next) {
+ if (0 == win->nPanes) {
+ if (win == window)
+ continue;
+
+ sprintf(tmpStr, "%s%s",
+ win->filenameSet ? win->path : "", win->filename);
+
+ list[nList] = XmStringCreateSimple(tmpStr);
+ textList[nList] = (TextWidget)win->lastFocus;
+ nList++;
+ }
+ else {
+ for (i = 0; i <= win->nPanes; i++) {
+ TextWidget t = i == 0 ? (TextWidget)win->textArea
+ : (TextWidget)win->textPanes[i - 1];
+ if (text == t)
+ continue;
+
+ sprintf(tmpStr, "[%d] %s%s", i,
+ win->filenameSet ? win->path : "", win->filename);
+
+ list[nList] = XmStringCreateSimple(tmpStr);
+ textList[nList] = t;
+ nList++;
+ }
+ }
+ }
+
+ /* stop here if there's no other window to move to */
+ if (!nList) {
+ XtFree((char *)list);
+ XtFree((char *)textList);
+ return;
+ }
+
+ /* create the dialog */
+ parent = window->shell;
+ popupTitle = XmStringCreateSimple("Scroll Group");
+ sprintf(tmpStr, "Sync scrolling %s with window/group", window->filename);
+ s1 = XmStringCreateSimple(tmpStr);
+ ac = 0;
+ XtSetArg(csdargs[ac], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); ac++;
+ XtSetArg(csdargs[ac], XmNdialogTitle, popupTitle); ac++;
+ XtSetArg(csdargs[ac], XmNlistLabelString, s1); ac++;
+ XtSetArg(csdargs[ac], XmNlistItems, list); ac++;
+ XtSetArg(csdargs[ac], XmNlistItemCount, nList); ac++;
+ XtSetArg(csdargs[ac], XmNvisibleItemCount, 12); ac++;
+ XtSetArg(csdargs[ac], XmNautoUnmanage, False); ac++;
+ dialog = CreateSelectionDialog(parent,"syncDocument",csdargs,ac);
+ XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT));
+ XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
+ XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_SELECTION_LABEL));
+ XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)scrollGroupDocumentCB, window);
+ XtAddCallback(dialog, XmNapplyCallback, (XtCallbackProc)scrollGroupDocumentCB, window);
+ XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)scrollGroupDocumentCB, window);
+ XmStringFree(s1);
+ XmStringFree(popupTitle);
+
+ /* free the window list */
+ for (i=0; i < nList; i++)
+ XmStringFree(list[i]);
+ XtFree((char *)list);
+
+ /* disable option if only one document in the window */
+ XtUnmanageChild(XmSelectionBoxGetChild(dialog, XmDIALOG_APPLY_BUTTON));
+
+ s1 = MKSTRING("Join");
+ XtVaSetValues(dialog, XmNokLabelString, s1, NULL);
+ XmStringFree(s1);
+
+ /* default to the first window on the list */
+ listBox = XmSelectionBoxGetChild(dialog, XmDIALOG_LIST);
+ XmListSelectPos(listBox, 1, True);
+
+ /* show the dialog */
+ DoneWithScrollGroupDialog = 0;
+ ManageDialogCenteredOnPointer(dialog);
+ while (!DoneWithScrollGroupDialog)
+ XtAppProcessEvent(XtWidgetToApplicationContext(parent), XtIMAll);
+
+ /* get the window to sync document into */
+ XmListGetSelectedPos(listBox, &position_list, &position_count);
+ targetText = textList[position_list[0] - 1];
+ XtFree((char *)position_list);
+ XtFree((char *)textList);
+ XtDestroyWidget(dialog);
+
+ /* now sync document */
+ if (DoneWithScrollGroupDialog == XmCR_OK)
+ TextScrollGroupJoinWith(text, targetText);
+}
+
static void hideTooltip(Widget tab)
{
Widget tooltip = XtNameToWidget(tab, "*BubbleShell");
diff -ur nedit.orig/source/window.h nedit.syncscroll/source/window.h
--- nedit.orig/source/window.h 2007-07-02 18:26:16.199244079 +0200
+++ nedit.syncscroll/source/window.h 2007-07-03 22:37:31.260309676 +0200
@@ -92,6 +92,7 @@
WindowInfo *MoveDocument(WindowInfo *toWindow, WindowInfo *window);
WindowInfo *DetachDocument(WindowInfo *window);
void MoveDocumentDialog(WindowInfo *window);
+void ScrollGroupDialog(WindowInfo *window, int paneIndex);
WindowInfo* GetTopDocument(Widget w);
Boolean IsTopDocument(const WindowInfo *window);
int IsIconic(WindowInfo *window);
More information about the Develop
mailing list