GTK+ Forums

Discussion forum for GTK+ and Programming. Ask questions, troubleshoot problems, view and post example code, or express your opinions.
It is currently Thu Apr 17, 2014 12:51 pm

All times are UTC




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: Composite widgets
PostPosted: Thu Jul 26, 2012 9:09 am 
Offline
Familiar Face

Joined: Thu Dec 15, 2011 6:23 pm
Posts: 36
Location: Hrvatska
This is example how to build composite widgets. Original code is from Tadej ( tadeboro ) in his answer to zerohour post.

It is variant of GtkSpinButton widget.
GtkSpinButton has BUG in design - it does NOT follow heigh for width logic. In fact it does, but only for entry part, buttons part are allways fixed in width - and fixed background image of +/- also. It can be useless on touch screen where size of buttons are crucial.

Tadej made good start - instead of using entry for parent, he used table, so it is easy to settle layout. I have made some minor changes - insert some part of code from original GtkSpinButton developer - to get smooth spin with timer, when you press buttons for long time.

here is code for header file c_spin.h :
Code:
/* GTK - The GIMP Toolkit
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* GtkSpinButton widget for GTK+
* Copyright (C) 1998 Lars Hamann and Stefan Jeske
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/

/*
* Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
* file for a list of people on the GTK+ Team.  See the ChangeLog
* files for a list of changes.  These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/

/*
* 2012 kepica made custom spin button
*      based od GtkSpinButton code
*      and Tadej code from GTKforums.com ( tadeboro )
*/

#ifndef C_SPIN_H_
#define C_SPIN_H_

#include <gtk/gtk.h>

G_BEGIN_DECLS

#define C_TYPE_WIDGET            (c_widget_get_type())
#define C_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), C_TYPE_WIDGET, CWidget))
#define C_WIDGET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), C_TYPE_WIDGET, CWidgetClass))
#define C_IS_WIDGET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), C_TYPE_WIDGET))
#define C_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), C_TYPE_WIDGET))
#define C_WIDGET_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), C_TYPE_WIDGET, CWidgetClass))

typedef struct _CWidget        CWidget;
typedef struct _CWidgetClass   CWidgetClass;
typedef struct _CWidgetPrivate CWidgetPrivate;

struct _CWidget
{
  GtkGrid parent;

  /*< Private >*/
  CWidgetPrivate *priv;
};

struct _CWidgetClass
{
  GtkGridClass parent_class;
  void (*value_changed) (CWidget *spin);
};

/* Public interface */
GType c_widget_get_type (void) G_GNUC_CONST;

gdouble   c_widget_get_value (CWidget *widget);
GtkWidget * c_widget_new (void);

void  c_spin_set_value (CWidget *spin,
                        gdouble  value);
void   c_spin_set_adjustment (CWidget  *spin,
                GtkAdjustment  *adjustment);
void   c_spin_set_digits (CWidget  *spin,
                   guint       digits);

G_END_DECLS


#endif /* C_SPIN_H_ */


Last edited by kepica on Mon Jul 30, 2012 6:34 am, edited 5 times in total.

Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Thu Jul 26, 2012 9:18 am 
Offline
Familiar Face

Joined: Thu Dec 15, 2011 6:23 pm
Posts: 36
Location: Hrvatska
here is second part, it is file c_spin.c :

Code:
#include "c_spin.h"

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/* structure */

struct _CWidgetPrivate
{
  GtkAdjustment *adjustment;

  gdouble value;
  GtkWidget *label,    // it is entry in fact
            *up,
            *down;

  guint32 timer;
  gdouble climb_rate;
  gdouble timer_step;

  gdouble upper;   // upper adjust
  gdouble lower;   // lower adjust
  gdouble step;    // step inc adjust

  guint button, digits, need_timer, numeric, snap_to_ticks, timer_calls, wrap;
};

enum
{
  PROP_0,
  PROP_VALUE,
  PROP_ADJUSTMENT,
  PROP_DIGITS,
  LAST_PROP
};

/* Signals */
enum
{
  VALUE_CHANGED,
  LAST_SIGNAL
};

static GObject *c_widget_constructor (GType                  type,
                                      guint                  n_constr_props,
                                      GObjectConstructParam *constr_params);
static void c_widget_set_property (GObject      *object,
                                   guint         prop_id,
                                   const GValue *value,
                                   GParamSpec   *pspec);
static void c_widget_get_property (GObject    *object,
                                   guint       prop_id,
                                   GValue     *value,
                                   GParamSpec *pspec);

static guint spin_signals[LAST_SIGNAL] = {0};
G_DEFINE_TYPE (CWidget, c_widget, GTK_TYPE_GRID)

/* ******************         from original GtkSpinButton */

#define MAX_TIMER_CALLS       5
#define EPSILON               1e-10
#define MAX_DIGITS            20
#define SPIN_TIME             166
#define B_WI               40
#define B_HI               30

static void
c_spin_value_changed (CWidget *spin)
{
   g_signal_emit (spin, spin_signals[VALUE_CHANGED], 0);
   gtk_widget_queue_draw (GTK_WIDGET (spin));
   g_object_notify (G_OBJECT (spin), "value");
}

void
c_spin_set_value (CWidget *spin, gdouble value)
{
  CWidgetPrivate *priv = spin->priv;
  priv->value = value;
  gchar *buf = g_strdup_printf ("%0.*f",
        priv->digits,
        priv->value
        );

  if (strcmp (buf, gtk_entry_get_text (GTK_ENTRY (priv->label ))))
    gtk_entry_set_text (GTK_ENTRY (priv->label ), buf);
  g_free (buf);
  c_spin_value_changed (spin);
}

void
c_spin_set_adjustment (CWidget *spin,
                       GtkAdjustment *adjustment)
{
  CWidgetPrivate *priv;
  g_return_if_fail (C_IS_WIDGET (spin));

  priv = spin->priv;

  if (priv->adjustment != adjustment)
      {
        if (priv->adjustment)
          {
           g_object_unref (priv->adjustment);
          }
        priv->adjustment = adjustment;
        if (adjustment)
          {
            g_object_ref_sink (adjustment);
            priv->timer_step = gtk_adjustment_get_step_increment (priv->adjustment);
            priv->timer_step = gtk_adjustment_get_step_increment (adjustment);
            priv->step = gtk_adjustment_get_step_increment (adjustment);
            priv->upper = gtk_adjustment_get_upper (adjustment);
            priv->lower = gtk_adjustment_get_lower (adjustment);
          }

        gtk_widget_queue_resize (GTK_WIDGET (spin));
      }

  gtk_widget_queue_resize (GTK_WIDGET (spin));
  g_object_notify (G_OBJECT (spin), "adjustment");
}

static void
c_spin_real_spin (CWidget *spin,
                  gdouble increment)
{
  CWidgetPrivate *priv = spin->priv;
  gdouble new_value = 0.0;
  gboolean wrapped = FALSE;

  new_value = priv->value + increment;

  if (increment > 0)
    {
      if (priv->wrap)
        {
          if (fabs (priv->value  - priv->upper) < EPSILON)
            {
              new_value = priv->lower ;
              wrapped = TRUE;
            }
          else if (new_value > priv->upper )
            new_value = priv->upper ;
        }
      else
        new_value = MIN (new_value, priv->upper );
    }
  else if (increment < 0)
    {
      if (priv->wrap)
        {
          if (fabs (priv->value - priv->lower ) < EPSILON)
            {
              new_value = priv->upper ;
              wrapped = TRUE;
            }
          else if (new_value < priv->lower )
            new_value = priv->lower;
        }
      else
        new_value = MAX (new_value, priv->lower );
    }

  if (fabs (new_value - priv->value ) > EPSILON)
    priv->value = new_value;

  c_spin_set_value(spin, new_value);
  gtk_widget_queue_draw (GTK_WIDGET (spin));
}

static gint
c_spin_timer (CWidget *spin)
{
  CWidgetPrivate *priv = spin->priv;
  gboolean retval = FALSE;

  if (priv->timer)
    {
     // argument za UP-1 / DOWN-2
      if (priv->button == 1)
        c_spin_real_spin (spin, priv->timer_step);
      else
        c_spin_real_spin (spin, -priv->timer_step);

      if (priv->need_timer)
        {
          // GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (spin));
          guint        timeout = SPIN_TIME;

          // g_object_get (settings, "gtk-timeout-repeat", &timeout, NULL);

          priv->need_timer = FALSE;
          priv->timer = gdk_threads_add_timeout (timeout,
                                              (GSourceFunc) c_spin_timer,
                                              (gpointer) spin);
        }
      else
        {
          if (priv->climb_rate > 0.0 )
            {
              if (priv->timer_calls < MAX_TIMER_CALLS)
                priv->timer_calls++;
              else
                {
                  priv->timer_calls = 0;
                  priv->timer_step += priv->climb_rate;
                }
            }
          retval = TRUE;
        }
    }

  return retval;
}

static gboolean
c_spin_stop_spinning (CWidget *spin)
{
  CWidgetPrivate *priv = spin->priv;
  gboolean did_spin = FALSE;

  if (priv->timer)
    {
      g_source_remove (priv->timer);
      priv->timer = 0;
      priv->need_timer = FALSE;

      did_spin = TRUE;
    }

  priv->button = 0;
  priv->timer_step = priv->step ;
  priv->timer_calls = 0;

  // priv->click_child = NULL;

  return did_spin;
}

static void
start_spinning (CWidget *spin,
                gdouble step)
{
  CWidgetPrivate *priv;

  priv = spin->priv;

  if (!priv->timer)
    {
      // GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (spin));
      guint        timeout = SPIN_TIME;

      // g_object_get (settings, "gtk-timeout-initial", &timeout, NULL);

      priv->timer_step = step;
      priv->need_timer = TRUE;
      priv->timer = gdk_threads_add_timeout (timeout,
                                   (GSourceFunc) c_spin_timer,
                                   (gpointer) spin);
    }
  c_spin_real_spin (spin, priv->button == 1 ? step : -step);

  gtk_widget_queue_draw (GTK_WIDGET (spin));
}

static void
c_spin_snap (CWidget *spin,
             gdouble val)
{
  CWidgetPrivate *priv = spin->priv;
  gdouble inc;
  gdouble tmp;

  inc = priv->step;
  if (inc == 0)
    return;

  tmp = (val - priv->lower ) / inc;
  if (tmp - floor (tmp) < ceil (tmp) - tmp)
    val = priv->lower + floor (tmp) * inc;
  else
    val = priv->lower + ceil (tmp) * inc;

  c_spin_set_value (spin, val);
}

void
c_spin_update (CWidget *spin)
{
  CWidgetPrivate *priv;
  gdouble val;

  g_return_if_fail (C_IS_WIDGET (spin));

  priv = spin->priv;
  val = priv->value;

  gtk_widget_queue_draw (GTK_WIDGET (spin));

    if   (val < priv->lower || val > priv->upper)
    {
      c_spin_value_changed (spin);
      return;
    }

  if (priv->snap_to_ticks)
    c_spin_snap (spin, val);
  else
    c_spin_set_value (spin, val);
}

void
c_spin_set_digits (CWidget *spin,
                   guint  digits)
{
  CWidgetPrivate *priv;

  g_return_if_fail (C_IS_WIDGET (spin));

  priv = spin->priv;

  if (priv->digits != digits)
    {
      priv->digits = digits;
      c_spin_value_changed (spin);
      g_object_notify (G_OBJECT (spin), "digits");
      gtk_widget_queue_resize (GTK_WIDGET (spin));
    }
}

void
c_spin_configure (CWidget *spin,
                  gdouble climb_rate,
                  guint digits)
{
  CWidgetPrivate *priv;

  g_return_if_fail (C_IS_WIDGET (spin));

  priv = spin->priv;

  g_object_freeze_notify (G_OBJECT (spin));
  if (priv->digits != digits)
    {
      priv->digits = digits;
      g_object_notify (G_OBJECT (spin), "digits");
    }

  if (priv->climb_rate != climb_rate)
    {
      priv->climb_rate = climb_rate;
      g_object_notify (G_OBJECT (spin), "climb-rate");
    }
  g_object_thaw_notify (G_OBJECT (spin));
}

/* ******************************* button callback */

static gboolean
button_up_cb  (GtkWidget *widget,
                 GdkEvent  *event,
                 gpointer   user_data)
{
  CWidget *spin = C_WIDGET (user_data);
  CWidgetPrivate *priv = spin->priv;

  if ( ((GdkEventButton*)event)->type == GDK_BUTTON_PRESS )
  {
     priv->button = 1;
     c_spin_update (spin);
     start_spinning (spin, priv->step);
  }


  if ( ((GdkEventButton*)event)->type == GDK_BUTTON_RELEASE )
  {
     priv->button = 1;
      c_spin_stop_spinning (spin);
  }
   return FALSE;
}

static gboolean
button_down_cb  (GtkWidget *widget,
                 GdkEvent  *event,
                 gpointer   user_data)
{
  CWidget *spin = C_WIDGET (user_data);
  CWidgetPrivate *priv = spin->priv;

  if ( ((GdkEventButton*)event)->type == GDK_BUTTON_PRESS )
    {
       priv->button = 2;
       c_spin_update (spin);
       start_spinning (spin, priv->step);
    }


  if ( ((GdkEventButton*)event)->type == GDK_BUTTON_RELEASE )
   {
           priv->button = 2;
          c_spin_stop_spinning (spin);
   }
    return FALSE;
}

/* *************************** TADEJ code     */

static void
c_widget_class_init (CWidgetClass *klass)
{
  GObjectClass *g_class = G_OBJECT_CLASS (klass);
  GParamSpec *pspec;

  g_class->constructor  = c_widget_constructor;
  g_class->set_property = c_widget_set_property;
  g_class->get_property = c_widget_get_property;

  pspec = g_param_spec_int ("value", "Value of widget", "Displayed value",
                            G_MININT, G_MAXINT, 0,
                            G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
  g_object_class_install_property (g_class, PROP_VALUE, pspec);

  pspec = g_param_spec_object ("adjustment", "Adjustment", "Adjustment",
                              GTK_TYPE_ADJUSTMENT,
                              G_PARAM_READWRITE);

  g_object_class_install_property (g_class, PROP_ADJUSTMENT, pspec);

  pspec = g_param_spec_uint ("digits", "Digits", "number of decimal places",
                                0, MAX_DIGITS, 0,
                                G_PARAM_READWRITE);

    g_object_class_install_property (g_class, PROP_DIGITS, pspec);

    spin_signals[VALUE_CHANGED] =
        g_signal_new ("value-changed",
                      G_TYPE_FROM_CLASS (g_class),
                      G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (CWidgetClass, value_changed),
                      NULL, NULL,
                      g_cclosure_marshal_VOID__VOID,   // _gtk_marshal_VOID__VOID
                      G_TYPE_NONE, 0);

   g_type_class_add_private (klass, sizeof (CWidgetPrivate));
}

static GObject *
c_widget_constructor (GType                  type,
                      guint                  n_constr_props,
                      GObjectConstructParam *constr_params)
{
  CWidgetPrivate *priv;
  GObject *object;
  GtkGrid *table;              // in fact GRID
/*
  PangoFontDescription *pfd;
  char *font;
  font = g_strdup("Serif PANGO_STYLE_BOLD 36");
  pfd = pango_font_description_from_string ( font);
*/
  object = G_OBJECT_CLASS (c_widget_parent_class)->constructor (type,
                                                                n_constr_props,
                                                                constr_params);
  priv = C_WIDGET (object)->priv;
  table = GTK_GRID (object);

  gtk_widget_push_composite_child ();

  GtkEntryBuffer *buff = gtk_entry_buffer_new("0", 4);
  priv->label = gtk_entry_new_with_buffer(buff);

  gtk_grid_attach (table, priv->label, 0, 0, 1, 2);
  gtk_widget_show (priv->label);

  priv->up = gtk_button_new();
  gtk_widget_set_name (GTK_WIDGET(priv->up), "spin_up");
/*
  GtkWidget *lab_up = gtk_label_new("+");
  gtk_widget_modify_font ( lab_up, pfd);
  gtk_container_add(GTK_CONTAINER(priv->up), lab_up);
*/
  gtk_widget_set_size_request(GTK_WIDGET(priv->up), B_WI, B_HI);

  // g_signal_connect (priv->up, "clicked", G_CALLBACK (cb_up), object);
  g_signal_connect(priv->up,
        "button-press-event",
        G_CALLBACK(button_up_cb),
        object);
  g_signal_connect(priv->up,
        "button-release-event",
        G_CALLBACK(button_up_cb),
        object);
  gtk_grid_attach (table, priv->up, 1, 0, 1, 1);
  gtk_widget_show (priv->up);

  priv->down = gtk_button_new ();
  gtk_widget_set_name (GTK_WIDGET(priv->down), "spin_down");
/*
  GtkWidget *lab_dn =  gtk_label_new("-");
  gtk_widget_modify_font ( lab_dn, pfd);
  gtk_container_add(GTK_CONTAINER(priv->down), lab_dn);
*/
  gtk_widget_set_size_request(GTK_WIDGET(priv->down), B_WI, B_HI);

  // g_signal_connect (priv->down, "clicked", G_CALLBACK (cb_down), object);
  g_signal_connect(priv->down,
        "button-press-event",
        G_CALLBACK(button_down_cb),
        object);
  g_signal_connect(priv->down,
        "button-release-event",
        G_CALLBACK(button_down_cb),
        object);

  gtk_grid_attach (table, priv->down, 1, 1, 1, 1);
  gtk_widget_show (priv->down);
/*
  g_free (font);
  pango_font_description_free (pfd);
*/
  gtk_widget_pop_composite_child ();

  return object;
}

static void
c_widget_set_property (GObject      *object,
                       guint         prop_id,
                       const GValue *value,
                       GParamSpec   *pspec)
{
  CWidget *spin = C_WIDGET (object);
  CWidgetPrivate *priv = spin->priv;
  GtkAdjustment *adjustment;

  switch (prop_id)
    {
    case PROP_VALUE:
      c_spin_set_value (spin, g_value_get_double (value));
      break;

    case PROP_ADJUSTMENT:
       adjustment = GTK_ADJUSTMENT (g_value_get_object (value));
       if (!adjustment)
               adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
        c_spin_set_adjustment (spin, adjustment);
        break;
    case PROP_DIGITS:
        c_spin_configure (spin,
                          priv->climb_rate,
                          g_value_get_double (value));
          break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
c_widget_get_property (GObject    *object,
                       guint       prop_id,
                       GValue     *value,
                       GParamSpec *pspec)
{
  CWidgetPrivate *priv = C_WIDGET (object)->priv;

  switch (prop_id)
    {
    case PROP_VALUE:
      g_value_set_double (value, priv->value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
c_widget_init (CWidget *widget)
{
  CWidgetPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (widget,
                                                      C_TYPE_WIDGET,
                                                      CWidgetPrivate);

  widget->priv = priv;
  priv->adjustment = NULL;
  priv->value = 0;
  priv->timer = 0;
  priv->climb_rate = 0.005;
  priv->timer_step = 0.0;
  priv->button = 0;
  priv->need_timer = FALSE;
  priv->timer_calls = 0;
  priv->digits = 0;
  priv->numeric = FALSE;
  priv->wrap = FALSE;
  priv->snap_to_ticks = FALSE;

  c_spin_set_adjustment (widget,  gtk_adjustment_new (0, 0, 0, 0, 0, 0));
}

/* Public interface */
gdouble
c_spin_get_value (CWidget *spin)
{
  g_return_val_if_fail (C_IS_WIDGET (spin), 0);

  return spin->priv->value;
}

GtkWidget *
c_widget_new (void)
{
  return g_object_new (C_TYPE_WIDGET, NULL);
}


Last edited by kepica on Mon Jul 30, 2012 6:35 am, edited 7 times in total.

Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Thu Jul 26, 2012 9:39 am 
Offline
Familiar Face

Joined: Thu Dec 15, 2011 6:23 pm
Posts: 36
Location: Hrvatska
this is the third part.
it has only part of code , how to create and configure new widget. you have to use this part in your main file, where you build your GTK application.

Code:
gdouble f_dummy = 0.0;
GtkAdjustment *adjust1 = GTK_ADJUSTMENT (gtk_adjustment_new ((gdouble) f_dummy, 0.0, 1.0, 0.01, 1.0, 0.0));
GtkWidget *b_spin = c_widget_new();
c_spin_set_adjustment(C_WIDGET(b_spin), adjust1);
c_spin_set_digits(C_WIDGET(b_spin), 2);
c_spin_set_value(C_WIDGET(b_spin), 0.5);
gtk_widget_set_name (GTK_WIDGET(b_spin), "spin1");
gtk_widget_set_size_request(GTK_WIDGET(b_spin), 220, 150);


and this is it. don't forget to put this widget to some container ( box or whatever ).

This custom spin has only one signal: VALUE_CHANGED
it can be used for user function callback, like this:
Code:
static void
spin_cb (CWidget *spin, gpointer user_data)
{
   gdouble ret;
   ret = c_spin_get_value(spin);
   // use RET value as you wish
}


You have to connect signal, like this:

Code:
g_signal_connect(GTK_WIDGET(b_spin),
  "value-changed",
  G_CALLBACK(spin_cb),
  NULL);


If you want nice widget you will have to style it with CSS file. Here is sample - how to style BIG entry and two buttons with background-image:
Code:
#spin1 #spin_up
{
   background-image:url('/path/to/up.jpg');
}
#spin1 #spin_down
{
   background-image:url('/path/to/down.jpg');
}

#spin1 .entry
{
   font: Serif 36;
   color: red;
}


now, I add + / - labels on buttons, it can use same image for background
or you can use different img with CSS - in that case remove labels

compile everything with GTK+3
cheers !

here is image - you can see both widget - custom at top - and standard at bottom
Image


Last edited by kepica on Mon Jul 30, 2012 6:36 am, edited 6 times in total.

Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Fri Jul 27, 2012 5:40 am 
Offline
GTK+ Guru

Joined: Fri Mar 25, 2011 5:16 pm
Posts: 176
Location: USA
Great job Kepica. You can style the buttons individually in the CSS by first setting their names using gtk_widget_set_name() in c_spin.c
As a suggestion, I would switch to GtkGrid since GtkTable is deprecated beginning with GTK+ version 3.4.


Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Fri Jul 27, 2012 7:59 am 
Offline
Familiar Face

Joined: Thu Dec 15, 2011 6:23 pm
Posts: 36
Location: Hrvatska
zerohour, thanks for response !

I did change GtkTable with GtkGrid - and updated previous post. thanks for tip !

I did not agree with you about CSS on buttons.
I change code and add labels + and - on buttons, instead.


Last edited by kepica on Mon Jul 30, 2012 6:37 am, edited 3 times in total.

Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Fri Jul 27, 2012 6:30 pm 
Offline
GTK+ Guru

Joined: Fri Mar 25, 2011 5:16 pm
Posts: 176
Location: USA
I tried using the last version of c_spin.c and I was able to style the buttons individually with CSS by setting their names first in c_spin.c

My enviroment is:
Ubuntu Natty (classic no effects mode), gtk+-3.2.3, gdk-pixbuf-2.24, glib-2.30.2, pango-1.29.1, atk-2.1.5
With this latest version of c_spin.c (no CSS portion) I'm receiving the following errors:
Quote:
In file included from c_spin_main.c:7:0:
c_spin.c: In function ‘c_widget_class_init’:
c_spin.c:468:23: warning: passing argument 7 of ‘g_signal_new’ makes pointer from integer without a cast
/home/zerohour/gtk/include/glib-2.0/gobject/gsignal.h:273:23: note: expected ‘GSignalCMarshaller’ but argument is of type ‘long unsigned int’

Here is my test file, c_spin_main.c
Code:
/* COMPILE WITH:  gcc -Wall -o c_spin_main `pkg-config --cflags --libs gtk+-3.0` c_spin_main.c
*/

#include <gtk/gtk.h>
#include "c_spin.c"

int main (int argc, char *argv[])
{
  GtkWidget *window;
  GtkWidget *grid;
  GtkWidget *b_spin;
  GtkAdjustment *adjust1;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  gtk_widget_set_size_request(window, 400, 400);
  gtk_window_set_title(GTK_WINDOW(window), "custom spin");
  g_signal_connect(G_OBJECT (window), "destroy",
                   G_CALLBACK(gtk_main_quit), NULL);

  gdouble f_dummy = 0.0;
  adjust1 = GTK_ADJUSTMENT (gtk_adjustment_new ((gdouble) f_dummy, 0.0, 1.0, 0.01, 1.0, 0.0));
  b_spin = c_widget_new();
  c_spin_set_adjustment(C_WIDGET(b_spin), adjust1);
  c_spin_set_digits(C_WIDGET(b_spin), 2);
  c_spin_set_value(C_WIDGET(b_spin), 0.5);
  gtk_widget_set_name (GTK_WIDGET(b_spin), "spin1");
  gtk_widget_set_size_request(GTK_WIDGET(b_spin), 220, 150);

  grid = gtk_grid_new();
  gtk_grid_attach (GTK_GRID(grid), GTK_WIDGET(b_spin), 0, 0, 1, 1);
  gtk_container_add (GTK_CONTAINER(window), GTK_WIDGET(grid));
  gtk_widget_show_all(window);
  gtk_main ();
  return 0;
}


Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Fri Jul 27, 2012 8:06 pm 
Offline
Never Seen the Sunlight

Joined: Wed Jul 23, 2008 10:31 am
Posts: 2406
Location: Slovenia
Hi.

That marshaller problem can probably be avoided if you pass NULL instead of G_TYPE_NONE. Or better yet, pass the proper marshalling function, which in this case should be g_cclosure_marshal_VOID__VOID.

Cheers,
Tadej


Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Fri Jul 27, 2012 11:45 pm 
Offline
GTK+ Guru

Joined: Fri Mar 25, 2011 5:16 pm
Posts: 176
Location: USA
I used g_cclosure_marshal_VOID__VOID and it works great now. Thank you tadeboro.


Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Sat Jul 28, 2012 5:41 am 
Offline
Familiar Face

Joined: Thu Dec 15, 2011 6:23 pm
Posts: 36
Location: Hrvatska
I fix it in code, thanks !

zerohour: YES you can name up/down buttons and style them in CSS file.
I fix post with correct tip.

Tadej: where can I find that macro:
Code:
g_cclosure_marshal_VOID__VOID,   // _gtk_marshal_VOID__VOID


In original GtkSpinButton code there is macro _gtk_marshal_VOID__VOID - I can't find where is definition of that macro.

Can you tell me please - where is definition file for that macro ?
Thank you very much.

Cheers!
Vjeko


Last edited by kepica on Mon Jul 30, 2012 6:38 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Composite widgets
PostPosted: Sat Jul 28, 2012 6:48 am 
Offline
Never Seen the Sunlight

Joined: Wed Jul 23, 2008 10:31 am
Posts: 2406
Location: Slovenia
HI kepica.

g_cclosure_marshal_VOID__VOID() is not macro, it's a function and is part of the GObject library. It is one of the convenience functions, provided by GObject, to ease the creation of new signals. You can see all of the predefined marshalers in closures part of GObject API reference.

But when you write complex library/application, most likely you'll need marshalers that are not provided by GObject. And this is where glib-genmarshal tool comes to help. This tool takes a list of requirements for marshalers (one per line) and generates required C code. And this is how GTK+ marshalers are created (input file is here and relevant Makefile rules are here).

Cheers,
Tadej


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group