diff --git a/src/classes/options.vala b/src/classes/options.vala index 1b00389c..a4fa7a3b 100644 --- a/src/classes/options.vala +++ b/src/classes/options.vala @@ -61,5 +61,11 @@ namespace org.westhoffswelt.pdfpresenter { * the presenter window */ public static uint current_size = 60; + + /** + * Time the talk starts at, to calculate and display a countdown to + * this time. + */ + public static string? start_time = null; } } diff --git a/src/classes/timer_label.vala b/src/classes/timer_label.vala index b15e1e93..a042dbc6 100644 --- a/src/classes/timer_label.vala +++ b/src/classes/timer_label.vala @@ -63,6 +63,22 @@ namespace org.westhoffswelt.pdfpresenter { */ protected uint last_minutes = 5; + /** + * Supportes states aka. modes of the timer + * + * These states are used to indicate if the talk has already started or + * it is been counted down to it's beginning, for example + */ + protected enum MODE { + pretalk, + talk + } + + /** + * The mode the timer is currently in + */ + protected MODE current_mode; + /** * Color used for normal timer rendering * @@ -88,11 +104,31 @@ namespace org.westhoffswelt.pdfpresenter { public Color negative_color; /** - * Default constructor taking the initial time as argument + * Default constructor taking the initial time as argument, as well as + * the time to countdown until the talk actually starts. + * + * The second argument is optional. If no countdown_time is specified + * the countdown will be disabled. The timer is paused in such a case + * at the given intial_time. */ - public TimerLabel( int initial_time ) { + public TimerLabel( int initial_time, int countdown_time = 0 ) { this.initial_time = initial_time; - this._time = initial_time; + + if ( countdown_time != 0 ) + { + this.current_mode = MODE.pretalk; + this._time = countdown_time; + // Auto start the timer after realization of the timer widget + this.realize.connect( () => + { + this.start(); + }); + } + else + { + this.current_mode = MODE.talk; + this._time = initial_time; + } // By default the colors are white, yellow and red Color.parse( "white", out this.normal_color ); @@ -104,7 +140,17 @@ namespace org.westhoffswelt.pdfpresenter { * Start the timer */ public void start() { - if ( this.initial_time != 0 && this.timeout == 0 ) { + // Check if there is a countdown_timer running, in which case it + // will be aborted and a jump to talk mode is executed. + if ( this.timeout != 0 && this.current_mode == MODE.pretalk ) + { + this.current_mode = MODE.talk; + this.reset(); + this.start(); + } + // Start the timer if it is not running and the currently set time + // is non zero + else if ( this._time != 0 && this.timeout == 0 ) { this.timeout = Timeout.add( 1000, this.on_timeout ); } } @@ -123,10 +169,19 @@ namespace org.westhoffswelt.pdfpresenter { * Reset the timer to its initial value * * Furthermore the stop state will be restored + * If the countdown is running the reset will simply be ignored because + * it does not make sense at all. + * + * In presentation mode the time will be reset to the initial + * presentation time. */ public void reset() { - this.stop(); - this._time = this.initial_time; + if ( this.current_mode != MODE.pretalk ) + { + this.stop(); + this._time = this.initial_time; + } + this.format_time(); } @@ -141,7 +196,15 @@ namespace org.westhoffswelt.pdfpresenter { * Update the timer on every timeout step (every second) */ protected bool on_timeout() { - --this._time; + if ( this._time-- == 0 && this.current_mode == MODE.pretalk ) + { + // The zero has been reached on the way down to a presentation + // start time. Therefore a mode switch is needed + this.current_mode = MODE.talk; + this.reset(); + this.start(); + } + this.format_time(); return true; } @@ -154,9 +217,16 @@ namespace org.westhoffswelt.pdfpresenter { uint time; uint hours, minutes, seconds; - // The default prefix is an empty string, as the time is normally not - // negative ;) + // In pretalk mode we display a negative sign before the the time, + // to indicate that we are actually counting down to the start of + // the presentation. + // Normally the default is a positive number. Therefore a negative + // sign is not needed and the prefix is just an empty string. string prefix = ""; + if ( this.current_mode == MODE.pretalk ) + { + prefix = "-"; + } if ( this._time >= 0 ) { // Time is positive diff --git a/src/classes/window/presenter.vala b/src/classes/window/presenter.vala index 7c6a64d1..3d67d5e1 100644 --- a/src/classes/window/presenter.vala +++ b/src/classes/window/presenter.vala @@ -146,9 +146,24 @@ namespace org.westhoffswelt.pdfpresenter.Window { (int)Math.floor( bottom_height * 0.8 * 0.75 ) * Pango.SCALE ); + // Calculate the countdown to display until the presentation has to + // start + int countdown = 0; + if ( Options.start_time != null ) + { + var start_time = this.parseStartTime( + Options.start_time + ); + + var tm = Time.local( time_t() ); + var now = tm.mktime(); + + countdown = (int)Math.fmax( 0, start_time - now ); + } + // The countdown timer is centered in the 90% bottom part of the screen // It takes 3/4 of the available width - this.timer = new TimerLabel( (int)Options.duration * 60 ); + this.timer = new TimerLabel( (int)Options.duration * 60, countdown ); this.timer.set_justify( Justification.CENTER ); this.timer.modify_font( font ); this.timer.set_size_request( @@ -338,5 +353,15 @@ namespace org.westhoffswelt.pdfpresenter.Window { ); observer.show(); } + + /** + * Parse the given start time string to a Time object + */ + private time_t parseStartTime( string start_time ) + { + var tm = Time.local( time_t() ); + tm.strptime( start_time, "%H:%M:%S" ); + return tm.mktime(); + } } } diff --git a/src/pdf_presenter_console.vala b/src/pdf_presenter_console.vala index 08170880..631bf60f 100644 --- a/src/pdf_presenter_console.vala +++ b/src/pdf_presenter_console.vala @@ -62,6 +62,7 @@ namespace org.westhoffswelt.pdfpresenter { */ const OptionEntry[] options = { { "duration", 'd', 0, OptionArg.INT, ref Options.duration, "Duration in minutes of the presentation used for timer display. (Default 45 minutes)", "N" }, + { "start-time", 't', 0, OptionArg.STRING, ref Options.start_time, "Start time of the presentation to be used as a countdown. (Format: hh:mm:ss (24h))", "T" }, { "last-minutes", 'l', 0, OptionArg.INT, ref Options.last_minutes, "Time in minutes, from which on the timer changes its color. (Default 5 minutes)", "N" }, { "current-size", 'u', 0, OptionArg.INT, ref Options.current_size, "Percentage of the presenter screen to be used for the current slide. (Default 60)", "N" }, { "switch-screens", 's', 0, 0, ref Options.display_switch, "Switch the presentation and the presenter screen.", null },