That's cleaner and fix a sign-compare warning in gcc. https://bugzilla.gnome.org/show_bug.cgi?id=666240
770 lines
29 KiB
C
770 lines
29 KiB
C
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
|
*
|
|
* Copyright (C) 2008 William Jon McCann <william.jon.mccann@gmail.com>
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
|
|
#include <glib.h>
|
|
#include <glib/gi18n-lib.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "gvc-level-bar.h"
|
|
|
|
#define NUM_BOXES 30
|
|
|
|
#define GVC_LEVEL_BAR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_LEVEL_BAR, GvcLevelBarPrivate))
|
|
|
|
#define MIN_HORIZONTAL_BAR_WIDTH 150
|
|
#define HORIZONTAL_BAR_HEIGHT 6
|
|
#define VERTICAL_BAR_WIDTH 6
|
|
#define MIN_VERTICAL_BAR_HEIGHT 400
|
|
|
|
typedef struct {
|
|
int peak_num;
|
|
int max_peak_num;
|
|
|
|
GdkRectangle area;
|
|
int delta;
|
|
int box_width;
|
|
int box_height;
|
|
int box_radius;
|
|
double bg_r;
|
|
double bg_g;
|
|
double bg_b;
|
|
double bdr_r;
|
|
double bdr_g;
|
|
double bdr_b;
|
|
double fl_r;
|
|
double fl_g;
|
|
double fl_b;
|
|
} LevelBarLayout;
|
|
|
|
struct GvcLevelBarPrivate
|
|
{
|
|
GtkOrientation orientation;
|
|
GtkAdjustment *peak_adjustment;
|
|
GtkAdjustment *rms_adjustment;
|
|
GvcLevelScale scale;
|
|
gdouble peak_fraction;
|
|
gdouble rms_fraction;
|
|
gdouble max_peak;
|
|
guint max_peak_id;
|
|
LevelBarLayout layout;
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_PEAK_ADJUSTMENT,
|
|
PROP_RMS_ADJUSTMENT,
|
|
PROP_SCALE,
|
|
PROP_ORIENTATION,
|
|
};
|
|
|
|
static void gvc_level_bar_class_init (GvcLevelBarClass *klass);
|
|
static void gvc_level_bar_init (GvcLevelBar *level_bar);
|
|
static void gvc_level_bar_finalize (GObject *object);
|
|
|
|
G_DEFINE_TYPE (GvcLevelBar, gvc_level_bar, GTK_TYPE_WIDGET)
|
|
|
|
#define check_rectangle(rectangle1, rectangle2) \
|
|
{ \
|
|
/* .x and .y are always 0 */ \
|
|
if (rectangle1.width != rectangle2.width) return TRUE; \
|
|
if (rectangle1.height != rectangle2.height) return TRUE; \
|
|
}
|
|
|
|
static gboolean
|
|
layout_changed (LevelBarLayout *layout1,
|
|
LevelBarLayout *layout2)
|
|
{
|
|
check_rectangle (layout1->area, layout2->area);
|
|
if (layout1->delta != layout2->delta) return TRUE;
|
|
if (layout1->peak_num != layout2->peak_num) return TRUE;
|
|
if (layout1->max_peak_num != layout2->max_peak_num) return TRUE;
|
|
if (layout1->bg_r != layout2->bg_r
|
|
|| layout1->bg_g != layout2->bg_g
|
|
|| layout1->bg_b != layout2->bg_b)
|
|
return TRUE;
|
|
if (layout1->bdr_r != layout2->bdr_r
|
|
|| layout1->bdr_g != layout2->bdr_g
|
|
|| layout1->bdr_b != layout2->bdr_b)
|
|
return TRUE;
|
|
if (layout1->fl_r != layout2->fl_r
|
|
|| layout1->fl_g != layout2->fl_g
|
|
|| layout1->fl_b != layout2->fl_b)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gdouble
|
|
fraction_from_adjustment (GvcLevelBar *bar,
|
|
GtkAdjustment *adjustment)
|
|
{
|
|
gdouble level;
|
|
gdouble fraction;
|
|
gdouble min;
|
|
gdouble max;
|
|
|
|
level = gtk_adjustment_get_value (adjustment);
|
|
|
|
min = gtk_adjustment_get_lower (adjustment);
|
|
max = gtk_adjustment_get_upper (adjustment);
|
|
|
|
switch (bar->priv->scale) {
|
|
case GVC_LEVEL_SCALE_LINEAR:
|
|
fraction = (level - min) / (max - min);
|
|
break;
|
|
case GVC_LEVEL_SCALE_LOG:
|
|
fraction = log10 ((level - min + 1) / (max - min + 1));
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
return fraction;
|
|
}
|
|
|
|
static gboolean
|
|
reset_max_peak (GvcLevelBar *bar)
|
|
{
|
|
gdouble min;
|
|
|
|
min = gtk_adjustment_get_lower (bar->priv->peak_adjustment);
|
|
bar->priv->max_peak = min;
|
|
bar->priv->layout.max_peak_num = 0;
|
|
gtk_widget_queue_draw (GTK_WIDGET (bar));
|
|
bar->priv->max_peak_id = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
bar_calc_layout (GvcLevelBar *bar)
|
|
{
|
|
GdkColor color;
|
|
int peak_level;
|
|
int max_peak_level;
|
|
GtkAllocation allocation;
|
|
GtkStyle *style;
|
|
|
|
gtk_widget_get_allocation (GTK_WIDGET (bar), &allocation);
|
|
bar->priv->layout.area.width = allocation.width - 2;
|
|
bar->priv->layout.area.height = allocation.height - 2;
|
|
|
|
style = gtk_widget_get_style (GTK_WIDGET (bar));
|
|
color = style->bg [GTK_STATE_NORMAL];
|
|
bar->priv->layout.bg_r = (float)color.red / 65535.0;
|
|
bar->priv->layout.bg_g = (float)color.green / 65535.0;
|
|
bar->priv->layout.bg_b = (float)color.blue / 65535.0;
|
|
color = style->dark [GTK_STATE_NORMAL];
|
|
bar->priv->layout.bdr_r = (float)color.red / 65535.0;
|
|
bar->priv->layout.bdr_g = (float)color.green / 65535.0;
|
|
bar->priv->layout.bdr_b = (float)color.blue / 65535.0;
|
|
color = style->bg [GTK_STATE_SELECTED];
|
|
bar->priv->layout.fl_r = (float)color.red / 65535.0;
|
|
bar->priv->layout.fl_g = (float)color.green / 65535.0;
|
|
bar->priv->layout.fl_b = (float)color.blue / 65535.0;
|
|
|
|
if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
|
|
peak_level = bar->priv->peak_fraction * bar->priv->layout.area.height;
|
|
max_peak_level = bar->priv->max_peak * bar->priv->layout.area.height;
|
|
|
|
bar->priv->layout.delta = bar->priv->layout.area.height / NUM_BOXES;
|
|
bar->priv->layout.area.x = 0;
|
|
bar->priv->layout.area.y = 0;
|
|
bar->priv->layout.box_height = bar->priv->layout.delta / 2;
|
|
bar->priv->layout.box_width = bar->priv->layout.area.width;
|
|
bar->priv->layout.box_radius = bar->priv->layout.box_width / 2;
|
|
} else {
|
|
peak_level = bar->priv->peak_fraction * bar->priv->layout.area.width;
|
|
max_peak_level = bar->priv->max_peak * bar->priv->layout.area.width;
|
|
|
|
bar->priv->layout.delta = bar->priv->layout.area.width / NUM_BOXES;
|
|
bar->priv->layout.area.x = 0;
|
|
bar->priv->layout.area.y = 0;
|
|
bar->priv->layout.box_width = bar->priv->layout.delta / 2;
|
|
bar->priv->layout.box_height = bar->priv->layout.area.height;
|
|
bar->priv->layout.box_radius = bar->priv->layout.box_height / 2;
|
|
}
|
|
|
|
/* This can happen if the level bar isn't realized */
|
|
if (bar->priv->layout.delta == 0)
|
|
return;
|
|
|
|
bar->priv->layout.peak_num = peak_level / bar->priv->layout.delta;
|
|
bar->priv->layout.max_peak_num = max_peak_level / bar->priv->layout.delta;
|
|
}
|
|
|
|
static void
|
|
update_peak_value (GvcLevelBar *bar)
|
|
{
|
|
gdouble val;
|
|
LevelBarLayout layout;
|
|
|
|
layout = bar->priv->layout;
|
|
|
|
val = fraction_from_adjustment (bar, bar->priv->peak_adjustment);
|
|
bar->priv->peak_fraction = val;
|
|
|
|
if (val > bar->priv->max_peak) {
|
|
if (bar->priv->max_peak_id > 0) {
|
|
g_source_remove (bar->priv->max_peak_id);
|
|
}
|
|
bar->priv->max_peak_id = g_timeout_add_seconds (1, (GSourceFunc)reset_max_peak, bar);
|
|
bar->priv->max_peak = val;
|
|
}
|
|
|
|
bar_calc_layout (bar);
|
|
|
|
if (layout_changed (&bar->priv->layout, &layout)) {
|
|
gtk_widget_queue_draw (GTK_WIDGET (bar));
|
|
}
|
|
}
|
|
|
|
static void
|
|
update_rms_value (GvcLevelBar *bar)
|
|
{
|
|
gdouble val;
|
|
|
|
val = fraction_from_adjustment (bar, bar->priv->rms_adjustment);
|
|
bar->priv->rms_fraction = val;
|
|
}
|
|
|
|
GtkOrientation
|
|
gvc_level_bar_get_orientation (GvcLevelBar *bar)
|
|
{
|
|
g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), 0);
|
|
return bar->priv->orientation;
|
|
}
|
|
|
|
void
|
|
gvc_level_bar_set_orientation (GvcLevelBar *bar,
|
|
GtkOrientation orientation)
|
|
{
|
|
g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
|
|
|
|
if (orientation != bar->priv->orientation) {
|
|
bar->priv->orientation = orientation;
|
|
gtk_widget_queue_draw (GTK_WIDGET (bar));
|
|
g_object_notify (G_OBJECT (bar), "orientation");
|
|
}
|
|
}
|
|
|
|
static void
|
|
on_peak_adjustment_value_changed (GtkAdjustment *adjustment,
|
|
GvcLevelBar *bar)
|
|
{
|
|
update_peak_value (bar);
|
|
}
|
|
|
|
static void
|
|
on_rms_adjustment_value_changed (GtkAdjustment *adjustment,
|
|
GvcLevelBar *bar)
|
|
{
|
|
update_rms_value (bar);
|
|
}
|
|
|
|
void
|
|
gvc_level_bar_set_peak_adjustment (GvcLevelBar *bar,
|
|
GtkAdjustment *adjustment)
|
|
{
|
|
g_return_if_fail (GVC_LEVEL_BAR (bar));
|
|
g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
|
|
|
|
if (bar->priv->peak_adjustment != NULL) {
|
|
g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment,
|
|
G_CALLBACK (on_peak_adjustment_value_changed),
|
|
bar);
|
|
g_object_unref (bar->priv->peak_adjustment);
|
|
}
|
|
|
|
bar->priv->peak_adjustment = g_object_ref_sink (adjustment);
|
|
|
|
g_signal_connect (bar->priv->peak_adjustment,
|
|
"value-changed",
|
|
G_CALLBACK (on_peak_adjustment_value_changed),
|
|
bar);
|
|
|
|
update_peak_value (bar);
|
|
|
|
g_object_notify (G_OBJECT (bar), "peak-adjustment");
|
|
}
|
|
|
|
void
|
|
gvc_level_bar_set_rms_adjustment (GvcLevelBar *bar,
|
|
GtkAdjustment *adjustment)
|
|
{
|
|
g_return_if_fail (GVC_LEVEL_BAR (bar));
|
|
g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
|
|
|
|
if (bar->priv->rms_adjustment != NULL) {
|
|
g_signal_handlers_disconnect_by_func (bar->priv->peak_adjustment,
|
|
G_CALLBACK (on_rms_adjustment_value_changed),
|
|
bar);
|
|
g_object_unref (bar->priv->rms_adjustment);
|
|
}
|
|
|
|
bar->priv->rms_adjustment = g_object_ref_sink (adjustment);
|
|
|
|
|
|
g_signal_connect (bar->priv->peak_adjustment,
|
|
"value-changed",
|
|
G_CALLBACK (on_peak_adjustment_value_changed),
|
|
bar);
|
|
|
|
update_rms_value (bar);
|
|
|
|
g_object_notify (G_OBJECT (bar), "rms-adjustment");
|
|
}
|
|
|
|
GtkAdjustment *
|
|
gvc_level_bar_get_peak_adjustment (GvcLevelBar *bar)
|
|
{
|
|
g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL);
|
|
|
|
return bar->priv->peak_adjustment;
|
|
}
|
|
|
|
GtkAdjustment *
|
|
gvc_level_bar_get_rms_adjustment (GvcLevelBar *bar)
|
|
{
|
|
g_return_val_if_fail (GVC_IS_LEVEL_BAR (bar), NULL);
|
|
|
|
return bar->priv->rms_adjustment;
|
|
}
|
|
|
|
void
|
|
gvc_level_bar_set_scale (GvcLevelBar *bar,
|
|
GvcLevelScale scale)
|
|
{
|
|
g_return_if_fail (GVC_IS_LEVEL_BAR (bar));
|
|
|
|
if (scale != bar->priv->scale) {
|
|
bar->priv->scale = scale;
|
|
|
|
update_peak_value (bar);
|
|
update_rms_value (bar);
|
|
|
|
g_object_notify (G_OBJECT (bar), "scale");
|
|
}
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GvcLevelBar *self = GVC_LEVEL_BAR (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_SCALE:
|
|
gvc_level_bar_set_scale (self, g_value_get_int (value));
|
|
break;
|
|
case PROP_ORIENTATION:
|
|
gvc_level_bar_set_orientation (self, g_value_get_enum (value));
|
|
break;
|
|
case PROP_PEAK_ADJUSTMENT:
|
|
gvc_level_bar_set_peak_adjustment (self, g_value_get_object (value));
|
|
break;
|
|
case PROP_RMS_ADJUSTMENT:
|
|
gvc_level_bar_set_rms_adjustment (self, g_value_get_object (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GvcLevelBar *self = GVC_LEVEL_BAR (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_SCALE:
|
|
g_value_set_int (value, self->priv->scale);
|
|
break;
|
|
case PROP_ORIENTATION:
|
|
g_value_set_enum (value, self->priv->orientation);
|
|
break;
|
|
case PROP_PEAK_ADJUSTMENT:
|
|
g_value_set_object (value, self->priv->peak_adjustment);
|
|
break;
|
|
case PROP_RMS_ADJUSTMENT:
|
|
g_value_set_object (value, self->priv->rms_adjustment);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static GObject *
|
|
gvc_level_bar_constructor (GType type,
|
|
guint n_construct_properties,
|
|
GObjectConstructParam *construct_params)
|
|
{
|
|
return G_OBJECT_CLASS (gvc_level_bar_parent_class)->constructor (type, n_construct_properties, construct_params);
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_size_request (GtkWidget *widget,
|
|
GtkRequisition *requisition)
|
|
{
|
|
GvcLevelBar *bar = GVC_LEVEL_BAR (widget);
|
|
|
|
switch (bar->priv->orientation) {
|
|
case GTK_ORIENTATION_VERTICAL:
|
|
requisition->width = VERTICAL_BAR_WIDTH;
|
|
requisition->height = MIN_VERTICAL_BAR_HEIGHT;
|
|
break;
|
|
case GTK_ORIENTATION_HORIZONTAL:
|
|
requisition->width = MIN_HORIZONTAL_BAR_WIDTH;
|
|
requisition->height = HORIZONTAL_BAR_HEIGHT;
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_get_preferred_width (GtkWidget *widget,
|
|
gint *minimum,
|
|
gint *natural)
|
|
{
|
|
GtkRequisition requisition;
|
|
|
|
gvc_level_bar_size_request (widget, &requisition);
|
|
|
|
if (minimum != NULL) {
|
|
*minimum = requisition.width;
|
|
}
|
|
if (natural != NULL) {
|
|
*natural = requisition.width;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_get_preferred_height (GtkWidget *widget,
|
|
gint *minimum,
|
|
gint *natural)
|
|
{
|
|
GtkRequisition requisition;
|
|
|
|
gvc_level_bar_size_request (widget, &requisition);
|
|
|
|
if (minimum != NULL) {
|
|
*minimum = requisition.height;
|
|
}
|
|
if (natural != NULL) {
|
|
*natural = requisition.height;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation)
|
|
{
|
|
GvcLevelBar *bar;
|
|
|
|
g_return_if_fail (GVC_IS_LEVEL_BAR (widget));
|
|
g_return_if_fail (allocation != NULL);
|
|
|
|
bar = GVC_LEVEL_BAR (widget);
|
|
|
|
/* FIXME: add height property, labels, etc */
|
|
GTK_WIDGET_CLASS (gvc_level_bar_parent_class)->size_allocate (widget, allocation);
|
|
|
|
gtk_widget_set_allocation (widget, allocation);
|
|
gtk_widget_get_allocation (widget, allocation);
|
|
|
|
if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
|
|
allocation->height = MIN (allocation->height, MIN_VERTICAL_BAR_HEIGHT);
|
|
allocation->width = MAX (allocation->width, VERTICAL_BAR_WIDTH);
|
|
} else {
|
|
allocation->width = MIN (allocation->width, MIN_HORIZONTAL_BAR_WIDTH);
|
|
allocation->height = MAX (allocation->height, HORIZONTAL_BAR_HEIGHT);
|
|
}
|
|
|
|
bar_calc_layout (bar);
|
|
}
|
|
|
|
static void
|
|
curved_rectangle (cairo_t *cr,
|
|
double x0,
|
|
double y0,
|
|
double width,
|
|
double height,
|
|
double radius)
|
|
{
|
|
double x1;
|
|
double y1;
|
|
|
|
x1 = x0 + width;
|
|
y1 = y0 + height;
|
|
|
|
if (!width || !height) {
|
|
return;
|
|
}
|
|
|
|
if (width / 2 < radius) {
|
|
if (height / 2 < radius) {
|
|
cairo_move_to (cr, x0, (y0 + y1) / 2);
|
|
cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1) / 2, y0);
|
|
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
|
|
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
|
|
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
|
|
} else {
|
|
cairo_move_to (cr, x0, y0 + radius);
|
|
cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
|
|
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
|
|
cairo_line_to (cr, x1, y1 - radius);
|
|
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
|
|
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
|
|
}
|
|
} else {
|
|
if (height / 2 < radius) {
|
|
cairo_move_to (cr, x0, (y0 + y1) / 2);
|
|
cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0);
|
|
cairo_line_to (cr, x1 - radius, y0);
|
|
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
|
|
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
|
|
cairo_line_to (cr, x0 + radius, y1);
|
|
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
|
|
} else {
|
|
cairo_move_to (cr, x0, y0 + radius);
|
|
cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
|
|
cairo_line_to (cr, x1 - radius, y0);
|
|
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
|
|
cairo_line_to (cr, x1, y1 - radius);
|
|
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
|
|
cairo_line_to (cr, x0 + radius, y1);
|
|
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
|
|
}
|
|
}
|
|
|
|
cairo_close_path (cr);
|
|
}
|
|
|
|
static int
|
|
gvc_level_bar_draw (GtkWidget *widget,
|
|
cairo_t *cr)
|
|
{
|
|
GvcLevelBar *bar;
|
|
|
|
g_return_val_if_fail (GVC_IS_LEVEL_BAR (widget), FALSE);
|
|
|
|
bar = GVC_LEVEL_BAR (widget);
|
|
|
|
if (bar->priv->orientation == GTK_ORIENTATION_VERTICAL) {
|
|
int i;
|
|
int by;
|
|
|
|
for (i = 0; i < NUM_BOXES; i++) {
|
|
by = i * bar->priv->layout.delta;
|
|
curved_rectangle (cr,
|
|
bar->priv->layout.area.x + 0.5,
|
|
by + 0.5,
|
|
bar->priv->layout.box_width - 1,
|
|
bar->priv->layout.box_height - 1,
|
|
bar->priv->layout.box_radius);
|
|
if ((bar->priv->layout.max_peak_num - 1) == i) {
|
|
/* fill peak foreground */
|
|
cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b);
|
|
cairo_fill_preserve (cr);
|
|
} else if ((bar->priv->layout.peak_num - 1) >= i) {
|
|
/* fill background */
|
|
cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
|
|
cairo_fill_preserve (cr);
|
|
/* fill foreground */
|
|
cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5);
|
|
cairo_fill_preserve (cr);
|
|
} else {
|
|
/* fill background */
|
|
cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
|
|
cairo_fill_preserve (cr);
|
|
}
|
|
|
|
/* stroke border */
|
|
cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b);
|
|
cairo_set_line_width (cr, 1);
|
|
cairo_stroke (cr);
|
|
}
|
|
|
|
} else {
|
|
int i;
|
|
int bx;
|
|
|
|
for (i = 0; i < NUM_BOXES; i++) {
|
|
bx = i * bar->priv->layout.delta;
|
|
curved_rectangle (cr,
|
|
bx + 0.5,
|
|
bar->priv->layout.area.y + 0.5,
|
|
bar->priv->layout.box_width - 1,
|
|
bar->priv->layout.box_height - 1,
|
|
bar->priv->layout.box_radius);
|
|
|
|
if ((bar->priv->layout.max_peak_num - 1) == i) {
|
|
/* fill peak foreground */
|
|
cairo_set_source_rgb (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b);
|
|
cairo_fill_preserve (cr);
|
|
} else if ((bar->priv->layout.peak_num - 1) >= i) {
|
|
/* fill background */
|
|
cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
|
|
cairo_fill_preserve (cr);
|
|
/* fill foreground */
|
|
cairo_set_source_rgba (cr, bar->priv->layout.fl_r, bar->priv->layout.fl_g, bar->priv->layout.fl_b, 0.5);
|
|
cairo_fill_preserve (cr);
|
|
} else {
|
|
/* fill background */
|
|
cairo_set_source_rgb (cr, bar->priv->layout.bg_r, bar->priv->layout.bg_g, bar->priv->layout.bg_b);
|
|
cairo_fill_preserve (cr);
|
|
}
|
|
|
|
/* stroke border */
|
|
cairo_set_source_rgb (cr, bar->priv->layout.bdr_r, bar->priv->layout.bdr_g, bar->priv->layout.bdr_b);
|
|
cairo_set_line_width (cr, 1);
|
|
cairo_stroke (cr);
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_class_init (GvcLevelBarClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->constructor = gvc_level_bar_constructor;
|
|
object_class->finalize = gvc_level_bar_finalize;
|
|
object_class->set_property = gvc_level_bar_set_property;
|
|
object_class->get_property = gvc_level_bar_get_property;
|
|
|
|
widget_class->draw = gvc_level_bar_draw;
|
|
widget_class->get_preferred_width = gvc_level_bar_get_preferred_width;
|
|
widget_class->get_preferred_height = gvc_level_bar_get_preferred_height;
|
|
widget_class->size_allocate = gvc_level_bar_size_allocate;
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_ORIENTATION,
|
|
g_param_spec_enum ("orientation",
|
|
"Orientation",
|
|
"The orientation of the bar",
|
|
GTK_TYPE_ORIENTATION,
|
|
GTK_ORIENTATION_HORIZONTAL,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property (object_class,
|
|
PROP_PEAK_ADJUSTMENT,
|
|
g_param_spec_object ("peak-adjustment",
|
|
"Peak Adjustment",
|
|
"The GtkAdjustment that contains the current peak value",
|
|
GTK_TYPE_ADJUSTMENT,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property (object_class,
|
|
PROP_RMS_ADJUSTMENT,
|
|
g_param_spec_object ("rms-adjustment",
|
|
"RMS Adjustment",
|
|
"The GtkAdjustment that contains the current rms value",
|
|
GTK_TYPE_ADJUSTMENT,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property (object_class,
|
|
PROP_SCALE,
|
|
g_param_spec_int ("scale",
|
|
"Scale",
|
|
"Scale",
|
|
0,
|
|
G_MAXINT,
|
|
GVC_LEVEL_SCALE_LINEAR,
|
|
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
|
|
|
|
g_type_class_add_private (klass, sizeof (GvcLevelBarPrivate));
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_init (GvcLevelBar *bar)
|
|
{
|
|
bar->priv = GVC_LEVEL_BAR_GET_PRIVATE (bar);
|
|
|
|
bar->priv->peak_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
|
|
0.0,
|
|
1.0,
|
|
0.05,
|
|
0.1,
|
|
0.1));
|
|
g_object_ref_sink (bar->priv->peak_adjustment);
|
|
g_signal_connect (bar->priv->peak_adjustment,
|
|
"value-changed",
|
|
G_CALLBACK (on_peak_adjustment_value_changed),
|
|
bar);
|
|
|
|
bar->priv->rms_adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0,
|
|
0.0,
|
|
1.0,
|
|
0.05,
|
|
0.1,
|
|
0.1));
|
|
g_object_ref_sink (bar->priv->rms_adjustment);
|
|
g_signal_connect (bar->priv->rms_adjustment,
|
|
"value-changed",
|
|
G_CALLBACK (on_rms_adjustment_value_changed),
|
|
bar);
|
|
|
|
gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE);
|
|
}
|
|
|
|
static void
|
|
gvc_level_bar_finalize (GObject *object)
|
|
{
|
|
GvcLevelBar *bar;
|
|
|
|
g_return_if_fail (object != NULL);
|
|
g_return_if_fail (GVC_IS_LEVEL_BAR (object));
|
|
|
|
bar = GVC_LEVEL_BAR (object);
|
|
|
|
if (bar->priv->max_peak_id > 0) {
|
|
g_source_remove (bar->priv->max_peak_id);
|
|
}
|
|
|
|
g_return_if_fail (bar->priv != NULL);
|
|
|
|
G_OBJECT_CLASS (gvc_level_bar_parent_class)->finalize (object);
|
|
}
|
|
|
|
GtkWidget *
|
|
gvc_level_bar_new (void)
|
|
{
|
|
GObject *bar;
|
|
bar = g_object_new (GVC_TYPE_LEVEL_BAR,
|
|
NULL);
|
|
return GTK_WIDGET (bar);
|
|
}
|