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 = parent->Bounds(); 145 frame.left = parent->Divider(); 146 frame.InsetBy(-1.0, -1.0); 147 parent->Invalidate(frame); 148 } 149 } 150 } 151 152 153 void 154 _BTextInput_::AlignTextRect() 155 { 156 // TODO: just to get something working, it wouldn't be correct for 157 // scrolled views 158 BRect textRect(Bounds()); 159 SetTextRect(textRect); 160 } 161 162 163 void 164 _BTextInput_::SetInitialText() 165 { 166 if (fPreviousText) { 167 free(fPreviousText); 168 fPreviousText = NULL; 169 } 170 171 if (Text()) 172 fPreviousText = strdup(Text()); 173 } 174 175 176 void 177 _BTextInput_::Paste(BClipboard *clipboard) 178 { 179 BTextView::Paste(clipboard); 180 Invalidate(); 181 } 182 183 184 void 185 _BTextInput_::InsertText(const char *inText, int32 inLength, 186 int32 inOffset, const text_run_array *inRuns) 187 { 188 char *buffer = NULL; 189 190 if (strpbrk(inText, "\r\n") && inLength <= 1024) { 191 buffer = (char *)malloc(inLength); 192 193 if (buffer) { 194 strcpy(buffer, inText); 195 196 for (int32 i = 0; i < inLength; i++) { 197 if (buffer[i] == '\r' || buffer[i] == '\n') 198 buffer[i] = ' '; 199 } 200 } 201 } 202 203 BTextView::InsertText(buffer ? buffer : inText, inLength, inOffset, 204 inRuns); 205 206 TextControl()->InvokeNotify(TextControl()->ModificationMessage(), 207 B_CONTROL_MODIFIED); 208 209 free(buffer); 210 } 211 212 213 void 214 _BTextInput_::DeleteText(int32 fromOffset, int32 toOffset) 215 { 216 BTextView::DeleteText(fromOffset, toOffset); 217 218 TextControl()->InvokeNotify(TextControl()->ModificationMessage(), 219 B_CONTROL_MODIFIED); 220 } 221 222 223 BTextControl * 224 _BTextInput_::TextControl() 225 { 226 BTextControl *textControl = NULL; 227 228 if (Parent()) 229 textControl = dynamic_cast<BTextControl*>(Parent()); 230 231 if (!textControl) 232 debugger("_BTextInput_ should have a BTextControl as parent"); 233 234 return textControl; 235 } 236