diff options
author | Alexey Yakovenko <wakeroid@gmail.com> | 2010-04-07 12:44:08 +0200 |
---|---|---|
committer | Alexey Yakovenko <wakeroid@gmail.com> | 2010-04-07 12:44:08 +0200 |
commit | dc2363526761820ced55ff0735771dfb747b2921 (patch) | |
tree | 480d44db8ab8a8d2754210d9f9b9dc9e91af99d3 | |
parent | 79fccb4ac4c50f1d1f50ad379bc40e7ab3b52367 (diff) | |
parent | 823669afef8942b45960391f2f3d732ab1ad06e3 (diff) |
Merge branch 'thesame' into devel
-rw-r--r-- | plugins/gtkui/Makefile.am | 3 | ||||
-rwxr-xr-x | plugins/gtkui/compile | 12 | ||||
-rw-r--r-- | plugins/gtkui/eq.c | 33 | ||||
-rw-r--r-- | plugins/gtkui/graphic.c | 1484 | ||||
-rw-r--r-- | plugins/gtkui/graphic.h | 44 | ||||
-rw-r--r-- | plugins/gtkui/graphic.vala | 737 | ||||
-rw-r--r-- | plugins/gtkui/test.vala | 30 |
7 files changed, 2341 insertions, 2 deletions
diff --git a/plugins/gtkui/Makefile.am b/plugins/gtkui/Makefile.am index 22e11995..02a2d5e4 100644 --- a/plugins/gtkui/Makefile.am +++ b/plugins/gtkui/Makefile.am @@ -17,7 +17,8 @@ gtkui_la_SOURCES = gtkui.c gtkui.h\ coverart.c coverart.h\ plcommon.c plcommon.h\ prefwin.c\ - eq.c eq.h + eq.c eq.h\ + graphic.c graphic.h gtkui_la_LDFLAGS = -module diff --git a/plugins/gtkui/compile b/plugins/gtkui/compile new file mode 100755 index 00000000..c608a7a1 --- /dev/null +++ b/plugins/gtkui/compile @@ -0,0 +1,12 @@ +#!/bin/sh + +#gcc g.c ddb-equalizer.c -g -O0 `pkg-config --libs --cflags gtk+-2.0 gdk-2.0` + +valac -C -H graphic.h --library graphic graphic.vala --pkg=gtk+-2.0 && +#gcc --shared -o libgraphic.so `pkg-config --libs --cflags gtk+-2.0 gdk-2.0` graphic.c && +valac -C test.vala graphic.vapi --pkg=gtk+-2.0 && +gcc test.c graphic.c -I. -o test `pkg-config --libs --cflags gtk+-2.0 gdk-2.0` +# gcc -shared graphic.c -o graphic.so `pkg-config --libs --cflags gtk+-2.0 gdk-2.0` +#valac graphic.vala --pkg=gtk+-2.0 +#gcc *.c `pkg-config --libs --cflags gtk+-2.0` + diff --git a/plugins/gtkui/eq.c b/plugins/gtkui/eq.c index a02b2bc0..1935cf6b 100644 --- a/plugins/gtkui/eq.c +++ b/plugins/gtkui/eq.c @@ -22,6 +22,7 @@ #include "gtkui.h" #include "support.h" #include "../supereq/supereq.h" +#include "graphic.h" static GtkWidget *eqwin; static GtkWidget *sliders[18]; @@ -74,8 +75,29 @@ eq_init_widgets (GtkWidget *container) { } void +graphic_value_changed (gpointer inst, double *values, gint count) +{ + DB_supereq_dsp_t *eq = NULL; + DB_dsp_t **plugs = deadbeef->plug_get_dsp_list (); + + for (int i = 0; plugs[i]; i++) + { + if (plugs[i]->plugin.id && !strcmp (plugs[i]->plugin.id, "supereq")) + { + eq = (DB_supereq_dsp_t *)plugs[i]; + for (int ii = 0; ii < count; ii++) + { + double val = db_to_amp (values[ii]); + eq->set_band (ii, val); + } + break; + } + } +} + +void eq_window_show (void) { - if (!eqwin) { +/* if (!eqwin) { eqwin = gtk_hbox_new (FALSE, 0); gtk_widget_set_size_request (eqwin, -1, 200); eq_init_widgets (eqwin); @@ -107,6 +129,15 @@ eq_window_show (void) { gtk_range_set_value (GTK_RANGE (scale), val); } } + gtk_widget_show (eqwin);*/ + + if (!eqwin) { + eqwin = deadbeef_graphic_new(); + g_signal_connect (eqwin, "on_changed", G_CALLBACK (graphic_value_changed), 0); + gtk_widget_set_size_request (eqwin, -1, 200); + GtkWidget *cont = lookup_widget (mainwin, "vbox1"); + gtk_box_pack_start (GTK_BOX (cont), eqwin, FALSE, FALSE, 0); + } gtk_widget_show (eqwin); } diff --git a/plugins/gtkui/graphic.c b/plugins/gtkui/graphic.c new file mode 100644 index 00000000..3a899afb --- /dev/null +++ b/plugins/gtkui/graphic.c @@ -0,0 +1,1484 @@ +/* graphic.c generated by valac, the Vala compiler + * generated from graphic.vala, do not modify */ + + +#include <glib.h> +#include <glib-object.h> +#include <stdlib.h> +#include <string.h> +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <pango/pango.h> +#include <float.h> +#include <math.h> +#include <cairo.h> +#include <gobject/gvaluecollector.h> + + +#define DEADBEEF_TYPE_GRAPHIC (deadbeef_graphic_get_type ()) +#define DEADBEEF_GRAPHIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEADBEEF_TYPE_GRAPHIC, DeadbeefGraphic)) +#define DEADBEEF_GRAPHIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEADBEEF_TYPE_GRAPHIC, DeadbeefGraphicClass)) +#define DEADBEEF_IS_GRAPHIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEADBEEF_TYPE_GRAPHIC)) +#define DEADBEEF_IS_GRAPHIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEADBEEF_TYPE_GRAPHIC)) +#define DEADBEEF_GRAPHIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEADBEEF_TYPE_GRAPHIC, DeadbeefGraphicClass)) + +typedef struct _DeadbeefGraphic DeadbeefGraphic; +typedef struct _DeadbeefGraphicClass DeadbeefGraphicClass; +typedef struct _DeadbeefGraphicPrivate DeadbeefGraphicPrivate; + +#define DEADBEEF_GRAPHIC_TYPE_POINT (deadbeef_graphic_point_get_type ()) +#define DEADBEEF_GRAPHIC_POINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEADBEEF_GRAPHIC_TYPE_POINT, DeadbeefGraphicPoint)) +#define DEADBEEF_GRAPHIC_POINT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEADBEEF_GRAPHIC_TYPE_POINT, DeadbeefGraphicPointClass)) +#define DEADBEEF_GRAPHIC_IS_POINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEADBEEF_GRAPHIC_TYPE_POINT)) +#define DEADBEEF_GRAPHIC_IS_POINT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEADBEEF_GRAPHIC_TYPE_POINT)) +#define DEADBEEF_GRAPHIC_POINT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEADBEEF_GRAPHIC_TYPE_POINT, DeadbeefGraphicPointClass)) + +typedef struct _DeadbeefGraphicPoint DeadbeefGraphicPoint; +typedef struct _DeadbeefGraphicPointClass DeadbeefGraphicPointClass; +#define __g_list_free_deadbeef_graphic_point_unref0(var) ((var == NULL) ? NULL : (var = (_g_list_free_deadbeef_graphic_point_unref (var), NULL))) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _pango_font_description_free0(var) ((var == NULL) ? NULL : (var = (pango_font_description_free (var), NULL))) +#define _gdk_cursor_unref0(var) ((var == NULL) ? NULL : (var = (gdk_cursor_unref (var), NULL))) +typedef struct _DeadbeefGraphicPointPrivate DeadbeefGraphicPointPrivate; +#define _deadbeef_graphic_point_unref0(var) ((var == NULL) ? NULL : (var = (deadbeef_graphic_point_unref (var), NULL))) +#define _g_free0(var) (var = (g_free (var), NULL)) +#define _cairo_destroy0(var) ((var == NULL) ? NULL : (var = (cairo_destroy (var), NULL))) +#define __g_slist_free_g_object_unref0(var) ((var == NULL) ? NULL : (var = (_g_slist_free_g_object_unref (var), NULL))) +typedef struct _DeadbeefGraphicParamSpecPoint DeadbeefGraphicParamSpecPoint; + +struct _DeadbeefGraphic { + GtkDrawingArea parent_instance; + DeadbeefGraphicPrivate * priv; +}; + +struct _DeadbeefGraphicClass { + GtkDrawingAreaClass parent_class; +}; + +struct _DeadbeefGraphicPrivate { + GList* points; + GList* current_point; + GdkColor back_color; + GdkColor fore_bright_color; + GdkColor fore_dark_color; + PangoContext* pango_ctx; + PangoFontDescription* font_desc; + double* values; + gint values_length1; + gint _values_size_; + double preamp; + gint mouse_y; + gboolean snap; + gboolean aa_mode; + gboolean curve_hook; + gboolean preamp_hook; + GtkMenu* menu; + GdkCursor* moving_cursor; + GdkCursor* updown_cursor; + GdkCursor* pointer_cursor; +}; + +struct _DeadbeefGraphicPoint { + GTypeInstance parent_instance; + volatile int ref_count; + DeadbeefGraphicPointPrivate * priv; + double x; + double y; +}; + +struct _DeadbeefGraphicPointClass { + GTypeClass parent_class; + void (*finalize) (DeadbeefGraphicPoint *self); +}; + +struct _DeadbeefGraphicParamSpecPoint { + GParamSpec parent_instance; +}; + + +extern gint btn_size; +gint btn_size = 7; +extern DeadbeefGraphic* deadbeef_graphic_inst; +DeadbeefGraphic* deadbeef_graphic_inst = NULL; +static gpointer deadbeef_graphic_point_parent_class = NULL; +static gpointer deadbeef_graphic_parent_class = NULL; + +#define spot_size 3 +#define margin_left 35 +#define margin_bottom 10 +#define bands 18 +GType deadbeef_graphic_get_type (void); +static gpointer deadbeef_graphic_point_ref (gpointer instance); +static void deadbeef_graphic_point_unref (gpointer instance); +static GParamSpec* deadbeef_graphic_param_spec_point (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) G_GNUC_UNUSED; +static void deadbeef_graphic_value_set_point (GValue* value, gpointer v_object) G_GNUC_UNUSED; +static void deadbeef_graphic_value_take_point (GValue* value, gpointer v_object) G_GNUC_UNUSED; +static gpointer deadbeef_graphic_value_get_point (const GValue* value) G_GNUC_UNUSED; +static GType deadbeef_graphic_point_get_type (void) G_GNUC_UNUSED; +#define DEADBEEF_GRAPHIC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEADBEEF_TYPE_GRAPHIC, DeadbeefGraphicPrivate)) +enum { + DEADBEEF_GRAPHIC_DUMMY_PROPERTY +}; +static void _g_list_free_deadbeef_graphic_point_unref (GList* self); +void deadbeef_graphic_aa_mode_changed (DeadbeefGraphic* self, GtkCheckMenuItem* item); +static void deadbeef_graphic_set_snap (DeadbeefGraphic* self, gboolean new_snap); +void deadbeef_graphic_mode_changed (DeadbeefGraphic* self, GtkCheckMenuItem* item); +static DeadbeefGraphicPoint* deadbeef_graphic_point_new (void); +static DeadbeefGraphicPoint* deadbeef_graphic_point_construct (GType object_type); +static void deadbeef_graphic_abs_to_screen (DeadbeefGraphic* self, double x, double y, GdkPoint* result); +static void deadbeef_graphic_abs_to_screen_d (DeadbeefGraphic* self, double x, double y, double* sx, double* sy); +static double deadbeef_graphic_cubic (DeadbeefGraphic* self, double y0, double y1, double y2, double y3, double mu); +static inline double deadbeef_graphic_scale (DeadbeefGraphic* self, double val); +static gboolean deadbeef_graphic_real_expose_event (GtkWidget* base, GdkEventExpose* event); +static gboolean deadbeef_graphic_get_point_at (DeadbeefGraphic* self, double x, double y); +static void deadbeef_graphic_recalc_values (DeadbeefGraphic* self); +static void deadbeef_graphic_snap_move (DeadbeefGraphic* self, double x, double y); +static void deadbeef_graphic_handle_curve_click (DeadbeefGraphic* self, GdkEventButton* event); +static gboolean deadbeef_graphic_in_curve_area (DeadbeefGraphic* self, gint x, gint y); +static gboolean deadbeef_graphic_real_button_press_event (GtkWidget* base, GdkEventButton* event); +static gboolean deadbeef_graphic_real_button_release_event (GtkWidget* base, GdkEventButton* event); +static gboolean deadbeef_graphic_real_leave_notify_event (GtkWidget* base, GdkEventCrossing* event); +static gboolean deadbeef_graphic_real_motion_notify_event (GtkWidget* base, GdkEventMotion* event); +DeadbeefGraphic* deadbeef_graphic_new (void); +DeadbeefGraphic* deadbeef_graphic_construct (GType object_type); +static void _deadbeef_graphic_aa_mode_changed_gtk_check_menu_item_toggled (GtkCheckMenuItem* _sender, gpointer self); +static void _deadbeef_graphic_mode_changed_gtk_check_menu_item_toggled (GtkCheckMenuItem* _sender, gpointer self); +static void _g_slist_free_g_object_unref (GSList* self); +static GObject * deadbeef_graphic_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties); +enum { + DEADBEEF_GRAPHIC_POINT_DUMMY_PROPERTY +}; +static void deadbeef_graphic_point_finalize (DeadbeefGraphicPoint* obj); +static void deadbeef_graphic_finalize (GObject* obj); + +const char* freqs[18] = {"32", "80", "110", "160", "220", "315", "450", "630", "900", "1.3k", "1.8k", "2.5k", "3.6k", "5k", "7k", "10k", "14k", "20k"}; + +static void g_cclosure_user_marshal_VOID__POINTER_INT (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data); + +static void _g_list_free_deadbeef_graphic_point_unref (GList* self) { + g_list_foreach (self, (GFunc) deadbeef_graphic_point_unref, NULL); + g_list_free (self); +} + + +void deadbeef_graphic_aa_mode_changed (DeadbeefGraphic* self, GtkCheckMenuItem* item) { + g_return_if_fail (self != NULL); + g_return_if_fail (item != NULL); + self->priv->aa_mode = gtk_check_menu_item_get_active (item); + gtk_widget_queue_draw ((GtkWidget*) self); +} + + +void deadbeef_graphic_mode_changed (DeadbeefGraphic* self, GtkCheckMenuItem* item) { + g_return_if_fail (self != NULL); + g_return_if_fail (item != NULL); + deadbeef_graphic_set_snap (self, gtk_check_menu_item_get_active (item)); +} + + +static gpointer _deadbeef_graphic_point_ref0 (gpointer self) { + return self ? deadbeef_graphic_point_ref (self) : NULL; +} + + +static void deadbeef_graphic_set_snap (DeadbeefGraphic* self, gboolean new_snap) { + g_return_if_fail (self != NULL); + self->priv->snap = new_snap; + if (self->priv->snap) { + double step; + step = 1.0 / ((double) (bands + 1)); + if (g_list_length (self->priv->points) > 0) { + GList* iter; + iter = NULL; + { + gboolean _tmp0_; + iter = self->priv->points->next; + _tmp0_ = TRUE; + while (TRUE) { + if (!_tmp0_) { + iter = iter->next; + } + _tmp0_ = FALSE; + if (!(iter != NULL)) { + break; + } + self->priv->points = g_list_remove_link (self->priv->points, iter->prev); + } + } + self->priv->points = g_list_remove_link (self->priv->points, self->priv->points); + } + { + gint i; + i = 0; + { + gboolean _tmp1_; + _tmp1_ = TRUE; + while (TRUE) { + DeadbeefGraphicPoint* point; + if (!_tmp1_) { + i++; + } + _tmp1_ = FALSE; + if (!(i < bands)) { + break; + } + point = deadbeef_graphic_point_new (); + point->x = (((double) i) + 1) * step; + point->y = self->priv->values[i]; + self->priv->points = g_list_prepend (self->priv->points, _deadbeef_graphic_point_ref0 (point)); + _deadbeef_graphic_point_unref0 (point); + } + } + } + self->priv->points = g_list_reverse (self->priv->points); + } +} + + +static void deadbeef_graphic_abs_to_screen (DeadbeefGraphic* self, double x, double y, GdkPoint* result) { + GdkPoint _tmp0_ = {0}; + g_return_if_fail (self != NULL); + *result = (memset (&_tmp0_, 0, sizeof (GdkPoint)), _tmp0_.x = ((gint) (x * (((GtkWidget*) self)->allocation.width - margin_left))) + margin_left, _tmp0_.y = (gint) (y * (((GtkWidget*) self)->allocation.height - margin_bottom)), _tmp0_); + return; +} + + +static void deadbeef_graphic_abs_to_screen_d (DeadbeefGraphic* self, double x, double y, double* sx, double* sy) { + g_return_if_fail (self != NULL); + *sx = (double) (((gint) (x * (((GtkWidget*) self)->allocation.width - margin_left))) + margin_left); + *sy = (double) ((gint) (y * (((GtkWidget*) self)->allocation.height - margin_bottom))); +} + + +static double deadbeef_graphic_cubic (DeadbeefGraphic* self, double y0, double y1, double y2, double y3, double mu) { + double result = 0.0; + g_return_val_if_fail (self != NULL, 0.0); + result = 0.5 * ((((2 * y1) + (((-y0) + y2) * mu)) + ((((((2 * y0) - (5 * y1)) + (4 * y2)) - y3) * mu) * mu)) + (((((((-y0) + (3 * y1)) - (3 * y2)) + y3) * mu) * mu) * mu)); + return result; +} + + +static gpointer _g_object_ref0 (gpointer self) { + return self ? g_object_ref (self) : NULL; +} + + +static gpointer _pango_font_description_copy0 (gpointer self) { + return self ? pango_font_description_copy (self) : NULL; +} + + +static gpointer _cairo_reference0 (gpointer self) { + return self ? cairo_reference (self) : NULL; +} + + +static gboolean deadbeef_graphic_real_expose_event (GtkWidget* base, GdkEventExpose* event) { + DeadbeefGraphic * self; + gboolean result = FALSE; + gint width; + gint height; + GdkPoint* _tmp1_; + gint _gpoints_size_; + gint gpoints_length1; + gint _tmp0_; + GdkPoint* gpoints; + GdkPoint _tmp2_ = {0}; + gint i; + GdkPoint _tmp4_ = {0}; + GdkDrawable* d; + GdkGCValues _tmp6_; + GdkGCValues _tmp5_ = {0}; + GdkGC* gc; + double step; + double vstep; + PangoLayout* l; + PangoContext* ctx; + PangoFontDescription* fd; + gboolean _tmp10_ = FALSE; + char* tmp; + char* _tmp11_; + GdkRectangle _tmp13_; + GdkRectangle _tmp12_ = {0}; + gint count; + GdkRectangle _tmp16_; + GdkRectangle _tmp15_ = {0}; + gint bar_w; + GdkRectangle _tmp22_; + GdkRectangle _tmp21_ = {0}; + GdkPoint gp = {0}; + guint pcount; + double* _tmp23_; + gint _ys_size_; + gint ys_length1; + double* ys; + double* _tmp24_; + gint _xs_size_; + gint xs_length1; + double* xs; + cairo_t* _tmp26_; + cairo_t* cairo; + gint prev_x; + gint prev_y; + self = (DeadbeefGraphic*) base; + width = ((GtkWidget*) self)->allocation.width; + height = ((GtkWidget*) self)->allocation.height; + gpoints = (_tmp1_ = g_new0 (GdkPoint, _tmp0_ = g_list_length (self->priv->points) + 2), gpoints_length1 = _tmp0_, _gpoints_size_ = gpoints_length1, _tmp1_); + gpoints[0] = (_tmp2_.x = margin_left, _tmp2_.y = (height - margin_bottom) / 2, _tmp2_); + i = 1; + { + GList* p_collection; + GList* p_it; + p_collection = self->priv->points; + for (p_it = p_collection; p_it != NULL; p_it = p_it->next) { + DeadbeefGraphicPoint* p; + p = _deadbeef_graphic_point_ref0 ((DeadbeefGraphicPoint*) p_it->data); + { + GdkPoint _tmp3_ = {0}; + gpoints[i] = (deadbeef_graphic_abs_to_screen (self, p->x, p->y, &_tmp3_), _tmp3_); + if (gpoints[i].x >= width) { + gpoints[i].x = width - 1; + } + i++; + _deadbeef_graphic_point_unref0 (p); + } + } + } + gpoints[i] = (_tmp4_.x = width - 1, _tmp4_.y = (height - margin_bottom) / 2, _tmp4_); + d = _g_object_ref0 ((GdkDrawable*) gtk_widget_get_window ((GtkWidget*) self)); + gc = _g_object_ref0 (GDK_DRAWABLE_GET_CLASS (d)->create_gc (d, (_tmp6_ = (memset (&_tmp5_, 0, sizeof (GdkGCValues)), _tmp5_), &_tmp6_), 0)); + gdk_gc_set_rgb_fg_color (gc, &self->priv->fore_dark_color); + step = ((double) (width - margin_left)) / ((double) (bands + 1)); + { + gboolean _tmp7_; + i = 0; + _tmp7_ = TRUE; + while (TRUE) { + if (!_tmp7_) { + i++; + } + _tmp7_ = FALSE; + if (!(i < bands)) { + break; + } + gdk_draw_line (d, gc, ((gint) ((i + 1) * step)) + margin_left, 0, ((gint) ((i + 1) * step)) + margin_left, height - margin_bottom); + } + } + vstep = (double) (height - margin_bottom); + { + double di; + di = (double) 0; + { + gboolean _tmp8_; + _tmp8_ = TRUE; + while (TRUE) { + if (!_tmp8_) { + di = di + 0.25; + } + _tmp8_ = FALSE; + if (!(di < 2)) { + break; + } + gdk_draw_line (d, gc, margin_left, (gint) ((di - self->priv->preamp) * vstep), width, (gint) ((di - self->priv->preamp) * vstep)); + } + } + } + gdk_gc_set_rgb_fg_color (gc, &self->priv->fore_bright_color); + l = gtk_widget_create_pango_layout ((GtkWidget*) self, NULL); + ctx = _g_object_ref0 (pango_layout_get_context (l)); + fd = _pango_font_description_copy0 (pango_context_get_font_description (ctx)); + pango_font_description_set_size (fd, 4); + pango_font_description_set_family_static (fd, "fixed"); + pango_context_set_font_description (ctx, fd); + { + gboolean _tmp9_; + i = 0; + _tmp9_ = TRUE; + while (TRUE) { + if (!_tmp9_) { + i++; + } + _tmp9_ = FALSE; + if (!(i < bands)) { + break; + } + pango_layout_set_text (l, freqs[i], (gint) g_utf8_strlen (freqs[i], -1)); + gdk_draw_layout (d, gc, ((gint) (((i + 1) * step) - 5)) + margin_left, (height - margin_bottom) + 2, l); + } + } + pango_layout_set_width (l, margin_left - 1); + pango_layout_set_alignment (l, PANGO_ALIGN_RIGHT); + if (self->priv->mouse_y != (-1)) { + _tmp10_ = self->priv->mouse_y < (height - margin_bottom); + } else { + _tmp10_ = FALSE; + } + if (_tmp10_) { + double db; + char* tmp; + db = deadbeef_graphic_scale (self, ((double) (self->priv->mouse_y - 1)) / ((double) ((height - margin_bottom) - 2))); + tmp = g_strdup_printf ("%.1f", db); + pango_layout_set_text (l, tmp, (gint) g_utf8_strlen (tmp, -1)); + gdk_draw_layout (d, gc, margin_left - 1, self->priv->mouse_y - 3, l); + _g_free0 (tmp); + } + tmp = g_strdup_printf ("%.1f", deadbeef_graphic_scale (self, (double) 1)); + pango_layout_set_text (l, tmp, (gint) g_utf8_strlen (tmp, -1)); + gdk_draw_layout (d, gc, margin_left - 1, (height - margin_bottom) - 6, l); + tmp = (_tmp11_ = g_strdup_printf ("%.1f", deadbeef_graphic_scale (self, (double) 0)), _g_free0 (tmp), _tmp11_); + pango_layout_set_text (l, tmp, (gint) g_utf8_strlen (tmp, -1)); + gdk_draw_layout (d, gc, margin_left - 1, 1, l); + pango_layout_set_text (l, "0db", 4); + gdk_draw_layout (d, gc, margin_left - 1, ((gint) ((1 - self->priv->preamp) * (height - margin_bottom))) - 3, l); + pango_layout_set_text (l, "preamp", 6); + pango_layout_set_alignment (l, PANGO_ALIGN_LEFT); + gdk_draw_layout (d, gc, 1, (height - margin_bottom) + 2, l); + gdk_draw_rectangle (d, gc, FALSE, margin_left, 0, (width - margin_left) - 1, (height - margin_bottom) - 1); + gdk_gc_set_line_attributes (gc, 2, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); + gdk_gc_set_clip_rectangle (gc, (_tmp13_ = (_tmp12_.x = 0, _tmp12_.y = (gint) (self->priv->preamp * (height - margin_bottom)), _tmp12_.width = 11, _tmp12_.height = height, _tmp12_), &_tmp13_)); + gdk_gc_set_rgb_fg_color (gc, &self->priv->fore_dark_color); + count = ((gint) ((height - margin_bottom) / 6)) + 1; + { + gint j; + j = 0; + { + gboolean _tmp14_; + _tmp14_ = TRUE; + while (TRUE) { + if (!_tmp14_) { + j++; + } + _tmp14_ = FALSE; + if (!(j < count)) { + break; + } + gdk_draw_rectangle (d, gc, TRUE, 1, ((height - margin_bottom) - (j * 6)) - 6, 11, 4); + } + } + } + gdk_gc_set_clip_rectangle (gc, (_tmp16_ = (_tmp15_.x = margin_left + 1, _tmp15_.y = 1, _tmp15_.width = (width - margin_left) - 2, _tmp15_.height = (height - margin_bottom) - 2, _tmp15_), &_tmp16_)); + gdk_gc_set_rgb_fg_color (gc, &self->priv->fore_dark_color); + bar_w = 11; + if (step < bar_w) { + bar_w = ((gint) step) - 1; + } + { + gboolean _tmp17_; + i = 0; + _tmp17_ = TRUE; + while (TRUE) { + GdkRectangle _tmp19_; + GdkRectangle _tmp18_ = {0}; + if (!_tmp17_) { + i++; + } + _tmp17_ = FALSE; + if (!(i < bands)) { + break; + } + gdk_gc_set_clip_rectangle (gc, (_tmp19_ = (_tmp18_.x = (((gint) ((i + 1) * step)) + margin_left) - (bar_w / 2), _tmp18_.y = (gint) (self->priv->values[i] * (height - margin_bottom)), _tmp18_.width = 11, _tmp18_.height = height, _tmp18_), &_tmp19_)); + count = ((gint) (((height - margin_bottom) * (1 - self->priv->values[i])) / 6)) + 1; + { + gint j; + j = 0; + { + gboolean _tmp20_; + _tmp20_ = TRUE; + while (TRUE) { + if (!_tmp20_) { + j++; + } + _tmp20_ = FALSE; + if (!(j < count)) { + break; + } + gdk_draw_rectangle (d, gc, TRUE, (((gint) ((i + 1) * step)) + margin_left) - (bar_w / 2), ((height - margin_bottom) - (j * 6)) - 6, bar_w, 4); + } + } + } + } + } + gdk_gc_set_clip_rectangle (gc, (_tmp22_ = (_tmp21_.x = 0, _tmp21_.y = 0, _tmp21_.width = width, _tmp21_.height = height, _tmp21_), &_tmp22_)); + gdk_gc_set_rgb_fg_color (gc, &self->priv->fore_bright_color); + pcount = g_list_length (self->priv->points); + ys = (_tmp23_ = g_new0 (double, pcount), ys_length1 = pcount, _ys_size_ = ys_length1, _tmp23_); + xs = (_tmp24_ = g_new0 (double, pcount), xs_length1 = pcount, _xs_size_ = xs_length1, _tmp24_); + i = 0; + { + GList* p_collection; + GList* p_it; + p_collection = self->priv->points; + for (p_it = p_collection; p_it != NULL; p_it = p_it->next) { + DeadbeefGraphicPoint* p; + p = _deadbeef_graphic_point_ref0 ((DeadbeefGraphicPoint*) p_it->data); + { + GdkPoint _tmp25_ = {0}; + gp = (deadbeef_graphic_abs_to_screen (self, p->x, p->y, &_tmp25_), _tmp25_); + gdk_draw_rectangle (d, gc, TRUE, gp.x - spot_size, gp.y - spot_size, spot_size * 2, spot_size * 2); + xs[i] = p->x; + ys[i] = p->y; + i++; + _deadbeef_graphic_point_unref0 (p); + } + } + } + _tmp26_ = NULL; + if (self->priv->aa_mode) { + cairo_t* _tmp27_; + _tmp26_ = (_tmp27_ = gdk_cairo_create (d), _cairo_destroy0 (_tmp26_), _tmp27_); + } else { + cairo_t* _tmp28_; + _tmp26_ = (_tmp28_ = NULL, _cairo_destroy0 (_tmp26_), _tmp28_); + } + cairo = _cairo_reference0 (_tmp26_); + prev_x = 0; + prev_y = 0; + if (pcount > 0) { + GdkPoint _tmp29_ = {0}; + gp = (deadbeef_graphic_abs_to_screen (self, xs[0], ys[0], &_tmp29_), _tmp29_); + if (self->priv->aa_mode) { + cairo_move_to (cairo, (double) margin_left, (double) gp.y); + } else { + gdk_draw_line (d, gc, margin_left, gp.y, gp.x, gp.y); + } + prev_x = gp.x; + prev_y = gp.y; + } + if (pcount >= 2) { + { + gboolean _tmp30_; + i = 0; + _tmp30_ = TRUE; + while (TRUE) { + double dx; + double dy; + gint pts; + if (!_tmp30_) { + i++; + } + _tmp30_ = FALSE; + if (!(i < (pcount - 1))) { + break; + } + if (((gint) ((xs[i + 1] - xs[i]) * width)) <= 5) { + GdkPoint _tmp31_ = {0}; + GdkPoint gp2; + GdkPoint _tmp32_ = {0}; + gp2 = (deadbeef_graphic_abs_to_screen (self, xs[i], ys[i], &_tmp31_), _tmp31_); + gp = (deadbeef_graphic_abs_to_screen (self, xs[i + 1], ys[i + 1], &_tmp32_), _tmp32_); + gdk_draw_line (d, gc, gp2.x, gp2.y, gp.x, gp.y); + prev_x = gp2.x; + prev_y = gp2.y; + continue; + } + dx = (xs[i + 1] - xs[i]) * width; + dy = (ys[i + 1] - ys[i]) * height; + pts = (gint) (sqrt ((dx * dx) + (dy * dy)) / 5.0); + step = ((double) (xs[i + 1] - xs[i])) / ((double) pts); + { + gint ii; + ii = 0; + { + gboolean _tmp33_; + _tmp33_ = TRUE; + while (TRUE) { + double y = 0.0; + gboolean _tmp34_ = FALSE; + if (!_tmp33_) { + ii++; + } + _tmp33_ = FALSE; + if (!(ii <= pts)) { + break; + } + if (i == 0) { + _tmp34_ = i == (pcount - 2); + } else { + _tmp34_ = FALSE; + } + if (_tmp34_) { + y = deadbeef_graphic_cubic (self, ys[0], ys[0], ys[1], ys[1], ((double) ii) / ((double) pts)); + } else { + if (i == 0) { + y = deadbeef_graphic_cubic (self, ys[0], ys[0], ys[1], ys[2], ((double) ii) / ((double) pts)); + } else { + if (i == (pcount - 2)) { + y = deadbeef_graphic_cubic (self, ys[i - 1], ys[i], ys[i + 1], ys[i + 1], ((double) ii) / ((double) pts)); + } else { + y = deadbeef_graphic_cubic (self, ys[i - 1], ys[i], ys[i + 1], ys[i + 2], ((double) ii) / ((double) pts)); + } + } + } + if (y < 0) { + y = (double) 0; + } + if (y > 1) { + y = (double) 1; + } + if (self->priv->aa_mode) { + double sx = 0.0; + double sy = 0.0; + deadbeef_graphic_abs_to_screen_d (self, (ii * step) + xs[i], y, &sx, &sy); + cairo_line_to (cairo, sx, sy); + } else { + GdkPoint _tmp35_ = {0}; + gp = (deadbeef_graphic_abs_to_screen (self, (ii * step) + xs[i], y, &_tmp35_), _tmp35_); + if (gp.y < 2) { + gp.y = 2; + } + if (gp.y > ((height - margin_bottom) - 2)) { + gp.y = (height - margin_bottom) - 2; + } + gdk_draw_point (d, gc, gp.x, gp.y); + prev_x = gp.x; + prev_y = gp.y; + } + } + } + } + } + } + } + if (pcount > 0) { + GdkPoint _tmp36_ = {0}; + gp = (deadbeef_graphic_abs_to_screen (self, xs[pcount - 1], ys[pcount - 1], &_tmp36_), _tmp36_); + if (self->priv->aa_mode) { + cairo_line_to (cairo, (double) (width - 1), (double) gp.y); + } else { + gdk_draw_line (d, gc, gp.x, gp.y, width - 1, gp.y); + } + } + if (self->priv->aa_mode) { + cairo_set_source_rgb (cairo, ((double) self->priv->fore_bright_color.red) / ((double) 0xffff), ((double) self->priv->fore_bright_color.green) / ((double) 0xffff), ((double) self->priv->fore_bright_color.blue) / ((double) 0xffff)); + cairo_stroke (cairo); + } + if (pcount == 0) { + gdk_draw_line (d, gc, margin_left, (height - margin_bottom) / 2, width - 1, (height - margin_bottom) / 2); + } + gdk_gc_set_line_attributes (gc, 1, GDK_LINE_ON_OFF_DASH, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); + gdk_draw_line (d, gc, margin_left + 1, self->priv->mouse_y, width, self->priv->mouse_y); + result = FALSE; + gpoints = (g_free (gpoints), NULL); + _g_object_unref0 (d); + _g_object_unref0 (gc); + _g_object_unref0 (l); + _g_object_unref0 (ctx); + _pango_font_description_free0 (fd); + _g_free0 (tmp); + ys = (g_free (ys), NULL); + xs = (g_free (xs), NULL); + _cairo_destroy0 (_tmp26_); + _cairo_destroy0 (cairo); + return result; +} + + +static gboolean deadbeef_graphic_get_point_at (DeadbeefGraphic* self, double x, double y) { + gboolean result = FALSE; + gboolean ret; + GList* iter; + double ss_x; + double ss_y; + g_return_val_if_fail (self != NULL, FALSE); + ret = FALSE; + iter = NULL; + ss_x = ((double) spot_size) / ((double) ((GtkWidget*) self)->allocation.width); + ss_y = ((double) spot_size) / ((double) ((GtkWidget*) self)->allocation.height); + { + gboolean _tmp0_; + iter = self->priv->points; + _tmp0_ = TRUE; + while (TRUE) { + gboolean _tmp1_ = FALSE; + if (!_tmp0_) { + iter = iter->next; + } + _tmp0_ = FALSE; + if (!(iter != NULL)) { + break; + } + if (fabs (((DeadbeefGraphicPoint*) iter->data)->x - x) <= ss_x) { + _tmp1_ = fabs (((DeadbeefGraphicPoint*) iter->data)->y - y) <= ss_y; + } else { + _tmp1_ = FALSE; + } + if (_tmp1_) { + self->priv->current_point = iter; + ret = TRUE; + break; + } + } + } + result = ret; + return result; +} + + +static inline double deadbeef_graphic_scale (DeadbeefGraphic* self, double val) { + double result = 0.0; + double k; + double d; + g_return_val_if_fail (self != NULL, 0.0); + k = (double) (-40); + d = (double) 20; + result = (((val + self->priv->preamp) - 0.5) * k) + d; + return result; +} + + +static void deadbeef_graphic_recalc_values (DeadbeefGraphic* self) { + guint pcount; + double* _tmp0_; + gint _ys_size_; + gint ys_length1; + double* ys; + double* _tmp1_; + gint _xs_size_; + gint xs_length1; + double* xs; + gint i; + double* _tmp7_; + gint _scaled_values_size_; + gint scaled_values_length1; + double* scaled_values; + g_return_if_fail (self != NULL); + pcount = g_list_length (self->priv->points); + ys = (_tmp0_ = g_new0 (double, pcount), ys_length1 = pcount, _ys_size_ = ys_length1, _tmp0_); + xs = (_tmp1_ = g_new0 (double, pcount), xs_length1 = pcount, _xs_size_ = xs_length1, _tmp1_); + i = 0; + { + GList* p_collection; + GList* p_it; + p_collection = self->priv->points; + for (p_it = p_collection; p_it != NULL; p_it = p_it->next) { + DeadbeefGraphicPoint* p; + p = _deadbeef_graphic_point_ref0 ((DeadbeefGraphicPoint*) p_it->data); + { + xs[i] = p->x; + ys[i] = p->y; + i++; + _deadbeef_graphic_point_unref0 (p); + } + } + } + if (pcount == 0) { + { + gboolean _tmp2_; + i = 0; + _tmp2_ = TRUE; + while (TRUE) { + if (!_tmp2_) { + i++; + } + _tmp2_ = FALSE; + if (!(i < bands)) { + break; + } + self->priv->values[i] = 0.5; + } + } + } else { + if (pcount == 1) { + { + gboolean _tmp3_; + i = 0; + _tmp3_ = TRUE; + while (TRUE) { + if (!_tmp3_) { + i++; + } + _tmp3_ = FALSE; + if (!(i < bands)) { + break; + } + self->priv->values[i] = ys[0]; + } + } + } else { + gint pi; + pi = 0; + { + gboolean _tmp4_; + i = 0; + _tmp4_ = TRUE; + while (TRUE) { + double x; + double y; + gboolean _tmp5_ = FALSE; + gboolean _tmp6_ = FALSE; + if (!_tmp4_) { + i++; + } + _tmp4_ = FALSE; + if (!(i < bands)) { + break; + } + x = ((double) (i + 1)) / ((double) (bands + 1)); + y = (double) 0; + if (xs[pi] > x) { + self->priv->values[i] = ys[pi]; + continue; + } + if (xs[pi + 1] < x) { + _tmp5_ = pi < (pcount - 1); + } else { + _tmp5_ = FALSE; + } + if (_tmp5_) { + pi++; + } + if (pi == (pcount - 1)) { + self->priv->values[i] = ys[pcount - 1]; + continue; + } + if (pi == 0) { + _tmp6_ = pi == (pcount - 2); + } else { + _tmp6_ = FALSE; + } + if (_tmp6_) { + y = deadbeef_graphic_cubic (self, ys[pi], ys[pi], ys[pi + 1], ys[pi + 1], (x - xs[pi]) / (xs[pi + 1] - xs[pi])); + } else { + if (pi == 0) { + y = deadbeef_graphic_cubic (self, ys[pi], ys[pi], ys[pi + 1], ys[pi + 2], (x - xs[pi]) / (xs[pi + 1] - xs[pi])); + } else { + if (pi == (pcount - 2)) { + y = deadbeef_graphic_cubic (self, ys[pi - 1], ys[pi], ys[pi + 1], ys[pi + 1], (x - xs[pi]) / (xs[pi + 1] - xs[pi])); + } else { + y = deadbeef_graphic_cubic (self, ys[pi - 1], ys[pi], ys[pi + 1], ys[pi + 2], (x - xs[pi]) / (xs[pi + 1] - xs[pi])); + } + } + } + if (y < 0) { + y = (double) 0; + } + if (y > 1) { + y = (double) 1; + } + self->priv->values[i] = y; + } + } + } + } + scaled_values = (_tmp7_ = g_new0 (double, bands), scaled_values_length1 = bands, _scaled_values_size_ = scaled_values_length1, _tmp7_); + { + gboolean _tmp8_; + i = 0; + _tmp8_ = TRUE; + while (TRUE) { + if (!_tmp8_) { + i++; + } + _tmp8_ = FALSE; + if (!(i < bands)) { + break; + } + scaled_values[i] = deadbeef_graphic_scale (self, self->priv->values[i]); + } + } + g_signal_emit_by_name (self, "on-changed", scaled_values, scaled_values_length1); + ys = (g_free (ys), NULL); + xs = (g_free (xs), NULL); + scaled_values = (g_free (scaled_values), NULL); +} + + +static void deadbeef_graphic_snap_move (DeadbeefGraphic* self, double x, double y) { + double step; + gint idx; + g_return_if_fail (self != NULL); + step = 1.0 / ((double) (bands + 1)); + idx = (gint) ((x - (step / 2)) / step); + if (idx < bands) { + self->priv->current_point = g_list_nth (self->priv->points, (guint) idx); + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->y = y; + } +} + + +static void deadbeef_graphic_handle_curve_click (DeadbeefGraphic* self, GdkEventButton* event) { + double x; + double y; + g_return_if_fail (self != NULL); + x = ((double) ((*event).x - margin_left)) / ((double) (((GtkWidget*) self)->allocation.width - margin_left)); + y = (*event).y / ((double) (((GtkWidget*) self)->allocation.height - margin_bottom)); + if ((*event).button == 1) { + if (self->priv->snap) { + deadbeef_graphic_snap_move (self, x, y); + } else { + if (!deadbeef_graphic_get_point_at (self, x, y)) { + DeadbeefGraphicPoint* point; + point = deadbeef_graphic_point_new (); + if (self->priv->points == NULL) { + self->priv->points = g_list_append (self->priv->points, _deadbeef_graphic_point_ref0 (point)); + self->priv->current_point = self->priv->points; + } else { + if (((DeadbeefGraphicPoint*) self->priv->points->data)->x > x) { + self->priv->points = g_list_prepend (self->priv->points, _deadbeef_graphic_point_ref0 (point)); + self->priv->current_point = self->priv->points; + } else { + gboolean found; + found = FALSE; + { + GList* i; + i = self->priv->points; + { + gboolean _tmp0_; + _tmp0_ = TRUE; + while (TRUE) { + gboolean _tmp1_ = FALSE; + if (!_tmp0_) { + i = i->next; + } + _tmp0_ = FALSE; + if (!(i->next != NULL)) { + break; + } + if (((DeadbeefGraphicPoint*) i->data)->x < x) { + _tmp1_ = ((DeadbeefGraphicPoint*) i->next->data)->x > x; + } else { + _tmp1_ = FALSE; + } + if (_tmp1_) { + self->priv->points = g_list_insert_before (self->priv->points, i->next, _deadbeef_graphic_point_ref0 (point)); + self->priv->current_point = i->next; + found = TRUE; + break; + } + } + } + } + if (!found) { + self->priv->points = g_list_append (self->priv->points, _deadbeef_graphic_point_ref0 (point)); + self->priv->current_point = g_list_last (self->priv->points); + } + } + } + _deadbeef_graphic_point_unref0 (point); + } + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->x = x; + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->y = y; + } + deadbeef_graphic_recalc_values (self); + gdk_window_set_cursor (gtk_widget_get_window ((GtkWidget*) self), self->priv->moving_cursor); + gtk_widget_queue_draw ((GtkWidget*) self); + } else { + if ((*event).button == 3) { + if (self->priv->snap) { + return; + } + if (deadbeef_graphic_get_point_at (self, x, y)) { + self->priv->points = g_list_remove (self->priv->points, (DeadbeefGraphicPoint*) self->priv->current_point->data); + deadbeef_graphic_recalc_values (self); + gtk_widget_queue_draw ((GtkWidget*) self); + } + gtk_widget_queue_draw ((GtkWidget*) self); + } + } +} + + +static gboolean deadbeef_graphic_in_curve_area (DeadbeefGraphic* self, gint x, gint y) { + gboolean result = FALSE; + gboolean _tmp0_ = FALSE; + gboolean _tmp1_ = FALSE; + gboolean _tmp2_ = FALSE; + g_return_val_if_fail (self != NULL, FALSE); + if (x > margin_left) { + _tmp2_ = x < (((GtkWidget*) self)->allocation.width - 1); + } else { + _tmp2_ = FALSE; + } + if (_tmp2_) { + _tmp1_ = y > 1; + } else { + _tmp1_ = FALSE; + } + if (_tmp1_) { + _tmp0_ = y < (((GtkWidget*) self)->allocation.height - margin_bottom); + } else { + _tmp0_ = FALSE; + } + result = _tmp0_; + return result; +} + + +static gboolean deadbeef_graphic_real_button_press_event (GtkWidget* base, GdkEventButton* event) { + DeadbeefGraphic * self; + gboolean result = FALSE; + gboolean _tmp0_ = FALSE; + gboolean _tmp1_ = FALSE; + gboolean _tmp2_ = FALSE; + self = (DeadbeefGraphic*) base; + if (deadbeef_graphic_in_curve_area (self, (gint) (*event).x, (gint) (*event).y)) { + self->priv->curve_hook = TRUE; + deadbeef_graphic_handle_curve_click (self, event); + result = FALSE; + return result; + } + if ((*event).x <= 11) { + _tmp2_ = (*event).y > 1; + } else { + _tmp2_ = FALSE; + } + if (_tmp2_) { + _tmp1_ = (*event).y <= (((GtkWidget*) self)->allocation.height - margin_bottom); + } else { + _tmp1_ = FALSE; + } + if (_tmp1_) { + _tmp0_ = (*event).button == 1; + } else { + _tmp0_ = FALSE; + } + if (_tmp0_) { + self->priv->preamp = (*event).y / ((double) (((GtkWidget*) self)->allocation.height - margin_bottom)); + self->priv->preamp_hook = TRUE; + } + if ((*event).button == 3) { + gtk_menu_popup (self->priv->menu, NULL, NULL, NULL, NULL, (*event).button, gtk_get_current_event_time ()); + } + result = FALSE; + return result; +} + + +static gboolean deadbeef_graphic_real_button_release_event (GtkWidget* base, GdkEventButton* event) { + DeadbeefGraphic * self; + gboolean result = FALSE; + self = (DeadbeefGraphic*) base; + self->priv->curve_hook = FALSE; + self->priv->preamp_hook = FALSE; + gdk_window_set_cursor (gtk_widget_get_window ((GtkWidget*) self), self->priv->pointer_cursor); + result = FALSE; + return result; +} + + +static gboolean deadbeef_graphic_real_leave_notify_event (GtkWidget* base, GdkEventCrossing* event) { + DeadbeefGraphic * self; + gboolean result = FALSE; + self = (DeadbeefGraphic*) base; + self->priv->mouse_y = -1; + gtk_widget_queue_draw ((GtkWidget*) self); + result = FALSE; + return result; +} + + +static gboolean deadbeef_graphic_real_motion_notify_event (GtkWidget* base, GdkEventMotion* event) { + DeadbeefGraphic * self; + gboolean result = FALSE; + double x; + double y; + self = (DeadbeefGraphic*) base; + x = ((double) ((*event).x - margin_left)) / ((double) (((GtkWidget*) self)->allocation.width - margin_left)); + y = (*event).y / ((double) (((GtkWidget*) self)->allocation.height - margin_bottom)); + if (y < 0) { + y = (double) 0; + } + if (y > 1) { + y = (double) 1; + } + if (self->priv->preamp_hook) { + self->priv->preamp = y; + gtk_widget_queue_draw ((GtkWidget*) self); + result = FALSE; + return result; + } + if (!deadbeef_graphic_in_curve_area (self, (gint) (*event).x, (gint) (*event).y)) { + self->priv->mouse_y = -1; + } else { + self->priv->mouse_y = (gint) (*event).y; + } + if (self->priv->curve_hook) { + if (self->priv->snap) { + deadbeef_graphic_snap_move (self, x, y); + } else { + gboolean _tmp0_ = FALSE; + gboolean _tmp1_ = FALSE; + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->x = x; + if (self->priv->current_point->prev != NULL) { + _tmp0_ = ((DeadbeefGraphicPoint*) self->priv->current_point->prev->data)->x > ((DeadbeefGraphicPoint*) self->priv->current_point->data)->x; + } else { + _tmp0_ = FALSE; + } + if (_tmp0_) { + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->x = ((DeadbeefGraphicPoint*) self->priv->current_point->prev->data)->x; + } + if (self->priv->current_point->next != NULL) { + _tmp1_ = ((DeadbeefGraphicPoint*) self->priv->current_point->next->data)->x < ((DeadbeefGraphicPoint*) self->priv->current_point->data)->x; + } else { + _tmp1_ = FALSE; + } + if (_tmp1_) { + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->x = ((DeadbeefGraphicPoint*) self->priv->current_point->next->data)->x; + } + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->y = y; + if (((DeadbeefGraphicPoint*) self->priv->current_point->data)->x > 1) { + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->x = (double) 1; + } + if (((DeadbeefGraphicPoint*) self->priv->current_point->data)->x < 0) { + ((DeadbeefGraphicPoint*) self->priv->current_point->data)->x = (double) 0; + } + } + deadbeef_graphic_recalc_values (self); + self->priv->mouse_y = (gint) (*event).y; + gtk_widget_queue_draw ((GtkWidget*) self); + } else { + if ((*event).x < 11) { + gdk_window_set_cursor (gtk_widget_get_window ((GtkWidget*) self), self->priv->updown_cursor); + } else { + if (!deadbeef_graphic_get_point_at (self, x, y)) { + gdk_window_set_cursor (gtk_widget_get_window ((GtkWidget*) self), self->priv->pointer_cursor); + } else { + gdk_window_set_cursor (gtk_widget_get_window ((GtkWidget*) self), self->priv->moving_cursor); + } + } + gtk_widget_queue_draw ((GtkWidget*) self); + } + result = FALSE; + return result; +} + + +DeadbeefGraphic* deadbeef_graphic_construct (GType object_type) { + DeadbeefGraphic * self; + self = g_object_newv (object_type, 0, NULL); + return self; +} + + +DeadbeefGraphic* deadbeef_graphic_new (void) { + return deadbeef_graphic_construct (DEADBEEF_TYPE_GRAPHIC); +} + + +static void _deadbeef_graphic_aa_mode_changed_gtk_check_menu_item_toggled (GtkCheckMenuItem* _sender, gpointer self) { + deadbeef_graphic_aa_mode_changed (self, _sender); +} + + +static void _deadbeef_graphic_mode_changed_gtk_check_menu_item_toggled (GtkCheckMenuItem* _sender, gpointer self) { + deadbeef_graphic_mode_changed (self, _sender); +} + + +static void _g_slist_free_g_object_unref (GSList* self) { + g_slist_foreach (self, (GFunc) g_object_unref, NULL); + g_slist_free (self); +} + + +static GObject * deadbeef_graphic_constructor (GType type, guint n_construct_properties, GObjectConstructParam * construct_properties) { + GObject * obj; + GObjectClass * parent_class; + DeadbeefGraphic * self; + parent_class = G_OBJECT_CLASS (deadbeef_graphic_parent_class); + obj = parent_class->constructor (type, n_construct_properties, construct_properties); + self = DEADBEEF_GRAPHIC (obj); + { + PangoFontDescription* _tmp3_; + PangoContext* _tmp4_; + GtkMenu* _tmp5_; + GtkCheckMenuItem* checkitem; + GtkMenuItem* mode_item; + GtkMenu* mode_menu; + GSList* group; + GtkRadioMenuItem* thesame_item; + GtkRadioMenuItem* waker_item; + gtk_widget_add_events ((GtkWidget*) self, (gint) (((GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK) | GDK_LEAVE_NOTIFY_MASK) | GDK_POINTER_MOTION_MASK)); + gtk_widget_modify_bg ((GtkWidget*) self, GTK_STATE_NORMAL, &self->priv->back_color); + self->priv->font_desc = (_tmp3_ = pango_font_description_from_string ("fixed 4"), _pango_font_description_free0 (self->priv->font_desc), _tmp3_); + self->priv->pango_ctx = (_tmp4_ = pango_context_new (), _g_object_unref0 (self->priv->pango_ctx), _tmp4_); + pango_context_set_font_description (self->priv->pango_ctx, self->priv->font_desc); + deadbeef_graphic_recalc_values (self); + self->priv->preamp = 0.5; + self->priv->menu = (_tmp5_ = g_object_ref_sink ((GtkMenu*) gtk_menu_new ()), _g_object_unref0 (self->priv->menu), _tmp5_); + checkitem = g_object_ref_sink ((GtkCheckMenuItem*) gtk_check_menu_item_new_with_label ("Antialiasing")); + gtk_widget_show ((GtkWidget*) checkitem); + g_signal_connect_object (checkitem, "toggled", (GCallback) _deadbeef_graphic_aa_mode_changed_gtk_check_menu_item_toggled, self, 0); + gtk_menu_shell_append ((GtkMenuShell*) self->priv->menu, (GtkWidget*) ((GtkMenuItem*) checkitem)); + mode_item = g_object_ref_sink ((GtkMenuItem*) gtk_menu_item_new ()); + gtk_widget_show ((GtkWidget*) mode_item); + gtk_menu_item_set_label (mode_item, "mode"); + gtk_menu_shell_append ((GtkMenuShell*) self->priv->menu, (GtkWidget*) mode_item); + mode_menu = g_object_ref_sink ((GtkMenu*) gtk_menu_new ()); + group = NULL; + thesame_item = g_object_ref_sink ((GtkRadioMenuItem*) gtk_radio_menu_item_new_with_label (group, "thesame")); + gtk_widget_show ((GtkWidget*) thesame_item); + gtk_menu_shell_append ((GtkMenuShell*) mode_menu, (GtkWidget*) ((GtkMenuItem*) thesame_item)); + waker_item = g_object_ref_sink ((GtkRadioMenuItem*) gtk_radio_menu_item_new_with_label_from_widget (thesame_item, "waker")); + gtk_widget_show ((GtkWidget*) waker_item); + g_signal_connect_object ((GtkCheckMenuItem*) waker_item, "toggled", (GCallback) _deadbeef_graphic_mode_changed_gtk_check_menu_item_toggled, self, 0); + gtk_menu_shell_append ((GtkMenuShell*) mode_menu, (GtkWidget*) ((GtkMenuItem*) waker_item)); + gtk_menu_item_set_submenu (mode_item, (GtkWidget*) mode_menu); + _g_object_unref0 (checkitem); + _g_object_unref0 (mode_item); + _g_object_unref0 (mode_menu); + __g_slist_free_g_object_unref0 (group); + _g_object_unref0 (thesame_item); + _g_object_unref0 (waker_item); + } + return obj; +} + + +static DeadbeefGraphicPoint* deadbeef_graphic_point_construct (GType object_type) { + DeadbeefGraphicPoint* self; + self = (DeadbeefGraphicPoint*) g_type_create_instance (object_type); + return self; +} + + +static DeadbeefGraphicPoint* deadbeef_graphic_point_new (void) { + return deadbeef_graphic_point_construct (DEADBEEF_GRAPHIC_TYPE_POINT); +} + + +static void deadbeef_graphic_value_point_init (GValue* value) { + value->data[0].v_pointer = NULL; +} + + +static void deadbeef_graphic_value_point_free_value (GValue* value) { + if (value->data[0].v_pointer) { + deadbeef_graphic_point_unref (value->data[0].v_pointer); + } +} + + +static void deadbeef_graphic_value_point_copy_value (const GValue* src_value, GValue* dest_value) { + if (src_value->data[0].v_pointer) { + dest_value->data[0].v_pointer = deadbeef_graphic_point_ref (src_value->data[0].v_pointer); + } else { + dest_value->data[0].v_pointer = NULL; + } +} + + +static gpointer deadbeef_graphic_value_point_peek_pointer (const GValue* value) { + return value->data[0].v_pointer; +} + + +static gchar* deadbeef_graphic_value_point_collect_value (GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { + if (collect_values[0].v_pointer) { + DeadbeefGraphicPoint* object; + object = collect_values[0].v_pointer; + if (object->parent_instance.g_class == NULL) { + return g_strconcat ("invalid unclassed object pointer for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } else if (!g_value_type_compatible (G_TYPE_FROM_INSTANCE (object), G_VALUE_TYPE (value))) { + return g_strconcat ("invalid object type `", g_type_name (G_TYPE_FROM_INSTANCE (object)), "' for value type `", G_VALUE_TYPE_NAME (value), "'", NULL); + } + value->data[0].v_pointer = deadbeef_graphic_point_ref (object); + } else { + value->data[0].v_pointer = NULL; + } + return NULL; +} + + +static gchar* deadbeef_graphic_value_point_lcopy_value (const GValue* value, guint n_collect_values, GTypeCValue* collect_values, guint collect_flags) { + DeadbeefGraphicPoint** object_p; + object_p = collect_values[0].v_pointer; + if (!object_p) { + return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value)); + } + if (!value->data[0].v_pointer) { + *object_p = NULL; + } else if (collect_flags && G_VALUE_NOCOPY_CONTENTS) { + *object_p = value->data[0].v_pointer; + } else { + *object_p = deadbeef_graphic_point_ref (value->data[0].v_pointer); + } + return NULL; +} + + +static GParamSpec* deadbeef_graphic_param_spec_point (const gchar* name, const gchar* nick, const gchar* blurb, GType object_type, GParamFlags flags) { + DeadbeefGraphicParamSpecPoint* spec; + g_return_val_if_fail (g_type_is_a (object_type, DEADBEEF_GRAPHIC_TYPE_POINT), NULL); + spec = g_param_spec_internal (G_TYPE_PARAM_OBJECT, name, nick, blurb, flags); + G_PARAM_SPEC (spec)->value_type = object_type; + return G_PARAM_SPEC (spec); +} + + +static gpointer deadbeef_graphic_value_get_point (const GValue* value) { + g_return_val_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, DEADBEEF_GRAPHIC_TYPE_POINT), NULL); + return value->data[0].v_pointer; +} + + +static void deadbeef_graphic_value_set_point (GValue* value, gpointer v_object) { + DeadbeefGraphicPoint* old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, DEADBEEF_GRAPHIC_TYPE_POINT)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, DEADBEEF_GRAPHIC_TYPE_POINT)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + deadbeef_graphic_point_ref (value->data[0].v_pointer); + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + deadbeef_graphic_point_unref (old); + } +} + + +static void deadbeef_graphic_value_take_point (GValue* value, gpointer v_object) { + DeadbeefGraphicPoint* old; + g_return_if_fail (G_TYPE_CHECK_VALUE_TYPE (value, DEADBEEF_GRAPHIC_TYPE_POINT)); + old = value->data[0].v_pointer; + if (v_object) { + g_return_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (v_object, DEADBEEF_GRAPHIC_TYPE_POINT)); + g_return_if_fail (g_value_type_compatible (G_TYPE_FROM_INSTANCE (v_object), G_VALUE_TYPE (value))); + value->data[0].v_pointer = v_object; + } else { + value->data[0].v_pointer = NULL; + } + if (old) { + deadbeef_graphic_point_unref (old); + } +} + + +static void deadbeef_graphic_point_class_init (DeadbeefGraphicPointClass * klass) { + deadbeef_graphic_point_parent_class = g_type_class_peek_parent (klass); + DEADBEEF_GRAPHIC_POINT_CLASS (klass)->finalize = deadbeef_graphic_point_finalize; +} + + +static void deadbeef_graphic_point_instance_init (DeadbeefGraphicPoint * self) { + self->ref_count = 1; +} + + +static void deadbeef_graphic_point_finalize (DeadbeefGraphicPoint* obj) { + DeadbeefGraphicPoint * self; + self = DEADBEEF_GRAPHIC_POINT (obj); +} + + +static GType deadbeef_graphic_point_get_type (void) { + static volatile gsize deadbeef_graphic_point_type_id__volatile = 0; + if (g_once_init_enter (&deadbeef_graphic_point_type_id__volatile)) { + static const GTypeValueTable g_define_type_value_table = { deadbeef_graphic_value_point_init, deadbeef_graphic_value_point_free_value, deadbeef_graphic_value_point_copy_value, deadbeef_graphic_value_point_peek_pointer, "p", deadbeef_graphic_value_point_collect_value, "p", deadbeef_graphic_value_point_lcopy_value }; + static const GTypeInfo g_define_type_info = { sizeof (DeadbeefGraphicPointClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) deadbeef_graphic_point_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (DeadbeefGraphicPoint), 0, (GInstanceInitFunc) deadbeef_graphic_point_instance_init, &g_define_type_value_table }; + static const GTypeFundamentalInfo g_define_type_fundamental_info = { (G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE | G_TYPE_FLAG_DERIVABLE | G_TYPE_FLAG_DEEP_DERIVABLE) }; + GType deadbeef_graphic_point_type_id; + deadbeef_graphic_point_type_id = g_type_register_fundamental (g_type_fundamental_next (), "DeadbeefGraphicPoint", &g_define_type_info, &g_define_type_fundamental_info, 0); + g_once_init_leave (&deadbeef_graphic_point_type_id__volatile, deadbeef_graphic_point_type_id); + } + return deadbeef_graphic_point_type_id__volatile; +} + + +static gpointer deadbeef_graphic_point_ref (gpointer instance) { + DeadbeefGraphicPoint* self; + self = instance; + g_atomic_int_inc (&self->ref_count); + return instance; +} + + +static void deadbeef_graphic_point_unref (gpointer instance) { + DeadbeefGraphicPoint* self; + self = instance; + if (g_atomic_int_dec_and_test (&self->ref_count)) { + DEADBEEF_GRAPHIC_POINT_GET_CLASS (self)->finalize (self); + g_type_free_instance ((GTypeInstance *) self); + } +} + + +static void deadbeef_graphic_class_init (DeadbeefGraphicClass * klass) { + deadbeef_graphic_parent_class = g_type_class_peek_parent (klass); + g_type_class_add_private (klass, sizeof (DeadbeefGraphicPrivate)); + GTK_WIDGET_CLASS (klass)->expose_event = deadbeef_graphic_real_expose_event; + GTK_WIDGET_CLASS (klass)->button_press_event = deadbeef_graphic_real_button_press_event; + GTK_WIDGET_CLASS (klass)->button_release_event = deadbeef_graphic_real_button_release_event; + GTK_WIDGET_CLASS (klass)->leave_notify_event = deadbeef_graphic_real_leave_notify_event; + GTK_WIDGET_CLASS (klass)->motion_notify_event = deadbeef_graphic_real_motion_notify_event; + G_OBJECT_CLASS (klass)->constructor = deadbeef_graphic_constructor; + G_OBJECT_CLASS (klass)->finalize = deadbeef_graphic_finalize; + g_signal_new ("on_changed", DEADBEEF_TYPE_GRAPHIC, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__POINTER_INT, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_INT); +} + + +static void deadbeef_graphic_instance_init (DeadbeefGraphic * self) { + GdkColor _tmp0_ = {0}; + GdkColor _tmp1_ = {0}; + GdkColor _tmp2_ = {0}; + self->priv = DEADBEEF_GRAPHIC_GET_PRIVATE (self); + self->priv->points = NULL; + self->priv->current_point = NULL; + self->priv->back_color = (memset (&_tmp0_, 0, sizeof (GdkColor)), _tmp0_.red = (guint16) 0, _tmp0_.green = (guint16) 0, _tmp0_.blue = (guint16) 0, _tmp0_); + self->priv->fore_bright_color = (memset (&_tmp1_, 0, sizeof (GdkColor)), _tmp1_.red = (guint16) 0xffff, _tmp1_.green = (guint16) 0x7e00, _tmp1_.blue = (guint16) 0, _tmp1_); + self->priv->fore_dark_color = (memset (&_tmp2_, 0, sizeof (GdkColor)), _tmp2_.red = (guint16) 0x7800, _tmp2_.green = (guint16) 0x3b00, _tmp2_.blue = (guint16) 0, _tmp2_); + self->priv->values = g_new0 (double, bands); + self->priv->values_length1 = bands; + self->priv->_values_size_ = self->priv->values_length1; + self->priv->snap = FALSE; + self->priv->aa_mode = FALSE; + self->priv->curve_hook = FALSE; + self->priv->preamp_hook = FALSE; + self->priv->menu = NULL; + self->priv->moving_cursor = gdk_cursor_new (GDK_FLEUR); + self->priv->updown_cursor = gdk_cursor_new (GDK_DOUBLE_ARROW); + self->priv->pointer_cursor = gdk_cursor_new (GDK_LEFT_PTR); +} + + +static void deadbeef_graphic_finalize (GObject* obj) { + DeadbeefGraphic * self; + self = DEADBEEF_GRAPHIC (obj); + __g_list_free_deadbeef_graphic_point_unref0 (self->priv->points); + _g_object_unref0 (self->priv->pango_ctx); + _pango_font_description_free0 (self->priv->font_desc); + self->priv->values = (g_free (self->priv->values), NULL); + _g_object_unref0 (self->priv->menu); + _gdk_cursor_unref0 (self->priv->moving_cursor); + _gdk_cursor_unref0 (self->priv->updown_cursor); + _gdk_cursor_unref0 (self->priv->pointer_cursor); + G_OBJECT_CLASS (deadbeef_graphic_parent_class)->finalize (obj); +} + + +GType deadbeef_graphic_get_type (void) { + static volatile gsize deadbeef_graphic_type_id__volatile = 0; + if (g_once_init_enter (&deadbeef_graphic_type_id__volatile)) { + static const GTypeInfo g_define_type_info = { sizeof (DeadbeefGraphicClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) deadbeef_graphic_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (DeadbeefGraphic), 0, (GInstanceInitFunc) deadbeef_graphic_instance_init, NULL }; + GType deadbeef_graphic_type_id; + deadbeef_graphic_type_id = g_type_register_static (GTK_TYPE_DRAWING_AREA, "DeadbeefGraphic", &g_define_type_info, 0); + g_once_init_leave (&deadbeef_graphic_type_id__volatile, deadbeef_graphic_type_id); + } + return deadbeef_graphic_type_id__volatile; +} + + + +static void g_cclosure_user_marshal_VOID__POINTER_INT (GClosure * closure, GValue * return_value, guint n_param_values, const GValue * param_values, gpointer invocation_hint, gpointer marshal_data) { + typedef void (*GMarshalFunc_VOID__POINTER_INT) (gpointer data1, gpointer arg_1, gint arg_2, gpointer data2); + register GMarshalFunc_VOID__POINTER_INT callback; + register GCClosure * cc; + register gpointer data1, data2; + cc = (GCClosure *) closure; + g_return_if_fail (n_param_values == 3); + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = param_values->data[0].v_pointer; + } else { + data1 = param_values->data[0].v_pointer; + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__POINTER_INT) (marshal_data ? marshal_data : cc->callback); + callback (data1, g_value_get_pointer (param_values + 1), g_value_get_int (param_values + 2), data2); +} + + + diff --git a/plugins/gtkui/graphic.h b/plugins/gtkui/graphic.h new file mode 100644 index 00000000..6d588801 --- /dev/null +++ b/plugins/gtkui/graphic.h @@ -0,0 +1,44 @@ +/* graphic.h generated by valac, the Vala compiler, do not modify */ + + +#ifndef __GRAPHIC_H__ +#define __GRAPHIC_H__ + +#include <glib.h> +#include <gtk/gtk.h> + +G_BEGIN_DECLS + + +#define DEADBEEF_TYPE_GRAPHIC (deadbeef_graphic_get_type ()) +#define DEADBEEF_GRAPHIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DEADBEEF_TYPE_GRAPHIC, DeadbeefGraphic)) +#define DEADBEEF_GRAPHIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DEADBEEF_TYPE_GRAPHIC, DeadbeefGraphicClass)) +#define DEADBEEF_IS_GRAPHIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DEADBEEF_TYPE_GRAPHIC)) +#define DEADBEEF_IS_GRAPHIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DEADBEEF_TYPE_GRAPHIC)) +#define DEADBEEF_GRAPHIC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DEADBEEF_TYPE_GRAPHIC, DeadbeefGraphicClass)) + +typedef struct _DeadbeefGraphic DeadbeefGraphic; +typedef struct _DeadbeefGraphicClass DeadbeefGraphicClass; +typedef struct _DeadbeefGraphicPrivate DeadbeefGraphicPrivate; + +struct _DeadbeefGraphic { + GtkDrawingArea parent_instance; + DeadbeefGraphicPrivate * priv; +}; + +struct _DeadbeefGraphicClass { + GtkDrawingAreaClass parent_class; +}; + + +GType deadbeef_graphic_get_type (void); +extern DeadbeefGraphic* deadbeef_graphic_inst; +void deadbeef_graphic_aa_mode_changed (DeadbeefGraphic* self, GtkCheckMenuItem* item); +void deadbeef_graphic_mode_changed (DeadbeefGraphic* self, GtkCheckMenuItem* item); +DeadbeefGraphic* deadbeef_graphic_new (void); +DeadbeefGraphic* deadbeef_graphic_construct (GType object_type); + + +G_END_DECLS + +#endif diff --git a/plugins/gtkui/graphic.vala b/plugins/gtkui/graphic.vala new file mode 100644 index 00000000..d2cb1727 --- /dev/null +++ b/plugins/gtkui/graphic.vala @@ -0,0 +1,737 @@ +static const int spot_size = 3; +static const int margin_left = 35; +static const int margin_bottom = 10; +static const int bands = 18; +static int btn_size = 7; + +const string[] freqs = { + "32","80","110","160","220","315","450","630","900", + "1.3k","1.8k","2.5k","3.6k","5k","7k","10k","14k","20k" +}; + +namespace Deadbeef { + public class Graphic : Gtk.DrawingArea + { + public signal void on_changed (double[] values); + + class Point + { + public double x; + public double y; + } + + private List <Point> points = new List <Point> (); + private unowned List <Point> current_point = null; + + private Gdk.Color back_color = Gdk.Color() {red = 0, green = 0, blue = 0}; + private Gdk.Color fore_bright_color = Gdk.Color() {red = 0xffff, green = 0x7e00, blue = 0}; + private Gdk.Color fore_dark_color = Gdk.Color() {red = 0x7800, green = 0x3b00, blue = 0}; + + private Pango.Context pango_ctx; + private Pango.FontDescription font_desc; + + private double[] values = new double [bands]; + private double preamp; + + private int mouse_y; + + private bool snap = false; + private bool aa_mode = false; + + private bool curve_hook = false; + private bool preamp_hook = false; + + private Gtk.Menu menu = null; + + Gdk.Cursor moving_cursor = new Gdk.Cursor (Gdk.CursorType.FLEUR); + Gdk.Cursor updown_cursor = new Gdk.Cursor (Gdk.CursorType.DOUBLE_ARROW); + Gdk.Cursor pointer_cursor = new Gdk.Cursor (Gdk.CursorType.LEFT_PTR); + + //public Graphic () + construct + { + add_events (Gdk.EventMask.BUTTON_PRESS_MASK + | Gdk.EventMask.BUTTON_RELEASE_MASK + | Gdk.EventMask.LEAVE_NOTIFY_MASK + | Gdk.EventMask.POINTER_MOTION_MASK); + + modify_bg (Gtk.StateType.NORMAL, back_color); + + font_desc = Pango.FontDescription.from_string ("fixed 4"); + pango_ctx = new Pango.Context(); + pango_ctx.set_font_description (font_desc); + recalc_values(); + preamp = 0.5; + + menu = new Gtk.Menu (); + + var checkitem = new Gtk.CheckMenuItem.with_label ("Antialiasing"); + checkitem.show(); + checkitem.toggled.connect (aa_mode_changed); + menu.append (checkitem); + + var mode_item = new Gtk.MenuItem(); + mode_item.show (); + mode_item.label = "mode"; + menu.append (mode_item); + + var mode_menu = new Gtk.Menu (); + + var group = new GLib.SList <Gtk.RadioMenuItem> (); + + var thesame_item = new Gtk.RadioMenuItem.with_label (group, "thesame"); + thesame_item.show(); + mode_menu.append (thesame_item); + + var waker_item = new Gtk.RadioMenuItem.with_label_from_widget (thesame_item, "waker"); + waker_item.show(); + waker_item.toggled.connect (mode_changed); + mode_menu.append (waker_item); + + mode_item.set_submenu (mode_menu); + } + + public void + aa_mode_changed (Gtk.CheckMenuItem item) + { + aa_mode = item.active; + queue_draw (); + } + + public void + mode_changed (Gtk.CheckMenuItem item) + { + set_snap (item.active); + } + + private void + set_snap (bool new_snap) + { + snap = new_snap; + + if (snap) + { + double step = 1.0 / (double)(bands+1); + + if (points.length() > 0) + { + unowned List <Point> iter; + for (iter = points.next; iter != null; iter = iter.next) + points.remove_link (iter.prev); + points.remove_link (points); + } + + for (int i = 0; i < bands; i++) + { + Point point = new Point (); + point.x = ((double)i+1)*step; + point.y = values[i]; + points.prepend (point); + } + points.reverse (); + } + } + + private Gdk.Point + abs_to_screen (double x, double y) + { + return Gdk.Point () { + x = (int)(x * (this.allocation.width-margin_left))+margin_left, + y = (int)(y * (this.allocation.height-margin_bottom)) + }; + } + + private void + abs_to_screen_d (double x, double y, out double sx, out double sy) + { + sx = (int)(x * (this.allocation.width-margin_left))+margin_left; + sy = (int)(y * (this.allocation.height-margin_bottom)); + } + +/* private double + cubic (double y0, double y1, double y2, double y3, double mu) + { + double a0,a1,a2,a3,mu2; + + mu2 = mu*mu; + a0 = y3 - y2 - y0 + y1; + a1 = y0 - y1 - a0; + a2 = y2 - y0; + a3 = y1; + + return (a0*mu*mu2+a1*mu2+a2*mu+a3); + }*/ + + private double + cubic (double y0, double y1, double y2, double y3, double mu) + { + return 0.5 *((2 * y1) + + (-y0 + y2) * mu + + (2*y0 - 5*y1 + 4*y2 - y3) * mu*mu + + (-y0 + 3*y1- 3*y2 + y3) * mu*mu*mu); + } + + public override bool + expose_event (Gdk.EventExpose event) + { + int width = this.allocation.width; + int height = this.allocation.height; + + Gdk.Point[] gpoints = new Gdk.Point [points.length()+2]; + gpoints[0] = {margin_left, (height-margin_bottom) / 2}; + int i = 1; + foreach (var p in this.points) + { + gpoints[i] = abs_to_screen (p.x, p.y); + if (gpoints[i].x >= width) + gpoints[i].x = width - 1; + i++; + } + gpoints[i] = {width-1, (height-margin_bottom) / 2}; + + Gdk.Drawable d = get_window(); + var gc = d.create_gc (Gdk.GCValues(), 0); + + gc.set_rgb_fg_color (fore_dark_color); + //drawing grid: + double step = (double)(width - margin_left) / (double)(bands+1); + for (i = 0; i < bands; i++) + { + //does anyone know why this method is static? + Gdk.draw_line (d, gc, + (int)((i+1)*step)+margin_left, + 0, + (int)((i+1)*step)+margin_left, + height - margin_bottom); + } + + //double vstep = 1.0 / (double)(height-margin_bottom); + double vstep = (double)(height-margin_bottom); + for (double di=0; di < 2; di += 0.25) + { + Gdk.draw_line (d, gc, + margin_left, + (int)((di-preamp)*vstep), + width, + (int)((di-preamp)*vstep)); + } + + gc.set_rgb_fg_color (fore_bright_color); + + //drawing freqs: + Pango.Layout l = create_pango_layout (null); + var ctx = l.get_context (); + var fd = ctx.get_font_description (); + fd.set_size (4); + fd.set_family_static ("fixed"); + ctx.set_font_description (fd); + for (i = 0; i < bands; i++) + { + l.set_text (freqs[i], (int)freqs[i].len()); + Gdk.draw_layout (d, gc, (int)((i+1)*step-5)+margin_left, height-margin_bottom+2, l); + } + + //drawing db's: + l.set_width (margin_left-1); + l.set_alignment (Pango.Alignment.RIGHT); + + if ((mouse_y != -1) && (mouse_y < height - margin_bottom)) + { + double db = scale((double)(mouse_y-1) / (double)(height - margin_bottom - 2)); + string tmp = "%.1f".printf (db); + l.set_text (tmp, (int)tmp.len()); + Gdk.draw_layout (d, gc, margin_left-1, mouse_y-3, l); + } + + string tmp = "%.1f".printf (scale (1)); + l.set_text (tmp, (int)tmp.len()); + Gdk.draw_layout (d, gc, margin_left-1, height-margin_bottom-6, l); + + tmp = "%.1f".printf (scale (0)); + l.set_text (tmp, (int)tmp.len()); + Gdk.draw_layout (d, gc, margin_left-1, 1, l); + + l.set_text ("0db", 4); + Gdk.draw_layout (d, gc, margin_left-1, (int)((1-preamp)*(height-margin_bottom))-3, l); + + l.set_text ("preamp", 6); + l.set_alignment (Pango.Alignment.LEFT); + Gdk.draw_layout (d, gc, 1, height-margin_bottom+2, l); + + d.draw_rectangle (gc, false, margin_left, 0, width-margin_left-1, height-margin_bottom-1); + gc.set_line_attributes (2, Gdk.LineStyle.SOLID, Gdk.CapStyle.NOT_LAST, Gdk.JoinStyle.MITER); + + //draw preamp + gc.set_clip_rectangle ({0, (int)(preamp * (height-margin_bottom)), 11, height}); + + gc.set_rgb_fg_color (fore_dark_color); + int count = (int)((height-margin_bottom) / 6)+1; + for (int j = 0; j < count; j++) + d.draw_rectangle ( + gc, + true, + 1, + height-margin_bottom-j*6 - 6, + 11, + 4); + + gc.set_clip_rectangle ({margin_left+1, 1, width-margin_left-2, height-margin_bottom-2}); + + //drawing bars: + gc.set_rgb_fg_color (fore_dark_color); + + int bar_w = 11; + if (step < bar_w) + bar_w = (int)step-1; + + + for (i = 0; i < bands; i++) + { + gc.set_clip_rectangle ({ + (int)((i+1)*step)+margin_left - bar_w/2, + (int)(values[i] * (height-margin_bottom)), + 11, + height}); + count = (int)((height-margin_bottom) * (1-values[i]) / 6)+1; + for (int j = 0; j < count; j++) + d.draw_rectangle ( + gc, + true, + (int)((i+1)*step)+margin_left - bar_w/2, + height-margin_bottom-j*6 - 6, + bar_w, + 4); + } + gc.set_clip_rectangle ({0, 0, width, height}); + + //drawing curve: + gc.set_rgb_fg_color (fore_bright_color); + Gdk.Point gp; + uint pcount = points.length(); + double[] ys = new double [pcount]; + double[] xs = new double [pcount]; + i=0; + foreach (var p in this.points) + { + gp = abs_to_screen (p.x, p.y); + d.draw_rectangle (gc, true, gp.x-spot_size, gp.y-spot_size, spot_size*2, spot_size*2); + xs[i] = p.x; + ys[i] = p.y; + i++; + } + + Cairo.Context cairo = aa_mode ? Gdk.cairo_create (d) : null; + + int prev_x = 0; + int prev_y = 0; + + if (pcount > 0) + { + gp = abs_to_screen (xs[0], ys[0]); + if (aa_mode) + cairo.move_to (margin_left, gp.y); + else + Gdk.draw_line (d, gc, margin_left, gp.y, gp.x, gp.y); + prev_x = gp.x; + prev_y = gp.y; + } + + if (pcount >= 2) + { + for (i = 0; i < pcount-1; i++) + { + //stdout.printf ("%d\n", (int)((xs[i+1]-xs[i])*width)); + if ((int)((xs[i+1]-xs[i])*width) <= 5) + { + Gdk.Point gp2 = abs_to_screen (xs[i], ys[i]); + gp = abs_to_screen (xs[i+1], ys[i+1]); + Gdk.draw_line (d, gc, gp2.x, gp2.y, gp.x, gp.y); + prev_x = gp2.x; + prev_y = gp2.y; + continue; + } + //int pts = (int)((double)((xs[i+1] - xs[i]) * allocation.width) / 5.0); + //step = (double)(xs[i+1] - xs[i])/(double)pts; + + double dx = (xs[i+1] - xs[i])*width; + double dy = (ys[i+1] - ys[i])*height; + int pts = (int)(GLib.Math.sqrt (dx*dx + dy*dy) / 5.0); + //stdout.printf ("%f %f %d\n", dx, dy, pts); + step = (double)(xs[i+1] - xs[i])/(double)pts; + + for (int ii = 0; ii <= pts; ii++) + { + double y; + + if (i == 0 && i == pcount-2) //case when we have only two points + y = cubic (ys[0], ys[0], ys[1], ys[1], (double)ii/(double)pts); + + else if (i == 0) + y = cubic (ys[0], ys[0], ys[1], ys[2], (double)ii/(double)pts); + + else if (i == pcount-2) + y = cubic (ys[i-1], ys[i], ys[i+1], ys[i+1], (double)ii/(double)pts); + + else + y = cubic (ys[i-1], ys[i], ys[i+1], ys[i+2], (double)ii/(double)pts); + if (y < 0) y = 0; + if (y > 1) y = 1; + + if (aa_mode) + { + double sx, sy; + abs_to_screen_d (ii*step+xs[i], y, out sx, out sy); + cairo.line_to (sx, sy); +// prev_x = gp.x; +// prev_y = gp.y; + } + else + { + gp = abs_to_screen (ii*step+xs[i], y); + + if (gp.y < 2) gp.y = 2; + if (gp.y > height-margin_bottom-2) gp.y = height-margin_bottom-2; + + Gdk.draw_point (d, gc, gp.x, gp.y); + //Gdk.draw_line (d, gc, prev_x, prev_y, gp.x, gp.y); + prev_x = gp.x; + prev_y = gp.y; + } + } + } + } + if (pcount > 0) + { +// gp = abs_to_screen (xs[0], ys[0]); +// cairo.move_to (margin_left, gp.y); +// Gdk.draw_line (d, gc, margin_left, gp.y, gp.x, gp.y); + + gp = abs_to_screen (xs[pcount-1], ys[pcount-1]); + if (aa_mode) + cairo.line_to (width-1, gp.y); + else + Gdk.draw_line (d, gc, gp.x, gp.y, width-1, gp.y); + } + if (aa_mode) + { + cairo.set_source_rgb ( + (double)fore_bright_color.red / (double)0xffff, + (double)fore_bright_color.green / (double)0xffff, + (double)fore_bright_color.blue / (double)0xffff); + cairo.stroke(); + } + if (pcount == 0) + { + Gdk.draw_line (d, gc, margin_left, (height-margin_bottom)/2, width-1, (height-margin_bottom)/2); + } + + //drawing mouse coordinates: + gc.set_line_attributes (1, Gdk.LineStyle.ON_OFF_DASH, Gdk.CapStyle.NOT_LAST, Gdk.JoinStyle.MITER); + Gdk.draw_line (d, gc, margin_left+1, mouse_y, width, mouse_y); + + return false; + } + + //FIXME: I'm not sure returning value thru instance property is good + private bool + get_point_at (double x, double y) + { + bool ret = false; + + unowned List <Point> iter; + + double ss_x = (double)spot_size / (double)allocation.width; + double ss_y = (double)spot_size / (double)allocation.height; + + for (iter = points; iter != null; iter = iter.next) + { + if (GLib.Math.fabs (iter.data.x - x) <= ss_x && + GLib.Math.fabs (iter.data.y - y) <= ss_y) + { + current_point = iter; + ret = true; + break; + } + } + return ret; + } + + private inline double + scale (double val) + { + double k = -40; + double d = 20; + return (val+preamp-0.5) * k + d; + } + + private void + recalc_values () + { + uint pcount = points.length(); + double[] ys = new double [pcount]; + double[] xs = new double [pcount]; + int i=0; + foreach (var p in this.points) + { + xs[i] = p.x; + ys[i] = p.y; + i++; + } + + if (pcount == 0) + { + for (i=0; i < bands; i++) + values[i] = 0.5; + } + else if (pcount == 1) + { + for (i=0; i < bands; i++) + values[i] = ys[0]; + } + else + { + int pi = 0; + for (i = 0; i < bands; i++) + { + double x = (double)(i+1)/(double)(bands+1); + double y = 0; + + if (xs[pi] > x) //before first point + { + values[i] = ys[pi]; + continue; + } + + if ((xs[pi+1] < x) && (pi < pcount-1)) //passed to next point + pi++; + + if (pi == pcount-1) //after last point + { + values[i] = ys[pcount-1]; + continue; + } + + if (pi == 0 && pi == pcount-2) //two-points case + y = cubic (ys[pi], ys[pi], ys[pi+1], ys[pi+1], + (x - xs[pi])/(xs[pi+1] - xs[pi])); + + else if (pi == 0) + y = cubic (ys[pi], ys[pi], ys[pi+1], ys[pi+2], + (x - xs[pi])/(xs[pi+1] - xs[pi])); + + else if (pi == pcount-2) + y = cubic (ys[pi-1], ys[pi], ys[pi+1], ys[pi+1], + (x - xs[pi])/(xs[pi+1] - xs[pi])); + + else + y = cubic (ys[pi-1], ys[pi], ys[pi+1], ys[pi+2], + (x - xs[pi])/(xs[pi+1] - xs[pi])); + if (y < 0) y = 0; + if (y > 1) y = 1; + values[i] = y; + } + } + double[] scaled_values = new double[bands]; + for (i = 0; i < bands; i++) + scaled_values[i] = scale (values[i]); + on_changed (scaled_values); + } + + private void + snap_move (double x, double y) + { + double step = 1.0 / (double)(bands+1); + int idx = (int)((x-step/2)/step); + if (idx < bands) + { + current_point = points.nth (idx); + current_point.data.y = y; + } + } + + private void + handle_curve_click (Gdk.EventButton event) + { + double x = (double)(event.x - margin_left) / (double)(allocation.width - margin_left); + double y = event.y / (double)(allocation.height - margin_bottom); + + if (event.button == 1) + { + /* Handling left button: moving points */ + if (snap) + snap_move (x, y); + else + { + if (!get_point_at (x, y)) + { + var point = new Point(); + if (points == null) + { + points.append (point); + current_point = points; + } + else if (points.data.x > x) + { + points.prepend (point); + current_point = points; + } + else + { + var found = false; + for (unowned List <Point> i = points; i.next != null; i = i.next) + if (i.data.x < x && i.next.data.x > x) + { + points.insert_before (i.next, point); + current_point = i.next; + found = true; + break; + } + if (!found) + { + points.append (point); + current_point = points.last(); + } + } + } + current_point.data.x = x; + current_point.data.y = y; + } + recalc_values(); + get_window().set_cursor (moving_cursor); + queue_draw (); + } + else if (event.button == 3) + { + /* Handling right button: removing points */ + if (snap) + return; + if (get_point_at (x, y)) + { + points.remove (current_point.data); + recalc_values(); + queue_draw (); + } + queue_draw(); + } + } + + private bool + in_curve_area (int x, int y) + { + return + x > margin_left && + x < allocation.width-1 && + y > 1 && + y < allocation.height-margin_bottom; + } + + /* Mouse button got pressed over widget */ + public override bool + button_press_event (Gdk.EventButton event) + { + if (in_curve_area ((int)event.x, (int)event.y)) + { + curve_hook = true; + handle_curve_click (event); + return false; + } + + if (event.x <= 11 && + event.y > 1 && + event.y <= allocation.height-margin_bottom && + event.button == 1 + ) + { + preamp = event.y / (double)(allocation.height - margin_bottom); + preamp_hook = true; + } + + if (event.button == 3) + { + //stdout.printf (""); + menu.popup (null, null, null, event.button, Gtk.get_current_event_time()); + } + return false; + } + + /* Mouse button got released */ + public override bool + button_release_event (Gdk.EventButton event) + { + curve_hook = false; + preamp_hook = false; + get_window().set_cursor (pointer_cursor); + return false; + } + + public override bool + leave_notify_event (Gdk.EventCrossing event) + { + mouse_y = -1; + queue_draw(); + return false; + } + + /* Mouse pointer moved over widget */ + public override bool + motion_notify_event (Gdk.EventMotion event) + { + double x = (double)(event.x - margin_left) / (double)(allocation.width - margin_left); + double y = event.y / (double)(allocation.height - margin_bottom); + if (y < 0) y = 0; + if (y > 1) y = 1; + + if (preamp_hook) + { + preamp = y; + queue_draw(); + return false; + } + + if (!in_curve_area ((int)event.x, (int)event.y)) + mouse_y = -1; + else + mouse_y = (int)event.y; + + if (curve_hook) + { + if (snap) + snap_move (x, y); + else + { + current_point.data.x = x; + + if ((current_point.prev != null) && + current_point.prev.data.x > current_point.data.x) + current_point.data.x = current_point.prev.data.x; + + + if ((current_point.next != null) && + current_point.next.data.x < current_point.data.x) + current_point.data.x = current_point.next.data.x; + + current_point.data.y = y; + + if (current_point.data.x > 1) current_point.data.x = 1; + if (current_point.data.x < 0) current_point.data.x = 0; + } + + recalc_values(); + mouse_y = (int)event.y; + queue_draw (); + } + else + { + if (!get_point_at (x, y)) + get_window().set_cursor (pointer_cursor); + else + get_window().set_cursor (moving_cursor); + queue_draw (); + } + return false; + } + + public static Graphic inst = null; + + } +} diff --git a/plugins/gtkui/test.vala b/plugins/gtkui/test.vala new file mode 100644 index 00000000..9a50c952 --- /dev/null +++ b/plugins/gtkui/test.vala @@ -0,0 +1,30 @@ +using Deadbeef; + +Graphic gr = null; + +public static bool +redraw () +{ + gr.queue_draw (); + return true; +} + +public static int +main (string[] args) +{ + Gtk.init (ref args); + var wnd = new Gtk.Window (Gtk.WindowType.TOPLEVEL); + wnd.destroy.connect (Gtk.main_quit); + + gr = new Graphic (); + Graphic.inst = gr; + wnd.add (gr); + gr.show(); + wnd.show(); + + Timeout.add (50, redraw); + + Gtk.main(); + return 0; +} + |