⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gtkcurve.c

📁 gtk是linux一款强大的夸平台的图形化开发工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/* GTK - The GIMP Toolkit * Copyright (C) 1997 David Mosberger * * 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. *//* * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS * file for a list of people on the GTK+ Team.  See the ChangeLog * files for a list of changes.  These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/.  */#include <stdlib.h>#include <string.h>#include <math.h>#include "gtkcurve.h"#include "gtkdrawingarea.h"#include "gtkmain.h"#include "gtkradiobutton.h"#include "gtksignal.h"#include "gtktable.h"#define RADIUS		3	/* radius of the control points */#define MIN_DISTANCE	8	/* min distance between control points */#define GRAPH_MASK	(GDK_EXPOSURE_MASK |		\			 GDK_POINTER_MOTION_MASK |	\			 GDK_POINTER_MOTION_HINT_MASK |	\			 GDK_ENTER_NOTIFY_MASK |	\			 GDK_BUTTON_PRESS_MASK |	\			 GDK_BUTTON_RELEASE_MASK |	\			 GDK_BUTTON1_MOTION_MASK)enum {  ARG_0,  ARG_CURVE_TYPE,  ARG_MIN_X,  ARG_MAX_X,  ARG_MIN_Y,  ARG_MAX_Y};static GtkDrawingAreaClass *parent_class = NULL;static guint curve_type_changed_signal = 0;/* forward declarations: */static void gtk_curve_class_init   (GtkCurveClass *class);static void gtk_curve_init         (GtkCurve      *curve);static void gtk_curve_set_arg     (GtkObject      *object,				   GtkArg         *arg,				   guint           arg_id);static void gtk_curve_get_arg     (GtkObject      *object,				   GtkArg         *arg,				   guint           arg_id);static void gtk_curve_finalize     (GtkObject     *object);static gint gtk_curve_graph_events (GtkWidget     *widget, 				    GdkEvent      *event, 				    GtkCurve      *c);static void gtk_curve_size_graph   (GtkCurve      *curve);GtkTypegtk_curve_get_type (void){  static GtkType curve_type = 0;  if (!curve_type)    {      static const GtkTypeInfo curve_info =      {	"GtkCurve",	sizeof (GtkCurve),	sizeof (GtkCurveClass),	(GtkClassInitFunc) gtk_curve_class_init,	(GtkObjectInitFunc) gtk_curve_init,	/* reserved_1 */ NULL,        /* reserved_2 */ NULL,        (GtkClassInitFunc) NULL,      };      curve_type = gtk_type_unique (GTK_TYPE_DRAWING_AREA, &curve_info);    }  return curve_type;}static voidgtk_curve_class_init (GtkCurveClass *class){  GtkObjectClass *object_class;    parent_class = gtk_type_class (GTK_TYPE_DRAWING_AREA);    object_class = (GtkObjectClass *) class;    object_class->set_arg = gtk_curve_set_arg;  object_class->get_arg = gtk_curve_get_arg;  object_class->finalize = gtk_curve_finalize;    curve_type_changed_signal =    gtk_signal_new ("curve_type_changed", GTK_RUN_FIRST, object_class->type,		    GTK_SIGNAL_OFFSET (GtkCurveClass, curve_type_changed),		    gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);  gtk_object_class_add_signals (object_class, &curve_type_changed_signal, 1);    gtk_object_add_arg_type ("GtkCurve::curve_type", GTK_TYPE_CURVE_TYPE,			   GTK_ARG_READWRITE, ARG_CURVE_TYPE);  gtk_object_add_arg_type ("GtkCurve::min_x", GTK_TYPE_FLOAT,			   GTK_ARG_READWRITE, ARG_MIN_X);  gtk_object_add_arg_type ("GtkCurve::max_x", GTK_TYPE_FLOAT,			   GTK_ARG_READWRITE, ARG_MAX_X);  gtk_object_add_arg_type ("GtkCurve::min_y", GTK_TYPE_FLOAT,			   GTK_ARG_READWRITE, ARG_MIN_Y);  gtk_object_add_arg_type ("GtkCurve::max_y", GTK_TYPE_FLOAT,			   GTK_ARG_READWRITE, ARG_MAX_Y);}static voidgtk_curve_init (GtkCurve *curve){  gint old_mask;  curve->cursor_type = GDK_TOP_LEFT_ARROW;  curve->pixmap = NULL;  curve->curve_type = GTK_CURVE_TYPE_SPLINE;  curve->height = 0;  curve->grab_point = -1;  curve->num_points = 0;  curve->point = 0;  curve->num_ctlpoints = 0;  curve->ctlpoint = NULL;  curve->min_x = 0.0;  curve->max_x = 1.0;  curve->min_y = 0.0;  curve->max_y = 1.0;  old_mask = gtk_widget_get_events (GTK_WIDGET (curve));  gtk_widget_set_events (GTK_WIDGET (curve), old_mask | GRAPH_MASK);  gtk_signal_connect (GTK_OBJECT (curve), "event",		      (GtkSignalFunc) gtk_curve_graph_events, curve);  gtk_curve_size_graph (curve);}static voidgtk_curve_set_arg (GtkObject *object,		   GtkArg    *arg,		   guint      arg_id){  GtkCurve *curve = GTK_CURVE (object);    switch (arg_id)    {    case ARG_CURVE_TYPE:      gtk_curve_set_curve_type (curve, GTK_VALUE_ENUM (*arg));      break;    case ARG_MIN_X:      gtk_curve_set_range (curve, GTK_VALUE_FLOAT (*arg), curve->max_x,			   curve->min_y, curve->max_y);      break;    case ARG_MAX_X:      gtk_curve_set_range (curve, curve->min_x, GTK_VALUE_FLOAT (*arg),			   curve->min_y, curve->max_y);      break;	    case ARG_MIN_Y:      gtk_curve_set_range (curve, curve->min_x, curve->max_x,			   GTK_VALUE_FLOAT (*arg), curve->max_y);      break;    case ARG_MAX_Y:      gtk_curve_set_range (curve, curve->min_x, curve->max_x,			   curve->min_y, GTK_VALUE_FLOAT (*arg));      break;    }}static voidgtk_curve_get_arg (GtkObject *object,		   GtkArg    *arg,		   guint      arg_id){  GtkCurve *curve = GTK_CURVE (object);  switch (arg_id)    {    case ARG_CURVE_TYPE:      GTK_VALUE_ENUM (*arg) = curve->curve_type;      break;    case ARG_MIN_X:      GTK_VALUE_FLOAT (*arg) = curve->min_x;      break;    case ARG_MAX_X:      GTK_VALUE_FLOAT (*arg) = curve->max_x;      break;    case ARG_MIN_Y:      GTK_VALUE_FLOAT (*arg) = curve->min_y;      break;    case ARG_MAX_Y:      GTK_VALUE_FLOAT (*arg) = curve->max_y;      break;    default:      arg->type = GTK_TYPE_INVALID;      break;    }}static intproject (gfloat value, gfloat min, gfloat max, int norm){  return (norm - 1) * ((value - min) / (max - min)) + 0.5;}static gfloatunproject (gint value, gfloat min, gfloat max, int norm){  return value / (gfloat) (norm - 1) * (max - min) + min;}/* Solve the tridiagonal equation system that determines the second   derivatives for the interpolation points.  (Based on Numerical   Recipies 2nd Edition.) */static voidspline_solve (int n, gfloat x[], gfloat y[], gfloat y2[]){  gfloat p, sig, *u;  gint i, k;  u = g_malloc ((n - 1) * sizeof (u[0]));  y2[0] = u[0] = 0.0;	/* set lower boundary condition to "natural" */  for (i = 1; i < n - 1; ++i)    {      sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]);      p = sig * y2[i - 1] + 2.0;      y2[i] = (sig - 1.0) / p;      u[i] = ((y[i + 1] - y[i])	      / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]));      u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p;    }  y2[n - 1] = 0.0;  for (k = n - 2; k >= 0; --k)    y2[k] = y2[k] * y2[k + 1] + u[k];  g_free (u);}static gfloatspline_eval (int n, gfloat x[], gfloat y[], gfloat y2[], gfloat val){  gint k_lo, k_hi, k;  gfloat h, b, a;  /* do a binary search for the right interval: */  k_lo = 0; k_hi = n - 1;  while (k_hi - k_lo > 1)    {      k = (k_hi + k_lo) / 2;      if (x[k] > val)	k_hi = k;      else	k_lo = k;    }  h = x[k_hi] - x[k_lo];  g_assert (h > 0.0);  a = (x[k_hi] - val) / h;  b = (val - x[k_lo]) / h;  return a*y[k_lo] + b*y[k_hi] +    ((a*a*a - a)*y2[k_lo] + (b*b*b - b)*y2[k_hi]) * (h*h)/6.0;}static voidgtk_curve_interpolate (GtkCurve *c, gint width, gint height){  gfloat *vector;  int i;  vector = g_malloc (width * sizeof (vector[0]));  gtk_curve_get_vector (c, width, vector);  c->height = height;  if (c->num_points != width)    {      c->num_points = width;      if (c->point)	g_free (c->point);      c->point = g_malloc (c->num_points * sizeof (c->point[0]));    }  for (i = 0; i < width; ++i)    {      c->point[i].x = RADIUS + i;      c->point[i].y = RADIUS + height	- project (vector[i], c->min_y, c->max_y, height);    }  g_free (vector);}static voidgtk_curve_draw (GtkCurve *c, gint width, gint height){  GtkStateType state;  GtkStyle *style;  gint i;  if (!c->pixmap)    return;  if (c->height != height || c->num_points != width)    gtk_curve_interpolate (c, width, height);  state = GTK_STATE_NORMAL;  if (!GTK_WIDGET_IS_SENSITIVE (GTK_WIDGET (c)))    state = GTK_STATE_INSENSITIVE;  style = GTK_WIDGET (c)->style;  /* clear the pixmap: */  gtk_paint_flat_box (style, c->pixmap, GTK_STATE_NORMAL, GTK_SHADOW_NONE,		      NULL, GTK_WIDGET(c), "curve_bg",		      0, 0, width + RADIUS * 2, height + RADIUS * 2);  /* draw the grid lines: (XXX make more meaningful) */  for (i = 0; i < 5; i++)    {      gdk_draw_line (c->pixmap, style->dark_gc[state],		     RADIUS, i * (height / 4.0) + RADIUS,		     width + RADIUS, i * (height / 4.0) + RADIUS);      gdk_draw_line (c->pixmap, style->dark_gc[state],		     i * (width / 4.0) + RADIUS, RADIUS,		     i * (width / 4.0) + RADIUS, height + RADIUS);    }  gdk_draw_points (c->pixmap, style->fg_gc[state], c->point, c->num_points);  if (c->curve_type != GTK_CURVE_TYPE_FREE)    for (i = 0; i < c->num_ctlpoints; ++i)      {	gint x, y;	if (c->ctlpoint[i][0] < c->min_x)	  continue;	x = project (c->ctlpoint[i][0], c->min_x, c->max_x,		     width);	y = height -	  project (c->ctlpoint[i][1], c->min_y, c->max_y,		   height);	/* draw a bullet: */	gdk_draw_arc (c->pixmap, style->fg_gc[state], TRUE, x, y,		      RADIUS * 2, RADIUS*2, 0, 360*64);      }  gdk_draw_pixmap (GTK_WIDGET (c)->window, style->fg_gc[state], c->pixmap,		   0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2);}static gintgtk_curve_graph_events (GtkWidget *widget, GdkEvent *event, GtkCurve *c){  GdkCursorType new_type = c->cursor_type;  gint i, src, dst, leftbound, rightbound;  GdkEventButton *bevent;  GdkEventMotion *mevent;  GtkWidget *w;  gint tx, ty;  gint cx, x, y, width, height;  gint closest_point = 0;  gfloat rx, ry, min_x;  guint distance;  gint x1, x2, y1, y2;  w = GTK_WIDGET (c);  width = w->allocation.width - RADIUS * 2;  height = w->allocation.height - RADIUS * 2;  if ((width < 0) || (height < 0))    return FALSE;  /*  get the pointer position  */  gdk_window_get_pointer (w->window, &tx, &ty, NULL);  x = CLAMP ((tx - RADIUS), 0, width-1);  y = CLAMP ((ty - RADIUS), 0, height-1);  min_x = c->min_x;  distance = ~0U;  for (i = 0; i < c->num_ctlpoints; ++i)    {      cx = project (c->ctlpoint[i][0], min_x, c->max_x, width);      if ((guint) abs (x - cx) < distance)	{	  distance = abs (x - cx);	  closest_point = i;	}    }  switch (event->type)    {    case GDK_CONFIGURE:      if (c->pixmap)	gdk_pixmap_unref (c->pixmap);      c->pixmap = 0;      /* fall through */    case GDK_EXPOSE:      if (!c->pixmap)	c->pixmap = gdk_pixmap_new (w->window,				    w->allocation.width,				    w->allocation.height, -1);      gtk_curve_draw (c, width, height);      break;    case GDK_BUTTON_PRESS:      gtk_grab_add (widget);      bevent = (GdkEventButton *) event;      new_type = GDK_TCROSS;      switch (c->curve_type)	{	case GTK_CURVE_TYPE_LINEAR:	case GTK_CURVE_TYPE_SPLINE:	  if (distance > MIN_DISTANCE)	    {	      /* insert a new control point */	      if (c->num_ctlpoints > 0)		{		  cx = project (c->ctlpoint[closest_point][0], min_x,				c->max_x, width);		  if (x > cx)		    ++closest_point;		}	      ++c->num_ctlpoints;	      c->ctlpoint =		g_realloc (c->ctlpoint,			   c->num_ctlpoints * sizeof (*c->ctlpoint));	      for (i = c->num_ctlpoints - 1; i > closest_point; --i)		memcpy (c->ctlpoint + i, c->ctlpoint + i - 1,			sizeof (*c->ctlpoint));	    }	  c->grab_point = closest_point;	  c->ctlpoint[c->grab_point][0] =	    unproject (x, min_x, c->max_x, width);	  c->ctlpoint[c->grab_point][1] =	    unproject (height - y, c->min_y, c->max_y, height);	  gtk_curve_interpolate (c, width, height);	  break;	case GTK_CURVE_TYPE_FREE:	  c->point[x].x = RADIUS + x;	  c->point[x].y = RADIUS + y;	  c->grab_point = x;	  c->last = y;	  break;	}      gtk_curve_draw (c, width, height);      break;    case GDK_BUTTON_RELEASE:      gtk_grab_remove (widget);      /* delete inactive points: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -