nux-1.14.0
|
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 }