asset menu size fixups, new picons+prefs, more timecode del, stretch scrollbars,...
[goodguy/history.git] / cinelerra-5.1 / guicast / bcscrollbar.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2011 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 "bcscrollbar.h"
25 #include "clip.h"
26 #include "colors.h"
27 #include "vframe.h"
28
29 #include <string.h>
30
31 BC_ScrollBar::BC_ScrollBar(int x, int y, int orientation, int pixels,
32         int64_t length, int64_t position, int64_t handlelength,
33         VFrame **data)
34  : BC_SubWindow(x, y, 0, 0, -1)
35 {
36         this->length = length;
37         this->position = position;
38         this->handlelength = handlelength;
39         this->selection_status = 0;
40         this->highlight_status = 0;
41         this->stretch = orientation & SCROLL_STRETCH ? 1 : 0;
42         orientation &= ~SCROLL_STRETCH;
43         this->orientation = orientation;
44         this->pixels = pixels;
45
46         if( !data ) data = orientation == SCROLL_HORIZ ?
47                 BC_WindowBase::get_resources()->hscroll_data :
48                 BC_WindowBase::get_resources()->vscroll_data ;
49         this->data = data;
50
51         handle_pixel = 0;
52         handle_pixels = 0;
53         bound_to = 0;
54         repeat_count = 0;
55         memset(images, 0, sizeof(BC_Pixmap*) * SCROLL_IMAGES);
56 }
57
58 BC_ScrollBar::~BC_ScrollBar()
59 {
60         for(int i = 0; i < SCROLL_IMAGES; i++)
61                 if(images[i]) delete images[i];
62 }
63
64 int BC_ScrollBar::initialize()
65 {
66 //printf("BC_ScrollBar::initialize 1\n");
67         set_images(data);
68 //printf("BC_ScrollBar::initialize 1\n");
69
70         BC_SubWindow::initialize();
71 //printf("BC_ScrollBar::initialize 1\n");
72         draw(0);
73         return 0;
74 }
75
76 void BC_ScrollBar::set_images(VFrame **data)
77 {
78         for(int i = 0; i < SCROLL_IMAGES; i++)
79         {
80                 if(images[i]) delete images[i];
81                 images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
82 //printf("BC_ScrollBar::set_images %d %p\n", i, data[i]);
83         }
84         calculate_dimensions(w, h);
85 }
86
87 void BC_ScrollBar::calculate_dimensions(int &w, int &h)
88 {
89         switch(orientation)
90         {
91                 case SCROLL_HORIZ:
92                         w = pixels;
93                         h = data[SCROLL_HANDLE_UP]->get_h();
94                         break;
95
96                 case SCROLL_VERT:
97                         w = data[SCROLL_HANDLE_UP]->get_w();
98                         h = pixels;
99                         break;
100         }
101 }
102
103 int BC_ScrollBar::get_span(int orientation)
104 {
105         switch(orientation)
106         {
107                 case SCROLL_HORIZ:
108                         return BC_WindowBase::get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
109                         break;
110
111                 case SCROLL_VERT:
112                         return BC_WindowBase::get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
113                         break;
114         }
115         return 0;
116 }
117
118 int BC_ScrollBar::get_span()
119 {
120         switch(orientation)
121         {
122                 case SCROLL_HORIZ:
123                         return data[SCROLL_HANDLE_UP]->get_h();
124                         break;
125
126                 case SCROLL_VERT:
127                         return data[SCROLL_HANDLE_UP]->get_w();
128                         break;
129         }
130         return 0;
131 }
132
133 int BC_ScrollBar::get_arrow_pixels()
134 {
135         switch(orientation)
136         {
137                 case SCROLL_HORIZ:
138                         return data[SCROLL_BACKARROW_UP]->get_w();
139                         break;
140
141                 case SCROLL_VERT:
142                         return data[SCROLL_BACKARROW_UP]->get_h();
143                         break;
144         }
145         return 0;
146 }
147
148
149 void BC_ScrollBar::draw(int flush)
150 {
151         draw_top_background(parent_window, 0, 0, w, h);
152         get_handle_dimensions();
153
154         switch(orientation)
155         {
156                 case SCROLL_HORIZ:
157
158
159 //printf("BC_ScrollBar::draw 1 %d %d\n", selection_status, highlight_status == SCROLL_BACKARROW);
160 // Too small to draw anything
161                         if(get_w() < get_arrow_pixels() * 2 + 5)
162                         {
163                                 draw_3segmenth(0,
164                                         0,
165                                         get_w(),
166                                         images[SCROLL_HANDLE_UP]);
167                         }
168                         else
169                         {
170
171
172
173
174 // back arrow
175 //printf("BC_ScrollBar::draw 2 %p\n", images[SCROLL_BACKARROW_HI]);
176                                 if(selection_status == SCROLL_BACKARROW)
177                                         draw_pixmap(images[SCROLL_BACKARROW_DN],
178                                                 0,
179                                                 0);
180                                 else
181                                 if(highlight_status == SCROLL_BACKARROW)
182                                         draw_pixmap(images[SCROLL_BACKARROW_HI],
183                                                 0,
184                                                 0);
185                                 else
186                                         draw_pixmap(images[SCROLL_BACKARROW_UP],
187                                                 0,
188                                                 0);
189 //printf("BC_ScrollBar::draw 2\n");
190
191
192
193
194
195
196 // forward arrow
197                                 if(selection_status == SCROLL_FWDARROW)
198                                         draw_pixmap(images[SCROLL_FWDARROW_DN],
199                                                 get_w() - get_arrow_pixels(),
200                                                 0);
201                                 else
202                                 if(highlight_status == SCROLL_FWDARROW)
203                                         draw_pixmap(images[SCROLL_FWDARROW_HI],
204                                                 get_w() - get_arrow_pixels(),
205                                                 0);
206                                 else
207                                         draw_pixmap(images[SCROLL_FWDARROW_UP],
208                                                 get_w() - get_arrow_pixels(),
209                                                 0);
210
211
212
213
214
215 //printf("BC_ScrollBar::draw 2\n");
216
217 // handle background
218                                 draw_3segmenth(get_arrow_pixels(),
219                                         0,
220                                         handle_pixel - get_arrow_pixels(),
221                                         images[SCROLL_HANDLE_BG]);
222
223 // handle foreground
224 //printf("BC_ScrollBar::draw 2 %d %d\n", handle_pixel, handle_pixels);
225                                 if(selection_status == SCROLL_HANDLE)
226                                         draw_3segmenth(handle_pixel,
227                                                 0,
228                                                 handle_pixels,
229                                                 images[SCROLL_HANDLE_DN]);
230                                 else
231                                 if(highlight_status == SCROLL_HANDLE)
232                                         draw_3segmenth(handle_pixel,
233                                                 0,
234                                                 handle_pixels,
235                                                 images[SCROLL_HANDLE_HI]);
236                                 else
237                                         draw_3segmenth(handle_pixel,
238                                                 0,
239                                                 handle_pixels,
240                                                 images[SCROLL_HANDLE_UP]);
241 //printf("BC_ScrollBar::draw 2\n");
242
243 // handle background
244                                 draw_3segmenth(handle_pixel + handle_pixels,
245                                         0,
246                                         get_w() - get_arrow_pixels() - handle_pixel - handle_pixels,
247                                         images[SCROLL_HANDLE_BG]);
248 //printf("BC_ScrollBar::draw 3 %d %d\n", handle_pixel, handle_pixels);
249                         }
250                         break;
251
252
253
254
255
256
257
258
259                 case SCROLL_VERT:
260 // Too small to draw anything
261                         if(get_h() < get_arrow_pixels() * 2 + 5)
262                         {
263                                 draw_3segmentv(0,
264                                         0,
265                                         get_w(),
266                                         images[SCROLL_HANDLE_UP]);
267                         }
268                         else
269                         {
270
271
272
273
274 // back arrow
275 //printf("BC_ScrollBar::draw 2 %p\n", images[SCROLL_BACKARROW_HI]);
276                                 if(selection_status == SCROLL_BACKARROW)
277                                         draw_pixmap(images[SCROLL_BACKARROW_DN],
278                                                 0,
279                                                 0);
280                                 else
281                                 if(highlight_status == SCROLL_BACKARROW)
282                                         draw_pixmap(images[SCROLL_BACKARROW_HI],
283                                                 0,
284                                                 0);
285                                 else
286                                         draw_pixmap(images[SCROLL_BACKARROW_UP],
287                                                 0,
288                                                 0);
289 //printf("BC_ScrollBar::draw 2\n");
290
291
292
293
294
295
296 // forward arrow
297                                 if(selection_status == SCROLL_FWDARROW)
298                                         draw_pixmap(images[SCROLL_FWDARROW_DN],
299                                                 0,
300                                                 get_h() - get_arrow_pixels());
301                                 else
302                                 if(highlight_status == SCROLL_FWDARROW)
303                                         draw_pixmap(images[SCROLL_FWDARROW_HI],
304                                                 0,
305                                                 get_h() - get_arrow_pixels());
306                                 else
307                                         draw_pixmap(images[SCROLL_FWDARROW_UP],
308                                                 0,
309                                                 get_h() - get_arrow_pixels());
310
311
312
313
314
315 //printf("BC_ScrollBar::draw 2\n");
316
317 // handle background
318                                 draw_3segmentv(0,
319                                         get_arrow_pixels(),
320                                         handle_pixel - get_arrow_pixels(),
321                                         images[SCROLL_HANDLE_BG]);
322
323 // handle foreground
324 //printf("BC_ScrollBar::draw 2 %d %d\n", handle_pixel, handle_pixels);
325                                 if(selection_status == SCROLL_HANDLE)
326                                         draw_3segmentv(0,
327                                                 handle_pixel,
328                                                 handle_pixels,
329                                                 images[SCROLL_HANDLE_DN]);
330                                 else
331                                 if(highlight_status == SCROLL_HANDLE)
332                                         draw_3segmentv(0,
333                                                 handle_pixel,
334                                                 handle_pixels,
335                                                 images[SCROLL_HANDLE_HI]);
336                                 else
337                                         draw_3segmentv(0,
338                                                 handle_pixel,
339                                                 handle_pixels,
340                                                 images[SCROLL_HANDLE_UP]);
341 //printf("BC_ScrollBar::draw 2\n");
342
343 // handle background
344                                 draw_3segmentv(0,
345                                         handle_pixel + handle_pixels,
346                                         get_h() - get_arrow_pixels() - handle_pixel - handle_pixels,
347                                         images[SCROLL_HANDLE_BG]);
348 //printf("BC_ScrollBar::draw 3 %d %d\n", handle_pixel, handle_pixels);
349                         }
350                         break;
351         }
352         flash(flush);
353 }
354
355 void BC_ScrollBar::get_handle_dimensions()
356 {
357         int total_pixels = pixels -
358                 get_arrow_pixels() * 2;
359
360         if(length > 0)
361         {
362                 handle_pixels = (int64_t)((double)handlelength /
363                         length *
364                         total_pixels +
365                         .5);
366
367                 if(handle_pixels < get_resources()->scroll_minhandle)
368                         handle_pixels = get_resources()->scroll_minhandle;
369
370
371                 handle_pixel = (int64_t)((double)position /
372                                 length *
373                                 total_pixels + .5) +
374                         get_arrow_pixels();
375
376 // Handle pixels is beyond minimum right position.  Clamp it.
377                 if(handle_pixel > pixels - get_arrow_pixels() - get_resources()->scroll_minhandle)
378                 {
379                         handle_pixel = pixels - get_arrow_pixels() - get_resources()->scroll_minhandle;
380                         handle_pixels = get_resources()->scroll_minhandle;
381                 }
382 // Shrink handle_pixels until it fits inside scrollbar
383                 if(handle_pixel > pixels - get_arrow_pixels() - handle_pixels)
384                 {
385                         handle_pixels = pixels - get_arrow_pixels() - handle_pixel;
386                 }
387                 if(handle_pixel < get_arrow_pixels())
388                 {
389                         handle_pixels = handle_pixel + handle_pixels - get_arrow_pixels();
390                         handle_pixel = get_arrow_pixels();
391                 }
392                 if(handle_pixels < get_resources()->scroll_minhandle) handle_pixels = get_resources()->scroll_minhandle;
393         }
394         else
395         {
396                 handle_pixels = total_pixels;
397                 handle_pixel = get_arrow_pixels();
398         }
399
400         CLAMP(handle_pixel, get_arrow_pixels(), (int)(pixels - get_arrow_pixels()));
401         CLAMP(handle_pixels, 0, total_pixels);
402
403 // printf("BC_ScrollBar::get_handle_dimensions %d %d %d\n",
404 // total_pixels,
405 // handle_pixel,
406 // handle_pixels);
407 }
408
409 int BC_ScrollBar::cursor_enter_event()
410 {
411         if(top_level->event_win == win)
412         {
413                 if(!highlight_status)
414                 {
415                         highlight_status = get_cursor_zone(top_level->cursor_x,
416                                 top_level->cursor_y);
417                         draw(1);
418                 }
419                 return 1;
420         }
421         return 0;
422 }
423
424 int BC_ScrollBar::cursor_leave_event()
425 {
426         if(highlight_status)
427         {
428                 highlight_status = 0;
429                 draw(1);
430         }
431         return 0;
432 }
433
434 int BC_ScrollBar::cursor_motion_event()
435 {
436         if(top_level->event_win == win)
437         {
438                 if(highlight_status && !selection_status)
439                 {
440                         int new_highlight_status =
441                                 get_cursor_zone(top_level->cursor_x, top_level->cursor_y);
442                         if(new_highlight_status != highlight_status)
443                         {
444                                 highlight_status = new_highlight_status;
445                                 draw(1);
446                         }
447                 }
448                 else
449                 if(selection_status == SCROLL_HANDLE)
450                 {
451 //printf("BC_ScrollBar::cursor_motion_event 1\n");
452                         double total_pixels = pixels - get_arrow_pixels() * 2;
453                         int64_t cursor_pixel = (orientation == SCROLL_HORIZ) ?
454                                 top_level->cursor_x :
455                                 top_level->cursor_y;
456                         int64_t new_position = (int64_t)((double)(cursor_pixel - min_pixel) /
457                                 total_pixels * length);
458 //printf("BC_ScrollBar::cursor_motion_event 2\n");
459
460                         if(new_position > length - handlelength)
461                                 new_position = length - handlelength;
462                         if(new_position < 0) new_position = 0;
463
464                         if(new_position != position)
465                         {
466 //printf("BC_ScrollBar::cursor_motion_event 3\n");
467                                 position = new_position;
468                                 draw(1);
469                                 handle_event();
470 //printf("BC_ScrollBar::cursor_motion_event 4\n");
471                         }
472                 }
473                 return 1;
474         }
475         return 0;
476 }
477
478 int BC_ScrollBar::button_press_event()
479 {
480         if(top_level->event_win == win)
481         {
482 //printf("BC_ScrollBar::button_press_event %d %p\n", __LINE__, bound_to);
483                 if(!bound_to)
484                 {
485                         top_level->deactivate();
486                         activate();
487                 }
488
489                 if(get_buttonpress() == 4)
490                 {
491                         selection_status = SCROLL_BACKARROW;
492                         repeat_event(top_level->get_resources()->scroll_repeat);
493                 }
494                 else
495                 if(get_buttonpress() == 5)
496                 {
497                         selection_status = SCROLL_FWDARROW;
498                         repeat_count = 0;
499                         repeat_event(top_level->get_resources()->scroll_repeat);
500                 }
501                 else
502                 {
503                         selection_status = get_cursor_zone(top_level->cursor_x, top_level->cursor_y);
504                         if(selection_status == SCROLL_HANDLE)
505                         {
506                                 double total_pixels = pixels - get_arrow_pixels() * 2;
507                                 int64_t cursor_pixel = (orientation == SCROLL_HORIZ) ? top_level->cursor_x : top_level->cursor_y;
508                                 min_pixel = cursor_pixel - (int64_t)((double)position / length * total_pixels + .5);
509                                 max_pixel = (int)(cursor_pixel + total_pixels);
510                                 draw(1);
511                         }
512                         else
513                         if(selection_status)
514                         {
515                                 top_level->set_repeat(top_level->get_resources()->scroll_repeat);
516                                 repeat_count = 0;
517                                 repeat_event(top_level->get_resources()->scroll_repeat);
518                                 draw(1);
519                         }
520                 }
521                 return 1;
522         }
523         return 0;
524 }
525
526 int BC_ScrollBar::repeat_event(int64_t duration)
527 {
528         if(duration == top_level->get_resources()->scroll_repeat &&
529                 selection_status)
530         {
531 //printf("BC_ScrollBar::repeat_event %d %d\n", __LINE__, (int)repeat_count);
532                 repeat_count++;
533 // delay 1st repeat
534                 if(repeat_count >= 2 && repeat_count < 5) return 0;
535                 int64_t new_position = position;
536                 switch(selection_status)
537                 {
538                         case SCROLL_BACKPAGE:
539                                 new_position -= handlelength;
540                                 break;
541                         case SCROLL_FWDPAGE:
542                                 new_position += handlelength;
543                                 break;
544                         case SCROLL_BACKARROW:
545                                 new_position -= (handlelength+9) / 10;
546                                 break;
547                         case SCROLL_FWDARROW:
548                                 new_position += (handlelength+9) / 10;
549                                 break;
550                 }
551
552                 if(new_position > length - handlelength) new_position = length - handlelength;
553                 if(new_position < 0) new_position = 0;
554                 if(new_position != position)
555                 {
556                         position = new_position;
557                         draw(1);
558                         handle_event();
559                 }
560                 return 1;
561         }
562         return 0;
563 }
564
565 int BC_ScrollBar::button_release_event()
566 {
567 //printf("BC_ScrollBar::button_release_event %d\n", selection_status);
568         if(selection_status)
569         {
570                 if(selection_status != SCROLL_HANDLE)
571                         top_level->unset_repeat(top_level->get_resources()->scroll_repeat);
572
573                 selection_status = 0;
574                 draw(1);
575                 return 1;
576         }
577         return 0;
578 }
579
580 int BC_ScrollBar::get_cursor_zone(int cursor_x, int cursor_y)
581 {
582         if(orientation == SCROLL_VERT)
583         {
584                 cursor_x ^= cursor_y;
585                 cursor_y ^= cursor_x;
586                 cursor_x ^= cursor_y;
587         }
588
589
590
591         if(cursor_x >= pixels - get_arrow_pixels())
592                 return SCROLL_FWDARROW;
593         else
594         if(cursor_x >= get_arrow_pixels())
595         {
596                 if(cursor_x > handle_pixel + handle_pixels)
597                         return SCROLL_FWDPAGE;
598                 else
599                 if(cursor_x >= handle_pixel)
600                         return SCROLL_HANDLE;
601                 else
602                         return SCROLL_BACKPAGE;
603         }
604         else
605                 return SCROLL_BACKARROW;
606
607
608
609
610         return 0;
611 }
612
613 int BC_ScrollBar::activate()
614 {
615         top_level->active_subwindow = this;
616 //printf("BC_ScrollBar::activate %p %p\n", top_level->active_subwindow, this);
617         return 0;
618 }
619
620 int64_t BC_ScrollBar::get_value()
621 {
622         return position;
623 }
624
625 int64_t BC_ScrollBar::get_position()
626 {
627         return position;
628 }
629
630 int64_t BC_ScrollBar::get_length()
631 {
632         return length;
633 }
634
635 int BC_ScrollBar::get_pixels()
636 {
637         return pixels;
638 }
639
640 int BC_ScrollBar::in_use()
641 {
642         return selection_status != 0;
643 }
644
645 int64_t BC_ScrollBar::get_handlelength()
646 {
647         return handlelength;
648 }
649
650 int BC_ScrollBar::update_value(int64_t value)
651 {
652         this->position = value;
653         draw(1);
654         return 0;
655 }
656
657 int BC_ScrollBar::update_length(int64_t length, int64_t position, int64_t handlelength, int flush)
658 {
659         if( stretch ) length += handlelength/4;
660         this->length = length;
661         this->position = position;
662         this->handlelength = handlelength;
663         draw(flush);
664         return 0;
665 }
666
667 int BC_ScrollBar::reposition_window(int x, int y, int pixels)
668 {
669         if(x != get_x() || y != get_y() || pixels != this->pixels)
670         {
671                 this->pixels = pixels;
672                 int new_w, new_h;
673                 calculate_dimensions(new_w, new_h);
674                 BC_WindowBase::reposition_window(x, y, new_w, new_h);
675         }
676         draw(0);
677         return 0;
678 }
679