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: Jay Taoko <jaytaoko@inalogic.com> 00019 * 00020 */ 00021 00022 00023 #include "Nux.h" 00024 #include "WindowCompositor.h" 00025 #include "Layout.h" 00026 #include "View.h" 00027 00028 namespace nux 00029 { 00030 00031 NUX_IMPLEMENT_OBJECT_TYPE (View); 00032 00033 View::View (NUX_FILE_LINE_DECL) 00034 : InputArea (NUX_FILE_LINE_PARAM) 00035 { 00036 _font = GetSysFont (); 00037 _is_view_active = true; // The view is active by default 00038 m_CompositionLayout = 0; 00039 _need_redraw = false; 00040 m_UseStyleDrawing = true; 00041 m_TextColor = Color (1.0f, 1.0f, 1.0f, 1.0f); 00042 _can_pass_focus_to_composite_layout = true; 00043 _can_focus = true; 00044 00045 // Set widget default size; 00046 SetMinimumSize (DEFAULT_WIDGET_WIDTH, PRACTICAL_WIDGET_HEIGHT); 00047 mouse_down_outside_pointer_grab_area.connect (sigc::mem_fun (this, &View::DoMouseDownOutsideArea)); 00048 } 00049 00050 View::~View() 00051 { 00052 // It is possible that the window thread has been deleted before the view 00053 // itself, so check prior to calling. 00054 WindowThread* wt = GetWindowThread(); 00055 if (GetFocused() && HasPassiveFocus() == false && wt) 00056 { 00057 wt->SetFocusedArea (NULL); 00058 } 00059 00060 // It is possible that the object is in the refresh list. Remove it here 00061 // before it is deleted. 00062 if (wt) 00063 wt->RemoveObjectFromLayoutQueue(this); 00064 00065 RemoveLayout(); 00066 } 00067 00068 void View::DoMouseDownOutsideArea (int x, int y,unsigned long mousestate, unsigned long keystate) 00069 { 00070 if (GetFocused ()) 00071 { 00072 SetFocused (false); 00073 } 00074 } 00075 00076 long View::ProcessFocusEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo) 00077 { 00078 // we assume we were chained up to by our layout 00079 if (GetLayout () == NULL) 00080 return TraverseInfo; 00081 00082 Area *parent = GetParentObject (); 00083 if (parent == NULL) 00084 { 00085 GetLayout ()->SetFocused (false); 00086 GetLayout ()->SetFocused (true); // just reset the layout focus becase we are top level 00087 } 00088 00089 if (parent != NULL && parent->IsLayout ()) 00090 { 00091 Layout *parent_layout = (Layout *)parent; 00092 return parent_layout->ProcessFocusEvent (ievent, TraverseInfo, ProcessEventInfo); 00093 } 00094 00095 return TraverseInfo; 00096 } 00097 00098 // NUXTODO: Find better name 00099 long View::ComputeLayout2() 00100 { 00101 return ComputeChildLayout(); 00102 } 00103 00104 // NUXTODO: Find better name 00105 void View::ComputePosition2 (float offsetX, float offsetY) 00106 { 00107 PositionChildLayout (offsetX, offsetY); 00108 } 00109 00110 long View::ComputeChildLayout() 00111 { 00112 if (m_CompositionLayout) 00113 { 00114 //m_CompositionLayout->SetDirty (true); 00115 // if(m_CompositionLayout->GetStretchFactor() != 0) 00116 // { 00117 // PreLayoutManagement(); 00118 // long ret = m_CompositionLayout->ComputeLayout2(); 00119 // return PostLayoutManagement(ret); 00120 // } 00121 // else 00122 { 00123 PreLayoutManagement(); 00124 00125 int PreWidth = /*m_CompositionLayout->*/GetBaseWidth(); 00126 int PreHeight = /*m_CompositionLayout->*/GetBaseHeight(); 00127 00128 long ret = m_CompositionLayout->ComputeLayout2(); 00129 00130 PostLayoutManagement (ret); 00131 //return eCompliantWidth | eCompliantHeight; 00132 00133 int PostWidth = /*m_CompositionLayout->*/GetBaseWidth(); 00134 int PostHeight = /*m_CompositionLayout->*/GetBaseHeight(); 00135 00136 long size_compliance = 0; 00137 00138 // The layout has been resized to tightly pack its content 00139 if (PostWidth > PreWidth) 00140 { 00141 size_compliance |= eLargerWidth; // need scrollbar 00142 } 00143 else if (PostWidth < PreWidth) 00144 { 00145 size_compliance |= eSmallerWidth; 00146 } 00147 else 00148 { 00149 size_compliance |= eCompliantWidth; 00150 } 00151 00152 // The layout has been resized to tightly pack its content 00153 if (PostHeight > PreHeight) 00154 { 00155 size_compliance |= eLargerHeight; // need scrollbar 00156 } 00157 else if (PostHeight < PreHeight) 00158 { 00159 size_compliance |= eSmallerHeight; 00160 } 00161 else 00162 { 00163 size_compliance |= eCompliantHeight; 00164 } 00165 00166 //Area::SetGeometry(m_CompositionLayout->GetGeometry()); 00167 return size_compliance; 00168 } 00169 } 00170 else 00171 { 00172 PreLayoutManagement(); 00173 int ret = PostLayoutManagement (eCompliantHeight | eCompliantWidth); 00174 return ret; 00175 } 00176 00177 return 0; 00178 } 00179 00180 void View::PositionChildLayout (float offsetX, float offsetY) 00181 { 00182 if (m_CompositionLayout) 00183 { 00184 // This section from //1 to //2 is not needed. here we should not do any size management. Only position.. 00185 //1 00186 if (m_CompositionLayout->GetStretchFactor() != 0) 00187 { 00188 m_CompositionLayout->SetGeometry (GetGeometry() ); 00189 } 00190 else //2 00191 { 00192 m_CompositionLayout->SetBaseX (GetBaseX() ); 00193 m_CompositionLayout->SetBaseY (GetBaseY() ); 00194 } 00195 00196 m_CompositionLayout->ComputePosition2 (offsetX, offsetY); 00197 00198 } 00199 } 00200 00201 void View::PreLayoutManagement() 00202 { 00203 // Give the managed layout the same size and position as the Control. 00204 if (m_CompositionLayout) 00205 m_CompositionLayout->SetGeometry (GetGeometry() ); 00206 } 00207 00208 long View::PostLayoutManagement (long LayoutResult) 00209 { 00210 // Set the geometry of the control to be the same as the managed layout. 00211 // Only the size is changed. The position of the composition layout hasn't 00212 // been changed by ComputeLayout2. 00213 if (m_CompositionLayout) 00214 { 00215 // If The layout is empty, do not change the size of the parent element. 00216 if (!m_CompositionLayout->IsEmpty() ) 00217 Area::SetGeometry (m_CompositionLayout->GetGeometry() ); 00218 } 00219 00220 return LayoutResult; 00221 } 00222 00223 void View::PreResizeGeometry() 00224 { 00225 00226 } 00227 00228 void View::PostResizeGeometry() 00229 { 00230 } 00231 00232 long View::PostProcessEvent2 (IEvent &ievent, long TraverseInfo, long ProcessEventInfo) 00233 { 00234 return OnEvent (ievent, TraverseInfo, ProcessEventInfo); 00235 } 00236 00237 00238 void View::ProcessDraw (GraphicsEngine &GfxContext, bool force_draw) 00239 { 00240 _full_redraw = false; 00241 00242 GfxContext.PushModelViewMatrix (Get2DMatrix ()); 00243 00244 if (force_draw) 00245 { 00246 _need_redraw = true; 00247 _full_redraw = true; 00248 Draw (GfxContext, force_draw); 00249 DrawContent (GfxContext, force_draw); 00250 PostDraw (GfxContext, force_draw); 00251 } 00252 else 00253 { 00254 if (_need_redraw) 00255 { 00256 _full_redraw = true; 00257 Draw (GfxContext, false); 00258 DrawContent (GfxContext, false); 00259 PostDraw (GfxContext, false); 00260 } 00261 else 00262 { 00263 DrawContent (GfxContext, false); 00264 PostDraw (GfxContext, false); 00265 } 00266 } 00267 00268 // just leave this here, its helpful for debugging focus issues :) 00269 // if (GetFocused () && _can_pass_focus_to_composite_layout == false) 00270 // { 00271 // GetPainter ().Paint2DQuadColor (GfxContext, GetGeometry (), nux::Color (0.2, 1.0, 0.2, 1.0)); 00272 // } 00273 00274 // if (GetFocused () && _can_pass_focus_to_composite_layout == true) 00275 // { 00276 // GetPainter ().Paint2DQuadColor (GfxContext, GetGeometry (), nux::Color (1.0, 0.2, 0.2, 1.0)); 00277 // } 00278 00279 00280 GfxContext.PopModelViewMatrix (); 00281 00282 _need_redraw = false; 00283 _full_redraw = false; 00284 } 00285 00286 void View::Draw(GraphicsEngine &GfxContext, bool force_draw) 00287 { 00288 00289 } 00290 00291 void View::DrawContent(GraphicsEngine &GfxContext, bool force_draw) 00292 { 00293 00294 } 00295 00296 void View::PostDraw(GraphicsEngine &GfxContext, bool force_draw) 00297 { 00298 00299 } 00300 00301 void View::QueueDraw () 00302 { 00303 //GetWindowCompositor()..AddToDrawList(this); 00304 WindowThread* application = GetWindowThread (); 00305 if(application) 00306 { 00307 application->AddToDrawList(this); 00308 application->RequestRedraw(); 00309 //GetWindowCompositor().AddToDrawList(this); 00310 } 00311 if (m_CompositionLayout) 00312 m_CompositionLayout->QueueDraw (); 00313 00314 _need_redraw = true; 00315 OnQueueDraw.emit (this); 00316 } 00317 00318 void View::NeedSoftRedraw() 00319 { 00320 //GetWindowCompositor()..AddToDrawList(this); 00321 WindowThread* application = GetWindowThread (); 00322 if(application) 00323 { 00324 application->AddToDrawList(this); 00325 application->RequestRedraw(); 00326 } 00327 //_need_redraw = false; 00328 } 00329 00330 bool View::IsRedrawNeeded() 00331 { 00332 return _need_redraw; 00333 } 00334 00335 bool View::IsFullRedraw() const 00336 { 00337 return _full_redraw; 00338 } 00339 00340 void View::DoneRedraw() 00341 { 00342 _need_redraw = false; 00343 00344 if (m_CompositionLayout) 00345 { 00346 m_CompositionLayout->DoneRedraw(); 00347 } 00348 } 00349 00350 Layout* View::GetLayout() 00351 { 00352 return m_CompositionLayout; 00353 } 00354 00355 Layout *View::GetCompositionLayout() 00356 { 00357 return GetLayout (); 00358 } 00359 00360 bool View::SetLayout (Layout *layout) 00361 { 00362 nuxAssert(layout->IsLayout()); 00363 NUX_RETURN_VALUE_IF_NULL (layout, false); 00364 NUX_RETURN_VALUE_IF_TRUE (m_CompositionLayout == layout, true); 00365 00366 Area *parent = layout->GetParentObject(); 00367 00368 if (parent == this) 00369 { 00370 nuxAssert (m_CompositionLayout == layout); 00371 return false; 00372 } 00373 else if (parent != 0) 00374 { 00375 nuxDebugMsg (0, TEXT ("[View::SetCompositionLayout] Object already has a parent. You must UnParent the object before you can parenting again.") ); 00376 return false; 00377 } 00378 00379 if (m_CompositionLayout) 00380 { 00381 if (GetFocused ()) 00382 m_CompositionLayout->SetFocused (false); 00383 00384 _on_focus_changed_handler.disconnect (); 00385 00386 /* we need to emit the signal before the unparent, just in case 00387 one of the callbacks wanted to use this object */ 00388 00389 LayoutRemoved.emit (this, m_CompositionLayout); 00390 m_CompositionLayout->UnParentObject(); 00391 } 00392 layout->SetParentObject (this); 00393 m_CompositionLayout = layout; 00394 00395 GetWindowThread()->QueueObjectLayout (this); 00396 if (GetFocused ()) 00397 layout->SetFocused (true); 00398 00399 _on_focus_changed_handler = layout->ChildFocusChanged.connect (sigc::mem_fun (this, &View::OnChildFocusChanged)); 00400 00401 LayoutAdded.emit (this, m_CompositionLayout); 00402 00403 return true; 00404 } 00405 00406 void View::OnChildFocusChanged (/*Area *parent,*/ Area *child) 00407 { 00408 ChildFocusChanged.emit (/*parent,*/ child); 00409 } 00410 00411 bool View::SetCompositionLayout (Layout *layout) 00412 { 00413 return SetLayout (layout); 00414 } 00415 00416 void View::RemoveLayout() 00417 { 00418 NUX_RETURN_IF_NULL(m_CompositionLayout); 00419 00420 if (m_CompositionLayout) 00421 m_CompositionLayout->UnParentObject(); 00422 00423 m_CompositionLayout = 0; 00424 } 00425 00426 void View::RemoveCompositionLayout() 00427 { 00428 RemoveLayout(); 00429 } 00430 00431 bool View::SearchInAllSubNodes (Area *bo) 00432 { 00433 if (m_CompositionLayout) 00434 return m_CompositionLayout->SearchInAllSubNodes (bo); 00435 00436 return false; 00437 } 00438 00439 bool View::SearchInFirstSubNodes (Area *bo) 00440 { 00441 if (m_CompositionLayout) 00442 return m_CompositionLayout->SearchInFirstSubNodes (bo); 00443 00444 return false; 00445 } 00446 00447 void View::SetGeometry (const Geometry &geo) 00448 { 00449 Area::SetGeometry (geo); 00450 ComputeChildLayout(); 00451 PostResizeGeometry(); 00452 } 00453 00454 void View::SetFont (ObjectPtr<FontTexture> font) 00455 { 00456 _font = font; 00457 } 00458 00459 ObjectPtr<FontTexture> View::GetFont () 00460 { 00461 return _font; 00462 } 00463 00464 void View::SetTextColor (const Color &color) 00465 { 00466 m_TextColor = color; 00467 } 00468 00469 Color View::GetTextColor() 00470 { 00471 return m_TextColor; 00472 } 00473 00474 void View::ActivateView () 00475 { 00476 _is_view_active = true; 00477 } 00478 00479 void View::DeactivateView () 00480 { 00481 _is_view_active = false; 00482 } 00483 00484 bool View::IsViewActive () const 00485 { 00486 return _is_view_active; 00487 } 00488 00489 void View::SetViewActive (bool active) 00490 { 00491 _is_view_active = active; 00492 } 00493 00494 void View::GeometryChangePending () 00495 { 00496 QueueDraw (); 00497 } 00498 00499 void View::GeometryChanged () 00500 { 00501 QueueDraw (); 00502 } 00503 00504 bool View::DoGetFocused () 00505 { 00506 if (HasPassiveFocus ()) 00507 return GetLayout ()->GetFocused (); 00508 00509 return _is_focused; 00510 } 00511 00512 void View::DoSetFocused (bool focused) 00513 { 00514 if (GetFocused () == focused) 00515 { 00516 return; 00517 } 00518 00519 InputArea::DoSetFocused (focused); 00520 00521 if (HasPassiveFocus ()) 00522 { 00523 Layout *layout = GetLayout (); 00524 00525 InputArea::DoSetFocused (focused); 00526 00527 if (layout != NULL) 00528 { 00529 layout->SetFocused (focused); 00530 } 00531 } 00532 else if (focused == true) 00533 { 00534 // we only set the focused area if we are not passing focus 00535 nux::GetWindowThread ()->SetFocusedArea (this); 00536 } 00537 00538 if (focused == false) 00539 { 00540 bool has_focused_entry = false; 00541 Area *_parent = GetParentObject (); 00542 if (_parent == NULL) 00543 return; 00544 00545 if (_parent->IsLayout ()) 00546 has_focused_entry = _parent->GetFocused (); 00547 00548 if (has_focused_entry == false) 00549 SetFocusControl (false); 00550 00551 } 00552 } 00553 00554 bool View::DoCanFocus () 00555 { 00556 if (IsVisible () == false) 00557 return false; 00558 00559 if (_can_focus == false) 00560 return false; 00561 00562 if (_can_pass_focus_to_composite_layout) 00563 { 00564 if (GetLayout () != NULL) 00565 { 00566 return GetLayout ()->CanFocus (); 00567 } 00568 } 00569 00570 return _can_focus; 00571 } 00572 00573 void View::SetCanFocus (bool can_focus) 00574 { 00575 _can_focus = can_focus; 00576 if ((_can_focus == false) && GetFocused ()) 00577 { 00578 SetFocused (false); 00579 } 00580 } 00581 00582 // if we have a layout, returns true if we pass focus to it 00583 // else returns false 00584 bool View::HasPassiveFocus () 00585 { 00586 if (_can_pass_focus_to_composite_layout && GetLayout () != NULL) 00587 return true; 00588 00589 return false; 00590 } 00591 00592 void View::SetFocusControl (bool focus_control) 00593 { 00594 Area *_parent = GetParentObject (); 00595 if (_parent == NULL) 00596 return; 00597 00598 if (_parent->IsView ()) 00599 { 00600 View *parent = (View*)_parent; 00601 parent->SetFocusControl (focus_control); 00602 } 00603 else if (_parent->IsLayout ()) 00604 { 00605 Layout *parent = (Layout *)_parent; 00606 parent->SetFocusControl (focus_control); 00607 } 00608 } 00609 00610 bool View::HasFocusControl() 00611 { 00612 Area *_parent = GetParentObject(); 00613 if (_parent == NULL) 00614 return false; 00615 00616 if (_parent->IsView()) 00617 { 00618 View *parent = (View*)_parent; 00619 return parent->HasFocusControl(); 00620 } 00621 else if (_parent->IsLayout()) 00622 { 00623 Layout *parent = (Layout *)_parent; 00624 return parent->HasFocusControl(); 00625 } 00626 return false; 00627 } 00628 00629 Area* View::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) 00630 { 00631 bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); 00632 00633 if (mouse_inside == false) 00634 return NULL; 00635 00636 if (m_CompositionLayout) 00637 { 00638 Area* view = m_CompositionLayout->FindAreaUnderMouse(mouse_position, event_type); 00639 00640 if (view) 00641 return view; 00642 } 00643 00644 if ((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) 00645 return NULL; 00646 return this; 00647 } 00648 00649 Area* View::FindKeyFocusArea(unsigned int key_symbol, 00650 unsigned long x11_key_code, 00651 unsigned long special_keys_state) 00652 { 00653 if (has_key_focus_) 00654 { 00655 return this; 00656 } 00657 else if (next_object_to_key_focus_area_) 00658 { 00659 return next_object_to_key_focus_area_->FindKeyFocusArea(key_symbol, x11_key_code, special_keys_state); 00660 } 00661 return NULL; 00662 } 00663 00664 Area* View::KeyNavIteration(KeyNavDirection direction) 00665 { 00666 if (next_object_to_key_focus_area_) 00667 { 00668 return NULL; 00669 } 00670 00671 if (IsVisible() == false) 00672 return NULL; 00673 00674 if (AcceptKeyNavFocus()) 00675 { 00676 QueueDraw(); 00677 return this; 00678 } 00679 else if (m_CompositionLayout) 00680 { 00681 return m_CompositionLayout->KeyNavIteration(direction); 00682 } 00683 00684 return NULL; 00685 } 00686 00687 bool View::AcceptKeyNavFocus() 00688 { 00689 return true; 00690 } 00691 }