UI.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "CheckBox.h"
  24. #include "Context.h"
  25. #include "CoreEvents.h"
  26. #include "Cursor.h"
  27. #include "DropDownList.h"
  28. #include "FileSelector.h"
  29. #include "Font.h"
  30. #include "Graphics.h"
  31. #include "GraphicsEvents.h"
  32. #include "Input.h"
  33. #include "InputEvents.h"
  34. #include "LineEdit.h"
  35. #include "ListView.h"
  36. #include "Log.h"
  37. #include "Matrix3x4.h"
  38. #include "Profiler.h"
  39. #include "Renderer.h"
  40. #include "ResourceCache.h"
  41. #include "ScrollBar.h"
  42. #include "Shader.h"
  43. #include "ShaderVariation.h"
  44. #include "Slider.h"
  45. #include "Sort.h"
  46. #include "Sprite.h"
  47. #include "Text.h"
  48. #include "Text3D.h"
  49. #include "Texture2D.h"
  50. #include "UI.h"
  51. #include "UIEvents.h"
  52. #include "VertexBuffer.h"
  53. #include "Window.h"
  54. #include "View3D.h"
  55. #include <SDL.h>
  56. #include "DebugNew.h"
  57. namespace Urho3D
  58. {
  59. ShortStringHash VAR_ORIGIN("Origin");
  60. const ShortStringHash VAR_ORIGINAL_PARENT("OriginalParent");
  61. const ShortStringHash VAR_ORIGINAL_CHILD_INDEX("OriginalChildIndex");
  62. const ShortStringHash VAR_PARENT_CHANGED("ParentChanged");
  63. const float DEFAULT_DOUBLECLICK_INTERVAL = 0.5f;
  64. const int DEFAULT_FONT_TEXTURE_MAX_SIZE = 2048;
  65. const char* UI_CATEGORY = "UI";
  66. UI::UI(Context* context) :
  67. Object(context),
  68. rootElement_(new UIElement(context)),
  69. rootModalElement_(new UIElement(context)),
  70. mouseButtons_(0),
  71. qualifiers_(0),
  72. maxFontTextureSize_(DEFAULT_FONT_TEXTURE_MAX_SIZE),
  73. doubleClickInterval_(DEFAULT_DOUBLECLICK_INTERVAL),
  74. initialized_(false),
  75. usingTouchInput_(false),
  76. #ifdef WIN32
  77. nonFocusedMouseWheel_(false), // Default MS Windows behaviour
  78. #else
  79. nonFocusedMouseWheel_(true), // Default Mac OS X and Linux behaviour
  80. #endif
  81. useSystemClipBoard_(false),
  82. useMutableGlyphs_(false),
  83. forceAutoHint_(false),
  84. nonModalBatchSize_(0)
  85. {
  86. rootElement_->SetTraversalMode(TM_DEPTH_FIRST);
  87. rootModalElement_->SetTraversalMode(TM_DEPTH_FIRST);
  88. clickTimer_ = new Timer();
  89. // Register UI library object factories
  90. RegisterUILibrary(context_);
  91. SubscribeToEvent(E_SCREENMODE, HANDLER(UI, HandleScreenMode));
  92. SubscribeToEvent(E_MOUSEBUTTONDOWN, HANDLER(UI, HandleMouseButtonDown));
  93. SubscribeToEvent(E_MOUSEBUTTONUP, HANDLER(UI, HandleMouseButtonUp));
  94. SubscribeToEvent(E_MOUSEMOVE, HANDLER(UI, HandleMouseMove));
  95. SubscribeToEvent(E_MOUSEWHEEL, HANDLER(UI, HandleMouseWheel));
  96. SubscribeToEvent(E_TOUCHBEGIN, HANDLER(UI, HandleTouchBegin));
  97. SubscribeToEvent(E_TOUCHEND, HANDLER(UI, HandleTouchEnd));
  98. SubscribeToEvent(E_TOUCHMOVE, HANDLER(UI, HandleTouchMove));
  99. SubscribeToEvent(E_KEYDOWN, HANDLER(UI, HandleKeyDown));
  100. SubscribeToEvent(E_CHAR, HANDLER(UI, HandleChar));
  101. SubscribeToEvent(E_DROPFILE, HANDLER(UI, HandleDropFile));
  102. // Try to initialize right now, but skip if screen mode is not yet set
  103. Initialize();
  104. }
  105. UI::~UI()
  106. {
  107. delete clickTimer_;
  108. }
  109. void UI::SetCursor(Cursor* cursor)
  110. {
  111. // Remove old cursor (if any) and set new
  112. if (cursor_)
  113. {
  114. rootElement_->RemoveChild(cursor_);
  115. cursor_.Reset();
  116. }
  117. if (cursor)
  118. {
  119. rootElement_->AddChild(cursor);
  120. cursor_ = cursor;
  121. IntVector2 pos = cursor_->GetPosition();
  122. const IntVector2& rootSize = rootElement_->GetSize();
  123. pos.x_ = Clamp(pos.x_, 0, rootSize.x_ - 1);
  124. pos.y_ = Clamp(pos.y_, 0, rootSize.y_ - 1);
  125. cursor_->SetPosition(pos);
  126. }
  127. }
  128. void UI::SetFocusElement(UIElement* element)
  129. {
  130. using namespace FocusChanged;
  131. VariantMap eventData;
  132. eventData[P_CLICKEDELEMENT] = (void*)element;
  133. if (element)
  134. {
  135. // Return if already has focus
  136. if (focusElement_ == element)
  137. return;
  138. // Only allow child elements of the modal element to receive focus
  139. if (HasModalElement())
  140. {
  141. UIElement* topLevel = element->GetParent();
  142. while (topLevel && topLevel->GetParent() != rootElement_)
  143. topLevel = topLevel->GetParent();
  144. if (topLevel) // If parented to non-modal root then ignore
  145. return;
  146. }
  147. // Search for an element in the hierarchy that can alter focus. If none found, exit
  148. element = GetFocusableElement(element);
  149. if (!element)
  150. return;
  151. }
  152. // Remove focus from the old element
  153. if (focusElement_)
  154. {
  155. UIElement* oldFocusElement = focusElement_;
  156. focusElement_.Reset();
  157. VariantMap focusEventData;
  158. focusEventData[Defocused::P_ELEMENT] = oldFocusElement;
  159. oldFocusElement->SendEvent(E_DEFOCUSED, focusEventData);
  160. }
  161. // Then set focus to the new
  162. if (element && element->GetFocusMode() >= FM_FOCUSABLE)
  163. {
  164. focusElement_ = element;
  165. VariantMap focusEventData;
  166. focusEventData[Focused::P_ELEMENT] = element;
  167. element->SendEvent(E_FOCUSED, focusEventData);
  168. }
  169. eventData[P_ELEMENT] = (void*)element;
  170. SendEvent(E_FOCUSCHANGED, eventData);
  171. }
  172. bool UI::SetModalElement(UIElement* modalElement, bool enable)
  173. {
  174. if (!modalElement)
  175. return false;
  176. // Currently only allow modal window
  177. if (modalElement->GetType() != Window::GetTypeStatic())
  178. return false;
  179. assert(rootModalElement_);
  180. UIElement* currParent = modalElement->GetParent();
  181. if (enable)
  182. {
  183. // Make sure it is not already the child of the root modal element
  184. if (currParent == rootModalElement_)
  185. return false;
  186. // Adopt modal root as parent
  187. modalElement->SetVar(VAR_ORIGINAL_PARENT, currParent);
  188. modalElement->SetVar(VAR_ORIGINAL_CHILD_INDEX, currParent ? currParent->FindChild(modalElement) : M_MAX_UNSIGNED);
  189. modalElement->SetParent(rootModalElement_);
  190. // If it is a popup element, bring along its top-level parent
  191. UIElement* originElement = static_cast<UIElement*>(modalElement->GetVar(VAR_ORIGIN).GetPtr());
  192. if (originElement)
  193. {
  194. UIElement* element = originElement;
  195. while (element && element->GetParent() != rootElement_)
  196. element = element->GetParent();
  197. if (element)
  198. {
  199. originElement->SetVar(VAR_PARENT_CHANGED, element);
  200. UIElement* oriParent = element->GetParent();
  201. element->SetVar(VAR_ORIGINAL_PARENT, oriParent);
  202. element->SetVar(VAR_ORIGINAL_CHILD_INDEX, oriParent ? oriParent->FindChild(element) : M_MAX_UNSIGNED);
  203. element->SetParent(rootModalElement_);
  204. }
  205. }
  206. return true;
  207. }
  208. else
  209. {
  210. // Only the modal element can disable itself
  211. if (currParent != rootModalElement_)
  212. return false;
  213. // Revert back to original parent
  214. modalElement->SetParent(static_cast<UIElement*>(modalElement->GetVar(VAR_ORIGINAL_PARENT).GetPtr()), modalElement->GetVar(VAR_ORIGINAL_CHILD_INDEX).GetUInt());
  215. VariantMap& vars = const_cast<VariantMap&>(modalElement->GetVars());
  216. vars.Erase(VAR_ORIGINAL_PARENT);
  217. vars.Erase(VAR_ORIGINAL_CHILD_INDEX);
  218. // If it is a popup element, revert back its top-level parent
  219. UIElement* originElement = static_cast<UIElement*>(modalElement->GetVar(VAR_ORIGIN).GetPtr());
  220. if (originElement)
  221. {
  222. UIElement* element = static_cast<UIElement*>(originElement->GetVar(VAR_PARENT_CHANGED).GetPtr());
  223. if (element)
  224. {
  225. const_cast<VariantMap&>(originElement->GetVars()).Erase(VAR_PARENT_CHANGED);
  226. element->SetParent(static_cast<UIElement*>(element->GetVar(VAR_ORIGINAL_PARENT).GetPtr()), element->GetVar(VAR_ORIGINAL_CHILD_INDEX).GetUInt());
  227. vars = const_cast<VariantMap&>(element->GetVars());
  228. vars.Erase(VAR_ORIGINAL_PARENT);
  229. vars.Erase(VAR_ORIGINAL_CHILD_INDEX);
  230. }
  231. }
  232. return true;
  233. }
  234. }
  235. void UI::Clear()
  236. {
  237. rootElement_->RemoveAllChildren();
  238. rootModalElement_->RemoveAllChildren();
  239. if (cursor_)
  240. rootElement_->AddChild(cursor_);
  241. }
  242. void UI::Update(float timeStep)
  243. {
  244. assert(rootElement_ && rootModalElement_);
  245. PROFILE(UpdateUI);
  246. IntVector2 cursorPos;
  247. bool cursorVisible;
  248. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  249. // Mouse hover
  250. if (!usingTouchInput_ && cursorVisible)
  251. {
  252. WeakPtr<UIElement> element(GetElementAt(cursorPos));
  253. bool dragSource = dragElement_ && (dragElement_->GetDragDropMode() & DD_SOURCE) != 0;
  254. bool dragTarget = element && (element->GetDragDropMode() & DD_TARGET) != 0;
  255. bool dragDropTest = dragSource && dragTarget && element != dragElement_;
  256. // Hover effect
  257. // If a drag is going on, transmit hover only to the element being dragged, unless it's a drop target
  258. if (element && element->IsEnabled())
  259. {
  260. if (!dragElement_ || dragElement_ == element || dragDropTest)
  261. element->OnHover(element->ScreenToElement(cursorPos), cursorPos, mouseButtons_, qualifiers_, cursor_);
  262. }
  263. else
  264. SetCursorShape(CS_NORMAL);
  265. // Drag and drop test
  266. if (dragDropTest)
  267. {
  268. bool accept = element->OnDragDropTest(dragElement_);
  269. if (accept)
  270. {
  271. using namespace DragDropTest;
  272. VariantMap eventData;
  273. eventData[P_SOURCE] = (void*)dragElement_.Get();
  274. eventData[P_TARGET] = (void*)element.Get();
  275. eventData[P_ACCEPT] = accept;
  276. SendEvent(E_DRAGDROPTEST, eventData);
  277. accept = eventData[P_ACCEPT].GetBool();
  278. }
  279. SetCursorShape(accept ? CS_ACCEPTDROP : CS_REJECTDROP);
  280. }
  281. else if (dragSource)
  282. SetCursorShape(dragElement_ == element ? CS_ACCEPTDROP : CS_REJECTDROP);
  283. }
  284. // Touch hover
  285. Input* input = GetSubsystem<Input>();
  286. unsigned numTouches = input->GetNumTouches();
  287. for (unsigned i = 0; i < numTouches; ++i)
  288. {
  289. TouchState* touch = input->GetTouch(i);
  290. UIElement* element = GetElementAt(touch->position_);
  291. if (element && element->IsEnabled())
  292. element->OnHover(element->ScreenToElement(touch->position_), touch->position_, MOUSEB_LEFT, 0, 0);
  293. }
  294. Update(timeStep, rootElement_);
  295. Update(timeStep, rootModalElement_);
  296. }
  297. void UI::RenderUpdate()
  298. {
  299. assert(rootElement_ && rootModalElement_ && graphics_);
  300. PROFILE(GetUIBatches);
  301. // If the OS cursor is visible, do not render the UI's own cursor
  302. bool osCursorVisible = GetSubsystem<Input>()->IsMouseVisible();
  303. // Get rendering batches from the non-modal UI elements
  304. batches_.Clear();
  305. vertexData_.Clear();
  306. const IntVector2& rootSize = rootElement_->GetSize();
  307. IntRect currentScissor = IntRect(0, 0, rootSize.x_, rootSize.y_);
  308. GetBatches(rootElement_, currentScissor);
  309. // Save the batch size of the non-modal batches for later use
  310. nonModalBatchSize_ = batches_.Size();
  311. // Get rendering batches from the modal UI elements
  312. GetBatches(rootModalElement_, currentScissor);
  313. // Get batches from the cursor (and its possible children) last to draw it on top of everything
  314. if (cursor_ && cursor_->IsVisible() && !osCursorVisible)
  315. {
  316. currentScissor = IntRect(0, 0, rootSize.x_, rootSize.y_);
  317. cursor_->GetBatches(batches_, vertexData_, currentScissor);
  318. GetBatches(cursor_, currentScissor);
  319. }
  320. }
  321. void UI::Render()
  322. {
  323. PROFILE(RenderUI);
  324. SetVertexData(vertexBuffer_, vertexData_);
  325. SetVertexData(debugVertexBuffer_, debugVertexData_);
  326. // Render non-modal batches
  327. Render(vertexBuffer_, batches_, 0, nonModalBatchSize_);
  328. // Render debug draw
  329. Render(debugVertexBuffer_, debugDrawBatches_, 0, debugDrawBatches_.Size());
  330. // Render modal batches
  331. Render(vertexBuffer_, batches_, nonModalBatchSize_, batches_.Size());
  332. // Clear the debug draw batches and data
  333. debugDrawBatches_.Clear();
  334. debugVertexData_.Clear();
  335. }
  336. void UI::DebugDraw(UIElement* element)
  337. {
  338. if (element)
  339. {
  340. const IntVector2& rootSize = rootElement_->GetSize();
  341. element->GetDebugDrawBatches(debugDrawBatches_, debugVertexData_, IntRect(0, 0, rootSize.x_, rootSize.y_));
  342. }
  343. }
  344. SharedPtr<UIElement> UI::LoadLayout(Deserializer& source, XMLFile* styleFile)
  345. {
  346. SharedPtr<XMLFile> xml(new XMLFile(context_));
  347. if (!xml->Load(source))
  348. return SharedPtr<UIElement>();
  349. else
  350. return LoadLayout(xml, styleFile);
  351. }
  352. SharedPtr<UIElement> UI::LoadLayout(XMLFile* file, XMLFile* styleFile)
  353. {
  354. PROFILE(LoadUILayout);
  355. SharedPtr<UIElement> root;
  356. if (!file)
  357. {
  358. LOGERROR("Null UI layout XML file");
  359. return root;
  360. }
  361. LOGDEBUG("Loading UI layout " + file->GetName());
  362. XMLElement rootElem = file->GetRoot("element");
  363. if (!rootElem)
  364. {
  365. LOGERROR("No root UI element in " + file->GetName());
  366. return root;
  367. }
  368. String typeName = rootElem.GetAttribute("type");
  369. if (typeName.Empty())
  370. typeName = "UIElement";
  371. root = DynamicCast<UIElement>(context_->CreateObject(typeName));
  372. if (!root)
  373. {
  374. LOGERROR("Could not create unknown UI element " + typeName);
  375. return root;
  376. }
  377. // Use default style file of the root element if it has one
  378. if (!styleFile)
  379. styleFile = rootElement_->GetDefaultStyle(false);
  380. // Set it as default for later use by children elements
  381. if (styleFile)
  382. root->SetDefaultStyle(styleFile);
  383. root->LoadXML(rootElem, styleFile);
  384. return root;
  385. }
  386. bool UI::SaveLayout(Serializer& dest, UIElement* element)
  387. {
  388. PROFILE(SaveUILayout);
  389. return element && element->SaveXML(dest);
  390. }
  391. void UI::SetClipBoardText(const String& text)
  392. {
  393. clipBoard_ = text;
  394. if (useSystemClipBoard_)
  395. SDL_SetClipboardText(text.CString());
  396. }
  397. void UI::SetDoubleClickInterval(float interval)
  398. {
  399. doubleClickInterval_ = Max(interval, 0.0f);
  400. }
  401. void UI::SetMaxFontTextureSize(int size)
  402. {
  403. if (IsPowerOfTwo(size) && size >= FONT_TEXTURE_MIN_SIZE)
  404. {
  405. if (size != maxFontTextureSize_)
  406. {
  407. maxFontTextureSize_ = size;
  408. ReleaseFontFaces();
  409. }
  410. }
  411. }
  412. void UI::SetNonFocusedMouseWheel(bool nonFocusedMouseWheel)
  413. {
  414. nonFocusedMouseWheel_ = nonFocusedMouseWheel;
  415. }
  416. void UI::SetUseSystemClipBoard(bool enable)
  417. {
  418. useSystemClipBoard_ = enable;
  419. }
  420. void UI::SetUseMutableGlyphs(bool enable)
  421. {
  422. if (enable != useMutableGlyphs_)
  423. {
  424. useMutableGlyphs_ = enable;
  425. ReleaseFontFaces();
  426. }
  427. }
  428. void UI::SetForceAutoHint(bool enable)
  429. {
  430. if (enable != forceAutoHint_)
  431. {
  432. forceAutoHint_ = enable;
  433. ReleaseFontFaces();
  434. }
  435. }
  436. IntVector2 UI::GetCursorPosition() const
  437. {
  438. return cursor_ ? cursor_->GetPosition() : GetSubsystem<Input>()->GetMousePosition();
  439. }
  440. UIElement* UI::GetElementAt(const IntVector2& position, bool enabledOnly)
  441. {
  442. UIElement* result = 0;
  443. GetElementAt(result, HasModalElement() ? rootModalElement_ : rootElement_, position, enabledOnly);
  444. return result;
  445. }
  446. UIElement* UI::GetElementAt(int x, int y, bool enabledOnly)
  447. {
  448. return GetElementAt(IntVector2(x, y), enabledOnly);
  449. }
  450. UIElement* UI::GetFrontElement() const
  451. {
  452. const Vector<SharedPtr<UIElement> >& rootChildren = rootElement_->GetChildren();
  453. int maxPriority = M_MIN_INT;
  454. UIElement* front = 0;
  455. for (unsigned i = 0; i < rootChildren.Size(); ++i)
  456. {
  457. // Do not take into account input-disabled elements, hidden elements or those that are always in the front
  458. if (!rootChildren[i]->IsEnabled() || !rootChildren[i]->IsVisible() || !rootChildren[i]->GetBringToBack())
  459. continue;
  460. int priority = rootChildren[i]->GetPriority();
  461. if (priority > maxPriority)
  462. {
  463. maxPriority = priority;
  464. front = rootChildren[i];
  465. }
  466. }
  467. return front;
  468. }
  469. const String& UI::GetClipBoardText() const
  470. {
  471. if (useSystemClipBoard_)
  472. {
  473. char* text = SDL_GetClipboardText();
  474. clipBoard_ = String(text);
  475. if (text)
  476. SDL_free(text);
  477. }
  478. return clipBoard_;
  479. }
  480. bool UI::HasModalElement() const
  481. {
  482. return rootModalElement_->GetNumChildren() > 0;
  483. }
  484. void UI::Initialize()
  485. {
  486. Graphics* graphics = GetSubsystem<Graphics>();
  487. Renderer* renderer = GetSubsystem<Renderer>();
  488. if (!graphics || !graphics->IsInitialized() || !renderer)
  489. return;
  490. PROFILE(InitUI);
  491. graphics_ = graphics;
  492. rootElement_->SetSize(graphics->GetWidth(), graphics->GetHeight());
  493. rootModalElement_->SetSize(rootElement_->GetSize());
  494. noTextureVS_ = renderer->GetVertexShader("Basic_VCol");
  495. diffTextureVS_ = renderer->GetVertexShader("Basic_DiffVCol");
  496. noTexturePS_ = renderer->GetPixelShader("Basic_VCol");
  497. diffTexturePS_ = renderer->GetPixelShader("Basic_DiffVCol");
  498. diffMaskTexturePS_ = renderer->GetPixelShader("Basic_DiffAlphaMaskVCol");
  499. alphaTexturePS_ = renderer->GetPixelShader("Basic_AlphaVCol");
  500. vertexBuffer_ = new VertexBuffer(context_);
  501. debugVertexBuffer_ = new VertexBuffer(context_);
  502. initialized_ = true;
  503. SubscribeToEvent(E_POSTUPDATE, HANDLER(UI, HandlePostUpdate));
  504. SubscribeToEvent(E_RENDERUPDATE, HANDLER(UI, HandleRenderUpdate));
  505. LOGINFO("Initialized user interface");
  506. }
  507. void UI::Update(float timeStep, UIElement* element)
  508. {
  509. element->Update(timeStep);
  510. const Vector<SharedPtr<UIElement> >& children = element->GetChildren();
  511. for (Vector<SharedPtr<UIElement> >::ConstIterator i = children.Begin(); i != children.End(); ++i)
  512. Update(timeStep, *i);
  513. }
  514. void UI::SetVertexData(VertexBuffer* dest, const PODVector<float>& vertexData)
  515. {
  516. if (vertexData.Empty())
  517. return;
  518. // Update quad geometry into the vertex buffer
  519. // Resize the vertex buffer first if too small or much too large
  520. unsigned numVertices = vertexData.Size() / UI_VERTEX_SIZE;
  521. if (dest->GetVertexCount() < numVertices || dest->GetVertexCount() > numVertices * 2)
  522. dest->SetSize(numVertices, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true);
  523. dest->SetData(&vertexData[0]);
  524. }
  525. void UI::Render(VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigned batchStart, unsigned batchEnd)
  526. {
  527. // Engine does not render when window is closed or device is lost
  528. assert(graphics_ && graphics_->IsInitialized() && !graphics_->IsDeviceLost());
  529. if (batches.Empty())
  530. return;
  531. Vector2 invScreenSize(1.0f / (float)graphics_->GetWidth(), 1.0f / (float)graphics_->GetHeight());
  532. Vector2 scale(2.0f * invScreenSize.x_, -2.0f * invScreenSize.y_);
  533. Vector2 offset(-1.0f, 1.0f);
  534. Matrix4 projection(Matrix4::IDENTITY);
  535. projection.m00_ = scale.x_;
  536. projection.m03_ = offset.x_;
  537. projection.m11_ = scale.y_;
  538. projection.m13_ = offset.y_;
  539. projection.m22_ = 1.0f;
  540. projection.m23_ = 0.0f;
  541. projection.m33_ = 1.0f;
  542. graphics_->ClearParameterSources();
  543. graphics_->SetCullMode(CULL_CCW);
  544. graphics_->SetDepthTest(CMP_ALWAYS);
  545. graphics_->SetDepthWrite(false);
  546. graphics_->SetStencilTest(false);
  547. graphics_->ResetRenderTargets();
  548. graphics_->SetVertexBuffer(buffer);
  549. ShaderVariation* ps = 0;
  550. ShaderVariation* vs = 0;
  551. unsigned alphaFormat = Graphics::GetAlphaFormat();
  552. for (unsigned i = batchStart; i < batchEnd; ++i)
  553. {
  554. const UIBatch& batch = batches[i];
  555. if (batch.vertexStart_ == batch.vertexEnd_)
  556. continue;
  557. if (!batch.texture_)
  558. {
  559. ps = noTexturePS_;
  560. vs = noTextureVS_;
  561. }
  562. else
  563. {
  564. // If texture contains only an alpha channel, use alpha shader (for fonts)
  565. vs = diffTextureVS_;
  566. if (batch.texture_->GetFormat() == alphaFormat)
  567. ps = alphaTexturePS_;
  568. else if (batch.blendMode_ != BLEND_ALPHA && batch.blendMode_ != BLEND_ADDALPHA && batch.blendMode_ != BLEND_PREMULALPHA)
  569. ps = diffMaskTexturePS_;
  570. else
  571. ps = diffTexturePS_;
  572. }
  573. graphics_->SetShaders(vs, ps);
  574. if (graphics_->NeedParameterUpdate(SP_OBJECTTRANSFORM, this))
  575. graphics_->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
  576. if (graphics_->NeedParameterUpdate(SP_CAMERA, this))
  577. graphics_->SetShaderParameter(VSP_VIEWPROJ, projection);
  578. if (graphics_->NeedParameterUpdate(SP_MATERIAL, this))
  579. graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
  580. graphics_->SetBlendMode(batch.blendMode_);
  581. graphics_->SetScissorTest(true, batch.scissor_);
  582. graphics_->SetTexture(0, batch.texture_);
  583. graphics_->Draw(TRIANGLE_LIST, batch.vertexStart_ / UI_VERTEX_SIZE, (batch.vertexEnd_ - batch.vertexStart_) /
  584. UI_VERTEX_SIZE);
  585. }
  586. }
  587. void UI::GetBatches(UIElement* element, IntRect currentScissor)
  588. {
  589. // Set clipping scissor for child elements. No need to draw if zero size
  590. element->AdjustScissor(currentScissor);
  591. if (currentScissor.left_ == currentScissor.right_ || currentScissor.top_ == currentScissor.bottom_)
  592. return;
  593. element->SortChildren();
  594. const Vector<SharedPtr<UIElement> >& children = element->GetChildren();
  595. if (children.Empty())
  596. return;
  597. // For non-root elements draw all children of same priority before recursing into their children: assumption is that they have
  598. // same renderstate
  599. Vector<SharedPtr<UIElement> >::ConstIterator i = children.Begin();
  600. if (element->GetTraversalMode() == TM_BREADTH_FIRST)
  601. {
  602. Vector<SharedPtr<UIElement> >::ConstIterator j = i;
  603. while (i != children.End())
  604. {
  605. int currentPriority = (*i)->GetPriority();
  606. while (j != children.End() && (*j)->GetPriority() == currentPriority)
  607. {
  608. if ((*j)->IsWithinScissor(currentScissor) && (*j) != cursor_)
  609. (*j)->GetBatches(batches_, vertexData_, currentScissor);
  610. ++j;
  611. }
  612. // Now recurse into the children
  613. while (i != j)
  614. {
  615. if ((*i)->IsVisible() && (*i) != cursor_)
  616. GetBatches(*i, currentScissor);
  617. ++i;
  618. }
  619. }
  620. }
  621. // On the root level draw each element and its children immediately after to avoid artifacts
  622. else
  623. {
  624. while (i != children.End())
  625. {
  626. if ((*i) != cursor_)
  627. {
  628. if ((*i)->IsWithinScissor(currentScissor))
  629. (*i)->GetBatches(batches_, vertexData_, currentScissor);
  630. if ((*i)->IsVisible())
  631. GetBatches(*i, currentScissor);
  632. }
  633. ++i;
  634. }
  635. }
  636. }
  637. void UI::GetElementAt(UIElement*& result, UIElement* current, const IntVector2& position, bool enabledOnly)
  638. {
  639. if (!current)
  640. return;
  641. current->SortChildren();
  642. const Vector<SharedPtr<UIElement> >& children = current->GetChildren();
  643. LayoutMode parentLayoutMode = current->GetLayoutMode();
  644. for (unsigned i = 0; i < children.Size(); ++i)
  645. {
  646. UIElement* element = children[i];
  647. bool hasChildren = element->GetNumChildren() > 0;
  648. if (element != cursor_.Get() && element->IsVisible())
  649. {
  650. if (element->IsInside(position, true))
  651. {
  652. // Store the current result, then recurse into its children. Because children
  653. // are sorted from lowest to highest priority, the topmost match should remain
  654. if (element->IsEnabled() || !enabledOnly)
  655. result = element;
  656. if (hasChildren)
  657. GetElementAt(result, element, position, enabledOnly);
  658. // Layout optimization: if the element has no children, can break out after the first match
  659. else if (parentLayoutMode != LM_FREE)
  660. break;
  661. }
  662. else
  663. {
  664. if (hasChildren)
  665. {
  666. if (element->IsInsideCombined(position, true))
  667. GetElementAt(result, element, position, enabledOnly);
  668. }
  669. // Layout optimization: if position is much beyond the visible screen, check how many elements we can skip,
  670. // or if we already passed all visible elements
  671. else if (parentLayoutMode != LM_FREE)
  672. {
  673. if (!i)
  674. {
  675. int screenPos = (parentLayoutMode == LM_HORIZONTAL) ? element->GetScreenPosition().x_ :
  676. element->GetScreenPosition().y_;
  677. int layoutMinSize = current->GetLayoutMinSize();
  678. if (screenPos < 0 && layoutMinSize > 0)
  679. {
  680. unsigned toSkip = -screenPos / layoutMinSize;
  681. if (toSkip > 0)
  682. i += (toSkip - 1);
  683. }
  684. }
  685. else if (parentLayoutMode == LM_HORIZONTAL)
  686. {
  687. if (element->GetScreenPosition().x_ >= rootElement_->GetSize().x_)
  688. break;
  689. }
  690. else if (parentLayoutMode == LM_VERTICAL)
  691. {
  692. if (element->GetScreenPosition().y_ >= rootElement_->GetSize().y_)
  693. break;
  694. }
  695. }
  696. }
  697. }
  698. }
  699. }
  700. UIElement* UI::GetFocusableElement(UIElement* element)
  701. {
  702. while (element)
  703. {
  704. if (element->GetFocusMode() != FM_NOTFOCUSABLE)
  705. break;
  706. element = element->GetParent();
  707. }
  708. return element;
  709. }
  710. void UI::GetCursorPositionAndVisible(IntVector2& pos, bool& visible)
  711. {
  712. if (cursor_)
  713. {
  714. pos = cursor_->GetPosition();
  715. visible = cursor_->IsVisible();
  716. }
  717. else
  718. {
  719. Input* input = GetSubsystem<Input>();
  720. pos = input->GetMousePosition();
  721. visible = input->IsMouseVisible();
  722. }
  723. }
  724. void UI::SetCursorShape(CursorShape shape)
  725. {
  726. if (cursor_)
  727. cursor_->SetShape(shape);
  728. }
  729. void UI::ReleaseFontFaces()
  730. {
  731. LOGDEBUG("Reloading font faces");
  732. PODVector<Font*> fonts;
  733. GetSubsystem<ResourceCache>()->GetResources<Font>(fonts);
  734. for (unsigned i = 0; i < fonts.Size(); ++i)
  735. fonts[i]->ReleaseFaces();
  736. }
  737. void UI::ProcessClickBegin(const IntVector2& cursorPos, int button, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible)
  738. {
  739. if (cursorVisible)
  740. {
  741. WeakPtr<UIElement> element(GetElementAt(cursorPos));
  742. if (element)
  743. {
  744. // Handle focusing & bringing to front
  745. if (button == MOUSEB_LEFT)
  746. {
  747. SetFocusElement(element);
  748. element->BringToFront();
  749. }
  750. // Handle click
  751. element->OnClickBegin(element->ScreenToElement(cursorPos), cursorPos, button, buttons, qualifiers, cursor);
  752. SendClickEvent(E_UIMOUSECLICK, element, cursorPos, button, buttons, qualifiers);
  753. // Remember element clicked on for the click end
  754. clickElement_ = element;
  755. // Fire double click event if element matches and is in time
  756. if (doubleClickElement_ && element == doubleClickElement_ && clickTimer_->GetMSec(true) <
  757. (unsigned)(doubleClickInterval_ * 1000) && lastMouseButtons_ == buttons)
  758. {
  759. element->OnDoubleClick(element->ScreenToElement(cursorPos), cursorPos, button, buttons, qualifiers, cursor);
  760. doubleClickElement_.Reset();
  761. SendClickEvent(E_UIMOUSEDOUBLECLICK, element, cursorPos, button, buttons, qualifiers);
  762. }
  763. else
  764. {
  765. doubleClickElement_ = element;
  766. clickTimer_->Reset();
  767. }
  768. // Handle start of drag. Click handling may have caused destruction of the element, so check the pointer again
  769. if (element && !dragElement_ && buttons == MOUSEB_LEFT)
  770. {
  771. dragElement_ = element;
  772. element->OnDragBegin(element->ScreenToElement(cursorPos), cursorPos, buttons, qualifiers, cursor);
  773. SendDragEvent(E_DRAGBEGIN, element, cursorPos);
  774. }
  775. }
  776. else
  777. {
  778. // If clicked over no element, or a disabled element, lose focus
  779. SetFocusElement(0);
  780. SendClickEvent(E_UIMOUSECLICK, element, cursorPos, button, buttons, qualifiers);
  781. }
  782. lastMouseButtons_ = buttons;
  783. }
  784. }
  785. void UI::ProcessClickEnd(const IntVector2& cursorPos, int button, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible)
  786. {
  787. if (cursorVisible)
  788. {
  789. WeakPtr<UIElement> element(GetElementAt(cursorPos));
  790. // Handle end of click
  791. if (element)
  792. element->OnClickEnd(element->ScreenToElement(cursorPos), cursorPos, button, buttons, qualifiers, cursor, clickElement_);
  793. SendClickEvent(E_UIMOUSECLICKEND, element, cursorPos, button, buttons, qualifiers);
  794. // Handle end of drag
  795. if (dragElement_ && !buttons)
  796. {
  797. if (dragElement_->IsEnabled() && dragElement_->IsVisible())
  798. {
  799. dragElement_->OnDragEnd(dragElement_->ScreenToElement(cursorPos), cursorPos, cursor);
  800. SendDragEvent(E_DRAGEND, dragElement_, cursorPos);
  801. bool dragSource = dragElement_ && (dragElement_->GetDragDropMode() & DD_SOURCE) != 0;
  802. if (dragSource)
  803. {
  804. bool dragTarget = element && (element->GetDragDropMode() & DD_TARGET) != 0;
  805. bool dragDropFinish = dragSource && dragTarget && element != dragElement_;
  806. if (dragDropFinish)
  807. {
  808. bool accept = element->OnDragDropFinish(dragElement_);
  809. // OnDragDropFinish() may have caused destruction of the elements, so check the pointers again
  810. if (accept && dragElement_ && element)
  811. {
  812. using namespace DragDropFinish;
  813. VariantMap eventData;
  814. eventData[P_SOURCE] = (void*)dragElement_.Get();
  815. eventData[P_TARGET] = (void*)element.Get();
  816. eventData[P_ACCEPT] = accept;
  817. SendEvent(E_DRAGDROPFINISH, eventData);
  818. }
  819. }
  820. }
  821. }
  822. dragElement_.Reset();
  823. }
  824. clickElement_.Reset();
  825. }
  826. }
  827. void UI::ProcessMove(const IntVector2& cursorPos, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible)
  828. {
  829. if (cursorVisible && dragElement_ && buttons)
  830. {
  831. if (dragElement_->IsEnabled() && dragElement_->IsVisible())
  832. {
  833. dragElement_->OnDragMove(dragElement_->ScreenToElement(cursorPos), cursorPos, buttons, qualifiers, cursor);
  834. SendDragEvent(E_DRAGMOVE, dragElement_, cursorPos);
  835. }
  836. else
  837. {
  838. dragElement_->OnDragEnd(dragElement_->ScreenToElement(cursorPos), cursorPos, cursor);
  839. SendDragEvent(E_DRAGEND, dragElement_, cursorPos);
  840. dragElement_.Reset();
  841. }
  842. }
  843. }
  844. void UI::SendDragEvent(StringHash eventType, UIElement* element, const IntVector2& screenPos)
  845. {
  846. if (!element)
  847. return;
  848. IntVector2 relativePos = element->ScreenToElement(screenPos);
  849. using namespace DragBegin;
  850. VariantMap eventData;
  851. eventData[P_ELEMENT] = (void*)element;
  852. eventData[P_X] = screenPos.x_;
  853. eventData[P_Y] = screenPos.y_;
  854. eventData[P_ELEMENTX] = relativePos.x_;
  855. eventData[P_ELEMENTY] = relativePos.y_;
  856. element->SendEvent(eventType, eventData);
  857. }
  858. void UI::SendClickEvent(StringHash eventType, UIElement* element, const IntVector2& pos, int button, int buttons, int qualifiers)
  859. {
  860. VariantMap eventData;
  861. eventData[UIMouseClick::P_ELEMENT] = (void*)element;
  862. eventData[UIMouseClick::P_X] = pos.x_;
  863. eventData[UIMouseClick::P_Y] = pos.y_;
  864. eventData[UIMouseClick::P_BUTTON] = button;
  865. eventData[UIMouseClick::P_BUTTONS] = buttons;
  866. eventData[UIMouseClick::P_QUALIFIERS] = qualifiers;
  867. // For click end events, send also the element the click began on
  868. if (eventType == E_UIMOUSECLICKEND)
  869. eventData[UIMouseClickEnd::P_BEGINELEMENT] = clickElement_;
  870. SendEvent(eventType, eventData);
  871. }
  872. void UI::HandleScreenMode(StringHash eventType, VariantMap& eventData)
  873. {
  874. using namespace ScreenMode;
  875. if (!initialized_)
  876. Initialize();
  877. else
  878. {
  879. rootElement_->SetSize(eventData[P_WIDTH].GetInt(), eventData[P_HEIGHT].GetInt());
  880. rootModalElement_->SetSize(rootElement_->GetSize());
  881. }
  882. }
  883. void UI::HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
  884. {
  885. mouseButtons_ = eventData[MouseButtonDown::P_BUTTONS].GetInt();
  886. qualifiers_ = eventData[MouseButtonDown::P_QUALIFIERS].GetInt();
  887. usingTouchInput_ = false;
  888. IntVector2 cursorPos;
  889. bool cursorVisible;
  890. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  891. ProcessClickBegin(cursorPos, eventData[MouseButtonDown::P_BUTTON].GetInt(), mouseButtons_, qualifiers_, cursor_, cursorVisible);
  892. }
  893. void UI::HandleMouseButtonUp(StringHash eventType, VariantMap& eventData)
  894. {
  895. using namespace MouseButtonUp;
  896. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  897. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  898. IntVector2 cursorPos;
  899. bool cursorVisible;
  900. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  901. ProcessClickEnd(cursorPos, eventData[P_BUTTON].GetInt(), mouseButtons_, qualifiers_, cursor_, cursorVisible);
  902. }
  903. void UI::HandleMouseMove(StringHash eventType, VariantMap& eventData)
  904. {
  905. using namespace MouseMove;
  906. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  907. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  908. usingTouchInput_ = false;
  909. Input* input = GetSubsystem<Input>();
  910. const IntVector2& rootSize = rootElement_->GetSize();
  911. if (cursor_)
  912. {
  913. if (!input->IsMouseVisible())
  914. {
  915. // Relative mouse motion: move cursor only when visible
  916. if (cursor_->IsVisible())
  917. {
  918. IntVector2 pos = cursor_->GetPosition();
  919. pos.x_ += eventData[P_DX].GetInt();
  920. pos.y_ += eventData[P_DY].GetInt();
  921. pos.x_ = Clamp(pos.x_, 0, rootSize.x_ - 1);
  922. pos.y_ = Clamp(pos.y_, 0, rootSize.y_ - 1);
  923. cursor_->SetPosition(pos);
  924. }
  925. }
  926. else
  927. {
  928. // Absolute mouse motion: move always
  929. cursor_->SetPosition(IntVector2(eventData[P_X].GetInt(), eventData[P_Y].GetInt()));
  930. }
  931. }
  932. IntVector2 cursorPos;
  933. bool cursorVisible;
  934. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  935. ProcessMove(cursorPos, mouseButtons_, qualifiers_, cursor_, cursorVisible);
  936. }
  937. void UI::HandleMouseWheel(StringHash eventType, VariantMap& eventData)
  938. {
  939. using namespace MouseWheel;
  940. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  941. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  942. int delta = eventData[P_WHEEL].GetInt();
  943. usingTouchInput_ = false;
  944. IntVector2 cursorPos;
  945. bool cursorVisible;
  946. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  947. UIElement* element;
  948. if (!nonFocusedMouseWheel_&& (element = focusElement_))
  949. element->OnWheel(delta, mouseButtons_, qualifiers_);
  950. else
  951. {
  952. // If no element has actual focus or in non-focused mode, get the element at cursor
  953. if (cursorVisible)
  954. {
  955. element = GetElementAt(cursorPos);
  956. if (nonFocusedMouseWheel_)
  957. {
  958. // Going up the hierarchy chain to find element that could handle mouse wheel
  959. while (element)
  960. {
  961. if (element->GetType() == ListView::GetTypeStatic() ||
  962. element->GetType() == ScrollView::GetTypeStatic())
  963. break;
  964. element = element->GetParent();
  965. }
  966. }
  967. else
  968. // If the element itself is not focusable, search for a focusable parent,
  969. // although the focusable element may not actually handle mouse wheel
  970. element = GetFocusableElement(element);
  971. if (element && (nonFocusedMouseWheel_ || element->GetFocusMode() >= FM_FOCUSABLE))
  972. element->OnWheel(delta, mouseButtons_, qualifiers_);
  973. }
  974. }
  975. }
  976. void UI::HandleTouchBegin(StringHash eventType, VariantMap& eventData)
  977. {
  978. using namespace TouchBegin;
  979. IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
  980. WeakPtr<UIElement> element(GetElementAt(pos));
  981. usingTouchInput_ = true;
  982. ProcessClickBegin(pos, MOUSEB_LEFT, MOUSEB_LEFT, 0, 0, true);
  983. }
  984. void UI::HandleTouchEnd(StringHash eventType, VariantMap& eventData)
  985. {
  986. using namespace TouchEnd;
  987. IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
  988. // Transmit hover end to the position where the finger was lifted
  989. UIElement* element = GetElementAt(pos);
  990. if (element && element->IsEnabled())
  991. element->OnHover(element->ScreenToElement(pos), pos, 0, 0, 0);
  992. ProcessClickEnd(pos, MOUSEB_LEFT, 0, 0, 0, true);
  993. }
  994. void UI::HandleTouchMove(StringHash eventType, VariantMap& eventData)
  995. {
  996. using namespace TouchMove;
  997. IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
  998. usingTouchInput_ = true;
  999. ProcessMove(pos, MOUSEB_LEFT, 0, 0, true);
  1000. }
  1001. void UI::HandleKeyDown(StringHash eventType, VariantMap& eventData)
  1002. {
  1003. using namespace KeyDown;
  1004. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  1005. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  1006. int key = eventData[P_KEY].GetInt();
  1007. // Dismiss modal element if any when ESC key is pressed
  1008. if (key == KEY_ESC && HasModalElement())
  1009. {
  1010. UIElement* element = rootModalElement_->GetChild(rootModalElement_->GetNumChildren() - 1);
  1011. if (element->GetVars().Contains(VAR_ORIGIN))
  1012. // If it is a popup, dismiss by defocusing it
  1013. SetFocusElement(0);
  1014. else
  1015. {
  1016. // If it is a modal window, by resetting its modal flag
  1017. Window* window = dynamic_cast<Window*>(element);
  1018. if (window)
  1019. window->SetModal(false);
  1020. }
  1021. return;
  1022. }
  1023. UIElement* element = focusElement_;
  1024. if (element)
  1025. {
  1026. // Switch focus between focusable elements in the same top level window
  1027. if (key == KEY_TAB)
  1028. {
  1029. UIElement* topLevel = element->GetParent();
  1030. while (topLevel && topLevel->GetParent() != rootElement_ && topLevel->GetParent() != rootModalElement_)
  1031. topLevel = topLevel->GetParent();
  1032. if (topLevel)
  1033. {
  1034. topLevel->GetChildren(tempElements_, true);
  1035. for (PODVector<UIElement*>::Iterator i = tempElements_.Begin(); i != tempElements_.End();)
  1036. {
  1037. if ((*i)->GetFocusMode() < FM_FOCUSABLE)
  1038. i = tempElements_.Erase(i);
  1039. else
  1040. ++i;
  1041. }
  1042. for (unsigned i = 0; i < tempElements_.Size(); ++i)
  1043. {
  1044. if (tempElements_[i] == element)
  1045. {
  1046. UIElement* next = tempElements_[(i + 1) % tempElements_.Size()];
  1047. SetFocusElement(next);
  1048. return;
  1049. }
  1050. }
  1051. }
  1052. }
  1053. // Defocus the element
  1054. else if (key == KEY_ESC && element->GetFocusMode() == FM_FOCUSABLE_DEFOCUSABLE)
  1055. element->SetFocus(false);
  1056. // If none of the special keys, pass the key to the focused element
  1057. else
  1058. element->OnKey(key, mouseButtons_, qualifiers_);
  1059. }
  1060. }
  1061. void UI::HandleChar(StringHash eventType, VariantMap& eventData)
  1062. {
  1063. using namespace Char;
  1064. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  1065. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  1066. UIElement* element = focusElement_;
  1067. if (element)
  1068. element->OnChar(eventData[P_CHAR].GetInt(), mouseButtons_, qualifiers_);
  1069. }
  1070. void UI::HandlePostUpdate(StringHash eventType, VariantMap& eventData)
  1071. {
  1072. using namespace PostUpdate;
  1073. Update(eventData[P_TIMESTEP].GetFloat());
  1074. }
  1075. void UI::HandleRenderUpdate(StringHash eventType, VariantMap& eventData)
  1076. {
  1077. RenderUpdate();
  1078. }
  1079. void UI::HandleDropFile(StringHash eventType, VariantMap& eventData)
  1080. {
  1081. Input* input = GetSubsystem<Input>();
  1082. // Sending the UI variant of the event only makes sense if the OS cursor is visible (not locked to window center)
  1083. if (input->IsMouseVisible())
  1084. {
  1085. IntVector2 screenPos = input->GetMousePosition();
  1086. UIElement* element = GetElementAt(screenPos);
  1087. using namespace UIDropFile;
  1088. VariantMap uiEventData;
  1089. uiEventData[P_FILENAME] = eventData[P_FILENAME];
  1090. uiEventData[P_X] = screenPos.x_;
  1091. uiEventData[P_Y] = screenPos.y_;
  1092. uiEventData[P_ELEMENT] = (void*)element;
  1093. if (element)
  1094. {
  1095. IntVector2 relativePos = element->ScreenToElement(screenPos);
  1096. uiEventData[P_ELEMENTX] = relativePos.x_;
  1097. uiEventData[P_ELEMENTY] = relativePos.y_;
  1098. }
  1099. SendEvent(E_UIDROPFILE, uiEventData);
  1100. }
  1101. }
  1102. void RegisterUILibrary(Context* context)
  1103. {
  1104. Font::RegisterObject(context);
  1105. UIElement::RegisterObject(context);
  1106. BorderImage::RegisterObject(context);
  1107. Sprite::RegisterObject(context);
  1108. Button::RegisterObject(context);
  1109. CheckBox::RegisterObject(context);
  1110. Cursor::RegisterObject(context);
  1111. Text::RegisterObject(context);
  1112. Text3D::RegisterObject(context);
  1113. Window::RegisterObject(context);
  1114. View3D::RegisterObject(context);
  1115. LineEdit::RegisterObject(context);
  1116. Slider::RegisterObject(context);
  1117. ScrollBar::RegisterObject(context);
  1118. ScrollView::RegisterObject(context);
  1119. ListView::RegisterObject(context);
  1120. Menu::RegisterObject(context);
  1121. DropDownList::RegisterObject(context);
  1122. FileSelector::RegisterObject(context);
  1123. }
  1124. }