xref: /haiku/src/kits/interface/TextInput.cpp (revision a4f6a81235ca2522c01f532de13cad9b729d4029)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2004, Haiku, Inc.
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		TextInput.cpp
23 //	Authors:		Frans van Nispen (xlr8@tref.nl)
24 //					Marc Flerackers (mflerackers@androme.be)
25 //	Description:	The BTextView derivative owned by an instance of
26 //					BTextControl.
27 //------------------------------------------------------------------------------
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #include <InterfaceDefs.h>
33 #include <Message.h>
34 #include <TextControl.h>
35 #include <TextView.h>
36 #include <Window.h>
37 
38 #include "TextInput.h"
39 
40 
41 _BTextInput_::_BTextInput_(BRect frame, BRect textRect, uint32 resizeMask,
42 						   uint32 flags)
43 	:	BTextView(frame, "_input_", textRect, resizeMask, flags),
44 		fPreviousText(NULL),
45 		fBool(false)
46 {
47 	MakeResizable(true);
48 }
49 
50 
51 _BTextInput_::_BTextInput_(BMessage *archive)
52 	:	BTextView(archive),
53 		fPreviousText(NULL),
54 		fBool(false)
55 {
56 	MakeResizable(true);
57 }
58 
59 
60 _BTextInput_::~_BTextInput_()
61 {
62 	free(fPreviousText);
63 }
64 
65 
66 BArchivable *
67 _BTextInput_::Instantiate(BMessage *archive)
68 {
69 	if (validate_instantiation(archive, "_BTextInput_"))
70 		return new _BTextInput_(archive);
71 
72 	return NULL;
73 }
74 
75 
76 status_t
77 _BTextInput_::Archive(BMessage *data, bool deep) const
78 {
79 	return BTextView::Archive(data, true);
80 }
81 
82 
83 void
84 _BTextInput_::FrameResized(float width, float height)
85 {
86 	BTextView::FrameResized(width, height);
87 
88 	AlignTextRect();
89 }
90 
91 
92 void
93 _BTextInput_::KeyDown(const char* bytes, int32 numBytes)
94 {
95 	switch (*bytes) {
96 		case B_ENTER:
97 		{
98 			if (!TextControl()->IsEnabled())
99 				break;
100 
101 			if (fPreviousText == NULL || strcmp(Text(), fPreviousText) != 0) {
102 				TextControl()->Invoke();
103 				free(fPreviousText);
104 				fPreviousText = strdup(Text());
105 			}
106 
107 			SelectAll();
108 			break;
109 		}
110 
111 		case B_TAB:
112 			BView::KeyDown(bytes, numBytes);
113 			break;
114 
115 		default:
116 			BTextView::KeyDown(bytes, numBytes);
117 			break;
118 	}
119 }
120 
121 
122 void
123 _BTextInput_::MakeFocus(bool state)
124 {
125 	if (state == IsFocus())
126 		return;
127 
128 	BTextView::MakeFocus(state);
129 
130 	if (state) {
131 		SetInitialText();
132 
133 		fBool = true;
134 
135 		if (Window()) {
136 			BMessage *message = Window()->CurrentMessage();
137 
138 			if (message && message->what == B_KEY_DOWN)
139 				SelectAll();
140 		}
141 	} else {
142 		if (strcmp(Text(), fPreviousText) != 0)
143 			TextControl()->Invoke();
144 
145 		free(fPreviousText);
146 		fPreviousText = NULL;
147 		fBool = false;
148 
149 		if (Window()) {
150 			BMessage *message = Window()->CurrentMessage();
151 
152 			if (message && message->what == B_MOUSE_DOWN)
153 				Select(0, 0);
154 		}
155 	}
156 
157 	if (Window()) {
158 // TODO: why do we have to invalidate here?
159 // I'm leaving this in, but it looks suspicious... :-)
160 		Invalidate(Bounds());
161 		if (BTextControl* parent = dynamic_cast<BTextControl*>(Parent())) {
162 			BRect frame = parent->Bounds();
163 			frame.left = parent->Divider();
164 			frame.InsetBy(-1.0, -1.0);
165 			parent->Invalidate(frame);
166 		}
167 	}
168 }
169 
170 
171 void
172 _BTextInput_::AlignTextRect()
173 {
174 	// TODO: just to get something working, it wouldn't be correct for
175 	// scrolled views
176 	BRect textRect(Bounds());
177 	SetTextRect(textRect);
178 }
179 
180 
181 void
182 _BTextInput_::SetInitialText()
183 {
184 	if (fPreviousText) {
185 		free(fPreviousText);
186 		fPreviousText = NULL;
187 	}
188 
189 	if (Text())
190 		fPreviousText = strdup(Text());
191 }
192 
193 
194 void
195 _BTextInput_::Paste(BClipboard *clipboard)
196 {
197 	BTextView::Paste(clipboard);
198 	Invalidate();
199 }
200 
201 
202 void
203 _BTextInput_::InsertText(const char *inText, int32 inLength,
204 	int32 inOffset, const text_run_array *inRuns)
205 {
206 	char *buffer = NULL;
207 
208 	if (strpbrk(inText, "\r\n") && inLength <= 1024) {
209 		buffer = (char *)malloc(inLength);
210 
211 		if (buffer) {
212 			strcpy(buffer, inText);
213 
214 			for (int32 i = 0; i < inLength; i++) {
215 				if (buffer[i] == '\r' || buffer[i] == '\n')
216 					buffer[i] = ' ';
217 			}
218 		}
219 	}
220 
221 	BTextView::InsertText(buffer ? buffer : inText, inLength, inOffset,
222 		inRuns);
223 
224 	TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
225 		B_CONTROL_MODIFIED);
226 
227 	free(buffer);
228 }
229 
230 
231 void
232 _BTextInput_::DeleteText(int32 fromOffset, int32 toOffset)
233 {
234 	BTextView::DeleteText(fromOffset, toOffset);
235 
236 	TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
237 		B_CONTROL_MODIFIED);
238 }
239 
240 
241 BTextControl *
242 _BTextInput_::TextControl()
243 {
244 	BTextControl *textControl = NULL;
245 
246 	if (Parent())
247 		textControl = dynamic_cast<BTextControl*>(Parent());
248 
249 	if (!textControl)
250 		debugger("_BTextInput_ should have a BTextControl as parent");
251 
252 	return textControl;
253 }
254