Added resizing of selection area, and some documentation

This commit is contained in:
Joel Holdsworth 2008-08-16 16:02:12 +01:00
parent 39bd8aac74
commit 57aed7b40d
6 changed files with 264 additions and 27 deletions

View file

@ -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 ===== */

View file

@ -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);
};

View file

@ -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

View file

@ -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;
};

View file

@ -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
{

View file

@ -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