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 drawCaret(graphics, getFont()->getWidth(mText.substr(0, mCaretPosition)) - mXScroll); 120 } 121 122 graphics->setColor(getForegroundColor()); 123 graphics->setFont(getFont()); 124 graphics->drawText(mText, 1 - mXScroll, 1); 125 126 graphics->popClipArea(); 127 } 128 drawCaret(Graphics * graphics,int x)129 void TextField::drawCaret(Graphics* graphics, int x) 130 { 131 // Check the current clip area as a clip area with a different 132 // size than the widget might have been pushed (which is the 133 // case in the draw method when we push a clip area after we have 134 // drawn a border). 135 const Rectangle clipArea = graphics->getCurrentClipArea(); 136 137 graphics->setColor(getForegroundColor()); 138 graphics->drawLine(x, clipArea.height - 2, x, 1); 139 } 140 mousePressed(MouseEvent & mouseEvent)141 void TextField::mousePressed(MouseEvent& mouseEvent) 142 { 143 if (mouseEvent.getButton() == MouseEvent::LEFT) 144 { 145 mCaretPosition = getFont()->getStringIndexAt(mText, mouseEvent.getX() + mXScroll); 146 fixScroll(); 147 } 148 } 149 mouseDragged(MouseEvent & mouseEvent)150 void TextField::mouseDragged(MouseEvent& mouseEvent) 151 { 152 mouseEvent.consume(); 153 } 154 keyPressed(KeyEvent & keyEvent)155 void TextField::keyPressed(KeyEvent& keyEvent) 156 { 157 Key key = keyEvent.getKey(); 158 159 if (key.getValue() == Key::LEFT && mCaretPosition > 0) 160 { 161 --mCaretPosition; 162 } 163 164 else if (key.getValue() == Key::RIGHT && mCaretPosition < mText.size()) 165 { 166 ++mCaretPosition; 167 } 168 169 else if (key.getValue() == Key::DELETE && mCaretPosition < mText.size()) 170 { 171 mText.erase(mCaretPosition, 1); 172 } 173 174 else if (key.getValue() == Key::BACKSPACE && mCaretPosition > 0) 175 { 176 mText.erase(mCaretPosition - 1, 1); 177 --mCaretPosition; 178 } 179 180 else if (key.getValue() == Key::ENTER) 181 { 182 distributeActionEvent(); 183 } 184 185 else if (key.getValue() == Key::HOME) 186 { 187 mCaretPosition = 0; 188 } 189 190 else if (key.getValue() == Key::END) 191 { 192 mCaretPosition = mText.size(); 193 } 194 195 else if (key.isCharacter() 196 && key.getValue() != Key::TAB) 197 { 198 mText.insert(mCaretPosition, std::string(1,(char)key.getValue())); 199 ++mCaretPosition; 200 } 201 202 if (key.getValue() != Key::TAB) 203 { 204 keyEvent.consume(); 205 } 206 207 fixScroll(); 208 } 209 adjustSize()210 void TextField::adjustSize() 211 { 212 setWidth(getFont()->getWidth(mText) + 6); 213 adjustHeight(); 214 215 fixScroll(); 216 } 217 adjustHeight()218 void TextField::adjustHeight() 219 { 220 setHeight(getFont()->getHeight() + 4); 221 } 222 fixScroll()223 void TextField::fixScroll() 224 { 225 if (isFocused()) 226 { 227 int caretX = getFont()->getWidth(mText.substr(0, mCaretPosition)); 228 229 if (caretX - mXScroll >= getWidth() - 4) 230 { 231 mXScroll = caretX - getWidth() + 4; 232 } 233 else if (caretX - mXScroll <= 0) 234 { 235 mXScroll = caretX - getWidth() / 2; 236 237 if (mXScroll < 0) 238 { 239 mXScroll = 0; 240 } 241 } 242 } 243 } 244 setCaretPosition(unsigned int position)245 void TextField::setCaretPosition(unsigned int position) 246 { 247 if (position > mText.size()) 248 { 249 mCaretPosition = mText.size(); 250 } 251 else 252 { 253 mCaretPosition = position; 254 } 255 256 fixScroll(); 257 } 258 getCaretPosition() const259 unsigned int TextField::getCaretPosition() const 260 { 261 return mCaretPosition; 262 } 263 getText() const264 const std::string& TextField::getText() const 265 { 266 return mText; 267 } 268 fontChanged()269 void TextField::fontChanged() 270 { 271 fixScroll(); 272 } 273 } 274