diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index 0a3aa9b6702..549ad9bb31e 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -2092,6 +2092,17 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsIPresContext* aPresContext, NS_ASSERTION(nsnull != listView,"ListFrame's view is nsnull"); listView->SetViewFlags(NS_VIEW_PUBLIC_FLAG_DONT_CHECK_CHILDREN); + // Set initial visibility to hidden for the drop-down list + // XXX: This should not be necessary. Need to restructure the combo box as follows: + // Derive nsComboboxFrame from nsAreaFrame. Attach the placeholder frame, a label frame and + // a button frame. Override reresolve style context and reresolve the style on the ListBox. + // The event state manager should then be asked to set active and non-active based on + // The mouse click this would get rid of all of the ugly code here. The setting of the active + // Should cause re-resolution of the AreaFrame which will re-sync it. KMM. + listFrame->ReResolveStyleContext(aPresContext, hiddenPseudoStyle, NS_STYLE_HINT_NONE, nsnull, nsnull); + listView->SetVisibility(nsViewVisibility_kHide); + + // Create a place holder frame for the dropdown list nsIFrame* placeholderFrame = nsnull; CreatePlaceholderFrameFor(aPresContext, aContent, aNewFrame, aStyleContext, diff --git a/mozilla/layout/forms/nsComboboxControlFrame.cpp b/mozilla/layout/forms/nsComboboxControlFrame.cpp index 2f9f2a0f38f..6a23c04501a 100644 --- a/mozilla/layout/forms/nsComboboxControlFrame.cpp +++ b/mozilla/layout/forms/nsComboboxControlFrame.cpp @@ -694,6 +694,11 @@ NS_IMETHODIMP nsComboboxControlFrame::HandleEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsEventStatus& aEventStatus) { + if (aEvent->message == NS_MOUSE_EXIT) { + if (mArrowStyle == mBtnPressedStyleContext) { + mListControlFrame->CaptureMouseEvents(PR_TRUE); + } + } if (nsEventStatus_eConsumeNoDefault == aEventStatus) { return NS_OK; @@ -714,10 +719,6 @@ NS_IMETHODIMP nsComboboxControlFrame::HandleEvent(nsIPresContext& aPresContext, if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) { mArrowStyle = mBtnOutStyleContext; nsFormControlHelper::ForceDrawFrame(this); - //MouseClicked(&aPresContext); - - } else if (aEvent->message == NS_MOUSE_MOVE) { - } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) { mArrowStyle = mBtnPressedStyleContext; nsFormControlHelper::ForceDrawFrame(this); diff --git a/mozilla/layout/forms/nsIListControlFrame.h b/mozilla/layout/forms/nsIListControlFrame.h index b7f926c9e4a..908a34bd68d 100644 --- a/mozilla/layout/forms/nsIListControlFrame.h +++ b/mozilla/layout/forms/nsIListControlFrame.h @@ -33,9 +33,7 @@ class nsIContent; { 0x8d, 0xcf, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } } /** - * nsIListControlFrame is the common interface for frames of form controls. It - * provides a uniform way of creating widgets, resizing, and painting. - * @see nsLeafFrame and its base classes for more info + * nsIListControlFrame is the interface for frame-based listboxes. */ class nsIListControlFrame : public nsISupports { @@ -59,6 +57,13 @@ public: */ NS_IMETHOD AboutToDropDown() = 0; + /** + * Initiates mouse capture for the listbox + * + */ + NS_IMETHOD CaptureMouseEvents(PRBool aGrabMouseEvents) = 0; + + }; #endif diff --git a/mozilla/layout/forms/nsListControlFrame.cpp b/mozilla/layout/forms/nsListControlFrame.cpp index abd0de24e5d..bf38daff21b 100644 --- a/mozilla/layout/forms/nsListControlFrame.cpp +++ b/mozilla/layout/forms/nsListControlFrame.cpp @@ -353,6 +353,14 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, // Do the inherited Reflow. This reflow uses the computed widths which // are setup above. // Don't set the height. Let the height be unconstrained + + 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 ; + } + } nsScrollFrame::Reflow(aPresContext, aDesiredSize, @@ -362,10 +370,12 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, // Now that we have reflowed, we may need to adjust the width and height returned // for the listbox. - // 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; + 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 @@ -651,6 +661,31 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeListEvent(nsIPresContext& aPresConte return NS_OK; } +NS_IMETHODIMP +nsListControlFrame :: CaptureMouseEvents(PRBool aGrabMouseEvents) +{ + // get its view + nsIView* view = nsnull; + GetView(&view); + nsCOMPtr viewMan; + PRBool result; + + if (view) { + view->GetViewManager(*getter_AddRefs(viewMan)); + + if (viewMan) { + if (aGrabMouseEvents) { + viewMan->GrabMouseEvents(view,result); + } else { + viewMan->GrabMouseEvents(nsnull,result); + } + } + } + + return NS_OK; +} + + //---------------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, @@ -688,7 +723,13 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aP mCurrentHitContent = mHitContent; } + } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) { + // Initiate mouse capture + CaptureMouseEvents(PR_TRUE); + } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) { + // Stop grabbing mouse events + CaptureMouseEvents(PR_FALSE); // Start by finding the newly "hit" content from the hit frame PRInt32 index = SetContentSelected(mHitFrame, mHitContent, PR_TRUE); @@ -722,12 +763,12 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aP } if (mComboboxFrame) { - mComboboxFrame->ListWasSelected(&aPresContext); + mComboboxFrame->ListWasSelected(&aPresContext); } } - } + } return NS_OK; } diff --git a/mozilla/layout/forms/nsListControlFrame.h b/mozilla/layout/forms/nsListControlFrame.h index 379e3cea2bf..c9c90552897 100644 --- a/mozilla/layout/forms/nsListControlFrame.h +++ b/mozilla/layout/forms/nsListControlFrame.h @@ -149,10 +149,12 @@ public: virtual void SetFormFrame(nsFormFrame* aFrame); + // nsIListControlFrame NS_IMETHOD SetComboboxFrame(nsIFrame* aComboboxFrame); NS_IMETHOD GetSelectedItem(nsString & aStr); NS_IMETHOD AboutToDropDown(); + NS_IMETHOD CaptureMouseEvents(PRBool aGrabMouseEvents); // Static Methods static nsIDOMHTMLSelectElement* GetSelect(nsIContent * aContent); diff --git a/mozilla/layout/html/forms/public/nsIListControlFrame.h b/mozilla/layout/html/forms/public/nsIListControlFrame.h index b7f926c9e4a..908a34bd68d 100644 --- a/mozilla/layout/html/forms/public/nsIListControlFrame.h +++ b/mozilla/layout/html/forms/public/nsIListControlFrame.h @@ -33,9 +33,7 @@ class nsIContent; { 0x8d, 0xcf, 0x0, 0x60, 0x97, 0x3, 0xc1, 0x4e } } /** - * nsIListControlFrame is the common interface for frames of form controls. It - * provides a uniform way of creating widgets, resizing, and painting. - * @see nsLeafFrame and its base classes for more info + * nsIListControlFrame is the interface for frame-based listboxes. */ class nsIListControlFrame : public nsISupports { @@ -59,6 +57,13 @@ public: */ NS_IMETHOD AboutToDropDown() = 0; + /** + * Initiates mouse capture for the listbox + * + */ + NS_IMETHOD CaptureMouseEvents(PRBool aGrabMouseEvents) = 0; + + }; #endif diff --git a/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp b/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp index 2f9f2a0f38f..6a23c04501a 100644 --- a/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsComboboxControlFrame.cpp @@ -694,6 +694,11 @@ NS_IMETHODIMP nsComboboxControlFrame::HandleEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, nsEventStatus& aEventStatus) { + if (aEvent->message == NS_MOUSE_EXIT) { + if (mArrowStyle == mBtnPressedStyleContext) { + mListControlFrame->CaptureMouseEvents(PR_TRUE); + } + } if (nsEventStatus_eConsumeNoDefault == aEventStatus) { return NS_OK; @@ -714,10 +719,6 @@ NS_IMETHODIMP nsComboboxControlFrame::HandleEvent(nsIPresContext& aPresContext, if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) { mArrowStyle = mBtnOutStyleContext; nsFormControlHelper::ForceDrawFrame(this); - //MouseClicked(&aPresContext); - - } else if (aEvent->message == NS_MOUSE_MOVE) { - } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) { mArrowStyle = mBtnPressedStyleContext; nsFormControlHelper::ForceDrawFrame(this); diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.cpp b/mozilla/layout/html/forms/src/nsListControlFrame.cpp index abd0de24e5d..bf38daff21b 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsListControlFrame.cpp @@ -353,6 +353,14 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, // Do the inherited Reflow. This reflow uses the computed widths which // are setup above. // Don't set the height. Let the height be unconstrained + + 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 ; + } + } nsScrollFrame::Reflow(aPresContext, aDesiredSize, @@ -362,10 +370,12 @@ nsListControlFrame::Reflow(nsIPresContext& aPresContext, // Now that we have reflowed, we may need to adjust the width and height returned // for the listbox. - // 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; + 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 @@ -651,6 +661,31 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeListEvent(nsIPresContext& aPresConte return NS_OK; } +NS_IMETHODIMP +nsListControlFrame :: CaptureMouseEvents(PRBool aGrabMouseEvents) +{ + // get its view + nsIView* view = nsnull; + GetView(&view); + nsCOMPtr viewMan; + PRBool result; + + if (view) { + view->GetViewManager(*getter_AddRefs(viewMan)); + + if (viewMan) { + if (aGrabMouseEvents) { + viewMan->GrabMouseEvents(view,result); + } else { + viewMan->GrabMouseEvents(nsnull,result); + } + } + } + + return NS_OK; +} + + //---------------------------------------------------------------------- NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aPresContext, nsGUIEvent* aEvent, @@ -688,7 +723,13 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aP mCurrentHitContent = mHitContent; } + } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_DOWN) { + // Initiate mouse capture + CaptureMouseEvents(PR_TRUE); + } else if (aEvent->message == NS_MOUSE_LEFT_BUTTON_UP) { + // Stop grabbing mouse events + CaptureMouseEvents(PR_FALSE); // Start by finding the newly "hit" content from the hit frame PRInt32 index = SetContentSelected(mHitFrame, mHitContent, PR_TRUE); @@ -722,12 +763,12 @@ NS_IMETHODIMP nsListControlFrame::HandleLikeDropDownListEvent(nsIPresContext& aP } if (mComboboxFrame) { - mComboboxFrame->ListWasSelected(&aPresContext); + mComboboxFrame->ListWasSelected(&aPresContext); } } - } + } return NS_OK; } diff --git a/mozilla/layout/html/forms/src/nsListControlFrame.h b/mozilla/layout/html/forms/src/nsListControlFrame.h index 379e3cea2bf..c9c90552897 100644 --- a/mozilla/layout/html/forms/src/nsListControlFrame.h +++ b/mozilla/layout/html/forms/src/nsListControlFrame.h @@ -149,10 +149,12 @@ public: virtual void SetFormFrame(nsFormFrame* aFrame); + // nsIListControlFrame NS_IMETHOD SetComboboxFrame(nsIFrame* aComboboxFrame); NS_IMETHOD GetSelectedItem(nsString & aStr); NS_IMETHOD AboutToDropDown(); + NS_IMETHOD CaptureMouseEvents(PRBool aGrabMouseEvents); // Static Methods static nsIDOMHTMLSelectElement* GetSelect(nsIContent * aContent); diff --git a/mozilla/layout/html/forms/src/nsSelectControlFrame.cpp b/mozilla/layout/html/forms/src/nsSelectControlFrame.cpp index 2f057d36157..41575d15a80 100644 --- a/mozilla/layout/html/forms/src/nsSelectControlFrame.cpp +++ b/mozilla/layout/html/forms/src/nsSelectControlFrame.cpp @@ -1178,7 +1178,6 @@ NS_IMETHODIMP nsSelectControlFrame::SetProperty(nsIAtom* aName, const nsString& NS_IMETHODIMP nsSelectControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) { -#ifndef XP_MAC // Get the selected value of option from local cache (optimization vs. widget) if (nsHTMLAtoms::selected == aName) { PRInt32 error = 0; @@ -1221,6 +1220,5 @@ NS_IMETHODIMP nsSelectControlFrame::GetProperty(nsIAtom* aName, nsString& aValue } else { return nsFormControlFrame::GetProperty(aName, aValue); } -#endif return NS_OK; } diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp index 0a3aa9b6702..549ad9bb31e 100644 --- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -2092,6 +2092,17 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsIPresContext* aPresContext, NS_ASSERTION(nsnull != listView,"ListFrame's view is nsnull"); listView->SetViewFlags(NS_VIEW_PUBLIC_FLAG_DONT_CHECK_CHILDREN); + // Set initial visibility to hidden for the drop-down list + // XXX: This should not be necessary. Need to restructure the combo box as follows: + // Derive nsComboboxFrame from nsAreaFrame. Attach the placeholder frame, a label frame and + // a button frame. Override reresolve style context and reresolve the style on the ListBox. + // The event state manager should then be asked to set active and non-active based on + // The mouse click this would get rid of all of the ugly code here. The setting of the active + // Should cause re-resolution of the AreaFrame which will re-sync it. KMM. + listFrame->ReResolveStyleContext(aPresContext, hiddenPseudoStyle, NS_STYLE_HINT_NONE, nsnull, nsnull); + listView->SetVisibility(nsViewVisibility_kHide); + + // Create a place holder frame for the dropdown list nsIFrame* placeholderFrame = nsnull; CreatePlaceholderFrameFor(aPresContext, aContent, aNewFrame, aStyleContext,