1 /* 2 * Copyright 2001-2005, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Frans van Nispen (xlr8@tref.nl) 7 * Stephan Aßmus <superstippi@gmx.de> 8 * Ingo Weinhold <bonefish@cs.tu-berlin.de> 9 */ 10 11 /** BTextControl displays text that can act like a control. */ 12 13 14 #include <stdio.h> 15 16 #include <AbstractLayoutItem.h> 17 #include <LayoutUtils.h> 18 #include <Message.h> 19 #include <Region.h> 20 #include <TextControl.h> 21 #include <Window.h> 22 23 #include "TextInput.h" 24 25 26 class BTextControl::LabelLayoutItem : public BAbstractLayoutItem { 27 public: 28 LabelLayoutItem(BTextControl* parent); 29 30 virtual bool IsVisible(); 31 virtual void SetVisible(bool visible); 32 33 virtual BRect Frame(); 34 virtual void SetFrame(BRect frame); 35 36 virtual BView* View(); 37 38 virtual BSize BaseMinSize(); 39 virtual BSize BaseMaxSize(); 40 virtual BSize BasePreferredSize(); 41 virtual BAlignment BaseAlignment(); 42 43 private: 44 BTextControl* fParent; 45 BRect fFrame; 46 }; 47 48 49 class BTextControl::TextViewLayoutItem : public BAbstractLayoutItem { 50 public: 51 TextViewLayoutItem(BTextControl* parent); 52 53 virtual bool IsVisible(); 54 virtual void SetVisible(bool visible); 55 56 virtual BRect Frame(); 57 virtual void SetFrame(BRect frame); 58 59 virtual BView* View(); 60 61 virtual BSize BaseMinSize(); 62 virtual BSize BaseMaxSize(); 63 virtual BSize BasePreferredSize(); 64 virtual BAlignment BaseAlignment(); 65 66 private: 67 BTextControl* fParent; 68 BRect fFrame; 69 }; 70 71 72 // #pragma mark - 73 74 75 BTextControl::BTextControl(BRect frame, const char *name, const char *label, 76 const char *text, BMessage *message, uint32 mask, 77 uint32 flags) 78 : BControl(frame, name, label, message, mask, flags | B_FRAME_EVENTS) 79 { 80 _InitData(label, text); 81 _ValidateLayout(); 82 } 83 84 85 BTextControl::BTextControl(const char *name, const char *label, 86 const char *text, BMessage *message, 87 uint32 flags) 88 : BControl(BRect(0, 0, -1, -1), name, label, message, B_FOLLOW_NONE, 89 flags | B_FRAME_EVENTS | B_SUPPORTS_LAYOUT) 90 { 91 _InitData(label, text); 92 _ValidateLayout(); 93 } 94 95 96 BTextControl::BTextControl(const char *label, 97 const char *text, BMessage *message) 98 : BControl(BRect(0, 0, -1, -1), NULL, label, message, B_FOLLOW_NONE, 99 B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS | B_SUPPORTS_LAYOUT) 100 { 101 _InitData(label, text); 102 _ValidateLayout(); 103 } 104 105 106 BTextControl::~BTextControl() 107 { 108 SetModificationMessage(NULL); 109 } 110 111 112 BTextControl::BTextControl(BMessage* archive) 113 : BControl(archive) 114 { 115 _InitData(Label(), NULL, archive); 116 117 int32 labelAlignment = B_ALIGN_LEFT; 118 int32 textAlignment = B_ALIGN_LEFT; 119 120 if (archive->HasInt32("_a_label")) 121 archive->FindInt32("_a_label", &labelAlignment); 122 123 if (archive->HasInt32("_a_text")) 124 archive->FindInt32("_a_text", &textAlignment); 125 126 SetAlignment((alignment)labelAlignment, (alignment)textAlignment); 127 128 if (archive->HasFloat("_divide")) 129 archive->FindFloat("_divide", &fDivider); 130 131 if (archive->HasMessage("_mod_msg")) { 132 BMessage* message = new BMessage; 133 archive->FindMessage("_mod_msg", message); 134 SetModificationMessage(message); 135 } 136 } 137 138 139 BArchivable * 140 BTextControl::Instantiate(BMessage *archive) 141 { 142 if (validate_instantiation(archive, "BTextControl")) 143 return new BTextControl(archive); 144 else 145 return NULL; 146 } 147 148 149 status_t 150 BTextControl::Archive(BMessage *data, bool deep) const 151 { 152 status_t ret = BControl::Archive(data, deep); 153 alignment labelAlignment, textAlignment; 154 155 GetAlignment(&labelAlignment, &textAlignment); 156 157 if (ret == B_OK) 158 ret = data->AddInt32("_a_label", labelAlignment); 159 if (ret == B_OK) 160 ret = data->AddInt32("_a_text", textAlignment); 161 if (ret == B_OK) 162 ret = data->AddFloat("_divide", Divider()); 163 164 if (ModificationMessage() && (ret == B_OK)) 165 ret = data->AddMessage("_mod_msg", ModificationMessage()); 166 167 return ret; 168 } 169 170 171 void 172 BTextControl::SetText(const char *text) 173 { 174 if (InvokeKind() != B_CONTROL_INVOKED) 175 return; 176 177 fText->SetText(text); 178 179 if (IsFocus()) 180 fText->SetInitialText(); 181 182 fText->Invalidate(); 183 } 184 185 186 const char * 187 BTextControl::Text() const 188 { 189 return fText->Text(); 190 } 191 192 193 void 194 BTextControl::SetValue(int32 value) 195 { 196 BControl::SetValue(value); 197 } 198 199 200 status_t 201 BTextControl::Invoke(BMessage *message) 202 { 203 return BControl::Invoke(message); 204 } 205 206 207 BTextView * 208 BTextControl::TextView() const 209 { 210 return fText; 211 } 212 213 214 void 215 BTextControl::SetModificationMessage(BMessage *message) 216 { 217 delete fModificationMessage; 218 fModificationMessage = message; 219 } 220 221 222 BMessage * 223 BTextControl::ModificationMessage() const 224 { 225 return fModificationMessage; 226 } 227 228 229 void 230 BTextControl::SetAlignment(alignment labelAlignment, alignment textAlignment) 231 { 232 fText->SetAlignment(textAlignment); 233 fText->AlignTextRect(); 234 235 if (fLabelAlign != labelAlignment) { 236 fLabelAlign = labelAlignment; 237 Invalidate(); 238 } 239 } 240 241 242 void 243 BTextControl::GetAlignment(alignment* _label, alignment* _text) const 244 { 245 if (_label) 246 *_label = fLabelAlign; 247 if (_text) 248 *_text = fText->Alignment(); 249 } 250 251 252 void 253 BTextControl::SetDivider(float dividingLine) 254 { 255 fDivider = floorf(dividingLine + 0.5); 256 257 _LayoutTextView(); 258 259 if (Window()) { 260 fText->Invalidate(); 261 Invalidate(); 262 } 263 } 264 265 266 float 267 BTextControl::Divider() const 268 { 269 return fDivider; 270 } 271 272 273 void 274 BTextControl::Draw(BRect updateRect) 275 { 276 rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR); 277 rgb_color lighten1 = tint_color(noTint, B_LIGHTEN_1_TINT); 278 rgb_color lighten2 = tint_color(noTint, B_LIGHTEN_2_TINT); 279 rgb_color lightenMax = tint_color(noTint, B_LIGHTEN_MAX_TINT); 280 rgb_color darken1 = tint_color(noTint, B_DARKEN_1_TINT); 281 rgb_color darken2 = tint_color(noTint, B_DARKEN_2_TINT); 282 rgb_color darken4 = tint_color(noTint, B_DARKEN_4_TINT); 283 rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR); 284 285 bool enabled = IsEnabled(); 286 bool active = false; 287 288 if (fText->IsFocus() && Window()->IsActive()) 289 active = true; 290 291 // outer bevel 292 293 BRect rect = fText->Frame(); 294 rect.InsetBy(-2, -2); 295 296 if (enabled) 297 SetHighColor(darken1); 298 else 299 SetHighColor(noTint); 300 301 StrokeLine(rect.LeftBottom(), rect.LeftTop()); 302 StrokeLine(rect.RightTop()); 303 304 if (enabled) 305 SetHighColor(lighten2); 306 else 307 SetHighColor(lighten1); 308 309 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), rect.RightBottom()); 310 StrokeLine(BPoint(rect.right, rect.top + 1.0f), rect.RightBottom()); 311 312 // inner bevel 313 314 rect.InsetBy(1.0f, 1.0f); 315 316 if (active) { 317 SetHighColor(navigationColor); 318 StrokeRect(rect); 319 } else { 320 if (enabled) 321 SetHighColor(darken4); 322 else 323 SetHighColor(darken2); 324 325 StrokeLine(rect.LeftTop(), rect.LeftBottom()); 326 StrokeLine(rect.LeftTop(), rect.RightTop()); 327 328 SetHighColor(noTint); 329 StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), rect.RightBottom()); 330 StrokeLine(BPoint(rect.right, rect.top + 1.0f)); 331 } 332 333 // label 334 335 if (Label()) { 336 font_height fontHeight; 337 GetFontHeight(&fontHeight); 338 339 float y = fontHeight.ascent + fText->Frame().top + 1; 340 float x; 341 342 float labelWidth = StringWidth(Label()); 343 switch (fLabelAlign) { 344 case B_ALIGN_RIGHT: 345 x = fDivider - labelWidth - 3.0f; 346 break; 347 348 case B_ALIGN_CENTER: 349 x = fDivider - labelWidth / 2.0f; 350 break; 351 352 default: 353 x = 3.0f; 354 break; 355 } 356 357 BRect labelArea(x, Bounds().top, x + labelWidth, Bounds().bottom); 358 if (x < fDivider && updateRect.Intersects(labelArea)) { 359 labelArea.right = fText->Frame().left - 3; 360 361 BRegion clipRegion(labelArea); 362 ConstrainClippingRegion(&clipRegion); 363 SetHighColor(IsEnabled() ? ui_color(B_CONTROL_TEXT_COLOR) 364 : tint_color(noTint, B_DISABLED_LABEL_TINT)); 365 DrawString(Label(), BPoint(x, y)); 366 } 367 } 368 } 369 370 371 void 372 BTextControl::MouseDown(BPoint where) 373 { 374 if (!fText->IsFocus()) { 375 fText->MakeFocus(true); 376 fText->SelectAll(); 377 } 378 } 379 380 381 void 382 BTextControl::AttachedToWindow() 383 { 384 BControl::AttachedToWindow(); 385 386 _UpdateTextViewColors(IsEnabled()); 387 fText->MakeEditable(IsEnabled()); 388 } 389 390 391 void 392 BTextControl::MakeFocus(bool state) 393 { 394 if (state != fText->IsFocus()) { 395 fText->MakeFocus(state); 396 397 if (state) 398 fText->SelectAll(); 399 } 400 } 401 402 403 void 404 BTextControl::SetEnabled(bool enabled) 405 { 406 if (IsEnabled() == enabled) 407 return; 408 409 if (Window()) { 410 fText->MakeEditable(enabled); 411 412 _UpdateTextViewColors(enabled); 413 414 fText->Invalidate(); 415 Window()->UpdateIfNeeded(); 416 } 417 418 BControl::SetEnabled(enabled); 419 } 420 421 422 void 423 BTextControl::GetPreferredSize(float *_width, float *_height) 424 { 425 if (_height) { 426 // we need enough space for the label and the child text view 427 font_height fontHeight; 428 GetFontHeight(&fontHeight); 429 float labelHeight = ceil(fontHeight.ascent + fontHeight.descent 430 + fontHeight.leading); 431 float textHeight = ceilf(fText->LineHeight(0)) + 4.0; 432 433 *_height = max_c(labelHeight, textHeight); 434 } 435 436 if (_width) { 437 // TODO: this one I need to find out 438 float width = 20.0f + ceilf(StringWidth(Label())); 439 if (width < Bounds().Width()) 440 width = Bounds().Width(); 441 *_width = width; 442 } 443 } 444 445 446 void 447 BTextControl::ResizeToPreferred() 448 { 449 // TODO: change divider? 450 BView::ResizeToPreferred(); 451 } 452 453 454 void 455 BTextControl::SetFlags(uint32 flags) 456 { 457 if (!fSkipSetFlags) { 458 // If the textview is navigable, set it to not navigable if needed 459 // Else if it is not navigable, set it to navigable if needed 460 if (fText->Flags() & B_NAVIGABLE) { 461 if (!(flags & B_NAVIGABLE)) 462 fText->SetFlags(fText->Flags() & ~B_NAVIGABLE); 463 464 } else { 465 if (flags & B_NAVIGABLE) 466 fText->SetFlags(fText->Flags() | B_NAVIGABLE); 467 } 468 469 // Don't make this one navigable 470 flags &= ~B_NAVIGABLE; 471 } 472 473 BView::SetFlags(flags); 474 } 475 476 477 void 478 BTextControl::MessageReceived(BMessage *msg) 479 { 480 switch(msg->what) { 481 case B_SET_PROPERTY: 482 case B_GET_PROPERTY: 483 // TODO 484 break; 485 default: 486 BControl::MessageReceived(msg); 487 break; 488 } 489 } 490 491 492 BHandler * 493 BTextControl::ResolveSpecifier(BMessage *msg, int32 index, 494 BMessage *specifier, int32 form, 495 const char *property) 496 { 497 /* 498 BPropertyInfo propInfo(prop_list); 499 BHandler *target = NULL; 500 501 if (propInfo.FindMatch(message, 0, specifier, what, property) < B_OK) 502 return BControl::ResolveSpecifier(message, index, specifier, what, 503 property); 504 else 505 return this; 506 */ 507 return BControl::ResolveSpecifier(msg, index, specifier, form, property); 508 } 509 510 511 status_t 512 BTextControl::GetSupportedSuites(BMessage *data) 513 { 514 return BControl::GetSupportedSuites(data); 515 } 516 517 518 void 519 BTextControl::MouseUp(BPoint pt) 520 { 521 BControl::MouseUp(pt); 522 } 523 524 525 void 526 BTextControl::MouseMoved(BPoint pt, uint32 code, const BMessage *msg) 527 { 528 BControl::MouseMoved(pt, code, msg); 529 } 530 531 532 void 533 BTextControl::DetachedFromWindow() 534 { 535 BControl::DetachedFromWindow(); 536 } 537 538 539 void 540 BTextControl::AllAttached() 541 { 542 BControl::AllAttached(); 543 } 544 545 546 void 547 BTextControl::AllDetached() 548 { 549 BControl::AllDetached(); 550 } 551 552 553 void 554 BTextControl::FrameMoved(BPoint newPosition) 555 { 556 BControl::FrameMoved(newPosition); 557 } 558 559 560 void 561 BTextControl::FrameResized(float width, float height) 562 { 563 BControl::FrameResized(width, height); 564 565 // changes in width 566 567 BRect bounds = Bounds(); 568 const float border = 2.0f; 569 570 if (bounds.Width() > fPreviousWidth) { 571 // invalidate the region between the old and the new right border 572 BRect rect = bounds; 573 rect.left += fPreviousWidth - border; 574 rect.right--; 575 Invalidate(rect); 576 } else if (bounds.Width() < fPreviousWidth) { 577 // invalidate the region of the new right border 578 BRect rect = bounds; 579 rect.left = rect.right - border; 580 Invalidate(rect); 581 } 582 583 // changes in height 584 585 if (bounds.Height() > fPreviousHeight) { 586 // invalidate the region between the old and the new bottom border 587 BRect rect = bounds; 588 rect.top += fPreviousHeight - border; 589 rect.bottom--; 590 Invalidate(rect); 591 } else if (bounds.Height() < fPreviousHeight) { 592 // invalidate the region of the new bottom border 593 BRect rect = bounds; 594 rect.top = rect.bottom - border; 595 Invalidate(rect); 596 } 597 598 fPreviousWidth = uint16(bounds.Width()); 599 fPreviousHeight = uint16(bounds.Height()); 600 } 601 602 603 void 604 BTextControl::WindowActivated(bool active) 605 { 606 if (fText->IsFocus()) { 607 // invalidate to remove/show focus indication 608 BRect rect = fText->Frame(); 609 rect.InsetBy(-1, -1); 610 Invalidate(rect); 611 612 // help out embedded text view which doesn't 613 // get notified of this 614 fText->Invalidate(); 615 } 616 } 617 618 619 status_t 620 BTextControl::Perform(perform_code d, void *arg) 621 { 622 return BControl::Perform(d, arg); 623 } 624 625 626 BLayoutItem* 627 BTextControl::CreateLabelLayoutItem() 628 { 629 if (!fLabelLayoutItem) 630 fLabelLayoutItem = new LabelLayoutItem(this); 631 return fLabelLayoutItem; 632 } 633 634 635 BLayoutItem* 636 BTextControl::CreateTextViewLayoutItem() 637 { 638 if (!fTextViewLayoutItem) 639 fTextViewLayoutItem = new TextViewLayoutItem(this); 640 return fTextViewLayoutItem; 641 } 642 643 644 void BTextControl::_ReservedTextControl1() {} 645 void BTextControl::_ReservedTextControl2() {} 646 void BTextControl::_ReservedTextControl3() {} 647 void BTextControl::_ReservedTextControl4() {} 648 649 650 BTextControl & 651 BTextControl::operator=(const BTextControl&) 652 { 653 return *this; 654 } 655 656 657 void 658 BTextControl::_UpdateTextViewColors(bool enabled) 659 { 660 rgb_color textColor; 661 rgb_color color; 662 BFont font; 663 664 fText->GetFontAndColor(0, &font); 665 666 if (enabled) 667 textColor = ui_color(B_DOCUMENT_TEXT_COLOR); 668 else { 669 textColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 670 B_DISABLED_LABEL_TINT); 671 } 672 673 fText->SetFontAndColor(&font, B_FONT_ALL, &textColor); 674 675 if (enabled) { 676 color = ui_color(B_DOCUMENT_BACKGROUND_COLOR); 677 } else { 678 color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 679 B_LIGHTEN_2_TINT); 680 } 681 682 fText->SetViewColor(color); 683 fText->SetLowColor(color); 684 } 685 686 687 void 688 BTextControl::_CommitValue() 689 { 690 } 691 692 693 void 694 BTextControl::_InitData(const char* label, const char* initialText, 695 BMessage* archive) 696 { 697 BRect bounds(Bounds()); 698 699 fText = NULL; 700 fModificationMessage = NULL; 701 fLabelAlign = B_ALIGN_LEFT; 702 fDivider = 0.0f; 703 fPreviousWidth = bounds.Width(); 704 fPreviousHeight = bounds.Height(); 705 fLabelLayoutItem = NULL; 706 fTextViewLayoutItem = NULL; 707 fSkipSetFlags = false; 708 709 int32 flags = 0; 710 711 BFont font(be_plain_font); 712 713 if (!archive || !archive->HasString("_fname")) 714 flags |= B_FONT_FAMILY_AND_STYLE; 715 716 if (!archive || !archive->HasFloat("_fflt")) 717 flags |= B_FONT_SIZE; 718 719 if (flags != 0) 720 SetFont(&font, flags); 721 722 if (label) 723 fDivider = floorf(bounds.Width() / 2.0f); 724 725 uint32 navigableFlags = Flags() & B_NAVIGABLE; 726 if (navigableFlags != 0) { 727 fSkipSetFlags = true; 728 SetFlags(Flags() & ~B_NAVIGABLE); 729 fSkipSetFlags = false; 730 } 731 732 if (archive) 733 fText = static_cast<_BTextInput_ *>(FindView("_input_")); 734 else { 735 BRect frame(fDivider, bounds.top, 736 bounds.right, bounds.bottom); 737 // we are stroking the frame around the text view, which 738 // is 2 pixels wide 739 frame.InsetBy(2.0, 3.0); 740 BRect textRect(frame.OffsetToCopy(B_ORIGIN)); 741 742 fText = new _BTextInput_(frame, textRect, 743 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 744 B_WILL_DRAW | B_FRAME_EVENTS | navigableFlags); 745 AddChild(fText); 746 747 SetText(initialText); 748 fText->SetAlignment(B_ALIGN_LEFT); 749 fText->AlignTextRect(); 750 } 751 } 752 753 754 void 755 BTextControl::_ValidateLayout() 756 { 757 float height; 758 BTextControl::GetPreferredSize(NULL, &height); 759 760 ResizeTo(Bounds().Width(), height); 761 762 _LayoutTextView(); 763 764 fPreviousHeight = Bounds().Height(); 765 } 766 767 768 void 769 BTextControl::_LayoutTextView() 770 { 771 BRect frame = Bounds(); 772 frame.left = fDivider; 773 // we are stroking the frame around the text view, which 774 // is 2 pixels wide 775 frame.InsetBy(2.0, 2.0); 776 fText->MoveTo(frame.left, frame.top); 777 fText->ResizeTo(frame.Width(), frame.Height()); 778 779 BRect textRect(frame.OffsetToCopy(B_ORIGIN)); 780 781 // the label font could require the control to be higher than 782 // necessary for the text view, we compensate this by layouting 783 // the text rect to be in the middle, normally this means there 784 // is one pixel spacing on each side 785 float lineHeight = ceilf(fText->LineHeight(0)); 786 textRect.InsetBy(1, floorf((frame.Height() - lineHeight) / 2)); 787 fText->SetTextRect(textRect); 788 } 789 790 791 void 792 BTextControl::_UpdateFrame() 793 { 794 if (fLabelLayoutItem && fTextViewLayoutItem) { 795 BRect labelFrame = fLabelLayoutItem->Frame(); 796 BRect textFrame = fTextViewLayoutItem->Frame(); 797 MoveTo(labelFrame.left, labelFrame.top); 798 ResizeTo(textFrame.left + textFrame.Width() - labelFrame.left, 799 textFrame.top + textFrame.Height() - labelFrame.top); 800 SetDivider(textFrame.left - labelFrame.left); 801 } 802 } 803 804 805 // #pragma mark - 806 807 808 BTextControl::LabelLayoutItem::LabelLayoutItem(BTextControl* parent) 809 : fParent(parent), 810 fFrame() 811 { 812 } 813 814 815 bool 816 BTextControl::LabelLayoutItem::IsVisible() 817 { 818 return !fParent->IsHidden(fParent); 819 } 820 821 822 void 823 BTextControl::LabelLayoutItem::SetVisible(bool visible) 824 { 825 // not allowed 826 } 827 828 829 BRect 830 BTextControl::LabelLayoutItem::Frame() 831 { 832 return fFrame; 833 } 834 835 836 void 837 BTextControl::LabelLayoutItem::SetFrame(BRect frame) 838 { 839 fFrame = frame; 840 fParent->_UpdateFrame(); 841 } 842 843 844 BView* 845 BTextControl::LabelLayoutItem::View() 846 { 847 return fParent; 848 } 849 850 851 BSize 852 BTextControl::LabelLayoutItem::BaseMinSize() 853 { 854 // TODO: Cache the info. Might be too expensive for this call. 855 const char* label = fParent->Label(); 856 if (!label) 857 return BSize(-1, -1); 858 859 BSize size; 860 fParent->GetPreferredSize(NULL, &size.height); 861 862 size.width = fParent->StringWidth(label) + 2 * 3 - 1; 863 864 return size; 865 } 866 867 868 BSize 869 BTextControl::LabelLayoutItem::BaseMaxSize() 870 { 871 return BaseMinSize(); 872 } 873 874 875 BSize 876 BTextControl::LabelLayoutItem::BasePreferredSize() 877 { 878 return BaseMinSize(); 879 } 880 881 882 BAlignment 883 BTextControl::LabelLayoutItem::BaseAlignment() 884 { 885 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 886 } 887 888 889 // #pragma mark - 890 891 892 BTextControl::TextViewLayoutItem::TextViewLayoutItem(BTextControl* parent) 893 : fParent(parent), 894 fFrame() 895 { 896 } 897 898 899 bool 900 BTextControl::TextViewLayoutItem::IsVisible() 901 { 902 return !fParent->IsHidden(fParent); 903 } 904 905 906 void 907 BTextControl::TextViewLayoutItem::SetVisible(bool visible) 908 { 909 // not allowed 910 } 911 912 913 BRect 914 BTextControl::TextViewLayoutItem::Frame() 915 { 916 return fFrame; 917 } 918 919 920 void 921 BTextControl::TextViewLayoutItem::SetFrame(BRect frame) 922 { 923 fFrame = frame; 924 fParent->_UpdateFrame(); 925 } 926 927 928 BView* 929 BTextControl::TextViewLayoutItem::View() 930 { 931 return fParent; 932 } 933 934 935 BSize 936 BTextControl::TextViewLayoutItem::BaseMinSize() 937 { 938 // TODO: Cache the info. Might be too expensive for this call. 939 BSize size; 940 fParent->GetPreferredSize(NULL, &size.height); 941 942 // mmh, some arbitrary minimal width 943 size.width = 30; 944 945 return size; 946 } 947 948 949 BSize 950 BTextControl::TextViewLayoutItem::BaseMaxSize() 951 { 952 BSize size(BaseMinSize()); 953 size.width = B_SIZE_UNLIMITED; 954 return size; 955 } 956 957 958 BSize 959 BTextControl::TextViewLayoutItem::BasePreferredSize() 960 { 961 BSize size(BaseMinSize()); 962 // puh, no idea... 963 size.width = 100; 964 return size; 965 } 966 967 968 BAlignment 969 BTextControl::TextViewLayoutItem::BaseAlignment() 970 { 971 return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT); 972 } 973 974