nux-1.16.0
ComboBoxSimple.cpp
00001 /*
00002  * Copyright 2010 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 
00023 #include "Nux.h"
00024 #include "ComboBoxSimple.h"
00025 #include "MenuPage.h"
00026 #include "ActionItem.h"
00027 #include "TableItem.h"
00028 #include "TableCtrl.h"
00029 #include "StaticText.h"
00030 
00031 
00032 namespace nux
00033 {
00034   ComboBoxSimple::ComboBoxSimple (NUX_FILE_LINE_DECL)
00035     :   AbstractComboBox (NUX_FILE_LINE_PARAM)
00036   {
00037     m_block_focus       = false;
00038     _can_pass_focus_to_composite_layout = false;
00039     m_SelectedAction    = 0;
00040     m_CurrentMenu       = 0;
00041 
00042     m_CurrentMenu = new MenuPage (TEXT (""), NUX_TRACKER_LOCATION);
00043     m_CurrentMenu->SinkReference();
00044     m_CurrentMenu->SetParentObject(this);
00045     
00046     // Set Signals
00047     _combo_box_opening_area->mouse_down.connect (sigc::mem_fun (this, &ComboBoxSimple::RecvMouseDown));
00048     _combo_box_opening_area->mouse_up.connect (sigc::mem_fun (this, &ComboBoxSimple::RecvMouseUp));
00049     _combo_box_area->mouse_down.connect (sigc::mem_fun (this, &ComboBoxSimple::RecvMouseDown));
00050     _combo_box_area->mouse_up.connect (sigc::mem_fun (this, &ComboBoxSimple::RecvMouseUp));
00051 
00052     //m_Popup.sigPopupStop.connect(sigc::mem_fun(this, &ComboBox::OnPopupStop));
00053 
00054     // Set Geometry
00055     _combo_box_opening_area->SetGeometry (Geometry (0, 0, 20, DEFAULT_WIDGET_HEIGHT));
00056     //_combo_box_opening_area->SetMaximumSize(20, DEFAULT_WIDGET_HEIGHT);
00057     _combo_box_opening_area->SetMinimumSize (20, DEFAULT_WIDGET_HEIGHT);
00058 
00059     _combo_box_area->SetMinimumSize (2 * DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT);
00060     _combo_box_area->SetGeometry (Geometry (0, 0, 3 * DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT));
00061     _pango_static_text->SetClipping (_combo_box_area->GetBaseWidth());
00062     _combo_box_area->OnGeometryChanged.connect (sigc::mem_fun (this, &ComboBoxSimple::RecvGeometryChanged));
00063 
00064     //m_CurrentMenu = new MenuPage;
00065     m_CurrentMenu->SetParentMenu(0);
00066     m_CurrentMenu->sigActionTriggered.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvSigActionTriggered));
00067     m_CurrentMenu->sigTerminateMenuCascade.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvSigTerminateMenuCascade));
00068     m_CurrentMenu->sigClosingMenu.connect(sigc::mem_fun(this, &ComboBoxSimple::RecvClosingMenuSignal));
00069   }
00070 
00071   ComboBoxSimple::~ComboBoxSimple()
00072   {
00073     m_CurrentMenu->UnParentObject();
00074     m_CurrentMenu->UnReference();
00075   }
00076 
00077   void ComboBoxSimple::DoSetFocused (bool focused)
00078   {
00079     View::DoSetFocused (focused);
00080     if (focused == true)
00081     {
00082       m_block_focus = true;
00083       // we need to grab focus control from our parent layout
00084       // so that we can handle the key inputs ourself
00085       Area *_parent = GetParentObject();
00086       if (_parent == NULL)
00087         return;
00088 
00089       if (_parent->IsView ())
00090       {
00091         View *parent = (View*)_parent;
00092         parent->SetFocusControl (false);
00093       }
00094       else if (_parent->IsLayout ())
00095       {
00096         Layout *parent = (Layout *)_parent;
00097         parent->SetFocusControl (false);
00098       }
00099     }
00100     QueueDraw();
00101   }
00102 
00103   long ComboBoxSimple::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo)
00104   {
00105     long ret = TraverseInfo;
00106 
00107     //ret = m_Popup.ProcessEvent(ievent, ret, ProcessEventInfo); // implement isVisible on InputArea. If invisible, no event processed.
00108     ret = _combo_box_opening_area->OnEvent (ievent, ret, ProcessEventInfo);
00109     ret = _combo_box_area->OnEvent (ievent, ret, ProcessEventInfo);
00110 
00111     if (ievent.e_event == NUX_MOUSE_PRESSED)
00112     {
00113       bool mouse_down_on_menu_item = false;
00114 
00115       if (m_MenuIsActive == true)
00116       {
00117         if (_combo_box_opening_area->IsMouseInside() || _combo_box_area->IsMouseInside() )
00118           mouse_down_on_menu_item = true;
00119 
00120         if (mouse_down_on_menu_item == false)
00121         {
00122           if (m_CurrentMenu->TestMouseDown() == false)
00123           {
00124             RecvSigTerminateMenuCascade();
00125             m_MenuIsActive = false;
00126           }
00127         }
00128       }
00129     }
00130 
00131     /* must do focus processing after sending events to children */
00132     if (ievent.e_event == NUX_KEYDOWN && GetFocused () && m_block_focus == false)
00133     {
00134       FocusDirection direction;
00135       FocusEventType type;
00136 
00137       direction = FOCUS_DIRECTION_NONE;
00138 
00139       type = Focusable::GetFocusableEventType (ievent.e_event,
00140                                                ievent.GetKeySym(),
00141                                                ievent.GetText(),
00142                                                &direction);
00143       if (type == FOCUS_EVENT_DIRECTION)
00144       {
00145         if (direction == FOCUS_DIRECTION_PREV || direction == FOCUS_DIRECTION_NEXT ||
00146           direction == FOCUS_DIRECTION_LEFT || direction == FOCUS_DIRECTION_RIGHT)
00147         {
00148           // not pressed UP or Down so send focus to our parent layout
00149           Area *area = GetParentObject ();
00150           // if parent is null return, thats a valid usecase so no warnings.
00151           if (area)
00152           {
00153             long ret = 0;
00154             if ( area->IsView() )
00155             {
00156               View *ic = static_cast<View *>(area);
00157               ic->SetFocusControl (true);
00158               ret = ic->ProcessFocusEvent (ievent, ret, ProcessEventInfo);
00159             }
00160             else if ( area->IsLayout() )
00161             {
00162               Layout *layout = static_cast<Layout *>(area);
00163               layout->SetFocusControl (true);
00164               ret = layout->ProcessFocusEvent (ievent, ret, ProcessEventInfo);
00165             }
00166           }
00167         }
00168         else if (direction == FOCUS_DIRECTION_UP)
00169         {
00170           MoveSelectionUp ();
00171           sigTriggered.emit (this);
00172           sigActionTriggered.emit (GetItem (GetSelectionIndex ()));
00173         }
00174         else if (direction == FOCUS_DIRECTION_DOWN)
00175         {
00176           MoveSelectionDown ();
00177           sigTriggered.emit (this);
00178           sigActionTriggered.emit (GetItem (GetSelectionIndex ()));
00179         }
00180       }
00181     }
00182 
00183     if (m_block_focus == true)
00184       m_block_focus = false;
00185 
00186     ret = PostProcessEvent2 (ievent, ret, ProcessEventInfo);
00187     return ret;
00188   }
00189 
00190   Area* ComboBoxSimple::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00191   {
00192     bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00193 
00194     if(mouse_inside == false)
00195       return NULL;
00196 
00197     NUX_RETURN_VALUE_IF_TRUE(_combo_box_opening_area->TestMousePointerInclusion(mouse_position, event_type), _combo_box_opening_area);
00198     NUX_RETURN_VALUE_IF_TRUE(_combo_box_area->TestMousePointerInclusion(mouse_position, event_type), _combo_box_area);
00199 
00200     if((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent()))
00201       return NULL;
00202     return this;
00203   }
00204 
00205   void ComboBoxSimple::MoveSelectionUp ()
00206   {
00207     int current_index = GetSelectionIndex ();
00208     SetSelectionIndex (current_index - 1);
00209   }
00210 
00211   void ComboBoxSimple::MoveSelectionDown ()
00212   {
00213     int current_index = GetSelectionIndex ();
00214     SetSelectionIndex (current_index + 1);
00215   }
00216 
00217   ActionItem *ComboBoxSimple::AddItem (const TCHAR *label, int Uservalue)
00218   {
00219     if (m_CurrentMenu->GetNumItem() == 0)
00220     {
00221       // The first element added is the element featured on the combo box when it is closed.
00222       m_SelectedAction = m_CurrentMenu->AddAction (label, Uservalue);
00223       _combo_box_area->SetBaseString (m_SelectedAction->GetLabel ());
00224 
00225       _pango_static_text->SetText (m_SelectedAction->GetLabel ());
00226 
00227       return m_SelectedAction;
00228     }
00229     else
00230     {
00231       return m_CurrentMenu->AddAction (label, Uservalue);
00232     }
00233   }
00234 
00235   void ComboBoxSimple::RemoveItem (ActionItem *item)
00236   {
00237 
00238   }
00239 
00240   void ComboBoxSimple::RemoveAllItem()
00241   {
00242     m_CurrentMenu->RemoveAllItem();
00243   }
00244 
00245   void ComboBoxSimple::RecvMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags)
00246   {
00247     if (m_MenuIsActive == false)
00248     {
00249       // Open the MenuPage
00250       m_MenuIsActive = true;
00251       m_IsOpeningMenu = true;
00252 
00253       Geometry geo = m_CurrentMenu->GetGeometry();
00254       geo.SetX (_combo_box_area->GetAbsoluteX() );
00255       geo.SetY (_combo_box_area->GetAbsoluteY() + _combo_box_area->GetBaseHeight() );
00256       geo.SetWidth (_combo_box_area->GetBaseWidth() );
00257       //m_CurrentMenu->SetMinimumWidth (geo.width);
00258       //m_CurrentMenu->SetMaximumWidth (geo.width);
00259       m_CurrentMenu->SetGeometry (geo);
00260       m_CurrentMenu->ComputeChildLayout ();
00261       m_CurrentMenu->StartMenu (_combo_box_area->GetAbsoluteX(),
00262                                 _combo_box_area->GetAbsoluteY() + _combo_box_area->GetBaseHeight(),
00263                                 0, 0);
00264     }
00265     else
00266     {
00267       // If the mouse up that follows happen inside the area, then it is going to close the menu.
00268       m_IsOpeningMenu = false;
00269     }
00270 
00271     QueueDraw();
00272   }
00273 
00274   void ComboBoxSimple::RecvMouseUp (int x, int y, unsigned long button_flags, unsigned long key_flags)
00275   {
00276     if (m_MenuIsActive)
00277     {
00278       if (_combo_box_area->IsMouseInside() || _combo_box_opening_area->IsMouseInside() )
00279       {
00280         if (m_IsOpeningMenu == false)
00281         {
00282           // close the MenuPage that is Open
00283           m_CurrentMenu->StopMenu (0, 0);
00284           m_MenuIsActive = false;
00285         }
00286         else
00287         {
00288           // The MousePress before this MouseRelease, caused the MenuPage to open.
00289           // Set m_IsOpeningMenu so the next mouse release will close the menu.
00290           m_IsOpeningMenu = false;
00291           m_MenuIsActive = true;
00292         }
00293       }
00294       else
00295       {
00296         bool hit_inside_a_menu = false;
00297         bool b = m_CurrentMenu->TestMouseUp (x, y, button_flags, key_flags, hit_inside_a_menu);
00298 
00299         if (b || (hit_inside_a_menu == false) )
00300         {
00301           RecvSigTerminateMenuCascade();
00302           m_MenuIsActive = false;
00303         }
00304       }
00305     }
00306 
00307     QueueDraw();
00308   }
00309 
00310   void ComboBoxSimple::RecvSigActionTriggered (MenuPage *menu, ActionItem *action)
00311   {
00312     m_MenuIsActive = false;
00313     m_CurrentMenu->StopMenu();
00314 
00315     m_SelectedAction = action;
00316     _combo_box_area->SetBaseString(m_SelectedAction->GetLabel());
00317     m_IsOpeningMenu = false;
00318 
00319     _pango_static_text->SetText(m_SelectedAction->GetLabel());
00320 
00321     sigTriggered.emit (this);
00322     sigActionTriggered.emit (m_SelectedAction);
00323 
00324     QueueDraw();
00325     // You can do something if you want with the menu* and the action*
00326   }
00327 
00328   void ComboBoxSimple::RecvSigActionTriggered2(TableCtrl *table, TableItem *item, unsigned int row, unsigned int column)
00329   {
00330     m_MenuIsActive = false;
00331     m_CurrentMenu->StopMenu();
00332     m_IsOpeningMenu = false;
00333     QueueDraw();
00334     // You can do something if you want with the menu* and the action*
00335   }
00336 
00337   void ComboBoxSimple::RecvSigTerminateMenuCascade()
00338   {
00339     //m_MenuIsActive = false;
00340     m_CurrentMenu->StopMenu();
00341     m_IsOpeningMenu = false;
00342   }
00343 
00344   void ComboBoxSimple::RecvClosingMenuSignal(MenuPage* menu_page)
00345   {
00346     nuxAssert(menu_page == m_CurrentMenu);
00347     m_IsOpeningMenu = false;
00348     m_MenuIsActive = false;
00349 
00350     // When the menu is closing check if the mouse is still inside the combo box surface 
00351     // and set the _current_mouse_in flag accordingly.  
00352     if(!_combo_box_area->TestMousePointerInclusion(GetWindowCompositor().GetMousePosition(), NUX_NO_EVENT))
00353     {
00354       _combo_box_area->_event_processor._current_mouse_in = false;
00355     }
00356 
00357     if(!_combo_box_opening_area->TestMousePointerInclusion(GetWindowCompositor().GetMousePosition(), NUX_NO_EVENT))
00358     {
00359       _combo_box_opening_area->_event_processor._current_mouse_in = false;
00360     }
00361 
00362     QueueDraw();
00363   }
00364 
00365   void ComboBoxSimple::RecvGeometryChanged(Area *area, Geometry &geo)
00366   {
00367           _pango_static_text->SetClipping (geo.width);
00368   }
00369 
00370 
00371   const TCHAR *ComboBoxSimple::GetSelectionLabel() const
00372   {
00373     if (m_SelectedAction)
00374       return m_SelectedAction->GetLabel();
00375 
00376     return 0;
00377   }
00378 
00379   int ComboBoxSimple::GetSelectionUserValue() const
00380   {
00381     if (m_SelectedAction)
00382       return m_SelectedAction->GetUserValue();
00383 
00384     return 0;
00385   }
00386 
00387   int ComboBoxSimple::GetNumItem() const
00388   {
00389     return m_CurrentMenu->GetNumItem();
00390   }
00391 
00392   ActionItem *ComboBoxSimple::GetItem (int index) const
00393   {
00394     return m_CurrentMenu->GetActionItem (index);
00395   }
00396 
00397   int ComboBoxSimple::GetSelectionIndex() const
00398   {
00399     if (m_SelectedAction)
00400       return m_CurrentMenu->GetActionItemIndex (m_SelectedAction);
00401 
00402     return -1;
00403   }
00404 
00405   void ComboBoxSimple::SetSelectionIndex (int index)
00406   {
00407     if ((index >= 0) && (index < m_CurrentMenu->GetNumItem ()))
00408     {
00409       m_SelectedAction = m_CurrentMenu->GetActionItem (index);
00410       _combo_box_area->SetBaseString (m_SelectedAction->GetLabel ());
00411 
00412       _pango_static_text->SetText (m_SelectedAction->GetLabel ());
00413 
00414       QueueDraw ();
00415     }
00416     else if (m_CurrentMenu->GetNumItem() > 0)
00417     {
00418       // index is negative
00419       m_SelectedAction = m_CurrentMenu->GetActionItem (0);
00420       _combo_box_area->SetBaseString (m_SelectedAction->GetLabel ());
00421 
00422       _pango_static_text->SetText (m_SelectedAction->GetLabel ());
00423 
00424       QueueDraw();
00425     }
00426     else
00427     {
00428       m_SelectedAction = 0;
00429     }
00430   }
00431 
00432 
00433 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends