xref: /haiku/src/kits/interface/TextInput.cpp (revision fef6144999c2fa611f59ee6ffe6dd7999501385c)
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 	else
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 	AlignTextRect();
88 // TODO: just to get something working, it wouldn't be correct for
89 // scrolled views
90 BRect textRect(Bounds());
91 textRect.InsetBy(2.0, 2.0);
92 SetTextRect(textRect);
93 }
94 
95 
96 void
97 _BTextInput_::KeyDown(const char* bytes, int32 numBytes)
98 {
99 	switch (*bytes) {
100 		case B_ENTER:
101 		{
102 			if (!TextControl()->IsEnabled())
103 				break;
104 
105 			if(strcmp(Text(), fPreviousText) != 0) {
106 				TextControl()->Invoke();
107 				free(fPreviousText);
108 				fPreviousText = strdup(Text());
109 			}
110 
111 			SelectAll();
112 			break;
113 		}
114 
115 		case B_TAB:
116 			BView::KeyDown(bytes, numBytes);
117 			break;
118 
119 		default:
120 			BTextView::KeyDown(bytes, numBytes);
121 			break;
122 	}
123 }
124 
125 
126 void
127 _BTextInput_::MakeFocus(bool state)
128 {
129 	if (state == IsFocus())
130 		return;
131 
132 	BTextView::MakeFocus(state);
133 
134 	if (state) {
135 		SetInitialText();
136 
137 		fBool = true;
138 
139 		if (Window()) {
140 			BMessage *message = Window()->CurrentMessage();
141 
142 			if (message && message->what == B_KEY_DOWN)
143 				SelectAll();
144 		}
145 	} else {
146 		if (strcmp(Text(), fPreviousText) != 0)
147 			TextControl()->Invoke();
148 
149 		free(fPreviousText);
150 		fPreviousText = NULL;
151 		fBool = false;
152 
153 		if (Window()) {
154 			BMessage *message = Window()->CurrentMessage();
155 
156 			if (message && message->what == B_MOUSE_DOWN)
157 				Select(0, 0);
158 		}
159 	}
160 
161 	if (Window()) {
162 // TODO: why do we have to invalidate here?
163 // I'm leaving this in, but it looks suspicious... :-)
164 		Invalidate(Bounds());
165 		if (BView* parent = Parent()) {
166 			BRect frame = Frame();
167 			frame.InsetBy(-1.0, -1.0);
168 			parent->Invalidate(frame);
169 		}
170 	}
171 }
172 
173 
174 void
175 _BTextInput_::AlignTextRect()
176 {
177 
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 	BTextView::InsertText(buffer ? buffer : inText, inLength, inOffset,
221 		inRuns);
222 
223 	TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
224 		B_CONTROL_MODIFIED);
225 
226 	free(buffer);
227 }
228 
229 
230 void
231 _BTextInput_::DeleteText(int32 fromOffset, int32 toOffset)
232 {
233 	BTextView::DeleteText(fromOffset, toOffset);
234 
235 	TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
236 		B_CONTROL_MODIFIED);
237 }
238 
239 
240 BTextControl *
241 _BTextInput_::TextControl()
242 {
243 	BTextControl *textControl = NULL;
244 
245 	if (Parent())
246 		textControl = dynamic_cast<BTextControl*>(Parent());
247 
248 	if (!textControl)
249 		debugger("_BTextInput_ should have a BTextControl as parent");
250 
251 	return textControl;
252 }
253