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