/* -*- 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() : nsFormControlFrame() { 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 nsFormControlFrame::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: mLastMouseState = eMouseDown; 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; }