A.4. Calendar

class_add_ivar (GtkCalendar, #opflags, 0b0);

method GtkCalendar.change_option (flag)
{
  self.opflags = self.opflags ^ flag;
  self.display_options(self.opflags);
}

method GtkCalendar.safe_select_day(day)
{
  local max_date, ck_date = self.get_date();
  m = cadr(ck_date);
  y = car(ck_date);
 if (find_equal(m, list(0, 2, 4, 6, 7, 9, 11)))
   max_date = 31;
  else if (find_equal(m, list(3, 5, 8, 10))) // Thirty days hath September...
    max_date = 30;
  else if ((y % 4) == 0)
    max_date = 29;
  else
    max_date = 28;
  if (day > max_date)
    day = max_date;
  self.select_day(day);
}

function op_button(label, flag, box, active)
{
  local but = gtk_check_button_new_with_label(label);
  but.signal ("toggled", `(@cal).change_option(@flag));
  but.set_active(active);
  box.pack_start (but, TRUE, TRUE, 0);
}

function cal_changed(cal, spinner, dmy)
{
  local new_date = car(nth_cdr(cal.get_date(), dmy));

  if (dmy == 1)
    new_date = new_date +1;
  spinner.set_value(new_date);
}

function make_adj (low, up, step, pg_inc, pg_size)
{
  local adj = new(GtkAdjustment);
  adj.lower = low;
  adj.upper = up;
  adj.step_increment = step;
  adj.page_increment = pg_inc;
  adj.page_size = pg_size;
  adj;
}

function create_calendar ()
{
  local	box1, box2;
  
  win_calendar = new (GtkWindow);
  win_calendar.signal ("destroy", #win_calendar = nil);
  win_calendar.title = "GtkCalendar";

  box1 = new (GtkVBox);
  win_calendar.add (box1);

  box2 = new (GtkVBox);
  box2.border_width = 15;

  cal = gtk_calendar_new();
  cal.width = 250;
  cal.height = 130;
  cal.mark_day(5);
  cal.select_day(21);
  cal.select_month(5, 2003);
  cal.display_options(cal.opflags);
  box2.pack_start (cal, TRUE, TRUE, 0);

  op_button("Show heading",
	    GTK_CALENDAR_SHOW_HEADING, box2, TRUE);
  op_button("Show day names",
	    GTK_CALENDAR_SHOW_DAY_NAMES, box2, TRUE);
  op_button("No month or year change in heading",
	    GTK_CALENDAR_NO_MONTH_CHANGE, box2, FALSE);
  op_button("Show week numbers in left column",
	    GTK_CALENDAR_SHOW_WEEK_NUMBERS, box2, FALSE);
  op_button("Week starts on Monday",
	    GTK_CALENDAR_WEEK_START_MONDAY, box2, FALSE);

  table = new(GtkTable);
  table.n_columns = 3;
  table.n_rows = 3;
  table.set_row_spacings(5);
  table.set_col_spacings(5);
  table.set_homogeneous(FALSE);
  box2.pack_start(table, FALSE, FALSE, 0);

  label = new(GtkLabel);
  label.set_text("Select a day:");
  table.attach_defaults(label, 0, 1, 0, 1);
  
  adj = make_adj(1, 31, 1, 5, 0);
  spin1 = new(GtkSpinButton);
  spin1.configure(adj, 0, 0);
  spin1.set_value(21);
  spin1.set_wrap(TRUE);
  spin1.set_shadow_type(GTK_SHADOW_OUT);
  table.attach_defaults(spin1, 1, 2, 0, 1);

  but1 = new (GtkButton);
  but1.label = "Apply";
  table.attach_defaults(but1, 2, 3, 0, 1);

  label = new(GtkLabel);
  label.set_text("Select a month:");
  table.attach_defaults(label, 0, 1, 1, 2);
  
  adj = make_adj(1, 12, 1, 5, 0);
  spin2 = new(GtkSpinButton);
  spin2.configure(adj, 0, 0);
  spin2.set_value(6);
  spin2.set_wrap(TRUE);
  spin2.set_shadow_type(GTK_SHADOW_OUT);
  table.attach_defaults(spin2, 1, 2, 1, 2);

  but2 = new (GtkButton);
  but2.label = "Apply";
  table.attach_defaults(but2, 2, 3, 1, 2);

  label = new(GtkLabel);
  label.set_text("Select a year:");
  table.attach_defaults(label, 0, 1, 2, 3);
  
  adj = make_adj(1900, 2100, 1, 5, 0);
  spin3 = new(GtkSpinButton);
  spin3.configure(adj, 0, 0);
  spin3.set_value(2003);
  spin3.set_wrap(TRUE);
  spin3.set_shadow_type(GTK_SHADOW_OUT);
  table.attach_defaults(spin3, 1, 2, 2, 3);

  but3 = new (GtkButton);
  but3.label = "Apply";
  table.attach_defaults(but3, 2, 3, 2, 3);

  label = new(GtkLabel);
  label.set_text("Mark this day:");
  table.attach_defaults(label, 0, 1, 3, 4);
  
  adj = make_adj(1, 31, 1, 5, 0);
  spin4 = new(GtkSpinButton);
  spin4.configure(adj, 0, 0);
  spin4.set_value(5);
  spin4.set_wrap(TRUE);
  spin4.set_shadow_type(GTK_SHADOW_OUT);
  table.attach_defaults(spin4, 1, 2, 3, 4);

  but4 = new (GtkButton);
  but4.label = "Apply";
  table.attach_defaults(but4, 2, 3, 3, 4);

  label = new(GtkLabel);
  label.set_text("Unmark this day:");
  table.attach_defaults(label, 0, 1, 4, 5);
  
  adj = make_adj(1, 31, 1, 5, 0);
  spin5 = new(GtkSpinButton);
  spin5.configure(adj, 0, 0);
  spin5.set_value(5);
  spin5.set_wrap(TRUE);
  spin5.set_shadow_type(GTK_SHADOW_OUT);
  table.attach_defaults(spin5, 1, 2, 4, 5);

  but5 = new (GtkButton);
  but5.label = "Apply";
  table.attach_defaults(but5, 2, 3, 4, 5);

  but6 = new (GtkButton);
  but6.label = "Clear all marks";
  table.attach_defaults(but6, 0, 1, 5, 6);

  but1.signal("clicked", `(@cal).safe_select_day((@spin1).get_value_as_int()));
  but2.signal("clicked", `(@cal).select_month((@spin2).get_value_as_int() -1,
					     (@spin3).get_value_as_int()));
  but3.signal("clicked", `(@cal).select_month((@spin2).get_value_as_int() -1,
					     (@spin3).get_value_as_int()));
  but4.signal("clicked", `(@cal).mark_day((@spin4).get_value_as_int()));
  but5.signal("clicked", `(@cal).unmark_day((@spin5).get_value_as_int()));
  but6.signal("clicked", `(@cal).clear_marks());

  cal.signal("day_selected", `cal_changed(@cal, @spin1, 2));
  cal.signal("month_changed", `cal_changed(@cal, @spin2, 1));
  cal.signal("prev_year", `cal_changed(@cal, @spin3, 0));
  cal.signal("next_year", `cal_changed(@cal, @spin3, 0));

  box1.pack_start (box2, TRUE, TRUE, 0);

  separator = new (GtkHSeparator);
  box1.pack_start (separator, FALSE, TRUE, 0);
    
  box2 = new (GtkVBox);
  box2.border_width = 15;

  button = new(GtkButton);
  button.label = "Close";
  button.signal("clicked", `(@win_calendar).destroy());
  box2.pack_start(button, TRUE, TRUE, 5);
  box1.pack_start (box2, TRUE, TRUE, 0);
  
  win_calendar.show_all();
  win_calendar;
}

function main ()
{
  local window, win_calendar;
  TRUE=1;
  FALSE=0;
  window = create_calendar ();
  window.signal ("destroy", #exit_program(0));
  init_ipc("calendar", "calendarq");
  gtk_main ();
}