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 00025 #include "NuxGraphics/GLTextureResourceManager.h" 00026 00027 #include "HLayout.h" 00028 #include "WindowThread.h" 00029 #include "WindowCompositor.h" 00030 #include "FloatingWindow.h" 00031 00032 namespace nux 00033 { 00034 NUX_IMPLEMENT_OBJECT_TYPE (FloatingWindow); 00035 00036 /* 00037 Elements inside the Window have coordinates based on the top-left corner of the window. 00038 This is true whether we are drawing or computing the layout. When computing the layout, use x_root and y_root to 00039 pass the top-left corner position of the window. When drawing, make a similar adjustment. 00040 */ 00041 FloatingWindow::FloatingWindow (const TCHAR *WindowName, NUX_FILE_LINE_DECL) 00042 : BaseWindow (WindowName, NUX_FILE_LINE_PARAM) 00043 { 00044 m_bIsVisible = false; 00045 m_bSizeMatchLayout = false; 00046 m_bIsModal = false; 00047 m_bIsVisibleSizeGrip = true; 00048 m_SizeGripDragPositionX = 0; 00049 m_SizeGripDragPositionY = 0; 00050 m_hasTitleBar = true; 00051 _resize_handle_width = 20; 00052 _resize_handle_height = 20; 00053 _title_bar_height = 20; 00054 00055 _minimize_button = new InputArea(NUX_TRACKER_LOCATION); 00056 _minimize_button->Reference(); 00057 _minimize_button->SetParentObject(this); 00058 00059 _resize_handle = new InputArea(NUX_TRACKER_LOCATION); 00060 _resize_handle->SinkReference(); 00061 _resize_handle->SetParentObject(this); 00062 00063 _title_bar = new InputArea(NUX_TRACKER_LOCATION); 00064 _title_bar->SinkReference(); 00065 _title_bar->SetParentObject(this); 00066 00067 _close_button = new InputArea(NUX_TRACKER_LOCATION); 00068 _window_title_bar = new StaticTextBox (TEXT (""), NUX_TRACKER_LOCATION); 00069 00070 _title_bar_layout = new HLayout (NUX_TRACKER_LOCATION); 00071 _title_bar_layout->Reference(); 00072 00073 _minimize_button->SetMinMaxSize(20, 20); 00074 _minimize_button->SetGeometry(0, 0, 20, 20); 00075 _close_button->SetMinimumSize(20, 20); 00076 _close_button->SetGeometry(0, 0, 20, 20); 00077 _resize_handle->SetMinimumSize(_resize_handle_width, _resize_handle_height); 00078 _resize_handle->SetGeometry(Geometry(0, 0, _resize_handle_width, _resize_handle_height)); 00079 00080 _title_bar->mouse_down.connect(sigc::mem_fun(this, &FloatingWindow::RecvTitleBarMouseDown)); 00081 _title_bar->mouse_drag.connect(sigc::mem_fun(this, &FloatingWindow::RecvTitleBarMouseDrag)); 00082 _close_button->mouse_click.connect(sigc::mem_fun(this, &FloatingWindow::RecvCloseButtonClick)); 00083 00084 _resize_handle->mouse_drag.connect(sigc::mem_fun(this, &FloatingWindow::OnSizeGrigMouseDrag)); 00085 _resize_handle->mouse_down.connect(sigc::mem_fun(this, &FloatingWindow::OnSizeGrigMouseDown)); 00086 00087 _title_bar_layout->AddView((_window_title_bar), 1, eCenter, eFix); 00088 _title_bar_layout->AddView((_close_button), 0, eCenter, eFix); 00089 _title_bar_layout->SetParentObject(this); 00090 00091 00092 if(HasTitleBar()) 00093 SetTopBorder(24); 00094 else 00095 SetTopBorder(6); 00096 00097 SetBorder(2); 00098 00099 SetMinimumSize(32, 32); 00100 SetGeometry(Geometry(100, 100, 320, 200)); 00101 00102 NString Path = NUX_FINDRESOURCELOCATION (TEXT ("UITextures/AddButton.png") ); 00103 MinimizeIcon = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture (); 00104 MinimizeIcon->Update (Path.GetTCharPtr() ); 00105 Path = NUX_FINDRESOURCELOCATION (TEXT ("UITextures/CancelButton.png") ); 00106 CloseIcon = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture (); 00107 CloseIcon->Update (Path.GetTCharPtr() ); 00108 00109 SetWindowTitle (WindowName); 00110 } 00111 00112 FloatingWindow::~FloatingWindow() 00113 { 00114 m_InterfaceObject.clear(); 00115 00116 _resize_handle->UnParentObject(); 00117 _resize_handle->UnReference(); 00118 00119 _title_bar->UnParentObject(); 00120 _title_bar->UnReference(); 00121 00122 _minimize_button->UnReference(); 00123 CloseIcon->UnReference(); 00124 MinimizeIcon->UnReference(); 00125 00126 _title_bar_layout->UnParentObject(); 00127 _title_bar_layout->UnReference(); 00128 } 00129 00130 long FloatingWindow::ProcessEvent (IEvent &ievent, long TraverseInfo, long ProcessEventInfo) 00131 { 00132 long ret = TraverseInfo; 00133 long ProcEvInfo = 0; 00134 00135 IEvent window_event = ievent; 00136 Geometry base = GetGeometry(); 00137 window_event.e_x_root = base.x; 00138 window_event.e_y_root = base.y; 00139 00140 if (ievent.e_event == NUX_MOUSE_PRESSED) 00141 { 00142 if (!GetGeometry().IsPointInside (ievent.e_x - ievent.e_x_root, ievent.e_y - ievent.e_y_root) ) 00143 { 00144 ProcEvInfo = eDoNotProcess; 00145 //return TraverseInfo; 00146 } 00147 } 00148 00149 ret = _close_button->OnEvent (window_event, ret, ProcEvInfo); 00150 00151 if (HasTitleBar() ) 00152 { 00153 ret = _title_bar->OnEvent (window_event, ret, ProcEvInfo); 00154 } 00155 00156 // if(m_vertical_scrollbar_enable) 00157 // ret = vscrollbar->ProcessEvent(ievent, ret, ProcEvInfo); 00158 // if(m_horizontal_scrollbar_enable) 00159 // ret = hscrollbar->ProcessEvent(ievent, ret, ProcEvInfo); 00160 00161 if (IsSizeMatchContent() == false) 00162 { 00163 // Do not let the _resize_handle test the event because the window is not displaying it; 00164 int XGrip = window_event.e_x - window_event.e_x_root - _resize_handle->GetBaseX(); 00165 int YGrip = window_event.e_y - window_event.e_y_root - _resize_handle->GetBaseY(); 00166 00167 if (ievent.e_event == NUX_MOUSE_PRESSED) 00168 { 00169 // We want to false on one half of the size grip square to register a mouse down. This is meant to leave more room 00170 // for the scrollbar buttons (if any) at the bottom right of the window. 00171 if ((XGrip > 0) && (YGrip > 0) && (XGrip > _resize_handle_height - YGrip)) 00172 { 00173 ret = _resize_handle->OnEvent(window_event, ret, ProcEvInfo); 00174 } 00175 } 00176 else 00177 { 00178 ret = _resize_handle->OnEvent(window_event, ret, ProcEvInfo); 00179 } 00180 } 00181 00182 // The child layout get the Mouse down button only if the MouseDown happened inside the client view Area 00183 Geometry viewGeometry = GetGeometry(); //Geometry(m_ViewX, m_ViewY, m_ViewWidth, m_ViewHeight); 00184 00185 if (ievent.e_event == NUX_MOUSE_PRESSED) 00186 { 00187 if (!viewGeometry.IsPointInside (ievent.e_x - ievent.e_x_root, ievent.e_y - ievent.e_y_root) ) 00188 { 00189 ProcEvInfo = eDoNotProcess; 00190 } 00191 } 00192 00193 if (m_layout) 00194 ret = m_layout->ProcessEvent (window_event, ret, ProcEvInfo); 00195 00196 // PostProcessEvent2 must always have its last parameter set to 0 00197 // because the m_BackgroundArea is the real physical limit of the window. 00198 // So the previous test about IsPointInside do not prevail over m_BackgroundArea 00199 // testing the event by itself. 00200 ret = PostProcessEvent2 (ievent, ret, 0); 00201 return ret; 00202 } 00203 00204 Area* FloatingWindow::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type) 00205 { 00206 bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); 00207 00208 if(mouse_inside == false) 00209 return NULL; 00210 00211 NUX_RETURN_VALUE_IF_TRUE(_resize_handle->TestMousePointerInclusion(mouse_position, event_type), _resize_handle); 00212 NUX_RETURN_VALUE_IF_TRUE(_close_button->TestMousePointerInclusion(mouse_position, event_type), _close_button); 00213 00214 if(HasTitleBar()) 00215 { 00216 NUX_RETURN_VALUE_IF_TRUE(_title_bar->TestMousePointerInclusion(mouse_position, event_type), _title_bar); 00217 } 00218 00219 // if(_title_bar_layout) 00220 // { 00221 // nuxAssert(_title_bar_layout->IsLayout()); 00222 // Area* found_area = _title_bar_layout->FindAreaUnderMouse(mouse_position, event_type); 00223 // if(found_area) 00224 // return found_area; 00225 // } 00226 00227 if(m_layout) 00228 { 00229 nuxAssert(m_layout->IsLayout()); 00230 Area* found_area = m_layout->FindAreaUnderMouse(mouse_position, event_type); 00231 if(found_area) 00232 return found_area; 00233 } 00234 00235 if((event_type == NUX_MOUSE_WHEEL) && (!AcceptMouseWheelEvent())) 00236 return NULL; 00237 return this; 00238 } 00239 00240 void FloatingWindow::Draw (GraphicsEngine &GfxContext, bool force_draw) 00241 { 00242 Geometry base = GetGeometry(); 00243 // The elements position inside the window are referenced to top-left window corner. So bring base to (0, 0). 00244 base.SetX (0); 00245 base.SetY (0); 00246 GfxContext.PushClippingRectangle (base); 00247 00248 GetPainter().PushDrawShapeLayer (GfxContext, base, eSHAPE_CORNER_ROUND10, Color (0xFF707070), eCornerTopLeft | eCornerTopRight, true); 00249 00250 if (HasTitleBar() ) 00251 { 00252 GetPainter().PaintShapeCorner (GfxContext, Geometry (_title_bar->GetBaseX(), _title_bar->GetBaseY(), 00253 _title_bar->GetBaseWidth(), _title_bar->GetBaseHeight() ), Color (0xFF2f2f2f), 00254 eSHAPE_CORNER_ROUND10, eCornerTopLeft | eCornerTopRight); 00255 00256 GetPainter().PaintTextLineStatic (GfxContext, GetSysBoldFont(), _window_title_bar->GetGeometry(), _window_title, Color (0xFFFFFFFF), true, eAlignTextCenter); 00257 GetPainter().Draw2DTextureAligned (GfxContext, CloseIcon, _close_button->GetGeometry(), TextureAlignmentStyle (eTACenter, eTACenter) ); 00258 } 00259 00260 GetPainter().PopBackground(); 00261 GfxContext.PopClippingRectangle(); 00262 } 00263 00264 void FloatingWindow::DrawContent (GraphicsEngine &GfxContext, bool force_draw) 00265 { 00266 Geometry base = GetGeometry(); 00267 // The elements position inside the window are referenced to top-left window corner. So bring base to (0, 0). 00268 base.SetX (0); 00269 base.SetY (0); 00270 00271 GetPainter().PushShapeLayer (GfxContext, base, eSHAPE_CORNER_ROUND10, Color (0xFF707070), eCornerTopLeft | eCornerTopRight, true); 00272 00273 if (m_layout) 00274 { 00275 GfxContext.PushClippingRectangle (base); 00276 00277 m_layout->ProcessDraw (GfxContext, force_draw); 00278 00279 GfxContext.PopClippingRectangle(); 00280 } 00281 00282 GetPainter().PopBackground(); 00283 } 00284 00285 void FloatingWindow::PostDraw (GraphicsEngine &GfxContext, bool force_draw) 00286 { 00287 if (force_draw == false) 00288 { 00289 return; 00290 } 00291 00292 if ((IsVisibleSizeGrip () == true) && (IsSizeMatchContent () == false)) 00293 { 00294 // Do not draw the size grip if the window is constrained by the size of the container layout. 00295 Geometry geo = _resize_handle->GetGeometry (); 00296 GfxContext.QRP_Triangle (geo.x + geo.width, geo.y, geo.x, geo.y + geo.height, geo.x + geo.width, geo.y + geo.height, Color (0xFF999999)); 00297 } 00298 } 00299 00300 void FloatingWindow::EnableTitleBar (bool b) 00301 { 00302 m_hasTitleBar = b; 00303 ComputeChildLayout(); 00304 } 00305 00306 bool FloatingWindow::HasTitleBar() const 00307 { 00308 return m_hasTitleBar; 00309 } 00310 00311 void FloatingWindow::OnSizeGrigMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags) 00312 { 00313 if(IsSizeMatchContent()) 00314 { 00315 return; 00316 } 00317 00318 // Do not let the _resize_handle test the event because the window is not displaying it; 00319 int XGrip = x; 00320 int YGrip = y; 00321 00322 00323 // We want to false on one half of the size grip square to register a mouse down. This is meant to leave more room 00324 // for the scrollbar buttons (if any) at the bottom right of the window. 00325 if ((XGrip > 0) && (YGrip > 0) && (XGrip > _resize_handle_height - YGrip)) 00326 { 00327 // has grip 00328 } 00329 00330 m_SizeGripDragPositionX = x; 00331 m_SizeGripDragPositionY = y; 00332 //GetWindowCompositor().SetMouseFocusArea(this); 00333 } 00334 00335 void FloatingWindow::OnSizeGrigMouseDrag (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) 00336 { 00337 if(IsSizeMatchContent()) 00338 { 00339 return; 00340 } 00341 00342 Geometry geo; 00343 geo = GetGeometry(); 00344 00345 int ddx = 0; 00346 int ddy = 0; 00347 00348 if((dx > 0) && (x > m_SizeGripDragPositionX)) 00349 { 00350 ddx = dx; 00351 } 00352 00353 if((dx < 0) && (x < m_SizeGripDragPositionX)) 00354 { 00355 ddx = dx; 00356 } 00357 00358 if((dy > 0) && (y > m_SizeGripDragPositionY)) 00359 { 00360 ddy = dy; 00361 } 00362 00363 if((dy < 0) && (y < m_SizeGripDragPositionY)) 00364 { 00365 ddy = dy; 00366 } 00367 00368 geo.OffsetSize(ddx, ddy); 00369 00370 SetGeometry(geo); 00371 00372 #if defined(NUX_OS_LINUX) 00373 if (m_input_window != 0) 00374 { 00375 //nuxDebugMsg (TEXT("Resize Input window: %d, %d, %d, %d"), geo.x, geo.y, geo.width, geo.height); 00376 m_input_window->SetGeometry (GetGeometry()); 00377 } 00378 #endif 00379 00380 GetWindowThread()->AddObjectToRefreshList(this); 00381 QueueDraw(); 00382 } 00383 00384 void FloatingWindow::RecvTitleBarMouseDown (int x, int y, unsigned long button_flags, unsigned long key_flags) 00385 { 00386 _title_bar_mouse_down_location = Point(x, y); 00387 } 00388 00389 void FloatingWindow::RecvTitleBarMouseDrag (int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) 00390 { 00391 Geometry geo; 00392 geo = GetGeometry(); 00393 geo.OffsetPosition (dx, dy); 00394 00395 // Set the Window Size and Position 00396 Area::SetGeometry (geo); 00397 // No need to compute the window layout elements [LayoutWindowElements()]. They haven't changed. 00398 // No need to compute the layout [ComputeChildLayout()]. It hasn't changed. 00399 00400 _title_bar->SetGeometry (0, 0, geo.GetWidth(), _title_bar_height); 00401 00402 #if defined(NUX_OS_LINUX) 00403 if (m_input_window != 0) 00404 { 00405 //nuxDebugMsg (TEXT("Resize Input window: %d, %d, %d, %d"), geo.x, geo.y, geo.width, geo.height); 00406 m_input_window->SetGeometry (GetGeometry()); 00407 } 00408 #endif 00409 00410 QueueDraw(); 00411 } 00412 00413 void FloatingWindow::RecvCloseButtonClick (int x, int y, unsigned long button_flags, unsigned long key_flags) 00414 { 00415 #if defined(NUX_OS_LINUX) 00416 // Disable the input window if there is one. 00417 EnableInputWindow(false); 00418 #endif 00419 00420 StopModal(); 00421 } 00422 00423 // Get a change to do any work on an element. 00424 // Here we need to position the header by hand because it is not under the control of vlayout. 00425 void FloatingWindow::PreLayoutManagement() 00426 { 00427 Geometry geo = GetGeometry(); 00428 00429 if (m_configure_notify_callback) 00430 { 00431 (*m_configure_notify_callback) (GetGraphicsDisplay()->GetWindowWidth(), GetGraphicsDisplay()->GetWindowHeight(), geo, m_configure_notify_callback_data); 00432 00433 if (geo.IsNull() ) 00434 { 00435 nuxDebugMsg (TEXT ("[FloatingWindow::PreLayoutManagement] Received an invalid Geometry.") ); 00436 geo = GetGeometry(); 00437 } 00438 else 00439 { 00440 Area::SetGeometry (geo); 00441 // Get the geometry adjusted with respect to min and max dimension of this area. 00442 geo = GetGeometry(); 00443 } 00444 } 00445 00446 // Drag Bar Geometry 00447 if (HasTitleBar() ) 00448 { 00449 _title_bar->SetGeometry (0, 0, geo.GetWidth(), _title_bar_height); 00450 } 00451 00452 // Size grip Geometry 00453 Geometry SizeGripGeometry (geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height, 00454 _resize_handle_width, _resize_handle_height); 00455 _resize_handle->SetGeometry (SizeGripGeometry); 00456 00457 if (m_layout) 00458 { 00459 Geometry layout_geo = Geometry (m_Border, m_TopBorder, 00460 geo.GetWidth() - 2 * m_Border, geo.GetHeight() - m_Border - m_TopBorder); 00461 m_layout->SetGeometry (layout_geo); 00462 } 00463 } 00464 00465 // Get a change to do any work on an element. 00466 // Here we need to position the header by hand because it is not under the control of vlayout. 00467 long FloatingWindow::PostLayoutManagement (long LayoutResult) 00468 { 00469 if (IsSizeMatchContent() && m_layout) 00470 { 00471 Geometry layout_geometry = m_layout->GetGeometry(); 00472 00473 Geometry WindowGeometry = Geometry (GetGeometry().x, 00474 GetGeometry().y, 00475 layout_geometry.GetWidth() + 2 * m_Border, 00476 layout_geometry.GetHeight() + m_Border + m_TopBorder); 00477 00478 Area::SetGeometry (WindowGeometry); 00479 } 00480 00481 Geometry geo = GetGeometry(); 00482 00483 // Drag Bar Geometry 00484 if (HasTitleBar() ) 00485 { 00486 _title_bar->SetGeometry (0, 0, geo.GetWidth(), _title_bar_height); 00487 } 00488 00489 // Size grip Geometry 00490 Geometry temp (geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height, 00491 _resize_handle_width, _resize_handle_height); 00492 _resize_handle->SetGeometry (temp); 00493 00494 // Title Bar 00495 _title_bar_layout->SetGeometry (_title_bar->GetGeometry() ); 00496 GetWindowThread ()->ComputeElementLayout (_title_bar_layout); 00497 00498 // A FloatingWindow must kill the result of the management and pass it to the parent Layout. 00499 return (eCompliantHeight | eCompliantWidth); 00500 //return result; 00501 } 00502 00503 // Get a change to do any work on an element. 00504 // Here we need to position the header by hand because it is not under the control of vlayout. 00505 void FloatingWindow::PositionChildLayout (float offsetX, float offsetY) 00506 { 00507 //ScrollView::PositionChildLayout(offsetX, offsetY); 00508 00509 Geometry geo = GetGeometry(); 00510 00511 // Drag Bar Geometry 00512 if (HasTitleBar() ) 00513 { 00514 _title_bar->SetGeometry (0, 0, geo.GetWidth(), _title_bar_height); 00515 } 00516 00517 // Size grip Geometry 00518 Geometry temp (geo.GetWidth() - _resize_handle_width, geo.GetHeight() - _resize_handle_height, 00519 _resize_handle_width, _resize_handle_height); 00520 _resize_handle->SetGeometry (temp); 00521 00522 // Title Bar 00523 _title_bar_layout->SetGeometry (_title_bar->GetGeometry() ); 00524 GetWindowThread ()->ComputeElementLayout (_title_bar_layout); 00525 00526 } 00527 00528 void FloatingWindow::LayoutWindowElements() 00529 { 00530 // Define the geometry of some of the component of the window. Otherwise, if the composition layout is not set, 00531 // then the component won't be correctly placed after a SetGeometry. This can be redundant if the composition layout is set. 00532 Geometry base = GetGeometry(); 00533 _title_bar->SetGeometry (0, 0, base.GetWidth(), _title_bar_height); 00534 00535 _title_bar_layout->SetGeometry (_title_bar->GetGeometry() ); 00536 GetWindowThread ()->ComputeElementLayout (_title_bar_layout); 00537 00538 // Size grip Geometry 00539 Geometry temp (base.GetWidth() - _resize_handle_width, base.GetHeight() - _resize_handle_height, 00540 _resize_handle_width, _resize_handle_height); 00541 _resize_handle->SetGeometry (temp); 00542 } 00543 00544 void FloatingWindow::SetWindowTitle (const TCHAR *title) 00545 { 00546 NUX_RETURN_IF_NULL(title) 00547 _window_title = title; 00548 } 00549 00550 NString FloatingWindow::GetWindowTitle() 00551 { 00552 return _window_title; 00553 } 00554 00555 }