1 /* 2 * Copyright 2007-2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Julun <host.haiku@gmx.de> 7 */ 8 9 10 #include "CalendarView.h" 11 12 #include <stdlib.h> 13 14 #include <LayoutUtils.h> 15 #include <Window.h> 16 17 18 namespace BPrivate { 19 20 21 static float 22 FontHeight(const BView* view) 23 { 24 if (!view) 25 return 0.0; 26 27 BFont font; 28 view->GetFont(&font); 29 font_height fheight; 30 font.GetHeight(&fheight); 31 return ceilf(fheight.ascent + fheight.descent + fheight.leading); 32 } 33 34 35 // #pragma mark - 36 37 38 BCalendarView::BCalendarView(BRect frame, const char* name, uint32 resizeMask, 39 uint32 flags) 40 : 41 BView(frame, name, resizeMask, flags), 42 BInvoker(), 43 fSelectionMessage(NULL), 44 fDate(), 45 fFocusChanged(false), 46 fSelectionChanged(false), 47 fStartOfWeek((int32)B_WEEKDAY_MONDAY), 48 fDayNameHeaderVisible(true), 49 fWeekNumberHeaderVisible(true) 50 { 51 _InitObject(); 52 } 53 54 55 BCalendarView::BCalendarView(const char* name, uint32 flags) 56 : 57 BView(name, flags), 58 BInvoker(), 59 fSelectionMessage(NULL), 60 fDate(), 61 fFocusChanged(false), 62 fSelectionChanged(false), 63 fStartOfWeek((int32)B_WEEKDAY_MONDAY), 64 fDayNameHeaderVisible(true), 65 fWeekNumberHeaderVisible(true) 66 { 67 _InitObject(); 68 } 69 70 71 BCalendarView::~BCalendarView() 72 { 73 SetSelectionMessage(NULL); 74 } 75 76 77 BCalendarView::BCalendarView(BMessage* archive) 78 : 79 BView(archive), 80 BInvoker(), 81 fSelectionMessage(NULL), 82 fDate(archive), 83 fFocusChanged(false), 84 fSelectionChanged(false), 85 fStartOfWeek((int32)B_WEEKDAY_MONDAY), 86 fDayNameHeaderVisible(true), 87 fWeekNumberHeaderVisible(true) 88 { 89 if (archive->HasMessage("_invokeMsg")) { 90 BMessage* invokationMessage = new BMessage; 91 archive->FindMessage("_invokeMsg", invokationMessage); 92 SetInvocationMessage(invokationMessage); 93 } 94 95 if (archive->HasMessage("_selectMsg")) { 96 BMessage* selectionMessage = new BMessage; 97 archive->FindMessage("selectMsg", selectionMessage); 98 SetSelectionMessage(selectionMessage); 99 } 100 101 if (archive->FindInt32("_weekStart", &fStartOfWeek) != B_OK) 102 fStartOfWeek = (int32)B_WEEKDAY_MONDAY; 103 104 if (archive->FindBool("_dayHeader", &fDayNameHeaderVisible) != B_OK) 105 fDayNameHeaderVisible = true; 106 107 if (archive->FindBool("_weekHeader", &fWeekNumberHeaderVisible) != B_OK) 108 fWeekNumberHeaderVisible = true; 109 110 _SetupDayNames(); 111 _SetupDayNumbers(); 112 _SetupWeekNumbers(); 113 } 114 115 116 BArchivable* 117 BCalendarView::Instantiate(BMessage* archive) 118 { 119 if (validate_instantiation(archive, "BCalendarView")) 120 return new BCalendarView(archive); 121 122 return NULL; 123 } 124 125 126 status_t 127 BCalendarView::Archive(BMessage* archive, bool deep) const 128 { 129 status_t status = BView::Archive(archive, deep); 130 131 if (status == B_OK && InvocationMessage()) 132 status = archive->AddMessage("_invokeMsg", InvocationMessage()); 133 134 if (status == B_OK && SelectionMessage()) 135 status = archive->AddMessage("_selectMsg", SelectionMessage()); 136 137 if (status == B_OK) 138 status = fDate.Archive(archive); 139 140 if (status == B_OK) 141 status = archive->AddInt32("_weekStart", fStartOfWeek); 142 143 if (status == B_OK) 144 status = archive->AddBool("_dayHeader", fDayNameHeaderVisible); 145 146 if (status == B_OK) 147 status = archive->AddBool("_weekHeader", fWeekNumberHeaderVisible); 148 149 return status; 150 } 151 152 153 void 154 BCalendarView::AttachedToWindow() 155 { 156 BView::AttachedToWindow(); 157 158 if (!Messenger().IsValid()) 159 SetTarget(Window(), NULL); 160 } 161 162 163 void 164 BCalendarView::FrameResized(float width, float height) 165 { 166 Invalidate(Bounds()); 167 } 168 169 170 void 171 BCalendarView::Draw(BRect updateRect) 172 { 173 if (LockLooper()) { 174 if (fFocusChanged) { 175 _DrawFocusRect(); 176 UnlockLooper(); 177 return; 178 } 179 180 if (fSelectionChanged) { 181 _UpdateSelection(); 182 UnlockLooper(); 183 return; 184 } 185 186 _DrawDays(); 187 _DrawDayHeader(); 188 _DrawWeekHeader(); 189 190 rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR); 191 SetHighColor(tint_color(background, B_DARKEN_3_TINT)); 192 StrokeRect(Bounds()); 193 194 UnlockLooper(); 195 } 196 } 197 198 199 void 200 BCalendarView::DrawDay(BView* owner, BRect frame, const char* text, 201 bool isSelected, bool isEnabled, bool focus) 202 { 203 _DrawItem(owner, frame, text, isSelected, isEnabled, focus); 204 } 205 206 207 void 208 BCalendarView::DrawDayName(BView* owner, BRect frame, const char* text) 209 { 210 // we get the full rect, fake this as the internal function 211 // shrinks the frame to work properly when drawing a day item 212 _DrawItem(owner, frame.InsetByCopy(-1.0, -1.0), text, true); 213 } 214 215 216 void 217 BCalendarView::DrawWeekNumber(BView* owner, BRect frame, const char* text) 218 { 219 // we get the full rect, fake this as the internal function 220 // shrinks the frame to work properly when drawing a day item 221 _DrawItem(owner, frame.InsetByCopy(-1.0, -1.0), text, true); 222 } 223 224 225 uint32 226 BCalendarView::SelectionCommand() const 227 { 228 if (SelectionMessage()) 229 return SelectionMessage()->what; 230 231 return 0; 232 } 233 234 235 BMessage* 236 BCalendarView::SelectionMessage() const 237 { 238 return fSelectionMessage; 239 } 240 241 242 void 243 BCalendarView::SetSelectionMessage(BMessage* message) 244 { 245 delete fSelectionMessage; 246 fSelectionMessage = message; 247 } 248 249 250 uint32 251 BCalendarView::InvocationCommand() const 252 { 253 return BInvoker::Command(); 254 } 255 256 257 BMessage* 258 BCalendarView::InvocationMessage() const 259 { 260 return BInvoker::Message(); 261 } 262 263 264 void 265 BCalendarView::SetInvocationMessage(BMessage* message) 266 { 267 BInvoker::SetMessage(message); 268 } 269 270 271 void 272 BCalendarView::MakeFocus(bool state) 273 { 274 if (IsFocus() == state) 275 return; 276 277 BView::MakeFocus(state); 278 279 // TODO: solve this better 280 fFocusChanged = true; 281 Draw(_RectOfDay(fFocusedDay)); 282 fFocusChanged = false; 283 } 284 285 286 status_t 287 BCalendarView::Invoke(BMessage* message) 288 { 289 bool notify = false; 290 uint32 kind = InvokeKind(¬ify); 291 292 BMessage clone(kind); 293 status_t status = B_BAD_VALUE; 294 295 if (!message && !notify) 296 message = Message(); 297 298 if (!message) { 299 if (!IsWatched()) 300 return status; 301 } else 302 clone = *message; 303 304 clone.AddPointer("source", this); 305 clone.AddInt64("when", (int64)system_time()); 306 clone.AddMessenger("be:sender", BMessenger(this)); 307 308 int32 year; 309 int32 month; 310 _GetYearMonthForSelection(fSelectedDay, &year, &month); 311 312 clone.AddInt32("year", fDate.Year()); 313 clone.AddInt32("month", fDate.Month()); 314 clone.AddInt32("day", fDate.Day()); 315 316 if (message) 317 status = BInvoker::Invoke(&clone); 318 319 SendNotices(kind, &clone); 320 321 return status; 322 } 323 324 325 void 326 BCalendarView::MouseDown(BPoint where) 327 { 328 if (!IsFocus()) { 329 MakeFocus(); 330 Sync(); 331 Window()->UpdateIfNeeded(); 332 } 333 334 BRect frame = Bounds(); 335 if (fDayNameHeaderVisible) 336 frame.top += frame.Height() / 7 - 1.0; 337 338 if (fWeekNumberHeaderVisible) 339 frame.left += frame.Width() / 8 - 1.0; 340 341 if (!frame.Contains(where)) 342 return; 343 344 // try to set to new day 345 frame = _SetNewSelectedDay(where); 346 347 // on success 348 if (fSelectedDay != fNewSelectedDay) { 349 // update focus 350 fFocusChanged = true; 351 fNewFocusedDay = fNewSelectedDay; 352 Draw(_RectOfDay(fFocusedDay)); 353 fFocusChanged = false; 354 355 // update selection 356 fSelectionChanged = true; 357 Draw(frame); 358 Draw(_RectOfDay(fSelectedDay)); 359 fSelectionChanged = false; 360 361 // notify that selection changed 362 InvokeNotify(SelectionMessage(), B_CONTROL_MODIFIED); 363 } 364 365 int32 clicks; 366 // on double click invoke 367 BMessage* message = Looper()->CurrentMessage(); 368 if (message->FindInt32("clicks", &clicks) == B_OK && clicks > 1) 369 Invoke(); 370 } 371 372 373 void 374 BCalendarView::KeyDown(const char* bytes, int32 numBytes) 375 { 376 const int32 kRows = 6; 377 const int32 kColumns = 7; 378 379 int32 row = fFocusedDay.row; 380 int32 column = fFocusedDay.column; 381 382 switch (bytes[0]) { 383 case B_LEFT_ARROW: 384 column -= 1; 385 if (column < 0) { 386 column = kColumns - 1; 387 row -= 1; 388 if (row >= 0) 389 fFocusChanged = true; 390 } else 391 fFocusChanged = true; 392 break; 393 394 case B_RIGHT_ARROW: 395 column += 1; 396 if (column == kColumns) { 397 column = 0; 398 row += 1; 399 if (row < kRows) 400 fFocusChanged = true; 401 } else 402 fFocusChanged = true; 403 break; 404 405 case B_UP_ARROW: 406 row -= 1; 407 if (row >= 0) 408 fFocusChanged = true; 409 break; 410 411 case B_DOWN_ARROW: 412 row += 1; 413 if (row < kRows) 414 fFocusChanged = true; 415 break; 416 417 case B_PAGE_UP: 418 { 419 BDate date(fDate); 420 date.AddMonths(-1); 421 SetDate(date); 422 423 Invoke(); 424 break; 425 } 426 427 case B_PAGE_DOWN: 428 { 429 BDate date(fDate); 430 date.AddMonths(1); 431 SetDate(date); 432 433 Invoke(); 434 break; 435 } 436 437 case B_RETURN: 438 case B_SPACE: 439 { 440 fSelectionChanged = true; 441 BPoint pt = _RectOfDay(fFocusedDay).LeftTop(); 442 Draw(_SetNewSelectedDay(pt + BPoint(4.0, 4.0))); 443 Draw(_RectOfDay(fSelectedDay)); 444 fSelectionChanged = false; 445 446 Invoke(); 447 break; 448 } 449 450 default: 451 BView::KeyDown(bytes, numBytes); 452 break; 453 } 454 455 if (fFocusChanged) { 456 fNewFocusedDay.SetTo(row, column); 457 Draw(_RectOfDay(fFocusedDay)); 458 Draw(_RectOfDay(fNewFocusedDay)); 459 fFocusChanged = false; 460 } 461 } 462 463 464 void 465 BCalendarView::ResizeToPreferred() 466 { 467 float width; 468 float height; 469 470 GetPreferredSize(&width, &height); 471 BView::ResizeTo(width, height); 472 } 473 474 475 void 476 BCalendarView::GetPreferredSize(float* width, float* height) 477 { 478 _GetPreferredSize(width, height); 479 } 480 481 482 BSize 483 BCalendarView::MaxSize() 484 { 485 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), 486 BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED)); 487 } 488 489 490 BSize 491 BCalendarView::MinSize() 492 { 493 float width, height; 494 _GetPreferredSize(&width, &height); 495 return BLayoutUtils::ComposeSize(ExplicitMinSize(), BSize(width, height)); 496 } 497 498 499 BSize 500 BCalendarView::PreferredSize() 501 { 502 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), MinSize()); 503 } 504 505 506 int32 507 BCalendarView::Day() const 508 { 509 return fDate.Day(); 510 } 511 512 513 int32 514 BCalendarView::Year() const 515 { 516 int32 year; 517 _GetYearMonthForSelection(fSelectedDay, &year, NULL); 518 519 return year; 520 } 521 522 523 int32 524 BCalendarView::Month() const 525 { 526 int32 month; 527 _GetYearMonthForSelection(fSelectedDay, NULL, &month); 528 529 return month; 530 } 531 532 533 BDate 534 BCalendarView::Date() const 535 { 536 int32 year; 537 int32 month; 538 _GetYearMonthForSelection(fSelectedDay, &year, &month); 539 return BDate(year, month, fDate.Day()); 540 } 541 542 543 bool 544 BCalendarView::SetDate(const BDate& date) 545 { 546 if (!date.IsValid()) 547 return false; 548 549 if (fDate == date) 550 return true; 551 552 if (fDate.Year() == date.Year() && fDate.Month() == date.Month()) { 553 fDate = date; 554 555 _SetToDay(); 556 // update focus 557 fFocusChanged = true; 558 Draw(_RectOfDay(fFocusedDay)); 559 fFocusChanged = false; 560 561 // update selection 562 fSelectionChanged = true; 563 Draw(_RectOfDay(fSelectedDay)); 564 Draw(_RectOfDay(fNewSelectedDay)); 565 fSelectionChanged = false; 566 } else { 567 fDate = date; 568 569 _SetupDayNumbers(); 570 _SetupWeekNumbers(); 571 572 BRect frame = Bounds(); 573 if (fDayNameHeaderVisible) 574 frame.top += frame.Height() / 7 - 1.0; 575 576 if (fWeekNumberHeaderVisible) 577 frame.left += frame.Width() / 8 - 1.0; 578 579 Draw(frame.InsetBySelf(4.0, 4.0)); 580 } 581 582 return true; 583 } 584 585 586 bool 587 BCalendarView::SetDate(int32 year, int32 month, int32 day) 588 { 589 return SetDate(BDate(year, month, day)); 590 } 591 592 593 BWeekday 594 BCalendarView::StartOfWeek() const 595 { 596 return BWeekday(fStartOfWeek); 597 } 598 599 600 void 601 BCalendarView::SetStartOfWeek(BWeekday startOfWeek) 602 { 603 if (fStartOfWeek == (int32)startOfWeek) 604 return; 605 606 fStartOfWeek = (int32)startOfWeek; 607 608 _SetupDayNames(); 609 _SetupDayNumbers(); 610 _SetupWeekNumbers(); 611 612 Invalidate(Bounds().InsetBySelf(1.0, 1.0)); 613 } 614 615 616 bool 617 BCalendarView::IsDayNameHeaderVisible() const 618 { 619 return fDayNameHeaderVisible; 620 } 621 622 623 void 624 BCalendarView::SetDayNameHeaderVisible(bool visible) 625 { 626 if (fDayNameHeaderVisible == visible) 627 return; 628 629 fDayNameHeaderVisible = visible; 630 Invalidate(Bounds().InsetBySelf(1.0, 1.0)); 631 } 632 633 634 bool 635 BCalendarView::IsWeekNumberHeaderVisible() const 636 { 637 return fWeekNumberHeaderVisible; 638 } 639 640 641 void 642 BCalendarView::SetWeekNumberHeaderVisible(bool visible) 643 { 644 if (fWeekNumberHeaderVisible == visible) 645 return; 646 647 fWeekNumberHeaderVisible = visible; 648 Invalidate(Bounds().InsetBySelf(1.0, 1.0)); 649 } 650 651 652 void 653 BCalendarView::_InitObject() 654 { 655 fDate = BDate::CurrentDate(B_LOCAL_TIME); 656 657 BLocale::Default()->GetStartOfWeek((BWeekday*)&fStartOfWeek); 658 659 _SetupDayNames(); 660 _SetupDayNumbers(); 661 _SetupWeekNumbers(); 662 } 663 664 665 void 666 BCalendarView::_SetToDay() 667 { 668 BDate date(fDate.Year(), fDate.Month(), 1); 669 if (!date.IsValid()) 670 return; 671 672 const int32 firstDayOffset = (7 + date.DayOfWeek() - fStartOfWeek) % 7; 673 674 int32 day = 1 - firstDayOffset; 675 for (int32 row = 0; row < 6; ++row) { 676 for (int32 column = 0; column < 7; ++column) { 677 if (day == fDate.Day()) { 678 fNewFocusedDay.SetTo(row, column); 679 fNewSelectedDay.SetTo(row, column); 680 return; 681 } 682 day++; 683 } 684 } 685 686 fNewFocusedDay.SetTo(0, 0); 687 fNewSelectedDay.SetTo(0, 0); 688 } 689 690 691 void 692 BCalendarView::_GetYearMonthForSelection(const Selection& selection, 693 int32* year, int32* month) const 694 { 695 BDate startOfMonth(fDate.Year(), fDate.Month(), 1); 696 const int32 firstDayOffset 697 = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7; 698 const int32 daysInMonth = startOfMonth.DaysInMonth(); 699 700 BDate date(fDate); 701 const int32 dayOffset = selection.row * 7 + selection.column; 702 if (dayOffset < firstDayOffset) 703 date.AddMonths(-1); 704 else if (dayOffset >= firstDayOffset + daysInMonth) 705 date.AddMonths(1); 706 if (year != NULL) 707 *year = date.Year(); 708 if (month != NULL) 709 *month = date.Month(); 710 } 711 712 713 void 714 BCalendarView::_GetPreferredSize(float* _width, float* _height) 715 { 716 BFont font; 717 GetFont(&font); 718 font_height fontHeight; 719 font.GetHeight(&fontHeight); 720 721 const float height = FontHeight(this) + 4.0; 722 723 int32 rows = 7; 724 if (!fDayNameHeaderVisible) 725 rows = 6; 726 727 // height = font height * rows + 8 px border 728 *_height = height * rows + 8.0; 729 730 float width = 0.0; 731 for (int32 column = 0; column < 7; ++column) { 732 float tmp = StringWidth(fDayNames[column].String()) + 2.0; 733 width = tmp > width ? tmp : width; 734 } 735 736 int32 columns = 8; 737 if (!fWeekNumberHeaderVisible) 738 columns = 7; 739 740 // width = max width day name * 8 column + 8 px border 741 *_width = width * columns + 8.0; 742 } 743 744 745 void 746 BCalendarView::_SetupDayNames() 747 { 748 for (int32 i = 0; i <= 6; ++i) 749 fDayNames[i] = fDate.ShortDayName(1 + (fStartOfWeek - 1 + i) % 7); 750 } 751 752 753 void 754 BCalendarView::_SetupDayNumbers() 755 { 756 BDate startOfMonth(fDate.Year(), fDate.Month(), 1); 757 if (!startOfMonth.IsValid()) 758 return; 759 760 fFocusedDay.SetTo(0, 0); 761 fSelectedDay.SetTo(0, 0); 762 fNewFocusedDay.SetTo(0, 0); 763 764 const int32 daysInMonth = startOfMonth.DaysInMonth(); 765 const int32 firstDayOffset 766 = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7; 767 768 // calc the last day one month before 769 BDate lastDayInMonthBefore(startOfMonth); 770 lastDayInMonthBefore.AddDays(-1); 771 const int32 lastDayBefore = lastDayInMonthBefore.DaysInMonth(); 772 773 int32 counter = 0; 774 int32 firstDayAfter = 1; 775 for (int32 row = 0; row < 6; ++row) { 776 for (int32 column = 0; column < 7; ++column) { 777 int32 day = 1 + counter - firstDayOffset; 778 if (counter < firstDayOffset) 779 day += lastDayBefore; 780 else if (counter >= firstDayOffset + daysInMonth) 781 day = firstDayAfter++; 782 else if (day == fDate.Day()) { 783 fFocusedDay.SetTo(row, column); 784 fSelectedDay.SetTo(row, column); 785 fNewFocusedDay.SetTo(row, column); 786 } 787 counter++; 788 fDayNumbers[row][column].Truncate(0); 789 fDayNumbers[row][column] << day; 790 } 791 } 792 } 793 794 795 void 796 BCalendarView::_SetupWeekNumbers() 797 { 798 BDate date(fDate.Year(), fDate.Month(), 1); 799 if (!date.IsValid()) 800 return; 801 802 for (int32 row = 0; row < 6; ++row) { 803 fWeekNumbers[row].SetTo(""); 804 fWeekNumbers[row] << date.WeekNumber(); 805 date.AddDays(7); 806 } 807 } 808 809 810 void 811 BCalendarView::_DrawDay(int32 currRow, int32 currColumn, int32 row, 812 int32 column, int32 counter, BRect frame, const char* text, bool focus) 813 { 814 BDate startOfMonth(fDate.Year(), fDate.Month(), 1); 815 const int32 firstDayOffset 816 = (7 + startOfMonth.DayOfWeek() - fStartOfWeek) % 7; 817 const int32 daysMonth = startOfMonth.DaysInMonth(); 818 819 bool enabled = true; 820 bool selected = false; 821 // check for the current date 822 if (currRow == row && currColumn == column) { 823 selected = true; // draw current date selected 824 if (counter <= firstDayOffset || counter > firstDayOffset + daysMonth) { 825 enabled = false; // days of month before or after 826 selected = false; // not selected but able to get focus 827 } 828 } else { 829 if (counter <= firstDayOffset || counter > firstDayOffset + daysMonth) 830 enabled = false; // days of month before or after 831 } 832 833 DrawDay(this, frame, text, selected, enabled, focus); 834 } 835 836 837 void 838 BCalendarView::_DrawDays() 839 { 840 BRect frame = _FirstCalendarItemFrame(); 841 842 const int32 currRow = fSelectedDay.row; 843 const int32 currColumn = fSelectedDay.column; 844 845 const bool isFocus = IsFocus(); 846 const int32 focusRow = fFocusedDay.row; 847 const int32 focusColumn = fFocusedDay.column; 848 849 int32 counter = 0; 850 for (int32 row = 0; row < 6; ++row) { 851 BRect tmp = frame; 852 for (int32 column = 0; column < 7; ++column) { 853 counter++; 854 const char* day = fDayNumbers[row][column].String(); 855 bool focus = isFocus && focusRow == row && focusColumn == column; 856 _DrawDay(currRow, currColumn, row, column, counter, tmp, day, 857 focus); 858 859 tmp.OffsetBy(tmp.Width(), 0.0); 860 } 861 frame.OffsetBy(0.0, frame.Height()); 862 } 863 } 864 865 866 void 867 BCalendarView::_DrawFocusRect() 868 { 869 BRect frame = _FirstCalendarItemFrame(); 870 871 const int32 currRow = fSelectedDay.row; 872 const int32 currColumn = fSelectedDay.column; 873 874 const int32 focusRow = fFocusedDay.row; 875 const int32 focusColumn = fFocusedDay.column; 876 877 int32 counter = 0; 878 for (int32 row = 0; row < 6; ++row) { 879 BRect tmp = frame; 880 for (int32 column = 0; column < 7; ++column) { 881 counter++; 882 if (fNewFocusedDay.row == row && fNewFocusedDay.column == column) { 883 fFocusedDay.SetTo(row, column); 884 885 bool focus = IsFocus() && true; 886 const char* day = fDayNumbers[row][column].String(); 887 _DrawDay(currRow, currColumn, row, column, counter, tmp, day, 888 focus); 889 } else if (focusRow == row && focusColumn == column) { 890 const char* day = fDayNumbers[row][column].String(); 891 _DrawDay(currRow, currColumn, row, column, counter, tmp, day, 892 false); 893 } 894 tmp.OffsetBy(tmp.Width(), 0.0); 895 } 896 frame.OffsetBy(0.0, frame.Height()); 897 } 898 } 899 900 901 void 902 BCalendarView::_DrawDayHeader() 903 { 904 if (!fDayNameHeaderVisible) 905 return; 906 907 int32 offset = 1; 908 int32 columns = 8; 909 if (!fWeekNumberHeaderVisible) { 910 offset = 0; 911 columns = 7; 912 } 913 914 BRect frame = Bounds(); 915 frame.right = frame.Width() / columns - 1.0; 916 frame.bottom = frame.Height() / 7.0 - 2.0; 917 frame.OffsetBy(4.0, 4.0); 918 919 for (int32 i = 0; i < columns; ++i) { 920 if (i == 0 && fWeekNumberHeaderVisible) { 921 DrawDayName(this, frame, ""); 922 frame.OffsetBy(frame.Width(), 0.0); 923 continue; 924 } 925 DrawDayName(this, frame, fDayNames[i - offset].String()); 926 frame.OffsetBy(frame.Width(), 0.0); 927 } 928 } 929 930 931 void 932 BCalendarView::_DrawWeekHeader() 933 { 934 if (!fWeekNumberHeaderVisible) 935 return; 936 937 int32 rows = 7; 938 if (!fDayNameHeaderVisible) 939 rows = 6; 940 941 BRect frame = Bounds(); 942 frame.right = frame.Width() / 8.0 - 2.0; 943 frame.bottom = frame.Height() / rows - 1.0; 944 945 float offsetY = 4.0; 946 if (fDayNameHeaderVisible) 947 offsetY += frame.Height(); 948 949 frame.OffsetBy(4.0, offsetY); 950 951 for (int32 row = 0; row < 6; ++row) { 952 DrawWeekNumber(this, frame, fWeekNumbers[row].String()); 953 frame.OffsetBy(0.0, frame.Height()); 954 } 955 } 956 957 958 void 959 BCalendarView::_DrawItem(BView* owner, BRect frame, const char* text, 960 bool isSelected, bool isEnabled, bool focus) 961 { 962 rgb_color lColor = LowColor(); 963 rgb_color highColor = HighColor(); 964 965 rgb_color lowColor = { 255, 255, 255, 255 }; 966 967 if (isSelected) { 968 SetHighColor(tint_color(lowColor, B_DARKEN_2_TINT)); 969 SetLowColor(HighColor()); 970 } else 971 SetHighColor(lowColor); 972 973 FillRect(frame.InsetByCopy(1.0, 1.0)); 974 975 if (focus) { 976 SetHighColor(keyboard_navigation_color()); 977 StrokeRect(frame.InsetByCopy(1.0, 1.0)); 978 } 979 980 rgb_color black = { 0, 0, 0, 255 }; 981 SetHighColor(black); 982 if (!isEnabled) 983 SetHighColor(tint_color(black, B_LIGHTEN_2_TINT)); 984 985 float offsetH = frame.Width() / 2.0; 986 float offsetV = frame.Height() / 2.0 + FontHeight(owner) / 2.0 - 2.0; 987 988 DrawString(text, BPoint(frame.right - offsetH - StringWidth(text) / 2.0, 989 frame.top + offsetV)); 990 991 SetLowColor(lColor); 992 SetHighColor(highColor); 993 } 994 995 996 void 997 BCalendarView::_UpdateSelection() 998 { 999 BRect frame = _FirstCalendarItemFrame(); 1000 1001 const int32 currRow = fSelectedDay.row; 1002 const int32 currColumn = fSelectedDay.column; 1003 1004 const int32 focusRow = fFocusedDay.row; 1005 const int32 focusColumn = fFocusedDay.column; 1006 1007 int32 counter = 0; 1008 for (int32 row = 0; row < 6; ++row) { 1009 BRect tmp = frame; 1010 for (int32 column = 0; column < 7; ++column) { 1011 counter++; 1012 if (fNewSelectedDay.row == row 1013 && fNewSelectedDay.column == column) { 1014 fSelectedDay.SetTo(row, column); 1015 1016 const char* day = fDayNumbers[row][column].String(); 1017 bool focus = IsFocus() && focusRow == row 1018 && focusColumn == column; 1019 _DrawDay(row, column, row, column, counter, tmp, day, focus); 1020 } else if (currRow == row && currColumn == column) { 1021 const char* day = fDayNumbers[row][column].String(); 1022 bool focus = IsFocus() && focusRow == row 1023 && focusColumn == column; 1024 _DrawDay(currRow, currColumn, -1, -1, counter, tmp, day, focus); 1025 } 1026 tmp.OffsetBy(tmp.Width(), 0.0); 1027 } 1028 frame.OffsetBy(0.0, frame.Height()); 1029 } 1030 } 1031 1032 1033 BRect 1034 BCalendarView::_FirstCalendarItemFrame() const 1035 { 1036 int32 rows = 7; 1037 int32 columns = 8; 1038 1039 if (!fDayNameHeaderVisible) 1040 rows = 6; 1041 1042 if (!fWeekNumberHeaderVisible) 1043 columns = 7; 1044 1045 BRect frame = Bounds(); 1046 frame.right = frame.Width() / columns - 1.0; 1047 frame.bottom = frame.Height() / rows - 1.0; 1048 1049 float offsetY = 4.0; 1050 if (fDayNameHeaderVisible) 1051 offsetY += frame.Height(); 1052 1053 float offsetX = 4.0; 1054 if (fWeekNumberHeaderVisible) 1055 offsetX += frame.Width(); 1056 1057 return frame.OffsetBySelf(offsetX, offsetY); 1058 } 1059 1060 1061 BRect 1062 BCalendarView::_SetNewSelectedDay(const BPoint& where) 1063 { 1064 BRect frame = _FirstCalendarItemFrame(); 1065 1066 int32 counter = 0; 1067 for (int32 row = 0; row < 6; ++row) { 1068 BRect tmp = frame; 1069 for (int32 column = 0; column < 7; ++column) { 1070 counter++; 1071 if (tmp.Contains(where)) { 1072 fNewSelectedDay.SetTo(row, column); 1073 int32 year; 1074 int32 month; 1075 _GetYearMonthForSelection(fNewSelectedDay, &year, &month); 1076 if (month == fDate.Month()) { 1077 // only change date if a day in the current month has been 1078 // selected 1079 int32 day = atoi(fDayNumbers[row][column].String()); 1080 fDate.SetDate(year, month, day); 1081 } 1082 return tmp; 1083 } 1084 tmp.OffsetBy(tmp.Width(), 0.0); 1085 } 1086 frame.OffsetBy(0.0, frame.Height()); 1087 } 1088 1089 return frame; 1090 } 1091 1092 1093 BRect 1094 BCalendarView::_RectOfDay(const Selection& selection) const 1095 { 1096 BRect frame = _FirstCalendarItemFrame(); 1097 1098 int32 counter = 0; 1099 for (int32 row = 0; row < 6; ++row) { 1100 BRect tmp = frame; 1101 for (int32 column = 0; column < 7; ++column) { 1102 counter++; 1103 if (selection.row == row && selection.column == column) 1104 return tmp; 1105 tmp.OffsetBy(tmp.Width(), 0.0); 1106 } 1107 frame.OffsetBy(0.0, frame.Height()); 1108 } 1109 1110 return frame; 1111 } 1112 1113 1114 } // namespace BPrivate 1115