Author: rpmcruz Date: Sun Jan 18 17:11:35 2009 New Revision: 54747 URL: http://svn.opensuse.org/viewcvs/yast?rev=54747&view=rev Log: * src/YGDialog.h/cc: methods to retrive function key widget and and list of widgets from a given class. * src/YGPackageSelector.cc & src/ygtkscrolledwindow.h/c: moved right-click tree hack from the pkg selector to its own widget. * src/YGTable.cc: implemented Martin Vidner suggestion on function keys: http://mvidner.blogspot.com/2009/01/yast-ui-table-usability.html Modified: trunk/gtk/ChangeLog trunk/gtk/src/YGDialog.cc trunk/gtk/src/YGDialog.h trunk/gtk/src/YGPackageSelector.cc trunk/gtk/src/YGPushButton.cc trunk/gtk/src/YGTable.cc trunk/gtk/src/YGUtils.cc trunk/gtk/src/ygtkscrolledwindow.c trunk/gtk/src/ygtkscrolledwindow.h Modified: trunk/gtk/ChangeLog URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/ChangeLog?rev=54747&r1=54... ============================================================================== --- trunk/gtk/ChangeLog (original) +++ trunk/gtk/ChangeLog Sun Jan 18 17:11:35 2009 @@ -8,8 +8,17 @@ * src/pkg-selector-help.h: bug fix 448192 & 459457: improved pkg selector help a bit. - * src/YGLayout.cc: looks odd when adjusting menu buttons to the same - height as the other buttons. + * src/YGLayout.cc: bug fix 464904: looks odd when adjusting menu + buttons to the same height as the other buttons. + + * src/YGDialog.h/cc: methods to retrive function key widget and + and list of widgets from a given class. + + * src/YGPackageSelector.cc & src/ygtkscrolledwindow.h/c: moved + right-click tree hack from the pkg selector to its own widget. + + * src/YGTable.cc: implemented Martin Vidner suggestion on function + keys: http://mvidner.blogspot.com/2009/01/yast-ui-table-usability.html 2009-01-08 Ricardo Cruz <rpmcruz@alunos.dcc.fc.up.pt> Modified: trunk/gtk/src/YGDialog.cc URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/YGDialog.cc?rev=54747&... ============================================================================== --- trunk/gtk/src/YGDialog.cc (original) +++ trunk/gtk/src/YGDialog.cc Sun Jan 18 17:11:35 2009 @@ -11,6 +11,7 @@ #endif #include <gdk/gdkkeysyms.h> #include <math.h> // easter +#include <string.h> /* In the main dialog case, it doesn't necessarly have a window of its own. If there is already a main window, it should replace its content -- and when closed, @@ -529,6 +530,38 @@ } } +typedef bool (*FindWidgetsCb) (YWidget *widget, void *data) ; + +static void findWidgets ( + std::list <YWidget *> *widgets, YWidget *widget, FindWidgetsCb find_cb, void *cb_data) +{ + if (find_cb (widget, cb_data)) + widgets->push_back (widget); + for (YWidgetListConstIterator it = widget->childrenBegin(); + it != widget->childrenEnd(); it++) + findWidgets (widgets, *it, find_cb, cb_data); +} + +static bool IsFunctionWidget (YWidget *widget, void *data) +{ return widget->functionKey() == GPOINTER_TO_INT (data); } + +YWidget *YGDialog::getFunctionWidget (int key) +{ + std::list <YWidget *> widgets; + findWidgets (&widgets, this, IsFunctionWidget, GINT_TO_POINTER (key)); + return widgets.empty() ? NULL : widgets.front(); +} + +static bool IsClassWidget (YWidget *widget, void *data) +{ return !strcmp (widget->widgetClass(), (char *) data); } + +std::list <YWidget *> YGDialog::getClassWidgets (const char *className) +{ + std::list <YWidget *> widgets; + findWidgets (&widgets, this, IsClassWidget, (void *) className); + return widgets; +} + YDialog *YGWidgetFactory::createDialog (YDialogType dialogType, YDialogColorMode colorMode) { IMPL Modified: trunk/gtk/src/YGDialog.h URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/YGDialog.h?rev=54747&... ============================================================================== --- trunk/gtk/src/YGDialog.h (original) +++ trunk/gtk/src/YGDialog.h Sun Jan 18 17:11:35 2009 @@ -45,6 +45,9 @@ void setTitle (const std::string &title, bool sticky = false); void setIcon (const std::string &icon); + YWidget *getFunctionWidget (int key); + std::list <YWidget *> getClassWidgets (const char *className); + YGWIDGET_IMPL_CONTAINER (YDialog) }; Modified: trunk/gtk/src/YGPackageSelector.cc URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/YGPackageSelector.cc?rev=... ============================================================================== --- trunk/gtk/src/YGPackageSelector.cc (original) +++ trunk/gtk/src/YGPackageSelector.cc Sun Jan 18 17:11:35 2009 @@ -415,9 +415,6 @@ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button, event_time); gtk_widget_show_all (menu); } - - static gboolean popup_key_cb (GtkWidget *widget, View *pThis) - { pThis->signalPopup (0, gtk_get_current_event_time()); return TRUE; } }; struct ListView : public View { @@ -425,7 +422,7 @@ ListView (bool isTree, bool descriptiveTooltip, bool editable, PackagesView *parent) : View (parent), m_isTree (isTree), m_descriptiveTooltip (descriptiveTooltip) { - GtkTreeView *view = GTK_TREE_VIEW (m_widget = gtk_tree_view_new()); + GtkTreeView *view = GTK_TREE_VIEW (m_widget = ygtk_tree_view_new()); gtk_tree_view_set_headers_visible (view, FALSE); gtk_tree_view_set_search_column (view, YGtkZyppModel::NAME_COLUMN); GtkTreeViewColumn *column; @@ -467,10 +464,8 @@ if (editable) { g_signal_connect (G_OBJECT (m_widget), "row-activated", G_CALLBACK (package_activated_cb), this); - g_signal_connect (G_OBJECT (m_widget), "popup-menu", - G_CALLBACK (popup_key_cb), this); - g_signal_connect (G_OBJECT (m_widget), "button-press-event", - G_CALLBACK (popup_button_cb), this); + g_signal_connect (G_OBJECT (m_widget), "right-click", + G_CALLBACK (popup_menu_cb), this); } gtk_widget_set_has_tooltip (m_widget, TRUE); g_signal_connect (G_OBJECT (m_widget), "query-tooltip", @@ -514,25 +509,8 @@ packages.install(); } - static gboolean popup_button_cb (GtkWidget *widget, GdkEventButton *event, View *pThis) - { - // workaround (based on gedit): we want the tree view to receive this press in order - // to select the row, but we can't use connect_after, so we throw a dummy mouse press - if (event->type == GDK_BUTTON_PRESS && event->button == 3) { - static bool safeguard = false; - if (safeguard) return false; - safeguard = true; - if (pThis->countSelected() <= 1) { // if there is a selection, let it be - event->button = 1; - if (!gtk_widget_event (widget, (GdkEvent *) event)) - return FALSE; - } - pThis->signalPopup (3, event->time); - safeguard = false; - return TRUE; - } - return FALSE; - } + static void popup_menu_cb (YGtkTreeView *view, View *pThis) + { pThis->signalPopup(3, gtk_get_current_event_time()); } static gboolean can_select_row_cb (GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data) @@ -681,6 +659,8 @@ pThis->signalPopup (3, event->time); return FALSE; } + static gboolean popup_key_cb (GtkWidget *widget, View *pThis) + { pThis->signalPopup (0, gtk_get_current_event_time()); return TRUE; } }; GtkWidget *m_bin; Modified: trunk/gtk/src/YGPushButton.cc URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/YGPushButton.cc?rev=54747... ============================================================================== --- trunk/gtk/src/YGPushButton.cc (original) +++ trunk/gtk/src/YGPushButton.cc Sun Jan 18 17:11:35 2009 @@ -40,7 +40,7 @@ case 7: stock = GTK_STOCK_PREFERENCES; break; // Expert case 8: stock = GTK_STOCK_GO_BACK; break; case 9: stock = GTK_STOCK_CANCEL; break; -// case 10: stock = GTK_STOCK_GO_FORWARD; break; + case 10: stock = GTK_STOCK_OK; break; // Next/Finish/OK default: break; } #if YAST2_VERSION >= 2017006 Modified: trunk/gtk/src/YGTable.cc URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/YGTable.cc?rev=54747&... ============================================================================== --- trunk/gtk/src/YGTable.cc (original) +++ trunk/gtk/src/YGTable.cc Sun Jan 18 17:11:35 2009 @@ -9,6 +9,7 @@ #include "YSelectionWidget.h" #include "YGSelectionModel.h" #include "ygtkcellrenderertextpixbuf.h" +#include "ygtkscrolledwindow.h" /* A generic widget for table related widgets. */ class YGTableView : public YGScrolledWidget, public YGSelectionModel @@ -21,7 +22,7 @@ YGTableView (YWidget *ywidget, YWidget *parent, const string &label, bool ordinaryModel, bool isTree) : YGScrolledWidget (ywidget, parent, label, YD_VERT, - GTK_TYPE_TREE_VIEW, NULL) + YGTK_TYPE_TREE_VIEW, NULL) , YGSelectionModel ((YSelectionWidget *) ywidget, ordinaryModel, isTree) { IMPL @@ -203,6 +204,8 @@ }; #include "YTable.h" +#include "YGDialog.h" +#include <gdk/gdkkeysyms.h> class YGTable : public YTable, public YGTableView { @@ -243,6 +246,8 @@ connect (getWidget(), "row-activated", G_CALLBACK (activated_cb), (YGTableView *) this); connect (getSelection(), "changed", G_CALLBACK (selection_changed_cb), (YGTableView *) this); + connect (getWidget(), "right-click", G_CALLBACK (right_click_cb), this); + connect (getWidget(), "key-press-event", G_CALLBACK (key_press_event_cb), this); } virtual void setKeepSorting (bool keepSorting) @@ -322,6 +327,63 @@ } YGSELECTION_WIDGET_IMPL (YTable) + + // callbacks + + // hack up a popup menu and honor the delete key as suggested at: + // http://mvidner.blogspot.com/2009/01/yast-ui-table-usability.html + static void activateButton (YWidget *button) + { + YWidgetEvent *event = new YWidgetEvent (button, YEvent::Activated); + YGUI::ui()->sendEvent (event); + } + + static void right_click_cb (YGtkTreeView *view, gboolean outreach, YGTable *pThis) + { + if (!YGDialog::currentDialog()->getFunctionWidget (5) || + // undetermined case -- more than one table exists + YGDialog::currentDialog()->getClassWidgets ("YTable").size() > 1) { + gtk_widget_error_bell (GTK_WIDGET (view)); + return; + } + + struct inner { + static void key_activate_cb (GtkMenuItem *item, YWidget *button) + { activateButton (button); } + static void appendItem (GtkWidget *menu, const gchar *stock, int key) + { + YWidget *button = YGDialog::currentDialog()->getFunctionWidget (key); + if (button) { + GtkWidget *item; + item = gtk_image_menu_item_new_from_stock (stock, NULL); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + g_signal_connect (G_OBJECT (item), "activate", + G_CALLBACK (key_activate_cb), button); + } + } + }; + + GtkWidget *menu = gtk_menu_new(); + if (outreach) + inner::appendItem (menu, GTK_STOCK_ADD, 3); + else { + inner::appendItem (menu, GTK_STOCK_EDIT, 4); + inner::appendItem (menu, GTK_STOCK_DELETE, 5); + } + ygtk_tree_view_popup_menu (view, menu); + } + + static gboolean key_press_event_cb (GtkWidget *widget, GdkEventKey *event, YGTable *pThis) + { + if (event->keyval == GDK_Delete) { + YWidget *button = YGDialog::currentDialog()->getFunctionWidget (5); + if (button) + activateButton (button); + return TRUE; + } + return FALSE; + } + }; #if YAST2_VERSION >= 2017005 Modified: trunk/gtk/src/YGUtils.cc URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/YGUtils.cc?rev=54747&... ============================================================================== --- trunk/gtk/src/YGUtils.cc (original) +++ trunk/gtk/src/YGUtils.cc Sun Jan 18 17:11:35 2009 @@ -307,7 +307,7 @@ if (!*j) { // not valid text g_signal_stop_emission_by_name (editable, "insert_text"); - gdk_beep(); + gtk_widget_error_bell (GTK_WIDGET (editable)); return; } } Modified: trunk/gtk/src/ygtkscrolledwindow.c URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/ygtkscrolledwindow.c?rev=... ============================================================================== --- trunk/gtk/src/ygtkscrolledwindow.c (original) +++ trunk/gtk/src/ygtkscrolledwindow.c Sun Jan 18 17:11:35 2009 @@ -97,3 +97,82 @@ gtkobject_class->destroy = ygtk_scrolled_window_destroy; } +/* YGtkTreeView widget */ +// check the header file for information about this widget + +static guint right_click_signal = 0; + +G_DEFINE_TYPE (YGtkTreeView, ygtk_tree_view, GTK_TYPE_TREE_VIEW) + +static void ygtk_tree_view_init (YGtkTreeView *view) +{ +} + +static void _gtk_widget_destroy (gpointer widget) +{ gtk_widget_destroy (GTK_WIDGET (widget)); } + +void ygtk_tree_view_popup_menu (YGtkTreeView *view, GtkWidget *menu) +{ + GtkWidget *widget = GTK_WIDGET (view); + // popup hack -- we can't destroy the menu at hide because it may not have + // emitted signals yet -- destroy it when replaced or the widget destroyed + g_object_set_data_full (G_OBJECT (view), "popup", menu, _gtk_widget_destroy); + + guint32 time = gtk_get_current_event_time(); + gtk_menu_attach_to_widget (GTK_MENU (menu), widget, NULL); + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, time); + gtk_widget_show_all (menu); +} + +static gboolean ygtk_tree_view_button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + // workaround (based on gedit): we want the tree view to receive this press in order + // to select the row, but we can't use connect_after, so we throw a dummy mouse press + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + static gboolean safeguard = FALSE; + if (safeguard) return FALSE; + safeguard = TRUE; + + GtkTreeView *view = GTK_TREE_VIEW (widget); + GtkTreeSelection *selection = gtk_tree_view_get_selection (view); + + gboolean outreach; + outreach = !gtk_tree_view_get_path_at_pos (view, event->x, event->y, 0, 0, 0, 0); + if (gtk_tree_selection_count_selected_rows (selection) <= 1) { + // if there is a selection, let it be + event->button = 1; + if (!gtk_widget_event (widget, (GdkEvent *) event)) + return FALSE; + } + g_signal_emit (widget, right_click_signal, 0, outreach); + safeguard = FALSE; + return TRUE; + } + return GTK_WIDGET_CLASS (ygtk_tree_view_parent_class)->button_press_event (widget, event); +} + +static gboolean _ygtk_tree_view_popup_menu (GtkWidget *widget) +{ + GtkTreeView *view = GTK_TREE_VIEW (widget); + GtkTreeSelection *selection = gtk_tree_view_get_selection (view); + gboolean outreach = gtk_tree_selection_count_selected_rows (selection) == 0; + + g_signal_emit (widget, right_click_signal, 0, outreach); + return TRUE; +} + +GtkWidget *ygtk_tree_view_new (void) +{ return g_object_new (YGTK_TYPE_TREE_VIEW, NULL); } + +static void ygtk_tree_view_class_init (YGtkTreeViewClass *klass) +{ + GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass); + gtkwidget_class->button_press_event = ygtk_tree_view_button_press_event; + gtkwidget_class->popup_menu = _ygtk_tree_view_popup_menu; + + right_click_signal = g_signal_new ("right-click", + G_OBJECT_CLASS_TYPE (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (YGtkTreeViewClass, right_click), + NULL, NULL, gtk_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); +} + Modified: trunk/gtk/src/ygtkscrolledwindow.h URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/ygtkscrolledwindow.h?rev=... ============================================================================== --- trunk/gtk/src/ygtkscrolledwindow.h (original) +++ trunk/gtk/src/ygtkscrolledwindow.h Sun Jan 18 17:11:35 2009 @@ -49,3 +49,45 @@ G_END_DECLS #endif /*YGTK_SCROLLED_WINDOW_H*/ +/* YGtkTreeView hacks support for a right-click signal. +*/ + +#ifndef YGTK_TREE_VIEW_H +#define YGTK_TREE_VIEW_H + +#include <gtk/gtktreeview.h> +G_BEGIN_DECLS + +#define YGTK_TYPE_TREE_VIEW (ygtk_tree_view_get_type ()) +#define YGTK_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + YGTK_TYPE_TREE_VIEW, YGtkScrolledWindow)) +#define YGTK_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \ + YGTK_TYPE_TREE_VIEW, YGtkScrolledWindowClass)) +#define YGTK_IS_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + YGTK_TYPE_TREE_VIEW)) +#define YGTK_IS_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + YGTK_TYPE_TREE_VIEW)) +#define YGTK_TREE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + YGTK_TYPE_TREE_VIEW, YGtkScrolledWindowClass)) + +typedef struct _YGtkTreeView +{ + GtkTreeView parent; +} YGtkTreeView; + +typedef struct _YGtkTreeViewClass +{ + GtkTreeViewClass parent_class; + + // signals: + void (*right_click) (YGtkTreeView *view, gboolean outreach); +} YGtkTreeViewClass; + +GtkWidget* ygtk_tree_view_new (void); +GType ygtk_tree_view_get_type (void) G_GNUC_CONST; + +void ygtk_tree_view_popup_menu (YGtkTreeView *view, GtkWidget *menu); + +G_END_DECLS +#endif /*YGTK_TREE_VIEW_H*/ + -- To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org For additional commands, e-mail: yast-commit+help@opensuse.org