Implements PXEGeek's http://wiki.synfig.com/Wish_list entry: "Optionally display...
[synfig.git] / synfig-studio / trunk / src / gtkmm / dialog_setup.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file dialog_setup.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 "dialog_setup.h"
33 #include "app.h"
34 #include <gtkmm/scale.h>
35 #include <gtkmm/table.h>
36 #include <gtkmm/frame.h>
37 #include <gtkmm/notebook.h>
38 #include <gtkmm/spinbutton.h>
39 #include "widget_enum.h"
40
41 #include <ETL/stringf>
42 #include <ETL/misc>
43 #endif
44
45 /* === U S I N G =========================================================== */
46
47 using namespace std;
48 using namespace etl;
49 using namespace synfig;
50 using namespace studio;
51
52 /* === M A C R O S ========================================================= */
53
54 /* === G L O B A L S ======================================================= */
55
56 /* === P R O C E D U R E S ================================================= */
57
58 /* === M E T H O D S ======================================================= */
59
60 Dialog_Setup::Dialog_Setup():
61         Dialog(_("Synfig Studio Setup"),false,true),
62         adj_gamma_r(2.2,0.1,3.0,0.025,0.025,0.025),
63         adj_gamma_g(2.2,0.1,3.0,0.025,0.025,0.025),
64         adj_gamma_b(2.2,0.1,3.0,0.025,0.025,0.025),
65         adj_recent_files(15,1,50,1,1,1),
66         adj_undo_depth(100,10,5000,1,1,1),
67         toggle_use_colorspace_gamma(_("Visually Linear Color Selection"))
68 {
69         // Setup the buttons
70
71         Gtk::Button *ok_button(manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))));
72         ok_button->show();
73         add_action_widget(*ok_button,2);
74         ok_button->signal_clicked().connect(sigc::mem_fun(*this, &Dialog_Setup::on_ok_pressed));
75
76         Gtk::Button *apply_button(manage(new class Gtk::Button(Gtk::StockID("gtk-apply"))));
77         apply_button->show();
78         add_action_widget(*apply_button,1);
79         apply_button->signal_clicked().connect(sigc::mem_fun(*this, &Dialog_Setup::on_apply_pressed));
80
81         Gtk::Button *cancel_button(manage(new class Gtk::Button(Gtk::StockID("gtk-close"))));
82         cancel_button->show();
83         add_action_widget(*cancel_button,0);
84         cancel_button->signal_clicked().connect(sigc::mem_fun(*this, &Dialog_Setup::hide));
85
86
87         // Notebook
88         Gtk::Notebook *notebook=manage(new class Gtk::Notebook());
89         get_vbox()->pack_start(*notebook);
90
91
92         // Gamma
93         Gtk::Table *gamma_table=manage(new Gtk::Table(2,2,false));
94         notebook->append_page(*gamma_table,_("Gamma"));
95         //gamma_frame->add(*gamma_table);
96
97         gamma_table->attach(gamma_pattern, 0, 2, 0, 1, Gtk::EXPAND, Gtk::SHRINK|Gtk::FILL, 0, 0);
98
99         Gtk::HScale* scale_gamma_r(manage(new Gtk::HScale(adj_gamma_r)));
100         gamma_table->attach(*manage(new Gtk::Label(_("Red"))), 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
101         gamma_table->attach(*scale_gamma_r, 1, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
102         adj_gamma_r.signal_value_changed().connect(sigc::mem_fun(*this,&studio::Dialog_Setup::on_gamma_r_change));
103
104         Gtk::HScale* scale_gamma_g(manage(new Gtk::HScale(adj_gamma_g)));
105         gamma_table->attach(*manage(new Gtk::Label(_("Green"))), 0, 1, 2, 3, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
106         gamma_table->attach(*scale_gamma_g, 1, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
107         adj_gamma_g.signal_value_changed().connect(sigc::mem_fun(*this,&studio::Dialog_Setup::on_gamma_g_change));
108
109         Gtk::HScale* scale_gamma_b(manage(new Gtk::HScale(adj_gamma_b)));
110         gamma_table->attach(*manage(new Gtk::Label(_("Blue"))), 0, 1, 3, 4, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
111         gamma_table->attach(*scale_gamma_b, 1, 2, 3, 4, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
112         adj_gamma_b.signal_value_changed().connect(sigc::mem_fun(*this,&studio::Dialog_Setup::on_gamma_b_change));
113
114         gamma_table->attach(*manage(new Gtk::Label(_("Black Level"))), 0, 1, 4, 5, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
115         gamma_table->attach(black_level_selector, 1, 2, 4, 5, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
116         black_level_selector.signal_value_changed().connect(sigc::mem_fun(*this,&studio::Dialog_Setup::on_black_level_change));
117
118         //gamma_table->attach(*manage(new Gtk::Label(_("Red-Blue Level"))), 0, 1, 5, 6, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
119         //gamma_table->attach(red_blue_level_selector, 1, 2, 5, 6, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
120         //red_blue_level_selector.signal_value_changed().connect(sigc::mem_fun(*this,&studio::Dialog_Setup::on_red_blue_level_change));
121
122
123         // Misc
124         Gtk::Table *misc_table=manage(new Gtk::Table(2,2,false));
125         notebook->append_page(*misc_table,_("Misc."));
126
127         // Misc - Timestamp
128         timestamp_menu=manage(new class Gtk::Menu());
129         misc_table->attach(*manage(new Gtk::Label(_("Timestamp"))), 0, 1, 0, 1, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
130         misc_table->attach(timestamp_optionmenu, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
131
132 #define ADD_TIMESTAMP(desc,x)   \
133         timestamp_menu->items().push_back(      \
134                 Gtk::Menu_Helpers::MenuElem(    \
135                         desc,   \
136                         sigc::bind(     \
137                                 sigc::mem_fun(  \
138                                         *this,  \
139                                         &studio::Dialog_Setup::set_time_format  \
140                                 ),      \
141                                 x       \
142                         )       \
143                 )       \
144         );
145         ADD_TIMESTAMP("HH:MM:SS.FF",Time::FORMAT_VIDEO);
146         ADD_TIMESTAMP("(HHh MMm SSs) FFf",Time::FORMAT_NORMAL);
147         ADD_TIMESTAMP("(HHhMMmSSs)FFf",Time::FORMAT_NORMAL|Time::FORMAT_NOSPACES);
148         ADD_TIMESTAMP("HHh MMm SSs FFf",Time::FORMAT_NORMAL|Time::FORMAT_FULL);
149         ADD_TIMESTAMP("HHhMMmSSsFFf",Time::FORMAT_NORMAL|Time::FORMAT_NOSPACES|Time::FORMAT_FULL);
150
151         timestamp_optionmenu.set_menu(*timestamp_menu);
152
153 #undef ADD_TIMESTAMP
154
155         {
156                 ParamDesc param_desc;
157                 param_desc
158                         .set_hint("enum")
159                         .add_enum_value(Distance::SYSTEM_UNITS,"u",_("Units"))
160                         .add_enum_value(Distance::SYSTEM_PIXELS,"px",_("Pixels"))
161                         .add_enum_value(Distance::SYSTEM_POINTS,"pt",_("Points"))
162                         .add_enum_value(Distance::SYSTEM_INCHES,"in",_("Inches"))
163                         .add_enum_value(Distance::SYSTEM_METERS,"m",_("Meters"))
164                         .add_enum_value(Distance::SYSTEM_CENTIMETERS,"cm",_("Centimeters"))
165                         .add_enum_value(Distance::SYSTEM_MILLIMETERS,"mm",_("Millimeters"));
166
167                 widget_enum=manage(new Widget_Enum());
168                 widget_enum->set_param_desc(param_desc);
169
170                 misc_table->attach(*manage(new Gtk::Label(_("Unit System"))), 0, 1, 3, 4, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
171                 misc_table->attach(*widget_enum, 1, 2, 3, 4, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
172         }
173
174         // Misc - recent files
175         Gtk::SpinButton* recent_files_spinbutton(manage(new Gtk::SpinButton(adj_recent_files,1,0)));
176         misc_table->attach(*manage(new Gtk::Label(_("Recent Files"))), 0, 1, 1, 2, Gtk::SHRINK|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
177         misc_table->attach(*recent_files_spinbutton, 1, 2, 1, 2, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
178
179         // Misc - use_colorspace_gamma
180         misc_table->attach(toggle_use_colorspace_gamma, 0, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK|Gtk::FILL, 0, 0);
181
182         show_all_children();
183 }
184
185 Dialog_Setup::~Dialog_Setup()
186 {
187 }
188
189 void
190 Dialog_Setup::on_ok_pressed()
191 {
192     on_apply_pressed();
193         hide();
194 }
195
196 void
197 Dialog_Setup::on_apply_pressed()
198 {
199         App::gamma.set_all(1.0/adj_gamma_r.get_value(),1.0/adj_gamma_g.get_value(),1.0/adj_gamma_b.get_value(),black_level_selector.get_value(),red_blue_level_selector.get_value());
200
201         App::set_max_recent_files((int)adj_recent_files.get_value());
202
203         // Set the time format
204         App::set_time_format(get_time_format());
205
206         // Set the use_colorspace_gamma flag
207         App::use_colorspace_gamma=toggle_use_colorspace_gamma.get_active();
208
209         App::distance_system=Distance::System(widget_enum->get_value());
210
211         App::save_settings();
212 }
213
214 void
215 Dialog_Setup::on_gamma_r_change()
216 {
217         gamma_pattern.set_gamma_r(1.0/adj_gamma_r.get_value());
218         gamma_pattern.refresh();
219         gamma_pattern.queue_draw();
220 }
221
222 void
223 Dialog_Setup::on_gamma_g_change()
224 {
225         gamma_pattern.set_gamma_g(1.0/adj_gamma_g.get_value());
226         gamma_pattern.refresh();
227         gamma_pattern.queue_draw();
228 }
229
230 void
231 Dialog_Setup::on_gamma_b_change()
232 {
233         gamma_pattern.set_gamma_b(1.0/adj_gamma_b.get_value());
234         gamma_pattern.refresh();
235         gamma_pattern.queue_draw();
236 }
237
238 void
239 Dialog_Setup::on_black_level_change()
240 {
241         gamma_pattern.set_black_level(black_level_selector.get_value());
242         gamma_pattern.refresh();
243         gamma_pattern.queue_draw();
244 }
245
246 void
247 Dialog_Setup::on_red_blue_level_change()
248 {
249         gamma_pattern.set_red_blue_level(red_blue_level_selector.get_value());
250         gamma_pattern.refresh();
251         gamma_pattern.queue_draw();
252 }
253
254
255 void
256 Dialog_Setup::refresh()
257 {
258         adj_gamma_r.set_value(1.0/App::gamma.get_gamma_r());
259         adj_gamma_g.set_value(1.0/App::gamma.get_gamma_g());
260         adj_gamma_b.set_value(1.0/App::gamma.get_gamma_b());
261         black_level_selector.set_value(App::gamma.get_black_level());
262         red_blue_level_selector.set_value(App::gamma.get_red_blue_level());
263
264         // Refresh the temporary gamma
265         gamma_pattern.set_gamma_r(1.0/adj_gamma_r.get_value());
266         gamma_pattern.set_gamma_g(1.0/adj_gamma_g.get_value());
267         gamma_pattern.set_gamma_b(1.0/adj_gamma_b.get_value());
268         gamma_pattern.set_black_level(black_level_selector.get_value());
269         gamma_pattern.set_red_blue_level(red_blue_level_selector.get_value());
270         gamma_pattern.refresh();
271
272         adj_recent_files.set_value(App::get_max_recent_files());
273
274         // Refresh the time format
275         set_time_format(App::get_time_format());
276
277         widget_enum->set_value(App::distance_system);
278
279         // Refresh the status of the use_colorspace_gamma flag
280         toggle_use_colorspace_gamma.set_active(App::use_colorspace_gamma);
281
282 }
283
284 GammaPattern::GammaPattern():
285         tile_w(80),
286         tile_h(80)
287 {
288         set_size_request(tile_w*4,tile_h*3);
289         signal_expose_event().connect(sigc::mem_fun(*this, &studio::GammaPattern::redraw));
290 }
291
292 GammaPattern::~GammaPattern()
293 {
294 }
295
296 void
297 GammaPattern::refresh()
298 {
299         black[0].set_rgb_p(
300                 r_F32_to_F32(0.0),
301                 g_F32_to_F32(0.0),
302                 b_F32_to_F32(0.0)
303         );
304         white[0].set_rgb_p(
305                 r_F32_to_F32(1.0),
306                 g_F32_to_F32(1.0),
307                 b_F32_to_F32(1.0)
308         );
309         gray50[0].set_rgb_p(
310                 r_F32_to_F32(0.5),
311                 g_F32_to_F32(0.5),
312                 b_F32_to_F32(0.5)
313         );
314         gray25[0].set_rgb_p(
315                 r_F32_to_F32(0.25),
316                 g_F32_to_F32(0.25),
317                 b_F32_to_F32(0.25)
318         );
319
320         // Reds
321         black[1].set_rgb(black[0].get_red(),0,0);
322         gray25[1].set_rgb(gray25[0].get_red(),0,0);
323         gray50[1].set_rgb(gray50[0].get_red(),0,0);
324         white[1].set_rgb(white[0].get_red(),0,0);
325
326         // Greens
327         black[2].set_rgb(0,black[0].get_green(),0);
328         gray25[2].set_rgb(0,gray25[0].get_green(),0);
329         gray50[2].set_rgb(0,gray50[0].get_green(),0);
330         white[2].set_rgb(0,white[0].get_green(),0);
331
332         // blues
333         black[3].set_rgb(0,0,black[0].get_blue());
334         gray25[3].set_rgb(0,0,gray25[0].get_blue());
335         gray50[3].set_rgb(0,0,gray50[0].get_blue());
336         white[3].set_rgb(0,0,white[0].get_blue());
337 }
338
339 bool
340 GammaPattern::redraw(GdkEventExpose*bleh)
341 {
342         static const char hlines[] = { 3, 0 };
343
344         Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(get_window()));
345
346         int i;
347         Gdk::Color trueblack("#000000");
348
349         // 50% Pattern
350         for(i=0;i<4;i++)
351         {
352                 gc->set_rgb_fg_color(black[i]);
353                 get_window()->draw_rectangle(gc, true, i*tile_w, 0, tile_w, tile_h);
354
355                 gc->set_stipple(Gdk::Bitmap::create(hlines,2,2));
356                 gc->set_fill(Gdk::STIPPLED);
357                 gc->set_rgb_fg_color(white[i]);
358                 get_window()->draw_rectangle(gc, true, i*tile_w, 0, tile_w, tile_h);
359
360                 gc->set_fill(Gdk::SOLID);
361                 gc->set_rgb_fg_color(gray50[i]);
362
363                 get_window()->draw_rectangle(gc, true, i*tile_w+tile_w/4, tile_h/4, tile_w-tile_w/2, tile_h-tile_h/2);
364         }
365
366         // 25% Pattern
367         for(i=0;i<4;i++)
368         {
369                 gc->set_rgb_fg_color(black[i]);
370                 get_window()->draw_rectangle(gc, true, i*tile_w, tile_h, tile_w, tile_h);
371
372                 gc->set_stipple(Gdk::Bitmap::create(hlines,2,2));
373                 gc->set_fill(Gdk::STIPPLED);
374                 gc->set_rgb_fg_color(gray50[i]);
375                 get_window()->draw_rectangle(gc, true, i*tile_w, tile_h, tile_w, tile_h);
376
377                 gc->set_fill(Gdk::SOLID);
378                 gc->set_rgb_fg_color(gray25[i]);
379
380                 get_window()->draw_rectangle(gc, true, i*tile_w+tile_w/4, tile_h+tile_h/4, tile_w-tile_w/2, tile_h-tile_h/2);
381         }
382
383         // Black-level Pattern
384         gc->set_rgb_fg_color(trueblack);
385         get_window()->draw_rectangle(gc, true, 0, tile_h*2, tile_w*4, tile_h);
386         gc->set_fill(Gdk::SOLID);
387         for(i=0;i<4;i++)
388         {
389                 gc->set_rgb_fg_color(black[i]);
390
391                 get_window()->draw_rectangle(gc, true, i*tile_w+tile_w/4, tile_h*2+tile_h/4, tile_w-tile_w/2, tile_h-tile_h/2);
392         }
393
394         return true;
395 }
396
397
398 BlackLevelSelector::BlackLevelSelector()
399 {
400         set_size_request(-1,24);
401         signal_expose_event().connect(sigc::mem_fun(*this, &studio::BlackLevelSelector::redraw));
402
403         add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
404         add_events(Gdk::BUTTON1_MOTION_MASK);
405         add_events(Gdk::BUTTON1_MOTION_MASK);
406 }
407
408 BlackLevelSelector::~BlackLevelSelector()
409 {
410 }
411
412 bool
413 BlackLevelSelector::redraw(GdkEventExpose*bleh)
414 {
415         const int w(get_width()),h(get_height());
416
417         Gdk::Color color;
418
419         Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(get_window()));
420
421         int i;
422
423         // Draw the gradient
424         for(i=0;i<w;i++)
425         {
426                 color.set_rgb(i*65536/w,i*65536/w,i*65536/w);
427
428                 gc->set_rgb_fg_color(color);
429                 get_window()->draw_rectangle(gc, true, i, 0, 1, h);
430         }
431
432         // Draw a frame
433         gc->set_rgb_fg_color(Gdk::Color("#000000"));
434         get_window()->draw_rectangle(gc, false, 0, 0, w-1, h-1);
435
436         // Draw the position of the current value
437         i=(int)(level*w+0.5);
438         gc->set_rgb_fg_color(Gdk::Color("#ff0000"));
439         get_window()->draw_rectangle(gc, true, i, 1, 1, h-1);
440
441         // Print out the value
442         Glib::RefPtr<Pango::Layout> layout(Pango::Layout::create(get_pango_context()));
443         layout->set_text(etl::strprintf("%0.01f%%",level*100.0f));
444         layout->set_alignment(Pango::ALIGN_CENTER);
445         gc->set_rgb_fg_color(Gdk::Color("#a00000"));
446         get_window()->draw_layout(gc, w/2, 4, layout);
447
448         return true;
449 }
450
451
452
453 bool
454 BlackLevelSelector::on_event(GdkEvent *event)
455 {
456         int x(round_to_int(event->button.x));
457         //int y(round_to_int(event->button.y));
458
459     switch(event->type)
460     {
461         case GDK_MOTION_NOTIFY:
462                 level=(float)x/(float)get_width();
463                 if(level<0.0f)level=0.0f;
464                 if(level>1.0f)level=1.0f;
465                 signal_value_changed_();
466                 queue_draw();
467                 return true;
468                 break;
469         case GDK_BUTTON_PRESS:
470         case GDK_BUTTON_RELEASE:
471                 if(event->button.button==1)
472                 {
473                         level=(float)x/(float)get_width();
474                         if(level<0.0f)level=0.0f;
475                         if(level>1.0f)level=1.0f;
476                         signal_value_changed_();
477                         queue_draw();
478                         return true;
479                 }
480                 break;
481         default:
482                 break;
483         }
484
485         return false;
486 }
487
488
489 void
490 Dialog_Setup::set_time_format(Time::Format x)
491 {
492         time_format=x;
493         if(x<=Time::FORMAT_VIDEO)
494                 timestamp_optionmenu.set_history(0);
495         else
496         {
497                 if(x==(Time::FORMAT_NOSPACES|Time::FORMAT_FULL))
498                         timestamp_optionmenu.set_history(4);
499                 else if(x==(Time::FORMAT_FULL))
500                         timestamp_optionmenu.set_history(3);
501                 else if(x==(Time::FORMAT_NOSPACES))
502                         timestamp_optionmenu.set_history(2);
503                 else
504                         timestamp_optionmenu.set_history(1);
505         }
506 }
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523 RedBlueLevelSelector::RedBlueLevelSelector()
524 {
525         set_size_request(-1,24);
526         signal_expose_event().connect(sigc::mem_fun(*this, &studio::RedBlueLevelSelector::redraw));
527
528         add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
529         add_events(Gdk::BUTTON1_MOTION_MASK);
530         add_events(Gdk::BUTTON1_MOTION_MASK);
531 }
532
533 RedBlueLevelSelector::~RedBlueLevelSelector()
534 {
535 }
536
537 bool
538 RedBlueLevelSelector::redraw(GdkEventExpose*bleh)
539 {
540         const int w(get_width()),h(get_height());
541
542         Gdk::Color color;
543
544         Glib::RefPtr<Gdk::GC> gc(Gdk::GC::create(get_window()));
545
546         int i;
547
548         // Draw the gradient
549         for(i=0;i<w;i++)
550         {
551                 float red_blue(((float(i)/float(w)+0.5f)-1.0f)/2.0f+1.0f);
552                 float blue_red(2.0f-(red_blue));
553                 if(red_blue>1.0f)red_blue=1.0f;
554                 if(blue_red>1.0f)blue_red=1.0f;
555
556                 color.set_rgb(
557                         round_to_int(min(red_blue,1.0f)*65535),
558                         round_to_int(sqrt(min(red_blue,blue_red))*65535),
559                         round_to_int(min(blue_red,1.0f)*65535)
560                 );
561
562                 gc->set_rgb_fg_color(color);
563                 get_window()->draw_rectangle(gc, true, i, 0, 1, h);
564         }
565
566         // Draw a frame
567         gc->set_rgb_fg_color(Gdk::Color("#000000"));
568         get_window()->draw_rectangle(gc, false, 0, 0, w-1, h-1);
569
570         // Draw the position of the current value
571         i=(int)(((level-1.0f)*2.0f+1.0f-0.5f)*w+0.5);
572         gc->set_rgb_fg_color(Gdk::Color("#00ff00"));
573         get_window()->draw_rectangle(gc, true, i, 1, 1, h-1);
574
575         // Print out the value
576         Glib::RefPtr<Pango::Layout> layout(Pango::Layout::create(get_pango_context()));
577         layout->set_text(etl::strprintf("%0.02f",level));
578         layout->set_alignment(Pango::ALIGN_CENTER);
579         gc->set_rgb_fg_color(Gdk::Color("#a00000"));
580         get_window()->draw_layout(gc, w/2, 4, layout);
581
582         return true;
583 }
584
585
586
587 bool
588 RedBlueLevelSelector::on_event(GdkEvent *event)
589 {
590         int x(round_to_int(event->button.x));
591         //int y(round_to_int(event->button.y));
592
593     switch(event->type)
594     {
595         case GDK_MOTION_NOTIFY:
596                 level=(((float)(x)/(float)get_width()+0.5)-1.0f)/2.0f+1.0f;
597                 if(level<0.5f)level=0.5f;
598                 if(level>1.5f)level=1.5f;
599                 signal_value_changed_();
600                 queue_draw();
601                 return true;
602                 break;
603         case GDK_BUTTON_PRESS:
604         case GDK_BUTTON_RELEASE:
605                 if(event->button.button==1)
606                 {
607                         level=(((float)(x)/(float)get_width()+0.5)-1.0f)/2.0f+1.0f;
608                         if(level<0.5f)level=0.5f;
609                         if(level>1.5f)level=1.5f;
610                         signal_value_changed_();
611                         queue_draw();
612                         return true;
613                 }
614                 break;
615         default:
616                 break;
617         }
618
619         return false;
620 }