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 27namespace 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 57BArchivable* 58_BTextInput_::Instantiate(BMessage* archive) 59{ 60 if (validate_instantiation(archive, "_BTextInput_")) 61 return new _BTextInput_(archive); 62 63 return NULL; 64} 65 66 67status_t 68_BTextInput_::Archive(BMessage* data, bool deep) const 69{ 70 return BTextView::Archive(data, true); 71} 72 73 74void 75_BTextInput_::MouseDown(BPoint where) 76{ 77 fInMouseDown = true; 78 BTextView::MouseDown(where); 79 fInMouseDown = false; 80} 81 82 83void 84_BTextInput_::FrameResized(float width, float height) 85{ 86 BTextView::FrameResized(width, height); 87} 88 89 90void 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 120void 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 151BSize 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 163void 164_BTextInput_::SetInitialText() 165{ 166 free(fPreviousText); 167 fPreviousText = NULL; 168 169 if (Text() != NULL) 170 fPreviousText = strdup(Text()); 171} 172 173 174void 175_BTextInput_::Paste(BClipboard* clipboard) 176{ 177 BTextView::Paste(clipboard); 178 Invalidate(); 179} 180 181 182void 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 205void 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 215BTextControl* 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