Chapitre 19
Le calendrier

Le widget calendrier est une moyen efficace d’afficher et de retrouver des informations liées aux dates. C’est un widget très simple à créer et à utiliser.

Créer un widget calendrier est aussi simple que :

$calendar = Gtk2::Calendar->new();
Il arrive parfois que vous ayez beaucoup d’informations à changer à l’intérieur de ce widget. Les fonctions suivantes vous permettent de faire de multiples changements sans que l’utilisateur voit les multiples mises à jour à l’écran :
$calendar->freeze();  
$calendar->thaw();
freeze “gèle” la mise à jour de l’affichage de sorte que les modifications de l’on peut faire n’apparaissent pas et thaw “dégèle” la mise à jour de l’affichage du widget ainsi les modifications que l’on a pu faire sont visibles.

Le widget calendrier possède quelques options qui vous permettent de changer le look du widget ainsi que la manière dont il opère :

$calendar->display_options( $flags );
L’argument $flag peut être formé en combinant les cinq options suivantes :

Les fonctions suivantes sont utilisées pour déclarer la date courante affichée :

$calendar->selected_month ( $mois , $année ) ;  
$calendar->selected_day ( $jour );
La valeur de retour de selected_month est une valeur booléenne qui indique si la sélection est réussie.

Avec selected_day, le nombre spécifié est sélectionné à l’intérieur du mois courant, si c’est possible. Une valeur $jour de 0 déselectionnera la sélection courante.

En plus d’avoir un jour sélectionné, n’importe quel nombre de jour dans le mois peuvent être “marqués”. Un jour marqué est surligné dans l’affichage du calendrier. Les fonctions suivantes sont fournies pour manipuler les jours marqués :

$calendar->mark_day ( $jour ) ;  
$calendar->unmark_day ( $jour );  
$calendar->clear_marks();
Les jours marqués actuellement sont stockés dans un tableau. Ce tableau est composé de 31 éléments ainsi, si vous voulez savoir si un jour est marqué, vous devez accéder à l’élément correspondant du tableau ( n’oubliez pas que les éléments d’un tableau sont numérotés de 0 à n-1 ). Par exemple :
if ( $calendar->marked_date [$jour - 1] )  
   {  
    print ( "Le jour $jour est marqué.\n );  
   }
Notez que les marques sont persistantes à travers les changements de mois et d’années.

La dernière fonction concernant le calendrier est utilisée pour retrouver la date courante sélectionnée.

( $année , $mois , $jour ) = $calendar->get_date();
Le widget calendrier peut générer un nombre de signaux indiquant les sélections de dates et les changements. Les noms des signaux sont très explicites :

Exemple

Il ne nous reste plus qu’à mettre ensemble toutes ces fonctions. On obtient :

calendrier

# !/usr/bin/perl -w

# Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Gršonlund
# Copyright (C) 2000 Tony Gale
#
# Copyright (C) 2003 by the gtk2-perl team (see the file AUTHORS for the full
# list)
#
# This library 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.1 of the License, or (at your option)
# any later version.
#
# This library is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. ee 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 library ; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 2111-1307 SA.
#
# $Header: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/examples/calendar.pl,v 1.5 2003/09/22 00:04:23 rwmcfa1 Exp
#

# this was originally gtk-2.2.1/examples/buttonbox/buttonbox.c
# ported to gtk2-perl (and perl-ized) by rm

use strict ;
use Gtk2 ;

use constant TRUE => 1 ;
use constant FALSE => 0 ;

use constant DEF_PAD => 10 ;
use constant DEF_PAD_SMALL => 5 ;

use constant TM_YEAR_BASE => 1900 ;

sub calendar_select_font
{
my $calendar = shift ;

my $fsd = Gtk2::FontSelectionDialog->new(’Sélection de police’ ) ;
$fsd->set_position(’mouse’ ) ;
$fsd->ok_button->signal_connect( ’clicked’ => sub {
my $font_name = $fsd->get_font_name ;
if ( $font_name ne )
{
$calendar->modify_font(
Gtk2::Pango::FontDescription->from_string(
$font_name) ) ;
}
$fsd->destroy ;
}) ;

$fsd->cancel_button->signal_connect_swapped( ’clicked’ => sub {
$fsd->destroy ;
}) ;

$fsd->show ;
}


sub calendar_set_signal_strings
{
my $sig_ref = shift ;
my $new_sig = shift ;

$sig_ref->{prev2}->set_text($sig_ref->{prev}->get_text) ;
$sig_ref->{prev}->set_text($sig_ref->{curr}->get_text) ;
$sig_ref->{curr}->set_text($new_sig) ;
}

sub create_calendar
{
my $window ;
my $vbox ;
my $vbox2 ;
my $vbox3 ;
my $hbox ;
my $hbbox ;
my $calendar ;
my @toggles ;
my $button ;
my $frame ;
my $separator ;
my $label ;
my $bbox ;
my $i ;

my %signals = () ;

$window = Gtk2::Window->new(”toplevel” ) ;
$window->set_title(’Exemple de Calendrier’ ) ;

$window->set_border_width(5 ) ;
$window->signal_connect( ’destroy’ => sub {
Gtk2->main_quit ;
} ) ;
$window->set_resizable(FALSE) ;

$vbox = Gtk2::VBox->new(FALSE, DEF_PAD) ;
$window->add($vbox) ;

#
# La partie haute de la fenêtre
#

$hbox = Gtk2::HBox->new(FALSE, DEF_PAD) ;
$vbox->pack_start($hbox, TRUE, TRUE, DEF_PAD) ;

$hbbox = Gtk2::HButtonBox->new ;
$hbox->pack_start($hbbox, FALSE, FALSE, DEF_PAD) ;
$hbbox->set_layout(’spread’ ) ;
$hbbox->set_spacing(5 ) ;

# Calendar widget
$frame = Gtk2::Frame->new(’Calendrier’ ) ;
$hbbox->pack_start($frame, FALSE, TRUE, DEF_PAD) ;
$calendar = Gtk2::Calendar->new ;

$calendar->mark_day(19 ) ;
$frame->add($calendar) ;
$calendar->display_options([]) ;

$calendar->signal_connect( ’month_changed’ => sub {
my ($year, $month, $day) = $calendar->get_date ;
calendar_set_signal_strings($_[1 ], ’month changed: ’ .
sprintf(”%02d/%d/%d” , $month+1 , $day, $year) ) ;
}, \%signals ) ;
$calendar->signal_connect( ’day_selected’ => sub {
my ($year, $month, $day) = $calendar->get_date ;
calendar_set_signal_strings($_[1 ], ’day selected: ’ .
sprintf(”%02d/%d/%d” , $month+1 , $day, $year) ) ;
}, \%signals ) ;
$calendar->signal_connect( ’day_selected_double_click’ => sub {
my ($year, $month, $day) = $calendar->get_date ;
calendar_set_signal_strings($_[1 ],
’day selected double click: ’ .
sprintf(”%02d/%d/%d” , $month+1 , $day, $year) ) ;
}, \%signals ) ;
$calendar->signal_connect( ’prev_month’ => sub {
my ($year, $month, $day) = $calendar->get_date ;
calendar_set_signal_strings($_[1 ], ’prev month: ’ .
sprintf(”%02d/%d/%d” , $month+1 , $day, $year) ) ;
}, \%signals ) ;
$calendar->signal_connect( ’next_month’ => sub {
my ($year, $month, $day) = $calendar->get_date ;
calendar_set_signal_strings($_[1 ], ’next month: ’ .
sprintf(”%02d/%d/%d” , $month+1 , $day, $year) ) ;
}, \%signals ) ;
$calendar->signal_connect( ’prev_year’ => sub {
my ($year, $month, $day) = $calendar->get_date ;
calendar_set_signal_strings($_[1 ], ’prev year: ’ .
sprintf(”%02d/%d/%d” , $month+1 , $day, $year) ) ;
}, \%signals ) ;
$calendar->signal_connect( ’next_year’ => sub {
my ($year, $month, $day) = $calendar->get_date ;
calendar_set_signal_strings($_[1 ], ’next year: ’ .
sprintf(”%02d/%d/%d” , $month+1 , $day, $year) ) ;
}, \%signals ) ;

$separator = Gtk2::VSeparator->new ;
$hbox->pack_start($separator, FALSE, TRUE, 0 ) ;

$vbox2 = Gtk2::VBox->new(FALSE, DEF_PAD) ;
$hbox->pack_start($vbox2, FALSE, FALSE, DEF_PAD) ;

# Construit le bon cadre avec les interrupteurs à l’intérieur

$frame = Gtk2::Frame->new(’Options’ ) ;
$vbox2->pack_start($frame, TRUE, TRUE, DEF_PAD) ;
$vbox3= Gtk2::VBox->new(TRUE, DEF_PAD_SMALL) ;
$frame->add($vbox3) ;

my @flags = (
’Show Heading’ ,
’Show Day Names’ ,
’No Month Change’ ,
’Show Week Numbers’ ,
’Week Start Monday’ ,
) ;
my @flags_fr = (
”Montre le mois et l’année” ,
’Montre le nom des jours’ ,
’Pas de changement de mois’ ,
’Montre les numéros de semaine’ ,
’La semaine commence le lundi’ ,
) ;
for ( $i = 0 ; $i < 5 ; $i++ )
{
$toggles[$i] = Gtk2::CheckButton->new($flags_fr[$i]) ;
$toggles[$i]->signal_connect( ’toggled’ => sub {
my $j ;
my $opts = [] ;
for ($j = 0 ; $j < scalar(@flags) ; $j++ )
{
if ( $toggles[$j]->get_active )
{
push @$opts, $flags[$j] ;
}
}
$calendar->display_options($opts) ;
}) ;
$vbox3->pack_start($toggles[$i], TRUE, TRUE, 0 ) ;
}
foreach (@flags)
{
$_ =  s/\s/-/g ;
$_ = lc($_) ;
print $_,\n” ;
}

# Construit le bouton de sélection de la police
$button = Gtk2::Button->new(’Police...’ ) ;
$button->signal_connect( ’clicked’ => sub {
calendar_select_font($_[1 ]) ;
}, $calendar ) ;
$vbox2->pack_start($button, FALSE, FALSE, 0 ) ;

#
# Construit la partie concernant les signaux.
#

$frame = Gtk2::Frame->new(’Signaux’ ) ;
$vbox->pack_start($frame, TRUE, TRUE, DEF_PAD) ;

$vbox2 = Gtk2::VBox->new(TRUE, DEF_PAD_SMALL) ;
$frame->add($vbox2) ;

$hbox = Gtk2::HBox->new(FALSE, 3 ) ;
$vbox2->pack_start($hbox, FALSE, TRUE, 0 ) ;
$label = Gtk2::Label->new(’Signal:’ ) ;
$hbox->pack_start($label, FALSE, TRUE, 0 ) ;
$signals{curr} = Gtk2::Label->new( ) ;
$hbox->pack_start($signals{curr}, FALSE, TRUE, 0 ) ;

$hbox = Gtk2::HBox->new(FALSE, 3 ) ;
$vbox2->pack_start($hbox, FALSE, TRUE, 0 ) ;
$label = Gtk2::Label->new(’Signal précédent :’ ) ;
$hbox->pack_start($label, FALSE, TRUE, 0 ) ;
$signals{prev} = Gtk2::Label->new( ) ;
$hbox->pack_start($signals{prev}, FALSE, TRUE, 0 ) ;

$hbox = Gtk2::HBox->new(FALSE, 3 ) ;
$vbox2->pack_start($hbox, FALSE, TRUE, 0 ) ;
$label = Gtk2::Label->new(’Signal précédent le précédent :’ ) ;
$hbox->pack_start($label, FALSE, TRUE, 0 ) ;
$signals{prev2} = Gtk2::Label->new( ) ;
$hbox->pack_start($signals{prev2}, FALSE, TRUE, 0 ) ;

$bbox = Gtk2::HButtonBox->new ;
$vbox->pack_start($bbox, FALSE, FALSE, 0 ) ;
$bbox->set_layout(’end’ ) ;

$button = Gtk2::Button->new_from_stock(’gtk-close’ ) ;
$button->signal_connect( ’clicked’ => sub {
Gtk2->main_quit ;
} ) ;
$bbox->add($button) ;
$button->set_flags(’can-default’ ) ;
$button->grab_default ;

$window->show_all ;
}


Gtk2->init ;

create_calendar ;

Gtk2->main ;

exit 0 ;