xref: /haiku/src/kits/shared/CalendarView.cpp (revision 6846765fbf83f501df7ab9b10811971cbb5375a3)
178092ae7SKarsten Heimrich /*
2c8b61804SAxel Dörfler  * Copyright 2007-2011, Haiku, Inc. All Rights Reserved.
378092ae7SKarsten Heimrich  * Distributed under the terms of the MIT License.
478092ae7SKarsten Heimrich  *
578092ae7SKarsten Heimrich  * Authors:
678092ae7SKarsten Heimrich  *		Julun <host.haiku@gmx.de>
778092ae7SKarsten Heimrich  */
878092ae7SKarsten Heimrich 
91b3303e7SAxel Dörfler 
1078092ae7SKarsten Heimrich #include "CalendarView.h"
1178092ae7SKarsten Heimrich 
121b3303e7SAxel Dörfler #include <stdlib.h>
1378092ae7SKarsten Heimrich 
142530274dSRyan Leavengood #include <LayoutUtils.h>
1578092ae7SKarsten Heimrich #include <Window.h>
1678092ae7SKarsten Heimrich 
1778092ae7SKarsten Heimrich 
1878092ae7SKarsten Heimrich namespace BPrivate {
1978092ae7SKarsten Heimrich 
201b3303e7SAxel Dörfler 
21c8b61804SAxel Dörfler static float
2278092ae7SKarsten Heimrich FontHeight(const BView* view)
2378092ae7SKarsten Heimrich {
2478092ae7SKarsten Heimrich 	if (!view)
2578092ae7SKarsten Heimrich 		return 0.0;
2678092ae7SKarsten Heimrich 
2778092ae7SKarsten Heimrich 	BFont font;
2878092ae7SKarsten Heimrich 	view->GetFont(&font);
2978092ae7SKarsten Heimrich 	font_height fheight;
3078092ae7SKarsten Heimrich 	font.GetHeight(&fheight);
3178092ae7SKarsten Heimrich 	return ceilf(fheight.ascent + fheight.descent + fheight.leading);
3278092ae7SKarsten Heimrich }
331b3303e7SAxel Dörfler 
34c8b61804SAxel Dörfler 
35c8b61804SAxel Dörfler // #pragma mark -
3678092ae7SKarsten Heimrich 
3778092ae7SKarsten Heimrich 
38*6846765fSOliver Tappe BCalendarView::BCalendarView(BRect frame, const char* name, uint32 resizeMask,
39*6846765fSOliver Tappe 	uint32 flags)
401b3303e7SAxel Dörfler 	:
411b3303e7SAxel Dörfler 	BView(frame, name, resizeMask, flags),
4278092ae7SKarsten Heimrich 	BInvoker(),
4378092ae7SKarsten Heimrich 	fSelectionMessage(NULL),
44*6846765fSOliver Tappe 	fDate(),
4578092ae7SKarsten Heimrich 	fFocusChanged(false),
4678092ae7SKarsten Heimrich 	fSelectionChanged(false),
47*6846765fSOliver Tappe 	fStartOfWeek((int32)B_WEEKDAY_MONDAY),
4878092ae7SKarsten Heimrich 	fDayNameHeaderVisible(true),
4978092ae7SKarsten Heimrich 	fWeekNumberHeaderVisible(true)
5078092ae7SKarsten Heimrich {
5178092ae7SKarsten Heimrich 	_InitObject();
5278092ae7SKarsten Heimrich }
5378092ae7SKarsten Heimrich 
5478092ae7SKarsten Heimrich 
552530274dSRyan Leavengood BCalendarView::BCalendarView(const char* name, uint32 flags)
562530274dSRyan Leavengood 	:
572530274dSRyan Leavengood 	BView(name, flags),
582530274dSRyan Leavengood 	BInvoker(),
592530274dSRyan Leavengood 	fSelectionMessage(NULL),
60*6846765fSOliver Tappe 	fDate(),
612530274dSRyan Leavengood 	fFocusChanged(false),
622530274dSRyan Leavengood 	fSelectionChanged(false),
63*6846765fSOliver Tappe 	fStartOfWeek((int32)B_WEEKDAY_MONDAY),
641e07062bSOliver Tappe 	fDayNameHeaderVisible(true),
651e07062bSOliver Tappe 	fWeekNumberHeaderVisible(true)
661e07062bSOliver Tappe {
671e07062bSOliver Tappe 	_InitObject();
681e07062bSOliver Tappe }
691e07062bSOliver Tappe 
701e07062bSOliver Tappe 
7178092ae7SKarsten Heimrich BCalendarView::~BCalendarView()
7278092ae7SKarsten Heimrich {
7378092ae7SKarsten Heimrich 	SetSelectionMessage(NULL);
7478092ae7SKarsten Heimrich }
7578092ae7SKarsten Heimrich 
7678092ae7SKarsten Heimrich 
7778092ae7SKarsten Heimrich BCalendarView::BCalendarView(BMessage* archive)
781b3303e7SAxel Dörfler 	:
791b3303e7SAxel Dörfler 	BView(archive),
8078092ae7SKarsten Heimrich 	BInvoker(),
8178092ae7SKarsten Heimrich 	fSelectionMessage(NULL),
82*6846765fSOliver Tappe 	fDate(archive),
8378092ae7SKarsten Heimrich 	fFocusChanged(false),
8478092ae7SKarsten Heimrich 	fSelectionChanged(false),
85*6846765fSOliver Tappe 	fStartOfWeek((int32)B_WEEKDAY_MONDAY),
8678092ae7SKarsten Heimrich 	fDayNameHeaderVisible(true),
8778092ae7SKarsten Heimrich 	fWeekNumberHeaderVisible(true)
8878092ae7SKarsten Heimrich {
8978092ae7SKarsten Heimrich 	if (archive->HasMessage("_invokeMsg")) {
9078092ae7SKarsten Heimrich 		BMessage* invokationMessage = new BMessage;
9178092ae7SKarsten Heimrich 		archive->FindMessage("_invokeMsg", invokationMessage);
9278092ae7SKarsten Heimrich 		SetInvocationMessage(invokationMessage);
9378092ae7SKarsten Heimrich 	}
9478092ae7SKarsten Heimrich 
9578092ae7SKarsten Heimrich 	if (archive->HasMessage("_selectMsg")) {
9678092ae7SKarsten Heimrich 		BMessage* selectionMessage = new BMessage;
9778092ae7SKarsten Heimrich 		archive->FindMessage("selectMsg", selectionMessage);
9878092ae7SKarsten Heimrich 		SetSelectionMessage(selectionMessage);
9978092ae7SKarsten Heimrich 	}
10078092ae7SKarsten Heimrich 
101*6846765fSOliver Tappe 	if (archive->FindInt32("_weekStart", &fStartOfWeek) != B_OK)
102*6846765fSOliver Tappe 		fStartOfWeek = (int32)B_WEEKDAY_MONDAY;
10378092ae7SKarsten Heimrich 
10478092ae7SKarsten Heimrich 	if (archive->FindBool("_dayHeader", &fDayNameHeaderVisible) != B_OK)
10578092ae7SKarsten Heimrich 		fDayNameHeaderVisible = true;
10678092ae7SKarsten Heimrich 
10778092ae7SKarsten Heimrich 	if (archive->FindBool("_weekHeader", &fWeekNumberHeaderVisible) != B_OK)
10878092ae7SKarsten Heimrich 		fWeekNumberHeaderVisible = true;
10978092ae7SKarsten Heimrich 
11078092ae7SKarsten Heimrich 	_SetupDayNames();
11178092ae7SKarsten Heimrich 	_SetupDayNumbers();
11278092ae7SKarsten Heimrich 	_SetupWeekNumbers();
11378092ae7SKarsten Heimrich }
11478092ae7SKarsten Heimrich 
11578092ae7SKarsten Heimrich 
11678092ae7SKarsten Heimrich BArchivable*
11778092ae7SKarsten Heimrich BCalendarView::Instantiate(BMessage* archive)
11878092ae7SKarsten Heimrich {
11978092ae7SKarsten Heimrich 	if (validate_instantiation(archive, "BCalendarView"))
12078092ae7SKarsten Heimrich 		return new BCalendarView(archive);
12178092ae7SKarsten Heimrich 
12278092ae7SKarsten Heimrich 	return NULL;
12378092ae7SKarsten Heimrich }
12478092ae7SKarsten Heimrich 
12578092ae7SKarsten Heimrich 
12678092ae7SKarsten Heimrich status_t
12778092ae7SKarsten Heimrich BCalendarView::Archive(BMessage* archive, bool deep) const
12878092ae7SKarsten Heimrich {
12978092ae7SKarsten Heimrich 	status_t status = BView::Archive(archive, deep);
13078092ae7SKarsten Heimrich 
13178092ae7SKarsten Heimrich 	if (status == B_OK && InvocationMessage())
13278092ae7SKarsten Heimrich 		status = archive->AddMessage("_invokeMsg", InvocationMessage());
13378092ae7SKarsten Heimrich 
13478092ae7SKarsten Heimrich 	if (status == B_OK && SelectionMessage())
13578092ae7SKarsten Heimrich 		status = archive->AddMessage("_selectMsg", SelectionMessage());
13678092ae7SKarsten Heimrich 
13778092ae7SKarsten Heimrich 	if (status == B_OK)
138*6846765fSOliver Tappe 		status = fDate.Archive(archive);
13978092ae7SKarsten Heimrich 
14078092ae7SKarsten Heimrich 	if (status == B_OK)
141*6846765fSOliver Tappe 		status = archive->AddInt32("_weekStart", fStartOfWeek);
14278092ae7SKarsten Heimrich 
14378092ae7SKarsten Heimrich 	if (status == B_OK)
14478092ae7SKarsten Heimrich 		status = archive->AddBool("_dayHeader", fDayNameHeaderVisible);
14578092ae7SKarsten Heimrich 
14678092ae7SKarsten Heimrich 	if (status == B_OK)
14778092ae7SKarsten Heimrich 		status = archive->AddBool("_weekHeader", fWeekNumberHeaderVisible);
14878092ae7SKarsten Heimrich 
14978092ae7SKarsten Heimrich 	return status;
15078092ae7SKarsten Heimrich }
15178092ae7SKarsten Heimrich 
15278092ae7SKarsten Heimrich 
15378092ae7SKarsten Heimrich void
15478092ae7SKarsten Heimrich BCalendarView::AttachedToWindow()
15578092ae7SKarsten Heimrich {
15678092ae7SKarsten Heimrich 	BView::AttachedToWindow();
15778092ae7SKarsten Heimrich 
15878092ae7SKarsten Heimrich 	if (!Messenger().IsValid())
15978092ae7SKarsten Heimrich 		SetTarget(Window(), NULL);
16078092ae7SKarsten Heimrich }
16178092ae7SKarsten Heimrich 
16278092ae7SKarsten Heimrich 
16378092ae7SKarsten Heimrich void
16478092ae7SKarsten Heimrich BCalendarView::FrameResized(float width, float height)
16578092ae7SKarsten Heimrich {
16678092ae7SKarsten Heimrich 	Invalidate(Bounds());
16778092ae7SKarsten Heimrich }
16878092ae7SKarsten Heimrich 
16978092ae7SKarsten Heimrich 
17078092ae7SKarsten Heimrich void
17178092ae7SKarsten Heimrich BCalendarView::Draw(BRect updateRect)
17278092ae7SKarsten Heimrich {
17378092ae7SKarsten Heimrich 	if (LockLooper()) {
17478092ae7SKarsten Heimrich 		if (fFocusChanged) {
17578092ae7SKarsten Heimrich 			_DrawFocusRect();
17678092ae7SKarsten Heimrich 			UnlockLooper();
17778092ae7SKarsten Heimrich 			return;
17878092ae7SKarsten Heimrich 		}
17978092ae7SKarsten Heimrich 
18078092ae7SKarsten Heimrich 		if (fSelectionChanged) {
18178092ae7SKarsten Heimrich 			_UpdateSelection();
18278092ae7SKarsten Heimrich 			UnlockLooper();
18378092ae7SKarsten Heimrich 			return;
18478092ae7SKarsten Heimrich 		}
18578092ae7SKarsten Heimrich 
18678092ae7SKarsten Heimrich 		_DrawDays();
18778092ae7SKarsten Heimrich 		_DrawDayHeader();
18878092ae7SKarsten Heimrich 		_DrawWeekHeader();
18978092ae7SKarsten Heimrich 
19078092ae7SKarsten Heimrich 		rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
19178092ae7SKarsten Heimrich 		SetHighColor(tint_color(background, B_DARKEN_3_TINT));
19278092ae7SKarsten Heimrich 		StrokeRect(Bounds());
19378092ae7SKarsten Heimrich 
19478092ae7SKarsten Heimrich 		UnlockLooper();
19578092ae7SKarsten Heimrich 	}
19678092ae7SKarsten Heimrich }
19778092ae7SKarsten Heimrich 
19878092ae7SKarsten Heimrich 
19978092ae7SKarsten Heimrich void
20078092ae7SKarsten Heimrich BCalendarView::DrawDay(BView* owner, BRect frame, const char* text,
20178092ae7SKarsten Heimrich 	bool isSelected, bool isEnabled, bool focus)
20278092ae7SKarsten Heimrich {
20378092ae7SKarsten Heimrich 	_DrawItem(owner, frame, text, isSelected, isEnabled, focus);
20478092ae7SKarsten Heimrich }
20578092ae7SKarsten Heimrich 
20678092ae7SKarsten Heimrich 
20778092ae7SKarsten Heimrich void
20878092ae7SKarsten Heimrich BCalendarView::DrawDayName(BView* owner, BRect frame, const char* text)
20978092ae7SKarsten Heimrich {
21078092ae7SKarsten Heimrich 	// we get the full rect, fake this as the internal function
21178092ae7SKarsten Heimrich 	// shrinks the frame to work properly when drawing a day item
21278092ae7SKarsten Heimrich 	_DrawItem(owner, frame.InsetByCopy(-1.0, -1.0), text, true);
21378092ae7SKarsten Heimrich }
21478092ae7SKarsten Heimrich 
21578092ae7SKarsten Heimrich 
21678092ae7SKarsten Heimrich void
21778092ae7SKarsten Heimrich BCalendarView::DrawWeekNumber(BView* owner, BRect frame, const char* text)
21878092ae7SKarsten Heimrich {
21978092ae7SKarsten Heimrich 	// we get the full rect, fake this as the internal function
22078092ae7SKarsten Heimrich 	// shrinks the frame to work properly when drawing a day item
22178092ae7SKarsten Heimrich 	_DrawItem(owner, frame.InsetByCopy(-1.0, -1.0), text, true);
22278092ae7SKarsten Heimrich }
22378092ae7SKarsten Heimrich 
22478092ae7SKarsten Heimrich 
22578092ae7SKarsten Heimrich uint32
22678092ae7SKarsten Heimrich BCalendarView::SelectionCommand() const
22778092ae7SKarsten Heimrich {
22878092ae7SKarsten Heimrich 	if (SelectionMessage())
22978092ae7SKarsten Heimrich 		return SelectionMessage()->what;
23078092ae7SKarsten Heimrich 
23178092ae7SKarsten Heimrich 	return 0;
23278092ae7SKarsten Heimrich }
23378092ae7SKarsten Heimrich 
23478092ae7SKarsten Heimrich 
23578092ae7SKarsten Heimrich BMessage*
23678092ae7SKarsten Heimrich BCalendarView::SelectionMessage() const
23778092ae7SKarsten Heimrich {
23878092ae7SKarsten Heimrich 	return fSelectionMessage;
23978092ae7SKarsten Heimrich }
24078092ae7SKarsten Heimrich 
24178092ae7SKarsten Heimrich 
24278092ae7SKarsten Heimrich void
24378092ae7SKarsten Heimrich BCalendarView::SetSelectionMessage(BMessage* message)
24478092ae7SKarsten Heimrich {
24578092ae7SKarsten Heimrich 	delete fSelectionMessage;
24678092ae7SKarsten Heimrich 	fSelectionMessage = message;
24778092ae7SKarsten Heimrich }
24878092ae7SKarsten Heimrich 
24978092ae7SKarsten Heimrich 
25078092ae7SKarsten Heimrich uint32
25178092ae7SKarsten Heimrich BCalendarView::InvocationCommand() const
25278092ae7SKarsten Heimrich {
25378092ae7SKarsten Heimrich 	return BInvoker::Command();
25478092ae7SKarsten Heimrich }
25578092ae7SKarsten Heimrich 
25678092ae7SKarsten Heimrich 
25778092ae7SKarsten Heimrich BMessage*
25878092ae7SKarsten Heimrich BCalendarView::InvocationMessage() const
25978092ae7SKarsten Heimrich {
26078092ae7SKarsten Heimrich 	return BInvoker::Message();
26178092ae7SKarsten Heimrich }
26278092ae7SKarsten Heimrich 
26378092ae7SKarsten Heimrich 
26478092ae7SKarsten Heimrich void
26578092ae7SKarsten Heimrich BCalendarView::SetInvocationMessage(BMessage* message)
26678092ae7SKarsten Heimrich {
26778092ae7SKarsten Heimrich 	BInvoker::SetMessage(message);
26878092ae7SKarsten Heimrich }
26978092ae7SKarsten Heimrich 
27078092ae7SKarsten Heimrich 
27178092ae7SKarsten Heimrich void
27278092ae7SKarsten Heimrich BCalendarView::MakeFocus(bool state)
27378092ae7SKarsten Heimrich {
27478092ae7SKarsten Heimrich 	if (IsFocus() == state)
27578092ae7SKarsten Heimrich 		return;
27678092ae7SKarsten Heimrich 
27778092ae7SKarsten Heimrich 	BView::MakeFocus(state);
27878092ae7SKarsten Heimrich 
2791b3303e7SAxel Dörfler 	// TODO: solve this better
28078092ae7SKarsten Heimrich 	fFocusChanged = true;
28178092ae7SKarsten Heimrich 	Draw(_RectOfDay(fFocusedDay));
28278092ae7SKarsten Heimrich 	fFocusChanged = false;
28378092ae7SKarsten Heimrich }
28478092ae7SKarsten Heimrich 
28578092ae7SKarsten Heimrich 
28678092ae7SKarsten Heimrich status_t
28778092ae7SKarsten Heimrich BCalendarView::Invoke(BMessage* message)
28878092ae7SKarsten Heimrich {
28978092ae7SKarsten Heimrich 	bool notify = false;
29078092ae7SKarsten Heimrich 	uint32 kind = InvokeKind(&notify);
29178092ae7SKarsten Heimrich 
29278092ae7SKarsten Heimrich 	BMessage clone(kind);
29378092ae7SKarsten Heimrich 	status_t status = B_BAD_VALUE;
29478092ae7SKarsten Heimrich 
29578092ae7SKarsten Heimrich 	if (!message && !notify)
29678092ae7SKarsten Heimrich 		message = Message();
29778092ae7SKarsten Heimrich 
29878092ae7SKarsten Heimrich 	if (!message) {
29978092ae7SKarsten Heimrich 		if (!IsWatched())
30078092ae7SKarsten Heimrich 			return status;
30178092ae7SKarsten Heimrich 	} else
30278092ae7SKarsten Heimrich 		clone = *message;
30378092ae7SKarsten Heimrich 
30478092ae7SKarsten Heimrich 	clone.AddPointer("source", this);
30578092ae7SKarsten Heimrich 	clone.AddInt64("when", (int64)system_time());
30678092ae7SKarsten Heimrich 	clone.AddMessenger("be:sender", BMessenger(this));
30778092ae7SKarsten Heimrich 
30878092ae7SKarsten Heimrich 	int32 year;
30978092ae7SKarsten Heimrich 	int32 month;
310*6846765fSOliver Tappe 	_GetYearMonthForSelection(fSelectedDay, &year, &month);
31178092ae7SKarsten Heimrich 
312*6846765fSOliver Tappe 	clone.AddInt32("year", fDate.Year());
313*6846765fSOliver Tappe 	clone.AddInt32("month", fDate.Month());
314*6846765fSOliver Tappe 	clone.AddInt32("day", fDate.Day());
31578092ae7SKarsten Heimrich 
31678092ae7SKarsten Heimrich 	if (message)
31778092ae7SKarsten Heimrich 		status = BInvoker::Invoke(&clone);
31878092ae7SKarsten Heimrich 
31978092ae7SKarsten Heimrich 	SendNotices(kind, &clone);
32078092ae7SKarsten Heimrich 
32178092ae7SKarsten Heimrich 	return status;
32278092ae7SKarsten Heimrich }
32378092ae7SKarsten Heimrich 
32478092ae7SKarsten Heimrich 
32578092ae7SKarsten Heimrich void
32678092ae7SKarsten Heimrich BCalendarView::MouseDown(BPoint where)
32778092ae7SKarsten Heimrich {
32878092ae7SKarsten Heimrich 	if (!IsFocus()) {
32978092ae7SKarsten Heimrich 		MakeFocus();
33078092ae7SKarsten Heimrich 		Sync();
33178092ae7SKarsten Heimrich 		Window()->UpdateIfNeeded();
33278092ae7SKarsten Heimrich 	}
33378092ae7SKarsten Heimrich 
33478092ae7SKarsten Heimrich 	BRect frame = Bounds();
33578092ae7SKarsten Heimrich 	if (fDayNameHeaderVisible)
33678092ae7SKarsten Heimrich 		frame.top += frame.Height() / 7 - 1.0;
33778092ae7SKarsten Heimrich 
33878092ae7SKarsten Heimrich 	if (fWeekNumberHeaderVisible)
33978092ae7SKarsten Heimrich 		frame.left += frame.Width() / 8 - 1.0;
34078092ae7SKarsten Heimrich 
34178092ae7SKarsten Heimrich 	if (!frame.Contains(where))
34278092ae7SKarsten Heimrich 		return;
34378092ae7SKarsten Heimrich 
34478092ae7SKarsten Heimrich 	// try to set to new day
34578092ae7SKarsten Heimrich 	frame = _SetNewSelectedDay(where);
34678092ae7SKarsten Heimrich 
34778092ae7SKarsten Heimrich 	// on success
34878092ae7SKarsten Heimrich 	if (fSelectedDay != fNewSelectedDay) {
34978092ae7SKarsten Heimrich 		// update focus
35078092ae7SKarsten Heimrich 		fFocusChanged = true;
35178092ae7SKarsten Heimrich 		fNewFocusedDay = fNewSelectedDay;
35278092ae7SKarsten Heimrich 		Draw(_RectOfDay(fFocusedDay));
35378092ae7SKarsten Heimrich 		fFocusChanged = false;
35478092ae7SKarsten Heimrich 
35578092ae7SKarsten Heimrich 		// update selection
35678092ae7SKarsten Heimrich 		fSelectionChanged = true;
35778092ae7SKarsten Heimrich 		Draw(frame);
35878092ae7SKarsten Heimrich 		Draw(_RectOfDay(fSelectedDay));
35978092ae7SKarsten Heimrich 		fSelectionChanged = false;
36078092ae7SKarsten Heimrich 
36178092ae7SKarsten Heimrich 		// notify that selection changed
36278092ae7SKarsten Heimrich 		InvokeNotify(SelectionMessage(), B_CONTROL_MODIFIED);
36378092ae7SKarsten Heimrich 	}
36478092ae7SKarsten Heimrich 
36578092ae7SKarsten Heimrich 	int32 clicks;
36678092ae7SKarsten Heimrich 	// on double click invoke
36778092ae7SKarsten Heimrich 	BMessage* message = Looper()->CurrentMessage();
36878092ae7SKarsten Heimrich 	if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1)
36978092ae7SKarsten Heimrich 		Invoke();
37078092ae7SKarsten Heimrich }
37178092ae7SKarsten Heimrich 
37278092ae7SKarsten Heimrich 
37378092ae7SKarsten Heimrich void
37478092ae7SKarsten Heimrich BCalendarView::KeyDown(const char* bytes, int32 numBytes)
37578092ae7SKarsten Heimrich {
37678092ae7SKarsten Heimrich 	const int32 kRows = 6;
37778092ae7SKarsten Heimrich 	const int32 kColumns = 7;
37878092ae7SKarsten Heimrich 
37978092ae7SKarsten Heimrich 	int32 row = fFocusedDay.row;
38078092ae7SKarsten Heimrich 	int32 column = fFocusedDay.column;
38178092ae7SKarsten Heimrich 
38278092ae7SKarsten Heimrich 	switch (bytes[0]) {
38378092ae7SKarsten Heimrich 		case B_LEFT_ARROW:
38478092ae7SKarsten Heimrich 			column -= 1;
38578092ae7SKarsten Heimrich 			if (column < 0) {
38678092ae7SKarsten Heimrich 				column = kColumns - 1;
38778092ae7SKarsten Heimrich 				row -= 1;
38878092ae7SKarsten Heimrich 				if (row >= 0)
38978092ae7SKarsten Heimrich 					fFocusChanged = true;
39078092ae7SKarsten Heimrich 			} else
39178092ae7SKarsten Heimrich 				fFocusChanged = true;
392*6846765fSOliver Tappe 			break;
39378092ae7SKarsten Heimrich 
39478092ae7SKarsten Heimrich 		case B_RIGHT_ARROW:
39578092ae7SKarsten Heimrich 			column += 1;
39678092ae7SKarsten Heimrich 			if (column == kColumns) {
39778092ae7SKarsten Heimrich 				column = 0;
39878092ae7SKarsten Heimrich 				row += 1;
39978092ae7SKarsten Heimrich 				if (row < kRows)
40078092ae7SKarsten Heimrich 					fFocusChanged = true;
40178092ae7SKarsten Heimrich 			} else
40278092ae7SKarsten Heimrich 				fFocusChanged = true;
403*6846765fSOliver Tappe 			break;
40478092ae7SKarsten Heimrich 
40578092ae7SKarsten Heimrich 		case B_UP_ARROW:
40678092ae7SKarsten Heimrich 			row -= 1;
40778092ae7SKarsten Heimrich 			if (row >= 0)
40878092ae7SKarsten Heimrich 				fFocusChanged = true;
409*6846765fSOliver Tappe 			break;
41078092ae7SKarsten Heimrich 
41178092ae7SKarsten Heimrich 		case B_DOWN_ARROW:
41278092ae7SKarsten Heimrich 			row += 1;
41378092ae7SKarsten Heimrich 			if (row < kRows)
41478092ae7SKarsten Heimrich 				fFocusChanged = true;
415*6846765fSOliver Tappe 			break;
416*6846765fSOliver Tappe 
417*6846765fSOliver Tappe 		case B_PAGE_UP:
418*6846765fSOliver Tappe 		{
419*6846765fSOliver Tappe 			BDate date(fDate);
420*6846765fSOliver Tappe 			date.AddMonths(-1);
421*6846765fSOliver Tappe 			SetDate(date);
422*6846765fSOliver Tappe 
423*6846765fSOliver Tappe 			Invoke();
424*6846765fSOliver Tappe 			break;
425*6846765fSOliver Tappe 		}
426*6846765fSOliver Tappe 
427*6846765fSOliver Tappe 		case B_PAGE_DOWN:
428*6846765fSOliver Tappe 		{
429*6846765fSOliver Tappe 			BDate date(fDate);
430*6846765fSOliver Tappe 			date.AddMonths(1);
431*6846765fSOliver Tappe 			SetDate(date);
432*6846765fSOliver Tappe 
433*6846765fSOliver Tappe 			Invoke();
434*6846765fSOliver Tappe 			break;
435*6846765fSOliver Tappe 		}
43678092ae7SKarsten Heimrich 
43778092ae7SKarsten Heimrich 		case B_RETURN:
438*6846765fSOliver Tappe 		case B_SPACE:
439*6846765fSOliver Tappe 		{
44078092ae7SKarsten Heimrich 			fSelectionChanged = true;
44178092ae7SKarsten Heimrich 			BPoint pt = _RectOfDay(fFocusedDay).LeftTop();
44278092ae7SKarsten Heimrich 			Draw(_SetNewSelectedDay(pt + BPoint(4.0, 4.0)));
44378092ae7SKarsten Heimrich 			Draw(_RectOfDay(fSelectedDay));
44478092ae7SKarsten Heimrich 			fSelectionChanged = false;
44578092ae7SKarsten Heimrich 
44678092ae7SKarsten Heimrich 			Invoke();
447*6846765fSOliver Tappe 			break;
448*6846765fSOliver Tappe 		}
44978092ae7SKarsten Heimrich 
45078092ae7SKarsten Heimrich 		default:
45178092ae7SKarsten Heimrich 			BView::KeyDown(bytes, numBytes);
45278092ae7SKarsten Heimrich 			break;
45378092ae7SKarsten Heimrich 	}
45478092ae7SKarsten Heimrich 
45578092ae7SKarsten Heimrich 	if (fFocusChanged) {
45678092ae7SKarsten Heimrich 		fNewFocusedDay.SetTo(row, column);
45778092ae7SKarsten Heimrich 		Draw(_RectOfDay(fFocusedDay));
45878092ae7SKarsten Heimrich 		Draw(_RectOfDay(fNewFocusedDay));
45978092ae7SKarsten Heimrich 		fFocusChanged = false;
46078092ae7SKarsten Heimrich 	}
46178092ae7SKarsten Heimrich }
46278092ae7SKarsten Heimrich 
46378092ae7SKarsten Heimrich 
46478092ae7SKarsten Heimrich void
46578092ae7SKarsten Heimrich BCalendarView::ResizeToPreferred()
46678092ae7SKarsten Heimrich {
46778092ae7SKarsten Heimrich 	float width;
46878092ae7SKarsten Heimrich 	float height;
46978092ae7SKarsten Heimrich 
47078092ae7SKarsten Heimrich 	GetPreferredSize(&width, &height);
47178092ae7SKarsten Heimrich 	BView::ResizeTo(width, height);
47278092ae7SKarsten Heimrich }
47378092ae7SKarsten Heimrich 
47478092ae7SKarsten Heimrich 
47578092ae7SKarsten Heimrich void
47678092ae7SKarsten Heimrich BCalendarView::GetPreferredSize(float* width, float* height)
47778092ae7SKarsten Heimrich {
47878092ae7SKarsten Heimrich 	_GetPreferredSize(width, height);
47978092ae7SKarsten Heimrich }
48078092ae7SKarsten Heimrich 
48178092ae7SKarsten Heimrich 
4822530274dSRyan Leavengood BSize
4832530274dSRyan Leavengood BCalendarView::MaxSize()
4842530274dSRyan Leavengood {
4852530274dSRyan Leavengood 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
4862530274dSRyan Leavengood 		BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
4872530274dSRyan Leavengood }
4882530274dSRyan Leavengood 
4892530274dSRyan Leavengood 
4902530274dSRyan Leavengood BSize
4912530274dSRyan Leavengood BCalendarView::MinSize()
4922530274dSRyan Leavengood {
4932530274dSRyan Leavengood 	float width, height;
4942530274dSRyan Leavengood 	_GetPreferredSize(&width, &height);
495*6846765fSOliver Tappe 	return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(width, height));
4962530274dSRyan Leavengood }
4972530274dSRyan Leavengood 
4982530274dSRyan Leavengood 
4992530274dSRyan Leavengood BSize
5002530274dSRyan Leavengood BCalendarView::PreferredSize()
5012530274dSRyan Leavengood {
502*6846765fSOliver Tappe 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize());
5032530274dSRyan Leavengood }
5042530274dSRyan Leavengood 
5052530274dSRyan Leavengood 
50678092ae7SKarsten Heimrich int32
50778092ae7SKarsten Heimrich BCalendarView::Day() const
50878092ae7SKarsten Heimrich {
509*6846765fSOliver Tappe 	return fDate.Day();
51078092ae7SKarsten Heimrich }
51178092ae7SKarsten Heimrich 
51278092ae7SKarsten Heimrich 
51378092ae7SKarsten Heimrich int32
51478092ae7SKarsten Heimrich BCalendarView::Year() const
51578092ae7SKarsten Heimrich {
51678092ae7SKarsten Heimrich 	int32 year;
517*6846765fSOliver Tappe 	_GetYearMonthForSelection(fSelectedDay, &year, NULL);
51878092ae7SKarsten Heimrich 
51978092ae7SKarsten Heimrich 	return year;
52078092ae7SKarsten Heimrich }
52178092ae7SKarsten Heimrich 
52278092ae7SKarsten Heimrich 
52378092ae7SKarsten Heimrich int32
52478092ae7SKarsten Heimrich BCalendarView::Month() const
52578092ae7SKarsten Heimrich {
52678092ae7SKarsten Heimrich 	int32 month;
527*6846765fSOliver Tappe 	_GetYearMonthForSelection(fSelectedDay, NULL, &month);
52878092ae7SKarsten Heimrich 
52978092ae7SKarsten Heimrich 	return month;
53078092ae7SKarsten Heimrich }
53178092ae7SKarsten Heimrich 
53278092ae7SKarsten Heimrich 
53378092ae7SKarsten Heimrich BDate
53478092ae7SKarsten Heimrich BCalendarView::Date() const
53578092ae7SKarsten Heimrich {
53678092ae7SKarsten Heimrich 	int32 year;
53778092ae7SKarsten Heimrich 	int32 month;
538*6846765fSOliver Tappe 	_GetYearMonthForSelection(fSelectedDay, &year, &month);
539*6846765fSOliver Tappe 	return BDate(year, month, fDate.Day());
54078092ae7SKarsten Heimrich }
54178092ae7SKarsten Heimrich 
54278092ae7SKarsten Heimrich 
54378092ae7SKarsten Heimrich bool
54478092ae7SKarsten Heimrich BCalendarView::SetDate(const BDate& date)
54578092ae7SKarsten Heimrich {
546c1ed5d75SKarsten Heimrich 	if (!date.IsValid())
547c1ed5d75SKarsten Heimrich 		return false;
548c1ed5d75SKarsten Heimrich 
549*6846765fSOliver Tappe 	if (fDate == date)
55078092ae7SKarsten Heimrich 		return true;
55178092ae7SKarsten Heimrich 
552*6846765fSOliver Tappe 	if (fDate.Year() == date.Year() && fDate.Month() == date.Month()) {
553*6846765fSOliver Tappe 		fDate = date;
554*6846765fSOliver Tappe 
55578092ae7SKarsten Heimrich 		_SetToDay();
55678092ae7SKarsten Heimrich 		// update focus
55778092ae7SKarsten Heimrich 		fFocusChanged = true;
55878092ae7SKarsten Heimrich 		Draw(_RectOfDay(fFocusedDay));
55978092ae7SKarsten Heimrich 		fFocusChanged = false;
56078092ae7SKarsten Heimrich 
56178092ae7SKarsten Heimrich 		// update selection
56278092ae7SKarsten Heimrich 		fSelectionChanged = true;
56378092ae7SKarsten Heimrich 		Draw(_RectOfDay(fSelectedDay));
56478092ae7SKarsten Heimrich 		Draw(_RectOfDay(fNewSelectedDay));
56578092ae7SKarsten Heimrich 		fSelectionChanged = false;
56678092ae7SKarsten Heimrich 	} else {
567*6846765fSOliver Tappe 		fDate = date;
56878092ae7SKarsten Heimrich 
56978092ae7SKarsten Heimrich 		_SetupDayNumbers();
57078092ae7SKarsten Heimrich 		_SetupWeekNumbers();
57178092ae7SKarsten Heimrich 
57278092ae7SKarsten Heimrich 		BRect frame = Bounds();
57378092ae7SKarsten Heimrich 		if (fDayNameHeaderVisible)
57478092ae7SKarsten Heimrich 			frame.top += frame.Height() / 7 - 1.0;
57578092ae7SKarsten Heimrich 
57678092ae7SKarsten Heimrich 		if (fWeekNumberHeaderVisible)
57778092ae7SKarsten Heimrich 			frame.left += frame.Width() / 8 - 1.0;
57878092ae7SKarsten Heimrich 
57978092ae7SKarsten Heimrich 		Draw(frame.InsetBySelf(4.0, 4.0));
58078092ae7SKarsten Heimrich 	}
58178092ae7SKarsten Heimrich 
58278092ae7SKarsten Heimrich 	return true;
58378092ae7SKarsten Heimrich }
58478092ae7SKarsten Heimrich 
58578092ae7SKarsten Heimrich 
586*6846765fSOliver Tappe bool
587*6846765fSOliver Tappe BCalendarView::SetDate(int32 year, int32 month, int32 day)
58878092ae7SKarsten Heimrich {
589*6846765fSOliver Tappe 	return SetDate(BDate(year, month, day));
590*6846765fSOliver Tappe }
591*6846765fSOliver Tappe 
592*6846765fSOliver Tappe 
593*6846765fSOliver Tappe BWeekday
594*6846765fSOliver Tappe BCalendarView::StartOfWeek() const
595*6846765fSOliver Tappe {
596*6846765fSOliver Tappe 	return BWeekday(fStartOfWeek);
59778092ae7SKarsten Heimrich }
59878092ae7SKarsten Heimrich 
59978092ae7SKarsten Heimrich 
60078092ae7SKarsten Heimrich void
601*6846765fSOliver Tappe BCalendarView::SetStartOfWeek(BWeekday startOfWeek)
60278092ae7SKarsten Heimrich {
603*6846765fSOliver Tappe 	if (fStartOfWeek == (int32)startOfWeek)
60478092ae7SKarsten Heimrich 		return;
60578092ae7SKarsten Heimrich 
606*6846765fSOliver Tappe 	fStartOfWeek = (int32)startOfWeek;
60778092ae7SKarsten Heimrich 
60878092ae7SKarsten Heimrich 	_SetupDayNames();
60978092ae7SKarsten Heimrich 	_SetupDayNumbers();
61078092ae7SKarsten Heimrich 	_SetupWeekNumbers();
61178092ae7SKarsten Heimrich 
61278092ae7SKarsten Heimrich 	Invalidate(Bounds().InsetBySelf(1.0, 1.0));
61378092ae7SKarsten Heimrich }
61478092ae7SKarsten Heimrich 
61578092ae7SKarsten Heimrich 
61678092ae7SKarsten Heimrich bool
61778092ae7SKarsten Heimrich BCalendarView::IsDayNameHeaderVisible() const
61878092ae7SKarsten Heimrich {
61978092ae7SKarsten Heimrich 	return fDayNameHeaderVisible;
62078092ae7SKarsten Heimrich }
62178092ae7SKarsten Heimrich 
62278092ae7SKarsten Heimrich 
62378092ae7SKarsten Heimrich void
62478092ae7SKarsten Heimrich BCalendarView::SetDayNameHeaderVisible(bool visible)
62578092ae7SKarsten Heimrich {
62678092ae7SKarsten Heimrich 	if (fDayNameHeaderVisible == visible)
62778092ae7SKarsten Heimrich 		return;
62878092ae7SKarsten Heimrich 
62978092ae7SKarsten Heimrich 	fDayNameHeaderVisible = visible;
63078092ae7SKarsten Heimrich 	Invalidate(Bounds().InsetBySelf(1.0, 1.0));
63178092ae7SKarsten Heimrich }
63278092ae7SKarsten Heimrich 
63378092ae7SKarsten Heimrich 
63478092ae7SKarsten Heimrich bool
63578092ae7SKarsten Heimrich BCalendarView::IsWeekNumberHeaderVisible() const
63678092ae7SKarsten Heimrich {
63778092ae7SKarsten Heimrich 	return fWeekNumberHeaderVisible;
63878092ae7SKarsten Heimrich }
63978092ae7SKarsten Heimrich 
64078092ae7SKarsten Heimrich 
64178092ae7SKarsten Heimrich void
64278092ae7SKarsten Heimrich BCalendarView::SetWeekNumberHeaderVisible(bool visible)
64378092ae7SKarsten Heimrich {
64478092ae7SKarsten Heimrich 	if (fWeekNumberHeaderVisible == visible)
64578092ae7SKarsten Heimrich 		return;
64678092ae7SKarsten Heimrich 
64778092ae7SKarsten Heimrich 	fWeekNumberHeaderVisible = visible;
64878092ae7SKarsten Heimrich 	Invalidate(Bounds().InsetBySelf(1.0, 1.0));
64978092ae7SKarsten Heimrich }
65078092ae7SKarsten Heimrich 
65178092ae7SKarsten Heimrich 
65278092ae7SKarsten Heimrich void
65378092ae7SKarsten Heimrich BCalendarView::_InitObject()
65478092ae7SKarsten Heimrich {
655*6846765fSOliver Tappe 	fDate = BDate::CurrentDate(B_LOCAL_TIME);
656*6846765fSOliver Tappe 
657*6846765fSOliver Tappe 	BLocale::Default()->GetStartOfWeek((BWeekday*)&fStartOfWeek);
65878092ae7SKarsten Heimrich 
65978092ae7SKarsten Heimrich 	_SetupDayNames();
66078092ae7SKarsten Heimrich 	_SetupDayNumbers();
66178092ae7SKarsten Heimrich 	_SetupWeekNumbers();
66278092ae7SKarsten Heimrich }
66378092ae7SKarsten Heimrich 
66478092ae7SKarsten Heimrich 
66578092ae7SKarsten Heimrich void
66678092ae7SKarsten Heimrich BCalendarView::_SetToDay()
66778092ae7SKarsten Heimrich {
668*6846765fSOliver Tappe 	BDate date(fDate.Year(), fDate.Month(), 1);
66978092ae7SKarsten Heimrich 	if (!date.IsValid())
67078092ae7SKarsten Heimrich 		return;
67178092ae7SKarsten Heimrich 
672*6846765fSOliver Tappe 	const int32 firstDayOffset = (7 + date.DayOfWeek() - fStartOfWeek) % 7;
67378092ae7SKarsten Heimrich 
674*6846765fSOliver Tappe 	int32 day = 1 - firstDayOffset;
67578092ae7SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
67678092ae7SKarsten Heimrich 		for (int32 column = 0; column < 7; ++column) {
677*6846765fSOliver Tappe 			if (day == fDate.Day()) {
67878092ae7SKarsten Heimrich 				fNewFocusedDay.SetTo(row, column);
67978092ae7SKarsten Heimrich 				fNewSelectedDay.SetTo(row, column);
68078092ae7SKarsten Heimrich 				return;
68178092ae7SKarsten Heimrich 			}
682*6846765fSOliver Tappe 			day++;
68378092ae7SKarsten Heimrich 		}
68478092ae7SKarsten Heimrich 	}
685*6846765fSOliver Tappe 
686*6846765fSOliver Tappe 	fNewFocusedDay.SetTo(0, 0);
687*6846765fSOliver Tappe 	fNewSelectedDay.SetTo(0, 0);
68878092ae7SKarsten Heimrich }
68978092ae7SKarsten Heimrich 
69078092ae7SKarsten Heimrich 
69178092ae7SKarsten Heimrich void
692*6846765fSOliver Tappe BCalendarView::_GetYearMonthForSelection(const Selection& selection,
693*6846765fSOliver Tappe 	int32* year, int32* month) const
69478092ae7SKarsten Heimrich {
695*6846765fSOliver Tappe 	BDate startOfMonth(fDate.Year(), fDate.Month(), 1);
696*6846765fSOliver Tappe 	const int32 firstDayOffset
697*6846765fSOliver Tappe 		= (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7;
698*6846765fSOliver Tappe 	const int32 daysInMonth = startOfMonth.DaysInMonth();
69978092ae7SKarsten Heimrich 
700*6846765fSOliver Tappe 	BDate date(fDate);
701*6846765fSOliver Tappe 	const int32 dayOffset = selection.row * 7 + selection.column;
702*6846765fSOliver Tappe 	if (dayOffset < firstDayOffset)
703*6846765fSOliver Tappe 		date.AddMonths(-1);
704*6846765fSOliver Tappe 	else if (dayOffset >= firstDayOffset + daysInMonth)
705*6846765fSOliver Tappe 		date.AddMonths(1);
706*6846765fSOliver Tappe 	if (year != NULL)
70778092ae7SKarsten Heimrich 		*year = date.Year();
708*6846765fSOliver Tappe 	if (month != NULL)
70978092ae7SKarsten Heimrich 		*month = date.Month();
71078092ae7SKarsten Heimrich }
71178092ae7SKarsten Heimrich 
71278092ae7SKarsten Heimrich 
71378092ae7SKarsten Heimrich void
71478092ae7SKarsten Heimrich BCalendarView::_GetPreferredSize(float* _width, float* _height)
71578092ae7SKarsten Heimrich {
71678092ae7SKarsten Heimrich 	BFont font;
71778092ae7SKarsten Heimrich 	GetFont(&font);
71878092ae7SKarsten Heimrich 	font_height fontHeight;
71978092ae7SKarsten Heimrich 	font.GetHeight(&fontHeight);
72078092ae7SKarsten Heimrich 
72178092ae7SKarsten Heimrich 	const float height = FontHeight(this) + 4.0;
72278092ae7SKarsten Heimrich 
72378092ae7SKarsten Heimrich 	int32 rows = 7;
72478092ae7SKarsten Heimrich 	if (!fDayNameHeaderVisible)
72578092ae7SKarsten Heimrich 		rows = 6;
72678092ae7SKarsten Heimrich 
72778092ae7SKarsten Heimrich 	// height = font height * rows + 8 px border
72878092ae7SKarsten Heimrich 	*_height = height * rows + 8.0;
72978092ae7SKarsten Heimrich 
73078092ae7SKarsten Heimrich 	float width = 0.0;
73178092ae7SKarsten Heimrich 	for (int32 column = 0; column < 7; ++column) {
73278092ae7SKarsten Heimrich 		float tmp = StringWidth(fDayNames[column].String()) + 2.0;
73378092ae7SKarsten Heimrich 		width = tmp > width ? tmp : width;
73478092ae7SKarsten Heimrich 	}
73578092ae7SKarsten Heimrich 
73678092ae7SKarsten Heimrich 	int32 columns = 8;
73778092ae7SKarsten Heimrich 	if (!fWeekNumberHeaderVisible)
73878092ae7SKarsten Heimrich 		columns = 7;
73978092ae7SKarsten Heimrich 
74078092ae7SKarsten Heimrich 	// width = max width day name * 8 column + 8 px border
74178092ae7SKarsten Heimrich 	*_width = width * columns + 8.0;
74278092ae7SKarsten Heimrich }
74378092ae7SKarsten Heimrich 
74478092ae7SKarsten Heimrich 
74578092ae7SKarsten Heimrich void
74678092ae7SKarsten Heimrich BCalendarView::_SetupDayNames()
74778092ae7SKarsten Heimrich {
748*6846765fSOliver Tappe 	for (int32 i = 0; i <= 6; ++i)
749*6846765fSOliver Tappe 		fDayNames[i] = fDate.ShortDayName(1 + (fStartOfWeek - 1 + i) % 7);
75078092ae7SKarsten Heimrich }
75178092ae7SKarsten Heimrich 
75278092ae7SKarsten Heimrich 
75378092ae7SKarsten Heimrich void
75478092ae7SKarsten Heimrich BCalendarView::_SetupDayNumbers()
75578092ae7SKarsten Heimrich {
756*6846765fSOliver Tappe 	BDate startOfMonth(fDate.Year(), fDate.Month(), 1);
757*6846765fSOliver Tappe 	if (!startOfMonth.IsValid())
75878092ae7SKarsten Heimrich 		return;
75978092ae7SKarsten Heimrich 
76078092ae7SKarsten Heimrich 	fFocusedDay.SetTo(0, 0);
76178092ae7SKarsten Heimrich 	fSelectedDay.SetTo(0, 0);
76278092ae7SKarsten Heimrich 	fNewFocusedDay.SetTo(0, 0);
76378092ae7SKarsten Heimrich 
764*6846765fSOliver Tappe 	const int32 daysInMonth = startOfMonth.DaysInMonth();
765*6846765fSOliver Tappe 	const int32 firstDayOffset
766*6846765fSOliver Tappe 		= (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7;
76778092ae7SKarsten Heimrich 
76878092ae7SKarsten Heimrich 	// calc the last day one month before
769*6846765fSOliver Tappe 	BDate lastDayInMonthBefore(startOfMonth);
770*6846765fSOliver Tappe 	lastDayInMonthBefore.AddDays(-1);
771*6846765fSOliver Tappe 	const int32 lastDayBefore = lastDayInMonthBefore.DaysInMonth();
77278092ae7SKarsten Heimrich 
77378092ae7SKarsten Heimrich 	int32 counter = 0;
77478092ae7SKarsten Heimrich 	int32 firstDayAfter = 1;
77578092ae7SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
77678092ae7SKarsten Heimrich 		for (int32 column = 0; column < 7; ++column) {
777*6846765fSOliver Tappe 			int32 day = 1 + counter - firstDayOffset;
778*6846765fSOliver Tappe 			if (counter < firstDayOffset)
77978092ae7SKarsten Heimrich 				day += lastDayBefore;
780*6846765fSOliver Tappe 			else if (counter >= firstDayOffset + daysInMonth)
78178092ae7SKarsten Heimrich 				day = firstDayAfter++;
782*6846765fSOliver Tappe 			else if (day == fDate.Day()) {
78378092ae7SKarsten Heimrich 				fFocusedDay.SetTo(row, column);
78478092ae7SKarsten Heimrich 				fSelectedDay.SetTo(row, column);
78578092ae7SKarsten Heimrich 				fNewFocusedDay.SetTo(row, column);
78678092ae7SKarsten Heimrich 			}
78778092ae7SKarsten Heimrich 			counter++;
788*6846765fSOliver Tappe 			fDayNumbers[row][column].Truncate(0);
78978092ae7SKarsten Heimrich 			fDayNumbers[row][column] << day;
79078092ae7SKarsten Heimrich 		}
79178092ae7SKarsten Heimrich 	}
79278092ae7SKarsten Heimrich }
79378092ae7SKarsten Heimrich 
794*6846765fSOliver Tappe 
79578092ae7SKarsten Heimrich void
79678092ae7SKarsten Heimrich BCalendarView::_SetupWeekNumbers()
79778092ae7SKarsten Heimrich {
798*6846765fSOliver Tappe 	BDate date(fDate.Year(), fDate.Month(), 1);
79978092ae7SKarsten Heimrich 	if (!date.IsValid())
80078092ae7SKarsten Heimrich 		return;
80178092ae7SKarsten Heimrich 
802c1ed5d75SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
80378092ae7SKarsten Heimrich 		fWeekNumbers[row].SetTo("");
804f0932941SMichael Pfeiffer 		fWeekNumbers[row] << date.WeekNumber();
805f0932941SMichael Pfeiffer 		date.AddDays(7);
806c1ed5d75SKarsten Heimrich 	}
80778092ae7SKarsten Heimrich }
80878092ae7SKarsten Heimrich 
80978092ae7SKarsten Heimrich 
81078092ae7SKarsten Heimrich void
81187663db4SOliver Tappe BCalendarView::_DrawDay(int32 currRow, int32 currColumn, int32 row,
81287663db4SOliver Tappe 	int32 column, int32 counter, BRect frame, const char* text, bool focus)
81378092ae7SKarsten Heimrich {
814*6846765fSOliver Tappe 	BDate startOfMonth(fDate.Year(), fDate.Month(), 1);
815*6846765fSOliver Tappe 	const int32 firstDayOffset
816*6846765fSOliver Tappe 		= (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7;
817*6846765fSOliver Tappe 	const int32 daysMonth = startOfMonth.DaysInMonth();
81878092ae7SKarsten Heimrich 
81978092ae7SKarsten Heimrich 	bool enabled = true;
82078092ae7SKarsten Heimrich 	bool selected = false;
82178092ae7SKarsten Heimrich 	// check for the current date
82278092ae7SKarsten Heimrich 	if (currRow == row  && currColumn == column) {
82378092ae7SKarsten Heimrich 		selected = true;	// draw current date selected
824*6846765fSOliver Tappe 		if (counter <= firstDayOffset || counter > firstDayOffset + daysMonth) {
82578092ae7SKarsten Heimrich 			enabled = false;	// days of month before or after
82678092ae7SKarsten Heimrich 			selected = false;	// not selected but able to get focus
82778092ae7SKarsten Heimrich 		}
82878092ae7SKarsten Heimrich 	} else {
829*6846765fSOliver Tappe 		if (counter <= firstDayOffset || counter > firstDayOffset + daysMonth)
83078092ae7SKarsten Heimrich 			enabled = false;	// days of month before or after
83178092ae7SKarsten Heimrich 	}
83278092ae7SKarsten Heimrich 
83378092ae7SKarsten Heimrich 	DrawDay(this, frame, text, selected, enabled, focus);
83478092ae7SKarsten Heimrich }
83578092ae7SKarsten Heimrich 
83678092ae7SKarsten Heimrich 
83778092ae7SKarsten Heimrich void
83878092ae7SKarsten Heimrich BCalendarView::_DrawDays()
83978092ae7SKarsten Heimrich {
84078092ae7SKarsten Heimrich 	BRect frame = _FirstCalendarItemFrame();
84178092ae7SKarsten Heimrich 
84278092ae7SKarsten Heimrich 	const int32 currRow = fSelectedDay.row;
84378092ae7SKarsten Heimrich 	const int32 currColumn = fSelectedDay.column;
84478092ae7SKarsten Heimrich 
84578092ae7SKarsten Heimrich 	const bool isFocus = IsFocus();
84678092ae7SKarsten Heimrich 	const int32 focusRow = fFocusedDay.row;
84778092ae7SKarsten Heimrich 	const int32 focusColumn = fFocusedDay.column;
84878092ae7SKarsten Heimrich 
84978092ae7SKarsten Heimrich 	int32 counter = 0;
85078092ae7SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
85178092ae7SKarsten Heimrich 		BRect tmp = frame;
85278092ae7SKarsten Heimrich 		for (int32 column = 0; column < 7; ++column) {
85378092ae7SKarsten Heimrich 			counter++;
85478092ae7SKarsten Heimrich 			const char* day = fDayNumbers[row][column].String();
85578092ae7SKarsten Heimrich 			bool focus = isFocus && focusRow == row && focusColumn == column;
85687663db4SOliver Tappe 			_DrawDay(currRow, currColumn, row, column, counter, tmp, day,
85787663db4SOliver Tappe 				focus);
85878092ae7SKarsten Heimrich 
85978092ae7SKarsten Heimrich 			tmp.OffsetBy(tmp.Width(), 0.0);
86078092ae7SKarsten Heimrich 		}
86178092ae7SKarsten Heimrich 		frame.OffsetBy(0.0, frame.Height());
86278092ae7SKarsten Heimrich 	}
86378092ae7SKarsten Heimrich }
86478092ae7SKarsten Heimrich 
86578092ae7SKarsten Heimrich 
86678092ae7SKarsten Heimrich void
86778092ae7SKarsten Heimrich BCalendarView::_DrawFocusRect()
86878092ae7SKarsten Heimrich {
86978092ae7SKarsten Heimrich 	BRect frame = _FirstCalendarItemFrame();
87078092ae7SKarsten Heimrich 
87178092ae7SKarsten Heimrich 	const int32 currRow = fSelectedDay.row;
87278092ae7SKarsten Heimrich 	const int32 currColumn = fSelectedDay.column;
87378092ae7SKarsten Heimrich 
87478092ae7SKarsten Heimrich 	const int32 focusRow = fFocusedDay.row;
87578092ae7SKarsten Heimrich 	const int32 focusColumn = fFocusedDay.column;
87678092ae7SKarsten Heimrich 
87778092ae7SKarsten Heimrich 	int32 counter = 0;
87878092ae7SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
87978092ae7SKarsten Heimrich 		BRect tmp = frame;
88078092ae7SKarsten Heimrich 		for (int32 column = 0; column < 7; ++column) {
88178092ae7SKarsten Heimrich 			counter++;
88278092ae7SKarsten Heimrich 			if (fNewFocusedDay.row == row && fNewFocusedDay.column == column) {
88378092ae7SKarsten Heimrich 				fFocusedDay.SetTo(row, column);
88478092ae7SKarsten Heimrich 
88578092ae7SKarsten Heimrich 				bool focus = IsFocus() && true;
88678092ae7SKarsten Heimrich 				const char* day = fDayNumbers[row][column].String();
88787663db4SOliver Tappe 				_DrawDay(currRow, currColumn, row, column, counter, tmp, day,
88887663db4SOliver Tappe 					focus);
889*6846765fSOliver Tappe 			} else if (focusRow == row && focusColumn == column) {
89078092ae7SKarsten Heimrich 				const char* day = fDayNumbers[row][column].String();
89187663db4SOliver Tappe 				_DrawDay(currRow, currColumn, row, column, counter, tmp, day,
89287663db4SOliver Tappe 					false);
89378092ae7SKarsten Heimrich 			}
89478092ae7SKarsten Heimrich 			tmp.OffsetBy(tmp.Width(), 0.0);
89578092ae7SKarsten Heimrich 		}
89678092ae7SKarsten Heimrich 		frame.OffsetBy(0.0, frame.Height());
89778092ae7SKarsten Heimrich 	}
89878092ae7SKarsten Heimrich }
89978092ae7SKarsten Heimrich 
90078092ae7SKarsten Heimrich 
90178092ae7SKarsten Heimrich void
90278092ae7SKarsten Heimrich BCalendarView::_DrawDayHeader()
90378092ae7SKarsten Heimrich {
90478092ae7SKarsten Heimrich 	if (!fDayNameHeaderVisible)
90578092ae7SKarsten Heimrich 		return;
90678092ae7SKarsten Heimrich 
90778092ae7SKarsten Heimrich 	int32 offset = 1;
90878092ae7SKarsten Heimrich 	int32 columns = 8;
90978092ae7SKarsten Heimrich 	if (!fWeekNumberHeaderVisible) {
91078092ae7SKarsten Heimrich 		offset = 0;
91178092ae7SKarsten Heimrich 		columns = 7;
91278092ae7SKarsten Heimrich 	}
91378092ae7SKarsten Heimrich 
91478092ae7SKarsten Heimrich 	BRect frame = Bounds();
91578092ae7SKarsten Heimrich 	frame.right = frame.Width() / columns - 1.0;
91678092ae7SKarsten Heimrich 	frame.bottom = frame.Height() / 7.0 - 2.0;
91778092ae7SKarsten Heimrich 	frame.OffsetBy(4.0, 4.0);
91878092ae7SKarsten Heimrich 
91978092ae7SKarsten Heimrich 	for (int32 i = 0; i < columns; ++i) {
92078092ae7SKarsten Heimrich 		if (i == 0 && fWeekNumberHeaderVisible) {
92178092ae7SKarsten Heimrich 			DrawDayName(this, frame, "");
92278092ae7SKarsten Heimrich 			frame.OffsetBy(frame.Width(), 0.0);
92378092ae7SKarsten Heimrich 			continue;
92478092ae7SKarsten Heimrich 		}
92578092ae7SKarsten Heimrich 		DrawDayName(this, frame, fDayNames[i - offset].String());
92678092ae7SKarsten Heimrich 		frame.OffsetBy(frame.Width(), 0.0);
92778092ae7SKarsten Heimrich 	}
92878092ae7SKarsten Heimrich }
92978092ae7SKarsten Heimrich 
93078092ae7SKarsten Heimrich 
93178092ae7SKarsten Heimrich void
93278092ae7SKarsten Heimrich BCalendarView::_DrawWeekHeader()
93378092ae7SKarsten Heimrich {
93478092ae7SKarsten Heimrich 	if (!fWeekNumberHeaderVisible)
93578092ae7SKarsten Heimrich 		return;
93678092ae7SKarsten Heimrich 
93778092ae7SKarsten Heimrich 	int32 rows = 7;
93878092ae7SKarsten Heimrich 	if (!fDayNameHeaderVisible)
93978092ae7SKarsten Heimrich 		rows = 6;
94078092ae7SKarsten Heimrich 
94178092ae7SKarsten Heimrich 	BRect frame = Bounds();
94278092ae7SKarsten Heimrich 	frame.right = frame.Width() / 8.0 - 2.0;
94378092ae7SKarsten Heimrich 	frame.bottom = frame.Height() / rows - 1.0;
94478092ae7SKarsten Heimrich 
94578092ae7SKarsten Heimrich 	float offsetY = 4.0;
94678092ae7SKarsten Heimrich 	if (fDayNameHeaderVisible)
94778092ae7SKarsten Heimrich 		offsetY += frame.Height();
94878092ae7SKarsten Heimrich 
94978092ae7SKarsten Heimrich 	frame.OffsetBy(4.0, offsetY);
95078092ae7SKarsten Heimrich 
95178092ae7SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
95278092ae7SKarsten Heimrich 		DrawWeekNumber(this, frame, fWeekNumbers[row].String());
95378092ae7SKarsten Heimrich 		frame.OffsetBy(0.0, frame.Height());
95478092ae7SKarsten Heimrich 	}
95578092ae7SKarsten Heimrich }
95678092ae7SKarsten Heimrich 
95778092ae7SKarsten Heimrich 
95878092ae7SKarsten Heimrich void
95978092ae7SKarsten Heimrich BCalendarView::_DrawItem(BView* owner, BRect frame, const char* text,
96078092ae7SKarsten Heimrich 	bool isSelected, bool isEnabled, bool focus)
96178092ae7SKarsten Heimrich {
96278092ae7SKarsten Heimrich 	rgb_color lColor = LowColor();
96378092ae7SKarsten Heimrich 	rgb_color highColor = HighColor();
96478092ae7SKarsten Heimrich 
96578092ae7SKarsten Heimrich 	rgb_color lowColor = { 255, 255, 255, 255 };
96678092ae7SKarsten Heimrich 
96778092ae7SKarsten Heimrich 	if (isSelected) {
96878092ae7SKarsten Heimrich 		SetHighColor(tint_color(lowColor, B_DARKEN_2_TINT));
96978092ae7SKarsten Heimrich 		SetLowColor(HighColor());
97078092ae7SKarsten Heimrich 	} else
97178092ae7SKarsten Heimrich 		SetHighColor(lowColor);
97278092ae7SKarsten Heimrich 
97378092ae7SKarsten Heimrich 	FillRect(frame.InsetByCopy(1.0, 1.0));
97478092ae7SKarsten Heimrich 
97578092ae7SKarsten Heimrich 	if (focus) {
97678092ae7SKarsten Heimrich 		SetHighColor(keyboard_navigation_color());
97778092ae7SKarsten Heimrich 		StrokeRect(frame.InsetByCopy(1.0, 1.0));
97878092ae7SKarsten Heimrich 	}
97978092ae7SKarsten Heimrich 
98078092ae7SKarsten Heimrich 	rgb_color black = { 0, 0, 0, 255 };
98178092ae7SKarsten Heimrich 	SetHighColor(black);
98278092ae7SKarsten Heimrich 	if (!isEnabled)
98378092ae7SKarsten Heimrich 		SetHighColor(tint_color(black, B_LIGHTEN_2_TINT));
98478092ae7SKarsten Heimrich 
98578092ae7SKarsten Heimrich 	float offsetH = frame.Width() / 2.0;
986*6846765fSOliver Tappe 	float offsetV = frame.Height() / 2.0 + FontHeight(owner) / 2.0 - 2.0;
98778092ae7SKarsten Heimrich 
988*6846765fSOliver Tappe 	DrawString(text, BPoint(frame.right - offsetH - StringWidth(text) / 2.0,
989*6846765fSOliver Tappe 			frame.top + offsetV));
99078092ae7SKarsten Heimrich 
99178092ae7SKarsten Heimrich 	SetLowColor(lColor);
99278092ae7SKarsten Heimrich 	SetHighColor(highColor);
99378092ae7SKarsten Heimrich }
99478092ae7SKarsten Heimrich 
99578092ae7SKarsten Heimrich 
99678092ae7SKarsten Heimrich void
99778092ae7SKarsten Heimrich BCalendarView::_UpdateSelection()
99878092ae7SKarsten Heimrich {
99978092ae7SKarsten Heimrich 	BRect frame = _FirstCalendarItemFrame();
100078092ae7SKarsten Heimrich 
100178092ae7SKarsten Heimrich 	const int32 currRow = fSelectedDay.row;
100278092ae7SKarsten Heimrich 	const int32 currColumn = fSelectedDay.column;
100378092ae7SKarsten Heimrich 
100478092ae7SKarsten Heimrich 	const int32 focusRow = fFocusedDay.row;
100578092ae7SKarsten Heimrich 	const int32 focusColumn = fFocusedDay.column;
100678092ae7SKarsten Heimrich 
100778092ae7SKarsten Heimrich 	int32 counter = 0;
100878092ae7SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
100978092ae7SKarsten Heimrich 		BRect tmp = frame;
101078092ae7SKarsten Heimrich 		for (int32 column = 0; column < 7; ++column) {
101178092ae7SKarsten Heimrich 			counter++;
101287663db4SOliver Tappe 			if (fNewSelectedDay.row == row
101387663db4SOliver Tappe 				&& fNewSelectedDay.column == column) {
101478092ae7SKarsten Heimrich 				fSelectedDay.SetTo(row, column);
101578092ae7SKarsten Heimrich 
101678092ae7SKarsten Heimrich 				const char* day = fDayNumbers[row][column].String();
101787663db4SOliver Tappe 				bool focus = IsFocus() && focusRow == row
101887663db4SOliver Tappe 					&& focusColumn == column;
101978092ae7SKarsten Heimrich 				_DrawDay(row, column, row, column, counter, tmp, day, focus);
1020*6846765fSOliver Tappe 			} else if (currRow == row && currColumn == column) {
102178092ae7SKarsten Heimrich 				const char* day = fDayNumbers[row][column].String();
102287663db4SOliver Tappe 				bool focus = IsFocus() && focusRow == row
102387663db4SOliver Tappe 					&& focusColumn == column;
102478092ae7SKarsten Heimrich 				_DrawDay(currRow, currColumn, -1, -1, counter, tmp, day, focus);
102578092ae7SKarsten Heimrich 			}
102678092ae7SKarsten Heimrich 			tmp.OffsetBy(tmp.Width(), 0.0);
102778092ae7SKarsten Heimrich 		}
102878092ae7SKarsten Heimrich 		frame.OffsetBy(0.0, frame.Height());
102978092ae7SKarsten Heimrich 	}
103078092ae7SKarsten Heimrich }
103178092ae7SKarsten Heimrich 
103278092ae7SKarsten Heimrich 
103378092ae7SKarsten Heimrich BRect
103478092ae7SKarsten Heimrich BCalendarView::_FirstCalendarItemFrame() const
103578092ae7SKarsten Heimrich {
103678092ae7SKarsten Heimrich 	int32 rows = 7;
103778092ae7SKarsten Heimrich 	int32 columns = 8;
103878092ae7SKarsten Heimrich 
103978092ae7SKarsten Heimrich 	if (!fDayNameHeaderVisible)
104078092ae7SKarsten Heimrich 		rows = 6;
104178092ae7SKarsten Heimrich 
104278092ae7SKarsten Heimrich 	if (!fWeekNumberHeaderVisible)
104378092ae7SKarsten Heimrich 		columns = 7;
104478092ae7SKarsten Heimrich 
104578092ae7SKarsten Heimrich 	BRect frame = Bounds();
104678092ae7SKarsten Heimrich 	frame.right = frame.Width() / columns - 1.0;
104778092ae7SKarsten Heimrich 	frame.bottom = frame.Height() / rows - 1.0;
104878092ae7SKarsten Heimrich 
104978092ae7SKarsten Heimrich 	float offsetY = 4.0;
105078092ae7SKarsten Heimrich 	if (fDayNameHeaderVisible)
105178092ae7SKarsten Heimrich 		offsetY += frame.Height();
105278092ae7SKarsten Heimrich 
105378092ae7SKarsten Heimrich 	float offsetX = 4.0;
105478092ae7SKarsten Heimrich 	if (fWeekNumberHeaderVisible)
105578092ae7SKarsten Heimrich 		offsetX += frame.Width();
105678092ae7SKarsten Heimrich 
105778092ae7SKarsten Heimrich 	return frame.OffsetBySelf(offsetX, offsetY);
105878092ae7SKarsten Heimrich }
105978092ae7SKarsten Heimrich 
106078092ae7SKarsten Heimrich 
106178092ae7SKarsten Heimrich BRect
106278092ae7SKarsten Heimrich BCalendarView::_SetNewSelectedDay(const BPoint& where)
106378092ae7SKarsten Heimrich {
106478092ae7SKarsten Heimrich 	BRect frame = _FirstCalendarItemFrame();
106578092ae7SKarsten Heimrich 
106678092ae7SKarsten Heimrich 	int32 counter = 0;
106778092ae7SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
106878092ae7SKarsten Heimrich 		BRect tmp = frame;
106978092ae7SKarsten Heimrich 		for (int32 column = 0; column < 7; ++column) {
107078092ae7SKarsten Heimrich 			counter++;
107178092ae7SKarsten Heimrich 			if (tmp.Contains(where)) {
107278092ae7SKarsten Heimrich 				fNewSelectedDay.SetTo(row, column);
1073*6846765fSOliver Tappe 				int32 year;
1074*6846765fSOliver Tappe 				int32 month;
1075*6846765fSOliver Tappe 				_GetYearMonthForSelection(fNewSelectedDay, &year, &month);
1076*6846765fSOliver Tappe 				if (month == fDate.Month()) {
1077*6846765fSOliver Tappe 					// only change date if a day in the current month has been
1078*6846765fSOliver Tappe 					// selected
1079*6846765fSOliver Tappe 					int32 day = atoi(fDayNumbers[row][column].String());
1080*6846765fSOliver Tappe 					fDate.SetDate(year, month, day);
1081*6846765fSOliver Tappe 				}
108278092ae7SKarsten Heimrich 				return tmp;
108378092ae7SKarsten Heimrich 			}
108478092ae7SKarsten Heimrich 			tmp.OffsetBy(tmp.Width(), 0.0);
108578092ae7SKarsten Heimrich 		}
108678092ae7SKarsten Heimrich 		frame.OffsetBy(0.0, frame.Height());
108778092ae7SKarsten Heimrich 	}
108878092ae7SKarsten Heimrich 
108978092ae7SKarsten Heimrich 	return frame;
109078092ae7SKarsten Heimrich }
109178092ae7SKarsten Heimrich 
109278092ae7SKarsten Heimrich 
109378092ae7SKarsten Heimrich BRect
109478092ae7SKarsten Heimrich BCalendarView::_RectOfDay(const Selection& selection) const
109578092ae7SKarsten Heimrich {
109678092ae7SKarsten Heimrich 	BRect frame = _FirstCalendarItemFrame();
109778092ae7SKarsten Heimrich 
109878092ae7SKarsten Heimrich 	int32 counter = 0;
109978092ae7SKarsten Heimrich 	for (int32 row = 0; row < 6; ++row) {
110078092ae7SKarsten Heimrich 		BRect tmp = frame;
110178092ae7SKarsten Heimrich 		for (int32 column = 0; column < 7; ++column) {
110278092ae7SKarsten Heimrich 			counter++;
1103*6846765fSOliver Tappe 			if (selection.row == row && selection.column == column)
110478092ae7SKarsten Heimrich 				return tmp;
110578092ae7SKarsten Heimrich 			tmp.OffsetBy(tmp.Width(), 0.0);
110678092ae7SKarsten Heimrich 		}
110778092ae7SKarsten Heimrich 		frame.OffsetBy(0.0, frame.Height());
110878092ae7SKarsten Heimrich 	}
110978092ae7SKarsten Heimrich 
111078092ae7SKarsten Heimrich 	return frame;
111178092ae7SKarsten Heimrich }
111278092ae7SKarsten Heimrich 
111378092ae7SKarsten Heimrich 
111478092ae7SKarsten Heimrich }	// namespace BPrivate
1115