xref: /haiku/src/kits/interface/TextInput.cpp (revision ffcd67bc8277349aebf089d7357716698aafd55b)
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 = parent->Bounds();
145 			frame.left = parent->Divider();
146 			frame.InsetBy(-1.0, -1.0);
147 			parent->Invalidate(frame);
148 		}
149 	}
150 }
151 
152 
153 void
154 _BTextInput_::AlignTextRect()
155 {
156 	// TODO: just to get something working, it wouldn't be correct for
157 	// scrolled views
158 	BRect textRect(Bounds());
159 	SetTextRect(textRect);
160 }
161 
162 
163 void
164 _BTextInput_::SetInitialText()
165 {
166 	if (fPreviousText) {
167 		free(fPreviousText);
168 		fPreviousText = NULL;
169 	}
170 
171 	if (Text())
172 		fPreviousText = strdup(Text());
173 }
174 
175 
176 void
177 _BTextInput_::Paste(BClipboard *clipboard)
178 {
179 	BTextView::Paste(clipboard);
180 	Invalidate();
181 }
182 
183 
184 void
185 _BTextInput_::InsertText(const char *inText, int32 inLength,
186 	int32 inOffset, const text_run_array *inRuns)
187 {
188 	char *buffer = NULL;
189 
190 	if (strpbrk(inText, "\r\n") && inLength <= 1024) {
191 		buffer = (char *)malloc(inLength);
192 
193 		if (buffer) {
194 			strcpy(buffer, inText);
195 
196 			for (int32 i = 0; i < inLength; i++) {
197 				if (buffer[i] == '\r' || buffer[i] == '\n')
198 					buffer[i] = ' ';
199 			}
200 		}
201 	}
202 
203 	BTextView::InsertText(buffer ? buffer : inText, inLength, inOffset,
204 		inRuns);
205 
206 	TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
207 		B_CONTROL_MODIFIED);
208 
209 	free(buffer);
210 }
211 
212 
213 void
214 _BTextInput_::DeleteText(int32 fromOffset, int32 toOffset)
215 {
216 	BTextView::DeleteText(fromOffset, toOffset);
217 
218 	TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
219 		B_CONTROL_MODIFIED);
220 }
221 
222 
223 BTextControl *
224 _BTextInput_::TextControl()
225 {
226 	BTextControl *textControl = NULL;
227 
228 	if (Parent())
229 		textControl = dynamic_cast<BTextControl*>(Parent());
230 
231 	if (!textControl)
232 		debugger("_BTextInput_ should have a BTextControl as parent");
233 
234 	return textControl;
235 }
236