xref: /haiku/src/kits/interface/TextControl.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
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