Mozilla/mozilla/layout/html/forms/src/nsCheckboxControlFrame.cpp
kmcclusk%netscape.com 2a00ad3de1 Defaultchecked attribute is set to match the checked attribute just after
the radio button or checkbox element is created. Checkboxes and Radio buttons
maintain their current state using the checked attribute stored in the
content model. They no longer use the nsIWidget to maintain their current setting.
Checkboxes and Radio buttons now print correctly. (i.e checked/unchecked state matches the
screen.)


git-svn-id: svn://10.0.0.236/trunk@17202 18797224-902f-48f8-a5cc-f745e15eee43
1999-01-06 00:02:27 +00:00

364 lines
10 KiB
C++

/* -*- 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 "nsICheckButton.h"
#include "nsFormControlFrame.h"
#include "nsFormFrame.h"
#include "nsIContent.h"
#include "prtypes.h"
#include "nsIFrame.h"
#include "nsIAtom.h"
#include "nsIPresContext.h"
#include "nsIHTMLContent.h"
#include "nsHTMLIIDs.h"
#include "nsWidgetsCID.h"
#include "nsIView.h"
#include "nsHTMLAtoms.h"
#include "nsIStyleContext.h"
#include "nsStyleUtil.h"
#include "nsIFormControl.h"
#include "nsIDOMHTMLInputElement.h"
#define NS_DESIRED_CHECKBOX_SIZE 20
#define NS_ABSOLUTE_CHECKBOX_SIZE 12
static NS_DEFINE_IID(kICheckButtonIID, NS_ICHECKBUTTON_IID);
static NS_DEFINE_IID(kIDOMHTMLInputElementIID, NS_IDOMHTMLINPUTELEMENT_IID);
class nsCheckboxControlFrame : public nsFormControlFrame {
public:
nsCheckboxControlFrame();
virtual void PostCreateWidget(nsIPresContext* aPresContext,
nscoord& aWidth,
nscoord& aHeight);
NS_IMETHOD AttributeChanged(nsIPresContext* aPresContext,
nsIContent* aChild,
nsIAtom* aAttribute,
PRInt32 aHint);
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();
//
// Methods used to GFX-render the checkbox
//
virtual void PaintCheckBox(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect);
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 void GetDesiredSize(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredLayoutSize,
nsSize& aDesiredWidgetSize);
PRBool mMouseDownOnCheckbox;
};
nsresult
NS_NewCheckboxControlFrame(nsIFrame*& aResult)
{
aResult = new nsCheckboxControlFrame;
if (nsnull == aResult) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
nsCheckboxControlFrame::nsCheckboxControlFrame()
{
mMouseDownOnCheckbox = PR_FALSE;
}
const nsIID&
nsCheckboxControlFrame::GetIID()
{
static NS_DEFINE_IID(kCheckboxIID, NS_ICHECKBUTTON_IID);
return kCheckboxIID;
}
const nsIID&
nsCheckboxControlFrame::GetCID()
{
static NS_DEFINE_IID(kCheckboxCID, NS_CHECKBUTTON_CID);
return kCheckboxCID;
}
void
nsCheckboxControlFrame::GetDesiredSize(nsIPresContext* aPresContext,
const nsHTMLReflowState& aReflowState,
nsHTMLReflowMetrics& aDesiredLayoutSize,
nsSize& aDesiredWidgetSize)
{
float p2t;
aPresContext->GetScaledPixelsToTwips(p2t);
#ifdef XP_PC
aDesiredWidgetSize.width = NSIntPixelsToTwips(NS_DESIRED_CHECKBOX_SIZE, p2t);
aDesiredWidgetSize.height = NSIntPixelsToTwips(NS_DESIRED_CHECKBOX_SIZE, p2t);
#endif
aDesiredLayoutSize.width = aDesiredWidgetSize.width;
aDesiredLayoutSize.height = aDesiredWidgetSize.height;
aDesiredLayoutSize.ascent = aDesiredLayoutSize.height;
aDesiredLayoutSize.descent = 0;
}
void
nsCheckboxControlFrame::PostCreateWidget(nsIPresContext* aPresContext, nscoord& aWidth, nscoord& aHeight)
{
if (!mWidget) {
return;
}
SetColors(*aPresContext);
mWidget->Enable(!nsFormFrame::GetDisabled(this));
// set the widget to the initial state
nsICheckButton* checkbox = nsnull;
if (NS_OK == mWidget->QueryInterface(GetIID(),(void**)&checkbox)) {
PRBool checked;
nsresult result = GetCurrentCheckState(&checked);
if (NS_CONTENT_ATTR_HAS_VALUE == result) {
checkbox->SetState(checked);
}
NS_RELEASE(checkbox);
}
}
NS_IMETHODIMP
nsCheckboxControlFrame::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);
}
}
}
return result;
}
void
nsCheckboxControlFrame::MouseClicked(nsIPresContext* aPresContext)
{
mMouseDownOnCheckbox = PR_FALSE;
PRBool oldState;
GetCurrentCheckState(&oldState);
PRBool newState = oldState ? PR_FALSE : PR_TRUE;
SetCurrentCheckState(newState);
}
PRInt32
nsCheckboxControlFrame::GetMaxNumValues()
{
return 1;
}
PRBool
nsCheckboxControlFrame::GetNamesValues(PRInt32 aMaxNumValues, PRInt32& aNumValues,
nsString* aValues, nsString* aNames)
{
nsAutoString name;
nsresult nameResult = GetName(&name);
if ((aMaxNumValues <= 0) || (NS_CONTENT_ATTR_HAS_VALUE != nameResult)) {
return PR_FALSE;
}
PRBool result = PR_TRUE;
nsAutoString value;
nsresult valueResult = GetValue(&value);
nsICheckButton* checkBox = nsnull;
if ((nsnull != mWidget) &&
(NS_OK == mWidget->QueryInterface(kICheckButtonIID,(void**)&checkBox))) {
PRBool state = PR_FALSE;
checkBox->GetState(state);
if (PR_TRUE != state) {
result = PR_FALSE;
} else {
if (NS_CONTENT_ATTR_HAS_VALUE == valueResult) {
aValues[0] = "on";
} else {
aValues[0] = value;
}
aNames[0] = name;
aNumValues = 1;
}
NS_RELEASE(checkBox);
}
return result;
}
void
nsCheckboxControlFrame::Reset()
{
PRBool checked;
GetDefaultCheckState(&checked);
SetCurrentCheckState(checked);
}
void
nsCheckboxControlFrame::PaintCheckBox(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect)
{
//XXX: Resolution of styles should be cached. This is very
// inefficient to do this each time the checkbox is cliced on.
/**
* Resolve style for a pseudo frame within the given aParentContent & aParentContext.
* The tag should be uppercase and inclue the colon.
* ie: NS_NewAtom(":FIRST-LINE");
*/
nsIStyleContext* style = nsnull;
if (PR_TRUE == mMouseDownOnCheckbox) {
nsIAtom * sbAtom = NS_NewAtom(":CHECKBOX-LOOK");
style = aPresContext.ResolvePseudoStyleContextFor(mContent, sbAtom, mStyleContext);
NS_RELEASE(sbAtom);
}
else {
nsIAtom * sbAtom = NS_NewAtom(":CHECKBOX-SELECT-LOOK");
style = aPresContext.ResolvePseudoStyleContextFor(mContent, sbAtom, mStyleContext);
NS_RELEASE(sbAtom);
}
const nsStyleColor* color = (const nsStyleColor*)style->GetStyleData(eStyleStruct_Color);
aRenderingContext.PushState();
float p2t;
aPresContext.GetScaledPixelsToTwips(p2t);
//Offset fixed size checkbox in to the middle of the area reserved for the checkbox
const int printOffsetX = (NS_DESIRED_CHECKBOX_SIZE - NS_ABSOLUTE_CHECKBOX_SIZE);
const int printOffsetY = (NS_DESIRED_CHECKBOX_SIZE - NS_ABSOLUTE_CHECKBOX_SIZE);
aRenderingContext.Translate(NSIntPixelsToTwips(printOffsetX, p2t),
NSIntPixelsToTwips(printOffsetY, p2t));
// Draw's background + border
nsFormControlFrame::PaintFixedSizeCheckMarkBorder(aRenderingContext, p2t, *color);
PRBool checked = PR_TRUE;
// Get current checked state from content model
nsresult result = GetCurrentCheckState(&checked);
if (PR_TRUE == checked) {
PaintFixedSizeCheckMark(aRenderingContext, p2t);
}
PRBool clip;
aRenderingContext.PopState(clip);
NS_IF_RELEASE(style);
}
NS_METHOD
nsCheckboxControlFrame::Paint(nsIPresContext& aPresContext,
nsIRenderingContext& aRenderingContext,
const nsRect& aDirtyRect,
nsFramePaintLayer aWhichLayer)
{
if (eFramePaintLayer_Content == aWhichLayer) {
PaintCheckBox(aPresContext, aRenderingContext, aDirtyRect);
}
return NS_OK;
}
NS_METHOD nsCheckboxControlFrame::HandleEvent(nsIPresContext& aPresContext,
nsGUIEvent* aEvent,
nsEventStatus& aEventStatus)
{
if (nsEventStatus_eConsumeNoDefault == aEventStatus) {
return NS_OK;
}
if (nsnull == mWidget) {
// Handle GFX rendered widget Mouse Down event
PRInt32 type;
PRBool checked;
GetType(&type);
switch (aEvent->message) {
case NS_MOUSE_LEFT_BUTTON_DOWN:
mMouseDownOnCheckbox = PR_TRUE;
// XXX: Hack, force refresh by changing attribute to current
GetCurrentCheckState(&checked);
SetCurrentCheckState(checked);
break;
case NS_MOUSE_EXIT:
mMouseDownOnCheckbox = PR_FALSE;
// XXX: Hack, force refresh by changing attribute to current
GetCurrentCheckState(&checked);
SetCurrentCheckState(checked);
break;
}
}
return(nsFormControlFrame::HandleEvent(aPresContext, aEvent, aEventStatus));
}