Loki Davison schrieb:
> On 5/2/07, audio-mobster <[EMAIL PROTECTED]> wrote:
>> Loki Davison schrieb:
>> > Phat is a collection of GTK+ widgets geared toward audio apps.
>> > Bug fixes and a few small feature updates. Most of the work done by
>> > Nedko! ;)
>> >
>> > We need help to implement all of Thorsten's new ideas. Check out
>> > http://thorwil.wordpress.com/ I'm really not able to do much coding at
>> > the moment due to RSI / overuse injury issues. I'm trying to keep away
>> >> from a computer. There has been some discussion of making phat dual
>> > toolkit, gtk and qt4. Help with this would be very useful too. Contact
>> > me if you want to help and need svn access.
>> >
>> > Phat and pyphat can be download at http://phat.berlios.de/
>> >
>> > Cheers,
>> > Loki
>> > _______________________________________________
>> > Linux-audio-dev mailing list
>> > [email protected]
>> > http://lists.linuxaudio.org/mailman/listinfo.cgi/linux-audio-dev
>> >
>> Hi
>>
>> I already started implementing a SVG-Cairo version of a knob.
>> I'm playing with bounds and magnetic middle...
>>
>> Greets Uli
>> _______________________________________________
>> Linux-audio-dev mailing list
>> [email protected]
>> http://lists.linuxaudio.org/mailman/listinfo.cgi/linux-audio-dev
>>
>
> put it in SVN, then everyone else can play with it too! Give me a yell
> for access.
>
> Loki
> _______________________________________________
> Linux-audio-dev mailing list
> [email protected]
> http://lists.linuxaudio.org/mailman/listinfo.cgi/linux-audio-dev
>
The sources are derived from cairo-clock:
http://cairographics.org/documentation
The tutorial by Davyd Madeley.
I added first support for scrolling, bounds and magnetic.
See drawing function phat_svg_knob_face_scroll() and
emit_scroll_event_signal().
The button is still upside down.
No shading or translucency yet, I got no compositmanager running.
all: test_widget
test_widget: test_widget.c phatsvgknob.c phatsvgknob.h
phatsvgknob-marshallers.c phatsvgknob-marshallers.h
gcc -g -o test_widget test_widget.c phatsvgknob.c
phatsvgknob-marshallers.c \
`pkg-config --libs --cflags gtk+-2.0`
phatsvgknob-marshallers.c: phatsvgknob-marshallers.list
glib-genmarshal --prefix _phatsvgknob_marshal --body $< > $@
phatsvgknob-marshallers.h: phatsvgknob-marshallers.list
glib-genmarshal --prefix _phatsvgknob_marshal --header $< > $@
clean:
-rm -rf test_widget Binaries/test_widget/*
* phatsvgknob.c
*
* A GTK+ widget that implements a knob face
*
* (C) 2007, Ulrich Lorenz Schlueter
*
* derived from:
* http://www.gnomejournal.org/article/34/writing-a-widget-using-cairo-and-gtk28
* http://gnomejournal.org/article/36/writing-a-widget-using-cairo-and-gtk28-part-2
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Authors:
* Ulrich Lorenz Schlueter <[EMAIL PROTECTED]>
*/
#include <gtk/gtk.h>
#include <math.h>
#include <time.h>
#include "phatsvgknob.h"
#include "phatsvgknob-marshallers.h"
#define PHAT_SVG_KNOB_FACE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PHAT_TYPE_SVG_KNOB_FACE, PhatSvgKnobFacePrivate))
G_DEFINE_TYPE (PhatSvgKnobFace, phat_svg_knob_face, GTK_TYPE_DRAWING_AREA);
static gboolean phat_svg_knob_face_expose (GtkWidget *knob, GdkEventExpose *event);
static gboolean phat_svg_knob_face_button_press (GtkWidget *knob, GdkEventButton *event);
static gboolean phat_svg_knob_face_button_release (GtkWidget *knob, GdkEventButton *event);
static gboolean phat_svg_knob_face_motion_notify (GtkWidget *knob, GdkEventMotion *event);
static gboolean phat_svg_knob_face_scroll (GtkWidget *knob, GdkEventScroll *event);
static gboolean phat_svg_knob_face_update (gpointer data);
typedef struct _PhatSvgKnobFacePrivate PhatSvgKnobFacePrivate;
struct _PhatSvgKnobFacePrivate
{
double decibel; /* the decibels */
double decibel_offset; /* the offset of the decibels */
gboolean dragging; /* true if the interface is being dragged */
};
enum
{
VALUE_CHANGED,
LAST_SIGNAL,
};
static guint phat_svg_knob_face_signals[LAST_SIGNAL] = { 0 };
static void
phat_svg_knob_face_class_init (PhatSvgKnobFaceClass *class)
{
GObjectClass *obj_class;
GtkWidgetClass *widget_class;
obj_class = G_OBJECT_CLASS (class);
widget_class = GTK_WIDGET_CLASS (class);
/* GtkWidget signals */
widget_class->expose_event = phat_svg_knob_face_expose;
widget_class->button_press_event = phat_svg_knob_face_button_press;
widget_class->button_release_event = phat_svg_knob_face_button_release;
widget_class->motion_notify_event = phat_svg_knob_face_motion_notify;
widget_class->scroll_event = phat_svg_knob_face_scroll;
/* PhatSvgKnobFace signals */
phat_svg_knob_face_signals[VALUE_CHANGED] = g_signal_new (
"value-changed",
G_OBJECT_CLASS_TYPE (obj_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PhatSvgKnobFaceClass, value_changed),
NULL, NULL,
_phatsvgknob_marshal_VOID__INT_INT,
G_TYPE_NONE, 2,
G_TYPE_INT,
G_TYPE_INT);
g_type_class_add_private (obj_class, sizeof (PhatSvgKnobFacePrivate));
}
static void
phat_svg_knob_face_init (PhatSvgKnobFace *knob)
{
gtk_widget_add_events (GTK_WIDGET (knob),
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_SCROLL_MASK |GDK_POINTER_MOTION_MASK);
phat_svg_knob_face_update (knob);
}
static void
draw (GtkWidget *knob, cairo_t *cr)
{
PhatSvgKnobFacePrivate *priv;
double x, y;
double radius;
int i;
double decibels;
priv = PHAT_SVG_KNOB_FACE_GET_PRIVATE (knob);
x = knob->allocation.width / 2;
y = knob->allocation.height / 2;
radius = MIN (knob->allocation.width / 2,
knob->allocation.height / 2) - 10;
/* knob back */
cairo_arc (cr, x, y, radius, 0, 2 * M_PI);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_fill_preserve(cr);
cairo_set_source_rgb (cr, 1, 0.5, 0);
cairo_stroke (cr);
cairo_save (cr);
/* knob ticks */
for (i = 6; i < 25; i++)
{
int inset;
cairo_save (cr); /* stack-pen-size */
if ( i % 3 == 0 )
{
inset = 0.075 * radius;
cairo_set_line_width (cr, 1.5 * cairo_get_line_width (cr));
} else {
inset = 0.05 * radius;
cairo_set_line_width (cr, 1 * cairo_get_line_width (cr));
}
cairo_move_to (cr,
x + (radius + inset) * cos (i * M_PI / 10),
y + (radius + inset) * sin (i * M_PI / 10));
cairo_line_to (cr,
x + radius * cos (i * M_PI / 10),
y + radius * sin (i * M_PI / 10));
cairo_stroke (cr);
cairo_restore (cr); /* stack-pen-size */
}
/* knob hands */
decibels = priv->decibel + priv->decibel_offset;
/* decibel hand:
* the decibel hand is rotated 6 degrees (pi/45 r) per decibel
*/
cairo_move_to (cr, x, y);
cairo_set_line_width (cr, 2.3 * cairo_get_line_width (cr));
cairo_line_to (cr, x + radius * sin (M_PI / PHAT_SVG_KNOB_DEFAULT_ADJUST * decibels),
y + radius * -cos (M_PI / PHAT_SVG_KNOB_DEFAULT_ADJUST * decibels));
cairo_stroke (cr);
cairo_restore (cr);
}
static gboolean
phat_svg_knob_face_expose (GtkWidget *knob, GdkEventExpose *event)
{
cairo_t *cr;
/* get a cairo_t */
cr = gdk_cairo_create(knob->window);
cairo_rectangle (cr,
event->area.x, event->area.y,
event->area.width, event->area.height);
cairo_clip (cr);
draw (knob, cr);
cairo_destroy (cr);
return FALSE;
}
static gboolean
phat_svg_knob_face_button_press (GtkWidget *knob, GdkEventButton *event)
{
PhatSvgKnobFacePrivate *priv;
double decibels;
double lx, ly;
double px, py;
double u, d2;
priv = PHAT_SVG_KNOB_FACE_GET_PRIVATE (knob);
decibels = priv->decibel + priv->decibel_offset;
/* From
* http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
*/
px = event->x - knob->allocation.width / 2;
py = knob->allocation.height / 2 - event->y;
lx = sin (M_PI / PHAT_SVG_KNOB_DEFAULT_ADJUST * decibels); ly = cos (M_PI / PHAT_SVG_KNOB_DEFAULT_ADJUST * decibels);
u = lx * px + ly * py;
/* on opposite side of origin */
if (u < 0) return FALSE;
d2 = pow (px - u * lx, 2) + pow (py - u * ly, 2);
if (d2 < 25) /* 5 pixels away from the line */
{
priv->dragging = TRUE;
}
return FALSE;
}
static void
phat_svg_knob_face_redraw_canvas (PhatSvgKnobFace *knob)
{
GtkWidget *widget;
GdkRegion *region;
widget = GTK_WIDGET (knob);
if (!widget->window) return;
region = gdk_drawable_get_clip_region (widget->window);
/* redraw the cairo canvas completely by exposing it */
gdk_window_invalidate_region (widget->window, region, TRUE);
gdk_window_process_updates (widget->window, TRUE);
gdk_region_destroy (region);
}
static emit_value_changed_signal (PhatSvgKnobFace *knob, int x, int y)
{
PhatSvgKnobFacePrivate *priv;
double phi;
double decibels;
priv = PHAT_SVG_KNOB_FACE_GET_PRIVATE (knob);
/* decode the decibel hand */
/* normalise the coordinates around the origin */
x -= GTK_WIDGET (knob)->allocation.width / 2;
y -= GTK_WIDGET (knob)->allocation.height / 2;
/* phi is a bearing from north clockwise, use the same geometry as we
* did to position the decibel hand originally */
phi = atan2 (x, -y);
if (phi < 0)
phi += M_PI * 2;
decibels = phi * PHAT_SVG_KNOB_DEFAULT_ADJUST / M_PI;
if(decibels<=5){
/* Stop drawing on min */
priv->decibel=5;
priv->decibel_offset = 0;
decibels=5;
} else if(decibels>=85){
/* Stop drawing on max */
priv->decibel=85;
priv->decibel_offset = 0;
decibels=85;
} else if(decibels>=43 && decibels<=47){
/* Magnetic on 45 */
priv->decibel=45;
priv->decibel_offset = 0;
decibels=45;
} else {
/* update the offset */
priv->decibel_offset = decibels - priv->decibel;
priv->decibel= decibels;
}
phat_svg_knob_face_redraw_canvas (knob);
g_signal_emit (knob,
phat_svg_knob_face_signals[VALUE_CHANGED],
0, decibels);
}
static emit_scroll_event_signal (PhatSvgKnobFace *knob, int direction)
{
PhatSvgKnobFacePrivate *priv;
priv = PHAT_SVG_KNOB_FACE_GET_PRIVATE (knob);
if(direction==0){
priv->decibel = priv->decibel + 1;
} else if(direction==1){
priv->decibel = priv->decibel -1;
} else if(direction==2){
priv->decibel = priv->decibel + 5;
} else {
priv->decibel = priv->decibel -5;
}
/* Stop drawing on min */
if(priv->decibel<=5){
priv->decibel=5;
}
/* Stop drawing on max */
if (priv->decibel>=85){
priv->decibel=85;
}
phat_svg_knob_face_redraw_canvas(knob);
g_signal_emit (knob,
phat_svg_knob_face_signals[VALUE_CHANGED],
0, priv->decibel);
}
static gboolean
phat_svg_knob_face_scroll (GtkWidget *knob, GdkEventScroll *event)
{
emit_scroll_event_signal (PHAT_SVG_KNOB_FACE (knob),
event->direction);
return FALSE;
}
static gboolean
phat_svg_knob_face_motion_notify (GtkWidget *knob, GdkEventMotion *event)
{
PhatSvgKnobFacePrivate *priv;
int x, y;
priv = PHAT_SVG_KNOB_FACE_GET_PRIVATE (knob);
if (priv->dragging)
{
emit_value_changed_signal (PHAT_SVG_KNOB_FACE (knob),
event->x, event->y);
}
return FALSE;
}
static gboolean
phat_svg_knob_face_button_release (GtkWidget *knob, GdkEventButton *event)
{
PhatSvgKnobFacePrivate *priv;
priv = PHAT_SVG_KNOB_FACE_GET_PRIVATE (knob);
if (priv->dragging)
{
priv = PHAT_SVG_KNOB_FACE_GET_PRIVATE (knob);
priv->dragging = FALSE;
emit_value_changed_signal (PHAT_SVG_KNOB_FACE (knob),
event->x, event->y);
}
return FALSE;
}
static gboolean
phat_svg_knob_face_update (gpointer data)
{
PhatSvgKnobFace *knob;
PhatSvgKnobFacePrivate *priv;
knob = PHAT_SVG_KNOB_FACE (data);
priv = PHAT_SVG_KNOB_FACE_GET_PRIVATE (knob);
phat_svg_knob_face_redraw_canvas (knob);
return TRUE; /* keep running this event */
}
GtkWidget *
phat_svg_knob_face_new (void)
{
return g_object_new (PHAT_TYPE_SVG_KNOB_FACE, NULL);
}
/*
* phatsvgknob.h
*
* A GTK+ widget that implements a knob face
*
* (C) 2007, Ulrich Lorenz Schlueter
*
* derived from:
* http://www.gnomejournal.org/article/34/writing-a-widget-using-cairo-and-gtk28
* http://gnomejournal.org/article/36/writing-a-widget-using-cairo-and-gtk28-part-2
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Authors:
* Ulrich Lorenz Schlueter <[EMAIL PROTECTED]>
*/
#ifndef __PHAT_SVG_KNOB_FACE_H__
#define __PHAT_SVG_KNOB_FACE_H__
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define PHAT_TYPE_SVG_KNOB_FACE (phat_svg_knob_face_get_type ())
#define PHAT_SVG_KNOB_FACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PHAT_TYPE_SVG_KNOB_FACE, PhatSvgKnobFace))
#define PHAT_SVG_KNOB_FACE_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), PHAT_SVG_KNOB_FACE, PhatSvgKnobFaceClass))
#define PHAT_IS_SVG_KNOB_FACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PHAT_TYPE_SVG_KNOB_FACE))
#define PHAT_IS_SVG_KNOB_FACE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), PHAT_TYPE_SVG_KNOB_FACE))
#define PHAT_SVG_KNOB_FACE_GET_CLASS (G_TYPE_INSTANCE_GET_CLASS ((obj), PHAT_TYPE_SVG_KNOB_FACE, PhatSvgKnobFaceClass))
#define PHAT_SVG_KNOB_DEFAULT_ADJUST (45)
typedef struct _PhatSvgKnobFace PhatSvgKnobFace;
typedef struct _PhatSvgKnobFaceClass PhatSvgKnobFaceClass;
struct _PhatSvgKnobFace
{
GtkDrawingArea parent;
/* < private > */
};
struct _PhatSvgKnobFaceClass
{
GtkDrawingAreaClass parent_class;
void (* value_changed) (PhatSvgKnobFace *knob, double decibel);
};
GtkWidget *phat_svg_knob_face_new (void);
G_END_DECLS
#endif
#include <glib-object.h>
#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
#define g_marshal_value_peek_char(v) g_value_get_char (v)
#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
#define g_marshal_value_peek_int(v) g_value_get_int (v)
#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
#define g_marshal_value_peek_long(v) g_value_get_long (v)
#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
#define g_marshal_value_peek_float(v) g_value_get_float (v)
#define g_marshal_value_peek_double(v) g_value_get_double (v)
#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v) g_value_get_param (v)
#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
#define g_marshal_value_peek_object(v) g_value_get_object (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
* Do not access GValues directly in your code. Instead, use the
* g_value_get_*() functions
*/
#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
#define g_marshal_value_peek_char(v) (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
#define g_marshal_value_peek_int(v) (v)->data[0].v_int
#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
#define g_marshal_value_peek_long(v) (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v) (v)->data[0].v_float
#define g_marshal_value_peek_double(v) (v)->data[0].v_double
#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG */
/* VOID:INT,INT (phatsvgknob-marshallers.list:2) */
void
_phatsvgknob_marshal_VOID__INT_INT (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data)
{
typedef void (*GMarshalFunc_VOID__INT_INT) (gpointer data1,
gint arg_1,
gint arg_2,
gpointer data2);
register GMarshalFunc_VOID__INT_INT callback;
register GCClosure *cc = (GCClosure*) closure;
register gpointer data1, data2;
g_return_if_fail (n_param_values == 3);
if (G_CCLOSURE_SWAP_DATA (closure))
{
data1 = closure->data;
data2 = g_value_peek_pointer (param_values + 0);
}
else
{
data1 = g_value_peek_pointer (param_values + 0);
data2 = closure->data;
}
callback = (GMarshalFunc_VOID__INT_INT) (marshal_data ? marshal_data : cc->callback);
callback (data1,
g_marshal_value_peek_int (param_values + 1),
g_marshal_value_peek_int (param_values + 2),
data2);
}
#ifndef ___phatsvgknob_marshal_MARSHAL_H__
#define ___phatsvgknob_marshal_MARSHAL_H__
#include <glib-object.h>
G_BEGIN_DECLS
/* VOID:INT,INT (phatsvgknob-marshallers.list:2) */
extern void _phatsvgknob_marshal_VOID__INT_INT (GClosure *closure,
GValue *return_value,
guint n_param_values,
const GValue *param_values,
gpointer invocation_hint,
gpointer marshal_data);
G_END_DECLS
#endif /* ___phatsvgknob_marshal_MARSHAL_H__ */
# these marshallers are generated with glib-genmarshal(1)
VOID:INT,INT
/*
* main.c
*
* Test widget
*
* (C) 2007, Ulrich Lorenz Schlueter
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Authors:
* Ulrich Lorenz Schlueter <[EMAIL PROTECTED]>
*/
#include <gtk/gtk.h>
#include "phatsvgknob.h"
static void
value_changed_cb (PhatSvgKnobFace *knob, double decibel, gpointer data)
{
g_print ("value-changed - %02f\n", decibel);
}
int
main (int argc, char **argv)
{
GtkWidget *window;
GtkWidget *knob;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
knob = phat_svg_knob_face_new ();
gtk_widget_set_size_request (knob, 100, 100);
gtk_container_add (GTK_CONTAINER (window), knob);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
g_signal_connect (knob, "value-changed",
G_CALLBACK (value_changed_cb), NULL);
gtk_widget_show_all (window);
gtk_main ();
}
_______________________________________________
Linux-audio-dev mailing list
[email protected]
http://lists.linuxaudio.org/mailman/listinfo.cgi/linux-audio-dev