238 lines
6 KiB
C++
238 lines
6 KiB
C++
/*
|
|
timeline-ibeam-tool.cpp - Implementation of the IBeamTool class
|
|
|
|
Copyright (C) Lumiera.org
|
|
2008, Joel Holdsworth <joel@airwebreathe.org.uk>
|
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
* *****************************************************/
|
|
|
|
#include "timeline-ibeam-tool.hpp"
|
|
#include "../timeline-widget.hpp"
|
|
|
|
using namespace lumiera::gui::widgets;
|
|
|
|
namespace lumiera {
|
|
namespace gui {
|
|
namespace widgets {
|
|
namespace timeline {
|
|
|
|
// ===== Constants ===== //
|
|
|
|
const int IBeamTool::DragZoneWidth = 5;
|
|
const int IBeamTool::ScrollSlideRateDivisor = 16;
|
|
const int IBeamTool::ScrollSlideEventInterval = 40;
|
|
|
|
// ===== Implementation ===== //
|
|
|
|
IBeamTool::IBeamTool(TimelineBody *timeline_body) :
|
|
dragType(None),
|
|
pinnedDragTime(0),
|
|
scrollSlideRate(0),
|
|
Tool(timeline_body)
|
|
{
|
|
|
|
}
|
|
|
|
IBeamTool::~IBeamTool()
|
|
{
|
|
end_scroll_slide();
|
|
}
|
|
|
|
ToolType
|
|
IBeamTool::get_type() const
|
|
{
|
|
return IBeam;
|
|
}
|
|
|
|
Gdk::Cursor
|
|
IBeamTool::get_cursor() const
|
|
{
|
|
// Are we dragging?
|
|
// Make the cursor indicate that type of drag
|
|
switch(dragType)
|
|
{
|
|
case Selection:
|
|
return Gdk::Cursor(Gdk::XTERM);
|
|
case GrabStart:
|
|
return Gdk::Cursor(Gdk::LEFT_SIDE);
|
|
case GrabEnd:
|
|
return Gdk::Cursor(Gdk::RIGHT_SIDE);
|
|
}
|
|
|
|
// Are we hovering over the ends of the selection?
|
|
// Make the cursor indicate that the user can resize the selection.
|
|
if(is_mouse_in_start_drag_zone())
|
|
return Gdk::Cursor(Gdk::LEFT_SIDE);
|
|
if(is_mouse_in_end_drag_zone())
|
|
return Gdk::Cursor(Gdk::RIGHT_SIDE);
|
|
|
|
// By default return an I-beam cursor
|
|
return Gdk::Cursor(Gdk::XTERM);
|
|
}
|
|
|
|
void
|
|
IBeamTool::on_button_press_event(GdkEventButton* event)
|
|
{
|
|
Tool::on_button_press_event(event);
|
|
|
|
TimelineWidget *timeline_widget = get_timeline_widget();
|
|
|
|
if(event->button == 1)
|
|
{
|
|
const gavl_time_t time = timeline_widget->x_to_time(event->x);
|
|
|
|
if(is_mouse_in_start_drag_zone())
|
|
{
|
|
// User began to drag the start of the selection
|
|
dragType = GrabStart;
|
|
pinnedDragTime = timeline_widget->get_selection_end();
|
|
}
|
|
else if(is_mouse_in_end_drag_zone())
|
|
{
|
|
// User began to drag the end of the selection
|
|
dragType = GrabEnd;
|
|
pinnedDragTime = timeline_widget->get_selection_start();
|
|
}
|
|
else
|
|
{
|
|
// User began the drag in clear space, begin a Select drag
|
|
dragType = Selection;
|
|
pinnedDragTime = time;
|
|
timeline_widget->set_selection(time, time);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
IBeamTool::on_button_release_event(GdkEventButton* event)
|
|
{
|
|
// Ensure that we can't get a mixed up state
|
|
ENSURE(isDragging == (dragType != None));
|
|
ENSURE(isDragging == (event->button == 1));
|
|
|
|
if(event->button == 1)
|
|
{
|
|
set_leading_x(event->x);
|
|
|
|
// Terminate the drag now the button is released
|
|
dragType = None;
|
|
|
|
// If there was a scroll slide, terminate it
|
|
end_scroll_slide();
|
|
|
|
// Apply the cursor - there are some corner cases where it can
|
|
// change by the end of the drag
|
|
apply_cursor();
|
|
}
|
|
|
|
Tool::on_button_release_event(event);
|
|
}
|
|
|
|
void
|
|
IBeamTool::on_motion_notify_event(GdkEventMotion *event)
|
|
{
|
|
Tool::on_motion_notify_event(event);
|
|
|
|
// Ensure that we can't get a mixed up state
|
|
ENSURE(isDragging == (dragType != None));
|
|
|
|
if(isDragging)
|
|
{
|
|
set_leading_x(event->x);
|
|
|
|
// Is the mouse out of bounds? if so we must begin scrolling
|
|
const Gdk::Rectangle body_rect(get_body_rectangle());
|
|
if(event->x < 0)
|
|
begin_scroll_slide(
|
|
event->x / ScrollSlideRateDivisor);
|
|
else if(event->x > body_rect.get_width())
|
|
begin_scroll_slide(
|
|
(event->x - body_rect.get_width()) / ScrollSlideRateDivisor);
|
|
else end_scroll_slide();
|
|
}
|
|
|
|
apply_cursor();
|
|
}
|
|
|
|
bool
|
|
IBeamTool::on_scroll_slide_timer()
|
|
{
|
|
get_timeline_widget()->shift_view(scrollSlideRate);
|
|
|
|
// Return true to keep the timer going
|
|
return true;
|
|
}
|
|
|
|
void
|
|
IBeamTool::set_leading_x(const int x)
|
|
{
|
|
TimelineWidget *timeline_widget = get_timeline_widget();
|
|
|
|
const gavl_time_t time = timeline_widget->x_to_time(x);
|
|
if(time > pinnedDragTime)
|
|
timeline_widget->set_selection(pinnedDragTime, time);
|
|
else
|
|
timeline_widget->set_selection(time, pinnedDragTime);
|
|
}
|
|
|
|
void
|
|
IBeamTool::begin_scroll_slide(int scroll_slide_rate)
|
|
{
|
|
scrollSlideRate = scroll_slide_rate;
|
|
if(!scrollSlideEvent.connected())
|
|
scrollSlideEvent = Glib::signal_timeout().connect(
|
|
sigc::mem_fun(this, &IBeamTool::on_scroll_slide_timer),
|
|
ScrollSlideEventInterval);
|
|
}
|
|
|
|
void
|
|
IBeamTool::end_scroll_slide()
|
|
{
|
|
scrollSlideRate = 0;
|
|
if(scrollSlideEvent.connected())
|
|
scrollSlideEvent.disconnect();
|
|
}
|
|
|
|
bool
|
|
IBeamTool::is_mouse_in_start_drag_zone() const
|
|
{
|
|
TimelineWidget *timeline_widget = get_timeline_widget();
|
|
|
|
const int start_x = timeline_widget->time_to_x(
|
|
timeline_widget->get_selection_start());
|
|
|
|
return (mousePoint.get_x() <= start_x &&
|
|
mousePoint.get_x() > start_x - DragZoneWidth);
|
|
}
|
|
|
|
bool
|
|
IBeamTool::is_mouse_in_end_drag_zone() const
|
|
{
|
|
TimelineWidget *timeline_widget = get_timeline_widget();
|
|
|
|
const int end_x = timeline_widget->time_to_x(
|
|
timeline_widget->get_selection_end());
|
|
|
|
return (mousePoint.get_x() >= end_x &&
|
|
mousePoint.get_x() < end_x + DragZoneWidth);
|
|
}
|
|
|
|
} // namespace timeline
|
|
} // namespace widgets
|
|
} // namespace gui
|
|
} // namespace lumiera
|
|
|