2 * Copyright 2001-2015, Haiku Inc.
3 * Distributed under the terms of the MIT License.
6 * Frans van Nispen (xlr8@tref.nl)
7 * Stephan Aßmus <superstippi@gmx.de>
8 * Ingo Weinhold <bonefish@cs.tu-berlin.de>
12 /*! BTextControl displays text that can act like a control. */
15 #include <TextControl.h>
19 #include <AbstractLayoutItem.h>
20 #include <ControlLook.h>
21 #include <LayoutUtils.h>
23 #include <PropertyInfo.h>
27 #include <binary_compatibility/Interface.h>
28 #include <binary_compatibility/Support.h>
30 #include "TextInput.h"
33 //#define TRACE_TEXT_CONTROL
34 #ifdef TRACE_TEXT_CONTROL
36 # include <FunctionTracer.h>
37 static int32 sFunctionDepth
= -1;
38 # define CALLED(x...) FunctionTracer _ft("BTextControl", __FUNCTION__, \
40 # define TRACE(x...) { BString _to; \
41 _to.Append(' ', (sFunctionDepth + 1) * 2); \
42 printf("%s", _to.String()); printf(x); }
50 const char* const kFrameField
= "BTextControl:layoutitem:frame";
51 const char* const kTextViewItemField
= "BTextControl:textViewItem";
52 const char* const kLabelItemField
= "BMenuField:labelItem";
56 static property_info sPropertyList
[] = {
59 { B_GET_PROPERTY
, B_SET_PROPERTY
},
60 { B_DIRECT_SPECIFIER
},
68 class BTextControl::LabelLayoutItem
: public BAbstractLayoutItem
{
70 LabelLayoutItem(BTextControl
* parent
);
71 LabelLayoutItem(BMessage
* from
);
73 virtual bool IsVisible();
74 virtual void SetVisible(bool visible
);
76 virtual BRect
Frame();
77 virtual void SetFrame(BRect frame
);
79 void SetParent(BTextControl
* parent
);
80 virtual BView
* View();
82 virtual BSize
BaseMinSize();
83 virtual BSize
BaseMaxSize();
84 virtual BSize
BasePreferredSize();
85 virtual BAlignment
BaseAlignment();
87 BRect
FrameInParent() const;
89 virtual status_t
Archive(BMessage
* into
, bool deep
= true) const;
90 static BArchivable
* Instantiate(BMessage
* from
);
93 BTextControl
* fParent
;
98 class BTextControl::TextViewLayoutItem
: public BAbstractLayoutItem
{
100 TextViewLayoutItem(BTextControl
* parent
);
101 TextViewLayoutItem(BMessage
* from
);
103 virtual bool IsVisible();
104 virtual void SetVisible(bool visible
);
106 virtual BRect
Frame();
107 virtual void SetFrame(BRect frame
);
109 void SetParent(BTextControl
* parent
);
110 virtual BView
* View();
112 virtual BSize
BaseMinSize();
113 virtual BSize
BaseMaxSize();
114 virtual BSize
BasePreferredSize();
115 virtual BAlignment
BaseAlignment();
117 BRect
FrameInParent() const;
119 virtual status_t
Archive(BMessage
* into
, bool deep
= true) const;
120 static BArchivable
* Instantiate(BMessage
* from
);
122 BTextControl
* fParent
;
127 struct BTextControl::LayoutData
{
128 LayoutData(float width
, float height
)
130 label_layout_item(NULL
),
131 text_view_layout_item(NULL
),
132 previous_width(width
),
133 previous_height(height
),
138 LabelLayoutItem
* label_layout_item
;
139 TextViewLayoutItem
* text_view_layout_item
;
140 float previous_width
; // used in FrameResized() for
141 float previous_height
; // invalidation
142 font_height font_info
;
151 static const int32 kFrameMargin
= 2;
152 static const int32 kLabelInputSpacing
= 3;
155 // #pragma mark - BTextControl
158 BTextControl::BTextControl(BRect frame
, const char* name
, const char* label
,
159 const char* text
, BMessage
* message
, uint32 resizeMask
, uint32 flags
)
161 BControl(frame
, name
, label
, message
, resizeMask
, flags
| B_FRAME_EVENTS
)
169 BTextControl::BTextControl(const char* name
, const char* label
,
170 const char* text
, BMessage
* message
, uint32 flags
)
172 BControl(name
, label
, message
, flags
| B_FRAME_EVENTS
)
180 BTextControl::BTextControl(const char* label
, const char* text
,
183 BControl(NULL
, label
, message
,
184 B_WILL_DRAW
| B_NAVIGABLE
| B_FRAME_EVENTS
)
192 BTextControl::~BTextControl()
194 SetModificationMessage(NULL
);
199 // #pragma mark - Archiving
202 BTextControl::BTextControl(BMessage
* archive
)
204 BControl(BUnarchiver::PrepareArchive(archive
))
206 BUnarchiver
unarchiver(archive
);
208 _InitData(Label(), archive
);
210 if (!BUnarchiver::IsArchiveManaged(archive
))
211 _InitText(NULL
, archive
);
214 if (archive
->HasFloat("_divide"))
215 err
= archive
->FindFloat("_divide", &fDivider
);
217 if (err
== B_OK
&& archive
->HasMessage("_mod_msg")) {
218 BMessage
* message
= new BMessage
;
219 err
= archive
->FindMessage("_mod_msg", message
);
220 SetModificationMessage(message
);
223 unarchiver
.Finish(err
);
228 BTextControl::Instantiate(BMessage
* archive
)
230 if (validate_instantiation(archive
, "BTextControl"))
231 return new BTextControl(archive
);
238 BTextControl::Archive(BMessage
* data
, bool deep
) const
240 BArchiver
archiver(data
);
241 status_t result
= BControl::Archive(data
, deep
);
243 alignment labelAlignment
;
244 alignment textAlignment
;
246 GetAlignment(&labelAlignment
, &textAlignment
);
249 result
= data
->AddInt32("_a_label", labelAlignment
);
252 result
= data
->AddInt32("_a_text", textAlignment
);
255 result
= data
->AddFloat("_divide", Divider());
257 if (result
== B_OK
&& ModificationMessage() != NULL
)
258 result
= data
->AddMessage("_mod_msg", ModificationMessage());
260 return archiver
.Finish(result
);
265 BTextControl::AllArchived(BMessage
* into
) const
267 BArchiver
archiver(into
);
270 if (archiver
.IsArchived(fLayoutData
->text_view_layout_item
)) {
271 err
= archiver
.AddArchivable(kTextViewItemField
,
272 fLayoutData
->text_view_layout_item
);
275 if (err
== B_OK
&& archiver
.IsArchived(fLayoutData
->label_layout_item
)) {
276 err
= archiver
.AddArchivable(kLabelItemField
,
277 fLayoutData
->label_layout_item
);
285 BTextControl::AllUnarchived(const BMessage
* from
)
288 if ((err
= BControl::AllUnarchived(from
)) != B_OK
)
291 _InitText(NULL
, from
);
293 BUnarchiver
unarchiver(from
);
294 if (unarchiver
.IsInstantiated(kTextViewItemField
)) {
295 err
= unarchiver
.FindObject(kTextViewItemField
,
296 BUnarchiver::B_DONT_ASSUME_OWNERSHIP
,
297 fLayoutData
->text_view_layout_item
);
300 fLayoutData
->text_view_layout_item
->SetParent(this);
305 if (unarchiver
.IsInstantiated(kLabelItemField
)) {
306 err
= unarchiver
.FindObject(kLabelItemField
,
307 BUnarchiver::B_DONT_ASSUME_OWNERSHIP
,
308 fLayoutData
->label_layout_item
);
311 fLayoutData
->label_layout_item
->SetParent(this);
317 // #pragma mark - Hook methods
321 BTextControl::AllAttached()
323 BControl::AllAttached();
328 BTextControl::AllDetached()
330 BControl::AllDetached();
335 BTextControl::AttachedToWindow()
337 BControl::AttachedToWindow();
339 _UpdateTextViewColors(IsEnabled());
340 fText
->MakeEditable(IsEnabled());
345 BTextControl::DetachedFromWindow()
347 BControl::DetachedFromWindow();
352 BTextControl::Draw(BRect updateRect
)
354 bool enabled
= IsEnabled();
355 bool active
= fText
->IsFocus() && Window()->IsActive();
357 BRect rect
= fText
->Frame();
358 rect
.InsetBy(-2, -2);
360 rgb_color base
= ui_color(B_PANEL_BACKGROUND_COLOR
);
361 uint32 flags
= fLook
;
363 flags
|= BControlLook::B_DISABLED
;
366 flags
|= BControlLook::B_FOCUSED
;
368 be_control_look
->DrawTextControlBorder(this, rect
, updateRect
, base
,
371 if (Label() != NULL
) {
372 if (fLayoutData
->label_layout_item
!= NULL
) {
373 rect
= fLayoutData
->label_layout_item
->FrameInParent();
376 rect
.right
= fDivider
- kLabelInputSpacing
;
379 be_control_look
->DrawLabel(this, Label(), rect
, updateRect
,
380 base
, flags
, BAlignment(fLabelAlign
, B_ALIGN_MIDDLE
));
386 BTextControl::FrameMoved(BPoint newPosition
)
388 BControl::FrameMoved(newPosition
);
393 BTextControl::FrameResized(float width
, float height
)
397 BControl::FrameResized(width
, height
);
399 // TODO: this causes flickering still...
403 BRect bounds
= Bounds();
405 if (bounds
.Width() > fLayoutData
->previous_width
) {
406 // invalidate the region between the old and the new right border
408 rect
.left
+= fLayoutData
->previous_width
- kFrameMargin
;
411 } else if (bounds
.Width() < fLayoutData
->previous_width
) {
412 // invalidate the region of the new right border
414 rect
.left
= rect
.right
- kFrameMargin
;
420 if (bounds
.Height() > fLayoutData
->previous_height
) {
421 // invalidate the region between the old and the new bottom border
423 rect
.top
+= fLayoutData
->previous_height
- kFrameMargin
;
426 // invalidate label area
428 rect
.right
= fDivider
;
430 } else if (bounds
.Height() < fLayoutData
->previous_height
) {
431 // invalidate the region of the new bottom border
433 rect
.top
= rect
.bottom
- kFrameMargin
;
435 // invalidate label area
437 rect
.right
= fDivider
;
441 fLayoutData
->previous_width
= bounds
.Width();
442 fLayoutData
->previous_height
= bounds
.Height();
444 TRACE("width: %.2f, height: %.2f\n", bounds
.Width(), bounds
.Height());
449 BTextControl::Invoke(BMessage
* message
)
451 return BControl::Invoke(message
);
456 BTextControl::LayoutInvalidated(bool descendants
)
460 fLayoutData
->valid
= false;
465 BTextControl::MessageReceived(BMessage
* message
)
467 if (message
->what
== B_GET_PROPERTY
|| message
->what
== B_SET_PROPERTY
) {
468 BMessage
reply(B_REPLY
);
469 bool handled
= false;
474 const char* property
;
475 if (message
->GetCurrentSpecifier(&index
, &specifier
, &form
, &property
) == B_OK
) {
476 if (strcmp(property
, "Value") == 0) {
477 if (message
->what
== B_GET_PROPERTY
) {
478 reply
.AddString("result", fText
->Text());
481 const char* value
= NULL
;
483 if (message
->FindString("data", &value
) == B_OK
) {
484 fText
->SetText(value
);
485 reply
.AddInt32("error", B_OK
);
493 message
->SendReply(&reply
);
498 BControl::MessageReceived(message
);
503 BTextControl::MouseDown(BPoint where
)
505 if (!fText
->IsFocus())
506 fText
->MakeFocus(true);
511 BTextControl::MouseMoved(BPoint where
, uint32 transit
,
512 const BMessage
* dragMessage
)
514 BControl::MouseMoved(where
, transit
, dragMessage
);
519 BTextControl::MouseUp(BPoint where
)
521 BControl::MouseUp(where
);
526 BTextControl::WindowActivated(bool active
)
528 if (fText
->IsFocus()) {
529 // invalidate to remove/show focus indication
530 BRect rect
= fText
->Frame();
531 rect
.InsetBy(-1, -1);
534 // help out embedded text view which doesn't
535 // get notified of this
541 // #pragma mark - Getters and Setters
545 BTextControl::SetText(const char* text
)
547 if (InvokeKind() != B_CONTROL_INVOKED
)
552 fText
->SetText(text
);
554 if (fText
->IsFocus()) {
555 fText
->SetInitialText();
564 BTextControl::Text() const
566 return fText
->Text();
571 BTextControl::TextLength() const
573 return fText
->TextLength();
578 BTextControl::MarkAsInvalid(bool invalid
)
583 fLook
|= BControlLook::B_INVALID
;
585 fLook
&= ~BControlLook::B_INVALID
;
593 BTextControl::SetValue(int32 value
)
595 BControl::SetValue(value
);
600 BTextControl::TextView() const
607 BTextControl::SetModificationMessage(BMessage
* message
)
609 delete fModificationMessage
;
610 fModificationMessage
= message
;
615 BTextControl::ModificationMessage() const
617 return fModificationMessage
;
622 BTextControl::SetAlignment(alignment labelAlignment
, alignment textAlignment
)
624 fText
->SetAlignment(textAlignment
);
625 fText
->AlignTextRect();
627 if (fLabelAlign
!= labelAlignment
) {
628 fLabelAlign
= labelAlignment
;
635 BTextControl::GetAlignment(alignment
* _label
, alignment
* _text
) const
638 *_label
= fLabelAlign
;
641 *_text
= fText
->Alignment();
646 BTextControl::SetDivider(float position
)
648 fDivider
= floorf(position
+ 0.5);
660 BTextControl::Divider() const
667 BTextControl::MakeFocus(bool state
)
669 if (state
!= fText
->IsFocus()) {
670 fText
->MakeFocus(state
);
679 BTextControl::SetEnabled(bool enable
)
681 if (IsEnabled() == enable
)
684 if (Window() != NULL
) {
685 fText
->MakeEditable(enable
);
687 fText
->SetFlags(fText
->Flags() | B_NAVIGABLE
);
689 fText
->SetFlags(fText
->Flags() & ~B_NAVIGABLE
);
691 _UpdateTextViewColors(enable
);
694 Window()->UpdateIfNeeded();
697 BControl::SetEnabled(enable
);
702 BTextControl::GetPreferredSize(float* _width
, float* _height
)
706 _ValidateLayoutData();
709 float minWidth
= fLayoutData
->min
.width
;
710 if (Label() == NULL
&& !(Flags() & B_SUPPORTS_LAYOUT
)) {
711 // Indeed, only if there is no label! BeOS backwards compatible
713 minWidth
= max_c(minWidth
, Bounds().Width());
719 *_height
= fLayoutData
->min
.height
;
724 BTextControl::ResizeToPreferred()
726 BView::ResizeToPreferred();
729 const char* label
= Label();
731 fDivider
= ceil(StringWidth(label
)) + 2.0;
738 BTextControl::SetFlags(uint32 flags
)
740 // If the textview is navigable, set it to not navigable if needed
741 // Else if it is not navigable, set it to navigable if needed
742 if (fText
->Flags() & B_NAVIGABLE
) {
743 if (!(flags
& B_NAVIGABLE
))
744 fText
->SetFlags(fText
->Flags() & ~B_NAVIGABLE
);
747 if (flags
& B_NAVIGABLE
)
748 fText
->SetFlags(fText
->Flags() | B_NAVIGABLE
);
751 // Don't make this one navigable
752 flags
&= ~B_NAVIGABLE
;
754 BView::SetFlags(flags
);
758 // #pragma mark - Scripting
762 BTextControl::ResolveSpecifier(BMessage
* message
, int32 index
,
763 BMessage
* specifier
, int32 what
, const char* property
)
765 BPropertyInfo
propInfo(sPropertyList
);
767 if (propInfo
.FindMatch(message
, 0, specifier
, what
, property
) >= B_OK
)
770 return BControl::ResolveSpecifier(message
, index
, specifier
, what
,
776 BTextControl::GetSupportedSuites(BMessage
* data
)
778 return BControl::GetSupportedSuites(data
);
782 // #pragma mark - Layout
786 BTextControl::MinSize()
790 _ValidateLayoutData();
791 return BLayoutUtils::ComposeSize(ExplicitMinSize(), fLayoutData
->min
);
796 BTextControl::MaxSize()
800 _ValidateLayoutData();
802 BSize max
= fLayoutData
->min
;
803 max
.width
= B_SIZE_UNLIMITED
;
805 return BLayoutUtils::ComposeSize(ExplicitMaxSize(), max
);
810 BTextControl::PreferredSize()
814 _ValidateLayoutData();
815 return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), fLayoutData
->min
);
820 BTextControl::LayoutAlignment()
824 _ValidateLayoutData();
825 return BLayoutUtils::ComposeAlignment(ExplicitAlignment(),
826 BAlignment(B_ALIGN_LEFT
, B_ALIGN_VERTICAL_CENTER
));
831 BTextControl::CreateLabelLayoutItem()
833 if (!fLayoutData
->label_layout_item
)
834 fLayoutData
->label_layout_item
= new LabelLayoutItem(this);
836 return fLayoutData
->label_layout_item
;
841 BTextControl::CreateTextViewLayoutItem()
843 if (!fLayoutData
->text_view_layout_item
)
844 fLayoutData
->text_view_layout_item
= new TextViewLayoutItem(this);
846 return fLayoutData
->text_view_layout_item
;
851 BTextControl::DoLayout()
853 // Bail out, if we shan't do layout.
854 if (!(Flags() & B_SUPPORTS_LAYOUT
))
859 // If the user set a layout, we let the base class version call its
866 _ValidateLayoutData();
868 // validate current size
869 BSize
size(Bounds().Size());
870 if (size
.width
< fLayoutData
->min
.width
)
871 size
.width
= fLayoutData
->min
.width
;
873 if (size
.height
< fLayoutData
->min
.height
)
874 size
.height
= fLayoutData
->min
.height
;
876 BRect
dirty(fText
->Frame());
881 if (fLayoutData
->text_view_layout_item
!= NULL
) {
882 if (fLayoutData
->label_layout_item
!= NULL
) {
883 // We have layout items. They define the divider location.
884 divider
= fabs(fLayoutData
->text_view_layout_item
->Frame().left
885 - fLayoutData
->label_layout_item
->Frame().left
);
887 textFrame
= fLayoutData
->text_view_layout_item
->FrameInParent();
889 if (fLayoutData
->label_width
> 0) {
890 divider
= fLayoutData
->label_width
891 + be_control_look
->DefaultLabelSpacing();
893 textFrame
.Set(divider
, 0, size
.width
, size
.height
);
896 // place the text view and set the divider
897 textFrame
.InsetBy(kFrameMargin
, kFrameMargin
);
898 BLayoutUtils::AlignInFrame(fText
, textFrame
);
902 // invalidate dirty region
903 dirty
= dirty
| fText
->Frame();
904 dirty
.InsetBy(-kFrameMargin
, -kFrameMargin
);
910 // #pragma mark - protected methods
914 BTextControl::SetIcon(const BBitmap
* icon
, uint32 flags
)
916 return BControl::SetIcon(icon
, flags
);
920 // #pragma mark - private methods
924 BTextControl::Perform(perform_code code
, void* _data
)
927 case PERFORM_CODE_MIN_SIZE
:
928 ((perform_data_min_size
*)_data
)->return_value
929 = BTextControl::MinSize();
932 case PERFORM_CODE_MAX_SIZE
:
933 ((perform_data_max_size
*)_data
)->return_value
934 = BTextControl::MaxSize();
937 case PERFORM_CODE_PREFERRED_SIZE
:
938 ((perform_data_preferred_size
*)_data
)->return_value
939 = BTextControl::PreferredSize();
942 case PERFORM_CODE_LAYOUT_ALIGNMENT
:
943 ((perform_data_layout_alignment
*)_data
)->return_value
944 = BTextControl::LayoutAlignment();
947 case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH
:
948 ((perform_data_has_height_for_width
*)_data
)->return_value
949 = BTextControl::HasHeightForWidth();
952 case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH
:
954 perform_data_get_height_for_width
* data
955 = (perform_data_get_height_for_width
*)_data
;
956 BTextControl::GetHeightForWidth(data
->width
, &data
->min
, &data
->max
,
961 case PERFORM_CODE_SET_LAYOUT
:
963 perform_data_set_layout
* data
= (perform_data_set_layout
*)_data
;
964 BTextControl::SetLayout(data
->layout
);
968 case PERFORM_CODE_LAYOUT_INVALIDATED
:
970 perform_data_layout_invalidated
* data
971 = (perform_data_layout_invalidated
*)_data
;
972 BTextControl::LayoutInvalidated(data
->descendants
);
976 case PERFORM_CODE_DO_LAYOUT
:
978 BTextControl::DoLayout();
982 case PERFORM_CODE_SET_ICON
:
984 perform_data_set_icon
* data
= (perform_data_set_icon
*)_data
;
985 return BTextControl::SetIcon(data
->icon
, data
->flags
);
988 case PERFORM_CODE_ALL_UNARCHIVED
:
990 perform_data_all_unarchived
* data
991 = (perform_data_all_unarchived
*)_data
;
992 data
->return_value
= BTextControl::AllUnarchived(data
->archive
);
996 case PERFORM_CODE_ALL_ARCHIVED
:
998 perform_data_all_archived
* data
999 = (perform_data_all_archived
*)_data
;
1000 data
->return_value
= BTextControl::AllArchived(data
->archive
);
1005 return BControl::Perform(code
, _data
);
1009 // #pragma mark - FBC padding
1012 void BTextControl::_ReservedTextControl1() {}
1013 void BTextControl::_ReservedTextControl2() {}
1014 void BTextControl::_ReservedTextControl3() {}
1015 void BTextControl::_ReservedTextControl4() {}
1019 BTextControl::operator=(const BTextControl
&)
1026 BTextControl::_UpdateTextViewColors(bool enable
)
1028 rgb_color textColor
;
1032 fText
->GetFontAndColor(0, &font
);
1035 textColor
= ui_color(B_DOCUMENT_TEXT_COLOR
);
1037 textColor
= tint_color(ui_color(B_PANEL_BACKGROUND_COLOR
),
1038 B_DISABLED_LABEL_TINT
);
1041 fText
->SetFontAndColor(&font
, B_FONT_ALL
, &textColor
);
1044 color
= ui_color(B_DOCUMENT_BACKGROUND_COLOR
);
1046 color
= tint_color(ui_color(B_PANEL_BACKGROUND_COLOR
),
1050 fText
->SetViewColor(color
);
1051 fText
->SetLowColor(color
);
1056 BTextControl::_CommitValue()
1062 BTextControl::_InitData(const char* label
, const BMessage
* archive
)
1064 BRect
bounds(Bounds());
1067 fModificationMessage
= NULL
;
1068 fLabelAlign
= B_ALIGN_LEFT
;
1070 fLayoutData
= new LayoutData(bounds
.Width(), bounds
.Height());
1074 BFont
font(be_plain_font
);
1076 if (!archive
|| !archive
->HasString("_fname"))
1077 flags
|= B_FONT_FAMILY_AND_STYLE
;
1079 if (!archive
|| !archive
->HasFloat("_fflt"))
1080 flags
|= B_FONT_SIZE
;
1083 SetFont(&font
, flags
);
1086 fDivider
= floorf(bounds
.Width() / 2.0f
);
1093 BTextControl::_InitText(const char* initialText
, const BMessage
* archive
)
1096 fText
= static_cast<BPrivate::_BTextInput_
*>(FindView("_input_"));
1098 if (fText
== NULL
) {
1099 BRect
bounds(Bounds());
1100 BRect
frame(fDivider
, bounds
.top
, bounds
.right
, bounds
.bottom
);
1101 // we are stroking the frame around the text view, which
1103 frame
.InsetBy(kFrameMargin
, kFrameMargin
);
1104 BRect
textRect(frame
.OffsetToCopy(B_ORIGIN
));
1106 fText
= new BPrivate::_BTextInput_(frame
, textRect
,
1107 B_FOLLOW_ALL
, B_WILL_DRAW
| B_FRAME_EVENTS
1108 | (Flags() & B_NAVIGABLE
));
1111 SetText(initialText
);
1112 fText
->SetAlignment(B_ALIGN_LEFT
);
1113 fText
->AlignTextRect();
1116 // Although this is not strictly initializing the text view,
1117 // it cannot be done while fText is NULL, so it resides here.
1119 int32 labelAlignment
= B_ALIGN_LEFT
;
1120 int32 textAlignment
= B_ALIGN_LEFT
;
1122 status_t err
= B_OK
;
1123 if (archive
->HasInt32("_a_label"))
1124 err
= archive
->FindInt32("_a_label", &labelAlignment
);
1126 if (err
== B_OK
&& archive
->HasInt32("_a_text"))
1127 err
= archive
->FindInt32("_a_text", &textAlignment
);
1129 SetAlignment((alignment
)labelAlignment
, (alignment
)textAlignment
);
1132 uint32 navigableFlags
= Flags() & B_NAVIGABLE
;
1133 if (navigableFlags
!= 0)
1134 BView::SetFlags(Flags() & ~B_NAVIGABLE
);
1139 BTextControl::_ValidateLayout()
1143 _ValidateLayoutData();
1145 ResizeTo(Bounds().Width(), fLayoutData
->min
.height
);
1152 BTextControl::_LayoutTextView()
1157 if (fLayoutData
->text_view_layout_item
!= NULL
) {
1158 frame
= fLayoutData
->text_view_layout_item
->FrameInParent();
1161 frame
.left
= fDivider
;
1164 // we are stroking the frame around the text view, which
1166 frame
.InsetBy(kFrameMargin
, kFrameMargin
);
1167 fText
->MoveTo(frame
.left
, frame
.top
);
1168 fText
->ResizeTo(frame
.Width(), frame
.Height());
1169 fText
->AlignTextRect();
1171 TRACE("width: %.2f, height: %.2f\n", Frame().Width(), Frame().Height());
1172 TRACE("fDivider: %.2f\n", fDivider
);
1173 TRACE("fText frame: (%.2f, %.2f, %.2f, %.2f)\n",
1174 frame
.left
, frame
.top
, frame
.right
, frame
.bottom
);
1179 BTextControl::_UpdateFrame()
1183 if (fLayoutData
->text_view_layout_item
!= NULL
) {
1184 BRect textFrame
= fLayoutData
->text_view_layout_item
->Frame();
1186 if (fLayoutData
->label_layout_item
!= NULL
)
1187 labelFrame
= fLayoutData
->label_layout_item
->Frame();
1190 if (labelFrame
.IsValid()) {
1191 frame
= textFrame
| labelFrame
;
1194 fDivider
= fabs(textFrame
.left
- labelFrame
.left
);
1201 MoveTo(frame
.left
, frame
.top
);
1202 BSize
oldSize(Bounds().Size());
1203 ResizeTo(frame
.Width(), frame
.Height());
1204 BSize
newSize(Bounds().Size());
1206 // If the size changes, ResizeTo() will trigger a relayout, otherwise
1207 // we need to do that explicitly.
1208 if (newSize
!= oldSize
)
1215 BTextControl::_ValidateLayoutData()
1219 if (fLayoutData
->valid
)
1222 // cache font height
1223 font_height
& fh
= fLayoutData
->font_info
;
1226 const char* label
= Label();
1227 if (label
!= NULL
) {
1228 fLayoutData
->label_width
= ceilf(StringWidth(label
));
1229 fLayoutData
->label_height
= ceilf(fh
.ascent
) + ceilf(fh
.descent
);
1231 fLayoutData
->label_width
= 0;
1232 fLayoutData
->label_height
= 0;
1235 // compute the minimal divider
1237 if (fLayoutData
->label_width
> 0) {
1238 divider
= fLayoutData
->label_width
1239 + be_control_look
->DefaultLabelSpacing();
1242 // If we shan't do real layout, we let the current divider take influence.
1243 if (!(Flags() & B_SUPPORTS_LAYOUT
))
1244 divider
= max_c(divider
, fDivider
);
1246 // get the minimal (== preferred) text view size
1247 fLayoutData
->text_view_min
= fText
->MinSize();
1249 TRACE("text view min width: %.2f\n", fLayoutData
->text_view_min
.width
);
1251 // compute our minimal (== preferred) size
1252 BSize
min(fLayoutData
->text_view_min
);
1253 min
.width
+= 2 * kFrameMargin
;
1254 min
.height
+= 2 * kFrameMargin
;
1257 min
.width
+= divider
;
1259 if (fLayoutData
->label_height
> min
.height
)
1260 min
.height
= fLayoutData
->label_height
;
1262 fLayoutData
->min
= min
;
1264 fLayoutData
->valid
= true;
1265 ResetLayoutInvalidation();
1267 TRACE("width: %.2f, height: %.2f\n", min
.width
, min
.height
);
1271 // #pragma mark - BTextControl::LabelLayoutItem
1274 BTextControl::LabelLayoutItem::LabelLayoutItem(BTextControl
* parent
)
1282 BTextControl::LabelLayoutItem::LabelLayoutItem(BMessage
* from
)
1284 BAbstractLayoutItem(from
),
1288 from
->FindRect(kFrameField
, &fFrame
);
1293 BTextControl::LabelLayoutItem::IsVisible()
1295 return !fParent
->IsHidden(fParent
);
1300 BTextControl::LabelLayoutItem::SetVisible(bool visible
)
1307 BTextControl::LabelLayoutItem::Frame()
1314 BTextControl::LabelLayoutItem::SetFrame(BRect frame
)
1317 fParent
->_UpdateFrame();
1322 BTextControl::LabelLayoutItem::SetParent(BTextControl
* parent
)
1329 BTextControl::LabelLayoutItem::View()
1336 BTextControl::LabelLayoutItem::BaseMinSize()
1338 fParent
->_ValidateLayoutData();
1340 if (!fParent
->Label())
1341 return BSize(-1, -1);
1343 return BSize(fParent
->fLayoutData
->label_width
1344 + be_control_look
->DefaultLabelSpacing(),
1345 fParent
->fLayoutData
->label_height
);
1350 BTextControl::LabelLayoutItem::BaseMaxSize()
1352 return BaseMinSize();
1357 BTextControl::LabelLayoutItem::BasePreferredSize()
1359 return BaseMinSize();
1364 BTextControl::LabelLayoutItem::BaseAlignment()
1366 return BAlignment(B_ALIGN_USE_FULL_WIDTH
, B_ALIGN_USE_FULL_HEIGHT
);
1371 BTextControl::LabelLayoutItem::FrameInParent() const
1373 return fFrame
.OffsetByCopy(-fParent
->Frame().left
, -fParent
->Frame().top
);
1378 BTextControl::LabelLayoutItem::Archive(BMessage
* into
, bool deep
) const
1380 BArchiver
archiver(into
);
1381 status_t err
= BAbstractLayoutItem::Archive(into
, deep
);
1383 err
= into
->AddRect(kFrameField
, fFrame
);
1385 return archiver
.Finish(err
);
1390 BTextControl::LabelLayoutItem::Instantiate(BMessage
* from
)
1392 if (validate_instantiation(from
, "BTextControl::LabelLayoutItem"))
1393 return new LabelLayoutItem(from
);
1398 // #pragma mark - BTextControl::TextViewLayoutItem
1401 BTextControl::TextViewLayoutItem::TextViewLayoutItem(BTextControl
* parent
)
1406 // by default the part right of the divider shall have an unlimited maximum
1408 SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED
, B_SIZE_UNSET
));
1412 BTextControl::TextViewLayoutItem::TextViewLayoutItem(BMessage
* from
)
1414 BAbstractLayoutItem(from
),
1418 from
->FindRect(kFrameField
, &fFrame
);
1423 BTextControl::TextViewLayoutItem::IsVisible()
1425 return !fParent
->IsHidden(fParent
);
1430 BTextControl::TextViewLayoutItem::SetVisible(bool visible
)
1437 BTextControl::TextViewLayoutItem::Frame()
1444 BTextControl::TextViewLayoutItem::SetFrame(BRect frame
)
1447 fParent
->_UpdateFrame();
1452 BTextControl::TextViewLayoutItem::SetParent(BTextControl
* parent
)
1459 BTextControl::TextViewLayoutItem::View()
1466 BTextControl::TextViewLayoutItem::BaseMinSize()
1468 fParent
->_ValidateLayoutData();
1470 BSize size
= fParent
->fLayoutData
->text_view_min
;
1471 size
.width
+= 2 * kFrameMargin
;
1472 size
.height
+= 2 * kFrameMargin
;
1479 BTextControl::TextViewLayoutItem::BaseMaxSize()
1481 BSize
size(BaseMinSize());
1482 size
.width
= B_SIZE_UNLIMITED
;
1489 BTextControl::TextViewLayoutItem::BasePreferredSize()
1491 BSize
size(BaseMinSize());
1500 BTextControl::TextViewLayoutItem::BaseAlignment()
1502 return BAlignment(B_ALIGN_USE_FULL_WIDTH
, B_ALIGN_USE_FULL_HEIGHT
);
1507 BTextControl::TextViewLayoutItem::FrameInParent() const
1509 return fFrame
.OffsetByCopy(-fParent
->Frame().left
, -fParent
->Frame().top
);
1514 BTextControl::TextViewLayoutItem::Archive(BMessage
* into
, bool deep
) const
1516 BArchiver
archiver(into
);
1517 status_t err
= BAbstractLayoutItem::Archive(into
, deep
);
1519 err
= into
->AddRect(kFrameField
, fFrame
);
1521 return archiver
.Finish(err
);
1526 BTextControl::TextViewLayoutItem::Instantiate(BMessage
* from
)
1528 if (validate_instantiation(from
, "BTextControl::TextViewLayoutItem"))
1529 return new TextViewLayoutItem(from
);
1536 B_IF_GCC_2(InvalidateLayout__12BTextControlb
,
1537 _ZN12BTextControl16InvalidateLayoutEb
)(BView
* view
, bool descendants
)
1539 perform_data_layout_invalidated data
;
1540 data
.descendants
= descendants
;
1542 view
->Perform(PERFORM_CODE_LAYOUT_INVALIDATED
, &data
);