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