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 #include "Nux.h" 00023 00024 #include "NuxGraphics/GLTextureResourceManager.h" 00025 00026 #include "Layout.h" 00027 #include "HLayout.h" 00028 #include "WindowCompositor.h" 00029 #include "BaseWindow.h" 00030 #include "TextEntry.h" 00031 00032 namespace nux 00033 { 00034 00035 NUX_IMPLEMENT_OBJECT_TYPE (BaseWindow); 00036 00037 const int SizeGripWidth = 20; 00038 const int SizeGripHeight = 20; 00039 const int TitleBarHeight = 20; 00040 00041 /* 00042 Elements inside the Window have coordinates based on the top-left corner of the window. 00043 This is true whether we are drawing or computing the layout. When computing the layout, use x_root and y_root to 00044 pass the top-left corner position of the window. When drawing, make a similar adjustment. 00045 */ 00046 00047 BaseWindow::BaseWindow (const TCHAR *WindowName, NUX_FILE_LINE_DECL) 00048 : View (NUX_FILE_LINE_PARAM) 00049 , _paint_layer(new ColorLayer(Color(0xFF707070))) 00050 , _opacity (1.0f) 00051 { 00052 premultiply = true; 00053 _name = WindowName; 00054 _child_need_redraw = true; 00055 m_TopBorder = 0; 00056 m_Border = 0; 00057 _size_match_layout = false; 00058 _is_visible = false; 00059 _is_modal = false; 00060 #if defined(NUX_OS_LINUX) 00061 m_input_window_enabled = false; 00062 m_input_window = 0; 00063 #endif 00064 m_layout = 0; 00065 m_configure_notify_callback = NULL; 00066 m_configure_notify_callback_data = NULL; 00067 _entering_visible_state = false; 00068 _entering_hidden_state = false; 00069 _enter_focus_input_area = NULL; 00070 accept_key_nav_focus_ = false; 00071 00072 // Should be at the end of the constructor 00073 GetWindowCompositor().RegisterWindow (this); 00074 00075 SetMinimumSize (1, 1); 00076 SetGeometry(Geometry(100, 100, 320, 200)); 00077 } 00078 00079 BaseWindow::~BaseWindow() 00080 { 00081 if (_enter_focus_input_area) 00082 { 00083 _enter_focus_input_area->UnReference (); 00084 } 00085 00086 #if defined(NUX_OS_LINUX) 00087 if (m_input_window) 00088 delete m_input_window; 00089 #endif 00090 } 00091 00092 long BaseWindow::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo) 00093 { 00094 long ret = TraverseInfo; 00095 long ProcEvInfo = 0; 00096 00097 IEvent window_event = ievent; 00098 Geometry base = GetGeometry(); 00099 window_event.e_x_root = base.x; 00100 window_event.e_y_root = base.y; 00101 00102 // The child layout get the Mouse down button only if the MouseDown happened inside the client view Area 00103 Geometry viewGeometry = GetGeometry(); 00104 00105 if (ievent.e_event == NUX_MOUSE_PRESSED) 00106 { 00107 if (!viewGeometry.IsPointInside (ievent.e_x - ievent.e_x_root, ievent.e_y - ievent.e_y_root) ) 00108 { 00109 ProcEvInfo = eDoNotProcess; 00110 } 00111 } 00112 00113 if (m_layout) 00114 ret = m_layout->ProcessEvent (window_event, ret, ProcEvInfo); 00115 00116 // PostProcessEvent2 must always have its last parameter set to 0 00117 // because the m_BackgroundArea is the real physical limit of the window. 00118 // So the previous test about IsPointInside do not prevail over m_BackgroundArea 00119 // testing the event by itself. 00120 ret = PostProcessEvent2 (ievent, ret, 0); 00121 return ret; 00122 } 00123 00124 Area* BaseWindow::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) 00125 { 00126 bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); 00127 00128 if(mouse_inside == false) 00129 return NULL; 00130 00131 if(m_layout) 00132 { 00133 nuxAssert(m_layout->IsLayout()); 00134 Area* found_area = m_layout->FindAreaUnderMouse(mouse_position, event_type); 00135 if(found_area) 00136 return found_area; 00137 } 00138 00139 if((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) 00140 return NULL; 00141 return this; 00142 } 00143 00144 void BaseWindow::Draw (GraphicsEngine &GfxContext, bool force_draw) 00145 { 00146 Geometry base = GetGeometry(); 00147 // The elements position inside the window are referenced to top-left window corner. So bring base to (0, 0). 00148 base.SetX (0); 00149 base.SetY (0); 00150 GfxContext.PushClippingRectangle (base); 00151 00152 GetPainter().PushDrawLayer(GfxContext, base, _paint_layer.get()); 00153 00154 GetPainter().PopBackground(); 00155 GfxContext.PopClippingRectangle(); 00156 } 00157 00158 void BaseWindow::DrawContent (GraphicsEngine &GfxContext, bool force_draw) 00159 { 00160 00161 Geometry base = GetGeometry(); 00162 // The elements position inside the window are referenced to top-left window corner. So bring base to (0, 0). 00163 base.SetX (0); 00164 base.SetY (0); 00165 00166 00167 GetPainter().PushLayer(GfxContext, base, _paint_layer.get()); 00168 00169 if (m_layout) 00170 { 00171 GfxContext.PushClippingRectangle (base); 00172 m_layout->ProcessDraw (GfxContext, force_draw); 00173 GfxContext.PopClippingRectangle(); 00174 } 00175 00176 GetPainter().PopBackground(); 00177 } 00178 00179 void BaseWindow::PostDraw (GraphicsEngine &GfxContext, bool force_draw) 00180 { 00181 00182 } 00183 00184 void BaseWindow::SetConfigureNotifyCallback (ConfigureNotifyCallback Callback, void *Data) 00185 { 00186 m_configure_notify_callback = Callback; 00187 m_configure_notify_callback_data = Data; 00188 } 00189 00190 void BaseWindow::AddWidget (View *ic) 00191 { 00192 if (ic && m_layout) 00193 { 00194 m_layout->AddView (ic, 0); 00195 // 0: the WidgetLayout geometry will be set to SetGeometry(0,0,1,1); 00196 // and the children will take their natural size by expending WidgetLayout. 00197 // If the parent of WidgetLayout offers more space, it won't be used by WidgetLayout. 00198 00199 ComputeChildLayout(); 00200 } 00201 } 00202 00203 void BaseWindow::AddWidget (View *ic, int stretchfactor) 00204 { 00205 if (ic && m_layout) 00206 { 00207 m_layout->AddView (ic, stretchfactor); 00208 // if(stretchfactor ==0): the WidgetLayout geometry will be set to SetGeometry(0,0,1,1); 00209 // and the children will take their natural size by expending WidgetLayout. 00210 // If the parent of WidgetLayout offers more space, it won't be used by WidgetLayout. 00211 00212 ComputeChildLayout(); 00213 } 00214 } 00215 00216 void BaseWindow::AddWidget (std::list<View *> *ViewList) 00217 { 00218 m_CompositionLayout->Clear(); 00219 00220 std::list<View *>::iterator it; 00221 00222 for (it = ViewList->begin(); it != ViewList->end(); it++) 00223 { 00224 AddWidget ( (*it) ); 00225 } 00226 } 00227 00228 Layout* BaseWindow::GetLayout () 00229 { 00230 return m_layout; 00231 } 00232 00233 bool BaseWindow::SetLayout (Layout *layout) 00234 { 00235 if (View::SetLayout (layout) == false) 00236 return false; 00237 00238 m_layout = layout; 00239 Geometry geo = GetGeometry(); 00240 Geometry layout_geo = Geometry (geo.x + m_Border, geo.y + m_TopBorder, 00241 geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder); 00242 m_layout->SetGeometry (layout_geo); 00243 00244 // When this call returns the layout computation is done. 00245 ComputeChildLayout(); 00246 // or use 00247 //GetWindowThread()->QueueObjectLayout(m_layout); 00248 00249 return true; 00250 } 00251 00252 // Get a change to do any work on an element. 00253 // Here we need to position the header by hand because it is not under the control of vlayout. 00254 void BaseWindow::PreLayoutManagement() 00255 { 00256 Geometry geo = GetGeometry(); 00257 00258 if (m_configure_notify_callback) 00259 { 00260 (*m_configure_notify_callback) (GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data); 00261 00262 if (geo.IsNull() ) 00263 { 00264 nuxDebugMsg (TEXT ("[BaseWindow::PreLayoutManagement] Received an invalid Geometry.") ); 00265 geo = GetGeometry(); 00266 } 00267 else 00268 { 00269 Area::SetGeometry (geo); 00270 // Get the geometry adjusted with respect to min and max dimension of this area. 00271 geo = GetGeometry(); 00272 } 00273 } 00274 00275 if (m_layout) 00276 { 00277 Geometry layout_geo = Geometry (m_Border, m_TopBorder, 00278 geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder); 00279 00280 if (IsSizeMatchContent ()) 00281 m_layout->SetGeometry (Geometry (0, 0, 1, 1)); 00282 else 00283 m_layout->SetGeometry (layout_geo); 00284 } 00285 } 00286 00287 // Get a change to do any work on an element. 00288 // Here we need to position the header by hand because it is not under the control of vlayout. 00289 long BaseWindow::PostLayoutManagement (long LayoutResult) 00290 { 00291 if (IsSizeMatchContent() && m_layout) 00292 { 00293 Geometry layout_geometry = m_layout->GetGeometry(); 00294 00295 Geometry WindowGeometry = Geometry (GetGeometry().x, 00296 GetGeometry().y, 00297 layout_geometry.GetWidth() + 2 * m_Border, 00298 layout_geometry.GetHeight() + m_Border + m_TopBorder); 00299 00300 Area::SetGeometry (WindowGeometry); 00301 } 00302 00303 // A BaseWindow must kill the result of the management and pass it to the parent Layout. 00304 return (eCompliantHeight | eCompliantWidth); 00305 //return result; 00306 } 00307 00308 // Get a change to do any work on an element. 00309 // Here we need to position the header by hand because it is not under the control of vlayout. 00310 void BaseWindow::PositionChildLayout (float offsetX, float offsetY) 00311 { 00312 00313 } 00314 00315 #if defined(NUX_OS_LINUX) 00316 void BaseWindow::EnableInputWindow (bool b, 00317 const char* title, 00318 bool take_focus, 00319 bool override_redirect) 00320 { 00321 if (b) 00322 { 00323 if (m_input_window == 0) 00324 m_input_window = new XInputWindow (title, take_focus, override_redirect); 00325 00326 m_input_window->Show (); 00327 m_input_window->SetGeometry (GetGeometry()); 00328 m_input_window_enabled = true; 00329 } 00330 else 00331 { 00332 if (m_input_window) 00333 m_input_window->Hide (); 00334 m_input_window_enabled = false; 00335 } 00336 } 00337 00338 bool BaseWindow::InputWindowEnabled () 00339 { 00340 return m_input_window_enabled; 00341 } 00342 00343 void BaseWindow::InputWindowEnableStruts (bool enable) 00344 { 00345 if (m_input_window) 00346 m_input_window->EnableStruts (enable); 00347 } 00348 00349 bool BaseWindow::InputWindowStrutsEnabled () 00350 { 00351 return m_input_window_enabled && m_input_window->StrutsEnabled (); 00352 } 00353 00354 void BaseWindow::SetInputFocus () 00355 { 00356 if (m_input_window) 00357 m_input_window->SetInputFocus (); 00358 } 00359 00360 Window BaseWindow::GetInputWindowId () 00361 { 00362 if (m_input_window) 00363 return m_input_window->GetWindow (); 00364 else 00365 return 0; 00366 } 00367 00368 #endif 00369 00370 void BaseWindow::SetGeometry (const Geometry &geo) 00371 { 00372 Area::SetGeometry (geo); 00373 00374 #if defined(NUX_OS_LINUX) 00375 if (m_input_window) 00376 m_input_window->SetGeometry (geo); 00377 #endif 00378 //LayoutWindowElements(); 00379 //ComputeChildLayout(); 00380 } 00381 00382 void BaseWindow::LayoutWindowElements() 00383 { 00384 // Define the geometry of some of the component of the window. Otherwise, if the composition layout is not set, 00385 // then the component won't be correctly placed after a SetGeometry. This can be redondant if the composition layout is set. 00386 Geometry base = GetGeometry(); 00387 } 00388 00389 void BaseWindow::SetBorder (int border) 00390 { 00391 if (m_Border != border) 00392 { 00393 m_Border = border; 00394 } 00395 } 00396 00397 void BaseWindow::SetTopBorder (int border) 00398 { 00399 if (m_TopBorder != border) 00400 { 00401 m_TopBorder = border; 00402 } 00403 } 00404 00405 int BaseWindow::GetBorder() const 00406 { 00407 return m_Border; 00408 } 00409 00410 int BaseWindow::GetTopBorder() const 00411 { 00412 return m_TopBorder; 00413 } 00414 00415 void BaseWindow::ShowWindow(bool visible, bool StartModal /* = false */) 00416 { 00417 if (visible == _is_visible) 00418 return; 00419 00420 _is_visible = visible; 00421 _is_modal = StartModal; 00422 00423 if (_is_visible) 00424 { 00425 if (m_layout) 00426 { 00427 m_layout->SetGeometry(GetGeometry()); 00428 } 00429 00430 _entering_visible_state = true; 00431 00432 sigVisible.emit(this); 00433 GetWindowCompositor().sigVisibleViewWindow.emit(this); 00434 00435 ComputeChildLayout(); 00436 } 00437 else 00438 { 00439 _entering_hidden_state = true; 00440 sigHidden.emit(this); 00441 GetWindowCompositor().sigHiddenViewWindow.emit(this); 00442 } 00443 00444 if (_is_modal) 00445 GetWindowCompositor().StartModalWindow(ObjectWeakPtr<BaseWindow>(this)); 00446 00447 // Whether this view is added or removed, call QueueDraw. in the case where this view is removed, this is a signal 00448 // that the region below this view need to be redrawn. 00449 QueueDraw(); 00450 } 00451 00452 bool BaseWindow::IsVisible() const 00453 { 00454 return _is_visible; 00455 } 00456 00457 void BaseWindow::StopModal() 00458 { 00459 _is_visible = false; 00460 _is_modal = false; 00461 //ShowWindow(false); 00462 GetWindowCompositor().StopModalWindow (ObjectWeakPtr<BaseWindow> (this)); 00463 } 00464 00465 bool BaseWindow::IsModal() const 00466 { 00467 return _is_modal; 00468 } 00469 00470 void BaseWindow::NotifyConfigurationChange (int Width, int Height) 00471 { 00472 Geometry geo = GetGeometry(); 00473 00474 if (m_configure_notify_callback) 00475 { 00476 (*m_configure_notify_callback) (GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data); 00477 00478 if (geo.IsNull() ) 00479 { 00480 nuxDebugMsg (TEXT ("[BaseWindow::NotifyConfigurationChange] Received an invalid Geometry.") ); 00481 geo = GetGeometry(); 00482 } 00483 else 00484 { 00485 Area::SetGeometry (geo); 00486 // Get the geometry adjusted with respect to min and max dimension of this area. 00487 geo = GetGeometry(); 00488 } 00489 } 00490 else 00491 { 00492 return; 00493 } 00494 } 00495 00496 void BaseWindow::SetBackgroundLayer (AbstractPaintLayer *layer) 00497 { 00498 NUX_RETURN_IF_NULL (layer); 00499 _paint_layer.reset(layer->Clone()); 00500 } 00501 00502 void BaseWindow::SetBackgroundColor (const Color &color) 00503 { 00504 _paint_layer.reset(new ColorLayer(color)); 00505 } 00506 00507 void BaseWindow::PushHigher (BaseWindow* floating_view) 00508 { 00509 GetWindowCompositor().PushHigher (this, floating_view); 00510 } 00511 00512 void BaseWindow::PushToFront () 00513 { 00514 GetWindowCompositor().PushToFront (this); 00515 } 00516 00517 void BaseWindow::PushToBack () 00518 { 00519 GetWindowCompositor().PushToBack (this); 00520 } 00521 00522 bool BaseWindow::ChildNeedsRedraw () 00523 { 00524 return _child_need_redraw; 00525 } 00526 00527 void* BaseWindow::GetBackupTextureData (int &width, int &height, int &format) 00528 { 00529 return GetWindowCompositor ().GetBackupTextureData (this, width, height, format); 00530 } 00531 00532 void BaseWindow::SetEnterFocusInputArea (InputArea *input_area) 00533 { 00534 if (_enter_focus_input_area) 00535 { 00536 _enter_focus_input_area->UnReference (); 00537 } 00538 00539 _enter_focus_input_area = input_area; 00540 if (_enter_focus_input_area) 00541 _enter_focus_input_area->Reference (); 00542 00543 } 00544 00545 void BaseWindow::SetOpacity (float opacity) 00546 { 00547 if (_opacity == opacity) 00548 return; 00549 00550 _opacity = opacity; 00551 00552 _opacity = CLAMP (_opacity, 0.0f, 1.0f); 00553 00554 QueueDraw (); 00555 } 00556 00557 float BaseWindow::GetOpacity () 00558 { 00559 return _opacity; 00560 } 00561 00562 void BaseWindow::SetAcceptKeyNavFocus(bool accept) 00563 { 00564 accept_key_nav_focus_ = accept; 00565 } 00566 00567 bool BaseWindow::AcceptKeyNavFocus() 00568 { 00569 return accept_key_nav_focus_; 00570 } 00571 } 00572