1 /* _______ __ __ __ ______ __ __ _______ __ __ 2 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ 3 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / 4 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / 5 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / 6 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / 7 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ 8 * 9 * Copyright (c) 2004, 2005 darkbits Js_./ 10 * Per Larsson a.k.a finalman _RqZ{a<^_aa 11 * Olof Naess�n a.k.a jansem/yakslem _asww7!uY`> )\a// 12 * _Qhm`] _f "'c 1!5m 13 * Visit: http://guichan.darkbits.org )Qk<P ` _: :+' .' "{[ 14 * .)j(] .d_/ '-( P . S 15 * License: (BSD) <Td/Z <fP"5(\"??"\a. .L 16 * Redistribution and use in source and _dV>ws?a-?' ._/L #' 17 * binary forms, with or without )4d[#7r, . ' )d`)[ 18 * modification, are permitted provided _Q-5'5W..j/?' -?!\)cam' 19 * that the following conditions are met: j<<WP+k/);. _W=j f 20 * 1. Redistributions of source code must .$%w\/]Q . ."' . mj$ 21 * retain the above copyright notice, ]E.pYY(Q]>. a J@\ 22 * this list of conditions and the j(]1u<sE"L,. . ./^ ]{a 23 * following disclaimer. 4'_uomm\. )L);-4 (3= 24 * 2. Redistributions in binary form must )_]X{Z('a_"a7'<a"a, ]"[ 25 * reproduce the above copyright notice, #}<]m7`Za??4,P-"'7. ).m 26 * this list of conditions and the ]d2e)Q(<Q( ?94 b- LQ/ 27 * following disclaimer in the <B!</]C)d_, '(<' .f. =C+m 28 * documentation and/or other materials .Z!=J ]e []('-4f _ ) -.)m]' 29 * provided with the distribution. .w[5]' _[ /.)_-"+? _/ <W" 30 * 3. Neither the name of Guichan nor the :$we` _! + _/ . j? 31 * names of its contributors may be used =3)= _f (_yQmWW$#( " 32 * to endorse or promote products derived - W, sQQQQmZQ#Wwa].. 33 * from this software without specific (js, \[QQW$QWW#?!V"". 34 * prior written permission. ]y:.<\.. . 35 * -]n w/ ' [. 36 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT )/ )/ ! 37 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY < (; sac , ' 38 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ]^ .- % 39 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF c < r 40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR aga< <La 41 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 5% )P'-3L 42 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR _bQf` y`..)a 43 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ,J?4P'.P"_(\?d'., 44 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES _Pa,)!f/<[]/ ?" 45 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT _2-..:. .r+_,.. . 46 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ?a.<%"' " -'.a_ _, 47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ^ 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 49 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 50 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 51 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 52 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55 /* 56 * For comments regarding functions please see the header file. 57 */ 58 59 #include <ctype.h> // for isascii 60 #include <assert.h> 61 #include "guichan/focushandler.h" 62 #include "guichan/exception.h" 63 64 namespace gcn 65 { FocusHandler()66 FocusHandler::FocusHandler() 67 { 68 mFocusedWidget = NULL; 69 mDraggedWidget = NULL; 70 mToBeFocused = NULL; 71 mToBeDragged = NULL; 72 mModalFocusedWidget = NULL; 73 } 74 requestFocus(Widget * widget)75 void FocusHandler::requestFocus(Widget* widget) 76 { 77 mToBeFocused = widget; 78 } 79 setFocus(Widget * widget)80 void FocusHandler::setFocus(Widget* widget) 81 { 82 mFocusedWidget = widget; 83 } 84 requestDrag(Widget * widget)85 void FocusHandler::requestDrag(Widget* widget) 86 { 87 mToBeDragged = widget; 88 } 89 requestModalFocus(Widget * widget)90 void FocusHandler::requestModalFocus(Widget* widget) 91 { 92 if (mModalFocusedWidget != NULL && mModalFocusedWidget != widget) 93 { 94 assert(!"Another widget allready has modal focus."); 95 //throw GCN_EXCEPTION("Another widget allready has modal focus."); 96 } 97 98 mModalFocusedWidget = widget; 99 100 if (mFocusedWidget != NULL && !mFocusedWidget->hasModalFocus()) 101 { 102 focusNone(); 103 } 104 105 if (mDraggedWidget != NULL && !mDraggedWidget->hasModalFocus()) 106 { 107 dragNone(); 108 } 109 } 110 releaseModalFocus(Widget * widget)111 void FocusHandler::releaseModalFocus(Widget* widget) 112 { 113 if (mModalFocusedWidget == widget) 114 { 115 mModalFocusedWidget = NULL; 116 } 117 } 118 getFocused() const119 Widget* FocusHandler::getFocused() const 120 { 121 return mFocusedWidget; 122 } 123 getDragged() const124 Widget* FocusHandler::getDragged() const 125 { 126 return mDraggedWidget; 127 } 128 getModalFocused() const129 Widget* FocusHandler::getModalFocused() const 130 { 131 return mModalFocusedWidget; 132 } 133 focusNext()134 void FocusHandler::focusNext() 135 { 136 int i; 137 int focusedWidget = -1; 138 for (i = 0; i < (int)mWidgets.size(); ++i) 139 { 140 if (mWidgets[i] == mFocusedWidget) 141 { 142 focusedWidget = i; 143 } 144 } 145 int focused = focusedWidget; 146 147 // i is a counter that ensures that the following loop 148 // won't get stuck in an infinite loop 149 i = (int)mWidgets.size(); 150 do 151 { 152 ++focusedWidget; 153 154 if (i==0) 155 { 156 focusedWidget = -1; 157 break; 158 } 159 160 --i; 161 162 if (focusedWidget >= (int)mWidgets.size()) 163 { 164 focusedWidget = 0; 165 } 166 167 if (focusedWidget == focused) 168 { 169 return; 170 } 171 } 172 while (!mWidgets.at(focusedWidget)->isFocusable()); 173 174 if (focusedWidget >= 0) 175 { 176 mFocusedWidget = mWidgets.at(focusedWidget); 177 mWidgets.at(focusedWidget)->gotFocus(); 178 } 179 180 if (focused >= 0) 181 { 182 mWidgets.at(focused)->lostFocus(); 183 } 184 } 185 focusPrevious()186 void FocusHandler::focusPrevious() 187 { 188 if (mWidgets.size() == 0) 189 { 190 mFocusedWidget = NULL; 191 return; 192 } 193 194 int i; 195 int focusedWidget = -1; 196 for (i = 0; i < (int)mWidgets.size(); ++i) 197 { 198 if (mWidgets[i] == mFocusedWidget) 199 { 200 focusedWidget = i; 201 } 202 } 203 int focused = focusedWidget; 204 205 // i is a counter that ensures that the following loop 206 // won't get stuck in an infinite loop 207 i = (int)mWidgets.size(); 208 do 209 { 210 --focusedWidget; 211 212 if (i==0) 213 { 214 focusedWidget = -1; 215 break; 216 } 217 218 --i; 219 220 if (focusedWidget <= 0) 221 { 222 focusedWidget = mWidgets.size() - 1; 223 } 224 225 if (focusedWidget == focused) 226 { 227 return; 228 } 229 } 230 while (!mWidgets.at(focusedWidget)->isFocusable()); 231 232 if (focusedWidget >= 0) 233 { 234 mFocusedWidget = mWidgets.at(focusedWidget); 235 mWidgets.at(focusedWidget)->gotFocus(); 236 } 237 238 if (focused >= 0) 239 { 240 mWidgets.at(focused)->lostFocus(); 241 } 242 } 243 hasFocus(const Widget * widget) const244 bool FocusHandler::hasFocus(const Widget* widget) const 245 { 246 return mFocusedWidget == widget; 247 } 248 isDragged(const Widget * widget) const249 bool FocusHandler::isDragged(const Widget* widget) const 250 { 251 return mDraggedWidget == widget; 252 } 253 add(Widget * widget)254 void FocusHandler::add(Widget* widget) 255 { 256 mWidgets.push_back(widget); 257 } 258 remove(Widget * widget)259 void FocusHandler::remove(Widget* widget) 260 { 261 if (widget == mFocusedWidget) 262 { 263 mFocusedWidget = NULL; 264 } 265 if (widget == mDraggedWidget) 266 { 267 mDraggedWidget = NULL; 268 } 269 if (widget == mToBeFocused) 270 { 271 mToBeFocused = NULL; 272 } 273 if (widget == mToBeDragged) 274 { 275 mToBeDragged = NULL; 276 } 277 278 if (hasFocus(widget)) 279 { 280 mFocusedWidget = NULL; 281 mToBeFocused = NULL; 282 } 283 284 int i = 0; 285 WidgetIterator iter; 286 287 for (iter = mWidgets.begin(); iter != mWidgets.end(); ++iter) 288 { 289 ++i; 290 291 if ((*iter) == widget) 292 { 293 mWidgets.erase(iter); 294 return; 295 } 296 } 297 } 298 focusNone()299 void FocusHandler::focusNone() 300 { 301 302 if (mFocusedWidget != NULL) 303 { 304 Widget* focused = mFocusedWidget; 305 mFocusedWidget = NULL; 306 focused->lostFocus(); 307 } 308 309 mToBeFocused = NULL; 310 } 311 dragNone()312 void FocusHandler::dragNone() 313 { 314 mDraggedWidget = NULL; 315 } 316 checkHotKey(const KeyInput & keyInput)317 void FocusHandler::checkHotKey(const KeyInput &keyInput) 318 { 319 int keyin = keyInput.getKey().getValue(); 320 321 for (int i = 0; i < (int)mWidgets.size(); ++i) 322 { 323 int hotKey = mWidgets[i]->getHotKey(); 324 325 if (hotKey == 0) 326 { 327 continue; 328 } 329 330 if ((isascii(keyin) && tolower(keyin) == hotKey) || keyin == hotKey) 331 { 332 if (keyInput.getType() == KeyInput::PRESS) 333 { 334 mWidgets[i]->hotKeyPress(); 335 if (mWidgets[i]->isFocusable()) 336 { 337 this->requestFocus(mWidgets[i]); 338 } 339 } 340 else 341 { 342 mWidgets[i]->hotKeyRelease(); 343 } 344 break; 345 } 346 } 347 } 348 tabNext()349 void FocusHandler::tabNext() 350 { 351 if (mFocusedWidget != NULL) 352 { 353 if (!mFocusedWidget->isTabOutEnabled()) 354 { 355 return; 356 } 357 } 358 359 if (mWidgets.size() == 0) 360 { 361 mFocusedWidget = NULL; 362 return; 363 } 364 365 int i; 366 int focusedWidget = -1; 367 for (i = 0; i < (int)mWidgets.size(); ++i) 368 { 369 if (mWidgets[i] == mFocusedWidget) 370 { 371 focusedWidget = i; 372 } 373 } 374 int focused = focusedWidget; 375 bool done = false; 376 377 // i is a counter that ensures that the following loop 378 // won't get stuck in an infinite loop 379 i = (int)mWidgets.size(); 380 do 381 { 382 ++focusedWidget; 383 384 if (i==0) 385 { 386 focusedWidget = -1; 387 break; 388 } 389 390 --i; 391 392 if (focusedWidget >= (int)mWidgets.size()) 393 { 394 focusedWidget = 0; 395 } 396 397 if (focusedWidget == focused) 398 { 399 return; 400 } 401 402 if (mWidgets.at(focusedWidget)->isFocusable() && 403 mWidgets.at(focusedWidget)->isTabInEnabled() && 404 (mModalFocusedWidget == NULL || 405 mWidgets.at(focusedWidget)->hasModalFocus())) 406 { 407 done = true; 408 } 409 } 410 while (!done); 411 412 if (focusedWidget >= 0) 413 { 414 mFocusedWidget = mWidgets.at(focusedWidget); 415 mWidgets.at(focusedWidget)->gotFocus(); 416 } 417 418 if (focused >= 0) 419 { 420 mWidgets.at(focused)->lostFocus(); 421 } 422 } 423 tabPrevious()424 void FocusHandler::tabPrevious() 425 { 426 if (mFocusedWidget != NULL) 427 { 428 if (!mFocusedWidget->isTabOutEnabled()) 429 { 430 return; 431 } 432 } 433 434 if (mWidgets.size() == 0) 435 { 436 mFocusedWidget = NULL; 437 return; 438 } 439 440 int i; 441 int focusedWidget = -1; 442 for (i = 0; i < (int)mWidgets.size(); ++i) 443 { 444 if (mWidgets[i] == mFocusedWidget) 445 { 446 focusedWidget = i; 447 } 448 } 449 int focused = focusedWidget; 450 bool done = false; 451 452 // i is a counter that ensures that the following loop 453 // won't get stuck in an infinite loop 454 i = (int)mWidgets.size(); 455 do 456 { 457 --focusedWidget; 458 459 if (i==0) 460 { 461 focusedWidget = -1; 462 break; 463 } 464 465 --i; 466 467 if (focusedWidget <= 0) 468 { 469 focusedWidget = mWidgets.size() - 1; 470 } 471 472 if (focusedWidget == focused) 473 { 474 return; 475 } 476 477 if (mWidgets.at(focusedWidget)->isFocusable() && 478 mWidgets.at(focusedWidget)->isTabInEnabled() && 479 (mModalFocusedWidget == NULL || 480 mWidgets.at(focusedWidget)->hasModalFocus())) 481 { 482 done = true; 483 } 484 } 485 while (!done); 486 487 if (focusedWidget >= 0) 488 { 489 mFocusedWidget = mWidgets.at(focusedWidget); 490 mWidgets.at(focusedWidget)->gotFocus(); 491 } 492 493 if (focused >= 0) 494 { 495 mWidgets.at(focused)->lostFocus(); 496 } 497 } 498 applyChanges()499 void FocusHandler::applyChanges() 500 { 501 if (mToBeFocused != NULL) 502 { 503 unsigned int i = 0; 504 int toBeFocusedIndex = -1; 505 for (i = 0; i < mWidgets.size(); ++i) 506 { 507 if (mWidgets[i] == mToBeFocused) 508 { 509 toBeFocusedIndex = i; 510 break; 511 } 512 } 513 514 if (toBeFocusedIndex < 0) 515 { 516 assert(!"Trying to focus a none existing widget."); 517 //throw GCN_EXCEPTION("Trying to focus a none existing widget."); 518 } 519 520 Widget *oldFocused = mFocusedWidget; 521 522 if (oldFocused != mToBeFocused) 523 { 524 mFocusedWidget = mWidgets.at(toBeFocusedIndex); 525 526 if (oldFocused != NULL) 527 { 528 oldFocused->lostFocus(); 529 } 530 531 mWidgets.at(toBeFocusedIndex)->gotFocus(); 532 } 533 mToBeFocused = NULL; 534 } 535 536 if (mToBeDragged != NULL) 537 { 538 unsigned int i = 0; 539 int toBeDraggedIndex = -1; 540 for (i = 0; i < mWidgets.size(); ++i) 541 { 542 if (mWidgets[i] == mToBeDragged) 543 { 544 toBeDraggedIndex = i; 545 break; 546 } 547 } 548 549 if (toBeDraggedIndex < 0) 550 { 551 assert(!"Trying to give drag to a none existing widget."); 552 //throw GCN_EXCEPTION("Trying to give drag to a none existing widget"); 553 } 554 555 mDraggedWidget = mWidgets.at(toBeDraggedIndex); 556 mToBeDragged = NULL; 557 } 558 } 559 } 560