1 /* _______ __ __ __ ______ __ __ _______ __ __ 2 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ 3 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / 4 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / 5 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / 6 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / 7 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ 8 * 9 * Copyright (c) 2004 - 2008 Olof Naess�n and Per Larsson 10 * 11 * 12 * Per Larsson a.k.a finalman 13 * Olof Naess�n a.k.a jansem/yakslem 14 * 15 * Visit: http://guichan.sourceforge.net 16 * 17 * License: (BSD) 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in 25 * the documentation and/or other materials provided with the 26 * distribution. 27 * 3. Neither the name of Guichan nor the names of its contributors may 28 * be used to endorse or promote products derived from this software 29 * without specific prior written permission. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 37 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 38 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 /* 45 * For comments regarding functions please see the header file. 46 */ 47 48 #include "guichan/widgets/textfield.hpp" 49 50 #include "guichan/font.hpp" 51 #include "guichan/graphics.hpp" 52 #include "guichan/key.hpp" 53 #include "guichan/mouseinput.hpp" 54 55 namespace gcn 56 { TextField()57 TextField::TextField() 58 { 59 mCaretPosition = 0; 60 mXScroll = 0; 61 62 setFocusable(true); 63 64 addMouseListener(this); 65 addKeyListener(this); 66 } 67 TextField(const std::string & text)68 TextField::TextField(const std::string& text) 69 { 70 mCaretPosition = 0; 71 mXScroll = 0; 72 73 mText = text; 74 adjustSize(); 75 76 setFocusable(true); 77 78 addMouseListener(this); 79 addKeyListener(this); 80 } 81 setText(const std::string & text)82 void TextField::setText(const std::string& text) 83 { 84 if(text.size() < mCaretPosition ) 85 { 86 mCaretPosition = text.size(); 87 } 88 89 mText = text; 90 } 91 draw(Graphics * graphics)92 void TextField::draw(Graphics* graphics) 93 { 94 Color faceColor = getBaseColor(); 95 Color highlightColor, shadowColor; 96 int alpha = getBaseColor().a; 97 highlightColor = faceColor + 0x303030; 98 highlightColor.a = alpha; 99 shadowColor = faceColor - 0x303030; 100 shadowColor.a = alpha; 101 102 // Draw a border. 103 graphics->setColor(shadowColor); 104 graphics->drawLine(0, 0, getWidth() - 1, 0); 105 graphics->drawLine(0, 1, 0, getHeight() - 2); 106 graphics->setColor(highlightColor); 107 graphics->drawLine(getWidth() - 1, 1, getWidth() - 1, getHeight() - 1); 108 graphics->drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1); 109 110 // Push a clip area so the other drawings don't need to worry 111 // about the border. 112 graphics->pushClipArea(Rectangle(1, 1, getWidth() - 2, getHeight() - 2)); 113 114 graphics->setColor(getBackgroundColor()); 115 graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight())); 116 117 if (isFocused()) 118 { 119 graphics->setColor(getSelectionColor()); 120 graphics->drawRectangle(Rectangle(0, 0, getWidth() - 2, getHeight() - 2)); 121 graphics->drawRectangle(Rectangle(1, 1, getWidth() - 4, getHeight() - 4)); 122 } 123 124 if (isFocused()) 125 { 126 drawCaret(graphics, getFont()->getWidth(mText.substr(0, mCaretPosition)) - mXScroll); 127 } 128 129 graphics->setColor(getForegroundColor()); 130 graphics->setFont(getFont()); 131 graphics->drawText(mText, 3 - mXScroll, 1); 132 133 graphics->popClipArea(); 134 } 135 drawCaret(Graphics * graphics,int x)136 void TextField::drawCaret(Graphics* graphics, int x) 137 { 138 // Check the current clip area as a clip area with a different 139 // size than the widget might have been pushed (which is the 140 // case in the draw method when we push a clip area after we have 141 // drawn a border). 142 const Rectangle clipArea = graphics->getCurrentClipArea(); 143 144 graphics->setColor(getForegroundColor()); 145 graphics->drawLine(x, clipArea.height - 2, x, 1); 146 } 147 mousePressed(MouseEvent & mouseEvent)148 void TextField::mousePressed(MouseEvent& mouseEvent) 149 { 150 if (mouseEvent.getButton() == MouseEvent::LEFT) 151 { 152 mCaretPosition = getFont()->getStringIndexAt(mText, mouseEvent.getX() + mXScroll); 153 fixScroll(); 154 } 155 } 156 mouseDragged(MouseEvent & mouseEvent)157 void TextField::mouseDragged(MouseEvent& mouseEvent) 158 { 159 mouseEvent.consume(); 160 } 161 keyPressed(KeyEvent & keyEvent)162 void TextField::keyPressed(KeyEvent& keyEvent) 163 { 164 Key key = keyEvent.getKey(); 165 166 if (key.getValue() == Key::LEFT && mCaretPosition > 0) 167 { 168 --mCaretPosition; 169 } 170 171 else if (key.getValue() == Key::RIGHT && mCaretPosition < mText.size()) 172 { 173 ++mCaretPosition; 174 } 175 176 else if (key.getValue() == Key::DELETE && mCaretPosition < mText.size()) 177 { 178 mText.erase(mCaretPosition, 1); 179 } 180 181 else if (key.getValue() == Key::BACKSPACE && mCaretPosition > 0) 182 { 183 mText.erase(mCaretPosition - 1, 1); 184 --mCaretPosition; 185 } 186 187 else if (key.getValue() == Key::ENTER) 188 { 189 distributeActionEvent(); 190 } 191 192 else if (key.getValue() == Key::HOME) 193 { 194 mCaretPosition = 0; 195 } 196 197 else if (key.getValue() == Key::END) 198 { 199 mCaretPosition = mText.size(); 200 } 201 202 else if (key.isCharacter() 203 && key.getValue() != Key::TAB) 204 { 205 mText.insert(mCaretPosition, std::string(1,(char)key.getValue())); 206 ++mCaretPosition; 207 } 208 209 if (key.getValue() != Key::TAB) 210 { 211 keyEvent.consume(); 212 } 213 214 fixScroll(); 215 } 216 adjustSize()217 void TextField::adjustSize() 218 { 219 setWidth(getFont()->getWidth(mText) + 7); 220 adjustHeight(); 221 222 fixScroll(); 223 } 224 adjustHeight()225 void TextField::adjustHeight() 226 { 227 setHeight(getFont()->getHeight() + 4); 228 } 229 fixScroll()230 void TextField::fixScroll() 231 { 232 if (isFocused()) 233 { 234 int caretX = getFont()->getWidth(mText.substr(0, mCaretPosition)); 235 236 if (caretX - mXScroll >= getWidth() - 4) 237 { 238 mXScroll = caretX - getWidth() + 4; 239 } 240 else if (caretX - mXScroll <= 0) 241 { 242 mXScroll = caretX - getWidth() / 2; 243 244 if (mXScroll < 0) 245 { 246 mXScroll = 0; 247 } 248 } 249 } 250 } 251 setCaretPosition(unsigned int position)252 void TextField::setCaretPosition(unsigned int position) 253 { 254 if (position > mText.size()) 255 { 256 mCaretPosition = mText.size(); 257 } 258 else 259 { 260 mCaretPosition = position; 261 } 262 263 fixScroll(); 264 } 265 getCaretPosition() const266 unsigned int TextField::getCaretPosition() const 267 { 268 return mCaretPosition; 269 } 270 getText() const271 const std::string& TextField::getText() const 272 { 273 return mText; 274 } 275 fontChanged()276 void TextField::fontChanged() 277 { 278 fixScroll(); 279 } 280 } 281