Logo Search packages:      
Sourcecode: baycomepp version File versions  Download package

widgets.c

/* 
 * Custom Widgets
 * Copyright (C) 1999 Thomas Sailer <sailer@ife.ee.ethz.ch>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <math.h>
#include "widgets.h"
#include <gtk/gtkgc.h>
#include <gtk/gtkmain.h>

#define SCOPEMAXPOINTS 512
#define PRIO G_PRIORITY_LOW

struct _ScopePoint {
      guint16 dx;
      guint16 y;
};

static void scope_class_init(ScopeClass *klass);
static void scope_init(Scope *trace);
static void scope_finalize(GtkObject *object);
static gint scope_expose(GtkWidget *widget, GdkEventExpose *event);
static void scope_size_request(GtkWidget *widget, GtkRequisition *requisition);
static gint scope_idle_callback(gpointer data);

static GtkWidgetClass *scope_parent_class = NULL;
static ScopeClass *scope_class = NULL;


guint scope_get_type(void)
{
      static guint trace_type = 0;

      if (!trace_type)
      {
            static const GtkTypeInfo trace_info =
            {
                  "Scope",
                  sizeof(Scope),
                  sizeof(ScopeClass),
                  (GtkClassInitFunc) scope_class_init,
                  (GtkObjectInitFunc) scope_init,
                  /* reserved_1 */ NULL,
                  /* reserved_2 */ NULL,
                  (GtkClassInitFunc) NULL,
            };
            trace_type = gtk_type_unique(gtk_widget_get_type(), &trace_info);
      }
      return trace_type;
}

static void scope_class_init(ScopeClass *klass)
{
      GtkObjectClass *object_class;
      GtkWidgetClass *widget_class;

      object_class = (GtkObjectClass*)klass;
      widget_class = (GtkWidgetClass*)klass;

      scope_parent_class = gtk_type_class(gtk_widget_get_type());
      scope_class = klass;

      object_class->finalize = scope_finalize;
      widget_class->size_request = scope_size_request;
      widget_class->expose_event = scope_expose;
}

static void scope_init(Scope *trace)
{
      GTK_WIDGET_SET_FLAGS(trace, GTK_NO_WINDOW);

      trace->idlefunc = 0;

      /* initialize the colors */
      trace->zerolinecol.red = 65535;
      trace->zerolinecol.green = 13107;
      trace->zerolinecol.blue = 0;
      trace->samplingcol.red = 13763;
      trace->samplingcol.green = 42598;
      trace->samplingcol.blue = 5243;
      trace->zeroline_gc = trace->sampling_gc = NULL;
      /* initialize the trace history */
      trace->ptnum = trace->ptptr = 0;
      trace->pt = NULL;
}


static void scope_size_request(GtkWidget *widget, GtkRequisition *requisition)
{
      Scope *trace;
  
      g_return_if_fail(widget != NULL);
      g_return_if_fail(IS_SCOPE(widget));
      g_return_if_fail(requisition != NULL);
      trace = SCOPE(widget);
      requisition->width = MIN(trace->ptnum * 4, 512);
      requisition->height = 256;
}


GtkWidget* scope_new(char *name, char *str1, char *str2, gint int1, gint int2)
{
      Scope *trace;

      trace = gtk_type_new(scope_get_type());
      trace->ptnum = CLAMP(int1, 2, SCOPEMAXPOINTS);;
      trace->pt = g_malloc0(trace->ptnum * sizeof(struct _ScopePoint));
      return GTK_WIDGET(trace);
}

static void scope_finalize(GtkObject *object)
{
      Scope *trace;

      g_return_if_fail(object != NULL);
      g_return_if_fail(IS_SCOPE(object));
      trace = SCOPE(object);
      if (trace->idlefunc)
            gtk_idle_remove(trace->idlefunc);
      if (trace->zeroline_gc)
            gtk_gc_release(trace->zeroline_gc);
      if (trace->sampling_gc)
            gtk_gc_release(trace->sampling_gc);
      if (trace->pt)
            g_free(trace->pt);
      (*GTK_OBJECT_CLASS(scope_parent_class)->finalize)(object);
}

static gint scope_expose(GtkWidget *widget, GdkEventExpose *event)
{
      Scope *trace;

      g_return_val_if_fail(widget != NULL, FALSE);
      g_return_val_if_fail(IS_SCOPE(widget), FALSE);
      g_return_val_if_fail (event != NULL, FALSE);
      if (GTK_WIDGET_DRAWABLE(widget)) {
            trace = SCOPE(widget);
            if (!trace->idlefunc)
                  trace->idlefunc = gtk_idle_add_priority(PRIO, scope_idle_callback, trace);
      }
      return FALSE;
}

static void scope_draw(Scope *trace)
{
      GdkGCValues gc_values;
      guint totx, idx, i, si;
      guint32 mulx, muly, zeroy, x;
      GdkPoint p[SCOPEMAXPOINTS+1];
      GdkSegment s[SCOPEMAXPOINTS];

      /* init gc's if necessary */
      if (!trace->zeroline_gc) {
            if (!gdk_color_alloc(trace->widget.style->colormap, &trace->zerolinecol))
                  g_warning("unable to allocate color: ( %d %d %d )",
                          trace->zerolinecol.red, trace->zerolinecol.green, trace->zerolinecol.blue);
            gc_values.foreground = trace->zerolinecol;
            trace->zeroline_gc = gtk_gc_get(trace->widget.style->depth, 
                                    trace->widget.style->colormap,
                                    &gc_values, GDK_GC_FOREGROUND);
      }
      if (!trace->sampling_gc) {
            if (!gdk_color_alloc(trace->widget.style->colormap, &trace->samplingcol))
                  g_warning("unable to allocate color: ( %d %d %d )",
                          trace->samplingcol.red, trace->samplingcol.green, trace->samplingcol.blue);
            gc_values.foreground = trace->samplingcol;
            trace->sampling_gc = gtk_gc_get(trace->widget.style->depth,
                                    trace->widget.style->colormap,
                                    &gc_values, GDK_GC_FOREGROUND);
      }
      /* first determine the total x size and calculate multiplication factors */
      for (totx = 0, idx = trace->ptptr, i = 1; i < trace->ptnum; i++) {
            idx++;
            if (idx >= trace->ptnum)
                  idx = 0;
            totx += trace->pt[idx].dx & 0x7fff;
      }
      mulx = (((guint32)trace->widget.allocation.width) << 16) / MAX(totx, 1);
      muly = trace->widget.allocation.height;
      zeroy = (0x8000 * muly) >> 16;
      /* prepare sampling ticks and lines */
      for (si = x = i = 0, idx = trace->ptptr; i < trace->ptnum; i++) {
            p[i].x = trace->widget.allocation.x + ((x * mulx) >> 16);
            p[i].y = trace->widget.allocation.y + ((trace->pt[idx].y * muly) >> 16);
            if (trace->pt[idx].dx & 0x8000) {
                  s[si].x1 = s[si].x2 = p[i].x;
                  s[si].y1 = trace->widget.allocation.y + zeroy - 4;
                  s[si].y2 = trace->widget.allocation.y + zeroy + 4;
                  si++;
            }
            idx++;
            if (idx >= trace->ptnum)
                  idx = 0;
            x += trace->pt[idx].dx & 0x7fff;
      }
      /* now draw everything */
      gdk_draw_rectangle(trace->widget.window, trace->widget.style->base_gc[trace->widget.state],
                     TRUE, trace->widget.allocation.x, trace->widget.allocation.y, 
                     trace->widget.allocation.x+trace->widget.allocation.width, 
                     trace->widget.allocation.y+trace->widget.allocation.height);
      gdk_draw_line(trace->widget.window, trace->zeroline_gc, 
                  trace->widget.allocation.x,
                  trace->widget.allocation.y+zeroy, 
                  trace->widget.allocation.x+trace->widget.allocation.width-1, 
                  trace->widget.allocation.y+zeroy);
      gdk_draw_segments(trace->widget.window, trace->sampling_gc, s, si);
      gdk_draw_lines(trace->widget.window, trace->widget.style->fg_gc[trace->widget.state],
                   p, trace->ptnum);
}


static gint scope_idle_callback(gpointer data)
{
      g_return_val_if_fail(data != NULL, FALSE);
      g_return_val_if_fail(IS_SCOPE(data), FALSE);
      SCOPE(data)->idlefunc = 0;
      if (!GTK_WIDGET_DRAWABLE(GTK_WIDGET(data)))
            return FALSE;
      if (!SCOPE(data)->pt || !SCOPE(data)->ptnum)
            return FALSE;
      scope_draw(SCOPE(data));
      return FALSE;  /* don't call this callback again */
}


void scope_addvalue(Scope *trace, guint16 deltax, gint16 y, guint flags)
{
      g_return_if_fail(trace != NULL);
      g_return_if_fail(IS_SCOPE(trace));
      trace->pt[trace->ptptr].y = 32767-y;
      trace->pt[trace->ptptr].dx = deltax & 0x7fff;
      if (flags)
            trace->pt[trace->ptptr].dx |= 0x8000;
      trace->ptptr++;
      if (trace->ptptr >= trace->ptnum)
            trace->ptptr = 0;
      if (GTK_WIDGET_DRAWABLE(GTK_WIDGET(trace))) {
            if (!trace->idlefunc)
                  trace->idlefunc = gtk_idle_add_priority(PRIO, scope_idle_callback, trace);
      }
}

void scope_addvalues(Scope *trace, guint num, guint16 *deltax, gint16 *y)
{
      guint i;

      g_return_if_fail(trace != NULL);
      g_return_if_fail(IS_SCOPE(trace));
      g_return_if_fail(y != NULL);
      for (i = 0; i < num; i++) {
            trace->pt[trace->ptptr].y = 32767-y[i];
            trace->pt[trace->ptptr].dx = deltax ? (deltax[i] & 0x7fff) : 1;
            trace->ptptr++;
            if (trace->ptptr >= trace->ptnum)
                  trace->ptptr = 0;
      }
      if (GTK_WIDGET_DRAWABLE(GTK_WIDGET(trace))) {
            if (!trace->idlefunc)
                  trace->idlefunc = gtk_idle_add_priority(PRIO, scope_idle_callback, trace);
      }
}


/* ---------------------------------------------------------------------- */

/*
 * This fft routine is from ~gabriel/src/filters/fft/fft.c;
 * I am unsure of the original source.  The file contains no
 * copyright notice or description.
 * The declaration is changed to the prototype form but the
 * function body is unchanged.  (J. T. Buck)
 */

#define SWAP(a, b) tempr=(a); (a)=(b); (b)=tempr

/*
 * Replace data by its discrete Fourier transform, if isign is
 * input as 1, or by its inverse discrete Fourier transform, if 
 * "isign" is input as -1.  "data'"is a complex array of length "nn",
 * input as a real array data[0..2*nn-1]. "nn" MUST be an integer
 * power of 2 (this is not checked for!?)
 */

static void fft_rif(float *data, int nn, int isign) {
        int n;
        int mmax;
        int m, j, istep, i;
        float wtemp, wr, wpr, wpi, wi, theta;
        float tempr, tempi;

        data--;
        n = nn << 1;
        j = 1;

        for (i = 1; i < n; i += 2) {
                if(j > i) {
                        SWAP(data[j], data[i]);
                        SWAP(data[j+1], data[i+1]);
                }
                m= n >> 1;
                while (m >= 2 && j >m) {
                        j -= m;
                        m >>= 1;
                }
                j += m;
        }
        mmax = 2;
        while (n > mmax) {
                istep = 2*mmax;
                theta = -6.28318530717959/(isign*mmax);
                wtemp = sin(0.5*theta);
                wpr = -2.0*wtemp*wtemp;
                wpi = sin(theta);
                wr = 1.0;
                wi = 0.0;
                for (m = 1; m < mmax; m += 2) {
                        for (i = m; i < n; i += istep) {
                                j = i + mmax;
                                tempr = wr*data[j] - wi*data[j+1];
                                tempi = wr*data[j+1] + wi*data[j];
                                data[j] = data[i] - tempr;
                                data[j+1] = data[i+1] - tempi;
                                data[i] += tempr;
                                data[i+1] += tempi;
                        }
                        wr = (wtemp=wr)*wpr - wi*wpi+wr;
                        wi = wi*wpr + wtemp*wpi + wi;
                }
                mmax = istep;
        }
}
        
#undef SWAP

static inline float hamming(float x)
{
        return 0.54-0.46*cos(2*M_PI*x);
}

/* ---------------------------------------------------------------------- */

#define SPECTRUMMAXPOINTS 1024

static void spectrum_class_init(SpectrumClass *klass);
static void spectrum_init(Spectrum *trace);
static void spectrum_finalize(GtkObject *object);
static gint spectrum_expose(GtkWidget *widget, GdkEventExpose *event);
static void spectrum_size_request(GtkWidget *widget, GtkRequisition *requisition);
static gint spectrum_idle_callback(gpointer data);

static GtkWidgetClass *spectrum_parent_class = NULL;
static SpectrumClass *spectrum_class = NULL;


guint spectrum_get_type(void)
{
      static guint trace_type = 0;

      if (!trace_type)
      {
            static const GtkTypeInfo trace_info =
            {
                  "Spectrum",
                  sizeof(Spectrum),
                  sizeof(SpectrumClass),
                  (GtkClassInitFunc) spectrum_class_init,
                  (GtkObjectInitFunc) spectrum_init,
                  /* reserved_1 */ NULL,
                  /* reserved_2 */ NULL,
                  (GtkClassInitFunc) NULL,
            };
            trace_type = gtk_type_unique(gtk_widget_get_type(), &trace_info);
      }
      return trace_type;
}

static void spectrum_class_init(SpectrumClass *klass)
{
      GtkObjectClass *object_class;
      GtkWidgetClass *widget_class;

      object_class = (GtkObjectClass*)klass;
      widget_class = (GtkWidgetClass*)klass;

      spectrum_parent_class = gtk_type_class(gtk_widget_get_type());
      spectrum_class = klass;

      object_class->finalize = spectrum_finalize;
      widget_class->size_request = spectrum_size_request;
      widget_class->expose_event = spectrum_expose;
}

static void spectrum_init(Spectrum *trace)
{
      GTK_WIDGET_SET_FLAGS(trace, GTK_NO_WINDOW);

      trace->idlefunc = 0;

      /* initialize the colors */
      trace->gridcol.red = 65535;
      trace->gridcol.green = 13107;
      trace->gridcol.blue = 0;
      trace->samplingcol.red = 13763;
      trace->samplingcol.green = 42598;
      trace->samplingcol.blue = 5243;
      trace->grid_gc = trace->sampling_gc = NULL;
      /* initialize the trace history */
      trace->ptnum = trace->ptptr = 0;
      trace->pt = NULL;
}


static void spectrum_size_request(GtkWidget *widget, GtkRequisition *requisition)
{
      Spectrum *trace;
  
      g_return_if_fail(widget != NULL);
      g_return_if_fail(IS_SPECTRUM(widget));
      g_return_if_fail(requisition != NULL);
      trace = SPECTRUM(widget);
      requisition->width = MIN(trace->ptnum * 4, 512);
      requisition->height = 256;
}


GtkWidget* spectrum_new(char *name, char *str1, char *str2, gint int1, gint int2)
{
      guint i, j;
      Spectrum *trace;

      trace = gtk_type_new(spectrum_get_type());
      i = CLAMP(int1, 4, SPECTRUMMAXPOINTS);
      j = 0;
      while (i > 1) {
            i >>= 1;
            j++;
      }
      trace->ptnum = 1 << j;
            trace->pt = g_malloc0(trace->ptnum * sizeof(gint16));
      return GTK_WIDGET(trace);
}

static void spectrum_finalize(GtkObject *object)
{
      Spectrum *trace;

      g_return_if_fail(object != NULL);
      g_return_if_fail(IS_SPECTRUM(object));
      trace = SPECTRUM(object);
      if (trace->idlefunc)
            gtk_idle_remove(trace->idlefunc);
      if (trace->grid_gc)
            gtk_gc_release(trace->grid_gc);
      if (trace->sampling_gc)
            gtk_gc_release(trace->sampling_gc);
      if (trace->pt)
            g_free(trace->pt);
      (*GTK_OBJECT_CLASS(spectrum_parent_class)->finalize)(object);
}

static gint spectrum_expose(GtkWidget *widget, GdkEventExpose *event)
{
      Spectrum *trace;

      g_return_val_if_fail(widget != NULL, FALSE);
      g_return_val_if_fail(IS_SPECTRUM(widget), FALSE);
      g_return_val_if_fail (event != NULL, FALSE);
      if (GTK_WIDGET_DRAWABLE(widget)) {
            trace = SPECTRUM(widget);
            if (!trace->idlefunc)
                  trace->idlefunc = gtk_idle_add_priority(PRIO, spectrum_idle_callback, trace);
      }
      return FALSE;
}

static void spectrum_draw(Spectrum *trace)
{
      GdkGCValues gc_values;
      guint idx, i;
      guint32 mulx;
      gint y;
      GdkPoint p[SPECTRUMMAXPOINTS/2+1];
      float f[2*SPECTRUMMAXPOINTS];
      float ftmp1, ftmp2, ftmp3;

      /* init gc's if necessary */
      if (!trace->grid_gc) {
            if (!gdk_color_alloc(trace->widget.style->colormap, &trace->gridcol))
                  g_warning("unable to allocate color: ( %d %d %d )",
                          trace->gridcol.red, trace->gridcol.green, trace->gridcol.blue);
            gc_values.foreground = trace->gridcol;
            trace->grid_gc = gtk_gc_get(trace->widget.style->depth, 
                                  trace->widget.style->colormap,
                                  &gc_values, GDK_GC_FOREGROUND);
      }
      if (!trace->sampling_gc) {
            if (!gdk_color_alloc(trace->widget.style->colormap, &trace->samplingcol))
                  g_warning("unable to allocate color: ( %d %d %d )",
                          trace->samplingcol.red, trace->samplingcol.green, trace->samplingcol.blue);
            gc_values.foreground = trace->samplingcol;
            trace->sampling_gc = gtk_gc_get(trace->widget.style->depth,
                                    trace->widget.style->colormap,
                                    &gc_values, GDK_GC_FOREGROUND);
      }
      /* first determine the total x size and calculate multiplication factors */
      ftmp1 = 1.0 / (float)trace->ptnum;
      for (idx = trace->ptptr, i = 0; i < trace->ptnum; i++) {
            f[2*i] = trace->pt[idx] * hamming((float)i * ftmp1);
            f[2*i+1] = 0;
            idx++;
            if (idx >= trace->ptnum)
                  idx = 0;
      }
      fft_rif(f, trace->ptnum, 1);
      mulx = (((guint32)trace->widget.allocation.width) << 17) / trace->ptnum;
      /* prepare sampling ticks and lines */
      ftmp2 = trace->widget.allocation.height * 0.0723824136504;  /* 1/ln(10^6) */
      ftmp3 = 21.4875015613 + 4.6;
      for (i = 0; i < trace->ptnum / 2; i++) {
            ftmp1 = f[2*i] * f[2*i] + f[2*i+1] * f[2*i+1];
            if (ftmp1 < 2168)
                  p[i].y = trace->widget.allocation.y + trace->widget.allocation.height - 1;
            else {
                  y = ftmp2 * (ftmp3 - log(ftmp1));
                  y = CLAMP(y, 0, trace->widget.allocation.height-1);
                  p[i].y = trace->widget.allocation.y + y;
            }
            p[i].x = trace->widget.allocation.x + ((i * mulx) >> 16);
      }
      /* now draw everything */
      gdk_draw_rectangle(trace->widget.window, trace->widget.style->base_gc[trace->widget.state],
                     TRUE, trace->widget.allocation.x, trace->widget.allocation.y, 
                     trace->widget.allocation.x+trace->widget.allocation.width, 
                     trace->widget.allocation.y+trace->widget.allocation.height);
      for (i = 0; i < 3; i++)
            gdk_draw_line(trace->widget.window, trace->grid_gc, 
                        trace->widget.allocation.x,
                        trace->widget.allocation.y+i*(trace->widget.allocation.height/3), 
                        trace->widget.allocation.x+trace->widget.allocation.width-1,
                        trace->widget.allocation.y+i*(trace->widget.allocation.height/3));
      gdk_draw_line(trace->widget.window, trace->grid_gc, 
                  trace->widget.allocation.x,
                  trace->widget.allocation.y+trace->widget.allocation.height-1, 
                  trace->widget.allocation.x+trace->widget.allocation.width-1,
                  trace->widget.allocation.y+trace->widget.allocation.height-1);
      gdk_draw_lines(trace->widget.window, trace->widget.style->fg_gc[trace->widget.state],
                   p, trace->ptnum / 2);
}


static gint spectrum_idle_callback(gpointer data)
{
      g_return_val_if_fail(data != NULL, FALSE);
      g_return_val_if_fail(IS_SPECTRUM(data), FALSE);
      SPECTRUM(data)->idlefunc = 0;
      if (!GTK_WIDGET_DRAWABLE(GTK_WIDGET(data)))
            return FALSE;
      if (!SPECTRUM(data)->pt || !SPECTRUM(data)->ptnum)
            return FALSE;
      spectrum_draw(SPECTRUM(data));
      return FALSE;  /* don't call this callback again */
}


void spectrum_addvalue(Spectrum *trace, gint16 y)
{
      g_return_if_fail(trace != NULL);
      g_return_if_fail(IS_SPECTRUM(trace));
      trace->pt[trace->ptptr] = y;
      trace->ptptr++;
      if (trace->ptptr >= trace->ptnum)
            trace->ptptr = 0;
      if (GTK_WIDGET_DRAWABLE(GTK_WIDGET(trace))) {
            if (!trace->idlefunc)
                  trace->idlefunc = gtk_idle_add_priority(PRIO, spectrum_idle_callback, trace);
      }
}

void spectrum_addvalues(Spectrum *trace, guint num, gint16 *y)
{
      guint i;

      g_return_if_fail(trace != NULL);
      g_return_if_fail(IS_SPECTRUM(trace));
      g_return_if_fail(y != NULL);
      for (i = 0; i < num; i++) {
            trace->pt[trace->ptptr] = y[i];
            trace->ptptr++;
            if (trace->ptptr >= trace->ptnum)
                  trace->ptptr = 0;
      }
      if (GTK_WIDGET_DRAWABLE(GTK_WIDGET(trace))) {
            if (!trace->idlefunc)
                  trace->idlefunc = gtk_idle_add_priority(PRIO, spectrum_idle_callback, trace);
      }
}

Generated by  Doxygen 1.6.0   Back to index