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 "View.h" 00025 #include "GridVLayout.h" 00026 #include "HLayout.h" 00027 #include "VLayout.h" 00028 00029 namespace nux 00030 { 00031 00032 static const t_s32 VERROR = 0; 00033 NUX_IMPLEMENT_OBJECT_TYPE (GridVLayout); 00034 00035 GridVLayout::GridVLayout (NUX_FILE_LINE_DECL) 00036 : Layout (NUX_FILE_LINE_PARAM) 00037 { 00038 #if DEBUG_LAYOUT 00039 m_h_in_margin = 10; 00040 m_h_out_margin = 10; 00041 m_v_in_margin = 10; 00042 m_v_out_margin = 10; 00043 #endif 00044 00045 _children_size = Size (64, 64); 00046 _force_children_size = true; 00047 _partial_visibility = true; 00048 _num_row = 1; 00049 _num_column = 1; 00050 _dynamic_column = true; 00051 _width_match_content = true; 00052 00053 // Start packing the elements from the top. Is the layout has more space than the elements can use, 00054 // leave that space at the bottom of the GridVLayout. 00055 m_ContentStacking = eStackLeft; 00056 00057 SetMinimumSize(32, 32); 00058 } 00059 00060 GridVLayout::~GridVLayout() 00061 { 00062 00063 } 00064 00065 int GridVLayout::GetChildPos (Area *child) 00066 { 00067 int position = 0; 00068 std::list<Area *>::const_iterator it; 00069 for (it = GetChildren ().begin(); it != GetChildren ().end(); it++) 00070 { 00071 if ((*it) == child) 00072 break; 00073 00074 if ((*it)->CanFocus ()) 00075 { 00076 position++; 00077 } 00078 } 00079 00080 return position; 00081 } 00082 00083 Area* GridVLayout::GetChildAtPosition (int pos) 00084 { 00085 int position = 0; 00086 std::list<Area *>::const_iterator it; 00087 for (it = GetChildren ().begin(); it != GetChildren ().end(); it++) 00088 { 00089 if (position == pos) 00090 return (*it); 00091 00092 if ((*it)->CanFocus ()) 00093 { 00094 position++; 00095 } 00096 } 00097 00098 return NULL; 00099 } 00100 00101 void GridVLayout::EnablePartialVisibility (bool partial_visibility) 00102 { 00103 _partial_visibility = partial_visibility; 00104 } 00105 00106 void GridVLayout::SetChildrenSize (int width, int height) 00107 { 00108 _children_size = Size (width, height); 00109 } 00110 00111 Size GridVLayout::GetChildrenSize () const 00112 { 00113 return _children_size; 00114 } 00115 00116 void GridVLayout::ForceChildrenSize (bool force) 00117 { 00118 _force_children_size = force; 00119 } 00120 00121 int GridVLayout::GetNumColumn () const 00122 { 00123 return _num_column; 00124 } 00125 00126 int GridVLayout::GetNumRow () const 00127 { 00128 return _num_row; 00129 } 00130 00131 void GridVLayout::SetWidthMatchContent (bool match_content) 00132 { 00133 _width_match_content = match_content; 00134 } 00135 00136 bool GridVLayout::GetWidthMatchContent () const 00137 { 00138 return _width_match_content; 00139 } 00140 00141 void GridVLayout::GetCompositeList (std::list<Area *> *ViewList) 00142 { 00143 std::list<Area *>::iterator it; 00144 00145 for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) 00146 { 00147 if ( (*it)->IsView() ) 00148 { 00149 View *ic = static_cast<View *>(*it); 00150 ViewList->push_back (ic); 00151 } 00152 else if ( (*it)->IsLayout() ) 00153 { 00154 Layout *layout = static_cast<Layout *>(*it); 00155 layout->GetCompositeList (ViewList); 00156 } 00157 } 00158 } 00159 00160 long GridVLayout::ComputeLayout2() 00161 { 00162 std::list<Area *> elements; 00163 00164 if (GetStretchFactor() == 0) 00165 { 00166 ApplyMinHeight(); 00167 } 00168 00169 if (_layout_element_list.size() == 0) 00170 { 00171 return eCompliantHeight | eCompliantWidth; 00172 } 00173 00174 t_s32 num_elements = 0; 00175 00176 std::list<Area *>::iterator it; 00177 for (it = _layout_element_list.begin(); it != _layout_element_list.end(); it++) 00178 { 00179 if ((*it)->IsVisible ()) 00180 { 00181 (*it)->SetLayoutDone (false); 00182 elements.push_back (*it); 00183 num_elements++; 00184 } 00185 } 00186 00187 t_s32 original_width = GetBaseWidth(); 00188 00189 nux::Geometry base = GetGeometry(); 00190 it = elements.begin(); 00191 int num_row = 0; 00192 int num_column = 0; 00193 00194 if (num_elements > 0) 00195 ++num_column; 00196 00197 if (_dynamic_column) 00198 { 00199 int X = base.x + m_h_out_margin; 00200 int Y = base.y + m_v_out_margin; 00201 00202 bool first_element_of_column = true; 00203 00204 for (int i = 0; i < num_elements; i++) 00205 { 00206 if (num_column == 1) 00207 num_row++; 00208 00209 if (first_element_of_column) 00210 { 00211 first_element_of_column = false; 00212 } 00213 00214 if (_force_children_size) 00215 { 00216 (*it)->SetMinimumSize (_children_size.width, _children_size.height); 00217 } 00218 00219 (*it)->SetGeometry (nux::Geometry (X, Y, _children_size.width, _children_size.height)); 00220 00221 (*it)->ComputeLayout2(); 00222 00223 Y += _children_size.height + m_v_in_margin; 00224 00225 it++; 00226 00227 if ((!_partial_visibility) && (Y + _children_size.height > base.y + base.height - m_v_out_margin)) 00228 { 00229 X += _children_size.width + m_h_in_margin; 00230 Y = base.y + m_v_out_margin; 00231 00232 first_element_of_column = true; 00233 if(i < num_elements - 1) 00234 ++num_column; 00235 } 00236 else if (Y >= base.y + base.height) 00237 { 00238 X += _children_size.width + m_h_in_margin; 00239 Y = base.y + m_v_out_margin; 00240 00241 first_element_of_column = true; 00242 if (i < num_elements - 1) 00243 ++num_column; 00244 } 00245 } 00246 } 00247 00248 _num_row = num_row; 00249 _num_column = num_column; 00250 00251 if ((GetStretchFactor() == 0) || _width_match_content) 00252 { 00253 int w = num_column * _children_size.width + 2 * m_h_out_margin + (num_column - 1) * m_h_in_margin; 00254 SetMinimumWidth (w); 00255 SetBaseWidth (w); 00256 } 00257 00258 long size_compliance = 0L; 00259 00260 if (GetBaseWidth() > original_width + VERROR) 00261 { 00262 #if DEBUG_LAYOUT_COMPUTATION 00263 // The layout has been resized larger in WIDTH to tightly pack its content. 00264 // Or you can say that the layout refuse to be smaller than total WIDTH of its elements. 00265 std::cout << "ComputeLayout2: VLayout Width block at " << GetWidth() << std::endl; 00266 #endif 00267 size_compliance |= eLargerWidth; // need scrollbar 00268 } 00269 else if (GetBaseWidth() + VERROR < original_width) 00270 { 00271 #if DEBUG_LAYOUT_COMPUTATION 00272 // The layout is smaller. 00273 std::cout << "ComputeLayout2: VLayout Width smaller = " << GetWidth() << std::endl; 00274 #endif 00275 size_compliance |= eSmallerWidth; 00276 } 00277 else 00278 { 00279 #if DEBUG_LAYOUT_COMPUTATION 00280 // The layout and its content resized together without trouble. 00281 std::cout << "ComputeLayout2: VLayout Width compliant = " << GetWidth() << std::endl; 00282 #endif 00283 size_compliance |= eCompliantWidth; 00284 } 00285 00286 { 00287 #if DEBUG_LAYOUT_COMPUTATION 00288 // The layout and its content resized together without trouble. 00289 std::cout << "ComputeLayout2: VLayout Height compliant = " << m_fittingHeight << std::endl; 00290 #endif 00291 size_compliance |= eCompliantHeight; 00292 } 00293 00294 return size_compliance; 00295 } 00296 00297 void GridVLayout::ProcessDraw (GraphicsEngine &GfxContext, bool force_draw) 00298 { 00299 std::list<Area *> elements; 00300 std::list<Area *>::iterator it = _layout_element_list.begin (); 00301 00302 GfxContext.PushModelViewMatrix (Get2DMatrix ()); 00303 00304 for (it = _layout_element_list.begin (); it != _layout_element_list.end (); ++it) 00305 { 00306 if ((*it)->IsVisible ()) 00307 elements.push_back (*it); 00308 } 00309 00310 it = elements.begin (); 00311 00312 Geometry base = GetGeometry (); 00313 Geometry parent_geometry = GetAbsoluteGeometry (); 00314 Geometry visibility_geometry = parent_geometry; 00315 if (GetToplevel ()) 00316 { 00317 parent_geometry = GetToplevel ()->GetAbsoluteGeometry (); 00318 } 00319 00320 visibility_geometry = parent_geometry.Intersect (GetAbsoluteGeometry ()); 00321 00322 GfxContext.PushClippingRectangle (base); 00323 00324 for (int i = 0; i < _num_column; i++) 00325 { 00326 for (int j = 0; j < _num_row; j++) 00327 { 00328 if (it == elements.end ()) 00329 break; 00330 00331 Geometry intersection = base.Intersect ((*it)->GetGeometry ()); 00332 00333 // Test if the element is inside the Grid before rendering. 00334 if (!visibility_geometry.IsNull ()) 00335 { 00336 int X = base.x + m_h_out_margin + i * (_children_size.width + m_h_in_margin); 00337 int Y = base.y + m_v_out_margin + j * (_children_size.height + m_v_in_margin); 00338 00339 GfxContext.PushClippingRectangle (Geometry (X, Y, _children_size.width, _children_size.height)); 00340 if ((*it)->IsView ()) 00341 { 00342 View *ic = static_cast<View *>(*it); 00343 ic->ProcessDraw (GfxContext, force_draw); 00344 } 00345 else if ((*it)->IsLayout ()) 00346 { 00347 Layout *layout = static_cast<Layout *>(*it); 00348 layout->ProcessDraw (GfxContext, force_draw); 00349 } 00350 00351 GfxContext.PopClippingRectangle (); 00352 } 00353 00354 it++; 00355 } 00356 } 00357 00358 GfxContext.PopClippingRectangle (); 00359 GfxContext.PopModelViewMatrix (); 00360 00361 _queued_draw = false; 00362 } 00363 00364 Area* GridVLayout::KeyNavIteration(KeyNavDirection direction) 00365 { 00366 if (_layout_element_list.size() == 0) 00367 return NULL; 00368 00369 if (IsVisible() == false) 00370 return NULL; 00371 00372 if (next_object_to_key_focus_area_) 00373 { 00374 std::list<Area*>::iterator it; 00375 std::list<Area*>::iterator it_next; 00376 it = std::find (_layout_element_list.begin(), _layout_element_list.end(), next_object_to_key_focus_area_); 00377 it_next = it; 00378 ++it_next; 00379 00380 if (it == _layout_element_list.end()) 00381 { 00382 // Should never happen 00383 nuxAssert (0); 00384 return NULL; 00385 } 00386 00387 int position = GetChildPos(*it); // note that (*it) == next_object_to_key_focus_area_ 00388 int nun_column = GetNumColumn(); 00389 int nun_row = GetNumRow(); 00390 00391 if ((direction == KEY_NAV_UP) && (it == _layout_element_list.begin())) 00392 { 00393 // first item 00394 return NULL; 00395 } 00396 00397 if ((direction == KEY_NAV_DOWN) && (it_next == _layout_element_list.end())) 00398 { 00399 // last item 00400 return NULL; 00401 } 00402 00403 if ((direction == KEY_NAV_UP) && ((position % nun_row) == 0)) 00404 { 00405 // Left edge 00406 return NULL; 00407 } 00408 00409 if ((direction == KEY_NAV_DOWN) && (position == (position / nun_row) * nun_row + (nun_row -1))) 00410 { 00411 // right edge 00412 return NULL; 00413 } 00414 00415 if ((direction == KEY_NAV_LEFT) && ((position / nun_row) == 0)) 00416 { 00417 // top edge 00418 return NULL; 00419 } 00420 00421 if ((direction == KEY_NAV_RIGHT) && ((position / nun_row) == nun_column)) 00422 { 00423 // bottom edge 00424 return NULL; 00425 } 00426 00428 if (direction == KEY_NAV_UP) 00429 { 00430 --it; 00431 Area* key_nav_focus = (*it)->KeyNavIteration(direction); 00432 00433 while (key_nav_focus == NULL) 00434 { 00435 int pos = GetChildPos(*it); 00436 if (it == _layout_element_list.begin() || ((pos % nun_row) == 0)) 00437 break; 00438 00439 --it; 00440 key_nav_focus = (*it)->KeyNavIteration(direction); 00441 } 00442 00443 return key_nav_focus; 00444 } 00445 00446 if (direction == KEY_NAV_DOWN) 00447 { 00448 ++it; 00449 Area* key_nav_focus = (*it)->KeyNavIteration(direction); 00450 00451 while (key_nav_focus == NULL) 00452 { 00453 ++it; 00454 int pos = GetChildPos(*it); 00455 00456 if ((it == _layout_element_list.end()) || (pos == (pos / nun_row) * nun_row + (nun_row -1))) 00457 break; 00458 00459 key_nav_focus = (*it)->KeyNavIteration(direction); 00460 } 00461 00462 return key_nav_focus; 00463 } 00464 00465 if (direction == KEY_NAV_LEFT) 00466 { 00467 for (int i = 0; i < nun_row; ++i) 00468 { 00469 --it; 00470 } 00471 return (*it)->KeyNavIteration(direction); 00472 } 00473 00474 if (direction == KEY_NAV_RIGHT) 00475 { 00476 for (int i = 0; i < nun_row; ++i) 00477 { 00478 ++it; 00479 if (it == _layout_element_list.end()) 00480 return NULL; 00481 } 00482 return (*it)->KeyNavIteration(direction); 00483 } 00484 } 00485 else 00486 { 00487 std::list<Area*>::iterator it; 00488 it = _layout_element_list.begin(); 00489 return (*it)->KeyNavIteration(direction); 00490 } 00491 00492 return NULL; 00493 } 00494 }