xref: /haiku/src/kits/interface/TextInput.cpp (revision b2537f99cdffc40818b65879120ecae67b29d7d9)
1 /*
2  * Copyright 2001-2007, Haiku Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Frans van Nispen (xlr8@tref.nl)
7  *		Marc Flerackers (mflerackers@androme.be)
8  */
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <InterfaceDefs.h>
15 #include <Message.h>
16 #include <TextControl.h>
17 #include <TextView.h>
18 #include <Window.h>
19 
20 #include "TextInput.h"
21 
22 
23 _BTextInput_::_BTextInput_(BRect frame, BRect textRect, uint32 resizeMask,
24 						   uint32 flags)
25 	:	BTextView(frame, "_input_", textRect, resizeMask, flags),
26 		fPreviousText(NULL),
27 		fBool(false)
28 {
29 	MakeResizable(true);
30 }
31 
32 
33 _BTextInput_::_BTextInput_(BMessage *archive)
34 	:	BTextView(archive),
35 		fPreviousText(NULL),
36 		fBool(false)
37 {
38 	MakeResizable(true);
39 }
40 
41 
42 _BTextInput_::~_BTextInput_()
43 {
44 	free(fPreviousText);
45 }
46 
47 
48 BArchivable *
49 _BTextInput_::Instantiate(BMessage *archive)
50 {
51 	if (validate_instantiation(archive, "_BTextInput_"))
52 		return new _BTextInput_(archive);
53 
54 	return NULL;
55 }
56 
57 
58 status_t
59 _BTextInput_::Archive(BMessage *data, bool deep) const
60 {
61 	return BTextView::Archive(data, true);
62 }
63 
64 
65 void
66 _BTextInput_::FrameResized(float width, float height)
67 {
68 	BTextView::FrameResized(width, height);
69 
70 	AlignTextRect();
71 }
72 
73 
74 void
75 _BTextInput_::KeyDown(const char* bytes, int32 numBytes)
76 {
77 	switch (*bytes) {
78 		case B_ENTER:
79 		{
80 			if (!TextControl()->IsEnabled())
81 				break;
82 
83 			if (fPreviousText == NULL || strcmp(Text(), fPreviousText) != 0) {
84 				TextControl()->Invoke();
85 				free(fPreviousText);
86 				fPreviousText = strdup(Text());
87 			}
88 
89 			SelectAll();
90 			break;
91 		}
92 
93 		case B_TAB:
94 			BView::KeyDown(bytes, numBytes);
95 			break;
96 
97 		default:
98 			BTextView::KeyDown(bytes, numBytes);
99 			break;
100 	}
101 }
102 
103 
104 void
105 _BTextInput_::MakeFocus(bool state)
106 {
107 	if (state == IsFocus())
108 		return;
109 
110 	BTextView::MakeFocus(state);
111 
112 	if (state) {
113 		SetInitialText();
114 
115 		fBool = true;
116 
117 		if (Window()) {
118 			BMessage *message = Window()->CurrentMessage();
119 
120 			if (message && message->what == B_KEY_DOWN)
121 				SelectAll();
122 		}
123 	} else {
124 		if (strcmp(Text(), fPreviousText) != 0)
125 			TextControl()->Invoke();
126 
127 		free(fPreviousText);
128 		fPreviousText = NULL;
129 		fBool = false;
130 
131 		if (Window()) {
132 			BMessage *message = Window()->CurrentMessage();
133 
134 			if (message && message->what == B_MOUSE_DOWN)
135 				Select(0, 0);
136 		}
137 	}
138 
139 	if (Window()) {
140 // TODO: why do we have to invalidate here?
141 // I'm leaving this in, but it looks suspicious... :-)
142 		Invalidate(Bounds());
143 		if (BTextControl* parent = dynamic_cast<BTextControl*>(Parent())) {
144 			BRect frame = Frame();
145 			frame.InsetBy(-1.0, -1.0);
146 			parent->Invalidate(frame);
147 		}
148 	}
149 }
150 
151 
152 void
153 _BTextInput_::AlignTextRect()
154 {
155 	// TODO: just to get something working, it wouldn't be correct for
156 	// scrolled views
157 	BRect textRect(Bounds());
158 	SetTextRect(textRect);
159 }
160 
161 
162 void
163 _BTextInput_::SetInitialText()
164 {
165 	if (fPreviousText) {
166 		free(fPreviousText);
167 		fPreviousText = NULL;
168 	}
169 
170 	if (Text())
171 		fPreviousText = strdup(Text());
172 }
173 
174 
175 void
176 _BTextInput_::Paste(BClipboard *clipboard)
177 {
178 	BTextView::Paste(clipboard);
179 	Invalidate();
180 }
181 
182 
183 void
184 _BTextInput_::InsertText(const char *inText, int32 inLength,
185 	int32 inOffset, const text_run_array *inRuns)
186 {
187 	char *buffer = NULL;
188 
189 	if (strpbrk(inText, "\r\n") && inLength <= 1024) {
190 		buffer = (char *)malloc(inLength);
191 
192 		if (buffer) {
193 			strcpy(buffer, inText);
194 
195 			for (int32 i = 0; i < inLength; i++) {
196 				if (buffer[i] == '\r' || buffer[i] == '\n')
197 					buffer[i] = ' ';
198 			}
199 		}
200 	}
201 
202 	BTextView::InsertText(buffer ? buffer : inText, inLength, inOffset,
203 		inRuns);
204 
205 	TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
206 		B_CONTROL_MODIFIED);
207 
208 	free(buffer);
209 }
210 
211 
212 void
213 _BTextInput_::DeleteText(int32 fromOffset, int32 toOffset)
214 {
215 	BTextView::DeleteText(fromOffset, toOffset);
216 
217 	TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
218 		B_CONTROL_MODIFIED);
219 }
220 
221 
222 BTextControl *
223 _BTextInput_::TextControl()
224 {
225 	BTextControl *textControl = NULL;
226 
227 	if (Parent())
228 		textControl = dynamic_cast<BTextControl*>(Parent());
229 
230 	if (!textControl)
231 		debugger("_BTextInput_ should have a BTextControl as parent");
232 
233 	return textControl;
234 }
235