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);
}