Back to index

lightning-sunbird  0.9+nobinonly
nsDeckFrame.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 //
00039 // Eric Vaughan
00040 // Netscape Communications
00041 //
00042 // See documentation in associated header file
00043 //
00044 
00045 #include "nsDeckFrame.h"
00046 #include "nsStyleContext.h"
00047 #include "nsPresContext.h"
00048 #include "nsIContent.h"
00049 #include "nsCOMPtr.h"
00050 #include "nsUnitConversion.h"
00051 #include "nsINameSpaceManager.h"
00052 #include "nsXULAtoms.h"
00053 #include "nsHTMLParts.h"
00054 #include "nsIPresShell.h"
00055 #include "nsCSSRendering.h"
00056 #include "nsIViewManager.h"
00057 #include "nsBoxLayoutState.h"
00058 #include "nsStackLayout.h"
00059 
00060 nsresult
00061 NS_NewDeckFrame(nsIPresShell* aPresShell, nsIFrame** aNewFrame,
00062                 nsIBoxLayout* aLayoutManager)
00063 {
00064   NS_PRECONDITION(aNewFrame, "null OUT ptr");
00065   if (!aNewFrame) {
00066     return NS_ERROR_NULL_POINTER;
00067   }
00068   nsDeckFrame* it = new (aPresShell) nsDeckFrame(aPresShell, aLayoutManager);
00069   if (!it)
00070     return NS_ERROR_OUT_OF_MEMORY;
00071 
00072   *aNewFrame = it;
00073   return NS_OK;
00074   
00075 } // NS_NewDeckFrame
00076 
00077 
00078 nsDeckFrame::nsDeckFrame(nsIPresShell* aPresShell,
00079                          nsIBoxLayout* aLayoutManager)
00080   : nsBoxFrame(aPresShell), mIndex(0)
00081 {
00082      // if no layout manager specified us the static sprocket layout
00083   nsCOMPtr<nsIBoxLayout> layout = aLayoutManager;
00084 
00085   if (!layout) {
00086     NS_NewStackLayout(aPresShell, layout);
00087   }
00088 
00089   SetLayoutManager(layout);
00090 }
00091 
00095 NS_IMETHODIMP
00096 nsDeckFrame::ChildrenMustHaveWidgets(PRBool& aMust) const
00097 {
00098   aMust = PR_TRUE;
00099   return NS_OK;
00100 }
00101 
00102 NS_IMETHODIMP
00103 nsDeckFrame::AttributeChanged(nsIContent*     aChild,
00104                               PRInt32         aNameSpaceID,
00105                               nsIAtom*        aAttribute,
00106                               PRInt32         aModType)
00107 {
00108   nsresult rv = nsBoxFrame::AttributeChanged(aChild, aNameSpaceID,
00109                                              aAttribute, aModType);
00110 
00111 
00112    // if the index changed hide the old element and make the now element visible
00113   if (aAttribute == nsXULAtoms::selectedIndex) {
00114     IndexChanged(GetPresContext());
00115   }
00116 
00117   return rv;
00118 }
00119 
00120 NS_IMETHODIMP
00121 nsDeckFrame::Init(nsPresContext* aPresContext,
00122                   nsIContent*     aContent,
00123                   nsIFrame*       aParent,
00124                   nsStyleContext* aStyleContext,
00125                   nsIFrame*       aPrevInFlow)
00126 {
00127   nsresult rv = nsBoxFrame::Init(aPresContext, aContent,
00128                                  aParent, aStyleContext,
00129                                  aPrevInFlow);
00130 
00131   mIndex = GetSelectedIndex();
00132 
00133   return rv;
00134 }
00135 
00136 void
00137 nsDeckFrame::HideBox(nsPresContext* aPresContext, nsIBox* aBox)
00138 {
00139   nsIView* view = aBox->GetView();
00140 
00141   if (view) {
00142     nsIViewManager* viewManager = view->GetViewManager();
00143     viewManager->SetViewVisibility(view, nsViewVisibility_kHide);
00144     viewManager->ResizeView(view, nsRect(0, 0, 0, 0));
00145   }
00146 }
00147 
00148 void
00149 nsDeckFrame::ShowBox(nsPresContext* aPresContext, nsIBox* aBox)
00150 {
00151   nsRect rect = aBox->GetRect();
00152   nsIView* view = aBox->GetView();
00153   if (view) {
00154     nsIViewManager* viewManager = view->GetViewManager();
00155     rect.x = rect.y = 0;
00156     viewManager->ResizeView(view, rect);
00157     viewManager->SetViewVisibility(view, nsViewVisibility_kShow);
00158   }
00159 }
00160 
00161 void
00162 nsDeckFrame::IndexChanged(nsPresContext* aPresContext)
00163 {
00164   //did the index change?
00165   PRInt32 index = GetSelectedIndex();
00166   if (index == mIndex)
00167     return;
00168 
00169   // redraw
00170   nsBoxLayoutState state(aPresContext);
00171   Redraw(state);
00172 
00173   // hide the currently showing box
00174   nsIBox* currentBox = GetBoxAt(mIndex);
00175   if (currentBox) // only hide if it exists
00176      HideBox(aPresContext, currentBox);
00177 
00178   // show the new box
00179   nsIBox* newBox = GetBoxAt(index);
00180   if (newBox) // only show if it exists
00181      ShowBox(aPresContext, newBox);
00182 
00183   mIndex = index;
00184 }
00185 
00186 PRInt32
00187 nsDeckFrame::GetSelectedIndex()
00188 {
00189   // default index is 0
00190   PRInt32 index = 0;
00191 
00192   // get the index attribute
00193   nsAutoString value;
00194   if (NS_CONTENT_ATTR_HAS_VALUE == mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::selectedIndex, value))
00195   {
00196     PRInt32 error;
00197 
00198     // convert it to an integer
00199     index = value.ToInteger(&error);
00200   }
00201 
00202   return index;
00203 }
00204 
00205 nsIBox* 
00206 nsDeckFrame::GetSelectedBox()
00207 {
00208  // ok we want to paint only the child that as at the given index
00209   PRInt32 index = GetSelectedIndex();
00210  
00211   // get the child at that index. 
00212   return GetBoxAt(index); 
00213 }
00214 
00215 
00216 NS_IMETHODIMP
00217 nsDeckFrame::Paint(nsPresContext*      aPresContext,
00218                    nsIRenderingContext& aRenderingContext,
00219                    const nsRect&        aDirtyRect,
00220                    nsFramePaintLayer    aWhichLayer,
00221                    PRUint32             aFlags)
00222 {
00223   // if a tab is hidden all its children are too.
00224 
00225   if (!GetStyleVisibility()->mVisible)
00226     return NS_OK;
00227 
00228   if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
00229     PaintSelf(aPresContext, aRenderingContext, aDirtyRect);
00230   }
00231 
00232   // only paint the seleced box
00233   nsIBox* box = GetSelectedBox();
00234   if (box) {
00235     PaintChild(aPresContext, aRenderingContext, aDirtyRect, box, aWhichLayer);
00236   }
00237 
00238   return NS_OK;
00239 
00240 }
00241 
00242 
00243 NS_IMETHODIMP
00244 nsDeckFrame::GetFrameForPoint(const nsPoint&    aPoint, 
00245                               nsFramePaintLayer aWhichLayer,    
00246                               nsIFrame**        aFrame)
00247 {
00248   // if it is not inside us fail
00249   if (!mRect.Contains(aPoint)) {
00250     return NS_ERROR_FAILURE;
00251   }
00252 
00253   // get the selected frame and see if the point is in it.
00254   nsIBox* selectedBox = GetSelectedBox();
00255   if (selectedBox) {
00256     nsPoint tmp(aPoint.x - mRect.x, aPoint.y - mRect.y);
00257 
00258     if (NS_SUCCEEDED(selectedBox->GetFrameForPoint(tmp, aWhichLayer, aFrame)))
00259       return NS_OK;
00260   }
00261     
00262   // if its not in our child just return us.
00263   if (aWhichLayer == NS_FRAME_PAINT_LAYER_BACKGROUND) {
00264       *aFrame = this;
00265       return NS_OK;
00266   }
00267 
00268   return NS_ERROR_FAILURE;
00269 }
00270 
00271 
00272 NS_IMETHODIMP
00273 nsDeckFrame::DoLayout(nsBoxLayoutState& aState)
00274 {
00275   // Make sure we tweak the state so it does not resize our children.
00276   // We will do that.
00277   PRUint32 oldFlags = aState.LayoutFlags();
00278   aState.SetLayoutFlags(NS_FRAME_NO_SIZE_VIEW | NS_FRAME_NO_VISIBILITY);
00279 
00280   // do a normal layout
00281   nsresult rv = nsBoxFrame::DoLayout(aState);
00282 
00283   // run though each child. Hide all but the selected one
00284   nsIBox* box = nsnull;
00285   GetChildBox(&box);
00286 
00287   nscoord count = 0;
00288   while (box) 
00289   {
00290     // make collapsed children not show up
00291     if (count == mIndex) 
00292       ShowBox(aState.PresContext(), box);
00293     else
00294       HideBox(aState.PresContext(), box);
00295 
00296     nsresult rv2 = box->GetNextBox(&box);
00297     NS_ASSERTION(NS_SUCCEEDED(rv2), "failed to get next child");
00298     count++;
00299   }
00300 
00301   aState.SetLayoutFlags(oldFlags);
00302 
00303   return rv;
00304 }
00305