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