nux-1.16.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: Neil Jagdish Patel <neil.patel@canonical.com> 00019 * 00020 */ 00021 00022 00023 #include "Nux.h" 00024 #include "View.h" 00025 #include "LayeredLayout.h" 00026 00027 #include <math.h> 00028 00029 namespace nux 00030 { 00031 class LayeredChildProperties : public Area::LayoutProperties 00032 { 00033 public: 00034 00035 LayeredChildProperties (bool expand, int x, int y, int width, int height) 00036 : m_expand (expand), 00037 m_x (x), 00038 m_y (y), 00039 m_width (width), 00040 m_height (height) 00041 { 00042 00043 } 00044 00045 ~LayeredChildProperties () 00046 { 00047 } 00048 00049 void Update (bool expand, int x, int y, int width, int height) 00050 { 00051 m_expand = expand; 00052 m_x = x; 00053 m_y = y; 00054 m_width = width; 00055 m_height = height; 00056 } 00057 00058 bool m_expand; 00059 int m_x; 00060 int m_y; 00061 int m_width; 00062 int m_height; 00063 00064 sigc::signal<void, Area *, bool>::iterator m_vis_it; 00065 }; 00066 00067 NUX_IMPLEMENT_OBJECT_TYPE (LayeredLayout); 00068 00069 LayeredLayout::LayeredLayout (NUX_FILE_LINE_DECL) 00070 : Layout (NUX_FILE_LINE_PARAM), 00071 m_active_index (0), 00072 m_active_area (NULL), 00073 m_paint_all (false), 00074 m_input_mode (INPUT_MODE_ACTIVE), 00075 m_child_draw_queued (false) 00076 { 00077 m_ContentStacking = eStackLeft; 00078 OnChildQueueDraw.connect (sigc::mem_fun (this, &LayeredLayout::ChildQueueDraw)); 00079 } 00080 00081 LayeredLayout::~LayeredLayout() 00082 { 00083 } 00084 00085 long LayeredLayout::DoFocusPrev (IEvent &ievent, long TraverseInfo, long ProcessEventInfo) 00086 { 00087 if (GetInputMode () == INPUT_MODE_ACTIVE) 00088 { 00089 Area *parent = GetParentObject (); 00090 if (parent != NULL) 00091 return SendEventToArea (parent, ievent, TraverseInfo, ProcessEventInfo); 00092 } 00093 else 00094 { 00095 return Layout::DoFocusPrev (ievent, TraverseInfo, ProcessEventInfo); 00096 } 00097 00098 return TraverseInfo; 00099 } 00100 00101 long LayeredLayout::DoFocusNext (IEvent &ievent, long TraverseInfo, long ProcessEventInfo) 00102 { 00103 if (GetInputMode () == INPUT_MODE_ACTIVE) 00104 { 00105 Area *parent = GetParentObject (); 00106 if (parent != NULL) 00107 return SendEventToArea (parent, ievent, TraverseInfo, ProcessEventInfo); 00108 } 00109 else 00110 { 00111 return Layout::DoFocusNext (ievent, TraverseInfo, ProcessEventInfo); 00112 } 00113 00114 return TraverseInfo; 00115 } 00116 void LayeredLayout::GetCompositeList (std::list<Area *> *ViewList) 00117 { 00118 std::list<Area *>::iterator it; 00119 00120 for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) 00121 { 00122 if ( (*it)->IsView() ) 00123 { 00124 View *ic = NUX_STATIC_CAST (View *, (*it) ); 00125 ViewList->push_back (ic); 00126 } 00127 else if ( (*it)->IsLayout() ) 00128 { 00129 Layout *layout = NUX_STATIC_CAST (Layout *, (*it) ); 00130 layout->GetCompositeList (ViewList); 00131 } 00132 } 00133 } 00134 00135 long LayeredLayout::ComputeLayout2() 00136 { 00137 nux::Geometry base = GetGeometry(); 00138 std::list<Area *>::iterator it; 00139 int total_max_width = 0; 00140 int total_max_height = 0; 00141 int ret = 0; 00142 00143 for (it = _layout_element_list.begin (); it != _layout_element_list.end (); ++it) 00144 { 00145 Area *area = *it; 00146 LayeredChildProperties *props; 00147 Geometry geo = base; 00148 00149 props = dynamic_cast<LayeredChildProperties *> (area->GetLayoutProperties ()); 00150 00151 if (props->m_expand) 00152 { 00153 int max_width, max_height; 00154 00155 // It wants to expand, however we need to check that it doesn't need at minimum more 00156 // space than we have 00157 max_width = MAX (base.width, area->GetMinimumWidth ()); 00158 max_height = MAX (base.height, area->GetMinimumHeight ()); 00159 00160 geo.width = max_width; 00161 geo.height = max_height; 00162 00163 total_max_width = MAX (total_max_width, max_width); 00164 total_max_height = MAX (total_max_height, max_height); 00165 } 00166 else 00167 { 00168 geo.x = base.x + props->m_x; 00169 geo.y = base.y + props->m_y; 00170 geo.width = props->m_width; 00171 geo.height = props->m_height; 00172 } 00173 00174 (*it)->SetGeometry (geo); 00175 (*it)->ComputeLayout2 (); 00176 } 00177 00178 SetBaseSize (total_max_width, total_max_height); 00179 00180 if (base.width < total_max_width) 00181 ret |= eLargerWidth; 00182 else 00183 ret |= eCompliantWidth; // We don't complain about getting more space 00184 00185 if (base.height < total_max_height) 00186 ret |= eLargerHeight; 00187 else 00188 ret |= eCompliantHeight; // Don't complain about getting more space 00189 00190 return ret; 00191 } 00192 00193 void LayeredLayout::PaintOne (Area *_area, GraphicsEngine &gfx_context, bool force_draw) 00194 { 00195 if (_area->IsArea ()) 00196 { 00197 InputArea *area = NUX_STATIC_CAST (InputArea *, _area); 00198 area->OnDraw (gfx_context, force_draw); 00199 } 00200 else if (_area->IsView ()) 00201 { 00202 View *ic = NUX_STATIC_CAST (View *, _area); 00203 ic->ProcessDraw (gfx_context, force_draw); 00204 } 00205 else if (_area->IsLayout ()) 00206 { 00207 Layout *layout = NUX_STATIC_CAST (Layout *, _area); 00208 layout->ProcessDraw (gfx_context, force_draw); 00209 } 00210 } 00211 00212 void LayeredLayout::ProcessDraw (GraphicsEngine &gfx_context, bool force_draw) 00213 { 00214 Geometry base = GetGeometry (); 00215 gfx_context.PushClippingRectangle (base); 00216 00217 if (m_paint_all) 00218 { 00219 std::list<Area *>::iterator it, eit = _layout_element_list.end (); 00220 t_u32 alpha = 0, src = 0, dest = 0; 00221 00222 gfx_context.GetRenderStates ().GetBlend (alpha, src, dest); 00223 gfx_context.GetRenderStates ().SetBlend (true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 00224 00225 nux::GetPainter().PaintBackground(gfx_context, base); 00226 nux::GetPainter().PushBackgroundStack(); 00227 00228 for (it = _layout_element_list.begin (); it != eit; ++it) 00229 { 00230 if ((*it)->IsVisible ()) 00231 PaintOne (static_cast<Area *> (*it), gfx_context, true); 00232 } 00233 00234 nux::GetPainter().PopBackgroundStack(); 00235 00236 gfx_context.GetRenderStates ().SetBlend (alpha, src, dest); 00237 00238 m_child_draw_queued = false; 00239 } 00240 else if (m_active_area && m_active_area->IsVisible ()) 00241 { 00242 PaintOne (m_active_area, gfx_context, force_draw); 00243 } 00244 00245 gfx_context.PopClippingRectangle (); 00246 _queued_draw = false; 00247 } 00248 00249 Area* LayeredLayout::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) 00250 { 00251 if(m_active_area == NULL) 00252 return NULL; 00253 00254 bool mouse_inside = m_active_area->TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); 00255 00256 if(mouse_inside == false) 00257 return NULL; 00258 00259 if(m_input_mode == INPUT_MODE_ACTIVE) 00260 { 00261 if (m_active_area && m_active_area->IsVisible () && m_active_area->IsSensitive ()) 00262 return m_active_area->FindAreaUnderMouse(mouse_position, event_type); 00263 } 00264 else 00265 { 00266 std::list<Area *>::reverse_iterator it, eit = _layout_element_list.rend (); 00267 00268 for (it = _layout_element_list.rbegin (); it != eit; ++it) 00269 { 00270 Area *area = (*it); 00271 00272 if (area->IsVisible () && area->IsSensitive ()) 00273 { 00274 return m_active_area->FindAreaUnderMouse(mouse_position, event_type); 00275 } 00276 } 00277 } 00278 00279 return NULL; 00280 } 00281 00282 void LayeredLayout::AddLayout (Layout *layout, 00283 unsigned int stretch_factor, 00284 MinorDimensionPosition positioning, 00285 MinorDimensionSize extend, 00286 float percentage) 00287 { 00288 AddLayer (layout); 00289 } 00290 00291 void LayeredLayout::AddView (Area *view, 00292 unsigned int stretch_factor, 00293 MinorDimensionPosition positioning, 00294 MinorDimensionSize extend, 00295 float percentage) 00296 { 00297 AddLayer (view); 00298 } 00299 00300 void LayeredLayout::RemoveChildObject (Area *area) 00301 { 00302 RemoveLayer (area); 00303 } 00304 00305 void LayeredLayout::Clear () 00306 { 00307 m_active_index = 0; 00308 m_active_area = NULL; 00309 00310 Layout::Clear (); 00311 } 00312 00313 void LayeredLayout::ChildQueueDraw (Area *area) 00314 { 00315 m_child_draw_queued = true; 00316 } 00317 00318 void LayeredLayout::ChildVisibilityChanged (Area *area, bool visible) 00319 { 00320 QueueDraw (); 00321 } 00322 00323 // 00324 // LayeredLayout Methods 00325 // 00326 void LayeredLayout::AddLayer (Area *area, bool expand, int x, int y, int width, int height) 00327 { 00328 LayeredChildProperties *props; 00329 00330 // return if the area is NULL 00331 NUX_RETURN_IF_NULL(area); 00332 // Return if the area already has a parent 00333 NUX_RETURN_IF_NOTNULL(area->GetParentObject ()); 00334 00335 props = new LayeredChildProperties (expand, x, y, width, height); 00336 area->SetLayoutProperties (props); 00337 00338 if (!m_active_area) 00339 { 00340 m_active_area = area; 00341 } 00342 00343 props->m_vis_it = area->OnVisibleChanged.connect (sigc::mem_fun (this, &LayeredLayout::ChildVisibilityChanged)); 00344 00345 if (area->IsLayout ()) 00346 Layout::AddLayout (static_cast<Layout *> (area)); 00347 else 00348 Layout::AddView (area); 00349 00350 QueueDraw (); 00351 } 00352 00353 void LayeredLayout::UpdateLayer (Area *area, bool expand, int x, int y, int width, int height) 00354 { 00355 LayeredChildProperties *props; 00356 00357 NUX_RETURN_IF_NULL(area); 00358 00359 props = dynamic_cast<LayeredChildProperties *>(area->GetLayoutProperties ()); 00360 NUX_RETURN_IF_NULL(props); 00361 00362 props->Update (expand, x, y, width, height); 00363 00364 QueueDraw (); 00365 } 00366 00367 void LayeredLayout::RemoveLayer (Area *area) 00368 { 00369 LayeredChildProperties *props; 00370 00371 NUX_RETURN_IF_NULL(area); 00372 00373 props = dynamic_cast<LayeredChildProperties *>(area->GetLayoutProperties ()); 00374 NUX_RETURN_IF_NULL(props); 00375 00376 (*props->m_vis_it).disconnect (); 00377 area->SetLayoutProperties (NULL); 00378 00379 00380 if (m_active_area == area) 00381 { 00382 std::list<Area *>::iterator it, eit = _layout_element_list.end (); 00383 int i = 0; 00384 00385 m_active_index = 0; 00386 m_active_area = NULL; 00387 for (it = _layout_element_list.begin (); it != eit; ++it) 00388 { 00389 if (*it != area) 00390 { 00391 m_active_area = static_cast<Area *> (*it); 00392 m_active_index = i; 00393 break; 00394 } 00395 i++; 00396 } 00397 } 00398 00399 Layout::RemoveChildObject (area); 00400 } 00401 00402 void LayeredLayout::SetActiveLayerN (int index_) 00403 { 00404 std::list<Area *>::iterator it, eit = _layout_element_list.end (); 00405 int i = 0; 00406 00407 NUX_RETURN_IF_FALSE((t_uint32)index_ < _layout_element_list.size ()); 00408 00409 if (index_ == m_active_index) 00410 return; 00411 00412 m_active_index = index_; 00413 m_active_area = NULL; 00414 bool is_focused = GetFocused (); 00415 00416 for (it = _layout_element_list.begin (); it != eit; ++it) 00417 { 00418 if (i == m_active_index && !m_active_area) 00419 { 00420 m_active_area = static_cast<Area *> (*it); 00421 } 00422 00423 if ((*it)->IsView ()) 00424 { 00425 static_cast<View *> (*it)->QueueDraw (); 00426 if (is_focused) 00427 static_cast<View *> (*it)->SetFocused (true); 00428 } 00429 else if ((*it)->IsLayout ()) 00430 { 00431 static_cast<Layout *> (*it)->QueueDraw (); 00432 if (is_focused) 00433 static_cast<Layout *> (*it)->SetFocused (true); 00434 } 00435 00436 i++; 00437 } 00438 00439 QueueDraw (); 00440 } 00441 00442 int LayeredLayout::GetActiveLayerN () 00443 { 00444 return m_active_index; 00445 } 00446 00447 void LayeredLayout::SetActiveLayer (Area *area) 00448 { 00449 std::list<Area *>::iterator it, eit = _layout_element_list.end (); 00450 int i = 0; 00451 00452 for (it = _layout_element_list.begin (); it != eit; ++it) 00453 { 00454 Area *a = static_cast<Area *> (*it); 00455 00456 if (area == a) 00457 { 00458 SetActiveLayerN (i); 00459 return; 00460 } 00461 i++; 00462 } 00463 nuxDebugMsg("[LayeredLayout::LowerBottom] Area (%p) is not a child of LayeredLayout (%p)", area, this); 00464 } 00465 00466 void LayeredLayout::OnLayerGeometryChanged(Area* area, Geometry geo) 00467 { 00468 // Set the LayeredLayout to the same saize as the active layer; 00469 if(area && (area == m_active_area)) 00470 { 00471 SetGeometry(geo); 00472 } 00473 } 00474 00475 Area * LayeredLayout::GetActiveLayer () 00476 { 00477 return m_active_area; 00478 } 00479 00480 void LayeredLayout::SetPaintAll (bool paint_all) 00481 { 00482 if (m_paint_all == paint_all) 00483 return; 00484 00485 m_paint_all = paint_all; 00486 QueueDraw (); 00487 } 00488 00489 bool LayeredLayout::GetPaintAll () 00490 { 00491 return m_paint_all; 00492 } 00493 00494 void LayeredLayout::SetInputMode (LayeredLayout::InputMode input_mode) 00495 { 00496 if (m_input_mode == input_mode) 00497 return; 00498 00499 m_input_mode = input_mode; 00500 } 00501 00502 LayeredLayout::InputMode LayeredLayout::GetInputMode () 00503 { 00504 return m_input_mode; 00505 } 00506 00507 void LayeredLayout::Raise (Area *area, Area *above) 00508 { 00509 std::list<Area *>::iterator it, eit = _layout_element_list.end (); 00510 std::list<Area *>::iterator area_it = eit; 00511 std::list<Area *>::iterator above_it = eit; 00512 00513 NUX_RETURN_IF_NULL(area); 00514 NUX_RETURN_IF_NULL(above); 00515 00516 for (it = _layout_element_list.begin (); it != eit; ++it) 00517 { 00518 if (above == (*it)) 00519 above_it = it; 00520 else if (area == (*it)) 00521 area_it = it; 00522 } 00523 00524 if (area_it == eit) 00525 { 00526 nuxDebugMsg("[LayeredLayout::Raise] Area %p is not a valid layer", area); 00527 return; 00528 } 00529 if (above_it == eit) 00530 { 00531 nuxDebugMsg("[LayeredLayout::Raise] Area %p is not a valid layer", above); 00532 return; 00533 } 00534 00535 _layout_element_list.erase (area_it); 00536 _layout_element_list.insert (++above_it, area); 00537 } 00538 00539 void LayeredLayout::Lower (Area *area, Area *below) 00540 { 00541 std::list<Area *>::iterator it, eit = _layout_element_list.end (); 00542 std::list<Area *>::iterator area_it = eit; 00543 std::list<Area *>::iterator below_it = eit; 00544 00545 NUX_RETURN_IF_NULL(area); 00546 NUX_RETURN_IF_NULL(below); 00547 00548 for (it = _layout_element_list.begin (); it != eit; ++it) 00549 { 00550 if (below == (*it)) 00551 below_it = it; 00552 else if (area == (*it)) 00553 area_it = it; 00554 } 00555 00556 if (area_it == eit) 00557 { 00558 nuxDebugMsg("[LayeredLayout::Lower] Area %p is not a valid layer", area); 00559 return; 00560 } 00561 if (below_it == eit) 00562 { 00563 nuxDebugMsg("[LayeredLayout::Lower] Area %p is not a valid layer", below); 00564 return; 00565 } 00566 00567 _layout_element_list.erase (area_it); 00568 _layout_element_list.insert (below_it, area); 00569 } 00570 00571 void LayeredLayout::RaiseTop (Area *area) 00572 { 00573 std::list<Area *>::iterator it, eit = _layout_element_list.end (); 00574 std::list<Area *>::iterator area_it = eit; 00575 00576 NUX_RETURN_IF_NULL(area); 00577 00578 for (it = _layout_element_list.begin (); it != eit; ++it) 00579 { 00580 if (area == (*it)) 00581 area_it = it; 00582 } 00583 00584 if (area_it == eit) 00585 { 00586 nuxDebugMsg("[LayeredLayout::RaiseTop] Area %p is not a valid layer", area); 00587 return; 00588 } 00589 00590 _layout_element_list.erase (area_it); 00591 _layout_element_list.insert (eit, area); 00592 } 00593 00594 void LayeredLayout::LowerBottom (Area *area) 00595 { 00596 std::list<Area *>::iterator it, eit = _layout_element_list.end (); 00597 std::list<Area *>::iterator area_it = eit; 00598 00599 NUX_RETURN_IF_NULL(area); 00600 00601 for (it = _layout_element_list.begin (); it != eit; ++it) 00602 { 00603 if (area == (*it)) 00604 area_it = it; 00605 } 00606 00607 if (area_it == eit) 00608 { 00609 nuxDebugMsg("[LayeredLayout::LowerBottom] Area %p is not a valid layer", area); 00610 return; 00611 } 00612 00613 _layout_element_list.erase (area_it); 00614 _layout_element_list.insert (_layout_element_list.begin (), area); 00615 } 00616 00617 bool LayeredLayout::FocusFirstChild () 00618 { 00619 if (m_input_mode == INPUT_MODE_ACTIVE) 00620 { 00621 m_active_area->SetFocused (true); 00622 return true; 00623 } 00624 else 00625 return Layout::FocusFirstChild (); 00626 } 00627 00628 bool LayeredLayout::FocusLastChild () 00629 { 00630 if (m_input_mode == INPUT_MODE_ACTIVE) 00631 { 00632 m_active_area->SetFocused (true); 00633 return true; 00634 } 00635 else 00636 return Layout::FocusLastChild (); 00637 } 00638 00639 Area* LayeredLayout::KeyNavIteration(KeyNavDirection direction) 00640 { 00641 if (m_active_area == NULL) 00642 return NULL; 00643 00644 if (m_active_area->IsVisible() == false) 00645 return NULL; 00646 00647 if (next_object_to_key_focus_area_) 00648 { 00649 return NULL; 00650 } 00651 else 00652 { 00653 return m_active_area->KeyNavIteration(direction); 00654 } 00655 00656 return NULL; 00657 } 00658 }