mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-12 14:37:50 +00:00
788 lines
30 KiB
C++
Executable File
788 lines
30 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 "fmtxarea.h"
|
|
#include "odctrl.h"
|
|
#include "intl_csi.h"
|
|
|
|
// This file is dedicated to form type select one elements
|
|
// otherwise known as list boxes on windows and
|
|
// their implementation as requried by the XP layout
|
|
// library.
|
|
|
|
// Construction simply clears all members.
|
|
CFormTextarea::CFormTextarea()
|
|
{
|
|
// No Widget yet.
|
|
m_pWidget = NULL;
|
|
|
|
#ifdef XP_WIN16
|
|
// No segment yet.
|
|
m_hSegment = NULL;
|
|
#endif
|
|
}
|
|
|
|
// Destruction cleans out all members.
|
|
CFormTextarea::~CFormTextarea()
|
|
{
|
|
}
|
|
|
|
// 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 CFormTextarea::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 CFormTextarea::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 CFormTextarea::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 stuff done in FillSizeInfo
|
|
r.Inflate(0, -1 * pDCCX->Pix2TwipsY(EDIT_SPACE) / 2);
|
|
|
|
// Do something simple.
|
|
pDCCX->Display3DBox(r, pDCCX->ResolveLightLineColor(), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
|
|
|
|
// Decide if we're doing scrollers.
|
|
BOOL bHorizontal = FALSE;
|
|
if(GetElementTextareaData() && GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_OFF) {
|
|
bHorizontal = TRUE;
|
|
}
|
|
|
|
// Figure rects of scrollers.
|
|
LTRB VScroller(r.right - pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth), r.top, r.right, r.bottom);
|
|
if(bHorizontal) {
|
|
VScroller.bottom -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
|
|
}
|
|
LTRB HScroller(r.left, r.bottom - pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight), r.right - pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth), r.bottom);
|
|
|
|
// Adjust the original rect inside of the scroll bars and border.
|
|
r.left += pDCCX->Pix2TwipsY(2);
|
|
r.top += pDCCX->Pix2TwipsY(2);
|
|
r.right -= pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth);
|
|
if(bHorizontal) {
|
|
r.bottom -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
|
|
}
|
|
else {
|
|
r.bottom -= pDCCX->Pix2TwipsY(2);
|
|
}
|
|
|
|
// Time for DC work.
|
|
HDC pDC = pDCCX->GetContextDC();
|
|
if(pDC) {
|
|
// Figure up the DrawText rectangle (so that we can get the proportionals right).
|
|
int32 lDrawnWidth = 0;
|
|
int32 lDrawnHeight = 0;
|
|
CyaFont *pMyFont = 0;
|
|
if(GetElementTextareaData() && GetElementTextareaData()->current_text) {
|
|
char *pText = (char *)GetElementTextareaData()->current_text;
|
|
int32 lLength = XP_STRLEN(pText);
|
|
|
|
|
|
pDCCX->SelectNetscapeFont( pDC, GetTextAttr(), pMyFont );
|
|
if (!pMyFont) {
|
|
m_pWidget->ReleaseDC(CDC::FromHandle(pDC));
|
|
DestroyWidget();
|
|
pDCCX->ReleaseContextDC(pDC);
|
|
return;
|
|
}
|
|
SetWidgetFont(pDC, m_pWidget->m_hWnd);
|
|
r.left += pMyFont->GetMeanWidth() - pDCCX->Pix2TwipsY(2);
|
|
|
|
// Decide the output area for all text.
|
|
RECT crClip;
|
|
::SetRect(&crClip, CASTINT(r.left), CASTINT(r.top),
|
|
CASTINT(r.right), CASTINT(r.bottom));
|
|
RECT crSize = crClip;
|
|
|
|
// Figure up the draw text style we're asking for.
|
|
UINT uStyle = DT_LEFT | DT_NOPREFIX;
|
|
if(GetElementTextareaData()->auto_wrap != TEXTAREA_WRAP_OFF) {
|
|
// Text should have already been wrapped, but do it anyhow.
|
|
uStyle |= DT_WORDBREAK;
|
|
}
|
|
|
|
// Figure out the size.
|
|
// This does not draw anything.
|
|
int16 wincsid = 0 ;
|
|
if(GetContext()->GetContext())
|
|
wincsid = INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext()));
|
|
|
|
CIntlWin::DrawText(wincsid, pDC, pText, CASTINT(lLength), &crSize, uStyle | DT_CALCRECT);
|
|
lDrawnWidth = crSize.right - crSize.left;
|
|
lDrawnHeight = crSize.bottom - crSize.top;
|
|
|
|
// Set us to transparncy and do the deed.
|
|
int iOldBk = ::SetBkMode(pDC, TRANSPARENT);
|
|
CIntlWin::DrawText(wincsid, pDC, pText, CASTINT(lLength), &crClip, uStyle);
|
|
::SetBkMode(pDC, iOldBk);
|
|
pDCCX->ReleaseNetscapeFont( pDC, pMyFont );
|
|
// Restore the font.
|
|
}
|
|
|
|
// Draw the scrollers.
|
|
// Vertical is always present.
|
|
// Don't do if can't handle due to size limitations
|
|
pDCCX->Display3DBox(VScroller, pDCCX->ResolveLightLineColor(), pDCCX->ResolveLightLineColor(), pDCCX->Pix2TwipsY(2));
|
|
if(VScroller.Height() > pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight) * 2) {
|
|
POINT aPoints[3];
|
|
|
|
// Display top button.
|
|
LTRB TButton(VScroller.left, VScroller.top, VScroller.right, VScroller.top + pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight));
|
|
pDCCX->Display3DBox(TButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
|
|
TButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
|
|
VScroller.top += pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
|
|
|
|
// Arrow.
|
|
aPoints[0].x = CASTINT(TButton.left + TButton.Width() / 4);
|
|
aPoints[0].y = CASTINT(TButton.top + 2 * TButton.Height() / 3);
|
|
aPoints[1].x = CASTINT(TButton.left + TButton.Width() / 2);
|
|
aPoints[1].y = CASTINT(TButton.top + TButton.Height() / 3);
|
|
aPoints[2].x = CASTINT(TButton.left + 3 * TButton.Width() / 4);
|
|
aPoints[2].y = CASTINT(TButton.top + 2 * TButton.Height() / 3);
|
|
TRY {
|
|
HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
|
|
HBRUSH cbBlack;
|
|
HBRUSH pOldBrush = NULL;
|
|
if(cbBlack = CreateSolidBrush(RGB(0, 0, 0))) {
|
|
pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
|
|
}
|
|
HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
|
|
|
|
int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
|
|
::Polygon(pDC, aPoints, 3);
|
|
::SetPolyFillMode(pDC, iOldMode);
|
|
|
|
if(pOldPen) {
|
|
::SelectObject(pDC, pOldPen);
|
|
}
|
|
if(pOldBrush) {
|
|
::SelectObject(pDC, pOldBrush);
|
|
}
|
|
VERIFY(::DeleteObject(cpBlack));
|
|
VERIFY(::DeleteObject(cbBlack));
|
|
}
|
|
CATCH(CException, e) {
|
|
// Can't create pen.
|
|
}
|
|
END_CATCH
|
|
|
|
// Display bottom button.
|
|
LTRB BButton(VScroller.left, VScroller.bottom - pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight), VScroller.right, VScroller.bottom);
|
|
pDCCX->Display3DBox(BButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
|
|
BButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
|
|
VScroller.bottom -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
|
|
|
|
// Arrow.
|
|
aPoints[0].x = CASTINT(BButton.left + BButton.Width() / 4);
|
|
aPoints[0].y = CASTINT(BButton.top + BButton.Height() / 3);
|
|
aPoints[1].x = CASTINT(BButton.left + BButton.Width() / 2);
|
|
aPoints[1].y = CASTINT(BButton.top + 2 * BButton.Height() / 3);
|
|
aPoints[2].x = CASTINT(BButton.left + 3 * BButton.Width() / 4);
|
|
aPoints[2].y = CASTINT(BButton.top + BButton.Height() / 3);
|
|
TRY {
|
|
HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
|
|
HBRUSH cbBlack;
|
|
HBRUSH pOldBrush = NULL;
|
|
if(cbBlack = ::CreateSolidBrush(RGB(0, 0, 0))) {
|
|
pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
|
|
}
|
|
HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
|
|
|
|
int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
|
|
::Polygon(pDC, aPoints, 3);
|
|
::SetPolyFillMode(pDC, iOldMode);
|
|
|
|
if(pOldPen) {
|
|
::SelectObject(pDC, pOldPen);
|
|
}
|
|
if(pOldBrush) {
|
|
::SelectObject(pDC, pOldBrush);
|
|
}
|
|
VERIFY(::DeleteObject(cpBlack));
|
|
VERIFY(::DeleteObject(cbBlack));
|
|
}
|
|
CATCH(CException, e) {
|
|
// Can't create pen.
|
|
}
|
|
END_CATCH
|
|
|
|
// Decide if drawing inner tumbtrack.
|
|
if(r.Height() < lDrawnHeight) {
|
|
// Size of thumbtrack is a percentage.
|
|
int32 lPercent = r.Height() * 100 / lDrawnHeight;
|
|
int32 lThumb = lPercent * VScroller.Height() / 100;
|
|
LTRB Thumb(VScroller.left, VScroller.top, VScroller.right, VScroller.top + lThumb);
|
|
pDCCX->Display3DBox(Thumb, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
|
|
}
|
|
}
|
|
|
|
if(bHorizontal) {
|
|
// Don't do if can't handle due to size limitations
|
|
pDCCX->Display3DBox(HScroller, pDCCX->ResolveLightLineColor(), pDCCX->ResolveLightLineColor(), pDCCX->Pix2TwipsY(2));
|
|
if(HScroller.Width() > pDCCX->Pix2TwipsY(sysInfo.m_iScrollWidth) * 2) {
|
|
POINT aPoints[3];
|
|
|
|
// Display left button.
|
|
LTRB LButton(HScroller.left, HScroller.top, HScroller.left + pDCCX->Pix2TwipsY(sysInfo.m_iScrollWidth), HScroller.bottom);
|
|
pDCCX->Display3DBox(LButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
|
|
LButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
|
|
HScroller.left += pDCCX->Pix2TwipsY(sysInfo.m_iScrollWidth);
|
|
|
|
// Arrow.
|
|
aPoints[0].x = CASTINT(LButton.left + 2 * LButton.Width() / 3);
|
|
aPoints[0].y = CASTINT(LButton.top + LButton.Height() / 4);
|
|
aPoints[1].x = CASTINT(LButton.left + LButton.Width() / 3);
|
|
aPoints[1].y = CASTINT(LButton.top + LButton.Height() / 2);
|
|
aPoints[2].x = CASTINT(LButton.left + 2 * LButton.Width() / 3);
|
|
aPoints[2].y = CASTINT(LButton.top + 3 * LButton.Height() / 4);
|
|
TRY {
|
|
HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
|
|
HBRUSH cbBlack;
|
|
HBRUSH pOldBrush = NULL;
|
|
if(cbBlack = ::CreateSolidBrush(RGB(0, 0, 0))) {
|
|
pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
|
|
}
|
|
HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
|
|
|
|
int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
|
|
::Polygon(pDC, aPoints, 3);
|
|
::SetPolyFillMode(pDC, iOldMode);
|
|
|
|
if(pOldPen) {
|
|
::SelectObject(pDC, pOldPen);
|
|
}
|
|
if(pOldBrush) {
|
|
::SelectObject(pDC, pOldBrush);
|
|
}
|
|
VERIFY(::DeleteObject(cpBlack));
|
|
VERIFY(::DeleteObject(cbBlack));
|
|
}
|
|
CATCH(CException, e) {
|
|
// Can't create pen.
|
|
}
|
|
END_CATCH
|
|
|
|
// Display right button.
|
|
LTRB RButton(HScroller.right - pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth), HScroller.top, HScroller.right, HScroller.bottom);
|
|
pDCCX->Display3DBox(RButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
|
|
RButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
|
|
HScroller.right -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollWidth);
|
|
|
|
// Arrow.
|
|
aPoints[0].x = CASTINT(RButton.left + RButton.Width() / 3);
|
|
aPoints[0].y = CASTINT(RButton.top + RButton.Height() / 4);
|
|
aPoints[1].x = CASTINT(RButton.left + 2 * RButton.Width() / 3);
|
|
aPoints[1].y = CASTINT(RButton.top + RButton.Height() / 2);
|
|
aPoints[2].x = CASTINT(RButton.left + RButton.Width() / 3);
|
|
aPoints[2].y = CASTINT(RButton.top + 3 * RButton.Height() / 4);
|
|
TRY {
|
|
HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
|
|
HBRUSH cbBlack;
|
|
HBRUSH pOldBrush = NULL;
|
|
if(cbBlack = ::CreateSolidBrush(RGB(0, 0, 0))) {
|
|
pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
|
|
}
|
|
HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
|
|
|
|
int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
|
|
::Polygon(pDC, aPoints, 3);
|
|
::SetPolyFillMode(pDC, iOldMode);
|
|
|
|
if(pOldPen) {
|
|
::SelectObject(pDC, pOldPen);
|
|
}
|
|
if(pOldBrush) {
|
|
::SelectObject(pDC, pOldBrush);
|
|
}
|
|
VERIFY(::DeleteObject(cpBlack));
|
|
VERIFY(::DeleteObject(cbBlack));
|
|
}
|
|
CATCH(CException, e) {
|
|
// Can't create pen.
|
|
}
|
|
END_CATCH
|
|
|
|
// Decide if drawing inner tumbtrack.
|
|
if(r.Width() < lDrawnWidth) {
|
|
// Size of thumbtrack is a percentage.
|
|
int32 lPercent = r.Width() * 100 / lDrawnWidth;
|
|
int32 lThumb = lPercent * HScroller.Width() / 100;
|
|
LTRB Thumb(HScroller.left, HScroller.top, HScroller.left + lThumb, HScroller.bottom);
|
|
pDCCX->Display3DBox(Thumb, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
|
|
}
|
|
}
|
|
}
|
|
// Release the DC.
|
|
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 CFormTextarea::DestroyWidget()
|
|
{
|
|
// Get rid of the widget if around.
|
|
if(m_pWidget) {
|
|
m_pWidget->DestroyWindow();
|
|
delete m_pWidget;
|
|
m_pWidget = NULL;
|
|
}
|
|
|
|
#ifdef XP_WIN16
|
|
// Get rid of the extra segment if around.
|
|
if(m_hSegment) {
|
|
GlobalFree(m_hSegment);
|
|
m_hSegment = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Create the widget (window) implementation of the form
|
|
// but DO NOT DISPLAY.
|
|
void CFormTextarea::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.
|
|
m_hSegment = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 4 * 1024);
|
|
if(m_hSegment) {
|
|
LPVOID lpPtr = GlobalLock(m_hSegment);
|
|
LocalInit(HIWORD((LONG)lpPtr), 0, (WORD)(GlobalSize(m_hSegment) - 16));
|
|
UnlockSegment(HIWORD((LONG)lpPtr));
|
|
m_pWidget->SetInstance((HINSTANCE)HIWORD((LONG)lpPtr));
|
|
}
|
|
else {
|
|
delete m_pWidget;
|
|
m_pWidget = NULL;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// The style of the widget to be created.
|
|
DWORD dwStyle = WS_CHILD | WS_VSCROLL | WS_BORDER | ES_LEFT | WS_TABSTOP | ES_MULTILINE;
|
|
if(GetElementTextareaData()) {
|
|
// If no word wrapping, add a horizontal scrollbar.
|
|
if(GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_OFF) {
|
|
dwStyle |= WS_HSCROLL;
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
#ifdef XP_WIN16
|
|
GlobalFree(m_hSegment);
|
|
m_hSegment = NULL;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
CyaFont *pMyFont;
|
|
|
|
|
|
// Measure some text.
|
|
CDC *pDC = m_pWidget->GetDC();
|
|
if(pDC) {
|
|
CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
|
|
pDCCX->SelectNetscapeFont( pDC->GetSafeHdc(), GetTextAttr(), pMyFont );
|
|
if (pMyFont) {
|
|
SetWidgetFont(pDC->GetSafeHdc(), m_pWidget->m_hWnd);
|
|
GetElement()->text_attr->FE_Data = pMyFont;
|
|
// Default length is 20
|
|
// Default lines is 1
|
|
int32 lLength = 20;
|
|
int32 lLines = 1;
|
|
|
|
// See if we can measure the default text, and/or
|
|
// set up the size and size limits.
|
|
if(GetElementTextareaData()) {
|
|
if(GetElementTextareaData()->cols > 0) {
|
|
// Use provided size.
|
|
lLength = GetElementTextareaData()->cols;
|
|
}
|
|
if(GetElementTextareaData()->rows > 0) {
|
|
// Use provided size.
|
|
lLines = GetElementTextareaData()->rows;
|
|
}
|
|
}
|
|
|
|
// Now figure up the width and height we would like.
|
|
// int32 lWidgetWidth = (lLength + 1) * tm.tmAveCharWidth + sysInfo.m_iScrollWidth;
|
|
// int32 lWidgetHeight = (lLines + 1) * tm.tmHeight;
|
|
int32 lWidgetWidth = (lLength + 1) * pMyFont->GetMeanWidth() + sysInfo.m_iScrollWidth;
|
|
int32 lWidgetHeight = (lLines + 1) * pMyFont->GetHeight();
|
|
|
|
// If no word wrapping, account a horizontal scrollbar.
|
|
if(GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_OFF) {
|
|
lWidgetHeight += sysInfo.m_iScrollHeight;
|
|
}
|
|
|
|
// Move the window.
|
|
m_pWidget->MoveWindow(1, 1, CASTINT(lWidgetWidth), CASTINT(lWidgetHeight), FALSE);
|
|
|
|
pDCCX->ReleaseNetscapeFont( pDC->GetSafeHdc(), pMyFont );
|
|
pDCCX->ReleaseContextDC(pDC->GetSafeHdc());
|
|
m_pWidget->ReleaseDC(pDC);
|
|
}
|
|
else {
|
|
m_pWidget->ReleaseDC(pDC);
|
|
DestroyWidget();
|
|
}
|
|
|
|
}
|
|
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 CFormTextarea::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(GetElementTextareaData() && GetElementTextareaData()->current_text) {
|
|
pCurrent = (char *)GetElementTextareaData()->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 current 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 CFormTextarea::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(GetElementTextareaData() && GetElementTextareaData()->default_text) {
|
|
pDefault = (char *)GetElementTextareaData()->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
|
|
if(GetElementTextareaData()) {
|
|
// Clear the current text if present.
|
|
if(GetElementTextareaData()->current_text) {
|
|
XP_FREE(GetElementTextareaData()->current_text);
|
|
GetElementTextareaData()->current_text = NULL;
|
|
}
|
|
|
|
// Copy over the default_text.
|
|
if(GetElementTextareaData()->default_text) {
|
|
int32 lSize = XP_STRLEN((char *)GetElementTextareaData()->default_text) + 1;
|
|
GetElementTextareaData()->current_text = (XP_Block)XP_ALLOC(lSize);
|
|
if(GetElementTextareaData()->current_text) {
|
|
memcpy(GetElementTextareaData()->current_text,
|
|
GetElementTextareaData()->default_text,
|
|
CASTSIZE_T(lSize));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fill in the layout size information in the layout struct regarding
|
|
// the dimensions of the widget.
|
|
void CFormTextarea::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;
|
|
|
|
// Baseline needs text metric information.
|
|
GetElement()->baseline = GetElement()->height; // ugly default in case of failure below.
|
|
CDC *pDC = m_pWidget->GetDC();
|
|
if(pDC) {
|
|
// Need to specifically select the font before calling GetTextMetrics.
|
|
CyaFont *pMyFont;
|
|
CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
|
|
pDCCX->SelectNetscapeFont( pDC->GetSafeHdc(), GetTextAttr(), pMyFont );
|
|
if (pMyFont) {
|
|
SetWidgetFont(pDC->GetSafeHdc(), m_pWidget->m_hWnd);
|
|
GetElement()->baseline -= (pMyFont->GetHeight() / 2 + pMyFont->GetDescent()) / 2;
|
|
pDCCX->ReleaseNetscapeFont( pDC->GetSafeHdc(), pMyFont );
|
|
m_pWidget->ReleaseDC(pDC);
|
|
}
|
|
else {
|
|
m_pWidget->ReleaseDC(pDC);
|
|
DestroyWidget();
|
|
return;
|
|
}
|
|
|
|
}
|
|
}
|
|
else {
|
|
// No widget, tell layout nothing.
|
|
GetElement()->width = 0;
|
|
GetElement()->height = 0;
|
|
GetElement()->baseline = 0;
|
|
}
|
|
}
|
|
else if(GetContext()->IsPureDCContext()) {
|
|
// Do some printing specific stuff here...
|
|
int32 lWidth = 0;
|
|
int32 lHeight = 0;
|
|
int32 lBaseline = 0;
|
|
|
|
CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
|
|
HDC pDC = pDCCX->GetAttribDC();
|
|
if(pDC) {
|
|
// Have the DC, attempt to select the widget font.
|
|
CyaFont *pMyFont;
|
|
|
|
pDCCX->SelectNetscapeFont( pDC, GetTextAttr(), pMyFont );
|
|
if (pMyFont) {
|
|
SetWidgetFont(pDC, m_pWidget->m_hWnd);
|
|
int32 lColumns = 20;
|
|
int32 lRows = 1;
|
|
|
|
// See if we can measure the default text and/or set up
|
|
// size limits.
|
|
if(GetElementTextareaData()) {
|
|
if(GetElementTextareaData()->cols > 0) {
|
|
lColumns = GetElementTextareaData()->cols;
|
|
}
|
|
if(GetElementTextareaData()->rows > 0) {
|
|
lRows = GetElementTextareaData()->rows;
|
|
}
|
|
}
|
|
|
|
// Figure up width and height we would like.
|
|
// lWidth = (lColumns + 1) * tm.tmAveCharWidth + pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth);
|
|
// lHeight = (lRows + 1) * tm.tmHeight;
|
|
lWidth = (lColumns + 1) * pMyFont->GetMeanWidth() + pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth);
|
|
lHeight = (lRows + 1) * pMyFont->GetHeight();
|
|
|
|
// If no word wrapping, add a horizontal scrollbar.
|
|
if(GetElementTextareaData() && GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_OFF) {
|
|
lHeight += pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
|
|
}
|
|
|
|
// Adjust a little bit more, will need to know how to decode this
|
|
// in display.
|
|
lHeight += pDCCX->Pix2TwipsY(EDIT_SPACE);
|
|
|
|
// Figure the baseline.
|
|
// lBaseline = lHeight - ((tm.tmHeight / 2 + tm.tmDescent) / 2);
|
|
lBaseline = lHeight - ((pMyFont->GetHeight() / 2 + pMyFont->GetDescent()) / 2);
|
|
// }
|
|
|
|
pDCCX->ReleaseNetscapeFont( pDC, pMyFont );
|
|
}
|
|
else {
|
|
m_pWidget->ReleaseDC(CDC::FromHandle(pDC));
|
|
DestroyWidget();
|
|
}
|
|
|
|
pDCCX->ReleaseContextDC(pDC);
|
|
}
|
|
|
|
// Tell layout what we 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 CFormTextarea::UpdateCurrentData()
|
|
{
|
|
if(GetContext()) {
|
|
if(GetContext()->IsWindowContext()) {
|
|
if(m_pWidget && ::IsWindow(m_pWidget->GetSafeHwnd()) && GetElementTextareaData()) {
|
|
// Free off any current text.
|
|
if(GetElementTextareaData()->current_text) {
|
|
XP_FREE(GetElementTextareaData()->current_text);
|
|
GetElementTextareaData()->current_text = NULL;
|
|
}
|
|
|
|
// If we have hard wrapping, set the flag in the edit field now
|
|
// bofore we get the length.
|
|
if(GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_HARD) {
|
|
m_pWidget->FmtLines(TRUE);
|
|
}
|
|
|
|
// See if we've got anything.
|
|
int32 lLength = m_pWidget->GetWindowTextLength();
|
|
if(lLength > 0) {
|
|
GetElementTextareaData()->current_text = (XP_Block)XP_ALLOC(lLength + 1);
|
|
if(GetElementTextareaData()->current_text) {
|
|
m_pWidget->GetWindowText((char *)GetElementTextareaData()->current_text, CASTINT(lLength + 1));
|
|
|
|
// strip out the \r\r\n if we are a hard-break text area
|
|
if(GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_HARD) {
|
|
char *pSrc;
|
|
char *pDest;
|
|
|
|
// start both off at the beginning
|
|
pSrc = (char *)GetElementTextareaData()->current_text;
|
|
pDest = (char *)GetElementTextareaData()->current_text;
|
|
|
|
while(pSrc && *pSrc) {
|
|
if(pSrc[0] == '\r' && pSrc[1] == '\r' && pSrc[2] == '\n') {
|
|
// convert the soft line break into a hard line break
|
|
pSrc += 3;
|
|
*pDest++ = '\r';
|
|
*pDest++ = '\n';
|
|
}
|
|
else {
|
|
// just copy this one over
|
|
*pDest++ = *pSrc++;
|
|
}
|
|
}
|
|
|
|
// NULL termination is your friend
|
|
*pDest = '\0';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(GetContext()->IsPureDCContext()) {
|
|
// Printing/metafile
|
|
// Whatever is current is current.
|
|
}
|
|
}
|
|
}
|
|
|
|
HWND CFormTextarea::GetRaw()
|
|
{
|
|
return(m_pWidget ? m_pWidget->m_hWnd : NULL);
|
|
}
|
|
|