/* * CINELERRA * Copyright (C) 2011 Adam Williams * * 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 "bccolors.h" #include "vframe.h" #include 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->stretch = orientation & SCROLL_STRETCH ? 1 : 0; orientation &= ~SCROLL_STRETCH; this->orientation = orientation; this->pixels = pixels; if( !data ) data = orientation == SCROLL_HORIZ ? BC_WindowBase::get_resources()->hscroll_data : BC_WindowBase::get_resources()->vscroll_data ; this->data = 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) { w = h = pixels; switch( orientation ) { case SCROLL_HORIZ: h = data[SCROLL_HANDLE_UP]->get_h(); break; case SCROLL_VERT: w = data[SCROLL_HANDLE_UP]->get_w(); 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(); case SCROLL_VERT: return data[SCROLL_HANDLE_UP]->get_w(); } return 0; } int BC_ScrollBar::get_arrow_pixels() { switch(orientation) { case SCROLL_HORIZ: return data[SCROLL_BACKARROW_UP]->get_w(); case SCROLL_VERT: return data[SCROLL_BACKARROW_UP]->get_h(); } 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 + xS(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 + yS(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) { if( stretch ) length += handlelength/4; 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; }