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 386846765fSOliver Tappe BCalendarView::BCalendarView(BRect frame, const char* name, uint32 resizeMask, 396846765fSOliver Tappe uint32 flags) 401b3303e7SAxel Dörfler : 411b3303e7SAxel Dörfler BView(frame, name, resizeMask, flags), 4278092ae7SKarsten Heimrich BInvoker(), 4378092ae7SKarsten Heimrich fSelectionMessage(NULL), 446846765fSOliver Tappe fDate(), 4578092ae7SKarsten Heimrich fFocusChanged(false), 4678092ae7SKarsten Heimrich fSelectionChanged(false), 476846765fSOliver 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), 606846765fSOliver Tappe fDate(), 612530274dSRyan Leavengood fFocusChanged(false), 622530274dSRyan Leavengood fSelectionChanged(false), 636846765fSOliver 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), 826846765fSOliver Tappe fDate(archive), 8378092ae7SKarsten Heimrich fFocusChanged(false), 8478092ae7SKarsten Heimrich fSelectionChanged(false), 856846765fSOliver 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 1016846765fSOliver Tappe if (archive->FindInt32("_weekStart", &fStartOfWeek) != B_OK) 1026846765fSOliver 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) 1386846765fSOliver Tappe status = fDate.Archive(archive); 13978092ae7SKarsten Heimrich 14078092ae7SKarsten Heimrich if (status == B_OK) 1416846765fSOliver 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(¬ify); 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; 3106846765fSOliver Tappe _GetYearMonthForSelection(fSelectedDay, &year, &month); 31178092ae7SKarsten Heimrich 3126846765fSOliver Tappe clone.AddInt32("year", fDate.Year()); 3136846765fSOliver Tappe clone.AddInt32("month", fDate.Month()); 3146846765fSOliver 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; 3926846765fSOliver 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; 4036846765fSOliver Tappe break; 40478092ae7SKarsten Heimrich 40578092ae7SKarsten Heimrich case B_UP_ARROW: 40678092ae7SKarsten Heimrich row -= 1; 40778092ae7SKarsten Heimrich if (row >= 0) 40878092ae7SKarsten Heimrich fFocusChanged = true; 4096846765fSOliver Tappe break; 41078092ae7SKarsten Heimrich 41178092ae7SKarsten Heimrich case B_DOWN_ARROW: 41278092ae7SKarsten Heimrich row += 1; 41378092ae7SKarsten Heimrich if (row < kRows) 41478092ae7SKarsten Heimrich fFocusChanged = true; 4156846765fSOliver Tappe break; 4166846765fSOliver Tappe 4176846765fSOliver Tappe case B_PAGE_UP: 4186846765fSOliver Tappe { 4196846765fSOliver Tappe BDate date(fDate); 4206846765fSOliver Tappe date.AddMonths(-1); 4216846765fSOliver Tappe SetDate(date); 4226846765fSOliver Tappe 4236846765fSOliver Tappe Invoke(); 4246846765fSOliver Tappe break; 4256846765fSOliver Tappe } 4266846765fSOliver Tappe 4276846765fSOliver Tappe case B_PAGE_DOWN: 4286846765fSOliver Tappe { 4296846765fSOliver Tappe BDate date(fDate); 4306846765fSOliver Tappe date.AddMonths(1); 4316846765fSOliver Tappe SetDate(date); 4326846765fSOliver Tappe 4336846765fSOliver Tappe Invoke(); 4346846765fSOliver Tappe break; 4356846765fSOliver Tappe } 43678092ae7SKarsten Heimrich 43778092ae7SKarsten Heimrich case B_RETURN: 4386846765fSOliver Tappe case B_SPACE: 4396846765fSOliver 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(); 4476846765fSOliver Tappe break; 4486846765fSOliver 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); 4956846765fSOliver Tappe return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(width, height)); 4962530274dSRyan Leavengood } 4972530274dSRyan Leavengood 4982530274dSRyan Leavengood 4992530274dSRyan Leavengood BSize 5002530274dSRyan Leavengood BCalendarView::PreferredSize() 5012530274dSRyan Leavengood { 5026846765fSOliver Tappe return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize()); 5032530274dSRyan Leavengood } 5042530274dSRyan Leavengood 5052530274dSRyan Leavengood 50678092ae7SKarsten Heimrich int32 50778092ae7SKarsten Heimrich BCalendarView::Day() const 50878092ae7SKarsten Heimrich { 5096846765fSOliver Tappe return fDate.Day(); 51078092ae7SKarsten Heimrich } 51178092ae7SKarsten Heimrich 51278092ae7SKarsten Heimrich 51378092ae7SKarsten Heimrich int32 51478092ae7SKarsten Heimrich BCalendarView::Year() const 51578092ae7SKarsten Heimrich { 51678092ae7SKarsten Heimrich int32 year; 5176846765fSOliver 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; 5276846765fSOliver Tappe _GetYearMonthForSelection(fSelectedDay, NULL, &month); 52878092ae7SKarsten Heimrich 52978092ae7SKarsten Heimrich return month; 53078092ae7SKarsten Heimrich } 53178092ae7SKarsten Heimrich 53278092ae7SKarsten Heimrich 533afd5ec11SAdrien Destugues bool 534afd5ec11SAdrien Destugues BCalendarView::SetDay(int32 day) 535afd5ec11SAdrien Destugues { 536afd5ec11SAdrien Destugues BDate date = Date(); 537afd5ec11SAdrien Destugues date.SetDay(day); 538afd5ec11SAdrien Destugues if (!date.IsValid()) 539afd5ec11SAdrien Destugues return false; 540afd5ec11SAdrien Destugues SetDate(date); 541afd5ec11SAdrien Destugues return true; 542afd5ec11SAdrien Destugues } 543afd5ec11SAdrien Destugues 544afd5ec11SAdrien Destugues 545afd5ec11SAdrien Destugues bool 546afd5ec11SAdrien Destugues BCalendarView::SetMonth(int32 month) 547afd5ec11SAdrien Destugues { 548afd5ec11SAdrien Destugues if (month < 1 || month > 12) 549afd5ec11SAdrien Destugues return false; 550afd5ec11SAdrien Destugues BDate date = Date(); 551afd5ec11SAdrien Destugues int32 oldDay = date.Day(); 552afd5ec11SAdrien Destugues 553afd5ec11SAdrien Destugues date.SetMonth(month); 554afd5ec11SAdrien Destugues date.SetDay(1); // make sure the date is valid 555afd5ec11SAdrien Destugues 556afd5ec11SAdrien Destugues // We must make sure that the day in month fits inside the new month. 557afd5ec11SAdrien Destugues if (oldDay > date.DaysInMonth()) 558afd5ec11SAdrien Destugues date.SetDay(date.DaysInMonth()); 559afd5ec11SAdrien Destugues else 560afd5ec11SAdrien Destugues date.SetDay(oldDay); 561afd5ec11SAdrien Destugues SetDate(date); 562afd5ec11SAdrien Destugues return true; 563afd5ec11SAdrien Destugues } 564afd5ec11SAdrien Destugues 565afd5ec11SAdrien Destugues 566afd5ec11SAdrien Destugues bool 567afd5ec11SAdrien Destugues BCalendarView::SetYear(int32 year) 568afd5ec11SAdrien Destugues { 569afd5ec11SAdrien Destugues BDate date = Date(); 570afd5ec11SAdrien Destugues 571afd5ec11SAdrien Destugues // This can fail when going from 29 feb. on a leap year to a non-leap year. 572afd5ec11SAdrien Destugues if (date.Month() == 2 && date.Day() == 29 && !date.IsLeapYear(year)) 573afd5ec11SAdrien Destugues date.SetDay(28); 574afd5ec11SAdrien Destugues 575afd5ec11SAdrien Destugues // TODO we should also handle the "hole" at the switch between Julian and 576afd5ec11SAdrien Destugues // Gregorian calendars, which will result in an invalid date. 577afd5ec11SAdrien Destugues 578afd5ec11SAdrien Destugues date.SetYear(year); 579afd5ec11SAdrien Destugues SetDate(date); 580afd5ec11SAdrien Destugues return true; 581afd5ec11SAdrien Destugues } 582afd5ec11SAdrien Destugues 583afd5ec11SAdrien Destugues 58478092ae7SKarsten Heimrich BDate 58578092ae7SKarsten Heimrich BCalendarView::Date() const 58678092ae7SKarsten Heimrich { 58778092ae7SKarsten Heimrich int32 year; 58878092ae7SKarsten Heimrich int32 month; 5896846765fSOliver Tappe _GetYearMonthForSelection(fSelectedDay, &year, &month); 5906846765fSOliver Tappe return BDate(year, month, fDate.Day()); 59178092ae7SKarsten Heimrich } 59278092ae7SKarsten Heimrich 59378092ae7SKarsten Heimrich 59478092ae7SKarsten Heimrich bool 59578092ae7SKarsten Heimrich BCalendarView::SetDate(const BDate& date) 59678092ae7SKarsten Heimrich { 597c1ed5d75SKarsten Heimrich if (!date.IsValid()) 598c1ed5d75SKarsten Heimrich return false; 599c1ed5d75SKarsten Heimrich 6006846765fSOliver Tappe if (fDate == date) 60178092ae7SKarsten Heimrich return true; 60278092ae7SKarsten Heimrich 6036846765fSOliver Tappe if (fDate.Year() == date.Year() && fDate.Month() == date.Month()) { 6046846765fSOliver Tappe fDate = date; 6056846765fSOliver Tappe 60678092ae7SKarsten Heimrich _SetToDay(); 60778092ae7SKarsten Heimrich // update focus 60878092ae7SKarsten Heimrich fFocusChanged = true; 60978092ae7SKarsten Heimrich Draw(_RectOfDay(fFocusedDay)); 61078092ae7SKarsten Heimrich fFocusChanged = false; 61178092ae7SKarsten Heimrich 61278092ae7SKarsten Heimrich // update selection 61378092ae7SKarsten Heimrich fSelectionChanged = true; 61478092ae7SKarsten Heimrich Draw(_RectOfDay(fSelectedDay)); 61578092ae7SKarsten Heimrich Draw(_RectOfDay(fNewSelectedDay)); 61678092ae7SKarsten Heimrich fSelectionChanged = false; 61778092ae7SKarsten Heimrich } else { 6186846765fSOliver Tappe fDate = date; 61978092ae7SKarsten Heimrich 62078092ae7SKarsten Heimrich _SetupDayNumbers(); 62178092ae7SKarsten Heimrich _SetupWeekNumbers(); 62278092ae7SKarsten Heimrich 62378092ae7SKarsten Heimrich BRect frame = Bounds(); 62478092ae7SKarsten Heimrich if (fDayNameHeaderVisible) 62578092ae7SKarsten Heimrich frame.top += frame.Height() / 7 - 1.0; 62678092ae7SKarsten Heimrich 62778092ae7SKarsten Heimrich if (fWeekNumberHeaderVisible) 62878092ae7SKarsten Heimrich frame.left += frame.Width() / 8 - 1.0; 62978092ae7SKarsten Heimrich 63078092ae7SKarsten Heimrich Draw(frame.InsetBySelf(4.0, 4.0)); 63178092ae7SKarsten Heimrich } 63278092ae7SKarsten Heimrich 63378092ae7SKarsten Heimrich return true; 63478092ae7SKarsten Heimrich } 63578092ae7SKarsten Heimrich 63678092ae7SKarsten Heimrich 6376846765fSOliver Tappe bool 6386846765fSOliver Tappe BCalendarView::SetDate(int32 year, int32 month, int32 day) 63978092ae7SKarsten Heimrich { 6406846765fSOliver Tappe return SetDate(BDate(year, month, day)); 6416846765fSOliver Tappe } 6426846765fSOliver Tappe 6436846765fSOliver Tappe 6446846765fSOliver Tappe BWeekday 6456846765fSOliver Tappe BCalendarView::StartOfWeek() const 6466846765fSOliver Tappe { 6476846765fSOliver Tappe return BWeekday(fStartOfWeek); 64878092ae7SKarsten Heimrich } 64978092ae7SKarsten Heimrich 65078092ae7SKarsten Heimrich 65178092ae7SKarsten Heimrich void 6526846765fSOliver Tappe BCalendarView::SetStartOfWeek(BWeekday startOfWeek) 65378092ae7SKarsten Heimrich { 6546846765fSOliver Tappe if (fStartOfWeek == (int32)startOfWeek) 65578092ae7SKarsten Heimrich return; 65678092ae7SKarsten Heimrich 6576846765fSOliver Tappe fStartOfWeek = (int32)startOfWeek; 65878092ae7SKarsten Heimrich 65978092ae7SKarsten Heimrich _SetupDayNames(); 66078092ae7SKarsten Heimrich _SetupDayNumbers(); 66178092ae7SKarsten Heimrich _SetupWeekNumbers(); 66278092ae7SKarsten Heimrich 66378092ae7SKarsten Heimrich Invalidate(Bounds().InsetBySelf(1.0, 1.0)); 66478092ae7SKarsten Heimrich } 66578092ae7SKarsten Heimrich 66678092ae7SKarsten Heimrich 66778092ae7SKarsten Heimrich bool 66878092ae7SKarsten Heimrich BCalendarView::IsDayNameHeaderVisible() const 66978092ae7SKarsten Heimrich { 67078092ae7SKarsten Heimrich return fDayNameHeaderVisible; 67178092ae7SKarsten Heimrich } 67278092ae7SKarsten Heimrich 67378092ae7SKarsten Heimrich 67478092ae7SKarsten Heimrich void 67578092ae7SKarsten Heimrich BCalendarView::SetDayNameHeaderVisible(bool visible) 67678092ae7SKarsten Heimrich { 67778092ae7SKarsten Heimrich if (fDayNameHeaderVisible == visible) 67878092ae7SKarsten Heimrich return; 67978092ae7SKarsten Heimrich 68078092ae7SKarsten Heimrich fDayNameHeaderVisible = visible; 68178092ae7SKarsten Heimrich Invalidate(Bounds().InsetBySelf(1.0, 1.0)); 68278092ae7SKarsten Heimrich } 68378092ae7SKarsten Heimrich 68478092ae7SKarsten Heimrich 68578092ae7SKarsten Heimrich bool 68678092ae7SKarsten Heimrich BCalendarView::IsWeekNumberHeaderVisible() const 68778092ae7SKarsten Heimrich { 68878092ae7SKarsten Heimrich return fWeekNumberHeaderVisible; 68978092ae7SKarsten Heimrich } 69078092ae7SKarsten Heimrich 69178092ae7SKarsten Heimrich 69278092ae7SKarsten Heimrich void 69378092ae7SKarsten Heimrich BCalendarView::SetWeekNumberHeaderVisible(bool visible) 69478092ae7SKarsten Heimrich { 69578092ae7SKarsten Heimrich if (fWeekNumberHeaderVisible == visible) 69678092ae7SKarsten Heimrich return; 69778092ae7SKarsten Heimrich 69878092ae7SKarsten Heimrich fWeekNumberHeaderVisible = visible; 69978092ae7SKarsten Heimrich Invalidate(Bounds().InsetBySelf(1.0, 1.0)); 70078092ae7SKarsten Heimrich } 70178092ae7SKarsten Heimrich 70278092ae7SKarsten Heimrich 70378092ae7SKarsten Heimrich void 70478092ae7SKarsten Heimrich BCalendarView::_InitObject() 70578092ae7SKarsten Heimrich { 7066846765fSOliver Tappe fDate = BDate::CurrentDate(B_LOCAL_TIME); 7076846765fSOliver Tappe 708*0a925409SAdrien Destugues BDateFormat().GetStartOfWeek((BWeekday*)&fStartOfWeek); 70978092ae7SKarsten Heimrich 71078092ae7SKarsten Heimrich _SetupDayNames(); 71178092ae7SKarsten Heimrich _SetupDayNumbers(); 71278092ae7SKarsten Heimrich _SetupWeekNumbers(); 71378092ae7SKarsten Heimrich } 71478092ae7SKarsten Heimrich 71578092ae7SKarsten Heimrich 71678092ae7SKarsten Heimrich void 71778092ae7SKarsten Heimrich BCalendarView::_SetToDay() 71878092ae7SKarsten Heimrich { 7196846765fSOliver Tappe BDate date(fDate.Year(), fDate.Month(), 1); 72078092ae7SKarsten Heimrich if (!date.IsValid()) 72178092ae7SKarsten Heimrich return; 72278092ae7SKarsten Heimrich 7236846765fSOliver Tappe const int32 firstDayOffset = (7 + date.DayOfWeek() - fStartOfWeek) % 7; 72478092ae7SKarsten Heimrich 7256846765fSOliver Tappe int32 day = 1 - firstDayOffset; 72678092ae7SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 72778092ae7SKarsten Heimrich for (int32 column = 0; column < 7; ++column) { 7286846765fSOliver Tappe if (day == fDate.Day()) { 72978092ae7SKarsten Heimrich fNewFocusedDay.SetTo(row, column); 73078092ae7SKarsten Heimrich fNewSelectedDay.SetTo(row, column); 73178092ae7SKarsten Heimrich return; 73278092ae7SKarsten Heimrich } 7336846765fSOliver Tappe day++; 73478092ae7SKarsten Heimrich } 73578092ae7SKarsten Heimrich } 7366846765fSOliver Tappe 7376846765fSOliver Tappe fNewFocusedDay.SetTo(0, 0); 7386846765fSOliver Tappe fNewSelectedDay.SetTo(0, 0); 73978092ae7SKarsten Heimrich } 74078092ae7SKarsten Heimrich 74178092ae7SKarsten Heimrich 74278092ae7SKarsten Heimrich void 7436846765fSOliver Tappe BCalendarView::_GetYearMonthForSelection(const Selection& selection, 7446846765fSOliver Tappe int32* year, int32* month) const 74578092ae7SKarsten Heimrich { 7466846765fSOliver Tappe BDate startOfMonth(fDate.Year(), fDate.Month(), 1); 7476846765fSOliver Tappe const int32 firstDayOffset 7486846765fSOliver Tappe = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7; 7496846765fSOliver Tappe const int32 daysInMonth = startOfMonth.DaysInMonth(); 75078092ae7SKarsten Heimrich 7516846765fSOliver Tappe BDate date(fDate); 7526846765fSOliver Tappe const int32 dayOffset = selection.row * 7 + selection.column; 7536846765fSOliver Tappe if (dayOffset < firstDayOffset) 7546846765fSOliver Tappe date.AddMonths(-1); 7556846765fSOliver Tappe else if (dayOffset >= firstDayOffset + daysInMonth) 7566846765fSOliver Tappe date.AddMonths(1); 7576846765fSOliver Tappe if (year != NULL) 75878092ae7SKarsten Heimrich *year = date.Year(); 7596846765fSOliver Tappe if (month != NULL) 76078092ae7SKarsten Heimrich *month = date.Month(); 76178092ae7SKarsten Heimrich } 76278092ae7SKarsten Heimrich 76378092ae7SKarsten Heimrich 76478092ae7SKarsten Heimrich void 76578092ae7SKarsten Heimrich BCalendarView::_GetPreferredSize(float* _width, float* _height) 76678092ae7SKarsten Heimrich { 76778092ae7SKarsten Heimrich BFont font; 76878092ae7SKarsten Heimrich GetFont(&font); 76978092ae7SKarsten Heimrich font_height fontHeight; 77078092ae7SKarsten Heimrich font.GetHeight(&fontHeight); 77178092ae7SKarsten Heimrich 77278092ae7SKarsten Heimrich const float height = FontHeight(this) + 4.0; 77378092ae7SKarsten Heimrich 77478092ae7SKarsten Heimrich int32 rows = 7; 77578092ae7SKarsten Heimrich if (!fDayNameHeaderVisible) 77678092ae7SKarsten Heimrich rows = 6; 77778092ae7SKarsten Heimrich 77878092ae7SKarsten Heimrich // height = font height * rows + 8 px border 77978092ae7SKarsten Heimrich *_height = height * rows + 8.0; 78078092ae7SKarsten Heimrich 78178092ae7SKarsten Heimrich float width = 0.0; 78278092ae7SKarsten Heimrich for (int32 column = 0; column < 7; ++column) { 78378092ae7SKarsten Heimrich float tmp = StringWidth(fDayNames[column].String()) + 2.0; 78478092ae7SKarsten Heimrich width = tmp > width ? tmp : width; 78578092ae7SKarsten Heimrich } 78678092ae7SKarsten Heimrich 78778092ae7SKarsten Heimrich int32 columns = 8; 78878092ae7SKarsten Heimrich if (!fWeekNumberHeaderVisible) 78978092ae7SKarsten Heimrich columns = 7; 79078092ae7SKarsten Heimrich 79178092ae7SKarsten Heimrich // width = max width day name * 8 column + 8 px border 79278092ae7SKarsten Heimrich *_width = width * columns + 8.0; 79378092ae7SKarsten Heimrich } 79478092ae7SKarsten Heimrich 79578092ae7SKarsten Heimrich 79678092ae7SKarsten Heimrich void 79778092ae7SKarsten Heimrich BCalendarView::_SetupDayNames() 79878092ae7SKarsten Heimrich { 7996846765fSOliver Tappe for (int32 i = 0; i <= 6; ++i) 8006846765fSOliver Tappe fDayNames[i] = fDate.ShortDayName(1 + (fStartOfWeek - 1 + i) % 7); 80178092ae7SKarsten Heimrich } 80278092ae7SKarsten Heimrich 80378092ae7SKarsten Heimrich 80478092ae7SKarsten Heimrich void 80578092ae7SKarsten Heimrich BCalendarView::_SetupDayNumbers() 80678092ae7SKarsten Heimrich { 8076846765fSOliver Tappe BDate startOfMonth(fDate.Year(), fDate.Month(), 1); 8086846765fSOliver Tappe if (!startOfMonth.IsValid()) 80978092ae7SKarsten Heimrich return; 81078092ae7SKarsten Heimrich 81178092ae7SKarsten Heimrich fFocusedDay.SetTo(0, 0); 81278092ae7SKarsten Heimrich fSelectedDay.SetTo(0, 0); 81378092ae7SKarsten Heimrich fNewFocusedDay.SetTo(0, 0); 81478092ae7SKarsten Heimrich 8156846765fSOliver Tappe const int32 daysInMonth = startOfMonth.DaysInMonth(); 8166846765fSOliver Tappe const int32 firstDayOffset 8176846765fSOliver Tappe = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7; 81878092ae7SKarsten Heimrich 81978092ae7SKarsten Heimrich // calc the last day one month before 8206846765fSOliver Tappe BDate lastDayInMonthBefore(startOfMonth); 8216846765fSOliver Tappe lastDayInMonthBefore.AddDays(-1); 8226846765fSOliver Tappe const int32 lastDayBefore = lastDayInMonthBefore.DaysInMonth(); 82378092ae7SKarsten Heimrich 82478092ae7SKarsten Heimrich int32 counter = 0; 82578092ae7SKarsten Heimrich int32 firstDayAfter = 1; 82678092ae7SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 82778092ae7SKarsten Heimrich for (int32 column = 0; column < 7; ++column) { 8286846765fSOliver Tappe int32 day = 1 + counter - firstDayOffset; 8296846765fSOliver Tappe if (counter < firstDayOffset) 83078092ae7SKarsten Heimrich day += lastDayBefore; 8316846765fSOliver Tappe else if (counter >= firstDayOffset + daysInMonth) 83278092ae7SKarsten Heimrich day = firstDayAfter++; 8336846765fSOliver Tappe else if (day == fDate.Day()) { 83478092ae7SKarsten Heimrich fFocusedDay.SetTo(row, column); 83578092ae7SKarsten Heimrich fSelectedDay.SetTo(row, column); 83678092ae7SKarsten Heimrich fNewFocusedDay.SetTo(row, column); 83778092ae7SKarsten Heimrich } 83878092ae7SKarsten Heimrich counter++; 8396846765fSOliver Tappe fDayNumbers[row][column].Truncate(0); 84078092ae7SKarsten Heimrich fDayNumbers[row][column] << day; 84178092ae7SKarsten Heimrich } 84278092ae7SKarsten Heimrich } 84378092ae7SKarsten Heimrich } 84478092ae7SKarsten Heimrich 8456846765fSOliver Tappe 84678092ae7SKarsten Heimrich void 84778092ae7SKarsten Heimrich BCalendarView::_SetupWeekNumbers() 84878092ae7SKarsten Heimrich { 8496846765fSOliver Tappe BDate date(fDate.Year(), fDate.Month(), 1); 85078092ae7SKarsten Heimrich if (!date.IsValid()) 85178092ae7SKarsten Heimrich return; 85278092ae7SKarsten Heimrich 853c1ed5d75SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 85478092ae7SKarsten Heimrich fWeekNumbers[row].SetTo(""); 855f0932941SMichael Pfeiffer fWeekNumbers[row] << date.WeekNumber(); 856f0932941SMichael Pfeiffer date.AddDays(7); 857c1ed5d75SKarsten Heimrich } 85878092ae7SKarsten Heimrich } 85978092ae7SKarsten Heimrich 86078092ae7SKarsten Heimrich 86178092ae7SKarsten Heimrich void 86287663db4SOliver Tappe BCalendarView::_DrawDay(int32 currRow, int32 currColumn, int32 row, 86387663db4SOliver Tappe int32 column, int32 counter, BRect frame, const char* text, bool focus) 86478092ae7SKarsten Heimrich { 8656846765fSOliver Tappe BDate startOfMonth(fDate.Year(), fDate.Month(), 1); 8666846765fSOliver Tappe const int32 firstDayOffset 8676846765fSOliver Tappe = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7; 8686846765fSOliver Tappe const int32 daysMonth = startOfMonth.DaysInMonth(); 86978092ae7SKarsten Heimrich 87078092ae7SKarsten Heimrich bool enabled = true; 87178092ae7SKarsten Heimrich bool selected = false; 87278092ae7SKarsten Heimrich // check for the current date 87378092ae7SKarsten Heimrich if (currRow == row && currColumn == column) { 87478092ae7SKarsten Heimrich selected = true; // draw current date selected 8756846765fSOliver Tappe if (counter <= firstDayOffset || counter > firstDayOffset + daysMonth) { 87678092ae7SKarsten Heimrich enabled = false; // days of month before or after 87778092ae7SKarsten Heimrich selected = false; // not selected but able to get focus 87878092ae7SKarsten Heimrich } 87978092ae7SKarsten Heimrich } else { 8806846765fSOliver Tappe if (counter <= firstDayOffset || counter > firstDayOffset + daysMonth) 88178092ae7SKarsten Heimrich enabled = false; // days of month before or after 88278092ae7SKarsten Heimrich } 88378092ae7SKarsten Heimrich 88478092ae7SKarsten Heimrich DrawDay(this, frame, text, selected, enabled, focus); 88578092ae7SKarsten Heimrich } 88678092ae7SKarsten Heimrich 88778092ae7SKarsten Heimrich 88878092ae7SKarsten Heimrich void 88978092ae7SKarsten Heimrich BCalendarView::_DrawDays() 89078092ae7SKarsten Heimrich { 89178092ae7SKarsten Heimrich BRect frame = _FirstCalendarItemFrame(); 89278092ae7SKarsten Heimrich 89378092ae7SKarsten Heimrich const int32 currRow = fSelectedDay.row; 89478092ae7SKarsten Heimrich const int32 currColumn = fSelectedDay.column; 89578092ae7SKarsten Heimrich 89678092ae7SKarsten Heimrich const bool isFocus = IsFocus(); 89778092ae7SKarsten Heimrich const int32 focusRow = fFocusedDay.row; 89878092ae7SKarsten Heimrich const int32 focusColumn = fFocusedDay.column; 89978092ae7SKarsten Heimrich 90078092ae7SKarsten Heimrich int32 counter = 0; 90178092ae7SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 90278092ae7SKarsten Heimrich BRect tmp = frame; 90378092ae7SKarsten Heimrich for (int32 column = 0; column < 7; ++column) { 90478092ae7SKarsten Heimrich counter++; 90578092ae7SKarsten Heimrich const char* day = fDayNumbers[row][column].String(); 90678092ae7SKarsten Heimrich bool focus = isFocus && focusRow == row && focusColumn == column; 90787663db4SOliver Tappe _DrawDay(currRow, currColumn, row, column, counter, tmp, day, 90887663db4SOliver Tappe focus); 90978092ae7SKarsten Heimrich 91078092ae7SKarsten Heimrich tmp.OffsetBy(tmp.Width(), 0.0); 91178092ae7SKarsten Heimrich } 91278092ae7SKarsten Heimrich frame.OffsetBy(0.0, frame.Height()); 91378092ae7SKarsten Heimrich } 91478092ae7SKarsten Heimrich } 91578092ae7SKarsten Heimrich 91678092ae7SKarsten Heimrich 91778092ae7SKarsten Heimrich void 91878092ae7SKarsten Heimrich BCalendarView::_DrawFocusRect() 91978092ae7SKarsten Heimrich { 92078092ae7SKarsten Heimrich BRect frame = _FirstCalendarItemFrame(); 92178092ae7SKarsten Heimrich 92278092ae7SKarsten Heimrich const int32 currRow = fSelectedDay.row; 92378092ae7SKarsten Heimrich const int32 currColumn = fSelectedDay.column; 92478092ae7SKarsten Heimrich 92578092ae7SKarsten Heimrich const int32 focusRow = fFocusedDay.row; 92678092ae7SKarsten Heimrich const int32 focusColumn = fFocusedDay.column; 92778092ae7SKarsten Heimrich 92878092ae7SKarsten Heimrich int32 counter = 0; 92978092ae7SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 93078092ae7SKarsten Heimrich BRect tmp = frame; 93178092ae7SKarsten Heimrich for (int32 column = 0; column < 7; ++column) { 93278092ae7SKarsten Heimrich counter++; 93378092ae7SKarsten Heimrich if (fNewFocusedDay.row == row && fNewFocusedDay.column == column) { 93478092ae7SKarsten Heimrich fFocusedDay.SetTo(row, column); 93578092ae7SKarsten Heimrich 93678092ae7SKarsten Heimrich bool focus = IsFocus() && true; 93778092ae7SKarsten Heimrich const char* day = fDayNumbers[row][column].String(); 93887663db4SOliver Tappe _DrawDay(currRow, currColumn, row, column, counter, tmp, day, 93987663db4SOliver Tappe focus); 9406846765fSOliver Tappe } else if (focusRow == row && focusColumn == column) { 94178092ae7SKarsten Heimrich const char* day = fDayNumbers[row][column].String(); 94287663db4SOliver Tappe _DrawDay(currRow, currColumn, row, column, counter, tmp, day, 94387663db4SOliver Tappe false); 94478092ae7SKarsten Heimrich } 94578092ae7SKarsten Heimrich tmp.OffsetBy(tmp.Width(), 0.0); 94678092ae7SKarsten Heimrich } 94778092ae7SKarsten Heimrich frame.OffsetBy(0.0, frame.Height()); 94878092ae7SKarsten Heimrich } 94978092ae7SKarsten Heimrich } 95078092ae7SKarsten Heimrich 95178092ae7SKarsten Heimrich 95278092ae7SKarsten Heimrich void 95378092ae7SKarsten Heimrich BCalendarView::_DrawDayHeader() 95478092ae7SKarsten Heimrich { 95578092ae7SKarsten Heimrich if (!fDayNameHeaderVisible) 95678092ae7SKarsten Heimrich return; 95778092ae7SKarsten Heimrich 95878092ae7SKarsten Heimrich int32 offset = 1; 95978092ae7SKarsten Heimrich int32 columns = 8; 96078092ae7SKarsten Heimrich if (!fWeekNumberHeaderVisible) { 96178092ae7SKarsten Heimrich offset = 0; 96278092ae7SKarsten Heimrich columns = 7; 96378092ae7SKarsten Heimrich } 96478092ae7SKarsten Heimrich 96578092ae7SKarsten Heimrich BRect frame = Bounds(); 96678092ae7SKarsten Heimrich frame.right = frame.Width() / columns - 1.0; 96778092ae7SKarsten Heimrich frame.bottom = frame.Height() / 7.0 - 2.0; 96878092ae7SKarsten Heimrich frame.OffsetBy(4.0, 4.0); 96978092ae7SKarsten Heimrich 97078092ae7SKarsten Heimrich for (int32 i = 0; i < columns; ++i) { 97178092ae7SKarsten Heimrich if (i == 0 && fWeekNumberHeaderVisible) { 97278092ae7SKarsten Heimrich DrawDayName(this, frame, ""); 97378092ae7SKarsten Heimrich frame.OffsetBy(frame.Width(), 0.0); 97478092ae7SKarsten Heimrich continue; 97578092ae7SKarsten Heimrich } 97678092ae7SKarsten Heimrich DrawDayName(this, frame, fDayNames[i - offset].String()); 97778092ae7SKarsten Heimrich frame.OffsetBy(frame.Width(), 0.0); 97878092ae7SKarsten Heimrich } 97978092ae7SKarsten Heimrich } 98078092ae7SKarsten Heimrich 98178092ae7SKarsten Heimrich 98278092ae7SKarsten Heimrich void 98378092ae7SKarsten Heimrich BCalendarView::_DrawWeekHeader() 98478092ae7SKarsten Heimrich { 98578092ae7SKarsten Heimrich if (!fWeekNumberHeaderVisible) 98678092ae7SKarsten Heimrich return; 98778092ae7SKarsten Heimrich 98878092ae7SKarsten Heimrich int32 rows = 7; 98978092ae7SKarsten Heimrich if (!fDayNameHeaderVisible) 99078092ae7SKarsten Heimrich rows = 6; 99178092ae7SKarsten Heimrich 99278092ae7SKarsten Heimrich BRect frame = Bounds(); 99378092ae7SKarsten Heimrich frame.right = frame.Width() / 8.0 - 2.0; 99478092ae7SKarsten Heimrich frame.bottom = frame.Height() / rows - 1.0; 99578092ae7SKarsten Heimrich 99678092ae7SKarsten Heimrich float offsetY = 4.0; 99778092ae7SKarsten Heimrich if (fDayNameHeaderVisible) 99878092ae7SKarsten Heimrich offsetY += frame.Height(); 99978092ae7SKarsten Heimrich 100078092ae7SKarsten Heimrich frame.OffsetBy(4.0, offsetY); 100178092ae7SKarsten Heimrich 100278092ae7SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 100378092ae7SKarsten Heimrich DrawWeekNumber(this, frame, fWeekNumbers[row].String()); 100478092ae7SKarsten Heimrich frame.OffsetBy(0.0, frame.Height()); 100578092ae7SKarsten Heimrich } 100678092ae7SKarsten Heimrich } 100778092ae7SKarsten Heimrich 100878092ae7SKarsten Heimrich 100978092ae7SKarsten Heimrich void 101078092ae7SKarsten Heimrich BCalendarView::_DrawItem(BView* owner, BRect frame, const char* text, 101178092ae7SKarsten Heimrich bool isSelected, bool isEnabled, bool focus) 101278092ae7SKarsten Heimrich { 101378092ae7SKarsten Heimrich rgb_color lColor = LowColor(); 101478092ae7SKarsten Heimrich rgb_color highColor = HighColor(); 101578092ae7SKarsten Heimrich 101678092ae7SKarsten Heimrich rgb_color lowColor = { 255, 255, 255, 255 }; 101778092ae7SKarsten Heimrich 101878092ae7SKarsten Heimrich if (isSelected) { 101978092ae7SKarsten Heimrich SetHighColor(tint_color(lowColor, B_DARKEN_2_TINT)); 102078092ae7SKarsten Heimrich SetLowColor(HighColor()); 102178092ae7SKarsten Heimrich } else 102278092ae7SKarsten Heimrich SetHighColor(lowColor); 102378092ae7SKarsten Heimrich 102478092ae7SKarsten Heimrich FillRect(frame.InsetByCopy(1.0, 1.0)); 102578092ae7SKarsten Heimrich 102678092ae7SKarsten Heimrich if (focus) { 102778092ae7SKarsten Heimrich SetHighColor(keyboard_navigation_color()); 102878092ae7SKarsten Heimrich StrokeRect(frame.InsetByCopy(1.0, 1.0)); 102978092ae7SKarsten Heimrich } 103078092ae7SKarsten Heimrich 103178092ae7SKarsten Heimrich rgb_color black = { 0, 0, 0, 255 }; 103278092ae7SKarsten Heimrich SetHighColor(black); 103378092ae7SKarsten Heimrich if (!isEnabled) 103478092ae7SKarsten Heimrich SetHighColor(tint_color(black, B_LIGHTEN_2_TINT)); 103578092ae7SKarsten Heimrich 103678092ae7SKarsten Heimrich float offsetH = frame.Width() / 2.0; 10376846765fSOliver Tappe float offsetV = frame.Height() / 2.0 + FontHeight(owner) / 2.0 - 2.0; 103878092ae7SKarsten Heimrich 10396846765fSOliver Tappe DrawString(text, BPoint(frame.right - offsetH - StringWidth(text) / 2.0, 10406846765fSOliver Tappe frame.top + offsetV)); 104178092ae7SKarsten Heimrich 104278092ae7SKarsten Heimrich SetLowColor(lColor); 104378092ae7SKarsten Heimrich SetHighColor(highColor); 104478092ae7SKarsten Heimrich } 104578092ae7SKarsten Heimrich 104678092ae7SKarsten Heimrich 104778092ae7SKarsten Heimrich void 104878092ae7SKarsten Heimrich BCalendarView::_UpdateSelection() 104978092ae7SKarsten Heimrich { 105078092ae7SKarsten Heimrich BRect frame = _FirstCalendarItemFrame(); 105178092ae7SKarsten Heimrich 105278092ae7SKarsten Heimrich const int32 currRow = fSelectedDay.row; 105378092ae7SKarsten Heimrich const int32 currColumn = fSelectedDay.column; 105478092ae7SKarsten Heimrich 105578092ae7SKarsten Heimrich const int32 focusRow = fFocusedDay.row; 105678092ae7SKarsten Heimrich const int32 focusColumn = fFocusedDay.column; 105778092ae7SKarsten Heimrich 105878092ae7SKarsten Heimrich int32 counter = 0; 105978092ae7SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 106078092ae7SKarsten Heimrich BRect tmp = frame; 106178092ae7SKarsten Heimrich for (int32 column = 0; column < 7; ++column) { 106278092ae7SKarsten Heimrich counter++; 106387663db4SOliver Tappe if (fNewSelectedDay.row == row 106487663db4SOliver Tappe && fNewSelectedDay.column == column) { 106578092ae7SKarsten Heimrich fSelectedDay.SetTo(row, column); 106678092ae7SKarsten Heimrich 106778092ae7SKarsten Heimrich const char* day = fDayNumbers[row][column].String(); 106887663db4SOliver Tappe bool focus = IsFocus() && focusRow == row 106987663db4SOliver Tappe && focusColumn == column; 107078092ae7SKarsten Heimrich _DrawDay(row, column, row, column, counter, tmp, day, focus); 10716846765fSOliver Tappe } else if (currRow == row && currColumn == column) { 107278092ae7SKarsten Heimrich const char* day = fDayNumbers[row][column].String(); 107387663db4SOliver Tappe bool focus = IsFocus() && focusRow == row 107487663db4SOliver Tappe && focusColumn == column; 107578092ae7SKarsten Heimrich _DrawDay(currRow, currColumn, -1, -1, counter, tmp, day, focus); 107678092ae7SKarsten Heimrich } 107778092ae7SKarsten Heimrich tmp.OffsetBy(tmp.Width(), 0.0); 107878092ae7SKarsten Heimrich } 107978092ae7SKarsten Heimrich frame.OffsetBy(0.0, frame.Height()); 108078092ae7SKarsten Heimrich } 108178092ae7SKarsten Heimrich } 108278092ae7SKarsten Heimrich 108378092ae7SKarsten Heimrich 108478092ae7SKarsten Heimrich BRect 108578092ae7SKarsten Heimrich BCalendarView::_FirstCalendarItemFrame() const 108678092ae7SKarsten Heimrich { 108778092ae7SKarsten Heimrich int32 rows = 7; 108878092ae7SKarsten Heimrich int32 columns = 8; 108978092ae7SKarsten Heimrich 109078092ae7SKarsten Heimrich if (!fDayNameHeaderVisible) 109178092ae7SKarsten Heimrich rows = 6; 109278092ae7SKarsten Heimrich 109378092ae7SKarsten Heimrich if (!fWeekNumberHeaderVisible) 109478092ae7SKarsten Heimrich columns = 7; 109578092ae7SKarsten Heimrich 109678092ae7SKarsten Heimrich BRect frame = Bounds(); 109778092ae7SKarsten Heimrich frame.right = frame.Width() / columns - 1.0; 109878092ae7SKarsten Heimrich frame.bottom = frame.Height() / rows - 1.0; 109978092ae7SKarsten Heimrich 110078092ae7SKarsten Heimrich float offsetY = 4.0; 110178092ae7SKarsten Heimrich if (fDayNameHeaderVisible) 110278092ae7SKarsten Heimrich offsetY += frame.Height(); 110378092ae7SKarsten Heimrich 110478092ae7SKarsten Heimrich float offsetX = 4.0; 110578092ae7SKarsten Heimrich if (fWeekNumberHeaderVisible) 110678092ae7SKarsten Heimrich offsetX += frame.Width(); 110778092ae7SKarsten Heimrich 110878092ae7SKarsten Heimrich return frame.OffsetBySelf(offsetX, offsetY); 110978092ae7SKarsten Heimrich } 111078092ae7SKarsten Heimrich 111178092ae7SKarsten Heimrich 111278092ae7SKarsten Heimrich BRect 111378092ae7SKarsten Heimrich BCalendarView::_SetNewSelectedDay(const BPoint& where) 111478092ae7SKarsten Heimrich { 111578092ae7SKarsten Heimrich BRect frame = _FirstCalendarItemFrame(); 111678092ae7SKarsten Heimrich 111778092ae7SKarsten Heimrich int32 counter = 0; 111878092ae7SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 111978092ae7SKarsten Heimrich BRect tmp = frame; 112078092ae7SKarsten Heimrich for (int32 column = 0; column < 7; ++column) { 112178092ae7SKarsten Heimrich counter++; 112278092ae7SKarsten Heimrich if (tmp.Contains(where)) { 112378092ae7SKarsten Heimrich fNewSelectedDay.SetTo(row, column); 11246846765fSOliver Tappe int32 year; 11256846765fSOliver Tappe int32 month; 11266846765fSOliver Tappe _GetYearMonthForSelection(fNewSelectedDay, &year, &month); 11276846765fSOliver Tappe if (month == fDate.Month()) { 11286846765fSOliver Tappe // only change date if a day in the current month has been 11296846765fSOliver Tappe // selected 11306846765fSOliver Tappe int32 day = atoi(fDayNumbers[row][column].String()); 11316846765fSOliver Tappe fDate.SetDate(year, month, day); 11326846765fSOliver Tappe } 113378092ae7SKarsten Heimrich return tmp; 113478092ae7SKarsten Heimrich } 113578092ae7SKarsten Heimrich tmp.OffsetBy(tmp.Width(), 0.0); 113678092ae7SKarsten Heimrich } 113778092ae7SKarsten Heimrich frame.OffsetBy(0.0, frame.Height()); 113878092ae7SKarsten Heimrich } 113978092ae7SKarsten Heimrich 114078092ae7SKarsten Heimrich return frame; 114178092ae7SKarsten Heimrich } 114278092ae7SKarsten Heimrich 114378092ae7SKarsten Heimrich 114478092ae7SKarsten Heimrich BRect 114578092ae7SKarsten Heimrich BCalendarView::_RectOfDay(const Selection& selection) const 114678092ae7SKarsten Heimrich { 114778092ae7SKarsten Heimrich BRect frame = _FirstCalendarItemFrame(); 114878092ae7SKarsten Heimrich 114978092ae7SKarsten Heimrich int32 counter = 0; 115078092ae7SKarsten Heimrich for (int32 row = 0; row < 6; ++row) { 115178092ae7SKarsten Heimrich BRect tmp = frame; 115278092ae7SKarsten Heimrich for (int32 column = 0; column < 7; ++column) { 115378092ae7SKarsten Heimrich counter++; 11546846765fSOliver Tappe if (selection.row == row && selection.column == column) 115578092ae7SKarsten Heimrich return tmp; 115678092ae7SKarsten Heimrich tmp.OffsetBy(tmp.Width(), 0.0); 115778092ae7SKarsten Heimrich } 115878092ae7SKarsten Heimrich frame.OffsetBy(0.0, frame.Height()); 115978092ae7SKarsten Heimrich } 116078092ae7SKarsten Heimrich 116178092ae7SKarsten Heimrich return frame; 116278092ae7SKarsten Heimrich } 116378092ae7SKarsten Heimrich 116478092ae7SKarsten Heimrich 116578092ae7SKarsten Heimrich } // namespace BPrivate 1166