vfs: check userland buffers before reading them.
[haiku.git] / src / kits / interface / TextInput.cpp
blobd744595815d8cf15fb489757c29127fca153d76f
1 /*
2 * Copyright 2001-2015, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Frans van Nispen (xlr8@tref.nl)
7 * Marc Flerackers (mflerackers@androme.be)
8 */
11 #include "TextInput.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
17 #include <ControlLook.h>
18 #include <InterfaceDefs.h>
19 #include <LayoutUtils.h>
20 #include <Message.h>
21 #include <String.h>
22 #include <TextControl.h>
23 #include <TextView.h>
24 #include <Window.h>
27 namespace BPrivate {
30 _BTextInput_::_BTextInput_(BRect frame, BRect textRect, uint32 resizeMask,
31 uint32 flags)
33 BTextView(frame, "_input_", textRect, resizeMask, flags),
34 fPreviousText(NULL)
36 MakeResizable(true);
40 _BTextInput_::_BTextInput_(BMessage* archive)
42 BTextView(archive),
43 fPreviousText(NULL)
45 MakeResizable(true);
49 _BTextInput_::~_BTextInput_()
51 free(fPreviousText);
55 BArchivable*
56 _BTextInput_::Instantiate(BMessage* archive)
58 if (validate_instantiation(archive, "_BTextInput_"))
59 return new _BTextInput_(archive);
61 return NULL;
65 status_t
66 _BTextInput_::Archive(BMessage* data, bool deep) const
68 return BTextView::Archive(data, true);
72 void
73 _BTextInput_::MouseDown(BPoint where)
75 if (!IsFocus()) {
76 MakeFocus(true);
77 return;
80 // only pass through to base class if we already have focus
81 BTextView::MouseDown(where);
85 void
86 _BTextInput_::FrameResized(float width, float height)
88 BTextView::FrameResized(width, height);
90 AlignTextRect();
94 void
95 _BTextInput_::KeyDown(const char* bytes, int32 numBytes)
97 switch (*bytes) {
98 case B_ENTER:
100 if (!TextControl()->IsEnabled())
101 break;
103 if (fPreviousText == NULL || strcmp(Text(), fPreviousText) != 0) {
104 TextControl()->Invoke();
105 free(fPreviousText);
106 fPreviousText = strdup(Text());
109 SelectAll();
110 break;
113 case B_TAB:
114 BView::KeyDown(bytes, numBytes);
115 break;
117 default:
118 BTextView::KeyDown(bytes, numBytes);
119 AlignTextRect();
120 break;
125 void
126 _BTextInput_::MakeFocus(bool state)
128 if (state == IsFocus())
129 return;
131 BTextView::MakeFocus(state);
133 if (state) {
134 SetInitialText();
135 SelectAll();
136 } else {
137 if (strcmp(Text(), fPreviousText) != 0)
138 TextControl()->Invoke();
140 free(fPreviousText);
141 fPreviousText = NULL;
144 if (Window() != NULL) {
145 // Invalidate parent to draw or remove the focus mark
146 if (BTextControl* parent = dynamic_cast<BTextControl*>(Parent())) {
147 BRect frame = Frame();
148 frame.InsetBy(-1.0, -1.0);
149 parent->Invalidate(frame);
155 BSize
156 _BTextInput_::MinSize()
158 BSize min;
159 min.height = ceilf(LineHeight(0) + 2.0);
160 // we always add at least one pixel vertical inset top/bottom for
161 // the text rect.
162 min.width = min.height * 3;
163 return BLayoutUtils::ComposeSize(ExplicitMinSize(), min);
167 void
168 _BTextInput_::AlignTextRect()
170 // the label font could require the control to be higher than
171 // necessary for the text view, we compensate this by layouting
172 // the text rect to be in the middle, normally this means there
173 // is one pixel spacing on each side
174 BRect textRect(Bounds());
175 float vInset = max_c(1,
176 floorf((textRect.Height() - LineHeight(0)) / 2.0));
177 float hInset = 2;
178 float textFontWidth = TextRect().Width();
180 switch (Alignment()) {
181 case B_ALIGN_LEFT:
182 hInset = be_control_look->DefaultLabelSpacing();
183 break;
185 case B_ALIGN_RIGHT:
186 hInset = textRect.Width() - textFontWidth;
187 hInset -= be_control_look->DefaultLabelSpacing();
188 break;
190 case B_ALIGN_CENTER:
191 hInset = (textRect.Width() - textFontWidth) / 2.0;
192 break;
194 default:
195 break;
198 textRect.InsetBy(hInset, vInset);
199 SetTextRect(textRect);
203 void
204 _BTextInput_::SetInitialText()
206 free(fPreviousText);
207 fPreviousText = NULL;
209 if (Text() != NULL)
210 fPreviousText = strdup(Text());
214 void
215 _BTextInput_::Paste(BClipboard* clipboard)
217 BTextView::Paste(clipboard);
218 Invalidate();
222 void
223 _BTextInput_::InsertText(const char* inText, int32 inLength,
224 int32 inOffset, const text_run_array* inRuns)
226 // Filter all line breaks, note that inText is not terminated.
227 if (inLength == 1) {
228 if (*inText == '\n' || *inText == '\r')
229 BTextView::InsertText(" ", 1, inOffset, inRuns);
230 else
231 BTextView::InsertText(inText, 1, inOffset, inRuns);
232 } else {
233 BString filteredText(inText, inLength);
234 filteredText.ReplaceAll('\n', ' ');
235 filteredText.ReplaceAll('\r', ' ');
236 BTextView::InsertText(filteredText.String(), inLength, inOffset,
237 inRuns);
240 TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
241 B_CONTROL_MODIFIED);
245 void
246 _BTextInput_::DeleteText(int32 fromOffset, int32 toOffset)
248 BTextView::DeleteText(fromOffset, toOffset);
250 TextControl()->InvokeNotify(TextControl()->ModificationMessage(),
251 B_CONTROL_MODIFIED);
255 BTextControl*
256 _BTextInput_::TextControl()
258 BTextControl* textControl = NULL;
259 if (Parent() != NULL)
260 textControl = dynamic_cast<BTextControl*>(Parent());
262 if (textControl == NULL)
263 debugger("_BTextInput_ should have a BTextControl as parent");
265 return textControl;
269 } // namespace BPrivate