ListView.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "BorderImage.h"
  25. #include "Context.h"
  26. #include "InputEvents.h"
  27. #include "ListView.h"
  28. #include "Log.h"
  29. #include "StringUtils.h"
  30. #include "UIEvents.h"
  31. #include "DebugNew.h"
  32. static const ShortStringHash indentHash("Indent");
  33. static const std::string highlightModes[] =
  34. {
  35. "never",
  36. "focus",
  37. "always"
  38. };
  39. int GetItemIndent(UIElement* item)
  40. {
  41. if (!item)
  42. return 0;
  43. return item->vars_[indentHash].GetInt();
  44. }
  45. OBJECTTYPESTATIC(ListView);
  46. ListView::ListView(Context* context) :
  47. ScrollView(context),
  48. highlightMode_(HM_FOCUS),
  49. multiselect_(false),
  50. hierarchyMode_(false),
  51. clearSelectionOnDefocus_(false),
  52. doubleClickInterval_(0.5f),
  53. doubleClickTimer_(0.0f),
  54. lastClickedItem_(M_MAX_UNSIGNED)
  55. {
  56. UIElement* container = new UIElement(context_);
  57. container->SetActive(true);
  58. container->SetLayout(LM_VERTICAL);
  59. SetContentElement(container);
  60. SubscribeToEvent(E_UIMOUSECLICK, HANDLER(ListView, HandleUIMouseClick));
  61. }
  62. ListView::~ListView()
  63. {
  64. }
  65. void ListView::RegisterObject(Context* context)
  66. {
  67. context->RegisterFactory<ListView>();
  68. }
  69. void ListView::SetStyle(const XMLElement& element)
  70. {
  71. ScrollView::SetStyle(element);
  72. UIElement* root = GetRootElement();
  73. XMLElement itemElem = element.GetChildElement("listitem");
  74. if (root)
  75. {
  76. while (itemElem)
  77. {
  78. if (itemElem.HasAttribute("name"))
  79. {
  80. UIElement* item = root->GetChild(itemElem.GetString("name"), true);
  81. AddItem(item);
  82. if (itemElem.HasAttribute("indent"))
  83. item->vars_[indentHash] = itemElem.GetInt("indent");
  84. itemElem = itemElem.GetNextElement("listitem");
  85. }
  86. }
  87. }
  88. if (element.HasChildElement("highlight"))
  89. {
  90. std::string highlight = element.GetChildElement("highlight").GetStringLower("value");
  91. SetHighlightMode((HighlightMode)GetStringListIndex(highlight, highlightModes, 3, 1));
  92. }
  93. if (element.HasChildElement("multiselect"))
  94. SetMultiselect(element.GetChildElement("multiselect").GetBool("enable"));
  95. if (element.HasChildElement("hierarchy"))
  96. SetHierarchyMode(element.GetChildElement("hierarchy").GetBool("enable"));
  97. if (element.HasChildElement("clearselection"))
  98. SetClearSelectionOnDefocus(element.GetChildElement("clearselection").GetBool("enable"));
  99. if (element.HasChildElement("doubleclickinterval"))
  100. SetDoubleClickInterval(element.GetChildElement("doubleclickinterval").GetFloat("value"));
  101. XMLElement selectionElem = element.GetChildElement("selection");
  102. while (selectionElem)
  103. {
  104. AddSelection(selectionElem.GetInt("value"));
  105. selectionElem = selectionElem.GetNextElement("selection");
  106. }
  107. }
  108. void ListView::Update(float timeStep)
  109. {
  110. if (doubleClickTimer_ > 0.0f)
  111. doubleClickTimer_ = Max(doubleClickTimer_ - timeStep, 0.0f);
  112. }
  113. void ListView::OnKey(int key, int buttons, int qualifiers)
  114. {
  115. // If no selection, can not move with keys
  116. unsigned numItems = GetNumItems();
  117. unsigned selection = GetSelection();
  118. if ((selection != M_MAX_UNSIGNED) && (numItems))
  119. {
  120. // If either shift or ctrl held down, add to selection if multiselect enabled
  121. bool additive = (multiselect_) && (qualifiers != 0);
  122. switch (key)
  123. {
  124. case KEY_LEFT:
  125. if (hierarchyMode_)
  126. {
  127. SetChildItemsVisible(selection, false);
  128. return;
  129. }
  130. break;
  131. case KEY_RIGHT:
  132. if (hierarchyMode_)
  133. {
  134. SetChildItemsVisible(selection, true);
  135. return;
  136. }
  137. break;
  138. case KEY_RETURN:
  139. if (hierarchyMode_)
  140. {
  141. ToggleChildItemsVisible(selection);
  142. return;
  143. }
  144. break;
  145. case KEY_UP:
  146. ChangeSelection(-1, additive);
  147. return;
  148. case KEY_DOWN:
  149. ChangeSelection(1, additive);
  150. return;
  151. case KEY_PAGEUP:
  152. {
  153. // Convert page step to pixels and see how many items have to be skipped to reach that many pixels
  154. int stepPixels = ((int)(pageStep_ * scrollPanel_->GetHeight())) - GetSelectedItem()->GetHeight();
  155. unsigned newSelection = selection;
  156. unsigned okSelection = selection;
  157. while (newSelection < numItems)
  158. {
  159. UIElement* item = GetItem(newSelection);
  160. int height = 0;
  161. if (item->IsVisible())
  162. {
  163. height = item->GetHeight();
  164. okSelection = newSelection;
  165. }
  166. if (stepPixels < height)
  167. break;
  168. stepPixels -= height;
  169. --newSelection;
  170. }
  171. if (!additive)
  172. SetSelection(okSelection);
  173. else
  174. AddSelection(okSelection);
  175. }
  176. return;
  177. case KEY_PAGEDOWN:
  178. {
  179. int stepPixels = ((int)(pageStep_ * scrollPanel_->GetHeight())) - GetSelectedItem()->GetHeight();
  180. unsigned newSelection = selection;
  181. unsigned okSelection = selection;
  182. while (newSelection < numItems)
  183. {
  184. UIElement* item = GetItem(newSelection);
  185. int height = 0;
  186. if (item->IsVisible())
  187. {
  188. height = item->GetHeight();
  189. okSelection = newSelection;
  190. }
  191. if (stepPixels < height)
  192. break;
  193. stepPixels -= height;
  194. ++newSelection;
  195. }
  196. if (!additive)
  197. SetSelection(okSelection);
  198. else
  199. AddSelection(okSelection);
  200. }
  201. return;
  202. case KEY_HOME:
  203. ChangeSelection(-(int)GetNumItems(), additive);
  204. return;
  205. case KEY_END:
  206. ChangeSelection(GetNumItems(), additive);
  207. return;
  208. }
  209. }
  210. using namespace UnhandledKey;
  211. VariantMap eventData;
  212. eventData[P_ELEMENT] = (void*)this;
  213. eventData[P_KEY] = key;
  214. eventData[P_BUTTONS] = buttons;
  215. eventData[P_QUALIFIERS] = qualifiers;
  216. SendEvent(E_UNHANDLEDKEY, eventData);
  217. }
  218. void ListView::OnResize()
  219. {
  220. ScrollView::OnResize();
  221. // Set the content element width to match the scrollpanel
  222. const IntRect& clipBorder = scrollPanel_->GetClipBorder();
  223. contentElement_->SetWidth(scrollPanel_->GetWidth() - clipBorder.left_ - clipBorder.right_);
  224. }
  225. void ListView::OnFocus()
  226. {
  227. UpdateSelectionEffect();
  228. }
  229. void ListView::OnDefocus()
  230. {
  231. if (clearSelectionOnDefocus_)
  232. ClearSelection();
  233. UpdateSelectionEffect();
  234. }
  235. void ListView::AddItem(UIElement* item)
  236. {
  237. InsertItem(contentElement_->GetNumChildren(), item);
  238. }
  239. void ListView::InsertItem(unsigned index, UIElement* item)
  240. {
  241. if ((!item) || (item->GetParent() == contentElement_))
  242. return;
  243. // Enable input so that clicking the item can be detected
  244. item->SetActive(true);
  245. item->SetSelected(false);
  246. contentElement_->InsertChild(index, item);
  247. // If necessary, shift the following selections
  248. std::set<unsigned> prevSelections;
  249. selections_.clear();
  250. for (std::set<unsigned>::iterator j = prevSelections.begin(); j != prevSelections.end(); ++j)
  251. {
  252. if (*j >= index)
  253. selections_.insert(*j + 1);
  254. else
  255. selections_.insert(*j);
  256. }
  257. UpdateSelectionEffect();
  258. }
  259. void ListView::RemoveItem(UIElement* item)
  260. {
  261. unsigned numItems = GetNumItems();
  262. for (unsigned i = 0; i < numItems; ++i)
  263. {
  264. if (GetItem(i) == item)
  265. {
  266. item->SetSelected(false);
  267. selections_.erase(i);
  268. // Remove any child items in hierarchy mode
  269. unsigned removed = 1;
  270. if (hierarchyMode_)
  271. {
  272. int baseIndent = GetItemIndent(item);
  273. int j = i + 1;
  274. for (;;)
  275. {
  276. UIElement* childItem = GetItem(i + 1);
  277. if (!childItem)
  278. break;
  279. if (GetItemIndent(childItem) > baseIndent)
  280. {
  281. childItem->SetSelected(false);
  282. selections_.erase(j);
  283. contentElement_->RemoveChild(childItem);
  284. ++removed;
  285. }
  286. else
  287. break;
  288. ++j;
  289. }
  290. }
  291. // If necessary, shift the following selections
  292. std::set<unsigned> prevSelections;
  293. selections_.clear();
  294. for (std::set<unsigned>::iterator j = prevSelections.begin(); j != prevSelections.end(); ++j)
  295. {
  296. if (*j > i)
  297. selections_.insert(*j - removed);
  298. else
  299. selections_.insert(*j);
  300. }
  301. UpdateSelectionEffect();
  302. break;
  303. }
  304. }
  305. contentElement_->RemoveChild(item);
  306. }
  307. void ListView::RemoveItem(unsigned index)
  308. {
  309. RemoveItem(GetItem(index));
  310. }
  311. void ListView::RemoveAllItems()
  312. {
  313. unsigned numItems = GetNumItems();
  314. for (unsigned i = 0; i < numItems; ++i)
  315. contentElement_->GetChild(i)->SetSelected(false);
  316. contentElement_->RemoveAllChildren();
  317. ClearSelection();
  318. }
  319. void ListView::SetSelection(unsigned index)
  320. {
  321. std::set<unsigned> indices;
  322. indices.insert(index);
  323. SetSelections(indices);
  324. EnsureItemVisibility(index);
  325. }
  326. void ListView::SetSelections(const std::set<unsigned>& indices)
  327. {
  328. unsigned numItems = GetNumItems();
  329. // Remove first items that should no longer be selected
  330. for (std::set<unsigned>::iterator i = selections_.begin(); i != selections_.end();)
  331. {
  332. unsigned index = *i;
  333. if (indices.find(index) == indices.end())
  334. {
  335. std::set<unsigned>::iterator current = i++;
  336. selections_.erase(current);
  337. using namespace Iteselected_;
  338. VariantMap eventData;
  339. eventData[P_ELEMENT] = (void*)this;
  340. eventData[P_SELECTION] = index;
  341. SendEvent(E_ITEMDESELECTED, eventData);
  342. }
  343. else
  344. ++i;
  345. }
  346. // Then add missing items
  347. for (std::set<unsigned>::const_iterator i = indices.begin(); i != indices.end(); ++i)
  348. {
  349. unsigned index = *i;
  350. if (index < numItems)
  351. {
  352. // In singleselect mode, resend the event even for the same selection
  353. if ((selections_.find(index) == selections_.end()) || (!multiselect_))
  354. {
  355. selections_.insert(*i);
  356. using namespace Iteselected_;
  357. VariantMap eventData;
  358. eventData[P_ELEMENT] = (void*)this;
  359. eventData[P_SELECTION] = *i;
  360. SendEvent(E_ITEMSELECTED, eventData);
  361. }
  362. }
  363. // If no multiselect enabled, allow setting only one item
  364. if (!multiselect_)
  365. break;
  366. }
  367. UpdateSelectionEffect();
  368. }
  369. void ListView::AddSelection(unsigned index)
  370. {
  371. if (!multiselect_)
  372. SetSelection(index);
  373. else
  374. {
  375. if (index >= GetNumItems())
  376. return;
  377. std::set<unsigned> newSelections = selections_;
  378. newSelections.insert(index);
  379. SetSelections(newSelections);
  380. EnsureItemVisibility(index);
  381. }
  382. }
  383. void ListView::RemoveSelection(unsigned index)
  384. {
  385. if (index >= GetNumItems())
  386. return;
  387. std::set<unsigned> newSelections = selections_;
  388. newSelections.erase(index);
  389. SetSelections(newSelections);
  390. EnsureItemVisibility(index);
  391. }
  392. void ListView::ToggleSelection(unsigned index)
  393. {
  394. unsigned numItems = GetNumItems();
  395. if (index >= numItems)
  396. return;
  397. if (selections_.find(index) != selections_.end())
  398. RemoveSelection(index);
  399. else
  400. AddSelection(index);
  401. }
  402. void ListView::ChangeSelection(int delta, bool additive)
  403. {
  404. if (selections_.empty())
  405. return;
  406. if (!multiselect_)
  407. additive = false;
  408. // If going downwards, use the last selection as a base. Otherwise use first
  409. unsigned selection = delta > 0 ? *selections_.rbegin() : *selections_.begin();
  410. unsigned numItems = GetNumItems();
  411. unsigned newSelection = selection;
  412. unsigned okSelection = selection;
  413. while (delta != 0)
  414. {
  415. if (delta > 0)
  416. {
  417. ++newSelection;
  418. if (newSelection >= numItems)
  419. break;
  420. }
  421. if (delta < 0)
  422. {
  423. --newSelection;
  424. if (newSelection >= numItems)
  425. break;
  426. }
  427. UIElement* item = GetItem(newSelection);
  428. if (item->IsVisible())
  429. {
  430. okSelection = newSelection;
  431. if (delta > 0)
  432. --delta;
  433. if (delta < 0)
  434. ++delta;
  435. }
  436. }
  437. if (!additive)
  438. SetSelection(okSelection);
  439. else
  440. AddSelection(okSelection);
  441. }
  442. void ListView::ClearSelection()
  443. {
  444. SetSelections(std::set<unsigned>());
  445. UpdateSelectionEffect();
  446. }
  447. void ListView::SetHighlightMode(HighlightMode mode)
  448. {
  449. highlightMode_ = mode;
  450. UpdateSelectionEffect();
  451. }
  452. void ListView::SetMultiselect(bool enable)
  453. {
  454. multiselect_ = enable;
  455. }
  456. void ListView::SetHierarchyMode(bool enable)
  457. {
  458. hierarchyMode_ = enable;
  459. }
  460. void ListView::SetClearSelectionOnDefocus(bool enable)
  461. {
  462. clearSelectionOnDefocus_ = enable;
  463. }
  464. void ListView::SetDoubleClickInterval(float interval)
  465. {
  466. doubleClickInterval_ = interval;
  467. }
  468. void ListView::SetChildItemsVisible(unsigned index, bool enable)
  469. {
  470. unsigned numItems = GetNumItems();
  471. if ((!hierarchyMode_) || (index >= numItems))
  472. return;
  473. int baseIndent = GetItemIndent(GetItem(index));
  474. for (unsigned i = index + 1; i < numItems; ++i)
  475. {
  476. UIElement* item = GetItem(i);
  477. if (GetItemIndent(item) > baseIndent)
  478. item->SetVisible(enable);
  479. else
  480. break;
  481. }
  482. }
  483. void ListView::SetChildItemsVisible(bool enable)
  484. {
  485. unsigned numItems = GetNumItems();
  486. for (unsigned i = 0; i < numItems; ++i)
  487. {
  488. if (!GetItemIndent(GetItem(i)))
  489. SetChildItemsVisible(i, enable);
  490. }
  491. if (GetSelections().size() == 1)
  492. EnsureItemVisibility(GetSelection());
  493. }
  494. void ListView::ToggleChildItemsVisible(unsigned index)
  495. {
  496. unsigned numItems = GetNumItems();
  497. if ((!hierarchyMode_) || (index >= numItems))
  498. return;
  499. int baseIndent = GetItemIndent(GetItem(index));
  500. bool firstChild = true;
  501. UIElement* prevItem = 0;
  502. for (unsigned i = index + 1; i < numItems; ++i)
  503. {
  504. UIElement* item = GetItem(i);
  505. if (GetItemIndent(item) > baseIndent)
  506. {
  507. if (firstChild)
  508. {
  509. item->SetVisible(!item->IsVisible());
  510. firstChild = false;
  511. }
  512. else
  513. item->SetVisible(prevItem->IsVisible());
  514. }
  515. else
  516. break;
  517. prevItem = item;
  518. }
  519. }
  520. unsigned ListView::GetNumItems() const
  521. {
  522. return contentElement_->GetNumChildren();
  523. }
  524. UIElement* ListView::GetItem(unsigned index) const
  525. {
  526. return contentElement_->GetChild(index);
  527. }
  528. std::vector<UIElement*> ListView::GetItems() const
  529. {
  530. return contentElement_->GetChildren();
  531. }
  532. unsigned ListView::GetSelection() const
  533. {
  534. if (selections_.empty())
  535. return M_MAX_UNSIGNED;
  536. else
  537. return *selections_.begin();
  538. }
  539. UIElement* ListView::GetSelectedItem() const
  540. {
  541. return contentElement_->GetChild(GetSelection());
  542. }
  543. std::vector<UIElement*> ListView::GetSelectedItems() const
  544. {
  545. std::vector<UIElement*> ret;
  546. for (std::set<unsigned>::const_iterator i = selections_.begin(); i != selections_.end(); ++i)
  547. {
  548. UIElement* item = GetItem(*i);
  549. if (item)
  550. ret.push_back(item);
  551. }
  552. return ret;
  553. }
  554. void ListView::UpdateSelectionEffect()
  555. {
  556. unsigned numItems = GetNumItems();
  557. for (unsigned i = 0; i < numItems; ++i)
  558. {
  559. UIElement* item = GetItem(i);
  560. if ((highlightMode_ != HM_NEVER) && (selections_.find(i) != selections_.end()))
  561. item->SetSelected((focus_) || (highlightMode_ == HM_ALWAYS));
  562. else
  563. item->SetSelected(false);
  564. }
  565. }
  566. void ListView::EnsureItemVisibility(unsigned index)
  567. {
  568. UIElement* item = GetItem(index);
  569. if ((!item) || (!item->IsVisible()))
  570. return;
  571. IntVector2 currentOffset = item->GetScreenPosition() - scrollPanel_->GetScreenPosition() - contentElement_->GetPosition();
  572. IntVector2 newView = GetViewPosition();
  573. const IntRect& clipBorder = scrollPanel_->GetClipBorder();
  574. IntVector2 windowSize(scrollPanel_->GetWidth() - clipBorder.left_ - clipBorder.right_, scrollPanel_->GetHeight() -
  575. clipBorder.top_ - clipBorder.bottom_);
  576. if (currentOffset.y_ < 0)
  577. newView.y_ += currentOffset.y_;
  578. if (currentOffset.y_ + item->GetHeight() > windowSize.y_)
  579. newView.y_ += currentOffset.y_ + item->GetHeight() - windowSize.y_;
  580. SetViewPosition(newView);
  581. }
  582. void ListView::HandleUIMouseClick(StringHash eventType, VariantMap& eventData)
  583. {
  584. if (eventData[UIMouseClick::P_BUTTON].GetInt() != MOUSEB_LEFT)
  585. return;
  586. int qualifiers = eventData[UIMouseClick::P_QUALIFIERS].GetInt();
  587. UIElement* element = static_cast<UIElement*>(eventData[UIMouseClick::P_ELEMENT].GetPtr());
  588. unsigned numItems = GetNumItems();
  589. for (unsigned i = 0; i < numItems; ++i)
  590. {
  591. if (element == GetItem(i))
  592. {
  593. // Check doubleclick
  594. bool isDoubleClick = false;
  595. if ((!multiselect_) || (!qualifiers))
  596. {
  597. if ((doubleClickTimer_ > 0.0f) && (lastClickedItem_ == i))
  598. {
  599. isDoubleClick = true;
  600. doubleClickTimer_ = 0.0f;
  601. }
  602. else
  603. {
  604. doubleClickTimer_ = doubleClickInterval_;
  605. lastClickedItem_ = i;
  606. }
  607. SetSelection(i);
  608. }
  609. // Check multiselect with shift & ctrl
  610. if (multiselect_)
  611. {
  612. if (qualifiers & QUAL_SHIFT)
  613. {
  614. if (selections_.empty())
  615. SetSelection(i);
  616. else
  617. {
  618. unsigned first = *selections_.begin();
  619. unsigned last = *selections_.rbegin();
  620. std::set<unsigned> newSelections = selections_;
  621. if ((i == first) || (i == last))
  622. {
  623. for (unsigned j = first; j <= last; ++j)
  624. newSelections.insert(j);
  625. }
  626. else if (i < first)
  627. {
  628. for (unsigned j = i; j <= first; ++j)
  629. newSelections.insert(j);
  630. }
  631. else if (i < last)
  632. {
  633. if ((abs((int)i - (int)first)) <= (abs((int)i - (int)last)))
  634. {
  635. for (unsigned j = first; j <= i; ++j)
  636. newSelections.insert(j);
  637. }
  638. else
  639. {
  640. for (unsigned j = i; j <= last; ++j)
  641. newSelections.insert(j);
  642. }
  643. }
  644. else if (i > last)
  645. {
  646. for (unsigned j = last; j <= i; ++j)
  647. newSelections.insert(j);
  648. }
  649. SetSelections(newSelections);
  650. }
  651. }
  652. else if (qualifiers & QUAL_CTRL)
  653. ToggleSelection(i);
  654. }
  655. if (isDoubleClick)
  656. {
  657. if (hierarchyMode_)
  658. ToggleChildItemsVisible(i);
  659. VariantMap eventData;
  660. eventData[ItemDoubleClicked::P_ELEMENT] = (void*)this;
  661. eventData[ItemDoubleClicked::P_SELECTION] = i;
  662. SendEvent(E_ITEMDOUBLECLICKED, eventData);
  663. }
  664. return;
  665. }
  666. }
  667. }