Merge branch 'master' of git://git.lumiera.org/LUMIERA

This commit is contained in:
Michael Ploujnikov 2008-09-03 18:55:19 -04:00
commit 06504c7b04
21 changed files with 954 additions and 264 deletions

View file

@ -61,7 +61,7 @@ def setupBasicEnvironment():
opts = defineCmdlineOptions()
env = LumieraEnvironment(options=opts
,toolpath = [TOOLDIR]
,tools = ["default", "BuilderGCH"]
,tools = ["default", "BuilderGCH", "BuilderDoxygen"]
)
env.Append ( CCCOM=' -std=gnu99') # workaround for a bug: CCCOM currently doesn't honor CFLAGS, only CCFLAGS
@ -173,24 +173,21 @@ def configurePlatform(env):
# run all configuration checks in the given env
# Perform checks for prerequisites --------------------------------------------
problems = []
if not conf.TryAction('pkg-config --version > $TARGET')[0]:
print 'We need pkg-config for including library configurations, exiting.'
Exit(1)
problems.append('We need pkg-config for including library configurations, exiting.')
if not conf.CheckLibWithHeader('m', 'math.h','C'):
print 'Did not find math.h / libm, exiting.'
Exit(1)
problems.append('Did not find math.h / libm.')
if not conf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'):
print 'Functions for runtime dynamic loading not available, exiting.'
Exit(1)
problems.append('Functions for runtime dynamic loading not available.')
if not conf.CheckLibWithHeader('nobugmt', 'nobug.h', 'C'):
print 'Did not find NoBug [http://www.pipapo.org/pipawiki/NoBug], exiting.'
Exit(1)
problems.append('Did not find NoBug [http://www.pipapo.org/pipawiki/NoBug].')
if not conf.CheckLibWithHeader('pthread', 'pthread.h', 'C'):
print 'Did not find the pthread lib or pthread.h, exiting.'
problems.append('Did not find the pthread lib or pthread.h.')
else:
conf.env.Append(CPPFLAGS = ' -DHAVE_PTHREAD')
conf.env.Append(CCFLAGS = ' -pthread')
@ -202,57 +199,56 @@ def configurePlatform(env):
conf.env.Append(CPPFLAGS = ' -DHAS_VALGRIND_VALGIND_H')
if not conf.CheckCXXHeader('tr1/memory'):
print 'We rely on the std::tr1 proposed standard extension for shared_ptr.'
Exit(1)
problems.append('We rely on the std::tr1 proposed standard extension for shared_ptr.')
if not conf.CheckCXXHeader('boost/config.hpp'):
print 'We need the C++ boost-lib.'
Exit(1)
problems.append('We need the C++ boost-lib.')
else:
if not conf.CheckCXXHeader('boost/shared_ptr.hpp'):
print 'We need boost::shared_ptr (shared_ptr.hpp).'
Exit(1)
problems.append('We need boost::shared_ptr (shared_ptr.hpp).')
if not conf.CheckLibWithHeader('boost_program_options-mt','boost/program_options.hpp','C++'):
print 'We need boost::program_options (including binary lib for linking).'
Exit(1)
problems.append('We need boost::program_options (including binary lib for linking).')
if not conf.CheckLibWithHeader('boost_regex-mt','boost/regex.hpp','C++'):
print 'We need the boost regular expression lib (incl. binary lib for linking).'
Exit(1)
problems.append('We need the boost regular expression lib (incl. binary lib for linking).')
# if not conf.CheckLibWithHeader('gavl', ['gavlconfig.h', 'gavl/gavl.h'], 'C'):
if not conf.CheckPkgConfig('gavl', 1.0):
print 'Did not find Gmerlin Audio Video Lib [http://gmerlin.sourceforge.net/gavl.html], exiting.'
Exit(1)
problems.append('Did not find Gmerlin Audio Video Lib [http://gmerlin.sourceforge.net/gavl.html].')
else:
conf.env.mergeConf('gavl')
if not conf.CheckPkgConfig('gtkmm-2.4', 2.8):
print 'Unable to configure GTK--, exiting.'
Exit(1)
problems.append('Unable to configure GTK--, exiting.')
if not conf.CheckPkgConfig('glibmm-2.4', '2.16'):
print 'Unable to configure Lib glib--, exiting.'
Exit(1)
problems.append('Unable to configure Lib glib--, exiting.')
if not conf.CheckPkgConfig('cairomm-1.0', 0.6):
print 'Unable to configure Cairo--, exiting.'
Exit(1)
problems.append('Unable to configure Cairo--, exiting.')
if not conf.CheckPkgConfig('gdl-1.0', '0.6.1'):
print 'Unable to configure the GNOME DevTool Library, exiting.'
Exit(1)
problems.append('Unable to configure the GNOME DevTool Library, exiting.')
if not conf.CheckPkgConfig('librsvg-2.0', '2.18.1'):
print 'Need rsvg Library for rendering icons.'
Exit(1)
problems.append('Need rsvg Library for rendering icons.')
if not conf.CheckPkgConfig('xv'): Exit(1)
if not conf.CheckPkgConfig('xv'): problems.append('Need lib xv')
# if not conf.CheckPkgConfig('xext'): Exit(1)
# if not conf.CheckPkgConfig('sm'): Exit(1)
#
# obviously not needed?
# report missing dependencies
if problems:
print "*** unable to build due to the following problems:"
for isue in problems:
print " * %s" % isue
print
print "build aborted."
Exit(1)
print "** Gathered Library Info: %s" % conf.env.libInfo.keys()
@ -340,16 +336,9 @@ def definePostBuildTargets(env, artifacts):
env.Clean ('build', [ 'scache.conf', '.sconf_temp', '.sconsign.dblite', 'config.log' ])
env.Clean ('build', [ '$SRCDIR/pre.gch' ])
# Doxygen documentation
# Note: at the moment we only depend on Doxyfile
# obviousely, we should depend on all sourcefiles
# real Doxygen builder for scons is under developement for 0.97
# so for the moment I prefere not to bother
doxyfile = File('doc/devel/Doxyfile')
env.NoClean(doxyfile)
doxydoc = artifacts['doxydoc'] = [ Dir('doc/devel/html'), Dir('doc/devel/latex') ]
env.Command(doxydoc, doxyfile, "doxygen Doxyfile 2>&1 |tee ,doxylog", chdir='doc/devel')
env.Clean ('doc/devel', doxydoc + ['doc/devel/,doxylog'])
doxydoc = artifacts['doxydoc'] = env.Doxygen('doc/devel/Doxyfile')
env.Alias ('doxydoc', doxydoc)
env.Clean ('doxydoc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt'])
def defineInstallTargets(env, artifacts):

View file

@ -0,0 +1,230 @@
# -*- python -*-
##
## BuilderDoxygen.py - SCons builder for generating Doxygen documentation
##
#
# Astxx, the Asterisk C++ API and Utility Library.
# Copyright (C) 2005, 2006 Matthew A. Nicholson
# Copyright (C) 2006 Tim Blechmann
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License version 2.1 as published by the Free Software Foundation.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library; if not, see http://www.gnu.org/licenses/
#####################################################################
# history: 8/2008 adapted for Lumiera build system
# added patch for Doxyfile in subdirectory
# see http://www.scons.org/wiki/DoxygenBuilder
import os
import os.path
import glob
from fnmatch import fnmatch
def DoxyfileParse(file_contents):
"""
Parse a Doxygen source file and return a dictionary of all the values.
Values will be strings and lists of strings.
"""
data = {}
import shlex
lex = shlex.shlex(instream = file_contents, posix = True)
lex.wordchars += "*+./-:"
lex.whitespace = lex.whitespace.replace("\n", "")
lex.escape = ""
lineno = lex.lineno
token = lex.get_token()
key = token # the first token should be a key
last_token = ""
key_token = False
next_key = False
new_data = True
def append_data(data, key, new_data, token):
if new_data or len(data[key]) == 0:
data[key].append(token)
else:
data[key][-1] += token
while token:
if token in ['\n']:
if last_token not in ['\\']:
key_token = True
elif token in ['\\']:
pass
elif key_token:
key = token
key_token = False
else:
if token == "+=":
if not data.has_key(key):
data[key] = list()
elif token == "=":
data[key] = list()
else:
append_data( data, key, new_data, token )
new_data = True
last_token = token
token = lex.get_token()
if last_token == '\\' and token != '\n':
new_data = False
append_data( data, key, new_data, '\\' )
# compress lists of len 1 into single strings
for (k, v) in data.items():
if len(v) == 0:
data.pop(k)
# items in the following list will be kept as lists and not converted to strings
if k in ["INPUT", "FILE_PATTERNS", "EXCLUDE_PATTERNS"]:
continue
if len(v) == 1:
data[k] = v[0]
return data
def DoxySourceScan(node, env, path):
"""
Doxygen Doxyfile source scanner. This should scan the Doxygen file and add
any files used to generate docs to the list of source files.
"""
default_file_patterns = [
'*.c', '*.cc', '*.cxx', '*.cpp', '*.c++', '*.java', '*.ii', '*.ixx',
'*.ipp', '*.i++', '*.inl', '*.h', '*.hh ', '*.hxx', '*.hpp', '*.h++',
'*.idl', '*.odl', '*.cs', '*.php', '*.php3', '*.inc', '*.m', '*.mm',
'*.py',
]
default_exclude_patterns = [
'*~',
]
sources = []
data = DoxyfileParse(node.get_contents())
if data.get("RECURSIVE", "NO") == "YES":
recursive = True
else:
recursive = False
file_patterns = data.get("FILE_PATTERNS", default_file_patterns)
exclude_patterns = data.get("EXCLUDE_PATTERNS", default_exclude_patterns)
#
# We're running in the top-level directory, but the doxygen
# configuration file is in the same directory as node; this means
# that relative pathnames in node must be adjusted before they can
# go onto the sources list
conf_dir = os.path.dirname(str(node))
for node in data.get("INPUT", []):
if not os.path.isabs(node):
node = os.path.join(conf_dir, node)
if os.path.isfile(node):
sources.append(node)
elif os.path.isdir(node):
if recursive:
for root, dirs, files in os.walk(node):
for f in files:
filename = os.path.join(root, f)
pattern_check = reduce(lambda x, y: x or bool(fnmatch(filename, y)), file_patterns, False)
exclude_check = reduce(lambda x, y: x and fnmatch(filename, y), exclude_patterns, True)
if pattern_check and not exclude_check:
sources.append(filename)
else:
for pattern in file_patterns:
sources.extend(glob.glob("/".join([node, pattern])))
sources = map( lambda path: env.File(path), sources )
return sources
def DoxySourceScanCheck(node, env):
"""Check if we should scan this file"""
return os.path.isfile(node.path)
def DoxyEmitter(source, target, env):
"""Doxygen Doxyfile emitter"""
# possible output formats and their default values and output locations
output_formats = {
"HTML": ("YES", "html"),
"LATEX": ("YES", "latex"),
"RTF": ("NO", "rtf"),
"MAN": ("NO", "man"),
"XML": ("NO", "xml"),
}
data = DoxyfileParse(source[0].get_contents())
targets = []
out_dir = data.get("OUTPUT_DIRECTORY", ".")
# add our output locations
for (k, v) in output_formats.items():
if data.get("GENERATE_" + k, v[0]) == "YES":
targets.append(env.Dir( os.path.join(out_dir, data.get(k + "_OUTPUT", v[1]))) )
# don't clobber targets
for node in targets:
env.Precious(node)
# set up cleaning stuff
for node in targets:
env.Clean(node, node)
return (targets, source)
def generate(env):
"""
Add builders and construction variables for the
Doxygen tool. This is currently for Doxygen 1.4.6.
"""
doxyfile_scanner = env.Scanner(
DoxySourceScan,
"DoxySourceScan",
scan_check = DoxySourceScanCheck,
)
import SCons.Builder
doxyfile_builder = SCons.Builder.Builder(
action = "cd ${SOURCE.dir} && (${DOXYGEN} ${SOURCE.file} 2>&1 |tee ,doxylog)",
emitter = DoxyEmitter,
target_factory = env.fs.Entry,
single_source = True,
source_scanner = doxyfile_scanner,
)
env.Append(BUILDERS = {
'Doxygen': doxyfile_builder,
})
env.AppendUnique(
DOXYGEN = 'doxygen',
)
def exists(env):
"""
Make sure doxygen exists.
"""
return env.Detect("doxygen")

View file

@ -18,8 +18,7 @@
# 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.
# along with this program; if not, see http://www.gnu.org/licenses/
#####################################################################
# history: 8/2008 adapted for Lumiera build system

View file

@ -1,2 +1,3 @@
,doxylog
warnings.txt
html/*

View file

@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = Lumiera
PROJECT_NUMBER = 3.0+alpha
PROJECT_NUMBER = 0.1+pre
OUTPUT_DIRECTORY =
CREATE_SUBDIRS = YES
OUTPUT_LANGUAGE = English
@ -32,7 +32,7 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
DETAILS_AT_TOP = YES
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
@ -65,8 +65,8 @@ CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = YES
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
@ -179,7 +179,7 @@ HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_FEEDNAME = "Lumiera Doxygen docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
HTML_DYNAMIC_SECTIONS = NO
CHM_FILE =

View file

@ -114,6 +114,11 @@ GtkLumiera& application();
*/
namespace dialogs {}
/**
* The namespace of data model classes.
*/
namespace model {}
/**
* The namespace of all video output implementations.
*/

View file

@ -140,16 +140,15 @@ style "timeline_ruler" = "default_base"
gtkmm__CustomObject_TimelineRuler::min_division_width = 100
gtkmm__CustomObject_TimelineRuler::mouse_chevron_size = 5
gtkmm__CustomObject_TimelineRuler::selection_chevron_size = 5
gtkmm__CustomObject_TimelineRuler::playback_arrow_colour = "#2D2D90"
gtkmm__CustomObject_TimelineRuler::playback_arrow_alpha = 0.5
gtkmm__CustomObject_TimelineRuler::playback_arrow_size = 10
gtkmm__CustomObject_TimelineRuler::playback_arrow_stem_size = 3
}
style "timeline_header_base" = "default_base"
{
# fg[NORMAL] = { 0.77, 0.77, 0.72 }
# bg[NORMAL] = { 0.18, 0.19, 0.22 }
# bg[ACTIVE] = { 0.20, 0.20, 0.20 }
# bg[PRELIGHT] = { 0.20, 0.20, 0.20 }
# bg[INSENSITIVE] = { 0.20, 0.20, 0.20 }
# bg[SELECTED] = { 0.20, 0.20, 0.20 }
}
class "gtkmm__CustomObject_TimelineBody" style:highest "timeline_body"

View file

@ -23,6 +23,10 @@
#include "../gtk-lumiera.hpp"
#include "timeline-panel.hpp"
extern "C" {
#include "../../lib/time.h"
}
using namespace Gtk;
using namespace sigc;
using namespace lumiera::gui::widgets;
@ -39,14 +43,24 @@ TimelinePanel::TimelinePanel() :
iBeamTool(Gtk::StockID("tool_i_beam")),
zoomIn(Stock::ZOOM_IN),
zoomOut(Stock::ZOOM_OUT),
timeIndicator(),
updatingToolbar(false)
{
// Setup the widget
timelineWidget.mouse_hover_signal().connect(
mem_fun(this, &TimelinePanel::on_mouse_hover));
// Setup the toolbar
timeIndicatorButton.set_label_widget(timeIndicator);
toolbar.append(timeIndicatorButton);
toolbar.append(seperator1);
toolbar.append(arrowTool, mem_fun(this,
&TimelinePanel::on_arrow_tool));
toolbar.append(iBeamTool, mem_fun(this,
&TimelinePanel::on_ibeam_tool));
toolbar.append(seperator1);
toolbar.append(seperator2);
toolbar.append(zoomIn, mem_fun(this, &TimelinePanel::on_zoom_in));
toolbar.append(zoomOut, mem_fun(this, &TimelinePanel::on_zoom_out));
@ -58,8 +72,10 @@ TimelinePanel::TimelinePanel() :
pack_start(toolbar, PACK_SHRINK);
pack_start(timelineWidget, PACK_EXPAND_WIDGET);
// Set the initial UI state
update_tool_buttons();
update_zoom_buttons();
show_time(0);
}
void
@ -93,6 +109,12 @@ TimelinePanel::on_zoom_out()
update_zoom_buttons();
}
void
TimelinePanel::on_mouse_hover(gavl_time_t time)
{
show_time(time);
}
void
TimelinePanel::update_tool_buttons()
{
@ -114,6 +136,12 @@ TimelinePanel::update_zoom_buttons()
TimelineWidget::MaxScale);
}
void
TimelinePanel::show_time(gavl_time_t time)
{
timeIndicator.set_text(lumiera_tmpbuf_print_time(time));
}
} // namespace panels
} // namespace gui
} // namespace lumiera

View file

@ -55,9 +55,15 @@ private:
void on_zoom_in();
void on_zoom_out();
void on_time_pressed();
void on_mouse_hover(gavl_time_t time);
private:
void update_tool_buttons();
void update_zoom_buttons();
void show_time(gavl_time_t time);
private:
@ -65,6 +71,7 @@ private:
// Widgets
Gtk::Toolbar toolbar;
Gtk::HBox toolStrip;
TimelineWidget timelineWidget;
// Toolbar Widgets
@ -76,6 +83,11 @@ private:
Gtk::ToolButton zoomIn;
Gtk::ToolButton zoomOut;
Gtk::SeparatorToolItem seperator2;
Gtk::Label timeIndicator;
Gtk::ToolButton timeIndicatorButton;
// Internals
bool updatingToolbar;

View file

@ -46,6 +46,8 @@ TimelineWidget::TimelineWidget() :
verticalAdjustment(0, 0, 0),
selectionStart(0),
selectionEnd(0),
playbackPeriodStart(0),
playbackPeriodEnd(0),
horizontalScroll(horizontalAdjustment),
verticalScroll(verticalAdjustment)
{
@ -108,7 +110,8 @@ TimelineWidget::set_time_offset(gavl_time_t time_offset)
timeOffset = time_offset;
horizontalAdjustment.set_value(time_offset);
ruler->update_view();
viewChangedSignal.emit();
}
int64_t
@ -127,7 +130,7 @@ TimelineWidget::set_time_scale(int64_t time_scale)
const int view_width = body->get_allocation().get_width();
horizontalAdjustment.set_page_size(timeScale * view_width);
ruler->update_view();
viewChangedSignal.emit();
}
void
@ -183,8 +186,12 @@ TimelineWidget::get_selection_end() const
}
void
TimelineWidget::set_selection(gavl_time_t start, gavl_time_t end)
TimelineWidget::set_selection(gavl_time_t start, gavl_time_t end,
bool reset_playback_period)
{
REQUIRE(ruler != NULL);
REQUIRE(body != NULL);
if(start < end)
{
selectionStart = start;
@ -196,6 +203,46 @@ TimelineWidget::set_selection(gavl_time_t start, gavl_time_t end)
selectionStart = end;
selectionEnd = start;
}
if(reset_playback_period)
{
playbackPeriodStart = selectionStart;
playbackPeriodEnd = selectionEnd;
}
ruler->queue_draw();
body->queue_draw();
}
gavl_time_t
TimelineWidget::get_playback_period_start() const
{
return playbackPeriodStart;
}
gavl_time_t
TimelineWidget::get_playback_period_end() const
{
return playbackPeriodEnd;
}
void
TimelineWidget::set_playback_period(gavl_time_t start, gavl_time_t end)
{
REQUIRE(ruler != NULL);
REQUIRE(body != NULL);
if(start < end)
{
playbackPeriodStart = start;
playbackPeriodEnd = end;
}
else
{
// The period is back-to-front, flip it round
playbackPeriodStart = end;
playbackPeriodEnd = start;
}
ruler->queue_draw();
body->queue_draw();
@ -215,11 +262,23 @@ TimelineWidget::set_tool(ToolType tool_type)
body->set_tool(tool_type);
}
sigc::signal<void>
TimelineWidget::view_changed_signal() const
{
return viewChangedSignal;
}
sigc::signal<void, gavl_time_t>
TimelineWidget::mouse_hover_signal() const
{
return mouseHoverSignal;
}
void
TimelineWidget::on_scroll()
{
timeOffset = horizontalAdjustment.get_value();
ruler->update_view();
viewChangedSignal.emit();
}
void
@ -309,6 +368,7 @@ TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event)
{
REQUIRE(event != NULL);
ruler->set_mouse_chevron_offset(event->x);
mouseHoverSignal.emit(x_to_time(event->x));
return true;
}

View file

@ -120,8 +120,30 @@ public:
/**
* Sets the period of the selection.
* @param start The start time.
* @param end The end time.
* @param reset_playback_period Specifies whether to set the playback
* period to the same as this new selection.
*/
void set_selection(gavl_time_t start, gavl_time_t end);
void set_selection(gavl_time_t start, gavl_time_t end,
bool reset_playback_period = true);
/**
* Gets the time at which the playback period begins.
*/
gavl_time_t get_playback_period_start() const;
/**
* Gets the time at which the playback period ends.
*/
gavl_time_t get_playback_period_end() const;
/**
* Sets the playback period.
* @param start The start time.
* @param end The end time.
*/
void set_playback_period(gavl_time_t start, gavl_time_t end);
/**
* Gets the type of the tool currently active.
@ -132,6 +154,12 @@ public:
* Sets the type of the tool currently active.
*/
void set_tool(timeline::ToolType tool_type);
public:
/* ===== Signals ===== */
sigc::signal<void> view_changed_signal() const;
sigc::signal<void, gavl_time_t> mouse_hover_signal() const;
/* ===== Events ===== */
protected:
@ -165,6 +193,8 @@ protected:
// Selection State
gavl_time_t selectionStart;
gavl_time_t selectionEnd;
gavl_time_t playbackPeriodStart;
gavl_time_t playbackPeriodEnd;
int totalHeight;
@ -179,9 +209,18 @@ protected:
Gtk::Adjustment horizontalAdjustment, verticalAdjustment;
Gtk::HScrollbar horizontalScroll;
Gtk::VScrollbar verticalScroll;
// Signals
sigc::signal<void> viewChangedSignal;
sigc::signal<void, gavl_time_t> mouseHoverSignal;
/* ===== Constants ===== */
public:
/**
* The maximum scale for timeline display.
* @remarks At MaxScale, every pixel on the timeline is equivalent
* to 30000000 gavl_time_t increments.
*/
static const int64_t MaxScale;
protected:

View file

@ -55,10 +55,8 @@ TimelineBody::TimelineBody(lumiera::gui::widgets::TimelineWidget
REQUIRE(timelineWidget != NULL);
// Connect up some events
timelineWidget->horizontalAdjustment.signal_value_changed().connect(
sigc::mem_fun(this, &TimelineBody::on_scroll) );
timelineWidget->verticalAdjustment.signal_value_changed().connect(
sigc::mem_fun(this, &TimelineBody::on_scroll) );
timelineWidget->view_changed_signal().connect(sigc::mem_fun(
this, &TimelineBody::on_update_view) );
// Install style properties
register_styles();
@ -109,6 +107,12 @@ TimelineBody::set_tool(timeline::ToolType tool_type)
tool->apply_cursor();
}
void
TimelineBody::on_update_view()
{
queue_draw();
}
void
TimelineBody::on_realize()
{
@ -125,112 +129,6 @@ TimelineBody::on_realize()
tool->apply_cursor();
}
void
TimelineBody::on_scroll()
{
queue_draw();
}
bool
TimelineBody::on_scroll_event (GdkEventScroll* event)
{
REQUIRE(event != NULL);
REQUIRE(timelineWidget != NULL);
if(event->state & GDK_CONTROL_MASK)
{
switch(event->direction)
{
case GDK_SCROLL_UP:
// User scrolled up. Zoom in
timelineWidget->zoom_view(event->x, 16);
break;
case GDK_SCROLL_DOWN:
// User scrolled down. Zoom out
timelineWidget->zoom_view(event->x, -16);
break;
}
}
else
{
switch(event->direction)
{
case GDK_SCROLL_UP:
// User scrolled up. Shift 1/16th left
timelineWidget->shift_view(-16);
break;
case GDK_SCROLL_DOWN:
// User scrolled down. Shift 1/16th right
timelineWidget->shift_view(16);
break;
}
}
}
bool
TimelineBody::on_button_press_event(GdkEventButton* event)
{
mouseDownX = event->x;
mouseDownY = event->y;
switch(event->button)
{
case 2:
begin_shift_drag();
break;
default:
dragType = None;
break;
}
// Forward the event to the tool
tool->on_button_press_event(event);
return true;
}
bool
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)
{
case Shift:
{
const int64_t scale = timelineWidget->get_time_scale();
gavl_time_t offset = beginShiftTimeOffset +
(int64_t)(mouseDownX - event->x) * scale;
timelineWidget->set_time_offset(offset);
set_vertical_offset((int)(mouseDownY - event->y) +
beginShiftVerticalOffset);
break;
}
}
// 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;
}
bool
TimelineBody::on_expose_event(GdkEventExpose* event)
{
@ -323,6 +221,106 @@ TimelineBody::on_expose_event(GdkEventExpose* event)
return true;
}
bool
TimelineBody::on_scroll_event (GdkEventScroll* event)
{
REQUIRE(event != NULL);
REQUIRE(timelineWidget != NULL);
if(event->state & GDK_CONTROL_MASK)
{
switch(event->direction)
{
case GDK_SCROLL_UP:
// User scrolled up. Zoom in
timelineWidget->zoom_view(event->x, 1);
break;
case GDK_SCROLL_DOWN:
// User scrolled down. Zoom out
timelineWidget->zoom_view(event->x, -1);
break;
}
}
else
{
switch(event->direction)
{
case GDK_SCROLL_UP:
// User scrolled up. Shift 1/16th left
timelineWidget->shift_view(-16);
break;
case GDK_SCROLL_DOWN:
// User scrolled down. Shift 1/16th right
timelineWidget->shift_view(16);
break;
}
}
}
bool
TimelineBody::on_button_press_event(GdkEventButton* event)
{
mouseDownX = event->x;
mouseDownY = event->y;
switch(event->button)
{
case 2:
begin_shift_drag();
break;
default:
dragType = None;
break;
}
// Forward the event to the tool
tool->on_button_press_event(event);
return true;
}
bool
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)
{
case Shift:
{
const int64_t scale = timelineWidget->get_time_scale();
gavl_time_t offset = beginShiftTimeOffset +
(int64_t)(mouseDownX - event->x) * scale;
timelineWidget->set_time_offset(offset);
set_vertical_offset((int)(mouseDownY - event->y) +
beginShiftVerticalOffset);
break;
}
}
// 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;
}
void
TimelineBody::begin_shift_drag()
@ -349,23 +347,18 @@ TimelineBody::register_styles() const
{
GtkWidgetClass *klass = GTK_WIDGET_CLASS(G_OBJECT_GET_CLASS(gobj()));
gtk_widget_class_install_style_property(
GTK_WIDGET_CLASS(G_OBJECT_GET_CLASS(gobj())),
g_param_spec_boxed("background",
"Track Background",
gtk_widget_class_install_style_property(klass,
g_param_spec_boxed("background", "Track Background",
"The background colour of timeline tracks",
GDK_TYPE_COLOR, G_PARAM_READABLE));
gtk_widget_class_install_style_property(
GTK_WIDGET_CLASS(G_OBJECT_GET_CLASS(gobj())),
g_param_spec_boxed("selection",
"End lines of a selection",
gtk_widget_class_install_style_property(klass,
g_param_spec_boxed("selection", "End lines of a selection",
"The colour of selection limit lines",
GDK_TYPE_COLOR, G_PARAM_READABLE));
gtk_widget_class_install_style_property(klass,
g_param_spec_float("selection_alpha",
"Selection Alpha",
g_param_spec_float("selection_alpha", "Selection Alpha",
"The transparency of the selection marque.",
0, 1.0, 0.5, G_PARAM_READABLE));
}

View file

@ -37,33 +37,72 @@ class TimelineWidget;
namespace timeline {
/**
* Implementation of the timeline body subwidget. This widget is
* displayed in the centre of the timeline widget, and displays the
* content of all timeline tracks.
*/
class TimelineBody : public Gtk::DrawingArea
{
public:
/**
* Constructor
* @param timeline_widget The owner widget of this ruler.
*/
TimelineBody(lumiera::gui::widgets::TimelineWidget *timeline_widget);
/**
* Destructor
*/
~TimelineBody();
/**
* Returns the type of the currently selected timeline tool.
*/
ToolType get_tool() const;
/**
* Selects a tool of a specified type.
* @param tool_type The type of tool to set.
*/
void set_tool(ToolType tool_type);
/* ===== Events ===== */
protected:
void on_realize();
void on_scroll();
/**
* An event handler for when the view window of the timeline changes.
*/
void on_update_view();
/**
* An event handler for when the widget is realized.
*/
void on_realize();
/**
* An event handler for when the window must be redrawn.
*/
bool on_expose_event(GdkEventExpose* event);
bool on_scroll_event(GdkEventScroll* event);
bool on_button_press_event (GdkEventButton* event);
/**
* The event handler for button press events.
*/
bool on_button_press_event(GdkEventButton* event);
bool on_button_release_event (GdkEventButton* event);
/**
* The event handler for button release events.
*/
bool on_button_release_event(GdkEventButton* event);
/**
* The event handler for mouse move events.
*/
bool on_motion_notify_event(GdkEventMotion *event);
bool on_expose_event(GdkEventExpose* event);
/* ===== Internals ===== */
private:
void begin_shift_drag();
@ -72,8 +111,14 @@ private:
void set_vertical_offset(int offset);
/**
* Registers all the styles that this class will respond to.
*/
void register_styles() const;
/**
* Reads styles from the present stylesheet.
*/
void read_styles();
private:

View file

@ -90,6 +90,7 @@ IBeamTool::on_button_press_event(GdkEventButton* event)
Tool::on_button_press_event(event);
TimelineWidget *timeline_widget = get_timeline_widget();
REQUIRE(timeline_widget != NULL);
if(event->button == 1)
{
@ -181,12 +182,16 @@ void
IBeamTool::set_leading_x(const int x)
{
TimelineWidget *timeline_widget = get_timeline_widget();
REQUIRE(timeline_widget != NULL);
const bool set_playback_period = dragType == Selection;
const gavl_time_t time = timeline_widget->x_to_time(x);
if(time > pinnedDragTime)
timeline_widget->set_selection(pinnedDragTime, time);
timeline_widget->set_selection(
pinnedDragTime, time, set_playback_period);
else
timeline_widget->set_selection(time, pinnedDragTime);
timeline_widget->set_selection(
time, pinnedDragTime, set_playback_period);
}
void

View file

@ -45,6 +45,8 @@ namespace timeline {
TimelineRuler::TimelineRuler(
lumiera::gui::widgets::TimelineWidget *timeline_widget) :
Glib::ObjectBase("TimelineRuler"),
isDragging(false),
pinnedDragTime(0),
mouseChevronOffset(0),
annotationHorzMargin(0),
annotationVertMargin(0),
@ -54,10 +56,17 @@ TimelineRuler::TimelineRuler(
minDivisionWidth(100),
mouseChevronSize(5),
selectionChevronSize(5),
playbackArrowAlpha(0.5f),
playbackArrowSize(10),
playbackArrowStemSize(3),
timelineWidget(timeline_widget)
{
REQUIRE(timelineWidget != NULL);
// Connect event handlers
timelineWidget->view_changed_signal().connect(sigc::mem_fun(
this, &TimelineRuler::on_update_view) );
// Install style properties
register_styles();
}
@ -70,7 +79,7 @@ TimelineRuler::set_mouse_chevron_offset(int offset)
}
void
TimelineRuler::update_view()
TimelineRuler::on_update_view()
{
rulerImage.clear();
queue_draw();
@ -82,7 +91,10 @@ TimelineRuler::on_realize()
Widget::on_realize();
// Set event notifications
add_events(Gdk::POINTER_MOTION_MASK | Gdk::SCROLL_MASK);
add_events(Gdk::POINTER_MOTION_MASK |
Gdk::SCROLL_MASK |
Gdk::BUTTON_PRESS_MASK |
Gdk::BUTTON_RELEASE_MASK);
// Load styles
read_styles();
@ -130,16 +142,47 @@ TimelineRuler::on_expose_event(GdkEventExpose* event)
// Draw the overlays
draw_mouse_chevron(cr, allocation);
draw_selection(cr, allocation);
draw_playback_period(cr, allocation);
return true;
}
bool
TimelineRuler::on_button_press_event(GdkEventButton* event)
{
REQUIRE(event != NULL);
if(event->button == 1)
{
pinnedDragTime = timelineWidget->x_to_time(event->x);
isDragging = true;
}
return true;
}
bool
TimelineRuler::on_button_release_event(GdkEventButton* event)
{
REQUIRE(event != NULL);
if(event->button == 1)
isDragging = false;
return true;
}
bool
TimelineRuler::on_motion_notify_event(GdkEventMotion *event)
{
REQUIRE(event != NULL);
set_mouse_chevron_offset(event->x);
if(isDragging)
set_leading_x(event->x);
return true;
}
@ -162,6 +205,18 @@ TimelineRuler::on_size_allocate(Gtk::Allocation& allocation)
rulerImage.clear(); // The widget has changed size - redraw
}
void
TimelineRuler::set_leading_x(const int x)
{
REQUIRE(timelineWidget != NULL);
const gavl_time_t time = timelineWidget->x_to_time(x);
if(time > pinnedDragTime)
timelineWidget->set_playback_period(pinnedDragTime, time);
else
timelineWidget->set_playback_period(time, pinnedDragTime);
}
void
TimelineRuler::draw_ruler(Cairo::RefPtr<Cairo::Context> cr,
const Gdk::Rectangle ruler_rect)
@ -171,8 +226,8 @@ TimelineRuler::draw_ruler(Cairo::RefPtr<Cairo::Context> cr,
REQUIRE(ruler_rect.get_height() > 0);
REQUIRE(timelineWidget != NULL);
const gavl_time_t left_offset = timelineWidget->timeOffset;
const int64_t time_scale = timelineWidget->timeScale;
const gavl_time_t left_offset = timelineWidget->get_time_offset();
const int64_t time_scale = timelineWidget->get_time_scale();
// Preparation steps
const int height = ruler_rect.get_height();
@ -299,6 +354,74 @@ TimelineRuler::draw_selection(Cairo::RefPtr<Cairo::Context> cr,
}
}
void
TimelineRuler::draw_playback_period(Cairo::RefPtr<Cairo::Context> cr,
const Gdk::Rectangle ruler_rect)
{
REQUIRE(cr);
REQUIRE(ruler_rect.get_width() > 0);
REQUIRE(ruler_rect.get_height() > 0);
REQUIRE(timelineWidget != NULL);
// Calculate coordinates
const float halfSize = playbackArrowSize / 2;
const float a = timelineWidget->time_to_x(
timelineWidget->playbackPeriodStart) + 1 + 0.5f;
const float b = a + halfSize;
const float d = timelineWidget->time_to_x(
timelineWidget->playbackPeriodEnd) + 0.5f;
const float c = d - halfSize;
const float e = ruler_rect.get_height() - playbackArrowSize - 0.5f;
const float f = e + (playbackArrowSize - playbackArrowStemSize) / 2;
const float g = ruler_rect.get_height() - playbackArrowSize / 2
- 0.5f;
const float i = ruler_rect.get_height() - 0.5f;
const float h = i - (playbackArrowSize - playbackArrowStemSize) / 2;
// Contruct the path
if(d - a >= playbackArrowSize)
{
// Draw an arrow: <===>
cr->move_to(a, g);
cr->line_to(b, e);
cr->line_to(b, f);
cr->line_to(c, f);
cr->line_to(c, e);
cr->line_to(d, g);
cr->line_to(c, i);
cr->line_to(c, h);
cr->line_to(b, h);
cr->line_to(b, i);
cr->line_to(a, g);
}
else
{
// The space is too narrow for an arrow, so draw calipers: > <
cr->move_to(a, g);
cr->rel_line_to(-halfSize, -halfSize);
cr->rel_line_to(0, playbackArrowSize);
cr->move_to(d, g);
cr->rel_line_to(halfSize, -halfSize);
cr->rel_line_to(0, playbackArrowSize);
}
// Fill
cr->set_source_rgba(
(float)playbackArrowColour.red / 0xFFFF,
(float)playbackArrowColour.green / 0xFFFF,
(float)playbackArrowColour.blue / 0xFFFF,
playbackArrowAlpha);
cr->fill_preserve();
// Stroke
gdk_cairo_set_source_color(cr->cobj(), &playbackArrowColour);
cr->set_line_width(1);
cr->stroke();
}
gavl_time_t
TimelineRuler::calculate_major_spacing() const
{
@ -402,6 +525,29 @@ TimelineRuler::register_styles() const
"Selection Chevron Size",
"The height of the selection chevrons in pixels.",
0, G_MAXINT, 5, G_PARAM_READABLE));
gtk_widget_class_install_style_property(klass,
g_param_spec_boxed("playback_arrow_colour",
"End lines of a selection",
"The colour of selection limit lines",
GDK_TYPE_COLOR, G_PARAM_READABLE));
gtk_widget_class_install_style_property(klass,
g_param_spec_float("playback_arrow_alpha", "Playback Arrow Alpha",
"The transparency of the playback period arrow.",
0, 1.0, 0.5, G_PARAM_READABLE));
gtk_widget_class_install_style_property(klass,
g_param_spec_int("playback_arrow_size",
"Playback Arrow Head Size",
"The height of the playback arrow head in pixels.",
0, G_MAXINT, 10, G_PARAM_READABLE));
gtk_widget_class_install_style_property(klass,
g_param_spec_int("playback_arrow_stem_size",
"Playback Arrow Stem Size",
"The height of the playback arrow head in pixels.",
0, G_MAXINT, 3, G_PARAM_READABLE));
}
void
@ -415,6 +561,13 @@ TimelineRuler::read_styles()
get_style_property("min_division_width", minDivisionWidth);
get_style_property("mouse_chevron_size", mouseChevronSize);
get_style_property("selection_chevron_size", selectionChevronSize);
playbackArrowColour = WindowManager::read_style_colour_property(
*this, "playback_arrow_colour", 0, 0, 0);
get_style_property("playback_arrow_alpha", playbackArrowAlpha);
get_style_property("playback_arrow_size", playbackArrowSize);
get_style_property("playback_arrow_stem_size",
playbackArrowStemSize);
}
} // namespace timeline

View file

@ -37,54 +37,154 @@ class TimelineWidget;
namespace timeline {
/**
* A subwidget of the TimelineWidget. This class implements a ruler
* which is placed along the top edge of the timeline.
*/
class TimelineRuler : public Gtk::DrawingArea
{
public:
/**
* Constructor
* @param timeline_widget The owner widget of this ruler.
*/
TimelineRuler(
lumiera::gui::widgets::TimelineWidget *timeline_widget);
/**
* Sets the offset of the mouse chevron in pixels from the left
* edge of the widget. If offset is less than 0 or greater than the
* width, the chevron will not be visible.
* Sets offset of the mouse chevron
* @param offset The offset of the mouse chevron in pixels from the
* left edge of the widget. If offset is less than 0 or greater than
* the width, the chevron will not be visible.
*/
void set_mouse_chevron_offset(int offset);
void update_view();
/* ===== Events ===== */
protected:
private:
/**
* An event handler for when the view window of the timeline changes.
* @remarks Causes the ruler to be redrawn from scratch. The cached
* ruler backdrop is destroyed and redrawn.
*/
void on_update_view();
/**
* An event handler for when the widget is realized.
*/
void on_realize();
/**
* An event handler for when the window must be redrawn.
*/
bool on_expose_event(GdkEventExpose *event);
/**
* The event handler for button press events.
*/
bool on_button_press_event(GdkEventButton* event);
/**
* The event handler for button release events.
*/
bool on_button_release_event(GdkEventButton* event);
/**
* The event handler for mouse move events.
*/
bool on_motion_notify_event(GdkEventMotion *event);
/**
* The handler for when the widget must calculate it's new shape.
*/
void on_size_request(Gtk::Requisition *requisition);
/**
* The handler for when the widget must take the size of a given
* area.
*/
void on_size_allocate(Gtk::Allocation& allocation);
/* ===== Internals ===== */
private:
void draw_ruler(Cairo::RefPtr<Cairo::Context> cairo,
/* ===== Internal Methods ===== */
/**
* As the user drags, this function is called to update the position
* of the moving end of the playback period.
*/
void set_leading_x(const int x);
/**
* Draws the ruler graduations.
* @param cr The cairo context to draw the ruler into.
* @param ruler_rect The area of the ruler widget.
*/
void draw_ruler(Cairo::RefPtr<Cairo::Context> cr,
const Gdk::Rectangle ruler_rect);
/**
* Overlays the mouse chevron.
* @param cr The cairo context to draw the chevron into.
* @param ruler_rect The area of the ruler widget.
*/
void draw_mouse_chevron(Cairo::RefPtr<Cairo::Context> cr,
const Gdk::Rectangle ruler_rect);
/**
* Overlays the currently selected period.
* @param cr The cairo context to draw the selection into.
* @param ruler_rect The area of the ruler widget.
*/
void draw_selection(Cairo::RefPtr<Cairo::Context> cr,
const Gdk::Rectangle ruler_rect);
gavl_time_t calculate_major_spacing() const;
/**
* Overlays the currently selected playback period.
* @param cr The cairo context to draw the period into.
* @param ruler_rect The area of the ruler widget.
*/
void draw_playback_period(Cairo::RefPtr<Cairo::Context> cr,
const Gdk::Rectangle ruler_rect);
/**
* Given the current zoom, this function calculates the preiod
* between major graduations on the ruler scale.
* @return The period as a gavl_time_t
*/
gavl_time_t calculate_major_spacing() const;
/**
* Registers all the styles that this class will respond to.
*/
void register_styles() const;
/**
* Reads styles from the present stylesheet.
*/
void read_styles();
private:
// State values
/**
* This value is set to true if the user is dragging with the left
* mouse button.
*/
bool isDragging;
/**
* 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;
// Indicated values
/**
* The offset from the left of the control in pixels to draw the
* mouse chevron. If offset is less than 0 or greater than
* the width, the chevron will not be visible.
*/
int mouseChevronOffset;
// Style values
@ -96,11 +196,23 @@ private:
int minDivisionWidth;
int mouseChevronSize;
int selectionChevronSize;
// Owner
GdkColor playbackArrowColour;
float playbackArrowAlpha;
int playbackArrowSize;
int playbackArrowStemSize;
/**
* The owner widget
*/
lumiera::gui::widgets::TimelineWidget *timelineWidget;
// Cached ruler image
/**
* The caches image of the ruler, over which the chevrons etc. will
* be drawn.
* @remarks This backdrop is cached because it changes relatively
* infrequently in comparison to the chevrons, thus improving
* performance somewhat.
*/
Cairo::RefPtr<Cairo::ImageSurface> rulerImage;
};

View file

@ -95,14 +95,17 @@ Actions::Actions(WorkspaceWindow &workspace_window) :
void
Actions::update_action_state()
{
REQUIRE(workspaceWindow.assets_panel != NULL);
REQUIRE(workspaceWindow.timeline_panel != NULL);
REQUIRE(workspaceWindow.viewer_panel != NULL);
REQUIRE(workspaceWindow.assetsPanel != NULL);
REQUIRE(workspaceWindow.timelinePanel != NULL);
REQUIRE(workspaceWindow.viewerPanel != NULL);
is_updating_action_state = true;
assetsPanelAction->set_active(workspaceWindow.assets_panel->is_shown());
timelinePanelAction->set_active(workspaceWindow.timeline_panel->is_shown());
viewerPanelAction->set_active(workspaceWindow.viewer_panel->is_shown());
assetsPanelAction->set_active(
workspaceWindow.assetsPanel->is_shown());
timelinePanelAction->set_active(
workspaceWindow.timelinePanel->is_shown());
viewerPanelAction->set_active(
workspaceWindow.viewerPanel->is_shown());
is_updating_action_state = false;
}
@ -148,21 +151,21 @@ void
Actions::on_menu_view_assets()
{
if(!is_updating_action_state)
workspaceWindow.assets_panel->show(assetsPanelAction->get_active());
workspaceWindow.assetsPanel->show(assetsPanelAction->get_active());
}
void
Actions::on_menu_view_timeline()
{
if(!is_updating_action_state)
workspaceWindow.timeline_panel->show(timelinePanelAction->get_active());
workspaceWindow.timelinePanel->show(timelinePanelAction->get_active());
}
void
Actions::on_menu_view_viewer()
{
if(!is_updating_action_state)
workspaceWindow.viewer_panel->show(viewerPanelAction->get_active());
workspaceWindow.viewerPanel->show(viewerPanelAction->get_active());
}
void

View file

@ -49,9 +49,9 @@ WorkspaceWindow::WorkspaceWindow(Project *source_project) :
REQUIRE(source_project != NULL);
layout = NULL;
assets_panel = NULL;
viewer_panel = NULL;
timeline_panel = NULL;
assetsPanel = NULL;
viewerPanel = NULL;
timelinePanel = NULL;
create_ui();
}
@ -61,12 +61,12 @@ WorkspaceWindow::~WorkspaceWindow()
REQUIRE(layout != NULL);
g_object_unref(layout);
REQUIRE(assets_panel != NULL);
assets_panel->unreference();
REQUIRE(viewer_panel != NULL);
viewer_panel->unreference();
REQUIRE(timeline_panel != NULL);
timeline_panel->unreference();
REQUIRE(assetsPanel != NULL);
assetsPanel->unreference();
REQUIRE(viewerPanel != NULL);
viewerPanel->unreference();
REQUIRE(timelinePanel != NULL);
timelinePanel->unreference();
}
void
@ -78,7 +78,7 @@ WorkspaceWindow::create_ui()
//----- Set up the UI Manager -----//
// The UI will be nested within a VBox
add(base_container);
add(baseContainer);
uiManager = Gtk::UIManager::create();
uiManager->insert_action_group(actions.actionGroup);
@ -131,21 +131,22 @@ WorkspaceWindow::create_ui()
//----- Set up the Menu Bar -----//
Gtk::Widget* menu_bar = uiManager->get_widget("/MenuBar");
ASSERT(menu_bar != NULL);
base_container.pack_start(*menu_bar, Gtk::PACK_SHRINK);
baseContainer.pack_start(*menu_bar, Gtk::PACK_SHRINK);
//----- Set up the Tool Bar -----//
Gtk::Toolbar* toolbar = dynamic_cast<Gtk::Toolbar*>(uiManager->get_widget("/ToolBar"));
Gtk::Toolbar* toolbar = dynamic_cast<Gtk::Toolbar*>(
uiManager->get_widget("/ToolBar"));
ASSERT(toolbar != NULL);
toolbar->set_toolbar_style(TOOLBAR_ICONS);
base_container.pack_start(*toolbar, Gtk::PACK_SHRINK);
baseContainer.pack_start(*toolbar, Gtk::PACK_SHRINK);
//----- Create the Panels -----//
assets_panel = new AssetsPanel();
ENSURE(assets_panel != NULL);
viewer_panel = new ViewerPanel();
ENSURE(viewer_panel != NULL);
timeline_panel = new TimelinePanel();
ENSURE(timeline_panel != NULL);
assetsPanel = new AssetsPanel();
ENSURE(assetsPanel != NULL);
viewerPanel = new ViewerPanel();
ENSURE(viewerPanel != NULL);
timelinePanel = new TimelinePanel();
ENSURE(timelinePanel != NULL);
//----- Create the Dock -----//
dock = Glib::wrap(gdl_dock_new());
@ -154,30 +155,41 @@ WorkspaceWindow::create_ui()
dockbar = Glib::wrap(gdl_dock_bar_new ((GdlDock*)dock->gobj()));
dock_container.pack_start(*dockbar, PACK_SHRINK);
dock_container.pack_end(*dock, PACK_EXPAND_WIDGET);
base_container.pack_start(dock_container, PACK_EXPAND_WIDGET);
dockContainer.pack_start(*dockbar, PACK_SHRINK);
dockContainer.pack_end(*dock, PACK_EXPAND_WIDGET);
baseContainer.pack_start(dockContainer, PACK_EXPAND_WIDGET);
gdl_dock_add_item ((GdlDock*)dock->gobj(), assets_panel->get_dock_item(), GDL_DOCK_LEFT);
gdl_dock_add_item ((GdlDock*)dock->gobj(), viewer_panel->get_dock_item(), GDL_DOCK_RIGHT);
gdl_dock_add_item ((GdlDock*)dock->gobj(), timeline_panel->get_dock_item(), GDL_DOCK_BOTTOM);
gdl_dock_add_item ((GdlDock*)dock->gobj(),
assetsPanel->get_dock_item(), GDL_DOCK_LEFT);
gdl_dock_add_item ((GdlDock*)dock->gobj(),
viewerPanel->get_dock_item(), GDL_DOCK_RIGHT);
gdl_dock_add_item ((GdlDock*)dock->gobj(),
timelinePanel->get_dock_item(), GDL_DOCK_BOTTOM);
// Manually dock and move around some of the items
gdl_dock_item_dock_to (timeline_panel->get_dock_item(),
assets_panel->get_dock_item(), GDL_DOCK_BOTTOM, -1);
gdl_dock_item_dock_to (viewer_panel->get_dock_item(),
assets_panel->get_dock_item(), GDL_DOCK_RIGHT, -1);
show_all_children();
gdl_dock_item_dock_to (timelinePanel->get_dock_item(),
assetsPanel->get_dock_item(), GDL_DOCK_BOTTOM, -1);
gdl_dock_item_dock_to (viewerPanel->get_dock_item(),
assetsPanel->get_dock_item(), GDL_DOCK_RIGHT, -1);
gchar ph1[] = "ph1";
gdl_dock_placeholder_new (ph1, (GdlDockObject*)dock->gobj(), GDL_DOCK_TOP, FALSE);
gdl_dock_placeholder_new (ph1, (GdlDockObject*)dock->gobj(),
GDL_DOCK_TOP, FALSE);
gchar ph2[] = "ph2";
gdl_dock_placeholder_new (ph2, (GdlDockObject*)dock->gobj(), GDL_DOCK_BOTTOM, FALSE);
gdl_dock_placeholder_new (ph2, (GdlDockObject*)dock->gobj(),
GDL_DOCK_BOTTOM, FALSE);
gchar ph3[] = "ph3";
gdl_dock_placeholder_new (ph3, (GdlDockObject*)dock->gobj(), GDL_DOCK_LEFT, FALSE);
gdl_dock_placeholder_new (ph3, (GdlDockObject*)dock->gobj(),
GDL_DOCK_LEFT, FALSE);
gchar ph4[] = "ph4";
gdl_dock_placeholder_new (ph4, (GdlDockObject*)dock->gobj(), GDL_DOCK_RIGHT, FALSE);
gdl_dock_placeholder_new (ph4, (GdlDockObject*)dock->gobj(),
GDL_DOCK_RIGHT, FALSE);
//----- Create the status bar -----//
statusBar.set_has_resize_grip();
baseContainer.pack_start(statusBar, PACK_SHRINK);
show_all_children();
}
} // namespace workspace

View file

@ -56,7 +56,8 @@ class WorkspaceWindow : public Gtk::Window
{
public:
WorkspaceWindow(lumiera::gui::model::Project *source_project);
virtual ~WorkspaceWindow();
~WorkspaceWindow();
private:
void create_ui();
@ -68,18 +69,22 @@ private:
/* ===== UI ===== */
private:
Glib::RefPtr<Gtk::UIManager> uiManager;
Gtk::VBox base_container;
Gtk::HBox dock_container;
Gtk::VBox baseContainer;
Gtk::HBox dockContainer;
//----- Dock Frame -----//
Gtk::Widget *dock;
Gtk::Widget *dockbar;
GdlDockLayout *layout;
//----- Status Bar -----//
Gtk::Statusbar statusBar;
/* ===== Panels ===== */
private:
AssetsPanel *assets_panel;
ViewerPanel *viewer_panel;
TimelinePanel *timeline_panel;
AssetsPanel *assetsPanel;
ViewerPanel *viewerPanel;
TimelinePanel *timelinePanel;
/* ===== Helpers ===== */
private:

BIN
wiki/draw/LumiLogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -2150,16 +2150,16 @@ This distributed wiki might be used instead the pipapo.org wiki, investigate tha
Wiki works. It is simple to use and just flexible enough to handle the task. I don't go to install any other software for such tasks on my server. While the design progresses I'd propose to move our work into git repositories and eventually phase this wiki pages out anyways. I'd rather like to start out distributed/git right away .. but git gives us only a fine storage layer, for a design process we need some good presentation layer (later when using git and starting the implementation everyones favorite editor serves for that) I have no better ideas yet to solve the presentation problem other than using this wiki (or maybe Bouml).
</pre>
</div>
<div title="LumieraWiki" modifier="Ichthyostega" modified="200805200606" created="200706172308" tags="portal" changecount="34">
<pre>This is the entry point to several [[TiddlyWiki]]-Pages containing the developer and design documentation for Lumiera.
<div title="LumieraWiki" modifier="Ichthyostega" modified="200808280150" created="200706172308" tags="portal" changecount="41">
<pre>[&lt;img[draw/LumiLogo.png]]
* Cehteh started GitNotes where we will collect some information about git, howto and special setups
* since we prefer gpg signed tags in git and not each developer knows gpg well here is a Micro-GPG-HowTo
''Lumiera'' is the emerging professional non linear video editor for Linux
This is the entry point to several [[TiddlyWiki]]-Pages containing the developer and design documentation.
* we maintain (semi-) final design docs in DesignDocumentation
* Things get often worked out on IRC, see IRC-Transcripts for decisions made there and not yet put into the proper documentation places
Please __end your tiddlers in a newline__, this makes merging in git easier since the /pre tag used in tiddlywiki will become on a single line.
----
!Architecture and Subsystems
to get started, we create design drafts emphasizing different aspects and regions of Lumiera