mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +00:00
550 lines
18 KiB
C++
Executable File
550 lines
18 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 "fmtext.h"
|
|
#include "odctrl.h"
|
|
#include "intl_csi.h"
|
|
// This file is dedicated to form type text edit boxes on windows and
|
|
// their implementation as required by the XP layout library.
|
|
|
|
static const char gWndProcProperty[] = "CFormTextWndProc";
|
|
|
|
// Construction simply clears all members.
|
|
CFormText::CFormText()
|
|
{
|
|
// No widget yet.
|
|
m_pWidget = NULL;
|
|
mRealWndProc = 0;
|
|
}
|
|
|
|
// Destruction cleans out all members.
|
|
CFormText::~CFormText()
|
|
{
|
|
}
|
|
|
|
// 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 CFormText::SetElement(LO_FormElementStruct *pFormElement)
|
|
{
|
|
// Call the base.
|
|
CFormElement::SetElement(pFormElement);
|
|
|
|
// Let the widget know the element.
|
|
if(m_pWidget) {
|
|
m_pWidget->SetContext(GetContext() ? GetContext()->GetContext() : NULL, GetElement());
|
|
}
|
|
}
|
|
|
|
// Set the owning context.
|
|
// Use this to determine what context we live in and how we should
|
|
// represent ourself (DC or window).
|
|
void CFormText::SetContext(CAbstractCX *pCX)
|
|
{
|
|
// Call the base.
|
|
CFormElement::SetContext(pCX);
|
|
|
|
// Let the widget know the context.
|
|
if(m_pWidget) {
|
|
m_pWidget->SetContext(GetContext() ? GetContext()->GetContext() : NULL, GetElement());
|
|
}
|
|
}
|
|
|
|
// Display the form element given the particular context we are in.
|
|
// Possibly only use a DC for representation, or have the
|
|
// window move.
|
|
void CFormText::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);
|
|
LTRB r(Rect.left, Rect.top, Rect.right, Rect.bottom);
|
|
|
|
// Adjust for what we bastardized earlier in fill size info.
|
|
r.Inflate(0, -1 * pDCCX->Pix2TwipsY(EDIT_SPACE) / 2);
|
|
|
|
// Do something simple.
|
|
pDCCX->Display3DBox(r, pDCCX->ResolveLightLineColor(), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
|
|
|
|
// Final adjustment for below...
|
|
r.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Twips2PixY(2));
|
|
|
|
// Is there text to output.
|
|
if(GetElementTextData() && GetElementTextData()->current_text) {
|
|
char *pText = (char *)GetElementTextData()->current_text;
|
|
|
|
// Obtain the font for the text to be drawn.
|
|
// Get the DC.
|
|
HDC pDC = pDCCX->GetContextDC();
|
|
if(pDC) {
|
|
CyaFont *pMyFont;
|
|
|
|
pDCCX->SelectNetscapeFont( pDC, GetTextAttr(), pMyFont );
|
|
if (pMyFont) {
|
|
int32 lTextLength = XP_STRLEN(pText);
|
|
char *pTextBuf = new char[lTextLength + 1];
|
|
if(pTextBuf) {
|
|
// Clear it.
|
|
memset(pTextBuf, 0, CASTSIZE_T(lTextLength + 1));
|
|
|
|
// Decide if a password.
|
|
if(GetElementMinimalData()->type == FORM_TYPE_PASSWORD) {
|
|
memset(pTextBuf, '*', CASTSIZE_T(lTextLength));
|
|
}
|
|
else {
|
|
strcpy(pTextBuf, pText);
|
|
}
|
|
|
|
// Text mode must go transparent (some printers block out drawing around text).
|
|
int iOldBk = ::SetBkMode(pDC, TRANSPARENT);
|
|
|
|
// Decide the destination for the text rect.
|
|
// We need to move the text to the right and left some, and on the Y.
|
|
RECT crDest;
|
|
::SetRect(&crDest, CASTINT(r.left), CASTINT(r.top), CASTINT(r.right), CASTINT(r.bottom));
|
|
crDest.left += pMyFont->GetMeanWidth();
|
|
crDest.top += ((crDest.bottom - crDest.top) - (pMyFont->GetHeight())) / 2;
|
|
// Finally draw the text.
|
|
// The clipping rect is not the destination rect.
|
|
CIntlWin::ExtTextOut(
|
|
(GetContext()->GetContext() ?
|
|
INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext())) :0),
|
|
pDC, crDest.left,
|
|
crDest.top, ETO_CLIPPED, CRect(CASTINT(r.left),
|
|
CASTINT(r.top), CASTINT(r.right),
|
|
CASTINT(r.bottom)), pTextBuf, CASTINT(lTextLength), NULL);
|
|
|
|
// Restore Bk mode.
|
|
::SetBkMode(pDC, iOldBk);
|
|
|
|
// Get rid of the buffer.
|
|
delete[] pTextBuf;
|
|
// }
|
|
|
|
pDCCX->ReleaseNetscapeFont( pDC, pMyFont );
|
|
}
|
|
else {
|
|
m_pWidget->ReleaseDC(CDC::FromHandle(pDC));
|
|
DestroyWidget();
|
|
}
|
|
pDCCX->ReleaseContextDC(pDC);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(GetContext()->IsWindowContext()) {
|
|
MoveWindow(m_pWidget->m_hWnd, Rect.left, Rect.top + EDIT_SPACE / 2);
|
|
}
|
|
else {
|
|
// Is undefined....
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
|
|
// Call the base.
|
|
CFormElement::DisplayFormElement(Rect);
|
|
}
|
|
|
|
// Destroy the widget (window) implemenation of the form.
|
|
void CFormText::DestroyWidget()
|
|
{
|
|
// Get rid of the widget if around.
|
|
if(m_pWidget) {
|
|
RemoveProp(m_pWidget->m_hWnd, gWndProcProperty);
|
|
if (mRealWndProc)
|
|
SetWindowLong(m_pWidget->m_hWnd, GWL_WNDPROC,
|
|
(LONG)mRealWndProc);
|
|
m_pWidget->DestroyWindow();
|
|
delete m_pWidget;
|
|
m_pWidget = NULL;
|
|
}
|
|
}
|
|
|
|
// Create the widget (window) implementation of the form
|
|
// but DO NOT DISPLAY.
|
|
void CFormText::CreateWidget()
|
|
{
|
|
if(GetContext() && GetElement()) {
|
|
if(GetContext()->IsWindowContext() && VOID2CX(GetContext(), CPaneCX)->GetPane()) {
|
|
// Need a widget representation.
|
|
ASSERT(m_pWidget == NULL);
|
|
m_pWidget = new CODNetscapeEdit;
|
|
|
|
if(m_pWidget == NULL) {
|
|
return;
|
|
}
|
|
|
|
// Inform widget of context and element.
|
|
m_pWidget->SetContext(GetContext()->GetContext(), GetElement());
|
|
|
|
#ifdef XP_WIN16
|
|
// On 16 bits, we need to set the segment of the widget before creation.
|
|
HINSTANCE hSegment = GetSegment();
|
|
if(hSegment) {
|
|
m_pWidget->SetInstance(hSegment);
|
|
}
|
|
else {
|
|
delete m_pWidget;
|
|
m_pWidget = NULL;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// The style of the widget to be created.
|
|
DWORD dwStyle = WS_CHILD | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP;
|
|
if(GetElementMinimalData()) {
|
|
switch(GetElementMinimalData()->type) {
|
|
case FORM_TYPE_PASSWORD:
|
|
dwStyle |= ES_PASSWORD;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
// Must set styles.
|
|
delete m_pWidget;
|
|
m_pWidget = NULL;
|
|
return;
|
|
}
|
|
|
|
// Create the widget, hidden, and with a bad size.
|
|
BOOL bCreate =
|
|
#ifdef XP_WIN32
|
|
m_pWidget->CreateEx(WS_EX_CLIENTEDGE,
|
|
_T("EDIT"),
|
|
NULL,
|
|
dwStyle,
|
|
1, 1, 0, 0,
|
|
VOID2CX(GetContext(), CPaneCX)->GetPane(),
|
|
(HMENU)GetDynamicControlID(),
|
|
NULL);
|
|
|
|
#else
|
|
m_pWidget->Create(dwStyle, CRect(1, 1, 0, 0),
|
|
CWnd::FromHandle(VOID2CX(GetContext(), CPaneCX)->GetPane()),
|
|
GetDynamicControlID());
|
|
#endif
|
|
|
|
if(!bCreate) {
|
|
delete m_pWidget;
|
|
m_pWidget = NULL;
|
|
return;
|
|
}
|
|
|
|
SetProp(m_pWidget->m_hWnd, gWndProcProperty, this);
|
|
mRealWndProc = (WNDPROC)SetWindowLong(m_pWidget->m_hWnd,
|
|
GWL_WNDPROC, (LONG)TempWndProc);
|
|
|
|
// Next, need to size the widget.
|
|
// Obtain a font.
|
|
// Measure some text.
|
|
CDC *pDC = m_pWidget->GetDC();
|
|
CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
|
|
if(pDC) {
|
|
// Default length is 20
|
|
int32 lLength = 20;
|
|
CyaFont *pMyFont;
|
|
|
|
pDCCX->SelectNetscapeFont( pDC->GetSafeHdc(), GetTextAttr(), pMyFont );
|
|
if (pMyFont) {
|
|
SetWidgetFont(pDC->GetSafeHdc(), m_pWidget->m_hWnd);
|
|
GetElement()->text_attr->FE_Data = pMyFont;
|
|
// Now figure up the width and height we would like.
|
|
int32 lWidgetWidth = pMyFont->GetMaxWidth();
|
|
int32 lWidgetHeight = pMyFont->GetHeight() + (pMyFont->GetHeight() / 2);
|
|
|
|
// See if we can measure the default text, and/or
|
|
// set up the size and size limits.
|
|
if(GetElementTextData()) {
|
|
if(GetElementTextData()->size > 0) {
|
|
// Use provided size.
|
|
lLength = GetElementTextData()->size;
|
|
|
|
// Use average width.
|
|
lWidgetWidth += lLength * pMyFont->GetMeanWidth();
|
|
}
|
|
else if(GetElementTextData()->default_text) {
|
|
// Use length of text, exactly.
|
|
char *pDefault = (char *)GetElementTextData()->default_text;
|
|
|
|
lLength = XP_STRLEN(pDefault);
|
|
SIZE csz;
|
|
CIntlWin::GetTextExtentPointWithCyaFont(pMyFont,
|
|
INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext())),
|
|
pDC->GetSafeHdc(), pDefault, CASTINT(lLength), &csz);
|
|
// Use this width.
|
|
lWidgetWidth += csz.cx;
|
|
}
|
|
|
|
// Hold to the maximum size limit, and set it.
|
|
if(GetElementTextData()->max_size >= 0) {
|
|
m_pWidget->LimitText(CASTINT(GetElementTextData()->max_size));
|
|
}
|
|
}
|
|
|
|
// Restore old font selection.
|
|
pDCCX->ReleaseNetscapeFont( pDC->GetSafeHdc(), pMyFont );
|
|
m_pWidget->MoveWindow(1, 1, CASTINT(lWidgetWidth), CASTINT(lWidgetHeight), FALSE);
|
|
m_pWidget->ReleaseDC(pDC);
|
|
}
|
|
else {
|
|
m_pWidget->ReleaseDC(pDC);
|
|
DestroyWidget();
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
// No DC, no widget.
|
|
DestroyWidget();
|
|
return;
|
|
}
|
|
}
|
|
else if(GetContext()->IsPureDCContext()) {
|
|
// Need a drawn representation.
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copy the current data out of the layout struct into the form
|
|
// widget, or mark that you should represent using the current data.
|
|
void CFormText::UseCurrentData()
|
|
{
|
|
// Detect context type and do the right thing.
|
|
if(GetContext()) {
|
|
if(GetContext()->IsWindowContext()) {
|
|
// Need a widget.
|
|
if(m_pWidget) {
|
|
// Determine the current text to set.
|
|
char *pCurrent = "";
|
|
if(GetElementTextData() && GetElementTextData()->current_text) {
|
|
pCurrent = (char *)GetElementTextData()->current_text;
|
|
}
|
|
// We have to SetContext to the widget before we SetWindowText
|
|
// Otherwise, the widget don't know what csid the text is.
|
|
m_pWidget->SetContext(GetContext()->GetContext(), GetElement());
|
|
|
|
m_pWidget->SetWindowText(pCurrent);
|
|
}
|
|
}
|
|
else if(GetContext()->IsPureDCContext()) {
|
|
// Printing/metafile
|
|
// Whatever is in current data is current....
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copy the default data out of the layout struct into the form
|
|
// widget, or mark that you should represent using the default data.
|
|
void CFormText::UseDefaultData()
|
|
{
|
|
// Detect context type and do the right thing.
|
|
if(GetContext()) {
|
|
if(GetContext()->IsWindowContext()) {
|
|
// Need a widget.
|
|
if(m_pWidget) {
|
|
// Determine the default text to set.
|
|
char *pDefault = "";
|
|
if(GetElementTextData() && GetElementTextData()->default_text) {
|
|
pDefault = (char *)GetElementTextData()->default_text;
|
|
}
|
|
// We have to SetContext to the widget before we SetWindowText
|
|
// Otherwise, the widget don't know what csid the text is.
|
|
m_pWidget->SetContext(GetContext()->GetContext(), GetElement());
|
|
m_pWidget->SetWindowText(pDefault);
|
|
}
|
|
}
|
|
else if(GetContext()->IsPureDCContext()) {
|
|
// Printing/metafile
|
|
// Delete any current data, attempt to use the default data if present.
|
|
if(GetElementTextData()) {
|
|
if(GetElementTextData()->current_text) {
|
|
XP_FREE(GetElementTextData()->current_text);
|
|
GetElementTextData()->current_text = NULL;
|
|
}
|
|
|
|
if(GetElementTextData()->default_text) {
|
|
char *pText = (char *)GetElementTextData()->default_text;
|
|
int32 lSize = XP_STRLEN(pText) + 1;
|
|
GetElementTextData()->current_text = (XP_Block)XP_ALLOC(lSize);
|
|
memcpy(GetElementTextData()->current_text, pText, CASTSIZE_T(lSize));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fill in the layout size information in the layout struct regarding
|
|
// the dimensions of the widget.
|
|
void CFormText::FillSizeInfo()
|
|
{
|
|
// Detect context type and do the right thing.
|
|
if(GetContext() && GetElement()) {
|
|
if(GetContext()->IsWindowContext()) {
|
|
// Need a widget.
|
|
if(m_pWidget) {
|
|
// Determine our window position.
|
|
CRect crRect;
|
|
m_pWidget->GetWindowRect(crRect);
|
|
|
|
// Munge the coordinate a little for layout.
|
|
// We'll have to know how to decode this information
|
|
// in the display routine (by half).
|
|
GetElement()->width = crRect.Width();
|
|
GetElement()->height = crRect.Height() + EDIT_SPACE;
|
|
GetElement()->border_vert_space = EDIT_SPACE/2;
|
|
GetElement()->baseline = GetElement()->height - GetElement()->height / 4;
|
|
}
|
|
else {
|
|
// No widget, tell layout nothing.
|
|
GetElement()->width = 0;
|
|
GetElement()->height = 0;
|
|
GetElement()->baseline = 0;
|
|
}
|
|
}
|
|
else if(GetContext()->IsPureDCContext()) {
|
|
int32 lWidth = 0;
|
|
int32 lHeight = 0;
|
|
int32 lBaseline = 0;
|
|
|
|
// Need to figure the size of the widget.
|
|
CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
|
|
HDC pDC = pDCCX->GetAttribDC();
|
|
if(pDC) {
|
|
CyaFont *pMyFont;
|
|
int32 lLength = 20;
|
|
|
|
pDCCX->SelectNetscapeFont( pDC, GetTextAttr(), pMyFont );
|
|
if (pMyFont) {
|
|
lWidth = pMyFont->GetMaxWidth();
|
|
lHeight = pMyFont->GetHeight() + pMyFont->GetHeight() / 2 + pDCCX->Twips2PixY(EDIT_SPACE);
|
|
|
|
// Attempt to measure text.
|
|
if(GetElementTextData()) {
|
|
if(GetElementTextData()->size > 0) {
|
|
// Use provided size.
|
|
lLength = GetElementTextData()->size;
|
|
|
|
// Figure width using average char width.
|
|
lWidth += lLength * pMyFont->GetMeanWidth();
|
|
}
|
|
else if(GetElementTextData()->default_text) {
|
|
// Use length of text instead.
|
|
char *pText = (char *)GetElementTextData()->default_text;
|
|
lLength = XP_STRLEN(pText);
|
|
|
|
// Use exact size information.
|
|
SIZE csz;
|
|
CIntlWin::GetTextExtentPointWithCyaFont(pMyFont,
|
|
INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext())),
|
|
pDC, pText, CASTINT(lLength), &csz);
|
|
lWidth += csz.cx;
|
|
}
|
|
}
|
|
|
|
// Figure baseline.
|
|
lBaseline = lHeight - (pMyFont->GetHeight() / 2 + pMyFont->GetDescent()) / 2;
|
|
pDCCX->ReleaseNetscapeFont( pDC, pMyFont );
|
|
}
|
|
else {
|
|
m_pWidget->ReleaseDC(CDC::FromHandle(pDC));
|
|
DestroyWidget();
|
|
}
|
|
pDCCX->ReleaseContextDC(pDC);
|
|
}
|
|
|
|
// Inform layout what we now know.
|
|
GetElement()->width = lWidth;
|
|
GetElement()->height = lHeight;
|
|
GetElement()->baseline = lBaseline;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copy the current data out of the form element back into the
|
|
// layout struct.
|
|
void CFormText::UpdateCurrentData(BOOL bSubmit)
|
|
{
|
|
if(GetContext()) {
|
|
if(GetContext()->IsWindowContext()) {
|
|
if(m_pWidget && ::IsWindow(m_pWidget->GetSafeHwnd()) && GetElementTextData()) {
|
|
// Free off any current text.
|
|
if(GetElementTextData()->current_text) {
|
|
XP_FREE(GetElementTextData()->current_text);
|
|
GetElementTextData()->current_text = NULL;
|
|
}
|
|
// See if we've got anything.
|
|
int32 lLength = m_pWidget->GetWindowTextLength();
|
|
if(lLength > 0) {
|
|
GetElementTextData()->current_text = (XP_Block)XP_ALLOC(lLength + 1);
|
|
if(GetElementTextData()->current_text) {
|
|
m_pWidget->GetWindowText((char *)GetElementTextData()->current_text, CASTINT(lLength + 1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(GetContext()->IsPureDCContext()) {
|
|
// Printing/metafile
|
|
// If there is no current data, attempt to use the default data if present.
|
|
if(GetElementTextData()) {
|
|
if(GetElementTextData()->default_text) {
|
|
char *pText = (char *)GetElementTextData()->default_text;
|
|
if(GetElementTextData()->current_text == NULL) {
|
|
int32 lSize = XP_STRLEN(pText) + 1;
|
|
GetElementTextData()->current_text = (XP_Block)XP_ALLOC(lSize);
|
|
memcpy(GetElementTextData()->current_text, pText, CASTSIZE_T(lSize));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HWND CFormText::GetRaw()
|
|
{
|
|
return(m_pWidget ? m_pWidget->m_hWnd : NULL);
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK EXPORT CFormText::TempWndProc(HWND hWnd, UINT message,
|
|
WPARAM wParam, LPARAM lParam) {
|
|
|
|
LRESULT ret;
|
|
CFormText *thisObj = (CFormText *)GetProp(hWnd, gWndProcProperty);
|
|
|
|
ASSERT(thisObj);
|
|
if (!thisObj)
|
|
return 0;
|
|
|
|
/* Standard processing is fine, except for mouseactivate messages. We explicitly
|
|
activate the window if the standard windproc seems to think we should. A
|
|
doubleclick in an inactive window running under NT 4.0 will otherwise cause
|
|
the window to lose focus (and textedit fields in forms seem to be inactive
|
|
unless we take this step.)
|
|
*/
|
|
ret = CallWindowProc(thisObj->mRealWndProc, hWnd, message, wParam, lParam);
|
|
if (message == WM_MOUSEACTIVATE && (ret == MA_ACTIVATE || ret == MA_ACTIVATEANDEAT))
|
|
CallWindowProc(thisObj->mRealWndProc, hWnd, WM_ACTIVATE, WA_ACTIVE, NULL);
|
|
return ret;
|
|
}
|