gimp r26331 - in branches/soc-2008-tagging: . app/widgets
- From: aurisj svn gnome org
- To: svn-commits-list gnome org
- Subject: gimp r26331 - in branches/soc-2008-tagging: . app/widgets
- Date: Mon, 28 Jul 2008 21:25:05 +0000 (UTC)
Author: aurisj
Date: Mon Jul 28 21:25:05 2008
New Revision: 26331
URL: http://svn.gnome.org/viewvc/gimp?rev=26331&view=rev
Log:
2008-07-29 Aurimas JuÅka <aurisj svn gnome org>
* app/widgets/Makefile.am
* app/widgets/gimpcombotagentry.c
* app/widgets/gimptagpopup.[ch]
* app/widgets/widgets-types.h: popup part of GimpComboTagEntry has
been moved to a separate class GimpTagPopup in order to prepare for
upcoming feature additions.
Added:
branches/soc-2008-tagging/app/widgets/gimptagpopup.c
branches/soc-2008-tagging/app/widgets/gimptagpopup.h
Modified:
branches/soc-2008-tagging/ChangeLog
branches/soc-2008-tagging/app/widgets/Makefile.am
branches/soc-2008-tagging/app/widgets/gimpcombotagentry.c
branches/soc-2008-tagging/app/widgets/widgets-types.h
Modified: branches/soc-2008-tagging/app/widgets/Makefile.am
==============================================================================
--- branches/soc-2008-tagging/app/widgets/Makefile.am (original)
+++ branches/soc-2008-tagging/app/widgets/Makefile.am Mon Jul 28 21:25:05 2008
@@ -265,6 +265,8 @@
gimpstrokeeditor.h \
gimptagentry.c \
gimptagentry.h \
+ gimptagpopup.c \
+ gimptagpopup.h \
gimptemplateeditor.c \
gimptemplateeditor.h \
gimptemplateview.c \
Modified: branches/soc-2008-tagging/app/widgets/gimpcombotagentry.c
==============================================================================
--- branches/soc-2008-tagging/app/widgets/gimpcombotagentry.c (original)
+++ branches/soc-2008-tagging/app/widgets/gimpcombotagentry.c Mon Jul 28 21:25:05 2008
@@ -35,49 +35,9 @@
#include "core/gimptagged.h"
#include "gimptagentry.h"
+#include "gimptagpopup.h"
#include "gimpcombotagentry.h"
-#define MENU_SCROLL_STEP1 8
-#define MENU_SCROLL_STEP2 15
-#define MENU_SCROLL_FAST_ZONE 8
-#define MENU_SCROLL_TIMEOUT1 50
-#define MENU_SCROLL_TIMEOUT2 20
-
-#define GIMP_TAG_POPUP_MARGIN 5
-
-typedef struct
-{
- GimpTag *tag;
- GdkRectangle bounds;
- gboolean selected;
-} PopupTagData;
-
-typedef struct
-{
- GimpComboTagEntry *combo_entry;
- GtkWidget *popup;
- GtkWidget *alignment;
- GtkWidget *drawing_area;
- PangoContext *context;
- PangoLayout *layout;
- PopupTagData *tag_data;
- PopupTagData *prelight;
- gint tag_count;
- guint timeout_id;
- gint scroll_height;
- gint scroll_y;
- gint scroll_step;
- gint scroll_arrow_height;
- gboolean scroll_fast;
- gboolean arrows_visible;
- gboolean ignore_button_release;
- gboolean upper_arrow_prelight;
- gboolean lower_arrow_prelight;
- GtkStateType upper_arrow_state;
- GtkStateType lower_arrow_state;
-} PopupData;
-
-
static void gimp_combo_tag_entry_dispose (GObject *object);
static gboolean gimp_combo_tag_entry_expose_event (GtkWidget *widget,
GdkEventExpose *event,
@@ -92,32 +52,6 @@
GdkEvent *event,
gpointer user_data);
static void gimp_combo_tag_entry_popup_list (GimpComboTagEntry *combo_entry);
-static gboolean gimp_combo_tag_entry_popup_border_expose (GtkWidget *widget,
- GdkEventExpose *event,
- PopupData *popup_data);
-static gboolean gimp_combo_tag_entry_popup_expose (GtkWidget *widget,
- GdkEventExpose *event,
- PopupData *popup_dta);
-static gboolean gimp_combo_tag_entry_popup_event (GtkWidget *widget,
- GdkEvent *event,
- PopupData *popup_data);
-static gboolean gimp_combo_tag_entry_drawing_area_event(GtkWidget *widget,
- GdkEvent *event,
- PopupData *popup_data);
-static void gimp_combo_tag_entry_toggle_tag (GimpComboTagEntry *combo_entry,
- PopupTagData *tag_data);
-static gint gimp_combo_tag_entry_layout_tags (PopupData *popup_data,
- gint width);
-static void gimp_tag_popup_do_timeout_scroll (PopupData *popup_data,
- gboolean touchscreen_mode);
-
-static void popup_data_destroy (PopupData *popup_data);
-
-static void get_arrows_visible_area (PopupData *combo_entry,
- GdkRectangle *border,
- GdkRectangle *upper,
- GdkRectangle *lower,
- gint *arrow_space);
G_DEFINE_TYPE (GimpComboTagEntry, gimp_combo_tag_entry, GTK_TYPE_EVENT_BOX);
@@ -305,6 +239,11 @@
pango_attr_list_unref (combo_entry->normal_item_attr);
}
combo_entry->normal_item_attr = pango_attr_list_new ();
+ if (style->font_desc)
+ {
+ attribute = pango_attr_font_desc_new (style->font_desc);
+ pango_attr_list_insert (combo_entry->normal_item_attr, attribute);
+ }
color = style->text[GTK_STATE_NORMAL];
attribute = pango_attr_foreground_new (color.red, color.green, color.blue);
pango_attr_list_insert (combo_entry->normal_item_attr, attribute);
@@ -383,1019 +322,6 @@
static void
gimp_combo_tag_entry_popup_list (GimpComboTagEntry *combo_entry)
{
- GtkWidget *popup;
- GtkWidget *alignment;
- GtkWidget *drawing_area;
- GtkWidget *frame;
- gint x;
- gint y;
- gint width;
- gint height;
- gint popup_height;
- PopupData *popup_data;
- GHashTable *tag_hash;
- GList *tag_list;
- GList *tag_iterator;
- gint i;
- gint j;
- GdkGrabStatus grab_status;
- gint max_height;
- gint screen_height;
- gchar **current_tags;
- gint current_count;
- const gchar *list_tag;
- GdkRectangle popup_rects[2]; /* variants of popup placement */
- GdkRectangle popup_rect; /* best popup rect in screen coordinates */
-
- popup = gtk_window_new (GTK_WINDOW_POPUP);
- combo_entry->popup = popup;
- gtk_widget_add_events (GTK_WIDGET (popup),
- GDK_BUTTON_PRESS_MASK
- | GDK_BUTTON_RELEASE_MASK
- | GDK_POINTER_MOTION_MASK);
- gtk_window_set_screen (GTK_WINDOW (popup),
- gtk_widget_get_screen (GTK_WIDGET (combo_entry)));
-
- frame = gtk_frame_new (NULL);
- gtk_container_add (GTK_CONTAINER (popup), frame);
-
- alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
- gtk_container_add (GTK_CONTAINER (frame), alignment);
-
- drawing_area = gtk_drawing_area_new ();
- gtk_widget_add_events (GTK_WIDGET (drawing_area),
- GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
- gtk_container_add (GTK_CONTAINER (alignment), drawing_area);
-
- popup_data = g_malloc (sizeof (PopupData));
- memset (popup_data, 0, sizeof (PopupData));
- popup_data->popup = popup;
- popup_data->combo_entry = combo_entry;
- popup_data->alignment = alignment;
- popup_data->drawing_area = drawing_area;
- popup_data->context = gtk_widget_create_pango_context (GTK_WIDGET (popup));
- popup_data->layout = pango_layout_new (popup_data->context);
- popup_data->prelight = NULL;
- popup_data->upper_arrow_state = GTK_STATE_NORMAL;
- popup_data->lower_arrow_state = GTK_STATE_NORMAL;
- gtk_widget_style_get (popup,
- "scroll-arrow-vlength", &popup_data->scroll_arrow_height,
- NULL);
-
-
- current_tags = gimp_tag_entry_parse_tags (GIMP_TAG_ENTRY (combo_entry->tag_entry));
- current_count = g_strv_length (current_tags);
-
- tag_hash = GIMP_TAG_ENTRY (combo_entry->tag_entry)->tagged_container->tag_ref_counts;
- tag_list = g_hash_table_get_keys (tag_hash);
- tag_list = g_list_sort (tag_list, gimp_tag_compare_func);
- popup_data->tag_count = g_list_length (tag_list);
- popup_data->tag_data = g_malloc (sizeof (PopupTagData) * popup_data->tag_count);
- tag_iterator = tag_list;
- for (i = 0; i < popup_data->tag_count; i++)
- {
- popup_data->tag_data[i].tag = GIMP_TAG (tag_iterator->data);
- popup_data->tag_data[i].selected = FALSE;
- list_tag = gimp_tag_get_name (popup_data->tag_data[i].tag);
- for (j = 0; j < current_count; j++)
- {
- if (! strcmp (current_tags[j], list_tag))
- {
- popup_data->tag_data[i].selected = TRUE;
- break;
- }
- }
- tag_iterator = g_list_next (tag_iterator);
- }
- g_list_free (tag_list);
- g_strfreev (current_tags);
-
- width = GTK_WIDGET (combo_entry)->allocation.width - frame->style->xthickness * 2;
- height = gimp_combo_tag_entry_layout_tags (popup_data, width);
- gdk_window_get_origin (GTK_WIDGET (combo_entry)->window, &x, &y);
- max_height = GTK_WIDGET (combo_entry)->allocation.height * 7;
- screen_height = gdk_screen_get_height (gtk_widget_get_screen (GTK_WIDGET (combo_entry)));
- height += frame->style->ythickness * 2;
- popup_height = height;
- popup_rects[0].x = x;
- popup_rects[0].y = 0;
- popup_rects[0].width = GTK_WIDGET (combo_entry)->allocation.width;
- popup_rects[0].height = y + GTK_WIDGET (combo_entry)->allocation.height;
- popup_rects[1].x = popup_rects[0].x;
- popup_rects[1].y = y;
- popup_rects[1].width = popup_rects[0].width;
- popup_rects[1].height = screen_height - popup_rects[0].height;
- if (popup_rects[0].height >= popup_height)
- {
- popup_rect = popup_rects[0];
- popup_rect.y += popup_rects[0].height - popup_height;
- popup_rect.height = popup_height;
- }
- else if (popup_rects[1].height >= popup_height)
- {
- popup_rect = popup_rects[1];
- popup_rect.height = popup_height;
- }
- else
- {
- if (popup_rects[0].height >= popup_rects[1].height)
- {
- popup_rect = popup_rects[0];
- popup_rect.y += popup_data->scroll_arrow_height + frame->style->ythickness;
- }
- else
- {
- popup_rect = popup_rects[1];
- popup_rect.y -= popup_data->scroll_arrow_height + frame->style->ythickness;
- }
-
- popup_data->arrows_visible = TRUE;
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
- popup_data->scroll_arrow_height + 2,
- popup_data->scroll_arrow_height + 2, 2, 2);
- popup_height = popup_rect.height - popup_data->scroll_arrow_height * 2 + 4;
- popup_data->scroll_height = height - popup_rect.height;
- popup_data->scroll_y = 0;
- popup_data->scroll_step = 0;
- }
-
-
- drawing_area->requisition.width = width;
- drawing_area->requisition.height = popup_height;
-
- gtk_window_move (GTK_WINDOW (popup), popup_rect.x, popup_rect.y);
- gtk_window_resize (GTK_WINDOW (popup), popup_rect.width, popup_rect.height);
-
- gtk_widget_show_all (GTK_WIDGET (popup));
-
- g_object_set_data_full (G_OBJECT (popup), "popup-data",
- popup_data, (GDestroyNotify) popup_data_destroy);
-
- g_signal_connect (alignment, "expose-event",
- G_CALLBACK (gimp_combo_tag_entry_popup_border_expose),
- popup_data);
- g_signal_connect (drawing_area, "expose-event",
- G_CALLBACK (gimp_combo_tag_entry_popup_expose),
- popup_data);
- g_signal_connect (drawing_area, "event",
- G_CALLBACK (gimp_combo_tag_entry_drawing_area_event),
- popup_data);
- g_signal_connect (popup, "event",
- G_CALLBACK (gimp_combo_tag_entry_popup_event),
- popup_data);
-
- gtk_grab_add (popup);
- gtk_widget_grab_focus (combo_entry->tag_entry);
- grab_status = gdk_pointer_grab (popup->window, TRUE,
- GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK, NULL, NULL,
- GDK_CURRENT_TIME);
- if (grab_status != GDK_GRAB_SUCCESS)
- {
- /* pointer grab must be attained otherwise user would have
- * problems closing the popup window. */
- gtk_grab_remove (popup);
- gtk_widget_destroy (popup);
- }
-}
-
-static gint
-gimp_combo_tag_entry_layout_tags (PopupData *popup_data,
- gint width)
-{
- gint x;
- gint y;
- gint height = 0;
- gint i;
- gint line_height;
- gint space_width;
- PangoFontMetrics *font_metrics;
-
- x = GIMP_TAG_POPUP_MARGIN;
- y = GIMP_TAG_POPUP_MARGIN;
- font_metrics = pango_context_get_metrics (popup_data->context,
- pango_context_get_font_description (popup_data->context),
- NULL);
- line_height = pango_font_metrics_get_ascent (font_metrics) +
- pango_font_metrics_get_descent (font_metrics);
- space_width = pango_font_metrics_get_approximate_char_width (font_metrics);
- line_height /= PANGO_SCALE;
- space_width /= PANGO_SCALE;
- pango_font_metrics_unref (font_metrics);
- for (i = 0; i < popup_data->tag_count; i++)
- {
- pango_layout_set_text (popup_data->layout,
- gimp_tag_get_name (popup_data->tag_data[i].tag), -1);
- pango_layout_get_size (popup_data->layout,
- &popup_data->tag_data[i].bounds.width,
- &popup_data->tag_data[i].bounds.height);
- popup_data->tag_data[i].bounds.width /= PANGO_SCALE;
- popup_data->tag_data[i].bounds.height /= PANGO_SCALE;
- if (popup_data->tag_data[i].bounds.width + x + 6 +GIMP_TAG_POPUP_MARGIN > width)
- {
- x = GIMP_TAG_POPUP_MARGIN;
- y += line_height + 8;
- }
-
- popup_data->tag_data[i].bounds.x = x;
- popup_data->tag_data[i].bounds.y = y;
-
- x += popup_data->tag_data[i].bounds.width + space_width + 6;
- }
- height = y + line_height + GIMP_TAG_POPUP_MARGIN;
-
- return height;
-}
-
-static gboolean
-gimp_combo_tag_entry_popup_border_expose (GtkWidget *widget,
- GdkEventExpose *event,
- PopupData *popup_data)
-{
- GdkGC *gc;
- GdkRectangle border;
- GdkRectangle upper;
- GdkRectangle lower;
- gint arrow_space;
-
- if (event->window == widget->window)
- {
- gc = gdk_gc_new (GDK_DRAWABLE (widget->window));
-
- get_arrows_visible_area (popup_data, &border, &upper, &lower, &arrow_space);
-
- if (event->window == widget->window)
- {
- gint arrow_size = 0.7 * arrow_space;
-
- gtk_paint_box (widget->style,
- widget->window,
- GTK_STATE_NORMAL,
- GTK_SHADOW_OUT,
- &event->area, widget, "menu",
- 0, 0, -1, -1);
-
- if (popup_data->arrows_visible)
- {
- gtk_paint_box (widget->style,
- widget->window,
- popup_data->upper_arrow_state,
- GTK_SHADOW_OUT,
- &event->area, widget, "menu",
- upper.x,
- upper.y,
- upper.width,
- upper.height);
-
- gtk_paint_arrow (widget->style,
- widget->window,
- popup_data->upper_arrow_state,
- GTK_SHADOW_OUT,
- &event->area, widget, "menu_scroll_arrow_up",
- GTK_ARROW_UP,
- TRUE,
- upper.x + (upper.width - arrow_size) / 2,
- upper.y + widget->style->ythickness + (arrow_space - arrow_size) / 2,
- arrow_size, arrow_size);
- }
-
- if (popup_data->arrows_visible)
- {
- gtk_paint_box (widget->style,
- widget->window,
- popup_data->lower_arrow_state,
- GTK_SHADOW_OUT,
- &event->area, widget, "menu",
- lower.x,
- lower.y,
- lower.width,
- lower.height);
-
- gtk_paint_arrow (widget->style,
- widget->window,
- popup_data->lower_arrow_state,
- GTK_SHADOW_OUT,
- &event->area, widget, "menu_scroll_arrow_down",
- GTK_ARROW_DOWN,
- TRUE,
- lower.x + (lower.width - arrow_size) / 2,
- lower.y + widget->style->ythickness + (arrow_space - arrow_size) / 2,
- arrow_size, arrow_size);
- }
- }
-
- g_object_unref (gc);
- }
-
- return FALSE;
-}
-
-static void
-get_arrows_visible_area (PopupData *popup_data,
- GdkRectangle *border,
- GdkRectangle *upper,
- GdkRectangle *lower,
- gint *arrow_space)
-{
- GtkWidget *widget = GTK_WIDGET (popup_data->alignment);
- gint scroll_arrow_height = popup_data->scroll_arrow_height;
- guint padding_top;
- guint padding_bottom;
- guint padding_left;
- guint padding_right;
-
- gtk_alignment_get_padding (GTK_ALIGNMENT (popup_data->alignment),
- &padding_top, &padding_bottom,
- &padding_left, &padding_right);
-
- *border = widget->allocation;
-
- upper->x = border->x + padding_left;
- upper->y = border->y;
- upper->width = border->width - padding_left - padding_right;
- upper->height = padding_top;
-
- lower->x = border->x + padding_left;
- lower->y = border->y + border->height - padding_bottom;
- lower->width = border->width - padding_left - padding_right;
- lower->height = padding_bottom;
-
- *arrow_space = scroll_arrow_height;
-}
-
-static gboolean
-gimp_combo_tag_entry_popup_expose (GtkWidget *widget,
- GdkEventExpose *event,
- PopupData *popup_data)
-{
- GdkGC *gc;
- PangoRenderer *renderer;
- gint i;
-
- renderer = gdk_pango_renderer_get_default (gtk_widget_get_screen (widget));
- gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), widget->style->black_gc);
- gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer),
- widget->window);
-
- gc = gdk_gc_new (GDK_DRAWABLE (widget->window));
- gdk_gc_set_rgb_fg_color (gc, &popup_data->combo_entry->selected_item_color);
- gdk_gc_set_line_attributes (gc, 5, GDK_LINE_SOLID, GDK_CAP_ROUND,
- GDK_JOIN_ROUND);
-
- for (i = 0; i < popup_data->tag_count; i++)
- {
- pango_layout_set_text (popup_data->layout,
- gimp_tag_get_name (popup_data->tag_data[i].tag), -1);
- if (popup_data->tag_data[i].selected)
- {
- pango_layout_set_attributes (popup_data->layout,
- popup_data->combo_entry->selected_item_attr);
- }
- else
- {
- pango_layout_set_attributes (popup_data->layout,
- popup_data->combo_entry->normal_item_attr);
- }
-
- if (popup_data->tag_data[i].selected)
- {
- gdk_draw_rectangle (widget->window, gc, FALSE,
- popup_data->tag_data[i].bounds.x,
- popup_data->tag_data[i].bounds.y - popup_data->scroll_y,
- popup_data->tag_data[i].bounds.width,
- popup_data->tag_data[i].bounds.height);
- }
- pango_renderer_draw_layout (renderer, popup_data->layout,
- (popup_data->tag_data[i].bounds.x) * PANGO_SCALE,
- (popup_data->tag_data[i].bounds.y - popup_data->scroll_y) * PANGO_SCALE);
-
- if (&popup_data->tag_data[i] == popup_data->prelight)
- {
- gtk_paint_focus (widget->style, widget->window,
- popup_data->tag_data[i].selected ? GTK_STATE_SELECTED : GTK_STATE_NORMAL,
- &event->area, widget, NULL,
- popup_data->tag_data[i].bounds.x,
- popup_data->tag_data[i].bounds.y - popup_data->scroll_y,
- popup_data->tag_data[i].bounds.width,
- popup_data->tag_data[i].bounds.height);
- }
- }
-
- g_object_unref (gc);
-
- gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer), NULL);
- gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), NULL);
-
- return FALSE;
-}
-
-static gboolean
-gimp_tag_popup_scroll_timeout (gpointer data)
-{
- PopupData *popup_data;
- gboolean touchscreen_mode;
-
- popup_data = (PopupData*) data;
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (popup_data->popup)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- gimp_tag_popup_do_timeout_scroll (popup_data, touchscreen_mode);
-
- return TRUE;
-}
-
-static void
-gimp_tag_popup_remove_scroll_timeout (PopupData *popup_data)
-{
- if (popup_data->timeout_id)
- {
- g_source_remove (popup_data->timeout_id);
- popup_data->timeout_id = 0;
- }
-}
-
-static gboolean
-gimp_tag_popup_scroll_timeout_initial (gpointer data)
-{
- PopupData *popup_data;
- guint timeout;
- gboolean touchscreen_mode;
-
- popup_data = (PopupData*) (data);
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (popup_data->popup)),
- "gtk-timeout-repeat", &timeout,
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- gimp_tag_popup_do_timeout_scroll (popup_data, touchscreen_mode);
-
- gimp_tag_popup_remove_scroll_timeout (popup_data);
-
- popup_data->timeout_id = gdk_threads_add_timeout (timeout,
- gimp_tag_popup_scroll_timeout,
- popup_data);
-
- return FALSE;
-}
-
-static void
-gimp_tag_popup_start_scrolling (PopupData *popup_data)
-{
- guint timeout;
- gboolean touchscreen_mode;
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (popup_data->popup)),
- "gtk-timeout-repeat", &timeout,
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- gimp_tag_popup_do_timeout_scroll (popup_data, touchscreen_mode);
-
- popup_data->timeout_id = gdk_threads_add_timeout (timeout,
- gimp_tag_popup_scroll_timeout_initial,
- popup_data);
-}
-
-static void
-gimp_tag_popup_stop_scrolling (PopupData *popup_data)
-{
- gboolean touchscreen_mode;
-
- gimp_tag_popup_remove_scroll_timeout (popup_data);
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (popup_data->popup)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- if (!touchscreen_mode)
- {
- popup_data->upper_arrow_prelight = FALSE;
- popup_data->lower_arrow_prelight = FALSE;
- }
-}
-
-static void
-gimp_tag_popup_scroll_by (PopupData *popup_data,
- gint step)
-{
- gint new_scroll_y = popup_data->scroll_y + step;
-
- if (new_scroll_y < 0)
- {
- new_scroll_y = 0;
- if (popup_data->upper_arrow_state != GTK_STATE_INSENSITIVE)
- {
- gimp_tag_popup_stop_scrolling (popup_data);
- gtk_widget_queue_draw (GTK_WIDGET (popup_data->popup));
- }
- popup_data->upper_arrow_state = GTK_STATE_INSENSITIVE;
- }
- else
- {
- popup_data->upper_arrow_state = popup_data->upper_arrow_prelight ?
- GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
- }
-
- if (new_scroll_y >= popup_data->scroll_height)
- {
- new_scroll_y = popup_data->scroll_height - 1;
- if (popup_data->lower_arrow_state != GTK_STATE_INSENSITIVE)
- {
- gimp_tag_popup_stop_scrolling (popup_data);
- gtk_widget_queue_draw (GTK_WIDGET (popup_data->popup));
- }
- popup_data->lower_arrow_state = GTK_STATE_INSENSITIVE;
- }
- else
- {
- popup_data->lower_arrow_state = popup_data->lower_arrow_prelight ?
- GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
- }
-
- if (new_scroll_y != popup_data->scroll_y)
- {
- popup_data->scroll_y = new_scroll_y;
- gdk_window_scroll (popup_data->drawing_area->window, 0, -step);
- }
-}
-
-static void
-gimp_tag_popup_do_timeout_scroll (PopupData *popup_data,
- gboolean touchscreen_mode)
-{
- gimp_tag_popup_scroll_by (popup_data, popup_data->scroll_step);
-}
-
-
-static void
-get_arrows_sensitive_area (PopupData *popup_data,
- GdkRectangle *upper,
- GdkRectangle *lower)
-{
- GdkRectangle tmp_border;
- GdkRectangle tmp_upper;
- GdkRectangle tmp_lower;
- gint tmp_arrow_space;
-
- get_arrows_visible_area (popup_data, &tmp_border, &tmp_upper, &tmp_lower, &tmp_arrow_space);
- if (upper)
- {
- *upper = tmp_upper;
- }
- if (lower)
- {
- *lower = tmp_lower;
- }
-}
-
-static void
-gimp_tag_popup_handle_scrolling (PopupData *popup_data,
- gint x,
- gint y,
- gboolean enter,
- gboolean motion)
-{
- GdkRectangle rect;
- gboolean in_arrow;
- gboolean scroll_fast = FALSE;
- gboolean touchscreen_mode;
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (popup_data->popup)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- /* upper arrow handling */
-
- get_arrows_sensitive_area (popup_data, &rect, NULL);
-
- in_arrow = FALSE;
- if (popup_data->arrows_visible &&
- (x >= rect.x) && (x < rect.x + rect.width) &&
- (y >= rect.y) && (y < rect.y + rect.height))
- {
- in_arrow = TRUE;
- }
-
- if (touchscreen_mode)
- popup_data->upper_arrow_prelight = in_arrow;
-
- if (popup_data->upper_arrow_state != GTK_STATE_INSENSITIVE)
- {
- gboolean arrow_pressed = FALSE;
-
- if (popup_data->arrows_visible)
- {
- if (touchscreen_mode)
- {
- if (enter && popup_data->upper_arrow_prelight)
- {
- if (popup_data->timeout_id == 0)
- {
- gimp_tag_popup_remove_scroll_timeout (popup_data);
- popup_data->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
-
- if (!motion)
- {
- /* Only do stuff on click. */
- gimp_tag_popup_start_scrolling (popup_data);
- arrow_pressed = TRUE;
- }
- }
- else
- {
- arrow_pressed = TRUE;
- }
- }
- else if (!enter)
- {
- gimp_tag_popup_stop_scrolling (popup_data);
- }
- }
- else /* !touchscreen_mode */
- {
- scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
-
- if (enter && in_arrow &&
- (!popup_data->upper_arrow_prelight ||
- popup_data->scroll_fast != scroll_fast))
- {
- popup_data->upper_arrow_prelight = TRUE;
- popup_data->scroll_fast = scroll_fast;
-
- gimp_tag_popup_remove_scroll_timeout (popup_data);
- popup_data->scroll_step = scroll_fast ?
- -MENU_SCROLL_STEP2 : -MENU_SCROLL_STEP1;
-
- popup_data->timeout_id =
- gdk_threads_add_timeout (scroll_fast ?
- MENU_SCROLL_TIMEOUT2 :
- MENU_SCROLL_TIMEOUT1,
- gimp_tag_popup_scroll_timeout, popup_data);
- }
- else if (!enter && !in_arrow && popup_data->upper_arrow_prelight)
- {
- gimp_tag_popup_stop_scrolling (popup_data);
- }
- }
- }
-
- /* gimp_tag_popup_start_scrolling() might have hit the top of the
- * popup_data, so check if the button isn't insensitive before
- * changing it to something else.
- */
- if (popup_data->upper_arrow_state != GTK_STATE_INSENSITIVE)
- {
- GtkStateType arrow_state = GTK_STATE_NORMAL;
-
- if (arrow_pressed)
- arrow_state = GTK_STATE_ACTIVE;
- else if (popup_data->upper_arrow_prelight)
- arrow_state = GTK_STATE_PRELIGHT;
-
- if (arrow_state != popup_data->upper_arrow_state)
- {
- popup_data->upper_arrow_state = arrow_state;
-
- gdk_window_invalidate_rect (GTK_WIDGET (popup_data->popup)->window,
- &rect, FALSE);
- }
- }
- }
-
- /* lower arrow handling */
-
- get_arrows_sensitive_area (popup_data, NULL, &rect);
-
- in_arrow = FALSE;
- if (popup_data->arrows_visible &&
- (x >= rect.x) && (x < rect.x + rect.width) &&
- (y >= rect.y) && (y < rect.y + rect.height))
- {
- in_arrow = TRUE;
- }
-
- if (touchscreen_mode)
- popup_data->lower_arrow_prelight = in_arrow;
-
- if (popup_data->lower_arrow_state != GTK_STATE_INSENSITIVE)
- {
- gboolean arrow_pressed = FALSE;
-
- if (popup_data->arrows_visible)
- {
- if (touchscreen_mode)
- {
- if (enter && popup_data->lower_arrow_prelight)
- {
- if (popup_data->timeout_id == 0)
- {
- gimp_tag_popup_remove_scroll_timeout (popup_data);
- popup_data->scroll_step = MENU_SCROLL_STEP2; /* always fast */
-
- if (!motion)
- {
- /* Only do stuff on click. */
- gimp_tag_popup_start_scrolling (popup_data);
- arrow_pressed = TRUE;
- }
- }
- else
- {
- arrow_pressed = TRUE;
- }
- }
- else if (!enter)
- {
- gimp_tag_popup_stop_scrolling (popup_data);
- }
- }
- else /* !touchscreen_mode */
- {
- scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
-
- if (enter && in_arrow &&
- (!popup_data->lower_arrow_prelight ||
- popup_data->scroll_fast != scroll_fast))
- {
- popup_data->lower_arrow_prelight = TRUE;
- popup_data->scroll_fast = scroll_fast;
-
- gimp_tag_popup_remove_scroll_timeout (popup_data);
- popup_data->scroll_step = scroll_fast ?
- MENU_SCROLL_STEP2 : MENU_SCROLL_STEP1;
-
- popup_data->timeout_id =
- gdk_threads_add_timeout (scroll_fast ?
- MENU_SCROLL_TIMEOUT2 :
- MENU_SCROLL_TIMEOUT1,
- gimp_tag_popup_scroll_timeout, popup_data);
- }
- else if (!enter && !in_arrow && popup_data->lower_arrow_prelight)
- {
- gimp_tag_popup_stop_scrolling (popup_data);
- }
- }
- }
-
- /* gimp_tag_popup_start_scrolling() might have hit the bottom of the
- * popup_data, so check if the button isn't insensitive before
- * changing it to something else.
- */
- if (popup_data->lower_arrow_state != GTK_STATE_INSENSITIVE)
- {
- GtkStateType arrow_state = GTK_STATE_NORMAL;
-
- if (arrow_pressed)
- arrow_state = GTK_STATE_ACTIVE;
- else if (popup_data->lower_arrow_prelight)
- arrow_state = GTK_STATE_PRELIGHT;
-
- if (arrow_state != popup_data->lower_arrow_state)
- {
- popup_data->lower_arrow_state = arrow_state;
-
- gdk_window_invalidate_rect (GTK_WIDGET (popup_data->popup)->window,
- &rect, FALSE);
- }
- }
- }
-}
-
-static gboolean
-gimp_tag_popup_button_scroll (PopupData *popup_data,
- GdkEventButton *event)
-{
- if (popup_data->upper_arrow_prelight
- || popup_data->lower_arrow_prelight)
- {
- gboolean touchscreen_mode;
-
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (popup_data->popup)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
- if (touchscreen_mode)
- gimp_tag_popup_handle_scrolling (popup_data,
- event->x_root, event->y_root,
- event->type == GDK_BUTTON_PRESS,
- FALSE);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean
-gimp_combo_tag_entry_popup_event (GtkWidget *widget,
- GdkEvent *event,
- PopupData *popup_data)
-{
- if (event->type == GDK_BUTTON_PRESS)
- {
- GdkEventButton *button_event;
- gint x;
- gint y;
-
- button_event = (GdkEventButton *) event;
-
- if (button_event->window == widget->window
- && gimp_tag_popup_button_scroll (popup_data, button_event))
- {
- return TRUE;
- }
-
- gdk_window_get_pointer (widget->window, &x, &y, NULL);
-
- if (button_event->window != popup_data->drawing_area->window
- && (x < widget->allocation.y
- || y < widget->allocation.x
- || x > widget->allocation.x + widget->allocation.width
- || y > widget->allocation.y + widget->allocation.height))
- {
- /* user has clicked outside the popup area,
- * which means it should be hidden. */
- gtk_grab_remove (widget);
- gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
- GDK_CURRENT_TIME);
- gtk_widget_destroy (widget);
- }
- }
- else if (event->type == GDK_MOTION_NOTIFY)
- {
- gint x;
- gint y;
-
- gdk_window_get_pointer (widget->window, &x, &y, NULL);
- x += widget->allocation.x;
- y += widget->allocation.y;
- popup_data->ignore_button_release = FALSE;
- gimp_tag_popup_handle_scrolling (popup_data, x, y,
- popup_data->timeout_id == 0, TRUE);
- }
- else if (event->type == GDK_BUTTON_RELEASE)
- {
- if (((GdkEventButton *)event)->window == widget->window
- && ! popup_data->ignore_button_release
- && gimp_tag_popup_button_scroll (popup_data, (GdkEventButton *) event))
- {
- return TRUE;
- }
- }
- else if (event->type == GDK_GRAB_BROKEN)
- {
- gtk_grab_remove (widget);
- gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
- GDK_CURRENT_TIME);
- gtk_widget_destroy (widget);
- }
-
- return FALSE;
-}
-
-static gboolean
-gimp_combo_tag_entry_drawing_area_event (GtkWidget *widget,
- GdkEvent *event,
- PopupData *popup_data)
-{
- if (event->type == GDK_BUTTON_PRESS)
- {
- GdkEventButton *button_event;
- gint x;
- gint y;
- gint i;
- GdkRectangle *bounds;
- GimpTag *tag;
-
- button_event = (GdkEventButton *) event;
- x = button_event->x;
- y = button_event->y;
-
- y += popup_data->scroll_y;
-
- for (i = 0; i < popup_data->tag_count; i++)
- {
- bounds = &popup_data->tag_data[i].bounds;
- if (x >= bounds->x
- && y >= bounds->y
- && x < bounds->x + bounds->width
- && y < bounds->y + bounds->height)
- {
- tag = popup_data->tag_data[i].tag;
- gimp_combo_tag_entry_toggle_tag (popup_data->combo_entry,
- &popup_data->tag_data[i]);
- gtk_widget_queue_draw (widget);
- break;
- }
- }
- }
- else if (event->type == GDK_MOTION_NOTIFY)
- {
- GdkEventMotion *motion_event;
- gint x;
- gint y;
- gint i;
- GdkRectangle *bounds;
- PopupTagData *previous_prelight = popup_data->prelight;
-
- motion_event = (GdkEventMotion*) event;
- x = motion_event->x;
- y = motion_event->y;
- y += popup_data->scroll_y;
-
- popup_data->prelight = NULL;
- for (i = 0; i < popup_data->tag_count; i++)
- {
- bounds = &popup_data->tag_data[i].bounds;
- if (x >= bounds->x
- && y >= bounds->y
- && x < bounds->x + bounds->width
- && y < bounds->y + bounds->height)
- {
- popup_data->prelight = &popup_data->tag_data[i];
- break;
- }
- }
-
- if (previous_prelight != popup_data->prelight)
- {
- gtk_widget_queue_draw (widget);
- }
- }
-
- return FALSE;
-}
-
-static void
-gimp_combo_tag_entry_toggle_tag (GimpComboTagEntry *combo_entry,
- PopupTagData *tag_data)
-{
- gchar **current_tags;
- GString *tag_str;
- const gchar *tag;
- gint length;
- gint i;
- gboolean tag_toggled_off = FALSE;
-
- tag_data->selected = ! tag_data->selected;
-
- tag = gimp_tag_get_name (tag_data->tag);
- current_tags = gimp_tag_entry_parse_tags (GIMP_TAG_ENTRY (combo_entry->tag_entry));
- tag_str = g_string_new ("");
- length = g_strv_length (current_tags);
- for (i = 0; i < length; i++)
- {
- if (! strcmp (current_tags[i], tag))
- {
- tag_toggled_off = TRUE;
- }
- else
- {
- if (tag_str->len)
- {
- g_string_append (tag_str, ", ");
- }
- g_string_append (tag_str, current_tags[i]);
- }
- }
-
- if (! tag_toggled_off)
- {
- /* this tag was not selected yet,
- * so it needs to be toggled on. */
- if (tag_str->len)
- {
- g_string_append (tag_str, ", ");
- }
- g_string_append (tag_str, tag);
- }
-
- gimp_tag_entry_set_tag_string (GIMP_TAG_ENTRY (combo_entry->tag_entry),
- tag_str->str);
-
- g_string_free (tag_str, TRUE);
- g_strfreev (current_tags);
-}
-
-static void
-popup_data_destroy (PopupData *popup_data)
-{
- gimp_tag_popup_remove_scroll_timeout (popup_data);
-
- popup_data->combo_entry->popup = NULL;
-
- if (popup_data->layout)
- {
- g_object_unref (popup_data->layout);
- }
- if (popup_data->context)
- {
- g_object_unref (popup_data->context);
- }
-
- g_free (popup_data->tag_data);
- g_free (popup_data);
+ combo_entry->popup = gimp_tag_popup_new (combo_entry);
}
Added: branches/soc-2008-tagging/app/widgets/gimptagpopup.c
==============================================================================
--- (empty file)
+++ branches/soc-2008-tagging/app/widgets/gimptagpopup.c Mon Jul 28 21:25:05 2008
@@ -0,0 +1,1143 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimptagentry.c
+ * Copyright (C) 2008 Aurimas JuÅka <aurisj svn gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "widgets-types.h"
+
+#include "core/gimpcontainer.h"
+#include "core/gimpfilteredcontainer.h"
+#include "core/gimpcontext.h"
+#include "core/gimpviewable.h"
+#include "core/gimptag.h"
+#include "core/gimptagged.h"
+
+#include "gimptagentry.h"
+#include "gimptagpopup.h"
+#include "gimpcombotagentry.h"
+
+#define MENU_SCROLL_STEP1 8
+#define MENU_SCROLL_STEP2 15
+#define MENU_SCROLL_FAST_ZONE 8
+#define MENU_SCROLL_TIMEOUT1 50
+#define MENU_SCROLL_TIMEOUT2 20
+
+#define GIMP_TAG_POPUP_MARGIN 5
+
+static void gimp_tag_popup_dispose (GObject *object);
+
+static gboolean gimp_tag_popup_border_expose (GtkWidget *widget,
+ GdkEventExpose *event,
+ GimpTagPopup *tag_popup);
+static gboolean gimp_tag_popup_list_expose (GtkWidget *widget,
+ GdkEventExpose *event,
+ GimpTagPopup *tag_popup);
+static gboolean gimp_tag_popup_border_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data);
+static gboolean gimp_tag_popup_list_event (GtkWidget *widget,
+ GdkEvent *event,
+ GimpTagPopup *tag_popup);
+static void gimp_tag_popup_toggle_tag (GimpTagPopup *tag_popup,
+ PopupTagData *tag_data);
+static gint gimp_tag_popup_layout_tags (GimpTagPopup *tag_popup,
+ gint width);
+static void gimp_tag_popup_do_timeout_scroll (GimpTagPopup *tag_popup,
+ gboolean touchscreen_mode);
+static gboolean gimp_tag_popup_scroll_timeout (gpointer data);
+static void gimp_tag_popup_remove_scroll_timeout (GimpTagPopup *tag_popup);
+static gboolean gimp_tag_popup_scroll_timeout_initial (gpointer data);
+static void gimp_tag_popup_start_scrolling (GimpTagPopup *tag_popup);
+static void gimp_tag_popup_stop_scrolling (GimpTagPopup *tag_popup);
+static void gimp_tag_popup_scroll_by (GimpTagPopup *tag_popup,
+ gint step);
+static void gimp_tag_popup_handle_scrolling (GimpTagPopup *tag_popup,
+ gint x,
+ gint y,
+ gboolean enter,
+ gboolean motion);
+
+static gboolean gimp_tag_popup_button_scroll (GimpTagPopup *tag_popup,
+ GdkEventButton *event);
+
+static void get_arrows_visible_area (GimpTagPopup *combo_entry,
+ GdkRectangle *border,
+ GdkRectangle *upper,
+ GdkRectangle *lower,
+ gint *arrow_space);
+static void get_arrows_sensitive_area (GimpTagPopup *tag_popup,
+ GdkRectangle *upper,
+ GdkRectangle *lower);
+
+
+G_DEFINE_TYPE (GimpTagPopup, gimp_tag_popup, GTK_TYPE_WINDOW);
+
+#define parent_class gimp_tag_popup_parent_class
+
+
+static void
+gimp_tag_popup_class_init (GimpTagPopupClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gimp_tag_popup_dispose;
+}
+
+static void
+gimp_tag_popup_init (GimpTagPopup *tag_popup)
+{
+}
+
+static void
+gimp_tag_popup_dispose (GObject *object)
+{
+ GimpTagPopup *tag_popup = GIMP_TAG_POPUP (object);
+
+ gimp_tag_popup_remove_scroll_timeout (tag_popup);
+
+ /* FIXME: parent should do this on destroy event */
+ tag_popup->combo_entry->popup = NULL;
+
+ if (tag_popup->layout)
+ {
+ g_object_unref (tag_popup->layout);
+ tag_popup->layout = NULL;
+ }
+ if (tag_popup->context)
+ {
+ g_object_unref (tag_popup->context);
+ tag_popup->context = NULL;
+ }
+
+ g_free (tag_popup->tag_data);
+ tag_popup->tag_data = NULL;
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+GtkWidget *
+gimp_tag_popup_new (GimpComboTagEntry *combo_entry)
+{
+ GimpTagPopup *popup;
+ GtkWidget *alignment;
+ GtkWidget *drawing_area;
+ GtkWidget *frame;
+ gint x;
+ gint y;
+ gint width;
+ gint height;
+ gint popup_height;
+ GHashTable *tag_hash;
+ GList *tag_list;
+ GList *tag_iterator;
+ gint i;
+ gint j;
+ GdkGrabStatus grab_status;
+ gint max_height;
+ gint screen_height;
+ gchar **current_tags;
+ gint current_count;
+ const gchar *list_tag;
+ GdkRectangle popup_rects[2]; /* variants of popup placement */
+ GdkRectangle popup_rect; /* best popup rect in screen coordinates */
+
+ popup = g_object_new (GIMP_TYPE_TAG_POPUP,
+ "type", GTK_WINDOW_POPUP,
+ NULL);
+ gtk_widget_add_events (GTK_WIDGET (popup),
+ GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK);
+ gtk_window_set_screen (GTK_WINDOW (popup),
+ gtk_widget_get_screen (GTK_WIDGET (combo_entry)));
+
+ frame = gtk_frame_new (NULL);
+ gtk_container_add (GTK_CONTAINER (popup), frame);
+
+ alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_container_add (GTK_CONTAINER (frame), alignment);
+
+ drawing_area = gtk_drawing_area_new ();
+ gtk_widget_add_events (GTK_WIDGET (drawing_area),
+ GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
+ gtk_container_add (GTK_CONTAINER (alignment), drawing_area);
+
+ popup->combo_entry = combo_entry;
+ popup->alignment = alignment;
+ popup->drawing_area = drawing_area;
+ popup->context = gtk_widget_create_pango_context (GTK_WIDGET (popup));
+ popup->layout = pango_layout_new (popup->context);
+ popup->prelight = NULL;
+ popup->upper_arrow_state = GTK_STATE_NORMAL;
+ popup->lower_arrow_state = GTK_STATE_NORMAL;
+ gtk_widget_style_get (GTK_WIDGET (popup),
+ "scroll-arrow-vlength", &popup->scroll_arrow_height,
+ NULL);
+
+ pango_layout_set_attributes (popup->layout, combo_entry->normal_item_attr);
+
+
+ current_tags = gimp_tag_entry_parse_tags (GIMP_TAG_ENTRY (combo_entry->tag_entry));
+ current_count = g_strv_length (current_tags);
+
+ tag_hash = GIMP_TAG_ENTRY (combo_entry->tag_entry)->tagged_container->tag_ref_counts;
+ tag_list = g_hash_table_get_keys (tag_hash);
+ tag_list = g_list_sort (tag_list, gimp_tag_compare_func);
+ popup->tag_count = g_list_length (tag_list);
+ popup->tag_data = g_malloc (sizeof (PopupTagData) * popup->tag_count);
+ tag_iterator = tag_list;
+ for (i = 0; i < popup->tag_count; i++)
+ {
+ popup->tag_data[i].tag = GIMP_TAG (tag_iterator->data);
+ popup->tag_data[i].selected = FALSE;
+ list_tag = gimp_tag_get_name (popup->tag_data[i].tag);
+ for (j = 0; j < current_count; j++)
+ {
+ if (! strcmp (current_tags[j], list_tag))
+ {
+ popup->tag_data[i].selected = TRUE;
+ break;
+ }
+ }
+ tag_iterator = g_list_next (tag_iterator);
+ }
+ g_list_free (tag_list);
+ g_strfreev (current_tags);
+
+ width = GTK_WIDGET (combo_entry)->allocation.width - frame->style->xthickness * 2;
+ height = gimp_tag_popup_layout_tags (popup, width);
+ gdk_window_get_origin (GTK_WIDGET (combo_entry)->window, &x, &y);
+ max_height = GTK_WIDGET (combo_entry)->allocation.height * 7;
+ screen_height = gdk_screen_get_height (gtk_widget_get_screen (GTK_WIDGET (combo_entry)));
+ height += frame->style->ythickness * 2;
+ popup_height = height;
+ popup_rects[0].x = x;
+ popup_rects[0].y = 0;
+ popup_rects[0].width = GTK_WIDGET (combo_entry)->allocation.width;
+ popup_rects[0].height = y + GTK_WIDGET (combo_entry)->allocation.height;
+ popup_rects[1].x = popup_rects[0].x;
+ popup_rects[1].y = y;
+ popup_rects[1].width = popup_rects[0].width;
+ popup_rects[1].height = screen_height - popup_rects[0].height;
+ if (popup_rects[0].height >= popup_height)
+ {
+ popup_rect = popup_rects[0];
+ popup_rect.y += popup_rects[0].height - popup_height;
+ popup_rect.height = popup_height;
+ }
+ else if (popup_rects[1].height >= popup_height)
+ {
+ popup_rect = popup_rects[1];
+ popup_rect.height = popup_height;
+ }
+ else
+ {
+ if (popup_rects[0].height >= popup_rects[1].height)
+ {
+ popup_rect = popup_rects[0];
+ popup_rect.y += popup->scroll_arrow_height + frame->style->ythickness;
+ }
+ else
+ {
+ popup_rect = popup_rects[1];
+ popup_rect.y -= popup->scroll_arrow_height + frame->style->ythickness;
+ }
+
+ popup->arrows_visible = TRUE;
+ gtk_alignment_set_padding (GTK_ALIGNMENT (alignment),
+ popup->scroll_arrow_height + 2,
+ popup->scroll_arrow_height + 2, 2, 2);
+ popup_height = popup_rect.height - popup->scroll_arrow_height * 2 + 4;
+ popup->scroll_height = height - popup_rect.height;
+ popup->scroll_y = 0;
+ popup->scroll_step = 0;
+ }
+
+
+ drawing_area->requisition.width = width;
+ drawing_area->requisition.height = popup_height;
+
+ gtk_window_move (GTK_WINDOW (popup), popup_rect.x, popup_rect.y);
+ gtk_window_resize (GTK_WINDOW (popup), popup_rect.width, popup_rect.height);
+
+ gtk_widget_show_all (GTK_WIDGET (popup));
+
+ g_signal_connect (alignment, "expose-event",
+ G_CALLBACK (gimp_tag_popup_border_expose),
+ popup);
+ g_signal_connect (popup, "event",
+ G_CALLBACK (gimp_tag_popup_border_event),
+ NULL);
+ g_signal_connect (drawing_area, "expose-event",
+ G_CALLBACK (gimp_tag_popup_list_expose),
+ popup);
+ g_signal_connect (drawing_area, "event",
+ G_CALLBACK (gimp_tag_popup_list_event),
+ popup);
+
+ gtk_grab_add (GTK_WIDGET (popup));
+ gtk_widget_grab_focus (combo_entry->tag_entry);
+ grab_status = gdk_pointer_grab (GTK_WIDGET (popup)->window, TRUE,
+ GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK, NULL, NULL,
+ GDK_CURRENT_TIME);
+ if (grab_status != GDK_GRAB_SUCCESS)
+ {
+ /* pointer grab must be attained otherwise user would have
+ * problems closing the popup window. */
+ gtk_grab_remove (GTK_WIDGET (popup));
+ gtk_widget_destroy (GTK_WIDGET (popup));
+ return NULL;
+ }
+ else
+ {
+ return GTK_WIDGET (popup);
+ }
+}
+
+static gint
+gimp_tag_popup_layout_tags (GimpTagPopup *tag_popup,
+ gint width)
+{
+ gint x;
+ gint y;
+ gint height = 0;
+ gint i;
+ gint line_height;
+ gint space_width;
+ PangoFontMetrics *font_metrics;
+
+ x = GIMP_TAG_POPUP_MARGIN;
+ y = GIMP_TAG_POPUP_MARGIN;
+ font_metrics = pango_context_get_metrics (tag_popup->context,
+ pango_context_get_font_description (tag_popup->context),
+ NULL);
+ line_height = pango_font_metrics_get_ascent (font_metrics) +
+ pango_font_metrics_get_descent (font_metrics);
+ space_width = pango_font_metrics_get_approximate_char_width (font_metrics);
+ line_height /= PANGO_SCALE;
+ space_width /= PANGO_SCALE;
+ pango_font_metrics_unref (font_metrics);
+ for (i = 0; i < tag_popup->tag_count; i++)
+ {
+ pango_layout_set_text (tag_popup->layout,
+ gimp_tag_get_name (tag_popup->tag_data[i].tag), -1);
+ pango_layout_get_size (tag_popup->layout,
+ &tag_popup->tag_data[i].bounds.width,
+ &tag_popup->tag_data[i].bounds.height);
+ tag_popup->tag_data[i].bounds.width /= PANGO_SCALE;
+ tag_popup->tag_data[i].bounds.height /= PANGO_SCALE;
+ if (tag_popup->tag_data[i].bounds.width + x + 3 +GIMP_TAG_POPUP_MARGIN > width)
+ {
+ x = GIMP_TAG_POPUP_MARGIN;
+ y += line_height + 4;
+ }
+
+ tag_popup->tag_data[i].bounds.x = x;
+ tag_popup->tag_data[i].bounds.y = y;
+
+ x += tag_popup->tag_data[i].bounds.width + space_width + 3;
+ }
+ height = y + line_height + GIMP_TAG_POPUP_MARGIN;
+
+ return height;
+}
+
+static gboolean
+gimp_tag_popup_border_expose (GtkWidget *widget,
+ GdkEventExpose *event,
+ GimpTagPopup *tag_popup)
+{
+ GdkGC *gc;
+ GdkRectangle border;
+ GdkRectangle upper;
+ GdkRectangle lower;
+ gint arrow_space;
+
+ if (event->window == widget->window)
+ {
+ gc = gdk_gc_new (GDK_DRAWABLE (widget->window));
+
+ get_arrows_visible_area (tag_popup, &border, &upper, &lower, &arrow_space);
+
+ if (event->window == widget->window)
+ {
+ gint arrow_size = 0.7 * arrow_space;
+
+ gtk_paint_box (widget->style,
+ widget->window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ &event->area, widget, "menu",
+ 0, 0, -1, -1);
+
+ if (tag_popup->arrows_visible)
+ {
+ gtk_paint_box (widget->style,
+ widget->window,
+ tag_popup->upper_arrow_state,
+ GTK_SHADOW_OUT,
+ &event->area, widget, "menu",
+ upper.x,
+ upper.y,
+ upper.width,
+ upper.height);
+
+ gtk_paint_arrow (widget->style,
+ widget->window,
+ tag_popup->upper_arrow_state,
+ GTK_SHADOW_OUT,
+ &event->area, widget, "menu_scroll_arrow_up",
+ GTK_ARROW_UP,
+ TRUE,
+ upper.x + (upper.width - arrow_size) / 2,
+ upper.y + widget->style->ythickness + (arrow_space - arrow_size) / 2,
+ arrow_size, arrow_size);
+ }
+
+ if (tag_popup->arrows_visible)
+ {
+ gtk_paint_box (widget->style,
+ widget->window,
+ tag_popup->lower_arrow_state,
+ GTK_SHADOW_OUT,
+ &event->area, widget, "menu",
+ lower.x,
+ lower.y,
+ lower.width,
+ lower.height);
+
+ gtk_paint_arrow (widget->style,
+ widget->window,
+ tag_popup->lower_arrow_state,
+ GTK_SHADOW_OUT,
+ &event->area, widget, "menu_scroll_arrow_down",
+ GTK_ARROW_DOWN,
+ TRUE,
+ lower.x + (lower.width - arrow_size) / 2,
+ lower.y + widget->style->ythickness + (arrow_space - arrow_size) / 2,
+ arrow_size, arrow_size);
+ }
+ }
+
+ g_object_unref (gc);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gimp_tag_popup_border_event (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ GimpTagPopup *tag_popup = GIMP_TAG_POPUP (widget);
+
+ if (event->type == GDK_BUTTON_PRESS)
+ {
+ GdkEventButton *button_event;
+ gint x;
+ gint y;
+
+ button_event = (GdkEventButton *) event;
+
+ if (button_event->window == widget->window
+ && gimp_tag_popup_button_scroll (tag_popup, button_event))
+ {
+ return TRUE;
+ }
+
+ gdk_window_get_pointer (widget->window, &x, &y, NULL);
+
+ if (button_event->window != tag_popup->drawing_area->window
+ && (x < widget->allocation.y
+ || y < widget->allocation.x
+ || x > widget->allocation.x + widget->allocation.width
+ || y > widget->allocation.y + widget->allocation.height))
+ {
+ /* user has clicked outside the popup area,
+ * which means it should be hidden. */
+ gtk_grab_remove (widget);
+ gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
+ GDK_CURRENT_TIME);
+ gtk_widget_destroy (widget);
+ }
+ }
+ else if (event->type == GDK_MOTION_NOTIFY)
+ {
+ gint x;
+ gint y;
+
+ gdk_window_get_pointer (widget->window, &x, &y, NULL);
+ x += widget->allocation.x;
+ y += widget->allocation.y;
+ tag_popup->ignore_button_release = FALSE;
+ gimp_tag_popup_handle_scrolling (tag_popup, x, y,
+ tag_popup->timeout_id == 0, TRUE);
+ }
+ else if (event->type == GDK_BUTTON_RELEASE)
+ {
+ if (((GdkEventButton *)event)->window == widget->window
+ && ! tag_popup->ignore_button_release
+ && gimp_tag_popup_button_scroll (tag_popup, (GdkEventButton *) event))
+ {
+ return TRUE;
+ }
+ }
+ else if (event->type == GDK_GRAB_BROKEN)
+ {
+ gtk_grab_remove (widget);
+ gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
+ GDK_CURRENT_TIME);
+ gtk_widget_destroy (widget);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+gimp_tag_popup_list_expose (GtkWidget *widget,
+ GdkEventExpose *event,
+ GimpTagPopup *tag_popup)
+{
+ GdkGC *gc;
+ PangoRenderer *renderer;
+ gint i;
+
+ renderer = gdk_pango_renderer_get_default (gtk_widget_get_screen (widget));
+ gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), widget->style->black_gc);
+ gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer),
+ widget->window);
+
+ gc = gdk_gc_new (GDK_DRAWABLE (widget->window));
+ gdk_gc_set_rgb_fg_color (gc, &tag_popup->combo_entry->selected_item_color);
+ gdk_gc_set_line_attributes (gc, 5, GDK_LINE_SOLID, GDK_CAP_ROUND,
+ GDK_JOIN_ROUND);
+
+ for (i = 0; i < tag_popup->tag_count; i++)
+ {
+ pango_layout_set_text (tag_popup->layout,
+ gimp_tag_get_name (tag_popup->tag_data[i].tag), -1);
+ if (tag_popup->tag_data[i].selected)
+ {
+ pango_layout_set_attributes (tag_popup->layout,
+ tag_popup->combo_entry->selected_item_attr);
+ }
+ else
+ {
+ pango_layout_set_attributes (tag_popup->layout,
+ tag_popup->combo_entry->normal_item_attr);
+ }
+
+ if (tag_popup->tag_data[i].selected)
+ {
+ gdk_draw_rectangle (widget->window, gc, FALSE,
+ tag_popup->tag_data[i].bounds.x,
+ tag_popup->tag_data[i].bounds.y - tag_popup->scroll_y,
+ tag_popup->tag_data[i].bounds.width,
+ tag_popup->tag_data[i].bounds.height);
+ }
+ pango_renderer_draw_layout (renderer, tag_popup->layout,
+ (tag_popup->tag_data[i].bounds.x) * PANGO_SCALE,
+ (tag_popup->tag_data[i].bounds.y - tag_popup->scroll_y) * PANGO_SCALE);
+
+ if (&tag_popup->tag_data[i] == tag_popup->prelight)
+ {
+ gtk_paint_focus (widget->style, widget->window,
+ tag_popup->tag_data[i].selected ? GTK_STATE_SELECTED : GTK_STATE_NORMAL,
+ &event->area, widget, NULL,
+ tag_popup->tag_data[i].bounds.x,
+ tag_popup->tag_data[i].bounds.y - tag_popup->scroll_y,
+ tag_popup->tag_data[i].bounds.width,
+ tag_popup->tag_data[i].bounds.height);
+ }
+ }
+
+ g_object_unref (gc);
+
+ gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer), NULL);
+ gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), NULL);
+
+ return FALSE;
+}
+
+static gboolean
+gimp_tag_popup_list_event (GtkWidget *widget,
+ GdkEvent *event,
+ GimpTagPopup *tag_popup)
+{
+ if (event->type == GDK_BUTTON_PRESS)
+ {
+ GdkEventButton *button_event;
+ gint x;
+ gint y;
+ gint i;
+ GdkRectangle *bounds;
+ GimpTag *tag;
+
+ button_event = (GdkEventButton *) event;
+ x = button_event->x;
+ y = button_event->y;
+
+ y += tag_popup->scroll_y;
+
+ for (i = 0; i < tag_popup->tag_count; i++)
+ {
+ bounds = &tag_popup->tag_data[i].bounds;
+ if (x >= bounds->x
+ && y >= bounds->y
+ && x < bounds->x + bounds->width
+ && y < bounds->y + bounds->height)
+ {
+ tag = tag_popup->tag_data[i].tag;
+ gimp_tag_popup_toggle_tag (tag_popup,
+ &tag_popup->tag_data[i]);
+ gtk_widget_queue_draw (widget);
+ break;
+ }
+ }
+ }
+ else if (event->type == GDK_MOTION_NOTIFY)
+ {
+ GdkEventMotion *motion_event;
+ gint x;
+ gint y;
+ gint i;
+ GdkRectangle *bounds;
+ PopupTagData *previous_prelight = tag_popup->prelight;
+
+ motion_event = (GdkEventMotion*) event;
+ x = motion_event->x;
+ y = motion_event->y;
+ y += tag_popup->scroll_y;
+
+ tag_popup->prelight = NULL;
+ for (i = 0; i < tag_popup->tag_count; i++)
+ {
+ bounds = &tag_popup->tag_data[i].bounds;
+ if (x >= bounds->x
+ && y >= bounds->y
+ && x < bounds->x + bounds->width
+ && y < bounds->y + bounds->height)
+ {
+ tag_popup->prelight = &tag_popup->tag_data[i];
+ break;
+ }
+ }
+
+ if (previous_prelight != tag_popup->prelight)
+ {
+ gtk_widget_queue_draw (widget);
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+gimp_tag_popup_toggle_tag (GimpTagPopup *tag_popup,
+ PopupTagData *tag_data)
+{
+ gchar **current_tags;
+ GString *tag_str;
+ const gchar *tag;
+ gint length;
+ gint i;
+ gboolean tag_toggled_off = FALSE;
+
+ tag_data->selected = ! tag_data->selected;
+
+ tag = gimp_tag_get_name (tag_data->tag);
+ current_tags = gimp_tag_entry_parse_tags (GIMP_TAG_ENTRY (tag_popup->combo_entry->tag_entry));
+ tag_str = g_string_new ("");
+ length = g_strv_length (current_tags);
+ for (i = 0; i < length; i++)
+ {
+ if (! strcmp (current_tags[i], tag))
+ {
+ tag_toggled_off = TRUE;
+ }
+ else
+ {
+ if (tag_str->len)
+ {
+ g_string_append (tag_str, ", ");
+ }
+ g_string_append (tag_str, current_tags[i]);
+ }
+ }
+
+ if (! tag_toggled_off)
+ {
+ /* this tag was not selected yet,
+ * so it needs to be toggled on. */
+ if (tag_str->len)
+ {
+ g_string_append (tag_str, ", ");
+ }
+ g_string_append (tag_str, tag);
+ }
+
+ gimp_tag_entry_set_tag_string (GIMP_TAG_ENTRY (tag_popup->combo_entry->tag_entry),
+ tag_str->str);
+
+ g_string_free (tag_str, TRUE);
+ g_strfreev (current_tags);
+}
+
+static gboolean
+gimp_tag_popup_scroll_timeout (gpointer data)
+{
+ GimpTagPopup *tag_popup;
+ gboolean touchscreen_mode;
+
+ tag_popup = (GimpTagPopup*) data;
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (tag_popup)),
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
+ gimp_tag_popup_do_timeout_scroll (tag_popup, touchscreen_mode);
+
+ return TRUE;
+}
+
+static void
+gimp_tag_popup_remove_scroll_timeout (GimpTagPopup *tag_popup)
+{
+ if (tag_popup->timeout_id)
+ {
+ g_source_remove (tag_popup->timeout_id);
+ tag_popup->timeout_id = 0;
+ }
+}
+
+static gboolean
+gimp_tag_popup_scroll_timeout_initial (gpointer data)
+{
+ GimpTagPopup *tag_popup;
+ guint timeout;
+ gboolean touchscreen_mode;
+
+ tag_popup = (GimpTagPopup*) (data);
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (tag_popup)),
+ "gtk-timeout-repeat", &timeout,
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
+ gimp_tag_popup_do_timeout_scroll (tag_popup, touchscreen_mode);
+
+ gimp_tag_popup_remove_scroll_timeout (tag_popup);
+
+ tag_popup->timeout_id = gdk_threads_add_timeout (timeout,
+ gimp_tag_popup_scroll_timeout,
+ tag_popup);
+
+ return FALSE;
+}
+
+static void
+gimp_tag_popup_start_scrolling (GimpTagPopup *tag_popup)
+{
+ guint timeout;
+ gboolean touchscreen_mode;
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (tag_popup)),
+ "gtk-timeout-repeat", &timeout,
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
+ gimp_tag_popup_do_timeout_scroll (tag_popup, touchscreen_mode);
+
+ tag_popup->timeout_id = gdk_threads_add_timeout (timeout,
+ gimp_tag_popup_scroll_timeout_initial,
+ tag_popup);
+}
+
+static void
+gimp_tag_popup_stop_scrolling (GimpTagPopup *tag_popup)
+{
+ gboolean touchscreen_mode;
+
+ gimp_tag_popup_remove_scroll_timeout (tag_popup);
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (tag_popup)),
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
+ if (!touchscreen_mode)
+ {
+ tag_popup->upper_arrow_prelight = FALSE;
+ tag_popup->lower_arrow_prelight = FALSE;
+ }
+}
+
+static void
+gimp_tag_popup_scroll_by (GimpTagPopup *tag_popup,
+ gint step)
+{
+ gint new_scroll_y = tag_popup->scroll_y + step;
+
+ if (new_scroll_y < 0)
+ {
+ new_scroll_y = 0;
+ if (tag_popup->upper_arrow_state != GTK_STATE_INSENSITIVE)
+ {
+ gimp_tag_popup_stop_scrolling (tag_popup);
+ gtk_widget_queue_draw (GTK_WIDGET (tag_popup));
+ }
+ tag_popup->upper_arrow_state = GTK_STATE_INSENSITIVE;
+ }
+ else
+ {
+ tag_popup->upper_arrow_state = tag_popup->upper_arrow_prelight ?
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
+ }
+
+ if (new_scroll_y >= tag_popup->scroll_height)
+ {
+ new_scroll_y = tag_popup->scroll_height - 1;
+ if (tag_popup->lower_arrow_state != GTK_STATE_INSENSITIVE)
+ {
+ gimp_tag_popup_stop_scrolling (tag_popup);
+ gtk_widget_queue_draw (GTK_WIDGET (tag_popup));
+ }
+ tag_popup->lower_arrow_state = GTK_STATE_INSENSITIVE;
+ }
+ else
+ {
+ tag_popup->lower_arrow_state = tag_popup->lower_arrow_prelight ?
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
+ }
+
+ if (new_scroll_y != tag_popup->scroll_y)
+ {
+ tag_popup->scroll_y = new_scroll_y;
+ gdk_window_scroll (tag_popup->drawing_area->window, 0, -step);
+ }
+}
+
+static void
+gimp_tag_popup_do_timeout_scroll (GimpTagPopup *tag_popup,
+ gboolean touchscreen_mode)
+{
+ gimp_tag_popup_scroll_by (tag_popup, tag_popup->scroll_step);
+}
+
+static void
+gimp_tag_popup_handle_scrolling (GimpTagPopup *tag_popup,
+ gint x,
+ gint y,
+ gboolean enter,
+ gboolean motion)
+{
+ GdkRectangle rect;
+ gboolean in_arrow;
+ gboolean scroll_fast = FALSE;
+ gboolean touchscreen_mode;
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (tag_popup)),
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
+ /* upper arrow handling */
+
+ get_arrows_sensitive_area (tag_popup, &rect, NULL);
+
+ in_arrow = FALSE;
+ if (tag_popup->arrows_visible &&
+ (x >= rect.x) && (x < rect.x + rect.width) &&
+ (y >= rect.y) && (y < rect.y + rect.height))
+ {
+ in_arrow = TRUE;
+ }
+
+ if (touchscreen_mode)
+ tag_popup->upper_arrow_prelight = in_arrow;
+
+ if (tag_popup->upper_arrow_state != GTK_STATE_INSENSITIVE)
+ {
+ gboolean arrow_pressed = FALSE;
+
+ if (tag_popup->arrows_visible)
+ {
+ if (touchscreen_mode)
+ {
+ if (enter && tag_popup->upper_arrow_prelight)
+ {
+ if (tag_popup->timeout_id == 0)
+ {
+ gimp_tag_popup_remove_scroll_timeout (tag_popup);
+ tag_popup->scroll_step = -MENU_SCROLL_STEP2; /* always fast */
+
+ if (!motion)
+ {
+ /* Only do stuff on click. */
+ gimp_tag_popup_start_scrolling (tag_popup);
+ arrow_pressed = TRUE;
+ }
+ }
+ else
+ {
+ arrow_pressed = TRUE;
+ }
+ }
+ else if (!enter)
+ {
+ gimp_tag_popup_stop_scrolling (tag_popup);
+ }
+ }
+ else /* !touchscreen_mode */
+ {
+ scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE);
+
+ if (enter && in_arrow &&
+ (!tag_popup->upper_arrow_prelight ||
+ tag_popup->scroll_fast != scroll_fast))
+ {
+ tag_popup->upper_arrow_prelight = TRUE;
+ tag_popup->scroll_fast = scroll_fast;
+
+ gimp_tag_popup_remove_scroll_timeout (tag_popup);
+ tag_popup->scroll_step = scroll_fast ?
+ -MENU_SCROLL_STEP2 : -MENU_SCROLL_STEP1;
+
+ tag_popup->timeout_id =
+ gdk_threads_add_timeout (scroll_fast ?
+ MENU_SCROLL_TIMEOUT2 :
+ MENU_SCROLL_TIMEOUT1,
+ gimp_tag_popup_scroll_timeout, tag_popup);
+ }
+ else if (!enter && !in_arrow && tag_popup->upper_arrow_prelight)
+ {
+ gimp_tag_popup_stop_scrolling (tag_popup);
+ }
+ }
+ }
+
+ /* gimp_tag_popup_start_scrolling() might have hit the top of the
+ * tag_popup, so check if the button isn't insensitive before
+ * changing it to something else.
+ */
+ if (tag_popup->upper_arrow_state != GTK_STATE_INSENSITIVE)
+ {
+ GtkStateType arrow_state = GTK_STATE_NORMAL;
+
+ if (arrow_pressed)
+ arrow_state = GTK_STATE_ACTIVE;
+ else if (tag_popup->upper_arrow_prelight)
+ arrow_state = GTK_STATE_PRELIGHT;
+
+ if (arrow_state != tag_popup->upper_arrow_state)
+ {
+ tag_popup->upper_arrow_state = arrow_state;
+
+ gdk_window_invalidate_rect (GTK_WIDGET (tag_popup)->window,
+ &rect, FALSE);
+ }
+ }
+ }
+
+ /* lower arrow handling */
+
+ get_arrows_sensitive_area (tag_popup, NULL, &rect);
+
+ in_arrow = FALSE;
+ if (tag_popup->arrows_visible &&
+ (x >= rect.x) && (x < rect.x + rect.width) &&
+ (y >= rect.y) && (y < rect.y + rect.height))
+ {
+ in_arrow = TRUE;
+ }
+
+ if (touchscreen_mode)
+ tag_popup->lower_arrow_prelight = in_arrow;
+
+ if (tag_popup->lower_arrow_state != GTK_STATE_INSENSITIVE)
+ {
+ gboolean arrow_pressed = FALSE;
+
+ if (tag_popup->arrows_visible)
+ {
+ if (touchscreen_mode)
+ {
+ if (enter && tag_popup->lower_arrow_prelight)
+ {
+ if (tag_popup->timeout_id == 0)
+ {
+ gimp_tag_popup_remove_scroll_timeout (tag_popup);
+ tag_popup->scroll_step = MENU_SCROLL_STEP2; /* always fast */
+
+ if (!motion)
+ {
+ /* Only do stuff on click. */
+ gimp_tag_popup_start_scrolling (tag_popup);
+ arrow_pressed = TRUE;
+ }
+ }
+ else
+ {
+ arrow_pressed = TRUE;
+ }
+ }
+ else if (!enter)
+ {
+ gimp_tag_popup_stop_scrolling (tag_popup);
+ }
+ }
+ else /* !touchscreen_mode */
+ {
+ scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE);
+
+ if (enter && in_arrow &&
+ (!tag_popup->lower_arrow_prelight ||
+ tag_popup->scroll_fast != scroll_fast))
+ {
+ tag_popup->lower_arrow_prelight = TRUE;
+ tag_popup->scroll_fast = scroll_fast;
+
+ gimp_tag_popup_remove_scroll_timeout (tag_popup);
+ tag_popup->scroll_step = scroll_fast ?
+ MENU_SCROLL_STEP2 : MENU_SCROLL_STEP1;
+
+ tag_popup->timeout_id =
+ gdk_threads_add_timeout (scroll_fast ?
+ MENU_SCROLL_TIMEOUT2 :
+ MENU_SCROLL_TIMEOUT1,
+ gimp_tag_popup_scroll_timeout, tag_popup);
+ }
+ else if (!enter && !in_arrow && tag_popup->lower_arrow_prelight)
+ {
+ gimp_tag_popup_stop_scrolling (tag_popup);
+ }
+ }
+ }
+
+ /* gimp_tag_popup_start_scrolling() might have hit the bottom of the
+ * tag_popup, so check if the button isn't insensitive before
+ * changing it to something else.
+ */
+ if (tag_popup->lower_arrow_state != GTK_STATE_INSENSITIVE)
+ {
+ GtkStateType arrow_state = GTK_STATE_NORMAL;
+
+ if (arrow_pressed)
+ arrow_state = GTK_STATE_ACTIVE;
+ else if (tag_popup->lower_arrow_prelight)
+ arrow_state = GTK_STATE_PRELIGHT;
+
+ if (arrow_state != tag_popup->lower_arrow_state)
+ {
+ tag_popup->lower_arrow_state = arrow_state;
+
+ gdk_window_invalidate_rect (GTK_WIDGET (tag_popup)->window,
+ &rect, FALSE);
+ }
+ }
+ }
+}
+
+static gboolean
+gimp_tag_popup_button_scroll (GimpTagPopup *tag_popup,
+ GdkEventButton *event)
+{
+ if (tag_popup->upper_arrow_prelight
+ || tag_popup->lower_arrow_prelight)
+ {
+ gboolean touchscreen_mode;
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (tag_popup)),
+ "gtk-touchscreen-mode", &touchscreen_mode,
+ NULL);
+
+ if (touchscreen_mode)
+ gimp_tag_popup_handle_scrolling (tag_popup,
+ event->x_root, event->y_root,
+ event->type == GDK_BUTTON_PRESS,
+ FALSE);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+get_arrows_visible_area (GimpTagPopup *tag_popup,
+ GdkRectangle *border,
+ GdkRectangle *upper,
+ GdkRectangle *lower,
+ gint *arrow_space)
+{
+ GtkWidget *widget = GTK_WIDGET (tag_popup->alignment);
+ gint scroll_arrow_height = tag_popup->scroll_arrow_height;
+ guint padding_top;
+ guint padding_bottom;
+ guint padding_left;
+ guint padding_right;
+
+ gtk_alignment_get_padding (GTK_ALIGNMENT (tag_popup->alignment),
+ &padding_top, &padding_bottom,
+ &padding_left, &padding_right);
+
+ *border = widget->allocation;
+
+ upper->x = border->x + padding_left;
+ upper->y = border->y;
+ upper->width = border->width - padding_left - padding_right;
+ upper->height = padding_top;
+
+ lower->x = border->x + padding_left;
+ lower->y = border->y + border->height - padding_bottom;
+ lower->width = border->width - padding_left - padding_right;
+ lower->height = padding_bottom;
+
+ *arrow_space = scroll_arrow_height;
+}
+
+static void
+get_arrows_sensitive_area (GimpTagPopup *tag_popup,
+ GdkRectangle *upper,
+ GdkRectangle *lower)
+{
+ GdkRectangle tmp_border;
+ GdkRectangle tmp_upper;
+ GdkRectangle tmp_lower;
+ gint tmp_arrow_space;
+
+ get_arrows_visible_area (tag_popup, &tmp_border, &tmp_upper, &tmp_lower, &tmp_arrow_space);
+ if (upper)
+ {
+ *upper = tmp_upper;
+ }
+ if (lower)
+ {
+ *lower = tmp_lower;
+ }
+}
+
+
Added: branches/soc-2008-tagging/app/widgets/gimptagpopup.h
==============================================================================
--- (empty file)
+++ branches/soc-2008-tagging/app/widgets/gimptagpopup.h Mon Jul 28 21:25:05 2008
@@ -0,0 +1,77 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimptagpopup.h
+ * Copyright (C) 2008 Aurimas JuÅka <aurisj svn gnome org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GIMP_TAG_POPUP_H__
+#define __GIMP_TAG_POPUP_H__
+
+
+#define GIMP_TYPE_TAG_POPUP (gimp_tag_popup_get_type ())
+#define GIMP_TAG_POPUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TAG_POPUP, GimpTagPopup))
+#define GIMP_IS_TAG_POPUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TAG_POPUP))
+#define GIMP_IS_TAG_POPUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TAG_POPUP))
+#define GIMP_TAG_POPUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TAG_POPUP, GimpTagPopupClass))
+
+
+typedef struct _GimpTagPopupClass GimpTagPopupClass;
+
+typedef struct
+{
+ GimpTag *tag;
+ GdkRectangle bounds;
+ gboolean selected;
+} PopupTagData;
+
+struct _GimpTagPopup
+{
+ GtkWindow parent_instance;
+ GimpComboTagEntry *combo_entry;
+ GtkWidget *alignment;
+ GtkWidget *drawing_area;
+ PangoContext *context;
+ PangoLayout *layout;
+ PopupTagData *tag_data;
+ PopupTagData *prelight;
+ gint tag_count;
+ guint timeout_id;
+ gint scroll_height;
+ gint scroll_y;
+ gint scroll_step;
+ gint scroll_arrow_height;
+ gboolean scroll_fast;
+ gboolean arrows_visible;
+ gboolean ignore_button_release;
+ gboolean upper_arrow_prelight;
+ gboolean lower_arrow_prelight;
+ GtkStateType upper_arrow_state;
+ GtkStateType lower_arrow_state;
+};
+
+struct _GimpTagPopupClass
+{
+ GtkWindowClass parent_class;
+};
+
+
+GType gimp_tag_popup_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gimp_tag_popup_new (GimpComboTagEntry *tag_entry);
+
+#endif /* __GIMP_TAG_POPUP_H__ */
Modified: branches/soc-2008-tagging/app/widgets/widgets-types.h
==============================================================================
--- branches/soc-2008-tagging/app/widgets/widgets-types.h (original)
+++ branches/soc-2008-tagging/app/widgets/widgets-types.h Mon Jul 28 21:25:05 2008
@@ -181,6 +181,7 @@
typedef struct _GimpSizeBox GimpSizeBox;
typedef struct _GimpStrokeEditor GimpStrokeEditor;
typedef struct _GimpTagEntry GimpTagEntry;
+typedef struct _GimpTagPopup GimpTagPopup;
typedef struct _GimpTemplateEditor GimpTemplateEditor;
typedef struct _GimpThumbBox GimpThumbBox;
typedef struct _GimpUnitStore GimpUnitStore;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]