UI.cpp 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867
  1. //
  2. // Copyright (c) 2008-2016 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 "../Core/Context.h"
  24. #include "../Core/CoreEvents.h"
  25. #include "../Core/Profiler.h"
  26. #include "../Container/Sort.h"
  27. #include "../Graphics/Graphics.h"
  28. #include "../Graphics/GraphicsEvents.h"
  29. #include "../Graphics/Shader.h"
  30. #include "../Graphics/ShaderVariation.h"
  31. #include "../Graphics/Texture2D.h"
  32. #include "../Graphics/VertexBuffer.h"
  33. #include "../Input/Input.h"
  34. #include "../Input/InputEvents.h"
  35. #include "../IO/Log.h"
  36. #include "../Math/Matrix3x4.h"
  37. #include "../Resource/ResourceCache.h"
  38. #include "../UI/CheckBox.h"
  39. #include "../UI/Cursor.h"
  40. #include "../UI/DropDownList.h"
  41. #include "../UI/FileSelector.h"
  42. #include "../UI/Font.h"
  43. #include "../UI/LineEdit.h"
  44. #include "../UI/ListView.h"
  45. #include "../UI/MessageBox.h"
  46. #include "../UI/ScrollBar.h"
  47. #include "../UI/Slider.h"
  48. #include "../UI/Sprite.h"
  49. #include "../UI/Text.h"
  50. #include "../UI/Text3D.h"
  51. #include "../UI/ToolTip.h"
  52. #include "../UI/UI.h"
  53. #include "../UI/UIEvents.h"
  54. #include "../UI/Window.h"
  55. #include "../UI/View3D.h"
  56. #include <SDL/SDL.h>
  57. #include "../DebugNew.h"
  58. #define TOUCHID_MASK(id) (1 << id)
  59. namespace Urho3D
  60. {
  61. StringHash VAR_ORIGIN("Origin");
  62. const StringHash VAR_ORIGINAL_PARENT("OriginalParent");
  63. const StringHash VAR_ORIGINAL_CHILD_INDEX("OriginalChildIndex");
  64. const StringHash VAR_PARENT_CHANGED("ParentChanged");
  65. const float DEFAULT_DOUBLECLICK_INTERVAL = 0.5f;
  66. const float DEFAULT_DRAGBEGIN_INTERVAL = 0.5f;
  67. const float DEFAULT_TOOLTIP_DELAY = 0.5f;
  68. const int DEFAULT_DRAGBEGIN_DISTANCE = 5;
  69. const int DEFAULT_FONT_TEXTURE_MAX_SIZE = 2048;
  70. const char* UI_CATEGORY = "UI";
  71. UI::UI(Context* context) :
  72. Object(context),
  73. rootElement_(new UIElement(context)),
  74. rootModalElement_(new UIElement(context)),
  75. doubleClickInterval_(DEFAULT_DOUBLECLICK_INTERVAL),
  76. dragBeginInterval_(DEFAULT_DRAGBEGIN_INTERVAL),
  77. defaultToolTipDelay_(DEFAULT_TOOLTIP_DELAY),
  78. dragBeginDistance_(DEFAULT_DRAGBEGIN_DISTANCE),
  79. mouseButtons_(0),
  80. lastMouseButtons_(0),
  81. qualifiers_(0),
  82. maxFontTextureSize_(DEFAULT_FONT_TEXTURE_MAX_SIZE),
  83. initialized_(false),
  84. usingTouchInput_(false),
  85. #ifdef _WIN32
  86. nonFocusedMouseWheel_(false), // Default MS Windows behaviour
  87. #else
  88. nonFocusedMouseWheel_(true), // Default Mac OS X and Linux behaviour
  89. #endif
  90. useSystemClipboard_(false),
  91. #if defined(__ANDROID__) || defined(IOS)
  92. useScreenKeyboard_(true),
  93. #else
  94. useScreenKeyboard_(false),
  95. #endif
  96. useMutableGlyphs_(false),
  97. forceAutoHint_(false),
  98. uiRendered_(false),
  99. nonModalBatchSize_(0),
  100. dragElementsCount_(0),
  101. dragConfirmedCount_(0),
  102. uiScale_(1.0f)
  103. {
  104. rootElement_->SetTraversalMode(TM_DEPTH_FIRST);
  105. rootModalElement_->SetTraversalMode(TM_DEPTH_FIRST);
  106. // Register UI library object factories
  107. RegisterUILibrary(context_);
  108. SubscribeToEvent(E_SCREENMODE, URHO3D_HANDLER(UI, HandleScreenMode));
  109. SubscribeToEvent(E_MOUSEBUTTONDOWN, URHO3D_HANDLER(UI, HandleMouseButtonDown));
  110. SubscribeToEvent(E_MOUSEBUTTONUP, URHO3D_HANDLER(UI, HandleMouseButtonUp));
  111. SubscribeToEvent(E_MOUSEMOVE, URHO3D_HANDLER(UI, HandleMouseMove));
  112. SubscribeToEvent(E_MOUSEWHEEL, URHO3D_HANDLER(UI, HandleMouseWheel));
  113. SubscribeToEvent(E_TOUCHBEGIN, URHO3D_HANDLER(UI, HandleTouchBegin));
  114. SubscribeToEvent(E_TOUCHEND, URHO3D_HANDLER(UI, HandleTouchEnd));
  115. SubscribeToEvent(E_TOUCHMOVE, URHO3D_HANDLER(UI, HandleTouchMove));
  116. SubscribeToEvent(E_KEYDOWN, URHO3D_HANDLER(UI, HandleKeyDown));
  117. SubscribeToEvent(E_TEXTINPUT, URHO3D_HANDLER(UI, HandleTextInput));
  118. SubscribeToEvent(E_DROPFILE, URHO3D_HANDLER(UI, HandleDropFile));
  119. // Try to initialize right now, but skip if screen mode is not yet set
  120. Initialize();
  121. }
  122. UI::~UI()
  123. {
  124. }
  125. void UI::SetCursor(Cursor* cursor)
  126. {
  127. // Remove old cursor (if any) and set new
  128. if (cursor_)
  129. {
  130. rootElement_->RemoveChild(cursor_);
  131. cursor_.Reset();
  132. }
  133. if (cursor)
  134. {
  135. rootElement_->AddChild(cursor);
  136. cursor_ = cursor;
  137. IntVector2 pos = cursor_->GetPosition();
  138. const IntVector2& rootSize = rootElement_->GetSize();
  139. pos.x_ = Clamp(pos.x_, 0, rootSize.x_ - 1);
  140. pos.y_ = Clamp(pos.y_, 0, rootSize.y_ - 1);
  141. cursor_->SetPosition(pos);
  142. }
  143. }
  144. void UI::SetFocusElement(UIElement* element, bool byKey)
  145. {
  146. using namespace FocusChanged;
  147. UIElement* originalElement = element;
  148. if (element)
  149. {
  150. // Return if already has focus
  151. if (focusElement_ == element)
  152. return;
  153. // Only allow child elements of the modal element to receive focus
  154. if (HasModalElement())
  155. {
  156. UIElement* topLevel = element->GetParent();
  157. while (topLevel && topLevel->GetParent() != rootElement_)
  158. topLevel = topLevel->GetParent();
  159. if (topLevel) // If parented to non-modal root then ignore
  160. return;
  161. }
  162. // Search for an element in the hierarchy that can alter focus. If none found, exit
  163. element = GetFocusableElement(element);
  164. if (!element)
  165. return;
  166. }
  167. // Remove focus from the old element
  168. if (focusElement_)
  169. {
  170. UIElement* oldFocusElement = focusElement_;
  171. focusElement_.Reset();
  172. VariantMap& focusEventData = GetEventDataMap();
  173. focusEventData[Defocused::P_ELEMENT] = oldFocusElement;
  174. oldFocusElement->SendEvent(E_DEFOCUSED, focusEventData);
  175. }
  176. // Then set focus to the new
  177. if (element && element->GetFocusMode() >= FM_FOCUSABLE)
  178. {
  179. focusElement_ = element;
  180. VariantMap& focusEventData = GetEventDataMap();
  181. focusEventData[Focused::P_ELEMENT] = element;
  182. focusEventData[Focused::P_BYKEY] = byKey;
  183. element->SendEvent(E_FOCUSED, focusEventData);
  184. }
  185. VariantMap& eventData = GetEventDataMap();
  186. eventData[P_CLICKEDELEMENT] = originalElement;
  187. eventData[P_ELEMENT] = element;
  188. SendEvent(E_FOCUSCHANGED, eventData);
  189. }
  190. bool UI::SetModalElement(UIElement* modalElement, bool enable)
  191. {
  192. if (!modalElement)
  193. return false;
  194. // Currently only allow modal window
  195. if (modalElement->GetType() != Window::GetTypeStatic())
  196. return false;
  197. assert(rootModalElement_);
  198. UIElement* currParent = modalElement->GetParent();
  199. if (enable)
  200. {
  201. // Make sure it is not already the child of the root modal element
  202. if (currParent == rootModalElement_)
  203. return false;
  204. // Adopt modal root as parent
  205. modalElement->SetVar(VAR_ORIGINAL_PARENT, currParent);
  206. modalElement->SetVar(VAR_ORIGINAL_CHILD_INDEX, currParent ? currParent->FindChild(modalElement) : M_MAX_UNSIGNED);
  207. modalElement->SetParent(rootModalElement_);
  208. // If it is a popup element, bring along its top-level parent
  209. UIElement* originElement = static_cast<UIElement*>(modalElement->GetVar(VAR_ORIGIN).GetPtr());
  210. if (originElement)
  211. {
  212. UIElement* element = originElement;
  213. while (element && element->GetParent() != rootElement_)
  214. element = element->GetParent();
  215. if (element)
  216. {
  217. originElement->SetVar(VAR_PARENT_CHANGED, element);
  218. UIElement* oriParent = element->GetParent();
  219. element->SetVar(VAR_ORIGINAL_PARENT, oriParent);
  220. element->SetVar(VAR_ORIGINAL_CHILD_INDEX, oriParent ? oriParent->FindChild(element) : M_MAX_UNSIGNED);
  221. element->SetParent(rootModalElement_);
  222. }
  223. }
  224. return true;
  225. }
  226. else
  227. {
  228. // Only the modal element can disable itself
  229. if (currParent != rootModalElement_)
  230. return false;
  231. // Revert back to original parent
  232. modalElement->SetParent(static_cast<UIElement*>(modalElement->GetVar(VAR_ORIGINAL_PARENT).GetPtr()),
  233. modalElement->GetVar(VAR_ORIGINAL_CHILD_INDEX).GetUInt());
  234. VariantMap& vars = const_cast<VariantMap&>(modalElement->GetVars());
  235. vars.Erase(VAR_ORIGINAL_PARENT);
  236. vars.Erase(VAR_ORIGINAL_CHILD_INDEX);
  237. // If it is a popup element, revert back its top-level parent
  238. UIElement* originElement = static_cast<UIElement*>(modalElement->GetVar(VAR_ORIGIN).GetPtr());
  239. if (originElement)
  240. {
  241. UIElement* element = static_cast<UIElement*>(originElement->GetVar(VAR_PARENT_CHANGED).GetPtr());
  242. if (element)
  243. {
  244. const_cast<VariantMap&>(originElement->GetVars()).Erase(VAR_PARENT_CHANGED);
  245. element->SetParent(static_cast<UIElement*>(element->GetVar(VAR_ORIGINAL_PARENT).GetPtr()),
  246. element->GetVar(VAR_ORIGINAL_CHILD_INDEX).GetUInt());
  247. vars = const_cast<VariantMap&>(element->GetVars());
  248. vars.Erase(VAR_ORIGINAL_PARENT);
  249. vars.Erase(VAR_ORIGINAL_CHILD_INDEX);
  250. }
  251. }
  252. return true;
  253. }
  254. }
  255. void UI::Clear()
  256. {
  257. rootElement_->RemoveAllChildren();
  258. rootModalElement_->RemoveAllChildren();
  259. if (cursor_)
  260. rootElement_->AddChild(cursor_);
  261. }
  262. void UI::Update(float timeStep)
  263. {
  264. assert(rootElement_ && rootModalElement_);
  265. URHO3D_PROFILE(UpdateUI);
  266. // Expire hovers
  267. for (HashMap<WeakPtr<UIElement>, bool>::Iterator i = hoveredElements_.Begin(); i != hoveredElements_.End(); ++i)
  268. i->second_ = false;
  269. Input* input = GetSubsystem<Input>();
  270. bool mouseGrabbed = input->IsMouseGrabbed();
  271. IntVector2 cursorPos;
  272. bool cursorVisible;
  273. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  274. // Drag begin based on time
  275. if (dragElementsCount_ > 0 && !mouseGrabbed)
  276. {
  277. for (HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i = dragElements_.Begin(); i != dragElements_.End();)
  278. {
  279. WeakPtr<UIElement> dragElement = i->first_;
  280. UI::DragData* dragData = i->second_;
  281. if (!dragElement)
  282. {
  283. i = DragElementErase(i);
  284. continue;
  285. }
  286. if (!dragData->dragBeginPending)
  287. {
  288. ++i;
  289. continue;
  290. }
  291. if (dragData->dragBeginTimer.GetMSec(false) >= (unsigned)(dragBeginInterval_ * 1000))
  292. {
  293. dragData->dragBeginPending = false;
  294. IntVector2 beginSendPos = dragData->dragBeginSumPos / dragData->numDragButtons;
  295. dragConfirmedCount_++;
  296. if (!usingTouchInput_)
  297. dragElement->OnDragBegin(dragElement->ScreenToElement(beginSendPos), beginSendPos, dragData->dragButtons,
  298. qualifiers_, cursor_);
  299. else
  300. dragElement->OnDragBegin(dragElement->ScreenToElement(beginSendPos), beginSendPos, dragData->dragButtons, 0, 0);
  301. SendDragOrHoverEvent(E_DRAGBEGIN, dragElement, beginSendPos, IntVector2::ZERO, dragData);
  302. }
  303. ++i;
  304. }
  305. }
  306. // Mouse hover
  307. if (!mouseGrabbed && !input->GetTouchEmulation())
  308. {
  309. if (!usingTouchInput_ && cursorVisible)
  310. ProcessHover(cursorPos, mouseButtons_, qualifiers_, cursor_);
  311. }
  312. // Touch hover
  313. unsigned numTouches = input->GetNumTouches();
  314. for (unsigned i = 0; i < numTouches; ++i)
  315. {
  316. TouchState* touch = input->GetTouch(i);
  317. IntVector2 touchPos = touch->position_;
  318. touchPos.x_ = (int)(touchPos.x_ / uiScale_);
  319. touchPos.y_ = (int)(touchPos.y_ / uiScale_);
  320. ProcessHover(touchPos, TOUCHID_MASK(touch->touchID_), 0, 0);
  321. }
  322. // End hovers that expired without refreshing
  323. for (HashMap<WeakPtr<UIElement>, bool>::Iterator i = hoveredElements_.Begin(); i != hoveredElements_.End();)
  324. {
  325. if (i->first_.Expired() || !i->second_)
  326. {
  327. UIElement* element = i->first_;
  328. if (element)
  329. {
  330. using namespace HoverEnd;
  331. VariantMap& eventData = GetEventDataMap();
  332. eventData[P_ELEMENT] = element;
  333. element->SendEvent(E_HOVEREND, eventData);
  334. }
  335. i = hoveredElements_.Erase(i);
  336. }
  337. else
  338. ++i;
  339. }
  340. Update(timeStep, rootElement_);
  341. Update(timeStep, rootModalElement_);
  342. }
  343. void UI::RenderUpdate()
  344. {
  345. assert(rootElement_ && rootModalElement_ && graphics_);
  346. URHO3D_PROFILE(GetUIBatches);
  347. uiRendered_ = false;
  348. // If the OS cursor is visible, do not render the UI's own cursor
  349. bool osCursorVisible = GetSubsystem<Input>()->IsMouseVisible();
  350. // Get rendering batches from the non-modal UI elements
  351. batches_.Clear();
  352. vertexData_.Clear();
  353. const IntVector2& rootSize = rootElement_->GetSize();
  354. // Note: the scissors operate on unscaled coordinates. Scissor scaling is only performed during render
  355. IntRect currentScissor = IntRect(0, 0, rootSize.x_, rootSize.y_);
  356. if (rootElement_->IsVisible())
  357. GetBatches(rootElement_, currentScissor);
  358. // Save the batch size of the non-modal batches for later use
  359. nonModalBatchSize_ = batches_.Size();
  360. // Get rendering batches from the modal UI elements
  361. GetBatches(rootModalElement_, currentScissor);
  362. // Get batches from the cursor (and its possible children) last to draw it on top of everything
  363. if (cursor_ && cursor_->IsVisible() && !osCursorVisible)
  364. {
  365. currentScissor = IntRect(0, 0, rootSize.x_, rootSize.y_);
  366. cursor_->GetBatches(batches_, vertexData_, currentScissor);
  367. GetBatches(cursor_, currentScissor);
  368. }
  369. }
  370. void UI::Render(bool resetRenderTargets)
  371. {
  372. // Perform the default render only if not rendered yet
  373. if (resetRenderTargets && uiRendered_)
  374. return;
  375. URHO3D_PROFILE(RenderUI);
  376. // If the OS cursor is visible, apply its shape now if changed
  377. bool osCursorVisible = GetSubsystem<Input>()->IsMouseVisible();
  378. if (cursor_ && osCursorVisible)
  379. cursor_->ApplyOSCursorShape();
  380. SetVertexData(vertexBuffer_, vertexData_);
  381. SetVertexData(debugVertexBuffer_, debugVertexData_);
  382. // Render non-modal batches
  383. Render(resetRenderTargets, vertexBuffer_, batches_, 0, nonModalBatchSize_);
  384. // Render debug draw
  385. Render(resetRenderTargets, debugVertexBuffer_, debugDrawBatches_, 0, debugDrawBatches_.Size());
  386. // Render modal batches
  387. Render(resetRenderTargets, vertexBuffer_, batches_, nonModalBatchSize_, batches_.Size());
  388. // Clear the debug draw batches and data
  389. debugDrawBatches_.Clear();
  390. debugVertexData_.Clear();
  391. uiRendered_ = true;
  392. }
  393. void UI::DebugDraw(UIElement* element)
  394. {
  395. if (element)
  396. {
  397. const IntVector2& rootSize = rootElement_->GetSize();
  398. element->GetDebugDrawBatches(debugDrawBatches_, debugVertexData_, IntRect(0, 0, rootSize.x_, rootSize.y_));
  399. }
  400. }
  401. SharedPtr<UIElement> UI::LoadLayout(Deserializer& source, XMLFile* styleFile)
  402. {
  403. SharedPtr<XMLFile> xml(new XMLFile(context_));
  404. if (!xml->Load(source))
  405. return SharedPtr<UIElement>();
  406. else
  407. return LoadLayout(xml, styleFile);
  408. }
  409. SharedPtr<UIElement> UI::LoadLayout(XMLFile* file, XMLFile* styleFile)
  410. {
  411. URHO3D_PROFILE(LoadUILayout);
  412. SharedPtr<UIElement> root;
  413. if (!file)
  414. {
  415. URHO3D_LOGERROR("Null UI layout XML file");
  416. return root;
  417. }
  418. URHO3D_LOGDEBUG("Loading UI layout " + file->GetName());
  419. XMLElement rootElem = file->GetRoot("element");
  420. if (!rootElem)
  421. {
  422. URHO3D_LOGERROR("No root UI element in " + file->GetName());
  423. return root;
  424. }
  425. String typeName = rootElem.GetAttribute("type");
  426. if (typeName.Empty())
  427. typeName = "UIElement";
  428. root = DynamicCast<UIElement>(context_->CreateObject(typeName));
  429. if (!root)
  430. {
  431. URHO3D_LOGERROR("Could not create unknown UI element " + typeName);
  432. return root;
  433. }
  434. // Use default style file of the root element if it has one
  435. if (!styleFile)
  436. styleFile = rootElement_->GetDefaultStyle(false);
  437. // Set it as default for later use by children elements
  438. if (styleFile)
  439. root->SetDefaultStyle(styleFile);
  440. root->LoadXML(rootElem, styleFile);
  441. return root;
  442. }
  443. bool UI::SaveLayout(Serializer& dest, UIElement* element)
  444. {
  445. URHO3D_PROFILE(SaveUILayout);
  446. return element && element->SaveXML(dest);
  447. }
  448. void UI::SetClipboardText(const String& text)
  449. {
  450. clipBoard_ = text;
  451. if (useSystemClipboard_)
  452. SDL_SetClipboardText(text.CString());
  453. }
  454. void UI::SetDoubleClickInterval(float interval)
  455. {
  456. doubleClickInterval_ = Max(interval, 0.0f);
  457. }
  458. void UI::SetDragBeginInterval(float interval)
  459. {
  460. dragBeginInterval_ = Max(interval, 0.0f);
  461. }
  462. void UI::SetDragBeginDistance(int pixels)
  463. {
  464. dragBeginDistance_ = Max(pixels, 0);
  465. }
  466. void UI::SetDefaultToolTipDelay(float delay)
  467. {
  468. defaultToolTipDelay_ = Max(delay, 0.0f);
  469. }
  470. void UI::SetMaxFontTextureSize(int size)
  471. {
  472. if (IsPowerOfTwo((unsigned)size) && size >= FONT_TEXTURE_MIN_SIZE)
  473. {
  474. if (size != maxFontTextureSize_)
  475. {
  476. maxFontTextureSize_ = size;
  477. ReleaseFontFaces();
  478. }
  479. }
  480. }
  481. void UI::SetNonFocusedMouseWheel(bool nonFocusedMouseWheel)
  482. {
  483. nonFocusedMouseWheel_ = nonFocusedMouseWheel;
  484. }
  485. void UI::SetUseSystemClipboard(bool enable)
  486. {
  487. useSystemClipboard_ = enable;
  488. }
  489. void UI::SetUseScreenKeyboard(bool enable)
  490. {
  491. useScreenKeyboard_ = enable;
  492. }
  493. void UI::SetUseMutableGlyphs(bool enable)
  494. {
  495. if (enable != useMutableGlyphs_)
  496. {
  497. useMutableGlyphs_ = enable;
  498. ReleaseFontFaces();
  499. }
  500. }
  501. void UI::SetForceAutoHint(bool enable)
  502. {
  503. if (enable != forceAutoHint_)
  504. {
  505. forceAutoHint_ = enable;
  506. ReleaseFontFaces();
  507. }
  508. }
  509. IntVector2 UI::GetCursorPosition() const
  510. {
  511. return cursor_ ? cursor_->GetPosition() : GetSubsystem<Input>()->GetMousePosition();
  512. }
  513. UIElement* UI::GetElementAt(const IntVector2& position, bool enabledOnly)
  514. {
  515. UIElement* result = 0;
  516. GetElementAt(result, HasModalElement() ? rootModalElement_ : rootElement_, position, enabledOnly);
  517. return result;
  518. }
  519. UIElement* UI::GetElementAt(int x, int y, bool enabledOnly)
  520. {
  521. return GetElementAt(IntVector2(x, y), enabledOnly);
  522. }
  523. UIElement* UI::GetFrontElement() const
  524. {
  525. const Vector<SharedPtr<UIElement> >& rootChildren = rootElement_->GetChildren();
  526. int maxPriority = M_MIN_INT;
  527. UIElement* front = 0;
  528. for (unsigned i = 0; i < rootChildren.Size(); ++i)
  529. {
  530. // Do not take into account input-disabled elements, hidden elements or those that are always in the front
  531. if (!rootChildren[i]->IsEnabled() || !rootChildren[i]->IsVisible() || !rootChildren[i]->GetBringToBack())
  532. continue;
  533. int priority = rootChildren[i]->GetPriority();
  534. if (priority > maxPriority)
  535. {
  536. maxPriority = priority;
  537. front = rootChildren[i];
  538. }
  539. }
  540. return front;
  541. }
  542. const Vector<UIElement*> UI::GetDragElements()
  543. {
  544. // Do not return the element until drag begin event has actually been posted
  545. if (!dragElementsConfirmed_.Empty())
  546. return dragElementsConfirmed_;
  547. for (HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i = dragElements_.Begin(); i != dragElements_.End();)
  548. {
  549. WeakPtr<UIElement> dragElement = i->first_;
  550. UI::DragData* dragData = i->second_;
  551. if (!dragElement)
  552. {
  553. i = DragElementErase(i);
  554. continue;
  555. }
  556. if (!dragData->dragBeginPending)
  557. dragElementsConfirmed_.Push(dragElement);
  558. ++i;
  559. }
  560. return dragElementsConfirmed_;
  561. }
  562. UIElement* UI::GetDragElement(unsigned index)
  563. {
  564. GetDragElements();
  565. if (index >= dragElementsConfirmed_.Size())
  566. return (UIElement*)0;
  567. return dragElementsConfirmed_[index];
  568. }
  569. const String& UI::GetClipboardText() const
  570. {
  571. if (useSystemClipboard_)
  572. {
  573. char* text = SDL_GetClipboardText();
  574. clipBoard_ = String(text);
  575. if (text)
  576. SDL_free(text);
  577. }
  578. return clipBoard_;
  579. }
  580. bool UI::HasModalElement() const
  581. {
  582. return rootModalElement_->GetNumChildren() > 0;
  583. }
  584. void UI::Initialize()
  585. {
  586. Graphics* graphics = GetSubsystem<Graphics>();
  587. if (!graphics || !graphics->IsInitialized())
  588. return;
  589. URHO3D_PROFILE(InitUI);
  590. graphics_ = graphics;
  591. UIBatch::posAdjust = Vector3(Graphics::GetPixelUVOffset(), 0.0f);
  592. // Apply initial UI scale to set the root elements size
  593. SetScale(uiScale_);
  594. vertexBuffer_ = new VertexBuffer(context_);
  595. debugVertexBuffer_ = new VertexBuffer(context_);
  596. initialized_ = true;
  597. SubscribeToEvent(E_BEGINFRAME, URHO3D_HANDLER(UI, HandleBeginFrame));
  598. SubscribeToEvent(E_POSTUPDATE, URHO3D_HANDLER(UI, HandlePostUpdate));
  599. SubscribeToEvent(E_RENDERUPDATE, URHO3D_HANDLER(UI, HandleRenderUpdate));
  600. URHO3D_LOGINFO("Initialized user interface");
  601. }
  602. void UI::Update(float timeStep, UIElement* element)
  603. {
  604. // Keep a weak pointer to the element in case it destroys itself on update
  605. WeakPtr<UIElement> elementWeak(element);
  606. element->Update(timeStep);
  607. if (elementWeak.Expired())
  608. return;
  609. const Vector<SharedPtr<UIElement> >& children = element->GetChildren();
  610. // Update of an element may modify its child vector. Use just index-based iteration to be safe
  611. for (unsigned i = 0; i < children.Size(); ++i)
  612. Update(timeStep, children[i]);
  613. }
  614. void UI::SetVertexData(VertexBuffer* dest, const PODVector<float>& vertexData)
  615. {
  616. if (vertexData.Empty())
  617. return;
  618. // Update quad geometry into the vertex buffer
  619. // Resize the vertex buffer first if too small or much too large
  620. unsigned numVertices = vertexData.Size() / UI_VERTEX_SIZE;
  621. if (dest->GetVertexCount() < numVertices || dest->GetVertexCount() > numVertices * 2)
  622. dest->SetSize(numVertices, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true);
  623. dest->SetData(&vertexData[0]);
  624. }
  625. void UI::Render(bool resetRenderTargets, VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigned batchStart,
  626. unsigned batchEnd)
  627. {
  628. // Engine does not render when window is closed or device is lost
  629. assert(graphics_ && graphics_->IsInitialized() && !graphics_->IsDeviceLost());
  630. if (batches.Empty())
  631. return;
  632. Vector2 invScreenSize(1.0f / (float)graphics_->GetWidth(), 1.0f / (float)graphics_->GetHeight());
  633. Vector2 scale(2.0f * invScreenSize.x_, -2.0f * invScreenSize.y_);
  634. Vector2 offset(-1.0f, 1.0f);
  635. Matrix4 projection(Matrix4::IDENTITY);
  636. projection.m00_ = scale.x_ * uiScale_;
  637. projection.m03_ = offset.x_;
  638. projection.m11_ = scale.y_ * uiScale_;
  639. projection.m13_ = offset.y_;
  640. projection.m22_ = 1.0f;
  641. projection.m23_ = 0.0f;
  642. projection.m33_ = 1.0f;
  643. graphics_->ClearParameterSources();
  644. graphics_->SetColorWrite(true);
  645. graphics_->SetCullMode(CULL_CCW);
  646. graphics_->SetDepthTest(CMP_ALWAYS);
  647. graphics_->SetDepthWrite(false);
  648. graphics_->SetFillMode(FILL_SOLID);
  649. graphics_->SetStencilTest(false);
  650. if (resetRenderTargets)
  651. graphics_->ResetRenderTargets();
  652. graphics_->SetVertexBuffer(buffer);
  653. ShaderVariation* noTextureVS = graphics_->GetShader(VS, "Basic", "VERTEXCOLOR");
  654. ShaderVariation* diffTextureVS = graphics_->GetShader(VS, "Basic", "DIFFMAP VERTEXCOLOR");
  655. ShaderVariation* noTexturePS = graphics_->GetShader(PS, "Basic", "VERTEXCOLOR");
  656. ShaderVariation* diffTexturePS = graphics_->GetShader(PS, "Basic", "DIFFMAP VERTEXCOLOR");
  657. ShaderVariation* diffMaskTexturePS = graphics_->GetShader(PS, "Basic", "DIFFMAP ALPHAMASK VERTEXCOLOR");
  658. ShaderVariation* alphaTexturePS = graphics_->GetShader(PS, "Basic", "ALPHAMAP VERTEXCOLOR");
  659. unsigned alphaFormat = Graphics::GetAlphaFormat();
  660. for (unsigned i = batchStart; i < batchEnd; ++i)
  661. {
  662. const UIBatch& batch = batches[i];
  663. if (batch.vertexStart_ == batch.vertexEnd_)
  664. continue;
  665. ShaderVariation* ps;
  666. ShaderVariation* vs;
  667. if (!batch.texture_)
  668. {
  669. ps = noTexturePS;
  670. vs = noTextureVS;
  671. }
  672. else
  673. {
  674. // If texture contains only an alpha channel, use alpha shader (for fonts)
  675. vs = diffTextureVS;
  676. if (batch.texture_->GetFormat() == alphaFormat)
  677. ps = alphaTexturePS;
  678. else if (batch.blendMode_ != BLEND_ALPHA && batch.blendMode_ != BLEND_ADDALPHA && batch.blendMode_ != BLEND_PREMULALPHA)
  679. ps = diffMaskTexturePS;
  680. else
  681. ps = diffTexturePS;
  682. }
  683. graphics_->SetShaders(vs, ps);
  684. if (graphics_->NeedParameterUpdate(SP_OBJECT, this))
  685. graphics_->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
  686. if (graphics_->NeedParameterUpdate(SP_CAMERA, this))
  687. graphics_->SetShaderParameter(VSP_VIEWPROJ, projection);
  688. if (graphics_->NeedParameterUpdate(SP_MATERIAL, this))
  689. graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
  690. float elapsedTime = GetSubsystem<Time>()->GetElapsedTime();
  691. graphics_->SetShaderParameter(VSP_ELAPSEDTIME, elapsedTime);
  692. graphics_->SetShaderParameter(PSP_ELAPSEDTIME, elapsedTime);
  693. IntRect scissor = batch.scissor_;
  694. scissor.left_ = (int)(scissor.left_ * uiScale_);
  695. scissor.top_ = (int)(scissor.top_ * uiScale_);
  696. scissor.right_ = (int)(scissor.right_ * uiScale_);
  697. scissor.bottom_ = (int)(scissor.bottom_ * uiScale_);
  698. graphics_->SetBlendMode(batch.blendMode_);
  699. graphics_->SetScissorTest(true, scissor);
  700. graphics_->SetTexture(0, batch.texture_);
  701. graphics_->Draw(TRIANGLE_LIST, batch.vertexStart_ / UI_VERTEX_SIZE,
  702. (batch.vertexEnd_ - batch.vertexStart_) / UI_VERTEX_SIZE);
  703. }
  704. }
  705. void UI::GetBatches(UIElement* element, IntRect currentScissor)
  706. {
  707. // Set clipping scissor for child elements. No need to draw if zero size
  708. element->AdjustScissor(currentScissor);
  709. if (currentScissor.left_ == currentScissor.right_ || currentScissor.top_ == currentScissor.bottom_)
  710. return;
  711. element->SortChildren();
  712. const Vector<SharedPtr<UIElement> >& children = element->GetChildren();
  713. if (children.Empty())
  714. return;
  715. // For non-root elements draw all children of same priority before recursing into their children: assumption is that they have
  716. // same renderstate
  717. Vector<SharedPtr<UIElement> >::ConstIterator i = children.Begin();
  718. if (element->GetTraversalMode() == TM_BREADTH_FIRST)
  719. {
  720. Vector<SharedPtr<UIElement> >::ConstIterator j = i;
  721. while (i != children.End())
  722. {
  723. int currentPriority = (*i)->GetPriority();
  724. while (j != children.End() && (*j)->GetPriority() == currentPriority)
  725. {
  726. if ((*j)->IsWithinScissor(currentScissor) && (*j) != cursor_)
  727. (*j)->GetBatches(batches_, vertexData_, currentScissor);
  728. ++j;
  729. }
  730. // Now recurse into the children
  731. while (i != j)
  732. {
  733. if ((*i)->IsVisible() && (*i) != cursor_)
  734. GetBatches(*i, currentScissor);
  735. ++i;
  736. }
  737. }
  738. }
  739. // On the root level draw each element and its children immediately after to avoid artifacts
  740. else
  741. {
  742. while (i != children.End())
  743. {
  744. if ((*i) != cursor_)
  745. {
  746. if ((*i)->IsWithinScissor(currentScissor))
  747. (*i)->GetBatches(batches_, vertexData_, currentScissor);
  748. if ((*i)->IsVisible())
  749. GetBatches(*i, currentScissor);
  750. }
  751. ++i;
  752. }
  753. }
  754. }
  755. void UI::GetElementAt(UIElement*& result, UIElement* current, const IntVector2& position, bool enabledOnly)
  756. {
  757. if (!current)
  758. return;
  759. current->SortChildren();
  760. const Vector<SharedPtr<UIElement> >& children = current->GetChildren();
  761. LayoutMode parentLayoutMode = current->GetLayoutMode();
  762. for (unsigned i = 0; i < children.Size(); ++i)
  763. {
  764. UIElement* element = children[i];
  765. bool hasChildren = element->GetNumChildren() > 0;
  766. if (element != cursor_.Get() && element->IsVisible())
  767. {
  768. if (element->IsInside(position, true))
  769. {
  770. // Store the current result, then recurse into its children. Because children
  771. // are sorted from lowest to highest priority, the topmost match should remain
  772. if (element->IsEnabled() || !enabledOnly)
  773. result = element;
  774. if (hasChildren)
  775. GetElementAt(result, element, position, enabledOnly);
  776. // Layout optimization: if the element has no children, can break out after the first match
  777. else if (parentLayoutMode != LM_FREE)
  778. break;
  779. }
  780. else
  781. {
  782. if (hasChildren)
  783. {
  784. if (element->IsInsideCombined(position, true))
  785. GetElementAt(result, element, position, enabledOnly);
  786. }
  787. // Layout optimization: if position is much beyond the visible screen, check how many elements we can skip,
  788. // or if we already passed all visible elements
  789. else if (parentLayoutMode != LM_FREE)
  790. {
  791. if (!i)
  792. {
  793. int screenPos = (parentLayoutMode == LM_HORIZONTAL) ? element->GetScreenPosition().x_ :
  794. element->GetScreenPosition().y_;
  795. int layoutMaxSize = current->GetLayoutElementMaxSize();
  796. if (screenPos < 0 && layoutMaxSize > 0)
  797. {
  798. unsigned toSkip = (unsigned)(-screenPos / layoutMaxSize);
  799. if (toSkip > 0)
  800. i += (toSkip - 1);
  801. }
  802. }
  803. else if (parentLayoutMode == LM_HORIZONTAL)
  804. {
  805. if (element->GetScreenPosition().x_ >= rootElement_->GetSize().x_)
  806. break;
  807. }
  808. else if (parentLayoutMode == LM_VERTICAL)
  809. {
  810. if (element->GetScreenPosition().y_ >= rootElement_->GetSize().y_)
  811. break;
  812. }
  813. }
  814. }
  815. }
  816. }
  817. }
  818. UIElement* UI::GetFocusableElement(UIElement* element)
  819. {
  820. while (element)
  821. {
  822. if (element->GetFocusMode() != FM_NOTFOCUSABLE)
  823. break;
  824. element = element->GetParent();
  825. }
  826. return element;
  827. }
  828. void UI::GetCursorPositionAndVisible(IntVector2& pos, bool& visible)
  829. {
  830. // Prefer software cursor then OS-specific cursor
  831. if (cursor_ && cursor_->IsVisible())
  832. {
  833. pos = cursor_->GetPosition();
  834. visible = true;
  835. }
  836. else if (GetSubsystem<Input>()->GetMouseMode() == MM_RELATIVE)
  837. visible = true;
  838. else
  839. {
  840. Input* input = GetSubsystem<Input>();
  841. pos = input->GetMousePosition();
  842. visible = input->IsMouseVisible();
  843. if (!visible && cursor_)
  844. pos = cursor_->GetPosition();
  845. }
  846. pos.x_ = (int)(pos.x_ / uiScale_);
  847. pos.y_ = (int)(pos.y_ / uiScale_);
  848. }
  849. void UI::SetCursorShape(CursorShape shape)
  850. {
  851. if (cursor_)
  852. cursor_->SetShape(shape);
  853. }
  854. void UI::ReleaseFontFaces()
  855. {
  856. URHO3D_LOGDEBUG("Reloading font faces");
  857. PODVector<Font*> fonts;
  858. GetSubsystem<ResourceCache>()->GetResources<Font>(fonts);
  859. for (unsigned i = 0; i < fonts.Size(); ++i)
  860. fonts[i]->ReleaseFaces();
  861. }
  862. void UI::ProcessHover(const IntVector2& cursorPos, int buttons, int qualifiers, Cursor* cursor)
  863. {
  864. WeakPtr<UIElement> element(GetElementAt(cursorPos));
  865. for (HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i = dragElements_.Begin(); i != dragElements_.End();)
  866. {
  867. WeakPtr<UIElement> dragElement = i->first_;
  868. UI::DragData* dragData = i->second_;
  869. if (!dragElement)
  870. {
  871. i = DragElementErase(i);
  872. continue;
  873. }
  874. bool dragSource = dragElement && (dragElement->GetDragDropMode() & DD_SOURCE) != 0;
  875. bool dragTarget = element && (element->GetDragDropMode() & DD_TARGET) != 0;
  876. bool dragDropTest = dragSource && dragTarget && element != dragElement;
  877. // If drag start event has not been posted yet, do not do drag handling here
  878. if (dragData->dragBeginPending)
  879. dragSource = dragTarget = dragDropTest = false;
  880. // Hover effect
  881. // If a drag is going on, transmit hover only to the element being dragged, unless it's a drop target
  882. if (element && element->IsEnabled())
  883. {
  884. if (dragElement == element || dragDropTest)
  885. {
  886. element->OnHover(element->ScreenToElement(cursorPos), cursorPos, buttons, qualifiers, cursor);
  887. // Begin hover event
  888. if (!hoveredElements_.Contains(element))
  889. {
  890. SendDragOrHoverEvent(E_HOVERBEGIN, element, cursorPos, IntVector2::ZERO, 0);
  891. // Exit if element is destroyed by the event handling
  892. if (!element)
  893. return;
  894. }
  895. hoveredElements_[element] = true;
  896. }
  897. }
  898. // Drag and drop test
  899. if (dragDropTest)
  900. {
  901. bool accept = element->OnDragDropTest(dragElement);
  902. if (accept)
  903. {
  904. using namespace DragDropTest;
  905. VariantMap& eventData = GetEventDataMap();
  906. eventData[P_SOURCE] = dragElement.Get();
  907. eventData[P_TARGET] = element.Get();
  908. eventData[P_ACCEPT] = accept;
  909. SendEvent(E_DRAGDROPTEST, eventData);
  910. accept = eventData[P_ACCEPT].GetBool();
  911. }
  912. if (cursor)
  913. cursor->SetShape(accept ? CS_ACCEPTDROP : CS_REJECTDROP);
  914. }
  915. else if (dragSource && cursor)
  916. cursor->SetShape(dragElement == element ? CS_ACCEPTDROP : CS_REJECTDROP);
  917. ++i;
  918. }
  919. // Hover effect
  920. // If no drag is going on, transmit hover event.
  921. if (element && element->IsEnabled())
  922. {
  923. if (dragElementsCount_ == 0)
  924. {
  925. element->OnHover(element->ScreenToElement(cursorPos), cursorPos, buttons, qualifiers, cursor);
  926. // Begin hover event
  927. if (!hoveredElements_.Contains(element))
  928. {
  929. SendDragOrHoverEvent(E_HOVERBEGIN, element, cursorPos, IntVector2::ZERO, 0);
  930. // Exit if element is destroyed by the event handling
  931. if (!element)
  932. return;
  933. }
  934. hoveredElements_[element] = true;
  935. }
  936. }
  937. }
  938. void UI::ProcessClickBegin(const IntVector2& cursorPos, int button, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible)
  939. {
  940. if (cursorVisible)
  941. {
  942. WeakPtr<UIElement> element(GetElementAt(cursorPos));
  943. bool newButton;
  944. if (usingTouchInput_)
  945. newButton = (button & buttons) == 0;
  946. else
  947. newButton = true;
  948. buttons |= button;
  949. if (element)
  950. SetFocusElement(element);
  951. // Focus change events may destroy the element, check again.
  952. if (element)
  953. {
  954. // Handle focusing & bringing to front
  955. element->BringToFront();
  956. // Handle click
  957. element->OnClickBegin(element->ScreenToElement(cursorPos), cursorPos, button, buttons, qualifiers, cursor);
  958. SendClickEvent(E_UIMOUSECLICK, NULL, element, cursorPos, button, buttons, qualifiers);
  959. // Fire double click event if element matches and is in time
  960. if (doubleClickElement_ && element == doubleClickElement_ &&
  961. clickTimer_.GetMSec(true) < (unsigned)(doubleClickInterval_ * 1000) && lastMouseButtons_ == buttons)
  962. {
  963. element->OnDoubleClick(element->ScreenToElement(cursorPos), cursorPos, button, buttons, qualifiers, cursor);
  964. doubleClickElement_.Reset();
  965. SendClickEvent(E_UIMOUSEDOUBLECLICK, NULL, element, cursorPos, button, buttons, qualifiers);
  966. }
  967. else
  968. {
  969. doubleClickElement_ = element;
  970. clickTimer_.Reset();
  971. }
  972. // Handle start of drag. Click handling may have caused destruction of the element, so check the pointer again
  973. bool dragElementsContain = dragElements_.Contains(element);
  974. if (element && !dragElementsContain)
  975. {
  976. DragData* dragData = new DragData();
  977. dragElements_[element] = dragData;
  978. dragData->dragBeginPending = true;
  979. dragData->sumPos = cursorPos;
  980. dragData->dragBeginSumPos = cursorPos;
  981. dragData->dragBeginTimer.Reset();
  982. dragData->dragButtons = button;
  983. dragData->numDragButtons = CountSetBits((unsigned)dragData->dragButtons);
  984. dragElementsCount_++;
  985. dragElementsContain = dragElements_.Contains(element);
  986. }
  987. else if (element && dragElementsContain && newButton)
  988. {
  989. DragData* dragData = dragElements_[element];
  990. dragData->sumPos += cursorPos;
  991. dragData->dragBeginSumPos += cursorPos;
  992. dragData->dragButtons |= button;
  993. dragData->numDragButtons = CountSetBits((unsigned)dragData->dragButtons);
  994. }
  995. }
  996. else
  997. {
  998. // If clicked over no element, or a disabled element, lose focus (but not if there is a modal element)
  999. if (!HasModalElement())
  1000. SetFocusElement(0);
  1001. SendClickEvent(E_UIMOUSECLICK, NULL, element, cursorPos, button, buttons, qualifiers);
  1002. if (clickTimer_.GetMSec(true) < (unsigned)(doubleClickInterval_ * 1000) && lastMouseButtons_ == buttons)
  1003. SendClickEvent(E_UIMOUSEDOUBLECLICK, NULL, element, cursorPos, button, buttons, qualifiers);
  1004. }
  1005. lastMouseButtons_ = buttons;
  1006. }
  1007. }
  1008. void UI::ProcessClickEnd(const IntVector2& cursorPos, int button, int buttons, int qualifiers, Cursor* cursor, bool cursorVisible)
  1009. {
  1010. WeakPtr<UIElement> element;
  1011. if (cursorVisible)
  1012. element = GetElementAt(cursorPos);
  1013. // Handle end of drag
  1014. for (HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i = dragElements_.Begin(); i != dragElements_.End();)
  1015. {
  1016. WeakPtr<UIElement> dragElement = i->first_;
  1017. UI::DragData* dragData = i->second_;
  1018. if (!dragElement || !cursorVisible)
  1019. {
  1020. i = DragElementErase(i);
  1021. continue;
  1022. }
  1023. if (dragData->dragButtons & button)
  1024. {
  1025. // Handle end of click
  1026. if (element)
  1027. element->OnClickEnd(element->ScreenToElement(cursorPos), cursorPos, button, buttons, qualifiers, cursor,
  1028. dragElement);
  1029. SendClickEvent(E_UIMOUSECLICKEND, dragElement, element, cursorPos, button, buttons, qualifiers);
  1030. if (dragElement && dragElement->IsEnabled() && dragElement->IsVisible() && !dragData->dragBeginPending)
  1031. {
  1032. dragElement->OnDragEnd(dragElement->ScreenToElement(cursorPos), cursorPos, dragData->dragButtons, buttons,
  1033. cursor);
  1034. SendDragOrHoverEvent(E_DRAGEND, dragElement, cursorPos, IntVector2::ZERO, dragData);
  1035. bool dragSource = dragElement && (dragElement->GetDragDropMode() & DD_SOURCE) != 0;
  1036. if (dragSource)
  1037. {
  1038. bool dragTarget = element && (element->GetDragDropMode() & DD_TARGET) != 0;
  1039. bool dragDropFinish = dragSource && dragTarget && element != dragElement;
  1040. if (dragDropFinish)
  1041. {
  1042. bool accept = element->OnDragDropFinish(dragElement);
  1043. // OnDragDropFinish() may have caused destruction of the elements, so check the pointers again
  1044. if (accept && dragElement && element)
  1045. {
  1046. using namespace DragDropFinish;
  1047. VariantMap& eventData = GetEventDataMap();
  1048. eventData[P_SOURCE] = dragElement.Get();
  1049. eventData[P_TARGET] = element.Get();
  1050. eventData[P_ACCEPT] = accept;
  1051. SendEvent(E_DRAGDROPFINISH, eventData);
  1052. }
  1053. }
  1054. }
  1055. }
  1056. i = DragElementErase(i);
  1057. }
  1058. else
  1059. ++i;
  1060. }
  1061. }
  1062. void UI::ProcessMove(const IntVector2& cursorPos, const IntVector2& cursorDeltaPos, int buttons, int qualifiers, Cursor* cursor,
  1063. bool cursorVisible)
  1064. {
  1065. if (cursorVisible && dragElementsCount_ > 0 && buttons)
  1066. {
  1067. Input* input = GetSubsystem<Input>();
  1068. bool mouseGrabbed = input->IsMouseGrabbed();
  1069. for (HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i = dragElements_.Begin(); i != dragElements_.End();)
  1070. {
  1071. WeakPtr<UIElement> dragElement = i->first_;
  1072. UI::DragData* dragData = i->second_;
  1073. if (!dragElement)
  1074. {
  1075. i = DragElementErase(i);
  1076. continue;
  1077. }
  1078. if (!(dragData->dragButtons & buttons))
  1079. {
  1080. ++i;
  1081. continue;
  1082. }
  1083. // Calculate the position that we should send for this drag event.
  1084. IntVector2 sendPos;
  1085. if (usingTouchInput_)
  1086. {
  1087. dragData->sumPos += cursorDeltaPos;
  1088. sendPos.x_ = dragData->sumPos.x_ / dragData->numDragButtons;
  1089. sendPos.y_ = dragData->sumPos.y_ / dragData->numDragButtons;
  1090. }
  1091. else
  1092. {
  1093. dragData->sumPos = cursorPos;
  1094. sendPos = cursorPos;
  1095. }
  1096. if (dragElement->IsEnabled() && dragElement->IsVisible())
  1097. {
  1098. // Signal drag begin if distance threshold was exceeded
  1099. if (dragData->dragBeginPending && !mouseGrabbed)
  1100. {
  1101. IntVector2 beginSendPos;
  1102. beginSendPos.x_ = dragData->dragBeginSumPos.x_ / dragData->numDragButtons;
  1103. beginSendPos.y_ = dragData->dragBeginSumPos.y_ / dragData->numDragButtons;
  1104. IntVector2 offset = cursorPos - beginSendPos;
  1105. if (Abs(offset.x_) >= dragBeginDistance_ || Abs(offset.y_) >= dragBeginDistance_)
  1106. {
  1107. dragData->dragBeginPending = false;
  1108. dragConfirmedCount_++;
  1109. dragElement->OnDragBegin(dragElement->ScreenToElement(beginSendPos), beginSendPos, buttons, qualifiers,
  1110. cursor);
  1111. SendDragOrHoverEvent(E_DRAGBEGIN, dragElement, beginSendPos, IntVector2::ZERO, dragData);
  1112. }
  1113. }
  1114. if (!dragData->dragBeginPending)
  1115. {
  1116. dragElement->OnDragMove(dragElement->ScreenToElement(sendPos), sendPos, cursorDeltaPos, buttons, qualifiers,
  1117. cursor);
  1118. SendDragOrHoverEvent(E_DRAGMOVE, dragElement, sendPos, cursorDeltaPos, dragData);
  1119. }
  1120. }
  1121. else
  1122. {
  1123. dragElement->OnDragEnd(dragElement->ScreenToElement(sendPos), sendPos, dragData->dragButtons, buttons, cursor);
  1124. SendDragOrHoverEvent(E_DRAGEND, dragElement, sendPos, IntVector2::ZERO, dragData);
  1125. dragElement.Reset();
  1126. }
  1127. ++i;
  1128. }
  1129. }
  1130. }
  1131. void UI::SendDragOrHoverEvent(StringHash eventType, UIElement* element, const IntVector2& screenPos, const IntVector2& deltaPos,
  1132. UI::DragData* dragData)
  1133. {
  1134. if (!element)
  1135. return;
  1136. IntVector2 relativePos = element->ScreenToElement(screenPos);
  1137. using namespace DragMove;
  1138. VariantMap& eventData = GetEventDataMap();
  1139. eventData[P_ELEMENT] = element;
  1140. eventData[P_X] = screenPos.x_;
  1141. eventData[P_Y] = screenPos.y_;
  1142. eventData[P_ELEMENTX] = relativePos.x_;
  1143. eventData[P_ELEMENTY] = relativePos.y_;
  1144. if (eventType == E_DRAGMOVE)
  1145. {
  1146. eventData[P_DX] = deltaPos.x_;
  1147. eventData[P_DY] = deltaPos.y_;
  1148. }
  1149. if (dragData)
  1150. {
  1151. eventData[P_BUTTONS] = dragData->dragButtons;
  1152. eventData[P_NUMBUTTONS] = dragData->numDragButtons;
  1153. }
  1154. element->SendEvent(eventType, eventData);
  1155. }
  1156. void UI::SendClickEvent(StringHash eventType, UIElement* beginElement, UIElement* endElement, const IntVector2& pos, int button,
  1157. int buttons, int qualifiers)
  1158. {
  1159. VariantMap& eventData = GetEventDataMap();
  1160. eventData[UIMouseClick::P_ELEMENT] = endElement;
  1161. eventData[UIMouseClick::P_X] = pos.x_;
  1162. eventData[UIMouseClick::P_Y] = pos.y_;
  1163. eventData[UIMouseClick::P_BUTTON] = button;
  1164. eventData[UIMouseClick::P_BUTTONS] = buttons;
  1165. eventData[UIMouseClick::P_QUALIFIERS] = qualifiers;
  1166. // For click end events, send also the element the click began on
  1167. if (eventType == E_UIMOUSECLICKEND)
  1168. eventData[UIMouseClickEnd::P_BEGINELEMENT] = beginElement;
  1169. if (endElement)
  1170. {
  1171. // Send also element version of the event
  1172. if (eventType == E_UIMOUSECLICK)
  1173. endElement->SendEvent(E_CLICK, eventData);
  1174. else if (eventType == E_UIMOUSECLICKEND)
  1175. endElement->SendEvent(E_CLICKEND, eventData);
  1176. else if (eventType == E_UIMOUSEDOUBLECLICK)
  1177. endElement->SendEvent(E_DOUBLECLICK, eventData);
  1178. }
  1179. // Send the global event from the UI subsystem last
  1180. SendEvent(eventType, eventData);
  1181. }
  1182. void UI::HandleScreenMode(StringHash eventType, VariantMap& eventData)
  1183. {
  1184. using namespace ScreenMode;
  1185. if (!initialized_)
  1186. Initialize();
  1187. else
  1188. {
  1189. // Reapply UI scale to resize the root elements
  1190. SetScale(uiScale_);
  1191. }
  1192. }
  1193. void UI::HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
  1194. {
  1195. using namespace MouseButtonDown;
  1196. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  1197. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  1198. usingTouchInput_ = false;
  1199. IntVector2 cursorPos;
  1200. bool cursorVisible;
  1201. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  1202. // Handle drag cancelling
  1203. ProcessDragCancel();
  1204. Input* input = GetSubsystem<Input>();
  1205. if (!input->IsMouseGrabbed())
  1206. ProcessClickBegin(cursorPos, eventData[P_BUTTON].GetInt(), mouseButtons_, qualifiers_, cursor_, cursorVisible);
  1207. }
  1208. void UI::HandleMouseButtonUp(StringHash eventType, VariantMap& eventData)
  1209. {
  1210. using namespace MouseButtonUp;
  1211. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  1212. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  1213. IntVector2 cursorPos;
  1214. bool cursorVisible;
  1215. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  1216. ProcessClickEnd(cursorPos, eventData[P_BUTTON].GetInt(), mouseButtons_, qualifiers_, cursor_, cursorVisible);
  1217. }
  1218. void UI::HandleMouseMove(StringHash eventType, VariantMap& eventData)
  1219. {
  1220. using namespace MouseMove;
  1221. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  1222. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  1223. usingTouchInput_ = false;
  1224. Input* input = GetSubsystem<Input>();
  1225. const IntVector2& rootSize = rootElement_->GetSize();
  1226. IntVector2 DeltaP = IntVector2(eventData[P_DX].GetInt(), eventData[P_DY].GetInt());
  1227. if (cursor_)
  1228. {
  1229. if (!input->IsMouseVisible())
  1230. {
  1231. if (!input->IsMouseLocked())
  1232. cursor_->SetPosition(IntVector2(eventData[P_X].GetInt(), eventData[P_Y].GetInt()));
  1233. else if (cursor_->IsVisible())
  1234. {
  1235. // Relative mouse motion: move cursor only when visible
  1236. IntVector2 pos = cursor_->GetPosition();
  1237. pos.x_ += eventData[P_DX].GetInt();
  1238. pos.y_ += eventData[P_DY].GetInt();
  1239. pos.x_ = Clamp(pos.x_, 0, rootSize.x_ - 1);
  1240. pos.y_ = Clamp(pos.y_, 0, rootSize.y_ - 1);
  1241. cursor_->SetPosition(pos);
  1242. }
  1243. }
  1244. else
  1245. {
  1246. // Absolute mouse motion: move always
  1247. cursor_->SetPosition(IntVector2(eventData[P_X].GetInt(), eventData[P_Y].GetInt()));
  1248. }
  1249. }
  1250. IntVector2 cursorPos;
  1251. bool cursorVisible;
  1252. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  1253. ProcessMove(cursorPos, DeltaP, mouseButtons_, qualifiers_, cursor_, cursorVisible);
  1254. }
  1255. void UI::HandleMouseWheel(StringHash eventType, VariantMap& eventData)
  1256. {
  1257. Input* input = GetSubsystem<Input>();
  1258. if (input->IsMouseGrabbed())
  1259. return;
  1260. using namespace MouseWheel;
  1261. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  1262. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  1263. int delta = eventData[P_WHEEL].GetInt();
  1264. usingTouchInput_ = false;
  1265. IntVector2 cursorPos;
  1266. bool cursorVisible;
  1267. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  1268. UIElement* element;
  1269. if (!nonFocusedMouseWheel_ && (element = focusElement_))
  1270. element->OnWheel(delta, mouseButtons_, qualifiers_);
  1271. else
  1272. {
  1273. // If no element has actual focus or in non-focused mode, get the element at cursor
  1274. if (cursorVisible)
  1275. {
  1276. element = GetElementAt(cursorPos);
  1277. if (nonFocusedMouseWheel_)
  1278. {
  1279. // Going up the hierarchy chain to find element that could handle mouse wheel
  1280. while (element)
  1281. {
  1282. if (element->GetType() == ListView::GetTypeStatic() ||
  1283. element->GetType() == ScrollView::GetTypeStatic())
  1284. break;
  1285. element = element->GetParent();
  1286. }
  1287. }
  1288. else
  1289. // If the element itself is not focusable, search for a focusable parent,
  1290. // although the focusable element may not actually handle mouse wheel
  1291. element = GetFocusableElement(element);
  1292. if (element && (nonFocusedMouseWheel_ || element->GetFocusMode() >= FM_FOCUSABLE))
  1293. element->OnWheel(delta, mouseButtons_, qualifiers_);
  1294. }
  1295. }
  1296. }
  1297. void UI::HandleTouchBegin(StringHash eventType, VariantMap& eventData)
  1298. {
  1299. Input* input = GetSubsystem<Input>();
  1300. if (input->IsMouseGrabbed())
  1301. return;
  1302. using namespace TouchBegin;
  1303. IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
  1304. pos.x_ = int(pos.x_ / uiScale_);
  1305. pos.y_ = int(pos.y_ / uiScale_);
  1306. usingTouchInput_ = true;
  1307. int touchId = TOUCHID_MASK(eventData[P_TOUCHID].GetInt());
  1308. WeakPtr<UIElement> element(GetElementAt(pos));
  1309. if (element)
  1310. {
  1311. ProcessClickBegin(pos, touchId, touchDragElements_[element], 0, 0, true);
  1312. touchDragElements_[element] |= touchId;
  1313. }
  1314. else
  1315. ProcessClickBegin(pos, touchId, touchId, 0, 0, true);
  1316. }
  1317. void UI::HandleTouchEnd(StringHash eventType, VariantMap& eventData)
  1318. {
  1319. using namespace TouchEnd;
  1320. IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
  1321. pos.x_ = int(pos.x_ / uiScale_);
  1322. pos.y_ = int(pos.y_ / uiScale_);
  1323. // Get the touch index
  1324. int touchId = TOUCHID_MASK(eventData[P_TOUCHID].GetInt());
  1325. // Transmit hover end to the position where the finger was lifted
  1326. WeakPtr<UIElement> element(GetElementAt(pos));
  1327. // Clear any drag events that were using the touch id
  1328. for (HashMap<WeakPtr<UIElement>, int>::Iterator i = touchDragElements_.Begin(); i != touchDragElements_.End();)
  1329. {
  1330. int touches = i->second_;
  1331. if (touches & touchId)
  1332. i = touchDragElements_.Erase(i);
  1333. else
  1334. ++i;
  1335. }
  1336. if (element && element->IsEnabled())
  1337. element->OnHover(element->ScreenToElement(pos), pos, 0, 0, 0);
  1338. ProcessClickEnd(pos, touchId, 0, 0, 0, true);
  1339. }
  1340. void UI::HandleTouchMove(StringHash eventType, VariantMap& eventData)
  1341. {
  1342. using namespace TouchMove;
  1343. IntVector2 pos(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
  1344. IntVector2 deltaPos(eventData[P_DX].GetInt(), eventData[P_DY].GetInt());
  1345. pos.x_ = int(pos.x_ / uiScale_);
  1346. pos.y_ = int(pos.y_ / uiScale_);
  1347. deltaPos.x_ = int(deltaPos.x_ / uiScale_);
  1348. deltaPos.y_ = int(deltaPos.y_ / uiScale_);
  1349. usingTouchInput_ = true;
  1350. int touchId = TOUCHID_MASK(eventData[P_TOUCHID].GetInt());
  1351. ProcessMove(pos, deltaPos, touchId, 0, 0, true);
  1352. }
  1353. void UI::HandleKeyDown(StringHash eventType, VariantMap& eventData)
  1354. {
  1355. using namespace KeyDown;
  1356. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  1357. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  1358. int key = eventData[P_KEY].GetInt();
  1359. // Cancel UI dragging
  1360. if (key == KEY_ESCAPE && dragElementsCount_ > 0)
  1361. {
  1362. ProcessDragCancel();
  1363. return;
  1364. }
  1365. // Dismiss modal element if any when ESC key is pressed
  1366. if (key == KEY_ESCAPE && HasModalElement())
  1367. {
  1368. UIElement* element = rootModalElement_->GetChild(rootModalElement_->GetNumChildren() - 1);
  1369. if (element->GetVars().Contains(VAR_ORIGIN))
  1370. // If it is a popup, dismiss by defocusing it
  1371. SetFocusElement(0);
  1372. else
  1373. {
  1374. // If it is a modal window, by resetting its modal flag
  1375. Window* window = dynamic_cast<Window*>(element);
  1376. if (window && window->GetModalAutoDismiss())
  1377. window->SetModal(false);
  1378. }
  1379. return;
  1380. }
  1381. UIElement* element = focusElement_;
  1382. if (element)
  1383. {
  1384. // Switch focus between focusable elements in the same top level window
  1385. if (key == KEY_TAB)
  1386. {
  1387. UIElement* topLevel = element->GetParent();
  1388. while (topLevel && topLevel->GetParent() != rootElement_ && topLevel->GetParent() != rootModalElement_)
  1389. topLevel = topLevel->GetParent();
  1390. if (topLevel)
  1391. {
  1392. topLevel->GetChildren(tempElements_, true);
  1393. for (PODVector<UIElement*>::Iterator i = tempElements_.Begin(); i != tempElements_.End();)
  1394. {
  1395. if ((*i)->GetFocusMode() < FM_FOCUSABLE)
  1396. i = tempElements_.Erase(i);
  1397. else
  1398. ++i;
  1399. }
  1400. for (unsigned i = 0; i < tempElements_.Size(); ++i)
  1401. {
  1402. if (tempElements_[i] == element)
  1403. {
  1404. int dir = (qualifiers_ & QUAL_SHIFT) ? -1 : 1;
  1405. unsigned nextIndex = (tempElements_.Size() + i + dir) % tempElements_.Size();
  1406. UIElement* next = tempElements_[nextIndex];
  1407. SetFocusElement(next, true);
  1408. return;
  1409. }
  1410. }
  1411. }
  1412. }
  1413. // Defocus the element
  1414. else if (key == KEY_ESCAPE && element->GetFocusMode() == FM_FOCUSABLE_DEFOCUSABLE)
  1415. element->SetFocus(false);
  1416. // If none of the special keys, pass the key to the focused element
  1417. else
  1418. element->OnKey(key, mouseButtons_, qualifiers_);
  1419. }
  1420. }
  1421. void UI::HandleTextInput(StringHash eventType, VariantMap& eventData)
  1422. {
  1423. using namespace TextInput;
  1424. mouseButtons_ = eventData[P_BUTTONS].GetInt();
  1425. qualifiers_ = eventData[P_QUALIFIERS].GetInt();
  1426. UIElement* element = focusElement_;
  1427. if (element)
  1428. element->OnTextInput(eventData[P_TEXT].GetString(), mouseButtons_, qualifiers_);
  1429. }
  1430. void UI::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
  1431. {
  1432. // If have a cursor, and a drag is not going on, reset the cursor shape. Application logic that wants to apply
  1433. // custom shapes can do it after this, but needs to do it each frame
  1434. if (cursor_ && dragElementsCount_ == 0)
  1435. cursor_->SetShape(CS_NORMAL);
  1436. }
  1437. void UI::HandlePostUpdate(StringHash eventType, VariantMap& eventData)
  1438. {
  1439. using namespace PostUpdate;
  1440. Update(eventData[P_TIMESTEP].GetFloat());
  1441. }
  1442. void UI::HandleRenderUpdate(StringHash eventType, VariantMap& eventData)
  1443. {
  1444. RenderUpdate();
  1445. }
  1446. void UI::HandleDropFile(StringHash eventType, VariantMap& eventData)
  1447. {
  1448. Input* input = GetSubsystem<Input>();
  1449. // Sending the UI variant of the event only makes sense if the OS cursor is visible (not locked to window center)
  1450. if (input->IsMouseVisible())
  1451. {
  1452. IntVector2 screenPos = input->GetMousePosition();
  1453. screenPos.x_ = int(screenPos.x_ / uiScale_);
  1454. screenPos.y_ = int(screenPos.y_ / uiScale_);
  1455. UIElement* element = GetElementAt(screenPos);
  1456. using namespace UIDropFile;
  1457. VariantMap uiEventData;
  1458. uiEventData[P_FILENAME] = eventData[P_FILENAME];
  1459. uiEventData[P_X] = screenPos.x_;
  1460. uiEventData[P_Y] = screenPos.y_;
  1461. uiEventData[P_ELEMENT] = element;
  1462. if (element)
  1463. {
  1464. IntVector2 relativePos = element->ScreenToElement(screenPos);
  1465. uiEventData[P_ELEMENTX] = relativePos.x_;
  1466. uiEventData[P_ELEMENTY] = relativePos.y_;
  1467. }
  1468. SendEvent(E_UIDROPFILE, uiEventData);
  1469. }
  1470. }
  1471. HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator UI::DragElementErase(HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i)
  1472. {
  1473. // If running the engine frame in response to an event (re-entering UI frame logic) the dragElements_ may already be empty
  1474. if (dragElements_.Empty())
  1475. return dragElements_.End();
  1476. dragElementsConfirmed_.Clear();
  1477. DragData* dragData = i->second_;
  1478. if (!dragData->dragBeginPending)
  1479. --dragConfirmedCount_;
  1480. i = dragElements_.Erase(i);
  1481. --dragElementsCount_;
  1482. delete dragData;
  1483. return i;
  1484. }
  1485. void UI::ProcessDragCancel()
  1486. {
  1487. // How to tell difference between drag cancel and new selection on multi-touch?
  1488. if (usingTouchInput_)
  1489. return;
  1490. IntVector2 cursorPos;
  1491. bool cursorVisible;
  1492. GetCursorPositionAndVisible(cursorPos, cursorVisible);
  1493. for (HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i = dragElements_.Begin(); i != dragElements_.End();)
  1494. {
  1495. WeakPtr<UIElement> dragElement = i->first_;
  1496. UI::DragData* dragData = i->second_;
  1497. if (dragElement && dragElement->IsEnabled() && dragElement->IsVisible() && !dragData->dragBeginPending)
  1498. {
  1499. dragElement->OnDragCancel(dragElement->ScreenToElement(cursorPos), cursorPos, dragData->dragButtons, mouseButtons_,
  1500. cursor_);
  1501. SendDragOrHoverEvent(E_DRAGCANCEL, dragElement, cursorPos, IntVector2::ZERO, dragData);
  1502. i = DragElementErase(i);
  1503. }
  1504. else
  1505. ++i;
  1506. }
  1507. }
  1508. IntVector2 UI::SumTouchPositions(UI::DragData* dragData, const IntVector2& oldSendPos)
  1509. {
  1510. IntVector2 sendPos = oldSendPos;
  1511. if (usingTouchInput_)
  1512. {
  1513. int buttons = dragData->dragButtons;
  1514. dragData->sumPos = IntVector2::ZERO;
  1515. Input* input = GetSubsystem<Input>();
  1516. for (int i = 0; (1 << i) <= buttons; i++)
  1517. {
  1518. if ((1 << i) & buttons)
  1519. {
  1520. TouchState* ts = input->GetTouch((unsigned)i);
  1521. if (!ts)
  1522. break;
  1523. IntVector2 pos = ts->position_;
  1524. dragData->sumPos.x_ += (int)(pos.x_ / uiScale_);
  1525. dragData->sumPos.y_ += (int)(pos.y_ / uiScale_);
  1526. }
  1527. }
  1528. sendPos.x_ = dragData->sumPos.x_ / dragData->numDragButtons;
  1529. sendPos.y_ = dragData->sumPos.y_ / dragData->numDragButtons;
  1530. }
  1531. return sendPos;
  1532. }
  1533. void UI::SetScale(float scale)
  1534. {
  1535. uiScale_ = Max(scale, M_EPSILON);
  1536. Graphics* graphics = GetSubsystem<Graphics>();
  1537. if (graphics)
  1538. {
  1539. rootElement_->SetSize((int)((float)graphics->GetWidth() / uiScale_ + 0.5f), (int)((float)graphics_->GetHeight() /
  1540. uiScale_ + 0.5));
  1541. rootModalElement_->SetSize(rootElement_->GetSize());
  1542. }
  1543. }
  1544. void UI::SetWidth(float size)
  1545. {
  1546. Graphics* graphics = GetSubsystem<Graphics>();
  1547. if (graphics)
  1548. SetScale((float)graphics->GetWidth() / size);
  1549. }
  1550. void UI::SetHeight(float size)
  1551. {
  1552. Graphics* graphics = GetSubsystem<Graphics>();
  1553. if (graphics)
  1554. SetScale((float)graphics->GetHeight() / size);
  1555. }
  1556. void RegisterUILibrary(Context* context)
  1557. {
  1558. Font::RegisterObject(context);
  1559. UIElement::RegisterObject(context);
  1560. BorderImage::RegisterObject(context);
  1561. Sprite::RegisterObject(context);
  1562. Button::RegisterObject(context);
  1563. CheckBox::RegisterObject(context);
  1564. Cursor::RegisterObject(context);
  1565. Text::RegisterObject(context);
  1566. Text3D::RegisterObject(context);
  1567. Window::RegisterObject(context);
  1568. View3D::RegisterObject(context);
  1569. LineEdit::RegisterObject(context);
  1570. Slider::RegisterObject(context);
  1571. ScrollBar::RegisterObject(context);
  1572. ScrollView::RegisterObject(context);
  1573. ListView::RegisterObject(context);
  1574. Menu::RegisterObject(context);
  1575. DropDownList::RegisterObject(context);
  1576. FileSelector::RegisterObject(context);
  1577. MessageBox::RegisterObject(context);
  1578. ToolTip::RegisterObject(context);
  1579. }
  1580. }