From 4b50dd6645c9ffeb8738ff54eda8ea8f646f8d92 Mon Sep 17 00:00:00 2001 From: "kmcclusk%netscape.com" Date: Fri, 7 May 1999 20:30:16 +0000 Subject: [PATCH] bug #3547- Modified nsFileControlFrame.cpp to call nsFormFrame::AddFormControlFrame. bug #5589. Selection area is now calculated using the inherited Reflow rather than using the calculations used for the native listbox control. Fixed varous other rendering bugs related to frame-based listboxes. bug #2797. GetSize is no longer needed in nsListControlFrame and it has been removed. Fixed frame-based combobox nsComboboxFrame so that will set it's label to the first option in the drop-down list if a default value has not been specified. Added optgroup style rules to ua.css. Opt groups now render, but there are remaining problems with selection. Modified nsButtonControlFrame::Reflow to call nsFormFrame::AddFormControlFrame. This fixes a bug where Gfx-rendered submit button's were not working. Refactored code in nsListControlFrame in preparation for supporting option groups. Refactored selection code into SingleSelect and MultiSelect paths. Removed unused code in nsListControlFrame. Removed mSelectedFrame member variable. It is no longer needed. Fixed nsListControlFrame::SetProperty so that it will toggle the selection in a single select listbox. git-svn-id: svn://10.0.0.236/trunk@30740 18797224-902f-48f8-a5cc-f745e15eee43 --- .../layout/forms/nsComboboxControlFrame.cpp | 32 +- mozilla/layout/forms/nsComboboxControlFrame.h | 1 + mozilla/layout/forms/nsFileControlFrame.cpp | 5 + mozilla/layout/forms/nsListControlFrame.cpp | 715 +++++++++++------- mozilla/layout/forms/nsListControlFrame.h | 43 +- mozilla/layout/html/document/src/ua.css | 16 +- .../html/forms/src/nsButtonControlFrame.cpp | 5 + .../html/forms/src/nsComboboxControlFrame.cpp | 32 +- .../html/forms/src/nsComboboxControlFrame.h | 1 + .../html/forms/src/nsFileControlFrame.cpp | 5 + .../html/forms/src/nsListControlFrame.cpp | 715 +++++++++++------- .../html/forms/src/nsListControlFrame.h | 43 +- mozilla/layout/style/ua.css | 16 +- 13 files changed, 1011 insertions(+), 618 deletions(-) diff --git a/mozilla/layout/forms/nsComboboxControlFrame.cpp b/mozilla/layout/forms/nsComboboxControlFrame.cpp index 595d1c43ac5..1a8f5d8e416 100644 --- a/mozilla/layout/forms/nsComboboxControlFrame.cpp +++ b/mozilla/layout/forms/nsComboboxControlFrame.cpp @@ -128,6 +128,28 @@ nsComboboxControlFrame::IsSuccessful(nsIFormControlFrame* aSubmitter) return (NS_CONTENT_ATTR_HAS_VALUE == GetName(&name)); } + +// Initialize the text string in the combobox using either the current +// selection in the list box or the first item item in the list box. + +void nsComboboxControlFrame::InitTextStr() +{ + // Update the selected text string + mListControlFrame->GetSelectedItem(mTextStr); + + if (mTextStr == "") { + // No selection so use the first item in the list box + nsIFormControlFrame* fcFrame = nsnull; + nsresult result = mListFrame->QueryInterface(kIFormControlFrameIID, (void**)&fcFrame); + if ((NS_OK == result) && (nsnull != fcFrame)) { + // Set listbox selection to first item in the list box + fcFrame->SetProperty(nsHTMLAtoms::selectedindex, "0"); + // Get the listbox selection as a string + mListControlFrame->GetSelectedItem(mTextStr); + } + } +} + //-------------------------------------------------------------- void @@ -139,6 +161,8 @@ nsComboboxControlFrame::Reset() if ((NS_OK == result) && (nsnull != fcFrame)) { fcFrame->Reset(); } + + InitTextStr(); } void @@ -279,13 +303,19 @@ NS_IMETHODIMP nsComboboxControlFrame::Reflow(nsIPresContext& aPresConte // XXX Combo box should be changed to be implemented as a label and button frame. // This would eliminate all of this Reflow code. KMM + // add ourself as an nsIFormControlFrame + if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { + nsFormFrame::AddFormControlFrame(aPresContext, *this); + } + if (mFirstTime) { ReResolveStyleContext(&aPresContext, mStyleContext, NS_STYLE_HINT_REFLOW, nsnull, nsnull); // XXX This temporary mListFrame->ReResolveStyleContext(&aPresContext, mCurrentStyleContext, NS_STYLE_HINT_REFLOW, nsnull, nsnull); - nsFormFrame::AddFormControlFrame(aPresContext, *this); mFirstTime = PR_FALSE; + InitTextStr(); } + PRInt32 numChildren = mFrames.GetLength(); if (1 == numChildren) { diff --git a/mozilla/layout/forms/nsComboboxControlFrame.h b/mozilla/layout/forms/nsComboboxControlFrame.h index f7f7b1e53cc..ff243d029dc 100644 --- a/mozilla/layout/forms/nsComboboxControlFrame.h +++ b/mozilla/layout/forms/nsComboboxControlFrame.h @@ -138,6 +138,7 @@ protected: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer); virtual PRIntn GetSkipSides() const; + void InitTextStr(); nsFormFrame* mFormFrame; // Parent Form Frame nsIFrame * mPlaceHolderFrame; diff --git a/mozilla/layout/forms/nsFileControlFrame.cpp b/mozilla/layout/forms/nsFileControlFrame.cpp index 5cab8483af1..11b1e50a95d 100644 --- a/mozilla/layout/forms/nsFileControlFrame.cpp +++ b/mozilla/layout/forms/nsFileControlFrame.cpp @@ -187,6 +187,11 @@ NS_IMETHODIMP nsFileControlFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { + // add ourself as an nsIFormControlFrame + if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { + nsFormFrame::AddFormControlFrame(aPresContext, *this); + } + PRInt32 numChildren = mFrames.GetLength(); nsIFrame* childFrame; diff --git a/mozilla/layout/forms/nsListControlFrame.cpp b/mozilla/layout/forms/nsListControlFrame.cpp index 6c6c22fd0e9..63f6157857f 100644 --- a/mozilla/layout/forms/nsListControlFrame.cpp +++ b/mozilla/layout/forms/nsListControlFrame.cpp @@ -61,11 +61,18 @@ #include "nsIViewManager.h" #include "nsFormFrame.h" #include "nsIScrollableView.h" +#include "nsVoidArray.h" +#include "nsIDOMHTMLOptGroupElement.h" + + // Constants const char * kNormal = ""; const char * kSelected = "SELECTED"; const char * kSelectedFocus = "SELECTEDFOCUS"; +const nscoord kMaxDropDownRows = 3; +const PRInt32 kNothingSelected = -1; + //XXX: This is temporary. It simulates psuedo states by using a attribute selector on // -moz-option-selected in the ua.css style sheet. This will not be needed when //The event state manager is functional. KMM @@ -79,6 +86,8 @@ static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID); static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); +static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); +static NS_DEFINE_IID(kIDOMHTMLOptGroupElementIID, NS_IDOMHTMLOPTGROUPELEMENT_IID); //---------------------------------------------------------------------- @@ -98,22 +107,24 @@ nsListControlFrame::nsListControlFrame() { mHitFrame = nsnull; mCurrentHitFrame = nsnull; - mSelectedFrame = nsnull; mSelectedContent = nsnull; - mSelectedIndex = -1; + mSelectedIndex = kNothingSelected; mNumRows = 0; mIsInitializedFromContent = PR_FALSE; mNumSelections = 0; mInDropDownMode = PR_FALSE; mComboboxFrame = nsnull; mFormFrame = nsnull; + mSelectableFrames = new nsVoidArray; } //---------------------------------------------------------------------- nsListControlFrame::~nsListControlFrame() { - NS_IF_RELEASE(mComboboxFrame); + mComboboxFrame = nsnull; mFormFrame = nsnull; + delete mSelectableFrames; + mSelectableFrames = nsnull; } //---------------------------------------------------------------------- @@ -140,6 +151,48 @@ nsListControlFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) return nsScrollFrame::QueryInterface(aIID, aInstancePtr); } +PRBool nsListControlFrame::IsOptionGroup(nsIFrame* aFrame) +{ + PRBool result = PR_FALSE; + nsIContent*content = nsnull; + aFrame->GetContent(&content); + nsIDOMHTMLOptGroupElement* og = nsnull; + if (content && (NS_OK == content->QueryInterface(kIDOMHTMLOptGroupElementIID, (void**) &og))) { + if (og != nsnull) { + result = PR_TRUE; + NS_RELEASE(og); + } + NS_RELEASE(content); + } + + return result; +} + +void nsListControlFrame::ConstructSelectableList(nsIFrame* aFrame, nsVoidArray* aList) +{ + nsIFrame* kid = nsnull; + aFrame->FirstChild(nsnull, &kid); + while (nsnull != kid) { + if (IsOptionGroup(kid)) { + ConstructSelectableList(kid, aList); + } else { + aList->AppendElement(kid); + kid->GetNextSibling(&kid); + } + } +} + +nsIFrame* nsListControlFrame::GetFirstSelectableFrame(nsVoidArray *aList, PRInt32& aPos) +{ + aPos = 1; + return((nsIFrame*)aList->ElementAt(0)); +} + +nsIFrame* nsListControlFrame::GetNextSelectableFrame(nsVoidArray *aList, PRInt32& aPos) +{ + return((nsIFrame*)aList->ElementAt(aPos++)); +} + //---------------------------------------------------------------------- NS_IMETHODIMP @@ -177,7 +230,6 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, nsRect kidRect; nsPoint tmp; nsRect offset(0, 0, 0, 0); - nsPoint absPoint = aPoint; *aFrame = nsnull; nsIFrame* firstKid = nsnull; @@ -204,7 +256,8 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, // As a hack we adjust for missing view offset by adding code to the nsListControlFrame::GetFrameForPoint which first // gets the ScrollableView associated with the nsListControlFrame and asks for it's GetScrollPosition offsets. These are // added to the point that is passed in so the correct frame is returned from nsListControlFrame::GetFrameForPoint. - + + tmp.MoveTo(aPoint.x, aPoint.y); nsIView *view = nsnull; GetView(&view); if (nsnull != view) { @@ -213,17 +266,57 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, nsIScrollableView* scrollableView; if (NS_SUCCEEDED(view->QueryInterface(kIScrollableViewIID, (void **)&scrollableView))) { scrollableView->GetScrollPosition(offsetx, offsety); - absPoint.x += offsetx; - absPoint.y += offsety; + tmp.x += offsetx; + tmp.y += offsety; // Note: scrollableView is not ref counted so it's interface is not NS_RELEASE'd } } - + +#ifdef NS_OPTGROUPSUPPORT + nsIFrame* selectedFrame = nsnull; + nsresult rv = nsScrollFrame::GetFrameForPoint(tmp, &selectedFrame); + + + // Walk up the frames looking for a selectable frame. + // A selectable frame is defined as a frame sitting under the ScrollArea's + // Area Frame or the first optiongroup ancestor. + + if (nsnull != selectedFrame) { + PRBool done = PR_FALSE; + while (! done) { + nsIFrame* parent = nsnull; + selectedFrame->GetParent(&parent); + if (parent != nsnull) { + if ((parent == mContentFrame) || (IsOptionGroup(parent))) { + done = PR_TRUE; + } else { + // Continue looking at ancestors + selectedFrame = parent; + } + } else { + // Parent is null so stop looking + done = PR_TRUE; + } + } + } + + *aFrame = selectedFrame; + + return rv; + +#else + +//XXX: Remove the following code when the code above works + + // Remove the top border from the offset. + nsMargin border; + tmp.y -= mBorderOffsetY; + mContentFrame->FirstChild(aList, &kid); while (nsnull != kid) { kid->GetRect(kidRect); - if (kidRect.Contains(absPoint)) { - tmp.MoveTo(absPoint.x - kidRect.x, absPoint.y - kidRect.y); + if (kidRect.Contains(tmp)) { + tmp.MoveTo(tmp.x - kidRect.x, tmp.y - kidRect.y); nsIContent * content; kid->GetContent(&content); @@ -246,7 +339,7 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, kid->GetFrameState(&state); if (NS_FRAME_OUTSIDE_CHILDREN & state) { kid->GetRect(kidRect); - tmp.MoveTo(absPoint.x - kidRect.x, absPoint.y - kidRect.y); + tmp.MoveTo(tmp.x - kidRect.x, tmp.y - kidRect.y); if (NS_OK == kid->GetFrameForPoint(tmp, aFrame)) { return NS_OK; } @@ -255,6 +348,7 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, } *aFrame = this; return NS_ERROR_FAILURE; +#endif } @@ -290,40 +384,38 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, InitializeFromContent(PR_TRUE); } - nsIFrame* childFrame = nsnull; - mContentFrame->FirstChild(nsnull, &childFrame); - PRInt32 numChildren = LengthOf(childFrame); - - PRBool needsVerticalScrollbar = PR_FALSE; - if (PR_FALSE == mInDropDownMode) { - PRBool needsVerticalScrollbar = (numChildren > mNumRows); - } //--Calculate a width just big enough for the scrollframe to shrink around the //longest element in the list - //XXX: This is usually dangerous to do this type of coercion. Should it set the - //State back to the original when done??? - nsHTMLReflowState& tempReflowState = (nsHTMLReflowState&)aReflowState; - - // Get the size of option elements inside the listbox - nsSize desiredLineSize; - nsHTMLReflowMetrics desiredSize = aDesiredSize; - // Save original values which will be modified for the reflow state. - // They are set back to their original values at the end of reflow. - nscoord saveComputedWidth = tempReflowState.computedWidth; - nscoord saveAvailableWidth = tempReflowState.availableWidth; - + nsHTMLReflowState secondPassState(aReflowState); + nsHTMLReflowState firstPassState(aReflowState); + + // Get the size of option elements inside the listbox // Compute the width based on the longest line in the listbox. - // XXX: This should be changed to do the inherited reflow unconstrained for - // the width to get the real desired width. GetDesiredSize is limited to - // text strings. - //XXX: TODO: Use the width and height of an the first reflow to determine how high and wide - //to make the listbox, instead of calculating it. The second reflow can be done actually position - //the frames correctly using: tempReflowState.reason = eReflowReason_Resize; - GetDesiredSize(&aPresContext, aReflowState, desiredSize, desiredLineSize); + firstPassState.computedWidth = NS_UNCONSTRAINEDSIZE; + firstPassState.computedHeight = NS_UNCONSTRAINEDSIZE; + firstPassState.availableWidth = NS_UNCONSTRAINEDSIZE; + firstPassState.availableHeight = NS_UNCONSTRAINEDSIZE; - // Retrieve the scrollbar's width and height + + nsSize scrolledAreaSize(0,0); + nsHTMLReflowMetrics scrolledAreaDesiredSize(&scrolledAreaSize); + nsScrollFrame::Reflow(aPresContext, + scrolledAreaDesiredSize, + firstPassState, + aStatus); + + // Compute the bounding box of the contents of the list using the area + // calculated by the first reflow as a starting point. + + nscoord scrolledAreaWidth = scrolledAreaDesiredSize.maxElementSize->width; + nscoord scrolledAreaHeight = scrolledAreaDesiredSize.height; + + // The first reflow produces a box with the scrollbar width and borders + // added in so we need to subtract them out. + + // Retrieve the scrollbar's width and height float sbWidth = 0.0; float sbHeight = 0.0;; nsCOMPtr dc; @@ -333,88 +425,116 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, nscoord scrollbarWidth = NSToCoordRound(sbWidth); nscoord scrollbarHeight = NSToCoordRound(sbHeight); - if (mInDropDownMode) { - // For drop-down lists, always size the width of the list based on - // the desired lineSize. - tempReflowState.computedWidth = desiredLineSize.width + scrollbarWidth; - } else if (NS_UNCONSTRAINEDSIZE == tempReflowState.computedWidth) { - // Only set to the desired width if it hasn't been explicitly defined through CSS. - // GetDesiredSize must still be done above to calculate the desired height. - tempReflowState.computedWidth = desiredLineSize.width; + // Subtract out the scrollbar width + scrolledAreaWidth -= scrollbarWidth; + + // Subtract out the borders + nsMargin border; + if (!aReflowState.mStyleSpacing->GetBorder(border)) { + border.SizeTo(0, 0, 0, 0); } + //XXX: Should just get the border.top when needed instead of + //caching it. + mBorderOffsetY = border.top; - // Add vertical scrollbar, Always add it in, - // even though the vertical scrollbar is not needed all the time - // the inherited Reflow: allways leave space for the scrollbar by - // shrinking the scroll area by the scrollbar width + scrolledAreaWidth -= (border.left + border.right); + scrolledAreaHeight -= (border.top + border.bottom); - tempReflowState.computedWidth += scrollbarWidth; - - // Now that we have calculated the width required to just shrink around the longest line. - // Go ahead and reflow - // Do the inherited Reflow. This reflow uses the computed widths which - // are setup above. - // Don't set the height. Let the height be unconstrained + // Now the scrolledAreaWidth and scrolledAreaHeight are exactly + // wide and high enough to enclose their contents + nscoord visibleWidth = 0; if (mInDropDownMode) { - // The dropdown list height is the smaller of it's height setting or the height - // of the smallest box that can drawn around it's contents. - if (tempReflowState.computedHeight > (desiredSize.height)) { - tempReflowState.computedHeight = desiredSize.height ; + // Always set the width to be + // XXX: TODO The width of the list should be passed in so it can + // be set to the same as the text box + dropdown arrow. + visibleWidth = scrolledAreaWidth; + if (nsnull != mComboboxFrame) { + nsRect comboRect; + nsIFrame *comboFrame = nsnull; + if (NS_SUCCEEDED(mComboboxFrame->QueryInterface(kIFrameIID, (void **)&comboFrame))) { + comboFrame->GetRect(comboRect); + visibleWidth = comboRect.width; + visibleWidth -= (border.left + border.right); + } + } + + } else { + if (NS_UNCONSTRAINEDSIZE == aReflowState.computedWidth) { + visibleWidth = scrolledAreaWidth; + } else { + visibleWidth = aReflowState.computedWidth; } } - + + // Determine if a scrollbar will be needed, If so we need to add + // enough the width to allow for the scrollbar. + // The scrollbar will be needed under two conditions: + // (size * heightOfaRow) < scrolledAreaHeight or + // the height set through Style < scrolledAreaHeight. + + // Calculate the height of a row. + // XXX: Fix this for optgroup's. + nsIFrame* childFrame = nsnull; + mContentFrame->FirstChild(nsnull, &childFrame); + PRInt32 numChildren = LengthOf(childFrame); + PRInt32 heightOfARow = scrolledAreaHeight / numChildren; + + nscoord visibleHeight = 0; + if (mInDropDownMode) { + // Compute the visible height of the drop-down list + // The dropdown list height is the smaller of it's height setting or the height + // of the smallest box that can drawn around it's contents. + visibleHeight = scrolledAreaHeight; + + if (visibleHeight > (kMaxDropDownRows * heightOfARow)) + visibleHeight = (kMaxDropDownRows * heightOfARow); + + } else { + // Calculate the visible height of the listbox + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedHeight) { + visibleHeight = aReflowState.computedHeight; + } else { + if (numChildren == mNumRows) { + // Make sure scrollbars go away when the number of rows + // matchs the number of items to scroll. + visibleHeight = aReflowState.computedHeight; + } else { + visibleHeight = mNumRows * heightOfARow; + } + } + } + + PRBool needsVerticalScrollbar = PR_FALSE; + if (visibleHeight < scrolledAreaHeight) { + needsVerticalScrollbar = PR_TRUE; + } + + if ((needsVerticalScrollbar) && (! mInDropDownMode)) { + visibleWidth += scrollbarWidth; + } + + // Do a second reflow with the adjusted width and height settings + // This sets up all of the frames with the correct width and height. + secondPassState.computedWidth = visibleWidth; + secondPassState.computedHeight = visibleHeight; + secondPassState.reason = eReflowReason_Resize; nsScrollFrame::Reflow(aPresContext, aDesiredSize, - tempReflowState, + secondPassState, aStatus); - // Now that we have reflowed, we may need to adjust the width and height returned - // for the listbox. - - if (PR_FALSE == mInDropDownMode) { - // Set the desired height to the computed height above only if it has not - // been explicitly set by CSS. - if (NS_UNCONSTRAINEDSIZE == tempReflowState.computedHeight) { - aDesiredSize.height = desiredSize.height; - } - } - - //Need to addback the scrollbar because the inherited reflow - //subtracts the scrollbar width when computing the desired size. - //We don't subtract when there isn't a vertical scrollbar. This may - //seem odd, becuase above we always add in the scrollbar width before calling - //reflow. The reason is that inherited reflow always leaves blank space for - //the scrollbar, but we don't whant that behavior for the listbox'es scrollbars. - if (needsVerticalScrollbar) { - aDesiredSize.width += scrollbarWidth; - } // Set the max element size to be the same as the desired element size. if (nsnull != aDesiredSize.maxElementSize) { aDesiredSize.maxElementSize->width = aDesiredSize.width; aDesiredSize.maxElementSize->height = aDesiredSize.height; } - // XXX: Set the min element size here to the desired element size here?? - // Restore to original reflow state. - tempReflowState.computedWidth = saveComputedWidth; - tempReflowState.availableWidth = saveAvailableWidth; - aStatus = NS_FRAME_COMPLETE; return NS_OK; } -NS_IMETHODIMP nsListControlFrame::SetRect(const nsRect& aRect) -{ - nsScrollFrame::SetRect(aRect); - return NS_OK; -} -NS_IMETHODIMP nsListControlFrame::SizeTo(nscoord aWidth, nscoord aHeight) -{ - nsScrollFrame::SizeTo(aWidth, aHeight); - return NS_OK; -} //---------------------------------------------------------------------- nsIFrame * @@ -444,6 +564,7 @@ nsListControlFrame::GetOptionFromChild(nsIFrame* aParentFrame) return nsnull; } + //-------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::GetFormContent(nsIContent*& aContent) const @@ -466,6 +587,17 @@ nsListControlFrame::GetFont(nsIPresContext* aPresContext, } +void nsListControlFrame::ForceRedraw(nsIContent* aContent) +{ + //XXX: Hack. This should not be needed. The problem is DisplaySelected + //and DisplayDeselected set and unset an attribute on generic HTML content + //which does not know that it should repaint as the result of the attribute + //being set. This should not be needed once the event state manager handles + //selection. + nsFormControlHelper::ForceDrawFrame(this); +} + + // XXX: Here we introduce a new -moz-option-selected attribute so a attribute // selecitor n the ua.css can change the style when the option is selected. @@ -474,8 +606,11 @@ void nsListControlFrame::DisplaySelected(nsIContent* aContent) //XXX: This is temporary. It simulates psuedo states by using a attribute selector on // -moz-option-selected in the ua.css style sheet. This will not be needed when // The event state manager is functional. KMM + nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); aContent->SetAttribute(kNameSpaceID_None, selectedAtom, "", PR_TRUE); + ForceRedraw(aContent); + } void nsListControlFrame::DisplayDeselected(nsIContent* aContent) @@ -483,8 +618,11 @@ void nsListControlFrame::DisplayDeselected(nsIContent* aContent) //XXX: This is temporary. It simulates psuedo states by using a attribute selector on // -moz-option-selected in the ua.css style sheet. This will not be needed when // The event state manager is functional. KMM + nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); aContent->UnsetAttribute(kNameSpaceID_None, selectedAtom, PR_TRUE); + ForceRedraw(aContent); + } void nsListControlFrame::UpdateItem(nsIContent* aContent, PRBool aSelected) @@ -517,7 +655,7 @@ PRInt32 nsListControlFrame::SetContentSelected(nsIFrame * aHitFrame, kid->GetNextSibling(&kid); index++; } - return -1; + return kNothingSelected; } //---------------------------------------------------------------------- @@ -584,82 +722,104 @@ void nsListControlFrame::ExtendedSelection(PRInt32 aStartIndex, PRInt32 aEndInde } } +void nsListControlFrame::SingleSelection() +{ + // Store previous selection + PRInt32 oldSelectedIndex = mSelectedIndex; + // Get Current selection + mSelectedIndex = (PRInt32)SetContentSelected(mHitFrame, mHitContent, PR_FALSE); + if (mSelectedIndex != kNothingSelected) { + if (oldSelectedIndex != mSelectedIndex) { + // Deselect the previous selection if there is one + if (oldSelectedIndex != kNothingSelected) { + SetFrameSelected(oldSelectedIndex, PR_FALSE); + } + // Dipslay the new selection + SetFrameSelected(mSelectedIndex, PR_TRUE); + mSelectedContent = mHitContent; + } else { + // Selecting the currently selected item so do nothing. + } + } +} + +void nsListControlFrame::MultipleSelection(PRBool aIsShift, PRBool aIsControl) +{ + PRInt32 oldSelectedIndex = mSelectedIndex; + + mSelectedIndex = (PRInt32)SetContentSelected(mHitFrame, mHitContent, PR_FALSE); + if (kNothingSelected != mSelectedIndex) { + PRBool wasSelected = IsFrameSelected(mSelectedIndex); + SetFrameSelected(mSelectedIndex, PR_TRUE); + PRBool selected = wasSelected; + + if (aIsShift) { + selected = PR_TRUE; + if (mEndExtendedIndex == kNothingSelected) { + mEndExtendedIndex = mSelectedIndex; + ExtendedSelection(mStartExtendedIndex, mEndExtendedIndex, PR_FALSE, PR_TRUE); + } else { + if (mStartExtendedIndex < mEndExtendedIndex) { + if (mSelectedIndex < mStartExtendedIndex) { + ExtendedSelection(mSelectedIndex, mEndExtendedIndex, PR_TRUE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex > mEndExtendedIndex) { + ExtendedSelection(mEndExtendedIndex+1, mSelectedIndex, PR_FALSE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex < mEndExtendedIndex) { + ExtendedSelection(mSelectedIndex+1, mEndExtendedIndex, PR_FALSE, PR_FALSE); + mEndExtendedIndex = mSelectedIndex; + } + } else if (mStartExtendedIndex > mEndExtendedIndex) { + if (mSelectedIndex > mStartExtendedIndex) { + ExtendedSelection(mEndExtendedIndex, mSelectedIndex, PR_TRUE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex < mEndExtendedIndex) { + ExtendedSelection(mStartExtendedIndex+1, mEndExtendedIndex-1, PR_FALSE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex > mEndExtendedIndex) { + ExtendedSelection(mEndExtendedIndex, mSelectedIndex-1, PR_FALSE, PR_FALSE); + mEndExtendedIndex = mSelectedIndex; + } + } + } + } else if (aIsControl) { + selected = !selected; + if (nsnull != mSelectedContent) { + if (mHitContent != mSelectedContent) { + // Toggle the selection + UpdateItem(mHitContent, !wasSelected); + } else { +//XXX: Fix this mSelectedContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (selected?kSelectedFocus:kNormal), PR_TRUE); + } + } + } else { + mStartExtendedIndex = mSelectedIndex; + mEndExtendedIndex = kNothingSelected; + ClearSelection(); + selected = PR_TRUE; + } + + //XXX Fix this mHitContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (selected?kSelectedFocus:kNormal), PR_TRUE); + mSelectedContent = mHitContent; + } + +} + //---------------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::HandleLikeListEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsEventStatus& aEventStatus) { if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) { - PRInt32 oldSelectedIndex = mSelectedIndex; - - mSelectedIndex = (PRInt32)SetContentSelected(mHitFrame, mHitContent, PR_FALSE); - if (-1 < mSelectedIndex) { - PRBool wasSelected = IsFrameSelected(mSelectedIndex); - SetFrameSelected(mSelectedIndex, PR_TRUE); - PRBool selected = wasSelected; - if (mMultipleSelections) { - - if (((nsMouseEvent *)aEvent)->isShift) { - selected = PR_TRUE; - if (mEndExtendedIndex == -1) { - mEndExtendedIndex = mSelectedIndex; - ExtendedSelection(mStartExtendedIndex, mEndExtendedIndex, PR_FALSE, PR_TRUE); - } else { - if (mStartExtendedIndex < mEndExtendedIndex) { - if (mSelectedIndex < mStartExtendedIndex) { - ExtendedSelection(mSelectedIndex, mEndExtendedIndex, PR_TRUE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex > mEndExtendedIndex) { - ExtendedSelection(mEndExtendedIndex+1, mSelectedIndex, PR_FALSE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex < mEndExtendedIndex) { - ExtendedSelection(mSelectedIndex+1, mEndExtendedIndex, PR_FALSE, PR_FALSE); - mEndExtendedIndex = mSelectedIndex; - } - } else if (mStartExtendedIndex > mEndExtendedIndex) { - if (mSelectedIndex > mStartExtendedIndex) { - ExtendedSelection(mEndExtendedIndex, mSelectedIndex, PR_TRUE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex < mEndExtendedIndex) { - ExtendedSelection(mStartExtendedIndex+1, mEndExtendedIndex-1, PR_FALSE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex > mEndExtendedIndex) { - ExtendedSelection(mEndExtendedIndex, mSelectedIndex-1, PR_FALSE, PR_FALSE); - mEndExtendedIndex = mSelectedIndex; - } - } - } - } else if (((nsMouseEvent *)aEvent)->isControl) { - selected = !selected; - if (nsnull != mSelectedContent) { - if (mHitContent != mSelectedContent) { - // Toggle the selection - UpdateItem(mHitContent, !wasSelected); - } else { - //XXX: Fix this mSelectedContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (selected?kSelectedFocus:kNormal), PR_TRUE); - } - } - } else { - mStartExtendedIndex = mSelectedIndex; - mEndExtendedIndex = -1; - ClearSelection(); - selected = PR_TRUE; - } - } else { - if (nsnull != mSelectedContent) { - DisplayDeselected(mSelectedContent); - NS_RELEASE(mSelectedContent); - } - } - //XXX: Remove SetFrameSelected(mSelectedIndex, selected); - //XXX mHitContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (selected?kSelectedFocus:kNormal), PR_TRUE); - mSelectedContent = mHitContent; - mSelectedFrame = mHitFrame; - aEventStatus = nsEventStatus_eConsumeNoDefault; + if (mMultipleSelections) { + MultipleSelection(((nsMouseEvent *)aEvent)->isShift, ((nsMouseEvent *)aEvent)->isControl); + } else { + SingleSelection(); } - } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) { - aEventStatus = nsEventStatus_eConsumeNoDefault; } + + aEventStatus = nsEventStatus_eConsumeNoDefault; return NS_OK; } @@ -697,7 +857,7 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aP // When the DropDown occurs, if an item is selected it displayed as being selected. // It may or may not be currently visible, when the mouse is moved across any item // in the the list it is displayed as the currently selected item. - // (Selection doesn't actually occur until the mouse is released, or lciked and released) + // (Selection doesn't actually occur until the mouse is released, or clicked and released) if (aEvent->message == NS_MOUSE_MOVE) { // If the DropDown is currently has a selected item @@ -735,7 +895,7 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aP // Start by finding the newly "hit" content from the hit frame PRInt32 index = SetContentSelected(mHitFrame, mHitContent, PR_TRUE); - if (-1 < index) { + if (kNothingSelected != index) { nsIDOMHTMLOptionElement* option = nsnull; nsresult rv = mHitContent->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); @@ -868,6 +1028,8 @@ nsListControlFrame::Init(nsIPresContext& aPresContext, return result; } +// XXX: This following methods are not referenced. They should be removed if they +// are not needed //---------------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::GetMaxLength(PRInt32* aSize) @@ -906,19 +1068,7 @@ nsListControlFrame::GetSizeFromContent(PRInt32* aSize) const return result; } -//---------------------------------------------------------------------- -nscoord -nsListControlFrame::GetVerticalBorderWidth(float aPixToTwip) const -{ - return NSIntPixelsToTwips(3, aPixToTwip); -} - -//---------------------------------------------------------------------- -nscoord -nsListControlFrame::GetHorizontalBorderWidth(float aPixToTwip) const -{ - return GetVerticalBorderWidth(aPixToTwip); -} +//XXX: End of the un-referenced methods. //---------------------------------------------------------------------- nscoord @@ -939,101 +1089,6 @@ nsListControlFrame::GetHorizontalInsidePadding(nsIPresContext& aPresContext, } -//---------------------------------------------------------------------- - -void -nsListControlFrame::GetDesiredSize(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aDesiredLayoutSize, - nsSize& aDesiredWidgetSize) -{ - nsIDOMHTMLSelectElement* select = GetSelect(mContent); - if (!select) { - return; - } - nsIDOMHTMLCollection* options = GetOptions(mContent, select); - if (!options) { - NS_RELEASE(select); - return; - } - - // get the css size - nsSize styleSize; - nsFormControlFrame::GetStyleSize(*aPresContext, aReflowState, styleSize); - - // get the size of the longest option - PRInt32 maxWidth = 1; - PRUint32 numOptions; - options->GetLength(&numOptions); - - - for (PRUint32 i = 0; i < numOptions; i++) { - nsIDOMHTMLOptionElement* option = GetOption(*options, i); - if (option) { - nsAutoString text; - if (NS_CONTENT_ATTR_HAS_VALUE != option->GetText(text)) { - continue; - } - nsSize textSize; - // use the style for the select rather that the option, since widgets don't support it - nsFormControlHelper::GetTextSize(*aPresContext, this, text, textSize, aReflowState.rendContext); - if (textSize.width > maxWidth) { - maxWidth = textSize.width; - } - NS_RELEASE(option); - } - } - - PRInt32 rowHeight = 0; - nsSize desiredSize; - nsSize minSize; - PRBool widthExplicit, heightExplicit; - nsInputDimensionSpec textSpec(nsnull, PR_FALSE, nsnull, nsnull, - maxWidth, PR_TRUE, nsHTMLAtoms::size, 1); - // XXX fix CalculateSize to return PRUint32 - mNumRows = (PRUint32)nsFormControlHelper::CalculateSize (aPresContext, aReflowState.rendContext, this, styleSize, - textSpec, desiredSize, minSize, widthExplicit, - heightExplicit, rowHeight); - - float sp2t; - float p2t; - aPresContext->GetPixelsToTwips(&p2t); - aPresContext->GetScaledPixelsToTwips(&sp2t); - - if (mInDropDownMode) { - nscoord extra = desiredSize.height - (rowHeight * mNumRows); - - mNumRows = (numOptions > 20 ? 20 : numOptions); - desiredSize.height = (mNumRows * rowHeight) + extra; - } - - aDesiredLayoutSize.width = desiredSize.width; - - // XXX put this in widget library, combo boxes are fixed height (visible part) - //aDesiredLayoutSize.height = (mIsComboBox) - // ? rowHeight + (2 * GetVerticalInsidePadding(p2t, rowHeight)) - // : calcSize.height; - aDesiredLayoutSize.height = desiredSize.height; - aDesiredLayoutSize.ascent = aDesiredLayoutSize.height; - aDesiredLayoutSize.descent = 0; - - // XXX When this code is working, max element size needs to be set properly from CalculateSize - // above. look at some of the other form control to see how to do it. - - aDesiredWidgetSize.width = maxWidth; - aDesiredWidgetSize.height = rowHeight; - - if (aDesiredLayoutSize.maxElementSize) { - aDesiredLayoutSize.maxElementSize->width = minSize.width; - aDesiredLayoutSize.maxElementSize->height = minSize.height; - } - - NS_RELEASE(select); - NS_RELEASE(options); - -} - - //---------------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::GetMultiple(PRBool* aMultiple, nsIDOMHTMLSelectElement* aSelect) @@ -1076,7 +1131,6 @@ nsListControlFrame::AboutToDropDown() kid->GetContent(&content); if (i == mSelectedIndex) { mSelectedContent = content; - mSelectedFrame = kid; DisplaySelected(mSelectedContent); return NS_OK; } @@ -1158,6 +1212,10 @@ nsListControlFrame::InitializeFromContent(PRBool aDoDisplay) PRBool selected; option->GetDefaultSelected(&selected); SetFrameSelected(i, selected); + // Set the selected index for single selection list boxes. + if (selected) { + mSelectedIndex = i; + } if (mInDropDownMode) { if (selected) { @@ -1168,7 +1226,6 @@ nsListControlFrame::InitializeFromContent(PRBool aDoDisplay) mSelectedIndex = i; NS_RELEASE(option); mSelectedContent = content; - mSelectedFrame = kid; return; } } else { @@ -1434,8 +1491,8 @@ nsListControlFrame::SetFocus(PRBool aOn, PRBool aRepaint) // in this call? if (mSelectedContent) { //XXX: Need correct attribute here - mSelectedContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (aOn?kSelectedFocus:kNormal), PR_TRUE); - } +// mSelectedContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (aOn?kSelectedFocus:kNormal), PR_TRUE); + } } @@ -1479,8 +1536,92 @@ PRInt32 nsListControlFrame::GetNumberOfOptions() return(numOptions); } +// Set the selected attribute for an item in the listbox. If the listbox has +// been initialized the result of the setting the attribute is displayed otherwise +// it is not. -NS_IMETHODIMP nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue) +void +nsListControlFrame::SetContentSelectedAttribute(PRUint32 aIndex, PRBool aSelected) +{ + // Only display the result of the attribute changed if the listbox has been + // initialized. + if (mIsInitializedFromContent) { + // Update the attribute and display it + SetFrameSelected(aIndex, aSelected); + } else { + // Update the attribute without displaying it + nsIContent* content = GetOptionContent(aIndex); + NS_ASSERTION(nsnull != content, "Failed to retrieve option content"); + nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); + if (aSelected) { + content->SetAttribute(kNameSpaceID_None, selectedAtom, "", PR_FALSE); + } else { + content->UnsetAttribute(kNameSpaceID_None, selectedAtom, PR_FALSE); + } + NS_IF_RELEASE(content); + } +} + +// Set a single item in the listbox to selected. + +void +nsListControlFrame::SetSelectedIndex(PRInt32 aIndex, nsIContent *aContent) +{ + SetContentSelectedAttribute(aIndex, PR_TRUE); + mSelectedContent = aContent; + mSelectedIndex = aIndex; + + // Get the selected string from the content + nsIDOMHTMLOptionElement* option = nsnull; + nsresult rv = aContent->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); + if (NS_SUCCEEDED(rv)) { + nsAutoString text; + if (NS_CONTENT_ATTR_HAS_VALUE == option->GetText(text)) { + mSelectionStr = text; + } + NS_RELEASE(option); + } +} + + +// Select the specified item in the listbox using control logic. +// If it a single selection listbox the previous selection will be +// de-selected. + +void +nsListControlFrame::ToggleSelected(PRInt32 aIndex, nsIContent *aContent) +{ + PRBool multiple; + GetMultiple(&multiple); + + if (PR_TRUE == multiple) { + SetSelectedIndex(aIndex, aContent); + } else { + if (mSelectedIndex != kNothingSelected) { + SetContentSelectedAttribute(aIndex, PR_FALSE); + } + SetSelectedIndex(aIndex, aContent); + } +} + +// Select the specified item in the listbox using + +void +nsListControlFrame::SelectIndex(PRInt32 aIndex) +{ + nsIDOMHTMLCollection* options = GetOptions(mContent); + nsIDOMHTMLOptionElement* optionElement = GetOption(*options, aIndex); + nsIContent *content = nsnull; + nsresult result = optionElement->QueryInterface(kIContentIID, (void**) &content); + ToggleSelected(aIndex, content); + NS_RELEASE(content); + NS_RELEASE(optionElement); + NS_RELEASE(options); +} + + +NS_IMETHODIMP +nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue) { if (nsHTMLAtoms::selected == aName) { return NS_ERROR_INVALID_ARG; // Selected is readonly according to spec. @@ -1490,7 +1631,8 @@ NS_IMETHODIMP nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aV if (error) { return NS_ERROR_INVALID_ARG; // Couldn't convert to integer } else { - SetFrameSelected(selectedIndex, PR_TRUE); + // Select the specified item in the list box. + SelectIndex(selectedIndex); } } else { //XXX: TODO What about all othe other properties that form elements can set here? @@ -1499,7 +1641,8 @@ NS_IMETHODIMP nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aV return NS_OK; } -NS_IMETHODIMP nsListControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) +NS_IMETHODIMP +nsListControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) { // Get the selected value of option from local cache (optimization vs. widget) if (nsHTMLAtoms::selected == aName) { @@ -1516,7 +1659,7 @@ NS_IMETHODIMP nsListControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) // Spin through loooking for the first selection in the list PRInt32 index = 0; PRInt32 maxOptions = GetNumberOfOptions(); - PRInt32 selectedIndex = -1; + PRInt32 selectedIndex = kNothingSelected; for (index = 0; index < maxOptions; index++) { PRBool isSelected = PR_FALSE; diff --git a/mozilla/layout/forms/nsListControlFrame.h b/mozilla/layout/forms/nsListControlFrame.h index c9c90552897..4af053bc51e 100644 --- a/mozilla/layout/forms/nsListControlFrame.h +++ b/mozilla/layout/forms/nsListControlFrame.h @@ -32,6 +32,7 @@ class nsIDOMHTMLOptionElement; class nsFormFrame; class nsScrollFrame; class nsIComboboxControlFrame; +class nsVoidArray; /** @@ -83,26 +84,17 @@ public: NS_IMETHOD SetProperty(nsIAtom* aName, const nsString& aValue); NS_IMETHOD GetProperty(nsIAtom* aName, nsString& aValue); - virtual void GetDesiredSize(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aDesiredLayoutSize, - nsSize& aDesiredWidgetSize); - /*virtual nsresult Focus(nsIDOMEvent* aEvent); - virtual nsresult Blur(nsIDOMEvent* aEvent); - virtual nsresult HandleEvent(nsIDOMEvent* aEvent); - NS_IMETHOD AddEventListener(nsIDOMNode * aNode); - NS_IMETHOD RemoveEventListener(nsIDOMNode * aNode); - - NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);*/ - + virtual nsresult Blur(nsIDOMEvent* aEvent); */ + NS_METHOD GetMultiple(PRBool* aResult, nsIDOMHTMLSelectElement* aSelect = nsnull); +// XXX the following methods are not referenced. They should be removed when it is +// confirmed that they are not needed virtual nsresult GetSizeFromContent(PRInt32* aSize) const; NS_IMETHOD GetMaxLength(PRInt32* aSize); +// XXX: End of the unreferenced methods - virtual nscoord GetVerticalBorderWidth(float aPixToTwip) const; - virtual nscoord GetHorizontalBorderWidth(float aPixToTwip) const; virtual nscoord GetVerticalInsidePadding(float aPixToTwip, nscoord aInnerHeight) const; virtual nscoord GetHorizontalInsidePadding(nsIPresContext& aPresContext, @@ -110,17 +102,18 @@ public: nscoord aInnerWidth, nscoord aCharWidth) const; + virtual nsresult RequiresWidget(PRBool &aRequiresWidget); + NS_IMETHOD GetFont(nsIPresContext* aPresContext, nsFont& aFont); + + NS_IMETHOD GetFormContent(nsIContent*& aContent) const; - // nsIFrame - NS_IMETHOD SetRect(const nsRect& aRect); - NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); ///////////////////////// // nsHTMLContainerFrame @@ -183,6 +176,17 @@ protected: void DisplaySelected(nsIContent* aContent); void DisplayDeselected(nsIContent* aContent); void UpdateItem(nsIContent* aContent, PRBool aSelected); + void ForceRedraw(nsIContent* aContent); + PRBool IsOptionGroup(nsIFrame* aFrame); + void ConstructSelectableList(nsIFrame* aFrame, nsVoidArray *aList); + nsIFrame* GetFirstSelectableFrame(nsVoidArray *aList, PRInt32& aPos); + nsIFrame* GetNextSelectableFrame(nsVoidArray *aList, PRInt32& aPos); + void SingleSelection(); + void MultipleSelection(PRBool aIsShift, PRBool aIsControl); + void SelectIndex(PRInt32 aIndex); + void ToggleSelected(PRInt32 aIndex, nsIContent *aContent); + void SetSelectedIndex(PRInt32 aIndex, nsIContent *aContent); + void SetContentSelectedAttribute(PRUint32 aIndex, PRBool aSelected); // nsHTMLContainerFrame overrides @@ -202,10 +206,9 @@ protected: PRBool aDisplaySelected); // Data Members + nscoord mBorderOffsetY; nsFormFrame* mFormFrame; PRInt32 mNumRows; -//XXX: TODO: This should not be hardcoded to 64 -//ZZZ PRBool mIsFrameSelected[64]; PRInt32 mNumSelections; PRInt32 mMaxNumSelections; PRBool mMultipleSelections; @@ -216,13 +219,13 @@ protected: nsIContent * mHitContent; nsIFrame * mCurrentHitFrame; nsIContent * mCurrentHitContent; - nsIFrame * mSelectedFrame; nsIContent * mSelectedContent; PRBool mIsInitializedFromContent; nsIFrame * mContentFrame; PRBool mInDropDownMode; nsIComboboxControlFrame * mComboboxFrame; nsString mSelectionStr; + nsVoidArray* mSelectableFrames; }; diff --git a/mozilla/layout/html/document/src/ua.css b/mozilla/layout/html/document/src/ua.css index c2e7e2859f1..3b867eef998 100644 --- a/mozilla/layout/html/document/src/ua.css +++ b/mozilla/layout/html/document/src/ua.css @@ -686,6 +686,7 @@ select { border: 1px inset #c0c0c0; background-color: white; color:black; + white-space:nowrap; } option { display:block; @@ -707,6 +708,19 @@ option.selectedfocus { background-color: rgb(0,0,128); color: rgb(255,255,255); } + +optgroup { + font-style:italic; + font-weight:bold; +} + +optgroup > option { + position:relative; + left:20px; + font-style:normal; + font-weight:normal; +} + textarea { vertical-align: bottom; border: 2px inset #c0c0c0; @@ -915,8 +929,6 @@ sourcetext { :-moz-dropdown-list { position:absolute; - height:200px; - width:100px; background-color:white; border: 1px solid blue; } diff --git a/mozilla/layout/html/forms/src/nsButtonControlFrame.cpp b/mozilla/layout/html/forms/src/nsButtonControlFrame.cpp index 07f71c22730..160e1a18e0b 100644 --- a/mozilla/layout/html/forms/src/nsButtonControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsButtonControlFrame.cpp @@ -363,6 +363,11 @@ nsButtonControlFrame::Reflow(nsIPresContext& aPresContext, aPresContext.GetWidgetRenderingMode(&mode); if (eWidgetRendering_Gfx == mode || NS_FORM_INPUT_IMAGE == type) { + // add ourself as an nsIFormControlFrame + if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { + nsFormFrame::AddFormControlFrame(aPresContext, *this); + } + nsSize ignore; GetDesiredSize(&aPresContext, aReflowState, aDesiredSize, ignore); nsMargin bp(0,0,0,0); diff --git a/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp b/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp index 595d1c43ac5..1a8f5d8e416 100644 --- a/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp @@ -128,6 +128,28 @@ nsComboboxControlFrame::IsSuccessful(nsIFormControlFrame* aSubmitter) return (NS_CONTENT_ATTR_HAS_VALUE == GetName(&name)); } + +// Initialize the text string in the combobox using either the current +// selection in the list box or the first item item in the list box. + +void nsComboboxControlFrame::InitTextStr() +{ + // Update the selected text string + mListControlFrame->GetSelectedItem(mTextStr); + + if (mTextStr == "") { + // No selection so use the first item in the list box + nsIFormControlFrame* fcFrame = nsnull; + nsresult result = mListFrame->QueryInterface(kIFormControlFrameIID, (void**)&fcFrame); + if ((NS_OK == result) && (nsnull != fcFrame)) { + // Set listbox selection to first item in the list box + fcFrame->SetProperty(nsHTMLAtoms::selectedindex, "0"); + // Get the listbox selection as a string + mListControlFrame->GetSelectedItem(mTextStr); + } + } +} + //-------------------------------------------------------------- void @@ -139,6 +161,8 @@ nsComboboxControlFrame::Reset() if ((NS_OK == result) && (nsnull != fcFrame)) { fcFrame->Reset(); } + + InitTextStr(); } void @@ -279,13 +303,19 @@ NS_IMETHODIMP nsComboboxControlFrame::Reflow(nsIPresContext& aPresConte // XXX Combo box should be changed to be implemented as a label and button frame. // This would eliminate all of this Reflow code. KMM + // add ourself as an nsIFormControlFrame + if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { + nsFormFrame::AddFormControlFrame(aPresContext, *this); + } + if (mFirstTime) { ReResolveStyleContext(&aPresContext, mStyleContext, NS_STYLE_HINT_REFLOW, nsnull, nsnull); // XXX This temporary mListFrame->ReResolveStyleContext(&aPresContext, mCurrentStyleContext, NS_STYLE_HINT_REFLOW, nsnull, nsnull); - nsFormFrame::AddFormControlFrame(aPresContext, *this); mFirstTime = PR_FALSE; + InitTextStr(); } + PRInt32 numChildren = mFrames.GetLength(); if (1 == numChildren) { diff --git a/mozilla/layout/html/forms/src/nsComboboxControlFrame.h b/mozilla/layout/html/forms/src/nsComboboxControlFrame.h index f7f7b1e53cc..ff243d029dc 100644 --- a/mozilla/layout/html/forms/src/nsComboboxControlFrame.h +++ b/mozilla/layout/html/forms/src/nsComboboxControlFrame.h @@ -138,6 +138,7 @@ protected: const nsRect& aDirtyRect, nsFramePaintLayer aWhichLayer); virtual PRIntn GetSkipSides() const; + void InitTextStr(); nsFormFrame* mFormFrame; // Parent Form Frame nsIFrame * mPlaceHolderFrame; diff --git a/mozilla/layout/html/forms/src/nsFileControlFrame.cpp b/mozilla/layout/html/forms/src/nsFileControlFrame.cpp index 5cab8483af1..11b1e50a95d 100644 --- a/mozilla/layout/html/forms/src/nsFileControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsFileControlFrame.cpp @@ -187,6 +187,11 @@ NS_IMETHODIMP nsFileControlFrame::Reflow(nsIPresContext& aPresContext, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus) { + // add ourself as an nsIFormControlFrame + if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { + nsFormFrame::AddFormControlFrame(aPresContext, *this); + } + PRInt32 numChildren = mFrames.GetLength(); nsIFrame* childFrame; diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.cpp b/mozilla/layout/html/forms/src/nsListControlFrame.cpp index 6c6c22fd0e9..63f6157857f 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsListControlFrame.cpp @@ -61,11 +61,18 @@ #include "nsIViewManager.h" #include "nsFormFrame.h" #include "nsIScrollableView.h" +#include "nsVoidArray.h" +#include "nsIDOMHTMLOptGroupElement.h" + + // Constants const char * kNormal = ""; const char * kSelected = "SELECTED"; const char * kSelectedFocus = "SELECTEDFOCUS"; +const nscoord kMaxDropDownRows = 3; +const PRInt32 kNothingSelected = -1; + //XXX: This is temporary. It simulates psuedo states by using a attribute selector on // -moz-option-selected in the ua.css style sheet. This will not be needed when //The event state manager is functional. KMM @@ -79,6 +86,8 @@ static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID); static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID); static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); static NS_DEFINE_IID(kIDOMElementIID, NS_IDOMELEMENT_IID); +static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); +static NS_DEFINE_IID(kIDOMHTMLOptGroupElementIID, NS_IDOMHTMLOPTGROUPELEMENT_IID); //---------------------------------------------------------------------- @@ -98,22 +107,24 @@ nsListControlFrame::nsListControlFrame() { mHitFrame = nsnull; mCurrentHitFrame = nsnull; - mSelectedFrame = nsnull; mSelectedContent = nsnull; - mSelectedIndex = -1; + mSelectedIndex = kNothingSelected; mNumRows = 0; mIsInitializedFromContent = PR_FALSE; mNumSelections = 0; mInDropDownMode = PR_FALSE; mComboboxFrame = nsnull; mFormFrame = nsnull; + mSelectableFrames = new nsVoidArray; } //---------------------------------------------------------------------- nsListControlFrame::~nsListControlFrame() { - NS_IF_RELEASE(mComboboxFrame); + mComboboxFrame = nsnull; mFormFrame = nsnull; + delete mSelectableFrames; + mSelectableFrames = nsnull; } //---------------------------------------------------------------------- @@ -140,6 +151,48 @@ nsListControlFrame::QueryInterface(const nsIID& aIID, void** aInstancePtr) return nsScrollFrame::QueryInterface(aIID, aInstancePtr); } +PRBool nsListControlFrame::IsOptionGroup(nsIFrame* aFrame) +{ + PRBool result = PR_FALSE; + nsIContent*content = nsnull; + aFrame->GetContent(&content); + nsIDOMHTMLOptGroupElement* og = nsnull; + if (content && (NS_OK == content->QueryInterface(kIDOMHTMLOptGroupElementIID, (void**) &og))) { + if (og != nsnull) { + result = PR_TRUE; + NS_RELEASE(og); + } + NS_RELEASE(content); + } + + return result; +} + +void nsListControlFrame::ConstructSelectableList(nsIFrame* aFrame, nsVoidArray* aList) +{ + nsIFrame* kid = nsnull; + aFrame->FirstChild(nsnull, &kid); + while (nsnull != kid) { + if (IsOptionGroup(kid)) { + ConstructSelectableList(kid, aList); + } else { + aList->AppendElement(kid); + kid->GetNextSibling(&kid); + } + } +} + +nsIFrame* nsListControlFrame::GetFirstSelectableFrame(nsVoidArray *aList, PRInt32& aPos) +{ + aPos = 1; + return((nsIFrame*)aList->ElementAt(0)); +} + +nsIFrame* nsListControlFrame::GetNextSelectableFrame(nsVoidArray *aList, PRInt32& aPos) +{ + return((nsIFrame*)aList->ElementAt(aPos++)); +} + //---------------------------------------------------------------------- NS_IMETHODIMP @@ -177,7 +230,6 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, nsRect kidRect; nsPoint tmp; nsRect offset(0, 0, 0, 0); - nsPoint absPoint = aPoint; *aFrame = nsnull; nsIFrame* firstKid = nsnull; @@ -204,7 +256,8 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, // As a hack we adjust for missing view offset by adding code to the nsListControlFrame::GetFrameForPoint which first // gets the ScrollableView associated with the nsListControlFrame and asks for it's GetScrollPosition offsets. These are // added to the point that is passed in so the correct frame is returned from nsListControlFrame::GetFrameForPoint. - + + tmp.MoveTo(aPoint.x, aPoint.y); nsIView *view = nsnull; GetView(&view); if (nsnull != view) { @@ -213,17 +266,57 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, nsIScrollableView* scrollableView; if (NS_SUCCEEDED(view->QueryInterface(kIScrollableViewIID, (void **)&scrollableView))) { scrollableView->GetScrollPosition(offsetx, offsety); - absPoint.x += offsetx; - absPoint.y += offsety; + tmp.x += offsetx; + tmp.y += offsety; // Note: scrollableView is not ref counted so it's interface is not NS_RELEASE'd } } - + +#ifdef NS_OPTGROUPSUPPORT + nsIFrame* selectedFrame = nsnull; + nsresult rv = nsScrollFrame::GetFrameForPoint(tmp, &selectedFrame); + + + // Walk up the frames looking for a selectable frame. + // A selectable frame is defined as a frame sitting under the ScrollArea's + // Area Frame or the first optiongroup ancestor. + + if (nsnull != selectedFrame) { + PRBool done = PR_FALSE; + while (! done) { + nsIFrame* parent = nsnull; + selectedFrame->GetParent(&parent); + if (parent != nsnull) { + if ((parent == mContentFrame) || (IsOptionGroup(parent))) { + done = PR_TRUE; + } else { + // Continue looking at ancestors + selectedFrame = parent; + } + } else { + // Parent is null so stop looking + done = PR_TRUE; + } + } + } + + *aFrame = selectedFrame; + + return rv; + +#else + +//XXX: Remove the following code when the code above works + + // Remove the top border from the offset. + nsMargin border; + tmp.y -= mBorderOffsetY; + mContentFrame->FirstChild(aList, &kid); while (nsnull != kid) { kid->GetRect(kidRect); - if (kidRect.Contains(absPoint)) { - tmp.MoveTo(absPoint.x - kidRect.x, absPoint.y - kidRect.y); + if (kidRect.Contains(tmp)) { + tmp.MoveTo(tmp.x - kidRect.x, tmp.y - kidRect.y); nsIContent * content; kid->GetContent(&content); @@ -246,7 +339,7 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, kid->GetFrameState(&state); if (NS_FRAME_OUTSIDE_CHILDREN & state) { kid->GetRect(kidRect); - tmp.MoveTo(absPoint.x - kidRect.x, absPoint.y - kidRect.y); + tmp.MoveTo(tmp.x - kidRect.x, tmp.y - kidRect.y); if (NS_OK == kid->GetFrameForPoint(tmp, aFrame)) { return NS_OK; } @@ -255,6 +348,7 @@ nsListControlFrame::GetFrameForPointUsing(const nsPoint& aPoint, } *aFrame = this; return NS_ERROR_FAILURE; +#endif } @@ -290,40 +384,38 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, InitializeFromContent(PR_TRUE); } - nsIFrame* childFrame = nsnull; - mContentFrame->FirstChild(nsnull, &childFrame); - PRInt32 numChildren = LengthOf(childFrame); - - PRBool needsVerticalScrollbar = PR_FALSE; - if (PR_FALSE == mInDropDownMode) { - PRBool needsVerticalScrollbar = (numChildren > mNumRows); - } //--Calculate a width just big enough for the scrollframe to shrink around the //longest element in the list - //XXX: This is usually dangerous to do this type of coercion. Should it set the - //State back to the original when done??? - nsHTMLReflowState& tempReflowState = (nsHTMLReflowState&)aReflowState; - - // Get the size of option elements inside the listbox - nsSize desiredLineSize; - nsHTMLReflowMetrics desiredSize = aDesiredSize; - // Save original values which will be modified for the reflow state. - // They are set back to their original values at the end of reflow. - nscoord saveComputedWidth = tempReflowState.computedWidth; - nscoord saveAvailableWidth = tempReflowState.availableWidth; - + nsHTMLReflowState secondPassState(aReflowState); + nsHTMLReflowState firstPassState(aReflowState); + + // Get the size of option elements inside the listbox // Compute the width based on the longest line in the listbox. - // XXX: This should be changed to do the inherited reflow unconstrained for - // the width to get the real desired width. GetDesiredSize is limited to - // text strings. - //XXX: TODO: Use the width and height of an the first reflow to determine how high and wide - //to make the listbox, instead of calculating it. The second reflow can be done actually position - //the frames correctly using: tempReflowState.reason = eReflowReason_Resize; - GetDesiredSize(&aPresContext, aReflowState, desiredSize, desiredLineSize); + firstPassState.computedWidth = NS_UNCONSTRAINEDSIZE; + firstPassState.computedHeight = NS_UNCONSTRAINEDSIZE; + firstPassState.availableWidth = NS_UNCONSTRAINEDSIZE; + firstPassState.availableHeight = NS_UNCONSTRAINEDSIZE; - // Retrieve the scrollbar's width and height + + nsSize scrolledAreaSize(0,0); + nsHTMLReflowMetrics scrolledAreaDesiredSize(&scrolledAreaSize); + nsScrollFrame::Reflow(aPresContext, + scrolledAreaDesiredSize, + firstPassState, + aStatus); + + // Compute the bounding box of the contents of the list using the area + // calculated by the first reflow as a starting point. + + nscoord scrolledAreaWidth = scrolledAreaDesiredSize.maxElementSize->width; + nscoord scrolledAreaHeight = scrolledAreaDesiredSize.height; + + // The first reflow produces a box with the scrollbar width and borders + // added in so we need to subtract them out. + + // Retrieve the scrollbar's width and height float sbWidth = 0.0; float sbHeight = 0.0;; nsCOMPtr dc; @@ -333,88 +425,116 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, nscoord scrollbarWidth = NSToCoordRound(sbWidth); nscoord scrollbarHeight = NSToCoordRound(sbHeight); - if (mInDropDownMode) { - // For drop-down lists, always size the width of the list based on - // the desired lineSize. - tempReflowState.computedWidth = desiredLineSize.width + scrollbarWidth; - } else if (NS_UNCONSTRAINEDSIZE == tempReflowState.computedWidth) { - // Only set to the desired width if it hasn't been explicitly defined through CSS. - // GetDesiredSize must still be done above to calculate the desired height. - tempReflowState.computedWidth = desiredLineSize.width; + // Subtract out the scrollbar width + scrolledAreaWidth -= scrollbarWidth; + + // Subtract out the borders + nsMargin border; + if (!aReflowState.mStyleSpacing->GetBorder(border)) { + border.SizeTo(0, 0, 0, 0); } + //XXX: Should just get the border.top when needed instead of + //caching it. + mBorderOffsetY = border.top; - // Add vertical scrollbar, Always add it in, - // even though the vertical scrollbar is not needed all the time - // the inherited Reflow: allways leave space for the scrollbar by - // shrinking the scroll area by the scrollbar width + scrolledAreaWidth -= (border.left + border.right); + scrolledAreaHeight -= (border.top + border.bottom); - tempReflowState.computedWidth += scrollbarWidth; - - // Now that we have calculated the width required to just shrink around the longest line. - // Go ahead and reflow - // Do the inherited Reflow. This reflow uses the computed widths which - // are setup above. - // Don't set the height. Let the height be unconstrained + // Now the scrolledAreaWidth and scrolledAreaHeight are exactly + // wide and high enough to enclose their contents + nscoord visibleWidth = 0; if (mInDropDownMode) { - // The dropdown list height is the smaller of it's height setting or the height - // of the smallest box that can drawn around it's contents. - if (tempReflowState.computedHeight > (desiredSize.height)) { - tempReflowState.computedHeight = desiredSize.height ; + // Always set the width to be + // XXX: TODO The width of the list should be passed in so it can + // be set to the same as the text box + dropdown arrow. + visibleWidth = scrolledAreaWidth; + if (nsnull != mComboboxFrame) { + nsRect comboRect; + nsIFrame *comboFrame = nsnull; + if (NS_SUCCEEDED(mComboboxFrame->QueryInterface(kIFrameIID, (void **)&comboFrame))) { + comboFrame->GetRect(comboRect); + visibleWidth = comboRect.width; + visibleWidth -= (border.left + border.right); + } + } + + } else { + if (NS_UNCONSTRAINEDSIZE == aReflowState.computedWidth) { + visibleWidth = scrolledAreaWidth; + } else { + visibleWidth = aReflowState.computedWidth; } } - + + // Determine if a scrollbar will be needed, If so we need to add + // enough the width to allow for the scrollbar. + // The scrollbar will be needed under two conditions: + // (size * heightOfaRow) < scrolledAreaHeight or + // the height set through Style < scrolledAreaHeight. + + // Calculate the height of a row. + // XXX: Fix this for optgroup's. + nsIFrame* childFrame = nsnull; + mContentFrame->FirstChild(nsnull, &childFrame); + PRInt32 numChildren = LengthOf(childFrame); + PRInt32 heightOfARow = scrolledAreaHeight / numChildren; + + nscoord visibleHeight = 0; + if (mInDropDownMode) { + // Compute the visible height of the drop-down list + // The dropdown list height is the smaller of it's height setting or the height + // of the smallest box that can drawn around it's contents. + visibleHeight = scrolledAreaHeight; + + if (visibleHeight > (kMaxDropDownRows * heightOfARow)) + visibleHeight = (kMaxDropDownRows * heightOfARow); + + } else { + // Calculate the visible height of the listbox + if (NS_UNCONSTRAINEDSIZE != aReflowState.computedHeight) { + visibleHeight = aReflowState.computedHeight; + } else { + if (numChildren == mNumRows) { + // Make sure scrollbars go away when the number of rows + // matchs the number of items to scroll. + visibleHeight = aReflowState.computedHeight; + } else { + visibleHeight = mNumRows * heightOfARow; + } + } + } + + PRBool needsVerticalScrollbar = PR_FALSE; + if (visibleHeight < scrolledAreaHeight) { + needsVerticalScrollbar = PR_TRUE; + } + + if ((needsVerticalScrollbar) && (! mInDropDownMode)) { + visibleWidth += scrollbarWidth; + } + + // Do a second reflow with the adjusted width and height settings + // This sets up all of the frames with the correct width and height. + secondPassState.computedWidth = visibleWidth; + secondPassState.computedHeight = visibleHeight; + secondPassState.reason = eReflowReason_Resize; nsScrollFrame::Reflow(aPresContext, aDesiredSize, - tempReflowState, + secondPassState, aStatus); - // Now that we have reflowed, we may need to adjust the width and height returned - // for the listbox. - - if (PR_FALSE == mInDropDownMode) { - // Set the desired height to the computed height above only if it has not - // been explicitly set by CSS. - if (NS_UNCONSTRAINEDSIZE == tempReflowState.computedHeight) { - aDesiredSize.height = desiredSize.height; - } - } - - //Need to addback the scrollbar because the inherited reflow - //subtracts the scrollbar width when computing the desired size. - //We don't subtract when there isn't a vertical scrollbar. This may - //seem odd, becuase above we always add in the scrollbar width before calling - //reflow. The reason is that inherited reflow always leaves blank space for - //the scrollbar, but we don't whant that behavior for the listbox'es scrollbars. - if (needsVerticalScrollbar) { - aDesiredSize.width += scrollbarWidth; - } // Set the max element size to be the same as the desired element size. if (nsnull != aDesiredSize.maxElementSize) { aDesiredSize.maxElementSize->width = aDesiredSize.width; aDesiredSize.maxElementSize->height = aDesiredSize.height; } - // XXX: Set the min element size here to the desired element size here?? - // Restore to original reflow state. - tempReflowState.computedWidth = saveComputedWidth; - tempReflowState.availableWidth = saveAvailableWidth; - aStatus = NS_FRAME_COMPLETE; return NS_OK; } -NS_IMETHODIMP nsListControlFrame::SetRect(const nsRect& aRect) -{ - nsScrollFrame::SetRect(aRect); - return NS_OK; -} -NS_IMETHODIMP nsListControlFrame::SizeTo(nscoord aWidth, nscoord aHeight) -{ - nsScrollFrame::SizeTo(aWidth, aHeight); - return NS_OK; -} //---------------------------------------------------------------------- nsIFrame * @@ -444,6 +564,7 @@ nsListControlFrame::GetOptionFromChild(nsIFrame* aParentFrame) return nsnull; } + //-------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::GetFormContent(nsIContent*& aContent) const @@ -466,6 +587,17 @@ nsListControlFrame::GetFont(nsIPresContext* aPresContext, } +void nsListControlFrame::ForceRedraw(nsIContent* aContent) +{ + //XXX: Hack. This should not be needed. The problem is DisplaySelected + //and DisplayDeselected set and unset an attribute on generic HTML content + //which does not know that it should repaint as the result of the attribute + //being set. This should not be needed once the event state manager handles + //selection. + nsFormControlHelper::ForceDrawFrame(this); +} + + // XXX: Here we introduce a new -moz-option-selected attribute so a attribute // selecitor n the ua.css can change the style when the option is selected. @@ -474,8 +606,11 @@ void nsListControlFrame::DisplaySelected(nsIContent* aContent) //XXX: This is temporary. It simulates psuedo states by using a attribute selector on // -moz-option-selected in the ua.css style sheet. This will not be needed when // The event state manager is functional. KMM + nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); aContent->SetAttribute(kNameSpaceID_None, selectedAtom, "", PR_TRUE); + ForceRedraw(aContent); + } void nsListControlFrame::DisplayDeselected(nsIContent* aContent) @@ -483,8 +618,11 @@ void nsListControlFrame::DisplayDeselected(nsIContent* aContent) //XXX: This is temporary. It simulates psuedo states by using a attribute selector on // -moz-option-selected in the ua.css style sheet. This will not be needed when // The event state manager is functional. KMM + nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); aContent->UnsetAttribute(kNameSpaceID_None, selectedAtom, PR_TRUE); + ForceRedraw(aContent); + } void nsListControlFrame::UpdateItem(nsIContent* aContent, PRBool aSelected) @@ -517,7 +655,7 @@ PRInt32 nsListControlFrame::SetContentSelected(nsIFrame * aHitFrame, kid->GetNextSibling(&kid); index++; } - return -1; + return kNothingSelected; } //---------------------------------------------------------------------- @@ -584,82 +722,104 @@ void nsListControlFrame::ExtendedSelection(PRInt32 aStartIndex, PRInt32 aEndInde } } +void nsListControlFrame::SingleSelection() +{ + // Store previous selection + PRInt32 oldSelectedIndex = mSelectedIndex; + // Get Current selection + mSelectedIndex = (PRInt32)SetContentSelected(mHitFrame, mHitContent, PR_FALSE); + if (mSelectedIndex != kNothingSelected) { + if (oldSelectedIndex != mSelectedIndex) { + // Deselect the previous selection if there is one + if (oldSelectedIndex != kNothingSelected) { + SetFrameSelected(oldSelectedIndex, PR_FALSE); + } + // Dipslay the new selection + SetFrameSelected(mSelectedIndex, PR_TRUE); + mSelectedContent = mHitContent; + } else { + // Selecting the currently selected item so do nothing. + } + } +} + +void nsListControlFrame::MultipleSelection(PRBool aIsShift, PRBool aIsControl) +{ + PRInt32 oldSelectedIndex = mSelectedIndex; + + mSelectedIndex = (PRInt32)SetContentSelected(mHitFrame, mHitContent, PR_FALSE); + if (kNothingSelected != mSelectedIndex) { + PRBool wasSelected = IsFrameSelected(mSelectedIndex); + SetFrameSelected(mSelectedIndex, PR_TRUE); + PRBool selected = wasSelected; + + if (aIsShift) { + selected = PR_TRUE; + if (mEndExtendedIndex == kNothingSelected) { + mEndExtendedIndex = mSelectedIndex; + ExtendedSelection(mStartExtendedIndex, mEndExtendedIndex, PR_FALSE, PR_TRUE); + } else { + if (mStartExtendedIndex < mEndExtendedIndex) { + if (mSelectedIndex < mStartExtendedIndex) { + ExtendedSelection(mSelectedIndex, mEndExtendedIndex, PR_TRUE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex > mEndExtendedIndex) { + ExtendedSelection(mEndExtendedIndex+1, mSelectedIndex, PR_FALSE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex < mEndExtendedIndex) { + ExtendedSelection(mSelectedIndex+1, mEndExtendedIndex, PR_FALSE, PR_FALSE); + mEndExtendedIndex = mSelectedIndex; + } + } else if (mStartExtendedIndex > mEndExtendedIndex) { + if (mSelectedIndex > mStartExtendedIndex) { + ExtendedSelection(mEndExtendedIndex, mSelectedIndex, PR_TRUE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex < mEndExtendedIndex) { + ExtendedSelection(mStartExtendedIndex+1, mEndExtendedIndex-1, PR_FALSE, PR_TRUE); + mEndExtendedIndex = mSelectedIndex; + } else if (mSelectedIndex > mEndExtendedIndex) { + ExtendedSelection(mEndExtendedIndex, mSelectedIndex-1, PR_FALSE, PR_FALSE); + mEndExtendedIndex = mSelectedIndex; + } + } + } + } else if (aIsControl) { + selected = !selected; + if (nsnull != mSelectedContent) { + if (mHitContent != mSelectedContent) { + // Toggle the selection + UpdateItem(mHitContent, !wasSelected); + } else { +//XXX: Fix this mSelectedContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (selected?kSelectedFocus:kNormal), PR_TRUE); + } + } + } else { + mStartExtendedIndex = mSelectedIndex; + mEndExtendedIndex = kNothingSelected; + ClearSelection(); + selected = PR_TRUE; + } + + //XXX Fix this mHitContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (selected?kSelectedFocus:kNormal), PR_TRUE); + mSelectedContent = mHitContent; + } + +} + //---------------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::HandleLikeListEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsEventStatus& aEventStatus) { if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) { - PRInt32 oldSelectedIndex = mSelectedIndex; - - mSelectedIndex = (PRInt32)SetContentSelected(mHitFrame, mHitContent, PR_FALSE); - if (-1 < mSelectedIndex) { - PRBool wasSelected = IsFrameSelected(mSelectedIndex); - SetFrameSelected(mSelectedIndex, PR_TRUE); - PRBool selected = wasSelected; - if (mMultipleSelections) { - - if (((nsMouseEvent *)aEvent)->isShift) { - selected = PR_TRUE; - if (mEndExtendedIndex == -1) { - mEndExtendedIndex = mSelectedIndex; - ExtendedSelection(mStartExtendedIndex, mEndExtendedIndex, PR_FALSE, PR_TRUE); - } else { - if (mStartExtendedIndex < mEndExtendedIndex) { - if (mSelectedIndex < mStartExtendedIndex) { - ExtendedSelection(mSelectedIndex, mEndExtendedIndex, PR_TRUE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex > mEndExtendedIndex) { - ExtendedSelection(mEndExtendedIndex+1, mSelectedIndex, PR_FALSE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex < mEndExtendedIndex) { - ExtendedSelection(mSelectedIndex+1, mEndExtendedIndex, PR_FALSE, PR_FALSE); - mEndExtendedIndex = mSelectedIndex; - } - } else if (mStartExtendedIndex > mEndExtendedIndex) { - if (mSelectedIndex > mStartExtendedIndex) { - ExtendedSelection(mEndExtendedIndex, mSelectedIndex, PR_TRUE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex < mEndExtendedIndex) { - ExtendedSelection(mStartExtendedIndex+1, mEndExtendedIndex-1, PR_FALSE, PR_TRUE); - mEndExtendedIndex = mSelectedIndex; - } else if (mSelectedIndex > mEndExtendedIndex) { - ExtendedSelection(mEndExtendedIndex, mSelectedIndex-1, PR_FALSE, PR_FALSE); - mEndExtendedIndex = mSelectedIndex; - } - } - } - } else if (((nsMouseEvent *)aEvent)->isControl) { - selected = !selected; - if (nsnull != mSelectedContent) { - if (mHitContent != mSelectedContent) { - // Toggle the selection - UpdateItem(mHitContent, !wasSelected); - } else { - //XXX: Fix this mSelectedContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (selected?kSelectedFocus:kNormal), PR_TRUE); - } - } - } else { - mStartExtendedIndex = mSelectedIndex; - mEndExtendedIndex = -1; - ClearSelection(); - selected = PR_TRUE; - } - } else { - if (nsnull != mSelectedContent) { - DisplayDeselected(mSelectedContent); - NS_RELEASE(mSelectedContent); - } - } - //XXX: Remove SetFrameSelected(mSelectedIndex, selected); - //XXX mHitContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (selected?kSelectedFocus:kNormal), PR_TRUE); - mSelectedContent = mHitContent; - mSelectedFrame = mHitFrame; - aEventStatus = nsEventStatus_eConsumeNoDefault; + if (mMultipleSelections) { + MultipleSelection(((nsMouseEvent *)aEvent)->isShift, ((nsMouseEvent *)aEvent)->isControl); + } else { + SingleSelection(); } - } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) { - aEventStatus = nsEventStatus_eConsumeNoDefault; } + + aEventStatus = nsEventStatus_eConsumeNoDefault; return NS_OK; } @@ -697,7 +857,7 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aP // When the DropDown occurs, if an item is selected it displayed as being selected. // It may or may not be currently visible, when the mouse is moved across any item // in the the list it is displayed as the currently selected item. - // (Selection doesn't actually occur until the mouse is released, or lciked and released) + // (Selection doesn't actually occur until the mouse is released, or clicked and released) if (aEvent->message == NS_MOUSE_MOVE) { // If the DropDown is currently has a selected item @@ -735,7 +895,7 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aP // Start by finding the newly "hit" content from the hit frame PRInt32 index = SetContentSelected(mHitFrame, mHitContent, PR_TRUE); - if (-1 < index) { + if (kNothingSelected != index) { nsIDOMHTMLOptionElement* option = nsnull; nsresult rv = mHitContent->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); @@ -868,6 +1028,8 @@ nsListControlFrame::Init(nsIPresContext& aPresContext, return result; } +// XXX: This following methods are not referenced. They should be removed if they +// are not needed //---------------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::GetMaxLength(PRInt32* aSize) @@ -906,19 +1068,7 @@ nsListControlFrame::GetSizeFromContent(PRInt32* aSize) const return result; } -//---------------------------------------------------------------------- -nscoord -nsListControlFrame::GetVerticalBorderWidth(float aPixToTwip) const -{ - return NSIntPixelsToTwips(3, aPixToTwip); -} - -//---------------------------------------------------------------------- -nscoord -nsListControlFrame::GetHorizontalBorderWidth(float aPixToTwip) const -{ - return GetVerticalBorderWidth(aPixToTwip); -} +//XXX: End of the un-referenced methods. //---------------------------------------------------------------------- nscoord @@ -939,101 +1089,6 @@ nsListControlFrame::GetHorizontalInsidePadding(nsIPresContext& aPresContext, } -//---------------------------------------------------------------------- - -void -nsListControlFrame::GetDesiredSize(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aDesiredLayoutSize, - nsSize& aDesiredWidgetSize) -{ - nsIDOMHTMLSelectElement* select = GetSelect(mContent); - if (!select) { - return; - } - nsIDOMHTMLCollection* options = GetOptions(mContent, select); - if (!options) { - NS_RELEASE(select); - return; - } - - // get the css size - nsSize styleSize; - nsFormControlFrame::GetStyleSize(*aPresContext, aReflowState, styleSize); - - // get the size of the longest option - PRInt32 maxWidth = 1; - PRUint32 numOptions; - options->GetLength(&numOptions); - - - for (PRUint32 i = 0; i < numOptions; i++) { - nsIDOMHTMLOptionElement* option = GetOption(*options, i); - if (option) { - nsAutoString text; - if (NS_CONTENT_ATTR_HAS_VALUE != option->GetText(text)) { - continue; - } - nsSize textSize; - // use the style for the select rather that the option, since widgets don't support it - nsFormControlHelper::GetTextSize(*aPresContext, this, text, textSize, aReflowState.rendContext); - if (textSize.width > maxWidth) { - maxWidth = textSize.width; - } - NS_RELEASE(option); - } - } - - PRInt32 rowHeight = 0; - nsSize desiredSize; - nsSize minSize; - PRBool widthExplicit, heightExplicit; - nsInputDimensionSpec textSpec(nsnull, PR_FALSE, nsnull, nsnull, - maxWidth, PR_TRUE, nsHTMLAtoms::size, 1); - // XXX fix CalculateSize to return PRUint32 - mNumRows = (PRUint32)nsFormControlHelper::CalculateSize (aPresContext, aReflowState.rendContext, this, styleSize, - textSpec, desiredSize, minSize, widthExplicit, - heightExplicit, rowHeight); - - float sp2t; - float p2t; - aPresContext->GetPixelsToTwips(&p2t); - aPresContext->GetScaledPixelsToTwips(&sp2t); - - if (mInDropDownMode) { - nscoord extra = desiredSize.height - (rowHeight * mNumRows); - - mNumRows = (numOptions > 20 ? 20 : numOptions); - desiredSize.height = (mNumRows * rowHeight) + extra; - } - - aDesiredLayoutSize.width = desiredSize.width; - - // XXX put this in widget library, combo boxes are fixed height (visible part) - //aDesiredLayoutSize.height = (mIsComboBox) - // ? rowHeight + (2 * GetVerticalInsidePadding(p2t, rowHeight)) - // : calcSize.height; - aDesiredLayoutSize.height = desiredSize.height; - aDesiredLayoutSize.ascent = aDesiredLayoutSize.height; - aDesiredLayoutSize.descent = 0; - - // XXX When this code is working, max element size needs to be set properly from CalculateSize - // above. look at some of the other form control to see how to do it. - - aDesiredWidgetSize.width = maxWidth; - aDesiredWidgetSize.height = rowHeight; - - if (aDesiredLayoutSize.maxElementSize) { - aDesiredLayoutSize.maxElementSize->width = minSize.width; - aDesiredLayoutSize.maxElementSize->height = minSize.height; - } - - NS_RELEASE(select); - NS_RELEASE(options); - -} - - //---------------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::GetMultiple(PRBool* aMultiple, nsIDOMHTMLSelectElement* aSelect) @@ -1076,7 +1131,6 @@ nsListControlFrame::AboutToDropDown() kid->GetContent(&content); if (i == mSelectedIndex) { mSelectedContent = content; - mSelectedFrame = kid; DisplaySelected(mSelectedContent); return NS_OK; } @@ -1158,6 +1212,10 @@ nsListControlFrame::InitializeFromContent(PRBool aDoDisplay) PRBool selected; option->GetDefaultSelected(&selected); SetFrameSelected(i, selected); + // Set the selected index for single selection list boxes. + if (selected) { + mSelectedIndex = i; + } if (mInDropDownMode) { if (selected) { @@ -1168,7 +1226,6 @@ nsListControlFrame::InitializeFromContent(PRBool aDoDisplay) mSelectedIndex = i; NS_RELEASE(option); mSelectedContent = content; - mSelectedFrame = kid; return; } } else { @@ -1434,8 +1491,8 @@ nsListControlFrame::SetFocus(PRBool aOn, PRBool aRepaint) // in this call? if (mSelectedContent) { //XXX: Need correct attribute here - mSelectedContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (aOn?kSelectedFocus:kNormal), PR_TRUE); - } +// mSelectedContent->SetAttribute(kNameSpaceID_HTML, nsHTMLAtoms::kClass, (aOn?kSelectedFocus:kNormal), PR_TRUE); + } } @@ -1479,8 +1536,92 @@ PRInt32 nsListControlFrame::GetNumberOfOptions() return(numOptions); } +// Set the selected attribute for an item in the listbox. If the listbox has +// been initialized the result of the setting the attribute is displayed otherwise +// it is not. -NS_IMETHODIMP nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue) +void +nsListControlFrame::SetContentSelectedAttribute(PRUint32 aIndex, PRBool aSelected) +{ + // Only display the result of the attribute changed if the listbox has been + // initialized. + if (mIsInitializedFromContent) { + // Update the attribute and display it + SetFrameSelected(aIndex, aSelected); + } else { + // Update the attribute without displaying it + nsIContent* content = GetOptionContent(aIndex); + NS_ASSERTION(nsnull != content, "Failed to retrieve option content"); + nsCOMPtr selectedAtom ( dont_QueryInterface(NS_NewAtom(kMozSelected))); + if (aSelected) { + content->SetAttribute(kNameSpaceID_None, selectedAtom, "", PR_FALSE); + } else { + content->UnsetAttribute(kNameSpaceID_None, selectedAtom, PR_FALSE); + } + NS_IF_RELEASE(content); + } +} + +// Set a single item in the listbox to selected. + +void +nsListControlFrame::SetSelectedIndex(PRInt32 aIndex, nsIContent *aContent) +{ + SetContentSelectedAttribute(aIndex, PR_TRUE); + mSelectedContent = aContent; + mSelectedIndex = aIndex; + + // Get the selected string from the content + nsIDOMHTMLOptionElement* option = nsnull; + nsresult rv = aContent->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); + if (NS_SUCCEEDED(rv)) { + nsAutoString text; + if (NS_CONTENT_ATTR_HAS_VALUE == option->GetText(text)) { + mSelectionStr = text; + } + NS_RELEASE(option); + } +} + + +// Select the specified item in the listbox using control logic. +// If it a single selection listbox the previous selection will be +// de-selected. + +void +nsListControlFrame::ToggleSelected(PRInt32 aIndex, nsIContent *aContent) +{ + PRBool multiple; + GetMultiple(&multiple); + + if (PR_TRUE == multiple) { + SetSelectedIndex(aIndex, aContent); + } else { + if (mSelectedIndex != kNothingSelected) { + SetContentSelectedAttribute(aIndex, PR_FALSE); + } + SetSelectedIndex(aIndex, aContent); + } +} + +// Select the specified item in the listbox using + +void +nsListControlFrame::SelectIndex(PRInt32 aIndex) +{ + nsIDOMHTMLCollection* options = GetOptions(mContent); + nsIDOMHTMLOptionElement* optionElement = GetOption(*options, aIndex); + nsIContent *content = nsnull; + nsresult result = optionElement->QueryInterface(kIContentIID, (void**) &content); + ToggleSelected(aIndex, content); + NS_RELEASE(content); + NS_RELEASE(optionElement); + NS_RELEASE(options); +} + + +NS_IMETHODIMP +nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue) { if (nsHTMLAtoms::selected == aName) { return NS_ERROR_INVALID_ARG; // Selected is readonly according to spec. @@ -1490,7 +1631,8 @@ NS_IMETHODIMP nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aV if (error) { return NS_ERROR_INVALID_ARG; // Couldn't convert to integer } else { - SetFrameSelected(selectedIndex, PR_TRUE); + // Select the specified item in the list box. + SelectIndex(selectedIndex); } } else { //XXX: TODO What about all othe other properties that form elements can set here? @@ -1499,7 +1641,8 @@ NS_IMETHODIMP nsListControlFrame::SetProperty(nsIAtom* aName, const nsString& aV return NS_OK; } -NS_IMETHODIMP nsListControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) +NS_IMETHODIMP +nsListControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) { // Get the selected value of option from local cache (optimization vs. widget) if (nsHTMLAtoms::selected == aName) { @@ -1516,7 +1659,7 @@ NS_IMETHODIMP nsListControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) // Spin through loooking for the first selection in the list PRInt32 index = 0; PRInt32 maxOptions = GetNumberOfOptions(); - PRInt32 selectedIndex = -1; + PRInt32 selectedIndex = kNothingSelected; for (index = 0; index < maxOptions; index++) { PRBool isSelected = PR_FALSE; diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.h b/mozilla/layout/html/forms/src/nsListControlFrame.h index c9c90552897..4af053bc51e 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.h +++ b/mozilla/layout/html/forms/src/nsListControlFrame.h @@ -32,6 +32,7 @@ class nsIDOMHTMLOptionElement; class nsFormFrame; class nsScrollFrame; class nsIComboboxControlFrame; +class nsVoidArray; /** @@ -83,26 +84,17 @@ public: NS_IMETHOD SetProperty(nsIAtom* aName, const nsString& aValue); NS_IMETHOD GetProperty(nsIAtom* aName, nsString& aValue); - virtual void GetDesiredSize(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsHTMLReflowMetrics& aDesiredLayoutSize, - nsSize& aDesiredWidgetSize); - /*virtual nsresult Focus(nsIDOMEvent* aEvent); - virtual nsresult Blur(nsIDOMEvent* aEvent); - virtual nsresult HandleEvent(nsIDOMEvent* aEvent); - NS_IMETHOD AddEventListener(nsIDOMNode * aNode); - NS_IMETHOD RemoveEventListener(nsIDOMNode * aNode); - - NS_IMETHOD DeleteFrame(nsIPresContext& aPresContext);*/ - + virtual nsresult Blur(nsIDOMEvent* aEvent); */ + NS_METHOD GetMultiple(PRBool* aResult, nsIDOMHTMLSelectElement* aSelect = nsnull); +// XXX the following methods are not referenced. They should be removed when it is +// confirmed that they are not needed virtual nsresult GetSizeFromContent(PRInt32* aSize) const; NS_IMETHOD GetMaxLength(PRInt32* aSize); +// XXX: End of the unreferenced methods - virtual nscoord GetVerticalBorderWidth(float aPixToTwip) const; - virtual nscoord GetHorizontalBorderWidth(float aPixToTwip) const; virtual nscoord GetVerticalInsidePadding(float aPixToTwip, nscoord aInnerHeight) const; virtual nscoord GetHorizontalInsidePadding(nsIPresContext& aPresContext, @@ -110,17 +102,18 @@ public: nscoord aInnerWidth, nscoord aCharWidth) const; + virtual nsresult RequiresWidget(PRBool &aRequiresWidget); + NS_IMETHOD GetFont(nsIPresContext* aPresContext, nsFont& aFont); + + NS_IMETHOD GetFormContent(nsIContent*& aContent) const; - // nsIFrame - NS_IMETHOD SetRect(const nsRect& aRect); - NS_IMETHOD SizeTo(nscoord aWidth, nscoord aHeight); ///////////////////////// // nsHTMLContainerFrame @@ -183,6 +176,17 @@ protected: void DisplaySelected(nsIContent* aContent); void DisplayDeselected(nsIContent* aContent); void UpdateItem(nsIContent* aContent, PRBool aSelected); + void ForceRedraw(nsIContent* aContent); + PRBool IsOptionGroup(nsIFrame* aFrame); + void ConstructSelectableList(nsIFrame* aFrame, nsVoidArray *aList); + nsIFrame* GetFirstSelectableFrame(nsVoidArray *aList, PRInt32& aPos); + nsIFrame* GetNextSelectableFrame(nsVoidArray *aList, PRInt32& aPos); + void SingleSelection(); + void MultipleSelection(PRBool aIsShift, PRBool aIsControl); + void SelectIndex(PRInt32 aIndex); + void ToggleSelected(PRInt32 aIndex, nsIContent *aContent); + void SetSelectedIndex(PRInt32 aIndex, nsIContent *aContent); + void SetContentSelectedAttribute(PRUint32 aIndex, PRBool aSelected); // nsHTMLContainerFrame overrides @@ -202,10 +206,9 @@ protected: PRBool aDisplaySelected); // Data Members + nscoord mBorderOffsetY; nsFormFrame* mFormFrame; PRInt32 mNumRows; -//XXX: TODO: This should not be hardcoded to 64 -//ZZZ PRBool mIsFrameSelected[64]; PRInt32 mNumSelections; PRInt32 mMaxNumSelections; PRBool mMultipleSelections; @@ -216,13 +219,13 @@ protected: nsIContent * mHitContent; nsIFrame * mCurrentHitFrame; nsIContent * mCurrentHitContent; - nsIFrame * mSelectedFrame; nsIContent * mSelectedContent; PRBool mIsInitializedFromContent; nsIFrame * mContentFrame; PRBool mInDropDownMode; nsIComboboxControlFrame * mComboboxFrame; nsString mSelectionStr; + nsVoidArray* mSelectableFrames; }; diff --git a/mozilla/layout/style/ua.css b/mozilla/layout/style/ua.css index c2e7e2859f1..3b867eef998 100644 --- a/mozilla/layout/style/ua.css +++ b/mozilla/layout/style/ua.css @@ -686,6 +686,7 @@ select { border: 1px inset #c0c0c0; background-color: white; color:black; + white-space:nowrap; } option { display:block; @@ -707,6 +708,19 @@ option.selectedfocus { background-color: rgb(0,0,128); color: rgb(255,255,255); } + +optgroup { + font-style:italic; + font-weight:bold; +} + +optgroup > option { + position:relative; + left:20px; + font-style:normal; + font-weight:normal; +} + textarea { vertical-align: bottom; border: 2px inset #c0c0c0; @@ -915,8 +929,6 @@ sourcetext { :-moz-dropdown-list { position:absolute; - height:200px; - width:100px; background-color:white; border: 1px solid blue; }