home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / app / histogramwidget.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-20  |  8.2 KB  |  318 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <glib.h>
  22.  
  23. #include "apptypes.h"
  24.  
  25. #include "appenv.h"
  26. #include "drawable.h"
  27. #include "gdisplay.h"
  28. #include "gimage.h"
  29. #include "gimage_mask.h"
  30. #include "histogramwidget.h"
  31. #include "tile_manager.h"
  32.  
  33. #include "libgimp/gimpmath.h"
  34.  
  35.  
  36. #define WAITING 0
  37. #define WORKING 1
  38.  
  39. #define WORK_DELAY 1
  40.  
  41. #define HISTOGRAM_MASK GDK_EXPOSURE_MASK | \
  42.                        GDK_BUTTON_PRESS_MASK | \
  43.                        GDK_BUTTON_RELEASE_MASK | \
  44.                GDK_BUTTON1_MOTION_MASK
  45.  
  46. #define HISTOGRAM 0x1
  47. #define RANGE     0x2
  48. #define ALL       0xF
  49.  
  50.  
  51. enum
  52. {
  53.   RANGE_CHANGED,
  54.   LAST_SIGNAL
  55. };
  56.  
  57. static guint histogram_widget_signals[LAST_SIGNAL];
  58.  
  59. static void   histogram_widget_class_init (HistogramWidgetClass *klass);
  60. static void   histogram_widget_init       (HistogramWidget      *histogram);
  61.  
  62.  
  63. /**************************/
  64. /*  Function definitions  */
  65.  
  66. GtkType
  67. histogram_widget_get_type (void)
  68. {
  69.   static GtkType histogram_widet_type = 0;
  70.  
  71.   if (! histogram_widet_type)
  72.     {
  73.       static const GtkTypeInfo info =
  74.       {
  75.     "HistogramWidget",
  76.     sizeof (HistogramWidget),
  77.     sizeof (HistogramWidgetClass),
  78.     (GtkClassInitFunc) histogram_widget_class_init,
  79.     (GtkObjectInitFunc) histogram_widget_init,
  80.     NULL, NULL
  81.       };
  82.  
  83.       histogram_widet_type =
  84.     gtk_type_unique (gtk_drawing_area_get_type (), &info);
  85.     }
  86.  
  87.   return histogram_widet_type;
  88. }
  89.  
  90. static void
  91. histogram_widget_class_init (HistogramWidgetClass *klass)
  92. {
  93.   GtkObjectClass *object_class;
  94.  
  95.   object_class = GTK_OBJECT_CLASS (klass);
  96.  
  97.   histogram_widget_signals[RANGE_CHANGED] =
  98.     gtk_signal_new ("range_changed",
  99.             GTK_RUN_FIRST,
  100.             object_class->type,
  101.             GTK_SIGNAL_OFFSET (HistogramWidgetClass, range_changed),
  102.             gtk_marshal_NONE__INT_INT,
  103.             GTK_TYPE_NONE, 2,
  104.             GTK_TYPE_INT,
  105.             GTK_TYPE_INT);
  106.  
  107.   gtk_object_class_add_signals (GTK_OBJECT_CLASS (klass),
  108.                 histogram_widget_signals, LAST_SIGNAL);
  109.  
  110.   klass->range_changed = NULL;
  111. }
  112.  
  113. static void 
  114. histogram_widget_init (HistogramWidget *histogram)
  115. {
  116.   histogram->histogram = NULL;
  117.   histogram->channel   = GIMP_HISTOGRAM_VALUE;
  118.   histogram->start     = 0;
  119.   histogram->end       = 255;
  120. }
  121.  
  122. static void
  123. histogram_widget_draw (HistogramWidget *histogram,
  124.                gint             update)
  125. {
  126.   gdouble max;
  127.   gdouble v;
  128.   gint    i, x, y;
  129.   gint    x1, x2;
  130.   gint    width, height;
  131.  
  132.   width  = GTK_WIDGET (histogram)->allocation.width - 2;
  133.   height = GTK_WIDGET (histogram)->allocation.height - 2;
  134.  
  135.   if (update & HISTOGRAM)
  136.     {
  137.       /*  find the maximum value  */
  138.       max = gimp_histogram_get_maximum (histogram->histogram,
  139.                     histogram->channel);
  140.  
  141.       if (max > 0.0)
  142.     max = log (max);
  143.       else
  144.     max = 1.0;
  145.  
  146.       /*  clear the histogram  */
  147.       gdk_window_clear (GTK_WIDGET (histogram)->window);
  148.  
  149.       /*  Draw the axis  */
  150.       gdk_draw_line (GTK_WIDGET (histogram)->window,
  151.              GTK_WIDGET (histogram)->style->black_gc,
  152.              1, height + 1, width, height + 1);
  153.  
  154.       /*  Draw the spikes  */
  155.       for (i = 0; i < 256; i++)
  156.     {
  157.       x = (width * i) / 256 + 1;
  158.       v = gimp_histogram_get_value (histogram->histogram,
  159.                     histogram->channel, i);
  160.       if (v > 0.0)
  161.         y = (int) ((height * log (v)) / max);
  162.       else
  163.         y = 0;
  164.       gdk_draw_line (GTK_WIDGET (histogram)->window,
  165.              GTK_WIDGET (histogram)->style->black_gc,
  166.              x, height + 1,
  167.              x, height + 1 - y);
  168.     }
  169.     }
  170.  
  171.   if ((update & RANGE) && histogram->start >= 0)
  172.     {
  173.       x1 = (width * MIN (histogram->start, histogram->end)) / 256 + 1;
  174.       x2 = (width * MAX (histogram->start, histogram->end)) / 256 + 1;
  175.       gdk_gc_set_function (GTK_WIDGET (histogram)->style->black_gc, GDK_INVERT);
  176.       gdk_draw_rectangle (GTK_WIDGET (histogram)->window,
  177.               GTK_WIDGET (histogram)->style->black_gc, TRUE,
  178.               x1, 1, (x2 - x1) + 1, height);
  179.       gdk_gc_set_function (GTK_WIDGET (histogram)->style->black_gc, GDK_COPY);
  180.     }
  181. }
  182.  
  183. static gint
  184. histogram_widget_events (HistogramWidget *histogram,
  185.              GdkEvent        *event)
  186. {
  187.   GdkEventButton *bevent;
  188.   GdkEventMotion *mevent;
  189.   gint            width;
  190.  
  191.   switch (event->type)
  192.     {
  193.     case GDK_EXPOSE:
  194.       histogram_widget_draw (histogram, ALL);
  195.       break;
  196.  
  197.     case GDK_BUTTON_PRESS:
  198.       bevent = (GdkEventButton *) event;
  199.  
  200.       if (bevent->button != 1)
  201.     break;
  202.  
  203.       gdk_pointer_grab (GTK_WIDGET (histogram)->window, FALSE, 
  204.             GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK,
  205.             NULL, NULL, bevent->time);
  206.  
  207.       width = GTK_WIDGET (histogram)->allocation.width - 2;
  208.  
  209.       histogram_widget_draw (histogram, RANGE);
  210.  
  211.       histogram->start = CLAMP ((((bevent->x - 1) * 256) / width), 0, 255);
  212.       histogram->end = histogram->start;
  213.  
  214.       histogram_widget_draw (histogram, RANGE);
  215.       break;
  216.  
  217.     case GDK_BUTTON_RELEASE:
  218.       bevent = (GdkEventButton *) event;
  219.  
  220.       gdk_pointer_ungrab (bevent->time);
  221.  
  222.       gtk_signal_emit (GTK_OBJECT(histogram),
  223.                histogram_widget_signals[RANGE_CHANGED],
  224.                MIN (histogram->start, histogram->end),
  225.                MAX (histogram->start, histogram->end));
  226.       break;
  227.  
  228.     case GDK_MOTION_NOTIFY:
  229.       mevent = (GdkEventMotion *) event;
  230.       width = GTK_WIDGET (histogram)->allocation.width - 2;
  231.  
  232.       histogram_widget_draw (histogram, RANGE);
  233.  
  234.       histogram->start = CLAMP ((((mevent->x - 1) * 256) / width), 0, 255);
  235.  
  236.       histogram_widget_draw (histogram, RANGE);
  237.       break;
  238.  
  239.     default:
  240.       break;
  241.     }
  242.  
  243.   return FALSE;
  244. }
  245.  
  246. HistogramWidget *
  247. histogram_widget_new (gint width,
  248.               gint height)
  249. {
  250.   HistogramWidget *histogram;
  251.  
  252.   histogram = HISTOGRAM_WIDGET (gtk_type_new (HISTOGRAM_WIDGET_TYPE));
  253.  
  254.   gtk_drawing_area_size (GTK_DRAWING_AREA (histogram), width + 2, height + 2);
  255.   gtk_widget_set_events (GTK_WIDGET (histogram), HISTOGRAM_MASK);
  256.  
  257.   gtk_signal_connect (GTK_OBJECT (histogram), "event",
  258.               GTK_SIGNAL_FUNC (histogram_widget_events),
  259.               histogram);
  260.  
  261.   return histogram;
  262. }
  263.  
  264. void
  265. histogram_widget_update (HistogramWidget *histogram_widget,
  266.              GimpHistogram   *hist)
  267. {
  268.   histogram_widget->histogram = hist;
  269.  
  270.   if (!hist)
  271.     return;
  272.  
  273.   if (histogram_widget->channel >= gimp_histogram_nchannels (hist))
  274.     histogram_widget_channel (histogram_widget, 0);
  275.  
  276.   /*  Make sure the histogram is updated  */
  277.   gtk_widget_draw (GTK_WIDGET (histogram_widget), NULL);
  278.  
  279.   /*  Give a range callback  */
  280.   gtk_signal_emit (GTK_OBJECT (histogram_widget),
  281.            histogram_widget_signals[RANGE_CHANGED],
  282.            MIN (histogram_widget->start, histogram_widget->end),
  283.            MAX (histogram_widget->start, histogram_widget->end));
  284. }
  285.  
  286. void
  287. histogram_widget_range (HistogramWidget *histogram,
  288.             gint             start,
  289.             gint             end)
  290. {
  291.   histogram_widget_draw (histogram, RANGE);
  292.  
  293.   histogram->start = start;
  294.   histogram->end   = end;
  295.  
  296.   histogram_widget_draw (histogram, RANGE);
  297. }
  298.  
  299. void
  300. histogram_widget_channel (HistogramWidget *histogram,
  301.               int              channel)
  302. {
  303.   histogram->channel = channel;
  304.   histogram_widget_draw (histogram, ALL);
  305.  
  306.   /*  Give a range callback  */
  307.   gtk_signal_emit (GTK_OBJECT (histogram),
  308.            histogram_widget_signals[RANGE_CHANGED],
  309.            MIN (histogram->start, histogram->end),
  310.            MAX (histogram->start, histogram->end));
  311. }
  312.  
  313. GimpHistogram *
  314. histogram_widget_histogram (HistogramWidget *histogram)
  315. {
  316.   return histogram->histogram;
  317. }
  318.