Exciting new Alt/h help key provided by sge (Georgy) with many thanks!
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bcslider.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcpixmap.h"
23 #include "bcresources.h"
24 #include "bcslider.h"
25 #include "bccolors.h"
26 #include "fonts.h"
27 #include "keys.h"
28 #include "units.h"
29 #include "vframe.h"
30
31
32
33 #include <ctype.h>
34 #include <string.h>
35
36
37
38 BC_Slider::BC_Slider(int x, int y, int pixels, int pointer_motion_range, VFrame **images,
39                 int show_number, int vertical, int use_caption)
40  : BC_SubWindow(x, y, 0, 0, -1)
41 {
42         this->images = images;
43         this->show_number = show_number;
44         this->vertical = vertical;
45         this->pointer_motion_range = pointer_motion_range;
46         this->pixels = pixels;
47         this->button_pixel = button_pixel;
48         this->use_caption = use_caption;
49
50         status = SLIDER_UP;
51         pixmaps = new BC_Pixmap*[SLIDER_IMAGES];
52         for(int i = 0; i < SLIDER_IMAGES; i++)
53         {
54                 pixmaps[i] = 0;
55         }
56         button_down = 0;
57         enabled = 1;
58         active = 0;
59 }
60
61 BC_Slider::~BC_Slider()
62 {
63         for(int i = 0; i < SLIDER_IMAGES; i++) {
64                 if(pixmaps[i]) delete pixmaps[i];
65         }
66         if(pixmaps) delete [] pixmaps;
67 }
68
69 int BC_Slider::initialize()
70 {
71         if(!images) {
72                 this->images = vertical ?
73                         BC_WindowBase::get_resources()->vertical_slider_data :
74                         BC_WindowBase::get_resources()->horizontal_slider_data;
75         }
76
77         set_images(images);
78
79         if(vertical) {
80                 w = images[SLIDER_BG_UP]->get_w();
81                 h = pixels;
82         }
83         else
84         {
85                 w = pixels;
86                 h = images[SLIDER_BG_UP]->get_h();
87         }
88
89         text_height = get_text_height(SMALLFONT);
90         button_pixel = value_to_pixel();
91
92         BC_SubWindow::initialize();
93         draw_face(0);
94         show_window(0);
95         return 0;
96 }
97
98 int BC_Slider::get_span(int vertical)
99 {
100         if(vertical)
101         {
102                 return BC_WindowBase::get_resources()->vertical_slider_data[0]->get_w();
103         }
104         else
105         {
106                 return BC_WindowBase::get_resources()->horizontal_slider_data[0]->get_h();
107         }
108 }
109
110 int BC_Slider::draw_face(int flush)
111 {
112 // Clear background
113         draw_top_background(parent_window, 0, 0, get_w(), get_h());
114
115
116         if(vertical)
117         {
118                 draw_3segmentv(0,
119                         0,
120                         get_h(),
121                         pixmaps[SLIDER_IMAGES / 2 + status]);
122                 draw_pixmap(pixmaps[status], 0, button_pixel);
123                 if(use_caption)
124                 {
125                         set_color(RED);
126                         set_font(SMALLFONT);
127                         draw_text(0, h, get_caption());
128                 }
129         }
130         else
131         {
132                 //int y = get_h() / 2 - pixmaps[SLIDER_IMAGES / 2 + status]->get_h() / 2;
133                 draw_3segmenth(0, 0, get_w(), pixmaps[SLIDER_IMAGES / 2 + status]);
134                 draw_pixmap(pixmaps[status], button_pixel, 0);
135                 if(use_caption)
136                 {
137                         set_color(RED);
138                         set_font(SMALLFONT);
139                         draw_text(0, h, get_caption());
140                 }
141         }
142
143         flash(flush);
144         return 0;
145 }
146
147 int BC_Slider::set_images(VFrame **images)
148 {
149         for(int i = 0; i < SLIDER_IMAGES; i++)
150         {
151                 if(pixmaps[i]) delete pixmaps[i];
152                 pixmaps[i] = new BC_Pixmap(parent_window, images[i], PIXMAP_ALPHA);
153         }
154         return 0;
155 }
156
157 int BC_Slider::get_button_pixels()
158 {
159         return vertical ? pixmaps[SLIDER_UP]->get_h() :
160                 pixmaps[SLIDER_UP]->get_w();
161 }
162
163 void BC_Slider::show_value_tooltip()
164 {
165         if( !show_number ) return;
166 //printf("BC_Slider::show_value_tooltip %s\n", get_caption());
167         set_tooltip(get_caption());
168         keypress_tooltip_timer = 2000;
169         show_tooltip(xS(50));
170 }
171
172
173 int BC_Slider::repeat_event(int64_t duration)
174 {
175         if(duration == top_level->get_resources()->tooltip_delay)
176         {
177                 if(tooltip_on)
178                 {
179                         if(keypress_tooltip_timer > 0)
180                         {
181                                 keypress_tooltip_timer -= get_resources()->tooltip_delay;
182                         }
183                         else
184                         if(status != SLIDER_HI && status != SLIDER_DN)
185                         {
186                                 hide_tooltip();
187                         }
188                 }
189                 else
190                 if(status == SLIDER_HI && tooltip_text && show_number)
191                 {
192                         if(!tooltip_text[0] || isdigit(tooltip_text[0]))
193                         {
194                                 set_tooltip(get_caption());
195                                 show_tooltip(50);
196                         }
197                         else
198                         {
199 //printf("BC_Slider::repeat_event 1 %s\n", tooltip_text);
200                                 set_tooltip(get_caption());
201                                 show_tooltip();
202                         }
203                         return 1;
204                 }
205         }
206         return 0;
207 }
208
209
210 int BC_Slider::keypress_event()
211 {
212         int result = 0;
213         if(!active || !enabled) return context_help_check_and_show();
214         if(ctrl_down() || shift_down()) return context_help_check_and_show();
215
216         switch(get_keypress())
217         {
218                 case UP:
219                         increase_value_big();
220                         result = 1;
221                         break;
222                 case DOWN:
223                         decrease_value_big();
224                         result = 1;
225                         break;
226                 case LEFT:
227                         decrease_value();
228                         result = 1;
229                         break;
230                 case RIGHT:
231                         increase_value();
232                         result = 1;
233                         break;
234         }
235
236         if(result)
237         {
238                 handle_event();
239                 show_value_tooltip();
240                 draw_face(1);
241                 return result;
242         }
243
244         return context_help_check_and_show();
245 }
246
247 int BC_Slider::cursor_enter_event()
248 {
249 //printf("BC_Slider::cursor_enter_event 1\n");
250         if(top_level->event_win == win && status == SLIDER_UP)
251         {
252                 status = SLIDER_HI;
253                 draw_face(1);
254         }
255 //printf("BC_Slider::cursor_enter_event 2\n");
256         return 0;
257 }
258
259 int BC_Slider::cursor_leave_event()
260 {
261         if(status == SLIDER_HI)
262         {
263                 status = SLIDER_UP;
264                 draw_face(1);
265                 hide_tooltip();
266         }
267         return 0;
268 }
269
270 int BC_Slider::deactivate()
271 {
272         active = 0;
273         return 0;
274 }
275
276 int BC_Slider::activate()
277 {
278         top_level->active_subwindow = this;
279         active = 1;
280         return 0;
281 }
282
283 void BC_Slider::enable()
284 {
285         enabled = 1;
286         draw_face(1);
287 }
288
289 void BC_Slider::disable()
290 {
291         enabled = 0;
292         draw_face(1);
293 }
294
295 void BC_Slider::enable_show_value(int v)
296 {
297         show_number = v;
298 }
299
300 int BC_Slider::button_press_event()
301 {
302         int result = 0;
303         if(is_event_win() && enabled)
304         {
305                 if(!tooltip_on) top_level->hide_tooltip();
306                 if(status == SLIDER_HI)
307                 {
308                         if(get_buttonpress() == 4)
309                         {
310                                 increase_value();
311                                 handle_event();
312                                 show_value_tooltip();
313                                 draw_face(1);
314                         }
315                         else
316                         if(get_buttonpress() == 5)
317                         {
318                                 decrease_value();
319                                 handle_event();
320                                 show_value_tooltip();
321                                 draw_face(1);
322                         }
323                         else
324                         if(get_buttonpress() == 1)
325                         {
326                                 button_down = 1;
327                                 status = SLIDER_DN;
328                                 draw_face(1);
329                                 init_selection(top_level->cursor_x, top_level->cursor_y);
330                                 top_level->deactivate();
331                                 activate();
332                                 show_value_tooltip();
333                         }
334                         result = 1;
335                 }
336         }
337         return result;
338 }
339
340 int BC_Slider::button_release_event()
341 {
342         if(button_down)
343         {
344                 button_down = 0;
345                 if(cursor_inside())
346                         status = SLIDER_HI;
347                 else
348                 {
349                         status = SLIDER_UP;
350                         top_level->hide_tooltip();
351                 }
352                 draw_face(1);
353                 return 1;
354         }
355         return 0;
356 }
357
358 int BC_Slider::cursor_motion_event()
359 {
360         if(button_down)
361         {
362                 int old_pixel = button_pixel;
363                 int result = update_selection(top_level->cursor_x, top_level->cursor_y);
364                 if(button_pixel != old_pixel) draw_face(1);
365                 if(result)
366                 {
367                         handle_event();
368                         set_tooltip(get_caption());
369                 }
370                 return 1;
371         }
372         return 0;
373 }
374
375 int BC_Slider::reposition_window(int x, int y, int w, int h)
376 {
377         BC_SubWindow::reposition_window(x, y, w, h);
378         button_pixel = value_to_pixel();
379         draw_face(0);
380         return 0;
381 }
382
383
384 int BC_Slider::get_pointer_motion_range()
385 {
386         return pointer_motion_range;
387 }
388
389 void BC_Slider::set_pointer_motion_range(int value)
390 {
391         pointer_motion_range = value;
392 }
393
394
395 BC_ISlider::BC_ISlider(int x, int y, int vertical, int pixels, int pointer_motion_range,
396                         int64_t minvalue, int64_t maxvalue, int64_t value, int use_caption,
397                         VFrame **data, int *output)
398  : BC_Slider(x, y, pixels, pointer_motion_range, data, 1, vertical, use_caption)
399 {
400         this->minvalue = minvalue;
401         this->maxvalue = maxvalue;
402         this->value = value;
403         this->output = output;
404 }
405
406 int BC_ISlider::value_to_pixel()
407 {
408         if(maxvalue == minvalue) return 0;
409         else
410         {
411                 if(vertical)
412                         return (int)((1.0 - (double)(value - minvalue) / (maxvalue - minvalue)) *
413                                 (get_h() - get_button_pixels()));
414                 else
415                         return (int)((double)(value - minvalue) / (maxvalue - minvalue) *
416                                 (get_w() - get_button_pixels()));
417         }
418 }
419
420 int BC_ISlider::update(int64_t value)
421 {
422         if(this->value != value)
423         {
424                 this->value = value;
425                 int old_pixel = button_pixel;
426                 button_pixel = value_to_pixel();
427                 if(button_pixel != old_pixel) draw_face(1);
428         }
429         return 0;
430 }
431
432 int BC_ISlider::update(int pointer_motion_range,
433         int64_t value,
434         int64_t minvalue,
435         int64_t maxvalue)
436 {
437         this->minvalue = minvalue;
438         this->maxvalue = maxvalue;
439         this->value = value;
440         this->pointer_motion_range = pointer_motion_range;
441
442         int old_pixel = button_pixel;
443         button_pixel = value_to_pixel();
444         if(button_pixel != old_pixel) draw_face(1);
445         return 0;
446 }
447
448
449 int64_t BC_ISlider::get_value()
450 {
451         return value;
452 }
453
454 int64_t BC_ISlider::get_length()
455 {
456         return maxvalue - minvalue;
457 }
458
459 char* BC_ISlider::get_caption()
460 {
461         sprintf(caption, "%jd", value);
462         return caption;
463 }
464
465 int BC_ISlider::increase_value()
466 {
467         value++;
468         if(value > maxvalue) value = maxvalue;
469         button_pixel = value_to_pixel();
470         return 0;
471 }
472
473 int BC_ISlider::decrease_value()
474 {
475         value--;
476         if(value < minvalue) value = minvalue;
477         button_pixel = value_to_pixel();
478         return 0;
479 }
480
481 int BC_ISlider::increase_value_big()
482 {
483         value+=10;
484         if(value > maxvalue) value = maxvalue;
485         button_pixel = value_to_pixel();
486         return 0;
487 }
488
489 int BC_ISlider::decrease_value_big()
490 {
491         value-=10;
492         if(value < minvalue) value = minvalue;
493         button_pixel = value_to_pixel();
494         return 0;
495 }
496
497 int BC_ISlider::init_selection(int cursor_x, int cursor_y)
498 {
499         if(vertical)
500         {
501                 min_pixel = -(int)((1.0 - (double)(value - minvalue) / (maxvalue - minvalue)) * pointer_motion_range);
502                 min_pixel += cursor_y;
503         }
504         else
505         {
506                 min_pixel = -(int)((double)(value - minvalue) / (maxvalue - minvalue) * pointer_motion_range);
507                 min_pixel += cursor_x;
508         }
509         max_pixel = min_pixel + pointer_motion_range;
510         return 0;
511 }
512
513 int BC_ISlider::update_selection(int cursor_x, int cursor_y)
514 {
515         int64_t old_value = value;
516
517         if(vertical)
518         {
519                 value = (int64_t)((1.0 - (double)(cursor_y - min_pixel) /
520                         pointer_motion_range) *
521                         (maxvalue - minvalue) +
522                         minvalue);
523         }
524         else
525         {
526                 value = (int64_t)((double)(cursor_x - min_pixel) /
527                         pointer_motion_range *
528                         (maxvalue - minvalue) +
529                         minvalue);
530         }
531
532         if(value > maxvalue) value = maxvalue;
533         if(value < minvalue) value = minvalue;
534         button_pixel = value_to_pixel();
535
536         if(old_value != value)
537         {
538                 return 1;
539         }
540         return 0;
541 }
542
543 int BC_ISlider::handle_event()
544 {
545         if(output) *output = get_value();
546         return 1;
547 }
548
549
550 BC_FSlider::BC_FSlider(int x, int y, int vertical, int pixels, int pointer_motion_range,
551                         float minvalue, float maxvalue, float value, int use_caption,
552                         VFrame **data)
553  : BC_Slider(x, y, pixels, pointer_motion_range, data, 1, vertical, use_caption)
554 {
555         this->minvalue = minvalue;
556         this->maxvalue = maxvalue;
557         this->value = value;
558         this->precision = 0.1;
559         this->small_change = 0.1;
560         this->big_change = 1.0;
561 }
562
563 int BC_FSlider::value_to_pixel()
564 {
565 //printf("BC_FSlider::value_to_pixel %f %f\n", maxvalue, minvalue);
566         if(maxvalue == minvalue) return 0;
567         {
568                 if(vertical)
569                         return (int)((1.0 - (double)(value - minvalue) / (maxvalue - minvalue)) *
570                                 (get_h() - get_button_pixels()));
571                 else
572                         return (int)((double)(value - minvalue) / (maxvalue - minvalue) *
573                                 (get_w() - get_button_pixels()));
574         }
575 }
576
577 int BC_FSlider::update(float value)
578 {
579         if(this->value != value)
580         {
581                 this->value = value;
582                 int old_pixel = button_pixel;
583                 button_pixel = value_to_pixel();
584 //printf("BC_FSlider::update 1 %f %d\n", value, button_pixel);
585                 if(button_pixel != old_pixel) draw_face(1);
586         }
587         return 0;
588 }
589
590 int BC_FSlider::update(int pointer_motion_range, float value, float minvalue, float maxvalue)
591 {
592         this->minvalue = minvalue;
593         this->maxvalue = maxvalue;
594         this->value = value;
595         this->pointer_motion_range = pointer_motion_range;
596         int old_pixel = button_pixel;
597         button_pixel = value_to_pixel();
598         if(button_pixel != old_pixel) draw_face(1);
599         return 0;
600 }
601
602
603 float BC_FSlider::get_value()
604 {
605         return value;
606 }
607
608 float BC_FSlider::get_length()
609 {
610         return maxvalue - minvalue;
611 }
612
613 char* BC_FSlider::get_caption()
614 {
615         sprintf(caption, "%.02f", value);
616         return caption;
617 }
618
619 int BC_FSlider::increase_value()
620 {
621         value += small_change;
622         if(value > maxvalue) value = maxvalue;
623         button_pixel = value_to_pixel();
624         return 0;
625 }
626
627 int BC_FSlider::decrease_value()
628 {
629         value -= small_change;
630         if(value < minvalue) value = minvalue;
631         button_pixel = value_to_pixel();
632         return 0;
633 }
634
635 int BC_FSlider::increase_value_big()
636 {
637         value += big_change;
638         if(value > maxvalue) value = maxvalue;
639         button_pixel = value_to_pixel();
640         return 0;
641 }
642
643 int BC_FSlider::decrease_value_big()
644 {
645         value -= big_change;
646         if(value < minvalue) value = minvalue;
647         button_pixel = value_to_pixel();
648         return 0;
649 }
650
651 int BC_FSlider::init_selection(int cursor_x, int cursor_y)
652 {
653         if(vertical)
654         {
655                 min_pixel = -(int)((1.0 - (double)(value - minvalue) / (maxvalue - minvalue)) * pointer_motion_range);
656                 min_pixel += cursor_y;
657         }
658         else
659         {
660                 min_pixel = -(int)((double)(value - minvalue) / (maxvalue - minvalue) * pointer_motion_range);
661                 min_pixel += cursor_x;
662         }
663         max_pixel = min_pixel + pointer_motion_range;
664         return 0;
665 }
666
667 int BC_FSlider::update_selection(int cursor_x, int cursor_y)
668 {
669         float old_value = value;
670
671
672         if(vertical)
673         {
674                 value = ((1.0 - (double)(cursor_y - min_pixel) /
675                         pointer_motion_range) *
676                         (maxvalue - minvalue) +
677                         minvalue);
678         }
679         else
680         {
681                 value = ((double)(cursor_x - min_pixel) /
682                         pointer_motion_range *
683                         (maxvalue - minvalue) +
684                         minvalue);
685         }
686
687         value = Units::quantize(value, precision);
688         if(value > maxvalue) value = maxvalue;
689         if(value < minvalue) value = minvalue;
690         button_pixel = value_to_pixel();
691 // printf("BC_FSlider::update_selection 1 %d %d %d %d %f %f\n",
692 // pointer_motion_range, min_pixel, max_pixel, cursor_x, precision, value);
693
694         if(old_value != value)
695         {
696                 return 1;
697         }
698         return 0;
699 }
700
701 void BC_FSlider::set_precision(float value)
702 {
703         this->precision = value;
704 }
705
706 void BC_FSlider::set_pagination(float small_change, float big_change)
707 {
708         this->small_change = small_change;
709         this->big_change = big_change;
710 }
711
712
713 BC_PercentageSlider::BC_PercentageSlider(int x, int y, int vertical, int pixels, int pointer_motion_range,
714                 float minvalue, float maxvalue, float value, int use_caption,
715                 VFrame **data)
716  : BC_FSlider(x, y, vertical, pixels, pointer_motion_range, minvalue, maxvalue, value, use_caption, data)
717 {
718 }
719
720 char* BC_PercentageSlider::get_caption()
721 {
722         sprintf(caption, "%.0f%%", floor((value - minvalue) / (maxvalue - minvalue) * 100));
723         return caption;
724 }
725