diff --git a/ChangeLog b/ChangeLog index 2c56a69c..2efc7295 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +0.50: + * Right mouse button rotation now pivots around the camera. + * Added --no-time-travel option (Lars Schmertmann). + * Added --dir-name-position option (Lars Schmertmann). + * Added --file-extension-fallback option (Lars Schmertmann). + * Added --user-show-filter option (Victor Lopez). + * Fixed a bug in the Mercurial log parser that caused changes to be missed. + * Fixed file removal being cancelled by an action with an earlier timestamp. + * Fixed a bug in the log file format detection that could result in the wrong + first entry being displayed for a custom log. + +0.49: + * Fixed compatibility with GLM 0.9.9.0. + 0.48: * Can now generate logs from git sub module directories. diff --git a/INSTALL b/INSTALL index 44fb9484..d7a10359 100644 --- a/INSTALL +++ b/INSTALL @@ -27,8 +27,6 @@ Optional: SDL Image 2.0 needs to have been built with support PNG and JPEG images. -GLM is a header only library that you can get from http://glm.g-truc.net/ if your distribution does not include it. - 2. Building =========== @@ -65,8 +63,8 @@ If you already have these fonts, you can configure Gource to use them with: ./configure --enable-ttf-font-dir=/path/to/freefont/ -Gource includes a copy of the TinyXML library. To make Gource build against -the system library of TinyXML use: +Gource includes a copy of TinyXML. To build against the system version of the +library use: ./configure --with-tinyxml diff --git a/README b/README index 52bb4674..a9a4c4cb 100644 --- a/README +++ b/README @@ -34,7 +34,7 @@ card to run. 3. Using Gource =============== -gource +gource [options] [path] options: @@ -66,7 +66,7 @@ options: --transparent Make the background transparent. Only really useful for screenshots. - --start-date 'YYYY-MM-DD hh:mm:ss +tz' + --start-date "YYYY-MM-DD hh:mm:ss +tz" Start with the first entry after the supplied date and optional time. If a time zone offset isn't specified the local time zone is used. @@ -77,7 +77,7 @@ options: "2012-06-30 12:00" "2012-06-30 12:00:00 +12" - --stop-date 'YYYY-MM-DD hh:mm:ss +tz' + --stop-date "YYYY-MM-DD hh:mm:ss +tz" Stop after the last entry prior to the supplied date and optional time. Uses the same format as --start-date. @@ -106,6 +106,9 @@ options: --realtime Realtime playback speed. + --no-time-travel + Use the time of the last commit if the time of a commit is in the past. + -c, --time-scale SCALE Change simulation time scale. @@ -116,7 +119,7 @@ options: -e, --elasticity FLOAT Elasticity of nodes. - -b, --background-colour FFFFFF + -b, --background, --background-colour, --background-color FFFFFF Background colour in hex. --background-image IMAGE @@ -134,9 +137,21 @@ options: --font-size SIZE Font size used by the date and title. - --font-colour FFFFFF + --title-size SIZE + Font size used by just the title. + + --font-colour, --font-color FFFFFF Font colour used by the date and title in hex. + --title-colour, --title-color FFFFFF + Font colour used by just the title in hex. + + --date-height-pad VALUE + Value to add to the y position of the date. + + --title-height-pad VALUE + Value to add to the y position of the title. + --key Show file extension key. @@ -166,44 +181,54 @@ options: --highlight-users Highlight the names of all users. - --highlight-colour FFFFFF + --highlight-colour, --highlight-color FFFFFF Font colour for highlighted users in hex. - --selection-colour FFFFFF + --selection-colour, --selection-color FFFFFF Font colour for selected users and files. - --filename-colour FFFFFF + --filename-colour, --filename-color FFFFFF Font colour for filenames. - --dir-colour FFFFFF + --dir-colour, --dir-color FFFFFF Font colour for directories. --dir-name-depth DEPTH Draw names of directories down to a specific depth in the tree. + --dir-name-position FLOAT + Position along edge of the directory name + (between 0.1 and 1.0, default is 0.5). + --filename-time SECONDS Duration to keep filenames on screen (>= 2.0). --file-extensions Show filename extensions only. + --file-extension-fallback + Use filename as extension if the extension is missing or empty. + --file-filter REGEX - Filter out any files matching a specified regular expression. + Filter out file paths matching the specified regular expression. --file-show-filter REGEX - Show only files matching this regular expression. + Show only file paths matching the specified regular expression. --user-filter REGEX - Filter out any users matching a specified regular expression. + Filter usernames matching the specified regular expression. + + --user-show-filter REGEX + Show only usernames matching the specified regular expression. --user-image-dir DIRECTORY Directory containing .jpg or .png images of users - (eg 'Full Name.png') to use as avatars. + (eg "Full Name.png") to use as avatars. --default-user-image IMAGE Path of .jpg or .png to use as the default user image. - --colour-images + --colour-images, --color-images Colourize user images. --crop AXIS @@ -264,7 +289,7 @@ options: users - user avatars usernames - names of users - Separate multiple elements with commas (eg 'mouse,progress') + Separate multiple elements with commas (eg "mouse,progress") --hash-seed SEED Change the seed of hash function. @@ -275,7 +300,7 @@ options: --caption-size SIZE Caption size. - --caption-colour FFFFFF + --caption-colour, --caption-color FFFFFF Caption colour in hex. --caption-duration SECONDS diff --git a/autogen.sh b/autogen.sh index 3d0738a5..5867a668 100755 --- a/autogen.sh +++ b/autogen.sh @@ -4,7 +4,7 @@ if (autoreconf -f -i) ; then echo "Initializing submodules..." if (git submodule init) ; then echo "Updating submodules..." - if (git submodule update) ; then + if (git submodule update --init --recursive) ; then echo "Run './configure && make' to continue." else echo "Error: could not update submodules!" diff --git a/configure.ac b/configure.ac index 0f966ffd..6e5b34f2 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ AC_PREREQ(2.61) -AC_INIT(Gource, 0.48, [acaudwell@gmail.com]) +AC_INIT(Gource, 0.50, [acaudwell@gmail.com]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_SRCDIR([src/main.h]) AM_INIT_AUTOMAKE([dist-bzip2 foreign subdir-objects]) @@ -53,14 +53,13 @@ AX_BOOST_FILESYSTEM CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" LIBS="$LIBS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB" -#GLM -AC_CHECK_HEADER([glm/glm.hpp],, AC_MSG_ERROR(GLM headers are required. Please see INSTALL)) - #see if ttf-font-dir option is enabled AC_ARG_ENABLE(ttf-font-dir,[AS_HELP_STRING([--enable-ttf-font-dir=DIR],[directory containing GNU FreeFont TTF fonts])],[gourcefontdir="$enableval"],[gourcefontdir=""]) AM_CONDITIONAL([FONTDIR], [test "x$gourcefontdir" != "x"]) AC_SUBST(gourcefontdir) +#GLM +AC_CHECK_HEADER([glm/glm.hpp],, AC_MSG_ERROR(GLM headers are required. Please see INSTALL)) #see if building against system TinyXML library use_tinyxml_system_library=no diff --git a/data/gource.1 b/data/gource.1 index 43c00a0c..0a8352d0 100644 --- a/data/gource.1 +++ b/data/gource.1 @@ -3,7 +3,7 @@ Gource - a software version control visualization .SH SYNOPSIS \fIgource\fR - +[options] [path] .SH DESCRIPTION \fIgource\fR is an OpenGL-based 3D visualisation tool for source control repositories. @@ -36,7 +36,7 @@ Frameless window. \fB\-\-transparent\fR Make the background transparent. Only really useful for screenshots. .TP -\fB\-\-start\-date 'YYYY\-MM\-DD hh:mm:ss +tz'\fR +\fB\-\-start\-date "YYYY\-MM\-DD hh:mm:ss +tz"\fR Start with the first entry after the supplied date and optional time. If a time zone offset isn't specified the local time zone is used. @@ -47,7 +47,7 @@ Example accepted formats: "2012-06-30 12:00" "2012-06-30 12:00:00 +12" .TP -\fB\-\-stop\-date 'YYYY\-MM\-DD hh:mm:ss +tz'\fR +\fB\-\-stop\-date "YYYY\-MM\-DD hh:mm:ss +tz"\fR Stop at the last entry prior to the supplied date and optional time. Uses the same format as \-\-start\-date. @@ -76,6 +76,9 @@ Speed of simulation in seconds per day. \fB\-\-realtime\fR Realtime playback speed. .TP +\fB\-\-no\-time\-travel\fR +Use the time of the last commit if the time of a commit is in the past. +.TP \fB\-c, \-\-time\-scale SCALE\fR Change simulation time scale. .TP @@ -148,23 +151,32 @@ Font colour for directories. \fB\-\-dir\-name\-depth DEPTH\fR Draw names of directories down to a specific depth in the tree. .TP +\fB\-\-dir\-name\-position FLOAT +Position along edge of the directory name (between 0.1 and 1.0, default is 0.5). +.TP \fB\-\-filename\-time SECONDS\fR Duration to keep filenames on screen (>= 2.0). .TP \fB\-\-file\-extensions\fR Show filename extensions only. .TP +\fB\-\-file\-extension\-fallback\fR +Use filename as extension if the extension is missing or empty. +.TP \fB\-\-file\-filter REGEX\fR -Filter out any files matching a specified regular expression. +Filter out file paths matching the specified regular expression. .TP \fB\-\-file\-show\-filter REGEX\fR -Show only files matching this regular expression. +Show only file paths matching the specified regular expression. .TP \fB\-\-user\-filter REGEX\fR -Filter out any usernames matching a specified regular expression. +Filter usernames matching the specified regular expression. +.TP +\fB\-\-user\-show\-filter REGEX\fR +Show only usernames matching the specified regular expression. .TP \fB\-\-user\-image\-dir DIRECTORY\fR -Directory containing .jpg or .png images of users (eg 'Full Name.png') to use as avatars. +Directory containing .jpg or .png images of users (eg "Full Name.png") to use as avatars. .TP \fB\-\-default\-user\-image IMAGE\fR Path of .jpg to use as the default user image. @@ -226,7 +238,7 @@ Hide one or more display elements from the list below: users \- user avatars usernames \- names of users -Separate multiple elements with commas (eg 'mouse,progress') +Separate multiple elements with commas (eg "mouse,progress") .TP \fB\-\-hash\-seed SEED\fR diff --git a/m4/ax_boost_base.m4 b/m4/ax_boost_base.m4 index 8e6ee9a9..2bce5194 100644 --- a/m4/ax_boost_base.m4 +++ b/m4/ax_boost_base.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_base.html +# https://www.gnu.org/software/autoconf-archive/ax_boost_base.html # =========================================================================== # # SYNOPSIS @@ -33,7 +33,15 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 23 +#serial 43 + +# example boost program (need to pass version) +m4_define([_AX_BOOST_BASE_PROGRAM], + [AC_LANG_PROGRAM([[ +#include +]],[[ +(void) ((void)sizeof(char[1 - 2*!!((BOOST_VERSION) < ($1))])); +]])]) AC_DEFUN([AX_BOOST_BASE], [ @@ -44,101 +52,121 @@ AC_ARG_WITH([boost], or disable it (ARG=no) @<:@ARG=yes@:>@ ])], [ - if test "$withval" = "no"; then - want_boost="no" - elif test "$withval" = "yes"; then - want_boost="yes" - ac_boost_path="" - else - want_boost="yes" - ac_boost_path="$withval" - fi + AS_CASE([$withval], + [no],[want_boost="no";_AX_BOOST_BASE_boost_path=""], + [yes],[want_boost="yes";_AX_BOOST_BASE_boost_path=""], + [want_boost="yes";_AX_BOOST_BASE_boost_path="$withval"]) ], [want_boost="yes"]) AC_ARG_WITH([boost-libdir], - AS_HELP_STRING([--with-boost-libdir=LIB_DIR], - [Force given directory for boost libraries. Note that this will override library path detection, so use this parameter only if default library detection fails and you know exactly where your boost libraries are located.]), - [ - if test -d "$withval" - then - ac_boost_lib_path="$withval" - else - AC_MSG_ERROR(--with-boost-libdir expected directory name) - fi - ], - [ac_boost_lib_path=""] -) + [AS_HELP_STRING([--with-boost-libdir=LIB_DIR], + [Force given directory for boost libraries. + Note that this will override library path detection, + so use this parameter only if default library detection fails + and you know exactly where your boost libraries are located.])], + [ + AS_IF([test -d "$withval"], + [_AX_BOOST_BASE_boost_lib_path="$withval"], + [AC_MSG_ERROR([--with-boost-libdir expected directory name])]) + ], + [_AX_BOOST_BASE_boost_lib_path=""]) -if test "x$want_boost" = "xyes"; then - boost_lib_version_req=ifelse([$1], ,1.20.0,$1) - boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` - boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` - boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` - boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` - if test "x$boost_lib_version_req_sub_minor" = "x" ; then - boost_lib_version_req_sub_minor="0" - fi - WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` - AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) +BOOST_LDFLAGS="" +BOOST_CPPFLAGS="" +AS_IF([test "x$want_boost" = "xyes"], + [_AX_BOOST_BASE_RUNDETECT([$1],[$2],[$3])]) +AC_SUBST(BOOST_CPPFLAGS) +AC_SUBST(BOOST_LDFLAGS) +]) + + +# convert a version string in $2 to numeric and affect to polymorphic var $1 +AC_DEFUN([_AX_BOOST_BASE_TONUMERICVERSION],[ + AS_IF([test "x$2" = "x"],[_AX_BOOST_BASE_TONUMERICVERSION_req="1.20.0"],[_AX_BOOST_BASE_TONUMERICVERSION_req="$2"]) + _AX_BOOST_BASE_TONUMERICVERSION_req_shorten=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\.[[0-9]]*\)'` + _AX_BOOST_BASE_TONUMERICVERSION_req_major=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '\([[0-9]]*\)'` + AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_major" = "x"], + [AC_MSG_ERROR([You should at least specify libboost major version])]) + _AX_BOOST_BASE_TONUMERICVERSION_req_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.\([[0-9]]*\)'` + AS_IF([test "x$_AX_BOOST_BASE_TONUMERICVERSION_req_minor" = "x"], + [_AX_BOOST_BASE_TONUMERICVERSION_req_minor="0"]) + _AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + AS_IF([test "X$_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor" = "X"], + [_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor="0"]) + _AX_BOOST_BASE_TONUMERICVERSION_RET=`expr $_AX_BOOST_BASE_TONUMERICVERSION_req_major \* 100000 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_minor \* 100 \+ $_AX_BOOST_BASE_TONUMERICVERSION_req_sub_minor` + AS_VAR_SET($1,$_AX_BOOST_BASE_TONUMERICVERSION_RET) +]) + +dnl Run the detection of boost should be run only if $want_boost +AC_DEFUN([_AX_BOOST_BASE_RUNDETECT],[ + _AX_BOOST_BASE_TONUMERICVERSION(WANT_BOOST_VERSION,[$1]) succeeded=no + + AC_REQUIRE([AC_CANONICAL_HOST]) dnl On 64-bit systems check for system libraries in both lib64 and lib. dnl The former is specified by FHS, but e.g. Debian does not adhere to dnl this (as it rises problems for generic multi-arch support). dnl The last entry in the list is chosen by default when no libraries dnl are found, e.g. when only header-only libraries are installed! - libsubdirs="lib" - ax_arch=`uname -m` - case $ax_arch in - x86_64|ppc64|s390x|sparc64|aarch64) - libsubdirs="lib64 lib lib64" - ;; - esac + AS_CASE([${host_cpu}], + [x86_64],[libsubdirs="lib64 libx32 lib lib64"], + [ppc64|s390x|sparc64|aarch64|ppc64le],[libsubdirs="lib64 lib lib64"], + [libsubdirs="lib"] + ) dnl allow for real multi-arch paths e.g. /usr/lib/x86_64-linux-gnu. Give dnl them priority over the other paths since, if libs are found there, they dnl are almost assuredly the ones desired. - AC_REQUIRE([AC_CANONICAL_HOST]) - libsubdirs="lib/${host_cpu}-${host_os} $libsubdirs" - - case ${host_cpu} in - i?86) - libsubdirs="lib/i386-${host_os} $libsubdirs" - ;; - esac + AS_CASE([${host_cpu}], + [i?86],[multiarch_libsubdir="lib/i386-${host_os}"], + [multiarch_libsubdir="lib/${host_cpu}-${host_os}"] + ) dnl first we check the system location for boost libraries dnl this location ist chosen if boost libraries are installed with the --layout=system option dnl or if you install boost with RPM - if test "$ac_boost_path" != ""; then - BOOST_CPPFLAGS="-I$ac_boost_path/include" - for ac_boost_path_tmp in $libsubdirs; do - if test -d "$ac_boost_path"/"$ac_boost_path_tmp" ; then - BOOST_LDFLAGS="-L$ac_boost_path/$ac_boost_path_tmp" - break - fi - done - elif test "$cross_compiling" != yes; then - for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do - if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then - for libsubdir in $libsubdirs ; do - if ls "$ac_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + AS_IF([test "x$_AX_BOOST_BASE_boost_path" != "x"],[ + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) includes in "$_AX_BOOST_BASE_boost_path/include"]) + AS_IF([test -d "$_AX_BOOST_BASE_boost_path/include" && test -r "$_AX_BOOST_BASE_boost_path/include"],[ + AC_MSG_RESULT([yes]) + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include" + for _AX_BOOST_BASE_boost_path_tmp in $multiarch_libsubdir $libsubdirs; do + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION) lib path in "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"]) + AS_IF([test -d "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" && test -r "$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp" ],[ + AC_MSG_RESULT([yes]) + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$_AX_BOOST_BASE_boost_path_tmp"; + break; + ], + [AC_MSG_RESULT([no])]) + done],[ + AC_MSG_RESULT([no])]) + ],[ + if test X"$cross_compiling" = Xyes; then + search_libsubdirs=$multiarch_libsubdir + else + search_libsubdirs="$multiarch_libsubdir $libsubdirs" + fi + for _AX_BOOST_BASE_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path_tmp/include/boost" && test -r "$_AX_BOOST_BASE_boost_path_tmp/include/boost" ; then + for libsubdir in $search_libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path_tmp/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done - BOOST_LDFLAGS="-L$ac_boost_path_tmp/$libsubdir" - BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path_tmp/$libsubdir" + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path_tmp/include" break; fi done - fi + ]) dnl overwrite ld flags if we have required special directory with dnl --with-boost-libdir parameter - if test "$ac_boost_lib_path" != ""; then - BOOST_LDFLAGS="-L$ac_boost_lib_path" - fi + AS_IF([test "x$_AX_BOOST_BASE_boost_lib_path" != "x"], + [BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_lib_path"]) + AC_MSG_CHECKING([for boostlib >= $1 ($WANT_BOOST_VERSION)]) CPPFLAGS_SAVED="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" export CPPFLAGS @@ -149,15 +177,7 @@ if test "x$want_boost" = "xyes"; then AC_REQUIRE([AC_PROG_CXX]) AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= $WANT_BOOST_VERSION - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ + AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ AC_MSG_RESULT(yes) succeeded=yes found_system=yes @@ -169,30 +189,50 @@ if test "x$want_boost" = "xyes"; then dnl if we found no boost with system layout we search for boost libraries dnl built and installed without the --layout=system option or for a staged(not installed) version - if test "x$succeeded" != "xyes"; then + if test "x$succeeded" != "xyes" ; then + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + BOOST_CPPFLAGS= + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then + BOOST_LDFLAGS= + fi _version=0 - if test "$ac_boost_path" != ""; then - if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then - for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + if test -n "$_AX_BOOST_BASE_boost_path" ; then + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path"; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` V_CHECK=`expr $_version_tmp \> $_version` - if test "$V_CHECK" = "1" ; then + if test "x$V_CHECK" = "x1" ; then _version=$_version_tmp fi VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` - BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path/include/boost-$VERSION_UNDERSCORE" done + dnl if nothing found search for layout used in Windows distributions + if test -z "$BOOST_CPPFLAGS"; then + if test -d "$_AX_BOOST_BASE_boost_path/boost" && test -r "$_AX_BOOST_BASE_boost_path/boost"; then + BOOST_CPPFLAGS="-I$_AX_BOOST_BASE_boost_path" + fi + fi + dnl if we found something and BOOST_LDFLAGS was unset before + dnl (because "$_AX_BOOST_BASE_boost_lib_path" = ""), set it here. + if test -n "$BOOST_CPPFLAGS" && test -z "$BOOST_LDFLAGS"; then + for libsubdir in $libsubdirs ; do + if ls "$_AX_BOOST_BASE_boost_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi + done + BOOST_LDFLAGS="-L$_AX_BOOST_BASE_boost_path/$libsubdir" + fi fi else - if test "$cross_compiling" != yes; then - for ac_boost_path in /usr /usr/local /opt /opt/local ; do - if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then - for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do - _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + if test "x$cross_compiling" != "xyes" ; then + for _AX_BOOST_BASE_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$_AX_BOOST_BASE_boost_path" && test -r "$_AX_BOOST_BASE_boost_path" ; then + for i in `ls -d $_AX_BOOST_BASE_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$_AX_BOOST_BASE_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` V_CHECK=`expr $_version_tmp \> $_version` - if test "$V_CHECK" = "1" ; then + if test "x$V_CHECK" = "x1" ; then _version=$_version_tmp - best_path=$ac_boost_path + best_path=$_AX_BOOST_BASE_boost_path fi done fi @@ -200,7 +240,7 @@ if test "x$want_boost" = "xyes"; then VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" - if test "$ac_boost_lib_path" = ""; then + if test -z "$_AX_BOOST_BASE_boost_lib_path" ; then for libsubdir in $libsubdirs ; do if ls "$best_path/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done @@ -208,7 +248,7 @@ if test "x$want_boost" = "xyes"; then fi fi - if test "x$BOOST_ROOT" != "x"; then + if test -n "$BOOST_ROOT" ; then for libsubdir in $libsubdirs ; do if ls "$BOOST_ROOT/stage/$libsubdir/libboost_"* >/dev/null 2>&1 ; then break; fi done @@ -217,7 +257,7 @@ if test "x$want_boost" = "xyes"; then stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` V_CHECK=`expr $stage_version_shorten \>\= $_version` - if test "$V_CHECK" = "1" -a "$ac_boost_lib_path" = "" ; then + if test "x$V_CHECK" = "x1" && test -z "$_AX_BOOST_BASE_boost_lib_path" ; then AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) BOOST_CPPFLAGS="-I$BOOST_ROOT" BOOST_LDFLAGS="-L$BOOST_ROOT/stage/$libsubdir" @@ -232,15 +272,7 @@ if test "x$want_boost" = "xyes"; then export LDFLAGS AC_LANG_PUSH(C++) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ - @%:@include - ]], [[ - #if BOOST_VERSION >= $WANT_BOOST_VERSION - // Everything is okay - #else - # error Boost version is too old - #endif - ]])],[ + AC_COMPILE_IFELSE([_AX_BOOST_BASE_PROGRAM($WANT_BOOST_VERSION)],[ AC_MSG_RESULT(yes) succeeded=yes found_system=yes @@ -249,17 +281,15 @@ if test "x$want_boost" = "xyes"; then AC_LANG_POP([C++]) fi - if test "$succeeded" != "yes" ; then - if test "$_version" = "0" ; then - AC_MSG_NOTICE([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) + if test "x$succeeded" != "xyes" ; then + if test "x$_version" = "x0" ; then + AC_MSG_NOTICE([[We could not detect the boost libraries (version $1 or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in . See http://randspringer.de/boost for more documentation.]]) else AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) fi # execute ACTION-IF-NOT-FOUND (if present): ifelse([$3], , :, [$3]) else - AC_SUBST(BOOST_CPPFLAGS) - AC_SUBST(BOOST_LDFLAGS) AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) # execute ACTION-IF-FOUND (if present): ifelse([$2], , :, [$2]) @@ -267,6 +297,5 @@ if test "x$want_boost" = "xyes"; then CPPFLAGS="$CPPFLAGS_SAVED" LDFLAGS="$LDFLAGS_SAVED" -fi ]) diff --git a/m4/ax_boost_filesystem.m4 b/m4/ax_boost_filesystem.m4 index f162163c..c392f9d6 100644 --- a/m4/ax_boost_filesystem.m4 +++ b/m4/ax_boost_filesystem.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_filesystem.html +# https://www.gnu.org/software/autoconf-archive/ax_boost_filesystem.html # =========================================================================== # # SYNOPSIS @@ -31,7 +31,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 26 +#serial 27 AC_DEFUN([AX_BOOST_FILESYSTEM], [ diff --git a/m4/ax_boost_system.m4 b/m4/ax_boost_system.m4 index c4c45559..207d7be8 100644 --- a/m4/ax_boost_system.m4 +++ b/m4/ax_boost_system.m4 @@ -1,5 +1,5 @@ # =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_boost_system.html +# https://www.gnu.org/software/autoconf-archive/ax_boost_system.html # =========================================================================== # # SYNOPSIS @@ -31,7 +31,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 17 +#serial 19 AC_DEFUN([AX_BOOST_SYSTEM], [ @@ -68,9 +68,10 @@ AC_DEFUN([AX_BOOST_SYSTEM], ax_cv_boost_system, [AC_LANG_PUSH([C++]) CXXFLAGS_SAVE=$CXXFLAGS + CXXFLAGS= AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::system::system_category]])], + [[boost::system::error_category *a = 0;]])], ax_cv_boost_system=yes, ax_cv_boost_system=no) CXXFLAGS=$CXXFLAGS_SAVE AC_LANG_POP([C++]) diff --git a/src/action.cpp b/src/action.cpp index 1278a4ce..3059c7db 100644 --- a/src/action.cpp +++ b/src/action.cpp @@ -17,18 +17,12 @@ #include "action.h" -RAction::RAction(RUser* source, RFile* target, float addedtime) { - this->source = source; - this->target = target; - this->addedtime = addedtime; - - progress = 0.0; - - rate = 0.5; +RAction::RAction(RUser* source, RFile* target, time_t timestamp, float t, const vec3& colour) + : colour(colour), source(source), target(target), timestamp(timestamp), t(t), progress(0.0f), rate(0.5f) { } void RAction::apply() { - target->touch(colour); + target->touch(timestamp, colour); } void RAction::logic(float dt) { @@ -104,12 +98,12 @@ void RAction::draw(float dt) { glEnd(); } -CreateAction::CreateAction(RUser* source, RFile* target, float addedtime) : RAction(source, target, addedtime) { - colour = vec3(0.0, 1.0, 0.0); +CreateAction::CreateAction(RUser* source, RFile* target, time_t timestamp, float t) + : RAction(source, target, timestamp, t, vec3(0.0f, 1.0f, 0.0f)) { } -RemoveAction::RemoveAction(RUser* source, RFile* target, float addedtime): RAction(source, target, addedtime) { - colour = vec3(1.0, 0.0, 0.0); +RemoveAction::RemoveAction(RUser* source, RFile* target, time_t timestamp, float t) + : RAction(source, target, timestamp, t, vec3(1.0f, 0.0f, 0.0f)) { } void RemoveAction::logic(float dt) { @@ -118,13 +112,12 @@ void RemoveAction::logic(float dt) { RAction::logic(dt); if(old_progress < 1.0 && progress >= 1.0) { - target->remove(); + target->remove(timestamp); } } -ModifyAction::ModifyAction(RUser* source, RFile* target, float addedtime, const vec3& modify_colour) - : modify_colour(modify_colour), RAction(source, target, addedtime) { - colour = vec3(1.0, 0.7, 0.3); +ModifyAction::ModifyAction(RUser* source, RFile* target, time_t timestamp, float t, const vec3& modify_colour) + : RAction(source, target, timestamp, t, vec3(1.0f, 0.7f, 0.3f)), modify_colour(modify_colour) { } void ModifyAction::apply() { diff --git a/src/action.h b/src/action.h index 93d167a7..0cbb3848 100644 --- a/src/action.h +++ b/src/action.h @@ -32,12 +32,13 @@ class RAction { RUser* source; RFile* target; - float addedtime; + time_t timestamp; + float t; float progress; float rate; - RAction(RUser* source, RFile* target, float addedtime); + RAction(RUser* source, RFile* target, time_t timestamp, float t, const vec3& colour); virtual ~RAction() {}; inline bool isFinished() const { return (progress >= 1.0); }; @@ -50,12 +51,12 @@ class RAction { class CreateAction : public RAction { public: - CreateAction(RUser* source, RFile* target, float addedtime); + CreateAction(RUser* source, RFile* target, time_t timestamp, float t); }; class RemoveAction : public RAction { public: - RemoveAction(RUser* source, RFile* target, float addedtime); + RemoveAction(RUser* source, RFile* target, time_t timestamp, float t); void logic(float dt); }; @@ -64,7 +65,7 @@ class ModifyAction : public RAction { protected: vec3 modify_colour; public: - ModifyAction(RUser* source, RFile* target, float addedtime, const vec3& modify_colour); + ModifyAction(RUser* source, RFile* target, time_t timestamp, float t, const vec3& modify_colour); void apply(); }; diff --git a/src/dirnode.cpp b/src/dirnode.cpp index 8db076e7..6d23f385 100644 --- a/src/dirnode.cpp +++ b/src/dirnode.cpp @@ -114,15 +114,23 @@ void RDirNode::nodeUpdated(bool userInitiated) { } void RDirNode::rotate(float s, float c) { + pos = rotate_vec2(pos, s, c); + spos = rotate_vec2(spos, s, c); - if(parent != 0) { - pos = rotate_vec2(pos, s, c); - spos = rotate_vec2(spos, s, c); + for(std::list::iterator it = children.begin(); it != children.end(); it++) { + RDirNode* child = (*it); + child->rotate(s, c); } +} + +void RDirNode::rotate(float s, float c, const vec2& centre) { + + pos = rotate_vec2(pos - centre, s, c) + centre; + spos = rotate_vec2(spos - centre, s, c) + centre; for(std::list::iterator it = children.begin(); it != children.end(); it++) { RDirNode* child = (*it); - child->rotate(s, c); + child->rotate(s, c, centre); } } @@ -430,7 +438,7 @@ bool RDirNode::addFile(RFile* f) { if(f->path.find(file->fullpath) == 0) { //fprintf(stderr, "removing %s as is actually the directory of %s\n", file->fullpath.c_str(), f->fullpath.c_str()); - file->remove(true); + file->remove(); break; } } @@ -792,7 +800,6 @@ void RDirNode::move(float dt) { //the root node is the centre of the world if(parent == 0) { - pos = vec2(0.0f); return; } @@ -929,10 +936,10 @@ void RDirNode::drawDirName(FXFont& dirfont) const{ float alpha = gGourceSettings.highlight_dirs ? 1.0 : std::max(0.0f, 5.0f - since_last_node_change) / 5.0f; - vec2 mid = spline.getMidPoint(); + vec2 label_pos = spline.getLabelPos(); dirfont.setAlpha(alpha); - dirfont.draw(mid.x, mid.y, path_token); + dirfont.draw(label_pos.x, label_pos.y, path_token); } void RDirNode::calcScreenPos(GLint* viewport, GLdouble* modelview, GLdouble* projection) { diff --git a/src/dirnode.h b/src/dirnode.h index 7ae124f9..8a78782b 100644 --- a/src/dirnode.h +++ b/src/dirnode.h @@ -173,6 +173,7 @@ class RDirNode : public QuadItem { void setPos(const vec2 & pos); void rotate(float s, float c); + void rotate(float s, float c, const vec2& centre); void setParent(RDirNode* parent); diff --git a/src/file.cpp b/src/file.cpp index afb2da94..2ada6fb1 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -40,8 +40,10 @@ RFile::RFile(const std::string & name, const vec3 & colour, const vec2 & pos, in last_action = 0.0f; fade_start = -1.0f; + removed_timestamp = 0; expired = false; forced_removal = false; + removing = false; shadow = true; @@ -63,21 +65,24 @@ RFile::RFile(const std::string & name, const vec3 & colour, const vec2 & pos, in file_font.setColour(vec4(gGourceSettings.filename_colour, 1.0f)); } - //namelist = glGenLists(1); - //label = 0; setSelected(false); dir = 0; } RFile::~RFile() { - //glDeleteLists(namelist, 1); } -void RFile::remove(bool force) { +void RFile::remove(time_t removed_timestamp) { last_action = elapsed; fade_start = elapsed; - if(force) forced_removal = true; + removing = true; + this->removed_timestamp = removed_timestamp; +} + +void RFile::remove() { + forced_removal = true; + remove(0); } void RFile::setDir(RDirNode* dir) { @@ -119,42 +124,15 @@ void RFile::setFilename(const std::string& abs_file_path) { } //trim name to just extension - int dotsep=0; + size_t dotsep = name.rfind("."); - if((dotsep=name.rfind(".")) != std::string::npos && dotsep != name.size()-1) { + if(dotsep != std::string::npos && dotsep != name.size()-1) { ext = name.substr(dotsep+1); + } else if(gGourceSettings.file_extension_fallback) { + ext = name; } } -int call_count = 0; - - -void RFile::setSelected(bool selected) { -// if(font.getFTFont()!=0 && this->selected==selected) return; - //if(label && this->selected==selected) return; - -// if(!label) label = new FXLabel(); - - Pawn::setSelected(selected); - -// updateLabel(); - - //pre-compile name display list - //glNewList(namelist, GL_COMPILE); - // font.draw(0.0f, 0.0f, (selected || shortname.size()==0) ? name : shortname); - //glEndList(); -} - -void RFile::updateLabel() { -/* bool show_file_ext = gGourceSettings.file_extensions; - - if(selected) { - label->setText(file_selected_font, (selected || !show_file_ext) ? name : ext); - } else { - label->setText(file_font, (selected || !show_file_ext) ? name : ext); - }*/ -} - void RFile::colourize() { file_colour = ext.size() ? colourHash(ext) : vec3(1.0f, 1.0f, 1.0f); } @@ -246,17 +224,18 @@ void RFile::logic(float dt) { if(isHidden() && !forced_removal) elapsed = 0.0; } -void RFile::touch(const vec3 & colour) { - if(forced_removal) return; +void RFile::touch(time_t touched_timestamp, const vec3 & colour) { + if(forced_removal || (removing && touched_timestamp < removed_timestamp)) return; - fade_start = -1.0f; - //fprintf(stderr, "touch %s\n", fullpath.c_str()); + fade_start = -1.0f; + removing = false; + removed_timestamp = 0; last_action = elapsed; touch_colour = colour; - //un expire file + //un expire file if touched after being removed if(expired) { for(std::vector::iterator it = gGourceRemovedFiles.begin(); it != gGourceRemovedFiles.end(); it++) { if((*it) == this) { diff --git a/src/file.h b/src/file.h index 61128ee0..e8b75e87 100644 --- a/src/file.h +++ b/src/file.h @@ -30,8 +30,10 @@ class RFile : public Pawn { RDirNode* dir; + time_t removed_timestamp; bool forced_removal; bool expired; + bool removing; float fade_start; @@ -67,11 +69,7 @@ class RFile : public Pawn { float getAlpha() const; - void touch(const vec3 & colour); - - void setSelected(bool selected); - - void updateLabel(); + void touch(time_t touch_timestamp, const vec3& colour); void setHidden(bool hidden); @@ -83,7 +81,8 @@ class RFile : public Pawn { void logic(float dt); void draw(float dt); - void remove(bool force=false); + void remove(time_t removed_timestamp); + void remove(); vec2 getAbsolutePos() const; diff --git a/src/formats/commitlog.cpp b/src/formats/commitlog.cpp index 800e59cd..0a37a166 100644 --- a/src/formats/commitlog.cpp +++ b/src/formats/commitlog.cpp @@ -130,6 +130,7 @@ bool RCommitLog::checkFormat() { if(seekable) { //if the log is seekable, go back to the start ((SeekLog*)logf)->seekTo(0.0); + lastline.clear(); } else { //otherwise set the buffered flag as we have bufferd one commit buffered = true; @@ -171,7 +172,7 @@ bool RCommitLog::getCommitAt(float percent, RCommit& commit) { bool RCommitLog::getNextLine(std::string& line) { if(!lastline.empty()) { line = lastline; - lastline = std::string(""); + lastline.clear(); return true; } @@ -182,7 +183,7 @@ bool RCommitLog::getNextLine(std::string& line) { void RCommitLog::seekTo(float percent) { if(!seekable) return; - lastline = ""; + lastline.clear(); ((SeekLog*)logf)->seekTo(percent); } @@ -360,6 +361,19 @@ bool RCommit::isValid() { } } + // Only allow users that have been whitelisted + if(!gGourceSettings.user_show_filters.empty()) { + + for(std::vector::iterator ri = gGourceSettings.user_show_filters.begin(); ri != gGourceSettings.user_show_filters.end(); ri++) { + Regex* r = *ri; + + if(!r->match(username)) { + return false; + } + } + } + + return !files.empty(); } diff --git a/src/formats/hg.cpp b/src/formats/hg.cpp index 7a4e612c..984e6e6e 100644 --- a/src/formats/hg.cpp +++ b/src/formats/hg.cpp @@ -114,7 +114,7 @@ bool MercurialLog::parseCommitEntry(RCommit& commit) { std::string line; std::vector entries; - if(!logf->getNextLine(line)) return false; + if(!getNextLine(line)) return false; //custom line if(!hg_regex.match(line, &entries)) return false; diff --git a/src/gource.cpp b/src/gource.cpp index ae1cd8b8..efae7221 100644 --- a/src/gource.cpp +++ b/src/gource.cpp @@ -44,6 +44,19 @@ Gource::Gource(FrameExporter* exporter) { fontmedium.dropShadow(true); fontmedium.roundCoordinates(false); + int title_size = (gGourceSettings.title_font_size>0?gGourceSettings.title_font_size:gGourceSettings.font_size); + fonttitle = fontmanager.grab("FreeSans.ttf", title_size); + fonttitle.dropShadow(true); + fonttitle.roundCoordinates(false); + fonttitle.alignTop(false); + + // Fall back to generic font color if title font color was not set + if(gGourceSettings.title_font_colour.x < 0) { + gGourceSettings.title_font_colour = gGourceSettings.font_colour; + } + + title_x_offset = (int) fonttitle.getWidth(gGourceSettings.title) * 0.5; + fontcaption = fontmanager.grab("FreeSans.ttf", gGourceSettings.caption_size); fontcaption.dropShadow(true); fontcaption.roundCoordinates(false); @@ -753,8 +766,6 @@ void Gource::keyPress(SDL_KeyboardEvent *e) { gGourceSettings.file_extensions = true; gGourceSettings.hide_filenames = false; } - - update_file_labels = true; } if (e->keysym.sym == SDLK_r) { @@ -857,7 +868,6 @@ void Gource::reset() { active_user_bounds.reset(); dir_bounds.reset(); commitqueue.clear(); - tagfilemap.clear(); tagusermap.clear(); gGourceRemovedFiles.clear(); @@ -865,7 +875,6 @@ void Gource::reset() { if(dirNodeTree!=0) delete dirNodeTree; recolour = false; - update_file_labels = false; userTree = 0; dirNodeTree = 0; @@ -959,7 +968,6 @@ void Gource::deleteFile(RFile* file) { } files.erase(file->fullpath); - tagfilemap.erase(file->getTagID()); file_key.dec(file); //debugLog("removed file %s\n", file->fullpath.c_str()); @@ -985,7 +993,6 @@ RFile* Gource::addFile(const RCommitFile& cf) { RFile* file = new RFile(cf.filename, cf.colour, vec2(0.0,0.0), tagid); files[cf.filename] = file; - tagfilemap[tagid] = file; root->addFile(file); @@ -1120,6 +1127,13 @@ void Gource::readLog() { break; } + if(gGourceSettings.no_time_travel) { + time_t check_time = commitqueue.empty() ? lasttime : commitqueue.back().timestamp; + if(commit.timestamp < check_time) { + commit.timestamp = check_time; + } + } + commitqueue.push_back(commit); } @@ -1151,12 +1165,12 @@ void Gource::readLog() { //debugLog("current date: %s\n", displaydate.c_str()); } -void Gource::processCommit(RCommit& commit, float t) { +void Gource::processCommit(const RCommit& commit, float t) { //find files of this commit or create it - for(std::list::iterator it = commit.files.begin(); it != commit.files.end(); it++) { + for(std::list::const_iterator it = commit.files.begin(); it != commit.files.end(); it++) { - RCommitFile& cf = *it; + const RCommitFile& cf = *it; RFile* file = 0; //is this a directory (ends in slash) @@ -1187,7 +1201,7 @@ void Gource::processCommit(RCommit& commit, float t) { for(std::list::iterator it = dir_files.begin(); it != dir_files.end(); it++) { RFile* file = *it; - addFileAction(commit.username, cf, file, t); + addFileAction(commit, cf, file, t); } } @@ -1203,11 +1217,11 @@ void Gource::processCommit(RCommit& commit, float t) { if(!file) continue; } - addFileAction(commit.username, cf, file, t); + addFileAction(commit, cf, file, t); } } -void Gource::addFileAction(const std::string& username, const RCommitFile& cf, RFile* file, float t) { +void Gource::addFileAction(const RCommit& commit, const RCommitFile& cf, RFile* file, float t) { //create user if havent yet. do it here to ensure at least one of there files //was added (incase we hit gGourceSettings.max_files) @@ -1215,11 +1229,11 @@ void Gource::addFileAction(const std::string& username, const RCommitFile& cf, R RUser* user = 0; //see if user already exists - std::map::iterator seen_user = users.find(username); + std::map::iterator seen_user = users.find(commit.username); if(seen_user != users.end()) user = seen_user->second; if(user == 0) { - user = addUser(username); + user = addUser(commit.username); if(gGourceSettings.highlight_all_users) user->setHighlighted(true); else { @@ -1243,12 +1257,12 @@ void Gource::addFileAction(const std::string& username, const RCommitFile& cf, R commit_seq++; if(cf.action == "D") { - userAction = new RemoveAction(user, file, t); + userAction = new RemoveAction(user, file, commit.timestamp, t); } else { if(cf.action == "A") { - userAction = new CreateAction(user, file, t); + userAction = new CreateAction(user, file, commit.timestamp, t); } else { - userAction = new ModifyAction(user, file, t, cf.colour); + userAction = new ModifyAction(user, file, commit.timestamp, t, cf.colour); } } @@ -1623,14 +1637,28 @@ void Gource::logic(float t, float dt) { float s = sinf(rotate_angle); float c = cosf(rotate_angle); - root->rotate(s, c); + if(manual_rotate) { + // rotate around camera position if manual + vec2 centre = vec2(camera.getPos()); - for(std::map::iterator it = users.begin(); it!=users.end(); it++) { - RUser* user = it->second; + root->rotate(s, c, centre); + + for(std::map::iterator it = users.begin(); it!=users.end(); it++) { + RUser* user = it->second; + + vec2 rotated_user_pos = rotate_vec2(user->getPos() - centre, s, c) + centre; + user->setPos(rotated_user_pos); + } + } else { + root->rotate(s, c); + + for(std::map::iterator it = users.begin(); it!=users.end(); it++) { + RUser* user = it->second; - vec2 userpos = user->getPos(); + vec2 rotated_user_pos = rotate_vec2(user->getPos(), s, c); + user->setPos(rotated_user_pos); + } - user->setPos(rotate_vec2(userpos, s, c)); } rotate_angle = 0.0f; @@ -1641,13 +1669,6 @@ void Gource::logic(float t, float dt) { recolour = false; } - if(update_file_labels) { - for(std::map::iterator it = files.begin(); it != files.end(); it++) { - it->second->updateLabel(); - } - update_file_labels = false; - } - //still want to update camera while paused if(paused) { updateBounds(); @@ -2592,13 +2613,29 @@ void Gource::draw(float t, float dt) { fontmedium.setColour(vec4(gGourceSettings.font_colour, 1.0f)); if(!gGourceSettings.hide_date) { - fontmedium.draw(display.width/2 - date_x_offset, 20, displaydate); + int x, y; + if(gGourceSettings.swap_title_and_date) { + x = 10; + y = display.height + fontmedium.getDescender() - 10 - gGourceSettings.date_height_pad; + } else { + x = display.width/2 - date_x_offset; + y = fontmedium.getAscender() + 10 + gGourceSettings.date_height_pad; + } + fontmedium.draw(x, y, displaydate); } + fonttitle.setColour(vec4(gGourceSettings.title_font_colour, 1.0f)); + if(!gGourceSettings.title.empty()) { - fontmedium.alignTop(false); - fontmedium.draw(10, display.height - 10, gGourceSettings.title); - fontmedium.alignTop(true); + int x, y; + if(gGourceSettings.swap_title_and_date) { + x = display.width/2 - title_x_offset; + y = fonttitle.getAscender() + 10 + gGourceSettings.title_height_pad; + } else { + x = 10; + y = display.height + fonttitle.getDescender() - 10 - gGourceSettings.title_height_pad; + } + fonttitle.draw(x, y, gGourceSettings.title); } for(std::list::iterator it = active_captions.begin(); it!=active_captions.end(); it++) { diff --git a/src/gource.h b/src/gource.h index b5a5345b..8691c6c9 100644 --- a/src/gource.h +++ b/src/gource.h @@ -81,8 +81,6 @@ class Gource : public SDLApp { bool recolour; - bool update_file_labels; - bool use_selection_bounds; Bounds2D selection_bounds; @@ -117,6 +115,7 @@ class Gource : public SDLApp { std::string displaydate; int date_x_offset; + int title_x_offset; TextureResource* bloomtex; TextureResource* beamtex; @@ -132,7 +131,7 @@ class Gource : public SDLApp { TextBox textbox; - FXFont font, fontlarge, fontmedium, fontcaption; + FXFont font, fontlarge, fontmedium, fonttitle, fontcaption; bool first_read; bool paused; @@ -182,7 +181,6 @@ class Gource : public SDLApp { std::deque commitqueue; std::map users; std::map files; - std::map tagfilemap; std::map tagusermap; std::list captions; @@ -215,8 +213,8 @@ class Gource : public SDLApp { void logReadingError(const std::string& error); - void processCommit(RCommit& commit, float t); - void addFileAction(const std::string& username, const RCommitFile& cf, RFile* file, float t); + void processCommit(const RCommit& commit, float t); + void addFileAction(const RCommit& commit, const RCommitFile& cf, RFile* file, float t); std::string dateAtPosition(float percent); diff --git a/src/gource_settings.cpp b/src/gource_settings.cpp index 1b5132b4..a79d6543 100644 --- a/src/gource_settings.cpp +++ b/src/gource_settings.cpp @@ -45,7 +45,7 @@ void GourceSettings::help(bool extended_help) { printf("Gource v%s\n", GOURCE_VERSION); - printf("Usage: gource [OPTIONS] [PATH]\n"); + printf("Usage: gource [options] [path]\n"); printf("\nOptions:\n"); printf(" -h, --help Help\n\n"); printf(" -WIDTHxHEIGHT, --viewport Set viewport size\n"); @@ -70,6 +70,8 @@ void GourceSettings::help(bool extended_help) { printf(" --disable-auto-skip Disable auto skip\n"); printf(" -s, --seconds-per-day SECONDS Speed in seconds per day (default: 10)\n"); printf(" --realtime Realtime playback speed\n"); + printf(" --no-time-travel Use the time of the last commit if the\n"); + printf(" of a commit is in the past\n"); printf(" -c, --time-scale SCALE Change simulation time scale (default: 1.0)\n"); printf(" -e, --elasticity FLOAT Elasticity of nodes (default: 0.0)\n\n"); @@ -115,7 +117,17 @@ if(extended_help) { printf(" --font-size SIZE Font size used by date and title\n"); printf(" --font-colour FFFFFF Font colour used by date and title in hex\n\n"); - printf(" --file-extensions Show filename extensions only\n\n"); + printf(" --file-extensions Show filename extensions only\n"); + printf(" --file-extension-fallback Use filename as extension if the extension\n"); + printf(" is missing or empty\n\n"); + + printf(" --title-size SIZE Font size used by title (overrides font-size)\n"); + printf(" --title-colour FFFFFF Font colour used by title in hex (overrides font-colour)\n\n"); + + printf(" --date-height-pad SIZE Pad the date position in the y-dimension\n"); + printf(" --title-height-pad SIZE Pad the title position in the y-dimension\n\n"); + + printf(" --swap-title-and-date Exchange the posiiton of the title and date\n\n"); printf(" --git-branch Get the git log of a particular branch\n\n"); @@ -130,8 +142,9 @@ if(extended_help) { printf(" --transparent Make the background transparent\n\n"); printf(" --user-filter REGEX Ignore usernames matching this regex\n"); - printf(" --file-filter REGEX Ignore files matching this regex\n"); - printf(" --file-show-filter REGEX Show only files matching this regex\n\n"); + printf(" --user-show-filter REGEX Show only usernames matching this regex\n\n"); + printf(" --file-filter REGEX Ignore file paths matching this regex\n"); + printf(" --file-show-filter REGEX Show only file paths matching this regex\n\n"); printf(" --user-friction SECONDS Change the rate users slow down (default: 0.67)\n"); printf(" --user-scale SCALE Change scale of users (default: 1.0)\n"); @@ -147,7 +160,9 @@ if(extended_help) { printf(" --filename-colour Font colour for filenames.\n"); printf(" --dir-colour Font colour for directories.\n\n"); - printf(" --dir-name-depth DEPTH Draw names of directories down to a specific depth.\n\n"); + printf(" --dir-name-depth DEPTH Draw names of directories down to a specific depth.\n"); + printf(" --dir-name-position FLOAT Position along edge of the directory name\n"); + printf(" (between 0.0 and 1.0, default is 0.5).\n\n"); printf(" --filename-time SECONDS Duration to keep filenames on screen (default: 4.0)\n\n"); @@ -207,6 +222,17 @@ GourceSettings::GourceSettings() { arg_aliases["disable-progress"] = "hide-progress"; arg_aliases["highlight-all-users"] = "highlight-users"; + //american spelling of colour (color) + arg_aliases["color-images"] = "colour-images"; + arg_aliases["background-color"] = "background-colour"; + arg_aliases["font-color"] = "font-colour"; + arg_aliases["title-color"] = "title-colour"; + arg_aliases["highlight-color"] = "highlight-colour"; + arg_aliases["selection-color"] = "selection-colour"; + arg_aliases["dir-color"] = "dir-colour"; + arg_aliases["caption-color"] = "caption-colour"; + arg_aliases["filename-color"] = "filename-colour"; + //command line only options conf_sections["help"] = "command-line"; conf_sections["extended-help"] = "command-line"; @@ -223,31 +249,34 @@ GourceSettings::GourceSettings() { conf_sections["log-level"] = "command-line"; //boolean args - arg_types["help"] = "bool"; - arg_types["extended-help"] = "bool"; - arg_types["stop-on-idle"] = "bool"; - arg_types["stop-at-end"] = "bool"; - arg_types["dont-stop"] = "bool"; - arg_types["loop"] = "bool"; - arg_types["realtime"] = "bool"; - arg_types["colour-images"] = "bool"; - arg_types["hide-date"] = "bool"; - arg_types["hide-files"] = "bool"; - arg_types["hide-users"] = "bool"; - arg_types["hide-tree"] = "bool"; - arg_types["hide-usernames"] = "bool"; - arg_types["hide-filenames"] = "bool"; - arg_types["hide-dirnames"] = "bool"; - arg_types["hide-progress"] = "bool"; - arg_types["hide-bloom"] = "bool"; - arg_types["hide-mouse"] = "bool"; - arg_types["hide-root"] = "bool"; - arg_types["highlight-users"] = "bool"; - arg_types["highlight-dirs"] = "bool"; - arg_types["file-extensions"] = "bool"; - arg_types["key"] = "bool"; - arg_types["ffp"] = "bool"; - + arg_types["help"] = "bool"; + arg_types["extended-help"] = "bool"; + arg_types["stop-on-idle"] = "bool"; + arg_types["stop-at-end"] = "bool"; + arg_types["dont-stop"] = "bool"; + arg_types["loop"] = "bool"; + arg_types["realtime"] = "bool"; + arg_types["no-time-travel"] = "bool"; + arg_types["colour-images"] = "bool"; + arg_types["hide-date"] = "bool"; + arg_types["hide-files"] = "bool"; + arg_types["hide-users"] = "bool"; + arg_types["hide-tree"] = "bool"; + arg_types["hide-usernames"] = "bool"; + arg_types["hide-filenames"] = "bool"; + arg_types["hide-dirnames"] = "bool"; + arg_types["hide-progress"] = "bool"; + arg_types["hide-bloom"] = "bool"; + arg_types["hide-mouse"] = "bool"; + arg_types["hide-root"] = "bool"; + arg_types["highlight-users"] = "bool"; + arg_types["highlight-dirs"] = "bool"; + arg_types["file-extensions"] = "bool"; + arg_types["file-extension-fallback"] = "bool"; + arg_types["key"] = "bool"; + arg_types["ffp"] = "bool"; + + arg_types["swap-title-and-date"] = "bool"; arg_types["disable-auto-rotate"] = "bool"; arg_types["disable-auto-skip"] = "bool"; @@ -268,17 +297,22 @@ GourceSettings::GourceSettings() { arg_types["user-friction"] = "float"; arg_types["padding"] = "float"; arg_types["time-scale"] = "float"; + arg_types["dir-name-position"] = "float"; - arg_types["max-files"] = "int"; - arg_types["font-size"] = "int"; - arg_types["hash-seed"] = "int"; + arg_types["max-files"] = "int"; + arg_types["font-size"] = "int"; + arg_types["title-size"] = "int"; + arg_types["hash-seed"] = "int"; - arg_types["user-filter"] = "multi-value"; - arg_types["follow-user"] = "multi-value"; - arg_types["highlight-user"] = "multi-value"; + arg_types["date-height-pad"] = "int"; + arg_types["title-height-pad"] = "int"; + arg_types["user-filter"] = "multi-value"; + arg_types["user-show-filter"] = "multi-value"; arg_types["file-filter"] = "multi-value"; arg_types["file-show-filter"] = "multi-value"; + arg_types["follow-user"] = "multi-value"; + arg_types["highlight-user"] = "multi-value"; arg_types["log-level"] = "string"; arg_types["background-image"] = "string"; @@ -308,6 +342,7 @@ GourceSettings::GourceSettings() { arg_types["camera-mode"] = "string"; arg_types["title"] = "string"; arg_types["font-colour"] = "string"; + arg_types["title-colour"] = "string"; arg_types["highlight-colour"] = "string"; arg_types["selection-colour"] = "string"; arg_types["dir-colour"] = "string"; @@ -355,6 +390,7 @@ void GourceSettings::setGourceDefaults() { stop_on_idle = false; stop_at_end = false; dont_stop = false; + no_time_travel = false; show_key = false; @@ -399,7 +435,15 @@ void GourceSettings::setGourceDefaults() { highlight_colour = vec3(1.0f); selection_colour = vec3(1.0, 1.0, 0.3f); + title_font_size = -1; + title_font_colour = vec3(-1.0f); + swap_title_and_date = false; + + date_height_pad = 0; + title_height_pad = 0; + dir_name_depth = 0; + dir_name_position = 0.5f; elasticity = 0.0f; @@ -441,16 +485,23 @@ void GourceSettings::setGourceDefaults() { //delete file whitelists for(std::vector::iterator it = file_show_filters.begin(); it != file_show_filters.end(); it++) { delete (*it); - } + } file_show_filters.clear(); file_extensions = false; + file_extension_fallback = false; //delete user filters for(std::vector::iterator it = user_filters.begin(); it != user_filters.end(); it++) { delete (*it); } user_filters.clear(); + + //delete user whitelist + for(std::vector::iterator it = user_show_filters.begin(); it != user_show_filters.end(); it++) { + delete (*it); + } + user_show_filters.clear(); } void GourceSettings::commandLineOption(const std::string& name, const std::string& value) { @@ -636,6 +687,10 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc date_format = entry->getString(); } + if(gource_settings->getBool("swap-title-and-date")) { + swap_title_and_date=true; + } + if(gource_settings->getBool("disable-auto-rotate")) { disable_auto_rotate=true; } @@ -780,6 +835,10 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc if(!entry->hasValue()) conffile.entryException(entry, "specify caption file (filename)"); caption_file = entry->getString(); + + if(!boost::filesystem::exists(caption_file)) { + conffile.entryException(entry, "caption file not found"); + } } if((entry = gource_settings->getEntry("caption-duration")) != 0) { @@ -901,6 +960,31 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc } } + if((entry = gource_settings->getEntry("title-size")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify title font size"); + + title_font_size = entry->getInt(); + + if(title_font_size<1 || title_font_size>100) { + conffile.invalidValueException(entry); + } + } + + if((entry = gource_settings->getEntry("date-height-pad")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify date height padding size"); + + date_height_pad = entry->getInt(); + } + + if((entry = gource_settings->getEntry("title-height-pad")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify title height padding size"); + + title_height_pad = entry->getInt(); + } + if((entry = gource_settings->getEntry("hash-seed")) != 0) { if(!entry->hasValue()) conffile.entryException(entry, "specify hash seed (integer)"); @@ -926,6 +1010,24 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc } } + if((entry = gource_settings->getEntry("title-colour")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify title font colour (FFFFFF)"); + + int r,g,b; + + std::string colstring = entry->getString(); + + if(entry->isVec3()) { + title_font_colour = entry->getVec3(); + } else if(colstring.size()==6 && sscanf(colstring.c_str(), "%02x%02x%02x", &r, &g, &b) == 3) { + title_font_colour = vec3(r,g,b); + title_font_colour /= 255.0f; + } else { + conffile.invalidValueException(entry); + } + } + if((entry = gource_settings->getEntry("background-colour")) != 0) { if(!entry->hasValue()) conffile.entryException(entry, "specify background colour (FFFFFF)"); @@ -1190,6 +1292,10 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc days_per_second = 1.0 / 86400.0; } + if(gource_settings->getBool("no-time-travel")) { + no_time_travel = true; + } + if(gource_settings->getBool("dont-stop")) { dont_stop = true; } @@ -1325,6 +1431,10 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc file_extensions=true; } + if(gource_settings->getBool("file-extension-fallback")) { + file_extension_fallback=true; + } + if((entry = gource_settings->getEntry("file-filter")) != 0) { ConfEntryList* filters = gource_settings->getEntries("file-filter"); @@ -1394,6 +1504,29 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc } } + if((entry = gource_settings->getEntry("user-show-filter")) != 0) { + + ConfEntryList* filters = gource_settings->getEntries("user-show-filter"); + + for(ConfEntryList::iterator it = filters->begin(); it != filters->end(); it++) { + + entry = *it; + + if(!entry->hasValue()) conffile.entryException(entry, "specify user-show-filter (regex)"); + + std::string filter_string = entry->getString(); + + Regex* r = new Regex(filter_string, 1); + + if(!r->isValid()) { + delete r; + conffile.entryException(entry, "invalid user-show-filter regular expression"); + } + + user_show_filters.push_back(r); + } + } + if((entry = gource_settings->getEntry("dir-name-depth")) != 0) { if(!entry->hasValue()) conffile.entryException(entry, "specify dir-name-depth (depth)"); @@ -1405,6 +1538,17 @@ void GourceSettings::importGourceSettings(ConfFile& conffile, ConfSection* gourc } } + if((entry = gource_settings->getEntry("dir-name-position")) != 0) { + + if(!entry->hasValue()) conffile.entryException(entry, "specify dir-name-position (float)"); + + dir_name_position = entry->getFloat(); + + if(dir_name_position < 0.1f || dir_name_position > 1.0f) { + conffile.entryException(entry, "dir-name-position outside of range 0.1 - 1.0 (inclusive)"); + } + } + //validate path if(gource_settings->hasValue("path")) { path = gource_settings->getString("path"); diff --git a/src/gource_settings.h b/src/gource_settings.h index 3abed071..8bd33e43 100644 --- a/src/gource_settings.h +++ b/src/gource_settings.h @@ -18,7 +18,7 @@ #ifndef GOURCE_SETTINGS_H #define GOURCE_SETTINGS_H -#define GOURCE_VERSION "0.48" +#define GOURCE_VERSION "0.50" #include "core/texture.h" #include "core/settings.h" @@ -67,6 +67,7 @@ class GourceSettings : public SDLAppSettings { bool stop_on_idle; bool stop_at_end; bool dont_stop; + bool no_time_travel; float auto_skip_seconds; float days_per_second; @@ -102,6 +103,14 @@ class GourceSettings : public SDLAppSettings { int font_size; vec3 font_colour; + int title_font_size; + vec3 title_font_colour; + + int date_height_pad; + int title_height_pad; + + bool swap_title_and_date; + float elasticity; std::string git_branch; @@ -126,13 +135,16 @@ class GourceSettings : public SDLAppSettings { vec3 selection_colour; int dir_name_depth; + float dir_name_position; std::vector highlight_users; std::vector follow_users; std::vector file_filters; std::vector file_show_filters; std::vector user_filters; + std::vector user_show_filters; bool file_extensions; + bool file_extension_fallback; std::string caption_file; vec3 caption_colour; @@ -148,7 +160,7 @@ class GourceSettings : public SDLAppSettings { TextureResource* file_graphic; int log_level; - + GourceSettings(); void setGourceDefaults(); diff --git a/src/spline.cpp b/src/spline.cpp index bf9fbf70..e5cc891a 100644 --- a/src/spline.cpp +++ b/src/spline.cpp @@ -59,12 +59,17 @@ void SplineEdge::update(const vec2& pos1, const vec4& col1, const vec2& pos2, co spline_point.push_back(pt); spline_colour.push_back(coln); } - - midpoint = pos1 * 0.25f + pos2 * 0.25f + spos * 0.5f; + + const float pos = gGourceSettings.dir_name_position; + + const float s_quota = 0.5f - glm::abs(pos - 0.5f); + const float p_quota = 1.0f - s_quota; + + label_pos = pos1 * (p_quota * (1.0f - pos)) + pos2 * (p_quota * pos) + spos * s_quota; } -const vec2& SplineEdge::getMidPoint() const { - return midpoint; +const vec2& SplineEdge::getLabelPos() const { + return label_pos; } void SplineEdge::drawToVBO(quadbuf& buffer) const { diff --git a/src/spline.h b/src/spline.h index eadfe177..187c010f 100644 --- a/src/spline.h +++ b/src/spline.h @@ -31,13 +31,13 @@ class SplineEdge { std::vector spline_point; std::vector spline_colour; - vec2 midpoint; + vec2 label_pos; void drawBeam(const vec2 & pos1, const vec4 & col1, const vec2 & pos2, const vec4 & col2, float radius, bool first) const; public: SplineEdge(); - const vec2& getMidPoint() const; + const vec2& getLabelPos() const; void update(const vec2& pos1, const vec4& col1, const vec2& pos2, const vec4& col2, const vec2& spos); diff --git a/src/user.cpp b/src/user.cpp index f6509c3b..8875d2a3 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -246,7 +246,7 @@ void RUser::logic(float t, float dt) { RAction* action = *it; //add all files which are too old - if(gGourceSettings.max_file_lag>=0.0 && action->addedtime < t - gGourceSettings.max_file_lag) { + if(gGourceSettings.max_file_lag>=0.0 && action->t < t - gGourceSettings.max_file_lag) { it = actions.erase(it); actionCount--; action->rate = 2.0;