Class: RNDK::Calendar

Inherits:
Widget
  • Object
show all
Defined in:
lib/rndk/calendar.rb

Overview

Pop-up calendar Widget.

The Calendar Widget allows the user to traverse through months/years using the cursor keys.

Keybindings

Left Arrow:: Moves the cursor to the previous day. Right Arrow:: Moves the cursor to the next day. Up Arrow:: Moves the cursor to the next week. Down Arrow:: Moves the cursor to the previous week. t:: Sets the calendar to the current date. T:: Sets the calendar to the current date. n:: Advances the calendar one month ahead. N:: Advances the calendar six months ahead. p:: Advances the calendar one month back. P:: Advances the calendar six months back. -:: Advances the calendar one year ahead. +:: Advances the calendar one year back. Enter:: Exits the widget and returns a value of time_t which represents the day selected at 1 second after midnight. This also sets the widget data exit_type to :NORMAL. Tab:: Exits the widget and returns a value of time_t which represents the day selected at 1 second after midnight. This also sets the widget data exit_type to :NORMAL. Escape:: Exits the widget and returns selected date This also sets the widget data exit_type to :ESCAPE_HIT. Ctrl-L:: Refreshes the screen.

Constant Summary collapse

MONTHS_OF_THE_YEAR =
[
    'NULL',
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
]
DAYS_OF_THE_MONTH =
[
    -1,
    31,
    28,
    31,
    30,
    31,
    30,
    31,
    31,
    30,
    31,
    30,
    31,
]
MAX_DAYS =
32
MAX_MONTHS =
13
MAX_YEARS =
140
CALENDAR_LIMIT =
(MAX_DAYS * MAX_MONTHS * MAX_YEARS)

Instance Attribute Summary collapse

Attributes inherited from Widget

#BXAttr, #HZChar, #LLChar, #LRChar, #ULChar, #URChar, #VTChar, #accepts_focus, #binding_list, #border_size, #box, #exit_type, #has_focus, #is_visible, #screen, #screen_index, #supported_signals, #widget_type

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Widget

#Screen_XPOS, #Screen_YPOS, #after_processing, #before_processing, #bind_key, #bind_signal, #bindable_widget, #clean_bindings, #clean_title, #draw_title, #get_box, #getch, #is_bound?, #refresh_data, #run_key_binding, #run_signal_binding, #save_data, #setBXattr, #setHZchar, #setLLchar, #setLRchar, #setULchar, #setURchar, #setVTchar, #set_box, #set_exit_type, #set_title, #unbind_key, #valid?, #valid_type?

Constructor Details

#initialize(screen, config = {}) ⇒ Calendar

Note:

If day, month or year are zero, we'll use the current date for it (Time.now.gmtime). If all of them are 0, will use the complete date of today.

Creates a Calendar Widget.

  • x is the x position - can be an integer or RNDK::LEFT, RNDK::RIGHT, RNDK::CENTER.
  • y is the y position - can be an integer or RNDK::TOP, RNDK::BOTTOM, RNDK::CENTER.
  • day, month and year are integers on the format dd, mm, yyyy.
  • title can be more than one line - just split them with \ns.
  • *_color are specific colors.


134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/rndk/calendar.rb', line 134

def initialize(screen, config={})
  super()
  @widget_type = :calendar
  @supported_signals += [:before_input, :after_input]

  # This is UGLY AS HELL
  # But I don't have time to clean this up right now
  # (lots of widgets, you know)  :(
  x            = 0
  y            = 0
  title        = "calendar"
  day          = 0
  month        = 0
  year         = 0
  day_color   = 0
  month_color = 0
  year_color  = 0
  highlight    = RNDK::Color[:reverse]
  box          = true
  shadow       = false

  config.each do |key, val|
    x            = val if key == :x
    y            = val if key == :y
    title        = val if key == :title
    day          = val if key == :day
    month        = val if key == :month
    year         = val if key == :year
    day_color    = val if key == :day_color
    month_color  = val if key == :month_color
    year_color   = val if key == :year_color
    highlight    = val if key == :highlight
    box          = val if key == :box
    shadow       = val if key == :shadow
  end

  self.set_date(day, month, year)
  self.set_box box

  parent_width  = Ncurses.getmaxx(screen.window)
  parent_height = Ncurses.getmaxy(screen.window)

  box_width  = 24
  box_height = 11

  dayname = 'Su Mo Tu We Th Fr Sa '

  box_width   = self.set_title(title, box_width)
  box_height += @title_lines

  # Make sure we didn't extend beyond the dimensions
  # of the window.
  box_width = [box_width, parent_width].min
  box_height = [box_height, parent_height].min

  # Rejustify the x and y positions if we need to.
  xtmp = [x]
  ytmp = [y]
  RNDK.alignxy(screen.window, xtmp, ytmp, box_width, box_height)
  xpos = xtmp[0]
  ypos = ytmp[0]

  # Create the calendar window.
  @win = Ncurses.newwin(box_height, box_width, ypos, xpos)

  # Is the window nil?
  if @win.nil?
    self.destroy
    return nil
  end
  Ncurses.keypad(@win, true)

  # Set some variables.
  @x_offset = (box_width - 20) / 2
  @field_width = box_width - 2 * (1 + @border_size)

  # Set months and day names
  @month_name = Calendar::MONTHS_OF_THE_YEAR.clone
  @day_name = dayname

  # Set the rest of the widget values.
  @screen = screen
  @parent = screen.window

  @xpos = xpos
  @ypos = ypos

  @width      = box_width
  @box_width  = box_width
  @box_height = box_height

  @day_color   = day_color
  @month_color = month_color
  @year_color  = year_color
  @highlight    = highlight

  @accepts_focus = true
  @input_window  = @win

  @week_base = 0

  @shadow     = shadow
  @shadow_win = nil

  @label_win = Ncurses.subwin(@win,
                              1,
                              @field_width,
                              ypos + @title_lines + 1,
                              xpos + 1 + @border_size)
  if @label_win.nil?
    self.destroy
    return nil
  end

  @field_win = Ncurses.subwin(@win,
                              7,
                              20,
                              ypos + @title_lines + 3,
                              xpos + @x_offset)
  if @field_win.nil?
    self.destroy
    return nil
  end

  # Mon Nov 11 18:54:40
  # another `set_box box` was here
  # apparently nothing fucked up, see if I can delete this

  @marker = [0] * Calendar::CALENDAR_LIMIT

  # If a shadow was requested, then create the shadow window.
  if shadow
    @shadow_win = Ncurses.newwin(box_height,
                                 box_width,
                                 ypos + 1,
                                 xpos + 1)
  end

  self.bind_key('t') { self.set_date(0, 0, 0)        }
  self.bind_key('T') { self.set_date(0, 0, 0)        }
  self.bind_key('n') { self.incrementCalendarMonth 1 }
  self.bind_key('p') { self.decrementCalendarMonth 1 }
  self.bind_key('N') { self.incrementCalendarMonth 6 }
  self.bind_key('P') { self.decrementCalendarMonth 6 }
  self.bind_key('-') { self.decrementCalendarYear 1  }
  self.bind_key('+') { self.incrementCalendarYear 1  }

  screen.register(:calendar, self)
end

Instance Attribute Details

#dayObject (readonly)

Returns the value of attribute day.



41
42
43
# File 'lib/rndk/calendar.rb', line 41

def day
  @day
end

#monthObject (readonly)

Returns the value of attribute month.



41
42
43
# File 'lib/rndk/calendar.rb', line 41

def month
  @month
end

#week_baseObject

First day of the week - Sunday is 0, Monday is 1, etc.



44
45
46
# File 'lib/rndk/calendar.rb', line 44

def week_base
  @week_base
end

#yearObject (readonly)

Returns the value of attribute year.



41
42
43
# File 'lib/rndk/calendar.rb', line 41

def year
  @year
end

Class Method Details

.days_in_month(year, month) ⇒ Object

Returns how many days the month/year has.



105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rndk/calendar.rb', line 105

def self.days_in_month(year, month)
  month_length = DAYS_OF_THE_MONTH[month]

  if month == 2
    month_length += if Calendar.leap_year?(year)
                    then 1
                    else 0
                    end
  end

  month_length
end

.leap_year?(year) ⇒ Boolean

Tells if year is a leap year.

Returns:

  • (Boolean)


90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/rndk/calendar.rb', line 90

def self.leap_year? year
  result = false
  if year % 4 == 0
    if year % 100 == 0
      if year % 400 == 0
        result = true
      end
    else
      result = true
    end
  end
  result
end

.month_starting_weekday(year, month) ⇒ Object

Tells what day of the week the month starts on.



85
86
87
# File 'lib/rndk/calendar.rb', line 85

def self.month_starting_weekday(year, month)
  return Time.mktime(year, month, 1, 10, 0, 0).wday
end

Instance Method Details

#activate(actions = []) ⇒ Object

Activates the Widget, letting the user interact with it.

actions is an Array of characters. If it's non-null, will #inject each char on it into the Widget.

Returns:

  • The date or nil if something bad happened.



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/rndk/calendar.rb', line 300

def activate(actions=[])
  ret = nil
  self.draw

  if actions.nil? || actions.size == 0
    # Interacting with the user
    loop do
      input = self.getch

      # Inject the character into the widget.
      ret = self.inject input

      return ret if @exit_type != :EARLY_EXIT
    end

  else
    # Executing `actions`, one char at a time.
    actions.each do |action|
      ret = self.inject action

      return ret if @exit_type != :EARLY_EXIT
    end
  end
  ret
end

#destroyObject

See Also:



560
561
562
563
564
565
566
567
568
569
570
571
# File 'lib/rndk/calendar.rb', line 560

def destroy
  self.clean_title

  RNDK.window_delete @label_win
  RNDK.window_delete @field_win
  RNDK.window_delete @shadow_win
  RNDK.window_delete @win

  self.clean_bindings

  @screen.unregister self
end

#drawObject

Draws the Widget on the Screen.

If box is true, it is drawn with a box.



403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/rndk/calendar.rb', line 403

def draw

  header_len = @day_name.size
  col_len = (6 + header_len) / 7

  # Is there a shadow?
  Draw.drawShadow(@shadow_win) unless @shadow_win.nil?

  # Box the widget if asked.
  Draw.drawObjBox(@win, self) if @box

  self.draw_title @win

  # Draw in the day-of-the-week header.
  (0...7).each do |col|
    src = col_len * ((col + (@week_base % 7)) % 7)
    dst = col_len * col
    Draw.writeChar(@win,
                   @x_offset + dst,
                   @title_lines + 2,
                   @day_name[src..-1],
                   RNDK::HORIZONTAL,
                   0,
                   col_len)
  end

  Ncurses.wrefresh @win
  self.draw_field
end

#eraseObject

See Also:



550
551
552
553
554
555
556
557
# File 'lib/rndk/calendar.rb', line 550

def erase
  return unless self.valid?

  RNDK.window_erase @label_win
  RNDK.window_erase @field_win
  RNDK.window_erase @win
  RNDK.window_erase @shadow_win
end

#focusObject



650
651
652
653
# File 'lib/rndk/calendar.rb', line 650

def focus
  # Original: drawRNDKFscale(widget, ObjOf (widget)->box);
  self.draw
end

#get_current_timeObject

This returns what day of the week the month starts on.



645
646
647
648
# File 'lib/rndk/calendar.rb', line 645

def get_current_time
  # Determine the current time and determine if we are in DST.
  return Time.mktime(@year, @month, @day, 0, 0, 0).gmtime
end

#get_dateObject

Returns the current date the calendar is displaying.

Returns:

  • An array with [day, month, year] numbers.



502
503
504
# File 'lib/rndk/calendar.rb', line 502

def get_date
  [@day, @month, @year]
end

#get_day_colorObject



511
512
513
# File 'lib/rndk/calendar.rb', line 511

def get_day_color
  return @day_color
end

#get_highlightObject



538
539
540
# File 'lib/rndk/calendar.rb', line 538

def get_highlight
  return @highlight
end

#get_month_colorObject



520
521
522
# File 'lib/rndk/calendar.rb', line 520

def get_month_color
  return @month_color
end

#get_year_colorObject



529
530
531
# File 'lib/rndk/calendar.rb', line 529

def get_year_color
  return @year_color
end

#getCalendarCell(d, m, y) ⇒ Object

Returns current value on cell d/m/y.



290
291
292
# File 'lib/rndk/calendar.rb', line 290

def getCalendarCell(d, m, y)
  @marker[Calendar.calendar_index(d, m, y)]
end

#getMarker(day, month, year) ⇒ Object

Returns the marker on a specific date.



587
588
589
590
591
592
593
594
# File 'lib/rndk/calendar.rb', line 587

def getMarker(day, month, year)
  result = 0
  year = Calendar.global_year_index(year)
  if @marker != 0
    result = self.getCalendarCell(day, month, year)
  end
  result
end

#inject(input) ⇒ Object

See Also:



327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/rndk/calendar.rb', line 327

def inject input
  pp_return = true
  ret       = nil
  complete  = false

  self.set_exit_type(0)
  self.draw_field

  # Check if there is a pre-process function to be called.
  keep_going = self.run_signal_binding(:before_input, input)

  if keep_going

    # Check a predefined binding
    if self.is_bound? input
      self.run_key_binding input

      ## FIXME What the heck? Missing method?
      #self.checkEarlyExit

      #complete = true

    else
      case input
      when Ncurses::KEY_UP,    RNDK::PREV
        self.decrementCalendarDay 7
      when Ncurses::KEY_DOWN,  RNDK::NEXT
        self.incrementCalendarDay 7
      when Ncurses::KEY_LEFT,  RNDK::BACKCHAR
        self.decrementCalendarDay 1
      when Ncurses::KEY_RIGHT, RNDK::FORCHAR
        self.incrementCalendarDay 1
      when Ncurses::KEY_NPAGE then self.incrementCalendarMonth 1
      when Ncurses::KEY_PPAGE then self.decrementCalendarMonth 1

      when Ncurses::KEY_HOME
        self.set_date(0, 0, 0)

      when RNDK::KEY_ESC
        self.set_exit_type input
        complete = true
      when Ncurses::ERR
        self.set_exit_type input
        complete = true
      when RNDK::KEY_TAB, RNDK::KEY_RETURN, Ncurses::KEY_ENTER
        self.set_exit_type input
        ret = self.get_current_time
        complete = true
      when RNDK::REFRESH
        @screen.erase
        @screen.refresh
      end
    end

    # Should we do a post-process?
    self.run_signal_binding(:after_input) if not complete
  end

  if !complete
    self.set_exit_type(0)
  end

  @result_data = ret
  return ret
end

#move(x, y, relative, refresh_flag) ⇒ Object

See Also:



394
395
396
397
398
# File 'lib/rndk/calendar.rb', line 394

def move(x, y, relative, refresh_flag)
  windows = [@win, @field_win, @label_win, @shadow_win]

  self.move_specific(x, y, relative, refresh_flag, windows, [])
end

#normalize_dateObject

Makes sure that the internal dates exist, capping the values if too big/small.



628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
# File 'lib/rndk/calendar.rb', line 628

def normalize_date
  max = 1900 + MAX_YEARS - 1
  @year  = max if @year > max

  @year  = 1900 if @year  < 1900
  @month = 12   if @month > 12
  @month = 1    if @month < 1
  @day   = 1    if @day   < 1


  # Make sure the day given is within range of the month.
  month_length = Calendar.days_in_month(@year, @month)

  @day = month_length if @day > month_length
end

#positionObject

See Also:



661
662
663
# File 'lib/rndk/calendar.rb', line 661

def position
  super(@win)
end

#removeMarker(day, month, year) ⇒ Object

Removes a marker from the Calendar.



597
598
599
600
# File 'lib/rndk/calendar.rb', line 597

def removeMarker(day, month, year)
  year_index = Calendar.global_year_index(year)
  self.setCalendarCell(day, month, year_index, 0)
end

#set(config) ⇒ Object

Sets multiple attributes of the Widget.

See Calendar#initialize.



436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'lib/rndk/calendar.rb', line 436

def set(config)
  # This is UGLY AS HELL
  # But I don't have time to clean this up right now
  # (lots of widgets, you know)  :(
  x            = 0
  y            = 0
  title        = "calendar"
  day          = 0
  month        = 0
  year         = 0
  day_color    = 0
  month_color  = 0
  year_color   = 0
  highlight    = RNDK::Color[:reverse]
  box          = false
  shadow       = false

  config.each do |key, val|
    x            = val if key == :x
    y            = val if key == :y
    title        = val if key == :title
    day          = val if key == :day
    month        = val if key == :month
    year         = val if key == :year
    day_color    = val if key == :day_color
    month_color  = val if key == :month_color
    year_color   = val if key == :year_color
    highlight    = val if key == :highlight
    box          = val if key == :box
    shadow       = val if key == :shadow
  end

  self.set_date(day, month, year)                if not day.zero? and month.zero? and year.zero?
  self.set_day_color(day_color)                if not day_color.zero?
  self.set_month_color(month_color)            if not month_color.zero?
  self.set_year_color(year_color)              if not year_color.zero?
  self.set_highlight(highlight)                  if highlight != RNDK::Color[:reverse]
  self.set_box(box)                              if box
  @box_width = self.set_title(title, @box_width) if title != "calendar"
end

#set_bg_color(attrib) ⇒ Object

Sets the background attribute/color of the widget.



543
544
545
546
547
# File 'lib/rndk/calendar.rb', line 543

def set_bg_color attrib
  Ncurses.wbkgd(@win, attrib)
  Ncurses.wbkgd(@field_win, attrib)
  Ncurses.wbkgd(@label_win, attrib) unless @label_win.nil?
end

#set_date(day, month, year) ⇒ Object

Note:

If day, month or year are zero, we'll use the current date for it. If all of them are 0, will use the complete date of today.

Sets the current date.



483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'lib/rndk/calendar.rb', line 483

def set_date(day, month, year)

  # Get the current dates and set the default values for the
  # day/month/year values for the calendar
  date_info = Time.new.gmtime

  @day   = if day   == 0 then date_info.day   else day   end
  @month = if month == 0 then date_info.month else month end
  @year  = if year  == 0 then date_info.year  else year  end

  self.normalize_date

  # Get the start of the current month.
  @week_day = Calendar.month_starting_weekday(@year, @month)
end

#set_day_color(attribute) ⇒ Object

Sets the appearance/color of the days.



507
508
509
# File 'lib/rndk/calendar.rb', line 507

def set_day_color attribute
  @day_color = attribute
end

#set_days_names(days) ⇒ Object

Sets the names of the days of the week.

days is a String listing the 2-character abbreviations for the days.

The default value is "Su Mo Tu We Th Fr Sa"

"Su" (Sunday) is numbered zero internally, making it by default the first day of the week. Set the week_base member of the widget to select a different day.

For example, Monday would be 1, Tuesday 2, etc.



622
623
624
# File 'lib/rndk/calendar.rb', line 622

def set_days_names days
  @day_name = days.clone
end

#set_highlight(highlight) ⇒ Object

Sets the attribute/color of the highlight bar of the scrolling list.



534
535
536
# File 'lib/rndk/calendar.rb', line 534

def set_highlight highlight
  @highlight = highlight
end

#set_marker(day, month, year, marker) ⇒ Object

Sets a marker on a specific date.



574
575
576
577
578
579
580
581
582
583
584
# File 'lib/rndk/calendar.rb', line 574

def set_marker(day, month, year, marker)
  year_index = Calendar.global_year_index(year)
  oldmarker = self.getMarker(day, month, year)

  # Check to see if a marker has not already been set
  if oldmarker != 0
    self.setCalendarCell(day, month, year_index, oldmarker | RNDK::Color[:blink])
  else
    self.setCalendarCell(day, month, year_index, marker)
  end
end

#set_month_color(attribute) ⇒ Object

Sets the appearance/color of the month name.



516
517
518
# File 'lib/rndk/calendar.rb', line 516

def set_month_color attribute
  @month_color = attribute
end

#set_year_color(attribute) ⇒ Object

Sets the appearance/color of the year number.



525
526
527
# File 'lib/rndk/calendar.rb', line 525

def set_year_color attribute
  @year_color = attribute
end

#setCalendarCell(d, m, y, value) ⇒ Object

Sets d/m/y cell to have value.



285
286
287
# File 'lib/rndk/calendar.rb', line 285

def setCalendarCell(d, m, y, value)
  @marker[Calendar.calendar_index(d, m, y)] = value
end

#setMonthNames(months) ⇒ Object

Sets the month name.



603
604
605
606
607
# File 'lib/rndk/calendar.rb', line 603

def setMonthNames(months)
  (1...[months.size, @month_name.size].min).each do |x|
    @month_name[x] = months[x]
  end
end

#unfocusObject



655
656
657
658
# File 'lib/rndk/calendar.rb', line 655

def unfocus
  # Original: drawRNDKFscale(widget, ObjOf (widget)->box);
  self.draw
end