PageRenderTime 37ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llui/llfocusmgr.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 492 lines | 368 code | 71 blank | 53 comment | 76 complexity | 56948b365f5fc4d5b16a2ba34866197e MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llfocusmgr.cpp
  3. * @brief LLFocusMgr base class
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #include "llfocusmgr.h"
  28. #include "lluictrl.h"
  29. #include "v4color.h"
  30. const F32 FOCUS_FADE_TIME = 0.3f;
  31. LLFocusableElement::LLFocusableElement()
  32. : mFocusLostCallback(NULL),
  33. mFocusReceivedCallback(NULL),
  34. mFocusChangedCallback(NULL),
  35. mTopLostCallback(NULL)
  36. {
  37. }
  38. // virtual
  39. BOOL LLFocusableElement::handleKey(KEY key, MASK mask, BOOL called_from_parent)
  40. {
  41. return FALSE;
  42. }
  43. // virtual
  44. BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent)
  45. {
  46. return FALSE;
  47. }
  48. // virtual
  49. LLFocusableElement::~LLFocusableElement()
  50. {
  51. delete mFocusLostCallback;
  52. delete mFocusReceivedCallback;
  53. delete mFocusChangedCallback;
  54. delete mTopLostCallback;
  55. }
  56. void LLFocusableElement::onFocusReceived()
  57. {
  58. if (mFocusReceivedCallback) (*mFocusReceivedCallback)(this);
  59. if (mFocusChangedCallback) (*mFocusChangedCallback)(this);
  60. }
  61. void LLFocusableElement::onFocusLost()
  62. {
  63. if (mFocusLostCallback) (*mFocusLostCallback)(this);
  64. if (mFocusChangedCallback) (*mFocusChangedCallback)(this);
  65. }
  66. void LLFocusableElement::onTopLost()
  67. {
  68. if (mTopLostCallback) (*mTopLostCallback)(this);
  69. }
  70. BOOL LLFocusableElement::hasFocus() const
  71. {
  72. return gFocusMgr.getKeyboardFocus() == this;
  73. }
  74. void LLFocusableElement::setFocus(BOOL b)
  75. {
  76. }
  77. boost::signals2::connection LLFocusableElement::setFocusLostCallback( const focus_signal_t::slot_type& cb)
  78. {
  79. if (!mFocusLostCallback) mFocusLostCallback = new focus_signal_t();
  80. return mFocusLostCallback->connect(cb);
  81. }
  82. boost::signals2::connection LLFocusableElement::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
  83. {
  84. if (!mFocusReceivedCallback) mFocusReceivedCallback = new focus_signal_t();
  85. return mFocusReceivedCallback->connect(cb);
  86. }
  87. boost::signals2::connection LLFocusableElement::setFocusChangedCallback(const focus_signal_t::slot_type& cb)
  88. {
  89. if (!mFocusChangedCallback) mFocusChangedCallback = new focus_signal_t();
  90. return mFocusChangedCallback->connect(cb);
  91. }
  92. boost::signals2::connection LLFocusableElement::setTopLostCallback(const focus_signal_t::slot_type& cb)
  93. {
  94. if (!mTopLostCallback) mTopLostCallback = new focus_signal_t();
  95. return mTopLostCallback->connect(cb);
  96. }
  97. typedef std::list<LLHandle<LLView> > view_handle_list_t;
  98. typedef std::map<LLHandle<LLView>, LLHandle<LLView> > focus_history_map_t;
  99. struct LLFocusMgr::Impl
  100. {
  101. // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost
  102. view_handle_list_t mCachedKeyboardFocusList;
  103. focus_history_map_t mFocusHistory;
  104. };
  105. LLFocusMgr gFocusMgr;
  106. LLFocusMgr::LLFocusMgr()
  107. : mLockedView( NULL ),
  108. mMouseCaptor( NULL ),
  109. mKeyboardFocus( NULL ),
  110. mLastKeyboardFocus( NULL ),
  111. mDefaultKeyboardFocus( NULL ),
  112. mKeystrokesOnly(FALSE),
  113. mTopCtrl( NULL ),
  114. mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true
  115. mImpl(new LLFocusMgr::Impl)
  116. {
  117. }
  118. LLFocusMgr::~LLFocusMgr()
  119. {
  120. mImpl->mFocusHistory.clear();
  121. delete mImpl;
  122. mImpl = NULL;
  123. }
  124. void LLFocusMgr::releaseFocusIfNeeded( LLView* view )
  125. {
  126. if( childHasMouseCapture( view ) )
  127. {
  128. setMouseCapture( NULL );
  129. }
  130. if( childHasKeyboardFocus( view ))
  131. {
  132. if (view == mLockedView)
  133. {
  134. mLockedView = NULL;
  135. setKeyboardFocus( NULL );
  136. }
  137. else
  138. {
  139. setKeyboardFocus( mLockedView );
  140. }
  141. }
  142. LLUI::removePopup(view);
  143. }
  144. void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only)
  145. {
  146. // notes if keyboard focus is changed again (by onFocusLost/onFocusReceived)
  147. // making the rest of our processing unnecessary since it will already be
  148. // handled by the recursive call
  149. static bool focus_dirty;
  150. focus_dirty = false;
  151. if (mLockedView &&
  152. (new_focus == NULL ||
  153. (new_focus != mLockedView
  154. && dynamic_cast<LLView*>(new_focus)
  155. && !dynamic_cast<LLView*>(new_focus)->hasAncestor(mLockedView))))
  156. {
  157. // don't allow focus to go to anything that is not the locked focus
  158. // or one of its descendants
  159. return;
  160. }
  161. mKeystrokesOnly = keystrokes_only;
  162. if( new_focus != mKeyboardFocus )
  163. {
  164. mLastKeyboardFocus = mKeyboardFocus;
  165. mKeyboardFocus = new_focus;
  166. // list of the focus and it's ancestors
  167. view_handle_list_t old_focus_list = mImpl->mCachedKeyboardFocusList;
  168. view_handle_list_t new_focus_list;
  169. // walk up the tree to root and add all views to the new_focus_list
  170. for (LLView* ctrl = dynamic_cast<LLView*>(mKeyboardFocus); ctrl; ctrl = ctrl->getParent())
  171. {
  172. new_focus_list.push_back(ctrl->getHandle());
  173. }
  174. // remove all common ancestors since their focus is unchanged
  175. while (!new_focus_list.empty() &&
  176. !old_focus_list.empty() &&
  177. new_focus_list.back() == old_focus_list.back())
  178. {
  179. new_focus_list.pop_back();
  180. old_focus_list.pop_back();
  181. }
  182. // walk up the old focus branch calling onFocusLost
  183. // we bubble up the tree to release focus, and back down to add
  184. for (view_handle_list_t::iterator old_focus_iter = old_focus_list.begin();
  185. old_focus_iter != old_focus_list.end() && !focus_dirty;
  186. old_focus_iter++)
  187. {
  188. LLView* old_focus_view = old_focus_iter->get();
  189. if (old_focus_view)
  190. {
  191. mImpl->mCachedKeyboardFocusList.pop_front();
  192. old_focus_view->onFocusLost();
  193. }
  194. }
  195. // walk down the new focus branch calling onFocusReceived
  196. for (view_handle_list_t::reverse_iterator new_focus_riter = new_focus_list.rbegin();
  197. new_focus_riter != new_focus_list.rend() && !focus_dirty;
  198. new_focus_riter++)
  199. {
  200. LLView* new_focus_view = new_focus_riter->get();
  201. if (new_focus_view)
  202. {
  203. mImpl->mCachedKeyboardFocusList.push_front(new_focus_view->getHandle());
  204. new_focus_view->onFocusReceived();
  205. }
  206. }
  207. // if focus was changed as part of an onFocusLost or onFocusReceived call
  208. // stop iterating on current list since it is now invalid
  209. if (focus_dirty)
  210. {
  211. return;
  212. }
  213. // If we've got a default keyboard focus, and the caller is
  214. // releasing keyboard focus, move to the default.
  215. if (mDefaultKeyboardFocus != NULL && mKeyboardFocus == NULL)
  216. {
  217. mDefaultKeyboardFocus->setFocus(TRUE);
  218. }
  219. LLView* focus_subtree = dynamic_cast<LLView*>(mKeyboardFocus);
  220. LLView* viewp = dynamic_cast<LLView*>(mKeyboardFocus);
  221. // find root-most focus root
  222. while(viewp)
  223. {
  224. if (viewp->isFocusRoot())
  225. {
  226. focus_subtree = viewp;
  227. }
  228. viewp = viewp->getParent();
  229. }
  230. if (focus_subtree)
  231. {
  232. LLView* focused_view = dynamic_cast<LLView*>(mKeyboardFocus);
  233. mImpl->mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle<LLView>();
  234. }
  235. }
  236. if (lock)
  237. {
  238. lockFocus();
  239. }
  240. focus_dirty = true;
  241. }
  242. // Returns TRUE is parent or any descedent of parent has keyboard focus.
  243. BOOL LLFocusMgr::childHasKeyboardFocus(const LLView* parent ) const
  244. {
  245. LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus);
  246. while( focus_view )
  247. {
  248. if( focus_view == parent )
  249. {
  250. return TRUE;
  251. }
  252. focus_view = focus_view->getParent();
  253. }
  254. return FALSE;
  255. }
  256. // Returns TRUE is parent or any descedent of parent is the mouse captor.
  257. BOOL LLFocusMgr::childHasMouseCapture( const LLView* parent ) const
  258. {
  259. if( mMouseCaptor && dynamic_cast<LLView*>(mMouseCaptor) != NULL )
  260. {
  261. LLView* captor_view = (LLView*)mMouseCaptor;
  262. while( captor_view )
  263. {
  264. if( captor_view == parent )
  265. {
  266. return TRUE;
  267. }
  268. captor_view = captor_view->getParent();
  269. }
  270. }
  271. return FALSE;
  272. }
  273. void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus )
  274. {
  275. // should be ok to unlock here, as you have to know the locked view
  276. // in order to unlock it
  277. if (focus == mLockedView)
  278. {
  279. mLockedView = NULL;
  280. }
  281. if( mKeyboardFocus == focus )
  282. {
  283. mKeyboardFocus = NULL;
  284. }
  285. }
  286. bool LLFocusMgr::keyboardFocusHasAccelerators() const
  287. {
  288. LLView* focus_view = dynamic_cast<LLView*>(mKeyboardFocus);
  289. while( focus_view )
  290. {
  291. if(focus_view->hasAccelerators())
  292. {
  293. return true;
  294. }
  295. focus_view = focus_view->getParent();
  296. }
  297. return false;
  298. }
  299. void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor )
  300. {
  301. if( new_captor != mMouseCaptor )
  302. {
  303. LLMouseHandler* old_captor = mMouseCaptor;
  304. mMouseCaptor = new_captor;
  305. if (LLView::sDebugMouseHandling)
  306. {
  307. if (new_captor)
  308. {
  309. llinfos << "New mouse captor: " << new_captor->getName() << llendl;
  310. }
  311. else
  312. {
  313. llinfos << "New mouse captor: NULL" << llendl;
  314. }
  315. }
  316. if( old_captor )
  317. {
  318. old_captor->onMouseCaptureLost();
  319. }
  320. }
  321. }
  322. void LLFocusMgr::removeMouseCaptureWithoutCallback( const LLMouseHandler* captor )
  323. {
  324. if( mMouseCaptor == captor )
  325. {
  326. mMouseCaptor = NULL;
  327. }
  328. }
  329. BOOL LLFocusMgr::childIsTopCtrl( const LLView* parent ) const
  330. {
  331. LLView* top_view = (LLView*)mTopCtrl;
  332. while( top_view )
  333. {
  334. if( top_view == parent )
  335. {
  336. return TRUE;
  337. }
  338. top_view = top_view->getParent();
  339. }
  340. return FALSE;
  341. }
  342. // set new_top = NULL to release top_view.
  343. void LLFocusMgr::setTopCtrl( LLUICtrl* new_top )
  344. {
  345. LLUICtrl* old_top = mTopCtrl;
  346. if( new_top != old_top )
  347. {
  348. mTopCtrl = new_top;
  349. if (old_top)
  350. {
  351. old_top->onTopLost();
  352. }
  353. }
  354. }
  355. void LLFocusMgr::removeTopCtrlWithoutCallback( const LLUICtrl* top_view )
  356. {
  357. if( mTopCtrl == top_view )
  358. {
  359. mTopCtrl = NULL;
  360. }
  361. }
  362. void LLFocusMgr::lockFocus()
  363. {
  364. mLockedView = dynamic_cast<LLUICtrl*>(mKeyboardFocus);
  365. }
  366. void LLFocusMgr::unlockFocus()
  367. {
  368. mLockedView = NULL;
  369. }
  370. F32 LLFocusMgr::getFocusFlashAmt() const
  371. {
  372. return clamp_rescale(mFocusFlashTimer.getElapsedTimeF32(), 0.f, FOCUS_FADE_TIME, 1.f, 0.f);
  373. }
  374. LLColor4 LLFocusMgr::getFocusColor() const
  375. {
  376. static LLUIColor focus_color_cached = LLUIColorTable::instance().getColor("FocusColor");
  377. LLColor4 focus_color = lerp(focus_color_cached, LLColor4::white, getFocusFlashAmt());
  378. // de-emphasize keyboard focus when app has lost focus (to avoid typing into wrong window problem)
  379. if (!mAppHasFocus)
  380. {
  381. focus_color.mV[VALPHA] *= 0.4f;
  382. }
  383. return focus_color;
  384. }
  385. void LLFocusMgr::triggerFocusFlash()
  386. {
  387. mFocusFlashTimer.reset();
  388. }
  389. void LLFocusMgr::setAppHasFocus(BOOL focus)
  390. {
  391. if (!mAppHasFocus && focus)
  392. {
  393. triggerFocusFlash();
  394. }
  395. // release focus from "top ctrl"s, which generally hides them
  396. if (!focus)
  397. {
  398. LLUI::clearPopups();
  399. }
  400. mAppHasFocus = focus;
  401. }
  402. LLUICtrl* LLFocusMgr::getLastFocusForGroup(LLView* subtree_root) const
  403. {
  404. if (subtree_root)
  405. {
  406. focus_history_map_t::const_iterator found_it = mImpl->mFocusHistory.find(subtree_root->getHandle());
  407. if (found_it != mImpl->mFocusHistory.end())
  408. {
  409. // found last focus for this subtree
  410. return static_cast<LLUICtrl*>(found_it->second.get());
  411. }
  412. }
  413. return NULL;
  414. }
  415. void LLFocusMgr::clearLastFocusForGroup(LLView* subtree_root)
  416. {
  417. if (subtree_root)
  418. {
  419. mImpl->mFocusHistory.erase(subtree_root->getHandle());
  420. }
  421. }