Prep for 0.9.3 release.
[stopish] / src / stopish-stopwatch.c
1 //      stopish-stopwatch.c
2 //
3 //      Copyright 2010 Michael Cronenworth <mike@cchtml.com>
4 //
5 //      This program is free software; you can redistribute it and/or modify
6 //      it under the terms of the GNU General Public License as published by
7 //      the Free Software Foundation; either version 2 of the License, or
8 //      (at your option) any later version.
9 //
10 //      This program is distributed in the hope that it will be useful,
11 //      but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //      GNU General Public License for more details.
14 //
15 //      You should have received a copy of the GNU General Public License
16 //      along with this program; if not, write to the Free Software
17 //      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 //      MA 02110-1301, USA.
19
20 #include <gtk/gtk.h>
21 #include <hildon/hildon.h>
22 #include <stdlib.h>
23
24 #include "stopish.h"
25
26 struct timerData {
27     GtkWidget *vBox;
28     GtkWidget *label;
29     GtkWidget *labelHour;
30     GtkWidget *labelMinute;
31     GtkWidget *labelSecond;
32 };
33
34 static struct timerData timerdata;
35 static GtkWidget *timerHistoryLabel[4];
36 static GtkWidget *resetButton;
37 static GSList *historyList = NULL;
38 static int timerHandle = -1;
39
40
41 static gint timeout_cb( gpointer data );
42 static void start_cb( GtkButton* button, gpointer data );
43 static void reset_cb( GtkButton* button, gpointer data );
44
45
46 GtkWindow *stopish_stopwatch_new( void )
47 {
48     GtkWidget *window, *button, *label;
49     GtkWidget *vBoxMain, *vBox0, *hBox0;
50
51     window = hildon_stackable_window_new(  );
52
53     gtk_container_set_border_width( GTK_CONTAINER( window ), 20 );
54
55     gtk_window_set_title( GTK_WINDOW( window ), "Stopish" );
56
57     vBoxMain = gtk_vbox_new( FALSE, 10 );
58
59     // separator
60     label = gtk_label_new( NULL );
61     gtk_container_add( GTK_CONTAINER( vBoxMain ), label );
62
63     vBox0 = gtk_vbox_new( FALSE, 5 );
64
65     // stop watch area
66     timerdata.vBox = gtk_vbox_new( FALSE, 0 );
67     gtk_container_add( GTK_CONTAINER( vBox0 ), timerdata.vBox );
68     stopish_stopwatch_label_timer_landscape(  );
69
70     // history area
71     timerHistoryLabel[0] = gtk_label_new( NULL );
72     gtk_label_set_markup( GTK_LABEL( timerHistoryLabel[0] ),
73                           "<span size=\"large\"> </span>" );
74     gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel[0], FALSE, FALSE, 0 );
75     timerHistoryLabel[1] = gtk_label_new( NULL );
76     gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel[1], FALSE, FALSE, 0 );
77     timerHistoryLabel[2] = gtk_label_new( NULL );
78     gtk_label_set_markup( GTK_LABEL( timerHistoryLabel[2] ),
79                           "<span size=\"small\"> </span>" );
80     gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel[2], FALSE, FALSE, 0 );
81     timerHistoryLabel[3] = gtk_label_new( NULL );
82     gtk_label_set_markup( GTK_LABEL( timerHistoryLabel[3] ),
83                           "<span size=\"x-small\"> </span>" );
84     gtk_box_pack_start( GTK_BOX( vBox0 ), timerHistoryLabel[3], FALSE, FALSE, 0 );
85
86     gtk_container_add( GTK_CONTAINER( vBoxMain ), vBox0 );
87
88     // separator
89     label = gtk_label_new( NULL );
90     gtk_container_add( GTK_CONTAINER( vBoxMain ), label );
91
92     // button area
93     hBox0 = gtk_hbox_new( FALSE, 15 );
94     gtk_widget_set_size_request( hBox0, -1, 80 );
95
96     // start/pause stopwatch button
97     button = hildon_button_new_with_text( HILDON_SIZE_HALFSCREEN_WIDTH,
98                                           HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
99                                           "Start", NULL );
100     resetButton = hildon_button_new_with_text( HILDON_SIZE_HALFSCREEN_WIDTH,
101                                                HILDON_BUTTON_ARRANGEMENT_HORIZONTAL,
102                                                "Reset", NULL );
103     g_signal_connect( G_OBJECT( button ), "clicked",
104                       G_CALLBACK( start_cb ), resetButton );
105     gtk_container_add( GTK_CONTAINER( hBox0 ), button );
106
107     // reset button
108     gtk_widget_set_sensitive( resetButton, FALSE );
109     g_signal_connect( G_OBJECT( resetButton ), "clicked",
110                       G_CALLBACK( reset_cb ), button );
111     gtk_container_add( GTK_CONTAINER( hBox0 ), resetButton );
112
113     gtk_box_pack_start( GTK_BOX( vBoxMain ), hBox0, FALSE, FALSE, 0 );
114
115     gtk_container_add( GTK_CONTAINER( window ), vBoxMain );
116
117     gtk_widget_show_all( window );
118
119     return GTK_WINDOW( window );
120 }
121
122
123 void stopish_stopwatch_reset( void )
124 {
125     if ( timerHandle == -1 &&
126          stopish_get_mode(  ) != STOPISH_MODE_RESUME )
127         return;
128     gtk_button_clicked( GTK_BUTTON( resetButton ) );
129 }
130
131
132 void stopish_stopwatch_perf_timer_hour( GtkRadioButton* radio, GtkLabel *label )
133 {
134     stopish_timer_set_precision( TIMER_PRECISION_HOUR );
135     if ( stopish_get_orientation(  ) == STOPISH_LANDSCAPE )
136         stopish_stopwatch_label_timer_landscape(  );
137     else
138         stopish_stopwatch_label_timer_portrait(  );
139 }
140
141
142 void stopish_stopwatch_perf_timer_minute( GtkRadioButton* radio, GtkLabel *label )
143 {
144     stopish_timer_set_precision( TIMER_PRECISION_MINUTE );
145     if ( stopish_get_orientation(  ) == STOPISH_LANDSCAPE )
146         stopish_stopwatch_label_timer_landscape(  );
147     else
148         stopish_stopwatch_label_timer_portrait(  );
149 }
150
151
152 void stopish_stopwatch_label_timer_landscape( void )
153 {
154     gtk_widget_set_size_request( timerdata.vBox, 800, -1 );
155
156     gtk_widget_destroy( timerdata.label );
157     timerdata.label = gtk_label_new( NULL );
158     if ( stopish_timer_get_precision(  ) == TIMER_PRECISION_MINUTE )
159         gtk_label_set_markup( GTK_LABEL( timerdata.label ),
160                               "<span font_family=\"monospace\" "
161                               "size=\"80000\" weight=\"ultrabold\">"
162                               "00:00.0</span>" );
163     else
164         gtk_label_set_markup( GTK_LABEL( timerdata.label ),
165                               "<span font_family=\"monospace\" "
166                               "size=\"80000\" weight=\"ultrabold\">"
167                               "00:00:00.0</span>" );
168     gtk_misc_set_alignment( GTK_MISC( timerdata.label ), 0.5f, 0.5f );
169     gtk_container_add( GTK_CONTAINER( timerdata.vBox ), timerdata.label );
170     gtk_widget_show( timerdata.label );
171 }
172
173
174 void stopish_stopwatch_label_timer_portrait( void )
175 {
176     GtkWidget *vBox, *hBox, *label;
177
178     gtk_widget_set_size_request( timerdata.vBox, 480, -1 );
179
180     gtk_widget_destroy( timerdata.label );
181     vBox = gtk_vbox_new( FALSE, 10 );
182
183     if ( stopish_timer_get_precision(  ) == TIMER_PRECISION_HOUR ) {
184         hBox = gtk_hbox_new( FALSE, 10 );
185         label = gtk_label_new( "Hours" );
186         gtk_widget_set_size_request( label, 100, -1 );
187         gtk_misc_set_alignment( GTK_MISC( label ), 1.0f, 0.5f );
188         gtk_container_add( GTK_CONTAINER( hBox ), label );
189         timerdata.labelHour = gtk_label_new( NULL );
190         gtk_widget_set_size_request( timerdata.labelHour, 350, -1 );
191         gtk_misc_set_alignment( GTK_MISC( timerdata.labelHour ), 0.0f, 0.5f );
192         gtk_label_set_markup( GTK_LABEL( timerdata.labelHour ),
193                               "<span font_family=\"monospace\" "
194                               "size=\"90000\" weight=\"ultrabold\">"
195                               "00</span>" );
196         gtk_container_add( GTK_CONTAINER( hBox ), timerdata.labelHour );
197         gtk_container_add( GTK_CONTAINER( vBox ), hBox );
198     }
199
200     hBox = gtk_hbox_new( FALSE, 10 );
201     label = gtk_label_new( "Minutes" );
202     gtk_widget_set_size_request( label, 100, -1 );
203     gtk_misc_set_alignment( GTK_MISC( label ), 1.0f, 0.5f );
204     gtk_container_add( GTK_CONTAINER( hBox ), label );
205     timerdata.labelMinute = gtk_label_new( NULL );
206     gtk_widget_set_size_request( timerdata.labelMinute, 350, -1 );
207     gtk_misc_set_alignment( GTK_MISC( timerdata.labelMinute ), 0.0f, 0.5f );
208     gtk_label_set_markup( GTK_LABEL( timerdata.labelMinute ),
209                           "<span font_family=\"monospace\" "
210                           "size=\"90000\" weight=\"ultrabold\">"
211                           "00</span>" );
212     gtk_container_add( GTK_CONTAINER( hBox ), timerdata.labelMinute );
213     gtk_container_add( GTK_CONTAINER( vBox ), hBox );
214
215     hBox = gtk_hbox_new( FALSE, 10 );
216     label = gtk_label_new( "Seconds" );
217     gtk_widget_set_size_request( label, 100, -1 );
218     gtk_misc_set_alignment( GTK_MISC( label ), 1.0f, 0.5f );
219     gtk_container_add( GTK_CONTAINER( hBox ), label );
220     timerdata.labelSecond = gtk_label_new( NULL );
221     gtk_widget_set_size_request( timerdata.labelSecond, 350, -1 );
222     gtk_misc_set_alignment( GTK_MISC( timerdata.labelSecond ), 0.0f, 0.5f );
223     gtk_label_set_markup( GTK_LABEL( timerdata.labelSecond ),
224                           "<span font_family=\"monospace\" "
225                           "size=\"90000\" weight=\"ultrabold\">"
226                           "00.0</span>" );
227     gtk_container_add( GTK_CONTAINER( hBox ), timerdata.labelSecond );
228     gtk_container_add( GTK_CONTAINER( vBox ), hBox );
229
230     timerdata.label = vBox;
231     gtk_container_add( GTK_CONTAINER( timerdata.vBox ), vBox );
232     gtk_widget_show_all( vBox );
233 }
234
235
236 //
237 // Timer callback
238 //
239 static gint timeout_cb( gpointer data )
240 {
241     char formatBuffer[128], tempBuffer[8];
242     char *tempString;
243
244     // print to screen
245     tempString = stopish_get_time_string(  );
246     if ( stopish_get_orientation(  ) == STOPISH_LANDSCAPE ) {
247         sprintf( formatBuffer, "<span font_family=\"monospace\" "
248                                "size=\"80000\" weight=\"ultrabold\">"
249                                "%s</span>", tempString );
250         gtk_label_set_markup( GTK_LABEL( timerdata.label ), formatBuffer );
251     }
252     else {
253         if ( stopish_timer_get_precision(  ) == TIMER_PRECISION_HOUR ) {
254             sprintf( tempBuffer, "%.2s", tempString );
255             sprintf( formatBuffer, "<span font_family=\"monospace\" "
256                                    "size=\"90000\" weight=\"ultrabold\">"
257                                    "%s</span>", tempBuffer );
258             gtk_label_set_markup( GTK_LABEL( timerdata.labelHour ),
259                                   formatBuffer );
260         }
261         if ( stopish_timer_get_precision(  ) == TIMER_PRECISION_HOUR )
262             sprintf( tempBuffer, "%.2s", tempString + 3 );
263         else
264             sprintf( tempBuffer, "%.2s", tempString );
265         sprintf( formatBuffer, "<span font_family=\"monospace\" "
266                                "size=\"90000\" weight=\"ultrabold\">"
267                                "%s</span>", tempBuffer );
268         gtk_label_set_markup( GTK_LABEL( timerdata.labelMinute ),
269                               formatBuffer );
270         if ( stopish_timer_get_precision(  ) == TIMER_PRECISION_HOUR )
271             sprintf( tempBuffer, "%.4s", tempString + 6 );
272         else
273             sprintf( tempBuffer, "%.4s", tempString + 3 );
274         sprintf( formatBuffer, "<span font_family=\"monospace\" "
275                                "size=\"90000\" weight=\"ultrabold\">"
276                                "%s</span>", tempBuffer );
277         gtk_label_set_markup( GTK_LABEL( timerdata.labelSecond ),
278                               formatBuffer );
279     }
280     free( tempString );
281
282     return TRUE;
283 }
284
285
286 static void start_cb( GtkButton* button, gpointer data )
287 {
288     if ( stopish_get_mode(  ) == STOPISH_MODE_START ) {
289         // set label text and add timer handle
290         gtk_button_set_label( button, "Pause" );
291         stopish_set_mode( STOPISH_MODE_PAUSE );
292         stopish_set_time_start( stopish_current_time(  ) );
293         timerHandle = g_timeout_add( 100, timeout_cb, NULL );
294     }
295     else if ( stopish_get_mode(  ) == STOPISH_MODE_RESUME ) {
296         // resume timer
297         gtk_button_set_label( button, "Pause" );
298         stopish_set_mode( STOPISH_MODE_PAUSE );
299         stopish_timer_resume(  );
300         timerHandle = g_timeout_add( 100, timeout_cb, NULL );
301     }
302     else {
303         // pause timer, remove timeout
304         gtk_button_set_label( button, "Resume" );
305         stopish_set_mode( STOPISH_MODE_RESUME );
306         g_source_remove( timerHandle );
307         stopish_timer_save(  );
308         timerHandle = -1;
309     }
310
311     // allow user to reset timer
312     gtk_widget_set_sensitive( GTK_WIDGET( data ), TRUE );
313 }
314
315
316 static void reset_cb( GtkButton* button, gpointer data )
317 {
318     GSList *tempList;
319     char *tempString;
320     char formatString[128];
321
322     if ( stopish_get_mode(  ) == STOPISH_MODE_RESUME )
323         stopish_timer_resume(  );
324
325     // set label text and remove timer handle
326     gtk_button_set_label( GTK_BUTTON( data ), "Start" );
327     stopish_set_mode( STOPISH_MODE_START );
328     if ( stopish_get_orientation(  ) == STOPISH_LANDSCAPE )
329         stopish_stopwatch_label_timer_landscape(  );
330     else
331         stopish_stopwatch_label_timer_portrait(  );
332     g_source_remove( timerHandle );
333     timerHandle = -1;
334
335     // add current time to history
336     historyList = g_slist_prepend( historyList,
337                                    ( gpointer ) stopish_get_time_string(  ) );
338     sprintf( formatString, "<span size=\"large\">%s</span>",
339              ( char * ) historyList->data );
340     gtk_label_set_markup( GTK_LABEL( timerHistoryLabel[0] ),
341                           formatString );
342     tempList = historyList;
343     tempList = g_slist_next( tempList );
344     if ( tempList ) {
345         gtk_label_set_text( GTK_LABEL( timerHistoryLabel[1] ),
346                             ( char * ) tempList->data );
347     }
348     tempList = g_slist_next( tempList );
349     if ( tempList ) {
350         sprintf( formatString, "<span size=\"small\">%s</span>",
351                  ( char * ) tempList->data );
352         gtk_label_set_markup( GTK_LABEL( timerHistoryLabel[2] ),
353                               formatString );
354     }
355     tempList = g_slist_next( tempList );
356     if ( tempList ) {
357         sprintf( formatString, "<span size=\"x-small\">%s</span>",
358                  ( char * ) tempList->data );
359         gtk_label_set_markup( GTK_LABEL( timerHistoryLabel[3] ),
360                               formatString );
361     }
362
363     // remove the history time after the 4th
364     tempList = g_slist_next( tempList );
365     if ( tempList ) {
366         tempString = tempList->data;
367         historyList = g_slist_remove( historyList, tempList->data );
368         free( tempString );
369     }
370
371     // reset start time
372     stopish_set_time_start( 0 );
373
374     // disallow user to reset timer
375     gtk_widget_set_sensitive( GTK_WIDGET( button ), FALSE );
376 }