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