1 /* 2 * Copyright 2001-2020 Haiku Inc. All rights reserved. 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 * John Scipione (jscipione@gmail.com) 9 */ 10 11 12 #include "TextInput.h" 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 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> 25 26 27 namespace BPrivate { 28 29 30 _BTextInput_::_BTextInput_(BRect frame, BRect textRect, uint32 resizeMask, 31 uint32 flags) 32 : 33 BTextView(frame, "_input_", textRect, resizeMask, flags), 34 fPreviousText(NULL), 35 fInMouseDown(false) 36 { 37 MakeResizable(true); 38 } 39 40 41 _BTextInput_::_BTextInput_(BMessage* archive) 42 : 43 BTextView(archive), 44 fPreviousText(NULL), 45 fInMouseDown(false) 46 { 47 MakeResizable(true); 48 } 49 50 51 _BTextInput_::~_BTextInput_() 52 { 53 free(fPreviousText); 54 } 55 56 57 BArchivable* 58 _BTextInput_::Instantiate(BMessage* archive) 59 { 60 if (validate_instantiation(archive, "_BTextInput_")) 61 return new _BTextInput_(archive); 62 63 return NULL; 64 } 65 66 67 status_t 68 _BTextInput_::Archive(BMessage* data, bool deep) const 69 { 70 return BTextView::Archive(data, true); 71 } 72 73 74 void 75 _BTextInput_::MouseDown(BPoint where) 76 { 77 fInMouseDown = true; 78 BTextView::MouseDown(where); 79 fInMouseDown = false; 80 } 81 82 83 void 84 _BTextInput_::FrameResized(float width, float height) 85 { 86 BTextView::FrameResized(width, height); 87 } 88 89 90 void 91 _BTextInput_::KeyDown(const char* bytes, int32 numBytes) 92 { 93 switch (*bytes) { 94 case B_ENTER: 95 { 96 if (!TextControl()->IsEnabled()) 97 break; 98 99 if (fPreviousText == NULL || strcmp(Text(), fPreviousText) != 0) { 100 TextControl()->Invoke(); 101 free(fPreviousText); 102 fPreviousText = strdup(Text()); 103 } 104 105 SelectAll(); 106 break; 107 } 108 109 case B_TAB: 110 BView::KeyDown(bytes, numBytes); 111 break; 112 113 default: 114 BTextView::KeyDown(bytes, numBytes); 115 break; 116 } 117 } 118 119 120 void 121 _BTextInput_::MakeFocus(bool state) 122 { 123 if (state == IsFocus()) 124 return; 125 126 BTextView::MakeFocus(state); 127 128 if (state) { 129 SetInitialText(); 130 if (!fInMouseDown) 131 SelectAll(); 132 } else { 133 if (strcmp(Text(), fPreviousText) != 0) 134 TextControl()->Invoke(); 135 136 free(fPreviousText); 137 fPreviousText = NULL; 138 } 139 140 if (Window() != NULL) { 141 // Invalidate parent to draw or remove the focus mark 142 if (BTextControl* parent = dynamic_cast<BTextControl*>(Parent())) { 143 BRect frame = Frame(); 144 frame.InsetBy(-1.0, -1.0); 145 parent->Invalidate(frame); 146 } 147 } 148 } 149 150 151 BSize 152 _BTextInput_::MinSize() 153 { 154 BSize min; 155 min.height = ceilf(LineHeight(0) + 2.0); 156 // we always add at least one pixel vertical inset top/bottom for 157 // the text rect. 158 min.width = min.height * 3; 159 return BLayoutUtils::ComposeSize(ExplicitMinSize(), min); 160 } 161 162 163 void 164 _BTextInput_::SetInitialText() 165 { 166 free(fPreviousText); 167 fPreviousText = NULL; 168 169 if (Text() != NULL) 170 fPreviousText = strdup(Text()); 171 } 172 173 174 void 175 _BTextInput_::Paste(BClipboard* clipboard) 176 { 177 BTextView::Paste(clipboard); 178 Invalidate(); 179 } 180 181 182 void 183 _BTextInput_::InsertText(const char* inText, int32 inLength, 184 int32 inOffset, const text_run_array* inRuns) 185 { 186 // Filter all line breaks, note that inText is not terminated. 187 if (inLength == 1) { 188 if (*inText == '\n' || *inText == '\r') 189 BTextView::InsertText(" ", 1, inOffset, inRuns); 190 else 191 BTextView::InsertText(inText, 1, inOffset, inRuns); 192 } else { 193 BString filteredText(inText, inLength); 194 filteredText.ReplaceAll('\n', ' '); 195 filteredText.ReplaceAll('\r', ' '); 196 BTextView::InsertText(filteredText.String(), inLength, inOffset, 197 inRuns); 198 } 199 200 TextControl()->InvokeNotify(TextControl()->ModificationMessage(), 201 B_CONTROL_MODIFIED); 202 } 203 204 205 void 206 _BTextInput_::DeleteText(int32 fromOffset, int32 toOffset) 207 { 208 BTextView::DeleteText(fromOffset, toOffset); 209 210 TextControl()->InvokeNotify(TextControl()->ModificationMessage(), 211 B_CONTROL_MODIFIED); 212 } 213 214 215 BTextControl* 216 _BTextInput_::TextControl() 217 { 218 BTextControl* textControl = NULL; 219 if (Parent() != NULL) 220 textControl = dynamic_cast<BTextControl*>(Parent()); 221 222 if (textControl == NULL) 223 debugger("_BTextInput_ should have a BTextControl as parent"); 224 225 return textControl; 226 } 227 228 229 } // namespace BPrivate 230 231