/* -*- Mode: C++; tab-width: 4; 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 "stdafx.h" #include "fmradio.h" // This file is dedicated to form type radio elements // otherwise known as list boxes on windows and // their implementation as requried by the XP layout // library. // Construction simply clears all members. CFormRadio::CFormRadio() { // No widget. m_pWidget = NULL; } // Destruction cleans out all members. CFormRadio::~CFormRadio() { } // How to set the LO form element. // This may change during the lifetime of an instance, so use this // to update all referencing values. void CFormRadio::SetElement(LO_FormElementStruct *pFormElement) { // Call the base. CFormElement::SetElement(pFormElement); // Update the widget if present for correct callbacks. if(m_pWidget) { m_pWidget->RegisterForm(GetElement()); } } // Set the owning context. // Use this to determine what context we live in and how we should // represent ourself (DC or window). void CFormRadio::SetContext(CAbstractCX *pCX) { // Call the base. CFormElement::SetContext(pCX); // Update the widget if present for correct callbacks. if(m_pWidget) { m_pWidget->RegisterContext(GetContext() ? GetContext()->GetContext() : NULL); } } // Display the form element given the particular context we are in. // Possibly only use a DC for representation, or have the // window move. void CFormRadio::DisplayFormElement(LTRB& Rect) { // Display only has meaning if our context is a device context. if(GetContext() && GetContext()->IsDCContext()) { // Further, need to detect how we're going to be drawing ourselves. if(GetContext()->IsPureDCContext()) { // Only works from a DC, needs a GDI drawing representation. CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX); HDC pDC = pDCCX->GetContextDC(); if(pDC && Rect.Width() && Rect.Height()) { // Adjust the rect some (reverse what we did earlier for layout). RECT crRect; ::SetRect(&crRect, CASTINT(Rect.left), CASTINT(Rect.top), CASTINT(Rect.right), CASTINT(Rect.bottom)); ::InflateRect(&crRect, CASTINT(-1 * pDCCX->Pix2TwipsX(BUTTON_FUDGE) / 2), CASTINT(-1 * pDCCX->Pix2TwipsY(BUTTON_FUDGE) / 2)); // Figure out what type we're about to draw, and its current state. BOOL bRadio = FALSE; // Radio or checkbox. BOOL bChecked = FALSE; // State, checked or not. if(GetElementMinimalData()) { switch(GetElementMinimalData()->type) { case FORM_TYPE_RADIO: bRadio = TRUE; break; case FORM_TYPE_CHECKBOX: bRadio = FALSE; break; default: // Unknown! ASSERT(0); return; } } if(GetElementToggleData()) { bChecked = GetElementToggleData()->toggled ? TRUE : FALSE; } // Are we drawing a circle or a square? if(bRadio) { TRY { // Circle. // Select the outer pen. HPEN hpOuter = ::CreatePen(PS_SOLID, CASTINT(pDCCX->Pix2TwipsY(1)), pDCCX->ResolveLightLineColor()); HPEN hOldPen = (HPEN)::SelectObject(pDC, hpOuter); if(hOldPen) { // Draw an ellipse. ::Ellipse(pDC, crRect.left, crRect.top, crRect.right, crRect.bottom); // Select the inner pen. HPEN hpInner = ::CreatePen(PS_SOLID, CASTINT(pDCCX->Pix2TwipsY(1)), pDCCX->ResolveDarkLineColor()); ::SelectObject(pDC, hpInner); ::InflateRect(&crRect, CASTINT(-1 * pDCCX->Pix2TwipsX(1)), CASTINT(-1 * pDCCX->Pix2TwipsY(1))); ::Ellipse(pDC, crRect.left, crRect.top, crRect.right, crRect.bottom); // Are we drawing a circle in the radio button (checked?) if(bChecked) { HPEN hpBlack = CreatePen(PS_SOLID, CASTINT(pDCCX->Pix2TwipsY(1)), RGB(0, 0, 0)); ::SelectObject(pDC, hpBlack); // Get the brush with which to fill the ellipse this time around. HBRUSH hbBlack = ::CreateSolidBrush(RGB(0, 0, 0)); HBRUSH hOldBrush = (HBRUSH)::SelectObject(pDC, hbBlack); ::InflateRect(&crRect, CASTINT(-1 * pDCCX->Pix2TwipsX(3)), CASTINT(-1 * pDCCX->Pix2TwipsY(3))); ::Ellipse(pDC, crRect.left, crRect.top, crRect.right, crRect.bottom); // Restore the brush. if(hOldBrush) { ::SelectObject(pDC, hOldBrush); } VERIFY(::DeleteObject( hbBlack )); VERIFY(::DeleteObject( hpBlack )); } // Restore original pen. ::SelectObject(pDC, hOldPen); VERIFY(::DeleteObject( hpOuter )); VERIFY(::DeleteObject( hpInner )); } } CATCH(CException, e) { // Caught some pen/brush exception, do nothing special. } END_CATCH } else { // Square. pDCCX->Display3DBox(LTRB(crRect.left, crRect.top, crRect.right, crRect.bottom), pDCCX->ResolveLightLineColor(), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2)); // Are we checking it? if(bChecked) { ::InflateRect(&crRect, CASTINT(-1 * pDCCX->Pix2TwipsX(2)), CASTINT(-1 * pDCCX->Pix2TwipsY(2))); TRY { HPEN hpBlack = ::CreatePen(PS_SOLID, CASTINT(pDCCX->Pix2TwipsY(2)), RGB(0, 0, 0)); HPEN hOldPen = (HPEN)::SelectObject(pDC, hpBlack); if(hOldPen) { // Draw a check. int width = crRect.right - crRect.left; int height = crRect.bottom - crRect.top; ::MoveToEx(pDC, crRect.left + width / 4, crRect.top + height / 2, NULL); ::LineTo(pDC, crRect.left + width / 3, crRect.top + 3 * height / 4); ::LineTo(pDC, crRect.left + 3 * width / 4, crRect.top + height / 4); // Restore old pen. ::SelectObject(pDC, hOldPen); VERIFY(::DeleteObject(hpBlack)); } } CATCH(CException, e) { // Caught some pen exeption, do nothing special here. } END_CATCH } } pDCCX->ReleaseContextDC(pDC); } } else if(GetContext()->IsWindowContext()) { // Is a window, needs a widget/window representation. MoveWindow(m_pWidget->m_hWnd, Rect.left + BUTTON_FUDGE / 2, Rect.top + BUTTON_FUDGE / 2); } else { // Is undefined.... ASSERT(0); } } // Call the base. CFormElement::DisplayFormElement(Rect); } // Destroy the widget (window) implemenation of the form. void CFormRadio::DestroyWidget() { if(m_pWidget) { m_pWidget->DestroyWindow(); delete m_pWidget; m_pWidget = NULL; } } // Create the widget (window) implementation of the form // but DO NOT DISPLAY. void CFormRadio::CreateWidget() { if(GetContext() && GetElement()) { if(GetContext()->IsWindowContext() && VOID2CX(GetContext(), CPaneCX)->GetPane()) { // For a window context, allocate a widget. ASSERT(m_pWidget == NULL); m_pWidget = new CNetscapeButton(GetContext()->GetContext(), GetElement()); if(m_pWidget == NULL) { return; } // Figure the window style. DWORD dwStyle = WS_CHILD; if(GetElementMinimalData()) { switch(GetElementMinimalData()->type) { case FORM_TYPE_RADIO: dwStyle |= BS_RADIOBUTTON; break; case FORM_TYPE_CHECKBOX: dwStyle |= BS_CHECKBOX; // bug 49682 removed AUTO, see button.cpp click() break; default: // Unknown! ASSERT(0); delete m_pWidget; m_pWidget = NULL; return; } } else { // Must know the type. delete m_pWidget; m_pWidget = NULL; return; } BOOL bCreate = m_pWidget->Create(NULL, dwStyle, CRect(0, 0, 1, 1), CWnd::FromHandle(VOID2CX(GetContext(), CPaneCX)->GetPane()), GetDynamicControlID()); if(!bCreate) { delete m_pWidget; m_pWidget = NULL; return; } // Size the thing. // Buttons are 7 x 7 in dialog units. // Perform a conversion to pixels. LONG lUnits = GetDialogBaseUnits(); int32 lWidth = 7 * LOWORD(lUnits) / 4; int32 lHeight = 7 * HIWORD(lUnits) / 8; // Move it. m_pWidget->MoveWindow(1, 1, CASTINT(lWidth), CASTINT(lHeight), FALSE); } else if(GetContext()->IsPureDCContext()) { } } } // Copy the current data out of the layout struct into the form // widget, or mark that you should represent using the current data. void CFormRadio::UseCurrentData() { // Detect context type. if(GetContext()) { if(GetContext()->IsWindowContext()) { // Only continue if there's a widget at all. if(m_pWidget) { int iChecked = 0; // Sad default. if(GetElementToggleData()) { iChecked = GetElementToggleData()->toggled ? 1 : 0; } // Update the widget. if(m_pWidget->GetCheck() != iChecked) { m_pWidget->SetCheck(iChecked); } } } else if(GetContext()->IsPureDCContext()) { // Current data already reflected in toggle data. } } } // Copy the default data out of the layout struct into the form // widget, or mark that you should represent using the default data. void CFormRadio::UseDefaultData() { // Detect context type. if(GetContext()) { if(GetContext()->IsWindowContext()) { // Only continue if there's a widget at all. if(m_pWidget) { int iChecked = 0; // Sad default. if(GetElementToggleData()) { iChecked = GetElementToggleData()->default_toggle ? 1 : 0; } // Update the widget. m_pWidget->SetCheck(iChecked); } } else if(GetContext()->IsPureDCContext()) { // Set current to default. if(GetElementToggleData()) { GetElementToggleData()->toggled = GetElementToggleData()->default_toggle; } } } } // Fill in the layout size information in the layout struct regarding // the dimensions of the widget. void CFormRadio::FillSizeInfo() { // Detect context type. if(GetContext() && GetElement()) { if(GetContext()->IsWindowContext()) { // Only continue if there's a widget at all. if(m_pWidget) { // Determine out window position. CRect crWidget; m_pWidget->GetWindowRect(crWidget); // Munge it for layout. // We'll need to know how to undo this // in the display routine. GetElement()->width = crWidget.Width() + BUTTON_FUDGE; GetElement()->height = crWidget.Height() + BUTTON_FUDGE; GetElement()->baseline = GetElement()->height - (BUTTON_FUDGE - 1); GetElement()->border_vert_space = BUTTON_FUDGE/2; GetElement()->border_horiz_space = BUTTON_FUDGE/2; } else { GetElement()->width = 0; GetElement()->height = 0; GetElement()->baseline = 0; } } else if(GetContext()->IsPureDCContext()) { // Do some printing specific stuff here... CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX); // Size the thing. // Buttons are 7 x 7 in dialog units. // Perform a conversion to twips/whatever. LONG lUnits = GetDialogBaseUnits(); int32 lWidth = 7 * LOWORD(lUnits) / 4; int32 lHeight = 7 * HIWORD(lUnits) / 8; int32 lButtonFudge = pDCCX->Pix2TwipsY(BUTTON_FUDGE); lWidth = pDCCX->Pix2TwipsX(lWidth); lHeight = pDCCX->Pix2TwipsX(lHeight); GetElement()->width = lWidth + lButtonFudge; GetElement()->height = lHeight + lButtonFudge; GetElement()->baseline = GetElement()->height - (lButtonFudge - pDCCX->Pix2TwipsY(1)); } } } // Copy the current data out of the form element back into the // layout struct. void CFormRadio::UpdateCurrentData(BOOL bSubmit) { // Detect context type. if(GetContext()) { if(GetContext()->IsWindowContext()) { // Only continue if there's a widget at all. if(m_pWidget && ::IsWindow(m_pWidget->GetSafeHwnd())) { if(GetElementToggleData()) { // Update layout data as BOOL. GetElementToggleData()->toggled = m_pWidget->GetCheck() ? TRUE : FALSE; } } } else if(GetContext()->IsPureDCContext()) { // Nothing to update. } } } HWND CFormRadio::GetRaw() { return(m_pWidget ? m_pWidget->m_hWnd : NULL); }