home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / fmtxarea.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  30.7 KB  |  788 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "stdafx.h"
  20.  
  21. #include "fmtxarea.h"
  22. #include "odctrl.h"
  23. #include "intl_csi.h"
  24.  
  25. //    This file is dedicated to form type select one elements
  26. //        otherwise known as list boxes on windows and
  27. //        their implementation as requried by the XP layout
  28. //        library.
  29.  
  30. //    Construction simply clears all members.
  31. CFormTextarea::CFormTextarea()
  32. {
  33.     //    No Widget yet.
  34.     m_pWidget = NULL;
  35.  
  36. #ifdef XP_WIN16
  37.     //    No segment yet.
  38.     m_hSegment = NULL;
  39. #endif
  40. }
  41.  
  42. //    Destruction cleans out all members.
  43. CFormTextarea::~CFormTextarea()
  44. {
  45. }
  46.  
  47. //    How to set the LO form element.
  48. //    This may change during the lifetime of an instance, so use this
  49. //        to update all referencing values.
  50. void CFormTextarea::SetElement(LO_FormElementStruct *pFormElement)
  51. {
  52.     //    Call the base.
  53.     CFormElement::SetElement(pFormElement);
  54.  
  55.     //    Let the widget know the element.
  56.     if(m_pWidget)    {
  57.         m_pWidget->SetContext(GetContext() ? GetContext()->GetContext() : NULL, GetElement());
  58.     }
  59. }
  60.  
  61. //    Set the owning context.
  62. //    Use this to determine what context we live in and how we should
  63. //        represent ourself (DC or window).
  64. void CFormTextarea::SetContext(CAbstractCX *pCX)
  65. {
  66.     //    Call the base.
  67.     CFormElement::SetContext(pCX);
  68.  
  69.     //    Let the widget know the context.
  70.     if(m_pWidget)    {
  71.         m_pWidget->SetContext(GetContext() ? GetContext()->GetContext() : NULL, GetElement());
  72.     }
  73. }
  74.  
  75. //    Display the form element given the particular context we are in.
  76. //    Possibly only use a DC for representation, or have the
  77. //        window move.
  78. void CFormTextarea::DisplayFormElement(LTRB& Rect)
  79. {
  80.     //    Display only has meaning if our context is a device context.
  81.     if(GetContext() && GetContext()->IsDCContext())    {
  82.         //    Further, need to detect how we're going to be drawing ourselves.
  83.         if(GetContext()->IsPureDCContext())    {
  84.             //    Only works from a DC, needs a GDI drawing representation.
  85.             CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
  86.             LTRB r(Rect.left, Rect.top, Rect.right, Rect.bottom);
  87.  
  88.             //  Adjust for stuff done in FillSizeInfo
  89.             r.Inflate(0, -1 * pDCCX->Pix2TwipsY(EDIT_SPACE) / 2);
  90.  
  91.             //  Do something simple.
  92.             pDCCX->Display3DBox(r, pDCCX->ResolveLightLineColor(), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  93.  
  94.             //  Decide if we're doing scrollers.
  95.             BOOL bHorizontal = FALSE;
  96.             if(GetElementTextareaData() && GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_OFF)    {
  97.                 bHorizontal = TRUE;
  98.             }
  99.  
  100.             //  Figure rects of scrollers.
  101.             LTRB VScroller(r.right - pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth), r.top, r.right, r.bottom);
  102.             if(bHorizontal) {
  103.                 VScroller.bottom -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
  104.             }
  105.             LTRB HScroller(r.left, r.bottom - pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight), r.right - pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth), r.bottom);
  106.  
  107.             //  Adjust the original rect inside of the scroll bars and border.
  108.             r.left += pDCCX->Pix2TwipsY(2);
  109.             r.top += pDCCX->Pix2TwipsY(2);
  110.             r.right -= pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth);
  111.             if(bHorizontal) {
  112.                 r.bottom -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
  113.             }
  114.             else    {
  115.                 r.bottom -= pDCCX->Pix2TwipsY(2);
  116.             }
  117.  
  118.             //  Time for DC work.
  119.             HDC pDC = pDCCX->GetContextDC();
  120.             if(pDC) {
  121.                 //  Figure up the DrawText rectangle (so that we can get the proportionals right).
  122.                 int32 lDrawnWidth = 0;
  123.                 int32 lDrawnHeight = 0;
  124.                 CyaFont    *pMyFont = 0;
  125.                 if(GetElementTextareaData() && GetElementTextareaData()->current_text)    {
  126.                     char *pText = (char *)GetElementTextareaData()->current_text;
  127.                     int32 lLength = XP_STRLEN(pText);
  128.  
  129.                     
  130.                     pDCCX->SelectNetscapeFont( pDC, GetTextAttr(), pMyFont );
  131.                     if (!pMyFont) {
  132.                         m_pWidget->ReleaseDC(CDC::FromHandle(pDC));
  133.                         DestroyWidget();
  134.                         pDCCX->ReleaseContextDC(pDC);
  135.                         return;
  136.                     }
  137.                     SetWidgetFont(pDC, m_pWidget->m_hWnd);
  138.                     r.left += pMyFont->GetMeanWidth() - pDCCX->Pix2TwipsY(2);
  139.  
  140.                     //  Decide the output area for all text.
  141.                     RECT crClip;
  142.                     ::SetRect(&crClip, CASTINT(r.left), CASTINT(r.top),
  143.                         CASTINT(r.right), CASTINT(r.bottom));
  144.                     RECT crSize = crClip;
  145.  
  146.                     //  Figure up the draw text style we're asking for.
  147.                     UINT uStyle = DT_LEFT | DT_NOPREFIX;
  148.                     if(GetElementTextareaData()->auto_wrap != TEXTAREA_WRAP_OFF)    {
  149.                         //  Text should have already been wrapped, but do it anyhow.
  150.                         uStyle |= DT_WORDBREAK;
  151.                     }
  152.  
  153.                     //  Figure out the size.
  154.                     //  This does not draw anything.
  155.                     int16 wincsid = 0 ;
  156.                     if(GetContext()->GetContext())
  157.                         wincsid = INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext()));
  158.                 
  159.                     CIntlWin::DrawText(wincsid, pDC, pText, CASTINT(lLength), &crSize, uStyle | DT_CALCRECT);
  160.                     lDrawnWidth = crSize.right - crSize.left;
  161.                     lDrawnHeight = crSize.bottom - crSize.top;
  162.  
  163.                     //  Set us to transparncy and do the deed.
  164.                     int iOldBk = ::SetBkMode(pDC, TRANSPARENT);
  165.                     CIntlWin::DrawText(wincsid, pDC, pText, CASTINT(lLength), &crClip, uStyle);
  166.                     ::SetBkMode(pDC, iOldBk);
  167.                     pDCCX->ReleaseNetscapeFont( pDC, pMyFont );
  168.                     //  Restore the font.
  169.                 }            
  170.  
  171.                 //  Draw the scrollers.
  172.                 //  Vertical is always present.
  173.                 //  Don't do if can't handle due to size limitations
  174.                 pDCCX->Display3DBox(VScroller, pDCCX->ResolveLightLineColor(), pDCCX->ResolveLightLineColor(), pDCCX->Pix2TwipsY(2));
  175.                 if(VScroller.Height() > pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight) * 2)  {
  176.                     POINT aPoints[3];
  177.  
  178.                     //  Display top button.
  179.                     LTRB TButton(VScroller.left, VScroller.top, VScroller.right, VScroller.top + pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight));
  180.                     pDCCX->Display3DBox(TButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  181.                     TButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
  182.                     VScroller.top += pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
  183.  
  184.                     //  Arrow.
  185.                     aPoints[0].x = CASTINT(TButton.left + TButton.Width() / 4);
  186.                     aPoints[0].y = CASTINT(TButton.top + 2 * TButton.Height() / 3);
  187.                     aPoints[1].x = CASTINT(TButton.left + TButton.Width() / 2);
  188.                     aPoints[1].y = CASTINT(TButton.top + TButton.Height() / 3);
  189.                     aPoints[2].x = CASTINT(TButton.left + 3 * TButton.Width() / 4);
  190.                     aPoints[2].y = CASTINT(TButton.top + 2 * TButton.Height() / 3);
  191.                     TRY {
  192.                         HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
  193.                         HBRUSH cbBlack;
  194.                         HBRUSH pOldBrush = NULL;
  195.                         if(cbBlack = CreateSolidBrush(RGB(0, 0, 0)))  {
  196.                             pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
  197.                         }
  198.                         HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
  199.  
  200.                         int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
  201.                         ::Polygon(pDC, aPoints, 3);
  202.                         ::SetPolyFillMode(pDC, iOldMode);
  203.  
  204.                         if(pOldPen) {
  205.                             ::SelectObject(pDC, pOldPen);
  206.                         }
  207.                         if(pOldBrush)   {
  208.                             ::SelectObject(pDC, pOldBrush);
  209.                         }
  210.                         VERIFY(::DeleteObject(cpBlack));
  211.                         VERIFY(::DeleteObject(cbBlack));
  212.                     }
  213.                     CATCH(CException, e)    {
  214.                         //  Can't create pen.
  215.                     }
  216.                     END_CATCH
  217.  
  218.                     //  Display bottom button.
  219.                     LTRB BButton(VScroller.left, VScroller.bottom - pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight), VScroller.right, VScroller.bottom);
  220.                     pDCCX->Display3DBox(BButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  221.                     BButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
  222.                     VScroller.bottom -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
  223.  
  224.                     //  Arrow.
  225.                     aPoints[0].x = CASTINT(BButton.left + BButton.Width() / 4);
  226.                     aPoints[0].y = CASTINT(BButton.top + BButton.Height() / 3);
  227.                     aPoints[1].x = CASTINT(BButton.left + BButton.Width() / 2);
  228.                     aPoints[1].y = CASTINT(BButton.top + 2 * BButton.Height() / 3);
  229.                     aPoints[2].x = CASTINT(BButton.left + 3 * BButton.Width() / 4);
  230.                     aPoints[2].y = CASTINT(BButton.top + BButton.Height() / 3);
  231.                     TRY {
  232.                         HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
  233.                         HBRUSH cbBlack;
  234.                         HBRUSH pOldBrush = NULL;
  235.                         if(cbBlack = ::CreateSolidBrush(RGB(0, 0, 0)))  {
  236.                             pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
  237.                         }
  238.                         HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
  239.  
  240.                         int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
  241.                         ::Polygon(pDC, aPoints, 3);
  242.                         ::SetPolyFillMode(pDC, iOldMode);
  243.  
  244.                         if(pOldPen) {
  245.                             ::SelectObject(pDC, pOldPen);
  246.                         }
  247.                         if(pOldBrush)   {
  248.                             ::SelectObject(pDC, pOldBrush);
  249.                         }
  250.                         VERIFY(::DeleteObject(cpBlack));
  251.                         VERIFY(::DeleteObject(cbBlack));
  252.                     }
  253.                     CATCH(CException, e)    {
  254.                         //  Can't create pen.
  255.                     }
  256.                     END_CATCH
  257.  
  258.                     //  Decide if drawing inner tumbtrack.
  259.                     if(r.Height() < lDrawnHeight)  {
  260.                         //  Size of thumbtrack is a percentage.
  261.                         int32 lPercent = r.Height() * 100 / lDrawnHeight;
  262.                         int32 lThumb = lPercent * VScroller.Height() / 100;
  263.                         LTRB Thumb(VScroller.left, VScroller.top, VScroller.right, VScroller.top + lThumb);
  264.                         pDCCX->Display3DBox(Thumb, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  265.                     }
  266.                 }
  267.  
  268.                 if(bHorizontal) {
  269.                     //  Don't do if can't handle due to size limitations
  270.                     pDCCX->Display3DBox(HScroller, pDCCX->ResolveLightLineColor(), pDCCX->ResolveLightLineColor(), pDCCX->Pix2TwipsY(2));
  271.                     if(HScroller.Width() > pDCCX->Pix2TwipsY(sysInfo.m_iScrollWidth) * 2)  {
  272.                         POINT aPoints[3];
  273.  
  274.                         //  Display left button.
  275.                         LTRB LButton(HScroller.left, HScroller.top, HScroller.left + pDCCX->Pix2TwipsY(sysInfo.m_iScrollWidth), HScroller.bottom);
  276.                         pDCCX->Display3DBox(LButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  277.                         LButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
  278.                         HScroller.left += pDCCX->Pix2TwipsY(sysInfo.m_iScrollWidth);
  279.  
  280.                         //  Arrow.
  281.                         aPoints[0].x = CASTINT(LButton.left + 2 * LButton.Width() / 3);
  282.                         aPoints[0].y = CASTINT(LButton.top + LButton.Height() / 4);
  283.                         aPoints[1].x = CASTINT(LButton.left + LButton.Width() / 3);
  284.                         aPoints[1].y = CASTINT(LButton.top + LButton.Height() / 2);
  285.                         aPoints[2].x = CASTINT(LButton.left + 2 * LButton.Width() / 3);
  286.                         aPoints[2].y = CASTINT(LButton.top + 3 * LButton.Height() / 4);
  287.                         TRY {
  288.                             HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
  289.                             HBRUSH cbBlack;
  290.                             HBRUSH pOldBrush = NULL;
  291.                             if(cbBlack = ::CreateSolidBrush(RGB(0, 0, 0)))  {
  292.                                 pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
  293.                             }
  294.                             HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
  295.  
  296.                             int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
  297.                             ::Polygon(pDC, aPoints, 3);
  298.                             ::SetPolyFillMode(pDC, iOldMode);
  299.  
  300.                             if(pOldPen) {
  301.                                 ::SelectObject(pDC, pOldPen);
  302.                             }
  303.                             if(pOldBrush)   {
  304.                                 ::SelectObject(pDC, pOldBrush);
  305.                             }
  306.                             VERIFY(::DeleteObject(cpBlack));
  307.                             VERIFY(::DeleteObject(cbBlack));
  308.                         }
  309.                         CATCH(CException, e)    {
  310.                             //  Can't create pen.
  311.                         }
  312.                         END_CATCH
  313.  
  314.                         //  Display right button.
  315.                         LTRB RButton(HScroller.right - pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth), HScroller.top, HScroller.right, HScroller.bottom);
  316.                         pDCCX->Display3DBox(RButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  317.                         RButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
  318.                         HScroller.right -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollWidth);
  319.  
  320.                         //  Arrow.
  321.                         aPoints[0].x = CASTINT(RButton.left + RButton.Width() / 3);
  322.                         aPoints[0].y = CASTINT(RButton.top + RButton.Height() / 4);
  323.                         aPoints[1].x = CASTINT(RButton.left + 2 * RButton.Width() / 3);
  324.                         aPoints[1].y = CASTINT(RButton.top + RButton.Height() / 2);
  325.                         aPoints[2].x = CASTINT(RButton.left + RButton.Width() / 3);
  326.                         aPoints[2].y = CASTINT(RButton.top + 3 * RButton.Height() / 4);
  327.                         TRY {
  328.                             HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
  329.                             HBRUSH cbBlack;
  330.                             HBRUSH pOldBrush = NULL;
  331.                             if(cbBlack = ::CreateSolidBrush(RGB(0, 0, 0)))  {
  332.                                 pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
  333.                             }
  334.                             HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
  335.  
  336.                             int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
  337.                             ::Polygon(pDC, aPoints, 3);
  338.                             ::SetPolyFillMode(pDC, iOldMode);
  339.  
  340.                             if(pOldPen) {
  341.                                 ::SelectObject(pDC, pOldPen);
  342.                             }
  343.                             if(pOldBrush)   {
  344.                                 ::SelectObject(pDC, pOldBrush);
  345.                             }
  346.                             VERIFY(::DeleteObject(cpBlack));
  347.                             VERIFY(::DeleteObject(cbBlack));
  348.                         }
  349.                         CATCH(CException, e)    {
  350.                             //  Can't create pen.
  351.                         }
  352.                         END_CATCH
  353.  
  354.                         //  Decide if drawing inner tumbtrack.
  355.                         if(r.Width() < lDrawnWidth)  {
  356.                             //  Size of thumbtrack is a percentage.
  357.                             int32 lPercent = r.Width() * 100 / lDrawnWidth;
  358.                             int32 lThumb = lPercent * HScroller.Width() / 100;
  359.                             LTRB Thumb(HScroller.left, HScroller.top, HScroller.left + lThumb, HScroller.bottom);
  360.                             pDCCX->Display3DBox(Thumb, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  361.                         }
  362.                    }
  363.                }
  364.                 //  Release the DC.
  365.                 pDCCX->ReleaseContextDC(pDC);
  366.             }
  367.         }
  368.         else if(GetContext()->IsWindowContext())    {
  369.             MoveWindow(m_pWidget->m_hWnd, Rect.left, Rect.top + EDIT_SPACE / 2);
  370.         }
  371.         else    {
  372.             //    Is undefined....
  373.             ASSERT(0);
  374.         }
  375.     }
  376.  
  377.     //    Call the base.
  378.     CFormElement::DisplayFormElement(Rect);
  379. }
  380.  
  381.  
  382. //    Destroy the widget (window) implemenation of the form.
  383. void CFormTextarea::DestroyWidget()
  384. {
  385.     //    Get rid of the widget if around.
  386.     if(m_pWidget)    {
  387.         m_pWidget->DestroyWindow();
  388.         delete m_pWidget;
  389.         m_pWidget = NULL;
  390.     }
  391.  
  392. #ifdef XP_WIN16
  393.     //    Get rid of the extra segment if around.
  394.     if(m_hSegment)    {
  395.         GlobalFree(m_hSegment);
  396.         m_hSegment = NULL;
  397.     }
  398. #endif
  399. }
  400.  
  401. //    Create the widget (window) implementation of the form
  402. //        but DO NOT DISPLAY.
  403. void CFormTextarea::CreateWidget()
  404. {
  405.     if(GetContext() && GetElement())    {
  406.         if(GetContext()->IsWindowContext() && VOID2CX(GetContext(), CPaneCX)->GetPane())    {
  407.             //    Need a widget representation.
  408.             ASSERT(m_pWidget == NULL);
  409.             m_pWidget = new CODNetscapeEdit;
  410.             if(m_pWidget == NULL)    {
  411.                 return;
  412.             }
  413.  
  414.             //    Inform widget of context and element.
  415.             m_pWidget->SetContext(GetContext()->GetContext(), GetElement());
  416.  
  417. #ifdef XP_WIN16
  418.             //    On 16 bits, we need to set the segment of the widget before creation.
  419.             m_hSegment = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, 4 * 1024);
  420.             if(m_hSegment)    {
  421.                 LPVOID lpPtr = GlobalLock(m_hSegment);
  422.                 LocalInit(HIWORD((LONG)lpPtr), 0, (WORD)(GlobalSize(m_hSegment) - 16));
  423.                 UnlockSegment(HIWORD((LONG)lpPtr));
  424.                 m_pWidget->SetInstance((HINSTANCE)HIWORD((LONG)lpPtr)); 
  425.             }
  426.             else    {
  427.                 delete m_pWidget;
  428.                 m_pWidget = NULL;
  429.                 return;
  430.             }
  431. #endif
  432.  
  433.             //    The style of the widget to be created.
  434.             DWORD dwStyle = WS_CHILD | WS_VSCROLL | WS_BORDER | ES_LEFT | WS_TABSTOP | ES_MULTILINE;
  435.             if(GetElementTextareaData())    {
  436.                 //    If no word wrapping, add a horizontal scrollbar.
  437.                 if(GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_OFF)    {
  438.                     dwStyle |= WS_HSCROLL;
  439.                 }
  440.             }
  441.  
  442.             //    Create the widget, hidden, and with a bad size.
  443.             BOOL bCreate =
  444. #ifdef XP_WIN32
  445.                 m_pWidget->CreateEx(WS_EX_CLIENTEDGE, 
  446.                      _T("EDIT"),
  447.                      NULL,
  448.                      dwStyle, 
  449.                      1, 1, 0, 0,
  450.                      VOID2CX(GetContext(), CPaneCX)->GetPane(), 
  451.                      (HMENU)GetDynamicControlID(),
  452.                      NULL);            
  453. #else
  454.                 m_pWidget->Create(dwStyle, CRect(1, 1, 0, 0), 
  455.                     CWnd::FromHandle(VOID2CX(GetContext(), CPaneCX)->GetPane()), 
  456.                     GetDynamicControlID());
  457. #endif
  458.  
  459.             if(!bCreate)    {
  460.                 delete m_pWidget;
  461.                 m_pWidget = NULL;
  462. #ifdef XP_WIN16
  463.                 GlobalFree(m_hSegment);
  464.                 m_hSegment = NULL;
  465. #endif
  466.                 return;
  467.             }
  468.  
  469.             CyaFont    *pMyFont;
  470.             
  471.  
  472.             //    Measure some text.
  473.             CDC *pDC = m_pWidget->GetDC();
  474.             if(pDC)    {
  475.                 CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
  476.                 pDCCX->SelectNetscapeFont( pDC->GetSafeHdc(), GetTextAttr(), pMyFont );
  477.                 if (pMyFont) {
  478.                     SetWidgetFont(pDC->GetSafeHdc(), m_pWidget->m_hWnd);
  479.                     GetElement()->text_attr->FE_Data = pMyFont;
  480.                     //    Default length is 20
  481.                     //    Default lines is 1
  482.                     int32 lLength = 20;
  483.                     int32 lLines = 1;
  484.  
  485.                     //    See if we can measure the default text, and/or
  486.                     //        set up the size and size limits.
  487.                     if(GetElementTextareaData())    {
  488.                         if(GetElementTextareaData()->cols > 0)    {
  489.                             //    Use provided size.
  490.                             lLength = GetElementTextareaData()->cols;
  491.                         }
  492.                         if(GetElementTextareaData()->rows > 0)    {
  493.                             //    Use provided size.
  494.                             lLines = GetElementTextareaData()->rows;
  495.                         }
  496.                     }
  497.  
  498.                     //    Now figure up the width and height we would like.
  499.     //                int32 lWidgetWidth = (lLength + 1) * tm.tmAveCharWidth + sysInfo.m_iScrollWidth;
  500.     //                int32 lWidgetHeight = (lLines + 1) * tm.tmHeight;
  501.                     int32 lWidgetWidth = (lLength + 1) * pMyFont->GetMeanWidth() + sysInfo.m_iScrollWidth;
  502.                     int32 lWidgetHeight = (lLines + 1) * pMyFont->GetHeight();
  503.  
  504.                     //    If no word wrapping, account a horizontal scrollbar.
  505.                     if(GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_OFF)    {
  506.                         lWidgetHeight += sysInfo.m_iScrollHeight;
  507.                     }
  508.  
  509.                     //    Move the window.
  510.                     m_pWidget->MoveWindow(1, 1, CASTINT(lWidgetWidth), CASTINT(lWidgetHeight), FALSE);
  511.  
  512.                     pDCCX->ReleaseNetscapeFont( pDC->GetSafeHdc(), pMyFont );
  513.                     pDCCX->ReleaseContextDC(pDC->GetSafeHdc());
  514.                     m_pWidget->ReleaseDC(pDC);
  515.                 }
  516.                 else {
  517.                     m_pWidget->ReleaseDC(pDC);
  518.                     DestroyWidget();
  519.                 }
  520.  
  521.             }
  522.             else    {
  523.                 //    No DC, no widget.
  524.                 DestroyWidget();
  525.                 return;
  526.             }
  527.         }
  528.         else if(GetContext()->IsPureDCContext())    {
  529.             //    Need a drawn representation.
  530.         }
  531.     }
  532. }
  533.  
  534. //    Copy the current data out of the layout struct into the form
  535. //        widget, or mark that you should represent using the current data.
  536. void CFormTextarea::UseCurrentData()
  537. {
  538.     //    Detect context type and do the right thing.
  539.     if(GetContext())    {
  540.         if(GetContext()->IsWindowContext())    {
  541.             //    Need a widget.
  542.             if(m_pWidget)    {
  543.                 //    Determine the current text to set.
  544.                 char *pCurrent = "";
  545.                 if(GetElementTextareaData() && GetElementTextareaData()->current_text)    {
  546.                     pCurrent = (char *)GetElementTextareaData()->current_text;
  547.                 }
  548.                 // We have to SetContext to the widget before we SetWindowText
  549.                 // Otherwise, the widget don't know what csid the text is.
  550.                 m_pWidget->SetContext(GetContext()->GetContext(), GetElement());
  551.                 m_pWidget->SetWindowText(pCurrent);
  552.             }
  553.         }
  554.         else if(GetContext()->IsPureDCContext())    {
  555.             //    Printing/metafile
  556.             //  Whatever is current is current.
  557.         }
  558.     }
  559. }
  560.  
  561. //    Copy the default data out of the layout struct into the form
  562. //        widget, or mark that you should represent using the default data.
  563. void CFormTextarea::UseDefaultData()
  564. {
  565.     //    Detect context type and do the right thing.
  566.     if(GetContext())    {
  567.         if(GetContext()->IsWindowContext())    {
  568.             //    Need a widget.
  569.             if(m_pWidget)    {
  570.                 //    Determine the default text to set.
  571.                 char *pDefault = "";
  572.                 if(GetElementTextareaData() && GetElementTextareaData()->default_text)    {
  573.                     pDefault = (char *)GetElementTextareaData()->default_text;
  574.                 }
  575.                 // We have to SetContext to the widget before we SetWindowText
  576.                 // Otherwise, the widget don't know what csid the text is.
  577.                 m_pWidget->SetContext(GetContext()->GetContext(), GetElement());
  578.                 m_pWidget->SetWindowText(pDefault);
  579.             }
  580.         }
  581.         else if(GetContext()->IsPureDCContext())    {
  582.             //    Printing/metafile
  583.             if(GetElementTextareaData())    {
  584.                 //  Clear the current text if present.
  585.                 if(GetElementTextareaData()->current_text)    {
  586.                     XP_FREE(GetElementTextareaData()->current_text);
  587.                     GetElementTextareaData()->current_text = NULL;
  588.                 }
  589.  
  590.                 //  Copy over the default_text.
  591.                 if(GetElementTextareaData()->default_text)  {
  592.                     int32 lSize = XP_STRLEN((char *)GetElementTextareaData()->default_text) + 1;
  593.                     GetElementTextareaData()->current_text = (XP_Block)XP_ALLOC(lSize);
  594.                     if(GetElementTextareaData()->current_text)  {
  595.                         memcpy(GetElementTextareaData()->current_text,
  596.                             GetElementTextareaData()->default_text,
  597.                             CASTSIZE_T(lSize));
  598.                     }
  599.                 }
  600.             }
  601.         }
  602.     }
  603. }
  604.  
  605. //    Fill in the layout size information in the layout struct regarding
  606. //        the dimensions of the widget.
  607. void CFormTextarea::FillSizeInfo()
  608. {
  609.     //    Detect context type and do the right thing.
  610.     if(GetContext() && GetElement())    {
  611.         if(GetContext()->IsWindowContext())    {
  612.             //    Need a widget.
  613.             if(m_pWidget)    {
  614.                 //    Determine our window position.
  615.                 CRect crRect;
  616.                 m_pWidget->GetWindowRect(crRect);
  617.  
  618.                 //    Munge the coordinate a little for layout.
  619.                 //    We'll have to know how to decode this information
  620.                 //        in the display routine (by half).
  621.                 GetElement()->width = crRect.Width();
  622.                 GetElement()->height = crRect.Height() + EDIT_SPACE;
  623.                 GetElement()->border_vert_space = EDIT_SPACE/2;
  624.  
  625.                 //    Baseline needs text metric information.
  626.                 GetElement()->baseline = GetElement()->height;    //    ugly default in case of failure below.
  627.                 CDC *pDC = m_pWidget->GetDC();
  628.                 if(pDC)    {
  629.                     //    Need to specifically select the font before calling GetTextMetrics.
  630.                     CyaFont    *pMyFont;
  631.                     CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
  632.                     pDCCX->SelectNetscapeFont( pDC->GetSafeHdc(), GetTextAttr(), pMyFont );
  633.                     if (pMyFont) {
  634.                         SetWidgetFont(pDC->GetSafeHdc(), m_pWidget->m_hWnd);
  635.                         GetElement()->baseline -= (pMyFont->GetHeight() / 2 + pMyFont->GetDescent()) / 2;
  636.                         pDCCX->ReleaseNetscapeFont( pDC->GetSafeHdc(), pMyFont );
  637.                         m_pWidget->ReleaseDC(pDC);
  638.                     }
  639.                     else {
  640.                         m_pWidget->ReleaseDC(pDC);
  641.                         DestroyWidget();
  642.                         return;
  643.                     }
  644.  
  645.                 }
  646.             }
  647.             else    {
  648.                 //    No widget, tell layout nothing.
  649.                 GetElement()->width = 0;
  650.                 GetElement()->height = 0;
  651.                 GetElement()->baseline = 0;
  652.             }
  653.         }
  654.         else if(GetContext()->IsPureDCContext())    {
  655.             //    Do some printing specific stuff here...
  656.             int32 lWidth = 0;
  657.             int32 lHeight = 0;
  658.             int32 lBaseline = 0;
  659.  
  660.             CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
  661.             HDC pDC = pDCCX->GetAttribDC();
  662.             if(pDC) {
  663.                 //  Have the DC, attempt to select the widget font.
  664.                     CyaFont    *pMyFont;
  665.                     
  666.                     pDCCX->SelectNetscapeFont( pDC, GetTextAttr(), pMyFont );
  667.                     if (pMyFont) {
  668.                         SetWidgetFont(pDC, m_pWidget->m_hWnd);
  669.                         int32 lColumns = 20;
  670.                         int32 lRows = 1;
  671.  
  672.                         //  See if we can measure the default text and/or set up
  673.                         //      size limits.
  674.                         if(GetElementTextareaData())    {
  675.                             if(GetElementTextareaData()->cols > 0)  {
  676.                                 lColumns = GetElementTextareaData()->cols;
  677.                             }
  678.                             if(GetElementTextareaData()->rows > 0)  {
  679.                                 lRows = GetElementTextareaData()->rows;
  680.                             }
  681.                         }
  682.  
  683.                         //  Figure up width and height we would like.
  684. //                            lWidth = (lColumns + 1) * tm.tmAveCharWidth + pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth);
  685. //                            lHeight = (lRows + 1) * tm.tmHeight;
  686.                         lWidth = (lColumns + 1) * pMyFont->GetMeanWidth() + pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth);
  687.                         lHeight = (lRows + 1) * pMyFont->GetHeight();
  688.  
  689.                         //  If no word wrapping, add a horizontal scrollbar.
  690.                         if(GetElementTextareaData() && GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_OFF) {
  691.                             lHeight += pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
  692.                         }
  693.  
  694.                         //  Adjust a little bit more, will need to know how to decode this
  695.                         //      in display.
  696.                         lHeight += pDCCX->Pix2TwipsY(EDIT_SPACE);
  697.  
  698.                         //  Figure the baseline.
  699. //                            lBaseline = lHeight - ((tm.tmHeight / 2 + tm.tmDescent) / 2);
  700.                         lBaseline = lHeight - ((pMyFont->GetHeight() / 2 + pMyFont->GetDescent()) / 2);
  701. //                        }
  702.  
  703.                     pDCCX->ReleaseNetscapeFont( pDC, pMyFont );
  704.                 }
  705.                 else {
  706.                     m_pWidget->ReleaseDC(CDC::FromHandle(pDC));
  707.                     DestroyWidget();
  708.                 }
  709.  
  710.                 pDCCX->ReleaseContextDC(pDC);
  711.             }
  712.  
  713.             //  Tell layout what we know.
  714.             GetElement()->width = lWidth;
  715.             GetElement()->height = lHeight;
  716.             GetElement()->baseline = lBaseline;
  717.         }
  718.     }
  719. }
  720.  
  721. //    Copy the current data out of the form element back into the
  722. //        layout struct.
  723. void CFormTextarea::UpdateCurrentData()
  724. {
  725.     if(GetContext())    {
  726.         if(GetContext()->IsWindowContext())    {
  727.             if(m_pWidget && ::IsWindow(m_pWidget->GetSafeHwnd()) && GetElementTextareaData())    {
  728.                 //    Free off any current text.
  729.                 if(GetElementTextareaData()->current_text)    {
  730.                     XP_FREE(GetElementTextareaData()->current_text);
  731.                     GetElementTextareaData()->current_text = NULL;
  732.                 }
  733.  
  734.                 //    If we have hard wrapping, set the flag in the edit field now
  735.                 //        bofore we get the length.
  736.                 if(GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_HARD)    {
  737.                     m_pWidget->FmtLines(TRUE);
  738.                 }
  739.  
  740.                 //    See if we've got anything.
  741.                 int32 lLength = m_pWidget->GetWindowTextLength();
  742.                 if(lLength > 0)    {
  743.                     GetElementTextareaData()->current_text = (XP_Block)XP_ALLOC(lLength + 1);
  744.                     if(GetElementTextareaData()->current_text)    {
  745.                         m_pWidget->GetWindowText((char *)GetElementTextareaData()->current_text, CASTINT(lLength + 1));
  746.  
  747.                         // strip out the \r\r\n if we are a hard-break text area
  748.                         if(GetElementTextareaData()->auto_wrap == TEXTAREA_WRAP_HARD)    {
  749.                             char *pSrc;
  750.                             char *pDest;
  751.  
  752.                             // start both off at the beginning
  753.                             pSrc  = (char *)GetElementTextareaData()->current_text;
  754.                             pDest = (char *)GetElementTextareaData()->current_text;
  755.  
  756.                             while(pSrc && *pSrc)    {
  757.                                 if(pSrc[0] == '\r' && pSrc[1] == '\r' && pSrc[2] == '\n')    {
  758.                                     // convert the soft line break into a hard line break
  759.                                     pSrc += 3;
  760.                                     *pDest++ = '\r';
  761.                                     *pDest++ = '\n';
  762.                                 }
  763.                                 else    {
  764.                                     // just copy this one over
  765.                                     *pDest++ = *pSrc++;
  766.                                 }
  767.                             }
  768.  
  769.                             // NULL termination is your friend
  770.                             *pDest = '\0';
  771.                         }
  772.                     }
  773.                 }
  774.             }
  775.         }
  776.         else if(GetContext()->IsPureDCContext())    {
  777.             //    Printing/metafile
  778.             //  Whatever is current is current.
  779.         }
  780.     }
  781. }
  782.  
  783. HWND CFormTextarea::GetRaw()
  784. {
  785.     return(m_pWidget ? m_pWidget->m_hWnd : NULL);
  786. }
  787.  
  788.