Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / guicast / bcscrollbar.C
diff --git a/cinelerra-5.1/guicast/bcscrollbar.C b/cinelerra-5.1/guicast/bcscrollbar.C
new file mode 100644 (file)
index 0000000..8bfbc73
--- /dev/null
@@ -0,0 +1,686 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "bcpixmap.h"
+#include "bcresources.h"
+#include "bcscrollbar.h"
+#include "clip.h"
+#include "colors.h"
+#include "vframe.h"
+
+#include <string.h>
+
+BC_ScrollBar::BC_ScrollBar(int x, 
+       int y, 
+       int orientation, 
+       int pixels, 
+       int64_t length, 
+       int64_t position, 
+       int64_t handlelength,
+       VFrame **data)
+ : BC_SubWindow(x, y, 0, 0, -1)
+{
+       this->length = length;
+       this->position = position;
+       this->handlelength = handlelength;
+       this->selection_status = 0;
+       this->highlight_status = 0;
+       this->orientation = orientation;
+       this->pixels = pixels;
+
+       if(data) 
+               this->data = data;
+       else
+       if(orientation == SCROLL_HORIZ)
+               this->data = BC_WindowBase::get_resources()->hscroll_data;
+       else
+               this->data = BC_WindowBase::get_resources()->vscroll_data;
+
+       handle_pixel = 0;
+       handle_pixels = 0;
+       bound_to = 0;
+       repeat_count = 0;
+       memset(images, 0, sizeof(BC_Pixmap*) * SCROLL_IMAGES);
+}
+
+BC_ScrollBar::~BC_ScrollBar()
+{
+       for(int i = 0; i < SCROLL_IMAGES; i++)
+               if(images[i]) delete images[i];
+}
+
+int BC_ScrollBar::initialize()
+{
+//printf("BC_ScrollBar::initialize 1\n");
+       set_images(data);
+//printf("BC_ScrollBar::initialize 1\n");
+
+       BC_SubWindow::initialize();
+//printf("BC_ScrollBar::initialize 1\n");
+       draw(0);
+       return 0;
+}
+
+void BC_ScrollBar::set_images(VFrame **data)
+{
+       for(int i = 0; i < SCROLL_IMAGES; i++)
+       {
+               if(images[i]) delete images[i];
+               images[i] = new BC_Pixmap(parent_window, data[i], PIXMAP_ALPHA);
+//printf("BC_ScrollBar::set_images %d %p\n", i, data[i]);
+       }
+       calculate_dimensions(w, h);
+}
+
+
+
+void BC_ScrollBar::calculate_dimensions(int &w, int &h)
+{
+       switch(orientation)
+       {
+               case SCROLL_HORIZ:
+                       w = pixels;
+                       h = data[SCROLL_HANDLE_UP]->get_h();
+                       break;
+
+               case SCROLL_VERT:
+                       w = data[SCROLL_HANDLE_UP]->get_w();
+                       h = pixels;
+                       break;
+       }
+}
+
+int BC_ScrollBar::get_span(int orientation)
+{
+       switch(orientation)
+       {
+               case SCROLL_HORIZ:
+                       return BC_WindowBase::get_resources()->hscroll_data[SCROLL_HANDLE_UP]->get_h();
+                       break;
+
+               case SCROLL_VERT:
+                       return BC_WindowBase::get_resources()->vscroll_data[SCROLL_HANDLE_UP]->get_w();
+                       break;
+       }
+       return 0;
+}
+
+int BC_ScrollBar::get_span()
+{
+       switch(orientation)
+       {
+               case SCROLL_HORIZ:
+                       return data[SCROLL_HANDLE_UP]->get_h();
+                       break;
+
+               case SCROLL_VERT:
+                       return data[SCROLL_HANDLE_UP]->get_w();
+                       break;
+       }
+       return 0;
+}
+
+int BC_ScrollBar::get_arrow_pixels()
+{
+       switch(orientation)
+       {
+               case SCROLL_HORIZ:
+                       return data[SCROLL_BACKARROW_UP]->get_w();
+                       break;
+
+               case SCROLL_VERT:
+                       return data[SCROLL_BACKARROW_UP]->get_h();
+                       break;
+       }
+       return 0;
+}
+
+
+void BC_ScrollBar::draw(int flush)
+{
+       draw_top_background(parent_window, 0, 0, w, h);
+       get_handle_dimensions();
+
+       switch(orientation)
+       {
+               case SCROLL_HORIZ:
+
+
+//printf("BC_ScrollBar::draw 1 %d %d\n", selection_status, highlight_status == SCROLL_BACKARROW);
+// Too small to draw anything
+                       if(get_w() < get_arrow_pixels() * 2 + 5)
+                       {
+                               draw_3segmenth(0, 
+                                       0, 
+                                       get_w(),
+                                       images[SCROLL_HANDLE_UP]);
+                       }
+                       else
+                       {
+
+
+
+
+// back arrow
+//printf("BC_ScrollBar::draw 2 %p\n", images[SCROLL_BACKARROW_HI]);
+                               if(selection_status == SCROLL_BACKARROW)
+                                       draw_pixmap(images[SCROLL_BACKARROW_DN],
+                                               0,
+                                               0);
+                               else
+                               if(highlight_status == SCROLL_BACKARROW)
+                                       draw_pixmap(images[SCROLL_BACKARROW_HI],
+                                               0,
+                                               0);
+                               else
+                                       draw_pixmap(images[SCROLL_BACKARROW_UP],
+                                               0,
+                                               0);
+//printf("BC_ScrollBar::draw 2\n");
+
+
+
+
+
+
+// forward arrow
+                               if(selection_status == SCROLL_FWDARROW)
+                                       draw_pixmap(images[SCROLL_FWDARROW_DN],
+                                               get_w() - get_arrow_pixels(),
+                                               0);
+                               else
+                               if(highlight_status == SCROLL_FWDARROW)
+                                       draw_pixmap(images[SCROLL_FWDARROW_HI],
+                                               get_w() - get_arrow_pixels(),
+                                               0);
+                               else
+                                       draw_pixmap(images[SCROLL_FWDARROW_UP],
+                                               get_w() - get_arrow_pixels(),
+                                               0);
+
+
+
+
+
+//printf("BC_ScrollBar::draw 2\n");
+
+// handle background
+                               draw_3segmenth(get_arrow_pixels(),
+                                       0,
+                                       handle_pixel - get_arrow_pixels(),
+                                       images[SCROLL_HANDLE_BG]);
+
+// handle foreground
+//printf("BC_ScrollBar::draw 2 %d %d\n", handle_pixel, handle_pixels);
+                               if(selection_status == SCROLL_HANDLE)
+                                       draw_3segmenth(handle_pixel,
+                                               0,
+                                               handle_pixels,
+                                               images[SCROLL_HANDLE_DN]);
+                               else
+                               if(highlight_status == SCROLL_HANDLE)
+                                       draw_3segmenth(handle_pixel,
+                                               0,
+                                               handle_pixels,
+                                               images[SCROLL_HANDLE_HI]);
+                               else
+                                       draw_3segmenth(handle_pixel,
+                                               0,
+                                               handle_pixels,
+                                               images[SCROLL_HANDLE_UP]);
+//printf("BC_ScrollBar::draw 2\n");
+
+// handle background
+                               draw_3segmenth(handle_pixel + handle_pixels,
+                                       0,
+                                       get_w() - get_arrow_pixels() - handle_pixel - handle_pixels,
+                                       images[SCROLL_HANDLE_BG]);
+//printf("BC_ScrollBar::draw 3 %d %d\n", handle_pixel, handle_pixels);
+                       }
+                       break;
+
+
+
+
+
+
+
+
+               case SCROLL_VERT:
+// Too small to draw anything
+                       if(get_h() < get_arrow_pixels() * 2 + 5)
+                       {
+                               draw_3segmentv(0, 
+                                       0, 
+                                       get_w(),
+                                       images[SCROLL_HANDLE_UP]);
+                       }
+                       else
+                       {
+
+
+
+
+// back arrow
+//printf("BC_ScrollBar::draw 2 %p\n", images[SCROLL_BACKARROW_HI]);
+                               if(selection_status == SCROLL_BACKARROW)
+                                       draw_pixmap(images[SCROLL_BACKARROW_DN],
+                                               0,
+                                               0);
+                               else
+                               if(highlight_status == SCROLL_BACKARROW)
+                                       draw_pixmap(images[SCROLL_BACKARROW_HI],
+                                               0,
+                                               0);
+                               else
+                                       draw_pixmap(images[SCROLL_BACKARROW_UP],
+                                               0,
+                                               0);
+//printf("BC_ScrollBar::draw 2\n");
+
+
+
+
+
+
+// forward arrow
+                               if(selection_status == SCROLL_FWDARROW)
+                                       draw_pixmap(images[SCROLL_FWDARROW_DN],
+                                               0,
+                                               get_h() - get_arrow_pixels());
+                               else
+                               if(highlight_status == SCROLL_FWDARROW)
+                                       draw_pixmap(images[SCROLL_FWDARROW_HI],
+                                               0,
+                                               get_h() - get_arrow_pixels());
+                               else
+                                       draw_pixmap(images[SCROLL_FWDARROW_UP],
+                                               0,
+                                               get_h() - get_arrow_pixels());
+
+
+
+
+
+//printf("BC_ScrollBar::draw 2\n");
+
+// handle background
+                               draw_3segmentv(0,
+                                       get_arrow_pixels(),
+                                       handle_pixel - get_arrow_pixels(),
+                                       images[SCROLL_HANDLE_BG]);
+
+// handle foreground
+//printf("BC_ScrollBar::draw 2 %d %d\n", handle_pixel, handle_pixels);
+                               if(selection_status == SCROLL_HANDLE)
+                                       draw_3segmentv(0,
+                                               handle_pixel,
+                                               handle_pixels,
+                                               images[SCROLL_HANDLE_DN]);
+                               else
+                               if(highlight_status == SCROLL_HANDLE)
+                                       draw_3segmentv(0,
+                                               handle_pixel,
+                                               handle_pixels,
+                                               images[SCROLL_HANDLE_HI]);
+                               else
+                                       draw_3segmentv(0,
+                                               handle_pixel,
+                                               handle_pixels,
+                                               images[SCROLL_HANDLE_UP]);
+//printf("BC_ScrollBar::draw 2\n");
+
+// handle background
+                               draw_3segmentv(0,
+                                       handle_pixel + handle_pixels,
+                                       get_h() - get_arrow_pixels() - handle_pixel - handle_pixels,
+                                       images[SCROLL_HANDLE_BG]);
+//printf("BC_ScrollBar::draw 3 %d %d\n", handle_pixel, handle_pixels);
+                       }
+                       break;
+       }
+       flash(flush);
+}
+
+void BC_ScrollBar::get_handle_dimensions()
+{
+       int total_pixels = pixels - 
+               get_arrow_pixels() * 2;
+
+       if(length > 0)
+       {
+               handle_pixels = (int64_t)((double)handlelength / 
+                       length * 
+                       total_pixels + 
+                       .5);
+
+               if(handle_pixels < get_resources()->scroll_minhandle)
+                       handle_pixels = get_resources()->scroll_minhandle;
+
+
+               handle_pixel = (int64_t)((double)position / 
+                               length * 
+                               total_pixels + .5) + 
+                       get_arrow_pixels();
+
+// Handle pixels is beyond minimum right position.  Clamp it.
+               if(handle_pixel > pixels - get_arrow_pixels() - get_resources()->scroll_minhandle)
+               {
+                       handle_pixel = pixels - get_arrow_pixels() - get_resources()->scroll_minhandle;
+                       handle_pixels = get_resources()->scroll_minhandle;
+               }
+// Shrink handle_pixels until it fits inside scrollbar
+               if(handle_pixel > pixels - get_arrow_pixels() - handle_pixels)
+               {
+                       handle_pixels = pixels - get_arrow_pixels() - handle_pixel;
+               }
+               if(handle_pixel < get_arrow_pixels())
+               {
+                       handle_pixels = handle_pixel + handle_pixels - get_arrow_pixels();
+                       handle_pixel = get_arrow_pixels();
+               }
+               if(handle_pixels < get_resources()->scroll_minhandle) handle_pixels = get_resources()->scroll_minhandle;
+       }
+       else
+       {
+               handle_pixels = total_pixels;
+               handle_pixel = get_arrow_pixels();
+       }
+
+       CLAMP(handle_pixel, get_arrow_pixels(), (int)(pixels - get_arrow_pixels()));
+       CLAMP(handle_pixels, 0, total_pixels);
+
+// printf("BC_ScrollBar::get_handle_dimensions %d %d %d\n", 
+// total_pixels, 
+// handle_pixel,
+// handle_pixels);
+}
+
+int BC_ScrollBar::cursor_enter_event()
+{
+       if(top_level->event_win == win)
+       {
+               if(!highlight_status)
+               {
+                       highlight_status = get_cursor_zone(top_level->cursor_x, 
+                               top_level->cursor_y);
+                       draw(1);
+               }
+               return 1;
+       }
+       return 0;
+}
+
+int BC_ScrollBar::cursor_leave_event()
+{
+       if(highlight_status)
+       {
+               highlight_status = 0;
+               draw(1);
+       }
+       return 0;
+}
+
+int BC_ScrollBar::cursor_motion_event()
+{
+       if(top_level->event_win == win)
+       {
+               if(highlight_status && !selection_status)
+               {
+                       int new_highlight_status = 
+                               get_cursor_zone(top_level->cursor_x, top_level->cursor_y);
+                       if(new_highlight_status != highlight_status)
+                       {
+                               highlight_status = new_highlight_status;
+                               draw(1);
+                       }
+               }
+               else
+               if(selection_status == SCROLL_HANDLE)
+               {
+//printf("BC_ScrollBar::cursor_motion_event 1\n");
+                       double total_pixels = pixels - get_arrow_pixels() * 2;
+                       int64_t cursor_pixel = (orientation == SCROLL_HORIZ) ? 
+                               top_level->cursor_x : 
+                               top_level->cursor_y;
+                       int64_t new_position = (int64_t)((double)(cursor_pixel - min_pixel) / 
+                               total_pixels * length);
+//printf("BC_ScrollBar::cursor_motion_event 2\n");
+
+                       if(new_position > length - handlelength) 
+                               new_position = length - handlelength;
+                       if(new_position < 0) new_position = 0;
+
+                       if(new_position != position)
+                       {
+//printf("BC_ScrollBar::cursor_motion_event 3\n");
+                               position = new_position;
+                               draw(1);
+                               handle_event();
+//printf("BC_ScrollBar::cursor_motion_event 4\n");
+                       }
+               }
+               return 1;
+       }
+       return 0;
+}
+
+int BC_ScrollBar::button_press_event()
+{
+       if(top_level->event_win == win)
+       {
+//printf("BC_ScrollBar::button_press_event %d %p\n", __LINE__, bound_to);
+               if(!bound_to)
+               {
+                       top_level->deactivate();
+                       activate();
+               }
+
+               if(get_buttonpress() == 4)
+               {
+                       selection_status = SCROLL_BACKARROW;
+                       repeat_event(top_level->get_resources()->scroll_repeat);
+               }
+               else
+               if(get_buttonpress() == 5)
+               {
+                       selection_status = SCROLL_FWDARROW;
+                       repeat_count = 0;
+                       repeat_event(top_level->get_resources()->scroll_repeat);
+               }
+               else
+               {
+                       selection_status = get_cursor_zone(top_level->cursor_x, top_level->cursor_y);
+                       if(selection_status == SCROLL_HANDLE)
+                       {
+                               double total_pixels = pixels - get_arrow_pixels() * 2;
+                               int64_t cursor_pixel = (orientation == SCROLL_HORIZ) ? top_level->cursor_x : top_level->cursor_y;
+                               min_pixel = cursor_pixel - (int64_t)((double)position / length * total_pixels + .5);
+                               max_pixel = (int)(cursor_pixel + total_pixels);
+                               draw(1);
+                       }
+                       else
+                       if(selection_status)
+                       {
+                               top_level->set_repeat(top_level->get_resources()->scroll_repeat);
+                               repeat_count = 0;
+                               repeat_event(top_level->get_resources()->scroll_repeat);
+                               draw(1);
+                       }
+               }
+               return 1;
+       }
+       return 0;
+}
+
+int BC_ScrollBar::repeat_event(int64_t duration)
+{
+       if(duration == top_level->get_resources()->scroll_repeat && 
+               selection_status)
+       {
+//printf("BC_ScrollBar::repeat_event %d %d\n", __LINE__, (int)repeat_count);
+               repeat_count++;
+// delay 1st repeat
+               if(repeat_count >= 2 && repeat_count < 5) return 0;
+               int64_t new_position = position;
+               switch(selection_status)
+               {
+                       case SCROLL_BACKPAGE:
+                               new_position -= handlelength;
+                               break;
+                       case SCROLL_FWDPAGE:
+                               new_position += handlelength;
+                               break;
+                       case SCROLL_BACKARROW:
+                               new_position -= (handlelength+9) / 10;
+                               break;
+                       case SCROLL_FWDARROW:
+                               new_position += (handlelength+9) / 10;
+                               break;
+               }
+
+               if(new_position > length - handlelength) new_position = length - handlelength;
+               if(new_position < 0) new_position = 0;
+               if(new_position != position)
+               {
+                       position = new_position;
+                       draw(1);
+                       handle_event();
+               }
+               return 1;
+       }
+       return 0;
+}
+
+int BC_ScrollBar::button_release_event()
+{
+//printf("BC_ScrollBar::button_release_event %d\n", selection_status);
+       if(selection_status)
+       {
+               if(selection_status != SCROLL_HANDLE)
+                       top_level->unset_repeat(top_level->get_resources()->scroll_repeat);
+
+               selection_status = 0;
+               draw(1);
+               return 1;
+       }
+       return 0;
+}
+
+int BC_ScrollBar::get_cursor_zone(int cursor_x, int cursor_y)
+{
+       if(orientation == SCROLL_VERT)
+       {
+               cursor_x ^= cursor_y;
+               cursor_y ^= cursor_x;
+               cursor_x ^= cursor_y;
+       }
+
+
+
+       if(cursor_x >= pixels - get_arrow_pixels())
+               return SCROLL_FWDARROW;
+       else
+       if(cursor_x >= get_arrow_pixels())
+       {
+               if(cursor_x > handle_pixel + handle_pixels)
+                       return SCROLL_FWDPAGE;
+               else
+               if(cursor_x >= handle_pixel)
+                       return SCROLL_HANDLE;
+               else
+                       return SCROLL_BACKPAGE;
+       }
+       else
+               return SCROLL_BACKARROW;
+
+
+
+
+       return 0;
+}
+
+int BC_ScrollBar::activate()
+{
+       top_level->active_subwindow = this;
+//printf("BC_ScrollBar::activate %p %p\n", top_level->active_subwindow, this);
+       return 0;
+}
+
+int64_t BC_ScrollBar::get_value()
+{
+       return position;
+}
+
+int64_t BC_ScrollBar::get_position()
+{
+       return position;
+}
+
+int64_t BC_ScrollBar::get_length()
+{
+       return length;
+}
+
+int BC_ScrollBar::get_pixels()
+{
+       return pixels;
+}
+
+int BC_ScrollBar::in_use()
+{
+       return selection_status != 0;
+}
+
+int64_t BC_ScrollBar::get_handlelength()
+{
+       return handlelength;
+}
+
+int BC_ScrollBar::update_value(int64_t value)
+{
+       this->position = value;
+       draw(1);
+       return 0;
+}
+
+int BC_ScrollBar::update_length(int64_t length, int64_t position, int64_t handlelength, int flush)
+{
+       this->length = length;
+       this->position = position;
+       this->handlelength = handlelength;
+       draw(flush);
+       return 0;
+}
+
+int BC_ScrollBar::reposition_window(int x, int y, int pixels)
+{
+       if(x != get_x() || y != get_y() || pixels != this->pixels)
+       {
+               this->pixels = pixels;
+               int new_w, new_h;
+               calculate_dimensions(new_w, new_h);
+               BC_WindowBase::reposition_window(x, y, new_w, new_h);
+       }
+       draw(0);
+       return 0;
+}
+