1 /* 2 * Copyright 2001-2007, Haiku Inc. 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 */ 9 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <InterfaceDefs.h> 15 #include <Message.h> 16 #include <TextControl.h> 17 #include <TextView.h> 18 #include <Window.h> 19 20 #include "TextInput.h" 21 22 23 _BTextInput_::_BTextInput_(BRect frame, BRect textRect, uint32 resizeMask, 24 uint32 flags) 25 : BTextView(frame, "_input_", textRect, resizeMask, flags), 26 fPreviousText(NULL), 27 fBool(false) 28 { 29 MakeResizable(true); 30 } 31 32 33 _BTextInput_::_BTextInput_(BMessage *archive) 34 : BTextView(archive), 35 fPreviousText(NULL), 36 fBool(false) 37 { 38 MakeResizable(true); 39 } 40 41 42 _BTextInput_::~_BTextInput_() 43 { 44 free(fPreviousText); 45 } 46 47 48 BArchivable * 49 _BTextInput_::Instantiate(BMessage *archive) 50 { 51 if (validate_instantiation(archive, "_BTextInput_")) 52 return new _BTextInput_(archive); 53 54 return NULL; 55 } 56 57 58 status_t 59 _BTextInput_::Archive(BMessage *data, bool deep) const 60 { 61 return BTextView::Archive(data, true); 62 } 63 64 65 void 66 _BTextInput_::FrameResized(float width, float height) 67 { 68 BTextView::FrameResized(width, height); 69 70 AlignTextRect(); 71 } 72 73 74 void 75 _BTextInput_::KeyDown(const char* bytes, int32 numBytes) 76 { 77 switch (*bytes) { 78 case B_ENTER: 79 { 80 if (!TextControl()->IsEnabled()) 81 break; 82 83 if (fPreviousText == NULL || strcmp(Text(), fPreviousText) != 0) { 84 TextControl()->Invoke(); 85 free(fPreviousText); 86 fPreviousText = strdup(Text()); 87 } 88 89 SelectAll(); 90 break; 91 } 92 93 case B_TAB: 94 BView::KeyDown(bytes, numBytes); 95 break; 96 97 default: 98 BTextView::KeyDown(bytes, numBytes); 99 break; 100 } 101 } 102 103 104 void 105 _BTextInput_::MakeFocus(bool state) 106 { 107 if (state == IsFocus()) 108 return; 109 110 BTextView::MakeFocus(state); 111 112 if (state) { 113 SetInitialText(); 114 115 fBool = true; 116 117 if (Window()) { 118 BMessage *message = Window()->CurrentMessage(); 119 120 if (message && message->what == B_KEY_DOWN) 121 SelectAll(); 122 } 123 } else { 124 if (strcmp(Text(), fPreviousText) != 0) 125 TextControl()->Invoke(); 126 127 free(fPreviousText); 128 fPreviousText = NULL; 129 fBool = false; 130 131 if (Window()) { 132 BMessage *message = Window()->CurrentMessage(); 133 134 if (message && message->what == B_MOUSE_DOWN) 135 Select(0, 0); 136 } 137 } 138 139 if (Window()) { 140 // TODO: why do we have to invalidate here? 141 // I'm leaving this in, but it looks suspicious... :-) 142 Invalidate(Bounds()); 143 if (BTextControl* parent = dynamic_cast<BTextControl*>(Parent())) { 144 BRect frame = Frame(); 145 frame.InsetBy(-1.0, -1.0); 146 parent->Invalidate(frame); 147 } 148 } 149 } 150 151 152 void 153 _BTextInput_::AlignTextRect() 154 { 155 // TODO: just to get something working, it wouldn't be correct for 156 // scrolled views 157 BRect textRect(Bounds()); 158 SetTextRect(textRect); 159 } 160 161 162 void 163 _BTextInput_::SetInitialText() 164 { 165 if (fPreviousText) { 166 free(fPreviousText); 167 fPreviousText = NULL; 168 } 169 170 if (Text()) 171 fPreviousText = strdup(Text()); 172 } 173 174 175 void 176 _BTextInput_::Paste(BClipboard *clipboard) 177 { 178 BTextView::Paste(clipboard); 179 Invalidate(); 180 } 181 182 183 void 184 _BTextInput_::InsertText(const char *inText, int32 inLength, 185 int32 inOffset, const text_run_array *inRuns) 186 { 187 char *buffer = NULL; 188 189 if (strpbrk(inText, "\r\n") && inLength <= 1024) { 190 buffer = (char *)malloc(inLength); 191 192 if (buffer) { 193 strcpy(buffer, inText); 194 195 for (int32 i = 0; i < inLength; i++) { 196 if (buffer[i] == '\r' || buffer[i] == '\n') 197 buffer[i] = ' '; 198 } 199 } 200 } 201 202 BTextView::InsertText(buffer ? buffer : inText, inLength, inOffset, 203 inRuns); 204 205 TextControl()->InvokeNotify(TextControl()->ModificationMessage(), 206 B_CONTROL_MODIFIED); 207 208 free(buffer); 209 } 210 211 212 void 213 _BTextInput_::DeleteText(int32 fromOffset, int32 toOffset) 214 { 215 BTextView::DeleteText(fromOffset, toOffset); 216 217 TextControl()->InvokeNotify(TextControl()->ModificationMessage(), 218 B_CONTROL_MODIFIED); 219 } 220 221 222 BTextControl * 223 _BTextInput_::TextControl() 224 { 225 BTextControl *textControl = NULL; 226 227 if (Parent()) 228 textControl = dynamic_cast<BTextControl*>(Parent()); 229 230 if (!textControl) 231 debugger("_BTextInput_ should have a BTextControl as parent"); 232 233 return textControl; 234 } 235