btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / kits / shared / CalendarView.cpp
blob33a0771df6470f50c30f0b9b09fd830cb4d0b901
1 /*
2 * Copyright 2007-2011, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Julun <host.haiku@gmx.de>
7 */
10 #include "CalendarView.h"
12 #include <stdlib.h>
14 #include <DateFormat.h>
15 #include <LayoutUtils.h>
16 #include <Window.h>
19 namespace BPrivate {
22 static float
23 FontHeight(const BView* view)
25 if (!view)
26 return 0.0;
28 BFont font;
29 view->GetFont(&font);
30 font_height fheight;
31 font.GetHeight(&fheight);
32 return ceilf(fheight.ascent + fheight.descent + fheight.leading);
36 // #pragma mark -
39 BCalendarView::BCalendarView(BRect frame, const char* name, uint32 resizeMask,
40 uint32 flags)
42 BView(frame, name, resizeMask, flags),
43 BInvoker(),
44 fSelectionMessage(NULL),
45 fDate(),
46 fCurrentDate(BDate::CurrentDate(B_LOCAL_TIME)),
47 fFocusChanged(false),
48 fSelectionChanged(false),
49 fCurrentDayChanged(false),
50 fStartOfWeek((int32)B_WEEKDAY_MONDAY),
51 fDayNameHeaderVisible(true),
52 fWeekNumberHeaderVisible(true)
54 _InitObject();
58 BCalendarView::BCalendarView(const char* name, uint32 flags)
60 BView(name, flags),
61 BInvoker(),
62 fSelectionMessage(NULL),
63 fDate(),
64 fCurrentDate(BDate::CurrentDate(B_LOCAL_TIME)),
65 fFocusChanged(false),
66 fSelectionChanged(false),
67 fCurrentDayChanged(false),
68 fStartOfWeek((int32)B_WEEKDAY_MONDAY),
69 fDayNameHeaderVisible(true),
70 fWeekNumberHeaderVisible(true)
72 _InitObject();
76 BCalendarView::~BCalendarView()
78 SetSelectionMessage(NULL);
82 BCalendarView::BCalendarView(BMessage* archive)
84 BView(archive),
85 BInvoker(),
86 fSelectionMessage(NULL),
87 fDate(archive),
88 fCurrentDate(BDate::CurrentDate(B_LOCAL_TIME)),
89 fFocusChanged(false),
90 fSelectionChanged(false),
91 fCurrentDayChanged(false),
92 fStartOfWeek((int32)B_WEEKDAY_MONDAY),
93 fDayNameHeaderVisible(true),
94 fWeekNumberHeaderVisible(true)
96 if (archive->HasMessage("_invokeMsg")) {
97 BMessage* invokationMessage = new BMessage;
98 archive->FindMessage("_invokeMsg", invokationMessage);
99 SetInvocationMessage(invokationMessage);
102 if (archive->HasMessage("_selectMsg")) {
103 BMessage* selectionMessage = new BMessage;
104 archive->FindMessage("selectMsg", selectionMessage);
105 SetSelectionMessage(selectionMessage);
108 if (archive->FindInt32("_weekStart", &fStartOfWeek) != B_OK)
109 fStartOfWeek = (int32)B_WEEKDAY_MONDAY;
111 if (archive->FindBool("_dayHeader", &fDayNameHeaderVisible) != B_OK)
112 fDayNameHeaderVisible = true;
114 if (archive->FindBool("_weekHeader", &fWeekNumberHeaderVisible) != B_OK)
115 fWeekNumberHeaderVisible = true;
117 _SetupDayNames();
118 _SetupDayNumbers();
119 _SetupWeekNumbers();
123 BArchivable*
124 BCalendarView::Instantiate(BMessage* archive)
126 if (validate_instantiation(archive, "BCalendarView"))
127 return new BCalendarView(archive);
129 return NULL;
133 status_t
134 BCalendarView::Archive(BMessage* archive, bool deep) const
136 status_t status = BView::Archive(archive, deep);
138 if (status == B_OK && InvocationMessage())
139 status = archive->AddMessage("_invokeMsg", InvocationMessage());
141 if (status == B_OK && SelectionMessage())
142 status = archive->AddMessage("_selectMsg", SelectionMessage());
144 if (status == B_OK)
145 status = fDate.Archive(archive);
147 if (status == B_OK)
148 status = archive->AddInt32("_weekStart", fStartOfWeek);
150 if (status == B_OK)
151 status = archive->AddBool("_dayHeader", fDayNameHeaderVisible);
153 if (status == B_OK)
154 status = archive->AddBool("_weekHeader", fWeekNumberHeaderVisible);
156 return status;
160 void
161 BCalendarView::AttachedToWindow()
163 BView::AttachedToWindow();
165 if (!Messenger().IsValid())
166 SetTarget(Window(), NULL);
168 SetViewUIColor(B_LIST_BACKGROUND_COLOR);
172 void
173 BCalendarView::FrameResized(float width, float height)
175 _SetupDayNames();
176 Invalidate(Bounds());
180 void
181 BCalendarView::Draw(BRect updateRect)
183 if (LockLooper()) {
184 if (fFocusChanged) {
185 _DrawFocusRect();
186 UnlockLooper();
187 return;
190 if (fSelectionChanged) {
191 _UpdateSelection();
192 UnlockLooper();
193 return;
196 if (fCurrentDayChanged) {
197 _UpdateCurrentDay();
198 UnlockLooper();
199 return;
202 _DrawDays();
203 _DrawDayHeader();
204 _DrawWeekHeader();
206 rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
207 SetHighColor(tint_color(background, B_DARKEN_3_TINT));
208 StrokeRect(Bounds());
210 UnlockLooper();
215 void
216 BCalendarView::DrawDay(BView* owner, BRect frame, const char* text,
217 bool isSelected, bool isEnabled, bool focus, bool highlight)
219 _DrawItem(owner, frame, text, isSelected, isEnabled, focus, highlight);
223 void
224 BCalendarView::DrawDayName(BView* owner, BRect frame, const char* text)
226 // we get the full rect, fake this as the internal function
227 // shrinks the frame to work properly when drawing a day item
228 _DrawItem(owner, frame.InsetByCopy(-1.0, -1.0), text, true);
232 void
233 BCalendarView::DrawWeekNumber(BView* owner, BRect frame, const char* text)
235 // we get the full rect, fake this as the internal function
236 // shrinks the frame to work properly when drawing a day item
237 _DrawItem(owner, frame.InsetByCopy(-1.0, -1.0), text, true);
241 uint32
242 BCalendarView::SelectionCommand() const
244 if (SelectionMessage())
245 return SelectionMessage()->what;
247 return 0;
251 BMessage*
252 BCalendarView::SelectionMessage() const
254 return fSelectionMessage;
258 void
259 BCalendarView::SetSelectionMessage(BMessage* message)
261 delete fSelectionMessage;
262 fSelectionMessage = message;
266 uint32
267 BCalendarView::InvocationCommand() const
269 return BInvoker::Command();
273 BMessage*
274 BCalendarView::InvocationMessage() const
276 return BInvoker::Message();
280 void
281 BCalendarView::SetInvocationMessage(BMessage* message)
283 BInvoker::SetMessage(message);
287 void
288 BCalendarView::MakeFocus(bool state)
290 if (IsFocus() == state)
291 return;
293 BView::MakeFocus(state);
295 // TODO: solve this better
296 fFocusChanged = true;
297 Draw(_RectOfDay(fFocusedDay));
298 fFocusChanged = false;
302 status_t
303 BCalendarView::Invoke(BMessage* message)
305 bool notify = false;
306 uint32 kind = InvokeKind(&notify);
308 BMessage clone(kind);
309 status_t status = B_BAD_VALUE;
311 if (!message && !notify)
312 message = Message();
314 if (!message) {
315 if (!IsWatched())
316 return status;
317 } else
318 clone = *message;
320 clone.AddPointer("source", this);
321 clone.AddInt64("when", (int64)system_time());
322 clone.AddMessenger("be:sender", BMessenger(this));
324 int32 year;
325 int32 month;
326 _GetYearMonthForSelection(fSelectedDay, &year, &month);
328 clone.AddInt32("year", fDate.Year());
329 clone.AddInt32("month", fDate.Month());
330 clone.AddInt32("day", fDate.Day());
332 if (message)
333 status = BInvoker::Invoke(&clone);
335 SendNotices(kind, &clone);
337 return status;
341 void
342 BCalendarView::MouseDown(BPoint where)
344 if (!IsFocus()) {
345 MakeFocus();
346 Sync();
347 Window()->UpdateIfNeeded();
350 BRect frame = Bounds();
351 if (fDayNameHeaderVisible)
352 frame.top += frame.Height() / 7 - 1.0;
354 if (fWeekNumberHeaderVisible)
355 frame.left += frame.Width() / 8 - 1.0;
357 if (!frame.Contains(where))
358 return;
360 // try to set to new day
361 frame = _SetNewSelectedDay(where);
363 // on success
364 if (fSelectedDay != fNewSelectedDay) {
365 // update focus
366 fFocusChanged = true;
367 fNewFocusedDay = fNewSelectedDay;
368 Draw(_RectOfDay(fFocusedDay));
369 fFocusChanged = false;
371 // update selection
372 fSelectionChanged = true;
373 Draw(frame);
374 Draw(_RectOfDay(fSelectedDay));
375 fSelectionChanged = false;
377 // notify that selection changed
378 InvokeNotify(SelectionMessage(), B_CONTROL_MODIFIED);
381 int32 clicks;
382 // on double click invoke
383 BMessage* message = Looper()->CurrentMessage();
384 if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1)
385 Invoke();
389 void
390 BCalendarView::KeyDown(const char* bytes, int32 numBytes)
392 const int32 kRows = 6;
393 const int32 kColumns = 7;
395 int32 row = fFocusedDay.row;
396 int32 column = fFocusedDay.column;
398 switch (bytes[0]) {
399 case B_LEFT_ARROW:
400 column -= 1;
401 if (column < 0) {
402 column = kColumns - 1;
403 row -= 1;
404 if (row >= 0)
405 fFocusChanged = true;
406 } else
407 fFocusChanged = true;
408 break;
410 case B_RIGHT_ARROW:
411 column += 1;
412 if (column == kColumns) {
413 column = 0;
414 row += 1;
415 if (row < kRows)
416 fFocusChanged = true;
417 } else
418 fFocusChanged = true;
419 break;
421 case B_UP_ARROW:
422 row -= 1;
423 if (row >= 0)
424 fFocusChanged = true;
425 break;
427 case B_DOWN_ARROW:
428 row += 1;
429 if (row < kRows)
430 fFocusChanged = true;
431 break;
433 case B_PAGE_UP:
435 BDate date(fDate);
436 date.AddMonths(-1);
437 SetDate(date);
439 Invoke();
440 break;
443 case B_PAGE_DOWN:
445 BDate date(fDate);
446 date.AddMonths(1);
447 SetDate(date);
449 Invoke();
450 break;
453 case B_RETURN:
454 case B_SPACE:
456 fSelectionChanged = true;
457 BPoint pt = _RectOfDay(fFocusedDay).LeftTop();
458 Draw(_SetNewSelectedDay(pt + BPoint(4.0, 4.0)));
459 Draw(_RectOfDay(fSelectedDay));
460 fSelectionChanged = false;
462 Invoke();
463 break;
466 default:
467 BView::KeyDown(bytes, numBytes);
468 break;
471 if (fFocusChanged) {
472 fNewFocusedDay.SetTo(row, column);
473 Draw(_RectOfDay(fFocusedDay));
474 Draw(_RectOfDay(fNewFocusedDay));
475 fFocusChanged = false;
480 void
481 BCalendarView::Pulse()
483 _UpdateCurrentDate();
487 void
488 BCalendarView::ResizeToPreferred()
490 float width;
491 float height;
493 GetPreferredSize(&width, &height);
494 BView::ResizeTo(width, height);
498 void
499 BCalendarView::GetPreferredSize(float* width, float* height)
501 _GetPreferredSize(width, height);
505 BSize
506 BCalendarView::MaxSize()
508 return BLayoutUtils::ComposeSize(ExplicitMaxSize(),
509 BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
513 BSize
514 BCalendarView::MinSize()
516 float width, height;
517 _GetPreferredSize(&width, &height);
518 return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(width, height));
522 BSize
523 BCalendarView::PreferredSize()
525 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize());
529 int32
530 BCalendarView::Day() const
532 return fDate.Day();
536 int32
537 BCalendarView::Year() const
539 int32 year;
540 _GetYearMonthForSelection(fSelectedDay, &year, NULL);
542 return year;
546 int32
547 BCalendarView::Month() const
549 int32 month;
550 _GetYearMonthForSelection(fSelectedDay, NULL, &month);
552 return month;
556 bool
557 BCalendarView::SetDay(int32 day)
559 BDate date = Date();
560 date.SetDay(day);
561 if (!date.IsValid())
562 return false;
563 SetDate(date);
564 return true;
568 bool
569 BCalendarView::SetMonth(int32 month)
571 if (month < 1 || month > 12)
572 return false;
573 BDate date = Date();
574 int32 oldDay = date.Day();
576 date.SetMonth(month);
577 date.SetDay(1); // make sure the date is valid
579 // We must make sure that the day in month fits inside the new month.
580 if (oldDay > date.DaysInMonth())
581 date.SetDay(date.DaysInMonth());
582 else
583 date.SetDay(oldDay);
584 SetDate(date);
585 return true;
589 bool
590 BCalendarView::SetYear(int32 year)
592 BDate date = Date();
594 // This can fail when going from 29 feb. on a leap year to a non-leap year.
595 if (date.Month() == 2 && date.Day() == 29 && !date.IsLeapYear(year))
596 date.SetDay(28);
598 // TODO we should also handle the "hole" at the switch between Julian and
599 // Gregorian calendars, which will result in an invalid date.
601 date.SetYear(year);
602 SetDate(date);
603 return true;
607 BDate
608 BCalendarView::Date() const
610 int32 year;
611 int32 month;
612 _GetYearMonthForSelection(fSelectedDay, &year, &month);
613 return BDate(year, month, fDate.Day());
617 bool
618 BCalendarView::SetDate(const BDate& date)
620 if (!date.IsValid())
621 return false;
623 if (fDate == date)
624 return true;
626 if (fDate.Year() == date.Year() && fDate.Month() == date.Month()) {
627 fDate = date;
629 _SetToDay();
630 // update focus
631 fFocusChanged = true;
632 Draw(_RectOfDay(fFocusedDay));
633 fFocusChanged = false;
635 // update selection
636 fSelectionChanged = true;
637 Draw(_RectOfDay(fSelectedDay));
638 Draw(_RectOfDay(fNewSelectedDay));
639 fSelectionChanged = false;
640 } else {
641 fDate = date;
643 _SetupDayNumbers();
644 _SetupWeekNumbers();
646 BRect frame = Bounds();
647 if (fDayNameHeaderVisible)
648 frame.top += frame.Height() / 7 - 1.0;
650 if (fWeekNumberHeaderVisible)
651 frame.left += frame.Width() / 8 - 1.0;
653 Draw(frame.InsetBySelf(4.0, 4.0));
656 return true;
660 bool
661 BCalendarView::SetDate(int32 year, int32 month, int32 day)
663 return SetDate(BDate(year, month, day));
667 BWeekday
668 BCalendarView::StartOfWeek() const
670 return BWeekday(fStartOfWeek);
674 void
675 BCalendarView::SetStartOfWeek(BWeekday startOfWeek)
677 if (fStartOfWeek == (int32)startOfWeek)
678 return;
680 fStartOfWeek = (int32)startOfWeek;
682 _SetupDayNames();
683 _SetupDayNumbers();
684 _SetupWeekNumbers();
686 Invalidate(Bounds().InsetBySelf(1.0, 1.0));
690 bool
691 BCalendarView::IsDayNameHeaderVisible() const
693 return fDayNameHeaderVisible;
697 void
698 BCalendarView::SetDayNameHeaderVisible(bool visible)
700 if (fDayNameHeaderVisible == visible)
701 return;
703 fDayNameHeaderVisible = visible;
704 Invalidate(Bounds().InsetBySelf(1.0, 1.0));
708 void
709 BCalendarView::UpdateDayNameHeader()
711 if (!fDayNameHeaderVisible)
712 return;
714 _SetupDayNames();
715 Invalidate(Bounds().InsetBySelf(1.0, 1.0));
719 bool
720 BCalendarView::IsWeekNumberHeaderVisible() const
722 return fWeekNumberHeaderVisible;
726 void
727 BCalendarView::SetWeekNumberHeaderVisible(bool visible)
729 if (fWeekNumberHeaderVisible == visible)
730 return;
732 fWeekNumberHeaderVisible = visible;
733 Invalidate(Bounds().InsetBySelf(1.0, 1.0));
737 void
738 BCalendarView::_InitObject()
740 fDate = BDate::CurrentDate(B_LOCAL_TIME);
742 BDateFormat().GetStartOfWeek((BWeekday*)&fStartOfWeek);
744 _SetupDayNames();
745 _SetupDayNumbers();
746 _SetupWeekNumbers();
750 void
751 BCalendarView::_SetToDay()
753 BDate date(fDate.Year(), fDate.Month(), 1);
754 if (!date.IsValid())
755 return;
757 const int32 firstDayOffset = (7 + date.DayOfWeek() - fStartOfWeek) % 7;
759 int32 day = 1 - firstDayOffset;
760 for (int32 row = 0; row < 6; ++row) {
761 for (int32 column = 0; column < 7; ++column) {
762 if (day == fDate.Day()) {
763 fNewFocusedDay.SetTo(row, column);
764 fNewSelectedDay.SetTo(row, column);
765 return;
767 day++;
771 fNewFocusedDay.SetTo(0, 0);
772 fNewSelectedDay.SetTo(0, 0);
776 void
777 BCalendarView::_SetToCurrentDay()
779 BDate date(fCurrentDate.Year(), fCurrentDate.Month(), 1);
780 if (!date.IsValid())
781 return;
782 if (fDate.Year() != date.Year() || fDate.Month() != date.Month()) {
783 fNewCurrentDay.SetTo(-1, -1);
784 return;
786 const int32 firstDayOffset = (7 + date.DayOfWeek() - fStartOfWeek) % 7;
788 int32 day = 1 - firstDayOffset;
789 for (int32 row = 0; row < 6; ++row) {
790 for (int32 column = 0; column < 7; ++column) {
791 if (day == fCurrentDate.Day()) {
792 fNewCurrentDay.SetTo(row, column);
793 return;
795 day++;
799 fNewCurrentDay.SetTo(-1, -1);
803 void
804 BCalendarView::_GetYearMonthForSelection(const Selection& selection,
805 int32* year, int32* month) const
807 BDate startOfMonth(fDate.Year(), fDate.Month(), 1);
808 const int32 firstDayOffset
809 = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7;
810 const int32 daysInMonth = startOfMonth.DaysInMonth();
812 BDate date(fDate);
813 const int32 dayOffset = selection.row * 7 + selection.column;
814 if (dayOffset < firstDayOffset)
815 date.AddMonths(-1);
816 else if (dayOffset >= firstDayOffset + daysInMonth)
817 date.AddMonths(1);
818 if (year != NULL)
819 *year = date.Year();
820 if (month != NULL)
821 *month = date.Month();
825 void
826 BCalendarView::_GetPreferredSize(float* _width, float* _height)
828 BFont font;
829 GetFont(&font);
830 font_height fontHeight;
831 font.GetHeight(&fontHeight);
833 const float height = FontHeight(this) + 4.0;
835 int32 rows = 7;
836 if (!fDayNameHeaderVisible)
837 rows = 6;
839 // height = font height * rows + 8 px border
840 *_height = height * rows + 8.0;
842 float width = 0.0;
843 for (int32 column = 0; column < 7; ++column) {
844 float tmp = StringWidth(fDayNames[column].String()) + 2.0;
845 width = tmp > width ? tmp : width;
848 int32 columns = 8;
849 if (!fWeekNumberHeaderVisible)
850 columns = 7;
852 // width = max width day name * 8 column + 8 px border
853 *_width = width * columns + 8.0;
857 void
858 BCalendarView::_SetupDayNames()
860 BDateFormatStyle style = B_LONG_DATE_FORMAT;
861 float width, height;
862 while (style != B_DATE_FORMAT_STYLE_COUNT) {
863 _PopulateDayNames(style);
864 GetPreferredSize(&width, &height);
865 if (width < Bounds().Width())
866 return;
867 style = static_cast<BDateFormatStyle>(static_cast<int>(style) + 1);
872 void
873 BCalendarView::_PopulateDayNames(BDateFormatStyle style)
875 for (int32 i = 0; i <= 6; ++i) {
876 fDayNames[i] = "";
877 BDateFormat().GetDayName(1 + (fStartOfWeek - 1 + i) % 7,
878 fDayNames[i], style);
883 void
884 BCalendarView::_SetupDayNumbers()
886 BDate startOfMonth(fDate.Year(), fDate.Month(), 1);
887 if (!startOfMonth.IsValid())
888 return;
890 fFocusedDay.SetTo(0, 0);
891 fSelectedDay.SetTo(0, 0);
892 fNewFocusedDay.SetTo(0, 0);
893 fCurrentDay.SetTo(-1, -1);
895 const int32 daysInMonth = startOfMonth.DaysInMonth();
896 const int32 firstDayOffset
897 = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7;
899 // calc the last day one month before
900 BDate lastDayInMonthBefore(startOfMonth);
901 lastDayInMonthBefore.AddDays(-1);
902 const int32 lastDayBefore = lastDayInMonthBefore.DaysInMonth();
904 int32 counter = 0;
905 int32 firstDayAfter = 1;
906 for (int32 row = 0; row < 6; ++row) {
907 for (int32 column = 0; column < 7; ++column) {
908 int32 day = 1 + counter - firstDayOffset;
909 if (counter < firstDayOffset)
910 day += lastDayBefore;
911 else if (counter >= firstDayOffset + daysInMonth)
912 day = firstDayAfter++;
913 else if (day == fDate.Day()) {
914 fFocusedDay.SetTo(row, column);
915 fSelectedDay.SetTo(row, column);
916 fNewFocusedDay.SetTo(row, column);
918 if (day == fCurrentDate.Day() && counter >= firstDayOffset
919 && counter < firstDayOffset + daysInMonth
920 && fDate.Month() == fCurrentDate.Month()
921 && fDate.Year() == fCurrentDate.Year())
922 fCurrentDay.SetTo(row, column);
924 counter++;
925 fDayNumbers[row][column].Truncate(0);
926 fDayNumbers[row][column] << day;
932 void
933 BCalendarView::_SetupWeekNumbers()
935 BDate date(fDate.Year(), fDate.Month(), 1);
936 if (!date.IsValid())
937 return;
939 for (int32 row = 0; row < 6; ++row) {
940 fWeekNumbers[row].SetTo("");
941 fWeekNumbers[row] << date.WeekNumber();
942 date.AddDays(7);
947 void
948 BCalendarView::_DrawDay(int32 currRow, int32 currColumn, int32 row,
949 int32 column, int32 counter, BRect frame, const char* text,
950 bool focus, bool highlight)
952 BDate startOfMonth(fDate.Year(), fDate.Month(), 1);
953 const int32 firstDayOffset
954 = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7;
955 const int32 daysMonth = startOfMonth.DaysInMonth();
957 bool enabled = true;
958 bool selected = false;
959 // check for the current date
960 if (currRow == row && currColumn == column) {
961 selected = true; // draw current date selected
962 if (counter <= firstDayOffset || counter > firstDayOffset + daysMonth) {
963 enabled = false; // days of month before or after
964 selected = false; // not selected but able to get focus
966 } else {
967 if (counter <= firstDayOffset || counter > firstDayOffset + daysMonth)
968 enabled = false; // days of month before or after
971 DrawDay(this, frame, text, selected, enabled, focus, highlight);
975 void
976 BCalendarView::_DrawDays()
978 BRect frame = _FirstCalendarItemFrame();
980 const int32 currRow = fSelectedDay.row;
981 const int32 currColumn = fSelectedDay.column;
983 const bool isFocus = IsFocus();
984 const int32 focusRow = fFocusedDay.row;
985 const int32 focusColumn = fFocusedDay.column;
987 const int32 highlightRow = fCurrentDay.row;
988 const int32 highlightColumn = fCurrentDay.column;
990 int32 counter = 0;
991 for (int32 row = 0; row < 6; ++row) {
992 BRect tmp = frame;
993 for (int32 column = 0; column < 7; ++column) {
994 counter++;
995 const char* day = fDayNumbers[row][column].String();
996 bool focus = isFocus && focusRow == row && focusColumn == column;
997 bool highlight = highlightRow == row && highlightColumn == column;
998 _DrawDay(currRow, currColumn, row, column, counter, tmp, day,
999 focus, highlight);
1001 tmp.OffsetBy(tmp.Width(), 0.0);
1003 frame.OffsetBy(0.0, frame.Height());
1008 void
1009 BCalendarView::_DrawFocusRect()
1011 BRect frame = _FirstCalendarItemFrame();
1013 const int32 currRow = fSelectedDay.row;
1014 const int32 currColumn = fSelectedDay.column;
1016 const int32 focusRow = fFocusedDay.row;
1017 const int32 focusColumn = fFocusedDay.column;
1019 const int32 highlightRow = fCurrentDay.row;
1020 const int32 highlightColumn = fCurrentDay.column;
1022 int32 counter = 0;
1023 for (int32 row = 0; row < 6; ++row) {
1024 BRect tmp = frame;
1025 for (int32 column = 0; column < 7; ++column) {
1026 counter++;
1027 if (fNewFocusedDay.row == row && fNewFocusedDay.column == column) {
1028 fFocusedDay.SetTo(row, column);
1030 bool focus = IsFocus() && true;
1031 bool highlight = highlightRow == row && highlightColumn == column;
1032 const char* day = fDayNumbers[row][column].String();
1033 _DrawDay(currRow, currColumn, row, column, counter, tmp, day,
1034 focus, highlight);
1035 } else if (focusRow == row && focusColumn == column) {
1036 const char* day = fDayNumbers[row][column].String();
1037 bool highlight = highlightRow == row && highlightColumn == column;
1038 _DrawDay(currRow, currColumn, row, column, counter, tmp, day,
1039 false, highlight);
1041 tmp.OffsetBy(tmp.Width(), 0.0);
1043 frame.OffsetBy(0.0, frame.Height());
1048 void
1049 BCalendarView::_DrawDayHeader()
1051 if (!fDayNameHeaderVisible)
1052 return;
1054 int32 offset = 1;
1055 int32 columns = 8;
1056 if (!fWeekNumberHeaderVisible) {
1057 offset = 0;
1058 columns = 7;
1061 BRect frame = Bounds();
1062 frame.right = frame.Width() / columns - 1.0;
1063 frame.bottom = frame.Height() / 7.0 - 2.0;
1064 frame.OffsetBy(4.0, 4.0);
1066 for (int32 i = 0; i < columns; ++i) {
1067 if (i == 0 && fWeekNumberHeaderVisible) {
1068 DrawDayName(this, frame, "");
1069 frame.OffsetBy(frame.Width(), 0.0);
1070 continue;
1072 DrawDayName(this, frame, fDayNames[i - offset].String());
1073 frame.OffsetBy(frame.Width(), 0.0);
1078 void
1079 BCalendarView::_DrawWeekHeader()
1081 if (!fWeekNumberHeaderVisible)
1082 return;
1084 int32 rows = 7;
1085 if (!fDayNameHeaderVisible)
1086 rows = 6;
1088 BRect frame = Bounds();
1089 frame.right = frame.Width() / 8.0 - 2.0;
1090 frame.bottom = frame.Height() / rows - 1.0;
1092 float offsetY = 4.0;
1093 if (fDayNameHeaderVisible)
1094 offsetY += frame.Height();
1096 frame.OffsetBy(4.0, offsetY);
1098 for (int32 row = 0; row < 6; ++row) {
1099 DrawWeekNumber(this, frame, fWeekNumbers[row].String());
1100 frame.OffsetBy(0.0, frame.Height());
1105 void
1106 BCalendarView::_DrawItem(BView* owner, BRect frame, const char* text,
1107 bool isSelected, bool isEnabled, bool focus, bool isHighlight)
1109 rgb_color lColor = LowColor();
1110 rgb_color highColor = HighColor();
1112 rgb_color textColor = ui_color(B_LIST_ITEM_TEXT_COLOR);
1113 rgb_color bgColor = ui_color(B_LIST_BACKGROUND_COLOR);
1114 float tintDisabled = B_LIGHTEN_2_TINT;
1115 float tintHighlight = B_LIGHTEN_1_TINT;
1117 if (textColor.red + textColor.green + textColor.blue > 125 * 3)
1118 tintDisabled = B_DARKEN_2_TINT;
1120 if (bgColor.red + bgColor.green + bgColor.blue > 125 * 3)
1121 tintHighlight = B_DARKEN_1_TINT;
1123 if (isSelected) {
1124 SetHighColor(ui_color(B_LIST_SELECTED_BACKGROUND_COLOR));
1125 textColor = ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR);
1126 } else if (isHighlight)
1127 SetHighColor(tint_color(bgColor, tintHighlight));
1128 else
1129 SetHighColor(bgColor);
1131 SetLowColor(HighColor());
1133 FillRect(frame.InsetByCopy(1.0, 1.0));
1135 if (focus) {
1136 rgb_color focusColor = keyboard_navigation_color();
1137 SetHighColor(focusColor);
1138 StrokeRect(frame.InsetByCopy(1.0, 1.0));
1140 if (!isSelected)
1141 textColor = focusColor;
1144 SetHighColor(textColor);
1145 if (!isEnabled)
1146 SetHighColor(tint_color(textColor, tintDisabled));
1148 float offsetH = frame.Width() / 2.0;
1149 float offsetV = frame.Height() / 2.0 + FontHeight(owner) / 2.0 - 2.0;
1151 BFont font(be_plain_font);
1152 if (isHighlight)
1153 font.SetFace(B_BOLD_FACE);
1154 else
1155 font.SetFace(B_REGULAR_FACE);
1156 SetFont(&font);
1158 DrawString(text, BPoint(frame.right - offsetH - StringWidth(text) / 2.0,
1159 frame.top + offsetV));
1161 SetLowColor(lColor);
1162 SetHighColor(highColor);
1166 void
1167 BCalendarView::_UpdateSelection()
1169 BRect frame = _FirstCalendarItemFrame();
1171 const int32 currRow = fSelectedDay.row;
1172 const int32 currColumn = fSelectedDay.column;
1174 const int32 focusRow = fFocusedDay.row;
1175 const int32 focusColumn = fFocusedDay.column;
1177 const int32 highlightRow = fCurrentDay.row;
1178 const int32 highlightColumn = fCurrentDay.column;
1180 int32 counter = 0;
1181 for (int32 row = 0; row < 6; ++row) {
1182 BRect tmp = frame;
1183 for (int32 column = 0; column < 7; ++column) {
1184 counter++;
1185 if (fNewSelectedDay.row == row
1186 && fNewSelectedDay.column == column) {
1187 fSelectedDay.SetTo(row, column);
1189 const char* day = fDayNumbers[row][column].String();
1190 bool focus = IsFocus() && focusRow == row
1191 && focusColumn == column;
1192 bool highlight = highlightRow == row && highlightColumn == column;
1193 _DrawDay(row, column, row, column, counter, tmp, day, focus, highlight);
1194 } else if (currRow == row && currColumn == column) {
1195 const char* day = fDayNumbers[row][column].String();
1196 bool focus = IsFocus() && focusRow == row
1197 && focusColumn == column;
1198 bool highlight = highlightRow == row && highlightColumn == column;
1199 _DrawDay(currRow, currColumn, -1, -1, counter, tmp, day, focus, highlight);
1201 tmp.OffsetBy(tmp.Width(), 0.0);
1203 frame.OffsetBy(0.0, frame.Height());
1208 void
1209 BCalendarView::_UpdateCurrentDay()
1211 BRect frame = _FirstCalendarItemFrame();
1213 const int32 selectRow = fSelectedDay.row;
1214 const int32 selectColumn = fSelectedDay.column;
1216 const int32 focusRow = fFocusedDay.row;
1217 const int32 focusColumn = fFocusedDay.column;
1219 const int32 currRow = fCurrentDay.row;
1220 const int32 currColumn = fCurrentDay.column;
1222 int32 counter = 0;
1223 for (int32 row = 0; row < 6; ++row) {
1224 BRect tmp = frame;
1225 for (int32 column = 0; column < 7; ++column) {
1226 counter++;
1227 if (fNewCurrentDay.row == row
1228 && fNewCurrentDay.column == column) {
1229 fCurrentDay.SetTo(row, column);
1231 const char* day = fDayNumbers[row][column].String();
1232 bool focus = IsFocus() && focusRow == row
1233 && focusColumn == column;
1234 bool isSelected = selectRow == row && selectColumn == column;
1235 if (isSelected)
1236 _DrawDay(row, column, row, column, counter, tmp, day, focus, true);
1237 else
1238 _DrawDay(row, column, -1, -1, counter, tmp, day, focus, true);
1240 } else if (currRow == row && currColumn == column) {
1241 const char* day = fDayNumbers[row][column].String();
1242 bool focus = IsFocus() && focusRow == row
1243 && focusColumn == column;
1244 bool isSelected = selectRow == row && selectColumn == column;
1245 if(isSelected)
1246 _DrawDay(currRow, currColumn, row, column, counter, tmp, day, focus, false);
1247 else
1248 _DrawDay(currRow, currColumn, -1, -1, counter, tmp, day, focus, false);
1250 tmp.OffsetBy(tmp.Width(), 0.0);
1252 frame.OffsetBy(0.0, frame.Height());
1257 void
1258 BCalendarView::_UpdateCurrentDate()
1260 BDate date = BDate::CurrentDate(B_LOCAL_TIME);
1262 if (!date.IsValid())
1263 return;
1264 if (date == fCurrentDate)
1265 return;
1267 fCurrentDate = date;
1269 _SetToCurrentDay();
1270 fCurrentDayChanged = true;
1271 Draw(_RectOfDay(fCurrentDay));
1272 Draw(_RectOfDay(fNewCurrentDay));
1273 fCurrentDayChanged = false;
1275 return;
1279 BRect
1280 BCalendarView::_FirstCalendarItemFrame() const
1282 int32 rows = 7;
1283 int32 columns = 8;
1285 if (!fDayNameHeaderVisible)
1286 rows = 6;
1288 if (!fWeekNumberHeaderVisible)
1289 columns = 7;
1291 BRect frame = Bounds();
1292 frame.right = frame.Width() / columns - 1.0;
1293 frame.bottom = frame.Height() / rows - 1.0;
1295 float offsetY = 4.0;
1296 if (fDayNameHeaderVisible)
1297 offsetY += frame.Height();
1299 float offsetX = 4.0;
1300 if (fWeekNumberHeaderVisible)
1301 offsetX += frame.Width();
1303 return frame.OffsetBySelf(offsetX, offsetY);
1307 BRect
1308 BCalendarView::_SetNewSelectedDay(const BPoint& where)
1310 BRect frame = _FirstCalendarItemFrame();
1312 int32 counter = 0;
1313 for (int32 row = 0; row < 6; ++row) {
1314 BRect tmp = frame;
1315 for (int32 column = 0; column < 7; ++column) {
1316 counter++;
1317 if (tmp.Contains(where)) {
1318 fNewSelectedDay.SetTo(row, column);
1319 int32 year;
1320 int32 month;
1321 _GetYearMonthForSelection(fNewSelectedDay, &year, &month);
1322 if (month == fDate.Month()) {
1323 // only change date if a day in the current month has been
1324 // selected
1325 int32 day = atoi(fDayNumbers[row][column].String());
1326 fDate.SetDate(year, month, day);
1328 return tmp;
1330 tmp.OffsetBy(tmp.Width(), 0.0);
1332 frame.OffsetBy(0.0, frame.Height());
1335 return frame;
1339 BRect
1340 BCalendarView::_RectOfDay(const Selection& selection) const
1342 BRect frame = _FirstCalendarItemFrame();
1344 int32 counter = 0;
1345 for (int32 row = 0; row < 6; ++row) {
1346 BRect tmp = frame;
1347 for (int32 column = 0; column < 7; ++column) {
1348 counter++;
1349 if (selection.row == row && selection.column == column)
1350 return tmp;
1351 tmp.OffsetBy(tmp.Width(), 0.0);
1353 frame.OffsetBy(0.0, frame.Height());
1356 return frame;
1360 } // namespace BPrivate