merge latest work from Joel for colaboration on the Player mockup, adjusting build-dependencies

This commit is contained in:
Fischlurch 2009-01-18 22:13:17 +01:00
commit 63565ebd97
29 changed files with 749 additions and 119 deletions

View file

@ -257,7 +257,7 @@ def configurePlatform(env):
if not conf.CheckPkgConfig('glibmm-2.4', '2.16'):
problems.append('Unable to configure Lib glib--, exiting.')
if not conf.CheckPkgConfig('gthread-2.0', '2.16'):
if not conf.CheckPkgConfig('gthread-2.0', '2.12'):
problems.append('Need gthread support lib for glib-- based thread handling.')
if not conf.CheckPkgConfig('cairomm-1.0', 0.6):

View file

@ -141,9 +141,13 @@ PKG_CHECK_MODULES(LUMIERA_COMMON_LIBS, [sigc++-2.0 >= 2.0.17])
# gtk+-2.0 >= 2.12 gtkmm-2.4 >= 2.12 for Debian Lenny compatibility
PKG_CHECK_MODULES(LUMIERA_GUI, [
gtk+-2.0 >= 2.8 gtkmm-2.4 >= 2.8
gdl-1.0 >= 0.6.1 cairomm-1.0 >= 0.6.0
gavl >= 0.2.5 librsvg-2.0 >= 2.18.1])
gtk+-2.0 >= 2.8
gtkmm-2.4 >= 2.8
cairomm-1.0 >= 0.6.0
librsvg-2.0 >= 2.18.1
gdl-1.0 >= 0.6.1
gavl >= 0.2.5
gthread-2.0 >= 2.12.4])
# END Gtk Dependancies

View file

@ -163,6 +163,10 @@ libgui_la_SOURCES = \
$(lumigui_srcdir)/model/sequence.hpp \
$(lumigui_srcdir)/model/clip.cpp \
$(lumigui_srcdir)/model/clip.hpp \
$(lumigui_srcdir)/controller/controller.cpp \
$(lumigui_srcdir)/controller/controller.hpp \
$(lumigui_srcdir)/controller/playback-controller.cpp \
$(lumigui_srcdir)/controller/playback-controller.hpp \
$(lumigui_srcdir)/output/displayer.cpp \
$(lumigui_srcdir)/output/displayer.hpp \
$(lumigui_srcdir)/output/gdkdisplayer.cpp \

View file

@ -0,0 +1,41 @@
/*
controllerk.cpp - Implementation of the timeline track object
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 "controller.hpp"
namespace gui {
namespace controller {
Controller::Controller(model::Project &model_project) :
project(model_project)
{
}
PlaybackController& Controller::get_playback_controller()
{
return playback;
}
} // namespace controller
} // namespace gui

View file

@ -0,0 +1,56 @@
/*
controller.hpp - Declaration of the controller object
Copyright (C) Lumiera.org
2009, 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.
*/
/** @file controller/controller.hpp
** This file contains the definition of the controller object
*/
#include "playback-controller.hpp"
#ifndef CONTROLLER_HPP
#define CONTROLLER_HPP
namespace gui {
namespace model {
class Project;
} // namespace model
namespace controller {
class Controller
{
public:
Controller(model::Project &model_project);
PlaybackController& get_playback_controller();
private:
model::Project &project;
PlaybackController playback;
};
} // namespace controller
} // namespace gui
#endif // CONTROLLER_HPP

View file

@ -0,0 +1,207 @@
/*
playback-controller.cpp - Implementation of the playback controller object
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 "playback-controller.hpp"
#include "../gtk-lumiera.hpp"
namespace gui {
namespace controller {
PlaybackController::PlaybackController() :
finish_playback_thread(false),
playing(false)
{
start_playback_thread();
}
PlaybackController::~PlaybackController()
{
mutex.lock();
finish_playback_thread = true;
mutex.unlock();
thread->join();
}
void
PlaybackController::play()
{
Glib::Mutex::Lock lock(mutex);
playing = true;
}
void
PlaybackController::pause()
{
Glib::Mutex::Lock lock(mutex);
playing = false;
}
void
PlaybackController::stop()
{
Glib::Mutex::Lock lock(mutex);
playing = false;
}
bool
PlaybackController::is_playing()
{
Glib::Mutex::Lock lock(mutex);
return playing;
}
void
PlaybackController::start_playback_thread()
{
dispatcher.connect(sigc::mem_fun(this, &PlaybackController::on_frame));
thread = Glib::Thread::create (sigc::mem_fun(
this, &PlaybackController::playback_thread), true);
}
void
PlaybackController::attach_viewer(
const sigc::slot<void, void*>& on_frame)
{
frame_signal.connect(on_frame);
}
void
PlaybackController::playback_thread()
{
for(;;)
{
{
Glib::Mutex::Lock lock(mutex);
if(finish_playback_thread)
return;
}
if(is_playing())
pull_frame();
Glib::Thread::yield();
}
}
typedef unsigned char byte;
inline int
clamp(const int &val, const int &maxval, const int &minval)
{
if(val > maxval) return maxval;
if(val < minval) return minval;
return val;
}
inline void
rgb_to_yuv(int r, int g, int b, byte &y, byte &u, byte &v)
{
// This code isn't great, but it does the job
y = (byte)clamp((299 * r + 587 * g + 114 * b) / 1000, 235, 16);
v = (byte)clamp((500 * r - 419 * g - 81 * b) / 1000 + 127, 255, 0);
u = (byte)clamp((-169 * r - 331 * g + 500 * b) / 1000 + 127, 255, 0);
}
void rgb_buffer_to_yuy2(unsigned char *in, unsigned char *out)
{
for(int i = 0; i < 320*240*2; i+=4)
{
byte y0, u0, v0;
const byte r0 = *(in++);
const byte g0 = *(in++);
const byte b0 = *(in++);
rgb_to_yuv(r0, g0, b0, y0, u0, v0);
byte y1, u1, v1;
const byte r1 = *(in++);
const byte g1 = *(in++);
const byte b1 = *(in++);
rgb_to_yuv(r1, g1, b1, y1, u1, v1);
out[i] = y0;
out[i + 1] = (byte)(((int)u0 + (int)u1) / 2);
out[i + 2] = y1;
out[i + 3] = (byte)(((int)v0 + (int)v1) / 2);
}
}
void
PlaybackController::pull_frame()
{
static int frame = 0;
unsigned char in[320 * 240 * 3];
frame--;
if(frame <= 0)
frame = 200;
if(frame > 150)
{
for(int i = 0; i < 320*240*3; i+=3)
{
byte value = (byte)rand();
in[i] = value;
in[i+1] = value;
in[i+2] = value;
}
}
else
{
unsigned char row[320 * 3];
for(int x = 0; x < 320; x++)
{
byte &r = row[x*3];
byte &g = row[x*3+1];
byte &b = row[x*3+2];
if(x < 1*320/7) r = 0xC0, g = 0xC0, b = 0xC0;
else if(x < 2*320/7) r = 0xC0, g = 0xC0, b = 0x00;
else if(x < 3*320/7) r = 0x00, g = 0xC0, b = 0xC0;
else if(x < 4*320/7) r = 0x00, g = 0xC0, b = 0x00;
else if(x < 5*320/7) r = 0xC0, g = 0x00, b = 0xC0;
else if(x < 6*320/7) r = 0xC0, g = 0x00, b = 0x00;
else r = 0x00, g = 0x00, b = 0xC0;
}
for(int y = 0; y < 240; y++)
{
memcpy(in + y*320*3, row, sizeof(row));
}
}
rgb_buffer_to_yuy2(in, buffer);
dispatcher.emit();
}
void
PlaybackController::on_frame()
{
frame_signal.emit(buffer);
}
} // namespace controller
} // namespace gui

View file

@ -0,0 +1,84 @@
/*
playback-controller.hpp - Declaration of the playback controller object
Copyright (C) Lumiera.org
2009, 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.
*/
/** @file controller/playback-controller.hpp
** This file contains the definition of the playback controller object
*/
#include <sigc++/sigc++.h>
#include <glibmm.h>
#ifndef PLAYBACK_CONTROLLER_HPP
#define PLAYBACK_CONTROLLER_HPP
namespace gui {
namespace controller {
class PlaybackController
{
public:
PlaybackController();
~PlaybackController();
void play();
void pause();
void stop();
bool is_playing();
void attach_viewer(const sigc::slot<void, void*>& on_frame);
private:
void start_playback_thread();
void playback_thread();
void pull_frame();
void on_frame();
private:
Glib::Thread *thread;
Glib::StaticMutex mutex;
Glib::Dispatcher dispatcher;
volatile bool finish_playback_thread;
volatile bool playing;
unsigned char buffer[320 * 240 * 4];
sigc::signal<void, void*> frame_signal;
};
} // namespace controller
} // namespace gui
#endif // PLAYBACK_CONTROLLER_HPP

View file

@ -31,6 +31,7 @@
#include "window-manager.hpp"
#include "workspace/workspace-window.hpp"
#include "model/project.hpp"
#include "controller/controller.hpp"
extern "C" {
#include "common/interface.h"
@ -43,6 +44,7 @@ using namespace Glib;
using namespace gui;
using namespace gui::workspace;
using namespace gui::model;
using namespace gui::controller;
GtkLumiera the_application;
@ -55,17 +57,19 @@ namespace gui {
void
GtkLumiera::main(int argc, char *argv[])
{
Glib::thread_init();
Main kit(argc, argv);
Glib::set_application_name(AppTitle);
Project project;
Controller controller(project);
WindowManager window_manager;
window_manager.set_theme("lumiera_ui.rc");
WorkspaceWindow main_window(&project);
WorkspaceWindow main_window(project, controller);
kit.run(main_window);

View file

@ -26,8 +26,8 @@
namespace gui {
namespace panels {
AssetsPanel::AssetsPanel(model::Project *const owner_project) :
Panel(owner_project, "assets", _("Assets"), "panel_assets"),
AssetsPanel::AssetsPanel(workspace::WorkspaceWindow &workspace_window) :
Panel(workspace_window, "assets", _("Assets"), "panel_assets"),
placeholder("Assets/Media")
{
pack_start(placeholder);

View file

@ -34,11 +34,12 @@ namespace panels {
class AssetsPanel : public Panel
{
public:
/**
* Constructor
* @param owner_project The project associated with this panel.
* Contructor.
* @param workspace_window The window that owns this panel.
**/
AssetsPanel(model::Project *const owner_project);
AssetsPanel(workspace::WorkspaceWindow &workspace_window);
protected:
Gtk::Label placeholder;

View file

@ -26,12 +26,11 @@
namespace gui {
namespace panels {
Panel::Panel(model::Project *const owner_project,
Panel::Panel(workspace::WorkspaceWindow &workspace_window,
const gchar *name, const gchar *long_name,
GdlDockItemBehavior behavior) :
project(owner_project)
workspace(workspace_window)
{
REQUIRE(owner_project != NULL);
REQUIRE(name != NULL);
REQUIRE(long_name != NULL);
@ -42,12 +41,11 @@ Panel::Panel(model::Project *const owner_project,
ENSURE(dock_item != NULL);
}
Panel::Panel(model::Project *const owner_project,
Panel::Panel(workspace::WorkspaceWindow &workspace_window,
const gchar *name, const gchar *long_name, const gchar *stock_id,
GdlDockItemBehavior behavior) :
project(owner_project)
workspace(workspace_window)
{
REQUIRE(owner_project != NULL);
REQUIRE(name != NULL);
REQUIRE(long_name != NULL);
REQUIRE(stock_id != NULL);

View file

@ -32,8 +32,8 @@
namespace gui {
namespace model {
class Project;
namespace workspace {
class WorkspaceWindow;
}
namespace panels {
@ -46,24 +46,24 @@ class Panel : public Gtk::VBox
protected:
/**
* Constructs a panel object
* @param owner_project The project associated with this panel.
* @param workspace_window The window that owns this panel.
* @param name The internal name of this panel
* @param long_name The name to display on the caption
* @param behavior The GDL behaviour of this item
*/
Panel(model::Project *const owner_project,
Panel(workspace::WorkspaceWindow &workspace_window,
const gchar *name, const gchar *long_name,
GdlDockItemBehavior behavior = GDL_DOCK_ITEM_BEH_NORMAL);
/**
* Constructs a panel object with a stock item for a caption
* @param owner_project The project associated with this panel.
* @param owner_window The window that owns this panel.
* @param name The internal name of this panel
* @param long_name The name to display on the caption
* @param stock_id The id of the stock item to display on the caption
* @param behavior The GDL behaviour of this item
*/
Panel(model::Project *const owner_project,
Panel(workspace::WorkspaceWindow &owner_window,
const gchar *name, const gchar *long_name, const gchar *stock_id,
GdlDockItemBehavior behavior = GDL_DOCK_ITEM_BEH_NORMAL);
@ -99,7 +99,7 @@ private:
protected:
model::Project *const project;
workspace::WorkspaceWindow &workspace;
GdlDockItem* dock_item;
};

View file

@ -25,7 +25,9 @@
#include "../gtk-lumiera.hpp"
#include "timeline-panel.hpp"
#include "../workspace/workspace-window.hpp"
#include "../model/project.hpp"
#include "../controller/controller.hpp"
extern "C" {
#include "../../lib/time.h"
@ -43,8 +45,9 @@ namespace panels {
const int TimelinePanel::ZoomToolSteps = 2; // 2 seems comfortable
TimelinePanel::TimelinePanel(model::Project *const owner_project) :
Panel(owner_project, "timeline", _("Timeline"), "panel_timeline"),
TimelinePanel::TimelinePanel(workspace::WorkspaceWindow
&workspace_window) :
Panel(workspace_window, "timeline", _("Timeline"), "panel_timeline"),
timeIndicator(),
previousButton(Stock::MEDIA_PREVIOUS),
rewindButton(Stock::MEDIA_REWIND),
@ -65,7 +68,7 @@ TimelinePanel::TimelinePanel(model::Project *const owner_project) :
// mem_fun(this, &TimelinePanel::on_playback_period_drag_released));
// Hook up notifications
project->get_sequences().signal_changed().connect(
workspace.get_project().get_sequences().signal_changed().connect(
mem_fun(this, &TimelinePanel::on_sequence_list_changed));
// Setup the notebook
@ -119,15 +122,14 @@ TimelinePanel::~TimelinePanel()
void
TimelinePanel::on_play_pause()
{
// TEST CODE!
{
if(!is_playing())
{
play();
}
else
{
frameEvent.disconnect();
pause();
}
update_playback_buttons();
@ -136,12 +138,8 @@ TimelinePanel::on_play_pause()
void
TimelinePanel::on_stop()
{
// TEST CODE!
/*timelineWidget.set_playback_point(GAVL_TIME_UNDEFINED);
frameEvent.disconnect();
show_time(timelineWidget.get_playback_period_start());
update_playback_buttons();*/
workspace.get_controller().get_playback_controller().stop();
update_playback_buttons();
}
void
@ -223,7 +221,7 @@ TimelinePanel::update_notebook()
old_pages.swap(notebook_pages);
BOOST_FOREACH( shared_ptr< model::Sequence > sequence,
project->get_sequences() )
workspace.get_project().get_sequences() )
{
std::map<const model::Sequence*, shared_ptr<TimelineWidget> >::
iterator iterator = old_pages.find(sequence.get());
@ -283,20 +281,21 @@ TimelinePanel::update_zoom_buttons()
void
TimelinePanel::play()
{
workspace.get_controller().get_playback_controller().play();
}
void
TimelinePanel::pause()
{
/*if(timelineWidget.get_playback_point() == GAVL_TIME_UNDEFINED)
timelineWidget.set_playback_point(
timelineWidget.get_playback_period_start());
frameEvent = Glib::signal_timeout().connect(
sigc::mem_fun(this, &TimelinePanel::on_frame),
1000 / 25);*/
workspace.get_controller().get_playback_controller().pause();
}
bool
TimelinePanel::is_playing() const
{
// TEST CODE! - this should be hooked up to the real playback control
return frameEvent.connected();
return workspace.get_controller().get_playback_controller().
is_playing();
}
void

View file

@ -48,10 +48,9 @@ class TimelinePanel : public Panel
public:
/**
* Constructor
* @param owner_project The project associated with this panel.
* @param workspace_window The window that owns this panel.
*/
TimelinePanel(model::Project *const owner_project);
TimelinePanel(workspace::WorkspaceWindow &workspace_window);
/**
* Destructor
@ -88,6 +87,9 @@ private:
void update_zoom_buttons();
void play();
void pause();
bool is_playing() const;
void set_tool(gui::widgets::timeline::ToolType tool);
@ -138,7 +140,6 @@ private:
private:
// TEST CODE
bool on_frame();
sigc::connection frameEvent;
//----- Constants -----//
private:

View file

@ -23,17 +23,36 @@
#include "../gtk-lumiera.hpp"
#include "viewer-panel.hpp"
using namespace gui::widgets;
#include "../workspace/workspace-window.hpp"
#include "../controller/controller.hpp"
#include "../controller/playback-controller.hpp"
using namespace Gtk;
using namespace gui::widgets;
using namespace gui::controller;
namespace gui {
namespace panels {
ViewerPanel::ViewerPanel(model::Project *const owner_project) :
Panel(owner_project, "viewer", _("Viewer"), "panel_viewer")
ViewerPanel::ViewerPanel(workspace::WorkspaceWindow &workspace_window) :
Panel(workspace_window, "viewer", _("Viewer"), "panel_viewer")
{
//----- Pack in the Widgets -----//
pack_start(display, PACK_EXPAND_WIDGET);
PlaybackController &playback =
workspace_window.get_controller().get_playback_controller();
playback.attach_viewer(sigc::mem_fun(this, &ViewerPanel::on_frame));
}
void
ViewerPanel::on_frame(void *buffer)
{
Displayer *displayer = display.get_displayer();
REQUIRE(displayer);
displayer->put(buffer);
}
} // namespace panels

View file

@ -42,9 +42,13 @@ class ViewerPanel : public Panel
public:
/**
* Contructor.
@param owner_project The project associated with this panel.
* @param workspace_window The window that owns this panel.
**/
ViewerPanel(model::Project *const owner_project);
ViewerPanel(workspace::WorkspaceWindow &owner_window);
protected:
void on_frame(void *buffer);
protected:

View file

@ -484,6 +484,12 @@ TimelineWidget::get_y_scroll_offset() const
return (int)verticalAdjustment.get_value();
}
void
TimelineWidget::set_y_scroll_offset(const int offset)
{
verticalAdjustment.set_value(offset);
}
bool
TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event)
{

View file

@ -226,6 +226,8 @@ private:
int get_y_scroll_offset() const;
void set_y_scroll_offset(const int offset);
// ----- Event Handlers -----//
/**

View file

@ -36,6 +36,13 @@ using namespace util;
namespace gui {
namespace widgets {
namespace timeline {
// ===== Constants ===== //
const int TimelineHeaderContainer::ScrollSlideRateDivisor = 4;
const int TimelineHeaderContainer::ScrollSlideEventInterval = 40;
// ===== Implementation ===== //
TimelineHeaderContainer::TimelineHeaderContainer(
gui::widgets::TimelineWidget &timeline_widget) :
@ -176,7 +183,7 @@ bool TimelineHeaderContainer::on_button_release_event (
// Has the user been dragging?
if(layout.get_dragging_track())
layout.end_dragging_track();
end_drag();
return Container::on_button_release_event(event);
}
@ -201,14 +208,26 @@ bool TimelineHeaderContainer::on_motion_notify_event (
if((event->state & GDK_BUTTON1_MASK) && hoveringTrack &&
!layout.get_dragging_track())
{
layout.begin_dragging_track(mousePoint);
begin_drag();
return result;
}
// Are we currently dragging?
if(layout.get_dragging_track())
{
// Forward the message to the layout manager
layout.drag_to_point(mousePoint);
// Is the mouse out of bounds? if so we must begin scrolling
const int height = get_allocation().get_height();
const int y = mousePoint.get_y();
if(y < 0)
begin_scroll_slide(y / ScrollSlideRateDivisor);
else if(y > height)
begin_scroll_slide((y - height) / ScrollSlideRateDivisor);
else end_scroll_slide();
return result;
}
@ -304,6 +323,22 @@ TimelineHeaderContainer::on_hovering_track_changed(
}
bool
TimelineHeaderContainer::on_scroll_slide_timer()
{
// Shift the view
const int view_height = get_allocation().get_height();
timelineWidget.set_y_scroll_offset(
timelineWidget.get_y_scroll_offset() +
scrollSlideRate * view_height / 256);
// Keep the layout manager updated
timelineWidget.layoutHelper.drag_to_point(mousePoint);
// Return true to keep the timer going
return true;
}
void
TimelineHeaderContainer::layout_headers()
@ -365,6 +400,84 @@ TimelineHeaderContainer::lookup_timeline_track(
return timeline_track;
}
void
TimelineHeaderContainer::begin_drag()
{
TimelineLayoutHelper &layout = timelineWidget.layoutHelper;
shared_ptr<timeline::Track> dragging_track =
layout.begin_dragging_track(mousePoint);
ENSURE(dragging_track); // Something strange has happened if we
// were somehow not hovering on a track
const TimelineLayoutHelper::TrackTree::pre_order_iterator node =
layout.iterator_from_track(dragging_track->get_model_track());
set_keep_above_recursive(node, true);
}
void
TimelineHeaderContainer::end_drag()
{
TimelineLayoutHelper &layout = timelineWidget.layoutHelper;
shared_ptr<timeline::Track> dragging_track =
layout.get_dragging_track();
ENSURE(dragging_track); // Something strange has happened if we
// were somehow not dragging on a track
const TimelineLayoutHelper::TrackTree::pre_order_iterator node =
layout.iterator_from_track(dragging_track->get_model_track());
set_keep_above_recursive(node, false);
layout.end_dragging_track();
}
void
TimelineHeaderContainer::set_keep_above_recursive(
TimelineLayoutHelper::TrackTree::iterator_base node,
const bool keep_above)
{
TimelineLayoutHelper::TrackTree::pre_order_iterator iter;
const TimelineLayoutHelper::TrackTree &layout_tree =
timelineWidget.layoutHelper.get_layout_tree();
shared_ptr<timeline::Track> timeline_track =
lookup_timeline_track(*node);
REQUIRE(timeline_track);
Glib::RefPtr<Gdk::Window> window =
timeline_track->get_header_widget().get_window();
ENSURE(window); // Something strange has happened if there was no
// window
window->set_keep_above(keep_above);
for(iter = layout_tree.begin(node);
iter != layout_tree.end(node);
iter++)
{
set_keep_above_recursive(iter, keep_above);
}
}
void
TimelineHeaderContainer::begin_scroll_slide(int scroll_slide_rate)
{
scrollSlideRate = scroll_slide_rate;
if(!scrollSlideEvent.connected())
scrollSlideEvent = Glib::signal_timeout().connect(sigc::mem_fun(
this, &TimelineHeaderContainer::on_scroll_slide_timer),
ScrollSlideEventInterval);
}
void
TimelineHeaderContainer::end_scroll_slide()
{
scrollSlideRate = 0;
if(scrollSlideEvent.connected())
scrollSlideEvent.disconnect();
}
} // namespace timeline
} // namespace widgets
} // namespace gui

View file

@ -29,6 +29,7 @@
#define HEADER_CONTAINER_HPP
#include "../../gtk-lumiera.hpp"
#include "timeline-layout-helper.hpp"
namespace gui {
@ -139,6 +140,15 @@ private:
void on_hovering_track_changed(
boost::shared_ptr<timeline::Track> hovering_track);
private:
/* ===== Internal Event Handlers ===== */
/**
* An internal event handler, which is called when the scroll slide
* timer calls it.
*/
bool on_scroll_slide_timer();
/* ===== Internals ===== */
private:
@ -172,6 +182,27 @@ private:
**/
boost::shared_ptr<timeline::Track> lookup_timeline_track(
boost::shared_ptr<model::Track> model_track);
void begin_drag();
void end_drag();
void set_keep_above_recursive(
TimelineLayoutHelper::TrackTree::iterator_base node,
const bool keep_above);
/**
* Begins, or continues a scroll slide at a given rate
* @param scroll_slide_rate The distance to slide every timer event
* in units of 1/256th of the view height.
*/
void begin_scroll_slide(int scroll_slide_rate);
/**
* Ends a scroll slide, and disconnects the slide timer
*/
void end_scroll_slide();
private:
@ -195,11 +226,38 @@ private:
* click is not processed by track headers.
**/
Gtk::Menu contextMenu;
/**
* 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 header outside the area of the timeline body.
*/
sigc::connection scrollSlideEvent;
/**
* Specifies the rate at which scroll sliding is currently taking
* place.
*/
int scrollSlideRate;
//----- User Interaction State -----//
boost::shared_ptr<timeline::Track> hoveringTrack;
Gdk::Point mousePoint;
/* ===== Constants ===== */
/**
* 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;
friend class gui::widgets::TimelineWidget;
friend class timeline::Track;

View file

@ -128,32 +128,25 @@ TimelineLayoutHelper::track_from_y(int y)
return shared_ptr<timeline::Track>();
}
bool
shared_ptr<timeline::Track>
TimelineLayoutHelper::begin_dragging_track(
const Gdk::Point &mouse_point)
{
draggingTrack = header_from_point(mouse_point);
if(!draggingTrack)
return false;
return shared_ptr<timeline::Track>();
const Gdk::Rectangle &rect = headerBoxes[draggingTrack];
dragStartOffset = Gdk::Point(
mouse_point.get_x() - rect.get_x(),
mouse_point.get_y() - rect.get_y());
mouse_point.get_y() - rect.get_y() +
timelineWidget.get_y_scroll_offset());
// Find the track in the tree
const shared_ptr<model::Track> model_track =
draggingTrack->get_model_track();
REQUIRE(model_track);
for(draggingTrackIter = layoutTree.begin();
draggingTrackIter != layoutTree.end();
draggingTrackIter++)
{
if(*draggingTrackIter == model_track)
break;
}
draggingTrackIter = iterator_from_track(model_track);
return true;
return draggingTrack;
}
void
@ -187,7 +180,7 @@ TimelineLayoutHelper::drag_to_point(const Gdk::Point &point)
const weak_ptr<timeline::Track> track =
lookup_timeline_track(*iterator);
if(util::pt_in_rect(point, headerBoxes[track]))
if(util::pt_in_rect(dragPoint, headerBoxes[track]))
{
// Relocate the header
draggingTrackIter = layoutTree.move_after(
@ -211,6 +204,22 @@ TimelineLayoutHelper::is_animating() const
return animating;
}
TimelineLayoutHelper::TrackTree::pre_order_iterator
TimelineLayoutHelper::iterator_from_track(
boost::shared_ptr<model::Track> model_track)
{
REQUIRE(model_track);
TrackTree::pre_order_iterator iter;
for(iter = layoutTree.begin(); iter != layoutTree.end(); iter++)
{
if(*iter == model_track)
break;
}
return iter;
}
void
TimelineLayoutHelper::update_layout()
{
@ -243,24 +252,28 @@ TimelineLayoutHelper::layout_headers_recursive(
REQUIRE(depth >= 0);
int child_offset = 0;
TrackTree::sibling_iterator iterator;
for(iterator = layoutTree.begin(parent_iterator);
iterator != layoutTree.end(parent_iterator);
iterator++)
{
Gdk::Rectangle rect;
int track_height = 0;
const shared_ptr<model::Track> &model_track = *iterator;
REQUIRE(model_track);
shared_ptr<timeline::Track> timeline_track =
lookup_timeline_track(model_track);
const bool being_dragged = (timeline_track == draggingTrack);
// Is the track going to be shown?
if(parent_expanded)
{
// Calculate and store the box of the header
const int track_height = timeline_track->get_height();
track_height = timeline_track->get_height() +
TimelineWidget::TrackPadding;
const int indent = depth * indent_width;
rect = Gdk::Rectangle(
@ -270,19 +283,15 @@ TimelineLayoutHelper::layout_headers_recursive(
track_height); // height
// Offset for the next header
child_offset += track_height + TimelineWidget::TrackPadding;
child_offset += track_height;
// Is this header being dragged?
if(timeline_track == draggingTrack)
{
rect.set_y(dragPoint.get_y() - dragStartOffset.get_y());
}
if(being_dragged)
rect.set_y(dragPoint.get_y() - dragStartOffset.get_y());
headerBoxes[timeline_track] = rect;
}
// Is the track animating?
const bool is_track_animating =
timeline_track->is_expand_animating();
@ -292,10 +301,11 @@ TimelineLayoutHelper::layout_headers_recursive(
const bool expand_child =
(animating || timeline_track->get_expanded())
&& parent_expanded;
int child_branch_height = layout_headers_recursive(
iterator, branch_offset + child_offset,
header_width, indent_width, depth + 1, expand_child);
iterator, rect.get_y() + track_height,
header_width, indent_width, depth + 1,
expand_child);
// Do collapse animation as necessary
if(is_track_animating)

View file

@ -127,7 +127,8 @@ public:
**/
boost::shared_ptr<timeline::Track> track_from_y(int y);
bool begin_dragging_track(const Gdk::Point &mouse_point);
boost::shared_ptr<timeline::Track>
begin_dragging_track(const Gdk::Point &mouse_point);
void end_dragging_track();
@ -144,6 +145,16 @@ public:
int get_total_height() const;
bool is_animating() const;
/**
* A utility function which finds the iterator of a track in the
* layout tree.
* @param model_track The model track to look for.
* @return Returns the model iterator of layoutTree.end() if no
* iterator was found.
**/
TrackTree::pre_order_iterator iterator_from_track(
boost::shared_ptr<model::Track> model_track);
protected:

View file

@ -45,6 +45,12 @@ VideoDisplayWidget::~VideoDisplayWidget()
delete displayer;
}
Displayer*
VideoDisplayWidget::get_displayer() const
{
return displayer;
}
void
VideoDisplayWidget::on_realize()
{
@ -61,21 +67,6 @@ VideoDisplayWidget::on_realize()
add_events(Gdk::ALL_EVENTS_MASK);
}
bool
VideoDisplayWidget::on_button_press_event (GdkEventButton* event)
{
(void)event;
unsigned char buffer[320 * 240 * 4];
for(int i = 0; i < 320*240*4; i++)
buffer[i] = rand();
displayer->put((void*)buffer);
return true;
}
Displayer*
VideoDisplayWidget::createDisplayer( Gtk::Widget *drawingArea, int width, int height )
{

View file

@ -41,13 +41,12 @@ public:
VideoDisplayWidget();
~VideoDisplayWidget();
Displayer* get_displayer() const;
/* ===== Overrides ===== */
private:
virtual void on_realize();
// TEST CODE!!!!
virtual bool on_button_press_event (GdkEventButton* event);
/* ===== Internals ===== */
private:

View file

@ -188,7 +188,7 @@ Actions::on_menu_sequence_add()
dialogs::NameChooser dialog(workspaceWindow,
_("Add Sequence"), _("New Sequence"));
if(dialog.run() == RESPONSE_OK)
workspaceWindow.get_project()->add_new_sequence(dialog.get_name());
workspaceWindow.get_project().add_new_sequence(dialog.get_name());
}
/* ===== Track Menu Event Handlers ===== */

View file

@ -37,16 +37,17 @@
using namespace Gtk;
using namespace gui::model;
using namespace gui::controller;
namespace gui {
namespace workspace {
WorkspaceWindow::WorkspaceWindow(Project *source_project) :
WorkspaceWindow::WorkspaceWindow(Project &source_project,
gui::controller::Controller &source_controller) :
project(source_project),
controller(source_controller),
actions(*this)
{
REQUIRE(source_project != NULL);
{
layout = NULL;
assetsPanel = NULL;
viewerPanel = NULL;
@ -68,12 +69,18 @@ WorkspaceWindow::~WorkspaceWindow()
timelinePanel->unreference();
}
Project*
WorkspaceWindow::get_project() const
Project&
WorkspaceWindow::get_project()
{
return project;
}
Controller&
WorkspaceWindow::get_controller()
{
return controller;
}
void
WorkspaceWindow::create_ui()
{
@ -152,11 +159,11 @@ WorkspaceWindow::create_ui()
baseContainer.pack_start(*toolbar, Gtk::PACK_SHRINK);
//----- Create the Panels -----//
assetsPanel = new AssetsPanel(project);
assetsPanel = new AssetsPanel(*this);
ENSURE(assetsPanel != NULL);
viewerPanel = new ViewerPanel(project);
viewerPanel = new ViewerPanel(*this);
ENSURE(viewerPanel != NULL);
timelinePanel = new TimelinePanel(project);
timelinePanel = new TimelinePanel(*this);
ENSURE(timelinePanel != NULL);
//----- Create the Dock -----//

View file

@ -46,6 +46,10 @@ namespace model {
class Project;
} // model
namespace controller {
class Controller;
} // model
namespace workspace {
/**
@ -54,18 +58,25 @@ namespace workspace {
class WorkspaceWindow : public Gtk::Window
{
public:
WorkspaceWindow(gui::model::Project *source_project);
WorkspaceWindow(gui::model::Project &source_project,
gui::controller::Controller &source_controller);
~WorkspaceWindow();
gui::model::Project* get_project() const;
gui::model::Project& get_project();
gui::controller::Controller& get_controller();
private:
void create_ui();
/* ===== Model ===== */
private:
gui::model::Project *project;
gui::model::Project &project;
/* ===== Controller ===== */
private:
gui::controller::Controller &controller;
/* ===== UI ===== */
private:

View file

@ -747,7 +747,7 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
}
//}}}</pre>
</div>
<div title="BuildDependencies" modifier="Ichthyostega" modified="200808190851" created="200803261326" changecount="15">
<div title="BuildDependencies" modifier="Ichthyostega" modified="200901182029" created="200803261326" changecount="16">
<pre>! Programming Languages
* C
** a C99 compatible compiler, some GCC extensions are used, most are optional.
@ -787,7 +787,7 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
** libcairomm-1.0-dev (&gt;=0.6.0)
** libgdl-1-dev (&gt;=0.6.1)
*** libbonoboui2-dev (&gt;=2.14.0)
** libglibmm-2.4-dev (&gt;=2.16), requiring glib2.0 (&gt;=2.16)
** libglibmm-2.4-dev (&gt;=2.16), requiring glib2.0 (&gt;=2.16) and gthread-2.0 (&gt;=2.12.4)
** libxv-dev ~~(1.0.2 is known to work)~~

View file

@ -780,7 +780,7 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
}
//}}}</pre>
</div>
<div title="BuildDependenceis" modifier="Ichthyostega" modified="200808190850" created="200708120103" tags="organization buildsys" changecount="18">
<div title="BuildDependenceis" modifier="Ichthyostega" modified="200901182029" created="200708120103" tags="organization buildsys" changecount="19">
<pre>for __Building__
* gcc (4.1), glibc6 (2.3), libstdc++6 (4.1)
* [[build system|BuildSystem]] dependencies: SCons (0.96.90), Python (2.4), pkg-config
@ -799,7 +799,7 @@ config.macros.timeline.handler = function(place,macroName,params,wikifier,paramS
** libcairomm-1.0-dev (&gt;=0.6.0)
** libgdl-1-dev (&gt;=0.6.1)
*** libbonoboui2-dev (&gt;=2.14.0)
** libglibmm-2.4-dev (&gt;=2.16), requiring glib2.0 (&gt;=2.16)
** libglibmm-2.4-dev (&gt;=2.16), requiring glib2.0 (&gt;=2.16) and gthread-2.0 (&gt;=2.12.4)
** libxv-dev (&gt;=1.0.2)
//usually, newer versions are OK//