зеркало из https://github.com/mozilla/gecko-dev.git
411 строки
14 KiB
C++
Executable File
411 строки
14 KiB
C++
Executable File
/* -*- 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);
|
|
}
|
|
|