Back to index

nux  3.0.0
ScrollView.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright 2010-2011 Inalogic® Inc.
00004  *
00005  * This program is free software: you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License, as
00007  * published by the  Free Software Foundation; either version 2.1 or 3.0
00008  * of the License.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranties of
00012  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00013  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00014  * License for more details.
00015  *
00016  * You should have received a copy of both the GNU Lesser General Public
00017  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00018  *
00019  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00020  *
00021  */
00022 
00023 #include "Nux.h"
00024 #include "HScrollBar.h"
00025 #include "VScrollBar.h"
00026 #include "Layout.h"
00027 #include "HLayout.h"
00028 #include "VLayout.h"
00029 #include "ScrollView.h"
00030 
00031 namespace nux
00032 {
00033   NUX_IMPLEMENT_OBJECT_TYPE(ScrollView);
00034 
00035   ScrollView::ScrollView(NUX_FILE_LINE_DECL)
00036     : View(NUX_FILE_LINE_PARAM)
00037     , m_MouseWheelScrollSize(32)
00038       // TODO: these should really be Rects.
00039     , m_ViewContentX(0)
00040     , m_ViewContentY(0)
00041     , m_ViewContentWidth(0)
00042     , m_ViewContentHeight(0)
00043     , m_ViewX(0)
00044     , m_ViewY(0)
00045     , m_ViewWidth(0)
00046     , m_ViewHeight(0)
00047     , m_TextureIndex(0)
00048     , m_ReformatTexture(true)
00049     , m_horizontal_scrollbar_enable(true)
00050     , m_vertical_scrollbar_enable(true)
00051     , m_top_border(0)
00052     , m_border(0)
00053     , _delta_x(0)
00054     , _delta_y(0)
00055     , m_bSizeMatchContent(false)
00056     , m_ViewContentLeftMargin(0)
00057     , m_ViewContentRightMargin(0)
00058     , m_ViewContentTopMargin(0)
00059     , m_ViewContentBottomMargin(0)
00060   {
00061 
00062     //GetPainter().CreateBackgroundTexture(m_BackgroundTexture);
00063     _hscrollbar = new HScrollBar(NUX_TRACKER_LOCATION);
00064     _vscrollbar = new VScrollBar(NUX_TRACKER_LOCATION);
00065     // _hscrollbar and _vscrollbar have to be parented so they are correctly
00066     // rendered and so that GetRootGeometry/GetAbsoluteGeometry returns the
00067     // correct Geometry. This is necessary in embedded mode.
00068     _hscrollbar->SetParentObject(this);
00069     _vscrollbar->SetParentObject(this);
00070 
00071     _hscrollbar->SetReconfigureParentLayoutOnGeometryChange(false);
00072     _vscrollbar->SetReconfigureParentLayoutOnGeometryChange(false);
00073 
00074     SetMinimumSize(30, 30);
00075     SetGeometry(Geometry(0, 0, 400, 200));
00076 
00077     _hscrollbar->OnScrollLeft.connect(sigc::mem_fun(this, &ScrollView::ScrollLeft));
00078     _hscrollbar->OnScrollRight.connect(sigc::mem_fun(this, &ScrollView::ScrollRight));
00079     _vscrollbar->OnScrollUp.connect(sigc::mem_fun(this, &ScrollView::ScrollUp));
00080     _vscrollbar->OnScrollDown.connect(sigc::mem_fun(this, &ScrollView::ScrollDown));
00081 
00082     mouse_wheel.connect(sigc::mem_fun(this, &ScrollView::RecvMouseWheel));
00083     _vscrollbar->mouse_wheel.connect(sigc::mem_fun(this, &ScrollView::RecvMouseWheel));
00084 
00085     //FIXME disabling until we have better API for this
00086     //ChildFocusChanged.connect(sigc::mem_fun(this, &ScrollView::OnChildFocusChanged));
00087 
00088     FormatContent();
00089 
00090     SetAcceptMouseWheelEvent(true);
00091   }
00092 
00093   // customization for Unity
00094   void ScrollView::SetVScrollBar(VScrollBar* newVScrollBar)
00095   {
00096     if (_vscrollbar)
00097     {
00098       // disconnect old _vscrollbar
00099       _vscrollbar->OnScrollUp.connect(sigc::mem_fun(this,
00100                                                      &ScrollView::ScrollUp));
00101       _vscrollbar->OnScrollDown.connect(sigc::mem_fun(this,
00102                                                        &ScrollView::ScrollDown));
00103       _vscrollbar->mouse_wheel.connect(sigc::mem_fun(this,
00104                                                      &ScrollView::RecvMouseWheel));
00105       
00106       _vscrollbar->UnReference();
00107     }
00108 
00109     _vscrollbar = newVScrollBar;
00110 
00111     _vscrollbar->SetParentObject(this);
00112     _vscrollbar->SetReconfigureParentLayoutOnGeometryChange(false);
00113 
00114     // connect new _vscrollbar
00115     _vscrollbar->OnScrollUp.connect(sigc::mem_fun(this,
00116                                                    &ScrollView::ScrollUp));
00117     _vscrollbar->OnScrollDown.connect(sigc::mem_fun(this,
00118                                                      &ScrollView::ScrollDown));
00119     _vscrollbar->mouse_wheel.connect(sigc::mem_fun(this,
00120                                                    &ScrollView::RecvMouseWheel));
00121   }
00122 
00123   ScrollView::~ScrollView()
00124   {
00125     // Delete all the interface object: This is a problem... The widget should be destroy by there associated parameters
00126     _hscrollbar->UnReference();
00127     _vscrollbar->UnReference();
00128   }
00129 
00130   void ScrollView::OnChildFocusChanged(Area *child)
00131   {
00132 //     if (child->IsView())
00133 //     {
00134 //       View *view = (View*)child;
00135 //       if (view->HasPassiveFocus())
00136 //       {
00137 //         return;
00138 //       }
00139 //     }
00140     if (child->IsLayout())
00141       return;
00142 
00143     int child_y = child->GetGeometry().y - GetGeometry().y;
00144     int child_y_diff = child_y - abs(_delta_y);
00145 
00146 
00147     if (child_y_diff + child->GetGeometry().height < GetGeometry().height && child_y_diff >= 0)
00148     {
00149       return;
00150     }
00151 
00152     if (child_y_diff < 0)
00153     {
00154       ScrollUp(1, abs(child_y_diff));
00155     }
00156     else
00157     {
00158       int size = child_y_diff - GetGeometry().height;
00159 
00160       // always keeps the top of a view on the screen
00161       size += (child->GetGeometry().height, GetGeometry().height) ? child->GetGeometry().height : GetGeometry().height;
00162 
00163       ScrollDown(1, size);
00164     }
00165 
00166   }
00167 
00168   Area* ScrollView::FindAreaUnderMouse(const Point& mouse_position, NuxEventType event_type)
00169   {
00170     // Test if the mouse is inside the ScrollView.
00171     // The last parameter of TestMousePointerInclusion is a boolean used to test if the case
00172     // of mouse wheel events. If that boolean value is true, then TestMousePointerInclusion
00173     // returns true only if the mouse pointer is over this area and the the area accepts
00174     // mouse wheel events(see Area::SetAcceptMouseWheelEvent)
00175     bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type);
00176 
00177     if (mouse_inside == false)
00178     {
00179       // The mouse pointer is not over this Area. return NULL.
00180       return NULL;
00181     }
00182 
00183     Area* found_area;
00184 
00185     // Recursively go over the ui element that are managed by this ScrollView and look
00186     // for the area that is below the mouse.
00187 
00188     // Test the vertical scrollbar
00189     found_area = _vscrollbar->FindAreaUnderMouse(mouse_position, event_type);
00190     NUX_RETURN_VALUE_IF_NOTNULL(found_area, found_area);
00191 
00192     // Test the horizontal scrollbar
00193     found_area = _hscrollbar->FindAreaUnderMouse(mouse_position, event_type);
00194     NUX_RETURN_VALUE_IF_NOTNULL(found_area, found_area);
00195 
00196     // If the code gets here, it means that no area has been found yet.
00197     // Test the layout of the ScrollView
00198     return View::FindAreaUnderMouse(mouse_position, event_type);
00199   }
00200 
00201   bool ScrollView::SetLayout(Layout *layout)
00202   {
00203     if (View::SetLayout(layout) == false)
00204     {
00205       return false;
00206     }
00207 
00208     FormatContent();
00209 
00210     return true;
00211   }
00212 
00213   void ScrollView::Draw(GraphicsEngine &graphics_engine, bool force_draw)
00214   {
00215     graphics_engine.PushClippingRectangle(GetGeometry());
00216 
00217     Geometry base = GetGeometry();
00218 
00219     if (view_layout_)
00220       view_layout_->QueueDraw();
00221 
00222     GetPainter().PaintBackground(graphics_engine, base);
00223 
00224     if (m_vertical_scrollbar_enable)
00225     {
00226       _vscrollbar->QueueDraw();
00227     }
00228 
00229     if (m_horizontal_scrollbar_enable)
00230     {
00231       _hscrollbar->QueueDraw();
00232     }
00233 
00234     graphics_engine.PopClippingRectangle();
00235   }
00236 
00237   void ScrollView::DrawContent(GraphicsEngine &graphics_engine, bool force_draw)
00238   {
00239     if (IsFullRedraw())
00240       GetPainter().PushBackgroundStack();
00241       
00242     graphics_engine.PushClippingRectangle(GetGeometry());
00243 
00244     graphics_engine.PushClippingRectangle(Rect(m_ViewX, m_ViewY, m_ViewWidth, m_ViewHeight));
00245 
00246     if (view_layout_)
00247     {
00248 //       graphics_engine.PushClipOffset(_delta_x, _delta_y);
00249 //       graphics_engine.PushClippingRectangle(view_layout_->GetGeometry());
00250 //       graphics_engine.Push2DTranslationModelViewMatrix(_delta_x, _delta_y, 0.0f);
00251       view_layout_->ProcessDraw(graphics_engine, force_draw);
00252 //       graphics_engine.PopModelViewMatrix();
00253 //       graphics_engine.PopClippingRectangle();
00254 //       graphics_engine.PopClipOffset();
00255     }
00256 
00257     graphics_engine.PopClippingRectangle();
00258 
00259     if (m_vertical_scrollbar_enable)
00260     {
00261       _vscrollbar->ProcessDraw(graphics_engine, force_draw);
00262     }
00263 
00264     if (m_horizontal_scrollbar_enable)
00265     {
00266       _hscrollbar->ProcessDraw(graphics_engine, force_draw);
00267     }
00268 
00269     graphics_engine.PopClippingRectangle();
00270 
00271     if (IsFullRedraw())
00272       GetPainter().PopBackgroundStack();
00273   }
00274 
00275   void ScrollView::PostDraw(GraphicsEngine &graphics_engine, bool force_draw)
00276   {
00277 
00278   }
00279 
00281 // API //
00283   void ScrollView::EnableVerticalScrollBar(bool b)
00284   {
00285     m_vertical_scrollbar_enable = b;
00286     _delta_y = 0;
00287     ComputeContentSize();
00288   }
00289 
00290   void ScrollView::EnableHorizontalScrollBar(bool b)
00291   {
00292     m_horizontal_scrollbar_enable = b;
00293     _delta_x = 0;
00294     ComputeContentSize();
00295   }
00296 
00298 // Internal function //
00300 
00301   void ScrollView::SetGeometry(const Geometry &geo)
00302   {
00303     Area::SetGeometry(geo);
00304     //ComputeContentSize();
00305   }
00306 
00307   void ScrollView::FormatContent()
00308   {
00309     Geometry geo;
00310     geo = GetGeometry();
00311 
00312     ComputeContentSize();
00313   }
00314 
00315   void ScrollView::PreLayoutManagement()
00316   {
00317     // Give the managed layout the same size and position as the Control.
00318 
00319     Geometry geo = GetGeometry();
00320     int ScrollBarWidth = _vscrollbar->GetBaseWidth();
00321     int ScrollBarHeight = _hscrollbar->GetBaseHeight();
00322 
00323     nuxAssertMsg(ScrollBarWidth > 0, "[ScrollView::PreLayoutManagement] Invalid scrollbar width: %d", ScrollBarWidth);
00324     nuxAssertMsg(ScrollBarHeight > 0, "[ScrollView::PreLayoutManagement] Invalid scrollbar height: %d", ScrollBarHeight);
00325 
00326     m_ViewX = GetBaseX() + m_border + m_ViewContentLeftMargin;
00327     m_ViewY = GetBaseY() + m_top_border + m_ViewContentTopMargin;
00328 
00329     if (m_vertical_scrollbar_enable == false)
00330       m_ViewWidth = GetBaseWidth() - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin;
00331     else
00332       m_ViewWidth = GetBaseWidth() - ScrollBarWidth - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin;
00333 
00334     nuxAssertMsg(m_ViewWidth > 0, "[ScrollView::PreLayoutManagement] Invalid view width: %d", m_ViewWidth);
00335 
00336     if (m_horizontal_scrollbar_enable == false)
00337       m_ViewHeight = GetBaseHeight() - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin;
00338     else
00339       m_ViewHeight = GetBaseHeight() - ScrollBarHeight - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin;
00340 
00341     nuxAssertMsg(m_ViewHeight > 0, "[ScrollView::PreLayoutManagement] Invalid view height: %d", m_ViewHeight);
00342 
00343     if (m_ViewX + _delta_x +  m_ViewContentWidth < m_ViewX + m_ViewWidth)
00344     {
00345       // The position of the end of the content is smaller than the view right border position
00346       // Compute _delta_x so the end of the content match exactly the view right border position
00347       _delta_x = - (m_ViewContentWidth > m_ViewWidth ? m_ViewContentWidth - m_ViewWidth : 0);
00348       nuxAssert(_delta_x <= 0);
00349     }
00350 
00351     if (m_ViewY + _delta_y + m_ViewContentHeight < m_ViewY + m_ViewHeight)
00352     {
00353       // The position of the end of the content is smaller than the view right border position
00354       // Compute _delta_y so the end of the content match exactly the view right border position
00355       _delta_y = - (m_ViewContentHeight > m_ViewHeight ? m_ViewContentHeight - m_ViewHeight : 0);
00356       nuxAssert(_delta_y <= 0);
00357     }
00358 
00359     if (view_layout_)
00360     {
00361       // Set the composition layout to the size of the view area and offset it by(_delta_x, _delta_y)
00362 
00363       if (view_layout_->GetScaleFactor() != 0)
00364       {
00365         view_layout_->SetGeometry(
00366                 m_ViewX,
00367                 m_ViewY,
00368                 m_ViewWidth,
00369                 m_ViewHeight);
00370       }
00371 
00372       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00373     }
00374 
00375     // Horizontal scrollbar Geometry
00376     if (m_horizontal_scrollbar_enable)
00377     {
00378       if (m_vertical_scrollbar_enable == false)
00379       {
00380         // If there is no vertical scrollbar, take all the width available.
00381         _hscrollbar->SetBaseWidth(GetBaseWidth() - 2 * m_border);
00382       }
00383       else
00384         _hscrollbar->SetBaseWidth(GetBaseWidth() - ScrollBarWidth - 2 * m_border);
00385 
00386       _hscrollbar->SetBaseX(geo.x + m_border);
00387       _hscrollbar->SetBaseY(geo.y + geo.GetHeight() - _hscrollbar->GetBaseHeight() - m_border);
00388       _hscrollbar->ComputeContentSize();
00389     }
00390     else
00391     {
00392       // The horizontal scrollbar won't be visible but give it a proper size anyway.
00393       _hscrollbar->SetBaseWidth(GetBaseWidth() - ScrollBarWidth - 2 * m_border);
00394       _hscrollbar->SetBaseX(geo.x + m_border);
00395       _hscrollbar->SetBaseY(geo.y + geo.GetHeight() - _hscrollbar->GetBaseHeight() - m_border);
00396       _hscrollbar->ComputeContentSize();
00397     }
00398 
00399 
00400     // Vertical scrollbar Geometry
00401     if (m_vertical_scrollbar_enable)
00402     {
00403       if (m_horizontal_scrollbar_enable == false)
00404       {
00405         // If there is no horizontal scrollbar, take all the width available.
00406         _vscrollbar->SetBaseHeight(GetBaseHeight() - m_top_border - m_border);
00407       }
00408       else
00409         _vscrollbar->SetBaseHeight(GetBaseHeight() - ScrollBarHeight - m_top_border - m_border);
00410 
00411       _vscrollbar->SetBaseX(geo.x + geo.GetWidth() - ScrollBarWidth - m_border);
00412       _vscrollbar->SetBaseY(geo.y + m_top_border);
00413       _vscrollbar->ComputeContentSize();
00414     }
00415     else
00416     {
00417       // The vertical scrollbar won't be visible but give it a proper size anyway.
00418       _vscrollbar->SetBaseHeight(GetBaseHeight() - ScrollBarHeight - m_top_border - m_border);
00419       _vscrollbar->SetBaseX(geo.x + geo.GetWidth() - ScrollBarWidth - m_border);
00420       _vscrollbar->SetBaseY(geo.y + m_top_border);
00421       _vscrollbar->ComputeContentSize();
00422     }
00423   }
00424 
00425   long ScrollView::PostLayoutManagement(long LayoutResult)
00426   {
00427     if (IsSizeMatchContent())
00428       return PostLayoutManagement2(LayoutResult);
00429 
00430     int ScrollBarWidth = 0;
00431     int ScrollBarHeight = 0;
00432 
00433     if (view_layout_)
00434     {
00435       m_ViewContentX = view_layout_->GetBaseX();
00436       m_ViewContentY = view_layout_->GetBaseY();
00437       m_ViewContentWidth = view_layout_->GetBaseWidth();
00438       m_ViewContentHeight = view_layout_->GetBaseHeight();
00439     }
00440 
00441     if (m_horizontal_scrollbar_enable)
00442       ScrollBarHeight = _hscrollbar->GetBaseHeight();
00443 
00444     if (m_vertical_scrollbar_enable)
00445       ScrollBarWidth = _vscrollbar->GetBaseWidth();
00446 
00447     _hscrollbar->SetContainerSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00448                                   GetBaseY() + m_top_border + m_ViewContentTopMargin,
00449                                   GetBaseWidth() - ScrollBarWidth - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin,
00450                                   GetBaseHeight() - ScrollBarHeight - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin);
00451 
00452     if (m_horizontal_scrollbar_enable)
00453     {
00454       if (view_layout_)
00455       {
00456         _hscrollbar->SetContentSize(view_layout_->GetBaseX(), view_layout_->GetBaseY(),
00457                                     view_layout_->GetBaseWidth(), view_layout_->GetBaseHeight());
00458       }
00459       else
00460       {
00461         _hscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00462                                     GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0);
00463       }
00464 
00465       _hscrollbar->SetContentOffset(_delta_x, _delta_y);
00466     }
00467     else
00468     {
00469       _hscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00470                                   GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0);
00471       _hscrollbar->SetContentOffset(0, 0);
00472     }
00473 
00474     _vscrollbar->SetContainerSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00475                                   GetBaseY() + m_top_border + m_ViewContentTopMargin,
00476                                   GetBaseWidth() - ScrollBarWidth - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin,
00477                                   GetBaseHeight() - ScrollBarHeight - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin);
00478 
00479     if (m_vertical_scrollbar_enable)
00480     {
00481       if (view_layout_)
00482       {
00483         _vscrollbar->SetContentSize(view_layout_->GetBaseX(), view_layout_->GetBaseY(),
00484                                     view_layout_->GetBaseWidth(), view_layout_->GetBaseHeight());
00485       }
00486       else
00487       {
00488         _vscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00489                                     GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0);
00490       }
00491 
00492       _vscrollbar->SetContentOffset(_delta_x, _delta_y);
00493     }
00494     else
00495     {
00496       _vscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00497                                   GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0);
00498       _vscrollbar->SetContentOffset(0, 0);
00499     }
00500 
00501     // I may not be necessary to call this function here since ComputeContentPosition was called on ComputeContentPosition
00502     // during the layout process.
00503     if (view_layout_)
00504       view_layout_->ComputeContentPosition(0, 0);
00505 
00506     // The ScrollView always returns complient width and height to its parent layout.
00507     return (eCompliantHeight | eCompliantWidth);
00508   }
00509 
00510   long ScrollView::PostLayoutManagement2(long LayoutResult)
00511   {
00512     // In case IsSizeMatchContent returns True, The scroll view is resized to match its content.
00513     int ScrollbarWidth = 0;
00514     int ScrollbarHeight = 0;
00515 
00516     if (m_horizontal_scrollbar_enable)
00517       ScrollbarHeight = _hscrollbar->GetBaseHeight();
00518 
00519     if (m_vertical_scrollbar_enable)
00520       ScrollbarWidth = _vscrollbar->GetBaseWidth();
00521 
00522     // We want the controller to match the size of the content as defined in:
00523     //      m_ViewContentX
00524     //      m_ViewContentY
00525     //      m_ViewContentWidth
00526     //      m_ViewContentHeight
00527     // So we make the composition layout the same size as the content
00528     // Note that classes that inherits from ScrollView are responsible for setting the dimension of the ViewContent
00529 
00530     if (view_layout_)
00531     {
00532       view_layout_->SetBaseX(m_ViewContentX);
00533       view_layout_->SetBaseY(m_ViewContentY);
00534       view_layout_->SetBaseWidth(m_ViewContentWidth);
00535       view_layout_->SetBaseHeight(m_ViewContentHeight);
00536     }
00537 
00538     Geometry base;
00539     // Given the(m_ViewContentWidth, m_ViewContentHeight) compute the size of the ScrollView.
00540     // It is possible that the ScrollView size be limited by its min/Max dimension. If this happens, then the scrollbar will reflect that.
00541     base.SetX(m_ViewContentX - m_border - m_ViewContentLeftMargin);
00542     base.SetY(m_ViewContentY - m_top_border - m_ViewContentTopMargin);
00543 
00544     if (m_horizontal_scrollbar_enable)
00545       base.SetHeight(m_top_border + m_ViewContentTopMargin + m_ViewContentHeight + m_ViewContentBottomMargin + ScrollbarHeight + m_border);
00546     else
00547       base.SetHeight(m_top_border + m_ViewContentTopMargin + m_ViewContentHeight + m_ViewContentBottomMargin + m_border);
00548 
00549     if (m_vertical_scrollbar_enable)
00550       base.SetWidth(m_border + m_ViewContentLeftMargin + m_ViewContentWidth + m_ViewContentRightMargin + ScrollbarWidth + m_border);
00551     else
00552       base.SetWidth(m_border + m_ViewContentLeftMargin + m_ViewContentWidth + m_ViewContentRightMargin + m_border);
00553 
00554     // Set the size so that is is equal to the visible content.
00555     Area::SetBaseWidth(base.GetWidth());
00556     Area::SetBaseHeight(base.GetHeight());
00557     Geometry geo = GetGeometry();
00558 
00559     // Horizontal scrollbar Geometry
00560     if (m_horizontal_scrollbar_enable)
00561     {
00562       if (m_vertical_scrollbar_enable == false)
00563         _hscrollbar->SetBaseWidth(GetBaseWidth() - 2 * m_border);
00564       else
00565         _hscrollbar->SetBaseWidth(GetBaseWidth() - ScrollbarWidth - 2 * m_border);
00566 
00567       _hscrollbar->SetBaseX(geo.x + m_border);
00568       _hscrollbar->SetBaseY(geo.y + geo.GetHeight() - _hscrollbar->GetBaseHeight() - m_border);
00569       _hscrollbar->ComputeContentSize();
00570 
00571       //---
00572       _hscrollbar->SetContainerSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00573                                     GetBaseY() + m_top_border + m_ViewContentTopMargin,
00574                                     GetBaseWidth() - ScrollbarWidth - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin,
00575                                     GetBaseHeight() - ScrollbarHeight - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin);
00576 
00577       if (view_layout_)
00578       {
00579         _hscrollbar->SetContentSize(view_layout_->GetBaseX(), view_layout_->GetBaseY(),
00580                                     view_layout_->GetBaseWidth(), view_layout_->GetBaseHeight());
00581       }
00582       else
00583       {
00584         _hscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00585                                     GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0);
00586       }
00587 
00588       _hscrollbar->SetContentOffset(_delta_x, _delta_y);
00589     }
00590     else
00591     {
00592       _hscrollbar->SetBaseWidth(GetBaseWidth() - ScrollbarWidth - 2 * m_border);
00593       _hscrollbar->SetBaseX(geo.x + m_border);
00594       _hscrollbar->SetBaseY(geo.y + geo.GetHeight() - _hscrollbar->GetBaseHeight() - m_border);
00595       _hscrollbar->ComputeContentSize();
00596 
00597       //---
00598       _hscrollbar->SetContainerSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00599                                     GetBaseY() + m_top_border + m_ViewContentTopMargin,
00600                                     GetBaseWidth() - ScrollbarWidth - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin,
00601                                     GetBaseHeight() - ScrollbarHeight - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin);
00602       _hscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00603                                   GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0);
00604       _hscrollbar->SetContentOffset(0, 0);
00605     }
00606 
00607 
00608     // Vertical scrollbar Geometry
00609     if (m_vertical_scrollbar_enable)
00610     {
00611       if (m_horizontal_scrollbar_enable == false)
00612         _vscrollbar->SetBaseHeight(GetBaseHeight() - m_top_border - m_border);
00613       else
00614         _vscrollbar->SetBaseHeight(GetBaseHeight() - ScrollbarHeight - m_top_border - m_border);
00615 
00616       _vscrollbar->SetBaseX(geo.x + geo.GetWidth() - ScrollbarWidth - m_border);
00617       _vscrollbar->SetBaseY(geo.y + m_top_border);
00618       _vscrollbar->ComputeContentSize();
00619 
00620       //---
00621       _vscrollbar->SetContainerSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00622                                     GetBaseY() + m_top_border + m_ViewContentTopMargin,
00623                                     GetBaseWidth() - ScrollbarWidth - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin,
00624                                     GetBaseHeight() - ScrollbarHeight - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin);
00625 
00626       if (view_layout_)
00627       {
00628         _vscrollbar->SetContentSize(view_layout_->GetBaseX(), view_layout_->GetBaseY(),
00629                                     view_layout_->GetBaseWidth(), view_layout_->GetBaseHeight());
00630       }
00631       else
00632       {
00633         _vscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00634                                     GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0);
00635       }
00636 
00637       _vscrollbar->SetContentOffset(_delta_x, _delta_y);
00638     }
00639     else
00640     {
00641       _vscrollbar->SetBaseHeight(GetBaseHeight() - ScrollbarHeight - m_top_border - m_border);
00642       _vscrollbar->SetBaseX(geo.x + geo.GetWidth() - ScrollbarWidth - m_border);
00643       _vscrollbar->SetBaseY(geo.y + m_top_border);
00644       _vscrollbar->ComputeContentSize();
00645 
00646       //---
00647       _vscrollbar->SetContainerSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00648                                     GetBaseY() + m_top_border + m_ViewContentTopMargin,
00649                                     GetBaseWidth() - ScrollbarWidth - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin,
00650                                     GetBaseHeight() - ScrollbarHeight - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin);
00651       _vscrollbar->SetContentSize(GetBaseX() + m_border + m_ViewContentLeftMargin,
00652                                   GetBaseY() + m_top_border + m_ViewContentTopMargin, 0, 0);
00653       _vscrollbar->SetContentOffset(0, 0);
00654     }
00655 
00656     if (view_layout_)
00657       view_layout_->ComputeContentPosition(0, 0);
00658 
00659     return (eCompliantHeight | eCompliantWidth);
00660   }
00661 
00662 // When the ScrollView is in a Layout object, and that layout call View::ComputeContentPosition
00663 // the ScrollView must call its own ComputeContentPosition so it can properly do the positioning of the inner object.
00664 // Otherwise, view_layout_->ComputeContentPosition is called but it doesn't know that it may not contain all the
00665 // object of the ScrollView. Which result in incorrect positioning.
00666 // Here we touch only the position. Do not touch the width or height of object.
00667 // This function is called when the ScrollView is embedded within a Layout.
00668   void ScrollView::ComputeContentPosition(float offsetX, float offsetY)
00669   {
00670     Geometry geo = GetGeometry();
00671     int w = 0;
00672     int h = 0;
00673 
00674     w = _vscrollbar->GetBaseWidth();
00675     h = _hscrollbar->GetBaseHeight();
00676 
00677     m_ViewX = GetBaseX() + m_border + m_ViewContentLeftMargin;
00678     m_ViewY = GetBaseY() + m_top_border + m_ViewContentTopMargin;
00679 
00680     if (m_vertical_scrollbar_enable == false)
00681       m_ViewWidth = GetBaseWidth() - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin;
00682     else
00683       m_ViewWidth = GetBaseWidth() - w - 2 * m_border - m_ViewContentRightMargin - m_ViewContentLeftMargin;
00684 
00685     if (m_horizontal_scrollbar_enable == false)
00686       m_ViewHeight = GetBaseHeight() - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin;
00687     else
00688       m_ViewHeight = GetBaseHeight() - h - m_top_border - m_border - m_ViewContentBottomMargin - m_ViewContentTopMargin;
00689 
00690 
00691     if (m_ViewX + _delta_x +  m_ViewContentWidth < m_ViewX + m_ViewWidth)
00692     {
00693       _delta_x = - (m_ViewContentWidth > m_ViewWidth ? m_ViewContentWidth - m_ViewWidth : 0);
00694     }
00695 
00696     if (m_ViewY + _delta_y + m_ViewContentHeight < m_ViewY + m_ViewHeight)
00697     {
00698       _delta_y = - (m_ViewContentHeight > m_ViewHeight ? m_ViewContentHeight - m_ViewHeight : 0);
00699     }
00700 
00701     if (view_layout_)
00702     {
00703       view_layout_->SetBaseX(m_ViewX);
00704       view_layout_->SetBaseY(m_ViewY);
00705     }
00706 
00707     // Horizontal scrollbar Geometry
00708     if (m_horizontal_scrollbar_enable)
00709     {
00710       if (m_vertical_scrollbar_enable == false)
00711         _hscrollbar->SetBaseWidth(GetBaseWidth() - 2 * m_border);
00712       else
00713         _hscrollbar->SetBaseWidth(GetBaseWidth() - w - 2 * m_border);
00714 
00715       _hscrollbar->SetBaseX(geo.x + m_border);
00716       _hscrollbar->SetBaseY(geo.y + geo.GetHeight() - _hscrollbar->GetBaseHeight() - m_border);
00717       _hscrollbar->ComputeContentSize();
00718     }
00719 
00720     // Vertical scrollbar Geometry
00721     if (m_vertical_scrollbar_enable)
00722     {
00723       if (m_horizontal_scrollbar_enable == false)
00724         _vscrollbar->SetBaseHeight(GetBaseHeight() - m_top_border - m_border);
00725       else
00726         _vscrollbar->SetBaseHeight(GetBaseHeight() - h - m_top_border - m_border);
00727 
00728       _vscrollbar->SetBaseX(geo.x + geo.GetWidth() - w - m_border);
00729       _vscrollbar->SetBaseY(geo.y + m_top_border);
00730       _vscrollbar->ComputeContentSize();
00731     }
00732 
00733     if (view_layout_)
00734     {
00735       m_ViewContentX = view_layout_->GetBaseX();
00736       m_ViewContentY = view_layout_->GetBaseY();
00737     }
00738     else
00739     {
00740       m_ViewContentX = m_ViewX;
00741       m_ViewContentY = m_ViewY;
00742     }
00743 
00744     _vscrollbar->SetContentOffset(_delta_x, _delta_y);
00745     _hscrollbar->SetContentOffset(_delta_x, _delta_y);
00746 
00747     if (view_layout_)
00748     {
00749       view_layout_->ComputeContentPosition(0, 0);
00750     }
00751   }
00752 
00753 
00754   void ScrollView::ScrollLeft(float stepx, int mousedx)
00755   {
00756     if (view_layout_)
00757     {
00758       _delta_x += (float) stepx * (float) mousedx;;
00759 
00760       if (_delta_x > 0)
00761       {
00762         _delta_x = 0;
00763       }
00764       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00765       scrolling.emit(_delta_x, _delta_y);
00766     }
00767 
00768     if (view_layout_)
00769     {
00770       _hscrollbar->SetContentOffset(_delta_x, _delta_y);
00771       _hscrollbar->QueueDraw();
00772     }
00773 
00774     QueueDraw();
00775   }
00776 
00777   void ScrollView::ScrollRight(float stepx, int mousedx)
00778   {
00779     if (view_layout_)
00780     {
00781       _delta_x -= (float) stepx * (float) mousedx;
00782 
00783       if (m_ViewX + _delta_x +  m_ViewContentWidth < m_ViewX + m_ViewWidth)
00784       {
00785         _delta_x = - (m_ViewContentWidth > m_ViewWidth ? m_ViewContentWidth - m_ViewWidth : 0);
00786       }
00787       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00788       scrolling.emit(_delta_x, _delta_y);
00789     }
00790 
00791     if (view_layout_)
00792     {
00793       _hscrollbar->SetContentOffset(_delta_x, _delta_y);
00794       _hscrollbar->QueueDraw();
00795     }
00796 
00797     QueueDraw();
00798   }
00799 
00800   void ScrollView::ScrollUp(float stepy, int mousedy)
00801   {
00802     if (m_ViewContentHeight <= m_ViewHeight)
00803       return;
00804 
00805     if (view_layout_)
00806     {
00807       int last_delta_y = _delta_y;
00808       _delta_y += stepy * mousedy;
00809 
00810       if (_delta_y > 0)
00811       {
00812         _delta_y = 0;
00813       }
00814 
00815       if (last_delta_y != _delta_y)
00816       {
00817         QueueDraw();
00818         _vscrollbar->QueueDraw();
00819       }
00820 
00821       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00822       _vscrollbar->SetContentOffset(_delta_x, _delta_y);
00823 
00824       scrolling.emit(_delta_x, _delta_y);
00825     }
00826   }
00827 
00828   void ScrollView::ScrollDown(float stepy, int mousedy)
00829   {
00830     if (m_ViewContentHeight <= m_ViewHeight)
00831       return;
00832 
00833     if (view_layout_)
00834     {
00835       int last_delta_y = _delta_y;
00836       _delta_y -= stepy * mousedy;
00837 
00838       if (m_ViewY + _delta_y + m_ViewContentHeight < m_ViewY + m_ViewHeight)
00839       {
00840         _delta_y = - (m_ViewContentHeight > m_ViewHeight ? m_ViewContentHeight - m_ViewHeight : 0);
00841       }
00842 
00843       if (last_delta_y != _delta_y)
00844       {
00845         QueueDraw();
00846         _vscrollbar->QueueDraw();
00847       }
00848 
00849       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00850      _vscrollbar->SetContentOffset(_delta_x, _delta_y);
00851 
00852       scrolling.emit(_delta_x, _delta_y);
00853     }
00854   }
00855 
00856   void ScrollView::SetSizeMatchContent(bool b)
00857   {
00858     m_bSizeMatchContent = b;
00859 
00860     if (view_layout_)
00861       view_layout_->ComputeContentSize();
00862   }
00863 
00864   bool ScrollView::IsSizeMatchContent() const
00865   {
00866     return m_bSizeMatchContent;
00867   }
00868 
00869   void ScrollView::ResetScrollToLeft()
00870   {
00871     _delta_x = 0;
00872     if (view_layout_)
00873       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00874 
00875     _hscrollbar->SetContentOffset(_delta_x, _delta_y);
00876     _hscrollbar->QueueDraw();
00877 
00878     QueueDraw();
00879   }
00880 
00881   void ScrollView::ResetScrollToRight()
00882   {
00883     if (view_layout_)
00884     {
00885       _delta_x = - (m_ViewContentWidth > m_ViewWidth ? m_ViewContentWidth - m_ViewWidth : 0);
00886       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00887     }
00888     else
00889     {
00890       _delta_x = 0;
00891     }
00892 
00893 
00894 
00895     _hscrollbar->SetContentOffset(_delta_x, _delta_y);
00896     _hscrollbar->QueueDraw();
00897 
00898     QueueDraw();
00899   }
00900 
00901   void ScrollView::ResetScrollToUp()
00902   {
00903     _delta_y = 0;
00904     if (view_layout_)
00905       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00906 
00907     _vscrollbar->SetContentOffset(_delta_x, _delta_y);
00908     _vscrollbar->QueueDraw();
00909 
00910     QueueDraw();
00911   }
00912 
00913   void ScrollView::ResetScrollToDown()
00914   {
00915     if (view_layout_)
00916     {
00917       _delta_y = - (m_ViewContentHeight > m_ViewHeight ? m_ViewContentHeight - m_ViewHeight : 0);
00918       view_layout_->Set2DTranslation(_delta_x, _delta_y, 0);
00919     }
00920     else
00921     {
00922       _delta_y = 0;
00923     }
00924 
00925     _vscrollbar->SetContentOffset(_delta_x, _delta_y);
00926     _vscrollbar->QueueDraw();
00927 
00928     QueueDraw();
00929   }
00930 
00931   void ScrollView::RecvMouseWheel(int x, int y, int wheel_delta, long button_flags, unsigned long key_flags)
00932   {
00933     // nux can't tell the difference between horizontal and vertical mouse wheel events
00934     // so we are only going to support vertical
00935     if (wheel_delta < 0)
00936     {
00937       ScrollDown(abs(wheel_delta / NUX_MOUSEWHEEL_DELTA), m_MouseWheelScrollSize);
00938     }
00939     else
00940     {
00941       ScrollUp(abs(wheel_delta / NUX_MOUSEWHEEL_DELTA), m_MouseWheelScrollSize);
00942     }
00943   }
00944 
00945   bool ScrollView::AcceptKeyNavFocus()
00946   {
00947     return false;
00948   }
00949 }