### Tutorial

« Combo Box | Color Selection »

## Calendar

The Calendar widget is an effective way to display and retrieve monthly date related information. It is a very simple widget to create and work with.
You create a Calendar widget with the constructor:

`Calendar();`

There might be times where you need to change a lot of information within this widget and the following methods allow you to make multiple changes to a Calendar widget without the user seeing multiple on-screen updates.

`void freeze(); void thaw();`

They work just like the freeze/thaw methods of every other widget.
The Calendar widget has a few options that allow you to change the way the widget both looks and operates by using the method:

`void display_options(Gtk::CalendarDisplayOptionsField flags);`

The flags argument can be formed by combining either of the following five options using the logical bitwise OR (|) operation:

CALENDAR_SHOW_HEADING | - | this option specifies that the month and year should be shown when drawing the calendar.
CALENDAR_SHOW_DAY_NAMES | - | this option specifies that the three letter descriptions should be displayed for each day (e.g. Mon,Tue, etc.).
CALENDAR_NO_MONTH_CHANGE | - | this option states that the user should not and can not change the currently displayed month. This can be good if you only need to display a particular month such as if you are displaying 12 calendar widgets for every month in a particular year.
CALENDAR_SHOW_WEEK_NUMBERS | - | this option specifies that the number for each week should be displayed down the left side of the calendar. (e.g. Jan 1 = Week 1,Dec 31 = Week 52).
CALENDAR_WEEK_START_MONDAY | - | this option states that the calendar week will start on Monday instead of Sunday which is the default. This only affects the order in which days are displayed from left to right.

The following methods are used to set the the currently displayed date:

`bool select_month(int month, int year); void select_day(int day);`

The return value from Gtk::Calendar::select_month() is a bool value indicating whether the selection was successful.
With Gtk::Calendar::select_day() the specified day number is selected within the current month, if that is possible. A day value of 0 will deselect any current selection.
In addition to having a day selected, any number of days in the month may be "marked". A marked day is highlighted within the calendar display. The following methods are provided to manipulate marked days:

`bool mark_day(int day); bool unmark_day(int day); void clear_marks();`

The currently marked days are stored within an array within the wrapped GtkCalendar structure and can be accessed using the marked_date() accessor:

`std::vector<bool> marked_date() const;`

The returned vector is 31 elements long so to test whether a particular day is currently marked, you need to access the corresponding element of the vector (don't forget that vector elements are numbered 0 to n-1). For example:

`Gtk::Calendar *calendar = new Gtk::Calendar; ... // Is day 7 marked? if (calendar->marked_date()[7-1]) { // day is marked }`

Note that marks are persistent across month and year changes.
The final Calendar widget method is used to retrieve the currently selected date, month and/or year.

`void get_date(int *year, int *month, int *day) const;`

This method requires you to pass the addresses of int variables, into which the result will be placed. Passing null as a value will result in the corresponding value not being returned.
The Calendar widget can generate a number of signals indicating date selection and change. The names of these signals are self explanatory, and are:

- month_changed
- day_selected
- day_selected_double_click
- prev_month
- next_month
- prev_year
- next_year

That just leaves us with the need to put all of this together into example code.
The header file for Inti Calendar Example is calendar.h:

`#include<inti/main.h>
#include <inti/core.h>
#include <inti/gtk/calendar.h>
#include <inti/gtk/checkbutton.h>
#include <inti/gtk/label.h>
#include <inti/gtk/fontselection.h>
using namespace Inti;
class CalendarWindow : public Gtk::Window
{
static const int DEF_PAD = 10;
static const int DEF_PAD_SMALL = 5;
static const int TM_YEAR_BASE = 1900;
Pointer<Gtk::Calendar> calendar;
Pointer<Gtk::Label> last_signal;
Pointer<Gtk::Label> previous_signal;
Pointer<Gtk::Label> previous2_signal;
std::vector<Gtk::CheckButton*> checkboxes;
std::vector<bool> settings;
void set_flags();
String date_to_string();
void set_signal_strings(const char *str);
protected:
void on_toggle_flag(Gtk::CheckButton *toggle);
void on_select_font();
void on_font_selection_ok(Gtk::FontSelectionDialog *font_dialog);
void on_day_selected_double_click();
public:
CalendarWindow();
virtual ~CalendarWindow();
};
`

and the source file is calendar.cc

`#include"calendar.h"
#include <inti/gtk/frame.h>
#include <inti/gtk/buttonbox.h>
#include <inti/gtk/separator.h>
#include <inti/pango/font.h>
#include <inti/bind.h>
const int CalendarWindow::DEF_PAD;
const int CalendarWindow::DEF_PAD_SMALL;
const int CalendarWindow::TM_YEAR_BASE;
CalendarWindow::CalendarWindow()
{
for (int i = 0; i < 5; i++)
settings.push_back(false);
set_title("Inti Calendar Example");
set_border_width(5);
set_resizable(false);
Gtk::VBox *vbox = new Gtk::VBox(false, DEF_PAD);
add(*vbox);
// The top part of the window, Calendar, flags and fontsel.
Gtk::HBox *hbox = new Gtk::HBox(false, DEF_PAD);
vbox->pack_start(*hbox, true,true, DEF_PAD);
Gtk::HButtonBox *hbbox = new Gtk::HButtonBox;
hbox->pack_start(*hbbox, false,false, DEF_PAD);
hbbox->set_layout(Gtk::BUTTONBOX_SPREAD);
hbbox->set_spacing(5);
// Calendar widget
Gtk::Frame *frame = new Gtk::Frame("Calendar");
hbbox->pack_start(*frame, false,true, DEF_PAD);
calendar = new Gtk::Calendar;
set_flags();
calendar->mark_day(19);
frame->add(*calendar);
calendar->sig_month_changed().connect(bind(slot(this, &CalendarWindow::set_signal_strings), "month_changed: "));
calendar->sig_day_selected().connect(bind(slot(this, &CalendarWindow::set_signal_strings), "day_selected: "));
calendar->sig_day_selected_double_click().connect(slot(this, &CalendarWindow::on_day_selected_double_click));
calendar->sig_prev_month().connect(bind(slot(this, &CalendarWindow::set_signal_strings), "prev_month: "));
calendar->sig_next_month().connect(bind(slot(this, &CalendarWindow::set_signal_strings), "next_month: "));
calendar->sig_prev_year().connect(bind(slot(this, &CalendarWindow::set_signal_strings), "prev_year: "));
calendar->sig_next_year().connect(bind(slot(this, &CalendarWindow::set_signal_strings), "next_year: "));
Gtk::VSeparator *separator = new Gtk::VSeparator;
hbox->pack_start(*separator, false, true);
Gtk::VBox *vbox2 = new Gtk::VBox(false, DEF_PAD);
hbox->pack_start(*vbox2, DEF_PAD);
// Build the Right frame with the flags in
frame = new Gtk::Frame("Flags");
vbox2->pack_start(*frame, true,true, DEF_PAD);
Gtk::VBox *vbox3 = new Gtk::VBox(true, DEF_PAD_SMALL);
frame->add(*vbox3);
struct { char *label; } flags[] = {
{ "Show Heading" },
{ "Show Day Names" },
{ "No Month Change" },
{ "Show Week Numbers" },
{ "Week Start Monday" }
};
for (int i = 0; i < 5; i++)
{
Gtk::CheckButton *toggle = new Gtk::CheckButton(flags[i].label);
toggle->sig_toggled().connect(bind(slot(this, &CalendarWindow::on_toggle_flag), toggle));
vbox3->pack_start(*toggle);
checkboxes.push_back(toggle);
}
// Build the right font-button
Gtk::Button *button = new Gtk::Button("Font...");
button->sig_clicked().connect(slot(this, &CalendarWindow::on_select_font));
vbox2->pack_start(*button, false,false);
// Build the Signal-event part.
frame = new Gtk::Frame("Signal events");
vbox->pack_start(*frame, true,true, DEF_PAD);
vbox2 = new Gtk::VBox(true, DEF_PAD_SMALL);
frame->add(*vbox2);
hbox = new Gtk::HBox(false, 3);
vbox2->pack_start(*hbox, false);
Gtk::Label *label = new Gtk::Label("Signal:");
hbox->pack_start(*label, false);
last_signal = new Gtk::Label("");
hbox->pack_start(*last_signal, false);
hbox = new Gtk::HBox(false, 3);
vbox2->pack_start(*hbox, false);
label = new Gtk::Label("Previous signal:");
hbox->pack_start(*label, false);
previous_signal = new Gtk::Label("");
hbox->pack_start(*previous_signal, false);
hbox = new Gtk::HBox(false, 3);
vbox2->pack_start(*hbox, false);
label = new Gtk::Label("Second previous signal:");
hbox->pack_start(*label, false);
previous2_signal = new Gtk::Label("");
hbox->pack_start(*previous2_signal, false);
hbbox = new Gtk::HButtonBox;
vbox->pack_start(*hbbox, false,false);
hbbox->set_layout(Gtk::BUTTONBOX_END);
button = new Gtk::Button("Close");
button->sig_clicked().connect(slot(this, &CalendarWindow::dispose));
hbbox->add(*button);
button->set_flags(Gtk::CAN_DEFAULT);
button->grab_default();
show_all();
}
CalendarWindow::~CalendarWindow()
{
}
void
CalendarWindow::set_flags()
{
int options = 0;
for (int i = 0; i < 5; i++)
{
if (settings[i])
options = options + (1 << i);
}
if (calendar)
calendar->display_options(options);
}
void
CalendarWindow::on_toggle_flag(Gtk::CheckButton *toggle)
{
int j = 0;
for (int i = 0; i < 5; i++)
{
if (checkboxes[i] == toggle)
j = i;
}
settings[j] = !settings[j];
set_flags();
}
void
CalendarWindow::on_select_font()
{
static Gtk::FontSelectionDialog *font_dialog = 0;
if (!font_dialog)
{
font_dialog = new Gtk::FontSelectionDialog("Font Selection Dialog");
font_dialog->set_position(Gtk::WIN_POS_MOUSE);
sig_destroy().connect(slot(font_dialog, &Gtk::FontSelectionDialog::dispose));
font_dialog->ok_button()->sig_clicked().connect(bind(slot(this, &CalendarWindow::on_font_selection_ok), font_dialog));
font_dialog->cancel_button()->sig_clicked().connect(slot(*font_dialog, &Gtk::FontSelectionDialog::hide));
}
if (!font_dialog->is_visible())
font_dialog->show();
else
font_dialog->hide();
}
void
CalendarWindow::on_font_selection_ok(Gtk::FontSelectionDialog *font_dialog)
{
String font_name = font_dialog->get_font_name();
if (calendar)
{
Pango::FontDescription font_desc(font_name);
calendar->modify_font(font_desc);
}
}
void
CalendarWindow::on_day_selected_double_click()
{
set_signal_strings("day_selected_double_click: ");
struct tm tm;
memset(&tm, 0, sizeof (tm));
calendar->get_date(&tm.tm_year, &tm.tm_mon, &tm.tm_mday);
tm.tm_year -= TM_YEAR_BASE;
if (calendar->marked_date()[tm.tm_mday - 1] == 0)
calendar->mark_day(tm.tm_mday);
else
calendar->unmark_day(tm.tm_mday);
}
String
CalendarWindow::date_to_string()
{
struct tm tm;
memset(&tm, 0, sizeof (tm));
calendar->get_date(&tm.tm_year, &tm.tm_mon, &tm.tm_mday);
tm.tm_year -= TM_YEAR_BASE;
time_t time = mktime(&tm);
char buffer[256];
strftime(buffer, 255, "%x", gmtime(&time));
return buffer;
}
void
CalendarWindow::set_signal_strings(const char *str)
{
String text = previous_signal->get_text();
previous2_signal->set_text(text);
text = last_signal->get_text();
previous_signal->set_text(text);
text = str;
text.append(date_to_string());
last_signal->set_text(text);
}
int main (int argc, char *argv[])
{
using namespace Main;
init(&argc, &argv);
CalendarWindow window;
window.sig_destroy().connect(slot(&Inti::Main::quit));
run();
return 0;
}`

« Combo Box | Index Miscellaneous Widgets Top | Color Selection »