Initial implementation of I-Beam tool. Needs more work
This commit is contained in:
parent
45ca590c38
commit
2082f0843b
12 changed files with 428 additions and 133 deletions
|
|
@ -21,8 +21,6 @@
|
|||
* *****************************************************/
|
||||
|
||||
#include "timeline-widget.hpp"
|
||||
#include "timeline/timeline-arrow-tool.hpp"
|
||||
#include "timeline/timeline-ibeam-tool.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
|
|
@ -46,14 +44,17 @@ TimelineWidget::TimelineWidget() :
|
|||
totalHeight(0),
|
||||
horizontalAdjustment(0, 0, 0),
|
||||
verticalAdjustment(0, 0, 0),
|
||||
selectionStart(0),
|
||||
selectionEnd(0),
|
||||
horizontalScroll(horizontalAdjustment),
|
||||
verticalScroll(verticalAdjustment),
|
||||
tool(NULL)
|
||||
verticalScroll(verticalAdjustment)
|
||||
{
|
||||
body = new TimelineBody(this);
|
||||
ENSURE(body != NULL);
|
||||
headerContainer = new HeaderContainer(this);
|
||||
ENSURE(headerContainer != NULL);
|
||||
ruler = new TimelineRuler(this);
|
||||
ENSURE(ruler != NULL);
|
||||
|
||||
horizontalAdjustment.signal_value_changed().connect( sigc::mem_fun(
|
||||
this, &TimelineWidget::on_scroll) );
|
||||
|
|
@ -63,9 +64,10 @@ TimelineWidget::TimelineWidget() :
|
|||
this, &TimelineWidget::on_motion_in_body_notify_event) );
|
||||
|
||||
set_time_scale(GAVL_TIME_SCALE / 200);
|
||||
set_selection(2000000, 4000000);
|
||||
|
||||
attach(*body, 1, 2, 1, 2, FILL|EXPAND, FILL|EXPAND);
|
||||
attach(ruler, 1, 2, 0, 1, FILL|EXPAND, SHRINK);
|
||||
attach(*ruler, 1, 2, 0, 1, FILL|EXPAND, SHRINK);
|
||||
attach(*headerContainer, 0, 1, 1, 2, SHRINK, FILL|EXPAND);
|
||||
attach(horizontalScroll, 1, 2, 2, 3, FILL|EXPAND, SHRINK);
|
||||
attach(verticalScroll, 2, 3, 1, 2, SHRINK, FILL|EXPAND);
|
||||
|
|
@ -87,10 +89,10 @@ TimelineWidget::~TimelineWidget()
|
|||
REQUIRE(headerContainer != NULL);
|
||||
if(headerContainer != NULL)
|
||||
headerContainer->unreference();
|
||||
|
||||
REQUIRE(tool != NULL);
|
||||
if(tool != NULL)
|
||||
delete tool;
|
||||
|
||||
REQUIRE(ruler != NULL);
|
||||
if(ruler != NULL)
|
||||
ruler->unreference();
|
||||
}
|
||||
|
||||
gavl_time_t
|
||||
|
|
@ -102,9 +104,11 @@ TimelineWidget::get_time_offset() const
|
|||
void
|
||||
TimelineWidget::set_time_offset(gavl_time_t time_offset)
|
||||
{
|
||||
REQUIRE(ruler != NULL);
|
||||
|
||||
timeOffset = time_offset;
|
||||
horizontalAdjustment.set_value(time_offset);
|
||||
ruler.set_time_offset(time_offset);
|
||||
ruler->update_view();
|
||||
}
|
||||
|
||||
int64_t
|
||||
|
|
@ -116,11 +120,14 @@ TimelineWidget::get_time_scale() const
|
|||
void
|
||||
TimelineWidget::set_time_scale(int64_t time_scale)
|
||||
{
|
||||
REQUIRE(ruler != NULL);
|
||||
|
||||
timeScale = time_scale;
|
||||
ruler.set_time_scale(time_scale);
|
||||
|
||||
const int view_width = body->get_allocation().get_width();
|
||||
horizontalAdjustment.set_page_size(timeScale * view_width);
|
||||
|
||||
ruler->update_view();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -163,49 +170,56 @@ TimelineWidget::shift_view(int shift_size)
|
|||
shift_size * timeScale * view_width / 16);
|
||||
}
|
||||
|
||||
gavl_time_t
|
||||
TimelineWidget::get_selection_start() const
|
||||
{
|
||||
return selectionStart;
|
||||
}
|
||||
|
||||
gavl_time_t
|
||||
TimelineWidget::get_selection_end() const
|
||||
{
|
||||
return selectionEnd;
|
||||
}
|
||||
|
||||
void
|
||||
TimelineWidget::set_selection(gavl_time_t start, gavl_time_t end)
|
||||
{
|
||||
if(start < end)
|
||||
{
|
||||
selectionStart = start;
|
||||
selectionEnd = end;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The selection is back-to-front, flip it round
|
||||
selectionStart = end;
|
||||
selectionEnd = start;
|
||||
}
|
||||
|
||||
ruler->queue_draw();
|
||||
body->queue_draw();
|
||||
}
|
||||
|
||||
ToolType
|
||||
TimelineWidget::get_tool() const
|
||||
{
|
||||
REQUIRE(tool != NULL);
|
||||
if(tool != NULL)
|
||||
return tool->get_type();
|
||||
return None;
|
||||
REQUIRE(body != NULL);
|
||||
return body->get_tool();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineWidget::set_tool(ToolType tool_type)
|
||||
{
|
||||
// Tidy up old tool
|
||||
if(tool != NULL)
|
||||
{
|
||||
// Do we need to change tools?
|
||||
if(tool->get_type() == tool_type)
|
||||
return;
|
||||
|
||||
delete tool;
|
||||
}
|
||||
|
||||
// Create the new tool
|
||||
switch(tool_type)
|
||||
{
|
||||
case timeline::Arrow:
|
||||
tool = new timeline::ArrowTool(this);
|
||||
break;
|
||||
|
||||
case timeline::IBeam:
|
||||
tool = new timeline::IBeamTool(this);
|
||||
break;
|
||||
}
|
||||
|
||||
// Apply the cursor if possible
|
||||
tool->apply_cursor();
|
||||
REQUIRE(body != NULL);
|
||||
body->set_tool(tool_type);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineWidget::on_scroll()
|
||||
{
|
||||
timeOffset = horizontalAdjustment.get_value();
|
||||
ruler.set_time_offset(timeOffset);
|
||||
ruler->update_view();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -216,6 +230,18 @@ TimelineWidget::on_size_allocate(Allocation& allocation)
|
|||
update_scroll();
|
||||
}
|
||||
|
||||
int
|
||||
TimelineWidget::time_to_x(gavl_time_t time) const
|
||||
{
|
||||
return (int)((time - timeOffset) / timeScale);
|
||||
}
|
||||
|
||||
gavl_time_t
|
||||
TimelineWidget::x_to_time(int x) const
|
||||
{
|
||||
return (gavl_time_t)((int64_t)x * timeScale + timeOffset);
|
||||
}
|
||||
|
||||
void
|
||||
TimelineWidget::update_tracks()
|
||||
{
|
||||
|
|
@ -282,7 +308,7 @@ bool
|
|||
TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event)
|
||||
{
|
||||
REQUIRE(event != NULL);
|
||||
ruler.set_mouse_chevron_offset(event->x);
|
||||
ruler->set_mouse_chevron_offset(event->x);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#include "timeline/timeline-body.hpp"
|
||||
#include "timeline/timeline-ruler.hpp"
|
||||
#include "timeline/timeline-tool.hpp"
|
||||
#include "timeline/timeline-arrow-tool.hpp"
|
||||
#include "timeline/timeline-ibeam-tool.hpp"
|
||||
#include "timeline/track.hpp"
|
||||
|
||||
namespace lumiera {
|
||||
|
|
@ -96,18 +98,30 @@ public:
|
|||
**/
|
||||
void shift_view(int shift_size);
|
||||
|
||||
gavl_time_t get_selection_start() const;
|
||||
|
||||
gavl_time_t get_selection_end() const;
|
||||
|
||||
void set_selection(gavl_time_t start, gavl_time_t end);
|
||||
|
||||
timeline::ToolType get_tool() const;
|
||||
|
||||
void set_tool(timeline::ToolType tool_type);
|
||||
|
||||
|
||||
/* ===== Events ===== */
|
||||
protected:
|
||||
void on_scroll();
|
||||
|
||||
void on_size_allocate(Gtk::Allocation& allocation);
|
||||
|
||||
/* ===== Utilities ===== */
|
||||
protected:
|
||||
int time_to_x(gavl_time_t time) const;
|
||||
|
||||
gavl_time_t x_to_time(int x) const;
|
||||
|
||||
/* ===== Internals ===== */
|
||||
protected:
|
||||
private:
|
||||
|
||||
void update_tracks();
|
||||
|
||||
|
|
@ -118,8 +132,14 @@ protected:
|
|||
bool on_motion_in_body_notify_event(GdkEventMotion *event);
|
||||
|
||||
protected:
|
||||
|
||||
// View State
|
||||
gavl_time_t timeOffset;
|
||||
int64_t timeScale;
|
||||
|
||||
// Selection State
|
||||
gavl_time_t selectionStart;
|
||||
gavl_time_t selectionEnd;
|
||||
|
||||
int totalHeight;
|
||||
|
||||
|
|
@ -129,13 +149,11 @@ protected:
|
|||
|
||||
timeline::HeaderContainer *headerContainer;
|
||||
timeline::TimelineBody *body;
|
||||
timeline::TimelineRuler ruler;
|
||||
timeline::TimelineRuler *ruler;
|
||||
|
||||
Gtk::Adjustment horizontalAdjustment, verticalAdjustment;
|
||||
Gtk::HScrollbar horizontalScroll;
|
||||
Gtk::VScrollbar verticalScroll;
|
||||
|
||||
timeline::Tool *tool;
|
||||
|
||||
/* ===== Constants ===== */
|
||||
public:
|
||||
|
|
@ -148,7 +166,10 @@ protected:
|
|||
|
||||
friend class timeline::TimelineBody;
|
||||
friend class timeline::HeaderContainer;
|
||||
friend class timeline::TimelineRuler;
|
||||
friend class timeline::Tool;
|
||||
friend class timeline::ArrowTool;
|
||||
friend class timeline::IBeamTool;
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ namespace gui {
|
|||
namespace widgets {
|
||||
namespace timeline {
|
||||
|
||||
ArrowTool::ArrowTool(TimelineWidget *timeline_widget) :
|
||||
Tool(timeline_widget)
|
||||
ArrowTool::ArrowTool(TimelineBody *timeline_body) :
|
||||
Tool(timeline_body)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -45,6 +45,24 @@ ArrowTool::get_cursor() const
|
|||
return Gdk::Cursor(Gdk::ARROW);
|
||||
}
|
||||
|
||||
void
|
||||
ArrowTool::on_button_press_event(GdkEventButton* event)
|
||||
{
|
||||
Tool::on_button_press_event(event);
|
||||
}
|
||||
|
||||
void
|
||||
ArrowTool::on_button_release_event(GdkEventButton* event)
|
||||
{
|
||||
Tool::on_button_release_event(event);
|
||||
}
|
||||
|
||||
void
|
||||
ArrowTool::on_motion_notify_event(GdkEventMotion *event)
|
||||
{
|
||||
Tool::on_motion_notify_event(event);
|
||||
}
|
||||
|
||||
} // namespace timeline
|
||||
} // namespace widgets
|
||||
} // namespace gui
|
||||
|
|
|
|||
|
|
@ -37,12 +37,17 @@ namespace timeline {
|
|||
class ArrowTool : public Tool
|
||||
{
|
||||
public:
|
||||
ArrowTool(TimelineWidget *timeline_widget);
|
||||
ArrowTool(TimelineBody *timeline_body);
|
||||
|
||||
ToolType get_type() const;
|
||||
|
||||
protected:
|
||||
Gdk::Cursor get_cursor() const;
|
||||
|
||||
protected:
|
||||
void on_button_press_event(GdkEventButton* event);
|
||||
void on_button_release_event(GdkEventButton* event);
|
||||
void on_motion_notify_event(GdkEventMotion *event);
|
||||
};
|
||||
|
||||
} // namespace timeline
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
#include "../timeline-widget.hpp"
|
||||
#include "../../window-manager.hpp"
|
||||
|
||||
#include "timeline-arrow-tool.hpp"
|
||||
#include "timeline-ibeam-tool.hpp"
|
||||
|
||||
using namespace Gtk;
|
||||
using namespace std;
|
||||
using namespace lumiera::gui;
|
||||
|
|
@ -38,8 +41,10 @@ namespace gui {
|
|||
namespace widgets {
|
||||
namespace timeline {
|
||||
|
||||
TimelineBody::TimelineBody(lumiera::gui::widgets::TimelineWidget *timeline_widget) :
|
||||
TimelineBody::TimelineBody(lumiera::gui::widgets::TimelineWidget
|
||||
*timeline_widget) :
|
||||
Glib::ObjectBase("TimelineBody"),
|
||||
tool(NULL),
|
||||
dragType(None),
|
||||
mouseDownX(0),
|
||||
mouseDownY(0),
|
||||
|
|
@ -63,6 +68,51 @@ TimelineBody::TimelineBody(lumiera::gui::widgets::TimelineWidget *timeline_widge
|
|||
GDK_TYPE_COLOR, G_PARAM_READABLE));
|
||||
}
|
||||
|
||||
TimelineBody::~TimelineBody()
|
||||
{
|
||||
REQUIRE(tool != NULL);
|
||||
if(tool != NULL)
|
||||
delete tool;
|
||||
}
|
||||
|
||||
ToolType
|
||||
TimelineBody::get_tool() const
|
||||
{
|
||||
REQUIRE(tool != NULL);
|
||||
if(tool != NULL)
|
||||
return tool->get_type();
|
||||
return lumiera::gui::widgets::timeline::None;
|
||||
}
|
||||
|
||||
void
|
||||
TimelineBody::set_tool(timeline::ToolType tool_type)
|
||||
{
|
||||
// Tidy up old tool
|
||||
if(tool != NULL)
|
||||
{
|
||||
// Do we need to change tools?
|
||||
if(tool->get_type() == tool_type)
|
||||
return;
|
||||
|
||||
delete tool;
|
||||
}
|
||||
|
||||
// Create the new tool
|
||||
switch(tool_type)
|
||||
{
|
||||
case timeline::Arrow:
|
||||
tool = new ArrowTool(this);
|
||||
break;
|
||||
|
||||
case timeline::IBeam:
|
||||
tool = new IBeamTool(this);
|
||||
break;
|
||||
}
|
||||
|
||||
// Apply the cursor if possible
|
||||
tool->apply_cursor();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineBody::on_realize()
|
||||
{
|
||||
|
|
@ -76,7 +126,7 @@ TimelineBody::on_realize()
|
|||
Gdk::BUTTON_RELEASE_MASK);
|
||||
|
||||
// Apply the cursor if possible
|
||||
timelineWidget->tool->apply_cursor();
|
||||
tool->apply_cursor();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -138,7 +188,12 @@ TimelineBody::on_button_press_event(GdkEventButton* event)
|
|||
default:
|
||||
dragType = None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Forward the event to the tool
|
||||
tool->on_button_press_event(event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -146,11 +201,16 @@ TimelineBody::on_button_release_event(GdkEventButton* event)
|
|||
{
|
||||
// Terminate any drags
|
||||
dragType = None;
|
||||
|
||||
// Forward the event to the tool
|
||||
tool->on_button_release_event(event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TimelineBody::on_motion_notify_event(GdkEventMotion *event)
|
||||
{
|
||||
{
|
||||
REQUIRE(event != NULL);
|
||||
|
||||
switch(dragType)
|
||||
|
|
@ -168,6 +228,9 @@ TimelineBody::on_motion_notify_event(GdkEventMotion *event)
|
|||
}
|
||||
}
|
||||
|
||||
// Forward the event to the tool
|
||||
tool->on_motion_notify_event(event);
|
||||
|
||||
// false so that the message is passed up to the owner TimelineWidget
|
||||
return false;
|
||||
}
|
||||
|
|
@ -175,6 +238,8 @@ TimelineBody::on_motion_notify_event(GdkEventMotion *event)
|
|||
bool
|
||||
TimelineBody::on_expose_event(GdkEventExpose* event)
|
||||
{
|
||||
Cairo::Matrix view_matrix;
|
||||
|
||||
REQUIRE(event != NULL);
|
||||
REQUIRE(timelineWidget != NULL);
|
||||
|
||||
|
|
@ -196,6 +261,7 @@ TimelineBody::on_expose_event(GdkEventExpose* event)
|
|||
|
||||
// Translate the view by the scroll distance
|
||||
cairo->translate(0, -get_vertical_offset());
|
||||
cairo->get_matrix(view_matrix);
|
||||
|
||||
// Interate drawing each track
|
||||
BOOST_FOREACH( Track* track, timelineWidget->tracks )
|
||||
|
|
@ -217,8 +283,44 @@ TimelineBody::on_expose_event(GdkEventExpose* event)
|
|||
|
||||
// Shift for the next track
|
||||
cairo->translate(0, height + TimelineWidget::TrackPadding);
|
||||
}
|
||||
}
|
||||
|
||||
//----- Draw the selection -----//
|
||||
const int start_x = timelineWidget->time_to_x(
|
||||
timelineWidget->get_selection_start());
|
||||
const int end_x = timelineWidget->time_to_x(
|
||||
timelineWidget->get_selection_end());
|
||||
|
||||
cairo->set_matrix(view_matrix);
|
||||
|
||||
// Draw the cover
|
||||
if(end_x > 0 && start_x < allocation.get_width())
|
||||
{
|
||||
cairo->set_source_rgba(1.0, 0, 0, 0.5);
|
||||
cairo->rectangle(start_x + 0.5, 0,
|
||||
end_x - start_x, allocation.get_height());
|
||||
cairo->fill();
|
||||
}
|
||||
|
||||
cairo->set_source_rgb(1.0, 0, 0);
|
||||
cairo->set_line_width(1);
|
||||
|
||||
// Draw the start
|
||||
if(start_x >= 0 && start_x < allocation.get_width())
|
||||
{
|
||||
cairo->move_to(start_x + 0.5, 0);
|
||||
cairo->line_to(start_x + 0.5, allocation.get_height());
|
||||
cairo->stroke_preserve();
|
||||
}
|
||||
|
||||
// Draw the end
|
||||
if(end_x >= 0 && end_x < allocation.get_width())
|
||||
{
|
||||
cairo->move_to(end_x + 0.5, 0);
|
||||
cairo->line_to(end_x + 0.5, allocation.get_height());
|
||||
cairo->stroke_preserve();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#define TIMELINE_BODY_HPP
|
||||
|
||||
#include "../../gtk-lumiera.hpp"
|
||||
#include "timeline-tool.hpp"
|
||||
|
||||
namespace lumiera {
|
||||
namespace gui {
|
||||
|
|
@ -40,6 +41,12 @@ class TimelineBody : public Gtk::DrawingArea
|
|||
{
|
||||
public:
|
||||
TimelineBody(lumiera::gui::widgets::TimelineWidget *timeline_widget);
|
||||
|
||||
~TimelineBody();
|
||||
|
||||
ToolType get_tool() const;
|
||||
|
||||
void set_tool(ToolType tool_type);
|
||||
|
||||
/* ===== Events ===== */
|
||||
protected:
|
||||
|
|
@ -76,15 +83,20 @@ private:
|
|||
Shift
|
||||
};
|
||||
|
||||
// UI State Data
|
||||
DragType dragType;
|
||||
timeline::Tool *tool;
|
||||
double mouseDownX, mouseDownY;
|
||||
|
||||
// Scroll State
|
||||
DragType dragType;
|
||||
gavl_time_t beginShiftTimeOffset;
|
||||
int beginShiftVerticalOffset;
|
||||
int beginShiftVerticalOffset;
|
||||
|
||||
GdkColor background;
|
||||
|
||||
lumiera::gui::widgets::TimelineWidget *timelineWidget;
|
||||
|
||||
friend class ArrowTool;
|
||||
friend class IBeamTool;
|
||||
};
|
||||
|
||||
} // namespace timeline
|
||||
|
|
|
|||
|
|
@ -21,14 +21,15 @@
|
|||
* *****************************************************/
|
||||
|
||||
#include "timeline-ibeam-tool.hpp"
|
||||
#include "../timeline-widget.hpp"
|
||||
|
||||
namespace lumiera {
|
||||
namespace gui {
|
||||
namespace widgets {
|
||||
namespace timeline {
|
||||
|
||||
IBeamTool::IBeamTool(TimelineWidget *timeline_widget) :
|
||||
Tool(timeline_widget)
|
||||
IBeamTool::IBeamTool(TimelineBody *timeline_body) :
|
||||
Tool(timeline_body)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -44,6 +45,55 @@ IBeamTool::get_cursor() const
|
|||
return Gdk::Cursor(Gdk::XTERM);
|
||||
}
|
||||
|
||||
void
|
||||
IBeamTool::on_button_press_event(GdkEventButton* event)
|
||||
{
|
||||
Tool::on_button_press_event(event);
|
||||
|
||||
REQUIRE(timelineBody != NULL);
|
||||
lumiera::gui::widgets::TimelineWidget *timeline_widget =
|
||||
timelineBody->timelineWidget;
|
||||
REQUIRE(timeline_widget != NULL);
|
||||
|
||||
if(event->button == 1)
|
||||
{
|
||||
drag_start_time = timeline_widget->x_to_time(event->x);
|
||||
timeline_widget->set_selection(drag_start_time, drag_start_time);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IBeamTool::on_button_release_event(GdkEventButton* event)
|
||||
{
|
||||
Tool::on_button_release_event(event);
|
||||
|
||||
if(event->button == 1)
|
||||
set_leading_x(event->x);
|
||||
}
|
||||
|
||||
void
|
||||
IBeamTool::on_motion_notify_event(GdkEventMotion *event)
|
||||
{
|
||||
Tool::on_motion_notify_event(event);
|
||||
|
||||
if(isDragging)
|
||||
set_leading_x(event->x);
|
||||
}
|
||||
|
||||
void IBeamTool::set_leading_x(const int x)
|
||||
{
|
||||
REQUIRE(timelineBody != NULL);
|
||||
lumiera::gui::widgets::TimelineWidget *timeline_widget =
|
||||
timelineBody->timelineWidget;
|
||||
REQUIRE(timeline_widget != NULL);
|
||||
|
||||
const gavl_time_t time = timeline_widget->x_to_time(x);
|
||||
if(time > drag_start_time)
|
||||
timeline_widget->set_selection(drag_start_time, time);
|
||||
else
|
||||
timeline_widget->set_selection(time, drag_start_time);
|
||||
}
|
||||
|
||||
} // namespace timeline
|
||||
} // namespace widgets
|
||||
} // namespace gui
|
||||
|
|
|
|||
|
|
@ -38,12 +38,24 @@ namespace timeline {
|
|||
class IBeamTool : public Tool
|
||||
{
|
||||
public:
|
||||
IBeamTool(TimelineWidget *timeline_widget);
|
||||
IBeamTool(TimelineBody *timeline_body);
|
||||
|
||||
ToolType get_type() const;
|
||||
|
||||
protected:
|
||||
Gdk::Cursor get_cursor() const;
|
||||
|
||||
protected:
|
||||
void on_button_press_event(GdkEventButton* event);
|
||||
void on_button_release_event(GdkEventButton* event);
|
||||
void on_motion_notify_event(GdkEventMotion *event);
|
||||
|
||||
private:
|
||||
void set_leading_x(const int x);
|
||||
|
||||
protected:
|
||||
//----- Internals -----//
|
||||
gavl_time_t drag_start_time;
|
||||
};
|
||||
|
||||
} // namespace timeline
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <cairomm-1.0/cairomm/cairomm.h>
|
||||
|
||||
#include "timeline-ruler.hpp"
|
||||
#include "../timeline-widget.hpp"
|
||||
#include "../../window-manager.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
|
@ -41,39 +42,24 @@ namespace gui {
|
|||
namespace widgets {
|
||||
namespace timeline {
|
||||
|
||||
TimelineRuler::TimelineRuler() :
|
||||
TimelineRuler::TimelineRuler(
|
||||
lumiera::gui::widgets::TimelineWidget *timeline_widget) :
|
||||
Glib::ObjectBase("TimelineRuler"),
|
||||
timeOffset(-1),
|
||||
timeScale(1),
|
||||
mouseChevronOffset(0),
|
||||
annotationHorzMargin(0),
|
||||
annotationVertMargin(0),
|
||||
majorTickHeight(0),
|
||||
minorLongTickHeight(0),
|
||||
minorShortTickHeight(0),
|
||||
minDivisionWidth(100)
|
||||
{
|
||||
minDivisionWidth(100),
|
||||
timelineWidget(timeline_widget)
|
||||
{
|
||||
REQUIRE(timelineWidget != NULL);
|
||||
|
||||
// Install style properties
|
||||
register_styles();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineRuler::set_time_offset(gavl_time_t time_offset)
|
||||
{
|
||||
timeOffset = time_offset;
|
||||
rulerImage.clear();
|
||||
queue_draw();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineRuler::set_time_scale(int64_t time_scale)
|
||||
{
|
||||
REQUIRE(time_scale > 0);
|
||||
timeScale = time_scale;
|
||||
rulerImage.clear();
|
||||
queue_draw();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineRuler::set_mouse_chevron_offset(int offset)
|
||||
{
|
||||
|
|
@ -81,6 +67,13 @@ TimelineRuler::set_mouse_chevron_offset(int offset)
|
|||
queue_draw();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineRuler::update_view()
|
||||
{
|
||||
rulerImage.clear();
|
||||
queue_draw();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineRuler::on_realize()
|
||||
{
|
||||
|
|
@ -132,8 +125,9 @@ TimelineRuler::on_expose_event(GdkEventExpose* event)
|
|||
cairo->set_source(rulerImage, 0, 0);
|
||||
cairo->paint();
|
||||
|
||||
// Draw the mouse chevron
|
||||
// Draw the overlays
|
||||
draw_mouse_chevron(cairo, allocation);
|
||||
draw_selection(cairo, allocation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -168,11 +162,15 @@ TimelineRuler::on_size_allocate(Gtk::Allocation& allocation)
|
|||
|
||||
void
|
||||
TimelineRuler::draw_ruler(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
Gdk::Rectangle ruler_rect)
|
||||
const Gdk::Rectangle ruler_rect)
|
||||
{
|
||||
REQUIRE(cairo);
|
||||
REQUIRE(ruler_rect.get_width() > 0);
|
||||
REQUIRE(ruler_rect.get_height() > 0);
|
||||
REQUIRE(timelineWidget != NULL);
|
||||
|
||||
const gavl_time_t left_offset = timelineWidget->timeOffset;
|
||||
const int64_t time_scale = timelineWidget->timeScale;
|
||||
|
||||
// Preparation steps
|
||||
const int height = ruler_rect.get_height();
|
||||
|
|
@ -187,7 +185,7 @@ TimelineRuler::draw_ruler(Cairo::RefPtr<Cairo::Context> cairo,
|
|||
cairo->clip();
|
||||
|
||||
// Make sure we don't have impossible zoom
|
||||
if(timeScale <= 0)
|
||||
if(time_scale <= 0)
|
||||
return;
|
||||
|
||||
// Render ruler annotations
|
||||
|
|
@ -196,16 +194,16 @@ TimelineRuler::draw_ruler(Cairo::RefPtr<Cairo::Context> cairo,
|
|||
const gavl_time_t major_spacing = calculate_major_spacing();
|
||||
const gavl_time_t minor_spacing = major_spacing / 10;
|
||||
|
||||
int64_t time_offset = timeOffset - timeOffset % major_spacing;
|
||||
if(timeOffset < 0)
|
||||
int64_t time_offset = left_offset - left_offset % major_spacing;
|
||||
if(left_offset < 0)
|
||||
time_offset -= major_spacing;
|
||||
|
||||
int x = 0;
|
||||
const int64_t x_offset = timeOffset / timeScale;
|
||||
const int64_t x_offset = left_offset / time_scale;
|
||||
|
||||
do
|
||||
{
|
||||
x = (int)(time_offset / timeScale - x_offset);
|
||||
x = (int)(time_offset / time_scale - x_offset);
|
||||
|
||||
cairo->set_line_width(1);
|
||||
|
||||
|
|
@ -241,7 +239,7 @@ TimelineRuler::draw_ruler(Cairo::RefPtr<Cairo::Context> cairo,
|
|||
|
||||
void
|
||||
TimelineRuler::draw_mouse_chevron(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
Gdk::Rectangle ruler_rect)
|
||||
const Gdk::Rectangle ruler_rect)
|
||||
{
|
||||
REQUIRE(cairo);
|
||||
REQUIRE(ruler_rect.get_width() > 0);
|
||||
|
|
@ -258,19 +256,55 @@ TimelineRuler::draw_mouse_chevron(Cairo::RefPtr<Cairo::Context> cairo,
|
|||
|
||||
cairo->move_to(mouseChevronOffset + 0.5,
|
||||
ruler_rect.get_height());
|
||||
cairo->line_to(mouseChevronOffset + mouseChevronSize + 0.5,
|
||||
ruler_rect.get_height() - mouseChevronSize);
|
||||
cairo->line_to(mouseChevronOffset - mouseChevronSize + 0.5,
|
||||
ruler_rect.get_height() - mouseChevronSize);
|
||||
cairo->rel_line_to(-mouseChevronSize, -mouseChevronSize);
|
||||
cairo->rel_line_to(2 * mouseChevronSize, 0);
|
||||
|
||||
cairo->fill();
|
||||
}
|
||||
|
||||
void
|
||||
TimelineRuler::draw_selection(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
const Gdk::Rectangle ruler_rect)
|
||||
{
|
||||
REQUIRE(cairo);
|
||||
REQUIRE(ruler_rect.get_width() > 0);
|
||||
REQUIRE(ruler_rect.get_height() > 0);
|
||||
REQUIRE(timelineWidget != NULL);
|
||||
|
||||
Glib::RefPtr<Style> style = get_style();
|
||||
Gdk::Cairo::set_source_color(cairo, style->get_fg(STATE_NORMAL));
|
||||
|
||||
// Draw the selection start chevron
|
||||
const int a = timelineWidget->time_to_x(
|
||||
timelineWidget->selectionStart) + 1;
|
||||
if(a >= 0 && a < ruler_rect.get_width())
|
||||
{
|
||||
cairo->move_to(a, ruler_rect.get_height());
|
||||
cairo->rel_line_to(0, -mouseChevronSize);
|
||||
cairo->rel_line_to(-mouseChevronSize, 0);
|
||||
cairo->fill();
|
||||
}
|
||||
|
||||
// Draw the selection end chevron
|
||||
const int b = timelineWidget->time_to_x(
|
||||
timelineWidget->selectionEnd);
|
||||
if(b >= 0 && b < ruler_rect.get_width())
|
||||
{
|
||||
cairo->move_to(b, ruler_rect.get_height());
|
||||
cairo->rel_line_to(0, -mouseChevronSize);
|
||||
cairo->rel_line_to(mouseChevronSize, 0);
|
||||
cairo->fill();
|
||||
}
|
||||
}
|
||||
|
||||
gavl_time_t
|
||||
TimelineRuler::calculate_major_spacing() const
|
||||
{
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
REQUIRE(timelineWidget != NULL);
|
||||
|
||||
const int64_t time_scale = timelineWidget->timeScale;
|
||||
const gavl_time_t major_spacings[] = {
|
||||
GAVL_TIME_SCALE / 1000,
|
||||
GAVL_TIME_SCALE / 400,
|
||||
|
|
@ -298,7 +332,7 @@ TimelineRuler::calculate_major_spacing() const
|
|||
|
||||
for(i = 0; i < sizeof(major_spacings) / sizeof(gavl_time_t); i++)
|
||||
{
|
||||
const int64_t division_width = major_spacings[i] / timeScale;
|
||||
const int64_t division_width = major_spacings[i] / time_scale;
|
||||
|
||||
if(division_width > minDivisionWidth)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -32,26 +32,16 @@
|
|||
namespace lumiera {
|
||||
namespace gui {
|
||||
namespace widgets {
|
||||
|
||||
class TimelineWidget;
|
||||
|
||||
namespace timeline {
|
||||
|
||||
class TimelineRuler : public Gtk::DrawingArea
|
||||
{
|
||||
public:
|
||||
TimelineRuler();
|
||||
|
||||
/**
|
||||
* Sets the time offset. This is the time value displaid at the
|
||||
* left-hand edge of the ruler.
|
||||
*/
|
||||
void set_time_offset(gavl_time_t time_offset);
|
||||
|
||||
/**
|
||||
* Sets the time scale value.
|
||||
* @param time_scale The scale factor, which is the number of
|
||||
* microseconds per screen pixel. This value must be greater than
|
||||
* zero.
|
||||
*/
|
||||
void set_time_scale(int64_t time_scale);
|
||||
TimelineRuler(
|
||||
lumiera::gui::widgets::TimelineWidget *timeline_widget);
|
||||
|
||||
/**
|
||||
* Sets the offset of the mouse chevron in pixels from the left
|
||||
|
|
@ -59,6 +49,8 @@ public:
|
|||
* width, the chevron will not be visible.
|
||||
*/
|
||||
void set_mouse_chevron_offset(int offset);
|
||||
|
||||
void update_view();
|
||||
|
||||
/* ===== Events ===== */
|
||||
protected:
|
||||
|
|
@ -76,10 +68,13 @@ protected:
|
|||
/* ===== Internals ===== */
|
||||
private:
|
||||
void draw_ruler(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
Gdk::Rectangle ruler_rect);
|
||||
const Gdk::Rectangle ruler_rect);
|
||||
|
||||
void draw_mouse_chevron(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
Gdk::Rectangle ruler_rect);
|
||||
const Gdk::Rectangle ruler_rect);
|
||||
|
||||
void draw_selection(Cairo::RefPtr<Cairo::Context> cairo,
|
||||
const Gdk::Rectangle ruler_rect);
|
||||
|
||||
gavl_time_t calculate_major_spacing() const;
|
||||
|
||||
|
|
@ -88,9 +83,6 @@ private:
|
|||
void read_styles();
|
||||
|
||||
private:
|
||||
// View values
|
||||
gavl_time_t timeOffset;
|
||||
int64_t timeScale;
|
||||
|
||||
// Indicated values
|
||||
int mouseChevronOffset;
|
||||
|
|
@ -104,6 +96,9 @@ private:
|
|||
int minDivisionWidth;
|
||||
int mouseChevronSize;
|
||||
|
||||
// Owner
|
||||
lumiera::gui::widgets::TimelineWidget *timelineWidget;
|
||||
|
||||
// Cached ruler image
|
||||
Cairo::RefPtr<Cairo::ImageSurface> rulerImage;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -28,23 +28,20 @@ namespace gui {
|
|||
namespace widgets {
|
||||
namespace timeline {
|
||||
|
||||
Tool::Tool(TimelineWidget *timeline_widget) :
|
||||
timelineWidget(timeline_widget)
|
||||
Tool::Tool(TimelineBody *timeline_body) :
|
||||
timelineBody(timeline_body),
|
||||
isDragging(false)
|
||||
{
|
||||
REQUIRE(timeline_widget != NULL);
|
||||
REQUIRE(timeline_widget->body != NULL);
|
||||
REQUIRE(timeline_body != NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
Tool::apply_cursor()
|
||||
{
|
||||
REQUIRE(timelineWidget != NULL);
|
||||
|
||||
if(timelineWidget->body == NULL)
|
||||
return false;
|
||||
|
||||
REQUIRE(timelineBody != NULL);
|
||||
|
||||
Glib::RefPtr<Gdk::Window> window =
|
||||
timelineWidget->body->get_window();
|
||||
timelineBody->get_window();
|
||||
if(!window)
|
||||
return false;
|
||||
|
||||
|
|
@ -53,6 +50,24 @@ Tool::apply_cursor()
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Tool::on_button_press_event(GdkEventButton* event)
|
||||
{
|
||||
REQUIRE(event != NULL);
|
||||
|
||||
if(event->button == 1)
|
||||
isDragging = true;
|
||||
}
|
||||
|
||||
void
|
||||
Tool::on_button_release_event(GdkEventButton* event)
|
||||
{
|
||||
REQUIRE(event != NULL);
|
||||
|
||||
if(event->button == 1)
|
||||
isDragging = false;
|
||||
}
|
||||
|
||||
} // namespace timeline
|
||||
} // namespace widgets
|
||||
} // namespace gui
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@
|
|||
namespace lumiera {
|
||||
namespace gui {
|
||||
namespace widgets {
|
||||
|
||||
class TimelineWidget;
|
||||
|
||||
namespace timeline {
|
||||
|
||||
class TimelineBody;
|
||||
|
||||
enum ToolType
|
||||
{
|
||||
None,
|
||||
|
|
@ -47,18 +46,24 @@ enum ToolType
|
|||
class Tool
|
||||
{
|
||||
protected:
|
||||
Tool(TimelineWidget *timeline_widget);
|
||||
Tool(TimelineBody *timeline_body);
|
||||
|
||||
public:
|
||||
virtual ToolType get_type() const = 0;
|
||||
|
||||
bool apply_cursor();
|
||||
|
||||
protected:
|
||||
virtual Gdk::Cursor get_cursor() const = 0;
|
||||
virtual void on_button_press_event(GdkEventButton* event);
|
||||
virtual void on_button_release_event(GdkEventButton* event);
|
||||
virtual void on_motion_notify_event(GdkEventMotion *event) {}
|
||||
|
||||
protected:
|
||||
TimelineWidget *timelineWidget;
|
||||
virtual Gdk::Cursor get_cursor() const = 0;
|
||||
|
||||
protected:
|
||||
bool isDragging;
|
||||
|
||||
TimelineBody *timelineBody;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue