Back to index

unity  6.0.0
QuicklistView.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003 * Copyright (C) 2010 Canonical Ltd
00004 *
00005 * This program is free software: you can redistribute it and/or modify
00006 * it under the terms of the GNU General Public License version 3 as
00007 * published by the Free Software Foundation.
00008 *
00009 * This program is distributed in the hope that it will be useful,
00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 * GNU General Public License for more details.
00013 *
00014 * You should have received a copy of the GNU General Public License
00015 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 *
00017 * Authored by: Jay Taoko <jay.taoko@canonical.com>
00018 * Authored by: Mirco Müller <mirco.mueller@canonical.com
00019 */
00020 
00021 #include <Nux/Nux.h>
00022 #include <Nux/VLayout.h>
00023 #include <Nux/HLayout.h>
00024 #include <Nux/WindowThread.h>
00025 #include <Nux/WindowCompositor.h>
00026 #include <Nux/BaseWindow.h>
00027 #include <Nux/Button.h>
00028 #include <NuxGraphics/GraphicsEngine.h>
00029 #include <Nux/TextureArea.h>
00030 #include <NuxGraphics/CairoGraphics.h>
00031 #include <UnityCore/Variant.h>
00032 
00033 #include "unity-shared/CairoTexture.h"
00034 
00035 #include "QuicklistView.h"
00036 #include "QuicklistMenuItem.h"
00037 #include "QuicklistMenuItemLabel.h"
00038 #include "QuicklistMenuItemSeparator.h"
00039 #include "QuicklistMenuItemCheckmark.h"
00040 #include "QuicklistMenuItemRadio.h"
00041 
00042 #include "unity-shared/Introspectable.h"
00043 
00044 #include "unity-shared/ubus-server.h"
00045 #include "unity-shared/UBusMessages.h"
00046 
00047 namespace unity
00048 {
00049 namespace
00050 {
00051   const int ANCHOR_WIDTH = 10.0f;
00052 }
00053 
00054 NUX_IMPLEMENT_OBJECT_TYPE(QuicklistView);
00055 
00056 QuicklistView::QuicklistView()
00057   : _anchorX(0)
00058   , _anchorY(0)
00059   , _labelText("QuicklistView 1234567890")
00060   , _top_size(4)
00061   , _mouse_down(false)
00062   , _enable_quicklist_for_testing(false)
00063   , _anchor_width(10)
00064   , _anchor_height(18)
00065   , _corner_radius(4)
00066   , _padding(13)
00067   , _left_padding_correction(-1)
00068   , _bottom_padding_correction_normal(-2)
00069   , _bottom_padding_correction_single_item(-4)
00070   , _offset_correction(-1)
00071   , _cairo_text_has_changed(true)
00072   , _current_item_index(-1)
00073 {
00074   SetGeometry(nux::Geometry(0, 0, 1, 1));
00075 
00076   _use_blurred_background = true;
00077   _compute_blur_bkg = true;
00078 
00079   _left_space = new nux::SpaceLayout(_padding +
00080                                      _anchor_width +
00081                                      _corner_radius +
00082                                      _left_padding_correction,
00083                                      _padding +
00084                                      _anchor_width +
00085                                      _corner_radius +
00086                                      _left_padding_correction,
00087                                      1, 1000);
00088   _right_space = new nux::SpaceLayout(_padding + _corner_radius,
00089                                       _padding + _corner_radius,
00090                                       1, 1000);
00091   _top_space = new nux::SpaceLayout(1, 1000,
00092                                     _padding + _corner_radius,
00093                                     _padding + _corner_radius);
00094   _bottom_space = new nux::SpaceLayout(1, 1000,
00095                                        _padding + _corner_radius,
00096                                        _padding + _corner_radius);
00097 
00098   _vlayout = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION);
00099   _vlayout->AddLayout(_top_space, 0);
00100 
00101   _item_layout     = new nux::VLayout(TEXT(""), NUX_TRACKER_LOCATION);
00102   _vlayout->AddLayout(_item_layout, 0);
00103 
00104   _vlayout->AddLayout(_bottom_space, 0);
00105   _vlayout->SetMinimumWidth(140);
00106 
00107   _hlayout = new nux::HLayout(TEXT(""), NUX_TRACKER_LOCATION);
00108   _hlayout->AddLayout(_left_space, 0);
00109   _hlayout->AddLayout(_vlayout, 0, nux::eCenter, nux::eFull);
00110   _hlayout->AddLayout(_right_space, 0);
00111 
00112   SetWindowSizeMatchLayout(true);
00113   SetLayout(_hlayout);
00114 
00115   mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &QuicklistView::RecvMouseDownOutsideOfQuicklist));
00116   mouse_down.connect(sigc::mem_fun(this, &QuicklistView::RecvMouseDown));
00117   mouse_up.connect(sigc::mem_fun(this, &QuicklistView::RecvMouseUp));
00118   mouse_click.connect(sigc::mem_fun(this, &QuicklistView::RecvMouseClick));
00119   mouse_move.connect(sigc::mem_fun(this, &QuicklistView::RecvMouseMove));
00120   mouse_drag.connect(sigc::mem_fun(this, &QuicklistView::RecvMouseDrag));
00121   key_down.connect(sigc::mem_fun(this, &QuicklistView::RecvKeyPressed));
00122   begin_key_focus.connect(sigc::mem_fun(this, &QuicklistView::RecvStartFocus));
00123   end_key_focus.connect(sigc::mem_fun(this, &QuicklistView::RecvEndFocus));
00124 
00125   SetAcceptKeyNavFocus(true);
00126 }
00127 
00128 void
00129 QuicklistView::RecvStartFocus()
00130 {
00131   PushToFront();
00132 }
00133 
00134 void
00135 QuicklistView::RecvEndFocus()
00136 {
00137 }
00138 
00139 void
00140 QuicklistView::SelectItem(int index)
00141 {
00142   CancelItemsPrelightStatus();
00143   int target_item = -1;
00144 
00145   if (IsMenuItemSelectable(index))
00146   {
00147     QuicklistMenuItem* menu_item = GetNthItems(index);
00148 
00149     if (menu_item)
00150     {
00151       target_item = index;
00152       menu_item->_prelight = true;
00153     }
00154   }
00155 
00156   if (_current_item_index != target_item)
00157   {
00158     _current_item_index = target_item;
00159     selection_change.emit();
00160     QueueDraw();
00161   }
00162 }
00163 
00164 bool
00165 QuicklistView::IsMenuItemSelectable(int index)
00166 {
00167   QuicklistMenuItem* menu_item = nullptr;
00168 
00169   if (index < 0)
00170     return false;
00171 
00172   menu_item = GetNthItems(index);
00173   if (!menu_item)
00174     return false;
00175 
00176   return menu_item->GetSelectable();
00177 }
00178 
00179 void
00180 QuicklistView::RecvKeyPressed(unsigned long    eventType,
00181                               unsigned long    key_sym,
00182                               unsigned long    key_state,
00183                               const char*      character,
00184                               unsigned short   keyCount)
00185 {
00186   switch (key_sym)
00187   {
00188       // home or page up (highlight the first menu-hitem)
00189     case NUX_VK_PAGE_UP:
00190     case NUX_VK_HOME:
00191     {
00192       int num_items = GetNumItems();
00193       int target_index = -1;
00194 
00195       do
00196       {
00197         ++target_index;
00198       }
00199       while (!IsMenuItemSelectable(target_index) && target_index < num_items);
00200 
00201       if (target_index < num_items)
00202         SelectItem(target_index);
00203 
00204       break;
00205     }
00206       // end or page down (highlight the last menu-hitem)
00207     case NUX_VK_PAGE_DOWN:
00208     case NUX_VK_END:
00209     {
00210       int target_index = GetNumItems();
00211 
00212       do
00213       {
00214         --target_index;
00215       }
00216       while (!IsMenuItemSelectable(target_index) && target_index >= 0);
00217 
00218       if (target_index >= 0)
00219         SelectItem(target_index);
00220 
00221       break;
00222     }
00223       // up (highlight previous menu-item)
00224     case NUX_VK_UP:
00225     case NUX_KP_UP:
00226     {
00227       int target_index = _current_item_index;
00228       bool loop_back = false;
00229 
00230       if (target_index <= 0)
00231         target_index = GetNumItems();
00232 
00233       do
00234       {
00235         --target_index;
00236 
00237         // If the first item is not selectable, we must loop from the last one
00238         if (!loop_back && target_index == 0 && !IsMenuItemSelectable(target_index))
00239         {
00240           loop_back = true;
00241           target_index = GetNumItems() - 1;
00242         }
00243       }
00244       while (!IsMenuItemSelectable(target_index) && target_index >= 0);
00245 
00246       if (target_index >= 0)
00247         SelectItem(target_index);
00248 
00249       break;
00250     }
00251 
00252       // down (highlight next menu-item)
00253     case NUX_VK_DOWN:
00254     case NUX_KP_DOWN:
00255     {
00256       int target_index = _current_item_index;
00257       int num_items = GetNumItems();
00258       bool loop_back = false;
00259 
00260       if (target_index >= num_items - 1)
00261         target_index = -1;
00262 
00263       do
00264       {
00265         ++target_index;
00266 
00267         // If the last item is not selectable, we must loop from the first one
00268         if (!loop_back && target_index == num_items - 1 && !IsMenuItemSelectable(target_index))
00269         {
00270           loop_back = true;
00271           target_index = 0;
00272         }
00273       }
00274       while (!IsMenuItemSelectable(target_index) && target_index < num_items);
00275 
00276       if (target_index < num_items)
00277         SelectItem(target_index);
00278 
00279       break;
00280     }
00281 
00282       // left (close quicklist, go back to laucher key-nav)
00283     case NUX_VK_LEFT:
00284     case NUX_KP_LEFT:
00285       Hide();
00286       // inform Launcher we switch back to Launcher key-nav
00287       ubus_server_send_message(ubus_server_get_default(),
00288                                UBUS_QUICKLIST_END_KEY_NAV,
00289                                NULL);
00290       break;
00291 
00292       // esc (close quicklist, exit key-nav)
00293     case NUX_VK_ESCAPE:
00294       Hide();
00295       // inform UnityScreen we leave key-nav completely
00296       ubus_server_send_message(ubus_server_get_default(),
00297                                UBUS_LAUNCHER_END_KEY_NAV,
00298                                NULL);
00299       break;
00300 
00301       // <SPACE>, <RETURN> (activate selected menu-item)
00302     case NUX_VK_SPACE:
00303     case NUX_VK_ENTER:
00304     case NUX_KP_ENTER:
00305       if (IsMenuItemSelectable(_current_item_index))
00306       {
00307         ActivateItem(GetNthItems(_current_item_index));
00308         Hide();
00309       }
00310       break;
00311 
00312     default:
00313       break;
00314   }
00315 }
00316 
00317 QuicklistView::~QuicklistView()
00318 {
00319   for (auto item : _item_list)
00320   {
00321     // Remove from introspection
00322     RemoveChild(item);
00323     item->UnReference();
00324   }
00325 
00326   _item_list.clear();
00327 }
00328 
00329 void
00330 QuicklistView::EnableQuicklistForTesting(bool enable_testing)
00331 {
00332   _enable_quicklist_for_testing = enable_testing;
00333 }
00334 
00335 void QuicklistView::ShowQuicklistWithTipAt(int anchor_tip_x, int anchor_tip_y)
00336 {
00337   _anchorX = anchor_tip_x;
00338   _anchorY = anchor_tip_y;
00339 
00340   if (!_enable_quicklist_for_testing)
00341   {
00342     if ((_item_list.size() != 0))
00343     {
00344       int offscreen_size = GetBaseY() +
00345                            GetBaseHeight() -
00346                            nux::GetWindowThread()->GetGraphicsDisplay().GetWindowHeight();
00347 
00348       if (offscreen_size > 0)
00349         _top_size = offscreen_size;
00350       else
00351         _top_size = 4;
00352 
00353       int x = _anchorX - _padding;
00354       int y = _anchorY - _anchor_height / 2 - _top_size - _corner_radius - _padding;
00355 
00356       SetBaseX(x);
00357       SetBaseY(y);
00358     }
00359     else
00360     {
00361       _top_size = 0;
00362       int x = _anchorX - _padding;
00363       int y = _anchorY - _anchor_height / 2 - _top_size - _corner_radius - _padding;
00364 
00365       SetBaseX(x);
00366       SetBaseY(y);
00367     }
00368   }
00369 
00370   Show();
00371 }
00372 
00373 void QuicklistView::ShowWindow(bool b, bool start_modal)
00374 {
00375   unity::CairoBaseWindow::ShowWindow(b, start_modal);
00376 }
00377 
00378 void QuicklistView::Show()
00379 {
00380   if (!IsVisible())
00381   {
00382     // FIXME: ShowWindow shouldn't need to be called first
00383     ShowWindow(true);
00384     PushToFront();
00385     //EnableInputWindow (true, "quicklist", false, true);
00386     //SetInputFocus ();
00387     GrabPointer();
00388     GrabKeyboard();
00389     QueueDraw();
00390     _compute_blur_bkg = true;
00391   }
00392 }
00393 
00394 void QuicklistView::Hide()
00395 {
00396   if (IsVisible() && !_enable_quicklist_for_testing)
00397   {
00398     CancelItemsPrelightStatus();
00399     CaptureMouseDownAnyWhereElse(false);
00400     UnGrabPointer();
00401     UnGrabKeyboard();
00402     //EnableInputWindow (false);
00403     ShowWindow(false);
00404 
00405     if (_current_item_index != -1)
00406     {
00407       selection_change.emit();
00408       _current_item_index = -1;
00409     }
00410   }
00411 }
00412 
00413 void QuicklistView::Draw(nux::GraphicsEngine& gfxContext, bool forceDraw)
00414 {
00415   CairoBaseWindow::Draw(gfxContext, forceDraw);
00416 
00417   nux::Geometry base(GetGeometry());
00418   base.x = 0;
00419   base.y = 0;
00420 
00421   gfxContext.PushClippingRectangle(base);
00422 
00423   for (auto item : _item_list)
00424   {
00425     if (item->GetVisible())
00426       item->ProcessDraw(gfxContext, forceDraw);
00427   }
00428 
00429   gfxContext.PopClippingRectangle();
00430 }
00431 
00432 void QuicklistView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw)
00433 {}
00434 
00435 void QuicklistView::PreLayoutManagement()
00436 {
00437   int MaxItemWidth = 0;
00438   int TotalItemHeight = 0;
00439 
00440   for (auto item : _item_list)
00441   {
00442     // Make sure item is in layout if it should be
00443     if (!item->GetVisible())
00444     {
00445       _item_layout->RemoveChildObject(item);
00446       continue;
00447     }
00448     else if (!item->GetParentObject())
00449       _item_layout->AddView(item, 1, nux::eCenter, nux::eFull);
00450 
00451     int  textWidth  = 0;
00452     int  textHeight = 0;
00453     item->GetTextExtents(textWidth, textHeight);
00454     if (textWidth > MaxItemWidth)
00455       MaxItemWidth = textWidth;
00456     TotalItemHeight += textHeight;
00457   }
00458 
00459   if (TotalItemHeight < _anchor_height)
00460   {
00461     _top_space->SetMinMaxSize(1, (_anchor_height - TotalItemHeight) / 2 + 1 + _padding + _corner_radius);
00462     _bottom_space->SetMinMaxSize(1, (_anchor_height - TotalItemHeight) / 2 + 1 +
00463                                      _padding + _corner_radius +
00464                                      _bottom_padding_correction_single_item);
00465   }
00466   else
00467   {
00468     _top_space->SetMinMaxSize(_padding + _corner_radius, _padding + _corner_radius);
00469     _bottom_space->SetMinMaxSize(_padding + _corner_radius - 2,
00470                                  _padding + _corner_radius +
00471                                  _bottom_padding_correction_normal);
00472   }
00473 
00474   _item_layout->SetMinimumWidth(MaxItemWidth);
00475 
00476   BaseWindow::PreLayoutManagement();
00477 }
00478 
00479 long QuicklistView::PostLayoutManagement(long LayoutResult)
00480 {
00481   long result = BaseWindow::PostLayoutManagement(LayoutResult);
00482 
00483   UpdateTexture();
00484 
00485   int x = _padding + _anchor_width + _corner_radius + _offset_correction;
00486   int y = _padding + _corner_radius + _offset_correction;
00487 
00488   for (auto item : _item_list)
00489   {
00490     if (!item->GetVisible())
00491       continue;
00492 
00493     item->SetBaseX(x);
00494     item->SetBaseY(y);
00495 
00496     y += item->GetBaseHeight();
00497   }
00498 
00499   // We must correct the width of line separators. The rendering of the separator can be smaller than the width of the
00500   // quicklist. The reason for that is, the quicklist width is determined by the largest entry it contains. That size is
00501   // only after MaxItemWidth is computed in QuicklistView::PreLayoutManagement.
00502   // The setting of the separator width is done here after the Layout cycle for this widget is over. The width of the separator
00503   // has bee set correctly during the layout cycle, but the cairo rendering still need to be adjusted.
00504   int separator_width = _item_layout->GetBaseWidth();
00505 
00506   for (auto item : _item_list)
00507   {
00508     if (item->GetVisible() && item->CairoSurfaceWidth() != separator_width)
00509     {
00510       // Compute textures of the item.
00511       item->UpdateTexture();
00512     }
00513   }
00514 
00515   return result;
00516 }
00517 
00518 void QuicklistView::RecvCairoTextChanged(QuicklistMenuItem* cairo_text)
00519 {
00520   _cairo_text_has_changed = true;
00521 }
00522 
00523 void QuicklistView::RecvCairoTextColorChanged(QuicklistMenuItem* cairo_text)
00524 {
00525   NeedRedraw();
00526 }
00527 
00528 void QuicklistView::RecvItemMouseClick(QuicklistMenuItem* item, int x, int y)
00529 {
00530   _mouse_down = false;
00531   if (IsVisible() && item->GetEnabled())
00532   {
00533     // Check if the mouse was released over an item and emit the signal
00534     CheckAndEmitItemSignal(x + item->GetBaseX(), y + item->GetBaseY());
00535 
00536     Hide();
00537   }
00538 }
00539 
00540 void QuicklistView::CheckAndEmitItemSignal(int x, int y)
00541 {
00542   nux::Geometry geo;
00543   for (auto item : _item_list)
00544   {
00545     if (!item->GetVisible())
00546       continue;
00547 
00548     geo = item->GetGeometry();
00549     geo.width = _item_layout->GetBaseWidth();
00550 
00551     if (geo.IsPointInside(x, y))
00552     {
00553       // An action is performed: send the signal back to the application
00554       ActivateItem(item);
00555     }
00556   }
00557 }
00558 
00559 void QuicklistView::ActivateItem(QuicklistMenuItem* item)
00560 {
00561   if (item && item->_menuItem)
00562   {
00563     ubus_server_send_message(ubus_server_get_default(),
00564                              UBUS_PLACE_VIEW_CLOSE_REQUEST,
00565                              NULL);
00566 
00567     dbusmenu_menuitem_handle_event(item->_menuItem, "clicked", NULL, 0);
00568   }
00569 }
00570 
00571 void QuicklistView::RecvItemMouseRelease(QuicklistMenuItem* item, int x, int y)
00572 {
00573   _mouse_down = false;
00574 
00575 
00576   if (IsVisible() && item->GetEnabled())
00577   {
00578     // Check if the mouse was released over an item and emit the signal
00579     CheckAndEmitItemSignal(x + item->GetBaseX(), y + item->GetBaseY());
00580 
00581     Hide();
00582   }
00583 }
00584 
00585 void QuicklistView::CancelItemsPrelightStatus()
00586 {
00587   for (auto item : _item_list)
00588   {
00589     item->_prelight = false;
00590   }
00591 }
00592 
00593 void QuicklistView::RecvItemMouseDrag(QuicklistMenuItem* item, int x, int y)
00594 {
00595   nux::Geometry geo;
00596   for (auto item : _item_list)
00597   {
00598     int item_index = GetItemIndex(item);
00599 
00600     if (!IsMenuItemSelectable(item_index))
00601       continue;
00602 
00603     geo = item->GetGeometry();
00604     geo.width = _item_layout->GetBaseWidth();
00605 
00606     if (geo.IsPointInside(x + item->GetBaseX(), y + item->GetBaseY()))
00607     {
00608       SelectItem(item_index);
00609     }
00610   }
00611 }
00612 
00613 void QuicklistView::RecvItemMouseEnter(QuicklistMenuItem* item)
00614 {
00615   int item_index = GetItemIndex(item);
00616 
00617   SelectItem(item_index);
00618 }
00619 
00620 void QuicklistView::RecvItemMouseLeave(QuicklistMenuItem* item)
00621 {
00622   int item_index = GetItemIndex(item);
00623 
00624   if (item_index < 0 || item_index == _current_item_index)
00625     SelectItem(-1);
00626 }
00627 
00628 void QuicklistView::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags)
00629 {
00630 //     if (IsVisible ())
00631 //     {
00632 //       CaptureMouseDownAnyWhereElse (false);
00633 //       UnGrabPointer ();
00634 //       EnableInputWindow (false);
00635 //       ShowWindow (false);
00636 //     }
00637 }
00638 
00639 void QuicklistView::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags)
00640 {
00641   // Check if the mouse was released over an item and emit the signal
00642   CheckAndEmitItemSignal(x, y);
00643 }
00644 
00645 void QuicklistView::RecvMouseClick(int x, int y, unsigned long button_flags, unsigned long key_flags)
00646 {
00647   if (IsVisible())
00648   {
00649     Hide();
00650   }
00651 }
00652 
00653 void QuicklistView::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
00654 {
00655 
00656 }
00657 
00658 void QuicklistView::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags)
00659 {
00660 
00661 }
00662 
00663 void QuicklistView::RecvMouseDownOutsideOfQuicklist(int x, int y, unsigned long button_flags, unsigned long key_flags)
00664 {
00665   Hide();
00666 }
00667 
00668 void QuicklistView::RemoveAllMenuItem()
00669 {
00670   for (auto item : _item_list)
00671   {
00672     // Remove from introspection
00673     RemoveChild(item);
00674     item->UnReference();
00675   }
00676 
00677 
00678   _item_list.clear();
00679 
00680   _item_layout->Clear();
00681   _cairo_text_has_changed = true;
00682   nux::GetWindowThread()->QueueObjectLayout(this);
00683 }
00684 
00685 void QuicklistView::AddMenuItem(QuicklistMenuItem* item)
00686 {
00687   if (item == 0)
00688     return;
00689 
00690   item->sigTextChanged.connect(sigc::mem_fun(this, &QuicklistView::RecvCairoTextChanged));
00691   item->sigColorChanged.connect(sigc::mem_fun(this, &QuicklistView::RecvCairoTextColorChanged));
00692   item->sigMouseClick.connect(sigc::mem_fun(this, &QuicklistView::RecvItemMouseClick));
00693   item->sigMouseReleased.connect(sigc::mem_fun(this, &QuicklistView::RecvItemMouseRelease));
00694   item->sigMouseEnter.connect(sigc::mem_fun(this, &QuicklistView::RecvItemMouseEnter));
00695   item->sigMouseLeave.connect(sigc::mem_fun(this, &QuicklistView::RecvItemMouseLeave));
00696   item->sigMouseDrag.connect(sigc::mem_fun(this, &QuicklistView::RecvItemMouseDrag));
00697 
00698   _item_list.push_back(item);
00699   item->Reference();
00700   // Add to introspection
00701   AddChild(item);
00702 
00703   _cairo_text_has_changed = true;
00704   nux::GetWindowThread()->QueueObjectLayout(this);
00705   NeedRedraw();
00706 }
00707 
00708 void QuicklistView::RenderQuicklistView()
00709 {
00710 
00711 }
00712 
00713 int QuicklistView::GetNumItems()
00714 {
00715   return _item_list.size();
00716 }
00717 
00718 QuicklistMenuItem* QuicklistView::GetNthItems(int index)
00719 {
00720   if (index < (int)_item_list.size())
00721   {
00722     int i = 0;
00723     for (auto item : _item_list)
00724     {
00725       if (i++ == index)
00726         return item;
00727     }
00728   }
00729 
00730   return nullptr;
00731 }
00732 
00733 int QuicklistView::GetItemIndex(QuicklistMenuItem* item)
00734 {
00735   int index = -1;
00736 
00737   for (auto it : _item_list)
00738   {
00739     ++index;
00740 
00741     if (it == item)
00742       return index;
00743   }
00744 
00745   return index;
00746 }
00747 
00748 QuicklistMenuItemType QuicklistView::GetNthType(int index)
00749 {
00750   QuicklistMenuItem* item = GetNthItems(index);
00751   if (item)
00752     return item->GetItemType();
00753 
00754   return MENUITEM_TYPE_UNKNOWN;
00755 }
00756 
00757 std::list<QuicklistMenuItem*> QuicklistView::GetChildren()
00758 {
00759   return _item_list;
00760 }
00761 
00762 void QuicklistView::SelectFirstItem()
00763 {
00764   SelectItem(0);
00765 }
00766 
00767 void ql_tint_dot_hl(cairo_t* cr,
00768                     gint    width,
00769                     gint    height,
00770                     gfloat  hl_x,
00771                     gfloat  hl_y,
00772                     gfloat  hl_size,
00773                     gfloat* rgba_tint,
00774                     gfloat* rgba_hl,
00775                     gfloat* rgba_dot)
00776 {
00777   cairo_surface_t* dots_surf    = NULL;
00778   cairo_t*         dots_cr      = NULL;
00779   cairo_pattern_t* dots_pattern = NULL;
00780   cairo_pattern_t* hl_pattern   = NULL;
00781 
00782   // create context for dot-pattern
00783   dots_surf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 4, 4);
00784   dots_cr = cairo_create(dots_surf);
00785 
00786   // clear normal context
00787   cairo_scale(cr, 1.0f, 1.0f);
00788   cairo_set_source_rgba(cr, 0.0f, 0.0f, 0.0f, 0.0f);
00789   cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
00790   cairo_paint(cr);
00791 
00792   // prepare drawing for normal context
00793   cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
00794 
00795   // create path in normal context
00796   cairo_rectangle(cr, 0.0f, 0.0f, (gdouble) width, (gdouble) height);
00797 
00798   // fill path of normal context with tint
00799   cairo_set_source_rgba(cr,
00800                         rgba_tint[0],
00801                         rgba_tint[1],
00802                         rgba_tint[2],
00803                         rgba_tint[3]);
00804   cairo_fill_preserve(cr);
00805 
00806   // create pattern in dot-context
00807   cairo_set_operator(dots_cr, CAIRO_OPERATOR_CLEAR);
00808   cairo_paint(dots_cr);
00809   cairo_scale(dots_cr, 1.0f, 1.0f);
00810   cairo_set_operator(dots_cr, CAIRO_OPERATOR_OVER);
00811   cairo_set_source_rgba(dots_cr,
00812                         rgba_dot[0],
00813                         rgba_dot[1],
00814                         rgba_dot[2],
00815                         rgba_dot[3]);
00816   cairo_rectangle(dots_cr, 0.0f, 0.0f, 1.0f, 1.0f);
00817   cairo_fill(dots_cr);
00818   cairo_rectangle(dots_cr, 2.0f, 2.0f, 1.0f, 1.0f);
00819   cairo_fill(dots_cr);
00820   dots_pattern = cairo_pattern_create_for_surface(dots_surf);
00821 
00822   // fill path of normal context with dot-pattern
00823   cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
00824   cairo_set_source(cr, dots_pattern);
00825   cairo_pattern_set_extend(dots_pattern, CAIRO_EXTEND_REPEAT);
00826   cairo_fill_preserve(cr);
00827   cairo_pattern_destroy(dots_pattern);
00828   cairo_surface_destroy(dots_surf);
00829   cairo_destroy(dots_cr);
00830 
00831   // draw highlight
00832   cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
00833   hl_pattern = cairo_pattern_create_radial(hl_x,
00834                                            hl_y,
00835                                            0.0f,
00836                                            hl_x,
00837                                            hl_y,
00838                                            hl_size);
00839   cairo_pattern_add_color_stop_rgba(hl_pattern,
00840                                     0.0f,
00841                                     rgba_hl[0],
00842                                     rgba_hl[1],
00843                                     rgba_hl[2],
00844                                     rgba_hl[3]);
00845   cairo_pattern_add_color_stop_rgba(hl_pattern, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f);
00846   cairo_set_source(cr, hl_pattern);
00847   cairo_fill(cr);
00848   cairo_pattern_destroy(hl_pattern);
00849 }
00850 
00851 void ql_setup(cairo_surface_t** surf,
00852               cairo_t**         cr,
00853               gboolean          outline,
00854               gint              width,
00855               gint              height,
00856               gboolean          negative)
00857 {
00858 //     // create context
00859 //     if (outline)
00860 //       *surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
00861 //     else
00862 //       *surf = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height);
00863 //     *cr = cairo_create (*surf);
00864 
00865   // clear context
00866   cairo_scale(*cr, 1.0f, 1.0f);
00867   if (outline)
00868   {
00869     cairo_set_source_rgba(*cr, 0.0f, 0.0f, 0.0f, 0.0f);
00870     cairo_set_operator(*cr, CAIRO_OPERATOR_CLEAR);
00871   }
00872   else
00873   {
00874     cairo_set_operator(*cr, CAIRO_OPERATOR_OVER);
00875     if (negative)
00876       cairo_set_source_rgba(*cr, 0.0f, 0.0f, 0.0f, 0.0f);
00877     else
00878       cairo_set_source_rgba(*cr, 1.0f, 1.0f, 1.0f, 1.0f);
00879   }
00880   cairo_paint(*cr);
00881 }
00882 
00883 void ql_compute_full_mask_path(cairo_t* cr,
00884                                gfloat   anchor_width,
00885                                gfloat   anchor_height,
00886                                gint     width,
00887                                gint     height,
00888                                gint     upper_size,
00889                                gfloat   radius,
00890                                guint    pad)
00891 {
00892   //     0  1        2  3
00893   //     +--+--------+--+
00894   //     |              |
00895   //     + 14           + 4
00896   //     |              |
00897   //     |              |
00898   //     |              |
00899   //     + 13           |
00900   //    /               |
00901   //   /                |
00902   //  + 12              |
00903   //   \                |
00904   //    \               |
00905   //  11 +              |
00906   //     |              |
00907   //     |              |
00908   //     |              |
00909   //  10 +              + 5
00910   //     |              |
00911   //     +--+--------+--+ 6
00912   //     9  8        7
00913 
00914 
00915   gfloat padding  = pad;
00916   int ZEROPOINT5 = 0.0f;
00917 
00918   gfloat HeightToAnchor = 0.0f;
00919   HeightToAnchor = ((gfloat) height - 2.0f * radius - anchor_height - 2 * padding) / 2.0f;
00920   if (HeightToAnchor < 0.0f)
00921   {
00922     g_warning("Anchor-height and corner-radius a higher than whole texture!");
00923     return;
00924   }
00925 
00926   //gint dynamic_size = height - 2*radius - 2*padding - anchor_height;
00927   //gint upper_dynamic_size = upper_size;
00928   //gint lower_dynamic_size = dynamic_size - upper_dynamic_size;
00929 
00930   if (upper_size >= 0)
00931   {
00932     if (upper_size > height - 2.0f * radius - anchor_height - 2 * padding)
00933     {
00934       //g_warning ("[_compute_full_mask_path] incorrect upper_size value");
00935       HeightToAnchor = 0;
00936     }
00937     else
00938     {
00939       HeightToAnchor = height - 2.0f * radius - anchor_height - 2 * padding - upper_size;
00940     }
00941   }
00942   else
00943   {
00944     HeightToAnchor = (height - 2.0f * radius - anchor_height - 2 * padding) / 2.0f;
00945   }
00946 
00947   cairo_translate(cr, -0.5f, -0.5f);
00948 
00949   // create path
00950   cairo_move_to(cr, padding + anchor_width + radius + ZEROPOINT5, padding + ZEROPOINT5);  // Point 1
00951   cairo_line_to(cr, width - padding - radius, padding + ZEROPOINT5);    // Point 2
00952   cairo_arc(cr,
00953             width  - padding - radius + ZEROPOINT5,
00954             padding + radius + ZEROPOINT5,
00955             radius,
00956             -90.0f * G_PI / 180.0f,
00957             0.0f * G_PI / 180.0f);   // Point 4
00958   cairo_line_to(cr,
00959                 (gdouble) width - padding + ZEROPOINT5,
00960                 (gdouble) height - radius - padding + ZEROPOINT5); // Point 5
00961   cairo_arc(cr,
00962             (gdouble) width - padding - radius + ZEROPOINT5,
00963             (gdouble) height - padding - radius + ZEROPOINT5,
00964             radius,
00965             0.0f * G_PI / 180.0f,
00966             90.0f * G_PI / 180.0f);  // Point 7
00967   cairo_line_to(cr,
00968                 anchor_width + padding + radius + ZEROPOINT5,
00969                 (gdouble) height - padding + ZEROPOINT5); // Point 8
00970 
00971   cairo_arc(cr,
00972             anchor_width + padding + radius + ZEROPOINT5,
00973             (gdouble) height - padding - radius,
00974             radius,
00975             90.0f * G_PI / 180.0f,
00976             180.0f * G_PI / 180.0f); // Point 10
00977 
00978   cairo_line_to(cr,
00979                 padding + anchor_width + ZEROPOINT5,
00980                 (gdouble) height - padding - radius - HeightToAnchor + ZEROPOINT5);   // Point 11
00981   cairo_line_to(cr,
00982                 padding + ZEROPOINT5,
00983                 (gdouble) height - padding - radius - HeightToAnchor - anchor_height / 2.0f + ZEROPOINT5); // Point 12
00984   cairo_line_to(cr,
00985                 padding + anchor_width + ZEROPOINT5,
00986                 (gdouble) height - padding - radius - HeightToAnchor - anchor_height + ZEROPOINT5);  // Point 13
00987 
00988   cairo_line_to(cr, padding + anchor_width + ZEROPOINT5, padding + radius  + ZEROPOINT5);   // Point 14
00989   cairo_arc(cr,
00990             padding + anchor_width + radius + ZEROPOINT5,
00991             padding + radius + ZEROPOINT5,
00992             radius,
00993             180.0f * G_PI / 180.0f,
00994             270.0f * G_PI / 180.0f);
00995 
00996   cairo_close_path(cr);
00997 }
00998 
00999 void ql_compute_mask(cairo_t* cr)
01000 {
01001   cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
01002   cairo_fill_preserve(cr);
01003 }
01004 
01005 void ql_compute_outline(cairo_t* cr,
01006                         gfloat   line_width,
01007                         gfloat*  rgba_line,
01008                         gfloat   size)
01009 {
01010   cairo_pattern_t* pattern = NULL;
01011   float            x       = 0.0f;
01012   float            y       = 0.0f;
01013   float            offset  = 2.5f * ANCHOR_WIDTH / size;
01014 
01015   cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
01016 
01017   pattern = cairo_pattern_create_linear(x, y, size, y);
01018   cairo_pattern_add_color_stop_rgba(pattern, 0.0f,
01019                                     rgba_line[0],
01020                                     rgba_line[1],
01021                                     rgba_line[2],
01022                                     rgba_line[3]);
01023   cairo_pattern_add_color_stop_rgba(pattern, offset,
01024                                     rgba_line[0],
01025                                     rgba_line[1],
01026                                     rgba_line[2],
01027                                     rgba_line[3]);
01028   cairo_pattern_add_color_stop_rgba(pattern, 1.1f * offset,
01029                                     rgba_line[0] * 0.65f,
01030                                     rgba_line[1] * 0.65f,
01031                                     rgba_line[2] * 0.65f,
01032                                     rgba_line[3]);
01033   cairo_pattern_add_color_stop_rgba(pattern, 1.0f,
01034                                     rgba_line[0] * 0.65f,
01035                                     rgba_line[1] * 0.65f,
01036                                     rgba_line[2] * 0.65f,
01037                                     rgba_line[3]);
01038   cairo_set_source(cr, pattern);
01039   cairo_set_line_width(cr, line_width);
01040   cairo_stroke(cr);
01041   cairo_pattern_destroy(pattern);
01042 }
01043 
01044 void ql_draw(cairo_t* cr,
01045              gboolean outline,
01046              gfloat   line_width,
01047              gfloat*  rgba,
01048              gboolean negative,
01049              gboolean stroke)
01050 {
01051   // prepare drawing
01052   cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
01053 
01054   // actually draw the mask
01055   if (outline)
01056   {
01057     cairo_set_line_width(cr, line_width);
01058     cairo_set_source_rgba(cr, rgba[0], rgba[1], rgba[2], rgba[3]);
01059   }
01060   else
01061   {
01062     if (negative)
01063       cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 1.0f);
01064     else
01065       cairo_set_source_rgba(cr, 0.0f, 0.0f, 0.0f, 0.0f);
01066   }
01067 
01068   // stroke or fill?
01069   if (stroke)
01070     cairo_stroke_preserve(cr);
01071   else
01072     cairo_fill_preserve(cr);
01073 }
01074 
01075 void ql_finalize(cairo_t** cr,
01076                  gboolean  outline,
01077                  gfloat    line_width,
01078                  gfloat*   rgba,
01079                  gboolean  negative,
01080                  gboolean  stroke)
01081 {
01082   // prepare drawing
01083   cairo_set_operator(*cr, CAIRO_OPERATOR_SOURCE);
01084 
01085   // actually draw the mask
01086   if (outline)
01087   {
01088     cairo_set_line_width(*cr, line_width);
01089     cairo_set_source_rgba(*cr, rgba[0], rgba[1], rgba[2], rgba[3]);
01090   }
01091   else
01092   {
01093     if (negative)
01094       cairo_set_source_rgba(*cr, 1.0f, 1.0f, 1.0f, 1.0f);
01095     else
01096       cairo_set_source_rgba(*cr, 0.0f, 0.0f, 0.0f, 0.0f);
01097   }
01098 
01099   // stroke or fill?
01100   if (stroke)
01101     cairo_stroke(*cr);
01102   else
01103     cairo_fill(*cr);
01104 }
01105 
01106 void
01107 ql_compute_full_outline_shadow(
01108   cairo_t* cr,
01109   cairo_surface_t* surf,
01110   gint    width,
01111   gint    height,
01112   gfloat  anchor_width,
01113   gfloat  anchor_height,
01114   gint    upper_size,
01115   gfloat  corner_radius,
01116   guint   blur_coeff,
01117   gfloat* rgba_shadow,
01118   gfloat  line_width,
01119   gint    padding_size,
01120   gfloat* rgba_line)
01121 {
01122   ql_setup(&surf, &cr, TRUE, width, height, FALSE);
01123   ql_compute_full_mask_path(cr,
01124                             anchor_width,
01125                             anchor_height,
01126                             width,
01127                             height,
01128                             upper_size,
01129                             corner_radius,
01130                             padding_size);
01131 
01132   ql_draw(cr, TRUE, line_width, rgba_shadow, FALSE, FALSE);
01133   nux::CairoGraphics dummy(CAIRO_FORMAT_A1, 1, 1);
01134   dummy.BlurSurface(blur_coeff, surf);
01135   ql_compute_mask(cr);
01136   ql_compute_outline(cr, line_width, rgba_line, width);
01137 }
01138 
01139 void ql_compute_full_mask(
01140   cairo_t* cr,
01141   cairo_surface_t* surf,
01142   gint     width,
01143   gint     height,
01144   gfloat   radius,
01145   guint    shadow_radius,
01146   gfloat   anchor_width,
01147   gfloat   anchor_height,
01148   gint     upper_size,
01149   gboolean negative,
01150   gboolean outline,
01151   gfloat   line_width,
01152   gint     padding_size,
01153   gfloat*  rgba)
01154 {
01155   ql_setup(&surf, &cr, outline, width, height, negative);
01156   ql_compute_full_mask_path(cr,
01157                             anchor_width,
01158                             anchor_height,
01159                             width,
01160                             height,
01161                             upper_size,
01162                             radius,
01163                             padding_size);
01164   ql_finalize(&cr, outline, line_width, rgba, negative, outline);
01165 }
01166 
01167 void QuicklistView::UpdateTexture()
01168 {
01169   if (!_cairo_text_has_changed)
01170     return;
01171 
01172   int size_above_anchor = -1; // equal to size below
01173   int width = GetBaseWidth();
01174   int height = GetBaseHeight();
01175 
01176   if (!_enable_quicklist_for_testing)
01177   {
01178     if (!_item_list.empty())
01179     {
01180       int offscreen_size = GetBaseY() +
01181                            height -
01182                            nux::GetWindowThread()->GetGraphicsDisplay().GetWindowHeight();
01183 
01184       if (offscreen_size > 0)
01185         _top_size = offscreen_size;
01186       else
01187         _top_size = 4;
01188 
01189       size_above_anchor = _top_size;
01190       int x = _anchorX - _padding;
01191       int y = _anchorY - _anchor_height / 2 - _top_size - _corner_radius - _padding;
01192 
01193       SetBaseX(x);
01194       SetBaseY(y);
01195     }
01196     else
01197     {
01198       _top_size = 0;
01199       size_above_anchor = -1;
01200       int x = _anchorX - _padding;
01201       int y = _anchorY - _anchor_height / 2 - _top_size - _corner_radius - _padding;
01202 
01203       SetBaseX(x);
01204       SetBaseY(y);
01205     }
01206   }
01207 
01208   float blur_coef         = 6.0f;
01209 
01210   nux::CairoGraphics cairo_bg(CAIRO_FORMAT_ARGB32, width, height);
01211   nux::CairoGraphics cairo_mask(CAIRO_FORMAT_ARGB32, width, height);
01212   nux::CairoGraphics cairo_outline(CAIRO_FORMAT_ARGB32, width, height);
01213 
01214   cairo_t* cr_bg      = cairo_bg.GetContext();
01215   cairo_t* cr_mask    = cairo_mask.GetContext();
01216   cairo_t* cr_outline = cairo_outline.GetContext();
01217 
01218   float   tint_color[4]    = {0.0f, 0.0f, 0.0f, 0.60f};
01219   float   hl_color[4]      = {1.0f, 1.0f, 1.0f, 0.35f};
01220   float   dot_color[4]     = {1.0f, 1.0f, 1.0f, 0.03f};
01221   float   shadow_color[4]  = {0.0f, 0.0f, 0.0f, 1.00f};
01222   float   outline_color[4] = {1.0f, 1.0f, 1.0f, 0.40f};
01223   float   mask_color[4]    = {1.0f, 1.0f, 1.0f, 1.00f};
01224 //   float   anchor_width      = 10;
01225 //   float   anchor_height     = 18;
01226 
01227   ql_tint_dot_hl(cr_bg,
01228                  width,
01229                  height,
01230                  width / 2.0f,
01231                  0,
01232                  nux::Max<float>(width / 1.6f, height / 1.6f),
01233                  tint_color,
01234                  hl_color,
01235                  dot_color);
01236 
01237   ql_compute_full_outline_shadow
01238   (
01239     cr_outline,
01240     cairo_outline.GetSurface(),
01241     width,
01242     height,
01243     _anchor_width,
01244     _anchor_height,
01245     size_above_anchor,
01246     _corner_radius,
01247     blur_coef,
01248     shadow_color,
01249     1.0f,
01250     _padding,
01251     outline_color);
01252 
01253   ql_compute_full_mask(
01254     cr_mask,
01255     cairo_mask.GetSurface(),
01256     width,
01257     height,
01258     _corner_radius,  // radius,
01259     16,             // shadow_radius,
01260     _anchor_width,   // anchor_width,
01261     _anchor_height,  // anchor_height,
01262     size_above_anchor,             // upper_size,
01263     true,           // negative,
01264     false,          // outline,
01265     1.0,            // line_width,
01266     _padding,        // padding_size,
01267     mask_color);
01268 
01269   cairo_destroy(cr_bg);
01270   cairo_destroy(cr_outline);
01271   cairo_destroy(cr_mask);
01272 
01273   texture_bg_ = texture_ptr_from_cairo_graphics(cairo_bg);
01274   texture_mask_ = texture_ptr_from_cairo_graphics(cairo_mask);
01275   texture_outline_ = texture_ptr_from_cairo_graphics(cairo_outline);
01276 
01277   _cairo_text_has_changed = false;
01278 
01279   // Request a redraw, so this area will be added to Compiz list of dirty areas.
01280   NeedRedraw();
01281 }
01282 
01283 void QuicklistView::PositionChildLayout(float offsetX, float offsetY)
01284 {
01285 }
01286 
01287 void QuicklistView::LayoutWindowElements()
01288 {
01289 }
01290 
01291 void QuicklistView::NotifyConfigurationChange(int width, int height)
01292 {
01293 }
01294 
01295 void QuicklistView::SetText(std::string const& text)
01296 {
01297   if (_labelText == text)
01298     return;
01299 
01300   _labelText = text;
01301   UpdateTexture();
01302 }
01303 
01304 void QuicklistView::TestMenuItems(DbusmenuMenuitem* root)
01305 {
01306   RemoveAllMenuItem();
01307 
01308   if (root == 0)
01309     return;
01310 
01311   GList* child = NULL;
01312   for (child = dbusmenu_menuitem_get_children(root); child != NULL; child = g_list_next(child))
01313   {
01314     const gchar* type = dbusmenu_menuitem_property_get((DbusmenuMenuitem*)child->data, DBUSMENU_MENUITEM_PROP_TYPE);
01315     const gchar* toggle_type = dbusmenu_menuitem_property_get((DbusmenuMenuitem*)child->data, DBUSMENU_MENUITEM_PROP_TOGGLE_TYPE);
01316 
01317     if (g_strcmp0(type, DBUSMENU_CLIENT_TYPES_SEPARATOR) == 0)
01318     {
01319       QuicklistMenuItemSeparator* item = new QuicklistMenuItemSeparator((DbusmenuMenuitem*)child->data, NUX_TRACKER_LOCATION);
01320       AddMenuItem(item);
01321     }
01322     else if (g_strcmp0(toggle_type, DBUSMENU_MENUITEM_TOGGLE_CHECK) == 0)
01323     {
01324       QuicklistMenuItemCheckmark* item = new QuicklistMenuItemCheckmark((DbusmenuMenuitem*)child->data, NUX_TRACKER_LOCATION);
01325       AddMenuItem(item);
01326     }
01327     else if (g_strcmp0(toggle_type, DBUSMENU_MENUITEM_TOGGLE_RADIO) == 0)
01328     {
01329       QuicklistMenuItemRadio* item = new QuicklistMenuItemRadio((DbusmenuMenuitem*)child->data, NUX_TRACKER_LOCATION);
01330       AddMenuItem(item);
01331     }
01332     else //if (g_strcmp0 (type, DBUSMENU_MENUITEM_PROP_LABEL) == 0)
01333     {
01334       QuicklistMenuItemLabel* item = new QuicklistMenuItemLabel((DbusmenuMenuitem*)child->data, NUX_TRACKER_LOCATION);
01335       AddMenuItem(item);
01336     }
01337   }
01338 }
01339 
01340 // Introspection
01341 
01342 std::string QuicklistView::GetName() const
01343 {
01344   return "Quicklist";
01345 }
01346 
01347 void QuicklistView::AddProperties(GVariantBuilder* builder)
01348 {
01349   variant::BuilderWrapper(builder)
01350     .add(GetAbsoluteGeometry())
01351     .add("base_x", GetBaseX())
01352     .add("base_y", GetBaseY())
01353     .add("active", IsVisible());
01354 }
01355 
01356 //
01357 // Key navigation
01358 //
01359 bool
01360 QuicklistView::InspectKeyEvent(unsigned int eventType,
01361                                unsigned int keysym,
01362                                const char* character)
01363 {
01364   // The Quicklist accepts all key inputs.
01365   return true;
01366 }
01367 
01368 QuicklistMenuItem*
01369 QuicklistView::GetSelectedMenuItem()
01370 {
01371   return GetNthItems(_current_item_index);
01372 }
01373 
01374 debug::Introspectable::IntrospectableList QuicklistView::GetIntrospectableChildren()
01375 {
01376   _introspectable_children.clear();
01377   for (auto item: _item_list)
01378   {
01379     _introspectable_children.push_back(item);
01380   }
01381   return _introspectable_children;
01382 }
01383 
01384 } // NAMESPACE