# # Calendar widget, contributed by # David Naseby (david.naseby@eonesolutions.com.au). # # 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 (harryo@zip.com.au) also suggests a facility to jump # backward or forward a year at a time. # require 'fox12' require 'fox12/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, 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 include Fox app = FXApp.new('Calendar', 'FXRuby') app.init(ARGV) mainwin = FXMainWindow.new(app, "Calendar Test", nil, nil, DECOR_ALL, 0, 0, 500, 500) calendar = FXCalendar.new(mainwin, Time.now, nil, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y) calendar.connect(SEL_COMMAND) do |sender, sel, data| puts data.to_s end app.create mainwin.show(PLACEMENT_SCREEN) app.run end