1 /* === S Y N F I G ========================================================= */
2 /*!	\file dock_paledit.cpp
3 **	\brief Template File
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **	Copyright (c) 2007 Chris Moore
10 **	Copyright (c) 2010 Nikita Kitaev
11 **
12 **	This package is free software; you can redistribute it and/or
13 **	modify it under the terms of the GNU General Public License as
14 **	published by the Free Software Foundation; either version 2 of
15 **	the License, or (at your option) any later version.
16 **
17 **	This package is distributed in the hope that it will be useful,
18 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
19 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 **	General Public License for more details.
21 **	\endlegal
22 */
23 /* ========================================================================= */
24 
25 /* === H E A D E R S ======================================================= */
26 
27 #ifdef USING_PCH
28 #	include "pch.h"
29 #else
30 #ifdef HAVE_CONFIG_H
31 #	include <config.h>
32 #endif
33 
34 #include <synfig/general.h>
35 
36 #include <sys/stat.h>
37 #include "dock_paledit.h"
38 #include "../../widgets/widget_color.h"
39 #include <gtkmm/frame.h>
40 #include <gtkmm/table.h>
41 #include <gtkmm/label.h>
42 #include <synfigapp/canvasinterface.h>
43 #include <synfigapp/value_desc.h>
44 #include "../../widgets/widget_color.h"
45 #include <gtkmm/spinbutton.h>
46 #include <gtkmm/menu.h>
47 #include <gtkmm/imagemenuitem.h>
48 #include <synfigapp/main.h>
49 #include "../../app.h"
50 #include "../../dialogs/dialog_color.h"
51 #include <errno.h>
52 
53 #include <gui/localization.h>
54 
55 #endif
56 
57 /* === U S I N G =========================================================== */
58 
59 using namespace std;
60 using namespace etl;
61 using namespace synfig;
62 using namespace studio;
63 
64 /* === M A C R O S ========================================================= */
65 
66 /* === G L O B A L S ======================================================= */
67 /*
68 class studio::PaletteSettings : public synfigapp::Settings
69 {
70 	Dock_PalEdit* dialog_palette;
71 	synfig::String name;
72 public:
73 	PaletteSettings(Dock_PalEdit* window,const synfig::String& name):
74 		dialog_palette(window),
75 		name(name)
76 	{
77 		dialog_palette->dialog_settings.add_domain(this,name);
78 	}
79 
80 	virtual ~PaletteSettings()
81 	{
82 		dialog_palette->dialog_settings.remove_domain(name);
83 	}
84 
85 	virtual bool get_value(const synfig::String& key, synfig::String& value)const
86 	{
87 		int i(atoi(key.c_str()));
88 		if(i<0 || i>=dialog_palette->size())
89 			return false;
90 		Color c(dialog_palette->get_color(i));
91 		value=strprintf("%f %f %f %f",c.get_r(),c.get_g(),c.get_b(),c.get_a());
92 		return true;
93 	}
94 
95 	virtual bool set_value(const synfig::String& key,const synfig::String& value)
96 	{
97 		int i(atoi(key.c_str()));
98 		if(i<0)
99 			return false;
100 		if(i>=dialog_palette->size())
101 			dialog_palette->palette_.resize(i+1);
102 		float r,g,b,a;
103 		if(!strscanf(value,"%f %f %f %f",&r,&g,&b,&a))
104 			return false;
105 		dialog_palette->set_color(Color(r,g,b,a),i);
106 		return true;
107 	}
108 
109 	virtual KeyList get_key_list()const
110 	{
111 		synfigapp::Settings::KeyList ret(synfigapp::Settings::get_key_list());
112 
113 		int i;
114 		for(i=0;i<dialog_palette->size();i++)
115 			ret.push_back(strprintf("%03d",i));
116 		return ret;
117 	}
118 };
119 */
120 /* === P R O C E D U R E S ================================================= */
121 
122 /* === M E T H O D S ======================================================= */
123 
Dock_PalEdit()124 Dock_PalEdit::Dock_PalEdit():
125 	Dockable("pal_edit",_("Palette Editor"),Gtk::StockID("synfig-palette")),
126 	//palette_settings(new PaletteSettings(this,"colors")),
127 	table(2,2,false)
128 {
129 	action_group=Gtk::ActionGroup::create("action_group_pal_edit");
130 	action_group->add(Gtk::Action::create(
131 		"palette-add-color",
132 		Gtk::StockID("gtk-add"),
133 		_("Add Color"),
134 		_("Add current outline color\nto the palette")
135 	),
136 		sigc::mem_fun(
137 			*this,
138 			&Dock_PalEdit::on_add_pressed
139 		)
140 	);
141 	action_group->add(Gtk::Action::create(
142 		"palette-save",
143 		Gtk::StockID("gtk-save"),
144 		_("Save palette"),
145 		_("Save the current palette")
146 	),
147 		sigc::mem_fun(
148 			*this,
149 			&Dock_PalEdit::on_save_pressed
150 		)
151 	);
152 	action_group->add(Gtk::Action::create(
153 		"palette-load",
154 		Gtk::StockID("gtk-open"),
155 		_("Open a palette"),
156 		_("Open a saved palette")
157 	),
158 		sigc::mem_fun(
159 			*this,
160 			&Dock_PalEdit::on_open_pressed
161 		)
162 	);
163 	action_group->add(Gtk::Action::create(
164 		"palette-set-default",
165 		Gtk::StockID("gtk-refresh"),
166 		_("Load default"),
167 		_("Load default palette")
168 	),
169 		sigc::mem_fun(
170 			*this,
171 			&Dock_PalEdit::set_default_palette
172 		)
173 	);
174 
175 
176 	App::ui_manager()->insert_action_group(action_group);
177 
178     Glib::ustring ui_info =
179 	"<ui>"
180 	"	<toolbar action='toolbar-palette'>"
181 	"	<toolitem action='palette-add-color' />"
182 	"	<toolitem action='palette-save' />"
183 	"	<toolitem action='palette-load' />"
184 	"	<toolitem action='palette-set-default' />"
185 	"	</toolbar>"
186 	"</ui>"
187 	;
188 
189 	App::ui_manager()->add_ui_from_string(ui_info);
190 
191 	set_toolbar(*dynamic_cast<Gtk::Toolbar*>(App::ui_manager()->get_widget("/toolbar-palette")));
192 
193 	/*
194 	add_button(
195 		Gtk::StockID("gtk-add"),
196 		_("Add current outline color\nto the palette")
197 	)->signal_clicked().connect(
198 		sigc::mem_fun(
199 			*this,
200 			&Dock_PalEdit::on_add_pressed
201 		)
202 	);
203 	*/
204 
205 	add(table);
206 	table.set_homogeneous(true);
207 
208 	set_default_palette();
209 
210 	show_all_children();
211 }
212 
~Dock_PalEdit()213 Dock_PalEdit::~Dock_PalEdit()
214 {
215 	//delete palette_settings;
216 }
217 
218 void
set_palette(const synfig::Palette & x)219 Dock_PalEdit::set_palette(const synfig::Palette& x)
220 {
221 	palette_=x;
222 	refresh();
223 }
224 
225 void
on_add_pressed()226 Dock_PalEdit::on_add_pressed()
227 {
228 	add_color(synfigapp::Main::get_outline_color());
229 }
230 
231 void
on_save_pressed()232 Dock_PalEdit::on_save_pressed()
233 {
234 	// it would be nice to have initial spal file name same as current canvas name,
235 	// use "My Palette" as temporary spal file name as a hack.
236 	//synfig::String filename = selected_instance->get_file_name();
237 	synfig::String filename = "My Palette";
238 	while (App::dialog_save_file_spal(_("Please choose a file name"), filename, ANIMATION_DIR_PREFERENCE))
239 	{
240 		// If the filename still has wildcards, then we should
241 		// continue looking for the file we want
242 		string base_filename = basename(filename);
243 		if (find(base_filename.begin(),base_filename.end(),'*')!=base_filename.end())
244 			continue;
245 
246 		{
247 			struct stat	s;
248 			int stat_return = stat(filename.c_str(), &s);
249 
250 			// if stat() fails with something other than 'file doesn't exist', there's been a real
251 			// error of some kind.  let's give up now and ask for a new path.
252 			if (stat_return == -1 && errno != ENOENT)
253 			{
254 				perror(filename.c_str());
255 				string msg(strprintf(_("Unable to check whether '%s' exists."), filename.c_str()));
256 				App::dialog_message_1b(
257 						"ERROR",
258 						msg.c_str(),
259 						"detaisl",
260 						_("Close"));
261 
262 				continue;
263 			}
264 
265 			// if the file exists and the user doesn't want to overwrite it, keep prompting for a filename
266 			string message = strprintf(_("A file named \"%s\" already exists. "
267 							"Do you want to replace it?"),
268 						basename(filename).c_str());
269 
270 			string details = strprintf(_("The file already exists in \"%s\". "
271 							"Replacing it will overwrite its contents."),
272 						basename(dirname(filename)).c_str());
273 
274 			if ((stat_return == 0) && !App::dialog_message_2b(
275 				message,
276 				details,
277 				Gtk::MESSAGE_QUESTION,
278 				_("Use Another Name…"),
279 				_("Replace"))
280 			)
281 				continue;
282 		}
283 		palette_.save_to_file(filename);
284 		return;
285 	}
286 }
287 
288 void
on_open_pressed()289 Dock_PalEdit::on_open_pressed()
290 {
291 	synfig::String filename = "*.spal";
292 	while(App::dialog_open_file_spal(_("Please select a palette file"), filename, ANIMATION_DIR_PREFERENCE))
293 	{
294 		// If the filename still has wildcards, then we should
295 		// continue looking for the file we want
296 		if(find(filename.begin(),filename.end(),'*')!=filename.end())
297 			continue;
298 
299 		try
300 		{
301 			palette_=synfig::Palette::load_from_file(filename);
302 		}
303 		catch (...)
304 		{
305 			App::get_ui_interface()->error(_("Unable to open file"));
306 			continue;
307 		}
308 		break;
309 	}
310 	refresh();
311 }
312 
313 void
show_menu(int i)314 Dock_PalEdit::show_menu(int i)
315 {
316 	Gtk::Menu* menu(manage(new Gtk::Menu()));
317 	menu->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), menu));
318 
319 	Gtk::MenuItem *item;
320 	item = manage(new Gtk::ImageMenuItem(Gtk::StockID("gtk-select-color")));
321 	item->signal_activate().connect(
322 		sigc::bind(
323 			sigc::mem_fun(*this,&studio::Dock_PalEdit::edit_color),
324 			i ));
325 	item->show_all();
326 	menu->append(*item);
327 
328 	item = manage(new Gtk::ImageMenuItem(Gtk::StockID("gtk-delete")));
329 	item->signal_activate().connect(
330 		sigc::bind(
331 			sigc::mem_fun(*this,&studio::Dock_PalEdit::erase_color),
332 			i ));
333 	item->show_all();
334 	menu->append(*item);
335 
336 	menu->popup(3,gtk_get_current_event_time());
337 }
338 
339 int
add_color(const synfig::Color & x)340 Dock_PalEdit::add_color(const synfig::Color& x)
341 {
342 	palette_.push_back(x);
343 	signal_changed()();
344 	refresh();
345 	return size()-1;
346 }
347 
348 void
set_color(synfig::Color x,int i)349 Dock_PalEdit::set_color(synfig::Color x, int i)
350 {
351 	palette_[i].color=x;
352 	signal_changed()();
353 	refresh();
354 }
355 
356 Color
get_color(int i) const357 Dock_PalEdit::get_color(int i)const
358 {
359 	return palette_[i].color;
360 }
361 
362 void
erase_color(int i)363 Dock_PalEdit::erase_color(int i)
364 {
365 	palette_.erase(palette_.begin()+i);
366 	signal_changed()();
367 	refresh();
368 }
369 
370 void
refresh()371 Dock_PalEdit::refresh()
372 {
373 	const int width(12);
374 
375 	// Clear the table
376 	table.foreach(sigc::mem_fun(table,&Gtk::Table::remove));
377 
378 	for(int i=0;i<size();i++)
379 	{
380 		Widget_Color* widget_color(manage(new Widget_Color()));
381 		widget_color->set_value(get_color(i));
382 		widget_color->set_size_request(12,12);
383 		widget_color->signal_activate().connect(
384 			sigc::bind(
385 				sigc::mem_fun(*this,&studio::Dock_PalEdit::select_fill_color),
386 				i
387 			)
388 		);
389 		widget_color->signal_middle_click().connect(
390 			sigc::bind(
391 				sigc::mem_fun(*this,&studio::Dock_PalEdit::select_outline_color),
392 				i
393 			)
394 		);
395 		widget_color->signal_right_click().connect(
396 			sigc::bind(
397 				sigc::mem_fun(*this,&studio::Dock_PalEdit::show_menu),
398 				i
399 			)
400 		);
401 		int c(i%width),r(i/width);
402 		table.attach(*widget_color, c, c+1, r, r+1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
403 	}
404 	table.show_all();
405 	queue_draw();
406 }
407 
408 
409 void
edit_color(int i)410 Dock_PalEdit::edit_color(int i)
411 {
412 	App::dialog_color->reset();
413 	App::dialog_color->set_color(get_color(i));
414 	App::dialog_color->signal_edited().connect(
415 		sigc::bind(
416 			sigc::mem_fun(*this,&studio::Dock_PalEdit::set_color),
417 			i
418 		)
419 	);
420 	App::dialog_color->present();
421 }
422 
423 void
select_fill_color(int i)424 Dock_PalEdit::select_fill_color(int i)
425 {
426 	synfigapp::Main::set_fill_color(get_color(i));
427 }
428 
429 void
select_outline_color(int i)430 Dock_PalEdit::select_outline_color(int i)
431 {
432 	synfigapp::Main::set_outline_color(get_color(i));
433 }
434 
435 void
set_default_palette()436 Dock_PalEdit::set_default_palette()
437 {
438 	int width=12;
439 
440 	palette_.clear();
441 
442 	// Greys
443 	palette_.push_back(Color::alpha());
444 	for(int i=0;i<width-1;i++)
445 	{
446 		Color c(
447 			float(i)/(float)(width-2),
448 			float(i)/(float)(width-2),
449 			float(i)/(float)(width-2)
450 		);
451 		palette_.push_back(c);
452 	}
453 
454 	// Tans
455 	for(int i=0;i<width;i++)
456 	{
457 		float x(float(i)/(float)(width-1));
458 		const Color tan1(0.2,0.05,0);
459 		const Color tan2(0.85,0.64,0.20);
460 
461 		palette_.push_back(Color::blend(tan2,tan1,x));
462 	}
463 
464 	// Solids
465 	palette_.push_back(Color::red());
466 	palette_.push_back(Color(1.0f,0.25f,0.0f));	// Orange
467 	palette_.push_back(Color::yellow());
468 	palette_.push_back(Color(0.25f,1.00f,0.0f));	// yellow-green
469 	palette_.push_back(Color::green());
470 	palette_.push_back(Color(0.0f,1.00f,0.25f));	// green-blue
471 	palette_.push_back(Color::cyan());
472 	palette_.push_back(Color(0.0f,0.25f,1.0f));	// Sea Blue
473 	palette_.push_back(Color::blue());
474 	palette_.push_back(Color(0.25f,0.0f,1.0f));
475 	palette_.push_back(Color::magenta());
476 	palette_.push_back(Color(1.0f,0.0f,0.25f));
477 
478 
479 	const int levels(3);
480 
481 	// Colors
482 	for(int j=0;j<levels;j++)
483 	for(int i=0;i<width;i++)
484 	{
485 		Color c(Color::red());
486 		c.set_hue(c.get_hue()-Angle::rot(float(i)/(float)(width)));
487 		c=c.clamped();
488 		float s(float(levels-j)/float(levels));
489 		s*=s;
490 		c.set_r(c.get_r()*s);
491 		c.set_g(c.get_g()*s);
492 		c.set_b(c.get_b()*s);
493 		palette_.push_back(c);
494 	}
495 
496 
497 	/*
498 	const int levels(3);
499 
500 	for(int i=0;i<levels*levels*levels;i++)
501 	{
502 		Color c(
503 			float(i%levels)/(float)(levels-1),
504 			float(i/levels%levels)/(float)(levels-1),
505 			float(i/(levels*levels))/(float)(levels-1)
506 		);
507 		palette_.push_back(c);
508 	}
509 	*/
510 	refresh();
511 }
512 
513 int
size() const514 Dock_PalEdit::size()const
515 {
516 	return palette_.size();
517 }
518