[PATCH] GtkMenu scrolling function added
- From: aa <samuel animeta com>
- To: gtk-devel-list gnome org
- Subject: [PATCH] GtkMenu scrolling function added
- Date: Thu, 03 Aug 2000 17:29:15 +0800
General Information
===================
This patch enhances the GtkMenu widget with scrolling features,
and fix some position-related bugs.
REQUIREMENT
===========
GTK+ version 1.2.8.
Features
========
- enhance GtkMenu widget with scrolling features
- Automatically scrolling when the UP/DOWN arrow were clicked.
- The position of pop-up menu will be left-aligned, if nicessary.
Installation
============
change directory to gtk+-1.2.8/
patch -p0 < gtk+-1.2.8-menuscroll.patch
Modified files
==============
- gtk/gtkmenu.c
- gtk/gtkmenu.h
- gtk/gtkmenuitem.c
- gtk/gtkoptionmenu.c
- gtk/gtkmenushell.c
--
Regards,
Samuel Chen
Animeta System Inc., samuel@animeta.com
diff -c -r gtk/gtkmenu.c ../gtk+-1.2.8.new/gtk/gtkmenu.c
*** gtk/gtkmenu.c Sat Sep 4 07:50:37 1999
--- ../gtk+-1.2.8.new/gtk/gtkmenu.c Thu Aug 3 16:59:33 2000
***************
*** 62,76 ****
--- 62,85 ----
GdkEventExpose *event);
static gint gtk_menu_key_press (GtkWidget *widget,
GdkEventKey *event);
+ static gint gtk_menu_key_release (GtkWidget *widget,
+ GdkEventKey *event);
static gint gtk_menu_motion_notify (GtkWidget *widget,
GdkEventMotion *event);
static void gtk_menu_deactivate (GtkMenuShell *menu_shell);
static void gtk_menu_show_all (GtkWidget *widget);
static void gtk_menu_hide_all (GtkWidget *widget);
static void gtk_menu_position (GtkMenu *menu);
+ static void gtk_menu_top_position (GtkMenu *menu,
+ gint x,
+ gint y,
+ gint width,
+ gint height) ;
static void gtk_menu_reparent (GtkMenu *menu,
GtkWidget *new_parent,
gboolean unrealize);
+ static gboolean gtk_menu_timeout_up (gpointer data) ;
+ static gboolean gtk_menu_timeout_down (gpointer data) ;
static GtkMenuShellClass *parent_class = NULL;
static const gchar *attach_data_key = "gtk-menu-attach-data";
***************
*** 126,131 ****
--- 135,141 ----
widget_class->size_allocate = gtk_menu_size_allocate;
widget_class->expose_event = gtk_menu_expose;
widget_class->key_press_event = gtk_menu_key_press;
+ widget_class->key_release_event = gtk_menu_key_release;
widget_class->motion_notify_event = gtk_menu_motion_notify;
widget_class->show_all = gtk_menu_show_all;
widget_class->hide_all = gtk_menu_hide_all;
***************
*** 192,197 ****
--- 202,215 ----
menu->position_func = NULL;
menu->position_func_data = NULL;
+ menu->first_scroll_child = -1 ;
+ menu->last_scroll_child = -1 ;
+ menu->top_scroll_arrow_lit = FALSE ;
+ menu->bottom_scroll_arrow_lit = FALSE ;
+ menu->scroll_up_source_tag = 0 ;
+ menu->scroll_down_source_tag = 0 ;
+
+
menu->toplevel = gtk_window_new (GTK_WINDOW_POPUP);
gtk_signal_connect (GTK_OBJECT (menu->toplevel),
"event",
***************
*** 223,228 ****
--- 241,251 ----
g_return_if_fail (GTK_IS_MENU (object));
menu = GTK_MENU (object);
+
+ if (menu->scroll_up_source_tag)
+ g_source_remove (menu->scroll_up_source_tag) ;
+ if (menu->scroll_down_source_tag)
+ g_source_remove (menu->scroll_down_source_tag) ;
gtk_object_ref (object);
***************
*** 418,423 ****
--- 441,449 ----
widget = GTK_WIDGET (menu);
menu_shell = GTK_MENU_SHELL (menu);
+
+ menu->top_scroll_arrow_lit = FALSE ;
+ menu->bottom_scroll_arrow_lit = FALSE ;
menu_shell->parent_menu_shell = parent_menu_shell;
menu_shell->active = TRUE;
***************
*** 534,539 ****
--- 560,567 ----
}
gtk_menu_shell_deselect (menu_shell);
+
+ gtk_menu_set_scrolling (menu, FALSE, FALSE) ;
/* The X Grab, if present, will automatically be removed when we hide
* the window */
***************
*** 892,911 ****
menu_shell = GTK_MENU_SHELL (widget);
widget->allocation = *allocation;
if (GTK_WIDGET_REALIZED (widget))
gdk_window_move_resize (widget->window,
allocation->x, allocation->y,
! allocation->width, allocation->height);
!
if (menu_shell->children)
{
! child_allocation.x = (GTK_CONTAINER (menu)->border_width +
! widget->style->klass->xthickness);
! child_allocation.y = (GTK_CONTAINER (menu)->border_width +
! widget->style->klass->ythickness);
! child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2);
!
children = menu_shell->children;
while (children)
{
--- 920,947 ----
menu_shell = GTK_MENU_SHELL (widget);
widget->allocation = *allocation;
+
if (GTK_WIDGET_REALIZED (widget))
gdk_window_move_resize (widget->window,
allocation->x, allocation->y,
! allocation->width, allocation->height) ;
if (menu_shell->children)
{
! guint child_num ;
!
! child_allocation.x = GTK_CONTAINER (menu)->border_width +
! GTK_WIDGET (menu)->style->klass->xthickness ;
! child_allocation.y = GTK_CONTAINER (menu)->border_width +
! GTK_WIDGET (menu)->style->klass->ythickness ;
! child_allocation.width = MAX (1,
! (gint)allocation->width - child_allocation.x * 2);
!
! if (menu->first_scroll_child != -1)
! child_allocation.y = MENU_SCROLL_ARROW_HEIGHT ;
!
! child_num = 0 ;
!
children = menu_shell->children;
while (children)
{
***************
*** 917,929 ****
GtkRequisition child_requisition;
gtk_widget_get_child_requisition (child, &child_requisition);
! child_allocation.height = child_requisition.height;
!
! gtk_widget_size_allocate (child, &child_allocation);
! gtk_widget_queue_draw (child);
!
! child_allocation.y += child_allocation.height;
}
}
}
}
--- 953,984 ----
GtkRequisition child_requisition;
gtk_widget_get_child_requisition (child, &child_requisition);
! if ((child_num < menu->first_scroll_child
! && menu->first_scroll_child != -1)
! || (child_num > menu->last_scroll_child
! && menu->last_scroll_child != -1))
! {
! GtkAllocation outside_allocation ;
!
! outside_allocation.x = -child_requisition.width ;
! outside_allocation.y = -child_requisition.height ;
! outside_allocation.width = child_requisition.width ;
! outside_allocation.height = child_requisition.height ;
!
! gtk_widget_size_allocate (child, &outside_allocation) ;
! }
! else
! {
! child_allocation.height = child_requisition.height ;
!
! gtk_widget_size_allocate (child, &child_allocation) ;
! gtk_widget_queue_draw (child) ;
!
! child_allocation.y += child_allocation.height ;
! }
}
+
+ child_num ++ ;
}
}
}
***************
*** 936,947 ****
--- 991,1041 ----
if (GTK_WIDGET_DRAWABLE (widget))
{
+ guint border ;
+ guint width, height ;
+
+ border = GTK_CONTAINER (widget)->border_width +
+ widget->style->klass->ythickness + 1 ;
+ gdk_window_get_size (widget->window, &width, &height) ;
+
gtk_paint_box (widget->style,
widget->window,
GTK_STATE_NORMAL,
GTK_SHADOW_OUT,
NULL, widget, "menu",
0, 0, -1, -1);
+
+ if (GTK_MENU (widget)->first_scroll_child != -1)
+ {
+ gtk_paint_arrow (widget->style,
+ widget->window,
+ GTK_MENU (widget)->top_scroll_arrow_lit ?
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ NULL, widget, "menu",
+ GTK_ARROW_UP,
+ TRUE,
+ width / 2 - MENU_SCROLL_ARROW_HEIGHT / 2 + 1,
+ border-1,
+ MENU_SCROLL_ARROW_HEIGHT - 2,
+ MENU_SCROLL_ARROW_HEIGHT - 2) ;
+ }
+
+ if (GTK_MENU(widget)->last_scroll_child != -1)
+ {
+ gtk_paint_arrow (widget->style,
+ widget->window,
+ GTK_MENU (widget)->bottom_scroll_arrow_lit ?
+ GTK_STATE_PRELIGHT : GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ NULL, widget, "menu",
+ GTK_ARROW_DOWN,
+ TRUE,
+ width / 2 - MENU_SCROLL_ARROW_HEIGHT / 2 + 1,
+ height - border - MENU_SCROLL_ARROW_HEIGHT +1 ,
+ MENU_SCROLL_ARROW_HEIGHT - 2,
+ MENU_SCROLL_ARROW_HEIGHT - 2) ;
+ }
}
}
***************
*** 1015,1020 ****
--- 1109,1130 ----
}
static gint
+ gtk_menu_key_release (GtkWidget *widget,
+ GdkEventKey *event)
+ {
+ GtkMenuShell *menu_shell;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ menu_shell = GTK_MENU_SHELL (widget);
+ menu_shell->ignore_enter = FALSE ;
+
+ return TRUE;
+ }
+
+ static gint
gtk_menu_key_press (GtkWidget *widget,
GdkEventKey *event)
{
***************
*** 1026,1031 ****
--- 1136,1142 ----
g_return_val_if_fail (event != NULL, FALSE);
menu_shell = GTK_MENU_SHELL (widget);
+ menu_shell->ignore_enter = TRUE ;
if (GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event))
return TRUE;
***************
*** 1104,1121 ****
gtk_menu_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
{
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
if (GTK_MENU_SHELL (widget)->ignore_enter)
GTK_MENU_SHELL (widget)->ignore_enter = FALSE;
else
{
! gint width, height;
!
! gdk_window_get_size (event->window, &width, &height);
! if (event->x >= 0 && event->x < width &&
! event->y >= 0 && event->y < height)
{
GdkEvent send_event;
--- 1215,1245 ----
gtk_menu_motion_notify (GtkWidget *widget,
GdkEventMotion *event)
{
+ gboolean in_window ;
+ guint border ;
+ gint x, y, width, height ;
+ gboolean old_top_lit, old_bottom_lit ;
+ gboolean scroll_up, scroll_down ;
+
g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_MENU (widget), FALSE);
+
+ gdk_window_get_pointer (widget->window, &x, &y, NULL);
+ gdk_window_get_size (widget->window, &width, &height) ;
+
+ in_window = FALSE ;
+ if (x >= 0 && x < width &&
+ y >= 0 && y < height)
+ in_window = TRUE ;
+
+ border = GTK_CONTAINER (widget)->border_width +
+ widget->style->klass->ythickness ;
if (GTK_MENU_SHELL (widget)->ignore_enter)
GTK_MENU_SHELL (widget)->ignore_enter = FALSE;
else
{
! if (in_window)
{
GdkEvent send_event;
***************
*** 1128,1133 ****
--- 1252,1293 ----
}
}
+ old_top_lit = GTK_MENU (widget)->top_scroll_arrow_lit ;
+ old_bottom_lit = GTK_MENU (widget)->bottom_scroll_arrow_lit ;
+ GTK_MENU (widget)->top_scroll_arrow_lit = FALSE ;
+ GTK_MENU (widget)->bottom_scroll_arrow_lit = FALSE ;
+
+ scroll_up = FALSE ;
+ scroll_down = FALSE ;
+
+ if (y < border + MENU_SCROLL_ARROW_HEIGHT && y >= 0
+ && x >= 0 && x < width
+ && GTK_MENU (widget)->first_scroll_child != -1)
+ {
+ if (in_window)
+ GTK_MENU (widget)->top_scroll_arrow_lit = TRUE ;
+
+ if (GTK_MENU_SHELL(widget)->button)
+ scroll_up = TRUE ;
+ }
+
+ if (y >= height - border - MENU_SCROLL_ARROW_HEIGHT && y < height
+ && x >= 0 && x < width
+ && GTK_MENU (widget)->last_scroll_child != -1)
+ {
+ if (in_window)
+ GTK_MENU (widget)->bottom_scroll_arrow_lit = TRUE ;
+
+ if (GTK_MENU_SHELL(widget)->button)
+ scroll_down = TRUE ;
+ }
+
+ gtk_menu_set_scrolling (GTK_MENU (widget), scroll_up, scroll_down) ;
+
+ if (GTK_MENU (widget)->top_scroll_arrow_lit != old_top_lit
+ || GTK_MENU (widget)->bottom_scroll_arrow_lit != old_bottom_lit)
+ gtk_menu_paint (widget) ;
+
return FALSE;
}
***************
*** 1171,1177 ****
--- 1331,1339 ----
gtk_widget_size_request (widget, &requisition);
if (menu->position_func)
+ {
(* menu->position_func) (menu, &x, &y, menu->position_func_data);
+ }
else
{
gint screen_width;
***************
*** 1184,1198 ****
y = CLAMP (y - 2, 0, MAX (0, screen_height - requisition.height));
}
! /* FIXME: The MAX() here is because gtk_widget_set_uposition
! * is broken. Once we provide an alternate interface that
! * allows negative values, then we can remove them.
! */
! gtk_widget_set_uposition (GTK_MENU_SHELL (menu)->active ?
! menu->toplevel : menu->tearoff_window,
! MAX (x, 0), MAX (y, 0));
}
/* Reparent the menu, taking care of the refcounting
*/
static void
--- 1346,1471 ----
y = CLAMP (y - 2, 0, MAX (0, screen_height - requisition.height));
}
! gtk_menu_top_position (menu, x, y, requisition.width, requisition.height) ;
}
+ /* Set the actual position of the toplevel window. Also, if part of the
+ * toplevel window would fall offscreen, truncate the window and note that
+ * we will use scroll arrows.
+ */
+ static void
+ gtk_menu_top_position (GtkMenu *menu,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+ {
+ gint border_height;
+
+ border_height = GTK_CONTAINER (menu)->border_width +
+ GTK_WIDGET (menu)->style->klass->ythickness;
+
+ if (GTK_MENU_SHELL (menu)->active)
+ {
+ GList *child_list;
+ gint screen_height;
+ gint on_line;
+ gint last_line ;
+ guint offset = -1 ;
+
+ child_list = GTK_MENU_SHELL (menu)->children;
+ screen_height = gdk_screen_height ();
+
+ on_line = y + border_height * 2 ;
+
+ if (y < 0)
+ {
+ menu->first_scroll_child = 0;
+ while (child_list && on_line < MENU_SCROLL_ARROW_HEIGHT)
+ {
+ GtkWidget *child;
+
+ child = GTK_WIDGET (child_list->data);
+ if (GTK_WIDGET_VISIBLE (child))
+ {
+ height -= child->requisition.height;
+ on_line += child->requisition.height;
+ y += child->requisition.height;
+ }
+ offset ++ ;
+ child_list = child_list->next;
+ menu->first_scroll_child++;
+ }
+ y -= MENU_SCROLL_ARROW_HEIGHT;
+ height += MENU_SCROLL_ARROW_HEIGHT;
+ }
+ else
+ menu->first_scroll_child = -1;
+
+ if (y + height >= screen_height)
+ {
+ if (offset < 0)
+ menu->last_scroll_child = menu->first_scroll_child ;
+ else
+ menu->last_scroll_child = offset ;
+
+ last_line = on_line ;
+
+ while (child_list)
+ {
+ GtkWidget *child;
+
+ child = GTK_WIDGET (child_list->data);
+
+ if (GTK_WIDGET_VISIBLE (child))
+ {
+ if (on_line + child->requisition.height +
+ MENU_SCROLL_ARROW_HEIGHT > screen_height
+ && child_list->next)
+ {
+ if (last_line == on_line)
+ {
+ menu->last_scroll_child = 0 ;
+ on_line = screen_height - MENU_SCROLL_ARROW_HEIGHT ;
+ y = screen_height - (child->requisition.height +
+ MENU_SCROLL_ARROW_HEIGHT + border_height * 2) ;
+ }
+ break ;
+ }
+
+ if (on_line + child->requisition.height > screen_height)
+ break ;
+
+ last_line = on_line ;
+ on_line += child->requisition.height;
+ }
+ offset ++ ;
+ child_list = child_list->next;
+ menu->last_scroll_child++;
+
+ if (on_line > screen_height)
+ break ;
+ }
+
+ if (child_list && child_list->next)
+ on_line += MENU_SCROLL_ARROW_HEIGHT ;
+ if(menu->last_scroll_child < 0)
+ menu->last_scroll_child = menu->first_scroll_child;
+ height = on_line - y ;
+
+ }
+ else
+ menu->last_scroll_child = -1;
+
+ gtk_widget_set_uposition (menu->toplevel, x, y);
+ gtk_widget_set_usize (menu->toplevel, width, height);
+ }
+ else
+ {
+ gtk_widget_set_uposition (menu->tearoff_window, x, y);
+ }
+ }
+
/* Reparent the menu, taking care of the refcounting
*/
static void
***************
*** 1234,1239 ****
--- 1507,1884 ----
gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL);
}
+ /* Set the scrolling state of the menu. It is harmless to call this
+ * if there is no change in scrolling state. (That is, it won't interrupt
+ * or reset the scrolling timers if the scrolling settings are the same).
+ */
+ void
+ gtk_menu_set_scrolling (GtkMenu *menu,
+ gboolean scroll_up,
+ gboolean scroll_down)
+ {
+ if (!scroll_up && menu->scroll_up_source_tag)
+ {
+ g_source_remove (menu->scroll_up_source_tag);
+ menu->scroll_up_source_tag = 0;
+ }
+
+ if (!scroll_down && menu->scroll_down_source_tag)
+ {
+ g_source_remove (menu->scroll_down_source_tag);
+ menu->scroll_down_source_tag = 0;
+ }
+
+ if(scroll_up && !menu->scroll_up_source_tag)
+ {
+ if (gtk_menu_scroll_up (menu, 1))
+ menu->scroll_up_source_tag = g_timeout_add (MENU_SCROLL_TIMEOUT, gtk_menu_timeout_up, menu);
+ }
+
+ if(scroll_down && !menu->scroll_down_source_tag)
+ {
+ if (gtk_menu_scroll_down (menu, 1))
+ menu->scroll_down_source_tag = g_timeout_add (MENU_SCROLL_TIMEOUT, gtk_menu_timeout_down, menu);
+ }
+ }
+
+ gboolean
+ gtk_menu_has_scroll (GtkMenu *menu)
+ {
+ gint x, y, width, height ;
+ gint screen_height ;
+ gint on_line ;
+ gint on_child ;
+ gint border ;
+ GList *children_copy;
+ GList *child;
+ GtkRequisition requisition;
+
+ if (menu->first_scroll_child != -1
+ || menu->last_scroll_child != -1)
+ return TRUE ;
+
+
+ // check scroll up
+ gdk_window_get_geometry (menu->toplevel->window,
+ &x, &y,
+ &width, &height,
+ NULL);
+ screen_height = gdk_screen_height ();
+
+ border = GTK_CONTAINER (menu)->border_width +
+ GTK_WIDGET (menu)->style->klass->ythickness;
+
+ on_line = y + border * 2 ;
+ on_child = 0;
+ child = GTK_MENU_SHELL (menu)->children;
+ if (menu->first_scroll_child != -1)
+ {
+ on_child = menu->first_scroll_child ;
+ child = g_list_nth (child, menu->first_scroll_child) ;
+ }
+ while (child && on_line < screen_height)
+ {
+ GtkWidget *widget;
+ widget = GTK_WIDGET (child->data);
+ if (GTK_WIDGET_VISIBLE (widget))
+ {
+ gtk_widget_size_request (widget, &requisition);
+
+ if (on_line + requisition.height +
+ MENU_SCROLL_ARROW_HEIGHT >= screen_height
+ && child->next)
+ break ;
+
+ on_line += requisition.height ;
+ }
+
+ on_child ++ ;
+ child = child->next;
+ }
+
+ if (child)
+ return TRUE ;
+
+ // check scroll down
+ on_line = screen_height - border * 2 ;
+ children_copy = g_list_copy (GTK_MENU_SHELL (menu)->children);
+ children_copy = g_list_reverse(children_copy);
+ on_child = g_list_length (GTK_MENU_SHELL (menu)->children) -1;
+ child = children_copy ;
+ if (menu->last_scroll_child != -1)
+ {
+ on_child = menu->last_scroll_child ;
+ child = g_list_nth (child,
+ g_list_length (children_copy)-1 - on_child) ;
+ }
+ while (child && on_line >= y)
+ {
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (child->data);
+ if ((on_child <= menu->last_scroll_child
+ || menu->last_scroll_child == -1)
+ && GTK_WIDGET_VISIBLE (widget))
+ {
+ gtk_widget_size_request (widget, &requisition);
+
+ if (on_line + requisition.height +
+ MENU_SCROLL_ARROW_HEIGHT < y
+ && child->next)
+ break ;
+
+ on_line += requisition.height ;
+ }
+
+ on_child--;
+ child = child->next;
+ }
+
+ g_list_free(children_copy);
+
+ if (on_child >= 0)
+ return TRUE ;
+
+ return FALSE ;
+ }
+
+ gboolean
+ gtk_menu_scroll_up (GtkMenu *menu,
+ guint scroll_count)
+ {
+ gboolean return_value;
+ gint x, y, width, height;
+ gint screen_height;
+ gint on_line;
+ gint last_line;
+ gint on_child;
+ gint border;
+ GList *child;
+ GtkAllocation allocation;
+
+ return_value = TRUE;
+
+ gdk_window_get_geometry (menu->toplevel->window,
+ &x, &y,
+ &width, &height,
+ NULL);
+ screen_height = gdk_screen_height ();
+
+ border = GTK_CONTAINER (menu)->border_width +
+ GTK_WIDGET (menu)->style->klass->ythickness;
+
+ menu->first_scroll_child -= scroll_count ;
+ if (menu->first_scroll_child <= 0) {
+ menu->first_scroll_child = -1;
+ return_value = FALSE;
+ }
+
+ on_line = y + border * 2 ;
+ last_line = on_line;
+ if (menu->first_scroll_child != -1)
+ on_line += MENU_SCROLL_ARROW_HEIGHT;
+
+ on_child = 0;
+ child = GTK_MENU_SHELL (menu)->children;
+ if (menu->first_scroll_child != -1)
+ {
+ on_child = menu->first_scroll_child ;
+ child = g_list_nth (child, menu->first_scroll_child) ;
+ }
+
+ while (child && on_line <= screen_height)
+ {
+ GtkWidget *widget;
+ widget = GTK_WIDGET (child->data);
+
+ if (GTK_WIDGET_VISIBLE (widget))
+ {
+ if (on_line + widget->allocation.height +
+ MENU_SCROLL_ARROW_HEIGHT > screen_height
+ && child->next)
+ break ;
+
+ if (on_line + widget->allocation.height > screen_height)
+ break ;
+
+ last_line = on_line;
+ on_line += widget->allocation.height;
+ }
+
+ on_child++;
+ child = child->next;
+ }
+
+ if (child)
+ {
+ menu->last_scroll_child = on_child - 1;
+ if (menu->last_scroll_child < menu->first_scroll_child
+ && menu->first_scroll_child != -1)
+ menu->first_scroll_child = menu->last_scroll_child;
+ on_line += MENU_SCROLL_ARROW_HEIGHT ;
+ }
+ else
+ {
+ menu->last_scroll_child = -1 ;
+ }
+
+ gdk_window_move_resize (menu->toplevel->window,
+ x, y, width, on_line - y);
+
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation.width = width;
+ allocation.height = on_line - y;
+ gtk_widget_size_allocate (GTK_WIDGET (menu), &allocation);
+
+ return return_value;
+ }
+
+ gboolean
+ gtk_menu_scroll_down (GtkMenu *menu,
+ guint scroll_count)
+ {
+ gboolean return_value;
+ gint x, y, width, height;
+ gint screen_height;
+ gint on_line;
+ gint last_line;
+ gint new_height;
+ gint on_child;
+ gint border;
+ gint child_height = 0 ;
+ GList *children_copy;
+ GList *child;
+ GtkAllocation allocation;
+
+ return_value = TRUE;
+
+ gdk_window_get_geometry (menu->toplevel->window,
+ &x, &y,
+ &width, &height,
+ NULL);
+ screen_height = gdk_screen_height ();
+
+ border = GTK_CONTAINER (menu)->border_width +
+ GTK_WIDGET (menu)->style->klass->ythickness;
+
+ menu->last_scroll_child += scroll_count ;
+ if (menu->last_scroll_child >=
+ g_list_length (GTK_MENU_SHELL (menu)->children)-1) {
+ menu->last_scroll_child = -1;
+ return_value = FALSE;
+ }
+
+ on_line = screen_height - border * 2 ;
+ if (menu->last_scroll_child != -1)
+ on_line -= MENU_SCROLL_ARROW_HEIGHT ;
+ last_line = on_line;
+
+ children_copy = g_list_copy (GTK_MENU_SHELL (menu)->children);
+ children_copy = g_list_reverse(children_copy);
+ on_child = g_list_length (GTK_MENU_SHELL (menu)->children) -1;
+ child = children_copy ;
+ if (menu->last_scroll_child != -1)
+ {
+ on_child = menu->last_scroll_child ;
+ child = g_list_nth (child,
+ g_list_length (children_copy)-1 - on_child) ;
+ }
+
+ while (child && on_line >= y)
+ {
+ GtkWidget *widget;
+ widget = GTK_WIDGET (child->data);
+
+ if (GTK_WIDGET_VISIBLE (widget))
+ {
+ child_height = widget->allocation.height ;
+
+ if (on_line - widget->allocation.height -
+ MENU_SCROLL_ARROW_HEIGHT < y
+ && child->next)
+ {
+ if (last_line == on_line)
+ {
+ y = on_line - MENU_SCROLL_ARROW_HEIGHT
+ - widget->allocation.height ;
+ on_line -= widget->allocation.height ;
+ }
+ break ;
+ }
+
+ if (on_line + widget->allocation.height < y)
+ break ;
+
+ last_line = on_line;
+ on_line -= widget->allocation.height;
+ }
+
+ on_child--;
+ child = child->next;
+ }
+
+ if (child)
+ {
+ menu->first_scroll_child = on_child + 1;
+
+ if (menu->first_scroll_child > menu->last_scroll_child
+ && menu->last_scroll_child != -1)
+ menu->first_scroll_child = menu->last_scroll_child;
+ on_line -= MENU_SCROLL_ARROW_HEIGHT ;
+ }
+ else
+ {
+ menu->first_scroll_child = -1;
+ }
+
+ new_height = screen_height - on_line;
+
+ gdk_window_move_resize (menu->toplevel->window,
+ x, y, width, new_height);
+
+ allocation.x = 0;
+ allocation.y = 0;
+ allocation.width = width;
+ allocation.height = new_height;
+ gtk_widget_size_allocate (GTK_WIDGET (menu), &allocation);
+
+ g_list_free(children_copy);
+
+ return return_value;
+ }
+
+ static gboolean
+ gtk_menu_timeout_up (gpointer data)
+ {
+ GtkMenu *menu;
+
+ menu = GTK_MENU (data);
+
+ if (gtk_menu_scroll_up (menu, 1))
+ return TRUE;
+ else
+ {
+ menu->scroll_up_source_tag = 0;
+ return FALSE;
+ }
+ }
+
+ static gboolean
+ gtk_menu_timeout_down (gpointer data)
+ {
+ GtkMenu *menu;
+
+ menu = GTK_MENU (data);
+
+ if (gtk_menu_scroll_down (menu, 1))
+ return TRUE;
+ else
+ {
+ menu->scroll_down_source_tag = 0;
+ return FALSE;
+ }
+ }
static void
gtk_menu_hide_all (GtkWidget *widget)
diff -c -r gtk/gtkmenu.h ../gtk+-1.2.8.new/gtk/gtkmenu.h
*** gtk/gtkmenu.h Wed Mar 1 13:00:35 2000
--- ../gtk+-1.2.8.new/gtk/gtkmenu.h Thu Aug 3 16:54:26 2000
***************
*** 37,42 ****
--- 37,44 ----
extern "C" {
#endif /* __cplusplus */
+ #define MENU_SCROLL_ARROW_HEIGHT 16
+ #define MENU_SCROLL_TIMEOUT 200
#define GTK_TYPE_MENU (gtk_menu_get_type ())
#define GTK_MENU(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_MENU, GtkMenu))
***************
*** 74,79 ****
--- 76,91 ----
GtkWidget *tearoff_window;
guint torn_off : 1;
+
+ /* Internal information used for the scroll arrow handling */
+ gint first_scroll_child;
+ gint last_scroll_child;
+
+ gboolean top_scroll_arrow_lit;
+ gboolean bottom_scroll_arrow_lit;
+
+ guint scroll_up_source_tag;
+ guint scroll_down_source_tag;
};
struct _GtkMenuClass
***************
*** 158,163 ****
--- 170,182 ----
void gtk_menu_reorder_child (GtkMenu *menu,
GtkWidget *child,
gint position);
+
+ void gtk_menu_set_scrolling (GtkMenu *menu,
+ gboolean scroll_up,
+ gboolean scroll_down) ;
+ gboolean gtk_menu_has_scroll (GtkMenu *menu) ;
+ gboolean gtk_menu_scroll_up (GtkMenu *menu, guint scroll_count) ;
+ gboolean gtk_menu_scroll_down (GtkMenu *menu, guint scroll_count) ;
#ifdef __cplusplus
}
diff -c -r gtk/gtkmenuitem.c ../gtk+-1.2.8.new/gtk/gtkmenuitem.c
*** gtk/gtkmenuitem.c Sat Sep 4 07:50:37 1999
--- ../gtk+-1.2.8.new/gtk/gtkmenuitem.c Thu Aug 3 12:31:42 2000
***************
*** 699,704 ****
--- 699,712 ----
return;
}
+ if (gtk_menu_has_scroll(menu)) { // check scroll
+ if (tx + GTK_WIDGET(menu_item)->allocation.width
+ + GTK_WIDGET(menu)->requisition.width < screen_width)
+ tx += GTK_WIDGET (menu_item)->allocation.width ;
+ else
+ tx -= GTK_WIDGET(menu)->requisition.width ;
+ }
+
switch (menu_item->submenu_placement)
{
case GTK_TOP_BOTTOM:
diff -c -r gtk/gtkmenushell.c ../gtk+-1.2.8.new/gtk/gtkmenushell.c
*** gtk/gtkmenushell.c Sat Feb 5 02:29:29 2000
--- ../gtk+-1.2.8.new/gtk/gtkmenushell.c Thu Aug 3 15:00:04 2000
***************
*** 32,42 ****
#include "gtkmenushell.h"
#include "gtksignal.h"
#define MENU_SHELL_TIMEOUT 500
#define MENU_SHELL_CLASS(w) GTK_MENU_SHELL_CLASS (GTK_OBJECT (w)->klass)
-
enum {
DEACTIVATE,
SELECTION_DONE,
--- 32,43 ----
#include "gtkmenushell.h"
#include "gtksignal.h"
+ #include "gtkmenu.h"
+
#define MENU_SHELL_TIMEOUT 500
#define MENU_SHELL_CLASS(w) GTK_MENU_SHELL_CLASS (GTK_OBJECT (w)->klass)
enum {
DEACTIVATE,
SELECTION_DONE,
***************
*** 444,449 ****
--- 445,491 ----
}
}
+ if (GTK_IS_MENU(widget))
+ {
+ // check scroll arrow lit
+ gboolean in_window ;
+ guint border ;
+ gint x, y, width, height ;
+ gboolean scroll_up, scroll_down ;
+
+ GtkMenu *menu = GTK_MENU (widget) ;
+
+ gdk_window_get_pointer (widget->window, &x, &y, NULL) ;
+ gdk_window_get_size (widget->window, &width, &height) ;
+
+ in_window = FALSE ;
+ if (x >= 0 && x < width &&
+ y >= 0 && y < height)
+ in_window = TRUE ;
+ border = GTK_CONTAINER (widget)->border_width +
+ widget->style->klass->ythickness ;
+
+ scroll_up = FALSE ;
+ scroll_down = FALSE ;
+
+ if (y < border + MENU_SCROLL_ARROW_HEIGHT && y >= 0
+ && x >= 0 && x < width
+ && menu->first_scroll_child != -1)
+ {
+ scroll_up = TRUE ;
+ }
+
+ if (y >= height - border - MENU_SCROLL_ARROW_HEIGHT && y < height
+ && x >= 0 && x < width
+ && menu->last_scroll_child != -1)
+ {
+ scroll_down = TRUE ;
+ }
+
+ gtk_menu_set_scrolling (GTK_MENU (widget), scroll_up, scroll_down) ;
+ }
+
+
return TRUE;
}
***************
*** 475,480 ****
--- 517,546 ----
deactivate = TRUE;
+ if (GTK_IS_MENU(widget))
+ { // check arrow scroll
+ gint width, height, x, y ;
+ gint border ;
+ GtkMenu *menu = GTK_MENU(widget) ;
+
+ border = GTK_CONTAINER (widget)->border_width +
+ widget->style->klass->ythickness ;
+
+ gdk_window_get_pointer (widget->window, &x, &y, NULL) ;
+ gdk_window_get_size (widget->window, &width, &height) ;
+
+ if (menu->first_scroll_child != -1
+ && y < border + MENU_SCROLL_ARROW_HEIGHT && y >= 0
+ && x >= 0 && x < width)
+ return FALSE ;
+
+ if (menu->last_scroll_child != -1
+ && y >= height - border - MENU_SCROLL_ARROW_HEIGHT && y < height
+ && x >= 0 && x < width)
+ return TRUE ;
+
+ }
+
if ((event->time - menu_shell->activate_time) > MENU_SHELL_TIMEOUT)
{
if (menu_item && (menu_shell->active_menu_item == menu_item) &&
***************
*** 898,905 ****
}
}
! if (node)
! gtk_menu_shell_select_item (menu_shell, node->data);
}
}
--- 964,994 ----
}
}
! if (node)
! {
! gtk_menu_shell_select_item (menu_shell, node->data);
!
! if (menu_shell->active_menu_item && GTK_IS_MENU(menu_shell))
! {
! gint idx ;
! gint first_idx ;
! gint last_idx ;
!
! first_idx = GTK_MENU(menu_shell)->first_scroll_child ;
! last_idx = GTK_MENU(menu_shell)->last_scroll_child ;
! idx = g_list_index (menu_shell->children, menu_shell->active_menu_item) ;
! if (first_idx < 0)
! first_idx = 0 ;
! if (last_idx < 0)
! last_idx = g_list_length (menu_shell->children) ;
!
! if (idx < first_idx)
! gtk_menu_scroll_up (GTK_MENU(menu_shell), first_idx - idx) ;
!
! if (idx > last_idx)
! gtk_menu_scroll_down (GTK_MENU(menu_shell), idx - last_idx) ;
! }
! }
}
}
diff -c -r gtk/gtkoptionmenu.c ../gtk+-1.2.8.new/gtk/gtkoptionmenu.c
*** gtk/gtkoptionmenu.c Thu Jan 27 22:39:55 2000
--- ../gtk+-1.2.8.new/gtk/gtkoptionmenu.c Thu Aug 3 14:38:41 2000
***************
*** 618,624 ****
GtkWidget *child;
GtkRequisition requisition;
GList *children;
- gint shift_menu;
gint screen_width;
gint screen_height;
gint menu_xpos;
--- 618,623 ----
***************
*** 666,695 ****
screen_width = gdk_screen_width ();
screen_height = gdk_screen_height ();
! shift_menu = FALSE;
! if (menu_ypos < 0)
! {
! menu_ypos = 0;
! shift_menu = TRUE;
! }
! else if ((menu_ypos + height) > screen_height)
! {
! menu_ypos -= ((menu_ypos + height) - screen_height);
! shift_menu = TRUE;
! }
!
! if (shift_menu)
! {
! if ((menu_xpos + GTK_WIDGET (option_menu)->allocation.width + width) <= screen_width)
! menu_xpos += GTK_WIDGET (option_menu)->allocation.width;
! else
! menu_xpos -= width;
! }
!
if (menu_xpos < 0)
! menu_xpos = 0;
! else if ((menu_xpos + width) > screen_width)
! menu_xpos -= ((menu_xpos + width) - screen_width);
*x = menu_xpos;
*y = menu_ypos;
--- 665,674 ----
screen_width = gdk_screen_width ();
screen_height = gdk_screen_height ();
! if (menu_xpos + width >= screen_width)
! menu_xpos -= width ;
if (menu_xpos < 0)
! menu_xpos += GTK_WIDGET(option_menu)->allocation.width ;
*x = menu_xpos;
*y = menu_ypos;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]