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_MOVABLE | B_NOT_RESIZABLE
83			| B_NOT_ZOOMABLE),
84	fYearLabel(NULL),
85	fMonthLabel(NULL),
86	fCalendarView(NULL),
87	fSuppressFirstClose(true)
88{
89	SetFeel(B_FLOATING_ALL_WINDOW_FEEL);
90
91	RemoveShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY);
92	AddShortcut('W', B_COMMAND_KEY, new BMessage(B_QUIT_REQUESTED));
93
94	fYearLabel = new BStringView("year", "");
95	fMonthLabel = new BStringView("month", "");
96
97	fCalendarView = new BCalendarView(Bounds(), "calendar", B_FOLLOW_ALL);
98	fCalendarView->SetInvocationMessage(new BMessage(kInvokationMessage));
99
100	BGroupLayout* layout = new BGroupLayout(B_HORIZONTAL);
101	SetLayout(layout);
102
103	float width, height;
104	fMonthLabel->GetPreferredSize(&width, &height);
105
106	BGridLayout* gridLayout = BGridLayoutBuilder(5.0)
107		.Add(_SetupButton("-", kMonthDownMessage, height), 0, 0)
108		.Add(fMonthLabel, 1, 0)
109		.Add(_SetupButton("+", kMonthUpMessage, height), 2, 0)
110		.Add(BSpaceLayoutItem::CreateGlue(), 3, 0)
111		.Add(_SetupButton("-", kYearDownMessage, height), 4, 0)
112		.Add(fYearLabel, 5, 0)
113		.Add(_SetupButton("+", kYearUpMessage, height), 6, 0)
114		.SetInsets(5.0, 0.0, 5.0, 0.0);
115	gridLayout->SetMinColumnWidth(1, be_plain_font->StringWidth("September"));
116
117	BGroupView* groupView = new BGroupView(B_VERTICAL, 10.0);
118	BView* view = BGroupLayoutBuilder(B_VERTICAL, 5.0)
119		.Add(gridLayout->View())
120		.Add(fCalendarView)
121		.SetInsets(5.0, 5.0, 5.0, 5.0)
122		.TopView();
123	groupView->AddChild(view);
124	AddChild(groupView);
125
126	MoveTo(where);
127	_UpdateDate(BDate::CurrentDate(B_LOCAL_TIME));
128}
129
130
131CalendarMenuWindow::~CalendarMenuWindow()
132{
133}
134
135
136void
137CalendarMenuWindow::Show()
138{
139	BRect screen(BScreen().Frame());
140
141	float right = screen.right;
142	float bottom = screen.bottom;
143
144	BRect rightTop(right / 2.0, screen.top, right, bottom / 2.0);
145	BRect rightBottom(right / 2.0, bottom / 2.0, right + 1.0, bottom + 1.0);
146	BRect leftBottom(screen.left, bottom / 2.0, right / 2.0, bottom + 1.0);
147
148	BPoint where = Frame().LeftTop();
149	BSize size = GetLayout()->PreferredSize();
150
151	if (rightTop.Contains(where)) {
152		where.x -= size.width;
153	} else if (leftBottom.Contains(where)) {
154		where.y -= (size.height + 4.0);
155	} else if (rightBottom.Contains(where)) {
156		where.x -= size.width;
157		where.y -= (size.height + 4.0);
158	}
159
160	MoveTo(where);
161	fCalendarView->MakeFocus(true);
162
163	BWindow::Show();
164}
165
166
167void
168CalendarMenuWindow::WindowActivated(bool active)
169{
170	if (active)
171		return;
172
173	if (mouse_mode() != B_FOCUS_FOLLOWS_MOUSE) {
174		if (!active)
175			PostMessage(B_QUIT_REQUESTED);
176	} else {
177		if (fSuppressFirstClose && !active) {
178			fSuppressFirstClose = false;
179			return;
180		}
181
182		if (!fSuppressFirstClose && !active)
183			PostMessage(B_QUIT_REQUESTED);
184	}
185}
186
187
188void
189CalendarMenuWindow::MessageReceived(BMessage* message)
190{
191	switch (message->what) {
192		case kInvokationMessage:
193		{
194			int32 day, month, year;
195			message->FindInt32("day", &day);
196			message->FindInt32("month", &month);
197			message->FindInt32("year", &year);
198
199			_UpdateDate(BDate(year, month, day));
200			break;
201		}
202
203		case kMonthDownMessage:
204		case kMonthUpMessage:
205		{
206			BDate date = fCalendarView->Date();
207			date.AddMonths(kMonthDownMessage == message->what ? -1 : 1);
208			_UpdateDate(date);
209			break;
210		}
211
212		case kYearDownMessage:
213		case kYearUpMessage:
214		{
215			BDate date = fCalendarView->Date();
216			date.AddYears(kYearDownMessage == message->what ? -1 : 1);
217			_UpdateDate(date);
218			break;
219		}
220
221		default:
222			BWindow::MessageReceived(message);
223			break;
224	}
225}
226
227
228void
229CalendarMenuWindow::_UpdateDate(const BDate& date)
230{
231	if (!date.IsValid())
232		return;
233
234	fCalendarView->SetDate(date);
235
236	BString text;
237	text << date.Year();
238	fYearLabel->SetText(text.String());
239
240	fMonthLabel->SetText(date.LongMonthName(date.Month()).String());
241}
242
243
244BButton*
245CalendarMenuWindow::_SetupButton(const char* label, uint32 what, float height)
246{
247	FlatButton* button = new FlatButton(label, what);
248	button->SetExplicitMinSize(BSize(height, height));
249
250	return button;
251}
252