xref: /haiku/src/kits/interface/TextControl.cpp (revision eee4243d35225a35d0964ebebe94490eaca14261)
1105644bfSAxel Dörfler /*
2991c062fSAxel Dörfler  * Copyright 2001-2008, Haiku Inc.
3105644bfSAxel Dörfler  * Distributed under the terms of the MIT License.
4105644bfSAxel Dörfler  *
5105644bfSAxel Dörfler  * Authors:
6105644bfSAxel Dörfler  *		Frans van Nispen (xlr8@tref.nl)
7105644bfSAxel Dörfler  *		Stephan Aßmus <superstippi@gmx.de>
89ecf9d1cSIngo Weinhold  *		Ingo Weinhold <bonefish@cs.tu-berlin.de>
9105644bfSAxel Dörfler  */
10105644bfSAxel Dörfler 
11991c062fSAxel Dörfler /*!	BTextControl displays text that can act like a control. */
12105644bfSAxel Dörfler 
13c121b41fSRene Gollent #include <string.h>
14c121b41fSRene Gollent 
152f86ba45SStephan Aßmus #include <TextControl.h>
16105644bfSAxel Dörfler 
179ecf9d1cSIngo Weinhold #include <AbstractLayoutItem.h>
182f86ba45SStephan Aßmus #include <ControlLook.h>
199ecf9d1cSIngo Weinhold #include <LayoutUtils.h>
20058691d4SStefano Ceccherini #include <Message.h>
212a30a9e9SRene Gollent #include <PropertyInfo.h>
22455d1c46SAxel Dörfler #include <Region.h>
2352a38012Sejakowatz #include <Window.h>
2452a38012Sejakowatz 
2539fbf550SOliver Tappe #include <binary_compatibility/Interface.h>
265c47e35eSAlex Wilson #include <binary_compatibility/Support.h>
2739fbf550SOliver Tappe 
2852a38012Sejakowatz #include "TextInput.h"
2952a38012Sejakowatz 
3052a38012Sejakowatz 
3193ba577cSStephan Aßmus //#define TRACE_TEXT_CONTROL
3293ba577cSStephan Aßmus #ifdef TRACE_TEXT_CONTROL
3373161598SJérôme Duval #	include <stdio.h>
3493ba577cSStephan Aßmus #	include <FunctionTracer.h>
3593ba577cSStephan Aßmus 	static int32 sFunctionDepth = -1;
36349c911eSStephan Aßmus #	define CALLED(x...)	FunctionTracer _ft("BTextControl", __FUNCTION__, \
3793ba577cSStephan Aßmus 							sFunctionDepth)
3893ba577cSStephan Aßmus #	define TRACE(x...)	{ BString _to; \
3993ba577cSStephan Aßmus 							_to.Append(' ', (sFunctionDepth + 1) * 2); \
4093ba577cSStephan Aßmus 							printf("%s", _to.String()); printf(x); }
4193ba577cSStephan Aßmus #else
4293ba577cSStephan Aßmus #	define CALLED(x...)
4393ba577cSStephan Aßmus #	define TRACE(x...)
4493ba577cSStephan Aßmus #endif
4593ba577cSStephan Aßmus 
4693ba577cSStephan Aßmus 
475c47e35eSAlex Wilson namespace {
485c47e35eSAlex Wilson 	const char* const kFrameField = "BTextControl:layoutitem:frame";
495c47e35eSAlex Wilson 	const char* const kTextViewItemField = "BTextControl:textViewItem";
505c47e35eSAlex Wilson 	const char* const kLabelItemField = "BMenuField:labelItem";
515c47e35eSAlex Wilson }
525c47e35eSAlex Wilson 
535c47e35eSAlex Wilson 
542a30a9e9SRene Gollent static property_info sPropertyList[] = {
552a30a9e9SRene Gollent 	{
562a30a9e9SRene Gollent 		"Value",
572a30a9e9SRene Gollent 		{ B_GET_PROPERTY, B_SET_PROPERTY },
582a30a9e9SRene Gollent 		{ B_DIRECT_SPECIFIER },
592a30a9e9SRene Gollent 		NULL, 0,
602a30a9e9SRene Gollent 		{ B_STRING_TYPE }
612a30a9e9SRene Gollent 	},
622a30a9e9SRene Gollent 	{}
632a30a9e9SRene Gollent };
642a30a9e9SRene Gollent 
652a30a9e9SRene Gollent 
669ecf9d1cSIngo Weinhold class BTextControl::LabelLayoutItem : public BAbstractLayoutItem {
679ecf9d1cSIngo Weinhold public:
689ecf9d1cSIngo Weinhold 								LabelLayoutItem(BTextControl* parent);
695c47e35eSAlex Wilson 								LabelLayoutItem(BMessage* from);
709ecf9d1cSIngo Weinhold 
719ecf9d1cSIngo Weinhold 	virtual	bool				IsVisible();
729ecf9d1cSIngo Weinhold 	virtual	void				SetVisible(bool visible);
739ecf9d1cSIngo Weinhold 
749ecf9d1cSIngo Weinhold 	virtual	BRect				Frame();
759ecf9d1cSIngo Weinhold 	virtual	void				SetFrame(BRect frame);
769ecf9d1cSIngo Weinhold 
775c47e35eSAlex Wilson 			void				SetParent(BTextControl* parent);
789ecf9d1cSIngo Weinhold 	virtual	BView*				View();
799ecf9d1cSIngo Weinhold 
809ecf9d1cSIngo Weinhold 	virtual	BSize				BaseMinSize();
819ecf9d1cSIngo Weinhold 	virtual	BSize				BaseMaxSize();
829ecf9d1cSIngo Weinhold 	virtual	BSize				BasePreferredSize();
839ecf9d1cSIngo Weinhold 	virtual	BAlignment			BaseAlignment();
849ecf9d1cSIngo Weinhold 
855c47e35eSAlex Wilson 	virtual status_t			Archive(BMessage* into, bool deep = true) const;
865c47e35eSAlex Wilson 	static	BArchivable*		Instantiate(BMessage* from);
879ecf9d1cSIngo Weinhold private:
889ecf9d1cSIngo Weinhold 			BTextControl*		fParent;
899ecf9d1cSIngo Weinhold 			BRect				fFrame;
909ecf9d1cSIngo Weinhold };
919ecf9d1cSIngo Weinhold 
929ecf9d1cSIngo Weinhold 
939ecf9d1cSIngo Weinhold class BTextControl::TextViewLayoutItem : public BAbstractLayoutItem {
949ecf9d1cSIngo Weinhold public:
959ecf9d1cSIngo Weinhold 								TextViewLayoutItem(BTextControl* parent);
965c47e35eSAlex Wilson 								TextViewLayoutItem(BMessage* from);
979ecf9d1cSIngo Weinhold 
989ecf9d1cSIngo Weinhold 	virtual	bool				IsVisible();
999ecf9d1cSIngo Weinhold 	virtual	void				SetVisible(bool visible);
1009ecf9d1cSIngo Weinhold 
1019ecf9d1cSIngo Weinhold 	virtual	BRect				Frame();
1029ecf9d1cSIngo Weinhold 	virtual	void				SetFrame(BRect frame);
1039ecf9d1cSIngo Weinhold 
1045c47e35eSAlex Wilson 			void				SetParent(BTextControl* parent);
1059ecf9d1cSIngo Weinhold 	virtual	BView*				View();
1069ecf9d1cSIngo Weinhold 
1079ecf9d1cSIngo Weinhold 	virtual	BSize				BaseMinSize();
1089ecf9d1cSIngo Weinhold 	virtual	BSize				BaseMaxSize();
1099ecf9d1cSIngo Weinhold 	virtual	BSize				BasePreferredSize();
1109ecf9d1cSIngo Weinhold 	virtual	BAlignment			BaseAlignment();
1119ecf9d1cSIngo Weinhold 
1125c47e35eSAlex Wilson 	virtual status_t			Archive(BMessage* into, bool deep = true) const;
1135c47e35eSAlex Wilson 	static	BArchivable*		Instantiate(BMessage* from);
1149ecf9d1cSIngo Weinhold private:
1159ecf9d1cSIngo Weinhold 			BTextControl*		fParent;
1169ecf9d1cSIngo Weinhold 			BRect				fFrame;
1179ecf9d1cSIngo Weinhold };
1189ecf9d1cSIngo Weinhold 
1199ecf9d1cSIngo Weinhold 
120349c911eSStephan Aßmus struct BTextControl::LayoutData {
121349c911eSStephan Aßmus 	LayoutData(float width, float height)
1225c47e35eSAlex Wilson 		:
1235c47e35eSAlex Wilson 		label_layout_item(NULL),
124349c911eSStephan Aßmus 		text_view_layout_item(NULL),
125349c911eSStephan Aßmus 		previous_width(width),
126349c911eSStephan Aßmus 		previous_height(height),
127349c911eSStephan Aßmus 		valid(false)
128349c911eSStephan Aßmus 	{
129349c911eSStephan Aßmus 	}
130349c911eSStephan Aßmus 
131349c911eSStephan Aßmus 	LabelLayoutItem*	label_layout_item;
132349c911eSStephan Aßmus 	TextViewLayoutItem*	text_view_layout_item;
133349c911eSStephan Aßmus 	float				previous_width;		// used in FrameResized() for
134349c911eSStephan Aßmus 	float				previous_height;	// invalidation
135349c911eSStephan Aßmus 	font_height			font_info;
136349c911eSStephan Aßmus 	float				label_width;
137349c911eSStephan Aßmus 	float				label_height;
138349c911eSStephan Aßmus 	BSize				min;
139349c911eSStephan Aßmus 	BSize				text_view_min;
140349c911eSStephan Aßmus 	bool				valid;
141349c911eSStephan Aßmus };
142349c911eSStephan Aßmus 
143349c911eSStephan Aßmus 
1449ecf9d1cSIngo Weinhold // #pragma mark -
1459ecf9d1cSIngo Weinhold 
1469ecf9d1cSIngo Weinhold 
147349c911eSStephan Aßmus static const int32 kFrameMargin = 2;
148349c911eSStephan Aßmus static const int32 kLabelInputSpacing = 3;
149349c911eSStephan Aßmus 
150349c911eSStephan Aßmus 
15152a38012Sejakowatz BTextControl::BTextControl(BRect frame, const char* name, const char* label,
152991c062fSAxel Dörfler 		const char* text, BMessage* message, uint32 mask, uint32 flags)
1535c47e35eSAlex Wilson 	:
1545c47e35eSAlex Wilson 	BControl(frame, name, label, message, mask, flags | B_FRAME_EVENTS)
15552a38012Sejakowatz {
1565c47e35eSAlex Wilson 	_InitData(label);
1575c47e35eSAlex Wilson 	_InitText(text);
1589ecf9d1cSIngo Weinhold 	_ValidateLayout();
1599ecf9d1cSIngo Weinhold }
16052a38012Sejakowatz 
161105644bfSAxel Dörfler 
1629ecf9d1cSIngo Weinhold BTextControl::BTextControl(const char* name, const char* label,
163991c062fSAxel Dörfler 		const char* text, BMessage* message, uint32 flags)
1645c47e35eSAlex Wilson 	:
1655c47e35eSAlex Wilson 	BControl(name, label, message, flags | B_FRAME_EVENTS)
1669ecf9d1cSIngo Weinhold {
1675c47e35eSAlex Wilson 	_InitData(label);
1685c47e35eSAlex Wilson 	_InitText(text);
1699ecf9d1cSIngo Weinhold 	_ValidateLayout();
1709ecf9d1cSIngo Weinhold }
171105644bfSAxel Dörfler 
172ffe72abdSAxel Dörfler 
173991c062fSAxel Dörfler BTextControl::BTextControl(const char* label, const char* text,
174991c062fSAxel Dörfler 		BMessage* message)
1755c47e35eSAlex Wilson 	:
1765c47e35eSAlex Wilson 	BControl(NULL, label, message,
17793ba577cSStephan Aßmus 		B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS)
1789ecf9d1cSIngo Weinhold {
1795c47e35eSAlex Wilson 	_InitData(label);
1805c47e35eSAlex Wilson 	_InitText(text);
1819ecf9d1cSIngo Weinhold 	_ValidateLayout();
18252a38012Sejakowatz }
183058691d4SStefano Ceccherini 
184058691d4SStefano Ceccherini 
18552a38012Sejakowatz BTextControl::~BTextControl()
18652a38012Sejakowatz {
1879cb2dbe2SMarc Flerackers 	SetModificationMessage(NULL);
18853aaed9fSStephan Aßmus 	delete fLayoutData;
18952a38012Sejakowatz }
190058691d4SStefano Ceccherini 
191058691d4SStefano Ceccherini 
192ffe72abdSAxel Dörfler BTextControl::BTextControl(BMessage* archive)
1935c47e35eSAlex Wilson 	:
1945c47e35eSAlex Wilson 	BControl(BUnarchiver::PrepareArchive(archive))
19552a38012Sejakowatz {
1965c47e35eSAlex Wilson 	BUnarchiver unarchiver(archive);
19752a38012Sejakowatz 
1985c47e35eSAlex Wilson 	_InitData(Label(), archive);
19952a38012Sejakowatz 
2005c47e35eSAlex Wilson 	if (!BUnarchiver::IsArchiveManaged(archive))
2015c47e35eSAlex Wilson 		_InitText(NULL, archive);
20252a38012Sejakowatz 
2035c47e35eSAlex Wilson 	status_t err = B_OK;
204ffe72abdSAxel Dörfler 	if (archive->HasFloat("_divide"))
2055c47e35eSAlex Wilson 		err = archive->FindFloat("_divide", &fDivider);
2069cb2dbe2SMarc Flerackers 
2075c47e35eSAlex Wilson 	if (err == B_OK && archive->HasMessage("_mod_msg")) {
208ffe72abdSAxel Dörfler 		BMessage* message = new BMessage;
2095c47e35eSAlex Wilson 		err = archive->FindMessage("_mod_msg", message);
210ffe72abdSAxel Dörfler 		SetModificationMessage(message);
2119cb2dbe2SMarc Flerackers 	}
2125c47e35eSAlex Wilson 
2135c47e35eSAlex Wilson 	unarchiver.Finish(err);
21452a38012Sejakowatz }
215058691d4SStefano Ceccherini 
216058691d4SStefano Ceccherini 
217058691d4SStefano Ceccherini BArchivable*
218058691d4SStefano Ceccherini BTextControl::Instantiate(BMessage* archive)
21952a38012Sejakowatz {
2209cb2dbe2SMarc Flerackers 	if (validate_instantiation(archive, "BTextControl"))
2219cb2dbe2SMarc Flerackers 		return new BTextControl(archive);
222991c062fSAxel Dörfler 
22352a38012Sejakowatz 	return NULL;
22452a38012Sejakowatz }
225058691d4SStefano Ceccherini 
226058691d4SStefano Ceccherini 
227058691d4SStefano Ceccherini status_t
228058691d4SStefano Ceccherini BTextControl::Archive(BMessage *data, bool deep) const
22952a38012Sejakowatz {
2305c47e35eSAlex Wilson 	BArchiver archiver(data);
2313a543720SJérôme Duval 	status_t ret = BControl::Archive(data, deep);
232058691d4SStefano Ceccherini 	alignment labelAlignment, textAlignment;
23352a38012Sejakowatz 
234058691d4SStefano Ceccherini 	GetAlignment(&labelAlignment, &textAlignment);
2359cb2dbe2SMarc Flerackers 
23611d7ecebSJérôme Duval 	if (ret == B_OK)
23711d7ecebSJérôme Duval 		ret = data->AddInt32("_a_label", labelAlignment);
23811d7ecebSJérôme Duval 	if (ret == B_OK)
23911d7ecebSJérôme Duval 		ret = data->AddInt32("_a_text", textAlignment);
24011d7ecebSJérôme Duval 	if (ret == B_OK)
24111d7ecebSJérôme Duval 		ret = data->AddFloat("_divide", Divider());
2429cb2dbe2SMarc Flerackers 
24311d7ecebSJérôme Duval 	if (ModificationMessage() && (ret == B_OK))
24411d7ecebSJérôme Duval 		ret = data->AddMessage("_mod_msg", ModificationMessage());
2459cb2dbe2SMarc Flerackers 
2465c47e35eSAlex Wilson 	return archiver.Finish(ret);
2475c47e35eSAlex Wilson }
2485c47e35eSAlex Wilson 
2495c47e35eSAlex Wilson 
2505c47e35eSAlex Wilson status_t
2515c47e35eSAlex Wilson BTextControl::AllArchived(BMessage* into) const
2525c47e35eSAlex Wilson {
2535c47e35eSAlex Wilson 	BArchiver archiver(into);
2545c47e35eSAlex Wilson 	status_t err = B_OK;
2555c47e35eSAlex Wilson 
2565c47e35eSAlex Wilson 	if (archiver.IsArchived(fLayoutData->text_view_layout_item)) {
2575c47e35eSAlex Wilson 		err = archiver.AddArchivable(kTextViewItemField,
2585c47e35eSAlex Wilson 			fLayoutData->text_view_layout_item);
2595c47e35eSAlex Wilson 	}
2605c47e35eSAlex Wilson 
2615c47e35eSAlex Wilson 	if (err == B_OK && archiver.IsArchived(fLayoutData->label_layout_item)) {
2625c47e35eSAlex Wilson 		err = archiver.AddArchivable(kLabelItemField,
2635c47e35eSAlex Wilson 			fLayoutData->label_layout_item);
2645c47e35eSAlex Wilson 	}
2655c47e35eSAlex Wilson 
2665c47e35eSAlex Wilson 	return err;
2675c47e35eSAlex Wilson }
2685c47e35eSAlex Wilson 
2695c47e35eSAlex Wilson 
2705c47e35eSAlex Wilson status_t
2715c47e35eSAlex Wilson BTextControl::AllUnarchived(const BMessage* from)
2725c47e35eSAlex Wilson {
2735c47e35eSAlex Wilson 	status_t err;
2745c47e35eSAlex Wilson 	if ((err = BControl::AllUnarchived(from)) != B_OK)
2755c47e35eSAlex Wilson 		return err;
2765c47e35eSAlex Wilson 
2775c47e35eSAlex Wilson 	_InitText(NULL, from);
2785c47e35eSAlex Wilson 
2795c47e35eSAlex Wilson 	BUnarchiver unarchiver(from);
2805c47e35eSAlex Wilson 	if (unarchiver.IsInstantiated(kTextViewItemField)) {
2815c47e35eSAlex Wilson 		err = unarchiver.FindObject(kTextViewItemField,
2825c47e35eSAlex Wilson 			BUnarchiver::B_DONT_ASSUME_OWNERSHIP,
2835c47e35eSAlex Wilson 			fLayoutData->text_view_layout_item);
2845c47e35eSAlex Wilson 
2855c47e35eSAlex Wilson 		if (err == B_OK)
2865c47e35eSAlex Wilson 			fLayoutData->text_view_layout_item->SetParent(this);
2875c47e35eSAlex Wilson 		else
2885c47e35eSAlex Wilson 			return err;
2895c47e35eSAlex Wilson 	}
2905c47e35eSAlex Wilson 
2915c47e35eSAlex Wilson 	if (unarchiver.IsInstantiated(kLabelItemField)) {
2925c47e35eSAlex Wilson 		err = unarchiver.FindObject(kLabelItemField,
2935c47e35eSAlex Wilson 			BUnarchiver::B_DONT_ASSUME_OWNERSHIP,
2945c47e35eSAlex Wilson 			fLayoutData->label_layout_item);
2955c47e35eSAlex Wilson 
2965c47e35eSAlex Wilson 		if (err == B_OK)
2975c47e35eSAlex Wilson 			fLayoutData->label_layout_item->SetParent(this);
2985c47e35eSAlex Wilson 	}
2995c47e35eSAlex Wilson 	return err;
30052a38012Sejakowatz }
301058691d4SStefano Ceccherini 
302058691d4SStefano Ceccherini 
303058691d4SStefano Ceccherini void
304058691d4SStefano Ceccherini BTextControl::SetText(const char *text)
30552a38012Sejakowatz {
3069cb2dbe2SMarc Flerackers 	if (InvokeKind() != B_CONTROL_INVOKED)
3079cb2dbe2SMarc Flerackers 		return;
3089cb2dbe2SMarc Flerackers 
30993ba577cSStephan Aßmus 	CALLED();
31093ba577cSStephan Aßmus 
31152a38012Sejakowatz 	fText->SetText(text);
3129cb2dbe2SMarc Flerackers 
3135b349aa2SJérôme Duval 	if (fText->IsFocus()) {
3149cb2dbe2SMarc Flerackers 		fText->SetInitialText();
3155b349aa2SJérôme Duval 		fText->SelectAll();
3165b349aa2SJérôme Duval 	}
3179cb2dbe2SMarc Flerackers 
3189cb2dbe2SMarc Flerackers 	fText->Invalidate();
31952a38012Sejakowatz }
320058691d4SStefano Ceccherini 
321058691d4SStefano Ceccherini 
322058691d4SStefano Ceccherini const char *
323058691d4SStefano Ceccherini BTextControl::Text() const
32452a38012Sejakowatz {
32552a38012Sejakowatz 	return fText->Text();
32652a38012Sejakowatz }
327058691d4SStefano Ceccherini 
328058691d4SStefano Ceccherini 
329058691d4SStefano Ceccherini void
330058691d4SStefano Ceccherini BTextControl::SetValue(int32 value)
33152a38012Sejakowatz {
3329cb2dbe2SMarc Flerackers 	BControl::SetValue(value);
33352a38012Sejakowatz }
334058691d4SStefano Ceccherini 
335058691d4SStefano Ceccherini 
336058691d4SStefano Ceccherini status_t
337058691d4SStefano Ceccherini BTextControl::Invoke(BMessage *message)
33852a38012Sejakowatz {
339058691d4SStefano Ceccherini 	return BControl::Invoke(message);
34052a38012Sejakowatz }
341058691d4SStefano Ceccherini 
342058691d4SStefano Ceccherini 
343058691d4SStefano Ceccherini BTextView *
344058691d4SStefano Ceccherini BTextControl::TextView() const
34552a38012Sejakowatz {
3469cb2dbe2SMarc Flerackers 	return fText;
34752a38012Sejakowatz }
348058691d4SStefano Ceccherini 
349058691d4SStefano Ceccherini 
350058691d4SStefano Ceccherini void
351058691d4SStefano Ceccherini BTextControl::SetModificationMessage(BMessage *message)
35252a38012Sejakowatz {
3539cb2dbe2SMarc Flerackers 	delete fModificationMessage;
35452a38012Sejakowatz 	fModificationMessage = message;
35552a38012Sejakowatz }
356058691d4SStefano Ceccherini 
357058691d4SStefano Ceccherini 
358058691d4SStefano Ceccherini BMessage *
359058691d4SStefano Ceccherini BTextControl::ModificationMessage() const
36052a38012Sejakowatz {
36152a38012Sejakowatz 	return fModificationMessage;
36252a38012Sejakowatz }
363058691d4SStefano Ceccherini 
364058691d4SStefano Ceccherini 
365058691d4SStefano Ceccherini void
366058691d4SStefano Ceccherini BTextControl::SetAlignment(alignment labelAlignment, alignment textAlignment)
36752a38012Sejakowatz {
368058691d4SStefano Ceccherini 	fText->SetAlignment(textAlignment);
3699cb2dbe2SMarc Flerackers 	fText->AlignTextRect();
3709cb2dbe2SMarc Flerackers 
371058691d4SStefano Ceccherini 	if (fLabelAlign != labelAlignment) {
372058691d4SStefano Ceccherini 		fLabelAlign = labelAlignment;
3739cb2dbe2SMarc Flerackers 		Invalidate();
3749cb2dbe2SMarc Flerackers 	}
37552a38012Sejakowatz }
376058691d4SStefano Ceccherini 
377058691d4SStefano Ceccherini 
378058691d4SStefano Ceccherini void
379c432fbbbSAxel Dörfler BTextControl::GetAlignment(alignment* _label, alignment* _text) const
38052a38012Sejakowatz {
381c432fbbbSAxel Dörfler 	if (_label)
382c432fbbbSAxel Dörfler 		*_label = fLabelAlign;
383c432fbbbSAxel Dörfler 	if (_text)
384c432fbbbSAxel Dörfler 		*_text = fText->Alignment();
38552a38012Sejakowatz }
3869cb2dbe2SMarc Flerackers 
387058691d4SStefano Ceccherini 
388058691d4SStefano Ceccherini void
389058691d4SStefano Ceccherini BTextControl::SetDivider(float dividingLine)
390058691d4SStefano Ceccherini {
391a431f44bSStephan Aßmus 	fDivider = floorf(dividingLine + 0.5);
3922e6a5805SStephan Aßmus 
393a431f44bSStephan Aßmus 	_LayoutTextView();
39452a38012Sejakowatz 
395058691d4SStefano Ceccherini 	if (Window()) {
39652a38012Sejakowatz 		fText->Invalidate();
39752a38012Sejakowatz 		Invalidate();
39852a38012Sejakowatz 	}
3999cb2dbe2SMarc Flerackers }
400058691d4SStefano Ceccherini 
401058691d4SStefano Ceccherini 
402058691d4SStefano Ceccherini float
403058691d4SStefano Ceccherini BTextControl::Divider() const
40452a38012Sejakowatz {
40552a38012Sejakowatz 	return fDivider;
40652a38012Sejakowatz }
407058691d4SStefano Ceccherini 
408058691d4SStefano Ceccherini 
409058691d4SStefano Ceccherini void
410058691d4SStefano Ceccherini BTextControl::Draw(BRect updateRect)
41152a38012Sejakowatz {
4122f86ba45SStephan Aßmus 	bool enabled = IsEnabled();
4132f86ba45SStephan Aßmus 	bool active = fText->IsFocus() && Window()->IsActive();
4142f86ba45SStephan Aßmus 
4152f86ba45SStephan Aßmus 	BRect rect = fText->Frame();
4162f86ba45SStephan Aßmus 	rect.InsetBy(-2, -2);
4172f86ba45SStephan Aßmus 
4182f86ba45SStephan Aßmus 	if (be_control_look != NULL) {
4192f86ba45SStephan Aßmus 		rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
4202f86ba45SStephan Aßmus 		uint32 flags = 0;
4212f86ba45SStephan Aßmus 		if (!enabled)
4222f86ba45SStephan Aßmus 			flags |= BControlLook::B_DISABLED;
4232f86ba45SStephan Aßmus 		if (active)
4242f86ba45SStephan Aßmus 			flags |= BControlLook::B_FOCUSED;
4252f86ba45SStephan Aßmus 		be_control_look->DrawTextControlBorder(this, rect, updateRect, base,
4262f86ba45SStephan Aßmus 			flags);
4272f86ba45SStephan Aßmus 
4282f86ba45SStephan Aßmus 		rect = Bounds();
4292f86ba45SStephan Aßmus 		rect.right = fDivider - kLabelInputSpacing;
4302f86ba45SStephan Aßmus //		rect.right = fText->Frame().left - 2;
4312f86ba45SStephan Aßmus //		rect.right -= 3;//be_control_look->DefaultLabelSpacing();
4322f86ba45SStephan Aßmus 		be_control_look->DrawLabel(this, Label(), rect, updateRect,
4332f86ba45SStephan Aßmus 			base, flags, BAlignment(fLabelAlign, B_ALIGN_MIDDLE));
4342f86ba45SStephan Aßmus 
4352f86ba45SStephan Aßmus 		return;
4362f86ba45SStephan Aßmus 	}
4372f86ba45SStephan Aßmus 
4382f86ba45SStephan Aßmus 	// outer bevel
4392f86ba45SStephan Aßmus 
440c432fbbbSAxel Dörfler 	rgb_color noTint = ui_color(B_PANEL_BACKGROUND_COLOR);
441c432fbbbSAxel Dörfler 	rgb_color lighten1 = tint_color(noTint, B_LIGHTEN_1_TINT);
442c432fbbbSAxel Dörfler 	rgb_color lighten2 = tint_color(noTint, B_LIGHTEN_2_TINT);
443c432fbbbSAxel Dörfler 	rgb_color lightenMax = tint_color(noTint, B_LIGHTEN_MAX_TINT);
444c432fbbbSAxel Dörfler 	rgb_color darken1 = tint_color(noTint, B_DARKEN_1_TINT);
445c432fbbbSAxel Dörfler 	rgb_color darken2 = tint_color(noTint, B_DARKEN_2_TINT);
446c432fbbbSAxel Dörfler 	rgb_color darken4 = tint_color(noTint, B_DARKEN_4_TINT);
447c432fbbbSAxel Dörfler 	rgb_color navigationColor = ui_color(B_KEYBOARD_NAVIGATION_COLOR);
4489cb2dbe2SMarc Flerackers 
449455d1c46SAxel Dörfler 	if (enabled)
450455d1c46SAxel Dörfler 		SetHighColor(darken1);
451455d1c46SAxel Dörfler 	else
452455d1c46SAxel Dörfler 		SetHighColor(noTint);
453455d1c46SAxel Dörfler 
454455d1c46SAxel Dörfler 	StrokeLine(rect.LeftBottom(), rect.LeftTop());
455455d1c46SAxel Dörfler 	StrokeLine(rect.RightTop());
456455d1c46SAxel Dörfler 
457455d1c46SAxel Dörfler 	if (enabled)
458455d1c46SAxel Dörfler 		SetHighColor(lighten2);
459455d1c46SAxel Dörfler 	else
460455d1c46SAxel Dörfler 		SetHighColor(lighten1);
461455d1c46SAxel Dörfler 
462455d1c46SAxel Dörfler 	StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), rect.RightBottom());
463455d1c46SAxel Dörfler 	StrokeLine(BPoint(rect.right, rect.top + 1.0f), rect.RightBottom());
464455d1c46SAxel Dörfler 
465455d1c46SAxel Dörfler 	// inner bevel
466455d1c46SAxel Dörfler 
467455d1c46SAxel Dörfler 	rect.InsetBy(1.0f, 1.0f);
4689cb2dbe2SMarc Flerackers 
469058691d4SStefano Ceccherini 	if (active) {
470105644bfSAxel Dörfler 		SetHighColor(navigationColor);
4719cb2dbe2SMarc Flerackers 		StrokeRect(rect);
472058691d4SStefano Ceccherini 	} else {
4739cb2dbe2SMarc Flerackers 		if (enabled)
4749cb2dbe2SMarc Flerackers 			SetHighColor(darken4);
4759cb2dbe2SMarc Flerackers 		else
4769cb2dbe2SMarc Flerackers 			SetHighColor(darken2);
4779cb2dbe2SMarc Flerackers 
4789cb2dbe2SMarc Flerackers 		StrokeLine(rect.LeftTop(), rect.LeftBottom());
4799cb2dbe2SMarc Flerackers 		StrokeLine(rect.LeftTop(), rect.RightTop());
4809cb2dbe2SMarc Flerackers 
481105644bfSAxel Dörfler 		SetHighColor(noTint);
4829cb2dbe2SMarc Flerackers 		StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), rect.RightBottom());
4839cb2dbe2SMarc Flerackers 		StrokeLine(BPoint(rect.right, rect.top + 1.0f));
4849cb2dbe2SMarc Flerackers 	}
4859cb2dbe2SMarc Flerackers 
4867a25fcafSStefano Ceccherini 	// label
4877a25fcafSStefano Ceccherini 
488058691d4SStefano Ceccherini 	if (Label()) {
489349c911eSStephan Aßmus 		_ValidateLayoutData();
490349c911eSStephan Aßmus 		font_height& fontHeight = fLayoutData->font_info;
4919cb2dbe2SMarc Flerackers 
492a68292ddSStephan Aßmus 		float y = Bounds().top + (Bounds().Height() + 1 - fontHeight.ascent
493a68292ddSStephan Aßmus 			- fontHeight.descent) / 2 + fontHeight.ascent;
49452a38012Sejakowatz 		float x;
4959cb2dbe2SMarc Flerackers 
4967a25fcafSStefano Ceccherini 		float labelWidth = StringWidth(Label());
497058691d4SStefano Ceccherini 		switch (fLabelAlign) {
49852a38012Sejakowatz 			case B_ALIGN_RIGHT:
499349c911eSStephan Aßmus 				x = fDivider - labelWidth - kLabelInputSpacing;
50052a38012Sejakowatz 				break;
50152a38012Sejakowatz 
50252a38012Sejakowatz 			case B_ALIGN_CENTER:
503b8872c02SStephan Aßmus 				x = fDivider - labelWidth / 2.0;
50452a38012Sejakowatz 				break;
50552a38012Sejakowatz 
50652a38012Sejakowatz 			default:
507b8872c02SStephan Aßmus 				x = 0.0;
50852a38012Sejakowatz 				break;
50952a38012Sejakowatz 		}
51052a38012Sejakowatz 
5112c5a8894SStephan Aßmus 		BRect labelArea(x, Bounds().top, x + labelWidth, Bounds().bottom);
5127a25fcafSStefano Ceccherini 		if (x < fDivider && updateRect.Intersects(labelArea)) {
513349c911eSStephan Aßmus 			labelArea.right = fText->Frame().left - kLabelInputSpacing;
5147a25fcafSStefano Ceccherini 
5157a25fcafSStefano Ceccherini 			BRegion clipRegion(labelArea);
5167a25fcafSStefano Ceccherini 			ConstrainClippingRegion(&clipRegion);
517c432fbbbSAxel Dörfler 			SetHighColor(IsEnabled() ? ui_color(B_CONTROL_TEXT_COLOR)
518fa815db3SAxel Dörfler 				: tint_color(noTint, B_DISABLED_LABEL_TINT));
51952a38012Sejakowatz 			DrawString(Label(), BPoint(x, y));
52052a38012Sejakowatz 		}
52152a38012Sejakowatz 	}
5227a25fcafSStefano Ceccherini }
523058691d4SStefano Ceccherini 
524058691d4SStefano Ceccherini 
525058691d4SStefano Ceccherini void
526058691d4SStefano Ceccherini BTextControl::MouseDown(BPoint where)
52752a38012Sejakowatz {
528058691d4SStefano Ceccherini 	if (!fText->IsFocus()) {
5299cb2dbe2SMarc Flerackers 		fText->MakeFocus(true);
53052a38012Sejakowatz 	}
53152a38012Sejakowatz }
532058691d4SStefano Ceccherini 
533058691d4SStefano Ceccherini 
534058691d4SStefano Ceccherini void
535058691d4SStefano Ceccherini BTextControl::AttachedToWindow()
53652a38012Sejakowatz {
53752a38012Sejakowatz 	BControl::AttachedToWindow();
53852a38012Sejakowatz 
53979c35b39SAxel Dörfler 	_UpdateTextViewColors(IsEnabled());
5403a3f6c1eSAxel Dörfler 	fText->MakeEditable(IsEnabled());
54152a38012Sejakowatz }
542058691d4SStefano Ceccherini 
543058691d4SStefano Ceccherini 
544058691d4SStefano Ceccherini void
545058691d4SStefano Ceccherini BTextControl::MakeFocus(bool state)
54652a38012Sejakowatz {
5476d8d6cadSStephan Aßmus 	if (state != fText->IsFocus()) {
54852a38012Sejakowatz 		fText->MakeFocus(state);
5499cb2dbe2SMarc Flerackers 
5509cb2dbe2SMarc Flerackers 		if (state)
5519cb2dbe2SMarc Flerackers 			fText->SelectAll();
55252a38012Sejakowatz 	}
5536d8d6cadSStephan Aßmus }
554058691d4SStefano Ceccherini 
555058691d4SStefano Ceccherini 
556058691d4SStefano Ceccherini void
55779c35b39SAxel Dörfler BTextControl::SetEnabled(bool enabled)
55852a38012Sejakowatz {
55979c35b39SAxel Dörfler 	if (IsEnabled() == enabled)
5609cb2dbe2SMarc Flerackers 		return;
5619cb2dbe2SMarc Flerackers 
562058691d4SStefano Ceccherini 	if (Window()) {
56379c35b39SAxel Dörfler 		fText->MakeEditable(enabled);
564c80f8962SJérôme Duval 		if (enabled)
565c80f8962SJérôme Duval 			fText->SetFlags(fText->Flags() | B_NAVIGABLE);
566c80f8962SJérôme Duval 		else
567c80f8962SJérôme Duval 			fText->SetFlags(fText->Flags() & ~B_NAVIGABLE);
5689cb2dbe2SMarc Flerackers 
56979c35b39SAxel Dörfler 		_UpdateTextViewColors(enabled);
5709cb2dbe2SMarc Flerackers 
5719cb2dbe2SMarc Flerackers 		fText->Invalidate();
5729cb2dbe2SMarc Flerackers 		Window()->UpdateIfNeeded();
5739cb2dbe2SMarc Flerackers 	}
5749cb2dbe2SMarc Flerackers 
57579c35b39SAxel Dörfler 	BControl::SetEnabled(enabled);
57652a38012Sejakowatz }
577058691d4SStefano Ceccherini 
578058691d4SStefano Ceccherini 
579058691d4SStefano Ceccherini void
580105644bfSAxel Dörfler BTextControl::GetPreferredSize(float *_width, float *_height)
58152a38012Sejakowatz {
582349c911eSStephan Aßmus 	CALLED();
58352a38012Sejakowatz 
584349c911eSStephan Aßmus 	_ValidateLayoutData();
585105644bfSAxel Dörfler 
5861aaf53ecSStephan Aßmus 	if (_width) {
5871aaf53ecSStephan Aßmus 		float minWidth = fLayoutData->min.width;
5881aaf53ecSStephan Aßmus 		if (Label() == NULL && !(Flags() & B_SUPPORTS_LAYOUT)) {
5891aaf53ecSStephan Aßmus 			// Indeed, only if there is no label! BeOS backwards compatible
5901aaf53ecSStephan Aßmus 			// behavior:
5911aaf53ecSStephan Aßmus 			minWidth = max_c(minWidth, Bounds().Width());
5921aaf53ecSStephan Aßmus 		}
5931aaf53ecSStephan Aßmus 		*_width = minWidth;
5941aaf53ecSStephan Aßmus 	}
595349c911eSStephan Aßmus 
596349c911eSStephan Aßmus 	if (_height)
597349c911eSStephan Aßmus 		*_height = fLayoutData->min.height;
59852a38012Sejakowatz }
599058691d4SStefano Ceccherini 
600058691d4SStefano Ceccherini 
601058691d4SStefano Ceccherini void
602058691d4SStefano Ceccherini BTextControl::ResizeToPreferred()
60352a38012Sejakowatz {
604105644bfSAxel Dörfler 	BView::ResizeToPreferred();
6051bdc2a52SKarsten Heimrich 
6061bdc2a52SKarsten Heimrich 	fDivider = 0.0;
6071bdc2a52SKarsten Heimrich 	const char* label = Label();
6081bdc2a52SKarsten Heimrich 	if (label)
6091bdc2a52SKarsten Heimrich 		fDivider = ceil(StringWidth(label)) + 2.0;
6101bdc2a52SKarsten Heimrich 
6111bdc2a52SKarsten Heimrich 	_LayoutTextView();
61252a38012Sejakowatz }
613058691d4SStefano Ceccherini 
614058691d4SStefano Ceccherini 
615058691d4SStefano Ceccherini void
616058691d4SStefano Ceccherini BTextControl::SetFlags(uint32 flags)
61752a38012Sejakowatz {
6189cb2dbe2SMarc Flerackers 	// If the textview is navigable, set it to not navigable if needed
6199cb2dbe2SMarc Flerackers 	// Else if it is not navigable, set it to navigable if needed
620058691d4SStefano Ceccherini 	if (fText->Flags() & B_NAVIGABLE) {
6219cb2dbe2SMarc Flerackers 		if (!(flags & B_NAVIGABLE))
6229cb2dbe2SMarc Flerackers 			fText->SetFlags(fText->Flags() & ~B_NAVIGABLE);
623058691d4SStefano Ceccherini 
624058691d4SStefano Ceccherini 	} else {
6259cb2dbe2SMarc Flerackers 		if (flags & B_NAVIGABLE)
6269cb2dbe2SMarc Flerackers 			fText->SetFlags(fText->Flags() | B_NAVIGABLE);
6279cb2dbe2SMarc Flerackers 	}
6289cb2dbe2SMarc Flerackers 
629c80f8962SJérôme Duval 	// Don't make this one navigable
630c80f8962SJérôme Duval 	flags &= ~B_NAVIGABLE;
631c80f8962SJérôme Duval 
63252a38012Sejakowatz 	BView::SetFlags(flags);
63352a38012Sejakowatz }
634058691d4SStefano Ceccherini 
635058691d4SStefano Ceccherini 
636058691d4SStefano Ceccherini void
6372a30a9e9SRene Gollent BTextControl::MessageReceived(BMessage *message)
63852a38012Sejakowatz {
6392a30a9e9SRene Gollent 	if (message->what == B_GET_PROPERTY || message->what == B_SET_PROPERTY) {
6402a30a9e9SRene Gollent 		BMessage reply(B_REPLY);
6412a30a9e9SRene Gollent 		bool handled = false;
6424438cb3bSRene Gollent 
6432a30a9e9SRene Gollent 		BMessage specifier;
6442a30a9e9SRene Gollent 		int32 index;
6452a30a9e9SRene Gollent 		int32 form;
6462a30a9e9SRene Gollent 		const char *property;
6472a30a9e9SRene Gollent 		if (message->GetCurrentSpecifier(&index, &specifier, &form, &property) == B_OK) {
6482a30a9e9SRene Gollent 			if (strcmp(property, "Value") == 0) {
6492a30a9e9SRene Gollent 				if (message->what == B_GET_PROPERTY) {
6502a30a9e9SRene Gollent 					reply.AddString("result", fText->Text());
6512a30a9e9SRene Gollent 					handled = true;
6522a30a9e9SRene Gollent 				} else {
6532a30a9e9SRene Gollent 					const char *value = NULL;
6542a30a9e9SRene Gollent 					// B_SET_PROPERTY
6552a30a9e9SRene Gollent 					if (message->FindString("data", &value) == B_OK) {
6562a30a9e9SRene Gollent 						fText->SetText(value);
6572a30a9e9SRene Gollent 						reply.AddInt32("error", B_OK);
6582a30a9e9SRene Gollent 						handled = true;
65952a38012Sejakowatz 					}
66052a38012Sejakowatz 				}
6612a30a9e9SRene Gollent 			}
6622a30a9e9SRene Gollent 		}
6632a30a9e9SRene Gollent 
6642a30a9e9SRene Gollent 		if (handled) {
6652a30a9e9SRene Gollent 			message->SendReply(&reply);
6662a30a9e9SRene Gollent 			return;
6672a30a9e9SRene Gollent 		}
6682a30a9e9SRene Gollent 	}
6692a30a9e9SRene Gollent 
6702a30a9e9SRene Gollent 	BControl::MessageReceived(message);
6712a30a9e9SRene Gollent }
672058691d4SStefano Ceccherini 
673058691d4SStefano Ceccherini 
674058691d4SStefano Ceccherini BHandler *
6752a30a9e9SRene Gollent BTextControl::ResolveSpecifier(BMessage *message, int32 index,
6762a30a9e9SRene Gollent 										 BMessage *specifier, int32 what,
67752a38012Sejakowatz 										 const char *property)
67852a38012Sejakowatz {
6792a30a9e9SRene Gollent 	BPropertyInfo propInfo(sPropertyList);
6809cb2dbe2SMarc Flerackers 
6812a30a9e9SRene Gollent 	if (propInfo.FindMatch(message, 0, specifier, what, property) >= B_OK)
6822a30a9e9SRene Gollent 		return this;
6832a30a9e9SRene Gollent 
6849cb2dbe2SMarc Flerackers 	return BControl::ResolveSpecifier(message, index, specifier, what,
6859cb2dbe2SMarc Flerackers 		property);
68652a38012Sejakowatz }
687058691d4SStefano Ceccherini 
688058691d4SStefano Ceccherini 
689058691d4SStefano Ceccherini status_t
690058691d4SStefano Ceccherini BTextControl::GetSupportedSuites(BMessage *data)
69152a38012Sejakowatz {
6929cb2dbe2SMarc Flerackers 	return BControl::GetSupportedSuites(data);
69352a38012Sejakowatz }
694058691d4SStefano Ceccherini 
695058691d4SStefano Ceccherini 
696058691d4SStefano Ceccherini void
697058691d4SStefano Ceccherini BTextControl::MouseUp(BPoint pt)
69852a38012Sejakowatz {
69952a38012Sejakowatz 	BControl::MouseUp(pt);
70052a38012Sejakowatz }
701058691d4SStefano Ceccherini 
702058691d4SStefano Ceccherini 
703058691d4SStefano Ceccherini void
704058691d4SStefano Ceccherini BTextControl::MouseMoved(BPoint pt, uint32 code, const BMessage *msg)
70552a38012Sejakowatz {
70652a38012Sejakowatz 	BControl::MouseMoved(pt, code, msg);
70752a38012Sejakowatz }
708058691d4SStefano Ceccherini 
709058691d4SStefano Ceccherini 
710058691d4SStefano Ceccherini void
711058691d4SStefano Ceccherini BTextControl::DetachedFromWindow()
71252a38012Sejakowatz {
71352a38012Sejakowatz 	BControl::DetachedFromWindow();
71452a38012Sejakowatz }
715058691d4SStefano Ceccherini 
716058691d4SStefano Ceccherini 
717058691d4SStefano Ceccherini void
718058691d4SStefano Ceccherini BTextControl::AllAttached()
71952a38012Sejakowatz {
72052a38012Sejakowatz 	BControl::AllAttached();
72152a38012Sejakowatz }
722058691d4SStefano Ceccherini 
723058691d4SStefano Ceccherini 
724058691d4SStefano Ceccherini void
725058691d4SStefano Ceccherini BTextControl::AllDetached()
72652a38012Sejakowatz {
72752a38012Sejakowatz 	BControl::AllDetached();
72852a38012Sejakowatz }
729058691d4SStefano Ceccherini 
730058691d4SStefano Ceccherini 
731058691d4SStefano Ceccherini void
732058691d4SStefano Ceccherini BTextControl::FrameMoved(BPoint newPosition)
73352a38012Sejakowatz {
73452a38012Sejakowatz 	BControl::FrameMoved(newPosition);
73552a38012Sejakowatz }
736058691d4SStefano Ceccherini 
737058691d4SStefano Ceccherini 
738058691d4SStefano Ceccherini void
739ffe72abdSAxel Dörfler BTextControl::FrameResized(float width, float height)
74052a38012Sejakowatz {
74193ba577cSStephan Aßmus 	CALLED();
74293ba577cSStephan Aßmus 
743ffe72abdSAxel Dörfler 	BControl::FrameResized(width, height);
744ffe72abdSAxel Dörfler 
745349c911eSStephan Aßmus 	// TODO: this causes flickering still...
746349c911eSStephan Aßmus 
747ffe72abdSAxel Dörfler 	// changes in width
748ffe72abdSAxel Dörfler 
749ffe72abdSAxel Dörfler 	BRect bounds = Bounds();
750ffe72abdSAxel Dörfler 
751349c911eSStephan Aßmus 	if (bounds.Width() > fLayoutData->previous_width) {
752ffe72abdSAxel Dörfler 		// invalidate the region between the old and the new right border
753ffe72abdSAxel Dörfler 		BRect rect = bounds;
754349c911eSStephan Aßmus 		rect.left += fLayoutData->previous_width - kFrameMargin;
755ffe72abdSAxel Dörfler 		rect.right--;
756ffe72abdSAxel Dörfler 		Invalidate(rect);
757349c911eSStephan Aßmus 	} else if (bounds.Width() < fLayoutData->previous_width) {
758ffe72abdSAxel Dörfler 		// invalidate the region of the new right border
759ffe72abdSAxel Dörfler 		BRect rect = bounds;
760349c911eSStephan Aßmus 		rect.left = rect.right - kFrameMargin;
761ffe72abdSAxel Dörfler 		Invalidate(rect);
762ffe72abdSAxel Dörfler 	}
763ffe72abdSAxel Dörfler 
764ffe72abdSAxel Dörfler 	// changes in height
765ffe72abdSAxel Dörfler 
766349c911eSStephan Aßmus 	if (bounds.Height() > fLayoutData->previous_height) {
767ffe72abdSAxel Dörfler 		// invalidate the region between the old and the new bottom border
768ffe72abdSAxel Dörfler 		BRect rect = bounds;
769349c911eSStephan Aßmus 		rect.top += fLayoutData->previous_height - kFrameMargin;
770ffe72abdSAxel Dörfler 		rect.bottom--;
771ffe72abdSAxel Dörfler 		Invalidate(rect);
772349c911eSStephan Aßmus 		// invalidate label area
773349c911eSStephan Aßmus 		rect = bounds;
774349c911eSStephan Aßmus 		rect.right = fDivider;
775349c911eSStephan Aßmus 		Invalidate(rect);
776349c911eSStephan Aßmus 	} else if (bounds.Height() < fLayoutData->previous_height) {
777ffe72abdSAxel Dörfler 		// invalidate the region of the new bottom border
778ffe72abdSAxel Dörfler 		BRect rect = bounds;
779349c911eSStephan Aßmus 		rect.top = rect.bottom - kFrameMargin;
780349c911eSStephan Aßmus 		Invalidate(rect);
781349c911eSStephan Aßmus 		// invalidate label area
782349c911eSStephan Aßmus 		rect = bounds;
783349c911eSStephan Aßmus 		rect.right = fDivider;
784ffe72abdSAxel Dörfler 		Invalidate(rect);
785ffe72abdSAxel Dörfler 	}
786ffe72abdSAxel Dörfler 
787349c911eSStephan Aßmus 	fLayoutData->previous_width = bounds.Width();
788349c911eSStephan Aßmus 	fLayoutData->previous_height = bounds.Height();
78993ba577cSStephan Aßmus 
79093ba577cSStephan Aßmus 	TRACE("width: %.2f, height: %.2f\n", bounds.Width(), bounds.Height());
79152a38012Sejakowatz }
792058691d4SStefano Ceccherini 
793058691d4SStefano Ceccherini 
794058691d4SStefano Ceccherini void
795058691d4SStefano Ceccherini BTextControl::WindowActivated(bool active)
79652a38012Sejakowatz {
7976d8d6cadSStephan Aßmus 	if (fText->IsFocus()) {
798dde10e45SStephan Aßmus 		// invalidate to remove/show focus indication
7992c5a8894SStephan Aßmus 		BRect rect = fText->Frame();
8002c5a8894SStephan Aßmus 		rect.InsetBy(-1, -1);
8016d8d6cadSStephan Aßmus 		Invalidate(rect);
802dde10e45SStephan Aßmus 
803dde10e45SStephan Aßmus 		// help out embedded text view which doesn't
804dde10e45SStephan Aßmus 		// get notified of this
805dde10e45SStephan Aßmus 		fText->Invalidate();
8066d8d6cadSStephan Aßmus 	}
80752a38012Sejakowatz }
808058691d4SStefano Ceccherini 
809058691d4SStefano Ceccherini 
810349c911eSStephan Aßmus BSize
811349c911eSStephan Aßmus BTextControl::MinSize()
81252a38012Sejakowatz {
813349c911eSStephan Aßmus 	CALLED();
814349c911eSStephan Aßmus 
815349c911eSStephan Aßmus 	_ValidateLayoutData();
816349c911eSStephan Aßmus 	return BLayoutUtils::ComposeSize(ExplicitMinSize(), fLayoutData->min);
817349c911eSStephan Aßmus }
818349c911eSStephan Aßmus 
819349c911eSStephan Aßmus 
820349c911eSStephan Aßmus BSize
821349c911eSStephan Aßmus BTextControl::MaxSize()
822349c911eSStephan Aßmus {
823349c911eSStephan Aßmus 	CALLED();
824349c911eSStephan Aßmus 
825349c911eSStephan Aßmus 	_ValidateLayoutData();
826349c911eSStephan Aßmus 
827349c911eSStephan Aßmus 	BSize max = fLayoutData->min;
828349c911eSStephan Aßmus 	max.width = B_SIZE_UNLIMITED;
829349c911eSStephan Aßmus 
830349c911eSStephan Aßmus 	return BLayoutUtils::ComposeSize(ExplicitMaxSize(), max);
831349c911eSStephan Aßmus }
832349c911eSStephan Aßmus 
833349c911eSStephan Aßmus 
834349c911eSStephan Aßmus BSize
835349c911eSStephan Aßmus BTextControl::PreferredSize()
836349c911eSStephan Aßmus {
837349c911eSStephan Aßmus 	CALLED();
838349c911eSStephan Aßmus 
839349c911eSStephan Aßmus 	_ValidateLayoutData();
840349c911eSStephan Aßmus 	return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), fLayoutData->min);
841349c911eSStephan Aßmus }
842349c911eSStephan Aßmus 
843349c911eSStephan Aßmus 
844349c911eSStephan Aßmus void
845349c911eSStephan Aßmus BTextControl::InvalidateLayout(bool descendants)
846349c911eSStephan Aßmus {
847349c911eSStephan Aßmus 	CALLED();
848349c911eSStephan Aßmus 
849349c911eSStephan Aßmus 	fLayoutData->valid = false;
850349c911eSStephan Aßmus 
851349c911eSStephan Aßmus 	BView::InvalidateLayout(descendants);
85252a38012Sejakowatz }
853058691d4SStefano Ceccherini 
854058691d4SStefano Ceccherini 
8559ecf9d1cSIngo Weinhold BLayoutItem*
8569ecf9d1cSIngo Weinhold BTextControl::CreateLabelLayoutItem()
8579ecf9d1cSIngo Weinhold {
858349c911eSStephan Aßmus 	if (!fLayoutData->label_layout_item)
859349c911eSStephan Aßmus 		fLayoutData->label_layout_item = new LabelLayoutItem(this);
860349c911eSStephan Aßmus 	return fLayoutData->label_layout_item;
8619ecf9d1cSIngo Weinhold }
8629ecf9d1cSIngo Weinhold 
8639ecf9d1cSIngo Weinhold 
8649ecf9d1cSIngo Weinhold BLayoutItem*
8659ecf9d1cSIngo Weinhold BTextControl::CreateTextViewLayoutItem()
8669ecf9d1cSIngo Weinhold {
867349c911eSStephan Aßmus 	if (!fLayoutData->text_view_layout_item)
868349c911eSStephan Aßmus 		fLayoutData->text_view_layout_item = new TextViewLayoutItem(this);
869349c911eSStephan Aßmus 	return fLayoutData->text_view_layout_item;
870349c911eSStephan Aßmus }
871349c911eSStephan Aßmus 
872349c911eSStephan Aßmus 
873349c911eSStephan Aßmus void
874349c911eSStephan Aßmus BTextControl::DoLayout()
875349c911eSStephan Aßmus {
876349c911eSStephan Aßmus 	// Bail out, if we shan't do layout.
877349c911eSStephan Aßmus 	if (!(Flags() & B_SUPPORTS_LAYOUT))
878349c911eSStephan Aßmus 		return;
879349c911eSStephan Aßmus 
880349c911eSStephan Aßmus 	CALLED();
881349c911eSStephan Aßmus 
882349c911eSStephan Aßmus 	// If the user set a layout, we let the base class version call its
883349c911eSStephan Aßmus 	// hook.
884349c911eSStephan Aßmus 	if (GetLayout()) {
885349c911eSStephan Aßmus 		BView::DoLayout();
886349c911eSStephan Aßmus 		return;
887349c911eSStephan Aßmus 	}
888349c911eSStephan Aßmus 
889349c911eSStephan Aßmus 	_ValidateLayoutData();
890349c911eSStephan Aßmus 
891349c911eSStephan Aßmus 	// validate current size
892349c911eSStephan Aßmus 	BSize size(Bounds().Size());
893349c911eSStephan Aßmus 	if (size.width < fLayoutData->min.width)
894349c911eSStephan Aßmus 		size.width = fLayoutData->min.width;
895349c911eSStephan Aßmus 	if (size.height < fLayoutData->min.height)
896349c911eSStephan Aßmus 		size.height = fLayoutData->min.height;
897349c911eSStephan Aßmus 
898349c911eSStephan Aßmus 	// divider
899349c911eSStephan Aßmus 	float divider = 0;
900349c911eSStephan Aßmus 	if (fLayoutData->label_layout_item && fLayoutData->text_view_layout_item) {
901349c911eSStephan Aßmus 		// We have layout items. They define the divider location.
902349c911eSStephan Aßmus 		divider = fLayoutData->text_view_layout_item->Frame().left
903349c911eSStephan Aßmus 			- fLayoutData->label_layout_item->Frame().left;
904349c911eSStephan Aßmus 	} else {
905349c911eSStephan Aßmus 		if (fLayoutData->label_width > 0)
906349c911eSStephan Aßmus 			divider = fLayoutData->label_width + 5;
907349c911eSStephan Aßmus 	}
908349c911eSStephan Aßmus 
909349c911eSStephan Aßmus 	// text view
910349c911eSStephan Aßmus 	BRect dirty(fText->Frame());
91184b7e122SStephan Aßmus 	BRect textFrame(divider + kFrameMargin, kFrameMargin,
91284b7e122SStephan Aßmus 		size.width - kFrameMargin, size.height - kFrameMargin);
913349c911eSStephan Aßmus 
914349c911eSStephan Aßmus 	// place the text view and set the divider
915349c911eSStephan Aßmus 	BLayoutUtils::AlignInFrame(fText, textFrame);
916349c911eSStephan Aßmus 
917349c911eSStephan Aßmus 	fDivider = divider;
918349c911eSStephan Aßmus 
919349c911eSStephan Aßmus 	// invalidate dirty region
920349c911eSStephan Aßmus 	dirty = dirty | fText->Frame();
921349c911eSStephan Aßmus 	dirty.InsetBy(-kFrameMargin, -kFrameMargin);
922349c911eSStephan Aßmus 
923349c911eSStephan Aßmus 	Invalidate(dirty);
924349c911eSStephan Aßmus }
925349c911eSStephan Aßmus 
926349c911eSStephan Aßmus 
927349c911eSStephan Aßmus // #pragma mark -
928349c911eSStephan Aßmus 
929349c911eSStephan Aßmus 
930349c911eSStephan Aßmus status_t
93139fbf550SOliver Tappe BTextControl::Perform(perform_code code, void* _data)
932349c911eSStephan Aßmus {
93339fbf550SOliver Tappe 	switch (code) {
93439fbf550SOliver Tappe 		case PERFORM_CODE_MIN_SIZE:
93539fbf550SOliver Tappe 			((perform_data_min_size*)_data)->return_value
93639fbf550SOliver Tappe 				= BTextControl::MinSize();
93739fbf550SOliver Tappe 			return B_OK;
93839fbf550SOliver Tappe 		case PERFORM_CODE_MAX_SIZE:
93939fbf550SOliver Tappe 			((perform_data_max_size*)_data)->return_value
94039fbf550SOliver Tappe 				= BTextControl::MaxSize();
94139fbf550SOliver Tappe 			return B_OK;
94239fbf550SOliver Tappe 		case PERFORM_CODE_PREFERRED_SIZE:
94339fbf550SOliver Tappe 			((perform_data_preferred_size*)_data)->return_value
94439fbf550SOliver Tappe 				= BTextControl::PreferredSize();
94539fbf550SOliver Tappe 			return B_OK;
94639fbf550SOliver Tappe 		case PERFORM_CODE_LAYOUT_ALIGNMENT:
94739fbf550SOliver Tappe 			((perform_data_layout_alignment*)_data)->return_value
94839fbf550SOliver Tappe 				= BTextControl::LayoutAlignment();
94939fbf550SOliver Tappe 			return B_OK;
95039fbf550SOliver Tappe 		case PERFORM_CODE_HAS_HEIGHT_FOR_WIDTH:
95139fbf550SOliver Tappe 			((perform_data_has_height_for_width*)_data)->return_value
95239fbf550SOliver Tappe 				= BTextControl::HasHeightForWidth();
95339fbf550SOliver Tappe 			return B_OK;
95439fbf550SOliver Tappe 		case PERFORM_CODE_GET_HEIGHT_FOR_WIDTH:
95539fbf550SOliver Tappe 		{
95639fbf550SOliver Tappe 			perform_data_get_height_for_width* data
95739fbf550SOliver Tappe 				= (perform_data_get_height_for_width*)_data;
95839fbf550SOliver Tappe 			BTextControl::GetHeightForWidth(data->width, &data->min, &data->max,
95939fbf550SOliver Tappe 				&data->preferred);
96039fbf550SOliver Tappe 			return B_OK;
96139fbf550SOliver Tappe }
96239fbf550SOliver Tappe 		case PERFORM_CODE_SET_LAYOUT:
96339fbf550SOliver Tappe 		{
96439fbf550SOliver Tappe 			perform_data_set_layout* data = (perform_data_set_layout*)_data;
96539fbf550SOliver Tappe 			BTextControl::SetLayout(data->layout);
96639fbf550SOliver Tappe 			return B_OK;
96739fbf550SOliver Tappe 		}
968*eee4243dSAlex Wilson 		case PERFORM_CODE_LAYOUT_INVALIDATED:
96939fbf550SOliver Tappe 		{
970*eee4243dSAlex Wilson 			perform_data_layout_invalidated* data
971*eee4243dSAlex Wilson 				= (perform_data_layout_invalidated*)_data;
972*eee4243dSAlex Wilson 			BTextControl::LayoutInvalidated(data->descendants);
97339fbf550SOliver Tappe 			return B_OK;
97439fbf550SOliver Tappe 		}
97539fbf550SOliver Tappe 		case PERFORM_CODE_DO_LAYOUT:
97639fbf550SOliver Tappe 		{
97739fbf550SOliver Tappe 			BTextControl::DoLayout();
97839fbf550SOliver Tappe 			return B_OK;
97939fbf550SOliver Tappe 		}
9805c47e35eSAlex Wilson 		case PERFORM_CODE_ALL_UNARCHIVED:
9815c47e35eSAlex Wilson 		{
9825c47e35eSAlex Wilson 			perform_data_all_unarchived* data
9835c47e35eSAlex Wilson 				= (perform_data_all_unarchived*)_data;
9845c47e35eSAlex Wilson 
9855c47e35eSAlex Wilson 			data->return_value = BTextControl::AllUnarchived(data->archive);
9865c47e35eSAlex Wilson 			return B_OK;
9875c47e35eSAlex Wilson 		}
9885c47e35eSAlex Wilson 		case PERFORM_CODE_ALL_ARCHIVED:
9895c47e35eSAlex Wilson 		{
9905c47e35eSAlex Wilson 			perform_data_all_archived* data
9915c47e35eSAlex Wilson 				= (perform_data_all_archived*)_data;
9925c47e35eSAlex Wilson 
9935c47e35eSAlex Wilson 			data->return_value = BTextControl::AllArchived(data->archive);
9945c47e35eSAlex Wilson 			return B_OK;
9955c47e35eSAlex Wilson 		}
99639fbf550SOliver Tappe 	}
99739fbf550SOliver Tappe 
99839fbf550SOliver Tappe 	return BControl::Perform(code, _data);
9999ecf9d1cSIngo Weinhold }
10009ecf9d1cSIngo Weinhold 
10019ecf9d1cSIngo Weinhold 
10029cb2dbe2SMarc Flerackers void BTextControl::_ReservedTextControl1() {}
10039cb2dbe2SMarc Flerackers void BTextControl::_ReservedTextControl2() {}
10049cb2dbe2SMarc Flerackers void BTextControl::_ReservedTextControl3() {}
10059cb2dbe2SMarc Flerackers void BTextControl::_ReservedTextControl4() {}
1006058691d4SStefano Ceccherini 
1007058691d4SStefano Ceccherini 
1008058691d4SStefano Ceccherini BTextControl &
1009058691d4SStefano Ceccherini BTextControl::operator=(const BTextControl&)
101052a38012Sejakowatz {
101152a38012Sejakowatz 	return *this;
101252a38012Sejakowatz }
1013058691d4SStefano Ceccherini 
1014058691d4SStefano Ceccherini 
1015058691d4SStefano Ceccherini void
101679c35b39SAxel Dörfler BTextControl::_UpdateTextViewColors(bool enabled)
10173a3f6c1eSAxel Dörfler {
10183a3f6c1eSAxel Dörfler 	rgb_color textColor;
1019aae7000dSAxel Dörfler 	rgb_color color;
10203a3f6c1eSAxel Dörfler 	BFont font;
10213a3f6c1eSAxel Dörfler 
1022aae7000dSAxel Dörfler 	fText->GetFontAndColor(0, &font);
10233a3f6c1eSAxel Dörfler 
10243a3f6c1eSAxel Dörfler 	if (enabled)
1025aae7000dSAxel Dörfler 		textColor = ui_color(B_DOCUMENT_TEXT_COLOR);
102612aefeb4SAxel Dörfler 	else {
102712aefeb4SAxel Dörfler 		textColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
102812aefeb4SAxel Dörfler 			B_DISABLED_LABEL_TINT);
102912aefeb4SAxel Dörfler 	}
10303a3f6c1eSAxel Dörfler 
10313a3f6c1eSAxel Dörfler 	fText->SetFontAndColor(&font, B_FONT_ALL, &textColor);
10323a3f6c1eSAxel Dörfler 
10333a3f6c1eSAxel Dörfler 	if (enabled) {
1034aae7000dSAxel Dörfler 		color = ui_color(B_DOCUMENT_BACKGROUND_COLOR);
10353a3f6c1eSAxel Dörfler 	} else {
10363a3f6c1eSAxel Dörfler 		color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
10373a3f6c1eSAxel Dörfler 			B_LIGHTEN_2_TINT);
10383a3f6c1eSAxel Dörfler 	}
10393a3f6c1eSAxel Dörfler 
10403a3f6c1eSAxel Dörfler 	fText->SetViewColor(color);
10413a3f6c1eSAxel Dörfler 	fText->SetLowColor(color);
10423a3f6c1eSAxel Dörfler }
10433a3f6c1eSAxel Dörfler 
10443a3f6c1eSAxel Dörfler 
10453a3f6c1eSAxel Dörfler void
1046ffe72abdSAxel Dörfler BTextControl::_CommitValue()
10479cb2dbe2SMarc Flerackers {
10489cb2dbe2SMarc Flerackers }
1049058691d4SStefano Ceccherini 
1050058691d4SStefano Ceccherini 
1051058691d4SStefano Ceccherini void
10525c47e35eSAlex Wilson BTextControl::_InitData(const char* label, const BMessage* archive)
10539cb2dbe2SMarc Flerackers {
10549cb2dbe2SMarc Flerackers 	BRect bounds(Bounds());
10559cb2dbe2SMarc Flerackers 
10569cb2dbe2SMarc Flerackers 	fText = NULL;
10579cb2dbe2SMarc Flerackers 	fModificationMessage = NULL;
10589cb2dbe2SMarc Flerackers 	fLabelAlign = B_ALIGN_LEFT;
10599cb2dbe2SMarc Flerackers 	fDivider = 0.0f;
1060349c911eSStephan Aßmus 	fLayoutData = new LayoutData(bounds.Width(), bounds.Height());
10619cb2dbe2SMarc Flerackers 
10629cb2dbe2SMarc Flerackers 	int32 flags = 0;
10639cb2dbe2SMarc Flerackers 
1064918a22d9SDarkWyrm 	BFont font(be_plain_font);
10659cb2dbe2SMarc Flerackers 
1066ffe72abdSAxel Dörfler 	if (!archive || !archive->HasString("_fname"))
1067058691d4SStefano Ceccherini 		flags |= B_FONT_FAMILY_AND_STYLE;
10689cb2dbe2SMarc Flerackers 
1069ffe72abdSAxel Dörfler 	if (!archive || !archive->HasFloat("_fflt"))
1070058691d4SStefano Ceccherini 		flags |= B_FONT_SIZE;
10719cb2dbe2SMarc Flerackers 
10729cb2dbe2SMarc Flerackers 	if (flags != 0)
10739cb2dbe2SMarc Flerackers 		SetFont(&font, flags);
10749cb2dbe2SMarc Flerackers 
10759cb2dbe2SMarc Flerackers 	if (label)
10762e6a5805SStephan Aßmus 		fDivider = floorf(bounds.Width() / 2.0f);
10779cb2dbe2SMarc Flerackers 
10785c47e35eSAlex Wilson }
10795c47e35eSAlex Wilson 
10805c47e35eSAlex Wilson 
10815c47e35eSAlex Wilson void
10825c47e35eSAlex Wilson BTextControl::_InitText(const char* initialText, const BMessage* archive)
10835c47e35eSAlex Wilson {
1084ffe72abdSAxel Dörfler 	if (archive)
1085b8872c02SStephan Aßmus 		fText = static_cast<BPrivate::_BTextInput_*>(FindView("_input_"));
1086991c062fSAxel Dörfler 
1087991c062fSAxel Dörfler 	if (fText == NULL) {
10885c47e35eSAlex Wilson 		BRect bounds(Bounds());
1089ee2a3473SStephan Aßmus 		BRect frame(fDivider, bounds.top, bounds.right, bounds.bottom);
1090105644bfSAxel Dörfler 		// we are stroking the frame around the text view, which
10912e6a5805SStephan Aßmus 		// is 2 pixels wide
1092349c911eSStephan Aßmus 		frame.InsetBy(kFrameMargin, kFrameMargin);
1093111b4fbcSStefano Ceccherini 		BRect textRect(frame.OffsetToCopy(B_ORIGIN));
10949cb2dbe2SMarc Flerackers 
1095b8872c02SStephan Aßmus 		fText = new BPrivate::_BTextInput_(frame, textRect,
10965c47e35eSAlex Wilson 			B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS
10975c47e35eSAlex Wilson 			| (Flags() & B_NAVIGABLE));
10989cb2dbe2SMarc Flerackers 		AddChild(fText);
10999cb2dbe2SMarc Flerackers 
1100455d1c46SAxel Dörfler 		SetText(initialText);
11019cb2dbe2SMarc Flerackers 		fText->SetAlignment(B_ALIGN_LEFT);
11029cb2dbe2SMarc Flerackers 		fText->AlignTextRect();
11039cb2dbe2SMarc Flerackers 	}
11045c47e35eSAlex Wilson 
11055c47e35eSAlex Wilson 	// Although this is not strictly initializing the text view,
11065c47e35eSAlex Wilson 	// it cannot be done while fText is NULL, so it resides here.
11075c47e35eSAlex Wilson 	if (archive) {
11085c47e35eSAlex Wilson 		int32 labelAlignment = B_ALIGN_LEFT;
11095c47e35eSAlex Wilson 		int32 textAlignment = B_ALIGN_LEFT;
11105c47e35eSAlex Wilson 
11115c47e35eSAlex Wilson 		status_t err = B_OK;
11125c47e35eSAlex Wilson 		if (archive->HasInt32("_a_label"))
11135c47e35eSAlex Wilson 			err = archive->FindInt32("_a_label", &labelAlignment);
11145c47e35eSAlex Wilson 
11155c47e35eSAlex Wilson 		if (err == B_OK && archive->HasInt32("_a_text"))
11165c47e35eSAlex Wilson 			err = archive->FindInt32("_a_text", &textAlignment);
11175c47e35eSAlex Wilson 
11185c47e35eSAlex Wilson 		SetAlignment((alignment)labelAlignment, (alignment)textAlignment);
11195c47e35eSAlex Wilson 	}
112050960935SClemens Zeidler 
112150960935SClemens Zeidler 	uint32 navigableFlags = Flags() & B_NAVIGABLE;
112250960935SClemens Zeidler 	if (navigableFlags != 0)
112350960935SClemens Zeidler 		BView::SetFlags(Flags() & ~B_NAVIGABLE);
11249cb2dbe2SMarc Flerackers }
11259ecf9d1cSIngo Weinhold 
11269ecf9d1cSIngo Weinhold 
11279ecf9d1cSIngo Weinhold void
11289ecf9d1cSIngo Weinhold BTextControl::_ValidateLayout()
11299ecf9d1cSIngo Weinhold {
113093ba577cSStephan Aßmus 	CALLED();
113193ba577cSStephan Aßmus 
1132349c911eSStephan Aßmus 	_ValidateLayoutData();
11339ecf9d1cSIngo Weinhold 
1134349c911eSStephan Aßmus 	ResizeTo(Bounds().Width(), fLayoutData->min.height);
11359ecf9d1cSIngo Weinhold 
1136a431f44bSStephan Aßmus 	_LayoutTextView();
11379ecf9d1cSIngo Weinhold }
11389ecf9d1cSIngo Weinhold 
11399ecf9d1cSIngo Weinhold 
11409ecf9d1cSIngo Weinhold void
1141a431f44bSStephan Aßmus BTextControl::_LayoutTextView()
1142a431f44bSStephan Aßmus {
114393ba577cSStephan Aßmus 	CALLED();
114493ba577cSStephan Aßmus 
1145a431f44bSStephan Aßmus 	BRect frame = Bounds();
1146a431f44bSStephan Aßmus 	frame.left = fDivider;
1147a431f44bSStephan Aßmus 	// we are stroking the frame around the text view, which
1148a431f44bSStephan Aßmus 	// is 2 pixels wide
114984b7e122SStephan Aßmus 	frame.InsetBy(kFrameMargin, kFrameMargin);
1150a431f44bSStephan Aßmus 	fText->MoveTo(frame.left, frame.top);
1151a431f44bSStephan Aßmus 	fText->ResizeTo(frame.Width(), frame.Height());
1152b8872c02SStephan Aßmus 	fText->AlignTextRect();
115393ba577cSStephan Aßmus 
115493ba577cSStephan Aßmus 	TRACE("width: %.2f, height: %.2f\n", Frame().Width(), Frame().Height());
115593ba577cSStephan Aßmus 	TRACE("fDivider: %.2f\n", fDivider);
115693ba577cSStephan Aßmus 	TRACE("fText frame: (%.2f, %.2f, %.2f, %.2f)\n",
115793ba577cSStephan Aßmus 		frame.left, frame.top, frame.right, frame.bottom);
1158a431f44bSStephan Aßmus }
1159a431f44bSStephan Aßmus 
1160a431f44bSStephan Aßmus 
1161a431f44bSStephan Aßmus void
11629ecf9d1cSIngo Weinhold BTextControl::_UpdateFrame()
11639ecf9d1cSIngo Weinhold {
1164349c911eSStephan Aßmus 	CALLED();
1165349c911eSStephan Aßmus 
1166349c911eSStephan Aßmus 	if (fLayoutData->label_layout_item && fLayoutData->text_view_layout_item) {
1167349c911eSStephan Aßmus 		BRect labelFrame = fLayoutData->label_layout_item->Frame();
1168349c911eSStephan Aßmus 		BRect textFrame = fLayoutData->text_view_layout_item->Frame();
1169349c911eSStephan Aßmus 
1170349c911eSStephan Aßmus 		// update divider
1171349c911eSStephan Aßmus 		fDivider = textFrame.left - labelFrame.left;
1172349c911eSStephan Aßmus 
11739ecf9d1cSIngo Weinhold 		MoveTo(labelFrame.left, labelFrame.top);
1174349c911eSStephan Aßmus 		BSize oldSize = Bounds().Size();
11759ecf9d1cSIngo Weinhold 		ResizeTo(textFrame.left + textFrame.Width() - labelFrame.left,
11769ecf9d1cSIngo Weinhold 			textFrame.top + textFrame.Height() - labelFrame.top);
1177349c911eSStephan Aßmus 		BSize newSize = Bounds().Size();
1178349c911eSStephan Aßmus 
1179349c911eSStephan Aßmus 		// If the size changes, ResizeTo() will trigger a relayout, otherwise
1180349c911eSStephan Aßmus 		// we need to do that explicitly.
1181349c911eSStephan Aßmus 		if (newSize != oldSize)
1182349c911eSStephan Aßmus 			Relayout();
11839ecf9d1cSIngo Weinhold 	}
11849ecf9d1cSIngo Weinhold }
11859ecf9d1cSIngo Weinhold 
11869ecf9d1cSIngo Weinhold 
1187349c911eSStephan Aßmus void
1188349c911eSStephan Aßmus BTextControl::_ValidateLayoutData()
1189349c911eSStephan Aßmus {
1190349c911eSStephan Aßmus 	CALLED();
1191349c911eSStephan Aßmus 
1192349c911eSStephan Aßmus 	if (fLayoutData->valid)
1193349c911eSStephan Aßmus 		return;
1194349c911eSStephan Aßmus 
1195349c911eSStephan Aßmus 	// cache font height
1196349c911eSStephan Aßmus 	font_height& fh = fLayoutData->font_info;
1197349c911eSStephan Aßmus 	GetFontHeight(&fh);
1198349c911eSStephan Aßmus 
1199349c911eSStephan Aßmus 	if (Label() != NULL) {
1200349c911eSStephan Aßmus 		fLayoutData->label_width = ceilf(StringWidth(Label()));
1201349c911eSStephan Aßmus 		fLayoutData->label_height = ceilf(fh.ascent) + ceilf(fh.descent);
1202349c911eSStephan Aßmus 	} else {
1203349c911eSStephan Aßmus 		fLayoutData->label_width = 0;
1204349c911eSStephan Aßmus 		fLayoutData->label_height = 0;
1205349c911eSStephan Aßmus 	}
1206349c911eSStephan Aßmus 
1207349c911eSStephan Aßmus 	// compute the minimal divider
1208349c911eSStephan Aßmus 	float divider = 0;
1209349c911eSStephan Aßmus 	if (fLayoutData->label_width > 0)
1210349c911eSStephan Aßmus 		divider = fLayoutData->label_width + 5;
1211349c911eSStephan Aßmus 
1212349c911eSStephan Aßmus 	// If we shan't do real layout, we let the current divider take influence.
1213349c911eSStephan Aßmus 	if (!(Flags() & B_SUPPORTS_LAYOUT))
1214349c911eSStephan Aßmus 		divider = max_c(divider, fDivider);
1215349c911eSStephan Aßmus 
1216349c911eSStephan Aßmus 	// get the minimal (== preferred) text view size
1217349c911eSStephan Aßmus 	fLayoutData->text_view_min = fText->MinSize();
1218349c911eSStephan Aßmus 
1219349c911eSStephan Aßmus 	TRACE("text view min width: %.2f\n", fLayoutData->text_view_min.width);
1220349c911eSStephan Aßmus 
1221349c911eSStephan Aßmus 	// compute our minimal (== preferred) size
1222349c911eSStephan Aßmus 	BSize min(fLayoutData->text_view_min);
1223349c911eSStephan Aßmus 	min.width += 2 * kFrameMargin;
1224349c911eSStephan Aßmus 	min.height += 2 * kFrameMargin;
1225349c911eSStephan Aßmus 
1226349c911eSStephan Aßmus 	if (divider > 0)
1227349c911eSStephan Aßmus 		min.width += divider;
1228349c911eSStephan Aßmus 	if (fLayoutData->label_height > min.height)
1229349c911eSStephan Aßmus 		min.height = fLayoutData->label_height;
1230349c911eSStephan Aßmus 
1231349c911eSStephan Aßmus 	fLayoutData->min = min;
1232349c911eSStephan Aßmus 
1233349c911eSStephan Aßmus 	fLayoutData->valid = true;
1234c944d11fSStephan Aßmus 	ResetLayoutInvalidation();
1235349c911eSStephan Aßmus 
1236349c911eSStephan Aßmus 	TRACE("width: %.2f, height: %.2f\n", min.width, min.height);
1237349c911eSStephan Aßmus }
1238349c911eSStephan Aßmus 
1239349c911eSStephan Aßmus 
12409ecf9d1cSIngo Weinhold // #pragma mark -
12419ecf9d1cSIngo Weinhold 
12429ecf9d1cSIngo Weinhold 
12439ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::LabelLayoutItem(BTextControl* parent)
12445c47e35eSAlex Wilson 	:
12455c47e35eSAlex Wilson 	fParent(parent),
12469ecf9d1cSIngo Weinhold 	fFrame()
12479ecf9d1cSIngo Weinhold {
12489ecf9d1cSIngo Weinhold }
12499ecf9d1cSIngo Weinhold 
12509ecf9d1cSIngo Weinhold 
12515c47e35eSAlex Wilson BTextControl::LabelLayoutItem::LabelLayoutItem(BMessage* from)
12525c47e35eSAlex Wilson 	:
12535c47e35eSAlex Wilson 	BAbstractLayoutItem(from),
12545c47e35eSAlex Wilson 	fParent(NULL),
12555c47e35eSAlex Wilson 	fFrame()
12565c47e35eSAlex Wilson {
12575c47e35eSAlex Wilson 	from->FindRect(kFrameField, &fFrame);
12585c47e35eSAlex Wilson }
12595c47e35eSAlex Wilson 
12605c47e35eSAlex Wilson 
12619ecf9d1cSIngo Weinhold bool
12629ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::IsVisible()
12639ecf9d1cSIngo Weinhold {
12649ecf9d1cSIngo Weinhold 	return !fParent->IsHidden(fParent);
12659ecf9d1cSIngo Weinhold }
12669ecf9d1cSIngo Weinhold 
12679ecf9d1cSIngo Weinhold 
12689ecf9d1cSIngo Weinhold void
12699ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::SetVisible(bool visible)
12709ecf9d1cSIngo Weinhold {
12719ecf9d1cSIngo Weinhold 	// not allowed
12729ecf9d1cSIngo Weinhold }
12739ecf9d1cSIngo Weinhold 
12749ecf9d1cSIngo Weinhold 
12759ecf9d1cSIngo Weinhold BRect
12769ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::Frame()
12779ecf9d1cSIngo Weinhold {
12789ecf9d1cSIngo Weinhold 	return fFrame;
12799ecf9d1cSIngo Weinhold }
12809ecf9d1cSIngo Weinhold 
12819ecf9d1cSIngo Weinhold 
12829ecf9d1cSIngo Weinhold void
12839ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::SetFrame(BRect frame)
12849ecf9d1cSIngo Weinhold {
12859ecf9d1cSIngo Weinhold 	fFrame = frame;
12869ecf9d1cSIngo Weinhold 	fParent->_UpdateFrame();
12879ecf9d1cSIngo Weinhold }
12889ecf9d1cSIngo Weinhold 
12899ecf9d1cSIngo Weinhold 
12905c47e35eSAlex Wilson void
12915c47e35eSAlex Wilson BTextControl::LabelLayoutItem::SetParent(BTextControl* parent)
12925c47e35eSAlex Wilson {
12935c47e35eSAlex Wilson 	fParent = parent;
12945c47e35eSAlex Wilson }
12955c47e35eSAlex Wilson 
12965c47e35eSAlex Wilson 
12979ecf9d1cSIngo Weinhold BView*
12989ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::View()
12999ecf9d1cSIngo Weinhold {
13009ecf9d1cSIngo Weinhold 	return fParent;
13019ecf9d1cSIngo Weinhold }
13029ecf9d1cSIngo Weinhold 
13039ecf9d1cSIngo Weinhold 
13049ecf9d1cSIngo Weinhold BSize
13059ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::BaseMinSize()
13069ecf9d1cSIngo Weinhold {
1307349c911eSStephan Aßmus 	fParent->_ValidateLayoutData();
1308349c911eSStephan Aßmus 
1309349c911eSStephan Aßmus 	if (!fParent->Label())
13109ecf9d1cSIngo Weinhold 		return BSize(-1, -1);
13119ecf9d1cSIngo Weinhold 
1312349c911eSStephan Aßmus 	return BSize(fParent->fLayoutData->label_width + 5,
1313349c911eSStephan Aßmus 		fParent->fLayoutData->label_height);
13149ecf9d1cSIngo Weinhold }
13159ecf9d1cSIngo Weinhold 
13169ecf9d1cSIngo Weinhold 
13179ecf9d1cSIngo Weinhold BSize
13189ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::BaseMaxSize()
13199ecf9d1cSIngo Weinhold {
13209ecf9d1cSIngo Weinhold 	return BaseMinSize();
13219ecf9d1cSIngo Weinhold }
13229ecf9d1cSIngo Weinhold 
13239ecf9d1cSIngo Weinhold 
13249ecf9d1cSIngo Weinhold BSize
13259ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::BasePreferredSize()
13269ecf9d1cSIngo Weinhold {
13279ecf9d1cSIngo Weinhold 	return BaseMinSize();
13289ecf9d1cSIngo Weinhold }
13299ecf9d1cSIngo Weinhold 
13309ecf9d1cSIngo Weinhold 
13319ecf9d1cSIngo Weinhold BAlignment
13329ecf9d1cSIngo Weinhold BTextControl::LabelLayoutItem::BaseAlignment()
13339ecf9d1cSIngo Weinhold {
13349ecf9d1cSIngo Weinhold 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
13359ecf9d1cSIngo Weinhold }
13369ecf9d1cSIngo Weinhold 
13379ecf9d1cSIngo Weinhold 
13385c47e35eSAlex Wilson status_t
13395c47e35eSAlex Wilson BTextControl::LabelLayoutItem::Archive(BMessage* into, bool deep) const
13405c47e35eSAlex Wilson {
13415c47e35eSAlex Wilson 	BArchiver archiver(into);
13425c47e35eSAlex Wilson 	status_t err = BAbstractLayoutItem::Archive(into, deep);
13435c47e35eSAlex Wilson 	if (err == B_OK)
13445c47e35eSAlex Wilson 		err = into->AddRect(kFrameField, fFrame);
13455c47e35eSAlex Wilson 
13465c47e35eSAlex Wilson 	return archiver.Finish(err);
13475c47e35eSAlex Wilson }
13485c47e35eSAlex Wilson 
13495c47e35eSAlex Wilson 
13505c47e35eSAlex Wilson BArchivable*
13515c47e35eSAlex Wilson BTextControl::LabelLayoutItem::Instantiate(BMessage* from)
13525c47e35eSAlex Wilson {
13535c47e35eSAlex Wilson 	if (validate_instantiation(from, "BTextControl::LabelLayoutItem"))
13545c47e35eSAlex Wilson 		return new LabelLayoutItem(from);
13555c47e35eSAlex Wilson 	return NULL;
13565c47e35eSAlex Wilson }
13575c47e35eSAlex Wilson 
13585c47e35eSAlex Wilson 
13599ecf9d1cSIngo Weinhold // #pragma mark -
13609ecf9d1cSIngo Weinhold 
13619ecf9d1cSIngo Weinhold 
13629ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::TextViewLayoutItem(BTextControl* parent)
13635c47e35eSAlex Wilson 	:
13645c47e35eSAlex Wilson 	fParent(parent),
13659ecf9d1cSIngo Weinhold 	fFrame()
13669ecf9d1cSIngo Weinhold {
1367349c911eSStephan Aßmus 	// by default the part right of the divider shall have an unlimited maximum
1368349c911eSStephan Aßmus 	// width
1369349c911eSStephan Aßmus 	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
13709ecf9d1cSIngo Weinhold }
13719ecf9d1cSIngo Weinhold 
13729ecf9d1cSIngo Weinhold 
13735c47e35eSAlex Wilson BTextControl::TextViewLayoutItem::TextViewLayoutItem(BMessage* from)
13745c47e35eSAlex Wilson 	:
13755c47e35eSAlex Wilson 	BAbstractLayoutItem(from),
13765c47e35eSAlex Wilson 	fParent(NULL),
13775c47e35eSAlex Wilson 	fFrame()
13785c47e35eSAlex Wilson {
13795c47e35eSAlex Wilson 	from->FindRect(kFrameField, &fFrame);
13805c47e35eSAlex Wilson }
13815c47e35eSAlex Wilson 
13825c47e35eSAlex Wilson 
13839ecf9d1cSIngo Weinhold bool
13849ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::IsVisible()
13859ecf9d1cSIngo Weinhold {
13869ecf9d1cSIngo Weinhold 	return !fParent->IsHidden(fParent);
13879ecf9d1cSIngo Weinhold }
13889ecf9d1cSIngo Weinhold 
13899ecf9d1cSIngo Weinhold 
13909ecf9d1cSIngo Weinhold void
13919ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::SetVisible(bool visible)
13929ecf9d1cSIngo Weinhold {
13939ecf9d1cSIngo Weinhold 	// not allowed
13949ecf9d1cSIngo Weinhold }
13959ecf9d1cSIngo Weinhold 
13969ecf9d1cSIngo Weinhold 
13979ecf9d1cSIngo Weinhold BRect
13989ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::Frame()
13999ecf9d1cSIngo Weinhold {
14009ecf9d1cSIngo Weinhold 	return fFrame;
14019ecf9d1cSIngo Weinhold }
14029ecf9d1cSIngo Weinhold 
14039ecf9d1cSIngo Weinhold 
14049ecf9d1cSIngo Weinhold void
14059ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::SetFrame(BRect frame)
14069ecf9d1cSIngo Weinhold {
14079ecf9d1cSIngo Weinhold 	fFrame = frame;
14089ecf9d1cSIngo Weinhold 	fParent->_UpdateFrame();
14099ecf9d1cSIngo Weinhold }
14109ecf9d1cSIngo Weinhold 
14119ecf9d1cSIngo Weinhold 
14125c47e35eSAlex Wilson void
14135c47e35eSAlex Wilson BTextControl::TextViewLayoutItem::SetParent(BTextControl* parent)
14145c47e35eSAlex Wilson {
14155c47e35eSAlex Wilson 	fParent = parent;
14165c47e35eSAlex Wilson }
14175c47e35eSAlex Wilson 
14185c47e35eSAlex Wilson 
14199ecf9d1cSIngo Weinhold BView*
14209ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::View()
14219ecf9d1cSIngo Weinhold {
14229ecf9d1cSIngo Weinhold 	return fParent;
14239ecf9d1cSIngo Weinhold }
14249ecf9d1cSIngo Weinhold 
14259ecf9d1cSIngo Weinhold 
14269ecf9d1cSIngo Weinhold BSize
14279ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::BaseMinSize()
14289ecf9d1cSIngo Weinhold {
1429349c911eSStephan Aßmus 	fParent->_ValidateLayoutData();
14309ecf9d1cSIngo Weinhold 
1431349c911eSStephan Aßmus 	BSize size = fParent->fLayoutData->text_view_min;
1432349c911eSStephan Aßmus 	size.width += 2 * kFrameMargin;
1433349c911eSStephan Aßmus 	size.height += 2 * kFrameMargin;
14349ecf9d1cSIngo Weinhold 
14359ecf9d1cSIngo Weinhold 	return size;
14369ecf9d1cSIngo Weinhold }
14379ecf9d1cSIngo Weinhold 
14389ecf9d1cSIngo Weinhold 
14399ecf9d1cSIngo Weinhold BSize
14409ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::BaseMaxSize()
14419ecf9d1cSIngo Weinhold {
14429ecf9d1cSIngo Weinhold 	BSize size(BaseMinSize());
14439ecf9d1cSIngo Weinhold 	size.width = B_SIZE_UNLIMITED;
14449ecf9d1cSIngo Weinhold 	return size;
14459ecf9d1cSIngo Weinhold }
14469ecf9d1cSIngo Weinhold 
14479ecf9d1cSIngo Weinhold 
14489ecf9d1cSIngo Weinhold BSize
14499ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::BasePreferredSize()
14509ecf9d1cSIngo Weinhold {
14519ecf9d1cSIngo Weinhold 	BSize size(BaseMinSize());
14529ecf9d1cSIngo Weinhold 	// puh, no idea...
14539ecf9d1cSIngo Weinhold 	size.width = 100;
14549ecf9d1cSIngo Weinhold 	return size;
14559ecf9d1cSIngo Weinhold }
14569ecf9d1cSIngo Weinhold 
14579ecf9d1cSIngo Weinhold 
14589ecf9d1cSIngo Weinhold BAlignment
14599ecf9d1cSIngo Weinhold BTextControl::TextViewLayoutItem::BaseAlignment()
14609ecf9d1cSIngo Weinhold {
14619ecf9d1cSIngo Weinhold 	return BAlignment(B_ALIGN_USE_FULL_WIDTH, B_ALIGN_USE_FULL_HEIGHT);
14629ecf9d1cSIngo Weinhold }
14639ecf9d1cSIngo Weinhold 
14645c47e35eSAlex Wilson 
14655c47e35eSAlex Wilson status_t
14665c47e35eSAlex Wilson BTextControl::TextViewLayoutItem::Archive(BMessage* into, bool deep) const
14675c47e35eSAlex Wilson {
14685c47e35eSAlex Wilson 	BArchiver archiver(into);
14695c47e35eSAlex Wilson 	status_t err = BAbstractLayoutItem::Archive(into, deep);
14705c47e35eSAlex Wilson 	if (err == B_OK)
14715c47e35eSAlex Wilson 		err = into->AddRect(kFrameField, fFrame);
14725c47e35eSAlex Wilson 
14735c47e35eSAlex Wilson 	return archiver.Finish(err);
14745c47e35eSAlex Wilson }
14755c47e35eSAlex Wilson 
14765c47e35eSAlex Wilson 
14775c47e35eSAlex Wilson BArchivable*
14785c47e35eSAlex Wilson BTextControl::TextViewLayoutItem::Instantiate(BMessage* from)
14795c47e35eSAlex Wilson {
14805c47e35eSAlex Wilson 	if (validate_instantiation(from, "BTextControl::TextViewLayoutItem"))
14815c47e35eSAlex Wilson 		return new TextViewLayoutItem(from);
14825c47e35eSAlex Wilson 	return NULL;
14835c47e35eSAlex Wilson }
14845c47e35eSAlex Wilson 
14855c47e35eSAlex Wilson 
1486