diff --git a/mozilla/layout/forms/nsGfxButtonControlFrame.cpp b/mozilla/layout/forms/nsGfxButtonControlFrame.cpp new file mode 100644 index 00000000000..233477f9146 --- /dev/null +++ b/mozilla/layout/forms/nsGfxButtonControlFrame.cpp @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsGfxButtonControlFrame.h" +#include "nsHTMLAtoms.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsIButton.h" +#include "nsINameSpaceManager.h" + + +static NS_DEFINE_IID(kIButtonIID, NS_IBUTTON_IID); + +nsresult +NS_NewGfxButtonControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsGfxButtonControlFrame* it = new nsGfxButtonControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + + +nsGfxButtonControlFrame::nsGfxButtonControlFrame() +{ + mRenderer.SetNameSpace(kNameSpaceID_None); +} + +NS_IMETHODIMP +nsGfxButtonControlFrame::Init(nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv = Inherited::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); + mRenderer.SetFrame(this,aPresContext); + return rv; +} + + +// +// ReResolveStyleContext +// +// When the style context changes, make sure that all of our styles are still up to date. +// +NS_IMETHODIMP +nsGfxButtonControlFrame::ReResolveStyleContext ( nsIPresContext* aPresContext, nsIStyleContext* aParentContext, + PRInt32 aParentChange, + nsStyleChangeList* aChangeList, PRInt32* aLocalChange) +{ + // this re-resolves |mStyleContext|, so it may change + nsresult rv = Inherited::ReResolveStyleContext(aPresContext, aParentContext, + aParentChange, aChangeList, aLocalChange); + if (NS_FAILED(rv)) { + return rv; + } + + if (NS_COMFALSE != rv) { // frame style changed + if (aLocalChange) { + aParentChange = *aLocalChange; // tell children about or change + } + } + mRenderer.ReResolveStyles(*aPresContext, aParentChange, aChangeList, aLocalChange); + + return rv; + +} // ReResolveStyleContext + + + + +NS_METHOD +nsGfxButtonControlFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + const nsStyleDisplay* disp = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + if (!disp->mVisible) + return NS_OK; + + nsRect rect(0, 0, mRect.width, mRect.height); + mRenderer.PaintButton(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, rect); + + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + nsString label; + nsresult result = GetValue(&label); + + if (NS_CONTENT_ATTR_HAS_VALUE != result) { + GetDefaultLabel(label); + } + + nsRect content; + mRenderer.GetButtonContentRect(rect,content); + + // paint the title + const nsStyleFont* fontStyle = (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); + const nsStyleColor* colorStyle = (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color); + + aRenderingContext.SetFont(fontStyle->mFont); + + PRBool clipState; + aRenderingContext.PushState(); + aRenderingContext.SetClipRect(rect, nsClipCombine_kIntersect, clipState); + // if disabled paint + if (PR_TRUE == mRenderer.isDisabled()) + { + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + nscoord pixel = NSIntPixelsToTwips(1, p2t); + + aRenderingContext.SetColor(NS_RGB(255,255,255)); + aRenderingContext.DrawString(label, content.x + pixel, content.y+ pixel); + } + + aRenderingContext.SetColor(colorStyle->mColor); + aRenderingContext.DrawString(label, content.x, content.y); + aRenderingContext.PopState(clipState); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsGfxButtonControlFrame::AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint) +{ + if (nsHTMLAtoms::value == aAttribute) { + // redraw button with the changed value + Invalidate(mRect, PR_FALSE); + } + return NS_OK; +} + +NS_METHOD +nsGfxButtonControlFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + + // add ourself as an nsIFormControlFrame + if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { + nsFormFrame::AddFormControlFrame(aPresContext, *this); + } + + if ((NS_FORMSIZE_NOTSET != mSuggestedWidth) && ( + NS_FORMSIZE_NOTSET != mSuggestedHeight)) + { + aDesiredSize.width = mSuggestedWidth; + aDesiredSize.height = mSuggestedHeight; + aDesiredSize.ascent = mSuggestedHeight; + aDesiredSize.descent = 0; + if (aDesiredSize.maxElementSize) { + aDesiredSize.maxElementSize->width = mSuggestedWidth; + aDesiredSize.maxElementSize->height = mSuggestedWidth; + } + + if (nsnull != aDesiredSize.maxElementSize) { + aDesiredSize.maxElementSize->width = aDesiredSize.width; + aDesiredSize.maxElementSize->height = aDesiredSize.height; + } + + aStatus = NS_FRAME_COMPLETE; + return NS_OK; + + } + + nsSize ignore; + GetDesiredSize(&aPresContext, aReflowState, aDesiredSize, ignore); + + // if our size is intrinsic. Then we need to return the size we really need + // so include our inner borders we use for focus. + nsMargin added = mRenderer.GetAddedButtonBorderAndPadding(); + if (aReflowState.mComputedWidth == NS_INTRINSICSIZE) + aDesiredSize.width += added.left + added.right; + + if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) + aDesiredSize.height += added.top + added.bottom; + + nsMargin bp(0,0,0,0); + AddBordersAndPadding(&aPresContext, aReflowState, aDesiredSize, bp); + + + if (nsnull != aDesiredSize.maxElementSize) { + aDesiredSize.AddBorderPaddingToMaxElementSize(bp); + aDesiredSize.maxElementSize->width += added.left + added.right; + aDesiredSize.maxElementSize->height += added.top + added.bottom; + + } + aStatus = NS_FRAME_COMPLETE; + return NS_OK; +} + + +NS_IMETHODIMP +nsGfxButtonControlFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus) +{ + // if disabled do nothing + if (mRenderer.isDisabled()) { + return NS_OK; + } + + return Inherited::HandleEvent(aPresContext, aEvent, aEventStatus); +} diff --git a/mozilla/layout/forms/nsGfxButtonControlFrame.h b/mozilla/layout/forms/nsGfxButtonControlFrame.h new file mode 100644 index 00000000000..1021430ebd9 --- /dev/null +++ b/mozilla/layout/forms/nsGfxButtonControlFrame.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsGfxButtonControlFrame_h___ +#define nsGfxButtonControlFrame_h___ + +#include "nsNativeFormControlFrame.h" +#include "nsButtonControlFrame.h" +#include "nsButtonFrameRenderer.h" + +class nsGfxButtonControlFrame : public nsButtonControlFrame { +private: + typedef nsButtonControlFrame Inherited; + +public: + + nsGfxButtonControlFrame(); + + NS_IMETHOD Init(nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* asPrevInFlow); + + NS_IMETHOD ReResolveStyleContext ( nsIPresContext* aPresContext, + nsIStyleContext* aParentContext, + PRInt32 aParentChange, + nsStyleChangeList* aChangeList, + PRInt32* aLocalChange) ; + + NS_IMETHOD Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + NS_IMETHOD Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint); + + NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + +protected: + //GFX-rendered state variables + nsButtonFrameRenderer mRenderer; +}; + + +#endif + diff --git a/mozilla/layout/forms/nsGfxCheckboxControlFrame.cpp b/mozilla/layout/forms/nsGfxCheckboxControlFrame.cpp new file mode 100644 index 00000000000..ddd893e16f9 --- /dev/null +++ b/mozilla/layout/forms/nsGfxCheckboxControlFrame.cpp @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsGfxCheckboxControlFrame.h" +#include "nsICheckButton.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLParts.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsWidgetsCID.h" +#include "nsIComponentManager.h" + + + +nsresult +NS_NewGfxCheckboxControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsGfxCheckboxControlFrame* it = new nsGfxCheckboxControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsGfxCheckboxControlFrame::nsGfxCheckboxControlFrame() +{ + // Initialize GFX-rendered state + mMouseDownOnCheckbox = PR_FALSE; + mChecked = PR_FALSE; +} + +void +nsGfxCheckboxControlFrame::MouseClicked(nsIPresContext* aPresContext) +{ + mMouseDownOnCheckbox = PR_FALSE; + Inherited::MouseClicked(aPresContext); +} + +void +nsGfxCheckboxControlFrame::PaintCheckBox(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + aRenderingContext.PushState(); + + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + + PRBool checked = PR_FALSE; + + // Get current checked state through content model. + // XXX: This is very inefficient, but it is necessary in the case of printing. + // During printing the Paint is called but the actual state of the checkbox + // is in a frame in presentation shell 0. + /*XXXnsresult result = */GetCurrentCheckState(&checked); + if (PR_TRUE == checked) { + // Draw check mark + const nsStyleColor* color = (const nsStyleColor*) + mStyleContext->GetStyleData(eStyleStruct_Color); + aRenderingContext.SetColor(color->mColor); + nsFormControlHelper::PaintCheckMark(aRenderingContext, + p2t, mRect.width, mRect.height); + + } + PRBool clip; + aRenderingContext.PopState(clip); +} + + +NS_METHOD +nsGfxCheckboxControlFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + + const nsStyleDisplay* disp = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + if (!disp->mVisible) + return NS_OK; + + // Paint the background + Inherited::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + // Paint the checkmark + PaintCheckBox(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); + } + return NS_OK; +} + +NS_METHOD nsGfxCheckboxControlFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus) +{ + if (nsEventStatus_eConsumeNoDefault == aEventStatus) { + return NS_OK; + } + + // Handle GFX rendered widget Mouse Down event + PRInt32 type; + GetType(&type); + switch (aEvent->message) { + case NS_MOUSE_LEFT_BUTTON_DOWN: + mMouseDownOnCheckbox = PR_TRUE; + //XXX: TODO render gray rectangle on mouse down + break; + + case NS_MOUSE_EXIT: + mMouseDownOnCheckbox = PR_FALSE; + //XXX: TO DO clear gray rectangle on mouse up + break; + + } + + return(Inherited::HandleEvent(aPresContext, aEvent, aEventStatus)); +} + + +PRBool nsGfxCheckboxControlFrame::GetCheckboxState() +{ + return mChecked; +} + +void nsGfxCheckboxControlFrame::SetCheckboxState(PRBool aValue) +{ + mChecked = aValue; + nsFormControlHelper::ForceDrawFrame(this); +} + diff --git a/mozilla/layout/forms/nsGfxCheckboxControlFrame.h b/mozilla/layout/forms/nsGfxCheckboxControlFrame.h new file mode 100644 index 00000000000..cfa94df4a87 --- /dev/null +++ b/mozilla/layout/forms/nsGfxCheckboxControlFrame.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef nsGfxCheckboxControlFrame_h___ +#define nsGfxCheckboxControlFrame_h___ + +#include "nsCheckboxControlFrame.h" + + +class nsGfxCheckboxControlFrame : public nsCheckboxControlFrame { +private: + typedef nsCheckboxControlFrame Inherited; + +public: + nsGfxCheckboxControlFrame(); + + NS_IMETHOD GetFrameName(nsString& aResult) const { + return MakeFrameName("CheckboxControl", aResult); + } + + virtual void MouseClicked(nsIPresContext* aPresContext); + + // + // Methods used to GFX-render the checkbox + // + + virtual void PaintCheckBox(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + NS_IMETHOD Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + + //End of GFX-rendering methods + +protected: + virtual PRBool GetCheckboxState(); + virtual void SetCheckboxState(PRBool aValue); + + //GFX-rendered state variables + PRBool mMouseDownOnCheckbox; + PRBool mChecked; +}; + +#endif diff --git a/mozilla/layout/forms/nsGfxRadioControlFrame.cpp b/mozilla/layout/forms/nsGfxRadioControlFrame.cpp new file mode 100644 index 00000000000..e6436f38b90 --- /dev/null +++ b/mozilla/layout/forms/nsGfxRadioControlFrame.cpp @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsGfxRadioControlFrame.h" +#include "nsIRadioButton.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLParts.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsWidgetsCID.h" +#include "nsIComponentManager.h" +#include "nsCOMPtr.h" +#include "nsCSSRendering.h" + + +nsresult +NS_NewGfxRadioControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsGfxRadioControlFrame* it = new nsGfxRadioControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsGfxRadioControlFrame::nsGfxRadioControlFrame() +{ + // Initialize GFX-rendered state + mChecked = PR_FALSE; + mRadioButtonFaceStyle = nsnull; +} + +nsGfxRadioControlFrame::~nsGfxRadioControlFrame() +{ + NS_IF_RELEASE(mRadioButtonFaceStyle); +} + +//-------------------------------------------------------------- + + +NS_IMETHODIMP +nsGfxRadioControlFrame::ReResolveStyleContext(nsIPresContext* aPresContext, + nsIStyleContext* aParentContext, + PRInt32 aParentChange, + nsStyleChangeList* aChangeList, + PRInt32* aLocalChange) +{ + // this re-resolves |mStyleContext|, so it may change + nsresult rv = Inherited::ReResolveStyleContext(aPresContext, aParentContext, aParentChange, + aChangeList, aLocalChange); + if (NS_FAILED(rv)) { + return rv; + } + + if (NS_COMFALSE != rv) { // frame style changed + if (aLocalChange) { + aParentChange = *aLocalChange; // tell children about or change + } + } + + // see if the outline has changed. + nsCOMPtr oldRadioButtonFaceStyle = mRadioButtonFaceStyle; + aPresContext->ProbePseudoStyleContextFor(mContent, nsHTMLAtoms::radioPseudo, mStyleContext, + PR_FALSE, + &mRadioButtonFaceStyle); + + if ((mRadioButtonFaceStyle && oldRadioButtonFaceStyle.get()) && (mRadioButtonFaceStyle != oldRadioButtonFaceStyle.get())) { + Inherited::CaptureStyleChangeFor(this, oldRadioButtonFaceStyle, mRadioButtonFaceStyle, + aParentChange, aChangeList, aLocalChange); + } + + return rv; +} + + +NS_IMETHODIMP +nsGfxRadioControlFrame::SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext) +{ + mRadioButtonFaceStyle = aRadioButtonFaceStyleContext; + NS_ADDREF(mRadioButtonFaceStyle); + return NS_OK; +} + +void +nsGfxRadioControlFrame::PaintRadioButton(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + + PRBool checked = PR_TRUE; + GetCurrentCheckState(&checked); // Get check state from the content model + if (PR_TRUE == checked) { + // Paint the button for the radio button using CSS background rendering code + if (nsnull != mRadioButtonFaceStyle) { + const nsStyleColor* myColor = (const nsStyleColor*) + mRadioButtonFaceStyle->GetStyleData(eStyleStruct_Color); + const nsStyleSpacing* mySpacing = (const nsStyleSpacing*) + mRadioButtonFaceStyle->GetStyleData(eStyleStruct_Spacing); + const nsStylePosition* myPosition = (const nsStylePosition*) + mRadioButtonFaceStyle->GetStyleData(eStyleStruct_Position); + + nscoord width = myPosition->mWidth.GetCoordValue(); + nscoord height = myPosition->mHeight.GetCoordValue(); + // Position the button centered within the radio control's rectangle. + nscoord x = (mRect.width - width) / 2; + nscoord y = (mRect.height - height) / 2; + nsRect rect(x, y, width, height); + + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *myColor, *mySpacing, 0, 0); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *mySpacing, mRadioButtonFaceStyle, 0); + } + } +} + +NS_METHOD +nsGfxRadioControlFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + const nsStyleDisplay* disp = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + if (!disp->mVisible) + return NS_OK; + + // Paint the background + Inherited::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); + + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + PaintRadioButton(aPresContext, aRenderingContext, aDirtyRect); + } + return NS_OK; +} + + +PRBool nsGfxRadioControlFrame::GetRadioState() +{ + return mChecked; +} + +void nsGfxRadioControlFrame::SetRadioState(PRBool aValue) +{ + mChecked = aValue; + nsFormControlHelper::ForceDrawFrame(this); +} diff --git a/mozilla/layout/forms/nsGfxRadioControlFrame.h b/mozilla/layout/forms/nsGfxRadioControlFrame.h new file mode 100644 index 00000000000..5c2ecf727d3 --- /dev/null +++ b/mozilla/layout/forms/nsGfxRadioControlFrame.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsGfxRadioControlFrame_h___ +#define nsGfxRadioControlFrame_h___ + +#include "nsRadioControlFrame.h" + +// nsGfxRadioControlFrame + +class nsGfxRadioControlFrame : public nsRadioControlFrame +{ +private: + typedef nsRadioControlFrame Inherited; + +public: + nsGfxRadioControlFrame(); + ~nsGfxRadioControlFrame(); + + //nsIRadioControlFrame methods + NS_IMETHOD SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext); + + NS_IMETHOD ReResolveStyleContext(nsIPresContext* aPresContext, + nsIStyleContext* aParentContext, + PRInt32 aParentChange, + nsStyleChangeList* aChangeList, + PRInt32* aLocalChange); + + // + // XXX: The following paint methods are TEMPORARY. It is being used to get printing working + // under windows. Later it may be used to GFX-render the controls to the display. + // Expect this code to repackaged and moved to a new location in the future. + // + + NS_IMETHOD Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + virtual void PaintRadioButton(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + ///XXX: End o the temporary methods + +protected: + + virtual PRBool GetRadioState(); + virtual void SetRadioState(PRBool aValue); + + //GFX-rendered state variables + PRBool mChecked; + nsIStyleContext* mRadioButtonFaceStyle; + +private: + NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } + NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } +}; + + + +#endif + + diff --git a/mozilla/layout/html/forms/src/nsCheckboxControlFrame.h b/mozilla/layout/html/forms/src/nsCheckboxControlFrame.h new file mode 100644 index 00000000000..34a98b6b7c0 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsCheckboxControlFrame.h @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef nsCheckboxControlFrame_h___ +#define nsCheckboxControlFrame_h___ + +#include "nsNativeFormControlFrame.h" + + +class nsCheckboxControlFrame : public nsNativeFormControlFrame { +private: + typedef nsNativeFormControlFrame Inherited; + +public: + virtual void PostCreateWidget(nsIPresContext* aPresContext, + nscoord& aWidth, + nscoord& aHeight); + + NS_IMETHOD GetFrameName(nsString& aResult) const { + return MakeFrameName("CheckboxControl", aResult); + } + + virtual const nsIID& GetCID(); + + virtual const nsIID& GetIID(); + + virtual void MouseClicked(nsIPresContext* aPresContext); + + virtual PRInt32 GetMaxNumValues(); + + virtual PRBool GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues, nsString* aNames); + + virtual void Reset(); + + // nsIFormControlFrame + NS_IMETHOD SetProperty(nsIAtom* aName, const nsString& aValue); + NS_IMETHOD GetProperty(nsIAtom* aName, nsString& aValue); + + // Utility methods for implementing SetProperty/GetProperty + void SetCheckboxControlFrameState(const nsString& aValue); + void GetCheckboxControlFrameState(nsString& aValue); + + // nsFormControlFrame overrides + nsresult RequiresWidget(PRBool &aHasWidget); + + // + // Methods used to GFX-render the checkbox + // + + NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + + //End of GFX-rendering methods + +protected: + virtual PRBool GetCheckboxState() = 0; + virtual void SetCheckboxState(PRBool aValue) = 0; +}; + +#endif diff --git a/mozilla/layout/html/forms/src/nsGfxButtonControlFrame.cpp b/mozilla/layout/html/forms/src/nsGfxButtonControlFrame.cpp new file mode 100644 index 00000000000..233477f9146 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsGfxButtonControlFrame.cpp @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsGfxButtonControlFrame.h" +#include "nsHTMLAtoms.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsIButton.h" +#include "nsINameSpaceManager.h" + + +static NS_DEFINE_IID(kIButtonIID, NS_IBUTTON_IID); + +nsresult +NS_NewGfxButtonControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsGfxButtonControlFrame* it = new nsGfxButtonControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + + +nsGfxButtonControlFrame::nsGfxButtonControlFrame() +{ + mRenderer.SetNameSpace(kNameSpaceID_None); +} + +NS_IMETHODIMP +nsGfxButtonControlFrame::Init(nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* aPrevInFlow) +{ + nsresult rv = Inherited::Init(aPresContext, aContent, aParent, aContext, aPrevInFlow); + mRenderer.SetFrame(this,aPresContext); + return rv; +} + + +// +// ReResolveStyleContext +// +// When the style context changes, make sure that all of our styles are still up to date. +// +NS_IMETHODIMP +nsGfxButtonControlFrame::ReResolveStyleContext ( nsIPresContext* aPresContext, nsIStyleContext* aParentContext, + PRInt32 aParentChange, + nsStyleChangeList* aChangeList, PRInt32* aLocalChange) +{ + // this re-resolves |mStyleContext|, so it may change + nsresult rv = Inherited::ReResolveStyleContext(aPresContext, aParentContext, + aParentChange, aChangeList, aLocalChange); + if (NS_FAILED(rv)) { + return rv; + } + + if (NS_COMFALSE != rv) { // frame style changed + if (aLocalChange) { + aParentChange = *aLocalChange; // tell children about or change + } + } + mRenderer.ReResolveStyles(*aPresContext, aParentChange, aChangeList, aLocalChange); + + return rv; + +} // ReResolveStyleContext + + + + +NS_METHOD +nsGfxButtonControlFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + const nsStyleDisplay* disp = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + if (!disp->mVisible) + return NS_OK; + + nsRect rect(0, 0, mRect.width, mRect.height); + mRenderer.PaintButton(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer, rect); + + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + nsString label; + nsresult result = GetValue(&label); + + if (NS_CONTENT_ATTR_HAS_VALUE != result) { + GetDefaultLabel(label); + } + + nsRect content; + mRenderer.GetButtonContentRect(rect,content); + + // paint the title + const nsStyleFont* fontStyle = (const nsStyleFont*)mStyleContext->GetStyleData(eStyleStruct_Font); + const nsStyleColor* colorStyle = (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color); + + aRenderingContext.SetFont(fontStyle->mFont); + + PRBool clipState; + aRenderingContext.PushState(); + aRenderingContext.SetClipRect(rect, nsClipCombine_kIntersect, clipState); + // if disabled paint + if (PR_TRUE == mRenderer.isDisabled()) + { + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + nscoord pixel = NSIntPixelsToTwips(1, p2t); + + aRenderingContext.SetColor(NS_RGB(255,255,255)); + aRenderingContext.DrawString(label, content.x + pixel, content.y+ pixel); + } + + aRenderingContext.SetColor(colorStyle->mColor); + aRenderingContext.DrawString(label, content.x, content.y); + aRenderingContext.PopState(clipState); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsGfxButtonControlFrame::AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint) +{ + if (nsHTMLAtoms::value == aAttribute) { + // redraw button with the changed value + Invalidate(mRect, PR_FALSE); + } + return NS_OK; +} + +NS_METHOD +nsGfxButtonControlFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + + // add ourself as an nsIFormControlFrame + if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { + nsFormFrame::AddFormControlFrame(aPresContext, *this); + } + + if ((NS_FORMSIZE_NOTSET != mSuggestedWidth) && ( + NS_FORMSIZE_NOTSET != mSuggestedHeight)) + { + aDesiredSize.width = mSuggestedWidth; + aDesiredSize.height = mSuggestedHeight; + aDesiredSize.ascent = mSuggestedHeight; + aDesiredSize.descent = 0; + if (aDesiredSize.maxElementSize) { + aDesiredSize.maxElementSize->width = mSuggestedWidth; + aDesiredSize.maxElementSize->height = mSuggestedWidth; + } + + if (nsnull != aDesiredSize.maxElementSize) { + aDesiredSize.maxElementSize->width = aDesiredSize.width; + aDesiredSize.maxElementSize->height = aDesiredSize.height; + } + + aStatus = NS_FRAME_COMPLETE; + return NS_OK; + + } + + nsSize ignore; + GetDesiredSize(&aPresContext, aReflowState, aDesiredSize, ignore); + + // if our size is intrinsic. Then we need to return the size we really need + // so include our inner borders we use for focus. + nsMargin added = mRenderer.GetAddedButtonBorderAndPadding(); + if (aReflowState.mComputedWidth == NS_INTRINSICSIZE) + aDesiredSize.width += added.left + added.right; + + if (aReflowState.mComputedHeight == NS_INTRINSICSIZE) + aDesiredSize.height += added.top + added.bottom; + + nsMargin bp(0,0,0,0); + AddBordersAndPadding(&aPresContext, aReflowState, aDesiredSize, bp); + + + if (nsnull != aDesiredSize.maxElementSize) { + aDesiredSize.AddBorderPaddingToMaxElementSize(bp); + aDesiredSize.maxElementSize->width += added.left + added.right; + aDesiredSize.maxElementSize->height += added.top + added.bottom; + + } + aStatus = NS_FRAME_COMPLETE; + return NS_OK; +} + + +NS_IMETHODIMP +nsGfxButtonControlFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus) +{ + // if disabled do nothing + if (mRenderer.isDisabled()) { + return NS_OK; + } + + return Inherited::HandleEvent(aPresContext, aEvent, aEventStatus); +} diff --git a/mozilla/layout/html/forms/src/nsGfxButtonControlFrame.h b/mozilla/layout/html/forms/src/nsGfxButtonControlFrame.h new file mode 100644 index 00000000000..1021430ebd9 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsGfxButtonControlFrame.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsGfxButtonControlFrame_h___ +#define nsGfxButtonControlFrame_h___ + +#include "nsNativeFormControlFrame.h" +#include "nsButtonControlFrame.h" +#include "nsButtonFrameRenderer.h" + +class nsGfxButtonControlFrame : public nsButtonControlFrame { +private: + typedef nsButtonControlFrame Inherited; + +public: + + nsGfxButtonControlFrame(); + + NS_IMETHOD Init(nsIPresContext& aPresContext, + nsIContent* aContent, + nsIFrame* aParent, + nsIStyleContext* aContext, + nsIFrame* asPrevInFlow); + + NS_IMETHOD ReResolveStyleContext ( nsIPresContext* aPresContext, + nsIStyleContext* aParentContext, + PRInt32 aParentChange, + nsStyleChangeList* aChangeList, + PRInt32* aLocalChange) ; + + NS_IMETHOD Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + NS_IMETHOD Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint); + + NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + +protected: + //GFX-rendered state variables + nsButtonFrameRenderer mRenderer; +}; + + +#endif + diff --git a/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.cpp b/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.cpp new file mode 100644 index 00000000000..ddd893e16f9 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.cpp @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsGfxCheckboxControlFrame.h" +#include "nsICheckButton.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLParts.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsWidgetsCID.h" +#include "nsIComponentManager.h" + + + +nsresult +NS_NewGfxCheckboxControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsGfxCheckboxControlFrame* it = new nsGfxCheckboxControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsGfxCheckboxControlFrame::nsGfxCheckboxControlFrame() +{ + // Initialize GFX-rendered state + mMouseDownOnCheckbox = PR_FALSE; + mChecked = PR_FALSE; +} + +void +nsGfxCheckboxControlFrame::MouseClicked(nsIPresContext* aPresContext) +{ + mMouseDownOnCheckbox = PR_FALSE; + Inherited::MouseClicked(aPresContext); +} + +void +nsGfxCheckboxControlFrame::PaintCheckBox(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + aRenderingContext.PushState(); + + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + + PRBool checked = PR_FALSE; + + // Get current checked state through content model. + // XXX: This is very inefficient, but it is necessary in the case of printing. + // During printing the Paint is called but the actual state of the checkbox + // is in a frame in presentation shell 0. + /*XXXnsresult result = */GetCurrentCheckState(&checked); + if (PR_TRUE == checked) { + // Draw check mark + const nsStyleColor* color = (const nsStyleColor*) + mStyleContext->GetStyleData(eStyleStruct_Color); + aRenderingContext.SetColor(color->mColor); + nsFormControlHelper::PaintCheckMark(aRenderingContext, + p2t, mRect.width, mRect.height); + + } + PRBool clip; + aRenderingContext.PopState(clip); +} + + +NS_METHOD +nsGfxCheckboxControlFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + + const nsStyleDisplay* disp = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + if (!disp->mVisible) + return NS_OK; + + // Paint the background + Inherited::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + // Paint the checkmark + PaintCheckBox(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); + } + return NS_OK; +} + +NS_METHOD nsGfxCheckboxControlFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus) +{ + if (nsEventStatus_eConsumeNoDefault == aEventStatus) { + return NS_OK; + } + + // Handle GFX rendered widget Mouse Down event + PRInt32 type; + GetType(&type); + switch (aEvent->message) { + case NS_MOUSE_LEFT_BUTTON_DOWN: + mMouseDownOnCheckbox = PR_TRUE; + //XXX: TODO render gray rectangle on mouse down + break; + + case NS_MOUSE_EXIT: + mMouseDownOnCheckbox = PR_FALSE; + //XXX: TO DO clear gray rectangle on mouse up + break; + + } + + return(Inherited::HandleEvent(aPresContext, aEvent, aEventStatus)); +} + + +PRBool nsGfxCheckboxControlFrame::GetCheckboxState() +{ + return mChecked; +} + +void nsGfxCheckboxControlFrame::SetCheckboxState(PRBool aValue) +{ + mChecked = aValue; + nsFormControlHelper::ForceDrawFrame(this); +} + diff --git a/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.h b/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.h new file mode 100644 index 00000000000..cfa94df4a87 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsGfxCheckboxControlFrame.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef nsGfxCheckboxControlFrame_h___ +#define nsGfxCheckboxControlFrame_h___ + +#include "nsCheckboxControlFrame.h" + + +class nsGfxCheckboxControlFrame : public nsCheckboxControlFrame { +private: + typedef nsCheckboxControlFrame Inherited; + +public: + nsGfxCheckboxControlFrame(); + + NS_IMETHOD GetFrameName(nsString& aResult) const { + return MakeFrameName("CheckboxControl", aResult); + } + + virtual void MouseClicked(nsIPresContext* aPresContext); + + // + // Methods used to GFX-render the checkbox + // + + virtual void PaintCheckBox(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + NS_IMETHOD Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + + //End of GFX-rendering methods + +protected: + virtual PRBool GetCheckboxState(); + virtual void SetCheckboxState(PRBool aValue); + + //GFX-rendered state variables + PRBool mMouseDownOnCheckbox; + PRBool mChecked; +}; + +#endif diff --git a/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.cpp b/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.cpp new file mode 100644 index 00000000000..e6436f38b90 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.cpp @@ -0,0 +1,168 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsGfxRadioControlFrame.h" +#include "nsIRadioButton.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLParts.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsWidgetsCID.h" +#include "nsIComponentManager.h" +#include "nsCOMPtr.h" +#include "nsCSSRendering.h" + + +nsresult +NS_NewGfxRadioControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsGfxRadioControlFrame* it = new nsGfxRadioControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsGfxRadioControlFrame::nsGfxRadioControlFrame() +{ + // Initialize GFX-rendered state + mChecked = PR_FALSE; + mRadioButtonFaceStyle = nsnull; +} + +nsGfxRadioControlFrame::~nsGfxRadioControlFrame() +{ + NS_IF_RELEASE(mRadioButtonFaceStyle); +} + +//-------------------------------------------------------------- + + +NS_IMETHODIMP +nsGfxRadioControlFrame::ReResolveStyleContext(nsIPresContext* aPresContext, + nsIStyleContext* aParentContext, + PRInt32 aParentChange, + nsStyleChangeList* aChangeList, + PRInt32* aLocalChange) +{ + // this re-resolves |mStyleContext|, so it may change + nsresult rv = Inherited::ReResolveStyleContext(aPresContext, aParentContext, aParentChange, + aChangeList, aLocalChange); + if (NS_FAILED(rv)) { + return rv; + } + + if (NS_COMFALSE != rv) { // frame style changed + if (aLocalChange) { + aParentChange = *aLocalChange; // tell children about or change + } + } + + // see if the outline has changed. + nsCOMPtr oldRadioButtonFaceStyle = mRadioButtonFaceStyle; + aPresContext->ProbePseudoStyleContextFor(mContent, nsHTMLAtoms::radioPseudo, mStyleContext, + PR_FALSE, + &mRadioButtonFaceStyle); + + if ((mRadioButtonFaceStyle && oldRadioButtonFaceStyle.get()) && (mRadioButtonFaceStyle != oldRadioButtonFaceStyle.get())) { + Inherited::CaptureStyleChangeFor(this, oldRadioButtonFaceStyle, mRadioButtonFaceStyle, + aParentChange, aChangeList, aLocalChange); + } + + return rv; +} + + +NS_IMETHODIMP +nsGfxRadioControlFrame::SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext) +{ + mRadioButtonFaceStyle = aRadioButtonFaceStyleContext; + NS_ADDREF(mRadioButtonFaceStyle); + return NS_OK; +} + +void +nsGfxRadioControlFrame::PaintRadioButton(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + + PRBool checked = PR_TRUE; + GetCurrentCheckState(&checked); // Get check state from the content model + if (PR_TRUE == checked) { + // Paint the button for the radio button using CSS background rendering code + if (nsnull != mRadioButtonFaceStyle) { + const nsStyleColor* myColor = (const nsStyleColor*) + mRadioButtonFaceStyle->GetStyleData(eStyleStruct_Color); + const nsStyleSpacing* mySpacing = (const nsStyleSpacing*) + mRadioButtonFaceStyle->GetStyleData(eStyleStruct_Spacing); + const nsStylePosition* myPosition = (const nsStylePosition*) + mRadioButtonFaceStyle->GetStyleData(eStyleStruct_Position); + + nscoord width = myPosition->mWidth.GetCoordValue(); + nscoord height = myPosition->mHeight.GetCoordValue(); + // Position the button centered within the radio control's rectangle. + nscoord x = (mRect.width - width) / 2; + nscoord y = (mRect.height - height) / 2; + nsRect rect(x, y, width, height); + + nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *myColor, *mySpacing, 0, 0); + nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, this, + aDirtyRect, rect, *mySpacing, mRadioButtonFaceStyle, 0); + } + } +} + +NS_METHOD +nsGfxRadioControlFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + const nsStyleDisplay* disp = (const nsStyleDisplay*) + mStyleContext->GetStyleData(eStyleStruct_Display); + if (!disp->mVisible) + return NS_OK; + + // Paint the background + Inherited::Paint(aPresContext, aRenderingContext, aDirtyRect, aWhichLayer); + + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + PaintRadioButton(aPresContext, aRenderingContext, aDirtyRect); + } + return NS_OK; +} + + +PRBool nsGfxRadioControlFrame::GetRadioState() +{ + return mChecked; +} + +void nsGfxRadioControlFrame::SetRadioState(PRBool aValue) +{ + mChecked = aValue; + nsFormControlHelper::ForceDrawFrame(this); +} diff --git a/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.h b/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.h new file mode 100644 index 00000000000..5c2ecf727d3 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsGfxRadioControlFrame.h @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsGfxRadioControlFrame_h___ +#define nsGfxRadioControlFrame_h___ + +#include "nsRadioControlFrame.h" + +// nsGfxRadioControlFrame + +class nsGfxRadioControlFrame : public nsRadioControlFrame +{ +private: + typedef nsRadioControlFrame Inherited; + +public: + nsGfxRadioControlFrame(); + ~nsGfxRadioControlFrame(); + + //nsIRadioControlFrame methods + NS_IMETHOD SetRadioButtonFaceStyleContext(nsIStyleContext *aRadioButtonFaceStyleContext); + + NS_IMETHOD ReResolveStyleContext(nsIPresContext* aPresContext, + nsIStyleContext* aParentContext, + PRInt32 aParentChange, + nsStyleChangeList* aChangeList, + PRInt32* aLocalChange); + + // + // XXX: The following paint methods are TEMPORARY. It is being used to get printing working + // under windows. Later it may be used to GFX-render the controls to the display. + // Expect this code to repackaged and moved to a new location in the future. + // + + NS_IMETHOD Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + virtual void PaintRadioButton(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + ///XXX: End o the temporary methods + +protected: + + virtual PRBool GetRadioState(); + virtual void SetRadioState(PRBool aValue); + + //GFX-rendered state variables + PRBool mChecked; + nsIStyleContext* mRadioButtonFaceStyle; + +private: + NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } + NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } +}; + + + +#endif + + diff --git a/mozilla/layout/html/forms/src/nsNativeButtonControlFrame.cpp b/mozilla/layout/html/forms/src/nsNativeButtonControlFrame.cpp new file mode 100644 index 00000000000..0cf7af90d66 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeButtonControlFrame.cpp @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsNativeButtonControlFrame.h" +#include "nsHTMLAtoms.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsIButton.h" + +static NS_DEFINE_IID(kIButtonIID, NS_IBUTTON_IID); + +nsresult +NS_NewNativeButtonControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsNativeButtonControlFrame* it = new nsNativeButtonControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + + +NS_IMETHODIMP +nsNativeButtonControlFrame::AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint) +{ + nsresult result = NS_OK; + if (mWidget) { + if (nsHTMLAtoms::value == aAttribute) { + nsIButton* button = nsnull; + result = mWidget->QueryInterface(kIButtonIID, (void**)&button); + if ((NS_SUCCEEDED(result)) && (nsnull != button)) { + nsString value; + /*XXXnsresult result = */GetValue(&value); + button->SetLabel(value); + NS_RELEASE(button); + nsFormFrame::StyleChangeReflow(aPresContext, this); + } + } else if (nsHTMLAtoms::size == aAttribute) { + nsFormFrame::StyleChangeReflow(aPresContext, this); + } + // Allow the base class to handle common attributes supported + // by all form elements... + else { + result = Inherited::AttributeChanged(aPresContext, aChild, aAttribute, aHint); + } + } + return result; +} + + +void +nsNativeButtonControlFrame::PostCreateWidget(nsIPresContext* aPresContext, nscoord& aWidth, nscoord& aHeight) +{ + nsIButton* button = nsnull; + if (mWidget && (NS_OK == mWidget->QueryInterface(kIButtonIID,(void**)&button))) { + nsFont font(aPresContext->GetDefaultFixedFontDeprecated()); + GetFont(aPresContext, font); + mWidget->SetFont(font); + SetColors(*aPresContext); + + nsAutoString value; + nsresult result = GetValue(&value); + + if (NS_CONTENT_ATTR_HAS_VALUE != result) { + GetDefaultLabel(value); + } + button->SetLabel(value); + NS_RELEASE(button); + + mWidget->Enable(!nsFormFrame::GetDisabled(this)); + } +} + diff --git a/mozilla/layout/html/forms/src/nsNativeButtonControlFrame.h b/mozilla/layout/html/forms/src/nsNativeButtonControlFrame.h new file mode 100644 index 00000000000..a479feaadcc --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeButtonControlFrame.h @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsNativeButtonControlFrame_h___ +#define nsNativeButtonControlFrame_h___ + +#include "nsNativeFormControlFrame.h" +#include "nsButtonControlFrame.h" +#include "nsButtonFrameRenderer.h" + +class nsNativeButtonControlFrame : public nsButtonControlFrame { +private: + typedef nsButtonControlFrame Inherited; + +public: + + NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint); + + virtual void PostCreateWidget(nsIPresContext* aPresContext, + nscoord& aWidth, + nscoord& aHeight); +}; + + +#endif + diff --git a/mozilla/layout/html/forms/src/nsNativeCheckboxControlFram.cpp b/mozilla/layout/html/forms/src/nsNativeCheckboxControlFram.cpp new file mode 100644 index 00000000000..0f8176c9d88 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeCheckboxControlFram.cpp @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsNativeCheckboxControlFram.h" +#include "nsICheckButton.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLParts.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsILookAndFeel.h" +#include "nsWidgetsCID.h" +#include "nsIComponentManager.h" + + +#define NS_DEFAULT_CHECKBOX_SIZE 12 + +static NS_DEFINE_IID(kICheckButtonIID, NS_ICHECKBUTTON_IID); +static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID); +static NS_DEFINE_IID(kILookAndFeelIID, NS_ILOOKANDFEEL_IID); + + +nsresult +NS_NewNativeCheckboxControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsNativeCheckboxControlFrame* it = new nsNativeCheckboxControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + + +nscoord +nsNativeCheckboxControlFrame::GetCheckboxSize(float aPixToTwip) const +{ + nsILookAndFeel * lookAndFeel; + PRInt32 checkboxSize = 0; + if (NS_OK == nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, kILookAndFeelIID, (void**)&lookAndFeel)) { + lookAndFeel->GetMetric(nsILookAndFeel::eMetric_CheckboxSize, checkboxSize); + NS_RELEASE(lookAndFeel); + } + if (checkboxSize == 0) + checkboxSize = NS_DEFAULT_CHECKBOX_SIZE; + return NSIntPixelsToTwips(checkboxSize, aPixToTwip); +} + +void +nsNativeCheckboxControlFrame::GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredLayoutSize, + nsSize& aDesiredWidgetSize) +{ + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + + aDesiredWidgetSize.width = GetCheckboxSize(p2t); + aDesiredWidgetSize.height = aDesiredWidgetSize.width; + aDesiredLayoutSize.width = aDesiredWidgetSize.width; + aDesiredLayoutSize.height = aDesiredWidgetSize.height; + aDesiredLayoutSize.ascent = aDesiredLayoutSize.height; + aDesiredLayoutSize.descent = 0; + if (aDesiredLayoutSize.maxElementSize) { + aDesiredLayoutSize.maxElementSize->width = aDesiredLayoutSize.width; + aDesiredLayoutSize.maxElementSize->height = aDesiredLayoutSize.height; + } +} + + +void +nsNativeCheckboxControlFrame::PostCreateWidget(nsIPresContext* aPresContext, nscoord& aWidth, nscoord& aHeight) +{ + Inherited::PostCreateWidget(aPresContext, aWidth, aHeight); + + if (mWidget != nsnull) { + SetColors(*aPresContext); + mWidget->Enable(!nsFormFrame::GetDisabled(this)); + } +} + +NS_IMETHODIMP +nsNativeCheckboxControlFrame::AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint) +{ + nsresult result = NS_OK; + if (mWidget) { + if (nsHTMLAtoms::checked == aAttribute) { + nsICheckButton* button = nsnull; + result = mWidget->QueryInterface(GetIID(), (void**)&button); + if ((NS_SUCCEEDED(result)) && (nsnull != button)) { + PRBool checkedAttr; + GetCurrentCheckState(&checkedAttr); + PRBool checkedPrevState; + button->GetState(checkedPrevState); + if (checkedAttr != checkedPrevState) { + button->SetState(checkedAttr); + } + NS_RELEASE(button); + } + } + // Allow the base class to handle common attributes supported + // by all form elements... + else { + result = Inherited::AttributeChanged(aPresContext, aChild, aAttribute, aHint); + } + } + return result; +} + +PRBool nsNativeCheckboxControlFrame::GetCheckboxState() +{ + PRBool state = PR_FALSE; + + nsICheckButton* checkBox = nsnull; + if (nsnull != mWidget) { + // native-widget + if (NS_SUCCEEDED(mWidget->QueryInterface(kICheckButtonIID,(void**)&checkBox))) { + checkBox->GetState(state); + NS_RELEASE(checkBox); + } + } + return state; +} + + +void nsNativeCheckboxControlFrame::SetCheckboxState(PRBool aValue) +{ + if (nsnull != mWidget) { + nsICheckButton* checkBox = nsnull; + if (NS_OK == mWidget->QueryInterface(kICheckButtonIID,(void**)&checkBox)) { + checkBox->SetState(aValue); + NS_RELEASE(checkBox); + } + } +} diff --git a/mozilla/layout/html/forms/src/nsNativeCheckboxControlFram.h b/mozilla/layout/html/forms/src/nsNativeCheckboxControlFram.h new file mode 100644 index 00000000000..5f417bc1ae3 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeCheckboxControlFram.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#ifndef nsNativeCheckboxControlFrame_h___ +#define nsNativeCheckboxControlFrame_h___ + +#include "nsCheckboxControlFrame.h" + + +class nsNativeCheckboxControlFrame : public nsCheckboxControlFrame { +private: + typedef nsCheckboxControlFrame Inherited; + +public: + virtual void PostCreateWidget(nsIPresContext* aPresContext, + nscoord& aWidth, + nscoord& aHeight); + + NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint); + +protected: + virtual PRBool GetCheckboxState(); + virtual void SetCheckboxState(PRBool aValue); + + virtual nscoord GetCheckboxSize(float aPixToTwip) const; + virtual void GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredLayoutSize, + nsSize& aDesiredWidgetSize); +}; + +#endif diff --git a/mozilla/layout/html/forms/src/nsNativeFormControlFrame.cpp b/mozilla/layout/html/forms/src/nsNativeFormControlFrame.cpp new file mode 100644 index 00000000000..0f910939b6d --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeFormControlFrame.cpp @@ -0,0 +1,330 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsCOMPtr.h" +#include "nsHTMLAtoms.h" +#include "nsWidgetsCID.h" +#include "nsViewsCID.h" +#include "nsIDeviceContext.h" +#include "nsIPresShell.h" +#include "nsIViewManager.h" +#include "nsIComponentManager.h" +#include "nsIFormControl.h" +#include "nsFormFrame.h" +#include "nsNativeFormControlFrame.h" + +static NS_DEFINE_IID(kIWidgetIID, NS_IWIDGET_IID); +static NS_DEFINE_IID(kViewCID, NS_VIEW_CID); +static NS_DEFINE_IID(kIViewIID, NS_IVIEW_IID); + + +nsNativeFormControlFrame::nsNativeFormControlFrame() + : Inherited() +{ + mLastMouseState = eMouseNone; + mWidget = nsnull; +} + +nsNativeFormControlFrame::~nsNativeFormControlFrame() +{ + NS_IF_RELEASE(mWidget); +} + + +NS_METHOD +nsNativeFormControlFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + if (mDidInit) { + return Inherited::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + } + + nsresult result = NS_OK; + + nsCOMPtr dx; + aPresContext.GetDeviceContext(getter_AddRefs(dx)); + PRBool requiresWidget = PR_TRUE; + + // Checkto see if the device context supports widgets at all + if (dx) { + dx->SupportsNativeWidgets(requiresWidget); + } + + nsWidgetRendering mode; + aPresContext.GetWidgetRenderingMode(&mode); + if ((eWidgetRendering_Gfx == mode) || (eWidgetRendering_PartialGfx == mode)) { + // Check with the frame to see if requires a widget to render + if (PR_TRUE == requiresWidget) { + RequiresWidget(requiresWidget); + } + } + + if (! requiresWidget) { + return Inherited::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + } + + // add ourself as an nsIFormControlFrame + if (!mFormFrame && (eReflowReason_Initial == aReflowState.reason)) { + nsFormFrame::AddFormControlFrame(aPresContext, *this); + } + + GetDesiredSize(&aPresContext, aReflowState, aDesiredSize, mWidgetSize); + + { + nsCOMPtr presShell; + aPresContext.GetShell(getter_AddRefs(presShell)); + nsCOMPtr viewMan; + presShell->GetViewManager(getter_AddRefs(viewMan)); + nsRect boundBox(0, 0, aDesiredSize.width, aDesiredSize.height); + + // absolutely positioned controls already have a view but not a widget + nsIView* view = nsnull; + GetView(&view); + if (nsnull == view) { + result = nsComponentManager::CreateInstance(kViewCID, nsnull, kIViewIID, (void **)&view); + if (!NS_SUCCEEDED(result)) { + NS_ASSERTION(0, "Could not create view for form control"); + aStatus = NS_FRAME_NOT_COMPLETE; + return result; + } + + nsIFrame* parWithView; + nsIView *parView; + + GetParentWithView(&parWithView); + parWithView->GetView(&parView); + + // initialize the view as hidden since we don't know the (x,y) until Paint + result = view->Init(viewMan, boundBox, parView, nsnull, nsViewVisibility_kHide); + if (NS_OK != result) { + NS_ASSERTION(0, "view initialization failed"); + aStatus = NS_FRAME_NOT_COMPLETE; + return NS_OK; + } + + viewMan->InsertChild(parView, view, 0); + SetView(view); + } + + PRInt32 type; + GetType(&type); + const nsIID& id = GetCID(); + + if ((NS_FORM_INPUT_HIDDEN != type) && (PR_TRUE == requiresWidget)) { + // Do the following only if a widget is created + nsWidgetInitData* initData = GetWidgetInitData(aPresContext); // needs to be deleted + view->CreateWidget(id, initData); + + if (nsnull != initData) { + delete(initData); + } + + // set our widget + result = GetWidget(view, &mWidget); + if ((PR_FALSE == NS_SUCCEEDED(result)) || (nsnull == mWidget)) { // keep the ref on mWidget + NS_ASSERTION(0, "could not get widget"); + } + } + + PostCreateWidget(&aPresContext, aDesiredSize.width, aDesiredSize.height); + mDidInit = PR_TRUE; + + if ((aDesiredSize.width != boundBox.width) || (aDesiredSize.height != boundBox.height)) { + viewMan->ResizeView(view, aDesiredSize.width, aDesiredSize.height); + } + } + + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; + + if (nsnull != aDesiredSize.maxElementSize) { + //XXX aDesiredSize.AddBorderPaddingToMaxElementSize(borderPadding); + } + + aStatus = NS_FRAME_COMPLETE; + return NS_OK; +} + + +NS_IMETHODIMP +nsNativeFormControlFrame::AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint) +{ + if (mWidget) { + if (nsHTMLAtoms::disabled == aAttribute) { + mWidget->Enable(!nsFormFrame::GetDisabled(this)); + } + } + return NS_OK; +} + + +void +nsNativeFormControlFrame::SetColors(nsIPresContext& aPresContext) +{ + if (mWidget) { + nsCompatibility mode; + aPresContext.GetCompatibilityMode(&mode); + const nsStyleColor* color = + (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color); + if (nsnull != color) { + if (!(NS_STYLE_BG_COLOR_TRANSPARENT & color->mBackgroundFlags)) { + mWidget->SetBackgroundColor(color->mBackgroundColor); +#ifdef bug_1021_closed + } else if (eCompatibility_NavQuirks == mode) { +#else + } else { +#endif + mWidget->SetBackgroundColor(NS_RGB(0xFF, 0xFF, 0xFF)); + } + mWidget->SetForegroundColor(color->mColor); + } + } +} + + +// native widgets don't need to repaint +void +nsNativeFormControlFrame::SetFocus(PRBool aOn, PRBool aRepaint) +{ + if (mWidget) { + if (aOn) { + mWidget->SetFocus(); + } + else { + //Unsetting of focus on native widget is accomplised + //by pushing focus up to its parent + nsIWidget *parentWidget = mWidget->GetParent(); + if (parentWidget) { + parentWidget->SetFocus(); + NS_RELEASE(parentWidget); + } + } + } +} + +nsresult +nsNativeFormControlFrame::GetWidget(nsIWidget** aWidget) +{ + if (mWidget) { + NS_ADDREF(mWidget); + *aWidget = mWidget; + mWidget->Enable(!nsFormFrame::GetDisabled(this)); + return NS_OK; + } else { + *aWidget = nsnull; + return NS_FORM_NOTOK; + } +} + +nsresult +nsNativeFormControlFrame::GetWidget(nsIView* aView, nsIWidget** aWidget) +{ + nsIWidget* widget; + aView->GetWidget(widget); + nsresult result; + + if (nsnull == widget) { + *aWidget = nsnull; + result = NS_ERROR_FAILURE; + + } else { + result = widget->QueryInterface(kIWidgetIID, (void**)aWidget); // keep the ref + if (NS_FAILED(result)) { + NS_ASSERTION(0, "The widget interface is invalid"); // need to print out more details of the widget + } + NS_RELEASE(widget); + } + + return result; +} + + +NS_METHOD nsNativeFormControlFrame::HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus) +{ + if (nsnull == mWidget) { + return Inherited::HandleEvent(aPresContext, aEvent, aEventStatus); + } + + if (nsEventStatus_eConsumeNoDefault == aEventStatus) { + return NS_OK; + } + + // make sure that the widget in the event is this input + // XXX if there is no view, it could be an image button. Unfortunately, + // every image button will get every event. + nsIView* view; + GetView(&view); + if (view) { + if (mWidget != aEvent->widget) { + aEventStatus = nsEventStatus_eIgnore; + return NS_OK; + } + } + + // if not native then use the NS_MOUSE_LEFT_CLICK to see if pressed + // unfortunately native widgets don't seem to handle this right. + // so use the old code for native stuff. -EDV + + //printf(" %d %d %d %d (%d,%d) \n", this, aEvent->widget, aEvent->widgetSupports, + // aEvent->message, aEvent->point.x, aEvent->point.y); + + PRInt32 type; + GetType(&type); + switch (aEvent->message) { + case NS_MOUSE_ENTER: + mLastMouseState = eMouseEnter; + break; + + case NS_MOUSE_LEFT_BUTTON_DOWN: + if (NS_FORM_INPUT_IMAGE == type) { + mLastMouseState = eMouseDown; + } else { + mLastMouseState = (eMouseEnter == mLastMouseState) ? eMouseDown : eMouseNone; + } + break; + + case NS_MOUSE_LEFT_BUTTON_UP: + if (eMouseDown == mLastMouseState) { + MouseClicked(&aPresContext); + } + mLastMouseState = eMouseEnter; + break; + + case NS_MOUSE_EXIT: + mLastMouseState = eMouseNone; + break; + + case NS_CONTROL_CHANGE: + ControlChanged(&aPresContext); + break; + + case NS_KEY_DOWN: + return Inherited::HandleEvent(aPresContext, aEvent, aEventStatus); + } + + aEventStatus = nsEventStatus_eConsumeDoDefault; + return NS_OK; +} + diff --git a/mozilla/layout/html/forms/src/nsNativeFormControlFrame.h b/mozilla/layout/html/forms/src/nsNativeFormControlFrame.h new file mode 100644 index 00000000000..8b75cbe7998 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeFormControlFrame.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsNativeFormControlFrame_h___ +#define nsNativeFormControlFrame_h___ + +#include "nsFormControlFrame.h" + + +/** + * nsFormControlFrame is the base class 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 + */ +class nsNativeFormControlFrame : public nsFormControlFrame +{ +private: + typedef nsFormControlFrame Inherited; + +public: + nsNativeFormControlFrame(); + + + /** + * Respond to the request to resize and/or reflow + * @see nsIFrame::Reflow + */ + NS_IMETHOD Reflow(nsIPresContext& aCX, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + + NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint); + /** + * Respond to a gui event + * @see nsIFrame::HandleEvent + */ + NS_IMETHOD HandleEvent(nsIPresContext& aPresContext, + nsGUIEvent* aEvent, + nsEventStatus& aEventStatus); + + /** + * Get the widget associated with this frame + * @param aView the view associated with the frame. It is a convience parm. + * @param aWidget the address of address of where the widget will be placed. + * This method doses an AddRef on the widget. + */ + nsresult GetWidget(nsIView* aView, nsIWidget** aWidget); + nsresult GetWidget(nsIWidget** aWidget); + + PRBool HasNativeWidget() { return (nsnull != mWidget);} + + + + virtual void SetFocus(PRBool aOn = PR_TRUE, PRBool aRepaint = PR_FALSE); + + void SetColors(nsIPresContext& aPresContext); + +protected: + + virtual ~nsNativeFormControlFrame(); + + nsMouseState mLastMouseState; + nsIWidget* mWidget; + +}; + +#endif + diff --git a/mozilla/layout/html/forms/src/nsNativeRadioControlFrame.cpp b/mozilla/layout/html/forms/src/nsNativeRadioControlFrame.cpp new file mode 100644 index 00000000000..cb1ac169bb8 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeRadioControlFrame.cpp @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsNativeRadioControlFrame.h" +#include "nsIRadioButton.h" +#include "nsHTMLAtoms.h" +#include "nsHTMLParts.h" +#include "nsFormFrame.h" +#include "nsIFormControl.h" +#include "nsIContent.h" +#include "nsILookAndFeel.h" +#include "nsWidgetsCID.h" +#include "nsIComponentManager.h" +#include "nsStyleUtil.h" + + +static NS_DEFINE_IID(kIRadioIID, NS_IRADIOBUTTON_IID); +static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID); +static NS_DEFINE_IID(kILookAndFeelIID, NS_ILOOKANDFEEL_IID); + +#define NS_DEFAULT_RADIOBOX_SIZE 12 + +nsresult +NS_NewNativeRadioControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsNativeRadioControlFrame* it = new nsNativeRadioControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +//-------------------------------------------------------------- + + +nscoord +nsNativeRadioControlFrame::GetRadioboxSize(float aPixToTwip) const +{ + nsILookAndFeel * lookAndFeel; + PRInt32 radioboxSize = 0; + if (NS_OK == nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, kILookAndFeelIID, (void**)&lookAndFeel)) { + lookAndFeel->GetMetric(nsILookAndFeel::eMetric_RadioboxSize, radioboxSize); + NS_RELEASE(lookAndFeel); + } + if (radioboxSize == 0) + radioboxSize = NS_DEFAULT_RADIOBOX_SIZE; + return NSIntPixelsToTwips(radioboxSize, aPixToTwip); +} + +void +nsNativeRadioControlFrame::GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredLayoutSize, + nsSize& aDesiredWidgetSize) +{ + + nsWidgetRendering mode; + aPresContext->GetWidgetRenderingMode(&mode); + if ((eWidgetRendering_Gfx == mode) || (eWidgetRendering_PartialGfx == mode)) { + Inherited::GetDesiredSize(aPresContext,aReflowState,aDesiredLayoutSize, + aDesiredWidgetSize); + } else { + float p2t; + aPresContext->GetScaledPixelsToTwips(&p2t); + aDesiredWidgetSize.width = GetRadioboxSize(p2t); + aDesiredWidgetSize.height = aDesiredWidgetSize.width; + + aDesiredLayoutSize.width = aDesiredWidgetSize.width; + aDesiredLayoutSize.height = aDesiredWidgetSize.height; + aDesiredLayoutSize.ascent = aDesiredLayoutSize.height; + aDesiredLayoutSize.descent = 0; + if (aDesiredLayoutSize.maxElementSize) { + aDesiredLayoutSize.maxElementSize->width = aDesiredLayoutSize.width; + aDesiredLayoutSize.maxElementSize->height = aDesiredLayoutSize.height; + } + } +} + +void +nsNativeRadioControlFrame::PostCreateWidget(nsIPresContext* aPresContext, nscoord& aWidth, nscoord& aHeight) +{ + Inherited::PostCreateWidget(aPresContext, aWidth, aHeight); + + if (mWidget != nsnull) { + const nsStyleColor* color = + nsStyleUtil::FindNonTransparentBackground(mStyleContext); + + if (nsnull != color) { + mWidget->SetBackgroundColor(color->mBackgroundColor); + } else { + mWidget->SetBackgroundColor(NS_RGB(0xFF, 0xFF, 0xFF)); + } + mWidget->Enable(!nsFormFrame::GetDisabled(this)); + } + +} + + +NS_IMETHODIMP +nsNativeRadioControlFrame::AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint) +{ + nsresult result = NS_OK; + if (mWidget) { + if (nsHTMLAtoms::checked == aAttribute) { + nsIRadioButton* button = nsnull; + result = mWidget->QueryInterface(kIRadioIID, (void**)&button); + if ((NS_SUCCEEDED(result)) && (nsnull != button)) { + PRBool checkedAttr = PR_TRUE; + GetCurrentCheckState(&checkedAttr); + PRBool checkedPrevState = PR_TRUE; + button->GetState(checkedPrevState); + if (checkedAttr != checkedPrevState) { + button->SetState(checkedAttr); + mFormFrame->OnRadioChecked(*this, checkedAttr); + } + NS_RELEASE(button); + } + } + // Allow the base class to handle common attributes supported + // by all form elements... + else { + result = Inherited::AttributeChanged(aPresContext, aChild, aAttribute, aHint); + } + } + return result; +} + +PRBool nsNativeRadioControlFrame::GetRadioState() +{ + PRBool state = PR_FALSE; + + if (nsnull != mWidget) { + nsIRadioButton* radio = nsnull; + if (NS_SUCCEEDED(mWidget->QueryInterface(kIRadioIID,(void**)&radio))) { + radio->GetState(state); + NS_RELEASE(radio); + } + } + return state; +} + + +void nsNativeRadioControlFrame::SetRadioState(PRBool aValue) +{ + if (nsnull != mWidget) { + nsIRadioButton* radio = nsnull; + if (NS_OK == mWidget->QueryInterface(kIRadioIID,(void**)&radio)) { + radio->SetState(aValue); + NS_RELEASE(radio); + } + } +} diff --git a/mozilla/layout/html/forms/src/nsNativeRadioControlFrame.h b/mozilla/layout/html/forms/src/nsNativeRadioControlFrame.h new file mode 100644 index 00000000000..5aa4c58820f --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeRadioControlFrame.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsNativeRadioControlFrame_h___ +#define nsNativeRadioControlFrame_h___ + +#include "nsIRadioControlFrame.h" +#include "nsRadioControlFrame.h" +#include "nsVoidArray.h" +#include "nsString.h" +class nsIAtom; + +// nsNativeRadioControlFrame + +class nsNativeRadioControlFrame : public nsRadioControlFrame +{ +private: + typedef nsRadioControlFrame Inherited; + +public: + + + virtual void PostCreateWidget(nsIPresContext* aPresContext, + nscoord& aWidth, + nscoord& aHeight); + + NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint); + + +protected: + virtual PRBool GetRadioState(); + virtual void SetRadioState(PRBool aValue); + + virtual nscoord GetRadioboxSize(float aPixToTwip) const; + virtual void GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredLayoutSize, + nsSize& aDesiredWidgetSize); + +private: + NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; } + NS_IMETHOD_(nsrefcnt) Release() { return NS_OK; } +}; + + +#endif + + diff --git a/mozilla/layout/html/forms/src/nsNativeSelectControlFrame.cpp b/mozilla/layout/html/forms/src/nsNativeSelectControlFrame.cpp new file mode 100644 index 00000000000..6951722f484 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsNativeSelectControlFrame.cpp @@ -0,0 +1,1421 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +// YY need to pass isMultiple before create called +#include "nsCOMPtr.h" +#include "nsNativeFormControlFrame.h" +#include "nsFormFrame.h" +#include "nsIDOMNode.h" +#include "nsIDOMHTMLSelectElement.h" +#include "nsIDOMHTMLOptionElement.h" +#include "nsIDOMHTMLCollection.h" +#include "nsDOMEvent.h" +#include "nsIContent.h" +#include "prtypes.h" +#include "nsIFrame.h" +#include "nsISupports.h" +#include "nsIAtom.h" +#include "nsIPresContext.h" +#include "nsIHTMLContent.h" +#include "nsHTMLIIDs.h" +#include "nsIRadioButton.h" +#include "nsWidgetsCID.h" +#include "nsSize.h" +#include "nsHTMLAtoms.h" +#include "nsIView.h" +#include "nsIListWidget.h" +#include "nsIComboBox.h" +#include "nsIListBox.h" +#include "nsIStyleContext.h" +#include "nsStyleConsts.h" +#include "nsStyleUtil.h" +#include "nsFont.h" +#include "nsIDeviceContext.h" +#include "nsIFontMetrics.h" +#include "nsILookAndFeel.h" +#include "nsIComponentManager.h" + +static NS_DEFINE_IID(kIDOMHTMLSelectElementIID, NS_IDOMHTMLSELECTELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLOptionElementIID, NS_IDOMHTMLOPTIONELEMENT_IID); +static NS_DEFINE_IID(kIDOMHTMLCollectionIID, NS_IDOMHTMLCOLLECTION_IID); +static NS_DEFINE_IID(kIDOMNodeIID, NS_IDOMNODE_IID); +static NS_DEFINE_IID(kListWidgetIID, NS_ILISTWIDGET_IID); +static NS_DEFINE_IID(kComboBoxIID, NS_ICOMBOBOX_IID); +static NS_DEFINE_IID(kListBoxIID, NS_ILISTBOX_IID); +static NS_DEFINE_IID(kComboCID, NS_COMBOBOX_CID); +static NS_DEFINE_IID(kListCID, NS_LISTBOX_CID); +static NS_DEFINE_IID(kLookAndFeelCID, NS_LOOKANDFEEL_CID); +static NS_DEFINE_IID(kILookAndFeelIID, NS_ILOOKANDFEEL_IID); + + +class nsOption; + +class nsNativeSelectControlFrame : public nsNativeFormControlFrame { +private: + typedef nsNativeFormControlFrame Inherited; + +public: + nsNativeSelectControlFrame(); + + NS_IMETHOD GetFrameName(nsString& aResult) const { + return MakeFrameName("SelectControl", aResult); + } + + virtual nsWidgetInitData* GetWidgetInitData(nsIPresContext& aPresContext); + + virtual void PostCreateWidget(nsIPresContext* aPresContext, + nscoord& aWidth, + nscoord& aHeight); + + virtual const nsIID& GetCID(); + + virtual const nsIID& GetIID(); + + 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, + float aPixToTwip, + nscoord aInnerWidth, + nscoord aCharWidth) const; + virtual PRInt32 GetMaxNumValues(); + + virtual PRBool GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues, nsString* aNames); + + NS_METHOD GetMultiple(PRBool* aResult, nsIDOMHTMLSelectElement* aSelect = nsnull); + virtual void Reset(); + + // + // XXX: The following paint methods are TEMPORARY. It is being used to get printing working + // under windows. Later it may be used to GFX-render the controls to the display. + // Expect this code to repackaged and moved to a new location in the future. + // + NS_IMETHOD Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer); + + virtual void PaintOption(PRBool aPaintSelected, nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, nsString aText, nscoord aX, nscoord aY, + const nsRect& aInside, nscoord aTextHeight); + + virtual void PaintSelectControl(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect); + + ///XXX: End o the temporary methods + + virtual void MouseClicked(nsIPresContext* aPresContext); + virtual void ControlChanged(nsIPresContext* aPresContext); + + // nsIFormControLFrame + NS_IMETHOD SetProperty(nsIAtom* aName, const nsString& aValue); + NS_IMETHOD GetProperty(nsIAtom* aName, nsString& aValue); + + NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint); +protected: + PRUint32 mNumRows; + + nsIDOMHTMLSelectElement* GetSelect(); + nsIDOMHTMLCollection* GetOptions(nsIDOMHTMLSelectElement* aSelect = nsnull); + nsIDOMHTMLOptionElement* GetOption(nsIDOMHTMLCollection& aOptions, PRUint32 aIndex); + PRBool GetOptionValue(nsIDOMHTMLCollection& aCollecton, PRUint32 aIndex, nsString& aValue); + PRUint32 GetSelectedIndex(); + + virtual void GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredLayoutSize, + nsSize& aDesiredWidgetSize); + + void GetWidgetSize(nsIPresContext& aPresContext, nscoord& aWidth, nscoord& aHeight); + + PRBool mIsComboBox; + PRBool mOptionsAdded; + + // Store the state of the options in a local array whether the widget is + // GFX-rendered or not. This is used to detect changes in MouseClicked + PRUint32 mNumOptions; + PRBool* mOptionSelected; + + // Accessor methods for mOptionsSelected and mNumOptions + void GetOptionSelected(PRUint32 index, PRBool* aValue); + void SetOptionSelected(PRUint32 index, PRBool aValue); + void GetOptionSelectedFromWidget(PRInt32 index, PRBool* aValue); + + // Free our locally cached option array + ~nsNativeSelectControlFrame(); +}; + +nsresult +NS_NewNativeSelectControlFrame(nsIFrame** aNewFrame) +{ + NS_PRECONDITION(aNewFrame, "null OUT ptr"); + if (nsnull == aNewFrame) { + return NS_ERROR_NULL_POINTER; + } + nsNativeSelectControlFrame* it = new nsNativeSelectControlFrame; + if (!it) { + return NS_ERROR_OUT_OF_MEMORY; + } + *aNewFrame = it; + return NS_OK; +} + +nsNativeSelectControlFrame::nsNativeSelectControlFrame() + : nsNativeFormControlFrame() +{ + mIsComboBox = PR_FALSE; + mOptionsAdded = PR_FALSE; + mNumRows = 0; + mNumOptions = 0; + mOptionSelected = nsnull; +} + +// XXX is this the right way to clean up? +nsNativeSelectControlFrame::~nsNativeSelectControlFrame() +{ + if (mOptionSelected) + delete[] mOptionSelected; +} + +nscoord +nsNativeSelectControlFrame::GetVerticalBorderWidth(float aPixToTwip) const +{ + return NSIntPixelsToTwips(1, aPixToTwip); +} + +nscoord +nsNativeSelectControlFrame::GetHorizontalBorderWidth(float aPixToTwip) const +{ + return GetVerticalBorderWidth(aPixToTwip); +} + +nscoord +nsNativeSelectControlFrame::GetVerticalInsidePadding(float aPixToTwip, + nscoord aInnerHeight) const +{ + // XXX NOTE: the enums eMetric_ListVerticalInsidePadding and eMetric_ListShouldUseVerticalInsidePadding + // are ONLY needed because GTK is not using the "float" padding values and wants to only use an + // integer value for the padding instead of calculating like the other platforms. + // + // If GTK decides to start calculating the value, PLEASE remove these two enum from nsILookAndFeel and + // all the platforms nsLookAndFeel impementations so we don't have these extra values remaining in the code. + // The two enums are: + // eMetric_ListVerticalInsidePadding + // eMetric_ListShouldUseVerticalInsidePadding + // + float pad; + PRInt32 padInside; + PRInt32 shouldUsePadInside; + nsILookAndFeel * lookAndFeel; + if (NS_OK == nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, kILookAndFeelIID, (void**)&lookAndFeel)) { + lookAndFeel->GetMetric(nsILookAndFeel::eMetricFloat_ListVerticalInsidePadding, pad); + // These two (below) are really only needed for GTK + lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ListVerticalInsidePadding, padInside); + lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ListShouldUseVerticalInsidePadding, shouldUsePadInside); + NS_RELEASE(lookAndFeel); + } + + if (1 == shouldUsePadInside) { + return NSIntPixelsToTwips(padInside, aPixToTwip); // XXX this is probably wrong (GTK) + } else { + return (nscoord)NSToIntRound(float(aInnerHeight) * pad); + } +} + +PRInt32 +nsNativeSelectControlFrame::GetHorizontalInsidePadding(nsIPresContext& aPresContext, + float aPixToTwip, + nscoord aInnerWidth, + nscoord aCharWidth) const +{ + // XXX NOTE: the enum eMetric_ListShouldUseHorizontalInsideMinimumPadding + // is ONLY needed because GTK is not using the "float" padding values and wants to only use the + // "minimum" integer value for the padding instead of calculating and comparing like the other platforms. + // + // If GTK decides to start calculating and comparing the values, + // PLEASE remove these the enum from nsILookAndFeel and + // all the platforms nsLookAndFeel impementations so we don't have these extra values remaining in the code. + // The enum is: + // eMetric_ListShouldUseHorizontalInsideMinimumPadding + // + float pad; + PRInt32 padMin; + PRInt32 shouldUsePadMin; + nsILookAndFeel * lookAndFeel; + if (NS_OK == nsComponentManager::CreateInstance(kLookAndFeelCID, nsnull, kILookAndFeelIID, (void**)&lookAndFeel)) { + lookAndFeel->GetMetric(nsILookAndFeel::eMetricFloat_ListHorizontalInsidePadding, pad); + lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ListHorizontalInsideMinimumPadding, padMin); + // This one (below) is really only needed for GTK + lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ListShouldUseHorizontalInsideMinimumPadding, shouldUsePadMin); + NS_RELEASE(lookAndFeel); + } + + if (1 == shouldUsePadMin) { + return NSIntPixelsToTwips(padMin, aPixToTwip); // XXX this is probably wrong (GTK) + } else { + nscoord padding = (nscoord)NSToIntRound(float(aCharWidth) * pad); + nscoord min = NSIntPixelsToTwips(padMin, aPixToTwip); + if (padding > min) { + return padding; + } else { + return min; + } + } +} + +const nsIID& +nsNativeSelectControlFrame::GetIID() +{ + if (mIsComboBox) { + return kComboBoxIID; + } else { + return kListBoxIID; + } +} + +const nsIID& +nsNativeSelectControlFrame::GetCID() +{ + if (mIsComboBox) { + return kComboCID; + } else { + return kListCID; + } +} + +void +nsNativeSelectControlFrame::GetDesiredSize(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsHTMLReflowMetrics& aDesiredLayoutSize, + nsSize& aDesiredWidgetSize) +{ + nsIDOMHTMLCollection* options = GetOptions(); + if (!options) + return; + + // get the css size + nsSize styleSize; + 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) { + //option->CompressContent(); + 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); + + // here it is determined whether we are a combo box + PRInt32 sizeAttr; + GetSizeFromContent(&sizeAttr); + PRBool multiple; + if (!GetMultiple(&multiple) && + ((1 >= sizeAttr) || ((ATTR_NOTSET == sizeAttr) && (1 >= mNumRows)))) { + mIsComboBox = PR_TRUE; + } + + float sp2t; + float p2t; + aPresContext->GetPixelsToTwips(&p2t); + aPresContext->GetScaledPixelsToTwips(&sp2t); + + nscoord scrollbarWidth = 0; + nscoord scrollbarHeight = 0; + float scale; + nsCOMPtr dx; + aPresContext->GetDeviceContext(getter_AddRefs(dx)); + if (dx) { + float sbWidth; + float sbHeight; + dx->GetCanonicalPixelScale(scale); + dx->GetScrollBarDimensions(sbWidth, sbHeight); + scrollbarWidth = PRInt32(sbWidth * scale); + scrollbarHeight = PRInt32(sbHeight * scale); + } else { + scrollbarWidth = GetScrollbarWidth(sp2t); + scrollbarHeight = scrollbarWidth; + } + + aDesiredLayoutSize.width = desiredSize.width; + PRBool needScrollbar; +#ifdef XP_MAC + needScrollbar = PR_TRUE; + scrollbarWidth = (mIsComboBox) + ? NSIntPixelsToTwips(25, p2t*scale) + : (scrollbarWidth + NSIntPixelsToTwips(2, p2t*scale)); +#else + needScrollbar = ((mNumRows < numOptions) || mIsComboBox); +#endif + // account for vertical scrollbar, if present + if (!widthExplicit && needScrollbar) { + aDesiredLayoutSize.width += scrollbarWidth; + } + if (aDesiredLayoutSize.maxElementSize) { + aDesiredLayoutSize.maxElementSize->width = minSize.width; + if (!widthExplicit && needScrollbar) { + aDesiredLayoutSize.maxElementSize->width += scrollbarWidth; + } + } + + // XXX put this in widget library, combo boxes are fixed height (visible part) + aDesiredLayoutSize.height = (mIsComboBox) + ? rowHeight + (2 * GetVerticalInsidePadding(p2t, rowHeight)) + : desiredSize.height; + if (aDesiredLayoutSize.maxElementSize) { + aDesiredLayoutSize.maxElementSize->height = (mIsComboBox) + ? rowHeight + (2 * GetVerticalInsidePadding(p2t, rowHeight)) + : minSize.height; + } + + aDesiredLayoutSize.ascent = aDesiredLayoutSize.height; + aDesiredLayoutSize.descent = 0; + + aDesiredWidgetSize.width = aDesiredLayoutSize.width; + aDesiredWidgetSize.height = aDesiredLayoutSize.height; + if (mIsComboBox) { // add in pull down size + PRInt32 extra = NSIntPixelsToTwips(10, p2t*scale); + aDesiredWidgetSize.height += (rowHeight * (numOptions > 20 ? 20 : numOptions)) + extra; + } + + // override the width and height for a combo box that has already got a widget + if (mWidget && mIsComboBox) { + nscoord ignore; + GetWidgetSize(*aPresContext, ignore, aDesiredLayoutSize.height); + aDesiredLayoutSize.ascent = aDesiredLayoutSize.height; + if (aDesiredLayoutSize.maxElementSize) { + aDesiredLayoutSize.maxElementSize->height = aDesiredLayoutSize.height; + } + } + + NS_RELEASE(options); +} + +nsWidgetInitData* +nsNativeSelectControlFrame::GetWidgetInitData(nsIPresContext& aPresContext) +{ + if (mIsComboBox) { + nsComboBoxInitData* initData = new nsComboBoxInitData(); + if (initData) { + initData->clipChildren = PR_TRUE; + float twipToPix; + aPresContext.GetTwipsToPixels(&twipToPix); + initData->mDropDownHeight = NSTwipsToIntPixels(mWidgetSize.height, twipToPix); + } + return initData; + } else { + PRBool multiple; + GetMultiple(&multiple); + nsListBoxInitData* initData = nsnull; + if (multiple) { + initData = new nsListBoxInitData(); + if (initData) { + initData->clipChildren = PR_TRUE; + initData->mMultiSelect = PR_TRUE; + } + } + return initData; + } +} + +NS_IMETHODIMP +nsNativeSelectControlFrame::GetMultiple(PRBool* aMultiple, nsIDOMHTMLSelectElement* aSelect) +{ + if (!aSelect) { + nsIDOMHTMLSelectElement* thisSelect = nsnull; + nsresult result = mContent->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&thisSelect); + if ((NS_OK == result) && thisSelect) { + result = thisSelect->GetMultiple(aMultiple); + NS_RELEASE(thisSelect); + } + return result; + } else { + return aSelect->GetMultiple(aMultiple); + } +} + +nsIDOMHTMLSelectElement* +nsNativeSelectControlFrame::GetSelect() +{ + nsIDOMHTMLSelectElement* thisSelect = nsnull; + nsresult result = mContent->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&thisSelect); + if ((NS_OK == result) && thisSelect) { + return thisSelect; + } else { + return nsnull; + } +} + +PRUint32 +nsNativeSelectControlFrame::GetSelectedIndex() +{ + PRInt32 indx = -1; // No selection + nsIDOMHTMLSelectElement* thisSelect = nsnull; + if (NS_SUCCEEDED(mContent->QueryInterface(kIDOMHTMLSelectElementIID, (void**)&thisSelect))) { + thisSelect->GetSelectedIndex(&indx); + NS_RELEASE(thisSelect); + } + return(indx); +} + + +nsIDOMHTMLCollection* +nsNativeSelectControlFrame::GetOptions(nsIDOMHTMLSelectElement* aSelect) +{ + nsIDOMHTMLCollection* options = nsnull; + if (!aSelect) { + nsIDOMHTMLSelectElement* thisSelect = GetSelect(); + if (thisSelect) { + thisSelect->GetOptions(&options); + NS_RELEASE(thisSelect); + return options; + } else { + return nsnull; + } + } else { + aSelect->GetOptions(&options); + return options; + } +} + +void +nsNativeSelectControlFrame::GetWidgetSize(nsIPresContext& aPresContext, nscoord& aWidth, nscoord& aHeight) +{ + nsRect bounds; + mWidget->GetBounds(bounds); + float p2t; + aPresContext.GetPixelsToTwips(&p2t); + aWidth = NSIntPixelsToTwips(bounds.width, p2t); + aHeight = NSTwipsToIntPixels(bounds.height, p2t); +} + +void +nsNativeSelectControlFrame::PostCreateWidget(nsIPresContext* aPresContext, + nscoord& aWidth, + nscoord& aHeight) +{ + if (!mWidget) { + return; + } + + nsIListWidget* listWidget; + if (NS_OK != mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget)) { + NS_ASSERTION(PR_FALSE, "invalid widget"); + return; + } + + mWidget->Enable(!nsFormFrame::GetDisabled(this)); + nsFont font(aPresContext->GetDefaultFixedFontDeprecated()); + GetFont(aPresContext, font); + mWidget->SetFont(font); + SetColors(*aPresContext); + + // add the options + if (!mOptionsAdded) { + nsIDOMHTMLCollection* options = GetOptions(); + if (options) { + PRUint32 numOptions; + options->GetLength(&numOptions); + nsIDOMNode* node; + nsIDOMHTMLOptionElement* option; + + // Initialize the locally cached numOptions and optionSelected array. + // The values of the optionsSelected array are filled in by Reset() + mNumOptions = numOptions; + if ((numOptions > 0) && (mOptionSelected == nsnull)) { + mOptionSelected = new PRBool[numOptions]; + } + + for (PRUint32 i = 0; i < numOptions; i++) { + options->Item(i, &node); + if (node) { + nsresult result = node->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); + if ((NS_OK == result) && option) { + nsString text; + // XXX need to compress whitespace + if (NS_CONTENT_ATTR_HAS_VALUE != option->GetText(text)) { + text = " "; + } + listWidget->AddItemAt(text, i); + NS_RELEASE(option); + } + NS_RELEASE(node); + } + } + NS_RELEASE(options); + } + mOptionsAdded = PR_TRUE; + } + + NS_RELEASE(listWidget); + + // get the size of the combo box and let Reflow change its desired size + // XXX this technique should be considered for other widgets as well + if (mIsComboBox) { + nscoord ignore; + nscoord height; + GetWidgetSize(*aPresContext, ignore, height); + if (height > aHeight) { + aHeight = height; + } + } + + Reset(); // initializes selections +} + + +PRInt32 +nsNativeSelectControlFrame::GetMaxNumValues() +{ + PRBool multiple; + GetMultiple(&multiple); + if (multiple) { + PRUint32 length = 0; + nsIDOMHTMLCollection* options = GetOptions(); + if (options) { + options->GetLength(&length); + NS_RELEASE(options); + } + return (PRInt32)length; // XXX fix return on GetMaxNumValues + } else { + return 1; + } +} + +PRBool +nsNativeSelectControlFrame::GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues, + nsString* aValues, nsString* aNames) +{ + aNumValues = 0; + nsAutoString name; + nsresult result = GetName(&name); + if ((aMaxNumValues <= 0) || (NS_CONTENT_ATTR_NOT_THERE == result)) { + return PR_FALSE; + } + + nsIDOMHTMLCollection* options = GetOptions(); + if (!options) { + return PR_FALSE; + } + + PRBool status = PR_FALSE; + PRBool multiple; + GetMultiple(&multiple); + if (!multiple) { + nsIListWidget* listWidget; + result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget); + if ((NS_OK == result) && listWidget) { + PRInt32 indx = listWidget->GetSelectedIndex(); + NS_RELEASE(listWidget); + if (indx >= 0) { + nsAutoString value; + GetOptionValue(*options, indx, value); + aNumValues = 1; + aNames[0] = name; + aValues[0] = value; + status = PR_TRUE; + } + } + } else { + nsIListBox* listBox; + result = mWidget->QueryInterface(kListBoxIID, (void **) &listBox); + if ((NS_OK == result) && listBox) { + PRInt32 numSelections = listBox->GetSelectedCount(); + NS_ASSERTION(aMaxNumValues >= numSelections, "invalid max num values"); + if (numSelections >= 0) { + PRInt32* selections = new PRInt32[numSelections]; + listBox->GetSelectedIndices(selections, numSelections); + aNumValues = 0; + for (int i = 0; i < numSelections; i++) { + nsAutoString value; + GetOptionValue(*options, selections[i], value); + aNames[i] = name; + aValues[i] = value; + aNumValues++; + } + delete[] selections; + status = PR_TRUE; + } + NS_RELEASE(listBox); + } + } + + NS_RELEASE(options); + + return status; +} + + +void +nsNativeSelectControlFrame::Reset() +{ + nsIDOMHTMLCollection* options = GetOptions(); + if (!options) { + return; + } + + PRBool multiple; + GetMultiple(&multiple); + + PRUint32 numOptions; + options->GetLength(&numOptions); + + PRInt32 selectedIndex = -1; + nsIListWidget* listWidget; + nsresult result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget); + if ((NS_OK == result) && listWidget) { + listWidget->Deselect(); + for (PRUint32 i = 0; i < numOptions; i++) { + nsIDOMHTMLOptionElement* option = GetOption(*options, i); + if (option) { + PRBool selected = PR_FALSE; + + // Cache the state of each option locally + option->GetDefaultSelected(&selected); + SetOptionSelected(i, selected); + if (selected) { + listWidget->SelectItem(i); + if (selectedIndex < 0) + selectedIndex = i; + } + NS_RELEASE(option); + } + } + } + + // if none were selected, select 1st one if we are a combo box + if (mIsComboBox && (numOptions > 0) && (selectedIndex < 0)) { + listWidget->SelectItem(0); + SetOptionSelected(0, PR_TRUE); + } + NS_RELEASE(listWidget); + NS_RELEASE(options); +} + + + +/* XXX add this to nsHTMLOptionElement.cpp +void +nsOption::CompressContent() +{ + if (nsnull != mContent) { + mContent->CompressWhitespace(PR_TRUE, PR_TRUE); + } +}*/ + +nsIDOMHTMLOptionElement* +nsNativeSelectControlFrame::GetOption(nsIDOMHTMLCollection& aCollection, PRUint32 aIndex) +{ + nsIDOMNode* node = nsnull; + if ((NS_OK == aCollection.Item(aIndex, &node)) && node) { + nsIDOMHTMLOptionElement* option = nsnull; + node->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); + NS_RELEASE(node); + return option; + } + return nsnull; +} + +PRBool +nsNativeSelectControlFrame::GetOptionValue(nsIDOMHTMLCollection& aCollection, PRUint32 aIndex, nsString& aValue) +{ + PRBool status = PR_FALSE; + nsIDOMHTMLOptionElement* option = GetOption(aCollection, aIndex); + if (option) { + nsIHTMLContent* content = nsnull; + nsresult result = option->QueryInterface(kIHTMLContentIID, (void **)&content); + if (NS_SUCCEEDED(result) && content) { + nsHTMLValue value(aValue); + result = content->GetHTMLAttribute(nsHTMLAtoms::value, value); + if (NS_CONTENT_ATTR_HAS_VALUE == result) { + value.GetStringValue(aValue); + status = PR_TRUE; + } + NS_RELEASE(content); + } + if (!status) { + result = option->GetText(aValue); + if (aValue.Length() > 0) { + status = PR_TRUE; + } + } + NS_RELEASE(option); + } + return status; +} + + +void +nsNativeSelectControlFrame::PaintOption(PRBool aPaintSelected, nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, nsString aText, nscoord aX, nscoord aY, + const nsRect& aInside, + nscoord aTextHeight) +{ + nscolor foreground = NS_RGB(0, 0, 0); + nscolor background = NS_RGB(255, 255, 255); + if (PR_TRUE == aPaintSelected) { + background = NS_RGB(0, 0, 0); + foreground = NS_RGB(255, 255, 255); + } + + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); + nsRect rect(aInside.x, aY-onePixel, mRect.width-onePixel, aTextHeight+onePixel); + nscolor currentColor; + aRenderingContext.GetColor(currentColor); + aRenderingContext.SetColor(background); + aRenderingContext.FillRect(rect); + aRenderingContext.SetColor(foreground); + aRenderingContext.DrawString(aText, aX, aY); + aRenderingContext.SetColor(currentColor); +} + + +void +nsNativeSelectControlFrame::PaintSelectControl(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect) +{ + aRenderingContext.PushState(); + + /** + * Resolve style for a pseudo frame within the given aParentContent & aParentContext. + * The tag should be lowercase and inclue the colon. + * ie: NS_NewAtom(":first-line"); + */ + nsIAtom * sbAtom = NS_NewAtom(":scrollbar-look"); + nsIStyleContext* scrollbarStyle; + aPresContext.ResolvePseudoStyleContextFor(mContent, sbAtom, mStyleContext, + PR_FALSE, &scrollbarStyle); + NS_RELEASE(sbAtom); + + sbAtom = NS_NewAtom(":scrollbar-arrow-look"); + nsIStyleContext* arrowStyle; + aPresContext.ResolvePseudoStyleContextFor(mContent, sbAtom, mStyleContext, + PR_FALSE, &arrowStyle); + NS_RELEASE(sbAtom); + + + nsIDOMHTMLCollection* options = GetOptions(); + if (!options) { + return; + } + PRUint32 numOptions; + options->GetLength(&numOptions); + + float scale; + nsIDeviceContext * context; + aRenderingContext.GetDeviceContext(context); + context->GetCanonicalPixelScale(scale); + + const nsStyleSpacing* spacing = + (const nsStyleSpacing*)mStyleContext->GetStyleData(eStyleStruct_Spacing); + nsMargin border; + spacing->CalcBorderFor(this, border); + + float p2t; + aPresContext.GetScaledPixelsToTwips(&p2t); + nscoord onePixel = NSIntPixelsToTwips(1, p2t); + + nsRect outside(0, 0, mRect.width, mRect.height); + outside.Deflate(border); + outside.Deflate(onePixel, onePixel); + + nsRect inside(outside); + + aRenderingContext.SetColor(NS_RGB(0,0,0)); + + nsFont font(aPresContext.GetDefaultFixedFontDeprecated()); + GetFont(&aPresContext, font); + + aRenderingContext.SetFont(font); + + //nscoord textWidth; + nscoord textHeight; + nsString text; + + // Calculate the height of the text + nsIFontMetrics* metrics; + context->GetMetricsFor(font, metrics); + metrics->GetHeight(textHeight); + + // Calculate the width of the scrollbar + PRInt32 scrollbarWidth; + if (numOptions > mNumRows) { + float sbWidth; + float sbHeight; + context->GetCanonicalPixelScale(scale); + context->GetScrollBarDimensions(sbWidth, sbHeight); + scrollbarWidth = PRInt32(sbWidth * scale); + } else { + scrollbarWidth = 0; + } + + // shrink the inside rect's width for the scrollbar + inside.width -= scrollbarWidth; + PRBool clipEmpty; + aRenderingContext.PushState(); + nsRect clipRect(inside); + clipRect.Inflate(onePixel, onePixel); + + aRenderingContext.SetClipRect(clipRect, nsClipCombine_kReplace, clipEmpty); + + nscoord x = inside.x + onePixel; + nscoord y; + if (mIsComboBox) { + y = ((inside.height - textHeight) / 2) + inside.y; + } else { + y = inside.y; + } + + // Get Selected index out of Content model + PRInt32 selectedIndex = GetSelectedIndex(); + PRBool multiple = PR_FALSE; + GetMultiple(&multiple); + + nsIDOMNode* node; + nsIDOMHTMLOptionElement* option; + for (PRUint32 i = 0; i < numOptions; i++) { + options->Item(i, &node); + if (node) { + nsresult result = node->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); + if ((NS_OK == result) && option) { + // XXX need to compress whitespace + if (NS_CONTENT_ATTR_HAS_VALUE != option->GetText(text)) { + text = " "; + } + + if (mIsComboBox) { + // Paint a non-selected option + if ((selectedIndex == -1) && (i == 0)) { + PaintOption(PR_FALSE, aPresContext, aRenderingContext, text, x, y, inside, textHeight); + } + else if ((PRUint32)selectedIndex == i) { + PaintOption(PR_FALSE, aPresContext, aRenderingContext, text, x, y, inside, textHeight); + } + + if ((-1 == selectedIndex && (0 == i)) || ((PRUint32)selectedIndex == i)) { + i = numOptions; + } + + } else { + // Its a list box + if (!multiple) { + // Single select list box + if (selectedIndex == i) + PaintOption(PR_TRUE, aPresContext, aRenderingContext, text, x, y, inside, textHeight); + else + PaintOption(PR_FALSE, aPresContext, aRenderingContext, text, x, y, inside, textHeight); + } + else { + PRBool selected = PR_FALSE; + option->GetSelected(&selected); + // Multi-selection list box + if (selected) + PaintOption(PR_TRUE, aPresContext, aRenderingContext, text, x, y, inside, textHeight); + else + PaintOption(PR_FALSE, aPresContext, aRenderingContext, text, x, y, inside, textHeight); + } + y += textHeight; + if (i == mNumRows-1) { + i = numOptions; + } + } + } + + NS_RELEASE(option); + } + NS_RELEASE(node); + } + + + aRenderingContext.PopState(clipEmpty); + // Draw Scrollbars + if (numOptions > mNumRows) { + //const nsStyleColor* myColor = + // (const nsStyleColor*)mStyleContext->GetStyleData(eStyleStruct_Color); + + if (mIsComboBox) { + // Get the Scrollbar's Arrow's Style structs + const nsStyleSpacing* arrowSpacing = (const nsStyleSpacing*)arrowStyle->GetStyleData(eStyleStruct_Spacing); +//XXX const nsStyleColor* arrowColor = (const nsStyleColor*)arrowStyle->GetStyleData(eStyleStruct_Color); + + nsRect srect(mRect.width-scrollbarWidth-onePixel, onePixel, scrollbarWidth, mRect.height-(onePixel*2)); + nsFormControlHelper::PaintArrow(nsFormControlHelper::eArrowDirection_Down, aRenderingContext,aPresContext, + aDirtyRect, srect, onePixel, arrowStyle, *arrowSpacing, this, mRect); + } else { + nsRect srect(mRect.width-scrollbarWidth-onePixel, onePixel, scrollbarWidth, mRect.height-(onePixel*2)); + + nsFormControlHelper::PaintScrollbar(aRenderingContext,aPresContext, aDirtyRect, srect, PR_FALSE, onePixel, + scrollbarStyle, arrowStyle, this, mRect); + } + } + + + NS_RELEASE(context); + + NS_RELEASE(options); + aRenderingContext.PopState(clipEmpty); + + NS_RELEASE(scrollbarStyle); + NS_RELEASE(arrowStyle); + +} + +NS_METHOD +nsNativeSelectControlFrame::Paint(nsIPresContext& aPresContext, + nsIRenderingContext& aRenderingContext, + const nsRect& aDirtyRect, + nsFramePaintLayer aWhichLayer) +{ + Inherited::Paint(aPresContext, aRenderingContext, aDirtyRect, + aWhichLayer); + if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) { + PaintSelectControl(aPresContext, aRenderingContext, aDirtyRect); + } + return NS_OK; +} + +// Forward this on as a control changed event - this enables onChange for +// list boxes as ControlChanged is currently only sent for combos +void +nsNativeSelectControlFrame::MouseClicked(nsIPresContext* aPresContext) +{ + ControlChanged(aPresContext); +} + +// Update the locally cached selection array. +// If different option(s) are selected, send a DOM onChange event. +void +nsNativeSelectControlFrame::ControlChanged(nsIPresContext* aPresContext) +{ + if (!nsFormFrame::GetDisabled(this)) { + + PRBool changed = PR_FALSE; + PRBool multiple; + GetMultiple(&multiple); + if (!multiple) { + nsIListWidget* listWidget; + nsresult result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget); + if ((NS_OK == result) && listWidget) { + PRInt32 viewIndex = listWidget->GetSelectedIndex(); + NS_RELEASE(listWidget); + + PRBool wasSelected = PR_FALSE; + GetOptionSelected(viewIndex, &wasSelected); + + if (wasSelected == PR_FALSE) { + changed = PR_TRUE; + } + // Update the locally cached array + for (PRUint32 i=0; i < mNumOptions; i++) + SetOptionSelected(i, PR_FALSE); + SetOptionSelected(viewIndex, PR_TRUE); + + } + } else { + // Get the selected option from the widget + nsIListBox* listBox; + nsresult result = mWidget->QueryInterface(kListBoxIID, (void **) &listBox); + if (!(NS_OK == result) || !listBox) { + return; + } + PRUint32 numSelected = listBox->GetSelectedCount(); + PRInt32* selOptions = nsnull; + if (numSelected >= 0) { + selOptions = new PRInt32[numSelected]; + listBox->GetSelectedIndices(selOptions, numSelected); + } + NS_RELEASE(listBox); + + // XXX Assume options are sorted in selOptions + + PRUint32 selIndex = 0; + PRUint32 nextSel = 0; + if ((nsnull != selOptions) && (numSelected > 0)) { + nextSel = selOptions[selIndex]; + } + + // Step through each option in local cache + for (PRUint32 i=0; i < mNumOptions; i++) { + PRBool selectedInLocalCache = PR_FALSE; + PRBool selectedInView = (i == nextSel); + GetOptionSelected(i, &selectedInLocalCache); + if (selectedInView != selectedInLocalCache) { + changed = PR_TRUE; + SetOptionSelected(i, selectedInView); + + if (selectedInView) { + // Get the next selected option in the view + selIndex++; + if (selIndex < numSelected) { + nextSel = selOptions[selIndex]; + } + } + } + } + delete[] selOptions; + } + + if (changed) { + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent event; + event.eventStructType = NS_EVENT; + + event.message = NS_FORM_CHANGE; + if (nsnull != mContent) { + mContent->HandleDOMEvent(*aPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, status); + } + } + } +} + +// Get the selected state from the local cache (not widget) +void nsNativeSelectControlFrame::GetOptionSelected(PRUint32 indx, PRBool* aValue) +{ + if (nsnull != mOptionSelected) { + if (mNumOptions >= indx) { + *aValue = mOptionSelected[indx]; + return; + } + } + *aValue = PR_FALSE; +} + +// Get the selected state from the widget +void nsNativeSelectControlFrame::GetOptionSelectedFromWidget(PRInt32 indx, PRBool* aValue) +{ + *aValue = PR_FALSE; + nsresult result; + PRBool multiple; + + GetMultiple(&multiple); + if (!multiple) { + nsIListWidget* listWidget; + result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget); + + if ((NS_OK == result) && (nsnull != listWidget)) { + PRInt32 selIndex = listWidget->GetSelectedIndex(); + NS_RELEASE(listWidget); + + if (selIndex == indx) { + *aValue = PR_TRUE; + } + } + } + else { + nsIListBox* listBox; + result = mWidget->QueryInterface(kListBoxIID, (void **) &listBox); + if ((NS_OK == result) && (nsnull != listBox)) { + PRUint32 numSelected = listBox->GetSelectedCount(); + PRInt32* selOptions = nsnull; + if (numSelected > 0) { + // Could we set numSelected to 1 here? (memory, speed optimization) + selOptions = new PRInt32[numSelected]; + listBox->GetSelectedIndices(selOptions, numSelected); + PRUint32 i; + for (i = 0; i < numSelected; i++) { + if (selOptions[i] == indx) { + *aValue = PR_TRUE; + break; + } + } + delete[] selOptions; + } + NS_RELEASE(listBox); + } + } +} + +// Update the locally cached selection state (not widget) +void nsNativeSelectControlFrame::SetOptionSelected(PRUint32 indx, PRBool aValue) +{ + if (nsnull != mOptionSelected) { + if (mNumOptions >= indx) { + mOptionSelected[indx] = aValue; + } + } +} + +NS_IMETHODIMP +nsNativeSelectControlFrame::AttributeChanged(nsIPresContext* aPresContext, + nsIContent* aChild, + nsIAtom* aAttribute, + PRInt32 aHint) +{ + if (nsnull != mWidget) { + if (nsHTMLAtoms::disabled == aAttribute) { + mWidget->Enable(!nsFormFrame::GetDisabled(this)); + } + } + return NS_OK; +} + + +NS_IMETHODIMP nsNativeSelectControlFrame::SetProperty(nsIAtom* aName, const nsString& aValue) +{ + if (nsHTMLAtoms::selected == aName) { + return NS_ERROR_INVALID_ARG; // Selected is readonly according to spec. + } else if (nsHTMLAtoms::selectedindex == aName) { + PRInt32 error = 0; + PRInt32 selectedIndex = aValue.ToInteger(&error, 10); // Get index from aValue + if (error) + return NS_ERROR_INVALID_ARG; // Couldn't convert to integer + + // Update local cache of selected values + for (PRUint32 i=0; i < mNumOptions; i++) + SetOptionSelected(i, PR_FALSE); + SetOptionSelected(selectedIndex, PR_TRUE); + + // Update widget + nsIListWidget* listWidget; + nsresult result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget); + if ((NS_OK == result) && (nsnull != listWidget)) { + listWidget->Deselect(); + listWidget->SelectItem(selectedIndex); + NS_RELEASE(listWidget); + } + } else if (nsHTMLAtoms::option == aName) { // Add or Remove an option + nsString aValCopy(aValue); + aValCopy.Trim("ar",PR_TRUE,PR_FALSE); // Chop off leading a or r + PRInt32 error = 0; + PRUint32 actionIndex = aValCopy.ToInteger(&error, 10); + if (error) return NS_ERROR_INVALID_ARG; // Couldn't convert to integer + + // Grab the content model information (merge with postcreatewidget code?) + nsIDOMHTMLCollection* options = GetOptions(); + if (!options) return NS_ERROR_UNEXPECTED; + + // Save the cache data structure + PRUint32 saveNumOptions = mNumOptions; + PRBool* saveOptionSelected = mOptionSelected; + PRBool selected = PR_FALSE; + nsString text(" "); + + // Grab the widget (we need to update it) + nsIListWidget* listWidget; + nsresult result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget); + if ((NS_FAILED(result)) || (nsnull == listWidget)) { + return NS_ERROR_UNEXPECTED; + } + + if (!aValue.Find("a")) { // First character is "a" = add an option + mNumOptions++; + mOptionSelected = new PRBool[mNumOptions]; + if (!mOptionSelected) return NS_ERROR_OUT_OF_MEMORY; + + // Copy saved local cache into new local cache + for (PRUint32 i=0, j=0; j < mNumOptions; i++,j++) { + if (i == actionIndex) { // At the point of insertion + + // Get the correct selected value and text of the option + nsIDOMNode* node = nsnull; + options->Item(i, &node); + if (node) { + nsIDOMHTMLOptionElement* option = nsnull; + result = node->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); + if ((NS_OK == result) && option) { + option->GetDefaultSelected(&selected); + mOptionSelected[j]=selected; + + // XXX need to compress whitespace + if (NS_CONTENT_ATTR_HAS_VALUE != option->GetText(text)) { + text = " "; // needed? + } + NS_RELEASE(option); + } else { + mOptionSelected[j]=PR_FALSE; // Couldn't get selected val from content! + } + NS_RELEASE(node); + } else { + mOptionSelected[j]=PR_FALSE; // Couldn't get selected val from content! + } + j++; + } + + // Copy old selected value + if (j < mNumOptions) { + mOptionSelected[j]=saveOptionSelected[i]; + } + } + + // Update widget + listWidget->AddItemAt(text, actionIndex); + } else { + mNumOptions--; + if (mNumOptions) { + mOptionSelected = new PRBool[mNumOptions]; + if (!mOptionSelected) return NS_ERROR_OUT_OF_MEMORY; + } else { + mOptionSelected = nsnull; + } + // If we got the index, remove just that one option, like this: + if (actionIndex >= 0) { + // Copy saved local cache into new local cache + for (PRUint32 i=0, j=0; j < mNumOptions; i++,j++) { + if (i == (PRUint32)actionIndex) i++; // At the point of insertion + mOptionSelected[j]=saveOptionSelected[i]; + } + + // Update widget + listWidget->RemoveItemAt(actionIndex); + + // No index, so we'll have to remove all options and recreate. (Performance hit) + // We also loose the status of what has been selected. + } else { + // Remove all stale options + PRUint32 i; + for (i=saveNumOptions; i>=0; i--) { + listWidget->RemoveItemAt(i); + } + + // Add all the options back in + for (i=0; iItem(i, &node); + if (node) { + nsIDOMHTMLOptionElement* option = nsnull; + result = node->QueryInterface(kIDOMHTMLOptionElementIID, (void**)&option); + if ((NS_OK == result) && option) { + option->GetDefaultSelected(&selected); // Should be sel, not defsel :( + mOptionSelected[i]=selected; + + // XXX need to compress whitespace + if (NS_CONTENT_ATTR_HAS_VALUE != option->GetText(text)) { + text = " "; // needed? + } + NS_RELEASE(option); + } else { + mOptionSelected[i]=PR_FALSE; // Couldn't get selected val from content! + text = " "; + } + NS_RELEASE(node); + } else { + mOptionSelected[i]=PR_FALSE; // Couldn't get selected val from content! + text = " "; + } + listWidget->AddItemAt(text, i); + } + } + } + // Select options as needed (this is needed for Windows at least) + // Note, as mentioned above, we can't restore selection if option is + // replaced - no index is reported back to us - use DefaultSelected instead + listWidget->Deselect(); + PRInt32 selectedIndex = -1; + for (PRUint32 i=0; i < mNumOptions; i++) { + GetOptionSelected(i, &selected); + if (selected) { + listWidget->SelectItem(i); + selectedIndex = i; + } + } + if (mIsComboBox && (mNumOptions > 0) && (selectedIndex == -1)) { + listWidget->SelectItem(0); + SetOptionSelected(0, PR_TRUE); + } + + NS_RELEASE(options); + NS_RELEASE(listWidget); + if (saveOptionSelected) + delete [] saveOptionSelected; + } else { + return Inherited::SetProperty(aName, aValue); + } + return NS_OK; +} + +NS_IMETHODIMP nsNativeSelectControlFrame::GetProperty(nsIAtom* aName, nsString& aValue) +{ + // Get the selected value of option from local cache (optimization vs. widget) + if (nsHTMLAtoms::selected == aName) { + PRInt32 error = 0; + PRBool selected = PR_FALSE; + PRInt32 indx = aValue.ToInteger(&error, 10); // Get index from aValue + if (error == 0) + GetOptionSelectedFromWidget(indx, &selected); + nsFormControlHelper::GetBoolString(selected, aValue); + + // For selectedIndex, get the value from the widget + } else if (nsHTMLAtoms::selectedindex == aName) { + PRInt32 selectedIndex = -1; + PRBool multiple; + GetMultiple(&multiple); + if (!multiple) { + nsIListWidget* listWidget; + nsresult result = mWidget->QueryInterface(kListWidgetIID, (void **) &listWidget); + if ((NS_OK == result) && (nsnull != listWidget)) { + selectedIndex = listWidget->GetSelectedIndex(); + NS_RELEASE(listWidget); + } + } else { + // Listboxes don't do GetSelectedIndex on windows. Use GetSelectedIndices + nsIListBox* listBox; + nsresult result = mWidget->QueryInterface(kListBoxIID, (void **) &listBox); + if ((NS_OK == result) && (nsnull != listBox)) { + PRUint32 numSelected = listBox->GetSelectedCount(); + PRInt32* selOptions = nsnull; + if (numSelected > 0) { + // Could we set numSelected to 1 here? (memory, speed optimization) + selOptions = new PRInt32[numSelected]; + listBox->GetSelectedIndices(selOptions, numSelected); + selectedIndex = selOptions[0]; + delete[] selOptions; + } + NS_RELEASE(listBox); + } + } + aValue.Append(selectedIndex, 10); + } else { + return Inherited::GetProperty(aName, aValue); + } + return NS_OK; +} diff --git a/mozilla/layout/html/forms/src/nsRadioControlGroup.cpp b/mozilla/layout/html/forms/src/nsRadioControlGroup.cpp new file mode 100644 index 00000000000..ec3b0064375 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsRadioControlGroup.cpp @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsRadioControlGroup.h" + +nsRadioControlGroup::nsRadioControlGroup(nsString& aName) +:mName(aName), mCheckedRadio(nsnull) +{ +} + +nsRadioControlGroup::~nsRadioControlGroup() +{ + mCheckedRadio = nsnull; +} + +PRInt32 +nsRadioControlGroup::GetRadioCount() const +{ + return mRadios.Count(); +} + +nsRadioControlFrame* +nsRadioControlGroup::GetRadioAt(PRInt32 aIndex) const +{ + return (nsRadioControlFrame*) mRadios.ElementAt(aIndex); +} + +PRBool +nsRadioControlGroup::AddRadio(nsRadioControlFrame* aRadio) +{ + return mRadios.AppendElement(aRadio); +} + +PRBool +nsRadioControlGroup::RemoveRadio(nsRadioControlFrame* aRadio) +{ + return mRadios.RemoveElement(aRadio); +} + +nsRadioControlFrame* +nsRadioControlGroup::GetCheckedRadio() +{ + return mCheckedRadio; +} + +void +nsRadioControlGroup::SetCheckedRadio(nsRadioControlFrame* aRadio) +{ + mCheckedRadio = aRadio; +} + +void +nsRadioControlGroup::GetName(nsString& aNameResult) const +{ + aNameResult = mName; +} diff --git a/mozilla/layout/html/forms/src/nsRadioControlGroup.h b/mozilla/layout/html/forms/src/nsRadioControlGroup.h new file mode 100644 index 00000000000..7cfcf90d106 --- /dev/null +++ b/mozilla/layout/html/forms/src/nsRadioControlGroup.h @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#ifndef nsRadioControlGroup_h___ +#define nsRadioControlGroup_h___ + +#include "nsRadioControlFrame.h" + + +class nsRadioControlGroup +{ +public: + nsRadioControlGroup(nsString& aName); + virtual ~nsRadioControlGroup(); + + PRBool AddRadio(nsRadioControlFrame* aRadio); + PRInt32 GetRadioCount() const; + nsRadioControlFrame* GetRadioAt(PRInt32 aIndex) const; + PRBool RemoveRadio(nsRadioControlFrame* aRadio); + + nsRadioControlFrame* GetCheckedRadio(); + void SetCheckedRadio(nsRadioControlFrame* aRadio); + void GetName(nsString& aNameResult) const; + +protected: + nsString mName; + nsVoidArray mRadios; + nsRadioControlFrame* mCheckedRadio; + +}; + +#endif