Initial attempt at i18n support using gettext
[synfig.git] / synfig-studio / trunk / src / gtkmm / state_gradient.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file state_gradient.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include <gtkmm/dialog.h>
33 #include <gtkmm/entry.h>
34
35 #include <synfig/valuenode_dynamiclist.h>
36 #include <synfigapp/action_system.h>
37
38 #include "state_gradient.h"
39 #include "canvasview.h"
40 #include "workarea.h"
41 #include "app.h"
42
43 #include <synfigapp/action.h>
44 #include "event_mouse.h"
45 #include "event_layerclick.h"
46 #include "toolbox.h"
47 #include "dialog_tooloptions.h"
48 #include <gtkmm/optionmenu.h>
49 #include "duck.h"
50
51 #include "widget_enum.h"
52 #include <synfigapp/main.h>
53
54 #include "general.h"
55
56 #endif
57
58 /* === U S I N G =========================================================== */
59
60 using namespace std;
61 using namespace etl;
62 using namespace synfig;
63 using namespace studio;
64
65 /* === M A C R O S ========================================================= */
66
67 enum
68 {
69         GRADIENT_INTERPOLATION_LINEAR=0,
70         GRADIENT_RADIAL=1,
71         GRADIENT_CONICAL=2,
72         GRADIENT_SPIRAL=3
73 };
74
75 /* === G L O B A L S ======================================================= */
76
77 StateGradient studio::state_gradient;
78
79 /* === C L A S S E S & S T R U C T S ======================================= */
80
81 class studio::StateGradient_Context : public sigc::trackable
82 {
83         etl::handle<CanvasView> canvas_view_;
84         CanvasView::IsWorking is_working;
85
86         Duckmatic::Push duckmatic_push;
87
88         synfigapp::Settings& settings;
89
90         Point point_holder;
91
92         etl::handle<Duck> point2_duck;
93
94         void refresh_ducks();
95
96         bool prev_workarea_layer_status_;
97
98         Gtk::Table options_table;
99         Gtk::Entry entry_id;
100         Widget_Enum enum_type;
101         Widget_Enum     enum_blend;
102
103 public:
104         synfig::String get_id()const { return entry_id.get_text(); }
105         void set_id(const synfig::String& x) { return entry_id.set_text(x); }
106
107         int get_type()const { return enum_type.get_value(); }
108         void set_type(int x) { return enum_type.set_value(x); }
109
110         int get_blend()const { return enum_blend.get_value(); }
111         void set_blend(int x) { return enum_blend.set_value(x); }
112
113         Smach::event_result event_stop_handler(const Smach::event& x);
114
115         Smach::event_result event_refresh_handler(const Smach::event& x);
116
117         Smach::event_result event_mouse_click_handler(const Smach::event& x);
118         Smach::event_result event_refresh_tool_options(const Smach::event& x);
119
120         void refresh_tool_options();
121
122         StateGradient_Context(CanvasView* canvas_view);
123
124         ~StateGradient_Context();
125
126         const etl::handle<CanvasView>& get_canvas_view()const{return canvas_view_;}
127         etl::handle<synfigapp::CanvasInterface> get_canvas_interface()const{return canvas_view_->canvas_interface();}
128         synfig::Canvas::Handle get_canvas()const{return canvas_view_->get_canvas();}
129         WorkArea * get_work_area()const{return canvas_view_->get_work_area();}
130
131         //void on_user_click(synfig::Point point);
132         void load_settings();
133         void save_settings();
134         void reset();
135         void increment_id();
136
137         void make_gradient(const Point& p1, const Point& p2);
138         bool egress_on_selection_change;
139         Smach::event_result event_layer_selection_changed_handler(const Smach::event& /*x*/)
140         {
141                 if(egress_on_selection_change)
142                         throw Smach::egress_exception();
143                 return Smach::RESULT_OK;
144         }
145
146 };      // END of class StateGradient_Context
147
148 /* === M E T H O D S ======================================================= */
149
150 StateGradient::StateGradient():
151         Smach::state<StateGradient_Context>("gradient")
152 {
153         insert(event_def(EVENT_LAYER_SELECTION_CHANGED,&StateGradient_Context::event_layer_selection_changed_handler));
154         insert(event_def(EVENT_STOP,&StateGradient_Context::event_stop_handler));
155         insert(event_def(EVENT_TABLES_SHOW,&StateGradient_Context::event_stop_handler));
156         insert(event_def(EVENT_REFRESH,&StateGradient_Context::event_refresh_handler));
157         insert(event_def(EVENT_REFRESH_DUCKS,&StateGradient_Context::event_refresh_handler));
158         insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_DOWN,&StateGradient_Context::event_mouse_click_handler));
159         insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_DRAG,&StateGradient_Context::event_mouse_click_handler));
160         insert(event_def(EVENT_WORKAREA_MOUSE_BUTTON_UP,&StateGradient_Context::event_mouse_click_handler));
161         insert(event_def(EVENT_REFRESH_TOOL_OPTIONS,&StateGradient_Context::event_refresh_tool_options));
162 }
163
164 StateGradient::~StateGradient()
165 {
166 }
167
168 void
169 StateGradient_Context::load_settings()
170 {
171         String value;
172
173         if(settings.get_value("gradient.id",value))
174                 set_id(value);
175         else
176                 set_id("Gradient");
177
178         if(settings.get_value("gradient.type",value))
179                 set_type(atoi(value.c_str()));
180         else
181                 set_type(GRADIENT_INTERPOLATION_LINEAR);
182
183         if(settings.get_value("gradient.blend",value))
184                 set_blend(atoi(value.c_str()));
185         else
186                 set_blend(Color::BLEND_COMPOSITE);
187 }
188
189 void
190 StateGradient_Context::save_settings()
191 {
192         settings.set_value("gradient.id",get_id().c_str());
193         settings.set_value("gradient.type",strprintf("%d",get_type()));
194         settings.set_value("gradient.blend",strprintf("%d",get_blend()));
195 }
196
197 void
198 StateGradient_Context::reset()
199 {
200         refresh_ducks();
201 }
202
203 void
204 StateGradient_Context::increment_id()
205 {
206         String id(get_id());
207         int number=1;
208         int digits=0;
209
210         if(id.empty())
211                 id="Gradient";
212
213         // If there is a number
214         // already at the end of the
215         // id, then remove it.
216         if(id[id.size()-1]<='9' && id[id.size()-1]>='0')
217         {
218                 // figure out how many digits it is
219                 for(digits=0;(int)id.size()-1>=digits && id[id.size()-1-digits]<='9' && id[id.size()-1-digits]>='0';digits++)while(false);
220
221                 String str_number;
222                 str_number=String(id,id.size()-digits,id.size());
223                 id=String(id,0,id.size()-digits);
224
225                 number=atoi(str_number.c_str());
226         }
227         else
228         {
229                 number=1;
230                 digits=3;
231         }
232
233         number++;
234
235         // Add the number back onto the id
236         {
237                 const String format(strprintf("%%0%dd",digits));
238                 id+=strprintf(format.c_str(),number);
239         }
240
241         // Set the ID
242         set_id(id);
243 }
244
245 StateGradient_Context::StateGradient_Context(CanvasView* canvas_view):
246         canvas_view_(canvas_view),
247         is_working(*canvas_view),
248         duckmatic_push(get_work_area()),
249         settings(synfigapp::Main::get_selected_input_device()->settings()),
250         prev_workarea_layer_status_(get_work_area()->get_allow_layer_clicks()),
251         entry_id()
252 {
253         egress_on_selection_change=true;
254         // Set up the tool options dialog
255         ///options_table.attach(*manage(new Gtk::Label(_("Gradient Tool"))), 0, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
256         options_table.attach(entry_id, 0, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
257
258         enum_type.set_param_desc(ParamDesc("type")
259                 .set_local_name(_("Gradient Type"))
260                 .set_description(_("Determines the type of Gradient used"))
261                 .set_hint("enum")
262                 .add_enum_value(GRADIENT_INTERPOLATION_LINEAR,"linear",_("Linear"))
263                 .add_enum_value(GRADIENT_RADIAL,"radial",_("Radial"))
264                 .add_enum_value(GRADIENT_CONICAL,"conical",_("Conical"))
265                 .add_enum_value(GRADIENT_SPIRAL,"spiral",_("Spiral")));
266
267         enum_blend.set_param_desc(ParamDesc(Color::BLEND_COMPOSITE,"blend_method")
268                 .set_local_name(_("Blend Method"))
269                 .set_description(_("The blend method the gradient will use")));
270
271         load_settings();
272
273         options_table.attach(enum_type, 0, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
274         options_table.attach(enum_blend, 0, 2, 3, 4, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
275
276         options_table.show_all();
277         refresh_tool_options();
278         App::dialog_tool_options->present();
279
280
281         // Turn off layer clicking
282         get_work_area()->set_allow_layer_clicks(false);
283
284         get_canvas_view()->work_area->set_cursor(Gdk::CROSSHAIR);
285
286         // clear out the ducks
287         get_work_area()->clear_ducks();
288
289         // Refresh the work area
290         get_work_area()->queue_draw();
291
292         get_work_area()->refresh_cursor();
293
294         // Hide the tables if they are showing
295         get_canvas_view()->hide_tables();
296
297         // Disable the time bar
298         //get_canvas_view()->set_sensitive_timebar(false);
299
300         // Connect a signal
301         //get_work_area()->signal_user_click().connect(sigc::mem_fun(*this,&studio::StateGradient_Context::on_user_click));
302
303         App::toolbox->refresh();
304 }
305
306 void
307 StateGradient_Context::refresh_tool_options()
308 {
309         App::dialog_tool_options->clear();
310         App::dialog_tool_options->set_widget(options_table);
311         App::dialog_tool_options->set_local_name(_("Gradient Tool"));
312         App::dialog_tool_options->set_name("gradient");
313 }
314
315 Smach::event_result
316 StateGradient_Context::event_refresh_tool_options(const Smach::event& /*x*/)
317 {
318         refresh_tool_options();
319         return Smach::RESULT_ACCEPT;
320 }
321
322 StateGradient_Context::~StateGradient_Context()
323 {
324         save_settings();
325
326         // Restore layer clicking
327 //      get_work_area()->set_allow_layer_clicks(prev_workarea_layer_status_);
328         get_work_area()->set_allow_layer_clicks(true);
329         get_canvas_view()->work_area->reset_cursor();
330
331         App::dialog_tool_options->clear();
332
333         // Enable the time bar
334         //get_canvas_view()->set_sensitive_timebar(true);
335
336         // Bring back the tables if they were out before
337         //if(prev_table_status)get_canvas_view()->show_tables();
338
339         // Refresh the work area
340         get_work_area()->queue_draw();
341
342         //get_canvas_view()->show_tables();
343
344         get_work_area()->refresh_cursor();
345
346         App::toolbox->refresh();
347 }
348
349 Smach::event_result
350 StateGradient_Context::event_stop_handler(const Smach::event& /*x*/)
351 {
352         throw Smach::egress_exception();
353 }
354
355 Smach::event_result
356 StateGradient_Context::event_refresh_handler(const Smach::event& /*x*/)
357 {
358         refresh_ducks();
359         return Smach::RESULT_ACCEPT;
360 }
361
362 void
363 StateGradient_Context::make_gradient(const Point& _p1, const Point& _p2)
364 {
365         synfigapp::Action::PassiveGrouper group(get_canvas_interface()->get_instance().get(),_("New Gradient"));
366         synfigapp::PushMode push_mode(get_canvas_interface(),synfigapp::MODE_NORMAL);
367
368         Layer::Handle layer;
369
370         Canvas::Handle canvas(get_canvas_view()->get_canvas());
371         int depth(0);
372
373         // we are temporarily using the layer to hold something
374         layer=get_canvas_view()->get_selection_manager()->get_selected_layer();
375         if(layer)
376         {
377                 depth=layer->get_depth();
378                 canvas=layer->get_canvas();
379         }
380         const synfig::TransformStack& transform(get_canvas_view()->get_curr_transform_stack());
381         const Point p1(transform.unperform(_p1));
382         const Point p2(transform.unperform(_p2));
383
384         switch(get_type())
385         {
386         case GRADIENT_INTERPOLATION_LINEAR:
387
388                 layer=get_canvas_interface()->add_layer_to("linear_gradient",canvas,depth);
389                 layer->set_param("p1",p1);
390                 get_canvas_interface()->signal_layer_param_changed()(layer,"p1");
391                 layer->set_param("p2",p2);
392                 get_canvas_interface()->signal_layer_param_changed()(layer,"p2");
393                 break;
394         case GRADIENT_RADIAL:
395                 layer=get_canvas_interface()->add_layer_to("radial_gradient",canvas,depth);
396                 layer->set_param("center",p1);
397                 get_canvas_interface()->signal_layer_param_changed()(layer,"center");
398                 layer->set_param("radius",(p2-p1).mag());
399                 get_canvas_interface()->signal_layer_param_changed()(layer,"radius");
400                 break;
401         case GRADIENT_CONICAL:
402                 layer=get_canvas_interface()->add_layer_to("conical_gradient",canvas,depth);
403                 layer->set_param("center",p1);
404                 get_canvas_interface()->signal_layer_param_changed()(layer,"center");
405                 {
406                         Vector diff(p2-p1);
407                         layer->set_param("angle",Angle::tan(diff[1],diff[0]));
408                         get_canvas_interface()->signal_layer_param_changed()(layer,"angle");
409                 }
410                 break;
411         case GRADIENT_SPIRAL:
412                 layer=get_canvas_interface()->add_layer_to("spiral_gradient",canvas,depth);
413                 layer->set_param("center",p1);
414                 get_canvas_interface()->signal_layer_param_changed()(layer,"center");
415                 layer->set_param("radius",(p2-p1).mag());
416                 get_canvas_interface()->signal_layer_param_changed()(layer,"radius");
417                 {
418                         Vector diff(p2-p1);
419                         layer->set_param("angle",Angle::tan(diff[1],diff[0]));
420                         get_canvas_interface()->signal_layer_param_changed()(layer,"angle");
421                 }
422                 break;
423
424         default:
425                 return;
426         }
427
428         layer->set_param("blend_method",get_blend());
429         get_canvas_interface()->signal_layer_param_changed()(layer,"blend_method");
430
431         layer->set_description(get_id());
432         get_canvas_interface()->signal_layer_new_description()(layer,layer->get_description());
433
434         egress_on_selection_change=false;
435         get_canvas_interface()->get_selection_manager()->clear_selected_layers();
436         get_canvas_interface()->get_selection_manager()->set_selected_layer(layer);
437         egress_on_selection_change=true;
438
439         reset();
440         increment_id();
441 }
442
443 Smach::event_result
444 StateGradient_Context::event_mouse_click_handler(const Smach::event& x)
445 {
446         const EventMouse& event(*reinterpret_cast<const EventMouse*>(&x));
447
448         if(event.key==EVENT_WORKAREA_MOUSE_BUTTON_DOWN && event.button==BUTTON_LEFT)
449         {
450                 point_holder=get_work_area()->snap_point_to_grid(event.pos);
451                 etl::handle<Duck> duck=new Duck();
452                 duck->set_point(point_holder);
453                 duck->set_name("p1");
454                 duck->set_type(Duck::TYPE_POSITION);
455                 get_work_area()->add_duck(duck);
456
457                 point2_duck=new Duck();
458                 point2_duck->set_point(point_holder);
459                 point2_duck->set_name("p2");
460                 point2_duck->set_type(Duck::TYPE_POSITION);
461                 get_work_area()->add_duck(point2_duck);
462
463                 handle<Duckmatic::Bezier> bezier(new Duckmatic::Bezier());
464                 bezier->p1=bezier->c1=duck;
465                 bezier->p2=bezier->c2=point2_duck;
466                 get_work_area()->add_bezier(bezier);
467
468                 return Smach::RESULT_ACCEPT;
469         }
470
471         if(event.key==EVENT_WORKAREA_MOUSE_BUTTON_DRAG && event.button==BUTTON_LEFT)
472         {
473                 point2_duck->set_point(get_work_area()->snap_point_to_grid(event.pos));
474                 get_work_area()->queue_draw();
475                 return Smach::RESULT_ACCEPT;
476         }
477
478         if(event.key==EVENT_WORKAREA_MOUSE_BUTTON_UP && event.button==BUTTON_LEFT)
479         {
480                 make_gradient(point_holder, get_work_area()->snap_point_to_grid(event.pos));
481                 get_work_area()->clear_ducks();
482                 return Smach::RESULT_ACCEPT;
483         }
484
485         return Smach::RESULT_OK;
486 }
487
488
489 void
490 StateGradient_Context::refresh_ducks()
491 {
492         get_work_area()->clear_ducks();
493         get_work_area()->queue_draw();
494 }