Added resizing of selection area, and some documentation
This commit is contained in:
parent
39bd8aac74
commit
57aed7b40d
6 changed files with 264 additions and 27 deletions
|
|
@ -98,14 +98,29 @@ public:
|
|||
**/
|
||||
void shift_view(int shift_size);
|
||||
|
||||
/**
|
||||
* Gets the time at which the selection begins.
|
||||
*/
|
||||
gavl_time_t get_selection_start() const;
|
||||
|
||||
/**
|
||||
* Gets the time at which the selection begins.
|
||||
*/
|
||||
gavl_time_t get_selection_end() const;
|
||||
|
||||
/**
|
||||
* Sets the period of the selection.
|
||||
*/
|
||||
void set_selection(gavl_time_t start, gavl_time_t end);
|
||||
|
||||
/**
|
||||
* Gets the type of the tool currently active.
|
||||
*/
|
||||
timeline::ToolType get_tool() const;
|
||||
|
||||
/**
|
||||
* Sets the type of the tool currently active.
|
||||
*/
|
||||
void set_tool(timeline::ToolType tool_type);
|
||||
|
||||
/* ===== Events ===== */
|
||||
|
|
|
|||
|
|
@ -56,8 +56,19 @@ protected:
|
|||
Gdk::Cursor get_cursor() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The event handler for button press events.
|
||||
*/
|
||||
void on_button_press_event(GdkEventButton* event);
|
||||
|
||||
/**
|
||||
* The event handler for button release events.
|
||||
*/
|
||||
void on_button_release_event(GdkEventButton* event);
|
||||
|
||||
/**
|
||||
* The event handler for mouse move events.
|
||||
*/
|
||||
void on_motion_notify_event(GdkEventMotion *event);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "timeline-ibeam-tool.hpp"
|
||||
#include "../timeline-widget.hpp"
|
||||
|
||||
using namespace lumiera::gui::widgets;
|
||||
|
||||
namespace lumiera {
|
||||
namespace gui {
|
||||
namespace widgets {
|
||||
|
|
@ -30,13 +32,15 @@ namespace timeline {
|
|||
|
||||
// ===== Constants ===== //
|
||||
|
||||
const int IBeamTool::DragZoneWidth = 5;
|
||||
const int IBeamTool::ScrollSlideRateDivisor = 16;
|
||||
const int IBeamTool::ScrollSlideEventInterval = 40;
|
||||
|
||||
// ===== Implementation ===== //
|
||||
|
||||
IBeamTool::IBeamTool(TimelineBody *timeline_body) :
|
||||
dragStartTime(0),
|
||||
dragType(None),
|
||||
pinnedDragTime(0),
|
||||
scrollSlideRate(0),
|
||||
Tool(timeline_body)
|
||||
{
|
||||
|
|
@ -57,6 +61,26 @@ IBeamTool::get_type() const
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -65,29 +89,66 @@ IBeamTool::on_button_press_event(GdkEventButton* event)
|
|||
{
|
||||
Tool::on_button_press_event(event);
|
||||
|
||||
lumiera::gui::widgets::TimelineWidget *timeline_widget =
|
||||
get_timeline_widget();
|
||||
TimelineWidget *timeline_widget = get_timeline_widget();
|
||||
|
||||
if(event->button == 1)
|
||||
{
|
||||
dragStartTime = timeline_widget->x_to_time(event->x);
|
||||
timeline_widget->set_selection(dragStartTime, dragStartTime);
|
||||
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)
|
||||
{
|
||||
Tool::on_button_release_event(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);
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
@ -103,15 +164,14 @@ IBeamTool::on_motion_notify_event(GdkEventMotion *event)
|
|||
(event->x - body_rect.get_width()) / ScrollSlideRateDivisor);
|
||||
else end_scroll_slide();
|
||||
}
|
||||
|
||||
apply_cursor();
|
||||
}
|
||||
|
||||
bool
|
||||
IBeamTool::on_scroll_slide_timer()
|
||||
{
|
||||
lumiera::gui::widgets::TimelineWidget *timeline_widget =
|
||||
get_timeline_widget();
|
||||
|
||||
timeline_widget->shift_view(scrollSlideRate);
|
||||
{
|
||||
get_timeline_widget()->shift_view(scrollSlideRate);
|
||||
|
||||
// Return true to keep the timer going
|
||||
return true;
|
||||
|
|
@ -120,16 +180,13 @@ IBeamTool::on_scroll_slide_timer()
|
|||
void
|
||||
IBeamTool::set_leading_x(const int x)
|
||||
{
|
||||
REQUIRE(timelineBody != NULL);
|
||||
lumiera::gui::widgets::TimelineWidget *timeline_widget =
|
||||
timelineBody->timelineWidget;
|
||||
REQUIRE(timeline_widget != NULL);
|
||||
|
||||
TimelineWidget *timeline_widget = get_timeline_widget();
|
||||
|
||||
const gavl_time_t time = timeline_widget->x_to_time(x);
|
||||
if(time > dragStartTime)
|
||||
timeline_widget->set_selection(dragStartTime, time);
|
||||
if(time > pinnedDragTime)
|
||||
timeline_widget->set_selection(pinnedDragTime, time);
|
||||
else
|
||||
timeline_widget->set_selection(time, dragStartTime);
|
||||
timeline_widget->set_selection(time, pinnedDragTime);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -150,6 +207,30 @@ IBeamTool::end_scroll_slide()
|
|||
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
|
||||
|
|
|
|||
|
|
@ -47,22 +47,37 @@ public:
|
|||
*/
|
||||
IBeamTool(TimelineBody *timeline_body);
|
||||
|
||||
~IBeamTool();
|
||||
|
||||
/**
|
||||
* Gets the type of tool represented by this class
|
||||
*/
|
||||
ToolType get_type() const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~IBeamTool();
|
||||
|
||||
/**
|
||||
* Gets the cursor to display for this tool at this moment.
|
||||
*/
|
||||
Gdk::Cursor get_cursor() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The event handler for button press events.
|
||||
*/
|
||||
void on_button_press_event(GdkEventButton* event);
|
||||
|
||||
/**
|
||||
* The event handler for button release events.
|
||||
*/
|
||||
void on_button_release_event(GdkEventButton* event);
|
||||
|
||||
/**
|
||||
* The event handler for mouse move events.
|
||||
*/
|
||||
void on_motion_notify_event(GdkEventMotion *event);
|
||||
|
||||
private:
|
||||
|
|
@ -95,14 +110,96 @@ private:
|
|||
*/
|
||||
void end_scroll_slide();
|
||||
|
||||
/**
|
||||
* Determines if the cursor is hovering over the start of the
|
||||
* selection.
|
||||
*/
|
||||
bool is_mouse_in_start_drag_zone() const;
|
||||
|
||||
/**
|
||||
* Determines if the cursor is hovering over the end of the
|
||||
* selection.
|
||||
*/
|
||||
bool is_mouse_in_end_drag_zone() const;
|
||||
|
||||
private:
|
||||
/* ==== Enums ===== */
|
||||
|
||||
/**
|
||||
* An enum used to represent the type of drag currently take place.
|
||||
*/
|
||||
enum DragType
|
||||
{
|
||||
/**
|
||||
* No drag is occuring
|
||||
*/
|
||||
None,
|
||||
|
||||
/**
|
||||
* A selection drag is occuring.
|
||||
* @remarks The position of one end of the selection was set at
|
||||
* mouse-down of the drag, and the other end is set by
|
||||
* drag-release.
|
||||
*/
|
||||
Selection,
|
||||
|
||||
/**
|
||||
* The start of the selection is being dragged.
|
||||
*/
|
||||
GrabStart,
|
||||
|
||||
/**
|
||||
* The end of the selection is being dragged.
|
||||
*/
|
||||
GrabEnd
|
||||
};
|
||||
|
||||
/* ==== Internals ===== */
|
||||
gavl_time_t dragStartTime;
|
||||
/**
|
||||
* Specifies the type of drag currently taking place.
|
||||
*/
|
||||
DragType dragType;
|
||||
|
||||
/**
|
||||
* During a selection drag, one end of the selection is moving with
|
||||
* the mouse, the other is pinned. pinnedDragTime specifies the time
|
||||
* of that point.
|
||||
*/
|
||||
gavl_time_t pinnedDragTime;
|
||||
|
||||
/**
|
||||
* This connection is used to represent the timer which causes scroll
|
||||
* sliding to occur.
|
||||
* @remarks Scroll sliding is an animated scroll which occurs when
|
||||
* the user drags a selection outside the area of the timeline body.
|
||||
*/
|
||||
sigc::connection scrollSlideEvent;
|
||||
|
||||
/**
|
||||
* Specifies the rate at which scroll sliding is currently taking
|
||||
* place.
|
||||
*/
|
||||
int scrollSlideRate;
|
||||
|
||||
/* ===== Constants ===== */
|
||||
/**
|
||||
* DragZoneSize defines the width of the zone near to the end of the
|
||||
* selection in which dragging will cause the selection to resize.
|
||||
* @remarks The selection marque can be resized by dragging the ends
|
||||
* of it. Special cursors are shown when the mouse is in this region.
|
||||
*/
|
||||
static const int DragZoneWidth;
|
||||
|
||||
/**
|
||||
* The amount to divide the mouse overshoot by to produce the slide
|
||||
* scroll rate.
|
||||
* @remarks Smaller values cause faster scrolling.
|
||||
*/
|
||||
static const int ScrollSlideRateDivisor;
|
||||
|
||||
/**
|
||||
* The interval between scroll slide events in ms.
|
||||
*/
|
||||
static const int ScrollSlideEventInterval;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include "timeline-tool.hpp"
|
||||
#include "../timeline-widget.hpp"
|
||||
|
||||
using namespace Gdk;
|
||||
|
||||
namespace lumiera {
|
||||
namespace gui {
|
||||
namespace widgets {
|
||||
|
|
@ -40,7 +42,7 @@ Tool::apply_cursor()
|
|||
{
|
||||
REQUIRE(timelineBody != NULL);
|
||||
|
||||
Glib::RefPtr<Gdk::Window> window =
|
||||
Glib::RefPtr<Window> window =
|
||||
timelineBody->get_window();
|
||||
if(!window)
|
||||
return false;
|
||||
|
|
@ -68,6 +70,12 @@ Tool::on_button_release_event(GdkEventButton* event)
|
|||
isDragging = false;
|
||||
}
|
||||
|
||||
void
|
||||
Tool::on_motion_notify_event(GdkEventMotion *event)
|
||||
{
|
||||
mousePoint = Point(event->x, event->y);
|
||||
}
|
||||
|
||||
lumiera::gui::widgets::TimelineWidget*
|
||||
Tool::get_timeline_widget() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@ protected:
|
|||
Tool(TimelineBody *timeline_body);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destructor to be overriden by derived classes.
|
||||
* @remarks If this were not present, derrived class destructors
|
||||
* would not be called.
|
||||
*/
|
||||
virtual ~Tool() {};
|
||||
|
||||
/**
|
||||
|
|
@ -74,9 +79,29 @@ public:
|
|||
|
||||
public:
|
||||
/* ===== Event Handlers ===== */
|
||||
/**
|
||||
* The event handler for button press events.
|
||||
* @remarks This can be overriden by the derrived classes, but
|
||||
* Tool::on_button_press_event must be called <b>at the start</b>
|
||||
* of the derrived class's override.
|
||||
*/
|
||||
virtual void on_button_press_event(GdkEventButton* event);
|
||||
|
||||
/**
|
||||
* The event handler for button release events.
|
||||
* @remarks This can be overriden by the derrived classes, but
|
||||
* Tool::on_button_release_event must be called <b>at the end</b> of
|
||||
* the derrived class's override.
|
||||
*/
|
||||
virtual void on_button_release_event(GdkEventButton* event);
|
||||
virtual void on_motion_notify_event(GdkEventMotion *event) {}
|
||||
|
||||
/**
|
||||
* The event handler for mouse move events.
|
||||
* @remarks This can be overriden by the derrived classes, but
|
||||
* Tool::on_motion_notify_event must be called <b>at the start</b> of
|
||||
* the derrived class's override.
|
||||
*/
|
||||
virtual void on_motion_notify_event(GdkEventMotion *event);
|
||||
|
||||
protected:
|
||||
/* ===== Internal Overrides ===== */
|
||||
|
|
@ -103,11 +128,11 @@ protected:
|
|||
|
||||
protected:
|
||||
bool isDragging;
|
||||
Gdk::Point mousePoint;
|
||||
|
||||
TimelineBody *timelineBody;
|
||||
};
|
||||
|
||||
|
||||
} // namespace timeline
|
||||
} // namespace widgets
|
||||
} // namespace gui
|
||||
|
|
|
|||
Loading…
Reference in a new issue