# HG changeset patch
# User Darren Salt <[EMAIL PROTECTED]>
# Date 1170716606 0
# Node ID 6c337d2f29ef69b9c8fab491ebe8c1d5cb602455
# Parent  90b992be48a01f70d5e5a4911190d4a37b32ce1d
Allow slider widgets to be presented as buttons with pop-up windows.
The volume slider in the default windowed-mode toolbar is now a pop-up, and
the default full-screen toolbar gains a volume icon.

Update the documentation accordingly.

diff -r 6c337d2f29ef69b9c8fab491ebe8c1d5cb602455 -r 
90b992be48a01f70d5e5a4911190d4a37b32ce1d ChangeLog
--- a/ChangeLog Mon Feb 05 23:03:26 2007 +0000
+++ b/ChangeLog Mon Feb 05 22:51:19 2007 +0000
@@ -19,6 +19,8 @@ 0.5.900:2007/??/??
          - separate toolbar;
          - windowed-mode blanking prevention.
          Existing configurations are unaffected.
+       * Allow slider widgets to be presented as buttons with pop-up windows.
+         The volume slider in the default windowed-mode toolbar is a pop-up.
        * Obsoleted and disabled most of the deprecated JS functions, except
          for set_fullscreen() and toolbar_show() which remain deprecated.
          If you need the others, build with --enable-obsolete.
diff -r 6c337d2f29ef69b9c8fab491ebe8c1d5cb602455 -r 
90b992be48a01f70d5e5a4911190d4a37b32ce1d doc/Skin-HOWTO
--- a/doc/Skin-HOWTO    Mon Feb 05 23:03:26 2007 +0000
+++ b/doc/Skin-HOWTO    Mon Feb 05 22:51:19 2007 +0000
@@ -95,6 +95,7 @@ Properties common to all widgets:
        vertical=BOOL   whether the slider is horizontal or vertical
        show-value=BOOL whether the slider's value is shown
        inverted=BOOL   whether the slider's "increment" direction is reversed
+       popup=BOOL      whether the slider is presented in a pop-up
 
        Widget types:
            Buttons:
@@ -120,6 +121,19 @@ Properties common to all widgets:
            vslider     render as a vertical slider
            spin        render as a spin button
 
+       If the 'popup' property is set, then the slider is presented as a
+       button with a pop-up window. As such, the slider acts as a <button>,
+       except that you cannot use the 'onclick' property. In addition, the
+       following properties are available:
+
+       window-width=INT        the width of the window (default auto)
+       window-height=INT       the height of the window (default auto)
+
+       A vertical slider will normally be presented below the button and a
+       horizontal slider to one side (according to the normal text direction);
+       if it wouldn't be fully on-screen there, it'll be shown on the
+       opposite side.
+
 <flipbutton>
        THIS UI ITEM IS NOT CURRENTLY IMPLEMENTED.
        Clickable button, requiring two child widgets for the "off" and "on"
diff -r 6c337d2f29ef69b9c8fab491ebe8c1d5cb602455 -r 
90b992be48a01f70d5e5a4911190d4a37b32ce1d misc/toolbar-fullscreen.xml
--- a/misc/toolbar-fullscreen.xml       Mon Feb 05 23:03:26 2007 +0000
+++ b/misc/toolbar-fullscreen.xml       Mon Feb 05 22:51:19 2007 +0000
@@ -35,6 +35,7 @@
    <end />
    <control type="audio channel" />
    <control type="volume" width="105" box-expand="1" box-fill="1" />
+   <image stock="gxine-settings-volume" />
    <control type="mute" />
   </hbox>
  </vbox>
diff -r 6c337d2f29ef69b9c8fab491ebe8c1d5cb602455 -r 
90b992be48a01f70d5e5a4911190d4a37b32ce1d misc/toolbar-window.xml
--- a/misc/toolbar-window.xml   Mon Feb 05 23:03:26 2007 +0000
+++ b/misc/toolbar-window.xml   Mon Feb 05 22:51:19 2007 +0000
@@ -33,7 +33,8 @@
    <label text="" box-expand="1"/>
    <end />
    <control type="audio channel" />
-   <control type="volume" width="105" box-expand="1" box-fill="1" />
+   <control type="volume" vertical="1" popup="1" window-height="120"
+           inverse="1" image="gxine-settings-volume" relief="none" />
    <control type="mute" />
   </hbox>
 </vbox>
diff -r 6c337d2f29ef69b9c8fab491ebe8c1d5cb602455 -r 
90b992be48a01f70d5e5a4911190d4a37b32ce1d src/xml_widgets.c
--- a/src/xml_widgets.c Mon Feb 05 23:03:26 2007 +0000
+++ b/src/xml_widgets.c Mon Feb 05 22:51:19 2007 +0000
@@ -362,7 +362,15 @@ static GtkWidget *create_box (xml_node_t
  */
 
 static GtkWidget *
-create_button (xml_node_t *node)
+gxine_toggle_button_new_from_stock (const char *stock)
+{
+  GtkWidget *btn = gtk_toggle_button_new_with_label (stock);
+  gtk_button_set_use_stock (GTK_BUTTON (btn), TRUE);
+  return btn;
+}
+
+static GtkWidget *
+create_button (xml_node_t *node, gboolean click)
 /* Properties:
  *     stock           string  none            stock item
  *     label           string  none            text if stock is not set 
[translatable]
@@ -380,6 +388,18 @@ create_button (xml_node_t *node)
 #ifndef MAKE_TRANSLATION_SOURCE
   GtkWidget *button;
   static const char *relief[] = { "none", "half", NULL };
+
+  typedef GtkWidget *(*button_new_t) (const char *);
+  typedef GtkWidget *(*plain_new_t) (void);
+  static const struct {
+    button_new_t stock[2], mnemonic[2], label[2];
+    plain_new_t plain[2];
+  } newbtn = {
+    { gxine_toggle_button_new_from_stock, gtk_button_new_from_stock },
+    { gtk_toggle_button_new_with_mnemonic, gtk_button_new_with_mnemonic },
+    { gtk_toggle_button_new_with_label, gtk_button_new_with_label },
+    { gtk_toggle_button_new, gtk_button_new },
+  };
 #endif
 
   alt = xml_parser_get_property (node, "alt");
@@ -395,14 +415,14 @@ create_button (xml_node_t *node)
     return NULL;
 #else
     if (check_stock (image))
-      button = gtk_button_new_from_stock (image);
+      button = newbtn.stock[click] (image);
     else if (alt)
       button = xml_parser_get_bool (node, "mnemonic")
-              ? gtk_button_new_with_mnemonic (TRANSLATE (alt))
-              : gtk_button_new_with_label (TRANSLATE (alt));
+              ? newbtn.mnemonic[click] (TRANSLATE (alt))
+              : newbtn.label[click] (TRANSLATE (alt));
     else
     {
-      button = gtk_button_new ();
+      button = newbtn.plain[click] ();
       if (image)
        g_object_set (G_OBJECT (button), "image",
                      check_stock (image)
@@ -441,12 +461,12 @@ create_button (xml_node_t *node)
   if (label && !image)
   {
     button = xml_parser_get_bool (node, "mnemonic")
-            ? gtk_button_new_with_mnemonic (TRANSLATE (label))
-            : gtk_button_new_with_label (TRANSLATE (label));
+            ? newbtn.mnemonic[click] (TRANSLATE (label))
+            : newbtn.label[click] (TRANSLATE (label));
     goto created;
   }
 
-  button = gtk_button_new ();
+  button = newbtn.plain[click] ();
   if (label || image)
   {
     g_object_set (G_OBJECT (button),
@@ -487,11 +507,14 @@ create_button (xml_node_t *node)
   created:
   gtk_button_set_relief (GTK_BUTTON (button),
                         2 - lookup_type (node, "relief", relief));
-  /* set the command which is executed when the button is clicked */
-  label = xml_parser_get_property (node, "onclick");
-  if (label)
-    command_attach (button, "clicked", "js-onclick", label,
-                   _("XML button click"));
+  if (click)
+  {
+    /* set the command which is executed when the button is clicked */
+    label = xml_parser_get_property (node, "onclick");
+    if (label)
+      command_attach (button, "clicked", "js-onclick", label,
+                     _("XML button click"));
+  }
   return button;
 #endif /* ! MAKE_TRANSLATION_SOURCE */
 }
@@ -557,6 +580,106 @@ set_tip (GtkWidget *w, const stock_t *st
                          TRANSLATE (*stock->tip ? stock->tip : stock->name),
                          NULL);
 }
+
+static gboolean
+slider_button_cb (GtkWidget *widget, GdkEventButton *ev, gpointer data)
+{
+  gtk_grab_remove (widget);
+  gdk_keyboard_ungrab (ev->time);
+  gdk_pointer_ungrab (ev->time);
+  gtk_widget_hide (widget);
+  gtk_toggle_button_set_active (data, FALSE);
+  return FALSE;
+}
+
+static gboolean
+slider_widget_button_cb (GtkWidget *widget, GdkEventButton *ev, gpointer data)
+{
+  return slider_button_cb (gtk_widget_get_toplevel (widget), ev, data);
+}
+
+#include <gdk/gdkkeysyms.h>
+static gboolean
+slider_key_cb (GtkWidget *window, GdkEventKey *ev, gpointer data)
+{
+  switch (ev->keyval)
+  {
+  case GDK_Escape:
+  case GDK_KP_Enter:
+  case GDK_Return:
+  case GDK_space:
+    return slider_button_cb (window, (GdkEventButton *) ev, data);
+  default:
[... 3 lines omitted ...]
+
+static gboolean
+slider_window_cb (GtkWidget *button, gpointer window)
+{
+  if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
+    return FALSE;
+
+  gtk_window_set_transient_for (window,
+                               GTK_WINDOW (gtk_widget_get_toplevel (button)));
+
+  GdkWindow *parent = gtk_widget_get_parent_window (button);
+  GtkAllocation ppos;
+  gdk_window_get_position (parent, &ppos.x, &ppos.y);
+  gdk_drawable_get_size (GDK_DRAWABLE (parent), &ppos.width, &ppos.height);
+
+  GdkScreen *screen = gtk_widget_get_screen (button);
+  gint monitor = gdk_screen_get_monitor_at_window (screen, parent);
+  GdkRectangle geom;
+  gdk_screen_get_monitor_geometry (screen, monitor, &geom);
+
+  gint wx, wy;
+  GtkRequisition req;
+  gtk_widget_size_request (window, &req);
+  gtk_window_get_default_size (window, &wx, &wy);
+  if (wx > req.width)
+    req.width = wx;
+  if (wy > req.height)
+    req.height = wy;
+
+  wx = button->allocation.x + ppos.x; /* button left */
+  wy = button->allocation.y + ppos.y; /* button top */
+
+  if (GTK_IS_VSCALE (((GtkBin *) window)->child))
+  {
+    /* arrange vertically, preferably below */
+    wx += (button->allocation.width - req.width) / 2; /* centre-aligned */
+    wy += (wy + req.height + button->allocation.height > geom.y + geom.height)
+       ? -req.height                   /* below (if enough space) */
+       : button->allocation.height;    /* above */
+  }
+  else if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_RTL)
+  {
+    /* arrange vertically, preferably to the left (RTL) */
+    wx -= (wx - req.width < geom.x)
+       ? -button->allocation.width     /* left (if enough space) */
+       : req.width;                    /* right */
+    wy += (button->allocation.height - req.height) / 2; /* centre-aligned */
+  }
+  else
+  {
+    /* arrange vertically, preferably to the right (LTR) */
+    wx += (wx + req.width + button->allocation.width > geom.x + geom.width)
+       ? -req.width                    /* right (if enough space) */
+       : button->allocation.width;     /* left */
+    wy += (button->allocation.height - req.height) / 2; /* centre-aligned */
+  }
+
+  gtk_window_move (GTK_WINDOW (window), wx, wy);
+  gtk_widget_show_all (window);
+
+  gdk_keyboard_grab (((GtkWidget *)window)->window, TRUE, GDK_CURRENT_TIME);
+  gdk_pointer_grab (((GtkWidget *)window)->window, TRUE,
+                   GDK_BUTTON_RELEASE_MASK, NULL, NULL, GDK_CURRENT_TIME);
+  gtk_grab_add (window);
+
+  return TRUE;
+}
 #endif
 
 static GtkWidget *
@@ -564,7 +687,12 @@ create_stock_gxine (xml_node_t *node)
 /* Properties:
  *     type            string  none    widget identifer (see stock[].name)
  *     vertical        bool    FALSE   slider orientation
+ *     inverted        bool    FALSE   slider direction reversal
  *     show-value      bool    FALSE   show slider value numerically
+ *     popup           bool    FALSE   slider is a popup
+ *                                     (use button properties except onclick)
+ *     window-width    int     -1      popup window width
+ *     window-height   int     -1      popup window height
  */
 {
 #ifndef MAKE_TRANSLATION_SOURCE
@@ -685,10 +813,35 @@ create_stock_gxine (xml_node_t *node)
 
       if (GTK_IS_SCALE (w))
       {
+       gtk_scale_set_digits (GTK_SCALE (w), 0);
        gtk_scale_set_draw_value
          (GTK_SCALE (w), xml_parser_get_bool (node, "show-value"));
        gtk_range_set_inverted
          (GTK_RANGE (w), xml_parser_get_bool (node, "inverted"));
+       if (xml_parser_get_bool (node, "popup"))
+       {
+         GtkWindow *window = GTK_WINDOW (gtk_window_new (GTK_WINDOW_POPUP));
+         gtk_window_set_default_size (window,
+               xml_parser_get_property_int (node, "window-width", -1),
+               xml_parser_get_property_int (node, "window-height", -1));
+         gtk_window_set_decorated (window, FALSE);
+         gtk_window_set_skip_pager_hint (window, TRUE);
+         gtk_window_set_skip_taskbar_hint (window, TRUE);
+         gtk_container_add (GTK_CONTAINER (window), w);
+         gtk_widget_add_events ((GtkWidget *)window, GDK_BUTTON_RELEASE_MASK);
+         gtk_widget_show (w);
+         GtkWidget *btn = create_button (node, FALSE);
+         g_object_connect (G_OBJECT (window),
+           "signal::destroy-event", gtk_widget_hide_on_delete, btn,
+           "signal::button-release-event", G_CALLBACK (slider_button_cb), btn,
+           "signal::key-press-event", G_CALLBACK (slider_key_cb), btn,
+           NULL);
+          g_signal_connect (G_OBJECT (w), "button-release-event",
+                           G_CALLBACK (slider_widget_button_cb), btn);
+         g_signal_connect (G_OBJECT (btn), "toggled",
+                           G_CALLBACK (slider_window_cb), window);
+         w = btn; /* for popups, we return the button, not the slider */
+       }
       }
       else
        gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (w), TRUE);
@@ -990,7 +1143,7 @@ widget_parse (xml_node_t *node)
 
   case 'b':
     if (!strcasecmp (node->name + 1, "utton"))
-      widget = create_button (node);
+      widget = create_button (node, TRUE);
     break;
 
   case 'c':

-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier.
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Xine-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xine-cvslog

Reply via email to