Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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
#
# 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 '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, 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