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

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * Gradient editor module copyight (C) 1996-1997 Federico Mena Quintero
  5.  * federico@nuclecu.unam.mx
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURIGHTE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. /* Special thanks to:
  23.  *
  24.  * Luis Albarran (luis4@mindspring.com) - Nice UI suggestions
  25.  *
  26.  * Miguel de Icaza (miguel@nuclecu.unam.mx) - Pop-up menu suggestion
  27.  *
  28.  * Marcelo Malheiros (malheiro@dca.fee.unicamp.br) - many, many
  29.  * suggestions, nice gradient files
  30.  *
  31.  * Adam Moss (adam@uunet.pipex.com) - idea for the hint bar
  32.  *
  33.  * Everyone on #gimp - many suggestions
  34.  */
  35.  
  36. /* TODO:
  37.  *
  38.  * - Fix memory leaks: grad_free_gradient_editor() and any others
  39.  * which I may have missed.
  40.  *
  41.  * - Add all of Marcelo's neat suggestions:
  42.  *   - Hue rotate, saturation, brightness, contrast.
  43.  *
  44.  * - Better handling of bogus gradient files and inconsistent
  45.  *   segments.  Do not loop indefinitely in seg_get_segment_at() if
  46.  *   there is a missing segment between two others.
  47.  *
  48.  * - Add a Gradient brush mode (color changes as you move it).
  49.  */
  50.  
  51. #include "config.h"
  52.  
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56. #ifdef HAVE_UNISTD_H
  57. #include <unistd.h>
  58. #endif
  59.  
  60. #include <gtk/gtk.h>
  61.  
  62. #include "apptypes.h"
  63.  
  64. #include "appenv.h"
  65. #include "cursorutil.h"
  66. #include "datafiles.h"
  67. #include "errors.h"
  68. #include "gimpcontext.h"
  69. #include "gimpdnd.h"
  70. #include "gimprc.h"
  71. #include "gimpui.h"
  72. #include "gradient.h"
  73. #include "gradientP.h"
  74. #include "gradient_header.h"
  75. #include "gradient_select.h"
  76.  
  77. #include "libgimp/gimpenv.h"
  78. #include "libgimp/gimplimits.h"
  79. #include "libgimp/gimpmath.h"
  80. #include "libgimp/gimpcolorspace.h"
  81.  
  82. #include "libgimp/gimpintl.h"
  83.  
  84. #include "pixmaps/zoom_in.xpm"
  85. #include "pixmaps/zoom_out.xpm"
  86.  
  87.  
  88. /***** Magic numbers *****/
  89.  
  90. #define EPSILON 1e-10
  91.  
  92. #define GRAD_LIST_WIDTH  300
  93. #define GRAD_LIST_HEIGHT  80
  94.  
  95. #define GRAD_SCROLLBAR_STEP_SIZE 0.05
  96. #define GRAD_SCROLLBAR_PAGE_SIZE 0.75
  97.  
  98. #define GRAD_PREVIEW_WIDTH  600
  99. #define GRAD_PREVIEW_HEIGHT  64
  100. #define GRAD_CONTROL_HEIGHT  10
  101.  
  102. #define GRAD_COLOR_BOX_WIDTH  24
  103. #define GRAD_COLOR_BOX_HEIGHT 16
  104.  
  105. #define GRAD_NUM_COLORS 10
  106.  
  107. #define GRAD_MOVE_TIME 150 /* ms between mouse click and detection of movement in gradient control */
  108.  
  109. #define GRAD_PREVIEW_EVENT_MASK (GDK_EXPOSURE_MASK | \
  110.                                  GDK_LEAVE_NOTIFY_MASK | \
  111.                  GDK_POINTER_MOTION_MASK | \
  112.                                  GDK_POINTER_MOTION_HINT_MASK | \
  113.                  GDK_BUTTON_PRESS_MASK | \
  114.                                  GDK_BUTTON_RELEASE_MASK)
  115.  
  116. #define GRAD_CONTROL_EVENT_MASK (GDK_EXPOSURE_MASK | \
  117.                  GDK_LEAVE_NOTIFY_MASK | \
  118.                  GDK_POINTER_MOTION_MASK | \
  119.                  GDK_POINTER_MOTION_HINT_MASK | \
  120.                  GDK_BUTTON_PRESS_MASK | \
  121.                  GDK_BUTTON_RELEASE_MASK | \
  122.                  GDK_BUTTON1_MOTION_MASK)
  123.  
  124. enum
  125. {
  126.   GRAD_UPDATE_GRADIENT = 1 << 0,
  127.   GRAD_UPDATE_PREVIEW  = 1 << 1,
  128.   GRAD_UPDATE_CONTROL  = 1 << 2,
  129.   GRAD_RESET_CONTROL   = 1 << 3
  130. };
  131.  
  132. /* Gradient editor type */
  133.  
  134. typedef enum
  135. {
  136.   GRAD_DRAG_NONE = 0,
  137.   GRAD_DRAG_LEFT,
  138.   GRAD_DRAG_MIDDLE,
  139.   GRAD_DRAG_ALL
  140. } control_drag_mode_t;
  141.  
  142. typedef struct
  143. {
  144.   GtkWidget *shell;
  145.   GdkGC     *gc;
  146.   GtkWidget *hint_label;
  147.   GtkWidget *clist;
  148.   GtkWidget *scrollbar;
  149.   GtkWidget *preview;
  150.   GtkWidget *control;
  151.  
  152.   /*  Zoom and scrollbar  */
  153.   guint      zoom_factor;
  154.   GtkObject *scroll_data;
  155.  
  156.   /*  Instant update  */
  157.   gboolean   instant_update;
  158.  
  159.   /*  Gradient preview  */
  160.   guchar    *preview_rows[2]; /* For caching redraw info */
  161.   gint       preview_last_x;
  162.   gboolean   preview_button_down;
  163.  
  164.   /*  Gradient control  */
  165.   GdkPixmap           *control_pixmap;
  166.   grad_segment_t      *control_drag_segment; /* Segment which is being dragged */
  167.   grad_segment_t      *control_sel_l;        /* Left segment of selection */
  168.   grad_segment_t      *control_sel_r;        /* Right segment of selection */
  169.   control_drag_mode_t  control_drag_mode;    /* What is being dragged? */
  170.   guint32              control_click_time;   /* Time when mouse was pressed */
  171.   gboolean             control_compress;     /* Compressing/expanding handles */
  172.   gint                 control_last_x;       /* Last mouse position when dragging */
  173.   gdouble              control_last_gx;      /* Last position (wrt gradient) when dragging */
  174.   gdouble              control_orig_pos;     /* Original click position when dragging */
  175.  
  176.   GtkWidget *control_main_popup;              /* Popup menu */
  177.   GtkWidget *control_blending_label;          /* Blending function label */
  178.   GtkWidget *control_coloring_label;          /* Coloring type label */
  179.   GtkWidget *control_split_m_label;           /* Split at midpoint label */
  180.   GtkWidget *control_split_u_label;           /* Split uniformly label */
  181.   GtkWidget *control_delete_menu_item;        /* Delete menu item */
  182.   GtkWidget *control_delete_label;            /* Delete label */
  183.   GtkWidget *control_recenter_label;          /* Re-center label */
  184.   GtkWidget *control_redistribute_label;      /* Re-distribute label */
  185.   GtkWidget *control_flip_label;              /* Flip label */
  186.   GtkWidget *control_replicate_label;         /* Replicate label */
  187.   GtkWidget *control_blend_colors_menu_item;  /* Blend colors menu item */
  188.   GtkWidget *control_blend_opacity_menu_item; /* Blend opacity menu item */
  189.   GtkWidget *control_left_load_popup;         /* Left endpoint load menu */
  190.   GtkWidget *control_left_save_popup;         /* Left endpoint save menu */
  191.   GtkWidget *control_right_load_popup;        /* Right endpoint load menu */
  192.   GtkWidget *control_right_save_popup;        /* Right endpoint save menu */
  193.   GtkWidget *control_blending_popup;          /* Blending function menu */
  194.   GtkWidget *control_coloring_popup;          /* Coloring type menu */
  195.   GtkWidget *control_sel_ops_popup;           /* Selection ops menu */
  196.  
  197.   GtkAccelGroup *accel_group;
  198.  
  199.   /*  Blending and coloring menus  */
  200.   GtkWidget *control_blending_items[5 + 1]; /* Add 1 for the "Varies" item */
  201.   GtkWidget *control_coloring_items[3 + 1];
  202.  
  203.   /*  Split uniformly dialog  */
  204.   gint split_parts;
  205.  
  206.   /*  Replicate dialog  */
  207.   gint replicate_times;
  208.  
  209.   /*  Saved colors  */
  210.   struct
  211.   {
  212.     gdouble r, g, b, a;
  213.   } saved_colors[GRAD_NUM_COLORS];
  214.  
  215.   GtkWidget *left_load_color_boxes[GRAD_NUM_COLORS + 3];
  216.   GtkWidget *left_load_labels[GRAD_NUM_COLORS + 3];
  217.  
  218.   GtkWidget *left_save_color_boxes[GRAD_NUM_COLORS];
  219.   GtkWidget *left_save_labels[GRAD_NUM_COLORS];
  220.  
  221.   GtkWidget *right_load_color_boxes[GRAD_NUM_COLORS + 3];
  222.   GtkWidget *right_load_labels[GRAD_NUM_COLORS + 3];
  223.  
  224.   GtkWidget *right_save_color_boxes[GRAD_NUM_COLORS];
  225.   GtkWidget *right_save_labels[GRAD_NUM_COLORS];
  226.  
  227.   /*  Color dialogs  */
  228.   GtkWidget      *left_color_preview;
  229.   grad_segment_t *left_saved_segments;
  230.   gboolean        left_saved_dirty;
  231.  
  232.   GtkWidget      *right_color_preview;
  233.   grad_segment_t *right_saved_segments;
  234.   gboolean        right_saved_dirty;
  235. } GradientEditor;
  236.  
  237. /***** Local functions *****/
  238.  
  239. static gint    gradient_editor_clist_button_press (GtkWidget       *widget,
  240.                            GdkEventButton  *bevent,
  241.                            gpointer         data);
  242.  
  243. static gradient_t * gradient_editor_drag_gradient (GtkWidget       *widget,
  244.                            gpointer         data);
  245.  
  246. static void       gradient_editor_drop_gradient   (GtkWidget       *widget,
  247.                            gradient_t      *gradient,
  248.                            gpointer         data);
  249.  
  250. /* Gradient editor functions */
  251.  
  252. static GtkWidget * ed_create_button               (gchar           *label,
  253.                            gchar           *help_data,
  254.                            GtkSignalFunc    signal_func,
  255.                            gpointer         data);
  256.  
  257. static void      ed_fetch_foreground              (gdouble         *fg_r,
  258.                            gdouble         *fg_g,
  259.                            gdouble         *fg_b,
  260.                            gdouble         *fg_a);
  261. static void      ed_update_editor                 (gint             flags);
  262.  
  263. static void      ed_set_hint                      (gchar           *str);
  264.  
  265.  
  266. static void      ed_list_item_update              (GtkWidget       *widget, 
  267.                            gint             row,
  268.                            gint             column,
  269.                            GdkEventButton  *event,
  270.                            gpointer         data);
  271.  
  272. static void      ed_initialize_saved_colors       (void);
  273.  
  274. /* Main dialog button callbacks & functions */
  275.  
  276. static void      ed_new_gradient_callback         (GtkWidget       *widget,
  277.                            gpointer         data);
  278. static void      ed_do_new_gradient_callback      (GtkWidget       *widget,
  279.                            gchar           *gradient_name,
  280.                            gpointer         data);
  281.  
  282. static void      ed_copy_gradient_callback        (GtkWidget       *widget,
  283.                            gpointer         data);
  284. static void      ed_do_copy_gradient_callback     (GtkWidget       *widget,
  285.                            gchar           *gradient_name,
  286.                            gpointer         data);
  287.  
  288. static void      ed_delete_gradient_callback      (GtkWidget       *widget,
  289.                            gpointer         data);
  290. static void      ed_do_delete_gradient_callback   (GtkWidget       *widget,
  291.                            gboolean         delete,
  292.                            gpointer         data);
  293.  
  294. static void      ed_rename_gradient_callback      (GtkWidget       *widget,
  295.                            gpointer         data);
  296. static void      ed_do_rename_gradient_callback   (GtkWidget       *widget,
  297.                            gchar           *gradient_name,
  298.                            gpointer         data);
  299.  
  300. static void      ed_save_pov_callback             (GtkWidget       *widget,
  301.                            gpointer         data);
  302. static void      ed_do_save_pov_callback          (GtkWidget       *widget,
  303.                            gpointer         data);
  304. static void      ed_cancel_save_pov_callback      (GtkWidget       *widget,
  305.                            gpointer         data);
  306. static gint      ed_delete_save_pov_callback      (GtkWidget       *widget,
  307.                            GdkEvent        *event,
  308.                            gpointer         data);
  309.  
  310. static void      ed_refresh_grads_callback        (GtkWidget       *widget,
  311.                            gpointer         data);
  312. static void      ed_close_callback                (GtkWidget       *widget,
  313.                            gpointer         data);
  314.  
  315. /* Zoom, scrollbar & instant update callbacks */
  316.  
  317. static void      ed_scrollbar_update              (GtkAdjustment   *adjustment,
  318.                            gpointer         data);
  319. static void      ed_zoom_all_callback             (GtkWidget       *widget,
  320.                            gpointer         data);
  321. static void      ed_zoom_out_callback             (GtkWidget       *widget,
  322.                            gpointer         data);
  323. static void      ed_zoom_in_callback              (GtkWidget       *widget,
  324.                            gpointer         data);
  325. static void      ed_instant_update_update         (GtkWidget       *widget,
  326.                            gpointer         data);
  327.  
  328. /* Gradient preview functions */
  329.  
  330. static gint      preview_events                   (GtkWidget       *widget,
  331.                            GdkEvent        *event,
  332.                            gpointer         data);
  333. static void      preview_set_hint                 (gint             x);
  334.  
  335. static void      preview_set_foreground           (gint             x);
  336. static void      preview_set_background           (gint             x);
  337.  
  338. static void      gradient_update                  (void);
  339. static void      preview_update                   (gboolean         recalculate);
  340. static void      preview_fill_image               (gint             width,
  341.                            gint             height,
  342.                            gdouble          left,
  343.                            gdouble          right);
  344.  
  345. /* Gradient control functions */
  346.  
  347. static gint      control_events                   (GtkWidget       *widget,
  348.                            GdkEvent        *event,
  349.                            gpointer         data);
  350. static void      control_do_hint                  (gint             x,
  351.                            gint             y);
  352. static void      control_button_press             (gint             x,
  353.                            gint             y,
  354.                            guint            button,
  355.                            guint            state);
  356. static gboolean  control_point_in_handle          (gint             x,
  357.                            gint             y,
  358.                            grad_segment_t  *seg,
  359.                            control_drag_mode_t handle);
  360. static void      control_select_single_segment    (grad_segment_t  *seg);
  361. static void      control_extend_selection         (grad_segment_t  *seg,
  362.                            gdouble          pos);
  363. static void      control_motion                   (gint             x);
  364.  
  365. static void      control_compress_left            (grad_segment_t  *range_l,
  366.                            grad_segment_t  *range_r,
  367.                            grad_segment_t  *drag_seg,
  368.                            gdouble          pos);
  369. static void      control_compress_range           (grad_segment_t  *range_l,
  370.                            grad_segment_t  *range_r,
  371.                            gdouble          new_l,
  372.                            gdouble          new_r);
  373.  
  374. static double    control_move                     (grad_segment_t  *range_l,
  375.                            grad_segment_t  *range_r,
  376.                            gdouble          delta);
  377.  
  378. /* Control update/redraw functions */
  379.  
  380. static void      control_update                   (gboolean         recalculate);
  381. static void      control_draw                     (GdkPixmap       *pixmap,
  382.                            gint             width,
  383.                            gint             height,
  384.                            gdouble          left,
  385.                            gdouble          right);
  386. static void      control_draw_normal_handle       (GdkPixmap       *pixmap,
  387.                            gdouble          pos,
  388.                            gint             height);
  389. static void      control_draw_middle_handle       (GdkPixmap       *pixmap,
  390.                            gdouble          pos,
  391.                            gint             height);
  392. static void      control_draw_handle              (GdkPixmap       *pixmap,
  393.                            GdkGC           *border_gc,
  394.                            GdkGC           *fill_gc,
  395.                            gint             xpos,
  396.                            gint             height);
  397.  
  398. static gint      control_calc_p_pos               (gdouble          pos);
  399. static gdouble   control_calc_g_pos               (gint             pos);
  400.  
  401. /* Control popup functions */
  402.  
  403. static void      cpopup_create_main_menu          (void);
  404. static void      cpopup_do_popup                  (void);
  405.  
  406. static GtkWidget * cpopup_create_color_item           (GtkWidget  **color_box,
  407.                                GtkWidget  **label);
  408. static GtkWidget * cpopup_create_menu_item_with_label (gchar       *str,
  409.                                GtkWidget  **label);
  410.  
  411. static void      cpopup_adjust_menus              (void);
  412. static void      cpopup_adjust_blending_menu      (void);
  413. static void      cpopup_adjust_coloring_menu      (void);
  414. static void      cpopup_check_selection_params    (gint            *equal_blending,
  415.                            gint            *equal_coloring);
  416.  
  417. static void      cpopup_render_color_box          (GtkPreview      *preview,
  418.                            gdouble          r,
  419.                            gdouble          g,
  420.                            gdouble          b,
  421.                            gdouble          a);
  422.  
  423. static GtkWidget * cpopup_create_load_menu        (GtkWidget      **color_boxes,
  424.                            GtkWidget      **labels,
  425.                            gchar           *label1,
  426.                            gchar           *label2,
  427.                            GtkSignalFunc    callback,
  428.                            gchar            accel_key_0,
  429.                            guint8           accel_mods_0,
  430.                            gchar            accel_key_1,
  431.                            guint8           accel_mods_1,
  432.                            gchar            accel_key_2,
  433.                            guint8           accel_mods_2);
  434. static GtkWidget * cpopup_create_save_menu        (GtkWidget      **color_boxes,
  435.                            GtkWidget      **labels,
  436.                            GtkSignalFunc    callback);
  437.  
  438. static void      cpopup_update_saved_color        (gint             n,
  439.                            gdouble          r,
  440.                            gdouble          g,
  441.                            gdouble          b,
  442.                            gdouble          a);
  443.  
  444. static void      cpopup_load_left_callback        (GtkWidget       *widget,
  445.                            gpointer         data);
  446. static void      cpopup_save_left_callback        (GtkWidget       *widget,
  447.                            gpointer         data);
  448. static void      cpopup_load_right_callback       (GtkWidget       *widget,
  449.                            gpointer         data);
  450. static void      cpopup_save_right_callback       (GtkWidget       *widget,
  451.                            gpointer         data);
  452.  
  453. static void      cpopup_set_color_selection_color (GtkColorSelection *cs,
  454.                            gdouble            r,
  455.                            gdouble            g,
  456.                            gdouble            b,
  457.                            gdouble            a);
  458. static void      cpopup_get_color_selection_color (GtkColorSelection *cs,
  459.                            gdouble           *r,
  460.                            gdouble           *g,
  461.                            gdouble           *b,
  462.                            gdouble           *a);
  463.  
  464. static grad_segment_t * cpopup_save_selection     (void);
  465. static void             cpopup_free_selection     (grad_segment_t  *seg);
  466. static void             cpopup_replace_selection  (grad_segment_t  *replace_seg);
  467.  
  468. /* ----- */
  469.  
  470. static void   cpopup_create_color_dialog          (gchar           *title,
  471.                            double           r,
  472.                            double           g,
  473.                            double           b,
  474.                            double           a,
  475.                            GtkSignalFunc    color_changed_callback,
  476.                            GtkSignalFunc    ok_callback,
  477.                            GtkSignalFunc    cancel_callback,
  478.                            GtkSignalFunc    delete_callback);
  479.  
  480. static void   cpopup_set_left_color_callback      (GtkWidget       *widget,
  481.                            gpointer         data);
  482. static void   cpopup_left_color_changed           (GtkWidget       *widget,
  483.                            gpointer         data);
  484. static void   cpopup_left_color_dialog_ok         (GtkWidget       *widget,
  485.                            gpointer         data);
  486. static void   cpopup_left_color_dialog_cancel     (GtkWidget       *widget,
  487.                            gpointer         data);
  488. static gint   cpopup_left_color_dialog_delete     (GtkWidget       *widget,
  489.                            GdkEvent        *event,
  490.                            gpointer         data);
  491.  
  492. static void   cpopup_set_right_color_callback     (GtkWidget       *widget,
  493.                            gpointer         data);
  494. static void   cpopup_right_color_changed          (GtkWidget       *widget,
  495.                            gpointer         data);
  496. static void   cpopup_right_color_dialog_ok        (GtkWidget       *widget,
  497.                            gpointer         data);
  498. static void   cpopup_right_color_dialog_cancel    (GtkWidget       *widget,
  499.                            gpointer         data);
  500. static gint   cpopup_right_color_dialog_delete    (GtkWidget       *widget,
  501.                            GdkEvent        *event,
  502.                            gpointer         data);
  503.  
  504. /* ----- */
  505.  
  506. static GtkWidget * cpopup_create_blending_menu    (void);
  507. static void        cpopup_blending_callback       (GtkWidget       *widget,
  508.                            gpointer         data);
  509. static GtkWidget * cpopup_create_coloring_menu    (void);
  510. static void        cpopup_coloring_callback       (GtkWidget       *widget,
  511.                            gpointer         data);
  512.  
  513. /* ----- */
  514.  
  515. static void  cpopup_split_midpoint_callback       (GtkWidget       *widget,
  516.                            gpointer         data);
  517. static void  cpopup_split_midpoint                (grad_segment_t  *lseg,
  518.                            grad_segment_t **newl,
  519.                            grad_segment_t **newr);
  520.  
  521. static void  cpopup_split_uniform_callback        (GtkWidget       *widget,
  522.                            gpointer         data);
  523. static void  cpopup_split_uniform_scale_update    (GtkAdjustment   *adjustment,
  524.                            gpointer         data);
  525. static void  cpopup_split_uniform_split_callback  (GtkWidget       *widget,
  526.                            gpointer         data);
  527. static void  cpopup_split_uniform_cancel_callback (GtkWidget       *widget,
  528.                            gpointer         data);
  529. static void  cpopup_split_uniform                 (grad_segment_t  *lseg,
  530.                            gint             parts,
  531.                            grad_segment_t **newl,
  532.                            grad_segment_t **newr);
  533.  
  534. static void  cpopup_delete_callback               (GtkWidget       *widget,
  535.                            gpointer         data);
  536. static void  cpopup_recenter_callback             (GtkWidget       *widget,
  537.                            gpointer         data);
  538. static void  cpopup_redistribute_callback         (GtkWidget       *widget,
  539.                            gpointer         data);
  540.  
  541. /* Control popup -> Selection operations functions */
  542.  
  543. static GtkWidget * cpopup_create_sel_ops_menu     (void);
  544.  
  545. static void      cpopup_flip_callback             (GtkWidget       *widget,
  546.                            gpointer         data);
  547.  
  548. static void      cpopup_replicate_callback        (GtkWidget       *widget,
  549.                            gpointer         data);
  550. static void      cpopup_replicate_scale_update    (GtkAdjustment   *widget,
  551.                            gpointer         data);
  552. static void      cpopup_do_replicate_callback     (GtkWidget       *widget,
  553.                            gpointer         data);
  554. static void      cpopup_replicate_cancel_callback (GtkWidget       *widget,
  555.                            gpointer         data);
  556.  
  557. static void      cpopup_blend_colors              (GtkWidget       *widget,
  558.                            gpointer         data);
  559. static void      cpopup_blend_opacity             (GtkWidget       *widget,
  560.                            gpointer         data);
  561.  
  562. /* Blend function */
  563.  
  564. static void      cpopup_blend_endpoints           (gdouble          r0,
  565.                            gdouble          g0,
  566.                            gdouble          b0,
  567.                            gdouble          a0,
  568.                            gdouble          r1,
  569.                            gdouble          g1,
  570.                            gdouble          b1,
  571.                            gdouble          a1,
  572.                            gint             blend_colors,
  573.                            gint             blend_opacity);
  574.  
  575. /* Gradient functions */
  576.  
  577. static gradient_t     * grad_new_gradient             (void);
  578. static void             grad_free_gradient            (gradient_t *grad);
  579. static void             grad_free_gradients           (void);
  580. static void             grad_load_gradient            (gchar      *filename);
  581. static void             grad_save_gradient            (gradient_t *grad,
  582.                                gchar      *filename);
  583. static void             grad_save_all                 (gboolean    need_free);
  584.  
  585. static gradient_t     * grad_create_default_gradient  (void);
  586.  
  587. static gint             grad_insert_in_gradients_list (gradient_t *grad);
  588.  
  589. static void             grad_dump_gradient            (gradient_t *grad,
  590.                                FILE       *file);
  591. static void     gradients_list_uniquefy_gradient_name (gradient_t *gradient);
  592.  
  593.  
  594. /* Segment functions */
  595.  
  596. static grad_segment_t * seg_new_segment        (void);
  597. static void             seg_free_segment       (grad_segment_t       *seg);
  598. static void             seg_free_segments      (grad_segment_t       *seg);
  599.  
  600. static grad_segment_t * seg_get_segment_at     (gradient_t           *grad,
  601.                         gdouble               pos);
  602. static grad_segment_t * seg_get_last_segment   (grad_segment_t       *seg);
  603. static void             seg_get_closest_handle (gradient_t           *grad,
  604.                         gdouble               pos,
  605.                         grad_segment_t      **seg,
  606.                         control_drag_mode_t  *handle);
  607.  
  608. /* Calculation functions */
  609.  
  610. static gdouble   calc_linear_factor            (gdouble  middle,
  611.                         gdouble  pos);
  612. static gdouble   calc_curved_factor            (gdouble  middle,
  613.                         gdouble  pos);
  614. static gdouble   calc_sine_factor              (gdouble  middle,
  615.                         gdouble  pos);
  616. static gdouble   calc_sphere_increasing_factor (gdouble  middle,
  617.                         gdouble  pos);
  618. static gdouble   calc_sphere_decreasing_factor (gdouble  middle,
  619.                         gdouble  pos);
  620.  
  621. /* Files and paths functions */
  622.  
  623. static gchar   * build_user_filename           (gchar   *name,
  624.                         gchar   *path_str);
  625.  
  626.  
  627. /***** Global variables *****/
  628.  
  629. GSList * gradients_list = NULL; /* The list of gradients */
  630. gint     num_gradients  = 0;
  631.  
  632. /***** Local variables *****/
  633.  
  634. static GdkColor         black;
  635. static gradient_t     * curr_gradient     = NULL;
  636. static gradient_t     * dnd_gradient      = NULL;
  637. static GradientEditor * g_editor          = NULL;
  638.  
  639. static gradient_t     * standard_gradient = NULL;
  640.  
  641. static const gchar *blending_types[] =
  642. {
  643.   N_("Linear"),
  644.   N_("Curved"),
  645.   N_("Sinusoidal"),
  646.   N_("Spherical (increasing)"),
  647.   N_("Spherical (decreasing)")
  648. };
  649.  
  650. static const gchar *coloring_types[] =
  651. {
  652.   N_("Plain RGB"),
  653.   N_("HSV (counter-clockwise hue)"),
  654.   N_("HSV (clockwise hue)")
  655. };
  656.  
  657. /*  dnd stuff  */
  658. static GtkTargetEntry gradient_target_table[] =
  659. {
  660.   GIMP_TARGET_GRADIENT
  661. };
  662. static guint n_gradient_targets = (sizeof (gradient_target_table) /
  663.                    sizeof (gradient_target_table[0]));
  664.  
  665. /***** Public functions *****/
  666.  
  667. void
  668. gradients_init (gint no_data)
  669. {
  670.   if (gradients_list)
  671.     gradients_free ();
  672.  
  673.   if (gradient_path != NULL && !no_data)
  674.     datafiles_read_directories (gradient_path, grad_load_gradient, 0);
  675.  
  676.   gimp_context_refresh_gradients ();
  677. }
  678.  
  679. void
  680. gradients_free (void)
  681. {
  682.   grad_free_gradients ();
  683. }
  684.  
  685. gradient_t *
  686. gradients_get_standard_gradient (void)
  687. {
  688.   if (! standard_gradient)
  689.     {
  690.       standard_gradient = grad_create_default_gradient ();
  691.       standard_gradient->name     = g_strdup ("Standard");
  692.       standard_gradient->filename = NULL;
  693.       standard_gradient->dirty    = FALSE;
  694.     }
  695.  
  696.   return standard_gradient;
  697. }
  698.  
  699. gradient_t *
  700. gradient_list_get_gradient (GSList *list,
  701.                 gchar  *name)
  702. {
  703.   gradient_t *gradient;
  704.  
  705.   for (; list; list = g_slist_next (list))
  706.     {
  707.       gradient = (gradient_t *) list->data;
  708.  
  709.       if (strcmp (gradient->name, name) == 0)
  710.     return gradient;
  711.     }
  712.  
  713.   return NULL;
  714. }
  715.  
  716. gint
  717. gradient_list_get_gradient_index (GSList     *list,
  718.                   gradient_t *gradient)
  719. {
  720.   gradient_t *cmp_gradient;
  721.   gint        index;
  722.  
  723.   for (index = 0; list; list = g_slist_next (list), index++)
  724.     {
  725.       cmp_gradient = (gradient_t *) list->data;
  726.  
  727.       if (cmp_gradient == gradient)
  728.     return index;
  729.     }
  730.  
  731.   return -1;
  732. }
  733.  
  734. /*****/
  735.  
  736. void
  737. gradient_get_color_at (gradient_t *gradient,
  738.                gdouble     pos,
  739.                gdouble    *r,
  740.                gdouble    *g,
  741.                gdouble    *b,
  742.                gdouble    *a)
  743. {
  744.   gdouble         factor = 0.0;
  745.   grad_segment_t *seg;
  746.   gdouble         seg_len, middle;
  747.   gdouble         h0, s0, v0;
  748.   gdouble         h1, s1, v1;
  749.  
  750.   /* if there is no gradient return a totally transparent black */
  751.   if (gradient == NULL) 
  752.     {
  753.       r = 0; g = 0; b = 0; a = 0;
  754.       return;
  755.     }
  756.  
  757.   if (pos < 0.0)
  758.     pos = 0.0;
  759.   else if (pos > 1.0)
  760.     pos = 1.0;
  761.  
  762.   seg = seg_get_segment_at (gradient, pos);
  763.  
  764.   seg_len = seg->right - seg->left;
  765.  
  766.   if (seg_len < EPSILON)
  767.     {
  768.       middle = 0.5;
  769.       pos    = 0.5;
  770.     }
  771.   else
  772.     {
  773.       middle = (seg->middle - seg->left) / seg_len;
  774.       pos    = (pos - seg->left) / seg_len;
  775.     }
  776.  
  777.   switch (seg->type)
  778.     {
  779.     case GRAD_LINEAR:
  780.       factor = calc_linear_factor (middle, pos);
  781.       break;
  782.  
  783.     case GRAD_CURVED:
  784.       factor = calc_curved_factor (middle, pos);
  785.       break;
  786.  
  787.     case GRAD_SINE:
  788.       factor = calc_sine_factor (middle, pos);
  789.       break;
  790.  
  791.     case GRAD_SPHERE_INCREASING:
  792.       factor = calc_sphere_increasing_factor (middle, pos);
  793.       break;
  794.  
  795.     case GRAD_SPHERE_DECREASING:
  796.       factor = calc_sphere_decreasing_factor (middle, pos);
  797.       break;
  798.  
  799.     default:
  800.       grad_dump_gradient (gradient, stderr);
  801.       gimp_fatal_error ("gradient_get_color_at(): Unknown gradient type %d",
  802.             (int) seg->type);
  803.       break;
  804.     }
  805.  
  806.   /* Calculate color components */
  807.  
  808.   *a = seg->a0 + (seg->a1 - seg->a0) * factor;
  809.  
  810.   if (seg->color == GRAD_RGB)
  811.     {
  812.       *r = seg->r0 + (seg->r1 - seg->r0) * factor;
  813.       *g = seg->g0 + (seg->g1 - seg->g0) * factor;
  814.       *b = seg->b0 + (seg->b1 - seg->b0) * factor;
  815.     }
  816.   else
  817.     {
  818.       h0 = seg->r0;
  819.       s0 = seg->g0;
  820.       v0 = seg->b0;
  821.  
  822.       h1 = seg->r1;
  823.       s1 = seg->g1;
  824.       v1 = seg->b1;
  825.  
  826.       gimp_rgb_to_hsv_double (&h0, &s0, &v0);
  827.       gimp_rgb_to_hsv_double (&h1, &s1, &v1);
  828.  
  829.       s0 = s0 + (s1 - s0) * factor;
  830.       v0 = v0 + (v1 - v0) * factor;
  831.  
  832.       switch (seg->color)
  833.     {
  834.     case GRAD_HSV_CCW:
  835.       if (h0 < h1)
  836.         {
  837.           h0 = h0 + (h1 - h0) * factor;
  838.         }
  839.       else
  840.         {
  841.           h0 = h0 + (1.0 - (h0 - h1)) * factor;
  842.           if (h0 > 1.0)
  843.         h0 -= 1.0;
  844.         }
  845.       break;
  846.  
  847.     case GRAD_HSV_CW:
  848.       if (h1 < h0)
  849.         {
  850.           h0 = h0 - (h0 - h1) * factor;
  851.         }
  852.       else
  853.         {
  854.           h0 = h0 - (1.0 - (h1 - h0)) * factor;
  855.           if (h0 < 0.0)
  856.         h0 += 1.0;
  857.         }
  858.       break;
  859.  
  860.     default:
  861.       grad_dump_gradient (gradient, stderr);
  862.       gimp_fatal_error ("gradient_get_color_at(): Unknown coloring mode %d",
  863.                 (int) seg->color);
  864.       break;
  865.     }
  866.  
  867.       *r = h0;
  868.       *g = s0;
  869.       *b = v0;
  870.  
  871.       gimp_hsv_to_rgb_double (r, g, b);
  872.     }
  873. }
  874.  
  875. /***** The main gradient editor dialog *****/
  876.  
  877. void 
  878. gradient_editor_create (void)
  879. {
  880.   GtkWidget   *vbox;
  881.   GtkWidget   *hbox;
  882.   GtkWidget   *gvbox;
  883.   GtkWidget   *button;
  884.   GtkWidget   *frame;
  885.   GtkWidget   *scrolled_win;
  886.   GdkColormap *colormap;
  887.   gchar       *titles[2];
  888.   gint         column_width;
  889.   gint         select_pos;
  890.   gint         i;
  891.  
  892.   /* If the editor already exists, just show it */
  893.   if (g_editor)
  894.     {
  895.       if (! GTK_WIDGET_VISIBLE (g_editor->shell))
  896.     gtk_widget_show (g_editor->shell);
  897.       else
  898.     gdk_window_raise (g_editor->shell->window);
  899.  
  900.       return;
  901.     }
  902.  
  903.   g_editor = g_new (GradientEditor, 1);
  904.  
  905.   /* Shell and main vbox */
  906.   g_editor->shell =
  907.     gimp_dialog_new (_("Gradient Editor"), "gradient_editor",
  908.              gimp_standard_help_func,
  909.              "dialogs/gradient_editor/gradient_editor.html",
  910.              GTK_WIN_POS_NONE,
  911.              FALSE, TRUE, FALSE,
  912.  
  913.              _("Refresh"), ed_refresh_grads_callback,
  914.              NULL, NULL, NULL, FALSE, FALSE,
  915.              _("Close"), ed_close_callback,
  916.              NULL, NULL, NULL, TRUE, TRUE,
  917.  
  918.              NULL);
  919.  
  920.   vbox = gtk_vbox_new (FALSE, 4);
  921.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  922.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (g_editor->shell)->vbox), vbox);
  923.   gtk_widget_show (vbox);
  924.  
  925.   /* Gradients list box */
  926.   hbox = gtk_hbox_new (FALSE, 4);
  927.   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
  928.   gtk_widget_show (hbox);
  929.  
  930.   /* clist preview of gradients */
  931.   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  932.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
  933.                   GTK_POLICY_AUTOMATIC,
  934.                   GTK_POLICY_ALWAYS);
  935.   gtk_box_pack_start (GTK_BOX (hbox), scrolled_win, TRUE, TRUE, 0); 
  936.   gtk_widget_show (scrolled_win);
  937.  
  938.   titles[0] = _("Gradient");
  939.   titles[1] = _("Name");
  940.   g_editor->clist = gtk_clist_new_with_titles (2, titles);
  941.   gtk_clist_set_shadow_type (GTK_CLIST (g_editor->clist), GTK_SHADOW_IN);
  942.   gtk_clist_set_selection_mode (GTK_CLIST (g_editor->clist),
  943.                 GTK_SELECTION_BROWSE);
  944.   gtk_clist_set_row_height (GTK_CLIST (g_editor->clist), 18);
  945.   gtk_clist_set_use_drag_icons (GTK_CLIST (g_editor->clist), FALSE);
  946.   gtk_clist_column_titles_passive (GTK_CLIST (g_editor->clist));
  947.   gtk_container_add (GTK_CONTAINER (scrolled_win), g_editor->clist);
  948.  
  949.   column_width =
  950.     MAX (50, gtk_clist_optimal_column_width (GTK_CLIST (g_editor->clist), 0));
  951.   gtk_clist_set_column_min_width (GTK_CLIST (g_editor->clist), 0, 50);
  952.   gtk_clist_set_column_width (GTK_CLIST (g_editor->clist), 0, column_width);
  953.  
  954.   gtk_widget_show (g_editor->clist);
  955.  
  956.   colormap = gtk_widget_get_colormap (g_editor->clist);
  957.   gdk_color_parse ("black", &black);
  958.   gdk_color_alloc (colormap, &black);
  959.     
  960.   gtk_signal_connect (GTK_OBJECT (g_editor->clist), "button_press_event",
  961.                       GTK_SIGNAL_FUNC (gradient_editor_clist_button_press),
  962.                       NULL);
  963.  
  964.   gtk_signal_connect (GTK_OBJECT (g_editor->clist), "select_row",
  965.               GTK_SIGNAL_FUNC (ed_list_item_update),
  966.               NULL);
  967.  
  968.   /*  dnd stuff  */
  969.   gtk_drag_source_set (g_editor->clist,
  970.                GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
  971.                gradient_target_table, n_gradient_targets,
  972.                GDK_ACTION_COPY);
  973.   gimp_dnd_gradient_source_set (g_editor->clist, gradient_editor_drag_gradient,
  974.                 NULL);
  975.  
  976.   gtk_drag_dest_set (g_editor->clist,
  977.              GTK_DEST_DEFAULT_ALL,
  978.              gradient_target_table, n_gradient_targets,
  979.              GDK_ACTION_COPY);
  980.   gimp_dnd_gradient_dest_set (g_editor->clist, gradient_editor_drop_gradient,
  981.                   NULL);
  982.  
  983.   /* Frame & vbox for gradient functions */
  984.   frame = gtk_frame_new (_("Gradient Ops"));
  985.   gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  986.  
  987.   gvbox = gtk_vbox_new (FALSE, 2);
  988.   gtk_container_set_border_width (GTK_CONTAINER (gvbox), 4);
  989.   gtk_container_add (GTK_CONTAINER (frame), gvbox);
  990.  
  991.   /* Buttons for gradient functions */
  992.   button = ed_create_button (_("New Gradient"),
  993.                  "dialogs/gradient_editor/new_gradient.html",
  994.                  GTK_SIGNAL_FUNC (ed_new_gradient_callback),
  995.                  NULL);
  996.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  997.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  998.   gtk_widget_show (button);
  999.  
  1000.   button = ed_create_button (_("Copy Gradient"),
  1001.                  "dialogs/gradient_editor/copy_gradient.html",
  1002.                  GTK_SIGNAL_FUNC (ed_copy_gradient_callback),
  1003.                  NULL);
  1004.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1005.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1006.   gtk_widget_show (button);
  1007.  
  1008.   button = ed_create_button (_("Delete Gradient"),
  1009.                  "dialogs/gradient_editor/delete_gradient.html",
  1010.                  GTK_SIGNAL_FUNC (ed_delete_gradient_callback),
  1011.                  NULL);
  1012.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1013.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1014.   gtk_widget_show (button);
  1015.  
  1016.   button = ed_create_button (_("Rename Gradient"),
  1017.                  "dialogs/gradient_editor/rename_gradient.html",
  1018.                  GTK_SIGNAL_FUNC (ed_rename_gradient_callback),
  1019.                  NULL);
  1020.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1021.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1022.   gtk_widget_show (button);
  1023.  
  1024.   button = ed_create_button (_("Save as POV-Ray"),
  1025.                  "dialogs/gradient_editor/save_as_povray.html",
  1026.                  GTK_SIGNAL_FUNC (ed_save_pov_callback),
  1027.                  NULL);
  1028.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1029.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1030.   gtk_widget_show (button);
  1031.  
  1032.   gtk_widget_show (gvbox);
  1033.   gtk_widget_show (frame);
  1034.  
  1035.   /*  Horizontal box for zoom controls, scrollbar and instant update toggle  */
  1036.   hbox = gtk_hbox_new (FALSE, 4);
  1037.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 0);
  1038.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  1039.   gtk_widget_show (hbox);
  1040.  
  1041.   /*  Zoom all button */
  1042.   button = ed_create_button (_("Zoom all"), NULL,
  1043.                  GTK_SIGNAL_FUNC (ed_zoom_all_callback),
  1044.                  g_editor);
  1045.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1046.   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1047.   gtk_widget_show (button);
  1048.  
  1049.   /*  + and - buttons  */
  1050.   gtk_widget_realize (g_editor->shell);
  1051.  
  1052.   button = gimp_pixmap_button_new (zoom_in_xpm, NULL);
  1053.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1054.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1055.               GTK_SIGNAL_FUNC (ed_zoom_in_callback),
  1056.               g_editor);
  1057.   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1058.   gtk_widget_show (button);
  1059.  
  1060.   button = gimp_pixmap_button_new (zoom_out_xpm, NULL);
  1061.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1062.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1063.               GTK_SIGNAL_FUNC (ed_zoom_out_callback),
  1064.               g_editor);
  1065.   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1066.   gtk_widget_show (button);
  1067.  
  1068.   /*  Scrollbar  */
  1069.   g_editor->zoom_factor = 1;
  1070.  
  1071.   g_editor->scroll_data = gtk_adjustment_new (0.0, 0.0, 1.0,
  1072.                           1.0 * GRAD_SCROLLBAR_STEP_SIZE,
  1073.                           1.0 * GRAD_SCROLLBAR_PAGE_SIZE,
  1074.                           1.0);
  1075.  
  1076.   gtk_signal_connect (g_editor->scroll_data, "value_changed",
  1077.               GTK_SIGNAL_FUNC (ed_scrollbar_update),
  1078.               g_editor);
  1079.   gtk_signal_connect (g_editor->scroll_data, "changed",
  1080.               GTK_SIGNAL_FUNC (ed_scrollbar_update),
  1081.               g_editor);
  1082.  
  1083.   g_editor->scrollbar =
  1084.     gtk_hscrollbar_new (GTK_ADJUSTMENT (g_editor->scroll_data));
  1085.   gtk_range_set_update_policy (GTK_RANGE (g_editor->scrollbar),
  1086.                    GTK_UPDATE_CONTINUOUS);
  1087.   gtk_box_pack_start (GTK_BOX (hbox), g_editor->scrollbar, TRUE, TRUE, 0);
  1088.   gtk_widget_hide (g_editor->scrollbar);
  1089.  
  1090.   /* Instant update toggle */
  1091.   g_editor->instant_update = TRUE;
  1092.  
  1093.   button = gtk_check_button_new_with_label (_("Instant update"));
  1094.   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1095.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  1096.               GTK_SIGNAL_FUNC (ed_instant_update_update),
  1097.               g_editor);
  1098.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
  1099.   gtk_widget_show (button);
  1100.  
  1101.   /* Frame for gradient preview and gradient control */
  1102.   frame = gtk_frame_new (NULL);
  1103.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  1104.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  1105.   gtk_widget_show (frame);
  1106.  
  1107.   gvbox = gtk_vbox_new (FALSE, 0);
  1108.   gtk_container_add (GTK_CONTAINER (frame), gvbox); 
  1109.   gtk_widget_show (gvbox);
  1110.  
  1111.   /* Gradient preview */
  1112.   g_editor->preview_rows[0]     = NULL;
  1113.   g_editor->preview_rows[1]     = NULL;
  1114.   g_editor->preview_last_x      = 0;
  1115.   g_editor->preview_button_down = FALSE;
  1116.  
  1117.   g_editor->preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  1118.   gtk_preview_set_dither (GTK_PREVIEW (g_editor->preview), GDK_RGB_DITHER_MAX);
  1119.   gtk_preview_size (GTK_PREVIEW (g_editor->preview),
  1120.             GRAD_PREVIEW_WIDTH, GRAD_PREVIEW_HEIGHT);
  1121.  
  1122.   /*  Enable auto-resizing of the preview but ensure a minimal size  */
  1123.   gtk_widget_set_usize (g_editor->preview,
  1124.             GRAD_PREVIEW_WIDTH, GRAD_PREVIEW_HEIGHT);
  1125.   gtk_preview_set_expand (GTK_PREVIEW (g_editor->preview), TRUE);
  1126.  
  1127.   gtk_widget_set_events (g_editor->preview, GRAD_PREVIEW_EVENT_MASK);
  1128.   gtk_signal_connect (GTK_OBJECT (g_editor->preview), "event",
  1129.               GTK_SIGNAL_FUNC (preview_events),
  1130.               g_editor);
  1131.  
  1132.   gtk_drag_dest_set (g_editor->preview,
  1133.              GTK_DEST_DEFAULT_HIGHLIGHT |
  1134.              GTK_DEST_DEFAULT_MOTION |
  1135.              GTK_DEST_DEFAULT_DROP,
  1136.              gradient_target_table, n_gradient_targets,
  1137.              GDK_ACTION_COPY); 
  1138.   gimp_dnd_gradient_dest_set (g_editor->preview,
  1139.                   gradient_editor_drop_gradient,
  1140.                   NULL);
  1141.  
  1142.   gtk_box_pack_start (GTK_BOX (gvbox), g_editor->preview, TRUE, TRUE, 0);
  1143.   gtk_widget_show (g_editor->preview);
  1144.  
  1145.   /* Gradient control */
  1146.   g_editor->control_pixmap                  = NULL;
  1147.   g_editor->control_drag_segment            = NULL;
  1148.   g_editor->control_sel_l                   = NULL;
  1149.   g_editor->control_sel_r                   = NULL;
  1150.   g_editor->control_drag_mode               = GRAD_DRAG_NONE;
  1151.   g_editor->control_click_time              = 0;
  1152.   g_editor->control_compress                = FALSE;
  1153.   g_editor->control_last_x                  = 0;
  1154.   g_editor->control_last_gx                 = 0.0;
  1155.   g_editor->control_orig_pos                = 0.0;
  1156.   g_editor->control_main_popup              = NULL;
  1157.   g_editor->control_blending_label          = NULL;
  1158.   g_editor->control_coloring_label          = NULL;
  1159.   g_editor->control_split_m_label           = NULL;
  1160.   g_editor->control_split_u_label           = NULL;
  1161.   g_editor->control_delete_menu_item        = NULL;
  1162.   g_editor->control_delete_label            = NULL;
  1163.   g_editor->control_recenter_label          = NULL;
  1164.   g_editor->control_redistribute_label      = NULL;
  1165.   g_editor->control_flip_label              = NULL;
  1166.   g_editor->control_replicate_label         = NULL;
  1167.   g_editor->control_blend_colors_menu_item  = NULL;
  1168.   g_editor->control_blend_opacity_menu_item = NULL;
  1169.   g_editor->control_left_load_popup         = NULL;
  1170.   g_editor->control_left_save_popup         = NULL;
  1171.   g_editor->control_right_load_popup        = NULL;
  1172.   g_editor->control_right_save_popup        = NULL;
  1173.   g_editor->control_blending_popup          = NULL;
  1174.   g_editor->control_coloring_popup          = NULL;
  1175.   g_editor->control_sel_ops_popup           = NULL;
  1176.  
  1177.   g_editor->accel_group = NULL;
  1178.  
  1179.   for (i = 0;
  1180.        i < (sizeof (g_editor->control_blending_items) /
  1181.         sizeof (g_editor->control_blending_items[0]));
  1182.        i++)
  1183.     g_editor->control_blending_items[i] = NULL;
  1184.  
  1185.   for (i = 0;
  1186.        i < (sizeof (g_editor->control_coloring_items) /
  1187.         sizeof (g_editor->control_coloring_items[0]));
  1188.        i++)
  1189.     g_editor->control_coloring_items[i] = NULL;
  1190.  
  1191.   g_editor->control = gtk_drawing_area_new ();
  1192.   gtk_drawing_area_size (GTK_DRAWING_AREA (g_editor->control),
  1193.              GRAD_PREVIEW_WIDTH, GRAD_CONTROL_HEIGHT);
  1194.   gtk_widget_set_events (g_editor->control, GRAD_CONTROL_EVENT_MASK);
  1195.   gtk_signal_connect (GTK_OBJECT (g_editor->control), "event",
  1196.               (GdkEventFunc) control_events,
  1197.               g_editor);
  1198.   gtk_box_pack_start (GTK_BOX (gvbox), g_editor->control, TRUE, TRUE, 0);
  1199.   gtk_widget_show (g_editor->control);
  1200.  
  1201.   /* Hint bar and close button */
  1202.   g_editor->hint_label = gtk_label_new ("");
  1203.   gtk_misc_set_alignment (GTK_MISC (g_editor->hint_label), 0.0, 0.5);
  1204.   gtk_box_pack_start (GTK_BOX (vbox), g_editor->hint_label, FALSE, FALSE, 0);
  1205.   gtk_widget_show (g_editor->hint_label);
  1206.  
  1207.   /* Initialize other data */
  1208.   g_editor->left_color_preview  = NULL;
  1209.   g_editor->left_saved_segments = NULL;
  1210.   g_editor->left_saved_dirty    = FALSE;
  1211.  
  1212.   g_editor->right_color_preview  = NULL;
  1213.   g_editor->right_saved_segments = NULL;
  1214.   g_editor->right_saved_dirty    = FALSE;
  1215.  
  1216.   ed_initialize_saved_colors ();
  1217.   cpopup_create_main_menu ();
  1218.  
  1219.   if (gradients_list)
  1220.     {
  1221.       curr_gradient = dnd_gradient = (gradient_t *) gradients_list->data;
  1222.     }
  1223.   else
  1224.     {
  1225.       gint pos;
  1226.  
  1227.       curr_gradient = dnd_gradient = grad_create_default_gradient ();
  1228.       curr_gradient->name     = g_strdup (_("Default"));
  1229.       curr_gradient->filename =
  1230.     build_user_filename (curr_gradient->name, gradient_path);
  1231.       curr_gradient->dirty    = FALSE;
  1232.  
  1233.       pos = grad_insert_in_gradients_list (curr_gradient);
  1234.       gradient_select_insert_all (pos, curr_gradient);
  1235.       gimp_context_refresh_gradients ();
  1236.     }
  1237.  
  1238.   /* Show everything */
  1239.   g_editor->gc = gdk_gc_new (g_editor->shell->window);
  1240.   select_pos = gradient_clist_init (g_editor->shell, g_editor->gc,
  1241.                     g_editor->clist,
  1242.                     curr_gradient);
  1243.  
  1244.   gtk_widget_show (g_editor->shell);
  1245.  
  1246.   if (select_pos != -1)
  1247.     gtk_clist_moveto (GTK_CLIST (g_editor->clist), select_pos, 0, 0.0, 0.0);
  1248. }
  1249.  
  1250. void
  1251. gradient_editor_free (void)
  1252. {
  1253. }
  1254.  
  1255. gboolean
  1256. gradient_editor_set_gradient (gradient_t *gradient)
  1257. {
  1258.   gint n;
  1259.  
  1260.   n = gradient_list_get_gradient_index (gradients_list, gradient);
  1261.  
  1262.   if (n < 0)
  1263.     return FALSE;
  1264.  
  1265.   if (g_editor)
  1266.     {
  1267.       gtk_clist_select_row (GTK_CLIST (g_editor->clist), n, -1);
  1268.       gtk_clist_moveto (GTK_CLIST (g_editor->clist), n, 0, 0.5, 0.0);
  1269.     }
  1270.   else
  1271.     {
  1272.       curr_gradient = dnd_gradient = gradient;
  1273.     }
  1274.  
  1275.   return TRUE;
  1276. }
  1277.  
  1278. /***** Gradient editor functions *****/
  1279.  
  1280. static gint
  1281. gradient_editor_clist_button_press (GtkWidget      *widget,
  1282.                     GdkEventButton *bevent,
  1283.                     gpointer        data)
  1284. {
  1285.   if (bevent->button == 2)
  1286.     {
  1287.       GSList *list = NULL;
  1288.       gint row;
  1289.       gint column;
  1290.  
  1291.       gtk_clist_get_selection_info (GTK_CLIST (g_editor->clist),
  1292.                                     bevent->x, bevent->y,
  1293.                                     &row, &column);
  1294.  
  1295.       if (gradients_list)
  1296.     list = g_slist_nth (gradients_list, row);
  1297.  
  1298.       if (list)
  1299.     dnd_gradient = (gradient_t *) list->data;
  1300.       else
  1301.     dnd_gradient = NULL;
  1302.  
  1303.       return TRUE;
  1304.     }
  1305.  
  1306.   return FALSE;
  1307. }
  1308.  
  1309. static gradient_t *
  1310. gradient_editor_drag_gradient (GtkWidget  *widget,
  1311.                    gpointer    data)
  1312. {
  1313.   return dnd_gradient;
  1314. }
  1315.  
  1316. static void
  1317. gradient_editor_drop_gradient (GtkWidget  *widget,
  1318.                    gradient_t *gradient,
  1319.                    gpointer    data)
  1320. {
  1321.   gradient_editor_set_gradient (gradient);
  1322. }
  1323.  
  1324. /*****/
  1325.  
  1326. static void
  1327. ed_fetch_foreground (gdouble *fg_r,
  1328.              gdouble *fg_g,
  1329.              gdouble *fg_b,
  1330.              gdouble *fg_a)
  1331. {
  1332.   guchar r, g, b;
  1333.     
  1334.   gimp_context_get_foreground (gimp_context_get_user (), &r, &g, &b);
  1335.      
  1336.   *fg_r = (gdouble) r / 255.0;
  1337.   *fg_g = (gdouble) g / 255.0;
  1338.   *fg_b = (gdouble) b / 255.0;
  1339.   *fg_a = 1.0;                 /* opacity 100 % */
  1340. }
  1341.  
  1342. /*****/
  1343.  
  1344. static void
  1345. ed_update_editor (int flags)
  1346. {
  1347.   if (flags & GRAD_UPDATE_GRADIENT)
  1348.     {
  1349.       preview_update (TRUE);
  1350.       gradient_update ();
  1351.     }
  1352.  
  1353.   if (flags & GRAD_UPDATE_PREVIEW)
  1354.     preview_update (TRUE);
  1355.  
  1356.   if (flags & GRAD_UPDATE_CONTROL)
  1357.     control_update (FALSE);
  1358.  
  1359.   if (flags & GRAD_RESET_CONTROL)
  1360.     control_update (TRUE);
  1361. }
  1362.  
  1363. /*****/
  1364.  
  1365. static GtkWidget *
  1366. ed_create_button (gchar         *label,
  1367.           gchar         *help_data,
  1368.           GtkSignalFunc  signal_func,
  1369.           gpointer       data)
  1370. {
  1371.   GtkWidget *button;
  1372.  
  1373.   button = gtk_button_new_with_label (label);
  1374.   gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
  1375.   gtk_widget_show (button); 
  1376.  
  1377.   if (signal_func != NULL)
  1378.     gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1379.             signal_func,
  1380.             data);
  1381.  
  1382.   if (help_data)
  1383.     gimp_help_set_help_data (button, NULL, help_data);
  1384.  
  1385.   return button;
  1386. }
  1387.  
  1388. /*****/
  1389.  
  1390. static void
  1391. ed_set_hint (gchar *str)
  1392. {
  1393.   gtk_label_set_text (GTK_LABEL (g_editor->hint_label), str);
  1394. }
  1395.  
  1396. /*****/
  1397.  
  1398. static void
  1399. gradient_clist_fill_preview (gradient_t *gradient,
  1400.                  guchar     *buf,
  1401.                  gint        width,
  1402.                  gint        height,
  1403.                  gdouble     left,
  1404.                  gdouble     right)
  1405. {
  1406.   guchar  *p0, *p1;
  1407.   guchar  *even, *odd;
  1408.   gint     x, y;
  1409.   gdouble  dx, cur_x;
  1410.   gdouble  r, g, b, a;
  1411.   gdouble  c0, c1;
  1412.  
  1413.   dx    = (right - left) / (width - 1);
  1414.   cur_x = left;
  1415.   p0    = even = g_malloc (width * 3);
  1416.   p1    = odd  = g_malloc (width * 3);
  1417.  
  1418.   /* Create lines to fill the image */
  1419.  
  1420.   for (x = 0; x < width; x++)
  1421.     {
  1422.       gradient_get_color_at (gradient, cur_x, &r, &g, &b, &a);
  1423.  
  1424.       if ((x / GIMP_CHECK_SIZE_SM) & 1)
  1425.     {
  1426.       c0 = GIMP_CHECK_LIGHT;
  1427.       c1 = GIMP_CHECK_DARK;
  1428.     }
  1429.       else
  1430.     {
  1431.       c0 = GIMP_CHECK_DARK;
  1432.       c1 = GIMP_CHECK_LIGHT;
  1433.     }
  1434.  
  1435.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  1436.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  1437.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  1438.  
  1439.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  1440.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  1441.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  1442.  
  1443.       cur_x += dx;
  1444.     }
  1445.  
  1446.   for (y = 0; y < height; y++)
  1447.     {
  1448.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  1449.     {
  1450.       memcpy (buf + (width * y * 3), odd, width * 3); 
  1451.     }
  1452.       else
  1453.     {
  1454.       memcpy (buf + (width * y * 3), even, width * 3); 
  1455.     }
  1456.     }
  1457.  
  1458.   g_free (even);
  1459.   g_free (odd);
  1460. }
  1461.  
  1462. static void
  1463. gradient_clist_draw_small_preview (GdkGC      *gc,
  1464.                    GtkWidget  *clist,
  1465.                    gradient_t *gradient,
  1466.                    gint        pos)
  1467. {
  1468.   guchar rgb_buf[48 * 16 * 3];
  1469.  
  1470.   gradient_clist_fill_preview (gradient, rgb_buf, 48, 16, 0.0, 1.0);
  1471.  
  1472.   gdk_draw_rgb_image (gradient->pixmap, gc,
  1473.               0, 0,
  1474.               48, 16,
  1475.               GDK_RGB_DITHER_NORMAL,
  1476.               rgb_buf,
  1477.               48 * 3);
  1478.  
  1479.   gdk_gc_set_foreground (gc, &black);
  1480.   gdk_draw_rectangle (gradient->pixmap, gc, FALSE, 0, 0, 47, 15);
  1481.   gtk_clist_set_text (GTK_CLIST (clist), pos, 1, gradient->name);  
  1482. }
  1483.  
  1484. gint
  1485. gradient_clist_init (GtkWidget  *shell,
  1486.              GdkGC      *gc,
  1487.              GtkWidget  *clist,
  1488.              gradient_t *sel_gradient)
  1489. {
  1490.   GSList     *list;
  1491.   gradient_t *gradient;
  1492.   gint n;
  1493.   gint select_pos = -1;
  1494.  
  1495.   if (sel_gradient == NULL)
  1496.     sel_gradient = curr_gradient;
  1497.  
  1498.   if (sel_gradient == NULL)
  1499.     return 0;
  1500.  
  1501.   gtk_clist_freeze (GTK_CLIST (clist));
  1502.  
  1503.   for (list = gradients_list, n = 0; list; list = g_slist_next (list), n++)
  1504.     {
  1505.       gradient = (gradient_t *) list->data;
  1506.  
  1507.       if (gradient == sel_gradient)
  1508.     {
  1509.       gradient_clist_insert (shell, gc, clist, gradient, n, TRUE);
  1510.       select_pos = n;
  1511.     }
  1512.       else
  1513.     {
  1514.       gradient_clist_insert (shell, gc, clist, gradient, n, FALSE);
  1515.     }
  1516.     }
  1517.  
  1518.   gtk_clist_thaw (GTK_CLIST (clist));
  1519.  
  1520.   return select_pos;
  1521. }
  1522.  
  1523. void
  1524. gradient_clist_insert (GtkWidget  *shell,
  1525.                GdkGC      *gc,
  1526.                GtkWidget  *clist,
  1527.                gradient_t *gradient,
  1528.                gint        pos,
  1529.                gboolean    select)
  1530. {
  1531.   gchar *string[2];
  1532.  
  1533.   g_return_if_fail (gradient != NULL);
  1534.  
  1535.   string[0] = NULL;
  1536.   string[1] = gradient->name;
  1537.  
  1538.   pos = gtk_clist_insert (GTK_CLIST (clist), pos, string);
  1539.   gtk_clist_set_row_data (GTK_CLIST (clist), pos, gradient);
  1540.  
  1541.   if (gradient->pixmap == NULL)
  1542.     {
  1543.       gradient->pixmap =
  1544.     gdk_pixmap_new (shell->window, 48, 16,
  1545.             gtk_widget_get_visual (shell)->depth);
  1546.     }
  1547.  
  1548.   gradient_clist_draw_small_preview (gc, clist, gradient, pos);
  1549.  
  1550.   gtk_clist_set_pixmap (GTK_CLIST (clist), pos, 0, gradient->pixmap, NULL);
  1551.  
  1552.   if (select)
  1553.     {
  1554.       gtk_clist_select_row (GTK_CLIST (clist), pos, -1);
  1555.       gtk_clist_moveto (GTK_CLIST (clist), pos, 0, 0.5, 0.0);
  1556.     }
  1557. }
  1558.  
  1559. /*****/
  1560.  
  1561. static void
  1562. ed_list_item_update (GtkWidget      *widget, 
  1563.              gint            row,
  1564.              gint            column,
  1565.              GdkEventButton *event,
  1566.              gpointer        data)
  1567. {
  1568.   /* Update current gradient */
  1569.   curr_gradient = dnd_gradient = 
  1570.     (gradient_t *) gtk_clist_get_row_data (GTK_CLIST (widget), row); 
  1571.  
  1572.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL);
  1573. }
  1574.  
  1575. /*****/
  1576.  
  1577. static void
  1578. ed_initialize_saved_colors (void)
  1579. {
  1580.   int i;
  1581.  
  1582.   for (i = 0; i < (GRAD_NUM_COLORS + 3); i++)
  1583.     {
  1584.       g_editor->left_load_color_boxes[i] = NULL;
  1585.       g_editor->left_load_labels[i]      = NULL;
  1586.  
  1587.       g_editor->right_load_color_boxes[i] = NULL;
  1588.       g_editor->right_load_labels[i]      = NULL;
  1589.     }
  1590.  
  1591.   for (i = 0; i < GRAD_NUM_COLORS; i++)
  1592.     {
  1593.       g_editor->left_save_color_boxes[i] = NULL;
  1594.       g_editor->left_save_labels[i]      = NULL;
  1595.  
  1596.       g_editor->right_save_color_boxes[i] = NULL;
  1597.       g_editor->right_save_labels[i]      = NULL;
  1598.     }
  1599.  
  1600.   g_editor->saved_colors[0].r = 0.0; /* Black */
  1601.   g_editor->saved_colors[0].g = 0.0;
  1602.   g_editor->saved_colors[0].b = 0.0;
  1603.   g_editor->saved_colors[0].a = 1.0;
  1604.  
  1605.   g_editor->saved_colors[1].r = 0.5; /* 50% Gray */
  1606.   g_editor->saved_colors[1].g = 0.5;
  1607.   g_editor->saved_colors[1].b = 0.5;
  1608.   g_editor->saved_colors[1].a = 1.0;
  1609.  
  1610.   g_editor->saved_colors[2].r = 1.0; /* White */
  1611.   g_editor->saved_colors[2].g = 1.0;
  1612.   g_editor->saved_colors[2].b = 1.0;
  1613.   g_editor->saved_colors[2].a = 1.0;
  1614.  
  1615.   g_editor->saved_colors[3].r = 0.0; /* Clear */
  1616.   g_editor->saved_colors[3].g = 0.0;
  1617.   g_editor->saved_colors[3].b = 0.0;
  1618.   g_editor->saved_colors[3].a = 0.0;
  1619.  
  1620.   g_editor->saved_colors[4].r = 1.0; /* Red */
  1621.   g_editor->saved_colors[4].g = 0.0;
  1622.   g_editor->saved_colors[4].b = 0.0;
  1623.   g_editor->saved_colors[4].a = 1.0;
  1624.  
  1625.   g_editor->saved_colors[5].r = 1.0; /* Yellow */
  1626.   g_editor->saved_colors[5].g = 1.0;
  1627.   g_editor->saved_colors[5].b = 0.0;
  1628.   g_editor->saved_colors[5].a = 1.0;
  1629.  
  1630.   g_editor->saved_colors[6].r = 0.0; /* Green */
  1631.   g_editor->saved_colors[6].g = 1.0;
  1632.   g_editor->saved_colors[6].b = 0.0;
  1633.   g_editor->saved_colors[6].a = 1.0;
  1634.  
  1635.   g_editor->saved_colors[7].r = 0.0; /* Cyan */
  1636.   g_editor->saved_colors[7].g = 1.0;
  1637.   g_editor->saved_colors[7].b = 1.0;
  1638.   g_editor->saved_colors[7].a = 1.0;
  1639.  
  1640.   g_editor->saved_colors[8].r = 0.0; /* Blue */
  1641.   g_editor->saved_colors[8].g = 0.0;
  1642.   g_editor->saved_colors[8].b = 1.0;
  1643.   g_editor->saved_colors[8].a = 1.0;
  1644.  
  1645.   g_editor->saved_colors[9].r = 1.0; /* Magenta */
  1646.   g_editor->saved_colors[9].g = 0.0;
  1647.   g_editor->saved_colors[9].b = 1.0;
  1648.   g_editor->saved_colors[9].a = 1.0;
  1649. }
  1650.  
  1651. /***** Main gradient editor dialog callbacks *****/
  1652.  
  1653. /***** the "new gradient" dialog functions *****/
  1654.  
  1655. static void
  1656. ed_new_gradient_callback (GtkWidget *widget,
  1657.               gpointer   data)
  1658. {
  1659.   GtkWidget *qbox;
  1660.  
  1661.   qbox = gimp_query_string_box (_("New gradient"),
  1662.                 gimp_standard_help_func,
  1663.                 "dialogs/gradient_editor/new_gradient.html",
  1664.                 _("Enter a name for the new gradient"),
  1665.                 _("untitled"),
  1666.                 NULL, NULL,
  1667.                 ed_do_new_gradient_callback, NULL);
  1668.   gtk_widget_show (qbox);
  1669. }
  1670.  
  1671. static void
  1672. ed_do_new_gradient_callback (GtkWidget *widget,
  1673.                  gchar     *gradient_name,
  1674.                  gpointer   data)
  1675. {
  1676.   gradient_t *grad;
  1677.   gint        pos;
  1678.  
  1679.   if (!gradient_name)
  1680.     {
  1681.       g_warning ("received NULL in call_data");
  1682.       return;
  1683.     }
  1684.  
  1685.   grad = grad_create_default_gradient ();
  1686.  
  1687.   grad->name     = gradient_name; /* We don't need to copy since 
  1688.                      this memory is ours */
  1689.   grad->dirty    = TRUE;
  1690.   grad->filename = build_user_filename (grad->name, gradient_path);
  1691.  
  1692.   /* Put new gradient in list */
  1693.  
  1694.   pos = grad_insert_in_gradients_list (grad);
  1695.   gtk_clist_freeze (GTK_CLIST (g_editor->clist));
  1696.   gradient_clist_insert (g_editor->shell, g_editor->gc, g_editor->clist,
  1697.              grad, pos, TRUE);
  1698.   gtk_clist_thaw (GTK_CLIST (g_editor->clist));
  1699.   gtk_clist_moveto (GTK_CLIST (g_editor->clist), pos, 0, 0.5, 0.0);
  1700.  
  1701.   curr_gradient = dnd_gradient = grad;
  1702.  
  1703.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL);
  1704.  
  1705.   gradient_select_insert_all (pos, grad);
  1706. }
  1707.  
  1708. /***** The "copy gradient" dialog functions *****/
  1709.  
  1710. static void
  1711. ed_copy_gradient_callback (GtkWidget *widget,
  1712.                gpointer   data)
  1713. {
  1714.   GtkWidget *qbox;
  1715.   gchar     *name;
  1716.  
  1717.   if (curr_gradient == NULL) 
  1718.     return;
  1719.  
  1720.   name = g_strdup_printf (_("%s copy"), curr_gradient->name);
  1721.  
  1722.   qbox = gimp_query_string_box (_("Copy gradient"),
  1723.                 gimp_standard_help_func,
  1724.                 "dialogs/gradient_editor/copy_gradient.html",
  1725.                 _("Enter a name for the copied gradient"),
  1726.                 name,
  1727.                 NULL, NULL,
  1728.                 ed_do_copy_gradient_callback, NULL);
  1729.   gtk_widget_show (qbox);
  1730.  
  1731.   g_free (name);
  1732. }
  1733.  
  1734. static void
  1735. ed_do_copy_gradient_callback (GtkWidget *widget,
  1736.                   gchar     *gradient_name,
  1737.                   gpointer   data)
  1738. {
  1739.   gradient_t     *grad;
  1740.   gint            pos;
  1741.   grad_segment_t *head, *prev, *cur, *orig;
  1742.  
  1743.   if (!gradient_name)
  1744.     {
  1745.       g_warning ("received NULL in call_data");
  1746.       return;
  1747.     }
  1748.  
  1749.   /* Copy current gradient */
  1750.   grad = grad_new_gradient ();
  1751.   if (grad == NULL)
  1752.     return;
  1753.  
  1754.   grad->name     = gradient_name; /* We don't need to copy since 
  1755.                      this memory is ours */
  1756.   grad->dirty    = TRUE;
  1757.   grad->filename = build_user_filename (grad->name, gradient_path);
  1758.  
  1759.   prev = NULL;
  1760.   orig = curr_gradient->segments;
  1761.   head = NULL;
  1762.  
  1763.   while (orig)
  1764.     {
  1765.       cur = seg_new_segment ();
  1766.  
  1767.       *cur = *orig;  /* Copy everything */
  1768.  
  1769.       cur->prev = prev;
  1770.       cur->next = NULL;
  1771.  
  1772.       if (prev)
  1773.     prev->next = cur;
  1774.       else
  1775.     head = cur;  /* Remember head */
  1776.  
  1777.       prev = cur;
  1778.       orig = orig->next;
  1779.     }
  1780.  
  1781.   grad->segments = head;
  1782.  
  1783.   /* Put new gradient in list */
  1784.   pos = grad_insert_in_gradients_list (grad);
  1785.   gtk_clist_freeze (GTK_CLIST (g_editor->clist));
  1786.   gradient_clist_insert (g_editor->shell, g_editor->gc, g_editor->clist,
  1787.              grad, pos, TRUE);
  1788.   gtk_clist_thaw (GTK_CLIST (g_editor->clist));
  1789.  
  1790.   curr_gradient = dnd_gradient = grad;
  1791.  
  1792.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL);
  1793.  
  1794.   gradient_select_insert_all (pos, grad);
  1795. }
  1796.  
  1797. /***** The "rename gradient" dialog functions *****/
  1798.  
  1799. static void
  1800. ed_rename_gradient_callback (GtkWidget *widget,
  1801.                  gpointer   data)
  1802. {
  1803.   GtkWidget *qbox;
  1804.  
  1805.   if (curr_gradient == NULL)
  1806.     return;
  1807.  
  1808.   qbox = gimp_query_string_box (_("Rename gradient"),
  1809.                 gimp_standard_help_func,
  1810.                 "dialogs/gradient_editor/rename_gradient.html",
  1811.                 _("Enter a new name for the gradient"),
  1812.                 curr_gradient->name,
  1813.                 NULL, NULL,
  1814.                 ed_do_rename_gradient_callback,
  1815.                 curr_gradient);
  1816.   gtk_widget_show (qbox);
  1817. }
  1818.  
  1819. static void
  1820. ed_do_rename_gradient_callback (GtkWidget *widget,
  1821.                 gchar     *gradient_name,
  1822.                 gpointer   data)
  1823. {
  1824.   gradient_t *grad = (gradient_t *) data;
  1825.   gint        row;
  1826.  
  1827.   g_return_if_fail (grad != NULL);
  1828.  
  1829.   if (!gradient_name)
  1830.     {
  1831.       g_warning ("received NULL in call_data");
  1832.       return;
  1833.     }
  1834.  
  1835.   g_free (grad->name);
  1836.   grad->name  = gradient_name; /* We don't need to copy since 
  1837.                   this memory is ours */
  1838.   grad->dirty = TRUE;
  1839.  
  1840.   /* Delete file and free gradient */
  1841.   unlink (grad->filename);
  1842.  
  1843.   g_free (grad->filename);
  1844.   grad->filename = build_user_filename (grad->name, gradient_path);
  1845.  
  1846.   row = gtk_clist_find_row_from_data (GTK_CLIST (g_editor->clist), grad);
  1847.   if (row > -1)
  1848.     gtk_clist_set_text (GTK_CLIST (g_editor->clist), row, 1, grad->name);
  1849.  
  1850.   gradient_select_rename_all (grad);
  1851.  
  1852.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL);
  1853.     
  1854.   gimp_context_update_gradients (grad);
  1855. }
  1856.  
  1857. /***** The "delete gradient" dialog functions *****/
  1858.  
  1859. static void
  1860. ed_delete_gradient_callback (GtkWidget *widget,
  1861.                  gpointer   data)
  1862. {
  1863.   GtkWidget *dialog;
  1864.   gchar     *str;
  1865.  
  1866.   if (num_gradients <= 1 || curr_gradient == NULL)
  1867.     return;
  1868.  
  1869.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  1870.  
  1871.   str = g_strdup_printf (_("Are you sure you want to delete\n"
  1872.                "\"%s\" from the list and from disk?"),
  1873.              curr_gradient->name);
  1874.  
  1875.   dialog =
  1876.     gimp_query_boolean_box (_("Delete Gradient"),
  1877.                 gimp_standard_help_func,
  1878.                 "dialogs/gradient_editor/delete_gradient.html",
  1879.                 FALSE,
  1880.                 str,
  1881.                 _("Delete"), _("Cancel"),
  1882.                 NULL, NULL,
  1883.                 ed_do_delete_gradient_callback,
  1884.                 NULL);
  1885.  
  1886.   g_free (str);
  1887.  
  1888.   gtk_widget_show (dialog);
  1889. }
  1890.  
  1891. static void
  1892. ed_do_delete_gradient_callback (GtkWidget *widget,
  1893.                 gboolean   delete,
  1894.                 gpointer   data)
  1895. {
  1896.   gradient_t *delete_gradient;
  1897.   gint        row;
  1898.  
  1899.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  1900.  
  1901.   if (! delete || curr_gradient == NULL)
  1902.     return;
  1903.   
  1904.   delete_gradient = curr_gradient;
  1905.   curr_gradient   = NULL;
  1906.  
  1907.  /* Delete gradient from clists */
  1908.   gradient_select_delete_all (delete_gradient);
  1909.  
  1910.   row = gtk_clist_find_row_from_data (GTK_CLIST (g_editor->clist), 
  1911.                       delete_gradient);
  1912.   if (row > -1)
  1913.     gtk_clist_remove (GTK_CLIST (g_editor->clist), row);
  1914.  
  1915.   /* Delete gradient from gradients list */
  1916.   gradients_list = g_slist_remove (gradients_list, delete_gradient);
  1917.   num_gradients--;
  1918.  
  1919.   /* Delete file and free gradient*/
  1920.   unlink (delete_gradient->filename);
  1921.   grad_free_gradient (delete_gradient);
  1922.  
  1923.   gimp_context_refresh_gradients ();
  1924. }
  1925.  
  1926. /***** The "save as pov" dialog functions *****/
  1927.  
  1928. static void
  1929. ed_save_pov_callback (GtkWidget *widget,
  1930.               gpointer   data)
  1931. {
  1932.   GtkWidget *window;
  1933.  
  1934.   if (curr_gradient == NULL)
  1935.     return;
  1936.  
  1937.   window = gtk_file_selection_new (_("Save as POV-Ray"));
  1938.   gtk_window_set_wmclass (GTK_WINDOW (window), "save_gradient", "Gimp");
  1939.   gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
  1940.  
  1941.   gtk_container_set_border_width (GTK_CONTAINER (window), 2);
  1942.   gtk_container_set_border_width (GTK_CONTAINER (GTK_FILE_SELECTION (window)->button_area), 2);
  1943.  
  1944.   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->ok_button),
  1945.               "clicked",
  1946.               GTK_SIGNAL_FUNC (ed_do_save_pov_callback),
  1947.               window);
  1948.  
  1949.   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->cancel_button),
  1950.               "clicked",
  1951.               GTK_SIGNAL_FUNC (ed_cancel_save_pov_callback),
  1952.               window);
  1953.  
  1954.   gtk_signal_connect (GTK_OBJECT (window), "delete_event",
  1955.               GTK_SIGNAL_FUNC (ed_delete_save_pov_callback),
  1956.               window);
  1957.  
  1958.   /*  Connect the "F1" help key  */
  1959.   gimp_help_connect_help_accel (window, gimp_standard_help_func,
  1960.                 "dialogs/gradient_editor/save_as_povray.html");
  1961.  
  1962.   gtk_widget_show (window);
  1963.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  1964. }
  1965.  
  1966. static void
  1967. ed_do_save_pov_callback (GtkWidget *widget,
  1968.              gpointer   data)
  1969. {
  1970.   gchar          *filename;
  1971.   FILE           *file;
  1972.   grad_segment_t *seg;
  1973.  
  1974.   if (curr_gradient == NULL)
  1975.     return;
  1976.  
  1977.   filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (data));
  1978.  
  1979.   file = fopen (filename, "wb");
  1980.  
  1981.   if (!file)
  1982.     {
  1983.       g_message ("Could not open \"%s\"", filename);
  1984.     }
  1985.   else
  1986.     {
  1987.       fprintf (file, "/* color_map file created by the GIMP */\n");
  1988.       fprintf (file, "/* http://www.gimp.org/               */\n");
  1989.  
  1990.       fprintf (file, "color_map {\n");
  1991.  
  1992.       for (seg = curr_gradient->segments; seg; seg = seg->next)
  1993.     {
  1994.       /* Left */
  1995.       fprintf (file, "\t[%f color rgbt <%f, %f, %f, %f>]\n",
  1996.            seg->left,
  1997.            seg->r0, seg->g0, seg->b0, 1.0 - seg->a0);
  1998.  
  1999.       /* Middle */
  2000.       fprintf (file, "\t[%f color rgbt <%f, %f, %f, %f>]\n",
  2001.            seg->middle,
  2002.            (seg->r0 + seg->r1) / 2.0,
  2003.            (seg->g0 + seg->g1) / 2.0,
  2004.            (seg->b0 + seg->b1) / 2.0,
  2005.            1.0 - (seg->a0 + seg->a1) / 2.0);
  2006.  
  2007.       /* Right */
  2008.       fprintf (file, "\t[%f color rgbt <%f, %f, %f, %f>]\n",
  2009.            seg->right,
  2010.            seg->r1, seg->g1, seg->b1, 1.0 - seg->a1);
  2011.     }
  2012.  
  2013.       fprintf (file, "} /* color_map */\n");
  2014.       fclose (file);
  2015.     }
  2016.  
  2017.   gtk_widget_destroy (GTK_WIDGET (data));
  2018.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  2019. }
  2020.  
  2021. static void
  2022. ed_cancel_save_pov_callback (GtkWidget *widget,
  2023.                  gpointer   data)
  2024. {
  2025.   gtk_widget_destroy (GTK_WIDGET (data));
  2026.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  2027. }
  2028.  
  2029. static gint
  2030. ed_delete_save_pov_callback (GtkWidget *widget,
  2031.                  GdkEvent  *event,
  2032.                  gpointer   data)
  2033. {
  2034.   ed_cancel_save_pov_callback (widget, data);
  2035.  
  2036.   return TRUE;
  2037. }
  2038.  
  2039. /***** The main dialog action area button callbacks *****/
  2040.  
  2041. static void
  2042. ed_refresh_grads_callback (GtkWidget *widget,
  2043.                gpointer   data)
  2044. {
  2045.   gint select_pos;
  2046.  
  2047.   gtk_clist_freeze (GTK_CLIST (g_editor->clist));
  2048.   gtk_clist_clear (GTK_CLIST (g_editor->clist));
  2049.   gtk_clist_thaw (GTK_CLIST (g_editor->clist));
  2050.     
  2051.   gradient_select_free_all ();
  2052.  
  2053.   gradients_init (FALSE);
  2054.  
  2055.   if (gradients_list)
  2056.     {
  2057.       curr_gradient = dnd_gradient = (gradient_t *) gradients_list->data;
  2058.     }
  2059.   else
  2060.     {
  2061.       curr_gradient = dnd_gradient = grad_create_default_gradient ();
  2062.       curr_gradient->name     = g_strdup (_("Default"));
  2063.       curr_gradient->filename =
  2064.         build_user_filename (curr_gradient->name, gradient_path);
  2065.       curr_gradient->dirty    = FALSE;
  2066.  
  2067.       grad_insert_in_gradients_list (curr_gradient);
  2068.       gimp_context_refresh_gradients ();
  2069.     }
  2070.  
  2071.   select_pos = gradient_clist_init (g_editor->shell, g_editor->gc,
  2072.                     g_editor->clist,
  2073.                     curr_gradient);
  2074.  
  2075.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL); 
  2076.  
  2077.   if (select_pos != -1)
  2078.     gtk_clist_moveto (GTK_CLIST (g_editor->clist), select_pos, 0, 0.5, 0.0);
  2079.  
  2080.   gradient_select_refill_all ();
  2081. }
  2082.  
  2083. static void
  2084. ed_close_callback (GtkWidget *widget,
  2085.            gpointer   data)
  2086. {
  2087.   if (GTK_WIDGET_VISIBLE (g_editor->shell))
  2088.     gtk_widget_hide (g_editor->shell);
  2089. }
  2090.  
  2091. /***** Zoom, scrollbar & instant update callbacks *****/
  2092.  
  2093. static void
  2094. ed_scrollbar_update (GtkAdjustment *adjustment,
  2095.              gpointer       data)
  2096. {
  2097.   gchar *str;
  2098.  
  2099.   str = g_strdup_printf (_("Zoom factor: %d:1    Displaying [%0.6f, %0.6f]"),
  2100.              g_editor->zoom_factor, adjustment->value,
  2101.              adjustment->value + adjustment->page_size);
  2102.  
  2103.   ed_set_hint (str);
  2104.   g_free (str);
  2105.  
  2106.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_UPDATE_CONTROL);
  2107. }
  2108.  
  2109. static void
  2110. ed_zoom_all_callback (GtkWidget *widget,
  2111.               gpointer   data)
  2112. {
  2113.   GtkAdjustment *adjustment;
  2114.  
  2115.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  2116.  
  2117.   g_editor->zoom_factor = 1;
  2118.  
  2119.   gtk_widget_hide (g_editor->scrollbar);
  2120.  
  2121.   adjustment->value            = 0.0;
  2122.   adjustment->page_size        = 1.0;
  2123.   adjustment->step_increment = 1.0 * GRAD_SCROLLBAR_STEP_SIZE;
  2124.   adjustment->page_increment = 1.0 * GRAD_SCROLLBAR_PAGE_SIZE;
  2125.  
  2126.   gtk_signal_emit_by_name (g_editor->scroll_data, "changed");
  2127. }
  2128.  
  2129. static void
  2130. ed_zoom_out_callback (GtkWidget *widget,
  2131.               gpointer   data)
  2132. {
  2133.   GtkAdjustment *adjustment;
  2134.   gdouble        old_value;
  2135.   gdouble        value;
  2136.   gdouble        old_page_size;
  2137.   gdouble        page_size;
  2138.  
  2139.   if (g_editor->zoom_factor <= 1)
  2140.     return;
  2141.  
  2142.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  2143.  
  2144.   old_value     = adjustment->value;
  2145.   old_page_size = adjustment->page_size;
  2146.  
  2147.   g_editor->zoom_factor--;
  2148.  
  2149.   if (g_editor->zoom_factor==1)
  2150.     gtk_widget_hide (g_editor->scrollbar);
  2151.   else
  2152.     gtk_widget_show (g_editor->scrollbar);
  2153.  
  2154.   page_size = 1.0 / g_editor->zoom_factor;
  2155.   value     = old_value - (page_size - old_page_size) / 2.0;
  2156.  
  2157.   if (value < 0.0)
  2158.     value = 0.0;
  2159.   else if ((value + page_size) > 1.0)
  2160.     value = 1.0 - page_size;
  2161.  
  2162.   adjustment->value          = value;
  2163.   adjustment->page_size      = page_size;
  2164.   adjustment->step_increment = page_size * GRAD_SCROLLBAR_STEP_SIZE;
  2165.   adjustment->page_increment = page_size * GRAD_SCROLLBAR_PAGE_SIZE;
  2166.  
  2167.   gtk_signal_emit_by_name (g_editor->scroll_data, "changed");
  2168. }
  2169.  
  2170. static void
  2171. ed_zoom_in_callback (GtkWidget *widget,
  2172.              gpointer   data)
  2173. {
  2174.   GtkAdjustment *adjustment;
  2175.   gdouble        old_value;
  2176.   gdouble        old_page_size;
  2177.   gdouble        page_size;
  2178.  
  2179.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  2180.  
  2181.   old_value     = adjustment->value;
  2182.   old_page_size = adjustment->page_size;
  2183.  
  2184.   g_editor->zoom_factor++;
  2185.  
  2186.   page_size = 1.0 / g_editor->zoom_factor;
  2187.  
  2188.   adjustment->value             = old_value + (old_page_size - page_size) / 2.0;
  2189.   adjustment->page_size      = page_size;
  2190.   adjustment->step_increment = page_size * GRAD_SCROLLBAR_STEP_SIZE;
  2191.   adjustment->page_increment = page_size * GRAD_SCROLLBAR_PAGE_SIZE;
  2192.  
  2193.   gtk_signal_emit_by_name (g_editor->scroll_data, "changed");
  2194.   gtk_widget_show (g_editor->scrollbar);
  2195. }
  2196.  
  2197. static void
  2198. ed_instant_update_update (GtkWidget *widget,
  2199.               gpointer   data)
  2200. {
  2201.   if (GTK_TOGGLE_BUTTON (widget)->active)
  2202.     {
  2203.       g_editor->instant_update = TRUE;
  2204.       gtk_range_set_update_policy (GTK_RANGE (g_editor->scrollbar),
  2205.                    GTK_UPDATE_CONTINUOUS);
  2206.     }
  2207.   else
  2208.     {
  2209.       g_editor->instant_update = FALSE;
  2210.       gtk_range_set_update_policy (GTK_RANGE (g_editor->scrollbar),
  2211.                    GTK_UPDATE_DELAYED);
  2212.     }
  2213. }
  2214.  
  2215. /***** Gradient preview functions *****/
  2216.  
  2217. static gint
  2218. preview_events (GtkWidget *widget,
  2219.          GdkEvent  *event,
  2220.          gpointer   data)
  2221. {
  2222.   gint            x, y;
  2223.   GdkEventButton *bevent;
  2224.   GdkEventMotion *mevent;
  2225.  
  2226.   /* ignore events when no gradient is present */
  2227.   if (curr_gradient == NULL) 
  2228.     return FALSE;
  2229.  
  2230.   switch (event->type)
  2231.     {
  2232.     case GDK_EXPOSE:
  2233.       preview_update (FALSE);
  2234.       break;
  2235.  
  2236.     case GDK_LEAVE_NOTIFY:
  2237.       ed_set_hint ("");
  2238.       break;
  2239.  
  2240.     case GDK_MOTION_NOTIFY:
  2241.       gtk_widget_get_pointer (g_editor->preview, &x, &y);
  2242.  
  2243.       mevent = (GdkEventMotion *) event;
  2244.  
  2245.       if (x != g_editor->preview_last_x)
  2246.     {
  2247.       g_editor->preview_last_x = x;
  2248.  
  2249.       if (g_editor->preview_button_down)
  2250.         {
  2251.           if (mevent->state & GDK_CONTROL_MASK)
  2252.         preview_set_background (x);
  2253.           else
  2254.         preview_set_foreground (x);
  2255.         }
  2256.       else
  2257.         {
  2258.           preview_set_hint (x);
  2259.         }
  2260.     }
  2261.       break;
  2262.  
  2263.     case GDK_BUTTON_PRESS:
  2264.       gtk_widget_get_pointer (g_editor->preview, &x, &y);
  2265.  
  2266.       bevent = (GdkEventButton *) event;
  2267.  
  2268.       switch (bevent->button)
  2269.     {
  2270.     case 1:
  2271.       g_editor->preview_last_x = x;
  2272.       g_editor->preview_button_down = TRUE;
  2273.       if (bevent->state & GDK_CONTROL_MASK)
  2274.         preview_set_background (x);
  2275.       else
  2276.         preview_set_foreground (x);
  2277.       break;
  2278.  
  2279.     case 3:
  2280.       cpopup_do_popup ();
  2281.       break;
  2282.  
  2283.       /*  wheelmouse support  */
  2284.     case 4:
  2285.       {
  2286.         GtkAdjustment *adj = GTK_ADJUSTMENT (g_editor->scroll_data);
  2287.         gfloat new_value = adj->value - adj->page_increment / 2;
  2288.         new_value =
  2289.           CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  2290.         gtk_adjustment_set_value (adj, new_value);
  2291.       }
  2292.       break;
  2293.  
  2294.     case 5:
  2295.       {
  2296.         GtkAdjustment *adj = GTK_ADJUSTMENT (g_editor->scroll_data);
  2297.         gfloat new_value = adj->value + adj->page_increment / 2;
  2298.         new_value =
  2299.           CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  2300.         gtk_adjustment_set_value (adj, new_value);
  2301.       }
  2302.       break;
  2303.  
  2304.     default:
  2305.       break;
  2306.     }
  2307.  
  2308.       break;
  2309.  
  2310.     case GDK_BUTTON_RELEASE:
  2311.       if (g_editor->preview_button_down)
  2312.     {
  2313.       gtk_widget_get_pointer (g_editor->preview, &x, &y);
  2314.  
  2315.       bevent = (GdkEventButton *) event;
  2316.  
  2317.       g_editor->preview_last_x = x;
  2318.       g_editor->preview_button_down = FALSE;
  2319.       if (bevent->state & GDK_CONTROL_MASK)
  2320.         preview_set_background (x);
  2321.       else
  2322.         preview_set_foreground (x);
  2323.       break;
  2324.     }
  2325.  
  2326.       break;
  2327.  
  2328.     default:
  2329.       break;
  2330.     }
  2331.  
  2332.   return FALSE;
  2333. }
  2334.  
  2335. /*****/
  2336.  
  2337. static void
  2338. preview_set_hint (gint x)
  2339. {
  2340.   gdouble  xpos;
  2341.   gdouble  r, g, b, a;
  2342.   gdouble  h, s, v;
  2343.   gchar   *str;
  2344.  
  2345.   xpos = control_calc_g_pos (x);
  2346.  
  2347.   gradient_get_color_at (curr_gradient, xpos, &r, &g, &b, &a);
  2348.  
  2349.   h = r;
  2350.   s = g;
  2351.   v = b;
  2352.  
  2353.   gimp_rgb_to_hsv_double (&h, &s, &v);
  2354.  
  2355.   str = g_strdup_printf (_("Position: %0.6f    "
  2356.                "RGB (%0.3f, %0.3f, %0.3f)    "
  2357.                "HSV (%0.3f, %0.3f, %0.3f)    "
  2358.                "Opacity: %0.3f"),
  2359.              xpos, r, g, b, h * 360.0, s, v, a);
  2360.  
  2361.   ed_set_hint (str);
  2362.   g_free (str);
  2363. }
  2364.  
  2365. /*****/
  2366.  
  2367. static void
  2368. preview_set_foreground (gint x)
  2369. {
  2370.   gdouble  xpos;
  2371.   gdouble  r, g, b, a;
  2372.   gchar   *str;
  2373.  
  2374.   xpos = control_calc_g_pos (x);
  2375.   gradient_get_color_at (curr_gradient, xpos, &r, &g, &b, &a);
  2376.  
  2377.   gimp_context_set_foreground (gimp_context_get_user (),
  2378.                    r * 255.0, g * 255.0, b * 255.0);
  2379.  
  2380.   str = g_strdup_printf (_("Foreground color set to RGB (%d, %d, %d) <-> "
  2381.                "(%0.3f, %0.3f, %0.3f)"),
  2382.              (gint) (r * 255.0),
  2383.              (gint) (g * 255.0),
  2384.              (gint) (b * 255.0),
  2385.              r, g, b);
  2386.  
  2387.   ed_set_hint (str);
  2388.   g_free (str);
  2389. }
  2390.  
  2391. static void
  2392. preview_set_background (gint x)
  2393. {
  2394.   gdouble xpos;
  2395.   gdouble r, g, b, a;
  2396.   gchar   *str;
  2397.  
  2398.   xpos = control_calc_g_pos (x);
  2399.   gradient_get_color_at (curr_gradient, xpos, &r, &g, &b, &a);
  2400.  
  2401.   gimp_context_set_background (gimp_context_get_user (),
  2402.                    r * 255.0, g * 255.0, b * 255.0);
  2403.  
  2404.   str = g_strdup_printf (_("Background color to RGB (%d, %d, %d) <-> "
  2405.                "(%0.3f, %0.3f, %0.3f)"),
  2406.              (gint) (r * 255.0),
  2407.              (gint) (g * 255.0),
  2408.              (gint) (b * 255.0),
  2409.              r, g, b);
  2410.  
  2411.   ed_set_hint (str);
  2412.   g_free (str);
  2413. }
  2414.  
  2415. /*****/
  2416.  
  2417. static void
  2418. gradient_update (void)
  2419. {
  2420.   gint row;
  2421.  
  2422.   row = gtk_clist_find_row_from_data (GTK_CLIST (g_editor->clist), 
  2423.                       curr_gradient);  
  2424.   if (row < 0)
  2425.     return;
  2426.  
  2427.   gradient_clist_draw_small_preview (g_editor->gc, g_editor->clist,
  2428.                      curr_gradient, row);
  2429.  
  2430.   /*  Update all selectors that are on screen  */
  2431.   gradient_select_update_all (curr_gradient);
  2432.  
  2433.   /*  Update all contexts  */
  2434.   gimp_context_update_gradients (curr_gradient);
  2435. }
  2436.  
  2437. static void
  2438. preview_update (gboolean recalculate)
  2439. {
  2440.   glong          rowsiz;
  2441.   GtkAdjustment *adjustment;
  2442.   guint16        width;
  2443.   guint16        height;
  2444.  
  2445.   static guint16  last_width  = 0;
  2446.   static guint16  last_height = 0;
  2447.  
  2448.   /* We only update if we can draw to the widget and a gradient is present */
  2449.   if (curr_gradient == NULL) 
  2450.     return;
  2451.  
  2452.   if (! GTK_WIDGET_DRAWABLE (g_editor->preview))
  2453.     return;
  2454.  
  2455.   /*  See whether we have to re-create the preview widget
  2456.    *  (note that the preview automatically follows the size of it's container)
  2457.    */
  2458.   width  = g_editor->preview->allocation.width;
  2459.   height = g_editor->preview->allocation.height;
  2460.  
  2461.   if (! g_editor->preview_rows[0] ||
  2462.       ! g_editor->preview_rows[1] ||
  2463.       (width  != last_width)      ||
  2464.       (height != last_height))
  2465.     {
  2466.       if (g_editor->preview_rows[0])
  2467.     g_free (g_editor->preview_rows[0]);
  2468.  
  2469.       if (g_editor->preview_rows[1])
  2470.     g_free (g_editor->preview_rows[1]);
  2471.  
  2472.       rowsiz = width * 3 * sizeof (guchar);
  2473.  
  2474.       g_editor->preview_rows[0] = g_malloc (rowsiz);
  2475.       g_editor->preview_rows[1] = g_malloc (rowsiz);
  2476.  
  2477.       recalculate = TRUE; /* Force recalculation */
  2478.     }
  2479.  
  2480.   last_width = width;
  2481.   last_height = height;
  2482.  
  2483.   /* Have to redraw? */
  2484.   if (recalculate)
  2485.     {
  2486.       adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  2487.  
  2488.       preview_fill_image (width, height,
  2489.               adjustment->value,
  2490.               adjustment->value + adjustment->page_size);
  2491.  
  2492.       gtk_widget_draw (g_editor->preview, NULL);
  2493.     }
  2494. }
  2495.  
  2496. /*****/
  2497.  
  2498. static void
  2499. preview_fill_image (gint    width,
  2500.             gint    height,
  2501.             gdouble left,
  2502.             gdouble right)
  2503. {
  2504.   guchar  *p0, *p1;
  2505.   gint     x, y;
  2506.   gdouble  dx, cur_x;
  2507.   gdouble  r, g, b, a;
  2508.   gdouble  c0, c1;
  2509.  
  2510.   dx    = (right - left) / (width - 1);
  2511.   cur_x = left;
  2512.   p0    = g_editor->preview_rows[0];
  2513.   p1    = g_editor->preview_rows[1];
  2514.  
  2515.   /* Create lines to fill the image */
  2516.   for (x = 0; x < width; x++)
  2517.     {
  2518.       gradient_get_color_at (curr_gradient, cur_x, &r, &g, &b, &a);
  2519.  
  2520.       if ((x / GIMP_CHECK_SIZE) & 1)
  2521.     {
  2522.       c0 = GIMP_CHECK_LIGHT;
  2523.       c1 = GIMP_CHECK_DARK;
  2524.     }
  2525.       else
  2526.     {
  2527.       c0 = GIMP_CHECK_DARK;
  2528.       c1 = GIMP_CHECK_LIGHT;
  2529.     }
  2530.  
  2531.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  2532.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  2533.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  2534.  
  2535.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  2536.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  2537.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  2538.  
  2539.       cur_x += dx;
  2540.     }
  2541.  
  2542.   /* Fill image */
  2543.   for (y = 0; y < height; y++)
  2544.     {
  2545.       if ((y / GIMP_CHECK_SIZE) & 1)
  2546.     gtk_preview_draw_row (GTK_PREVIEW (g_editor->preview),
  2547.                   g_editor->preview_rows[1], 0, y, width);
  2548.       else
  2549.     gtk_preview_draw_row (GTK_PREVIEW (g_editor->preview),
  2550.                   g_editor->preview_rows[0], 0, y, width);
  2551.     }
  2552. }
  2553.  
  2554. /***** Gradient control functions *****/
  2555.  
  2556. /* *** WARNING *** WARNING *** WARNING ***
  2557.  *
  2558.  * All the event-handling code for the gradient control widget is
  2559.  * extremely hairy.  You are not expected to understand it.  If you
  2560.  * find bugs, mail me unless you are very brave and you want to fix
  2561.  * them yourself ;-)
  2562.  */
  2563.  
  2564. static gint
  2565. control_events (GtkWidget *widget,
  2566.         GdkEvent  *event,
  2567.         gpointer   data)
  2568. {
  2569.   GdkEventButton *bevent;
  2570.   grad_segment_t *seg;
  2571.   gint            x, y;
  2572.   guint32         time;
  2573.  
  2574.   switch (event->type)
  2575.     {
  2576.     case GDK_EXPOSE:
  2577.       control_update (FALSE);
  2578.       break;
  2579.  
  2580.     case GDK_LEAVE_NOTIFY:
  2581.       ed_set_hint ("");
  2582.       break;
  2583.  
  2584.     case GDK_BUTTON_PRESS:
  2585.       if (g_editor->control_drag_mode == GRAD_DRAG_NONE)
  2586.     {
  2587.       gtk_widget_get_pointer (g_editor->control, &x, &y);
  2588.  
  2589.       bevent = (GdkEventButton *) event;
  2590.  
  2591.       g_editor->control_last_x     = x;
  2592.       g_editor->control_click_time = bevent->time;
  2593.  
  2594.       control_button_press (x, y, bevent->button, bevent->state);
  2595.  
  2596.       if (g_editor->control_drag_mode != GRAD_DRAG_NONE)
  2597.         gtk_grab_add (widget);
  2598.     }
  2599.       break;
  2600.  
  2601.     case GDK_BUTTON_RELEASE:
  2602.       ed_set_hint ("");
  2603.  
  2604.       if (g_editor->control_drag_mode != GRAD_DRAG_NONE)
  2605.     {
  2606.       gtk_grab_remove (widget);
  2607.  
  2608.       gtk_widget_get_pointer (g_editor->control, &x, &y);
  2609.  
  2610.       time = ((GdkEventButton *) event)->time;
  2611.  
  2612.       if ((time - g_editor->control_click_time) >= GRAD_MOVE_TIME)
  2613.         {
  2614.           ed_update_editor (GRAD_UPDATE_GRADIENT); /* Possible move */
  2615.         }
  2616.       else if ((g_editor->control_drag_mode == GRAD_DRAG_MIDDLE) ||
  2617.            (g_editor->control_drag_mode == GRAD_DRAG_ALL))
  2618.         {
  2619.           seg = g_editor->control_drag_segment;
  2620.  
  2621.           if ((g_editor->control_drag_mode == GRAD_DRAG_ALL) &&
  2622.           g_editor->control_compress)
  2623.         control_extend_selection (seg, control_calc_g_pos (x));
  2624.           else
  2625.         control_select_single_segment (seg);
  2626.  
  2627.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2628.         }
  2629.  
  2630.       g_editor->control_drag_mode = GRAD_DRAG_NONE;
  2631.       g_editor->control_compress  = FALSE;
  2632.  
  2633.       control_do_hint (x, y);
  2634.     }
  2635.       break;
  2636.  
  2637.     case GDK_MOTION_NOTIFY:
  2638.       gtk_widget_get_pointer (g_editor->control, &x, &y);
  2639.  
  2640.       if (x != g_editor->control_last_x)
  2641.     {
  2642.       g_editor->control_last_x = x;
  2643.  
  2644.       if (g_editor->control_drag_mode != GRAD_DRAG_NONE)
  2645.         {
  2646.           time = ((GdkEventButton *) event)->time;
  2647.  
  2648.           if ((time - g_editor->control_click_time) >= GRAD_MOVE_TIME)
  2649.         control_motion(x);
  2650.         }
  2651.       else
  2652.         {
  2653.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2654.  
  2655.           control_do_hint (x, y);
  2656.         }
  2657.     }
  2658.       break;
  2659.  
  2660.     default:
  2661.       break;
  2662.     }
  2663.  
  2664.   return FALSE;
  2665. }
  2666.  
  2667. /*****/
  2668.  
  2669. static void
  2670. control_do_hint (gint x,
  2671.          gint y)
  2672. {
  2673.   grad_segment_t      *seg;
  2674.   control_drag_mode_t  handle;
  2675.   gboolean             in_handle;
  2676.   double               pos;
  2677.  
  2678.   pos = control_calc_g_pos (x);
  2679.  
  2680.   if ((pos < 0.0) || (pos > 1.0))
  2681.     return;
  2682.  
  2683.   seg_get_closest_handle (curr_gradient, pos, &seg, &handle);
  2684.  
  2685.   in_handle = control_point_in_handle (x, y, seg, handle);
  2686.  
  2687.   if (in_handle)
  2688.     {
  2689.       switch (handle)
  2690.     {
  2691.     case GRAD_DRAG_LEFT:
  2692.       if (seg != NULL)
  2693.         {
  2694.           if (seg->prev != NULL)
  2695.         ed_set_hint (_("Drag: move    Shift+drag: move & compress"));
  2696.           else
  2697.         ed_set_hint (_("Click: select    Shift+click: extend selection"));
  2698.         }
  2699.       else
  2700.         {
  2701.           ed_set_hint (_("Click: select    Shift+click: extend selection"));
  2702.         }
  2703.  
  2704.       break;
  2705.  
  2706.     case GRAD_DRAG_MIDDLE:
  2707.       ed_set_hint (_("Click: select    Shift+click: extend selection    "
  2708.              "Drag: move"));
  2709.  
  2710.       break;
  2711.  
  2712.     default:
  2713.       g_warning ("in_handle is true yet we got handle type %d",
  2714.              (int) handle);
  2715.       break;
  2716.     }
  2717.     }
  2718.   else
  2719.     ed_set_hint (_("Click: select    Shift+click: extend selection    "
  2720.            "Drag: move    Shift+drag: move & compress"));
  2721. }
  2722.  
  2723. /*****/
  2724.  
  2725. static void
  2726. control_button_press (gint  x,
  2727.               gint  y,
  2728.               guint button,
  2729.               guint state)
  2730. {
  2731.   grad_segment_t      *seg;
  2732.   control_drag_mode_t  handle;
  2733.   double               xpos;
  2734.   gboolean             in_handle;
  2735.  
  2736.   /* See which button was pressed */
  2737.  
  2738.   if (curr_gradient == NULL)
  2739.     return;
  2740.   
  2741.   switch (button)
  2742.     {
  2743.     case 1:
  2744.       break;
  2745.  
  2746.     case 3:
  2747.       cpopup_do_popup();
  2748.       return;
  2749.  
  2750.       /*  wheelmouse support  */
  2751.     case 4:
  2752.       {
  2753.     GtkAdjustment *adj = GTK_ADJUSTMENT (g_editor->scroll_data);
  2754.     gfloat new_value   = adj->value - adj->page_increment / 2;
  2755.  
  2756.     new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  2757.     gtk_adjustment_set_value (adj, new_value);
  2758.       }
  2759.       return;
  2760.  
  2761.     case 5:
  2762.       {
  2763.     GtkAdjustment *adj = GTK_ADJUSTMENT (g_editor->scroll_data);
  2764.     gfloat new_value   = adj->value + adj->page_increment / 2;
  2765.  
  2766.     new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  2767.     gtk_adjustment_set_value (adj, new_value);
  2768.       }
  2769.       return;
  2770.  
  2771.     default:
  2772.       return;
  2773.     }
  2774.  
  2775.   /* Find the closest handle */
  2776.  
  2777.   xpos = control_calc_g_pos (x);
  2778.  
  2779.   seg_get_closest_handle (curr_gradient, xpos, &seg, &handle);
  2780.  
  2781.   in_handle = control_point_in_handle (x, y, seg, handle);
  2782.  
  2783.   /* Now see what we have */
  2784.  
  2785.   if (in_handle)
  2786.     {
  2787.       switch (handle)
  2788.     {
  2789.     case GRAD_DRAG_LEFT:
  2790.       if (seg != NULL)
  2791.         {
  2792.           /* Left handle of some segment */
  2793.           if (state & GDK_SHIFT_MASK)
  2794.         {
  2795.           if (seg->prev != NULL)
  2796.             {
  2797.               g_editor->control_drag_mode    = GRAD_DRAG_LEFT;
  2798.               g_editor->control_drag_segment = seg;
  2799.               g_editor->control_compress     = TRUE;
  2800.             }
  2801.           else
  2802.             {
  2803.               control_extend_selection (seg, xpos);
  2804.               ed_update_editor (GRAD_UPDATE_CONTROL);
  2805.             }
  2806.         }
  2807.           else if (seg->prev != NULL)
  2808.         {
  2809.           g_editor->control_drag_mode    = GRAD_DRAG_LEFT;
  2810.           g_editor->control_drag_segment = seg;
  2811.         }
  2812.           else
  2813.         {
  2814.           control_select_single_segment (seg);
  2815.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2816.         }
  2817.  
  2818.           return;
  2819.         }
  2820.       else  /* seg == NULL */
  2821.         {
  2822.           /* Right handle of last segment */
  2823.           seg = seg_get_last_segment (curr_gradient->segments);
  2824.  
  2825.           if (state & GDK_SHIFT_MASK)
  2826.         {
  2827.           control_extend_selection (seg, xpos);
  2828.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2829.         }
  2830.           else
  2831.         {
  2832.           control_select_single_segment (seg);
  2833.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2834.         }
  2835.  
  2836.           return;
  2837.         }
  2838.  
  2839.       break;
  2840.  
  2841.     case GRAD_DRAG_MIDDLE:
  2842.       if (state & GDK_SHIFT_MASK)
  2843.         {
  2844.           control_extend_selection (seg, xpos);
  2845.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2846.         }
  2847.       else
  2848.         {
  2849.           g_editor->control_drag_mode    = GRAD_DRAG_MIDDLE;
  2850.           g_editor->control_drag_segment = seg;
  2851.         }
  2852.  
  2853.       return;
  2854.  
  2855.     default:
  2856.       g_warning ("in_handle is true yet we got handle type %d",
  2857.              (int) handle);
  2858.       return;
  2859.     }
  2860.     }
  2861.   else  /* !in_handle */
  2862.     {
  2863.       seg = seg_get_segment_at (curr_gradient, xpos);
  2864.  
  2865.       g_editor->control_drag_mode    = GRAD_DRAG_ALL;
  2866.       g_editor->control_drag_segment = seg;
  2867.       g_editor->control_last_gx      = xpos;
  2868.       g_editor->control_orig_pos     = xpos;
  2869.  
  2870.       if (state & GDK_SHIFT_MASK)
  2871.     g_editor->control_compress = TRUE;
  2872.  
  2873.       return;
  2874.     }
  2875. }
  2876.  
  2877. /*****/
  2878.  
  2879. static gboolean
  2880. control_point_in_handle (gint                 x,
  2881.              gint                 y,
  2882.              grad_segment_t      *seg,
  2883.              control_drag_mode_t  handle)
  2884. {
  2885.   gint handle_pos;
  2886.  
  2887.   switch (handle)
  2888.     {
  2889.     case GRAD_DRAG_LEFT:
  2890.       if (seg)
  2891.     {
  2892.       handle_pos = control_calc_p_pos (seg->left);
  2893.     }
  2894.       else
  2895.     {
  2896.       seg = seg_get_last_segment (curr_gradient->segments);
  2897.  
  2898.       handle_pos = control_calc_p_pos (seg->right);
  2899.     }
  2900.  
  2901.       break;
  2902.  
  2903.     case GRAD_DRAG_MIDDLE:
  2904.       handle_pos = control_calc_p_pos (seg->middle);
  2905.       break;
  2906.  
  2907.     default:
  2908.       g_warning ("can not handle drag mode %d", (gint) handle);
  2909.       return FALSE;
  2910.     }
  2911.  
  2912.   y /= 2;
  2913.  
  2914.   if ((x >= (handle_pos - y)) && (x <= (handle_pos + y)))
  2915.     return TRUE;
  2916.   else
  2917.     return FALSE;
  2918. }
  2919.  
  2920. /*****/
  2921.  
  2922. static void
  2923. control_select_single_segment (grad_segment_t *seg)
  2924. {
  2925.   g_editor->control_sel_l = seg;
  2926.   g_editor->control_sel_r = seg;
  2927. }
  2928.  
  2929. /*****/
  2930.  
  2931. static void
  2932. control_extend_selection (grad_segment_t *seg,
  2933.               double          pos)
  2934. {
  2935.   if (fabs (pos - g_editor->control_sel_l->left) <
  2936.       fabs (pos - g_editor->control_sel_r->right))
  2937.     g_editor->control_sel_l = seg;
  2938.   else
  2939.     g_editor->control_sel_r = seg;
  2940. }
  2941.  
  2942. /*****/
  2943.  
  2944. static void
  2945. control_motion (gint x)
  2946. {
  2947.   grad_segment_t *seg;
  2948.   gdouble         pos;
  2949.   gdouble         delta;
  2950.   gchar          *str = NULL;
  2951.  
  2952.   seg = g_editor->control_drag_segment;
  2953.  
  2954.   switch (g_editor->control_drag_mode)
  2955.     {
  2956.     case GRAD_DRAG_LEFT:
  2957.       pos = control_calc_g_pos (x);
  2958.  
  2959.       if (!g_editor->control_compress)
  2960.     seg->prev->right = seg->left = CLAMP (pos,
  2961.                           seg->prev->middle + EPSILON,
  2962.                           seg->middle - EPSILON);
  2963.       else
  2964.     control_compress_left (g_editor->control_sel_l,
  2965.                    g_editor->control_sel_r,
  2966.                    seg, pos);
  2967.  
  2968.       str = g_strdup_printf (_("Handle position: %0.6f"), seg->left);
  2969.       ed_set_hint (str);
  2970.  
  2971.       break;
  2972.  
  2973.     case GRAD_DRAG_MIDDLE:
  2974.       pos = control_calc_g_pos (x);
  2975.       seg->middle = CLAMP (pos, seg->left + EPSILON, seg->right - EPSILON);
  2976.  
  2977.       str = g_strdup_printf (_("Handle position: %0.6f"), seg->middle);
  2978.       ed_set_hint (str);
  2979.  
  2980.       break;
  2981.  
  2982.     case GRAD_DRAG_ALL:
  2983.       pos    = control_calc_g_pos (x);
  2984.       delta  = pos - g_editor->control_last_gx;
  2985.  
  2986.       if ((seg->left >= g_editor->control_sel_l->left) &&
  2987.       (seg->right <= g_editor->control_sel_r->right))
  2988.     delta = control_move (g_editor->control_sel_l,
  2989.                   g_editor->control_sel_r, delta);
  2990.       else
  2991.     delta = control_move (seg, seg, delta);
  2992.  
  2993.       g_editor->control_last_gx += delta;
  2994.  
  2995.       str = g_strdup_printf (_("Distance: %0.6f"),
  2996.                  g_editor->control_last_gx - g_editor->control_orig_pos);
  2997.       ed_set_hint (str);
  2998.  
  2999.       break;
  3000.  
  3001.     default:
  3002.       gimp_fatal_error ("Attempt to move bogus handle %d",
  3003.             (gint) g_editor->control_drag_mode);
  3004.       break;
  3005.     }
  3006.  
  3007.   if (str)
  3008.     g_free (str);
  3009.  
  3010.   curr_gradient->dirty = TRUE;
  3011.  
  3012.   if (g_editor->instant_update)
  3013.     ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  3014.   else
  3015.     ed_update_editor (GRAD_UPDATE_CONTROL);
  3016. }
  3017.  
  3018. /*****/
  3019.  
  3020. static void
  3021. control_compress_left (grad_segment_t *range_l,
  3022.                grad_segment_t *range_r,
  3023.                grad_segment_t *drag_seg,
  3024.                double          pos)
  3025. {
  3026.   grad_segment_t *seg;
  3027.   double          lbound, rbound;
  3028.   int             k;
  3029.  
  3030.   /* Check what we have to compress */
  3031.  
  3032.   if (!((drag_seg->left >= range_l->left) &&
  3033.     ((drag_seg->right <= range_r->right) || (drag_seg == range_r->next))))
  3034.     {
  3035.       /* We are compressing a segment outside the selection */
  3036.  
  3037.       range_l = range_r = drag_seg;
  3038.     }
  3039.  
  3040.   /* Calculate left bound for dragged hadle */
  3041.  
  3042.   if (drag_seg == range_l)
  3043.     lbound = range_l->prev->left + 2.0 * EPSILON;
  3044.   else
  3045.     {
  3046.       /* Count number of segments to the left of the dragged handle */
  3047.  
  3048.       seg = drag_seg;
  3049.       k   = 0;
  3050.  
  3051.       while (seg != range_l)
  3052.     {
  3053.       k++;
  3054.       seg = seg->prev;
  3055.     }
  3056.  
  3057.       /* 2*k handles have to fit */
  3058.  
  3059.       lbound = range_l->left + 2.0 * k * EPSILON;
  3060.     }
  3061.  
  3062.   /* Calculate right bound for dragged handle */
  3063.  
  3064.   if (drag_seg == range_r->next)
  3065.     rbound = range_r->next->right - 2.0 * EPSILON;
  3066.   else
  3067.     {
  3068.       /* Count number of segments to the right of the dragged handle */
  3069.  
  3070.       seg = drag_seg;
  3071.       k   = 1;
  3072.  
  3073.       while (seg != range_r)
  3074.     {
  3075.       k++;
  3076.       seg = seg->next;
  3077.     }
  3078.  
  3079.       /* 2*k handles have to fit */
  3080.  
  3081.       rbound = range_r->right - 2.0 * k * EPSILON;
  3082.     }
  3083.  
  3084.   /* Calculate position */
  3085.  
  3086.   pos = CLAMP (pos, lbound, rbound);
  3087.  
  3088.   /* Compress segments to the left of the handle */
  3089.  
  3090.   if (drag_seg == range_l)
  3091.     control_compress_range (range_l->prev, range_l->prev,
  3092.                 range_l->prev->left, pos);
  3093.   else
  3094.     control_compress_range (range_l, drag_seg->prev, range_l->left, pos);
  3095.  
  3096.   /* Compress segments to the right of the handle */
  3097.  
  3098.   if (drag_seg != range_r->next)
  3099.     control_compress_range (drag_seg, range_r, pos, range_r->right);
  3100.   else
  3101.     control_compress_range (drag_seg, drag_seg, pos, drag_seg->right);
  3102. }
  3103.  
  3104. /*****/
  3105.  
  3106. static void
  3107. control_compress_range (grad_segment_t *range_l,
  3108.             grad_segment_t *range_r,
  3109.             gdouble         new_l,
  3110.             gdouble         new_r)
  3111. {
  3112.   gdouble         orig_l, orig_r;
  3113.   gdouble         scale;
  3114.   grad_segment_t *seg, *aseg;
  3115.  
  3116.   orig_l = range_l->left;
  3117.   orig_r = range_r->right;
  3118.  
  3119.   scale = (new_r - new_l) / (orig_r - orig_l);
  3120.  
  3121.   seg = range_l;
  3122.  
  3123.   do
  3124.     {
  3125.       seg->left   = new_l + (seg->left - orig_l) * scale;
  3126.       seg->middle = new_l + (seg->middle - orig_l) * scale;
  3127.       seg->right  = new_l + (seg->right - orig_l) * scale;
  3128.  
  3129.       /* Next */
  3130.  
  3131.       aseg = seg;
  3132.       seg  = seg->next;
  3133.     }
  3134.   while (aseg != range_r);
  3135. }
  3136.  
  3137. /*****/
  3138.  
  3139. static gdouble
  3140. control_move (grad_segment_t *range_l,
  3141.           grad_segment_t *range_r,
  3142.           gdouble         delta)
  3143. {
  3144.   gdouble         lbound, rbound;
  3145.   gint            is_first, is_last;
  3146.   grad_segment_t *seg, *aseg;
  3147.  
  3148.   /* First or last segments in gradient? */
  3149.  
  3150.   is_first = (range_l->prev == NULL);
  3151.   is_last  = (range_r->next == NULL);
  3152.  
  3153.   /* Calculate drag bounds */
  3154.  
  3155.   if (!g_editor->control_compress)
  3156.     {
  3157.       if (!is_first)
  3158.     lbound = range_l->prev->middle + EPSILON;
  3159.       else
  3160.     lbound = range_l->left + EPSILON;
  3161.  
  3162.       if (!is_last)
  3163.     rbound = range_r->next->middle - EPSILON;
  3164.       else
  3165.     rbound = range_r->right - EPSILON;
  3166.     }
  3167.   else
  3168.     {
  3169.       if (!is_first)
  3170.     lbound = range_l->prev->left + 2.0 * EPSILON;
  3171.       else
  3172.     lbound = range_l->left + EPSILON;
  3173.  
  3174.       if (!is_last)
  3175.     rbound = range_r->next->right - 2.0 * EPSILON;
  3176.       else
  3177.     rbound = range_r->right - EPSILON;
  3178.     }
  3179.  
  3180.   /* Fix the delta if necessary */
  3181.  
  3182.   if (delta < 0.0)
  3183.     {
  3184.       if (!is_first)
  3185.     {
  3186.       if (range_l->left + delta < lbound)
  3187.         delta = lbound - range_l->left;
  3188.     }
  3189.       else
  3190.     if (range_l->middle + delta < lbound)
  3191.       delta = lbound - range_l->middle;
  3192.     }
  3193.   else
  3194.     {
  3195.       if (!is_last)
  3196.     {
  3197.       if (range_r->right + delta > rbound)
  3198.         delta = rbound - range_r->right;
  3199.     }
  3200.       else
  3201.     if (range_r->middle + delta > rbound)
  3202.       delta = rbound - range_r->middle;
  3203.     }
  3204.  
  3205.   /* Move all the segments inside the range */
  3206.  
  3207.   seg = range_l;
  3208.  
  3209.   do
  3210.     {
  3211.       if (!((seg == range_l) && is_first))
  3212.     seg->left   += delta;
  3213.  
  3214.       seg->middle += delta;
  3215.  
  3216.       if (!((seg == range_r) && is_last))
  3217.     seg->right  += delta;
  3218.  
  3219.       /* Next */
  3220.  
  3221.       aseg = seg;
  3222.       seg  = seg->next;
  3223.     }
  3224.   while (aseg != range_r);
  3225.  
  3226.   /* Fix the segments that surround the range */
  3227.  
  3228.   if (!is_first)
  3229.     {
  3230.       if (!g_editor->control_compress)
  3231.     range_l->prev->right = range_l->left;
  3232.       else
  3233.     control_compress_range (range_l->prev, range_l->prev,
  3234.                 range_l->prev->left, range_l->left);
  3235.     }
  3236.  
  3237.   if (!is_last)
  3238.     {
  3239.       if (!g_editor->control_compress)
  3240.     range_r->next->left = range_r->right;
  3241.       else
  3242.     control_compress_range (range_r->next, range_r->next,
  3243.                 range_r->right, range_r->next->right);
  3244.     }
  3245.  
  3246.   return delta;
  3247. }
  3248.  
  3249. /*****/
  3250.  
  3251. static void
  3252. control_update (gboolean recalculate)
  3253. {
  3254.   GtkAdjustment *adjustment;
  3255.   gint           cwidth, cheight;
  3256.   gint           pwidth, pheight;
  3257.  
  3258.   /* We only update if we can redraw and a gradient is present */
  3259.   if (curr_gradient == NULL) 
  3260.     return;
  3261.  
  3262.   if (! GTK_WIDGET_DRAWABLE (g_editor->control))
  3263.     return;
  3264.  
  3265.   /*  See whether we have to re-create the control pixmap
  3266.    *  depending on the preview's width
  3267.    */
  3268.   cwidth  = g_editor->preview->allocation.width;
  3269.   cheight = GRAD_CONTROL_HEIGHT;
  3270.  
  3271.   if (g_editor->control_pixmap)
  3272.     gdk_window_get_size (g_editor->control_pixmap, &pwidth, &pheight);
  3273.  
  3274.   if (!g_editor->control_pixmap ||
  3275.       (cwidth != pwidth) ||
  3276.       (cheight != pheight))
  3277.     {
  3278.       if (g_editor->control_pixmap)
  3279.     gdk_pixmap_unref (g_editor->control_pixmap);
  3280.  
  3281.       g_editor->control_pixmap =
  3282.     gdk_pixmap_new (g_editor->control->window, cwidth, cheight, -1);
  3283.  
  3284.       recalculate = TRUE;
  3285.     }
  3286.  
  3287.   /* Avaoid segfault on first invocation */
  3288.   if (cwidth < GRAD_PREVIEW_WIDTH)
  3289.     return;
  3290.  
  3291.   /* Have to reset the selection? */
  3292.   if (recalculate)
  3293.     control_select_single_segment (curr_gradient->segments);
  3294.  
  3295.   /* Redraw pixmap */
  3296.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  3297.  
  3298.   control_draw (g_editor->control_pixmap,
  3299.         cwidth, cheight,
  3300.         adjustment->value,
  3301.         adjustment->value + adjustment->page_size);
  3302.  
  3303.   gdk_draw_pixmap (g_editor->control->window, g_editor->control->style->black_gc,
  3304.            g_editor->control_pixmap, 0, 0, 0, 0, cwidth, cheight);
  3305. }
  3306.  
  3307. /*****/
  3308.  
  3309. static void
  3310. control_draw (GdkPixmap *pixmap,
  3311.           gint       width,
  3312.           gint       height,
  3313.           gdouble    left,
  3314.           gdouble    right)
  3315. {
  3316.   gint                    sel_l, sel_r;
  3317.   gdouble              g_pos;
  3318.   grad_segment_t      *seg;
  3319.   control_drag_mode_t  handle;
  3320.  
  3321.   /* Clear the pixmap */
  3322.  
  3323.   gdk_draw_rectangle (pixmap, g_editor->control->style->bg_gc[GTK_STATE_NORMAL],
  3324.               TRUE, 0, 0, width, height);
  3325.  
  3326.   /* Draw selection */
  3327.  
  3328.   sel_l = control_calc_p_pos (g_editor->control_sel_l->left);
  3329.   sel_r = control_calc_p_pos (g_editor->control_sel_r->right);
  3330.  
  3331.   gdk_draw_rectangle (pixmap,
  3332.               g_editor->control->style->dark_gc[GTK_STATE_NORMAL],
  3333.               TRUE, sel_l, 0, sel_r - sel_l + 1, height);
  3334.  
  3335.   /* Draw handles */
  3336.  
  3337.   seg = curr_gradient->segments;
  3338.  
  3339.   while (seg)
  3340.     {
  3341.       control_draw_normal_handle (pixmap, seg->left, height);
  3342.       control_draw_middle_handle (pixmap, seg->middle, height);
  3343.  
  3344.       /* Draw right handle only if this is the last segment */
  3345.  
  3346.       if (seg->next == NULL)
  3347.     control_draw_normal_handle (pixmap, seg->right, height);
  3348.  
  3349.       /* Next! */
  3350.  
  3351.       seg = seg->next;
  3352.     }
  3353.  
  3354.   /* Draw the handle which is closest to the mouse position */
  3355.  
  3356.   g_pos = control_calc_g_pos (g_editor->control_last_x);
  3357.  
  3358.   seg_get_closest_handle (curr_gradient, CLAMP (g_pos, 0.0, 1.0), &seg, &handle);
  3359.  
  3360.   switch (handle)
  3361.     {
  3362.     case GRAD_DRAG_LEFT:
  3363.       if (seg)
  3364.     {
  3365.       control_draw_normal_handle (pixmap, seg->left, height);
  3366.     }
  3367.       else
  3368.     {
  3369.       seg = seg_get_last_segment (curr_gradient->segments);
  3370.  
  3371.       control_draw_normal_handle (pixmap, seg->right, height);
  3372.     }
  3373.  
  3374.       break;
  3375.  
  3376.     case GRAD_DRAG_MIDDLE:
  3377.       control_draw_middle_handle (pixmap, seg->middle, height);
  3378.       break;
  3379.  
  3380.     default:
  3381.       break;
  3382.     }
  3383. }
  3384.  
  3385. /*****/
  3386.  
  3387. static void
  3388. control_draw_normal_handle (GdkPixmap *pixmap,
  3389.                 gdouble    pos,
  3390.                 gint       height)
  3391. {
  3392.   control_draw_handle (pixmap,
  3393.                g_editor->control->style->black_gc,
  3394.                g_editor->control->style->black_gc,
  3395.                control_calc_p_pos (pos), height);
  3396. }
  3397.  
  3398. static void
  3399. control_draw_middle_handle (GdkPixmap *pixmap,
  3400.                 gdouble    pos,
  3401.                 gint       height)
  3402. {
  3403.   control_draw_handle (pixmap,
  3404.                g_editor->control->style->black_gc,
  3405.                g_editor->control->style->bg_gc[GTK_STATE_PRELIGHT],
  3406.                control_calc_p_pos(pos), height);
  3407. }
  3408.  
  3409. static void
  3410. control_draw_handle (GdkPixmap *pixmap,
  3411.              GdkGC     *border_gc,
  3412.              GdkGC     *fill_gc,
  3413.              gint       xpos,
  3414.              gint       height)
  3415. {
  3416.   gint y;
  3417.   gint left, right, bottom;
  3418.  
  3419.   for (y = 0; y < height; y++)
  3420.     gdk_draw_line (pixmap, fill_gc, xpos - y / 2, y, xpos + y / 2, y);
  3421.  
  3422.   bottom = height - 1;
  3423.   left   = xpos - bottom / 2;
  3424.   right  = xpos + bottom / 2;
  3425.  
  3426.   gdk_draw_line (pixmap, border_gc, xpos, 0, left, bottom);
  3427.   gdk_draw_line (pixmap, border_gc, xpos, 0, right, bottom);
  3428.   gdk_draw_line (pixmap, border_gc, left, bottom, right, bottom);
  3429. }
  3430.  
  3431. /*****/
  3432.  
  3433. static gint
  3434. control_calc_p_pos (gdouble pos)
  3435. {
  3436.   gint           pwidth, pheight;
  3437.   GtkAdjustment *adjustment;
  3438.  
  3439.   /* Calculate the position (in widget's coordinates) of the
  3440.    * requested point from the gradient.  Rounding is done to
  3441.    * minimize mismatches between the rendered gradient preview
  3442.    * and the gradient control's handles.
  3443.    */
  3444.  
  3445.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  3446.   gdk_window_get_size (g_editor->control_pixmap, &pwidth, &pheight);
  3447.  
  3448.   return RINT ((pwidth - 1) * (pos - adjustment->value) / adjustment->page_size);
  3449. }
  3450.  
  3451. /*****/
  3452.  
  3453. static gdouble
  3454. control_calc_g_pos (gint pos)
  3455. {
  3456.   gint           pwidth, pheight;
  3457.   GtkAdjustment *adjustment;
  3458.  
  3459.   /* Calculate the gradient position that corresponds to widget's coordinates */
  3460.  
  3461.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  3462.   gdk_window_get_size (g_editor->control_pixmap, &pwidth, &pheight);
  3463.  
  3464.   return adjustment->page_size * pos / (pwidth - 1) + adjustment->value;
  3465. }
  3466.  
  3467. /***** Control popup functions *****/
  3468.  
  3469. static void
  3470. cpopup_create_main_menu (void)
  3471. {
  3472.   GtkWidget     *menu;
  3473.   GtkWidget     *menuitem;
  3474.   GtkWidget     *label;
  3475.   GtkAccelGroup *accel_group;
  3476.  
  3477.   menu = gtk_menu_new ();
  3478.   accel_group = gtk_accel_group_new ();
  3479.  
  3480.   g_editor->accel_group = accel_group;
  3481.  
  3482.   gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
  3483.   gtk_window_add_accel_group (GTK_WINDOW (g_editor->shell), accel_group);
  3484.  
  3485.   /* Left endpoint */
  3486.   menuitem = cpopup_create_color_item (&g_editor->left_color_preview, &label);
  3487.   gtk_label_set_text (GTK_LABEL (label), _("Left endpoint's color"));
  3488.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3489.               (GtkSignalFunc) cpopup_set_left_color_callback,
  3490.               NULL);
  3491.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3492.   gtk_widget_show (menuitem);
  3493.   gtk_widget_add_accelerator (menuitem, "activate",
  3494.                   accel_group,
  3495.                   'L', 0,
  3496.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3497.  
  3498.   menuitem = gtk_menu_item_new_with_label (_("Load from"));
  3499.   g_editor->control_left_load_popup =
  3500.     cpopup_create_load_menu (g_editor->left_load_color_boxes,
  3501.                  g_editor->left_load_labels,
  3502.                  _("Left neighbor's right endpoint"),
  3503.                  _("Right endpoint"),
  3504.                  (GtkSignalFunc) cpopup_load_left_callback,
  3505.                  'L', GDK_CONTROL_MASK,
  3506.                  'L', GDK_MOD1_MASK,
  3507.                  'F', GDK_CONTROL_MASK);
  3508.   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem),
  3509.                  g_editor->control_left_load_popup);
  3510.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3511.   gtk_widget_show (menuitem);
  3512.  
  3513.   menuitem = gtk_menu_item_new_with_label (_("Save to"));
  3514.   g_editor->control_left_save_popup =
  3515.     cpopup_create_save_menu (g_editor->left_save_color_boxes,
  3516.                  g_editor->left_save_labels,
  3517.                  (GtkSignalFunc) cpopup_save_left_callback);
  3518.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3519.                  g_editor->control_left_save_popup);
  3520.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3521.   gtk_widget_show (menuitem);
  3522.  
  3523.   /* Right endpoint */
  3524.   menuitem = gtk_menu_item_new ();
  3525.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3526.   gtk_widget_show (menuitem);
  3527.  
  3528.   menuitem = cpopup_create_color_item (&g_editor->right_color_preview, &label);
  3529.   gtk_label_set_text (GTK_LABEL (label), _("Right endpoint's color"));
  3530.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3531.               (GtkSignalFunc) cpopup_set_right_color_callback,
  3532.               NULL);
  3533.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3534.   gtk_widget_show (menuitem);
  3535.   gtk_widget_add_accelerator (menuitem, "activate",
  3536.                   accel_group,
  3537.                   'R', 0,
  3538.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3539.  
  3540.   menuitem = gtk_menu_item_new_with_label (_("Load from"));
  3541.   g_editor->control_right_load_popup =
  3542.     cpopup_create_load_menu (g_editor->right_load_color_boxes,
  3543.                  g_editor->right_load_labels,
  3544.                  _("Right neighbor's left endpoint"),
  3545.                  _("Left endpoint"),
  3546.                  (GtkSignalFunc) cpopup_load_right_callback,
  3547.                  'R', GDK_CONTROL_MASK,
  3548.                  'R', GDK_MOD1_MASK,
  3549.                  'F', GDK_MOD1_MASK);
  3550.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3551.                  g_editor->control_right_load_popup);
  3552.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3553.   gtk_widget_show (menuitem);
  3554.  
  3555.   menuitem = gtk_menu_item_new_with_label (_("Save to"));
  3556.   g_editor->control_right_save_popup =
  3557.     cpopup_create_save_menu (g_editor->right_save_color_boxes,
  3558.                  g_editor->right_save_labels,
  3559.                  (GtkSignalFunc) cpopup_save_right_callback);
  3560.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3561.                  g_editor->control_right_save_popup);
  3562.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3563.   gtk_widget_show (menuitem);
  3564.  
  3565.   /* Blending function */
  3566.   menuitem = gtk_menu_item_new ();
  3567.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3568.   gtk_widget_show (menuitem);
  3569.  
  3570.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_blending_label);
  3571.   g_editor->control_blending_popup = cpopup_create_blending_menu ();
  3572.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3573.                  g_editor->control_blending_popup);
  3574.   gtk_menu_append (GTK_MENU(menu), menuitem);
  3575.   gtk_widget_show (menuitem);
  3576.  
  3577.   /* Coloring type */
  3578.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_coloring_label);
  3579.   g_editor->control_coloring_popup = cpopup_create_coloring_menu ();
  3580.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3581.                  g_editor->control_coloring_popup);
  3582.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3583.   gtk_widget_show (menuitem);
  3584.  
  3585.   /* Operations */
  3586.   menuitem = gtk_menu_item_new ();
  3587.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3588.   gtk_widget_show (menuitem);
  3589.  
  3590.   /* Split at midpoint */
  3591.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_split_m_label);
  3592.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3593.               (GtkSignalFunc) cpopup_split_midpoint_callback,
  3594.               NULL);
  3595.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3596.   gtk_widget_show (menuitem);
  3597.   gtk_widget_add_accelerator(menuitem, "activate",
  3598.                  accel_group,
  3599.                  'S', 0,
  3600.                  GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3601.  
  3602.   /* Split uniformly */
  3603.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_split_u_label);
  3604.   gtk_signal_connect (GTK_OBJECT(menuitem), "activate",
  3605.               (GtkSignalFunc) cpopup_split_uniform_callback,
  3606.               NULL);
  3607.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3608.   gtk_widget_show (menuitem);
  3609.   gtk_widget_add_accelerator (menuitem, "activate",
  3610.                   accel_group,
  3611.                   'U', 0,
  3612.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3613.  
  3614.   /* Delete */
  3615.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_delete_label);
  3616.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3617.               (GtkSignalFunc) cpopup_delete_callback,
  3618.               NULL);
  3619.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3620.   gtk_widget_show (menuitem);
  3621.   g_editor->control_delete_menu_item = menuitem;
  3622.   gtk_widget_add_accelerator (menuitem, "activate",
  3623.                   accel_group,
  3624.                   'D', 0,
  3625.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3626.  
  3627.   /* Recenter */
  3628.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_recenter_label);
  3629.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3630.               (GtkSignalFunc) cpopup_recenter_callback,
  3631.               NULL);
  3632.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3633.   gtk_widget_show (menuitem);
  3634.   gtk_widget_add_accelerator (menuitem, "activate",
  3635.                   accel_group,
  3636.                   'C', 0,
  3637.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3638.  
  3639.   /* Redistribute */
  3640.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_redistribute_label);
  3641.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3642.               (GtkSignalFunc) cpopup_redistribute_callback,
  3643.               NULL);
  3644.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3645.   gtk_widget_show (menuitem);
  3646.   gtk_widget_add_accelerator (menuitem, "activate",
  3647.                   accel_group,
  3648.                   'C', GDK_CONTROL_MASK,
  3649.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3650.  
  3651.   /* Selection ops */
  3652.   menuitem = gtk_menu_item_new ();
  3653.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3654.   gtk_widget_show (menuitem);
  3655.  
  3656.   menuitem = gtk_menu_item_new_with_label (_("Selection operations"));
  3657.   g_editor->control_sel_ops_popup = cpopup_create_sel_ops_menu ();
  3658.   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem),
  3659.                  g_editor->control_sel_ops_popup);
  3660.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3661.   gtk_widget_show (menuitem);
  3662.  
  3663.   /* Done */
  3664.   g_editor->control_main_popup = menu;
  3665. }
  3666.  
  3667. static void
  3668. cpopup_do_popup (void)
  3669. {
  3670.   cpopup_adjust_menus ();
  3671.   gtk_menu_popup (GTK_MENU (g_editor->control_main_popup),
  3672.           NULL, NULL, NULL, NULL, 3, 0);
  3673. }
  3674.  
  3675. /***** Create a single menu item *****/
  3676.  
  3677. static GtkWidget *
  3678. cpopup_create_color_item (GtkWidget **color_box,
  3679.               GtkWidget **label)
  3680. {
  3681.   GtkWidget *menuitem;
  3682.   GtkWidget *hbox;
  3683.   GtkWidget *vbox;
  3684.   GtkWidget *wcolor_box;
  3685.   GtkWidget *wlabel;
  3686.  
  3687.   menuitem = gtk_menu_item_new();
  3688.  
  3689.   hbox = gtk_hbox_new (FALSE, 0);
  3690.   gtk_container_add (GTK_CONTAINER (menuitem), hbox);
  3691.   gtk_widget_show (hbox);
  3692.  
  3693.   vbox = gtk_vbox_new (FALSE, 0);
  3694.   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
  3695.   gtk_widget_show (vbox);
  3696.  
  3697.   wcolor_box = gtk_preview_new (GTK_PREVIEW_COLOR);
  3698.   gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
  3699.   gtk_preview_size (GTK_PREVIEW (wcolor_box),
  3700.             GRAD_COLOR_BOX_WIDTH, GRAD_COLOR_BOX_HEIGHT);
  3701.   gtk_box_pack_start (GTK_BOX (vbox), wcolor_box, FALSE, FALSE, 2);
  3702.   gtk_widget_show (wcolor_box);
  3703.  
  3704.   if (color_box)
  3705.     *color_box = wcolor_box;
  3706.  
  3707.   wlabel = gtk_label_new ("");
  3708.   gtk_misc_set_alignment (GTK_MISC (wlabel), 0.0, 0.5);
  3709.   gtk_box_pack_start (GTK_BOX (hbox), wlabel, FALSE, FALSE, 4);
  3710.   gtk_widget_show (wlabel);
  3711.  
  3712.   if (label)
  3713.     *label = wlabel;
  3714.  
  3715.   return menuitem;
  3716. }
  3717.  
  3718. static GtkWidget *
  3719. cpopup_create_menu_item_with_label (gchar      *str,
  3720.                     GtkWidget **label)
  3721. {
  3722.   GtkWidget *menuitem;
  3723.   GtkWidget *accel_label;
  3724.  
  3725.   menuitem = gtk_menu_item_new ();
  3726.  
  3727.   accel_label = gtk_accel_label_new (str);
  3728.   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
  3729.   gtk_container_add (GTK_CONTAINER (menuitem), accel_label);
  3730.   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menuitem);
  3731.   gtk_widget_show (accel_label);
  3732.  
  3733.   if (label)
  3734.     *label = accel_label;
  3735.  
  3736.   return menuitem;
  3737. }
  3738.  
  3739. /***** Update all menus *****/
  3740.  
  3741. static void
  3742. cpopup_adjust_menus (void)
  3743. {
  3744.   grad_segment_t *seg;
  3745.   gint            i;
  3746.   gdouble         fg_r, fg_g, fg_b;
  3747.   gdouble         fg_a;
  3748.  
  3749.   /* Render main menu color boxes */
  3750.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_color_preview),
  3751.                g_editor->control_sel_l->r0,
  3752.                g_editor->control_sel_l->g0,
  3753.                g_editor->control_sel_l->b0,
  3754.                g_editor->control_sel_l->a0);
  3755.  
  3756.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_color_preview),
  3757.                g_editor->control_sel_r->r1,
  3758.                g_editor->control_sel_r->g1,
  3759.                g_editor->control_sel_r->b1,
  3760.                g_editor->control_sel_r->a1);
  3761.  
  3762.   /* Render load color from endpoint color boxes */
  3763.  
  3764.   if (g_editor->control_sel_l->prev != NULL)
  3765.     seg = g_editor->control_sel_l->prev;
  3766.   else
  3767.     seg = seg_get_last_segment (g_editor->control_sel_l);
  3768.  
  3769.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_load_color_boxes[0]),
  3770.                seg->r1,
  3771.                seg->g1,
  3772.                seg->b1,
  3773.                seg->a1);
  3774.  
  3775.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_load_color_boxes[1]),
  3776.                g_editor->control_sel_r->r1,
  3777.                g_editor->control_sel_r->g1,
  3778.                g_editor->control_sel_r->b1,
  3779.                g_editor->control_sel_r->a1);
  3780.  
  3781.   if (g_editor->control_sel_r->next != NULL)
  3782.     seg = g_editor->control_sel_r->next;
  3783.   else
  3784.     seg = curr_gradient->segments;
  3785.  
  3786.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_load_color_boxes[0]),
  3787.                seg->r0,
  3788.                seg->g0,
  3789.                seg->b0,
  3790.                seg->a0);
  3791.  
  3792.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_load_color_boxes[1]),
  3793.                g_editor->control_sel_l->r0,
  3794.                g_editor->control_sel_l->g0,
  3795.                g_editor->control_sel_l->b0,
  3796.                g_editor->control_sel_l->a0);
  3797.  
  3798.   /* Render Foreground color boxes */
  3799.  
  3800.   ed_fetch_foreground (&fg_r, &fg_g, &fg_b, &fg_a);
  3801.  
  3802.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_load_color_boxes[2]),
  3803.                fg_r,
  3804.                fg_g,
  3805.                fg_b,
  3806.                fg_a);
  3807.  
  3808.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_load_color_boxes[2]),
  3809.                fg_r,
  3810.                fg_g,
  3811.                fg_b,
  3812.                fg_a);
  3813.     
  3814.   /* Render saved color boxes */
  3815.  
  3816.   for (i = 0; i < GRAD_NUM_COLORS; i++)
  3817.     cpopup_update_saved_color (i,
  3818.                    g_editor->saved_colors[i].r,
  3819.                    g_editor->saved_colors[i].g,
  3820.                    g_editor->saved_colors[i].b,
  3821.                    g_editor->saved_colors[i].a);
  3822.  
  3823.   /* Adjust labels */
  3824.  
  3825.   if (g_editor->control_sel_l == g_editor->control_sel_r)
  3826.     {
  3827.       gtk_label_set_text (GTK_LABEL (g_editor->control_blending_label),
  3828.               _("Blending function for segment"));
  3829.       gtk_label_set_text (GTK_LABEL (g_editor->control_coloring_label),
  3830.               _("Coloring type for segment"));
  3831.       gtk_label_set_text (GTK_LABEL (g_editor->control_split_m_label),
  3832.               _("Split segment at midpoint"));
  3833.       gtk_label_set_text (GTK_LABEL (g_editor->control_split_u_label),
  3834.               _("Split segment uniformly"));
  3835.       gtk_label_set_text (GTK_LABEL (g_editor->control_delete_label),
  3836.               _("Delete segment"));
  3837.       gtk_label_set_text (GTK_LABEL (g_editor->control_recenter_label),
  3838.               _("Re-center segment's midpoint"));
  3839.       gtk_label_set_text (GTK_LABEL (g_editor->control_redistribute_label),
  3840.               _("Re-distribute handles in segment"));
  3841.       gtk_label_set_text (GTK_LABEL (g_editor->control_flip_label),
  3842.               _("Flip segment"));
  3843.       gtk_label_set_text (GTK_LABEL (g_editor->control_replicate_label),
  3844.               _("Replicate segment"));
  3845.     }
  3846.   else
  3847.     {
  3848.       gtk_label_set_text (GTK_LABEL (g_editor->control_blending_label),
  3849.               _("Blending function for selection"));
  3850.       gtk_label_set_text (GTK_LABEL (g_editor->control_coloring_label),
  3851.               _("Coloring type for selection"));
  3852.       gtk_label_set_text (GTK_LABEL (g_editor->control_split_m_label),
  3853.               _("Split segments at midpoints"));
  3854.       gtk_label_set_text (GTK_LABEL (g_editor->control_split_u_label),
  3855.               _("Split segments uniformly"));
  3856.       gtk_label_set_text (GTK_LABEL (g_editor->control_delete_label),
  3857.               _("Delete selection"));
  3858.       gtk_label_set_text (GTK_LABEL (g_editor->control_recenter_label),
  3859.               _("Re-center midpoints in selection"));
  3860.       gtk_label_set_text (GTK_LABEL (g_editor->control_redistribute_label),
  3861.               _("Re-distribute handles in selection"));
  3862.       gtk_label_set_text (GTK_LABEL (g_editor->control_flip_label),
  3863.               _("Flip selection"));
  3864.       gtk_label_set_text (GTK_LABEL (g_editor->control_replicate_label),
  3865.               _("Replicate selection"));
  3866.     }
  3867.  
  3868.   /* Adjust blending and coloring menus */
  3869.   cpopup_adjust_blending_menu ();
  3870.   cpopup_adjust_coloring_menu ();
  3871.  
  3872.   /* Can invoke delete? */
  3873.   if ((g_editor->control_sel_l->prev == NULL) &&
  3874.       (g_editor->control_sel_r->next == NULL))
  3875.     gtk_widget_set_sensitive (g_editor->control_delete_menu_item, FALSE);
  3876.   else
  3877.     gtk_widget_set_sensitive (g_editor->control_delete_menu_item, TRUE);
  3878.  
  3879.   /* Can invoke blend colors / opacity? */
  3880.   if (g_editor->control_sel_l == g_editor->control_sel_r)
  3881.     {
  3882.       gtk_widget_set_sensitive (g_editor->control_blend_colors_menu_item, FALSE);
  3883.       gtk_widget_set_sensitive (g_editor->control_blend_opacity_menu_item, FALSE);
  3884.     }
  3885.   else
  3886.     {
  3887.       gtk_widget_set_sensitive (g_editor->control_blend_colors_menu_item, TRUE);
  3888.       gtk_widget_set_sensitive (g_editor->control_blend_opacity_menu_item, TRUE);
  3889.     }
  3890. }
  3891.  
  3892. static void
  3893. cpopup_adjust_blending_menu (void)
  3894. {
  3895.   gint  equal;
  3896.   glong i, num_items;
  3897.   gint  type;
  3898.  
  3899.   cpopup_check_selection_params (&equal, NULL);
  3900.  
  3901.   /* Block activate signals */
  3902.   num_items = (sizeof (g_editor->control_blending_items) /
  3903.            sizeof (g_editor->control_blending_items[0]));
  3904.  
  3905.   type = (int) g_editor->control_sel_l->type;
  3906.  
  3907.   for (i = 0; i < num_items; i++)
  3908.     gtk_signal_handler_block_by_data
  3909.       (GTK_OBJECT (g_editor->control_blending_items[i]), (gpointer) i);
  3910.  
  3911.   /* Set state */
  3912.   if (equal)
  3913.     {
  3914.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (g_editor->control_blending_items[type]), TRUE);
  3915.       gtk_widget_hide (g_editor->control_blending_items[num_items - 1]);
  3916.     }
  3917.   else
  3918.     {
  3919.       gtk_widget_show (g_editor->control_blending_items[num_items - 1]);
  3920.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (g_editor->control_blending_items[num_items - 1]), TRUE);
  3921.     }
  3922.  
  3923.   /* Unblock signals */
  3924.   for (i = 0; i < num_items; i++)
  3925.     gtk_signal_handler_unblock_by_data (GTK_OBJECT (g_editor->control_blending_items[i]), (gpointer) i);
  3926. }
  3927.  
  3928. static void
  3929. cpopup_adjust_coloring_menu (void)
  3930. {
  3931.   gint  equal;
  3932.   glong i, num_items;
  3933.   gint  coloring;
  3934.  
  3935.   cpopup_check_selection_params (NULL, &equal);
  3936.  
  3937.   /* Block activate signals */
  3938.   num_items = (sizeof (g_editor->control_coloring_items) /
  3939.            sizeof (g_editor->control_coloring_items[0]));
  3940.  
  3941.   coloring = (int) g_editor->control_sel_l->color;
  3942.  
  3943.   for (i = 0; i < num_items; i++)
  3944.     gtk_signal_handler_block_by_data (GTK_OBJECT (g_editor->control_coloring_items[i]), (gpointer) i);
  3945.  
  3946.   /* Set state */
  3947.   if (equal)
  3948.     {
  3949.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (g_editor->control_coloring_items[coloring]), TRUE);
  3950.       gtk_widget_hide (g_editor->control_coloring_items[num_items - 1]);
  3951.     }
  3952.   else
  3953.     {
  3954.       gtk_widget_show (g_editor->control_coloring_items[num_items - 1]);
  3955.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (g_editor->control_coloring_items[num_items - 1]), TRUE);
  3956.     }
  3957.  
  3958.   /* Unblock signals */
  3959.   for (i = 0; i < num_items; i++)
  3960.     gtk_signal_handler_unblock_by_data (GTK_OBJECT (g_editor->control_coloring_items[i]), (gpointer) i);
  3961. }
  3962.  
  3963. static void
  3964. cpopup_check_selection_params (gint *equal_blending,
  3965.                    gint *equal_coloring)
  3966. {
  3967.   grad_type_t     type;
  3968.   grad_color_t    color;
  3969.   int             etype, ecolor;
  3970.   grad_segment_t *seg, *aseg;
  3971.  
  3972.   type  = g_editor->control_sel_l->type;
  3973.   color = g_editor->control_sel_l->color;
  3974.  
  3975.   etype  = 1;
  3976.   ecolor = 1;
  3977.  
  3978.   seg = g_editor->control_sel_l;
  3979.  
  3980.   do
  3981.     {
  3982.       etype  = etype && (seg->type == type);
  3983.       ecolor = ecolor && (seg->color == color);
  3984.  
  3985.       aseg = seg;
  3986.       seg  = seg->next;
  3987.     }
  3988.   while (aseg != g_editor->control_sel_r);
  3989.  
  3990.   if (equal_blending)
  3991.     *equal_blending = etype;
  3992.  
  3993.   if (equal_coloring)
  3994.     *equal_coloring = ecolor;
  3995. }
  3996.  
  3997. /*****/
  3998.  
  3999. static void
  4000. cpopup_render_color_box (GtkPreview *preview,
  4001.              double      r,
  4002.              double      g,
  4003.              double      b,
  4004.              double      a)
  4005. {
  4006.   guchar  rows[3][GRAD_COLOR_BOX_WIDTH * 3];
  4007.   int     x, y;
  4008.   int     r0, g0, b0;
  4009.   int     r1, g1, b1;
  4010.   guchar *p0, *p1, *p2;
  4011.  
  4012.   /* Fill rows */
  4013.  
  4014.   r0 = (GIMP_CHECK_DARK + (r - GIMP_CHECK_DARK) * a) * 255.0;
  4015.   r1 = (GIMP_CHECK_LIGHT + (r - GIMP_CHECK_LIGHT) * a) * 255.0;
  4016.  
  4017.   g0 = (GIMP_CHECK_DARK + (g - GIMP_CHECK_DARK) * a) * 255.0;
  4018.   g1 = (GIMP_CHECK_LIGHT + (g - GIMP_CHECK_LIGHT) * a) * 255.0;
  4019.  
  4020.   b0 = (GIMP_CHECK_DARK + (b - GIMP_CHECK_DARK) * a) * 255.0;
  4021.   b1 = (GIMP_CHECK_LIGHT + (b - GIMP_CHECK_LIGHT) * a) * 255.0;
  4022.  
  4023.   p0 = rows[0];
  4024.   p1 = rows[1];
  4025.   p2 = rows[2];
  4026.  
  4027.   for (x = 0; x < GRAD_COLOR_BOX_WIDTH; x++)
  4028.     {
  4029.       if ((x == 0) || (x == (GRAD_COLOR_BOX_WIDTH - 1)))
  4030.     {
  4031.       *p0++ = 0;
  4032.       *p0++ = 0;
  4033.       *p0++ = 0;
  4034.  
  4035.       *p1++ = 0;
  4036.       *p1++ = 0;
  4037.       *p1++ = 0;
  4038.     }
  4039.       else
  4040.     if ((x / GIMP_CHECK_SIZE) & 1)
  4041.       {
  4042.         *p0++ = r1;
  4043.         *p0++ = g1;
  4044.         *p0++ = b1;
  4045.  
  4046.         *p1++ = r0;
  4047.         *p1++ = g0;
  4048.         *p1++ = b0;
  4049.       }
  4050.     else
  4051.       {
  4052.         *p0++ = r0;
  4053.         *p0++ = g0;
  4054.         *p0++ = b0;
  4055.  
  4056.         *p1++ = r1;
  4057.         *p1++ = g1;
  4058.         *p1++ = b1;
  4059.       }
  4060.  
  4061.       *p2++ = 0;
  4062.       *p2++ = 0;
  4063.       *p2++ = 0;
  4064.     }
  4065.  
  4066.   /* Fill preview */
  4067.  
  4068.   gtk_preview_draw_row (preview, rows[2], 0, 0, GRAD_COLOR_BOX_WIDTH);
  4069.  
  4070.   for (y = 1; y < (GRAD_COLOR_BOX_HEIGHT - 1); y++)
  4071.     if ((y / GIMP_CHECK_SIZE) & 1)
  4072.       gtk_preview_draw_row (preview, rows[1], 0, y, GRAD_COLOR_BOX_WIDTH);
  4073.     else
  4074.       gtk_preview_draw_row (preview, rows[0], 0, y, GRAD_COLOR_BOX_WIDTH);
  4075.  
  4076.   gtk_preview_draw_row (preview, rows[2], 0, y, GRAD_COLOR_BOX_WIDTH);
  4077. }
  4078.  
  4079. /***** Creale load & save menus *****/
  4080.  
  4081. static GtkWidget *
  4082. cpopup_create_load_menu (GtkWidget    **color_boxes,
  4083.              GtkWidget    **labels,
  4084.              gchar         *label1,
  4085.              gchar         *label2,
  4086.              GtkSignalFunc  callback,
  4087.              gchar accel_key_0, guint8 accel_mods_0,
  4088.              gchar accel_key_1, guint8 accel_mods_1,
  4089.              gchar accel_key_2, guint8 accel_mods_2)
  4090. {
  4091.   GtkWidget     *menu;
  4092.   GtkWidget     *menuitem;
  4093.   GtkAccelGroup *accel_group;
  4094.   gint i;
  4095.  
  4096.   menu = gtk_menu_new ();
  4097.   accel_group = g_editor->accel_group;
  4098.  
  4099.   gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
  4100.  
  4101.   /* Create items */
  4102.   for (i = 0; i < (GRAD_NUM_COLORS + 3); i++)
  4103.     {
  4104.       if (i == 3)
  4105.     {
  4106.       /* Insert separator between "to fetch" and "saved" colors */
  4107.       menuitem = gtk_menu_item_new ();
  4108.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4109.       gtk_widget_show (menuitem);
  4110.     }
  4111.  
  4112.       menuitem = cpopup_create_color_item (&color_boxes[i], &labels[i]);
  4113.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  4114.               callback, (gpointer) ((long) i));
  4115.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4116.       gtk_widget_show (menuitem);
  4117.  
  4118.       switch (i)
  4119.     {
  4120.     case 0:
  4121.       gtk_widget_add_accelerator (menuitem, "activate",
  4122.                       accel_group,
  4123.                       accel_key_0, accel_mods_0,
  4124.                       GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  4125.       break;
  4126.           
  4127.     case 1:
  4128.       gtk_widget_add_accelerator (menuitem, "activate",
  4129.                       accel_group,
  4130.                       accel_key_1, accel_mods_1,
  4131.                       GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  4132.       break;
  4133.           
  4134.     case 2:
  4135.       gtk_widget_add_accelerator (menuitem, "activate",
  4136.                       accel_group,
  4137.                       accel_key_2, accel_mods_2,
  4138.                       GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  4139.       break;
  4140.           
  4141.     default:
  4142.       break;
  4143.     }
  4144.     }
  4145.  
  4146.   /* Set labels */
  4147.   gtk_label_set_text (GTK_LABEL (labels[0]), label1);
  4148.   gtk_label_set_text (GTK_LABEL (labels[1]), label2);
  4149.   gtk_label_set_text (GTK_LABEL (labels[2]), _("FG color"));
  4150.  
  4151.   return menu;
  4152. }
  4153.  
  4154. static GtkWidget *
  4155. cpopup_create_save_menu (GtkWidget     **color_boxes,
  4156.              GtkWidget     **labels,
  4157.              GtkSignalFunc   callback)
  4158. {
  4159.   GtkWidget *menu;
  4160.   GtkWidget *menuitem;
  4161.   gint i;
  4162.  
  4163.   menu = gtk_menu_new ();
  4164.  
  4165.   for (i = 0; i < GRAD_NUM_COLORS; i++)
  4166.     {
  4167.       menuitem = cpopup_create_color_item (&color_boxes[i], &labels[i]);
  4168.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  4169.               callback, (gpointer) ((long) i));
  4170.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4171.       gtk_widget_show (menuitem);
  4172.     }
  4173.  
  4174.   return menu;
  4175. }
  4176.  
  4177. /*****/
  4178.  
  4179. static void
  4180. cpopup_update_saved_color (int    n,
  4181.                double r,
  4182.                double g,
  4183.                double b,
  4184.                double a)
  4185. {
  4186.   gchar *str;
  4187.  
  4188.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_load_color_boxes[n + 3]),
  4189.                r, g, b, a);
  4190.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_save_color_boxes[n]),
  4191.                r, g, b, a);
  4192.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_load_color_boxes[n + 3]),
  4193.                r, g, b, a);
  4194.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_save_color_boxes[n]),
  4195.                r, g, b, a);
  4196.  
  4197.   str = g_strdup_printf (_("RGBA (%0.3f, %0.3f, %0.3f, %0.3f)"), r, g, b, a);
  4198.  
  4199.   gtk_label_set_text (GTK_LABEL (g_editor->left_load_labels[n + 3]), str);
  4200.   gtk_label_set_text (GTK_LABEL (g_editor->left_save_labels[n]), str);
  4201.   gtk_label_set_text (GTK_LABEL (g_editor->right_load_labels[n + 3]), str);
  4202.   gtk_label_set_text (GTK_LABEL (g_editor->right_save_labels[n]), str);
  4203.  
  4204.   g_free (str);
  4205.  
  4206.   g_editor->saved_colors[n].r = r;
  4207.   g_editor->saved_colors[n].g = g;
  4208.   g_editor->saved_colors[n].b = b;
  4209.   g_editor->saved_colors[n].a = a;
  4210. }
  4211.  
  4212. /*****/
  4213.  
  4214. static void
  4215. cpopup_load_left_callback (GtkWidget *widget,
  4216.                gpointer   data)
  4217. {
  4218.   grad_segment_t *seg;
  4219.   double          fg_r, fg_g, fg_b;
  4220.   double          fg_a;
  4221.  
  4222.   switch ((long) data)
  4223.     {
  4224.     case 0: /* Fetch from left neighbor's right endpoint */
  4225.       if (g_editor->control_sel_l->prev != NULL)
  4226.     seg = g_editor->control_sel_l->prev;
  4227.       else
  4228.     seg = seg_get_last_segment (g_editor->control_sel_l);
  4229.  
  4230.       cpopup_blend_endpoints (seg->r1, seg->g1, seg->b1, seg->a1,
  4231.                   g_editor->control_sel_r->r1,
  4232.                   g_editor->control_sel_r->g1,
  4233.                   g_editor->control_sel_r->b1,
  4234.                   g_editor->control_sel_r->a1,
  4235.                   TRUE, TRUE);
  4236.       break;
  4237.  
  4238.     case 1: /* Fetch from right endpoint */
  4239.       cpopup_blend_endpoints (g_editor->control_sel_r->r1,
  4240.                   g_editor->control_sel_r->g1,
  4241.                   g_editor->control_sel_r->b1,
  4242.                   g_editor->control_sel_r->a1,
  4243.                   g_editor->control_sel_r->r1,
  4244.                   g_editor->control_sel_r->g1,
  4245.                   g_editor->control_sel_r->b1,
  4246.                   g_editor->control_sel_r->a1,
  4247.                   TRUE, TRUE);
  4248.       break;
  4249.  
  4250.     case 2: /* Fetch from FG color */
  4251.       ed_fetch_foreground (&fg_r, &fg_g, &fg_b, &fg_a);
  4252.       cpopup_blend_endpoints (fg_r,
  4253.                   fg_g,
  4254.                   fg_b,
  4255.                   fg_a,
  4256.                   g_editor->control_sel_r->r1,
  4257.                   g_editor->control_sel_r->g1,
  4258.                   g_editor->control_sel_r->b1,
  4259.                   g_editor->control_sel_r->a1,
  4260.                   TRUE, TRUE);
  4261.       break;
  4262.  
  4263.     default: /* Load a color */
  4264.       cpopup_blend_endpoints (g_editor->saved_colors[(long) data - 3].r,
  4265.                   g_editor->saved_colors[(long) data - 3].g,
  4266.                   g_editor->saved_colors[(long) data - 3].b,
  4267.                   g_editor->saved_colors[(long) data - 3].a,
  4268.                   g_editor->control_sel_r->r1,
  4269.                   g_editor->control_sel_r->g1,
  4270.                   g_editor->control_sel_r->b1,
  4271.                   g_editor->control_sel_r->a1,
  4272.                   TRUE, TRUE);
  4273.       break;
  4274.     }
  4275.  
  4276.   curr_gradient->dirty = TRUE;
  4277.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4278. }
  4279.  
  4280. static void
  4281. cpopup_save_left_callback (GtkWidget *widget,
  4282.                gpointer   data)
  4283. {
  4284.   g_editor->saved_colors[(long) data].r = g_editor->control_sel_l->r0;
  4285.   g_editor->saved_colors[(long) data].g = g_editor->control_sel_l->g0;
  4286.   g_editor->saved_colors[(long) data].b = g_editor->control_sel_l->b0;
  4287.   g_editor->saved_colors[(long) data].a = g_editor->control_sel_l->a0;
  4288. }
  4289.  
  4290. static void
  4291. cpopup_load_right_callback (GtkWidget *widget,
  4292.                 gpointer   data)
  4293. {
  4294.   grad_segment_t *seg;
  4295.   double          fg_r, fg_g, fg_b;
  4296.   double          fg_a;
  4297.  
  4298.   switch ((long) data)
  4299.     {
  4300.     case 0: /* Fetch from right neighbor's left endpoint */
  4301.       if (g_editor->control_sel_r->next != NULL)
  4302.     seg = g_editor->control_sel_r->next;
  4303.       else
  4304.     seg = curr_gradient->segments;
  4305.  
  4306.       cpopup_blend_endpoints (g_editor->control_sel_r->r0,
  4307.                   g_editor->control_sel_r->g0,
  4308.                   g_editor->control_sel_r->b0,
  4309.                   g_editor->control_sel_r->a0,
  4310.                   seg->r0, seg->g0, seg->b0, seg->a0,
  4311.                   TRUE, TRUE);
  4312.       break;
  4313.  
  4314.     case 1: /* Fetch from left endpoint */
  4315.       cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  4316.                   g_editor->control_sel_l->g0,
  4317.                   g_editor->control_sel_l->b0,
  4318.                   g_editor->control_sel_l->a0,
  4319.                   g_editor->control_sel_l->r0,
  4320.                   g_editor->control_sel_l->g0,
  4321.                   g_editor->control_sel_l->b0,
  4322.                   g_editor->control_sel_l->a0,
  4323.                   TRUE, TRUE);
  4324.       break;
  4325.  
  4326.     case 2: /* Fetch from FG color */
  4327.       ed_fetch_foreground (&fg_r, &fg_g, &fg_b, &fg_a);
  4328.       cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  4329.                   g_editor->control_sel_l->g0,
  4330.                   g_editor->control_sel_l->b0,
  4331.                   g_editor->control_sel_l->a0,
  4332.                   fg_r,
  4333.                   fg_g,
  4334.                   fg_b,
  4335.                   fg_a,
  4336.                   TRUE, TRUE);
  4337.       break;
  4338.  
  4339.     default: /* Load a color */
  4340.       cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  4341.                   g_editor->control_sel_l->g0,
  4342.                   g_editor->control_sel_l->b0,
  4343.                   g_editor->control_sel_l->a0,
  4344.                   g_editor->saved_colors[(long) data - 3].r,
  4345.                   g_editor->saved_colors[(long) data - 3].g,
  4346.                   g_editor->saved_colors[(long) data - 3].b,
  4347.                   g_editor->saved_colors[(long) data - 3].a,
  4348.                   TRUE, TRUE);
  4349.       break;
  4350.     }
  4351.  
  4352.   curr_gradient->dirty = TRUE;
  4353.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4354. }
  4355.  
  4356. static void
  4357. cpopup_save_right_callback (GtkWidget *widget,
  4358.                 gpointer   data)
  4359. {
  4360.   g_editor->saved_colors[(long) data].r = g_editor->control_sel_r->r1;
  4361.   g_editor->saved_colors[(long) data].g = g_editor->control_sel_r->g1;
  4362.   g_editor->saved_colors[(long) data].b = g_editor->control_sel_r->b1;
  4363.   g_editor->saved_colors[(long) data].a = g_editor->control_sel_r->a1;
  4364. }
  4365.  
  4366. /*****/
  4367.  
  4368. static void
  4369. cpopup_set_color_selection_color (GtkColorSelection *cs,
  4370.                   double             r,
  4371.                   double             g,
  4372.                   double             b,
  4373.                   double             a)
  4374. {
  4375.   gdouble color[4];
  4376.  
  4377.   color[0] = r;
  4378.   color[1] = g;
  4379.   color[2] = b;
  4380.   color[3] = a;
  4381.  
  4382.   gtk_color_selection_set_color (cs, color);
  4383. }
  4384.  
  4385. static void
  4386. cpopup_get_color_selection_color (GtkColorSelection *cs,
  4387.                   double            *r,
  4388.                   double            *g,
  4389.                   double            *b,
  4390.                   double            *a)
  4391. {
  4392.   gdouble color[4];
  4393.  
  4394.   gtk_color_selection_get_color (cs, color);
  4395.  
  4396.   *r = color[0];
  4397.   *g = color[1];
  4398.   *b = color[2];
  4399.   *a = color[3];
  4400. }
  4401.  
  4402. /*****/
  4403.  
  4404. static grad_segment_t *
  4405. cpopup_save_selection (void)
  4406. {
  4407.   grad_segment_t *seg, *prev, *tmp;
  4408.   grad_segment_t *oseg, *oaseg;
  4409.  
  4410.   prev = NULL;
  4411.   oseg = g_editor->control_sel_l;
  4412.   tmp  = NULL;
  4413.  
  4414.   do
  4415.     {
  4416.       seg = seg_new_segment ();
  4417.  
  4418.       *seg = *oseg; /* Copy everything */
  4419.  
  4420.       if (prev == NULL)
  4421.     tmp = seg; /* Remember first segment */
  4422.       else
  4423.     prev->next = seg;
  4424.  
  4425.       seg->prev = prev;
  4426.       seg->next = NULL;
  4427.  
  4428.       prev  = seg;
  4429.       oaseg = oseg;
  4430.       oseg  = oseg->next;
  4431.     }
  4432.   while (oaseg != g_editor->control_sel_r);
  4433.  
  4434.   return tmp;
  4435. }
  4436.  
  4437. /*****/
  4438.  
  4439. static void
  4440. cpopup_free_selection (grad_segment_t *seg)
  4441. {
  4442.   seg_free_segments (seg);
  4443. }
  4444.  
  4445. /*****/
  4446.  
  4447. static void
  4448. cpopup_replace_selection (grad_segment_t *replace_seg)
  4449. {
  4450.   grad_segment_t *lseg, *rseg;
  4451.   grad_segment_t *replace_last;
  4452.  
  4453.   /* Remember left and right segments */
  4454.  
  4455.   lseg = g_editor->control_sel_l->prev;
  4456.   rseg = g_editor->control_sel_r->next;
  4457.  
  4458.   replace_last = seg_get_last_segment (replace_seg);
  4459.  
  4460.   /* Free old selection */
  4461.  
  4462.   g_editor->control_sel_r->next = NULL;
  4463.  
  4464.   seg_free_segments (g_editor->control_sel_l);
  4465.  
  4466.   /* Link in new segments */
  4467.  
  4468.   if (lseg)
  4469.     lseg->next = replace_seg;
  4470.   else
  4471.     curr_gradient->segments = replace_seg;
  4472.  
  4473.   replace_seg->prev = lseg;
  4474.  
  4475.   if (rseg)
  4476.     rseg->prev = replace_last;
  4477.  
  4478.   replace_last->next = rseg;
  4479.  
  4480.   g_editor->control_sel_l = replace_seg;
  4481.   g_editor->control_sel_r = replace_last;
  4482.  
  4483.   curr_gradient->last_visited = NULL; /* Force re-search */
  4484. }
  4485.  
  4486. /***** Color dialogs for left and right endpoint *****/
  4487.  
  4488. static void
  4489. cpopup_create_color_dialog (gchar         *title,
  4490.                 double         r,
  4491.                 double         g,
  4492.                 double         b,
  4493.                 double         a,
  4494.                 GtkSignalFunc  color_changed_callback,
  4495.                 GtkSignalFunc  ok_callback,
  4496.                 GtkSignalFunc  cancel_callback,
  4497.                 GtkSignalFunc  delete_callback)
  4498. {
  4499.   GtkWidget               *window;
  4500.   GtkColorSelection       *cs;
  4501.   GtkColorSelectionDialog *csd;
  4502.  
  4503.   window = gtk_color_selection_dialog_new (title);
  4504.   gtk_container_set_border_width (GTK_CONTAINER (window), 2);
  4505.   gtk_widget_destroy (GTK_COLOR_SELECTION_DIALOG (window)->help_button);
  4506.  
  4507.   gimp_help_connect_help_accel (window, gimp_standard_help_func,
  4508.                 "dialogs/gradient_editor/gradient_editor.html");
  4509.  
  4510.   csd = GTK_COLOR_SELECTION_DIALOG (window);
  4511.   cs  = GTK_COLOR_SELECTION (csd->colorsel);
  4512.  
  4513.   gtk_color_selection_set_opacity (cs, TRUE);
  4514.   gtk_color_selection_set_update_policy (cs,
  4515.                      g_editor->instant_update ?
  4516.                      GTK_UPDATE_CONTINUOUS :
  4517.                      GTK_UPDATE_DELAYED);
  4518.  
  4519.   /* FIXME: this is a hack; we set the color twice so that the
  4520.    * color selector remembers it as its "old" color, too
  4521.    */
  4522.   cpopup_set_color_selection_color (cs, r, g, b, a);
  4523.   cpopup_set_color_selection_color (cs, r, g, b, a);
  4524.  
  4525.   gtk_signal_connect (GTK_OBJECT (csd), "delete_event",
  4526.              delete_callback, window);
  4527.  
  4528.   gtk_signal_connect (GTK_OBJECT (cs), "color_changed",
  4529.              color_changed_callback, window);
  4530.  
  4531.   gtk_signal_connect (GTK_OBJECT (csd->ok_button), "clicked",
  4532.               ok_callback, window);
  4533.  
  4534.   gtk_signal_connect (GTK_OBJECT (csd->cancel_button), "clicked",
  4535.               cancel_callback, window);
  4536.  
  4537.   gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
  4538.   gtk_widget_show (window);
  4539. }
  4540.  
  4541. /*****/
  4542.  
  4543. static void
  4544. cpopup_set_left_color_callback (GtkWidget *widget,
  4545.                 gpointer   data)
  4546. {
  4547.   g_editor->left_saved_dirty    = curr_gradient->dirty;
  4548.   g_editor->left_saved_segments = cpopup_save_selection ();
  4549.  
  4550.   cpopup_create_color_dialog (_("Left endpoint's color"),
  4551.                   g_editor->control_sel_l->r0,
  4552.                   g_editor->control_sel_l->g0,
  4553.                   g_editor->control_sel_l->b0,
  4554.                   g_editor->control_sel_l->a0,
  4555.                   (GtkSignalFunc) cpopup_left_color_changed,
  4556.                   (GtkSignalFunc) cpopup_left_color_dialog_ok,
  4557.                   (GtkSignalFunc) cpopup_left_color_dialog_cancel,
  4558.                   (GtkSignalFunc) cpopup_left_color_dialog_delete);
  4559.  
  4560.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  4561. }
  4562.  
  4563. static void
  4564. cpopup_left_color_changed (GtkWidget *widget,
  4565.                gpointer   data)
  4566. {
  4567.   GtkColorSelection *cs;
  4568.   double             r, g, b, a;
  4569.  
  4570.   cs = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (data)->colorsel);
  4571.  
  4572.   cpopup_get_color_selection_color (cs, &r, &g, &b, &a);
  4573.  
  4574.   cpopup_blend_endpoints (r, g, b, a,
  4575.               g_editor->control_sel_r->r1,
  4576.               g_editor->control_sel_r->g1,
  4577.               g_editor->control_sel_r->b1,
  4578.               g_editor->control_sel_r->a1,
  4579.               TRUE, TRUE);
  4580.  
  4581.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4582. }
  4583.  
  4584. static void
  4585. cpopup_left_color_dialog_ok (GtkWidget *widget,
  4586.                  gpointer   data)
  4587. {
  4588.   cpopup_left_color_changed (widget, data);
  4589.  
  4590.   curr_gradient->dirty = TRUE;
  4591.   cpopup_free_selection(g_editor->left_saved_segments);
  4592.  
  4593.   gtk_widget_destroy (GTK_WIDGET (data));
  4594.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4595. }
  4596.  
  4597. static void
  4598. cpopup_left_color_dialog_cancel (GtkWidget *widget,
  4599.                  gpointer   data)
  4600. {
  4601.   curr_gradient->dirty = g_editor->left_saved_dirty;
  4602.   cpopup_replace_selection (g_editor->left_saved_segments);
  4603.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4604.  
  4605.   gtk_widget_destroy (GTK_WIDGET (data));
  4606.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4607. }
  4608.  
  4609. static int
  4610. cpopup_left_color_dialog_delete (GtkWidget *widget,
  4611.                  GdkEvent  *event,
  4612.                  gpointer   data)
  4613. {
  4614.   cpopup_left_color_dialog_cancel (widget, data);
  4615.  
  4616.   return TRUE;
  4617. }
  4618.  
  4619. /*****/
  4620.  
  4621. static void
  4622. cpopup_set_right_color_callback (GtkWidget *widget,
  4623.                  gpointer   data)
  4624. {
  4625.   g_editor->right_saved_dirty    = curr_gradient->dirty;
  4626.   g_editor->right_saved_segments = cpopup_save_selection ();
  4627.  
  4628.   cpopup_create_color_dialog (_("Right endpoint's color"),
  4629.                   g_editor->control_sel_r->r1,
  4630.                   g_editor->control_sel_r->g1,
  4631.                   g_editor->control_sel_r->b1,
  4632.                   g_editor->control_sel_r->a1,
  4633.                   (GtkSignalFunc) cpopup_right_color_changed,
  4634.                   (GtkSignalFunc) cpopup_right_color_dialog_ok,
  4635.                   (GtkSignalFunc) cpopup_right_color_dialog_cancel,
  4636.                   (GtkSignalFunc) cpopup_right_color_dialog_delete);
  4637.  
  4638.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  4639. }
  4640.  
  4641. static void
  4642. cpopup_right_color_changed (GtkWidget *widget,
  4643.                 gpointer   data)
  4644. {
  4645.   GtkColorSelection *cs;
  4646.   double             r, g, b, a;
  4647.  
  4648.   cs = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (data)->colorsel);
  4649.  
  4650.   cpopup_get_color_selection_color (cs, &r, &g, &b, &a);
  4651.  
  4652.   cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  4653.               g_editor->control_sel_l->g0,
  4654.               g_editor->control_sel_l->b0,
  4655.               g_editor->control_sel_l->a0,
  4656.               r, g, b, a,
  4657.               TRUE, TRUE);
  4658.  
  4659.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4660. }
  4661.  
  4662. static void
  4663. cpopup_right_color_dialog_ok (GtkWidget *widget,
  4664.                   gpointer   data)
  4665. {
  4666.   cpopup_right_color_changed (widget, data);
  4667.  
  4668.   curr_gradient->dirty = TRUE;
  4669.   cpopup_free_selection (g_editor->right_saved_segments);
  4670.  
  4671.   gtk_widget_destroy (GTK_WIDGET (data));
  4672.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4673. }
  4674.  
  4675. static void
  4676. cpopup_right_color_dialog_cancel (GtkWidget *widget,
  4677.                   gpointer   data)
  4678. {
  4679.   curr_gradient->dirty = g_editor->right_saved_dirty;
  4680.   cpopup_replace_selection (g_editor->right_saved_segments);
  4681.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4682.  
  4683.   gtk_widget_destroy (GTK_WIDGET (data));
  4684.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4685. }
  4686.  
  4687. static int
  4688. cpopup_right_color_dialog_delete (GtkWidget *widget,
  4689.                   GdkEvent  *event,
  4690.                   gpointer   data)
  4691. {
  4692.   cpopup_right_color_dialog_cancel (widget, data);
  4693.  
  4694.   return TRUE;
  4695. }
  4696.  
  4697. /***** Blending menu *****/
  4698.  
  4699. static GtkWidget *
  4700. cpopup_create_blending_menu (void)
  4701. {
  4702.   GtkWidget *menu;
  4703.   GtkWidget *menuitem;
  4704.   GSList    *group;
  4705.   gint i;
  4706.   gint num_items;
  4707.  
  4708.   menu  = gtk_menu_new ();
  4709.   group = NULL;
  4710.  
  4711.   num_items = (sizeof (g_editor->control_blending_items) /
  4712.            sizeof (g_editor->control_blending_items[0]));
  4713.  
  4714.   for (i = 0; i < num_items; i++)
  4715.     {
  4716.       if (i == (num_items - 1))
  4717.     menuitem = gtk_radio_menu_item_new_with_label(group, _("(Varies)"));
  4718.       else
  4719.     menuitem =
  4720.       gtk_radio_menu_item_new_with_label (group,
  4721.                           gettext (blending_types[i]));
  4722.  
  4723.       group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  4724.  
  4725.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  4726.               (GtkSignalFunc) cpopup_blending_callback,
  4727.               (gpointer) ((long) i));
  4728.  
  4729.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4730.       gtk_widget_show (menuitem);
  4731.  
  4732.       g_editor->control_blending_items[i] = menuitem;
  4733.     }
  4734.  
  4735.   /* "Varies" is always disabled */
  4736.   gtk_widget_set_sensitive (g_editor->control_blending_items[num_items - 1], FALSE);
  4737.  
  4738.   return menu;
  4739. }
  4740.  
  4741. static void
  4742. cpopup_blending_callback (GtkWidget *widget,
  4743.               gpointer   data)
  4744. {
  4745.   grad_type_t     type;
  4746.   grad_segment_t *seg, *aseg;
  4747.  
  4748.   if (!GTK_CHECK_MENU_ITEM (widget)->active)
  4749.     return; /* Do nothing if the menu item is being deactivated */
  4750.  
  4751.   type = (grad_type_t) data;
  4752.   seg  = g_editor->control_sel_l;
  4753.  
  4754.   do
  4755.     {
  4756.       seg->type = type;
  4757.  
  4758.       aseg = seg;
  4759.       seg  = seg->next;
  4760.     }
  4761.   while (aseg != g_editor->control_sel_r);
  4762.  
  4763.   curr_gradient->dirty = TRUE;
  4764.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4765. }
  4766.  
  4767. /***** Coloring menu *****/
  4768.  
  4769. static GtkWidget *
  4770. cpopup_create_coloring_menu (void)
  4771. {
  4772.   GtkWidget *menu;
  4773.   GtkWidget *menuitem;
  4774.   GSList    *group;
  4775.   gint i;
  4776.   gint num_items;
  4777.  
  4778.   menu  = gtk_menu_new ();
  4779.   group = NULL;
  4780.  
  4781.   num_items = (sizeof (g_editor->control_coloring_items) /
  4782.            sizeof (g_editor->control_coloring_items[0]));
  4783.  
  4784.   for (i = 0; i < num_items; i++)
  4785.     {
  4786.       if (i == (num_items - 1))
  4787.     menuitem = gtk_radio_menu_item_new_with_label(group, _("(Varies)"));
  4788.       else
  4789.     menuitem = gtk_radio_menu_item_new_with_label (group, gettext (coloring_types[i]));
  4790.  
  4791.       group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  4792.  
  4793.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  4794.               (GtkSignalFunc) cpopup_coloring_callback,
  4795.               (gpointer) ((long) i));
  4796.  
  4797.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4798.       gtk_widget_show (menuitem);
  4799.  
  4800.       g_editor->control_coloring_items[i] = menuitem;
  4801.     }
  4802.  
  4803.   /* "Varies" is always disabled */
  4804.   gtk_widget_set_sensitive (g_editor->control_coloring_items[num_items - 1], FALSE);
  4805.  
  4806.   return menu;
  4807. }
  4808.  
  4809. static void
  4810. cpopup_coloring_callback (GtkWidget *widget,
  4811.               gpointer   data)
  4812. {
  4813.   grad_color_t    color;
  4814.   grad_segment_t *seg, *aseg;
  4815.  
  4816.   if (! GTK_CHECK_MENU_ITEM (widget)->active)
  4817.     return; /* Do nothing if the menu item is being deactivated */
  4818.  
  4819.   color = (grad_color_t) data;
  4820.   seg   = g_editor->control_sel_l;
  4821.  
  4822.   do
  4823.     {
  4824.       seg->color = color;
  4825.  
  4826.       aseg = seg;
  4827.       seg  = seg->next;
  4828.     }
  4829.   while (aseg != g_editor->control_sel_r);
  4830.  
  4831.   curr_gradient->dirty = TRUE;
  4832.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4833. }
  4834.  
  4835. /*****/
  4836.  
  4837. static void
  4838. cpopup_split_midpoint_callback (GtkWidget *widget,
  4839.                 gpointer   data)
  4840. {
  4841.   grad_segment_t *seg, *lseg, *rseg;
  4842.  
  4843.   seg = g_editor->control_sel_l;
  4844.  
  4845.   do
  4846.     {
  4847.       cpopup_split_midpoint (seg, &lseg, &rseg);
  4848.       seg = rseg->next;
  4849.     }
  4850.   while (lseg != g_editor->control_sel_r);
  4851.  
  4852.   g_editor->control_sel_r = rseg;
  4853.  
  4854.   curr_gradient->last_visited = NULL; /* Force re-search */
  4855.   curr_gradient->dirty = TRUE;
  4856.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  4857. }
  4858.  
  4859. static void
  4860. cpopup_split_midpoint (grad_segment_t  *lseg,
  4861.                grad_segment_t **newl,
  4862.                grad_segment_t **newr)
  4863. {
  4864.   double          r, g, b, a;
  4865.   grad_segment_t *newseg;
  4866.  
  4867.   /* Get color at original segment's midpoint */
  4868.   gradient_get_color_at (curr_gradient, lseg->middle, &r, &g, &b, &a);
  4869.  
  4870.   /* Create a new segment and insert it in the list */
  4871.  
  4872.   newseg = seg_new_segment();
  4873.  
  4874.   newseg->prev = lseg;
  4875.   newseg->next = lseg->next;
  4876.  
  4877.   lseg->next = newseg;
  4878.  
  4879.   if (newseg->next)
  4880.     newseg->next->prev = newseg;
  4881.  
  4882.   /* Set coordinates of new segment */
  4883.  
  4884.   newseg->left   = lseg->middle;
  4885.   newseg->right  = lseg->right;
  4886.   newseg->middle = (newseg->left + newseg->right) / 2.0;
  4887.  
  4888.   /* Set coordinates of original segment */
  4889.  
  4890.   lseg->right  = newseg->left;
  4891.   lseg->middle = (lseg->left + lseg->right) / 2.0;
  4892.  
  4893.   /* Set colors of both segments */
  4894.  
  4895.   newseg->r1 = lseg->r1;
  4896.   newseg->g1 = lseg->g1;
  4897.   newseg->b1 = lseg->b1;
  4898.   newseg->a1 = lseg->a1;
  4899.  
  4900.   lseg->r1 = newseg->r0 = r;
  4901.   lseg->g1 = newseg->g0 = g;
  4902.   lseg->b1 = newseg->b0 = b;
  4903.   lseg->a1 = newseg->a0 = a;
  4904.  
  4905.   /* Set parameters of new segment */
  4906.  
  4907.   newseg->type  = lseg->type;
  4908.   newseg->color = lseg->color;
  4909.  
  4910.   /* Done */
  4911.  
  4912.   *newl = lseg;
  4913.   *newr = newseg;
  4914. }
  4915.  
  4916. /*****/
  4917.  
  4918. static void
  4919. cpopup_split_uniform_callback (GtkWidget *widget,
  4920.                    gpointer   data)
  4921. {
  4922.   GtkWidget *dialog;
  4923.   GtkWidget *vbox;
  4924.   GtkWidget *label;
  4925.   GtkWidget *scale;
  4926.   GtkObject *scale_data;
  4927.  
  4928.   /*  Create dialog window  */
  4929.   dialog =
  4930.     gimp_dialog_new ((g_editor->control_sel_l == g_editor->control_sel_r) ?
  4931.              _("Split segment uniformly") :
  4932.              _("Split segments uniformly"),
  4933.              "gradient_segment_split_uniformly",
  4934.              gimp_standard_help_func,
  4935.              "dialogs/gradient_editor/split_segments_uniformly.html",
  4936.              GTK_WIN_POS_MOUSE,
  4937.              FALSE, TRUE, FALSE,
  4938.  
  4939.              _("Split"), cpopup_split_uniform_split_callback,
  4940.              NULL, NULL, NULL, TRUE, FALSE,
  4941.              _("Cancel"), cpopup_split_uniform_cancel_callback,
  4942.              NULL, NULL, NULL, FALSE, TRUE,
  4943.  
  4944.              NULL);
  4945.  
  4946.   /*  The main vbox  */
  4947.   vbox = gtk_vbox_new (FALSE, 0);
  4948.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
  4949.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
  4950.   gtk_widget_show (vbox);
  4951.  
  4952.   /*  Instructions  */
  4953.   label = gtk_label_new (_("Please select the number of uniform parts"));
  4954.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  4955.   gtk_widget_show (label);
  4956.  
  4957.   label =
  4958.     gtk_label_new ((g_editor->control_sel_l == g_editor->control_sel_r) ?
  4959.            _("in which you want to split the selected segment") :
  4960.            _("in which you want to split the segments in the selection"));
  4961.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  4962.   gtk_widget_show (label);
  4963.  
  4964.   /*  Scale  */
  4965.   g_editor->split_parts = 2;
  4966.   scale_data  = gtk_adjustment_new (2.0, 2.0, 21.0, 1.0, 1.0, 1.0);
  4967.  
  4968.   scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
  4969.   gtk_scale_set_digits (GTK_SCALE (scale), 0);
  4970.   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  4971.   gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 4);
  4972.   gtk_widget_show (scale);
  4973.  
  4974.   gtk_signal_connect (scale_data, "value_changed",
  4975.               (GtkSignalFunc) cpopup_split_uniform_scale_update,
  4976.               NULL);
  4977.  
  4978.   /*  Show!  */
  4979.   gtk_widget_show (dialog);
  4980.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  4981. }
  4982.  
  4983. static void
  4984. cpopup_split_uniform_scale_update (GtkAdjustment *adjustment,
  4985.                    gpointer       data)
  4986. {
  4987.   g_editor->split_parts = (gint) (adjustment->value + 0.5);
  4988. }
  4989.  
  4990. static void
  4991. cpopup_split_uniform_split_callback (GtkWidget *widget,
  4992.                      gpointer   data)
  4993. {
  4994.   grad_segment_t *seg, *aseg, *lseg, *rseg, *lsel;
  4995.  
  4996.   gtk_widget_destroy (GTK_WIDGET (data));
  4997.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4998.  
  4999.   seg  = g_editor->control_sel_l;
  5000.   lsel = NULL;
  5001.  
  5002.   do
  5003.     {
  5004.       aseg = seg;
  5005.  
  5006.       cpopup_split_uniform (seg, g_editor->split_parts, &lseg, &rseg);
  5007.  
  5008.       if (seg == g_editor->control_sel_l)
  5009.     lsel = lseg;
  5010.  
  5011.       seg = rseg->next;
  5012.     }
  5013.   while (aseg != g_editor->control_sel_r);
  5014.  
  5015.   g_editor->control_sel_l = lsel;
  5016.   g_editor->control_sel_r = rseg;
  5017.  
  5018.   curr_gradient->last_visited = NULL; /* Force re-search */
  5019.   curr_gradient->dirty = TRUE;
  5020.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5021. }
  5022.  
  5023. static void
  5024. cpopup_split_uniform_cancel_callback (GtkWidget *widget,
  5025.                       gpointer   data)
  5026. {
  5027.   gtk_widget_destroy (GTK_WIDGET (data));
  5028.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  5029. }
  5030.  
  5031. static void
  5032. cpopup_split_uniform (grad_segment_t  *lseg,
  5033.               int              parts,
  5034.               grad_segment_t **newl,
  5035.               grad_segment_t **newr)
  5036. {
  5037.   grad_segment_t *seg, *prev, *tmp;
  5038.   gdouble          seg_len;
  5039.   gint             i;
  5040.  
  5041.   seg_len = (lseg->right - lseg->left) / parts; /* Length of divisions */
  5042.  
  5043.   seg  = NULL;
  5044.   prev = NULL;
  5045.   tmp  = NULL;
  5046.  
  5047.   for (i = 0; i < parts; i++)
  5048.     {
  5049.       seg = seg_new_segment();
  5050.  
  5051.       if (i == 0)
  5052.     tmp = seg; /* Remember first segment */
  5053.  
  5054.       seg->left   = lseg->left + i * seg_len;
  5055.       seg->right  = lseg->left + (i + 1) * seg_len;
  5056.       seg->middle = (seg->left + seg->right) / 2.0;
  5057.  
  5058.       gradient_get_color_at (curr_gradient, seg->left,
  5059.                  &seg->r0, &seg->g0, &seg->b0, &seg->a0);
  5060.       gradient_get_color_at (curr_gradient, seg->right,
  5061.                  &seg->r1, &seg->g1, &seg->b1, &seg->a1);
  5062.  
  5063.       seg->type  = lseg->type;
  5064.       seg->color = lseg->color;
  5065.  
  5066.       seg->prev = prev;
  5067.       seg->next = NULL;
  5068.  
  5069.       if (prev)
  5070.     prev->next = seg;
  5071.  
  5072.       prev = seg;
  5073.     }
  5074.  
  5075.   /* Fix edges */
  5076.  
  5077.   tmp->r0 = lseg->r0;
  5078.   tmp->g0 = lseg->g0;
  5079.   tmp->b0 = lseg->b0;
  5080.   tmp->a0 = lseg->a0;
  5081.  
  5082.   seg->r1 = lseg->r1;
  5083.   seg->g1 = lseg->g1;
  5084.   seg->b1 = lseg->b1;
  5085.   seg->a1 = lseg->a1;
  5086.  
  5087.   tmp->left  = lseg->left;
  5088.   seg->right = lseg->right; /* To squish accumulative error */
  5089.  
  5090.   /* Link in list */
  5091.  
  5092.   tmp->prev = lseg->prev;
  5093.   seg->next = lseg->next;
  5094.  
  5095.   if (lseg->prev)
  5096.     lseg->prev->next = tmp;
  5097.   else
  5098.     curr_gradient->segments = tmp; /* We are on leftmost segment */
  5099.  
  5100.   if (lseg->next)
  5101.     lseg->next->prev = seg;
  5102.  
  5103.   curr_gradient->last_visited = NULL; /* Force re-search */
  5104.  
  5105.   /* Done */
  5106.  
  5107.   *newl = tmp;
  5108.   *newr = seg;
  5109.  
  5110.   /* Delete old segment */
  5111.  
  5112.   seg_free_segment (lseg);
  5113. }
  5114.  
  5115. /*****/
  5116.  
  5117. static void
  5118. cpopup_delete_callback (GtkWidget *widget,
  5119.             gpointer   data)
  5120. {
  5121.   grad_segment_t *lseg, *rseg, *seg, *aseg, *next;
  5122.   double          join;
  5123.  
  5124.   /* Remember segments to the left and to the right of the selection */
  5125.  
  5126.   lseg = g_editor->control_sel_l->prev;
  5127.   rseg = g_editor->control_sel_r->next;
  5128.  
  5129.   /* Cannot delete all the segments in the gradient */
  5130.  
  5131.   if ((lseg == NULL) && (rseg == NULL))
  5132.     return;
  5133.  
  5134.   /* Calculate join point */
  5135.  
  5136.   join = (g_editor->control_sel_l->left + g_editor->control_sel_r->right) / 2.0;
  5137.  
  5138.   if (lseg == NULL)
  5139.     join = 0.0;
  5140.   else if (rseg == NULL)
  5141.     join = 1.0;
  5142.  
  5143.   /* Move segments */
  5144.  
  5145.   if (lseg != NULL)
  5146.     control_compress_range (lseg, lseg, lseg->left, join);
  5147.  
  5148.   if (rseg != NULL)
  5149.     control_compress_range (rseg, rseg, join, rseg->right);
  5150.  
  5151.   /* Link */
  5152.  
  5153.   if (lseg)
  5154.     lseg->next = rseg;
  5155.  
  5156.   if (rseg)
  5157.     rseg->prev = lseg;
  5158.  
  5159.   /* Delete old segments */
  5160.  
  5161.   seg = g_editor->control_sel_l;
  5162.  
  5163.   do
  5164.     {
  5165.       next = seg->next;
  5166.       aseg = seg;
  5167.  
  5168.       seg_free_segment (seg);
  5169.  
  5170.       seg = next;
  5171.     }
  5172.   while (aseg != g_editor->control_sel_r);
  5173.  
  5174.   /* Change selection */
  5175.  
  5176.   if (rseg)
  5177.     {
  5178.       g_editor->control_sel_l = rseg;
  5179.       g_editor->control_sel_r = rseg;
  5180.     }
  5181.   else
  5182.     {
  5183.       g_editor->control_sel_l = lseg;
  5184.       g_editor->control_sel_r = lseg;
  5185.     }
  5186.  
  5187.   if (lseg == NULL)
  5188.     curr_gradient->segments = rseg;
  5189.  
  5190.   /* Done */
  5191.  
  5192.   curr_gradient->last_visited = NULL; /* Force re-search */
  5193.   curr_gradient->dirty = TRUE;
  5194.  
  5195.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5196. }
  5197.  
  5198. /*****/
  5199.  
  5200. static void
  5201. cpopup_recenter_callback (GtkWidget *wiodget,
  5202.               gpointer   data)
  5203. {
  5204.   grad_segment_t *seg, *aseg;
  5205.  
  5206.   seg = g_editor->control_sel_l;
  5207.  
  5208.   do
  5209.     {
  5210.       seg->middle = (seg->left + seg->right) / 2.0;
  5211.  
  5212.       aseg = seg;
  5213.       seg  = seg->next;
  5214.     }
  5215.   while (aseg != g_editor->control_sel_r);
  5216.  
  5217.   curr_gradient->dirty = TRUE;
  5218.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5219. }
  5220.  
  5221. /*****/
  5222.  
  5223. static void
  5224. cpopup_redistribute_callback (GtkWidget *widget,
  5225.                   gpointer   data)
  5226. {
  5227.   grad_segment_t *seg, *aseg;
  5228.   double          left, right, seg_len;
  5229.   int             num_segs;
  5230.   int             i;
  5231.  
  5232.   /* Count number of segments in selection */
  5233.  
  5234.   num_segs = 0;
  5235.   seg      = g_editor->control_sel_l;
  5236.  
  5237.   do
  5238.     {
  5239.       num_segs++;
  5240.       aseg = seg;
  5241.       seg  = seg->next;
  5242.     }
  5243.   while (aseg != g_editor->control_sel_r);
  5244.  
  5245.   /* Calculate new segment length */
  5246.  
  5247.   left    = g_editor->control_sel_l->left;
  5248.   right   = g_editor->control_sel_r->right;
  5249.   seg_len = (right - left) / num_segs;
  5250.  
  5251.   /* Redistribute */
  5252.  
  5253.   seg = g_editor->control_sel_l;
  5254.  
  5255.   for (i = 0; i < num_segs; i++)
  5256.     {
  5257.       seg->left   = left + i * seg_len;
  5258.       seg->right  = left + (i + 1) * seg_len;
  5259.       seg->middle = (seg->left + seg->right) / 2.0;
  5260.  
  5261.       seg = seg->next;
  5262.     }
  5263.  
  5264.   /* Fix endpoints to squish accumulative error */
  5265.  
  5266.   g_editor->control_sel_l->left  = left;
  5267.   g_editor->control_sel_r->right = right;
  5268.  
  5269.   /* Done */
  5270.  
  5271.   curr_gradient->dirty = TRUE;
  5272.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5273. }
  5274.  
  5275. /***** Control popup -> selection options functions *****/
  5276.  
  5277. static GtkWidget *
  5278. cpopup_create_sel_ops_menu (void)
  5279. {
  5280.   GtkWidget     *menu;
  5281.   GtkWidget     *menuitem;
  5282.   GtkAccelGroup *accel_group;
  5283.  
  5284.   menu = gtk_menu_new ();
  5285.   accel_group = g_editor->accel_group;
  5286.  
  5287.   gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
  5288.  
  5289.   /* Flip */
  5290.   menuitem =
  5291.     cpopup_create_menu_item_with_label ("", &g_editor->control_flip_label);
  5292.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  5293.               (GtkSignalFunc) cpopup_flip_callback,
  5294.               NULL);
  5295.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5296.   gtk_widget_show (menuitem);
  5297.   gtk_widget_add_accelerator (menuitem, "activate",
  5298.                   accel_group,
  5299.                   'F', 0,
  5300.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  5301.  
  5302.   /* Replicate */
  5303.   menuitem =
  5304.     cpopup_create_menu_item_with_label ("", &g_editor->control_replicate_label);
  5305.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  5306.               (GtkSignalFunc) cpopup_replicate_callback,
  5307.               NULL);
  5308.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5309.   gtk_widget_show (menuitem);
  5310.   gtk_widget_add_accelerator (menuitem, "activate",
  5311.                   accel_group,
  5312.                   'M', 0,
  5313.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  5314.  
  5315.   /* Blend colors / opacity */
  5316.   menuitem = gtk_menu_item_new ();
  5317.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5318.   gtk_widget_show (menuitem);
  5319.  
  5320.   menuitem = gtk_menu_item_new_with_label (_("Blend endpoints' colors"));
  5321.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  5322.               (GtkSignalFunc) cpopup_blend_colors,
  5323.               NULL);
  5324.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5325.   gtk_widget_show (menuitem);
  5326.   g_editor->control_blend_colors_menu_item = menuitem;
  5327.   gtk_widget_add_accelerator (menuitem, "activate",
  5328.                   accel_group,
  5329.                   'B', 0,
  5330.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  5331.  
  5332.   menuitem = gtk_menu_item_new_with_label (_("Blend endpoints' opacity"));
  5333.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  5334.               (GtkSignalFunc) cpopup_blend_opacity,
  5335.               NULL);
  5336.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5337.   gtk_widget_show (menuitem);
  5338.   gtk_widget_add_accelerator (menuitem, "activate",
  5339.                   accel_group,
  5340.                   'B', GDK_CONTROL_MASK,
  5341.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  5342.   g_editor->control_blend_opacity_menu_item = menuitem;
  5343.  
  5344.   return menu;
  5345. }
  5346.  
  5347. /*****/
  5348.  
  5349. static void
  5350. cpopup_flip_callback (GtkWidget *widget,
  5351.               gpointer   data)
  5352. {
  5353.   grad_segment_t *oseg, *oaseg;
  5354.   grad_segment_t *seg, *prev, *tmp;
  5355.   grad_segment_t *lseg, *rseg;
  5356.   double          left, right;
  5357.  
  5358.   left  = g_editor->control_sel_l->left;
  5359.   right = g_editor->control_sel_r->right;
  5360.  
  5361.   /* Build flipped segments */
  5362.  
  5363.   prev = NULL;
  5364.   oseg = g_editor->control_sel_r;
  5365.   tmp  = NULL;
  5366.  
  5367.   do
  5368.     {
  5369.       seg = seg_new_segment ();
  5370.  
  5371.       if (prev == NULL)
  5372.     {
  5373.       seg->left = left;
  5374.       tmp = seg; /* Remember first segment */
  5375.     }
  5376.       else
  5377.     seg->left = left + right - oseg->right;
  5378.  
  5379.       seg->middle = left + right - oseg->middle;
  5380.       seg->right  = left + right - oseg->left;
  5381.  
  5382.       seg->r0 = oseg->r1;
  5383.       seg->g0 = oseg->g1;
  5384.       seg->b0 = oseg->b1;
  5385.       seg->a0 = oseg->a1;
  5386.  
  5387.       seg->r1 = oseg->r0;
  5388.       seg->g1 = oseg->g0;
  5389.       seg->b1 = oseg->b0;
  5390.       seg->a1 = oseg->a0;
  5391.  
  5392.       switch (oseg->type)
  5393.     {
  5394.     case GRAD_SPHERE_INCREASING:
  5395.       seg->type = GRAD_SPHERE_DECREASING;
  5396.       break;
  5397.  
  5398.     case GRAD_SPHERE_DECREASING:
  5399.       seg->type = GRAD_SPHERE_INCREASING;
  5400.       break;
  5401.  
  5402.     default:
  5403.       seg->type = oseg->type;
  5404.     }
  5405.  
  5406.       switch (oseg->color)
  5407.     {
  5408.     case GRAD_HSV_CCW:
  5409.       seg->color = GRAD_HSV_CW;
  5410.       break;
  5411.  
  5412.     case GRAD_HSV_CW:
  5413.       seg->color = GRAD_HSV_CCW;
  5414.       break;
  5415.  
  5416.     default:
  5417.       seg->color = oseg->color;
  5418.     }
  5419.  
  5420.       seg->prev = prev;
  5421.       seg->next = NULL;
  5422.  
  5423.       if (prev)
  5424.     prev->next = seg;
  5425.  
  5426.       prev = seg;
  5427.  
  5428.       oaseg = oseg;
  5429.       oseg  = oseg->prev; /* Move backwards! */
  5430.     }
  5431.   while (oaseg != g_editor->control_sel_l);
  5432.  
  5433.   seg->right = right; /* Squish accumulative error */
  5434.  
  5435.   /* Free old segments */
  5436.  
  5437.   lseg = g_editor->control_sel_l->prev;
  5438.   rseg = g_editor->control_sel_r->next;
  5439.  
  5440.   oseg = g_editor->control_sel_l;
  5441.  
  5442.   do
  5443.     {
  5444.       oaseg = oseg->next;
  5445.       seg_free_segment (oseg);
  5446.       oseg = oaseg;
  5447.     }
  5448.   while (oaseg != rseg);
  5449.  
  5450.   /* Link in new segments */
  5451.  
  5452.   if (lseg)
  5453.     lseg->next = tmp;
  5454.   else
  5455.     curr_gradient->segments = tmp;
  5456.  
  5457.   tmp->prev = lseg;
  5458.  
  5459.   seg->next = rseg;
  5460.  
  5461.   if (rseg)
  5462.     rseg->prev = seg;
  5463.  
  5464.   /* Reset selection */
  5465.  
  5466.   g_editor->control_sel_l = tmp;
  5467.   g_editor->control_sel_r = seg;
  5468.  
  5469.   /* Done */
  5470.  
  5471.   curr_gradient->last_visited = NULL; /* Force re-search */
  5472.   curr_gradient->dirty = TRUE;
  5473.  
  5474.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5475. }
  5476.  
  5477. /*****/
  5478.  
  5479. static void
  5480. cpopup_replicate_callback (GtkWidget *widget,
  5481.                gpointer   data)
  5482. {
  5483.   GtkWidget *dialog;
  5484.   GtkWidget *vbox;
  5485.   GtkWidget *label;
  5486.   GtkWidget *scale;
  5487.   GtkObject *scale_data;
  5488.  
  5489.   /*  Create dialog window  */
  5490.   dialog =
  5491.     gimp_dialog_new ((g_editor->control_sel_l == g_editor->control_sel_r) ?
  5492.              _("Replicate segment") :
  5493.              _("Replicate selection"),
  5494.              "gradient_segment_replicate",
  5495.              gimp_standard_help_func,
  5496.              "dialogs/gradient_editor/replicate_segment.html",
  5497.              GTK_WIN_POS_MOUSE,
  5498.              FALSE, TRUE, FALSE,
  5499.  
  5500.              _("Replicate"), cpopup_do_replicate_callback,
  5501.              NULL, NULL, NULL, FALSE, FALSE,
  5502.              _("Cancel"), cpopup_replicate_cancel_callback,
  5503.              NULL, NULL, NULL, TRUE, TRUE,
  5504.  
  5505.              NULL);
  5506.  
  5507.   vbox = gtk_vbox_new (FALSE, 0);
  5508.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
  5509.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
  5510.   gtk_widget_show (vbox);
  5511.  
  5512.   /*  Instructions  */
  5513.   label = gtk_label_new (_("Please select the number of times"));
  5514.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  5515.   gtk_widget_show (label);
  5516.  
  5517.   label = gtk_label_new ((g_editor->control_sel_l == g_editor->control_sel_r) ?
  5518.              _("you want to replicate the selected segment") :
  5519.              _("you want to replicate the selection"));
  5520.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  5521.   gtk_widget_show (label);
  5522.  
  5523.   /*  Scale  */
  5524.   g_editor->replicate_times = 2;
  5525.   scale_data  = gtk_adjustment_new (2.0, 2.0, 21.0, 1.0, 1.0, 1.0);
  5526.  
  5527.   scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
  5528.   gtk_scale_set_digits (GTK_SCALE (scale), 0);
  5529.   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  5530.   gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, TRUE, 4);
  5531.   gtk_widget_show (scale);
  5532.  
  5533.   gtk_signal_connect (scale_data, "value_changed",
  5534.               (GtkSignalFunc) cpopup_replicate_scale_update,
  5535.               NULL);
  5536.  
  5537.   /*  Show!  */
  5538.   gtk_widget_show (dialog);
  5539.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  5540. }
  5541.  
  5542. static void
  5543. cpopup_replicate_scale_update (GtkAdjustment *adjustment,
  5544.                    gpointer       data)
  5545. {
  5546.   g_editor->replicate_times = (int) (adjustment->value + 0.5);
  5547. }
  5548.  
  5549. static void
  5550. cpopup_do_replicate_callback (GtkWidget *widget,
  5551.                   gpointer   data)
  5552. {
  5553.   gdouble          sel_left, sel_right, sel_len;
  5554.   gdouble          new_left;
  5555.   gdouble          factor;
  5556.   grad_segment_t  *prev, *seg, *tmp;
  5557.   grad_segment_t  *oseg, *oaseg;
  5558.   grad_segment_t  *lseg, *rseg;
  5559.   gint             i;
  5560.  
  5561.   gtk_widget_destroy (GTK_WIDGET (data));
  5562.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  5563.  
  5564.   /* Remember original parameters */
  5565.   sel_left  = g_editor->control_sel_l->left;
  5566.   sel_right = g_editor->control_sel_r->right;
  5567.   sel_len   = sel_right - sel_left;
  5568.  
  5569.   factor = 1.0 / g_editor->replicate_times;
  5570.  
  5571.   /* Build replicated segments */
  5572.  
  5573.   prev = NULL;
  5574.   seg  = NULL;
  5575.   tmp  = NULL;
  5576.  
  5577.   for (i = 0; i < g_editor->replicate_times; i++)
  5578.     {
  5579.       /* Build one cycle */
  5580.  
  5581.       new_left  = sel_left + i * factor * sel_len;
  5582.  
  5583.       oseg = g_editor->control_sel_l;
  5584.  
  5585.       do
  5586.     {
  5587.       seg = seg_new_segment();
  5588.  
  5589.       if (prev == NULL)
  5590.         {
  5591.           seg->left = sel_left;
  5592.           tmp = seg; /* Remember first segment */
  5593.         }
  5594.       else
  5595.         seg->left = new_left + factor * (oseg->left - sel_left);
  5596.  
  5597.       seg->middle = new_left + factor * (oseg->middle - sel_left);
  5598.       seg->right  = new_left + factor * (oseg->right - sel_left);
  5599.  
  5600.       seg->r0 = oseg->r0;
  5601.       seg->g0 = oseg->g0;
  5602.       seg->b0 = oseg->b0;
  5603.       seg->a0 = oseg->a0;
  5604.  
  5605.       seg->r1 = oseg->r1;
  5606.       seg->g1 = oseg->g1;
  5607.       seg->b1 = oseg->b1;
  5608.       seg->a1 = oseg->a1;
  5609.  
  5610.       seg->type  = oseg->type;
  5611.       seg->color = oseg->color;
  5612.  
  5613.       seg->prev = prev;
  5614.       seg->next = NULL;
  5615.  
  5616.       if (prev)
  5617.         prev->next = seg;
  5618.  
  5619.       prev = seg;
  5620.  
  5621.       oaseg = oseg;
  5622.       oseg  = oseg->next;
  5623.     }
  5624.       while (oaseg != g_editor->control_sel_r);
  5625.     }
  5626.  
  5627.   seg->right = sel_right; /* Squish accumulative error */
  5628.  
  5629.   /* Free old segments */
  5630.  
  5631.   lseg = g_editor->control_sel_l->prev;
  5632.   rseg = g_editor->control_sel_r->next;
  5633.  
  5634.   oseg = g_editor->control_sel_l;
  5635.  
  5636.   do
  5637.     {
  5638.       oaseg = oseg->next;
  5639.       seg_free_segment(oseg);
  5640.       oseg = oaseg;
  5641.     }
  5642.   while (oaseg != rseg);
  5643.  
  5644.   /* Link in new segments */
  5645.  
  5646.   if (lseg)
  5647.     lseg->next = tmp;
  5648.   else
  5649.     curr_gradient->segments = tmp;
  5650.  
  5651.   tmp->prev = lseg;
  5652.  
  5653.   seg->next = rseg;
  5654.  
  5655.   if (rseg)
  5656.     rseg->prev = seg;
  5657.  
  5658.   /* Reset selection */
  5659.  
  5660.   g_editor->control_sel_l = tmp;
  5661.   g_editor->control_sel_r = seg;
  5662.  
  5663.   /* Done */
  5664.  
  5665.   curr_gradient->last_visited = NULL; /* Force re-search */
  5666.   curr_gradient->dirty = TRUE;
  5667.  
  5668.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5669. }
  5670.  
  5671. static void
  5672. cpopup_replicate_cancel_callback (GtkWidget *widget,
  5673.                   gpointer   data)
  5674. {
  5675.   gtk_widget_destroy (GTK_WIDGET (data));
  5676.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  5677. }
  5678.  
  5679. /*****/
  5680.  
  5681. static void
  5682. cpopup_blend_colors (GtkWidget *widget,
  5683.              gpointer   data)
  5684. {
  5685.   cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  5686.               g_editor->control_sel_l->g0,
  5687.               g_editor->control_sel_l->b0,
  5688.               g_editor->control_sel_l->a0,
  5689.               g_editor->control_sel_r->r1,
  5690.               g_editor->control_sel_r->g1,
  5691.               g_editor->control_sel_r->b1,
  5692.               g_editor->control_sel_r->a1,
  5693.               TRUE, FALSE);
  5694.  
  5695.   curr_gradient->dirty = TRUE;
  5696.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  5697. }
  5698.  
  5699. static void
  5700. cpopup_blend_opacity (GtkWidget *widget,
  5701.               gpointer   data)
  5702. {
  5703.   cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  5704.               g_editor->control_sel_l->g0,
  5705.               g_editor->control_sel_l->b0,
  5706.               g_editor->control_sel_l->a0,
  5707.               g_editor->control_sel_r->r1,
  5708.               g_editor->control_sel_r->g1,
  5709.               g_editor->control_sel_r->b1,
  5710.               g_editor->control_sel_r->a1,
  5711.               FALSE, TRUE);
  5712.  
  5713.   curr_gradient->dirty = TRUE;
  5714.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  5715. }
  5716.  
  5717. /***** Main blend function *****/
  5718.  
  5719. static void
  5720. cpopup_blend_endpoints (double r0, double g0, double b0, double a0,
  5721.             double r1, double g1, double b1, double a1,
  5722.             int blend_colors,
  5723.             int blend_opacity)
  5724. {
  5725.   double          dr, dg, db, da;
  5726.   double          left, len;
  5727.   grad_segment_t *seg, *aseg;
  5728.  
  5729.   dr = r1 - r0;
  5730.   dg = g1 - g0;
  5731.   db = b1 - b0;
  5732.   da = a1 - a0;
  5733.  
  5734.   left  = g_editor->control_sel_l->left;
  5735.   len   = g_editor->control_sel_r->right - left;
  5736.  
  5737.   seg = g_editor->control_sel_l;
  5738.  
  5739.   do
  5740.     {
  5741.       if (blend_colors)
  5742.     {
  5743.       seg->r0 = r0 + (seg->left - left) / len * dr;
  5744.       seg->g0 = g0 + (seg->left - left) / len * dg;
  5745.       seg->b0 = b0 + (seg->left - left) / len * db;
  5746.  
  5747.       seg->r1 = r0 + (seg->right - left) / len * dr;
  5748.       seg->g1 = g0 + (seg->right - left) / len * dg;
  5749.       seg->b1 = b0 + (seg->right - left) / len * db;
  5750.     }
  5751.  
  5752.       if (blend_opacity)
  5753.     {
  5754.       seg->a0 = a0 + (seg->left - left) / len * da;
  5755.       seg->a1 = a0 + (seg->right - left) / len * da;
  5756.     }
  5757.  
  5758.       aseg = seg;
  5759.       seg = seg->next;
  5760.     }
  5761.   while (aseg != g_editor->control_sel_r);
  5762. }
  5763.  
  5764. /***** Gradient functions *****/
  5765.  
  5766. static gradient_t *
  5767. grad_new_gradient (void)
  5768. {
  5769.   gradient_t *grad;
  5770.  
  5771.   grad = g_new (gradient_t, 1);
  5772.  
  5773.   grad->name            = NULL;
  5774.   grad->filename     = NULL;
  5775.   grad->segments     = NULL;
  5776.   grad->last_visited = NULL;
  5777.   grad->dirty        = FALSE;
  5778.   grad->pixmap       = NULL;
  5779.  
  5780.   return grad;
  5781. }
  5782.  
  5783. /*****/
  5784.  
  5785. static void
  5786. grad_free_gradient (gradient_t *grad)
  5787. {
  5788.   g_assert (grad != NULL);
  5789.  
  5790.   if (grad->name)
  5791.     g_free (grad->name);
  5792.  
  5793.   if (grad->segments)
  5794.     seg_free_segments (grad->segments);
  5795.  
  5796.   if (grad->filename)
  5797.     g_free (grad->filename);
  5798.  
  5799.   if (grad->pixmap)
  5800.     gdk_pixmap_unref (grad->pixmap);
  5801.  
  5802.   g_free (grad);
  5803. }
  5804.  
  5805. /*****/
  5806.  
  5807. static void
  5808. grad_save_all (gboolean need_free)
  5809. {
  5810.   GSList     *node;
  5811.   gradient_t *grad;
  5812.  
  5813.   for (node = gradients_list; node; node = g_slist_next (node))
  5814.     {
  5815.       grad = node->data;
  5816.  
  5817.       /* If gradient has dirty flag set, save it */
  5818.       if (grad->dirty)
  5819.     grad_save_gradient (grad, grad->filename);
  5820.  
  5821.       if (need_free)
  5822.     grad_free_gradient (grad);
  5823.     }
  5824. }
  5825.  
  5826. /*****/
  5827.  
  5828. static void
  5829. grad_free_gradients (void)
  5830. {
  5831.   grad_save_all (TRUE);  
  5832.  
  5833.   g_slist_free (gradients_list);
  5834.  
  5835.   num_gradients  = 0;
  5836.   gradients_list = NULL;
  5837.   curr_gradient  = NULL;
  5838.   dnd_gradient   = NULL;
  5839. }
  5840.  
  5841. /*****/
  5842.  
  5843. static void
  5844. grad_load_gradient (gchar *filename)
  5845. {
  5846.   FILE           *file;
  5847.   gradient_t     *grad;
  5848.   grad_segment_t *seg;
  5849.   grad_segment_t *prev;
  5850.   gint            num_segments;
  5851.   gint            i;
  5852.   gint            type, color;
  5853.   gchar           line[1024];
  5854.  
  5855.   g_assert (filename != NULL);
  5856.  
  5857.   file = fopen (filename, "rb");
  5858.   if (!file)
  5859.     return;
  5860.  
  5861.   fgets (line, 1024, file);
  5862.   if (strcmp (line, "GIMP Gradient\n") != 0)
  5863.     return;
  5864.  
  5865.   grad = grad_new_gradient ();
  5866.  
  5867.   grad->filename = g_strdup (filename);
  5868.   grad->name     = g_strdup (g_basename (filename));
  5869.  
  5870.   fgets (line, 1024, file);
  5871.   num_segments = atoi (line);
  5872.  
  5873.   if (num_segments < 1)
  5874.     {
  5875.       g_message ("grad_load_gradient(): "
  5876.                  "invalid number of segments in \"%s\"", filename);
  5877.       g_free (grad);
  5878.       return;
  5879.     }
  5880.  
  5881.   prev = NULL;
  5882.  
  5883.   for (i = 0; i < num_segments; i++)
  5884.     {
  5885.       seg = seg_new_segment ();
  5886.       seg->prev = prev;
  5887.  
  5888.       if (prev)
  5889.     prev->next = seg;
  5890.       else
  5891.     grad->segments = seg;
  5892.  
  5893.       fgets (line, 1024, file);
  5894.  
  5895.       if (sscanf (line, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d%d",
  5896.           &(seg->left), &(seg->middle), &(seg->right),
  5897.           &(seg->r0), &(seg->g0), &(seg->b0), &(seg->a0),
  5898.           &(seg->r1), &(seg->g1), &(seg->b1), &(seg->a1),
  5899.           &type, &color) != 13)
  5900.     {
  5901.       g_message ("grad_load_gradient(): badly formatted "
  5902.                      "gradient segment %d in \"%s\" --- bad things may "
  5903.                      "happen soon", i, filename);
  5904.     }
  5905.       else
  5906.     {
  5907.       seg->type  = (grad_type_t) type;
  5908.       seg->color = (grad_color_t) color;
  5909.     }
  5910.  
  5911.       prev = seg;
  5912.     }
  5913.  
  5914.   fclose (file);
  5915.  
  5916.   grad_insert_in_gradients_list (grad);
  5917. }
  5918.  
  5919. /*****/
  5920.  
  5921. static void
  5922. grad_save_gradient (gradient_t *grad,
  5923.             char       *filename)
  5924. {
  5925.   FILE           *file;
  5926.   int             num_segments;
  5927.   grad_segment_t *seg;
  5928.  
  5929.   g_assert (grad != NULL);
  5930.  
  5931.   if (!filename)
  5932.     {
  5933.       g_message ("grad_save_gradient(): "
  5934.                  "can not save gradient with NULL filename");
  5935.       return;
  5936.     }
  5937.  
  5938.   file = fopen (filename, "wb");
  5939.   if (!file)
  5940.     {
  5941.       g_message ("grad_save_gradient(): can't open \"%s\"", filename);
  5942.       return;
  5943.     }
  5944.  
  5945.   /* File format is:
  5946.    *
  5947.    *   GIMP Gradient
  5948.    *   number_of_segments
  5949.    *   left middle right r0 g0 b0 a0 r1 g1 b1 a1 type coloring
  5950.    *   left middle right r0 g0 b0 a0 r1 g1 b1 a1 type coloring
  5951.    *   ...
  5952.    */
  5953.  
  5954.   fprintf (file, "GIMP Gradient\n");
  5955.  
  5956.   /* Count number of segments */
  5957.   num_segments = 0;
  5958.   seg          = grad->segments;
  5959.  
  5960.   while (seg)
  5961.     {
  5962.       num_segments++;
  5963.       seg = seg->next;
  5964.     }
  5965.  
  5966.   /* Write rest of file */
  5967.   fprintf (file, "%d\n", num_segments);
  5968.  
  5969.   for (seg = grad->segments; seg; seg = seg->next)
  5970.     fprintf (file, "%f %f %f %f %f %f %f %f %f %f %f %d %d\n",
  5971.          seg->left, seg->middle, seg->right,
  5972.          seg->r0, seg->g0, seg->b0, seg->a0,
  5973.          seg->r1, seg->g1, seg->b1, seg->a1,
  5974.          (int) seg->type, (int) seg->color);
  5975.  
  5976.   fclose(file);
  5977.  
  5978.   grad->dirty = FALSE;
  5979. }
  5980.  
  5981. /*****/
  5982.  
  5983. static gradient_t *
  5984. grad_create_default_gradient (void)
  5985. {
  5986.   gradient_t *grad;
  5987.  
  5988.   grad = grad_new_gradient ();
  5989.   grad->segments = seg_new_segment ();
  5990.  
  5991.   return grad;
  5992. }
  5993.  
  5994. /*****/
  5995.  
  5996. static gint
  5997. grad_insert_in_gradients_list (gradient_t *grad)
  5998. {
  5999.   GSList     *tmp;
  6000.   gradient_t *g;
  6001.   gint        n;
  6002.  
  6003.   g_return_val_if_fail (grad != NULL, 0);
  6004.  
  6005.   /* We insert gradients in alphabetical order.  Find the index
  6006.    * of the gradient after which we will insert the current one.
  6007.    */
  6008.  
  6009.   g = NULL;
  6010.  
  6011.   for (tmp = gradients_list, n = 0; tmp; tmp = g_slist_next (tmp), n++)
  6012.     {
  6013.       g = tmp->data;
  6014.  
  6015.       if (strcmp (grad->name, g->name) <= 0)
  6016.     break; /* We found the one we want */
  6017.     }
  6018.  
  6019.   /* is there a gradient with this name already? */
  6020.   if (g && strcmp (grad->name, g->name) == 0)
  6021.     gradients_list_uniquefy_gradient_name (grad);
  6022.  
  6023.   num_gradients++;
  6024.   gradients_list = g_slist_insert (gradients_list, grad, n);
  6025.  
  6026.   return n;
  6027. }
  6028.  
  6029. static void
  6030. gradients_list_uniquefy_gradient_name (gradient_t *gradient)
  6031. {
  6032.   GSList     *list;
  6033.   GSList     *listg;
  6034.   gradient_t *gradg;
  6035.   gint        number = 1;
  6036.   gchar      *newname;
  6037.   gchar      *oldname;
  6038.   gchar      *ext;
  6039.   
  6040.   g_return_if_fail (gradient != NULL);
  6041.   
  6042.   for (list = gradients_list; list; list = g_slist_next (list))
  6043.     {
  6044.       gradg = (gradient_t *) list->data;
  6045.       
  6046.       if (! gradg->name)
  6047.     continue;
  6048.  
  6049.       if (gradient != gradg &&
  6050.       strcmp (gradient->name, gradg->name) == 0)
  6051.     {
  6052.       /* names conflict */
  6053.       oldname = gradient->name;
  6054.       newname = g_malloc (strlen (oldname) + 10); /* if this aint enough 
  6055.                              yer screwed */
  6056.       strcpy (newname, oldname);
  6057.       if ((ext = strrchr (newname, '#')))
  6058.         {
  6059.           number = atoi (ext + 1);
  6060.           
  6061.           if (&ext[(gint)(log10 (number) + 1)] !=
  6062.           &newname[strlen (newname) - 1])
  6063.         {
  6064.           number = 1;
  6065.           ext = &newname[strlen (newname)];
  6066.         }
  6067.         }
  6068.       else
  6069.         {
  6070.           number = 1;
  6071.           ext = &newname[strlen (newname)];
  6072.         }
  6073.       sprintf (ext, "#%d", number + 1);
  6074.       
  6075.       for (listg = gradients_list; listg; listg = g_slist_next (listg))
  6076.         {
  6077.           gradg = (gradient_t *) listg->data;
  6078.  
  6079.           if (! gradg->name)
  6080.         continue;
  6081.  
  6082.           if (gradient != gradg &&
  6083.           strcmp (newname,  gradg->name) == 0)
  6084.         {
  6085.           number++;
  6086.           sprintf (ext, "#%d", number+1);
  6087.           listg = gradients_list;
  6088.         }
  6089.         }
  6090.       
  6091.       g_free (gradient->name);
  6092.       gradient->name = newname;
  6093.  
  6094.       /*  should resort the list here  */
  6095.  
  6096.       return;
  6097.     }
  6098.     }
  6099. }
  6100.  
  6101. /*****/
  6102.  
  6103. static void
  6104. grad_dump_gradient (gradient_t *grad,
  6105.             FILE       *file)
  6106. {
  6107.   grad_segment_t *seg;
  6108.  
  6109.   g_return_if_fail (grad != NULL);
  6110.   g_return_if_fail (file != NULL);  
  6111.  
  6112.   fprintf (file, "Name: \"%s\"\n", grad->name);
  6113.   fprintf (file, "Dirty: %d\n", grad->dirty);
  6114.   fprintf (file, "Filename: \"%s\"\n", grad->filename);
  6115.  
  6116.   for (seg = grad->segments; seg; seg = seg->next)
  6117.     {
  6118.       fprintf (file, "%c%p | %f %f %f | %f %f %f %f | %f %f %f %f | %d %d | %p %p\n",
  6119.            (seg == grad->last_visited) ? '>' : ' ',
  6120.            seg,
  6121.            seg->left, seg->middle, seg->right,
  6122.            seg->r0, seg->g0, seg->b0, seg->a0,
  6123.            seg->r1, seg->g1, seg->b1, seg->a1,
  6124.            (int) seg->type,
  6125.            (int) seg->color,
  6126.            seg->prev, seg->next);
  6127.     }
  6128. }
  6129.  
  6130. /***** Segment functions *****/
  6131.  
  6132. static grad_segment_t *
  6133. seg_new_segment (void)
  6134. {
  6135.   grad_segment_t *seg;
  6136.  
  6137.   seg = g_new (grad_segment_t, 1);
  6138.  
  6139.   seg->left   = 0.0;
  6140.   seg->middle = 0.5;
  6141.   seg->right  = 1.0;
  6142.  
  6143.   seg->r0 = seg->g0 = seg->b0 = 0.0;
  6144.   seg->r1 = seg->g1 = seg->b1 = seg->a0 = seg->a1 = 1.0;
  6145.  
  6146.   seg->type  = GRAD_LINEAR;
  6147.   seg->color = GRAD_RGB;
  6148.  
  6149.   seg->prev = seg->next = NULL;
  6150.  
  6151.   return seg;
  6152. }
  6153.  
  6154. /*****/
  6155.  
  6156. static void
  6157. seg_free_segment (grad_segment_t *seg)
  6158. {
  6159.   g_assert (seg != NULL);
  6160.  
  6161.   g_free (seg);
  6162. }
  6163.  
  6164. static void
  6165. seg_free_segments (grad_segment_t *seg)
  6166. {
  6167.   grad_segment_t *tmp;
  6168.  
  6169.   g_assert (seg != NULL);
  6170.  
  6171.   while (seg)
  6172.     {
  6173.       tmp = seg->next;
  6174.       seg_free_segment (seg);
  6175.       seg = tmp;
  6176.     }
  6177. }
  6178.  
  6179. /*****/
  6180.  
  6181. static grad_segment_t *
  6182. seg_get_segment_at (gradient_t *grad,
  6183.             double      pos)
  6184. {
  6185.   grad_segment_t *seg;
  6186.  
  6187.   g_assert (grad != NULL);
  6188.  
  6189.   /* handle FP imprecision at the edges of the gradient */
  6190.   pos = CLAMP (pos, 0.0, 1.0);
  6191.  
  6192.   if (grad->last_visited)
  6193.     seg = grad->last_visited;
  6194.   else
  6195.     seg = grad->segments;
  6196.  
  6197.   while (seg)
  6198.     {
  6199.       if (pos >= seg->left)
  6200.     {
  6201.       if (pos <= seg->right)
  6202.         {
  6203.           grad->last_visited = seg; /* for speed */
  6204.           return seg;
  6205.         }
  6206.       else
  6207.         {
  6208.           seg = seg->next;
  6209.         }
  6210.     }
  6211.       else
  6212.     {
  6213.       seg = seg->prev;
  6214.     }
  6215.     }
  6216.  
  6217.   /* Oops: we should have found a segment, but we didn't */
  6218.   grad_dump_gradient (grad, stderr);
  6219.   gimp_fatal_error ("seg_get_segment_at(): "
  6220.                     "No matching segment for position %0.15f", pos);
  6221.  
  6222.   return NULL; /* To shut up -Wall */
  6223. }
  6224.  
  6225. /*****/
  6226.  
  6227. static grad_segment_t *
  6228. seg_get_last_segment (grad_segment_t *seg)
  6229. {
  6230.   if (!seg)
  6231.     return NULL;
  6232.  
  6233.   while (seg->next)
  6234.     seg = seg->next;
  6235.  
  6236.   return seg;
  6237. }
  6238.  
  6239. /*****/
  6240.  
  6241. static void
  6242. seg_get_closest_handle (gradient_t           *grad,
  6243.             double                pos,
  6244.             grad_segment_t      **seg,
  6245.             control_drag_mode_t  *handle)
  6246. {
  6247.   double l_delta, m_delta, r_delta;
  6248.  
  6249.   *seg = seg_get_segment_at (grad, pos);
  6250.  
  6251.   m_delta = fabs (pos - (*seg)->middle);
  6252.  
  6253.   if (pos < (*seg)->middle)
  6254.     {
  6255.       l_delta = fabs (pos - (*seg)->left);
  6256.  
  6257.       if (l_delta < m_delta)
  6258.     *handle = GRAD_DRAG_LEFT;
  6259.       else
  6260.     *handle = GRAD_DRAG_MIDDLE;
  6261.     }
  6262.   else
  6263.     {
  6264.       r_delta = fabs (pos - (*seg)->right);
  6265.  
  6266.       if (m_delta < r_delta)
  6267.     {
  6268.       *handle = GRAD_DRAG_MIDDLE;
  6269.     }
  6270.       else
  6271.     {
  6272.       *seg = (*seg)->next;
  6273.       *handle = GRAD_DRAG_LEFT;
  6274.     }
  6275.     }
  6276. }
  6277.  
  6278. /***** Calculation functions *****/
  6279.  
  6280. static double
  6281. calc_linear_factor (double middle,
  6282.             double pos)
  6283. {
  6284.   if (pos <= middle)
  6285.     {
  6286.       if (middle < EPSILON)
  6287.     return 0.0;
  6288.       else
  6289.     return 0.5 * pos / middle;
  6290.     }
  6291.   else
  6292.     {
  6293.       pos -= middle;
  6294.       middle = 1.0 - middle;
  6295.  
  6296.       if (middle < EPSILON)
  6297.     return 1.0;
  6298.       else
  6299.     return 0.5 + 0.5 * pos / middle;
  6300.     }
  6301. }
  6302.  
  6303. static double
  6304. calc_curved_factor (double middle,
  6305.             double pos)
  6306. {
  6307.   if (middle < EPSILON)
  6308.     middle = EPSILON;
  6309.  
  6310.   return pow(pos, log (0.5) / log (middle));
  6311. }
  6312.  
  6313. static double
  6314. calc_sine_factor (double middle,
  6315.           double pos)
  6316. {
  6317.   pos = calc_linear_factor (middle, pos);
  6318.  
  6319.   return (sin ((-G_PI / 2.0) + G_PI * pos) + 1.0) / 2.0;
  6320. }
  6321.  
  6322. static double
  6323. calc_sphere_increasing_factor (double middle,
  6324.                    double pos)
  6325. {
  6326.   pos = calc_linear_factor (middle, pos) - 1.0;
  6327.  
  6328.   return sqrt (1.0 - pos * pos); /* Works for convex increasing and concave decreasing */
  6329. }
  6330.  
  6331. static double
  6332. calc_sphere_decreasing_factor (double middle,
  6333.                    double pos)
  6334. {
  6335.   pos = calc_linear_factor (middle, pos);
  6336.  
  6337.   return 1.0 - sqrt(1.0 - pos * pos); /* Works for convex decreasing and concave increasing */
  6338. }
  6339.  
  6340.  
  6341. /***** Files and paths functions *****/
  6342.  
  6343. static gchar *
  6344. build_user_filename (gchar *name,
  6345.              gchar *path_str)
  6346. {
  6347.   GList *grad_path;
  6348.   gchar *grad_dir;
  6349.   gchar *filename;
  6350.  
  6351.   g_assert (name != NULL);
  6352.  
  6353.   if (!path_str)
  6354.     return NULL; /* Perhaps this is not a good idea */
  6355.  
  6356.   grad_path = gimp_path_parse (path_str, 16, TRUE, NULL);
  6357.   grad_dir  = gimp_path_get_user_writable_dir (grad_path);
  6358.   gimp_path_free (grad_path);
  6359.  
  6360.   if (!grad_dir)
  6361.     return NULL; /* Perhaps this is not a good idea */
  6362.  
  6363.   filename = g_strdup_printf ("%s%s", grad_dir, name);
  6364.  
  6365.   g_free (grad_dir);
  6366.  
  6367.   return filename;
  6368. }
  6369.