#
# Calendar widget, contributed by
# David Naseby ([email protected]).
#
# Still could use methods for:
#
# * Get and set the day-of-the-month button properties (e.g. "poppy"
# style buttons versus regular pushbuttons)
# * Setting the date explicitly, possibly also messages like
# "advance/back up one day", "advance/back up one month", etc.
#
# * Should it have a display-only mode? In other words, buttons
# aren't clickable, just labels?
#
# Harry Ohlsen ([email protected]) also suggests a facility to jump
# backward or forward a year at a time.
#
require 'fox16/colors'
module Fox
# Calendar-specific options
CALENDAR_NORMAL = 0
CALENDAR_READONLY = 0x00020000
#
# Calendar widget
#
# == Events
#
# The following messages are sent by FXCalendar to its target:
#
# +SEL_COMMAND+:: sent when a day button is clicked; the message data is a Time object indicating the selected date
#
# == Calendar options
#
# +CALENDAR_NORMAL+:: normal display mode
# +CALENDAR_READONLY+:: read-only mode
#
class FXCalendar < FXVerticalFrame
DAYS = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT']
# Currently selected date [Time]
attr_reader :selected
# Font used for days [FXFont]
attr_reader :dayLabelFont
#
# Returns an initialized calendar widget
#
def initialize(parent, initial_date=Time.now, tgt=nil, sel=0, opts=0, x=0, y=0, w=0, h=0, pl=DEFAULT_PAD, pr=DEFAULT_PAD, pt=DEFAULT_PAD, pb=DEFAULT_PAD)
# Initialize the base class first
super(parent, opts, x, y, w, h, pl, pr, pt, pb)
# Save target and selector
self.target = tgt
self.selector = sel
@headerBGColor = FXColor::Black
@headerFGColor = FXColor::White
@dayLabelFont = FXFont.new(getApp, "helvetica", 7)
@date_showing = initial_date
# Header row
@header = FXHorizontalFrame.new(self, LAYOUT_FILL_X)
@header.backColor = @headerBGColor
@backBtn = FXArrowButton.new(@header, nil, 0, FRAME_RAISED|FRAME_THICK|ARROW_LEFT|ARROW_REPEAT)
@backBtn.connect(SEL_COMMAND) do |send, sel, ev|
@date_showing = _last_month
_build_date_matrix
@current_month.text = _header_date
end
@current_month = FXLabel.new(@header, _header_date, nil,
LAYOUT_FILL_X|JUSTIFY_CENTER_X|LAYOUT_FILL_Y)
@current_month.backColor = @headerBGColor
@current_month.textColor = @headerFGColor
@foreBtn = FXArrowButton.new(@header, nil, 0, FRAME_RAISED|FRAME_THICK|ARROW_RIGHT|ARROW_REPEAT)
@foreBtn.connect(SEL_COMMAND) do |send, sel, ev|
@date_showing = _next_month
_build_date_matrix
@current_month.text = _header_date
end
@matrix = FXMatrix.new(self, 7,
MATRIX_BY_COLUMNS|LAYOUT_FILL_X|LAYOUT_FILL_Y|PACK_UNIFORM_WIDTH|FRAME_RAISED,
0, 0, 0, 0, 0, 0, 0, 0)
DAYS.each { |day| _add_matrix_label(day) }
(7*6 - 1).times do
s = FXSwitcher.new(@matrix,
LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FILL_ROW|LAYOUT_FILL_COLUMN, 0,0,0,0,0,0,0,0)
FXFrame.new(s, LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0,0,0,0,0)
btn = FXButton.new(s, '99', nil, nil, 0,
LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_RAISED|FRAME_THICK,
0,0,0,0,0,0,0,0)
btn.connect(SEL_COMMAND) do |send, sel, ev|
@selected = Time.local(@date_showing.year, @date_showing.month,
send.text.to_i)
target.handle(self, Fox.MKUINT(selector, SEL_COMMAND), @selected) if target
end
end
_build_date_matrix()
end
# Return the current header background color
def headerBackColor
@headerBGColor
end
# Set the header background color
def headerBackColor=(clr)
@headerBGColor = clr
@header.backColor = clr
@current_month.backColor = clr
DAYS.each_index { |i| @matrix.childAtIndex(i).backColor = clr }
end
# Return the current header text color
def headerTextColor
@headerFGColor
end
# Set the header text color
def headerTextColor=(clr)
@headerFGColor = clr
@current_month.textColor = clr
DAYS.each_index { |i| @matrix.childAtIndex(i).textColor = clr }
end
# Change the font used for the days of the weeks
def dayLabelFont=(font)
if @dayLabelFont != font
@dayLabelFont = font
DAYS.each_index { |i| @matrix.childAtIndex(i).font = font }
update
end
end
private
def _header_date()
@date_showing.strftime("%B, %Y")
end
def _first_day
Time.local(@date_showing.year, @date_showing.month, 1)
end
def _last_day
year = @date_showing.year
month = @date_showing.month+1
if month > 12
year += 1
month = 1
end
Time.local(year, month, 1) - (60*60*24)
end
def _last_month
year = @date_showing.year
month = @date_showing.month - 1
if month < 1
year -= 1
month = 12
end
Time.local(year, month)
end
def _next_month
year = @date_showing.year
month = @date_showing.month + 1
if month > 12
year +=1
month = 1
end
Time.local(year, month)
end
def _build_date_matrix
(0...6*7-1).each do |index|
@matrix.childAtRowCol(index/7+1, index.modulo(7)).setCurrent(0)
end
(_first_day.wday... _last_day.day+_first_day.wday).each do |index|
day = index - _first_day.wday + 1
switcher = @matrix.childAtRowCol(index/7 + 1, index.modulo(7))
switcher.setCurrent(1)
switcher.childAtIndex(1).text = day.to_s
end
end
def _add_matrix_label(label)
l = FXLabel.new(@matrix, label, nil,
LAYOUT_FILL_X|LAYOUT_FILL_COLUMN|JUSTIFY_CENTER_X|FRAME_SUNKEN)
l.backColor = @headerBGColor
l.textColor = @headerFGColor
l.font = @dayLabelFont
end
end
end
if __FILE__ == $0
app = Fox::FXApp.new('Calendar', 'FXRuby')
app.init(ARGV)
mainwin = Fox::FXMainWindow.new(app, "Calendar Test", nil, nil, Fox::DECOR_ALL, 0, 0, 500, 500)
calendar = Fox::FXCalendar.new(mainwin, Time.now, nil, 0, Fox::LAYOUT_FILL_X|Fox::LAYOUT_FILL_Y)
calendar.connect(Fox::SEL_COMMAND) do |sender, sel, data|
puts data.to_s
end
app.create
mainwin.show(Fox::PLACEMENT_SCREEN)
app.run
end