xref: /haiku/src/apps/deskbar/CalendarMenuWindow.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
1 /*
2  * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "CalendarMenuWindow.h"
8 
9 #include <Button.h>
10 #include <CalendarView.h>
11 #include <GridLayoutBuilder.h>
12 #include <GroupLayout.h>
13 #include <GroupLayoutBuilder.h>
14 #include <GroupView.h>
15 #include <Locale.h>
16 #include <Screen.h>
17 #include <SpaceLayoutItem.h>
18 #include <String.h>
19 #include <StringView.h>
20 
21 
22 using BPrivate::BCalendarView;
23 using BPrivate::B_WEEK_START_SUNDAY;
24 using BPrivate::B_WEEK_START_MONDAY;
25 
26 
27 // #pragma mark -- FlatButton
28 
29 
30 class FlatButton : public BButton {
31 public:
32 					FlatButton(const BString& label, uint32 what)
33 						: BButton(label.String(), new BMessage(what)) {}
34 	virtual			~FlatButton() {}
35 
36 	virtual void	Draw(BRect updateRect);
37 };
38 
39 
40 void
41 FlatButton::Draw(BRect updateRect)
42 {
43 	updateRect = Bounds();
44 	rgb_color highColor = HighColor();
45 
46 	SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
47 	FillRect(updateRect);
48 
49 	font_height fh;
50 	GetFontHeight(&fh);
51 
52 	const char* label = Label();
53 	const float stringWidth = StringWidth(label);
54 	const float x = (updateRect.right - stringWidth) / 2.0f;
55 	const float labelY = updateRect.top
56 		+ ((updateRect.Height() - fh.ascent - fh.descent) / 2.0f)
57 		+ fh.ascent + 1.0f;
58 
59 	SetHighColor(highColor);
60 	DrawString(label, BPoint(x, labelY));
61 
62 	if (IsFocus()) {
63 		SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
64 		StrokeRect(updateRect);
65 	}
66 }
67 
68 
69 // #pragma mark -- CalendarMenuWindow
70 
71 
72 enum {
73 	kInvokationMessage,
74 	kMonthDownMessage,
75 	kMonthUpMessage,
76 	kYearDownMessage,
77 	kYearUpMessage
78 };
79 
80 
81 CalendarMenuWindow::CalendarMenuWindow(BPoint where)
82 	:
83 	BWindow(BRect(0.0, 0.0, 100.0, 130.0), "", B_BORDERED_WINDOW,
84 		B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS | B_CLOSE_ON_ESCAPE
85 		| B_NOT_MINIMIZABLE | B_NOT_ZOOMABLE),
86 	fYearLabel(NULL),
87 	fMonthLabel(NULL),
88 	fCalendarView(NULL),
89 	fSuppressFirstClose(true)
90 {
91 	BPrivate::week_start startOfWeek
92 		= (BPrivate::week_start)be_locale->StartOfWeek();
93 
94 	RemoveShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY);
95 	AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
96 
97 	fYearLabel = new BStringView("year", "");
98 	fYearLabel->SetFontSize(10.0);
99 
100 	fMonthLabel = new BStringView("month", "");
101 	fMonthLabel->SetFontSize(10.0);
102 
103 	fCalendarView = new BCalendarView(Bounds(), "calendar",
104 		startOfWeek, B_FOLLOW_ALL);
105 	fCalendarView->SetInvocationMessage(new BMessage(kInvokationMessage));
106 	fCalendarView->SetFontSize(10.0);
107 
108 	BGroupLayout* layout = new BGroupLayout(B_HORIZONTAL);
109 	SetLayout(layout);
110 
111 	float width, height;
112 	fMonthLabel->GetPreferredSize(&width, &height);
113 
114 	BGridLayout* gridLayout = BGridLayoutBuilder(5.0)
115 		.Add(_SetupButton("-", kMonthDownMessage, height), 0, 0)
116 		.Add(fMonthLabel, 1, 0)
117 		.Add(_SetupButton("+", kMonthUpMessage, height), 2, 0)
118 		.Add(BSpaceLayoutItem::CreateGlue(), 3, 0)
119 		.Add(_SetupButton("-", kYearDownMessage, height), 4, 0)
120 		.Add(fYearLabel, 5, 0)
121 		.Add(_SetupButton("+", kYearUpMessage, height), 6, 0)
122 		.SetInsets(5.0, 0.0, 5.0, 0.0);
123 	gridLayout->SetMinColumnWidth(1, be_plain_font->StringWidth("September"));
124 
125 	BGroupView* groupView = new BGroupView(B_VERTICAL, 10.0);
126 	BView* view = BGroupLayoutBuilder(B_VERTICAL, 5.0)
127 		.Add(gridLayout->View())
128 		.Add(fCalendarView)
129 		.SetInsets(5.0, 5.0, 5.0, 5.0)
130 		.TopView();
131 	groupView->AddChild(view);
132 	AddChild(groupView);
133 
134 	MoveTo(where);
135 	_UpdateUI(BDate::CurrentDate(B_LOCAL_TIME));
136 }
137 
138 
139 CalendarMenuWindow::~CalendarMenuWindow()
140 {
141 }
142 
143 
144 void
145 CalendarMenuWindow::Show()
146 {
147 	BRect screen(BScreen().Frame());
148 
149 	float right = screen.right;
150 	float bottom = screen.bottom;
151 
152 	BRect rightTop(right / 2.0, screen.top, right, bottom / 2.0);
153 	BRect rightBottom(right / 2.0, bottom / 2.0, right + 1.0, bottom + 1.0);
154 	BRect leftBottom(screen.left, bottom / 2.0, right / 2.0, bottom + 1.0);
155 
156 	BPoint where = Frame().LeftTop();
157 	BSize size = GetLayout()->PreferredSize();
158 
159 	if (rightTop.Contains(where)) {
160 		where.x -= size.width;
161 	} else if (leftBottom.Contains(where)) {
162 		where.y -= (size.height + 4.0);
163 	} else if (rightBottom.Contains(where)) {
164 		where.x -= size.width;
165 		where.y -= (size.height + 4.0);
166 	}
167 
168 	MoveTo(where);
169 	fCalendarView->MakeFocus(true);
170 
171 	BWindow::Show();
172 }
173 
174 
175 void
176 CalendarMenuWindow::WindowActivated(bool active)
177 {
178 	if (active)
179 		return;
180 
181 	if (mouse_mode() != B_FOCUS_FOLLOWS_MOUSE) {
182 		if (!active)
183 			PostMessage(B_QUIT_REQUESTED);
184 	} else {
185 		if (fSuppressFirstClose && !active) {
186 			fSuppressFirstClose = false;
187 			return;
188 		}
189 
190 		if (!fSuppressFirstClose && !active)
191 			PostMessage(B_QUIT_REQUESTED);
192 	}
193 }
194 
195 
196 void
197 CalendarMenuWindow::MessageReceived(BMessage* message)
198 {
199 	switch (message->what) {
200 		case kInvokationMessage:
201 		{
202 			int32 day, month, year;
203 			message->FindInt32("day", &day);
204 			message->FindInt32("month", &month);
205 			message->FindInt32("year", &year);
206 
207 			_UpdateUI(BDate(year, month, day));
208 			break;
209 		}
210 
211 		case kMonthDownMessage:
212 		case kMonthUpMessage:
213 		{
214 			BDate date = fCalendarView->Date();
215 
216 			int32 day = date.Day();
217 			int32 year = date.Year();
218 			int32 month = date.Month();
219 
220 			month += (kMonthDownMessage == message->what) ? -1 : 1;
221 			if (month < 1) {
222 				year--;
223 				month = 12;
224 			} else if (month > 12) {
225 				year++;
226 				month = 1;
227 			}
228 			date.SetDate(year, month, day);
229 
230 			if (day > date.DaysInMonth())
231 				day = date.DaysInMonth();
232 
233 			_UpdateUI(BDate(year, month, day));
234 			break;
235 		}
236 
237 		case kYearDownMessage:
238 		case kYearUpMessage:
239 		{
240 			BDate date = fCalendarView->Date();
241 			int32 i = kYearDownMessage == message->what ? -1 : 1;
242 			_UpdateUI(BDate(date.Year() + i, date.Month(), date.Day()));
243 			break;
244 		}
245 
246 		default:
247 			BWindow::MessageReceived(message);
248 			break;
249 	}
250 }
251 
252 
253 void
254 CalendarMenuWindow::_UpdateUI(const BDate& date)
255 {
256 	if (!date.IsValid())
257 		return;
258 
259 	fCalendarView->SetDate(date);
260 
261 	BString text;
262 	text << date.Year();
263 	fYearLabel->SetText(text.String());
264 
265 	fMonthLabel->SetText(date.LongMonthName(date.Month()).String());
266 }
267 
268 
269 BButton*
270 CalendarMenuWindow::_SetupButton(const char* label, uint32 what, float height)
271 {
272 	FlatButton* button = new FlatButton(label, what);
273 	button->SetExplicitMinSize(BSize(height, height));
274 	button->SetFontSize(be_plain_font->Size() * 0.8);
275 
276 	return button;
277 }
278 
279