diff --git a/Makefile.am b/Makefile.am index e6f29bf97..3cf851c55 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,6 @@ # Copyright (C) Lumiera.org # 2007, Christian Thaeter +# 2008, Joel Holdsworth # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -38,9 +39,15 @@ include $(top_srcdir)/src/common/Makefile.am include $(top_srcdir)/src/lib/Makefile.am include $(top_srcdir)/src/backend/Makefile.am +# gui +include $(top_srcdir)/src/gui/Makefile.am + # plugins #include $(top_srcdir)/src... +# resources +include $(top_srcdir)/icons/Makefile.am + # tests include $(top_srcdir)/tests/common/Makefile.am include $(top_srcdir)/tests/components/Makefile.am diff --git a/SConstruct b/SConstruct index 34d494b88..47dc7ef8a 100644 --- a/SConstruct +++ b/SConstruct @@ -291,6 +291,15 @@ def defineBuildTargets(env, artifacts): artifacts['lumiera'] = env.Program('$BINDIR/lumiera', ['$SRCDIR/main.cpp']+ core ) artifacts['plugins'] = env.SharedLibrary('$BINDIR/lumiera-plugin', objplug) + # the Lumiera GTK GUI + envgtk = env.Clone().mergeConf(['gtkmm-2.4','cairomm-1.0','gdl-1.0','xv','xext','sm']) + objgui = srcSubtree(envgtk,'$SRCDIR/gui') + + artifacts['lumigui'] = ( envgtk.Program('$BINDIR/lumigui', objgui + core) + + env.Install('$BINDIR', env.Glob('$ICONDIR/*.png')) + + env.Install('$BINDIR', env.Glob('$SRCDIR/gui/*.rc')) + ) + # call subdir SConscript(s) for independent components SConscript(dirs=[SRCDIR+'/tool'], exports='env artifacts core') SConscript(dirs=[TESTDIR], exports='env artifacts core') @@ -305,7 +314,7 @@ def definePostBuildTargets(env, artifacts): il = env.Alias('install-lib', '$DESTDIR/lib') env.Alias('install', [ib, il]) - build = env.Alias('build', artifacts['lumiera']+artifacts['plugins']+artifacts['tools']) + build = env.Alias('build', artifacts['lumiera']+artifacts['lumigui']+artifacts['plugins']+artifacts['tools']) allbu = env.Alias('allbuild', build+artifacts['testsuite']) env.Default('build') # additional files to be cleaned when cleaning 'build' diff --git a/admin/Makefile.am b/admin/Makefile.am index 6385eb910..9eb4fbb89 100644 --- a/admin/Makefile.am +++ b/admin/Makefile.am @@ -22,3 +22,7 @@ vgsuppression_SOURCES = $(admin_srcdir)/vgsuppression.c vgsuppression_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/ vgsuppression_LDADD = liblumi.a -lnobugmt -lpthread -ldl +noinst_PROGRAMS += rsvg-convert +rsvg_convert_SOURCES = $(admin_srcdir)/rsvg-convert.c +rsvg_convert_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror +rsvg_convert_LDADD = -lcairo -lglib-2.0 -lgthread-2.0 -lrsvg-2 diff --git a/admin/render-icon.py b/admin/render-icon.py new file mode 100755 index 000000000..ac8ab2453 --- /dev/null +++ b/admin/render-icon.py @@ -0,0 +1,167 @@ +#!/usr/bin/python + +# render-icons.py - Icon rendering utility script +# +# Copyright (C) Lumiera.org +# 2008, Joel Holdsworth +# +# 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. + +import sys +import getopt +from xml.dom import minidom +import os +import shutil + +#svgDir = "svg" +#prerenderedDir = "prerendered" +inkscapePath = "/usr/bin/inkscape" +rsvgPath = "./rsvg-convert" +artworkLayerPrefix = "artwork:" + +def createDirectory( name ): + if os.path.exists(name) == False: + os.mkdir(name) + +def copyMergeDirectory( src, dst ): + listing = os.listdir(src) + for file_name in listing: + src_file_path = os.path.join(src, file_name) + dst_file_path = os.path.join(dst, file_name) + shutil.copyfile(src_file_path, dst_file_path) + +def getDocumentSize( svg_element ): + width = float(svg_element.getAttribute("width")) + height = float(svg_element.getAttribute("height")) + return [width, height] + +def findChildLayerElement( parent_element ): + for node in parent_element.childNodes: + if node.nodeType == minidom.Node.ELEMENT_NODE: + if node.tagName == "g": + if node.getAttribute("inkscape:groupmode") == "layer": + return node + return None + +def parsePlateLayer( layer ): + rectangles = [] + for node in layer.childNodes: + if node.nodeType == minidom.Node.ELEMENT_NODE: + if node.tagName == "rect": + x = float(node.getAttribute("x")) + y = float(node.getAttribute("y")) + width = float(node.getAttribute("width")) + height = float(node.getAttribute("height")) + rectangles.append([x, y, width, height]) + return rectangles + +def parseSVG( file_path ): + print "Rendering " + file_path + svgdoc = minidom.parse(file_path) + for root_node in svgdoc.childNodes: + if root_node.nodeType == minidom.Node.ELEMENT_NODE: + if root_node.tagName == "svg": + size = getDocumentSize( root_node ) + layer = findChildLayerElement( root_node ) + if layer != None: + layer_name = layer.getAttribute("inkscape:label") + if layer_name[:len(artworkLayerPrefix)] == artworkLayerPrefix: + artwork_name = layer_name[len(artworkLayerPrefix):] + plate = findChildLayerElement( layer ) + if plate != None: + return artwork_name, size, parsePlateLayer( plate ) + return None + +def renderSvgInkscape(file_path, out_dir, artwork_name, rectangle, doc_size): + + # Calculate the rendering rectangle + x1 = rectangle[0] + y1 = doc_size[1] - rectangle[1] - rectangle[3] + x2 = x1 + rectangle[2] + y2 = y1 + rectangle[3] + + # Call Inkscape to do the render + os.spawnlp(os.P_WAIT, inkscapePath, inkscapePath, + file_path, + "-z", + "-a %g:%g:%g:%g" % (x1, y1, x2, y2), + "-w %g" % (rectangle[2]), "-h %g" % (rectangle[3]), + "--export-png=" + os.path.join(out_dir, "%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name))) + +def renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size): + # Prepare a Cairo context + width = int(rectangle[2]) + height = int(rectangle[3]) + + os.spawnlp(os.P_WAIT, rsvgPath, rsvgPath, + "--source-rect=%g:%g:%g:%g" % (rectangle[0], rectangle[1], rectangle[2], rectangle[3]), + "--output=" + os.path.join(out_dir, "%gx%g/%s.png" % (rectangle[2], rectangle[3], artwork_name)), + file_path) + +def renderSvgIcon(file_path, out_dir): + artwork_name, doc_size, rectangles = parseSVG(file_path) + for rectangle in rectangles: + renderSvgRsvg(file_path, out_dir, artwork_name, rectangle, doc_size) + +#def renderSvgIcons(): +# listing = os.listdir(svgDir) +# for file_path in listing: +# [root, extension] = os.path.splitext(file_path) +# if extension.lower() == ".svg": +# renderSvgIcon(os.path.join(svgDir, file_path)) + +#def copyPrerenderedIcons(): +# listing = os.listdir(prerenderedDir) +# for list_item in listing: +# src_dir = os.path.join(prerenderedDir, list_item) +# copyMergeDirectory(src_dir, list_item) + +def printHelp(): + print "render-icon.py - An icon rendering utility script for lumiera" + +def parseArguments(argv): + optlist, args = getopt.getopt(argv, "") + + if len(args) == 2: + return args[0], args[1] + + printHelp() + return None, None + +def main(argv): + in_path, out_dir = parseArguments(argv) + + if in_path == None or out_dir == None: + return + + if os.path.exists(out_dir) == False: + print "Directory not found: " + out_dir + return + + # Create the icons folders + createDirectory(os.path.join(out_dir, "48x48")) + createDirectory(os.path.join(out_dir, "32x32")) + createDirectory(os.path.join(out_dir, "24x24")) + createDirectory(os.path.join(out_dir, "22x22")) + createDirectory(os.path.join(out_dir, "16x16")) + + renderSvgIcon(in_path, out_dir) + + # Copy in prerendered icons + #copyPrerenderedIcons() + +if __name__=="__main__": + main(sys.argv[1:]) + diff --git a/admin/rsvg-convert.c b/admin/rsvg-convert.c new file mode 100644 index 000000000..7ed5a9910 --- /dev/null +++ b/admin/rsvg-convert.c @@ -0,0 +1,219 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- + + rsvg-convert.c: Command line utility for exercising rsvg with cairo. + + Copyright (C) 2005 Red Hat, Inc. + Copyright (C) 2005 Dom Lachowicz + Copyright (C) 2005 Caleb Moore + Copyright (C) 2008 Joel Holdsworth + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this program; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Authors: Carl Worth , + Caleb Moore , + Dom Lachowicz , + Joel Holdsworth +*/ + +#ifndef N_ +#define N_(X) X +#endif + +#include +#include +#include + +#include +#include + +#ifdef CAIRO_HAS_PS_SURFACE +#include +#endif + +#ifdef CAIRO_HAS_PDF_SURFACE +#include +#endif + +#ifdef CAIRO_HAS_SVG_SURFACE +#include +#endif + +#ifndef _ +#define _(X) X +#endif + +struct RsvgSizeCallbackData { + gint width; + gint height; +}; + +struct RsvgSourceRectangle { + double left; + double top; + double width; + double height; +}; + +static void +display_error (GError * err) +{ + if (err) { + g_print ("%s", err->message); + g_error_free (err); + } +} + +static void +rsvg_cairo_size_callback (int *width, int *height, gpointer data) +{ + RsvgDimensionData *dimensions = data; + *width = dimensions->width; + *height = dimensions->height; +} + +static cairo_status_t +rsvg_cairo_write_func (void *closure, const unsigned char *data, unsigned int length) +{ + fwrite (data, 1, length, (FILE *) closure); + return CAIRO_STATUS_SUCCESS; +} + +int +main (int argc, char **argv) +{ + GOptionContext *g_option_context; + int width = -1; + int height = -1; + char *source_rect_string = NULL; + char *output = NULL; + GError *error = NULL; + char *filename = NULL; + + char **args = NULL; + RsvgHandle *rsvg; + cairo_surface_t *surface = NULL; + cairo_t *cr = NULL; + RsvgDimensionData dimensions; + FILE *output_file = stdout; + + struct RsvgSourceRectangle source_rect = {0, 0, 0, 0}; + + GOptionEntry options_table[] = { + {"width", 'w', 0, G_OPTION_ARG_INT, &width, + N_("width [optional; defaults to the SVG's width]"), N_("")}, + {"height", 'h', 0, G_OPTION_ARG_INT, &height, + N_("height [optional; defaults to the SVG's height]"), N_("")}, + {"source-rect", 'r', 0, G_OPTION_ARG_STRING, &source_rect_string, + N_("source rectangle [optional; defaults to rectangle of the SVG document]"), N_("left:top:width:height")}, + {"output", 'o', 0, G_OPTION_ARG_STRING, &output, + N_("output filename"), NULL}, + {G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("FILE")}, + {NULL} + }; + + g_thread_init(NULL); + + g_option_context = g_option_context_new (_("- SVG Converter")); + g_option_context_add_main_entries (g_option_context, options_table, NULL); + g_option_context_set_help_enabled (g_option_context, TRUE); + if (!g_option_context_parse (g_option_context, &argc, &argv, &error)) { + display_error (error); + exit (1); + } + + g_option_context_free (g_option_context); + + if (output != NULL) { + output_file = fopen (output, "wb"); + if (!output_file) { + fprintf (stderr, _("Error saving to file: %s\n"), output); + exit (1); + } + } + + if (args[0] != NULL) { + filename = args[0]; + } + + /* Parse the source rect */ + if(source_rect_string != NULL) { + const int n = sscanf(source_rect_string, "%lg:%lg:%lg:%lg", + &source_rect.left, &source_rect.top, + &source_rect.width, &source_rect.height); + if(n != 4 || source_rect.width <= 0.0 || source_rect.height < 0.0) { + fprintf (stderr, _("Invalid source rect: %s\n"), source_rect_string); + exit(1); + } + } + + rsvg_init (); + + rsvg = rsvg_handle_new_from_file (filename, &error); + + if (!rsvg) { + fprintf (stderr, _("Error reading SVG:")); + display_error (error); + fprintf (stderr, "\n"); + exit (1); + } + + /* if the user did not specify a source rectangle, get the page size from the SVG */ + if(source_rect_string == NULL) { + rsvg_handle_set_size_callback (rsvg, rsvg_cairo_size_callback, &dimensions, NULL); + source_rect.left = 0; + source_rect.top = 0; + source_rect.width = dimensions.width; + source_rect.height = dimensions.height; + } + + rsvg_handle_get_dimensions (rsvg, &dimensions); + + if(width != -1 && height != -1) { + dimensions.width = width; + dimensions.height = height; + } else if(source_rect_string != NULL) { + dimensions.width = source_rect.width; + dimensions.height = source_rect.height; + } + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + dimensions.width, dimensions.height); + + cr = cairo_create (surface); + + cairo_translate(cr, -source_rect.left, -source_rect.top); + + if(width != -1 && height != -1 && source_rect_string != NULL) { + cairo_scale(cr, (double)dimensions.width / (double)source_rect.width, + (double)dimensions.height / (double)source_rect.height); + } + + rsvg_handle_render_cairo (rsvg, cr); + + cairo_surface_write_to_png_stream (surface, rsvg_cairo_write_func, output_file); + + g_object_unref (G_OBJECT (rsvg)); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + fclose (output_file); + + rsvg_term (); + + return 0; +} + diff --git a/configure.ac b/configure.ac index b72b7dfee..b5a61ab03 100644 --- a/configure.ac +++ b/configure.ac @@ -7,6 +7,7 @@ AC_PREREQ(2.59) AC_COPYRIGHT([ Copyright (C) Lumiera.org 2008, Christian Thaeter + Joel Holdsworth This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -120,6 +121,52 @@ AC_CHECK_HEADER([boost/regex.hpp], AC_LANG_POP([C++]) +############## Internatinalization +#GETTEXT_PACKAGE=gtk-lumiera +#AC_SUBST(GETTEXT_PACKAGE) +#AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [GETTEXT package name]) +#AM_GLIB_GNU_GETTEXT +#IT_PROG_INTLTOOL([0.35.0]) + +# END Internatinalization + + +############## X11 Dependancies +AC_PATH_X +AC_PATH_XTRA +# CFLAGS="$CFLAGS $X_CFLAGS" +LIBS="$LIBS $X_PRE_LIBS $X_LIBS $X_EXTRA_LIBS" + +AC_CHECK_HEADERS([X11/Xlib.h X11/Xutil.h],[], + [AC_MSG_ERROR([Xlib.h or Xutil.h not found install xdevel])]) + +AC_CHECK_HEADERS([sys/ipc.h sys/shm.h],, + [AC_MSG_ERROR([Required header not found. Please check that it is installed])] +) +AC_CHECK_HEADERS([X11/extensions/Xvlib.h X11/extensions/XShm.h],, + [AC_MSG_ERROR([Required xvideo (Xv) extension to X not found. Please check that it is installed.])], + [#include ] +) + +AC_CHECK_LIB(Xext, XInitExtension, , + [AC_MSG_ERROR([Could not link with libXext. Check that you have libXext installed])], -lX11 +) +AC_CHECK_LIB(Xv, XvQueryAdaptors, , + [AC_MSG_ERROR([Could not link with libXv. Check that you have libXv installed])] +) + +# END X11 Dependancies + + +############## Pkg Dependancies +PKG_CHECK_MODULES(GTK_LUMIERA, [ + 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]) + +AC_SUBST(GTK_LUMIERA_CFLAGS) +AC_SUBST(GTK_LUMIERA_LIBS) + +# END Gtk Dependancies # Print a summary AC_MSG_RESULT([ diff --git a/doc/devel/Doxyfile b/doc/devel/Doxyfile index 1d6c5f87c..28bab1f05 100644 --- a/doc/devel/Doxyfile +++ b/doc/devel/Doxyfile @@ -1,14 +1,14 @@ -# Doxyfile 1.5.1 +# Doxyfile 1.5.5 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = Lumiera PROJECT_NUMBER = 3.0+alpha OUTPUT_DIRECTORY = CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English -USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = NO ABBREVIATE_BRIEF = "The $name class" \ @@ -30,6 +30,7 @@ STRIP_FROM_PATH = ../../src/ \ STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES @@ -38,9 +39,14 @@ TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO BUILTIN_STL_SUPPORT = YES +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -49,6 +55,7 @@ EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO @@ -60,6 +67,7 @@ SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = YES +SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES @@ -79,12 +87,13 @@ WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = +WARN_LOGFILE = warnings.txt #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ../../src/ \ ../../tests/ +INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ @@ -130,6 +139,7 @@ RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = YES EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO @@ -168,6 +178,10 @@ HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +HTML_DYNAMIC_SECTIONS = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO @@ -251,6 +265,7 @@ PERL_PATH = /usr/bin/perl # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES +MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES CLASS_GRAPH = YES @@ -267,8 +282,7 @@ DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = -MAX_DOT_GRAPH_WIDTH = 1024 -MAX_DOT_GRAPH_HEIGHT = 1024 +DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = YES diff --git a/icons/Makefile.am b/icons/Makefile.am new file mode 100644 index 000000000..6693b6d1d --- /dev/null +++ b/icons/Makefile.am @@ -0,0 +1,65 @@ +# Copyright (C) Lumiera.org +# 2008, Joel Holdsworth +# +# 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. + +svgdir = $(top_srcdir)/icons/svg +prerendereddir = $(top_srcdir)/icons/prerendered +icondir = $(top_builddir) +iconcommand = python $(top_srcdir)/admin/render-icon.py + +16x16 = $(icondir)/16x16 +22x22 = $(icondir)/22x22 +24x24 = $(icondir)/24x24 +32x32 = $(icondir)/32x32 +48x48 = $(icondir)/48x48 + +16x16pre = $(prerendereddir)/16x16 +22x22pre = $(prerendereddir)/22x22 +24x24pre = $(prerendereddir)/24x24 +32x32pre = $(prerendereddir)/32x32 +48x48pre = $(prerendereddir)/48x48 + +lumigui_DEPENDENCIES += \ + rsvg-convert \ + $(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png \ + $(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png \ + $(16x16)/panel-assets.png $(22x22)/panel-assets.png $(32x32)/panel-assets.png \ + $(16x16)/panel-timeline.png \ + $(16x16)/panel-viewer.png $(22x22)/panel-viewer.png $(32x32)/panel-viewer.png + +$(16x16)/tool-arrow.png $(22x22)/tool-arrow.png $(24x24)/tool-arrow.png $(32x32)/tool-arrow.png $(48x48)/tool-arrow.png : $(svgdir)/tool-arrow.svg + $(iconcommand) $< $(icondir) +$(16x16)/tool-i-beam.png $(22x22)/tool-i-beam.png $(24x24)/tool-i-beam.png $(32x32)/tool-i-beam.png $(48x48)/tool-i-beam.png : $(svgdir)/tool-i-beam.svg + $(iconcommand) $< $(icondir) + +$(16x16)/panel-assets.png: + cp $(16x16pre)/panel-assets.png $(16x16) +$(22x22)/panel-assets.png: + cp $(22x22pre)/panel-assets.png $(22x22) +$(32x32)/panel-assets.png: + cp $(32x32pre)/panel-assets.png $(32x32) + +$(16x16)/panel-timeline.png: + cp $(16x16pre)/panel-timeline.png $(16x16) + +$(16x16)/panel-viewer.png: + cp $(16x16pre)/panel-viewer.png $(16x16) +$(22x22)/panel-viewer.png: + cp $(22x22pre)/panel-viewer.png $(22x22) +$(32x32)/panel-viewer.png: + cp $(32x32pre)/panel-viewer.png $(32x32) + + diff --git a/icons/prerendered/16x16/panel-assets.png b/icons/prerendered/16x16/panel-assets.png new file mode 100644 index 000000000..901542615 Binary files /dev/null and b/icons/prerendered/16x16/panel-assets.png differ diff --git a/icons/prerendered/16x16/panel-timeline.png b/icons/prerendered/16x16/panel-timeline.png new file mode 100644 index 000000000..e61a0aea1 Binary files /dev/null and b/icons/prerendered/16x16/panel-timeline.png differ diff --git a/icons/prerendered/16x16/panel-viewer.png b/icons/prerendered/16x16/panel-viewer.png new file mode 100644 index 000000000..a73a169ac Binary files /dev/null and b/icons/prerendered/16x16/panel-viewer.png differ diff --git a/icons/prerendered/22x22/panel-assets.png b/icons/prerendered/22x22/panel-assets.png new file mode 100644 index 000000000..dc7628738 Binary files /dev/null and b/icons/prerendered/22x22/panel-assets.png differ diff --git a/icons/prerendered/22x22/panel-viewer.png b/icons/prerendered/22x22/panel-viewer.png new file mode 100644 index 000000000..58fc213ec Binary files /dev/null and b/icons/prerendered/22x22/panel-viewer.png differ diff --git a/icons/prerendered/32x32/panel-assets.png b/icons/prerendered/32x32/panel-assets.png new file mode 100644 index 000000000..4b55b504a Binary files /dev/null and b/icons/prerendered/32x32/panel-assets.png differ diff --git a/icons/prerendered/32x32/panel-viewer.png b/icons/prerendered/32x32/panel-viewer.png new file mode 100644 index 000000000..b449f37a5 Binary files /dev/null and b/icons/prerendered/32x32/panel-viewer.png differ diff --git a/icons/svg/tool-arrow.svg b/icons/svg/tool-arrow.svg new file mode 100644 index 000000000..026b6633f --- /dev/null +++ b/icons/svg/tool-arrow.svg @@ -0,0 +1,732 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/icons/svg/tool-i-beam.svg b/icons/svg/tool-i-beam.svg new file mode 100644 index 000000000..7f26e1d55 --- /dev/null +++ b/icons/svg/tool-i-beam.svg @@ -0,0 +1,690 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/icons/timeline-panel.svg b/icons/timeline-panel.svg new file mode 100644 index 000000000..306f56c9b --- /dev/null +++ b/icons/timeline-panel.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 000000000..bc8cbb0fe --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,2 @@ +# please keep this list sorted alphabetically +# diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 000000000..f8afa6162 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,12 @@ +# List of source files containing translatable strings. + +src/gtk-lumiera.cpp + +src/workspace/actions.cpp + +src/dialogs/preferences-dialog.cpp +src/dialogs/render.cpp + +src/panels/assets-panel.cpp +src/panels/timeline-panel.cpp +src/panels/viewer-panel.cpp diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 06082da31..29d794f7a 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -25,7 +25,7 @@ liblumicommon_a_CXXFLAGS = $(CXXFLAGS) -Wall liblumicommon_a_CPPFLAGS = -I$(top_srcdir)/src/ liblumicommon_a_SOURCES = \ - $(liblumicommon_a_srcdir)/time.cpp \ + $(liblumicommon_a_srcdir)/lumitime.cpp \ $(liblumicommon_a_srcdir)/util.cpp \ $(liblumicommon_a_srcdir)/visitor.cpp \ $(liblumicommon_a_srcdir)/cmdline.cpp \ @@ -40,11 +40,11 @@ liblumicommon_a_SOURCES = \ noinst_HEADERS += \ $(liblumicommon_a_srcdir)/cmdline.hpp \ $(liblumicommon_a_srcdir)/factory.hpp \ + $(liblumicommon_a_srcdir)/frameid.hpp \ $(liblumicommon_a_srcdir)/singleton.hpp \ $(liblumicommon_a_srcdir)/singletonpolicies.hpp \ $(liblumicommon_a_srcdir)/singletonpreconfigure.hpp \ - $(liblumicommon_a_srcdir)/time.hpp \ - $(liblumicommon_a_srcdir)/typelist.hpp \ + $(liblumicommon_a_srcdir)/lumitime.hpp \ $(liblumicommon_a_srcdir)/visitor.hpp \ $(liblumicommon_a_srcdir)/visitordispatcher.hpp \ $(liblumicommon_a_srcdir)/visitorpolicies.hpp \ @@ -56,7 +56,10 @@ noinst_HEADERS += \ $(liblumicommon_a_srcdir)/query/mockconfigrules.hpp \ $(liblumicommon_a_srcdir)/singletonfactory.hpp \ $(liblumicommon_a_srcdir)/singletonsubclass.hpp \ - $(liblumicommon_a_srcdir)/typelistutil.hpp \ + $(liblumicommon_a_srcdir)/meta/typelist.hpp \ + $(liblumicommon_a_srcdir)/meta/configflags.hpp \ + $(liblumicommon_a_srcdir)/meta/generator.hpp \ + $(liblumicommon_a_srcdir)/meta/typelistutil.hpp \ $(liblumicommon_a_srcdir)/util.hpp \ $(liblumicommon_a_srcdir)/test/mockinjector.hpp \ $(liblumicommon_a_srcdir)/test/suite.hpp \ diff --git a/src/common/cmdline.cpp b/src/common/cmdline.cpp index 1e8e1849f..dec1a0620 100644 --- a/src/common/cmdline.cpp +++ b/src/common/cmdline.cpp @@ -27,7 +27,9 @@ #include "proc/nobugcfg.hpp" #include -#include +#include +#include +#include using boost::algorithm::split; using boost::algorithm::join; diff --git a/src/common/time.cpp b/src/common/lumitime.cpp similarity index 97% rename from src/common/time.cpp rename to src/common/lumitime.cpp index a37979c6b..bd50c78bf 100644 --- a/src/common/time.cpp +++ b/src/common/lumitime.cpp @@ -21,7 +21,7 @@ * *****************************************************/ -#include "common/time.hpp" +#include "common/lumitime.hpp" #include diff --git a/src/common/time.hpp b/src/common/lumitime.hpp similarity index 92% rename from src/common/time.hpp rename to src/common/lumitime.hpp index d065c3f36..33b5bb4c3 100644 --- a/src/common/time.hpp +++ b/src/common/lumitime.hpp @@ -1,5 +1,5 @@ /* - TIME.hpp - unified representation of a time point, including conversion functions + LUMITIME.hpp - unified representation of a time point, including conversion functions Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -21,8 +21,8 @@ */ -#ifndef LUMIERA_TIME_H -#define LUMIERA_TIME_H +#ifndef LUMIERA_LUMITIME_H +#define LUMIERA_LUMITIME_H #include diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am new file mode 100644 index 000000000..db652d99b --- /dev/null +++ b/src/gui/Makefile.am @@ -0,0 +1,90 @@ +# Copyright (C) Lumiera.org +# 2007, Joel Holdsworth +# +# 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. + +lumigui_srcdir = $(top_srcdir)/src/gui +#noinst_LIBRARIES += liblumigui.a + +#lumigui_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror +#lumigui_CPPFLAGS = -I$(top_srcdir)/src/ + +INCLUDES = \ + -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ + $(GTK_LUMIERA_CFLAGS) + +bin_PROGRAMS += lumigui + +lumigui_SOURCES = \ + $(lumigui_srcdir)/gtk-lumiera.cpp \ + $(lumigui_srcdir)/gtk-lumiera.hpp \ + $(lumigui_srcdir)/window-manager.cpp \ + $(lumigui_srcdir)/window-manager.hpp \ + $(lumigui_srcdir)/workspace/actions.cpp \ + $(lumigui_srcdir)/workspace/actions.hpp \ + $(lumigui_srcdir)/workspace/workspace-window.cpp \ + $(lumigui_srcdir)/workspace/workspace-window.hpp \ + $(lumigui_srcdir)/dialogs/render.cpp \ + $(lumigui_srcdir)/dialogs/render.hpp \ + $(lumigui_srcdir)/dialogs/preferences-dialog.cpp \ + $(lumigui_srcdir)/dialogs/preferences-dialog.hpp \ + $(lumigui_srcdir)/panels/panel.cpp \ + $(lumigui_srcdir)/panels/panel.hpp \ + $(lumigui_srcdir)/panels/timeline-panel.cpp \ + $(lumigui_srcdir)/panels/timeline-panel.hpp \ + $(lumigui_srcdir)/panels/viewer-panel.cpp \ + $(lumigui_srcdir)/panels/viewer-panel.hpp \ + $(lumigui_srcdir)/panels/assets-panel.cpp \ + $(lumigui_srcdir)/panels/asset-panels.hpp \ + $(lumigui_srcdir)/widgets/video-display-widget.cpp \ + $(lumigui_srcdir)/widgets/video-display-widget.hpp \ + $(lumigui_srcdir)/widgets/timeline-widget.cpp \ + $(lumigui_srcdir)/widgets/timeline-widget.hpp \ + $(lumigui_srcdir)/widgets/timeline/header-container.cpp \ + $(lumigui_srcdir)/widgets/timeline/header-container.hpp \ + $(lumigui_srcdir)/widgets/timeline/track.cpp \ + $(lumigui_srcdir)/widgets/timeline/track.hpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-body.cpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-body.hpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-ruler.cpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-ruler.hpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-tool.cpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-tool.hpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-arrow-tool.cpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-arrow-tool.hpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-ibeam-tool.cpp \ + $(lumigui_srcdir)/widgets/timeline/timeline-ibeam-tool.hpp \ + $(lumigui_srcdir)/model/project.cpp \ + $(lumigui_srcdir)/model/project.hpp \ + $(lumigui_srcdir)/output/displayer.cpp \ + $(lumigui_srcdir)/output/displayer.hpp \ + $(lumigui_srcdir)/output/gdkdisplayer.cpp \ + $(lumigui_srcdir)/output/gdkdisplayer.hpp \ + $(lumigui_srcdir)/output/xvdisplayer.cpp \ + $(lumigui_srcdir)/output/xvdisplayer.hpp + +lumigui_LDFLAGS = +lumigui_LDADD = $(GTK_LUMIERA_LIBS) liblumicommon.a liblumi.a + +lumigui_DEPENDENCIES = \ + $(top_builddir)/lumiera_ui.rc \ + $(top_builddir)/liblumicommon.a \ + $(top_builddir)/liblumi.a + +$(top_builddir)/lumiera_ui.rc: + cp $(lumigui_srcdir)/lumiera_ui.rc $(top_builddir) + diff --git a/src/gui/dialogs/preferences-dialog.cpp b/src/gui/dialogs/preferences-dialog.cpp new file mode 100644 index 000000000..10f187c1c --- /dev/null +++ b/src/gui/dialogs/preferences-dialog.cpp @@ -0,0 +1,61 @@ +/* + preferences-dialog.cpp - Implementation of the application preferences dialog + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "../gtk-lumiera.hpp" + +#include "preferences-dialog.hpp" + +using namespace Gtk; + +namespace lumiera { +namespace gui { +namespace dialogs { + + PreferencesDialog::PreferencesDialog(Window &parent) : + Dialog(_("Preferences"), parent, true) + { + VBox *v_box = get_vbox(); + g_assert(v_box != NULL); + + interfaceBox.pack_start(interfaceThemeCombo, PACK_SHRINK); + interfaceBox.set_spacing(4); + interfaceBox.set_border_width(5); + + notebook.append_page(interfaceBox, _("Interface")); + + v_box->pack_start(notebook); + + // Configure the dialog + v_box->set_spacing(4); + set_border_width(5); + set_resizable(false); + + // Configure the Cancel and OK buttons + add_button(Stock::CANCEL, RESPONSE_CANCEL); + add_button(Stock::OK, RESPONSE_OK); + + show_all_children(); + } + +} // namespace dialogs +} // namespace gui +} // namespace lumiera diff --git a/src/gui/dialogs/preferences-dialog.hpp b/src/gui/dialogs/preferences-dialog.hpp new file mode 100644 index 000000000..31ad169c7 --- /dev/null +++ b/src/gui/dialogs/preferences-dialog.hpp @@ -0,0 +1,61 @@ +/* + preferences-dialog.hpp - Definition of the application preferences dialog + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 render.hpp + ** This file contains the definition of the application preferences dialog + ** + */ + +#ifndef PREFERENCES_DIALOG_HPP +#define PREFERENCES_DIALOG_HPP + +#include + +using namespace Gtk; + +namespace lumiera { +namespace gui { +namespace dialogs { + + /** + * The defintion of render output dialog class + */ + class PreferencesDialog : public Dialog + { + public: + PreferencesDialog(Window &parent); + + protected: + + + protected: + Notebook notebook; + + VBox interfaceBox; + ComboBox interfaceThemeCombo; + + }; + +} // namespace dialogs +} // namespace gui +} // namespace lumiera + +#endif // PREFERENCES_DIALOG_HPP diff --git a/src/gui/dialogs/render.cpp b/src/gui/dialogs/render.cpp new file mode 100644 index 000000000..25dafdc88 --- /dev/null +++ b/src/gui/dialogs/render.cpp @@ -0,0 +1,101 @@ +/* + render.cpp - Definition of the main workspace window object + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "../gtk-lumiera.hpp" + +#include "render.hpp" + +using namespace Gtk; + +namespace lumiera { +namespace gui { +namespace dialogs { + + Render::Render(Window &parent) : + Dialog(_("Render"), parent, true), + outputFileLabel(_("Output File:")), + browseButtonImage(StockID(Stock::INDEX), ICON_SIZE_BUTTON), + outputFileBrowseButton(_("_Browse...")), + containerFormatLabel(_("Container Format:")), + renderButtonImage(StockID(Stock::OK), ICON_SIZE_BUTTON), + audioFrame(_("Audio")), + videoFrame(_("Video")) + { + VBox *v_box = get_vbox(); + ASSERT(v_box != NULL); + + // The Output File Row + outputFileHBox.pack_start(outputFileLabel, PACK_SHRINK); + outputFileHBox.pack_start(outputFilePathEntry); + + outputFileBrowseButton.set_image(browseButtonImage); + outputFileBrowseButton.signal_clicked().connect( + sigc::mem_fun(*this, &Render::on_button_browse)); + + outputFileHBox.pack_start(outputFileBrowseButton, PACK_SHRINK); + outputFileHBox.set_spacing(4); + v_box->pack_start(outputFileHBox, PACK_SHRINK); + + // The Container Format Row + containerFormatHBox.pack_start(containerFormatLabel, PACK_SHRINK); + containerFormatHBox.pack_start(containerFormat); + containerFormatHBox.set_spacing(4); + v_box->pack_start(containerFormatHBox, PACK_SHRINK); + + v_box->pack_start(audioFrame); + v_box->pack_start(videoFrame); + + // Configure the dialog + v_box->set_spacing(4); + set_border_width(5); + set_resizable(false); + + // Configure the Cancel and Render buttons + add_button(Stock::CANCEL, RESPONSE_CANCEL); + + Button *render_button = add_button(Stock::OK, RESPONSE_OK); + render_button->set_label(_("_Render")); + render_button->set_image(renderButtonImage); + render_button->set_flags(Gtk::CAN_DEFAULT); + render_button->grab_default(); + + show_all_children(); + } + + void Render::on_button_browse() + { + FileChooserDialog dialog(*this, _("Select a File Name for Rendering"), + FILE_CHOOSER_ACTION_SAVE); + + // Add response buttons the the dialog: + dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + dialog.add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); + + int result = dialog.run(); + INFO(gui, "%d", result); + if(result == RESPONSE_OK) + INFO(gui, "%d", "RESPONSE_OK"); + } + +} // namespace dialogs +} // namespace gui +} // namespace lumiera diff --git a/src/gui/dialogs/render.hpp b/src/gui/dialogs/render.hpp new file mode 100644 index 000000000..1474afe31 --- /dev/null +++ b/src/gui/dialogs/render.hpp @@ -0,0 +1,72 @@ +/* + render.hpp - Definition of the render output dialog + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 render.hpp + ** This file contains the definition of the render output dialog + ** + */ + +#ifndef RENDER_H +#define RENDER_H + +#include + +using namespace Gtk; + +namespace lumiera { +namespace gui { +namespace dialogs { + + /** + * The defintion of render output dialog class + */ + class Render : public Dialog + { + public: + Render(Window &parent); + + protected: + void on_button_browse(); + + protected: + HBox outputFileHBox; + Label outputFileLabel; + Entry outputFilePathEntry; + + Image browseButtonImage; + Button outputFileBrowseButton; + + HBox containerFormatHBox; + Label containerFormatLabel; + ComboBox containerFormat; + + Frame audioFrame; + + Frame videoFrame; + + Image renderButtonImage; + }; + +} // namespace dialogs +} // namespace gui +} // namespace lumiera + +#endif // RENDER_H diff --git a/src/gui/gtk-lumiera.cpp b/src/gui/gtk-lumiera.cpp new file mode 100644 index 000000000..ba11f168a --- /dev/null +++ b/src/gui/gtk-lumiera.cpp @@ -0,0 +1,92 @@ +/* + gtk-lumiera.cpp - The entry point for the GTK GUI application + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 +#include + +#ifdef ENABLE_NLS +# include +#endif + +#include "gtk-lumiera.hpp" +#include "window-manager.hpp" +#include "workspace/workspace-window.hpp" +#include "model/project.hpp" + +NOBUG_CPP_DEFINE_FLAG(gui); + +using namespace Gtk; +using namespace Glib; +using namespace lumiera::gui; +using namespace lumiera::gui::workspace; +using namespace lumiera::gui::model; + +GtkLumiera the_application; + +int +main (int argc, char *argv[]) +{ + return the_application.main(argc, argv); +} + + + +namespace lumiera { +namespace gui { + +int +GtkLumiera::main(int argc, char *argv[]) +{ + NOBUG_INIT; + + Main kit(argc, argv); + + Glib::set_application_name(AppTitle); + + Project project; + WindowManager window_manager; + + window_manager.set_theme("lumiera_ui.rc"); + + WorkspaceWindow main_window(&project); + + kit.run(main_window); +} + +Glib::ustring +GtkLumiera::get_home_data_path() +{ + const ustring app_name("lumiera"); + const ustring path(Glib::get_home_dir()); + return ustring::compose("%1/.%2", path, app_name); +} + +GtkLumiera& +application() +{ + return the_application; +} + +} // namespace gui +} // namespace lumiera + + diff --git a/src/gui/gtk-lumiera.hpp b/src/gui/gtk-lumiera.hpp new file mode 100644 index 000000000..41b355d80 --- /dev/null +++ b/src/gui/gtk-lumiera.hpp @@ -0,0 +1,142 @@ +/* + gtk-lumiera.hpp - Application wide global definitions + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 gtk-lumiera.hpp + ** This file contains application wide global definitions + ** user actions. + ** @see gtk-lumiera.cpp + */ + +#ifndef GTK_LUMIERA_HPP +#define GTK_LUMIERA_HPP + +#include +#include +#include + +extern "C" { +#include +} + +NOBUG_DECLARE_FLAG(gui); + +#ifdef ENABLE_NLS +# include +# define _(String) gettext (String) +# define gettext_noop(String) String +# define N_(String) gettext_noop (String) +#else +# define _(String) (String) +# define N_(String) String +# define textdomain(Domain) +# define bindtextdomain(Package, Directory) +#endif + +namespace lumiera { + +/** + * The namespace of all GUI code. + */ +namespace gui { + +/* ===== Global Constants ===== */ + +/** + * The name of the application + */ +static const gchar* AppTitle = "Lumiera"; + +/** + * The version number of the application + */ +static const gchar* AppVersion = N_("0.1-dev"); + +/** + * The copyright of the application + */ +static const gchar* AppCopyright = N_("© 2008 The Lumiera Team"); + +/** + * The website of the application + */ +static const gchar* AppWebsite = "www.lumiera.org"; + +/** + * An alphabetical list of the application's authors + */ +static const gchar* AppAuthors[] = { + "Joel Holdsworth", + "Christian Thaeter", + "Hermann Vosseler", + ""}; + +/* ===== The Application Class ===== */ + +/** + * The main application class. + */ +class GtkLumiera +{ +public: + int main(int argc, char *argv[]); + + static Glib::ustring get_home_data_path(); + +}; + +/** + * Returns a reference to the global application object + */ +GtkLumiera& application(); + +/* ===== Namespace Definitions ===== */ + +/** + * The namespace of all dialog box classes. + */ +namespace dialogs {} + +/** + * The namespace of all video output implementations. + */ +namespace output {} + +/** + * The namespace of all docking panel classes. + */ +namespace panels {} + +/** + * The namespace of all Lumiera custom widgets. + */ +namespace widgets {} + +/** + * The namespace of the workspace window, and it's helper classes. + */ +namespace workspace {} + +} // namespace gui +} // namespace lumiera + +#endif // GTK_LUMIERA_HPP + + diff --git a/src/gui/lumiera_ui.rc b/src/gui/lumiera_ui.rc index 428b7bed4..b68407039 100644 --- a/src/gui/lumiera_ui.rc +++ b/src/gui/lumiera_ui.rc @@ -124,6 +124,8 @@ class "GtkProgressBar" style:highest "lumiera_progressbars" style "timeline_body" { gtkmm__CustomObject_TimelineBody::background = "#7E838B" + gtkmm__CustomObject_TimelineBody::selection = "#2D2D90" + gtkmm__CustomObject_TimelineBody::selection_alpha = 0.5 } style "timeline_ruler" = "default_base" @@ -137,6 +139,7 @@ style "timeline_ruler" = "default_base" gtkmm__CustomObject_TimelineRuler::annotation_vert_margin = 0 gtkmm__CustomObject_TimelineRuler::min_division_width = 100 gtkmm__CustomObject_TimelineRuler::mouse_chevron_size = 5 + gtkmm__CustomObject_TimelineRuler::selection_chevron_size = 5 } style "timeline_header_base" = "default_base" diff --git a/src/gui/model/project.cpp b/src/gui/model/project.cpp new file mode 100644 index 000000000..345398c7a --- /dev/null +++ b/src/gui/model/project.cpp @@ -0,0 +1,38 @@ +/* + panel.cpp - Implementation of the Project class + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "project.hpp" + +namespace lumiera { +namespace gui { +namespace model { + +Project::Project() +{ + +} + +} // namespace model +} // namespace gui +} // namespace lumiera + + diff --git a/src/gui/model/project.hpp b/src/gui/model/project.hpp new file mode 100644 index 000000000..c7d02c51a --- /dev/null +++ b/src/gui/model/project.hpp @@ -0,0 +1,44 @@ +/* + project.hpp - Definition of the Project class + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 project.hpp + ** This file contains the definition of Project, a class which + ** store project data, and wraps proc layer data + */ + +#ifndef PROJECT_HPP +#define PROJECT_HPP + +namespace lumiera { +namespace gui { +namespace model { + +class Project +{ +public: + Project(); +}; + +} // namespace model +} // namespace gui +} // namespace lumiera + +#endif // PROJECT_HPP diff --git a/src/gui/output/displayer.cpp b/src/gui/output/displayer.cpp new file mode 100644 index 000000000..f2b036116 --- /dev/null +++ b/src/gui/output/displayer.cpp @@ -0,0 +1,86 @@ +/* + displayer.cpp - Implements the base class for displaying video + + Copyright (C) Lumiera.org + 2000, Arne Schirmacher + 2001-2007, Dan Dennedy + 2008, Joel Holdsworth + + 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 "../gtk-lumiera.hpp" +#include "displayer.hpp" +#include "xvdisplayer.hpp" +#include "gdkdisplayer.hpp" + +namespace lumiera { +namespace gui { +namespace output { + +bool +Displayer::usable() + { + return false; + } + +DisplayerInput +Displayer::format() + { + return DISPLAY_NONE; + } + +int +Displayer::preferredWidth() + { + return imageWidth; + } + +int +Displayer::preferredHeight() + { + return imageHeight; + } + +void +Displayer::calculateVideoLayout( + int widget_width, int widget_height, + int image_width, int image_height, + int &video_x, int &video_y, int &video_width, int &video_height ) + { + REQUIRE(widget_width >= 0); + REQUIRE(widget_height >= 0); + REQUIRE(image_width >= 0); + REQUIRE(image_height >= 0); + + double ratio_width = ( double ) widget_width / ( double ) image_width; + double ratio_height = ( double ) widget_height / ( double ) image_height; + double ratio_constant = ratio_height < ratio_width ? + ratio_height : ratio_width; + video_width = ( int ) ( image_width * ratio_constant + 0.5 ); + video_height = ( int ) ( image_height * ratio_constant + 0.5 ); + video_x = ( widget_width - video_width ) / 2; + video_y = ( widget_height - video_height ) / 2; + + ENSURE(video_x >= 0 && video_x < widget_width) + ENSURE(video_y >= 0 && video_y < widget_height) + ENSURE(video_width <= widget_width) + ENSURE(video_width <= widget_width) + } + +} // namespace output +} // namespace gui +} // namespace lumiera diff --git a/src/gui/output/displayer.hpp b/src/gui/output/displayer.hpp new file mode 100644 index 000000000..d5bf2a329 --- /dev/null +++ b/src/gui/output/displayer.hpp @@ -0,0 +1,135 @@ +/* + displayer.hpp - Defines the base class for displaying video + + Copyright (C) Lumiera.org + 2000, Arne Schirmacher + 2001-2007, Dan Dennedy + 2008, Joel Holdsworth + + 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 displayer.hpp + ** This file contains the defintion of Displayer; the base class + ** of all video display implementations + ** @see displayer.cpp + */ + +#ifndef DISPLAYER_HPP +#define DISPLAYER_HPP + +namespace lumiera { +namespace gui { +namespace output { + +#define MAX_WIDTH 720 +#define MAX_HEIGHT 576 + + /** Supported Displayer formats + */ + typedef enum { + DISPLAY_NONE, + DISPLAY_YUV, + DISPLAY_RGB, + DISPLAY_BGR, + DISPLAY_BGR0, + DISPLAY_RGB16 + } + DisplayerInput; + + /** + * A Displayer is a class which is responsible for rendering an image + * in some way (ie: Xvideo, GDK, OpenGL etc). + * + * @remarks All Displayer classes must extend the Displayer class and + * minimally rewrite: + * + * + usable() - to indicate if the object can be used, + * + format() - to indicate what type of input the put method expects + * + put( void * ) - deal with an image of the expected type and size + * + * By default, all images will be delivered to the put method in a + * resolution of IMG_WIDTH * IMG_HEIGHT. If another size is required, + * then the rewrite the methods: + * + * + preferredWidth + * + preferredHeight + * + * If the widget being written to doesn't need a fixed size, then + * rewrite the two other put methods as required. + */ + class Displayer + { + public: + + /** + * Indicates if an object can be used to render images on the + * running system. + */ + virtual bool usable(); + + /** + * Indicates the format required by the abstract put method. + */ + virtual DisplayerInput format(); + + /** + * Expected width of input to put. + */ + virtual int preferredWidth(); + + /** + * Expected height of input to put. + */ + virtual int preferredHeight(); + + /** + * Put an image of a given width and height with the expected input + * format (as indicated by the format method). + */ + virtual void put( void * ) = 0; + + protected: + + /** + * Calculates the coordinates for placing a video image inside a + * widget + * + * @param[in] widget_width The width of the display widget. + * @param[in] widget_height The height of the display widget. + * @param[in] image_width The width of the video image. + * @param[in] image_height The height of the video image. + * @param[out] video_x The x-coordinate of the top left + * corner of the scaled video image. + * @param[out] video_y The y-coordinate of the top left + * corner of the scaled video image. + * @param[out] video_width The width of the scale video image. + * @param[out] video_height The height of the scale video image. + */ + static void calculateVideoLayout( + int widget_width, int widget_height, + int image_width, int image_height, + int &video_x, int &video_y, int &video_width, int &video_height ); + + protected: + int imageWidth; + int imageHeight; + }; + +} // namespace output +} // namespace gui +} // namespace lumiera + +#endif // DISPLAYER_HPP diff --git a/src/gui/output/gdkdisplayer.cpp b/src/gui/output/gdkdisplayer.cpp new file mode 100644 index 000000000..3718b9f1e --- /dev/null +++ b/src/gui/output/gdkdisplayer.cpp @@ -0,0 +1,86 @@ +/* + gdkdisplayer.cpp - Implements the class for displaying video via GDK + + Copyright (C) Lumiera.org + 2000, Arne Schirmacher + 2001-2007, Dan Dennedy + 2008, Joel Holdsworth + + 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 "../gtk-lumiera.hpp" + +#include +#include +using std::cerr; +using std::endl; + +#include "gdkdisplayer.hpp" + +namespace lumiera { +namespace gui { +namespace output { + +GdkDisplayer::GdkDisplayer( Gtk::Widget *drawing_area, int width, int height ) : + drawingArea( drawing_area ) + { + REQUIRE(drawing_area != NULL); + REQUIRE(width > 0); + REQUIRE(height > 0); + + imageWidth = width, imageHeight = height; + } + +bool +GdkDisplayer::usable() + { + return true; + } + +void +GdkDisplayer::put( void *image ) + { + int video_x = 0, video_y = 0, video_width = 0, video_height = 0; + calculateVideoLayout( + drawingArea->get_width(), + drawingArea->get_height(), + preferredWidth(), preferredHeight(), + video_x, video_y, video_width, video_height ); + + GdkWindow *window = drawingArea->get_window()->gobj(); + ASSERT(window != NULL); + + GdkGC *gc = gdk_gc_new( window ); + ASSERT(gc != NULL); + + GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data( (const guchar*)image, GDK_COLORSPACE_RGB, FALSE, 8, + preferredWidth(), preferredHeight(), preferredWidth() * 3, NULL, NULL ); + ASSERT(pixbuf != NULL); + + GdkPixbuf *scaled_image = gdk_pixbuf_scale_simple( pixbuf, video_width, video_height, GDK_INTERP_NEAREST ); + ASSERT(scaled_image != NULL); + + gdk_draw_pixbuf( window, gc, scaled_image, 0, 0, video_x, video_y, -1, -1, GDK_RGB_DITHER_NORMAL, 0, 0 ); + + g_object_unref( scaled_image ); + g_object_unref( pixbuf ); + g_object_unref( gc ); + } + +} // namespace output +} // namespace gui +} // namespace lumiera diff --git a/src/gui/output/gdkdisplayer.hpp b/src/gui/output/gdkdisplayer.hpp new file mode 100644 index 000000000..40ef3b547 --- /dev/null +++ b/src/gui/output/gdkdisplayer.hpp @@ -0,0 +1,62 @@ +/* + gdkdisplayer.hpp - Defines the class for displaying video via GDK + + Copyright (C) Lumiera.org + 2000, Arne Schirmacher + 2001-2007, Dan Dennedy + 2008, Joel Holdsworth + + 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 gdkdisplayer.hpp + ** This file contains the definition of XvDisplayer, the XVideo + ** video output implementation + ** @see gdkdisplayer.cpp + ** @see displayer.hpp + */ + +#include "displayer.hpp" + +#ifndef GDKDISPLAYER_HPP +#define GDKDISPLAYER_HPP + +namespace Gtk { + class Widget; +} + +namespace lumiera { +namespace gui { +namespace output { + +class GdkDisplayer : public Displayer + { + public: + GdkDisplayer( Gtk::Widget *drawing_area, int width, int height ); + + void put( void *image ); + + protected: + bool usable(); + + private: + Gtk::Widget *drawingArea; + }; + +} // namespace output +} // namespace gui +} // namespace lumiera + +#endif // GDKDISPLAYER_HPP diff --git a/src/gui/output/xvdisplayer.cpp b/src/gui/output/xvdisplayer.cpp new file mode 100644 index 000000000..cf7eeb53f --- /dev/null +++ b/src/gui/output/xvdisplayer.cpp @@ -0,0 +1,226 @@ +/* + xvdisplayer.cpp - Implements the base class for XVideo display + + Copyright (C) Lumiera.org + 2000, Arne Schirmacher + 2001-2007, Dan Dennedy + 2008, Joel Holdsworth + + 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 "../gtk-lumiera.hpp" + +#include + +#include "xvdisplayer.hpp" + +namespace lumiera { +namespace gui { +namespace output { + +XvDisplayer::XvDisplayer( Gtk::Widget *drawing_area, int width, int height ) : + xvImage( NULL ), + drawingArea( drawing_area ), + gotPort( false ) + { + INFO(gui, "Trying XVideo at %d x %d", width, height); + + imageWidth = width, imageHeight = height; + + shmInfo.shmaddr = NULL; + + Glib::RefPtr area_window = drawing_area->get_window(); + + window = gdk_x11_drawable_get_xid( area_window->gobj() ); + display = gdk_x11_drawable_get_xdisplay( area_window->gobj() ); + + unsigned int count; + XvAdaptorInfo *adaptorInfo; + + if ( XvQueryAdaptors( display, window, &count, &adaptorInfo ) == Success ) + { + + INFO(gui, "XvQueryAdaptors count: %d", count); + for ( unsigned int n = 0; gotPort == false && n < count; ++n ) + { + // Diagnostics + INFO(gui, "%s, %d, %d, %d", adaptorInfo[ n ].name, + adaptorInfo[ n ].base_id, adaptorInfo[ n ].num_ports - 1); + + for ( port = adaptorInfo[ n ].base_id; + port < adaptorInfo[ n ].base_id + adaptorInfo[ n ].num_ports; + port ++ ) + { + if ( XvGrabPort( display, port, CurrentTime ) == Success ) + { + int formats; + XvImageFormatValues *list; + + list = XvListImageFormats( display, port, &formats ); + + INFO(gui, "formats supported: %d", formats); + + for ( int i = 0; i < formats; i ++ ) + { + INFO(gui, "0x%x (%c%c%c%c) %s", + list[ i ].id, + ( list[ i ].id ) & 0xff, + ( list[ i ].id >> 8 ) & 0xff, + ( list[ i ].id >> 16 ) & 0xff, + ( list[ i ].id >> 24 ) & 0xff, + ( list[ i ].format == XvPacked ) ? "packed" : "planar" ); + if ( list[ i ].id == 0x32595559 && !gotPort ) + gotPort = true; + } + + if ( !gotPort ) + { + XvUngrabPort( display, port, CurrentTime ); + } + else + { + grabbedPort = port; + break; + } + } + } + } + + if ( gotPort ) + { + int num; + unsigned int unum; + XvEncodingInfo *enc; + + XvQueryEncodings( display, grabbedPort, &unum, &enc ); + for ( unsigned int index = 0; index < unum; index ++ ) + { + INFO(gui, "%d: %s, %ldx%ld rate = %d/%d", index, enc->name, + enc->width, enc->height, enc->rate.numerator, + enc->rate.denominator ); + } + + XvAttribute *xvattr = XvQueryPortAttributes( display, port, &num ); + for ( int k = 0; k < num; k++ ) + { + if ( xvattr[k].flags & XvSettable ) + { + if ( strcmp( xvattr[k].name, "XV_AUTOPAINT_COLORKEY") == 0 ) + { + Atom val_atom = XInternAtom( display, xvattr[k].name, False ); + if ( XvSetPortAttribute( display, port, val_atom, 1 ) != Success ) + ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); + } + else if ( strcmp( xvattr[k].name, "XV_COLORKEY") == 0 ) + { + Atom val_atom = XInternAtom( display, xvattr[k].name, False ); + if ( XvSetPortAttribute( display, port, val_atom, 0x010102 ) != Success ) + ERROR(gui, "Couldn't set Xv attribute %s\n", xvattr[k].name); + } + } + } + } + + if ( gotPort ) + { + gc = XCreateGC( display, window, 0, &values ); + + xvImage = ( XvImage * ) XvShmCreateImage( display, port, 0x32595559, 0, width, height, &shmInfo ); + + shmInfo.shmid = shmget( IPC_PRIVATE, xvImage->data_size, IPC_CREAT | 0777 ); + if (shmInfo.shmid < 0) { + perror("shmget"); + gotPort = false; + } + else + { + shmInfo.shmaddr = ( char * ) shmat( shmInfo.shmid, 0, 0 ); + xvImage->data = shmInfo.shmaddr; + shmInfo.readOnly = 0; + if ( !XShmAttach( gdk_display, &shmInfo ) ) + { + gotPort = false; + } + XSync( display, false ); + shmctl( shmInfo.shmid, IPC_RMID, 0 ); +#if 0 + xvImage = ( XvImage * ) XvCreateImage( display, port, 0x32595559, pix, width , height ); +#endif + } + } + } + else + { + gotPort = false; + } + } + +XvDisplayer::~XvDisplayer() + { + ERROR(gui, "Destroying XV Displayer"); + + if ( gotPort ) + { + XvUngrabPort( display, grabbedPort, CurrentTime ); + } + + //if ( xvImage != NULL ) + // XvStopVideo( display, port, window ); + + if ( shmInfo.shmaddr != NULL ) + { + XShmDetach( display, &shmInfo ); + shmctl( shmInfo.shmid, IPC_RMID, 0 ); + shmdt( shmInfo.shmaddr ); + } + + if ( xvImage != NULL ) + XFree( xvImage ); + } + +bool +XvDisplayer::usable() + { + return gotPort; + } + +void +XvDisplayer::put( void *image ) + { + REQUIRE(image != NULL); + ASSERT(drawingArea != NULL); + + if(xvImage != NULL) + { + int video_x = 0, video_y = 0, video_width = 0, video_height = 0; + calculateVideoLayout( + drawingArea->get_width(), + drawingArea->get_height(), + preferredWidth(), preferredHeight(), + video_x, video_y, video_width, video_height ); + + memcpy( xvImage->data, image, xvImage->data_size ); + + XvShmPutImage( display, port, window, gc, xvImage, + 0, 0, preferredWidth(), preferredHeight(), + video_x, video_y, video_width, video_height, false ); + } + } + +} // namespace output +} // namespace gui +} // namespace lumiera diff --git a/src/gui/output/xvdisplayer.hpp b/src/gui/output/xvdisplayer.hpp new file mode 100644 index 000000000..aae4e0281 --- /dev/null +++ b/src/gui/output/xvdisplayer.hpp @@ -0,0 +1,79 @@ +/* + xvdisplayer.hpp - Defines the base class for XVideo display + + Copyright (C) Lumiera.org + 2000, Arne Schirmacher + 2001-2007, Dan Dennedy + 2008, Joel Holdsworth + + 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 xvdisplayer.hpp + ** This file contains the definition of XvDisplayer, the XVideo + ** video output implementation + ** @see xvdisplayer.cpp + ** @see displayer.hpp + */ + +#include +#include +#include +#include +#include + +#include "displayer.hpp" + +#ifndef XVDISPLAYER_HPP +#define XVDISPLAYER_HPP + +namespace Gtk { + class Widget; +} + +namespace lumiera { +namespace gui { +namespace output { + + class XvDisplayer : public Displayer + { + public: + XvDisplayer( Gtk::Widget *drawing_area, int width, int height ); + ~XvDisplayer(); + + void put( void *image ); + + protected: + bool usable(); + + private: + bool gotPort; + int grabbedPort; + Gtk::Widget *drawingArea; + Display *display; + Window window; + GC gc; + XGCValues values; + XvImage *xvImage; + unsigned int port; + XShmSegmentInfo shmInfo; + char pix[ MAX_WIDTH * MAX_HEIGHT * 4 ]; + }; + +} // namespace output +} // namespace gui +} // namespace lumiera + +#endif // XVDISPLAYER_HPP diff --git a/src/gui/panels/assets-panel.cpp b/src/gui/panels/assets-panel.cpp new file mode 100644 index 000000000..58535f0e0 --- /dev/null +++ b/src/gui/panels/assets-panel.cpp @@ -0,0 +1,39 @@ +/* + assets-panel.cpp - Implementation of the assets panel + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "../gtk-lumiera.hpp" +#include "assets-panel.hpp" + +namespace lumiera { +namespace gui { +namespace panels { + +AssetsPanel::AssetsPanel() : + Panel("assets", _("Assets"), "panel_assets"), + placeholder("Placeholder label. Is this supposed to be titled assets\nas in the proc layer? or resources\nas in cinelerra?") + { + pack_start(placeholder); + } + +} // namespace panels +} // namespace gui +} // namespace lumiera diff --git a/src/gui/panels/assets-panel.hpp b/src/gui/panels/assets-panel.hpp new file mode 100644 index 000000000..899c15db4 --- /dev/null +++ b/src/gui/panels/assets-panel.hpp @@ -0,0 +1,48 @@ +/* + assets-panel.hpp - Definition of the assets panel + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 assets-panel.hpp + ** This file contains the definition of the assets panel + */ + +#ifndef ASSETS_PANEL_HPP +#define ASSETS_PANEL_HPP + +#include "panel.hpp" + +namespace lumiera { +namespace gui { +namespace panels { + + class AssetsPanel : public Panel + { + public: + AssetsPanel(); + + protected: + Gtk::Label placeholder; + }; + +} // namespace panels +} // namespace gui +} // namespace lumiera + +#endif // ASSETS_PANEL_HPP diff --git a/src/gui/panels/panel.cpp b/src/gui/panels/panel.cpp new file mode 100644 index 000000000..814845113 --- /dev/null +++ b/src/gui/panels/panel.cpp @@ -0,0 +1,93 @@ +/* + panel.cpp - Implementation of Panel, the base class for docking panels + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "panel.hpp" +#include "../gtk-lumiera.hpp" + +namespace lumiera { +namespace gui { +namespace panels { + +Panel::Panel(const gchar *name, const gchar *long_name, + GdlDockItemBehavior behavior) +{ + dock_item = (GdlDockItem*)gdl_dock_item_new ( + name, long_name, behavior); + internal_setup(); + + ENSURE(dock_item != NULL); +} + +Panel::Panel(const gchar *name, const gchar *long_name, const gchar *stock_id, + GdlDockItemBehavior behavior) +{ + dock_item = (GdlDockItem*)gdl_dock_item_new_with_stock ( + name, long_name, stock_id, behavior); + g_object_ref(dock_item); + internal_setup(); + + ENSURE(dock_item != NULL); +} + +Panel::~Panel() +{ + REQUIRE(dock_item != NULL); + g_object_unref(dock_item); + dock_item = NULL; +} + +GdlDockItem* +Panel::get_dock_item() const +{ + return dock_item; +} + +void +Panel::show(bool show) +{ + REQUIRE(dock_item != NULL); + if(show) gdl_dock_item_show_item (dock_item); + else gdl_dock_item_hide_item (dock_item); +} + +bool +Panel::is_shown() const +{ + REQUIRE(dock_item != NULL); + return GTK_WIDGET_VISIBLE((GtkWidget*)dock_item); +} + +void +Panel::internal_setup() +{ + REQUIRE(dock_item != NULL); + REQUIRE(gobj() != NULL); + + gdl_dock_item_hide_grip(dock_item); + gtk_container_add ((GtkContainer*)dock_item, (GtkWidget*)gobj()); + gtk_widget_show ((GtkWidget*)dock_item); +} + +} // namespace panels +} // namespace gui +} // namespace lumiera + diff --git a/src/gui/panels/panel.hpp b/src/gui/panels/panel.hpp new file mode 100644 index 000000000..4c71217c6 --- /dev/null +++ b/src/gui/panels/panel.hpp @@ -0,0 +1,97 @@ +/* + panel.hpp - Definition of Panel, the base class for docking panels + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 panel.hpp + ** This file contains the definition of Panel; the base class + ** for all docking panels + */ + +#ifndef PANEL_HPP +#define PANEL_HPP + +#include "../gtk-lumiera.hpp" +#include + +namespace lumiera { +namespace gui { +namespace panels { + +/** +* The main lumiera panel window +*/ +class Panel : public Gtk::VBox +{ +protected: + /** + * Constructs a panel object + * @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(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 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(const gchar *name, const gchar *long_name, const gchar *stock_id, + GdlDockItemBehavior behavior = GDL_DOCK_ITEM_BEH_NORMAL); + + ~Panel(); + +public: + /** + * Returns a pointer to the underlying GdlDockItem structure + */ + GdlDockItem* get_dock_item() const; + + /** + * Shows or hides the panel. + * @param show A value of true will show the panel, + * false will hide it. */ + void show(bool show = true); + + /** + * Returns true if the panel is currently visible. + */ + bool is_shown() const; + +private: + /** + * @internal Used by both constructors + * The internal constructor for this class, whose purpose + * is to set up the internal container widgets. + */ + void internal_setup(); + +protected: + GdlDockItem* dock_item; +}; + +} // namespace panels +} // namespace gui +} // namespace lumiera + +#endif // PANEL_HPP diff --git a/src/gui/panels/timeline-panel.cpp b/src/gui/panels/timeline-panel.cpp new file mode 100644 index 000000000..00a3c3f0f --- /dev/null +++ b/src/gui/panels/timeline-panel.cpp @@ -0,0 +1,118 @@ +/* + timeline-panel.cpp - Implementation of the timeline panel + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "../gtk-lumiera.hpp" +#include "timeline-panel.hpp" + +using namespace Gtk; +using namespace sigc; +using namespace lumiera::gui::widgets; + +namespace lumiera { +namespace gui { +namespace panels { + +const int TimelinePanel::ZoomToolSteps = 2; // 2 seems comfortable + +TimelinePanel::TimelinePanel() : + Panel("timeline", _("Timeline"), "panel_timeline"), + arrowTool(Gtk::StockID("tool_arrow")), + iBeamTool(Gtk::StockID("tool_i_beam")), + zoomIn(Stock::ZOOM_IN), + zoomOut(Stock::ZOOM_OUT), + updatingToolbar(false) +{ + // Setup the toolbar + 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(zoomIn, mem_fun(this, &TimelinePanel::on_zoom_in)); + toolbar.append(zoomOut, mem_fun(this, &TimelinePanel::on_zoom_out)); + + toolbar.set_icon_size(IconSize(ICON_SIZE_LARGE_TOOLBAR)); + toolbar.set_toolbar_style(TOOLBAR_ICONS); + + // Add the toolbar + pack_start(toolbar, PACK_SHRINK); + pack_start(timelineWidget, PACK_EXPAND_WIDGET); + + update_tool_buttons(); + update_zoom_buttons(); +} + +void +TimelinePanel::on_arrow_tool() +{ + if(updatingToolbar) return; + timelineWidget.set_tool(timeline::Arrow); + update_tool_buttons(); +} + +void +TimelinePanel::on_ibeam_tool() +{ + if(updatingToolbar) return; + timelineWidget.set_tool(timeline::IBeam); + update_tool_buttons(); +} + +void +TimelinePanel::on_zoom_in() +{ + + timelineWidget.zoom_view(ZoomToolSteps); + update_zoom_buttons(); +} + +void +TimelinePanel::on_zoom_out() +{ + timelineWidget.zoom_view(-ZoomToolSteps); + update_zoom_buttons(); +} + +void +TimelinePanel::update_tool_buttons() +{ + if(!updatingToolbar) + { + updatingToolbar = true; + const timeline::ToolType tool = timelineWidget.get_tool(); + arrowTool.set_active(tool == timeline::Arrow); + iBeamTool.set_active(tool == timeline::IBeam); + updatingToolbar = false; + } +} + +void +TimelinePanel::update_zoom_buttons() +{ + zoomIn.set_sensitive(timelineWidget.get_time_scale() != 1); + zoomOut.set_sensitive(timelineWidget.get_time_scale() != + TimelineWidget::MaxScale); +} + +} // namespace panels +} // namespace gui +} // namespace lumiera diff --git a/src/gui/panels/timeline-panel.hpp b/src/gui/panels/timeline-panel.hpp new file mode 100644 index 000000000..37491c0d9 --- /dev/null +++ b/src/gui/panels/timeline-panel.hpp @@ -0,0 +1,90 @@ +/* + timeline-panel.hpp - Definition of the timeline panel + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 timeline-panel.hpp + ** This file contains the definition of the timeline panel + */ + +#ifndef TIMELINE_PANEL_HPP +#define TIMELINE_PANEL_HPP + +#include "panel.hpp" +#include "../widgets/timeline-widget.hpp" + +using namespace lumiera::gui::widgets; + +namespace lumiera { +namespace gui { +namespace panels { + +/** + * The definition of the timeline panel class, which holds timeline + * widgets. + */ +class TimelinePanel : public Panel +{ +public: + /** + * Constructor + */ + TimelinePanel(); + +private: + //----- Event Handlers -----// + void on_arrow_tool(); + void on_ibeam_tool(); + + void on_zoom_in(); + void on_zoom_out(); + +private: + void update_tool_buttons(); + void update_zoom_buttons(); + +private: + + //----- Data -----// + + // Widgets + Gtk::Toolbar toolbar; + TimelineWidget timelineWidget; + + // Toolbar Widgets + Gtk::ToggleToolButton arrowTool; + Gtk::ToggleToolButton iBeamTool; + + Gtk::SeparatorToolItem seperator1; + + Gtk::ToolButton zoomIn; + Gtk::ToolButton zoomOut; + + // Internals + bool updatingToolbar; + + //----- Constants -----// + static const int ZoomToolSteps; +}; + +} // namespace panels +} // namespace gui +} // namespace lumiera + +#endif // TIMELINE_PANEL_H diff --git a/src/gui/panels/viewer-panel.cpp b/src/gui/panels/viewer-panel.cpp new file mode 100644 index 000000000..323859b9a --- /dev/null +++ b/src/gui/panels/viewer-panel.cpp @@ -0,0 +1,59 @@ +/* + viewer-panel.cpp - Implementation of the viewer panel + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "../gtk-lumiera.hpp" +#include "viewer-panel.hpp" + +using namespace lumiera::gui::widgets; +using namespace Gtk; + +namespace lumiera { +namespace gui { +namespace panels { + +ViewerPanel::ViewerPanel() : + Panel("viewer", _("Viewer"), "panel_viewer"), + previousButton(Stock::MEDIA_PREVIOUS), + rewindButton(Stock::MEDIA_REWIND), + playPauseButton(Stock::MEDIA_PLAY), + forwardButton(Stock::MEDIA_FORWARD), + nextButton(Stock::MEDIA_NEXT) + { + //----- Set up the Tool Bar -----// + // Add the commands + toolBar.append(previousButton); + toolBar.append(rewindButton); + toolBar.append(playPauseButton); + toolBar.append(forwardButton); + toolBar.append(nextButton); + + // Configure the toolbar + toolBar.set_toolbar_style(TOOLBAR_ICONS); + + //----- Pack in the Widgets -----// + pack_start(display, PACK_EXPAND_WIDGET); + pack_start(toolBar, PACK_SHRINK); + } + +} // namespace panels +} // namespace gui +} // namespace lumiera diff --git a/src/gui/panels/viewer-panel.hpp b/src/gui/panels/viewer-panel.hpp new file mode 100644 index 000000000..9f92b4f63 --- /dev/null +++ b/src/gui/panels/viewer-panel.hpp @@ -0,0 +1,62 @@ +/* + viewer-panel.hpp - Definition of the viewer panel + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 viewer-panel.hpp + ** This file contains the definition of the viewer panel + */ + +#ifndef VIEWER_PANEL_HPP +#define VIEWER_PANEL_HPP + +#include + +#include "panel.hpp" +#include "../widgets/video-display-widget.hpp" + +using namespace lumiera::gui::widgets; +using namespace Gtk; + +namespace lumiera { +namespace gui { +namespace panels { + + class ViewerPanel : public Panel + { + public: + ViewerPanel(); + + protected: + + ToolButton previousButton; + ToolButton rewindButton; + ToolButton playPauseButton; + ToolButton forwardButton; + ToolButton nextButton; + + VideoDisplayWidget display; + Toolbar toolBar; + }; + +} // namespace panels +} // namespace gui +} // namespace lumiera + +#endif // VIEWER_PANEL_HPP diff --git a/src/gui/widgets/timeline-widget.cpp b/src/gui/widgets/timeline-widget.cpp new file mode 100644 index 000000000..fd22ab3f9 --- /dev/null +++ b/src/gui/widgets/timeline-widget.cpp @@ -0,0 +1,317 @@ +/* + timeline-widget.cpp - Implementation of the timeline widget + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "timeline-widget.hpp" + +#include + +using namespace Gtk; +using namespace std; +using namespace lumiera::gui::widgets::timeline; + +namespace lumiera { +namespace gui { +namespace widgets { + +const int TimelineWidget::TrackPadding = 1; +const int TimelineWidget::HeaderWidth = 100; +const double TimelineWidget::ZoomIncrement = 1.25; +const int64_t TimelineWidget::MaxScale = 30000000; + +TimelineWidget::TimelineWidget() : + Table(2, 2), + timeOffset(0), + timeScale(1), + totalHeight(0), + horizontalAdjustment(0, 0, 0), + verticalAdjustment(0, 0, 0), + selectionStart(0), + selectionEnd(0), + horizontalScroll(horizontalAdjustment), + 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) ); + verticalAdjustment.signal_value_changed().connect( sigc::mem_fun( + this, &TimelineWidget::on_scroll) ); + body->signal_motion_notify_event().connect( sigc::mem_fun( + 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(*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); + + tracks.push_back(&video1); + tracks.push_back(&video2); + + update_tracks(); + + set_tool(timeline::Arrow); +} + +TimelineWidget::~TimelineWidget() +{ + REQUIRE(body != NULL); + if(body != NULL) + body->unreference(); + + REQUIRE(headerContainer != NULL); + if(headerContainer != NULL) + headerContainer->unreference(); + + REQUIRE(ruler != NULL); + if(ruler != NULL) + ruler->unreference(); +} + +gavl_time_t +TimelineWidget::get_time_offset() const +{ + return timeOffset; +} + +void +TimelineWidget::set_time_offset(gavl_time_t time_offset) +{ + REQUIRE(ruler != NULL); + + timeOffset = time_offset; + horizontalAdjustment.set_value(time_offset); + ruler->update_view(); +} + +int64_t +TimelineWidget::get_time_scale() const +{ + return timeScale; +} + +void +TimelineWidget::set_time_scale(int64_t time_scale) +{ + REQUIRE(ruler != NULL); + + timeScale = time_scale; + + const int view_width = body->get_allocation().get_width(); + horizontalAdjustment.set_page_size(timeScale * view_width); + + ruler->update_view(); +} + +void +TimelineWidget::zoom_view(int zoom_size) +{ + const Allocation allocation = body->get_allocation(); + zoom_view(allocation.get_width() / 2, zoom_size); +} + +void +TimelineWidget::zoom_view(int point, int zoom_size) +{ + int64_t new_time_scale = (double)timeScale * pow(1.25, -zoom_size); + + // Limit zooming in too close + if(new_time_scale < 1) new_time_scale = 1; + + // Nudge zoom problems caused by integer rounding + if(new_time_scale == timeScale && zoom_size < 0) + new_time_scale++; + + // Limit zooming out too far + if(new_time_scale > MaxScale) + new_time_scale = MaxScale; + + // The view must be shifted so that the zoom is centred on the cursor + set_time_offset(get_time_offset() + + (timeScale - new_time_scale) * point); + + // Apply the new scale + set_time_scale(new_time_scale); +} + +void +TimelineWidget::shift_view(int shift_size) +{ + const int view_width = body->get_allocation().get_width(); + + set_time_offset(get_time_offset() + + shift_size * timeScale * view_width / 256); +} + +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(body != NULL); + return body->get_tool(); +} + +void +TimelineWidget::set_tool(ToolType tool_type) +{ + REQUIRE(body != NULL); + body->set_tool(tool_type); +} + +void +TimelineWidget::on_scroll() +{ + timeOffset = horizontalAdjustment.get_value(); + ruler->update_view(); +} + +void +TimelineWidget::on_size_allocate(Allocation& allocation) +{ + Widget::on_size_allocate(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() +{ + ASSERT(headerContainer != NULL); + headerContainer->update_headers(); + + // Recalculate the total height of the timeline scrolled area + totalHeight = 0; + BOOST_FOREACH( Track* track, tracks ) + { + ASSERT(track != NULL); + totalHeight += track->get_height() + TrackPadding; + } +} + +void +TimelineWidget::update_scroll() +{ + ASSERT(body != NULL); + const Allocation body_allocation = body->get_allocation(); + + //----- Horizontal Scroll ------// + + // TEST CODE + horizontalAdjustment.set_upper(1000 * GAVL_TIME_SCALE / 200); + horizontalAdjustment.set_lower(-1000 * GAVL_TIME_SCALE / 200); + + // Set the page size + horizontalAdjustment.set_page_size( + timeScale * body_allocation.get_width()); + + //----- Vertical Scroll -----// + + // Calculate the vertical length that can be scrolled: + // the total height of all the tracks minus one screenful + int y_scroll_length = totalHeight - body_allocation.get_height(); + if(y_scroll_length < 0) y_scroll_length = 0; + + // If by resizing we're now over-scrolled, scroll back to + // maximum distance + if((int)verticalAdjustment.get_value() > y_scroll_length) + verticalAdjustment.set_value(y_scroll_length); + + verticalAdjustment.set_upper(y_scroll_length); + + // Hide the scrollbar if no scrolling is possible +#if 0 + // Having this code included seems to cause a layout loop as the + // window is shrunk + if(y_scroll_length <= 0 && verticalScroll.is_visible()) + verticalScroll.hide(); + else if(y_scroll_length > 0 && !verticalScroll.is_visible()) + verticalScroll.show(); +#endif +} + +int +TimelineWidget::get_y_scroll_offset() const +{ + return (int)verticalAdjustment.get_value(); +} + +bool +TimelineWidget::on_motion_in_body_notify_event(GdkEventMotion *event) +{ + REQUIRE(event != NULL); + ruler->set_mouse_chevron_offset(event->x); + return true; +} + +} // namespace widgets +} // namespace gui +} // namespace lumiera diff --git a/src/gui/widgets/timeline-widget.hpp b/src/gui/widgets/timeline-widget.hpp new file mode 100644 index 000000000..76e4a16d7 --- /dev/null +++ b/src/gui/widgets/timeline-widget.hpp @@ -0,0 +1,205 @@ +/* + timeline-widget.hpp - Declaration of the timeline widget + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 timeline-widget.hpp + ** This file contains the definition of timeline widget + */ + +#ifndef TIMELINE_WIDGET_HPP +#define TIMELINE_WIDGET_HPP + +#include "../gtk-lumiera.hpp" +#include "timeline/header-container.hpp" +#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 { +namespace gui { +namespace widgets { + +/** + * The namespace of all timeline widget helper classes. + */ +namespace timeline {} + +/** + * The timeline widget class. + * @remarks This widget is a composite of several widgets contained + * within the timeline namespace. + */ +class TimelineWidget : public Gtk::Table +{ +public: + TimelineWidget(); + + ~TimelineWidget(); + + /* ===== Data Access ===== */ +public: + /** + * Gets the time offset. This is the time value displaid at the + * left-hand edge of the timeline body area. + */ + gavl_time_t get_time_offset() const; + + /** + * Sets the time offset. This is the time value displaid at the + * left-hand edge of the timeline body area. + */ + void set_time_offset(gavl_time_t time_offset); + + /** + * Gets the time scale value. + * @return The scale factor, which is the number of microseconds per + * screen pixel. + */ + int64_t get_time_scale() const; + + /** + * 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); + + /** + * Zooms the view in or out as by a number of steps while keeping + * centre of the view still. + * @param zoom_size The number of steps to zoom by. The scale factor + * is 1.25^(-zoom_size). + **/ + void zoom_view(int zoom_size); + + /** + * Zooms the view in or out as by a number of steps while keeping a + * given point on the timeline still. + * @param zoom_size The number of steps to zoom by. The scale factor + * is 1.25^(-zoom_size). + **/ + void zoom_view(int point, int zoom_size); + + /** + * Scrolls the view horizontally as a proportion of the view area. + * @param shift_size The size of the shift in 1/256ths of the view + * width. + **/ + void shift_view(int shift_size); + + /** + * Gets the time at which the selection begins. + */ + gavl_time_t get_selection_start() const; + + /** + * Gets the time at which the selection begins. + */ + gavl_time_t get_selection_end() const; + + /** + * Sets the period of the selection. + */ + void set_selection(gavl_time_t start, gavl_time_t end); + + /** + * Gets the type of the tool currently active. + */ + timeline::ToolType get_tool() const; + + /** + * Sets the type of the tool currently active. + */ + void set_tool(timeline::ToolType tool_type); + + /* ===== Events ===== */ +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 ===== */ +private: + + void update_tracks(); + + void update_scroll(); + + int get_y_scroll_offset() const; + + 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; + + timeline::Track video1; + timeline::Track video2; + std::vector tracks; + + timeline::HeaderContainer *headerContainer; + timeline::TimelineBody *body; + timeline::TimelineRuler *ruler; + + Gtk::Adjustment horizontalAdjustment, verticalAdjustment; + Gtk::HScrollbar horizontalScroll; + Gtk::VScrollbar verticalScroll; + + /* ===== Constants ===== */ +public: + static const int64_t MaxScale; + +protected: + static const int TrackPadding; + static const int HeaderWidth; + static const double ZoomIncrement; + + 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 +} // namespace gui +} // namespace lumiera + +#endif // TIMELINE_WIDGET_HPP + diff --git a/src/gui/widgets/timeline/header-container.cpp b/src/gui/widgets/timeline/header-container.cpp new file mode 100644 index 000000000..dfc085fc1 --- /dev/null +++ b/src/gui/widgets/timeline/header-container.cpp @@ -0,0 +1,199 @@ +/* + header-container.cpp - Implementation of the header container widget + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 + +#include "header-container.hpp" +#include "track.hpp" +#include "../timeline-widget.hpp" + +using namespace Gtk; +using namespace std; + +namespace lumiera { +namespace gui { +namespace widgets { +namespace timeline { + +HeaderContainer::HeaderContainer(lumiera::gui::widgets::TimelineWidget *timeline_widget) : + timelineWidget(timeline_widget) +{ + REQUIRE(timeline_widget != NULL); + + // This widget will not have a window at first + set_flags(Gtk::NO_WINDOW); + + set_redraw_on_allocate(false); + + // Connect to the timeline widget's vertical scroll event, + // so that we get notified when the view shifts + timelineWidget->verticalAdjustment.signal_value_changed().connect( + sigc::mem_fun(this, &HeaderContainer::on_scroll) ); +} + +void +HeaderContainer::update_headers() +{ + ASSERT(timelineWidget != NULL); + + BOOST_FOREACH( Track* track, timelineWidget->tracks ) + { + ASSERT(track != NULL); + + Glib::RefPtr headerFrame(new Gtk::Frame()); + headerFrame->add(track->get_header_widget()); + headerFrame->set_shadow_type (Gtk::SHADOW_ETCHED_OUT); + headerFrame->set_name ("TimelineHeaderBaseUnselected"); + headerFrame->set_parent(*this); + headerFrame->show(); + + const RootHeader header = { headerFrame, track }; + rootHeaders.push_back(header); + } + + layout_headers(); +} + +void +HeaderContainer::on_realize() +{ + set_flags(Gtk::NO_WINDOW); + + ensure_style(); + + // Call base class: + Gtk::Widget::on_realize(); + + // Create the GdkWindow: + GdkWindowAttr attributes; + memset(&attributes, 0, sizeof(attributes)); + + Allocation allocation = get_allocation(); + + // Set initial position and size of the Gdk::Window: + attributes.x = allocation.get_x(); + attributes.y = allocation.get_y(); + attributes.width = allocation.get_width(); + attributes.height = allocation.get_height(); + + attributes.event_mask = get_events () | Gdk::EXPOSURE_MASK; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.wclass = GDK_INPUT_OUTPUT; + + gdkWindow = Gdk::Window::create(get_window(), &attributes, + GDK_WA_X | GDK_WA_Y); + unset_flags(Gtk::NO_WINDOW); + set_window(gdkWindow); + + // Unset the background so as to make the colour match the parent window + unset_bg(STATE_NORMAL); + + // Make the widget receive expose events + gdkWindow->set_user_data(gobj()); +} + +void +HeaderContainer::on_unrealize() +{ + // Unreference any window we may have created + gdkWindow.clear(); + + // Call base class: + Gtk::Widget::on_unrealize(); +} + +void +HeaderContainer::on_size_request (Requisition* requisition) +{ + // Initialize the output parameter: + *requisition = Gtk::Requisition(); + + requisition->width = TimelineWidget::HeaderWidth; + requisition->height = 0; +} + +void +HeaderContainer::on_size_allocate (Allocation& allocation) +{ + // Use the offered allocation for this container: + set_allocation(allocation); + + // Resize the widget's window + if(gdkWindow) + gdkWindow->resize(allocation.get_width(), allocation.get_height()); + + // Relayout the child widgets of the headers + layout_headers(); +} + +void +HeaderContainer::forall_vfunc(gboolean /* include_internals */, + GtkCallback callback, gpointer callback_data) +{ + BOOST_FOREACH( RootHeader &header, rootHeaders ) + { + ASSERT(header.widget); + callback(header.widget->gobj(), callback_data); + } +} + +void +HeaderContainer::on_scroll() +{ + // If the scroll has changed, we will have to shift all the + // header widgets + layout_headers(); +} + +void +HeaderContainer::layout_headers() +{ + ASSERT(timelineWidget != NULL); + + int offset = 0; + const int y_scroll_offset = timelineWidget->get_y_scroll_offset(); + + const Allocation container_allocation = get_allocation(); + + BOOST_FOREACH( RootHeader &header, rootHeaders ) + { + ASSERT(header.widget); + ASSERT(header.track != NULL); + + const int height = header.track->get_height(); + ASSERT(height >= 0); + + Gtk::Allocation header_allocation; + header_allocation.set_x (0); + header_allocation.set_y (offset - y_scroll_offset); + header_allocation.set_width (container_allocation.get_width ()); + header_allocation.set_height (height); + header.widget->size_allocate(header_allocation); + + offset += height + TimelineWidget::TrackPadding; + } +} + +} // namespace timeline +} // namespace widgets +} // namespace gui +} // namespace lumiera diff --git a/src/gui/widgets/timeline/header-container.hpp b/src/gui/widgets/timeline/header-container.hpp new file mode 100644 index 000000000..bc74a9c2a --- /dev/null +++ b/src/gui/widgets/timeline/header-container.hpp @@ -0,0 +1,155 @@ +/* + header-container.hpp - Declaration of the header container widget + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 header-container.hpp + ** This file contains the definition of the header container + ** widget + */ + +#ifndef HEADER_CONTAINER_HPP +#define HEADER_CONTAINER_HPP + +#include "../../gtk-lumiera.hpp" +#include + +namespace lumiera { +namespace gui { +namespace widgets { + +class TimelineWidget; + +namespace timeline { + +class Track; + +/** + * A helper class for the TimelineWidget. HeaderContainer is + * container widget for all the left-hand-side header widgets + * associated with timeline tracks. + */ +class HeaderContainer : public Gtk::Container +{ +public: + /** + * Constructor + * + * @param[in] timeline_widget A pointer to the owner timeline widget + */ + HeaderContainer(lumiera::gui::widgets::TimelineWidget* + timeline_widget); + + /** + * Attaches the header all the header widgets of root + * tracks to this control. + * + * @note This must be called when the track list changes + * to synchronise the headers with the timeline body and + * the backend. + */ + void update_headers(); + + /* ===== Overrides ===== */ +private: + /** + * And event handler for the window realized signal. + */ + void on_realize(); + + /** + * And event handler for the window unrealized signal. + */ + void on_unrealize(); + + /** + * An event handler that is called to notify this widget to allocate + * a given area for itself. + * @param allocation The area to allocate for this widget. + */ + void on_size_allocate (Gtk::Allocation& allocation); + + /** + * An event handler that is called to offer an allocation to this + * widget. + * @param requisition The area offered for this widget. + */ + void on_size_request (Gtk::Requisition* requisition); + + /** + * Applies a given function to all the widgets in the container. + **/ + void forall_vfunc(gboolean include_internals, GtkCallback callback, + gpointer callback_data); + + /* ===== Events ===== */ +private: + /** + * This event is called when the scroll bar moves. + */ + void on_scroll(); + + /* ===== Internals ===== */ +private: + + /** + * Moves all the header widgets to the correct position + * given scroll, stacking etc. + */ + void layout_headers(); + +private: + + /** + * The owner TimelineWidget of which this class is a helper + */ + lumiera::gui::widgets::TimelineWidget *timelineWidget; + + /** + * A structure to represent a header widget and it's + * associated track + */ + struct RootHeader + { + Glib::RefPtr widget; + Track *track; + }; + + /** + * Contains a list of the root currently present on + * the timeline view + */ + std::vector< RootHeader > rootHeaders; + + /** + * The widget's window object. + * + * @note This is needed for the sake of clipping when + * widgets are scrolled. + */ + Glib::RefPtr gdkWindow; +}; + +} // namespace timeline +} // namespace widgets +} // namespace gui +} // namespace lumiera + +#endif // HEADER_CONTAINER_HPP + diff --git a/src/gui/widgets/timeline/timeline-arrow-tool.cpp b/src/gui/widgets/timeline/timeline-arrow-tool.cpp new file mode 100644 index 000000000..109d6190e --- /dev/null +++ b/src/gui/widgets/timeline/timeline-arrow-tool.cpp @@ -0,0 +1,70 @@ +/* + timeline-arrow-tool.cpp - Implementation of the ArrowTool class + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 "timeline-arrow-tool.hpp" + +namespace lumiera { +namespace gui { +namespace widgets { +namespace timeline { + +ArrowTool::ArrowTool(TimelineBody *timeline_body) : + Tool(timeline_body) +{ + +} + +ToolType +ArrowTool::get_type() const +{ + return Arrow; +} + +Gdk::Cursor +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 +} // namespace lumiera + diff --git a/src/gui/widgets/timeline/timeline-arrow-tool.hpp b/src/gui/widgets/timeline/timeline-arrow-tool.hpp new file mode 100644 index 000000000..a6ec1f1bf --- /dev/null +++ b/src/gui/widgets/timeline/timeline-arrow-tool.hpp @@ -0,0 +1,83 @@ +/* + timeline-arrow-tool.hpp - Declaration of the ArrowTool class + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 timeline-arrow-tool.hpp + ** This file contains the definition of the arrow tool class + */ + +#ifndef TIMELINE_ARROW_TOOL_HPP +#define TIMELINE_ARROW_TOOL_HPP + +#include +#include "timeline-tool.hpp" + +namespace lumiera { +namespace gui { +namespace widgets { +namespace timeline { + +/** + * A helper class to implement the timeline i-beam tool + */ +class ArrowTool : public Tool +{ +public: + /** + * Constructor + * @param timeline_body The owner timeline body object + */ + ArrowTool(TimelineBody *timeline_body); + + /** + * Gets the type of tool represented by this class + */ + ToolType get_type() const; + +protected: + + /** + * Gets the cursor to display for this tool at this moment. + */ + Gdk::Cursor get_cursor() const; + +protected: + /** + * The event handler for button press events. + */ + void on_button_press_event(GdkEventButton* event); + + /** + * The event handler for button release events. + */ + void on_button_release_event(GdkEventButton* event); + + /** + * The event handler for mouse move events. + */ + void on_motion_notify_event(GdkEventMotion *event); +}; + +} // namespace timeline +} // namespace widgets +} // namespace gui +} // namespace lumiera + +#endif // TIMELINE_ARROW_TOOL_HPP diff --git a/src/gui/widgets/timeline/timeline-body.cpp b/src/gui/widgets/timeline/timeline-body.cpp new file mode 100644 index 000000000..64f545190 --- /dev/null +++ b/src/gui/widgets/timeline/timeline-body.cpp @@ -0,0 +1,387 @@ +/* + timeline.cpp - Implementation of the timeline widget + + Copyright (C) Lumiera.org + 2008, Joel Holdsworth + + 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 +#include + +#include "timeline-body.hpp" +#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; +using namespace lumiera::gui::widgets; +using namespace lumiera::gui::widgets::timeline; + +namespace lumiera { +namespace gui { +namespace widgets { +namespace timeline { + +TimelineBody::TimelineBody(lumiera::gui::widgets::TimelineWidget + *timeline_widget) : + Glib::ObjectBase("TimelineBody"), + tool(NULL), + dragType(None), + mouseDownX(0), + mouseDownY(0), + beginShiftTimeOffset(0), + selectionAlpha(0.5), + timelineWidget(timeline_widget) +{ + 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) ); + + // Install style properties + register_styles(); +} + +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() +{ + Widget::on_realize(); + + // We wish to receive event notifications + add_events( + Gdk::POINTER_MOTION_MASK | + Gdk::SCROLL_MASK | + Gdk::BUTTON_PRESS_MASK | + Gdk::BUTTON_RELEASE_MASK); + + // Apply the cursor if possible + 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) +{ + Cairo::Matrix view_matrix; + + REQUIRE(event != NULL); + REQUIRE(timelineWidget != NULL); + + // This is where we draw on the window + Glib::RefPtr window = get_window(); + if(!window) + return false; + + // Makes sure the widget styles have been loaded + read_styles(); + + // Prepare to render via cairo + Glib::RefPtr