1 /* 2 * Copyright 2001-2008, 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 */ 9 10 11 #include "TextInput.h" 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 17 #include <InterfaceDefs.h> 18 #include <Message.h> 19 #include <TextControl.h> 20 #include <TextView.h> 21 #include <Window.h> 22 23 24 namespace BPrivate { 25 26 27 _BTextInput_::_BTextInput_(BRect frame, BRect textRect, uint32 resizeMask, 28 uint32 flags) 29 : BTextView(frame, "_input_", textRect, resizeMask, flags), 30 fPreviousText(NULL) 31 { 32 MakeResizable(true); 33 } 34 35 36 _BTextInput_::_BTextInput_(BMessage* archive) 37 : BTextView(archive), 38 fPreviousText(NULL) 39 { 40 MakeResizable(true); 41 } 42 43 44 _BTextInput_::~_BTextInput_() 45 { 46 free(fPreviousText); 47 } 48 49 50 BArchivable* 51 _BTextInput_::Instantiate(BMessage* archive) 52 { 53 if (validate_instantiation(archive, "_BTextInput_")) 54 return new _BTextInput_(archive); 55 56 return NULL; 57 } 58 59 60 status_t 61 _BTextInput_::Archive(BMessage* data, bool deep) const 62 { 63 return BTextView::Archive(data, true); 64 } 65 66 67 void 68 _BTextInput_::MouseDown(BPoint where) 69 { 70 if (!IsFocus()) { 71 MakeFocus(true); 72 return; 73 } 74 75 // only pass through to base class if we already have focus 76 BTextView::MouseDown(where); 77 } 78 79 80 void 81 _BTextInput_::FrameResized(float width, float height) 82 { 83 BTextView::FrameResized(width, height); 84 85 AlignTextRect(); 86 } 87 88 89 void 90 _BTextInput_::KeyDown(const char* bytes, int32 numBytes) 91 { 92 switch (*bytes) { 93 case B_ENTER: 94 { 95 if (!TextControl()->IsEnabled()) 96 break; 97 98 if (fPreviousText == NULL || strcmp(Text(), fPreviousText) != 0) { 99 TextControl()->Invoke(); 100 free(fPreviousText); 101 fPreviousText = strdup(Text()); 102 } 103 104 SelectAll(); 105 break; 106 } 107 108 case B_TAB: 109 BView::KeyDown(bytes, numBytes); 110 break; 111 112 default: 113 BTextView::KeyDown(bytes, numBytes); 114 break; 115 } 116 } 117 118 void 119 _BTextInput_::MakeFocus(bool state) 120 { 121 if (state == IsFocus()) 122 return; 123 124 BTextView::MakeFocus(state); 125 126 if (state) { 127 SetInitialText(); 128 SelectAll(); 129 } else { 130 if (strcmp(Text(), fPreviousText) != 0) 131 TextControl()->Invoke(); 132 133 free(fPreviousText); 134 fPreviousText = NULL; 135 } 136 137 // if (Window()) { 138 // TODO: why do we have to invalidate here? 139 // I'm leaving this in, but it looks suspicious... :-) 140 // Invalidate(Bounds()); 141 if (BTextControl* parent = dynamic_cast<BTextControl*>(Parent())) { 142 BRect frame = Frame(); 143 frame.InsetBy(-1.0, -1.0); 144 parent->Invalidate(frame); 145 } 146 // } 147 } 148 149 150 void 151 _BTextInput_::AlignTextRect() 152 { 153 // the label font could require the control to be higher than 154 // necessary for the text view, we compensate this by layouting 155 // the text rect to be in the middle, normally this means there 156 // is one pixel spacing on each side 157 BRect textRect(Bounds()); 158 textRect.left = 0.0; 159 float vInset = max_c(1, floorf((textRect.Height() - LineHeight(0)) / 2.0)); 160 textRect.InsetBy(2, vInset); 161 SetTextRect(textRect); 162 } 163 164 165 void 166 _BTextInput_::SetInitialText() 167 { 168 free(fPreviousText); 169 fPreviousText = NULL; 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 237 238 } // namespace BPrivate 239 240