From 698cce440f27d53e396808e5ed1723234f23a799 Mon Sep 17 00:00:00 2001 From: edgrif <edgrif> Date: Fri, 11 Jun 2010 16:06:36 +0000 Subject: [PATCH] fix bug causing us not to detect double click, really gdk's problem for not reporting it reliably. Also fix holes in mouse handling. --- src/zmapWindow/zmapWindow.c | 79 ++----- src/zmapWindow/zmapWindowDrawFeatures.c | 121 +++++----- src/zmapWindow/zmapWindowFeature.c | 287 +++++++++++++----------- 3 files changed, 218 insertions(+), 269 deletions(-) diff --git a/src/zmapWindow/zmapWindow.c b/src/zmapWindow/zmapWindow.c index 0d9937a49..77010b37d 100755 --- a/src/zmapWindow/zmapWindow.c +++ b/src/zmapWindow/zmapWindow.c @@ -26,9 +26,9 @@ * * Exported functions: See ZMap/zmapWindow.h * HISTORY: - * Last edited: May 24 16:04 2010 (edgrif) + * Last edited: Jun 11 16:31 2010 (edgrif) * Created: Thu Jul 24 14:36:27 2003 (edgrif) - * CVS info: $Id: zmapWindow.c,v 1.325 2010-06-10 14:50:31 mh17 Exp $ + * CVS info: $Id: zmapWindow.c,v 1.326 2010-06-11 16:06:36 edgrif Exp $ *------------------------------------------------------------------- */ @@ -2710,24 +2710,8 @@ static gboolean windowGeneralEventCB(GtkWidget *wigdet, GdkEvent *event, gpointe * zooming and we track mouse movements, if they have moved far enough then we do the zoom * on button release. * - * BUT if on button release they have only moved a tiny amount it means that they meant - * to _select_ a feature or column, _not_ lasso. In this case we have to reissue the original - * button press event, when we then receive that event we just ignore it so that its passed - * through to the object select code. - * - * A note from Roy (!): - * - * PLEASE be very careful when altering this function, as I've - * already messed stuff up when working on it! The event_handled - * boolean _SHOULD_ be set to true any time we handle the event. - * While this sounds obvious I fell over it when implementing the - * motion as well as button down and release. If there is a track - * of events, such as button/key down .. motion .. button release - * then the event_handled should be true for the whole of the life - * of the track of events. All of the statics above could/probably - * should be replaced with a struct... please think about this if - * adding any more! - * + * If the user does lassoing, ruler or moving the mark then we return TRUE to say we have + * handled the event, otherwise we pass the event on (so canvas items can receive events). */ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer data) { @@ -2741,12 +2725,8 @@ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer or rubber banding ? */ double wx, wy; /* These hold the current world coords of the event */ static double window_x, window_y ; /* Track number of pixels user moves mouse. */ - static GdkEventButton *but_press_copy = NULL ; /* Used to implement both lasso _and_ object - select with left button click. */ static MarkRegionUpdateStruct mark_updater = {0}; - /* We need to check that canvas is mapped here (slow connections) */ - /* We record whether we are inside the window to enable user to cancel certain mouse related * actions by moving outside the window. */ @@ -2790,18 +2770,8 @@ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer { case 1: { - - if (but_event->send_event) - { - /* If we receive a button press event where send_event == TRUE, its the one we sent ourselves - * to do feature select so don't process it. */ - - zMapDebugPrint(mouse_debug_G, "button_press %d was sent by us - don't process", but_event->button) ; - - event_handled = FALSE ; - } - else if ((item = foo_canvas_get_item_at(window->canvas, origin_x, origin_y)) - && ZMAP_IS_WINDOW_TEXT_ITEM(item)) + if ((item = foo_canvas_get_item_at(window->canvas, origin_x, origin_y)) + && ZMAP_IS_WINDOW_TEXT_ITEM(item)) { /* Don't handle if its text because the text item callbacks handle lasso'ing of * text. */ @@ -2815,9 +2785,6 @@ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer { /* Pucka button press that we need to handle. */ - /* Take a copy of the initial event in case we need to resend it to do feature select. */ - but_press_copy = (GdkEventButton *)gdk_event_copy((GdkEvent *)event) ; - /* Record where are we in the window at the start of mouse/button movement. */ window_x = but_event->x ; window_y = but_event->y ; @@ -2840,7 +2807,9 @@ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer window->rubberband = zMapDrawRubberbandCreate(window->canvas); } - event_handled = TRUE ; + /* At this stage we don't know if we are rubber banding etc. so pass the + * press on. */ + event_handled = FALSE ; } break ; @@ -2931,7 +2900,6 @@ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer } case GDK_MOTION_NOTIFY: { - /* interestingly we don't check the button number here.... */ if (dragging || guide) @@ -3057,11 +3025,11 @@ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer &wx, mark_updater.closest_to); wy = *(mark_updater.closest_to); moveRuler(window->mark_guide_line, NULL, NULL, wx, wy); + event_handled = TRUE; } - else if (mark_updater.in_mark_move_region && - (!mark_updater.activated) && - zmapWindowMarkIsSet(window->mark)) + else if (mark_updater.in_mark_move_region && (!mark_updater.activated) + && zmapWindowMarkIsSet(window->mark)) { GdkEventMotion *mot_event = (GdkEventMotion *)event; double world_dy; @@ -3080,8 +3048,8 @@ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer world_dy = canvas_dy / window->canvas->pixels_per_unit_y; - if((!((wy > mark_updater.mark_y1 - world_dy) && (wy < mark_updater.mark_y1 + world_dy))) && - (!((wy > mark_updater.mark_y2 - world_dy) && (wy < mark_updater.mark_y2 + world_dy)))) + if ((!((wy > mark_updater.mark_y1 - world_dy) && (wy < mark_updater.mark_y1 + world_dy))) + && (!((wy > mark_updater.mark_y2 - world_dy) && (wy < mark_updater.mark_y2 + world_dy)))) { mark_updater.in_mark_move_region = FALSE; mark_updater.closest_to = NULL; @@ -3125,34 +3093,17 @@ static gboolean canvasWindowEventCB(GtkWidget *widget, GdkEvent *event, gpointer zoomToRubberBandArea(window) ; - /* If there was a previous copy of a button press event we _know_ we - * can throw it away at this point because it will have been processed by - * a previous call to this routine. */ - if (but_press_copy) - { - gdk_event_free((GdkEvent *)but_press_copy) ; - but_press_copy = NULL ; - } - event_handled = TRUE; /* We _ARE_ handling */ } else { /* User hasn't really moved which means they meant to select a feature, not - * lasso an area so resend original button press so it will then be propagated - * down to item select code. */ + * lasso an area so pass event on and destroy rubberband object. */ /* Must get rid of rubberband item as it is not needed. */ gtk_object_destroy(GTK_OBJECT(window->rubberband)) ; window->rubberband = NULL ; - but_press_copy->send_event = TRUE ; /* Vital for use to detect that we - sent this event. */ - but_press_copy->time = but_event->time ; - gdk_event_put((GdkEvent *)but_press_copy) ; - - zMapDebugPrint(mouse_debug_G, "Resending original button_press %d", but_event->button) ; - event_handled = FALSE ; } } diff --git a/src/zmapWindow/zmapWindowDrawFeatures.c b/src/zmapWindow/zmapWindowDrawFeatures.c index 920f75ffb..029bcd3e0 100755 --- a/src/zmapWindow/zmapWindowDrawFeatures.c +++ b/src/zmapWindow/zmapWindowDrawFeatures.c @@ -26,9 +26,9 @@ * * Exported functions: * HISTORY: - * Last edited: Mar 11 14:19 2010 (edgrif) + * Last edited: Jun 11 16:09 2010 (edgrif) * Created: Thu Jul 29 10:45:00 2004 (rnc) - * CVS info: $Id: zmapWindowDrawFeatures.c,v 1.276 2010-06-10 14:50:31 mh17 Exp $ + * CVS info: $Id: zmapWindowDrawFeatures.c,v 1.277 2010-06-11 16:06:36 edgrif Exp $ *------------------------------------------------------------------- */ @@ -2139,97 +2139,76 @@ static gboolean strandBoundingBoxEventCB(FooCanvasItem *item, GdkEvent *event, g } +/* Handles events on a column, currently this is only mouse press/release events for + * highlighting and column menus. */ static gboolean columnBoundingBoxEventCB(FooCanvasItem *item, GdkEvent *event, gpointer data) { gboolean event_handled = FALSE ; - ZMapWindow window = (ZMapWindow)data ; - switch (event->type) + if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) { - case GDK_BUTTON_PRESS: - { - GdkEventButton *but_event = (GdkEventButton *)event ; - ZMapFeatureSet feature_set = NULL ; - ZMapWindowContainerFeatureSet container_set; - ZMapWindowContainerGroup container_parent; - - container_parent = zmapWindowContainerChildGetParent(item); - - /* These should go in container some time.... */ - container_set = (ZMapWindowContainerFeatureSet)container_parent; - - feature_set = zmapWindowContainerFeatureSetRecoverFeatureSet(container_set); + ZMapWindow window = (ZMapWindow)data ; + GdkEventButton *but_event = (GdkEventButton *)event ; + ZMapFeatureSet feature_set = NULL ; + ZMapWindowContainerFeatureSet container_set; + ZMapWindowContainerGroup container_parent; - zMapAssert(feature_set || container_set) ; + container_parent = zmapWindowContainerChildGetParent(item); -#warning COLUMN_HIGHLIGHT_NEEDS_TO_WORK_WITH_MULTIPLE_WINDOWS - /* Swop focus from previous item(s)/columns to this column. */ - zMapWindowUnHighlightFocusItems(window) ; + /* These should go in container some time.... */ + container_set = (ZMapWindowContainerFeatureSet)container_parent; + feature_set = zmapWindowContainerFeatureSetRecoverFeatureSet(container_set); + zMapAssert(feature_set || container_set) ; - zmapWindowFocusSetHotColumn(window->focus, (FooCanvasGroup *)container_parent); - zmapHighlightColumn(window, (FooCanvasGroup *)container_parent) ; - /* Button 1 and 3 are handled, 2 is passed on to a general handler which could be - * the root handler. */ - switch (but_event->button) - { - case 1: + /* Only buttons 1 and 3 are handled. */ + if (event->type == GDK_BUTTON_PRESS && but_event->button == 3) + { + /* Do the column menu. */ + if (feature_set) { - ZMapWindowSelectStruct select = {0} ; - GQuark feature_set_id ; - char *clipboard_text = NULL; + zmapMakeColumnMenu(but_event, window, item, feature_set, NULL) ; + + event_handled = TRUE ; + } + } + else if (event->type == GDK_BUTTON_RELEASE && but_event->button == 1) + { + /* Highlight a column. */ + ZMapWindowSelectStruct select = {0} ; + GQuark feature_set_id ; + char *clipboard_text = NULL; - if (feature_set) - feature_set_id = feature_set->original_id ; - else - feature_set_id = zmapWindowContainerFeatureSetColumnDisplayName(container_set); +#warning COLUMN_HIGHLIGHT_NEEDS_TO_WORK_WITH_MULTIPLE_WINDOWS + /* Swop focus from previous item(s)/columns to this column. */ + zMapWindowUnHighlightFocusItems(window) ; - select.feature_desc.struct_type = ZMAPFEATURE_STRUCT_FEATURESET ; + zmapWindowFocusSetHotColumn(window->focus, (FooCanvasGroup *)container_parent); + zmapHighlightColumn(window, (FooCanvasGroup *)container_parent) ; - select.feature_desc.feature_set = (char *)g_quark_to_string(feature_set_id) ; + if (feature_set) + feature_set_id = feature_set->original_id ; + else + feature_set_id = zmapWindowContainerFeatureSetColumnDisplayName(container_set); - select.feature_desc.feature_set_description = zmapWindowFeatureSetDescription(feature_set) ; + select.feature_desc.struct_type = ZMAPFEATURE_STRUCT_FEATURESET ; - clipboard_text = zmapWindowFeatureSetDescription(feature_set) ; + select.feature_desc.feature_set = (char *)g_quark_to_string(feature_set_id) ; - select.type = ZMAPWINDOW_SELECT_SINGLE; + select.feature_desc.feature_set_description = zmapWindowFeatureSetDescription(feature_set) ; - (*(window->caller_cbs->select))(window, window->app_data, (void *)&select) ; + clipboard_text = zmapWindowFeatureSetDescription(feature_set) ; - zMapWindowUtilsSetClipboard(window, clipboard_text); + select.type = ZMAPWINDOW_SELECT_SINGLE; - g_free(clipboard_text) ; + (*(window->caller_cbs->select))(window, window->app_data, (void *)&select) ; - event_handled = TRUE ; - break ; - } - /* There are > 3 button mouse, e.g. scroll wheels, which we don't want to handle. */ - default: - case 2: - { - event_handled = FALSE ; - break ; - } - case 3: - { - if (feature_set) - { - zmapMakeColumnMenu(but_event, window, item, feature_set, NULL) ; + zMapWindowUtilsSetClipboard(window, clipboard_text); - event_handled = TRUE ; - } - break ; - } - } - break ; - } - default: - { - /* By default we _don't_ handle events. */ - event_handled = FALSE ; + g_free(clipboard_text) ; - break ; - } + event_handled = TRUE ; + } } return event_handled ; diff --git a/src/zmapWindow/zmapWindowFeature.c b/src/zmapWindow/zmapWindowFeature.c index 9bd98e629..6dfdc61fb 100755 --- a/src/zmapWindow/zmapWindowFeature.c +++ b/src/zmapWindow/zmapWindowFeature.c @@ -28,9 +28,9 @@ * * Exported functions: See zmapWindow_P.h * HISTORY: - * Last edited: May 5 16:32 2010 (edgrif) + * Last edited: Jun 11 16:58 2010 (edgrif) * Created: Mon Jan 9 10:25:40 2006 (edgrif) - * CVS info: $Id: zmapWindowFeature.c,v 1.187 2010-06-10 14:50:31 mh17 Exp $ + * CVS info: $Id: zmapWindowFeature.c,v 1.188 2010-06-11 16:06:36 edgrif Exp $ *------------------------------------------------------------------- */ @@ -145,6 +145,8 @@ static ZMapGUIMenuItem makeMenuGeneralOps(int *start_index_inout, static void itemMenuCB(int menu_item_id, gpointer callback_data) ; static gboolean canvasItemEventCB(FooCanvasItem *item, GdkEvent *event, gpointer data) ; +static gboolean handleButton(GdkEventButton *but_event, ZMapWindow window, FooCanvasItem *item, ZMapFeature feature) ; + static gboolean canvasItemDestroyCB(FooCanvasItem *item, gpointer data) ; static void pfetchEntry(ZMapWindow window, char *sequence_name) ; @@ -794,33 +796,29 @@ static void featureCopySelectedItem(ZMapFeature feature_in, -/* SORT OUT HIGHLIGHTING BUG....... */ - +/* Handle events on items, note that events for text items are passed through without processing + * so the text item code can do highlighting etc. */ static gboolean canvasItemEventCB(FooCanvasItem *item, GdkEvent *event, gpointer data) { gboolean event_handled = FALSE ; /* By default we _don't_ handle events. */ ZMapWindow window = (ZMapWindowStruct*)data ; ZMapFeature feature ; - static guint32 last_but_press = 0 ; /* Used for double clicks... */ + static guint32 last_but_release = 0 ; /* Used for double clicks... */ static gboolean second_press = FALSE ; /* Used for double clicks... */ if (event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) { GdkEventButton *but_event = (GdkEventButton *)event ; - ZMapFeatureSubPartSpan sub_feature ; - ZMapWindowCanvasItem canvas_item ; - FooCanvasItem *sub_item = NULL, *highlight_item = NULL ; + FooCanvasItem *highlight_item = NULL ; zMapDebugPrint(mouse_debug_G, "Start: %s %d", (event->type == GDK_BUTTON_PRESS ? "button_press" : event->type == GDK_2BUTTON_PRESS ? "button_2press" : "button_release"), but_event->button) ; - if (!ZMAP_IS_CANVAS_ITEM(item)) { - #ifdef ED_G_NEVER_INCLUDE_THIS_CODE g_warning("Not a ZMapWindowCanvasItem."); #endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ @@ -833,136 +831,17 @@ static gboolean canvasItemEventCB(FooCanvasItem *item, GdkEvent *event, gpointer return FALSE; } - canvas_item = ZMAP_CANVAS_ITEM(item); - /* Get the feature attached to the item, checking that its type is valid */ feature = zMapWindowCanvasItemGetFeature(item); - sub_item = zMapWindowCanvasItemGetInterval(canvas_item, but_event->x, but_event->y, &sub_feature); - if (but_event->type == GDK_BUTTON_PRESS) { - /* Double clicks occur within 250 milliseconds so we ignore the second button - * press generated by clicks but catch the button2 press (see below). */ - if (but_event->time - last_but_press > 250) + if (but_event->button == 3) { - GdkModifierType shift_mask = GDK_SHIFT_MASK, - control_mask = GDK_CONTROL_MASK, - shift_control_mask = GDK_SHIFT_MASK | GDK_CONTROL_MASK, - unwanted_masks = GDK_LOCK_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK | GDK_MOD5_MASK, - locks_mask; - - /* In order to make the modifier only checks work we - * need to OR in the unwanted masks that might be on. - * This includes the shift lock and num lock. - * Depending on the setup of X these might be mapped - * to other things which is why MODs 2-5 are included - * This in theory should include the new (since 2.10) - * GDK_SUPER_MASK, GDK_HYPER_MASK and GDK_META_MASK */ - if((locks_mask = (but_event->state & unwanted_masks))) - { - shift_mask |= locks_mask; - control_mask |= locks_mask; - shift_control_mask |= locks_mask; - } - - /* Button 1 and 3 are handled, 2 is left for a general handler which could be - * the root handler. */ - if (but_event->button == 1 || but_event->button == 3) - { - gboolean replace_highlight = TRUE, highlight_same_names = TRUE, externally_handled = FALSE; - - if (zMapGUITestModifiersOnly(but_event, shift_mask)) - { - ZMapFeatureStruct feature_copy = {}; - - /* Only highlight the single item user clicked on. */ - highlight_same_names = FALSE ; - - /* Annotators say they don't want subparts sub selections + multiple - * selections for alignments. */ - if (feature->type == ZMAPSTYLE_MODE_ALIGNMENT) - { - highlight_item = item; - } - else - { - highlight_item = sub_item ; - } - - - /* monkey around to get feature_copy to be the right correct data */ - featureCopySelectedItem(feature, &feature_copy, highlight_item); - - if (zmapWindowFocusIsItemInHotColumn(window->focus, highlight_item) - && window->multi_select) - { - replace_highlight = FALSE ; - externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)(&feature_copy), - "multiple_select", highlight_item); - } - else - { - externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)(&feature_copy), - "single_select", highlight_item); - window->multi_select = TRUE ; - } - } -#ifdef ED_G_NEVER_INCLUDE_THIS_CODE - /* I've left this in because we might want to use Cntl-xxx at some time .... */ - else if (zMapGUITestModifiersOnly(but_event, control_mask)) - { - ZMapFeatureStruct feature_copy = {}; - - /* sub selections */ - highlight_item = sub_item ; - highlight_same_names = FALSE ; - - /* monkey around to get feature_copy to be the right correct data */ - featureCopySelectedItem(feature, &feature_copy, - highlight_item); - externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)(&feature_copy), "single_select", highlight_item); - } -#endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ - else if (zMapGUITestModifiersOnly(but_event, shift_control_mask)) - { - /* multiple selections */ - highlight_item = item; - - if (zmapWindowFocusIsItemInHotColumn(window->focus, highlight_item) - && window->multi_select) - { - replace_highlight = FALSE ; - externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)feature, "multiple_select", highlight_item); - } - else - { - externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)feature, "single_select", highlight_item); - window->multi_select = TRUE ; - } - } - else - { - /* single select */ - highlight_item = item; - externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)feature, "single_select", highlight_item); - window->multi_select = FALSE ; - } - - /* Pass information about the object clicked on back to the application. */ - zMapWindowUpdateInfoPanel(window, feature, sub_item, highlight_item, NULL, - replace_highlight, highlight_same_names) ; - - if (but_event->button == 3) - { - /* Pop up an item menu. */ - zmapMakeItemMenu(but_event, window, highlight_item) ; - } - } + /* Pop up an item menu. */ + zmapMakeItemMenu(but_event, window, item) ; } - last_but_press = but_event->time ; - event_handled = TRUE ; } else if (but_event->type == GDK_2BUTTON_PRESS) @@ -973,15 +852,24 @@ static gboolean canvasItemEventCB(FooCanvasItem *item, GdkEvent *event, gpointer } else /* button release */ { - if (second_press) + /* Gdk defines double clicks as occuring within 250 milliseconds of each other + * but unfortunately if on the first click we do a lot of processing, + * STUPID Gdk no longer delivers the GDK_2BUTTON_PRESS so we have to do this + * hack looking for the different in time. This can happen if user clicks on + * a very large feature causing us to paste a lot of text to the selection + * buffer. */ + guint but_threshold = 500 ; /* Separation of clicks in milliseconds. */ + + if (second_press || but_event->time - last_but_release < but_threshold) { - /* Handle second click of a double click. */ + /* Second click of a double click means show feature details. */ if (but_event->button == 1) { gboolean externally_handled = FALSE ; highlight_item = item; + /* If no external handling then show what we can. */ if (!(externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)feature, "edit", highlight_item))) { @@ -991,6 +879,12 @@ static gboolean canvasItemEventCB(FooCanvasItem *item, GdkEvent *event, gpointer second_press = FALSE ; } + else + { + event_handled = handleButton(but_event, window, item, feature) ; + } + + last_but_release = but_event->time ; event_handled = TRUE ; } @@ -1009,6 +903,131 @@ static gboolean canvasItemEventCB(FooCanvasItem *item, GdkEvent *event, gpointer } +/* Handle button single press to highlight and double to show feature details. */ +static gboolean handleButton(GdkEventButton *but_event, ZMapWindow window, FooCanvasItem *item, ZMapFeature feature) +{ + gboolean event_handled = FALSE ; + GdkModifierType shift_mask = GDK_SHIFT_MASK, + control_mask = GDK_CONTROL_MASK, + shift_control_mask = GDK_SHIFT_MASK | GDK_CONTROL_MASK, + unwanted_masks = GDK_LOCK_MASK | GDK_MOD2_MASK | GDK_MOD3_MASK | GDK_MOD4_MASK | GDK_MOD5_MASK, + locks_mask; + + /* In order to make the modifier only checks work we + * need to OR in the unwanted masks that might be on. + * This includes the shift lock and num lock. + * Depending on the setup of X these might be mapped + * to other things which is why MODs 2-5 are included + * This in theory should include the new (since 2.10) + * GDK_SUPER_MASK, GDK_HYPER_MASK and GDK_META_MASK */ + if((locks_mask = (but_event->state & unwanted_masks))) + { + shift_mask |= locks_mask; + control_mask |= locks_mask; + shift_control_mask |= locks_mask; + } + + /* Button 1 and 3 are handled, 2 is left for a general handler which could be + * the root handler. */ + if (but_event->button == 1 || but_event->button == 3) + { + FooCanvasItem *sub_item = NULL, *highlight_item = NULL ; + gboolean replace_highlight = TRUE, highlight_same_names = TRUE, externally_handled = FALSE; + ZMapFeatureSubPartSpan sub_feature ; + ZMapWindowCanvasItem canvas_item ; + + canvas_item = ZMAP_CANVAS_ITEM(item); + + sub_item = zMapWindowCanvasItemGetInterval(canvas_item, but_event->x, but_event->y, &sub_feature); + + if (zMapGUITestModifiersOnly(but_event, shift_mask)) + { + ZMapFeatureStruct feature_copy = {}; + + /* Only highlight the single item user clicked on. */ + highlight_same_names = FALSE ; + + /* Annotators say they don't want subparts sub selections + multiple + * selections for alignments. */ + if (feature->type == ZMAPSTYLE_MODE_ALIGNMENT) + { + highlight_item = item; + } + else + { + highlight_item = sub_item ; + } + + + /* monkey around to get feature_copy to be the right correct data */ + featureCopySelectedItem(feature, &feature_copy, highlight_item); + + if (zmapWindowFocusIsItemInHotColumn(window->focus, highlight_item) + && window->multi_select) + { + replace_highlight = FALSE ; + externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)(&feature_copy), + "multiple_select", highlight_item); + } + else + { + externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)(&feature_copy), + "single_select", highlight_item); + window->multi_select = TRUE ; + } + } +#ifdef ED_G_NEVER_INCLUDE_THIS_CODE + /* I've left this in because we might want to use Cntl-xxx at some time .... */ + else if (zMapGUITestModifiersOnly(but_event, control_mask)) + { + ZMapFeatureStruct feature_copy = {}; + + /* sub selections */ + highlight_item = sub_item ; + highlight_same_names = FALSE ; + + /* monkey around to get feature_copy to be the right correct data */ + featureCopySelectedItem(feature, &feature_copy, + highlight_item); + externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)(&feature_copy), "single_select", highlight_item); + } +#endif /* ED_G_NEVER_INCLUDE_THIS_CODE */ + else if (zMapGUITestModifiersOnly(but_event, shift_control_mask)) + { + /* multiple selections */ + highlight_item = item; + + if (zmapWindowFocusIsItemInHotColumn(window->focus, highlight_item) + && window->multi_select) + { + replace_highlight = FALSE ; + externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)feature, "multiple_select", highlight_item); + } + else + { + externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)feature, "single_select", highlight_item); + window->multi_select = TRUE ; + } + } + else + { + /* single select */ + highlight_item = item; + externally_handled = zmapWindowUpdateXRemoteData(window, (ZMapFeatureAny)feature, "single_select", highlight_item); + window->multi_select = FALSE ; + } + + /* Pass information about the object clicked on back to the application. */ + zMapWindowUpdateInfoPanel(window, feature, sub_item, highlight_item, NULL, + replace_highlight, highlight_same_names) ; + } + + + return event_handled ; +} + + + /* Build the menu for a feature item. */ void zmapMakeItemMenu(GdkEventButton *button_event, ZMapWindow window, FooCanvasItem *item) -- GitLab