home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / fmselmul.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  27.7 KB  |  749 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. #include "odctrl.h"
  21.  
  22. #include "fmselmul.h"
  23. #include "intl_csi.h"
  24.  
  25. //    This file is dedicated to form type select mult 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. CFormSelectMult::CFormSelectMult()
  32. {
  33.     //    No widget yet.
  34.     m_pWidget = NULL;
  35. }
  36.  
  37. //    Destruction cleans out all members.
  38. CFormSelectMult::~CFormSelectMult()
  39. {
  40. }
  41.  
  42. //    How to set the LO form element.
  43. //    This may change during the lifetime of an instance, so use this
  44. //        to update all referencing values.
  45. void CFormSelectMult::SetElement(LO_FormElementStruct *pFormElement)
  46. {
  47.     //    Call the base.
  48.     CFormElement::SetElement(pFormElement);
  49.  
  50.     //    Have our widget update itself.
  51.     if(m_pWidget)    {
  52.         m_pWidget->SetContext(GetContext() ? GetContext()->GetContext() : NULL, GetElement());
  53.     }
  54. }
  55.  
  56. //    Set the owning context.
  57. //    Use this to determine what context we live in and how we should
  58. //        represent ourself (DC or window).
  59. void CFormSelectMult::SetContext(CAbstractCX *pCX)
  60. {
  61.     //    Call the base.
  62.     CFormElement::SetContext(pCX);
  63.  
  64.     //    Have the widget update if present.
  65.     if(m_pWidget)    {
  66.         m_pWidget->SetContext(GetContext() ? GetContext()->GetContext() : NULL, GetElement());
  67.     }
  68. }
  69.  
  70. //    Display the form element given the particular context we are in.
  71. //    Possibly only use a DC for representation, or have the
  72. //        window move.
  73. void CFormSelectMult::DisplayFormElement(LTRB& Rect)
  74. {
  75.     //    Display only has meaning if our context is a device context.
  76.     if(GetContext() && GetContext()->IsDCContext())    {
  77.         //    Further, need to detect how we're going to be drawing ourselves.
  78.         if(GetContext()->IsPureDCContext())    {
  79.             //    Only works from a DC, needs a GDI drawing representation.
  80.             CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
  81.             LTRB r(Rect.left, Rect.top, Rect.right, Rect.bottom);
  82.  
  83.             //  Do something simple.
  84.             pDCCX->Display3DBox(r, pDCCX->ResolveLightLineColor(), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  85.             r.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
  86.  
  87.             HDC pDC = pDCCX->GetContextDC();
  88.             if(pDC) {
  89.                 if(GetElementSelectData())  {
  90.                     int32 lTotal = GetElementSelectData()->option_cnt;
  91.                     int32 lSize = GetElementSelectData()->size;
  92.                     if(lSize < 1)   {
  93.                         lSize = 1;
  94.                     }
  95.  
  96.                     //  Draw the scroll bar on the right.
  97.                     //  Adjust for size of scroller.
  98.                     r.right -= pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth);
  99.                     LTRB Scroller(r.right, r.top - pDCCX->Pix2TwipsY(2), r.right + pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth), r.bottom + pDCCX->Pix2TwipsY(2));
  100.                     //  Display generic outline.
  101.                     pDCCX->Display3DBox(Scroller, pDCCX->ResolveLightLineColor(), pDCCX->ResolveLightLineColor(), pDCCX->Pix2TwipsY(2));
  102.                     //  Don't do if can't handle due to size limitations
  103.                     if(Scroller.Height() > pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight) * 2)  {
  104.                         POINT aPoints[3];
  105.  
  106.                         //  Display top button.
  107.                         LTRB TButton(Scroller.left, Scroller.top, Scroller.right, Scroller.top + pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight));
  108.                         pDCCX->Display3DBox(TButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  109.                         TButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
  110.                         Scroller.top += pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
  111.  
  112.                         //  Arrow.
  113.                         aPoints[0].x = CASTINT(TButton.left + TButton.Width() / 4);
  114.                         aPoints[0].y = CASTINT(TButton.top + 2 * TButton.Height() / 3);
  115.                         aPoints[1].x = CASTINT(TButton.left + TButton.Width() / 2);
  116.                         aPoints[1].y = CASTINT(TButton.top + TButton.Height() / 3);
  117.                         aPoints[2].x = CASTINT(TButton.left + 3 * TButton.Width() / 4);
  118.                         aPoints[2].y = CASTINT(TButton.top + 2 * TButton.Height() / 3);
  119.                         TRY {
  120.                             HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
  121.                             HBRUSH cbBlack;
  122.                             HBRUSH pOldBrush = NULL;
  123.                             if(cbBlack = CreateSolidBrush(RGB(0, 0, 0)))  {
  124.                                 pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
  125.                             }
  126.                             HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
  127.  
  128.                             int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
  129.                             ::Polygon(pDC, aPoints, 3);
  130.                             ::SetPolyFillMode(pDC, iOldMode);
  131.  
  132.                             if(pOldPen) {
  133.                                 ::SelectObject(pDC, pOldPen);
  134.                             }
  135.                             if(pOldBrush)   {
  136.                                 ::SelectObject(pDC, pOldBrush);
  137.                             }
  138.                             VERIFY(::DeleteObject(cpBlack));
  139.                             VERIFY(::DeleteObject(cbBlack));
  140.                         }
  141.                         CATCH(CException, e)    {
  142.                             //  Can't create pen.
  143.                         }
  144.                         END_CATCH
  145.  
  146.                         //  Display bottom button.
  147.                         LTRB BButton(Scroller.left, Scroller.bottom - pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight), Scroller.right, Scroller.bottom);
  148.                         pDCCX->Display3DBox(BButton, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  149.                         BButton.Inflate(-1 * pDCCX->Twips2PixX(2), -1 * pDCCX->Pix2TwipsY(2));
  150.                         Scroller.bottom -= pDCCX->Pix2TwipsY(sysInfo.m_iScrollHeight);
  151.  
  152.                         //  Arrow.
  153.                         aPoints[0].x = CASTINT(BButton.left + BButton.Width() / 4);
  154.                         aPoints[0].y = CASTINT(BButton.top + BButton.Height() / 3);
  155.                         aPoints[1].x = CASTINT(BButton.left + BButton.Width() / 2);
  156.                         aPoints[1].y = CASTINT(BButton.top + 2 * BButton.Height() / 3);
  157.                         aPoints[2].x = CASTINT(BButton.left + 3 * BButton.Width() / 4);
  158.                         aPoints[2].y = CASTINT(BButton.top + BButton.Height() / 3);
  159.                         TRY {
  160.                             HPEN cpBlack = ::CreatePen(PS_SOLID, 0, RGB(0, 0, 0));
  161.                             HBRUSH cbBlack;
  162.                             HBRUSH pOldBrush = NULL;
  163.                             if(cbBlack = ::CreateSolidBrush(RGB(0, 0, 0)))  {
  164.                                 pOldBrush = (HBRUSH)::SelectObject(pDC, cbBlack);
  165.                             }
  166.                             HPEN pOldPen = (HPEN)::SelectObject(pDC, cpBlack);
  167.  
  168.                             int iOldMode = ::SetPolyFillMode(pDC, ALTERNATE);
  169.                             ::Polygon(pDC, aPoints, 3);
  170.                             ::SetPolyFillMode(pDC, iOldMode);
  171.  
  172.                             if(pOldPen) {
  173.                                 ::SelectObject(pDC, pOldPen);
  174.                             }
  175.                             if(pOldBrush)   {
  176.                                 ::SelectObject(pDC, pOldBrush);
  177.                             }
  178.                             VERIFY(::DeleteObject(cpBlack));
  179.                             VERIFY(::DeleteObject(cbBlack));
  180.                         }
  181.                         CATCH(CException, e)    {
  182.                             //  Can't create pen.
  183.                         }
  184.                         END_CATCH
  185.  
  186.                         //  Decide if drawing inner tumbtrack.
  187.                         if(lSize < lTotal)  {
  188.                             //  Size of thumbtrack is a percentage.
  189.                             int32 lPercent = lSize * 100 / lTotal;
  190.                             int32 lThumb = lPercent * Scroller.Height() / 100;
  191.                             LTRB Thumb(Scroller.left, Scroller.top, Scroller.right, Scroller.top + lThumb);
  192.                             pDCCX->Display3DBox(Thumb, RGB(0, 0, 0), pDCCX->ResolveDarkLineColor(), pDCCX->Pix2TwipsY(2));
  193.                         }
  194.                     }
  195.  
  196.                     //  Output the visible text.
  197.                     CyaFont    *pMyFont;
  198.                     VOID2CX(GetContext(), CWinCX)->SelectNetscapeFont( pDC, GetTextAttr(), pMyFont );
  199.                     if (pMyFont) {
  200.                         SetWidgetFont(pDC, m_pWidget->m_hWnd);
  201.                         lo_FormElementOptionData *pOptionData = (lo_FormElementOptionData *)GetElementSelectData()->options;
  202.                         if(pOptionData) {
  203.                             char *pCurrent = NULL;
  204.                             int32 lCounter = 0;
  205.  
  206.                             //  Need to modify output coords a bit.
  207.                             //  We'll move a bit to the right, and we'll clip a bit off the right.
  208.                             //  Also, we'll figure up the height of each entry (or the space we'll have to draw each one),
  209.                             //      and it's offset (center Y in each entry space).
  210.                             RECT crDest;
  211.                             ::SetRect(&crDest, CASTINT(r.left), CASTINT(r.top), CASTINT(r.right), CASTINT(r.bottom));
  212.                             int32 lQuantumHeight = (crDest.bottom - crDest.top) / lSize;
  213.                             int32 lHeightOffset = 0;
  214.                             TEXTMETRIC tm;
  215.  
  216.                             crDest.left += pMyFont->GetMeanWidth();
  217.  
  218.                             //  Decide if we offset the text into the quantum height
  219.                             //      for each entry.
  220.                             lHeightOffset = (lQuantumHeight - pMyFont->GetHeight()) / 2;
  221.  
  222.                             //  We'll want the text to be transparent.
  223.                             int iOldBk = ::SetBkMode(pDC, TRANSPARENT);
  224.  
  225.                             while(lCounter < GetElementSelectData()->option_cnt && lCounter < lSize)    {
  226.                                 //  Draw any selections that will be visible.
  227.                                 COLORREF rgbOldColor;
  228.                                 if(pOptionData[lCounter].selected)  {
  229.                                     RECT crFill;
  230.                                     ::SetRect(&crFill, CASTINT(r.left), CASTINT(r.top + lQuantumHeight * lCounter), CASTINT(r.right), CASTINT(r.top + lQuantumHeight * (lCounter + 1)));
  231.                                     HBRUSH cbFill;
  232.                                     HBRUSH hOldBrush;
  233.                                     if(cbFill = CreateSolidBrush(pDCCX->ResolveDarkLineColor()))  {
  234.                                         hOldBrush = (HBRUSH)::SelectObject(pDC, cbFill);
  235.                                         ::FillRect(pDC, &crFill, cbFill);
  236.                                         ::SelectObject(pDC, hOldBrush);
  237.                                         VERIFY(::DeleteObject(hOldBrush));
  238.                                     }
  239.  
  240.                                     //  Need to change text color to white.
  241.                                     rgbOldColor = ::SetTextColor(pDC, RGB(255, 255, 255));
  242.                                 }
  243.  
  244.                                 pCurrent = (char *)pOptionData[lCounter].text_value;
  245.                                 if(pCurrent)    {
  246.  
  247.                                     CIntlWin::ExtTextOut(
  248.                                         ((GetContext()->GetContext()) ?
  249.                                             INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext()))
  250.                                          : 0) ,
  251.  
  252.                                         pDC, 
  253.                                         crDest.left,
  254.                                         CASTINT(crDest.top + lQuantumHeight * lCounter + lHeightOffset),
  255.                                         ETO_CLIPPED,
  256.                                         CRect(CASTINT(r.left), CASTINT(r.top), CASTINT(r.right), CASTINT(r.bottom)),
  257.                                         pCurrent,
  258.                                         XP_STRLEN(pCurrent),
  259.                                         NULL);
  260.  
  261.                                 }
  262.  
  263.                                 //  Turn text color back if we were selected.
  264.                                 if(pOptionData[lCounter].selected)  {
  265.                                     ::SetTextColor(pDC, rgbOldColor);
  266.                                 }
  267.  
  268.                                 lCounter++;
  269.                             }
  270.  
  271.                             //  Restore BK mode.
  272.                             ::SetBkMode(pDC, iOldBk);
  273.                         }
  274.  
  275.                     pDCCX->ReleaseNetscapeFont( pDC, pMyFont );
  276.                     }
  277.                     else {
  278.                         m_pWidget->ReleaseDC(CDC::FromHandle(pDC));
  279.                         DestroyWidget();
  280.                     }
  281.                 }
  282.                 //  Release DC.
  283.                 pDCCX->ReleaseContextDC(pDC);
  284.             }
  285.         }
  286.         else if(GetContext()->IsWindowContext())    {
  287.             MoveWindow(m_pWidget->m_hWnd, Rect.left, Rect.top);
  288.         }
  289.         else    {
  290.             //    Is undefined....
  291.             ASSERT(0);
  292.         }
  293.     }
  294.  
  295.     //    Call the base.
  296.     CFormElement::DisplayFormElement(Rect);
  297. }
  298.  
  299. //    Destroy the widget (window) implemenation of the form.
  300. void CFormSelectMult::DestroyWidget()
  301. {
  302.     //    Get rid of the widget if present.
  303.     if(m_pWidget)    {
  304.  
  305.         m_pWidget->DestroyWindow();
  306.         delete m_pWidget;
  307.         m_pWidget = NULL;
  308.     }
  309. }
  310.  
  311. //    Create the widget (window) implementation of the form
  312. //        but DO NOT DISPLAY.
  313. void CFormSelectMult::CreateWidget()
  314. {
  315.     if(GetContext() && GetElement())    {
  316.         if(GetContext()->IsWindowContext() && VOID2CX(GetContext(), CPaneCX)->GetPane())    {
  317.             //    Allocate the widget.
  318.             ASSERT(m_pWidget == NULL);
  319.             m_pWidget = new CODMochaListBox();
  320.             if(m_pWidget == NULL)    {
  321.                 return;
  322.             }
  323.  
  324.             //    Inform the widget of the element and the context for callbacks.
  325.             m_pWidget->SetContext(GetContext()->GetContext(), GetElement());
  326.  
  327.             //    Determine the style for the list box.
  328.             DWORD dwStyle = WS_CHILD | WS_VSCROLL | WS_BORDER |
  329.                 LBS_DISABLENOSCROLL | LBS_NOTIFY | LBS_OWNERDRAWFIXED;
  330.             if(GetElementSelectData()->multiple)    {
  331.                 dwStyle |= LBS_EXTENDEDSEL | LBS_MULTIPLESEL;
  332.             }
  333.  
  334.             //    Create the widget hidden and with a bad size (will size it later).
  335.             BOOL bCreate =
  336. #ifdef XP_WIN16
  337.                 m_pWidget->Create(dwStyle, CRect(1, 1, 0, 0), 
  338.                     CWnd::FromHandle(VOID2CX(GetContext(), CPaneCX)->GetPane()), 
  339.                     GetDynamicControlID());
  340. #else
  341.                 m_pWidget->CreateEx(WS_EX_CLIENTEDGE,
  342.                     _T("LISTBOX"),
  343.                     NULL,
  344.                     dwStyle,
  345.                     1, 1, 0, 0,
  346.                     VOID2CX(GetContext(), CPaneCX)->GetPane(),
  347.                     (HMENU)GetDynamicControlID(),
  348.                     NULL);
  349. #endif
  350.             if(!bCreate)    {
  351.                 delete m_pWidget;
  352.                 m_pWidget = NULL;
  353.                 return;
  354.             }
  355.  
  356.             //    Next we need to correctly size the widget.
  357.             //    First step in doing that is selecting the correct font.
  358.  
  359.             //    Prepare to measure text.
  360.             CDC *pDC = m_pWidget->GetDC();
  361.             CyaFont    *pMyFont;  // the font use for the widget.
  362.             if(pDC)    {
  363.  
  364.                 VOID2CX(GetContext(), CPaneCX)->SelectNetscapeFont( pDC->GetSafeHdc(), GetTextAttr(), pMyFont );
  365.                 int32 lWidgetWidth;
  366.                 int32 lWidgetHeight = 0;
  367.                 SIZE csz;
  368.                 if (pMyFont) {
  369.                     GetElement()->text_attr->FE_Data = pMyFont;
  370.                     SetWidgetFont(pDC->GetSafeHdc(), m_pWidget->m_hWnd);
  371.                     //    Select the font while measuring text, or will be off.
  372.                     //    Default if no other text.
  373.                     CIntlWin::GetTextExtentPointWithCyaFont(pMyFont, 
  374.                         INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext())),
  375.                         pDC->GetSafeHdc(), "hi", 2, &csz);
  376.                     lWidgetWidth = csz.cx;
  377.                     lWidgetHeight = 0;
  378.  
  379.                     //    Count the max width by looping through all the entries.
  380.                     if(GetElementSelectData())    {
  381.                         lo_FormElementOptionData *pOptionData = (lo_FormElementOptionData *)GetElementSelectData()->options;
  382.                         if(pOptionData)    {
  383.                             char *pCurrent = NULL;
  384.                             int32 lCounter = 0;
  385.                             while(lCounter < GetElementSelectData()->option_cnt)    {
  386.                                 pCurrent = (char *)pOptionData[lCounter].text_value;
  387.                                 if(pCurrent && *pCurrent)    {
  388.                                     CIntlWin::GetTextExtentPointWithCyaFont(pMyFont, 
  389.                                             INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext())),
  390.                                             pDC->GetSafeHdc(), pCurrent, XP_STRLEN(pCurrent), &csz);
  391.  
  392.                                     if(csz.cx > lWidgetWidth)    {
  393.                                         lWidgetWidth = csz.cx;
  394.                                     }
  395.                                 }
  396.  
  397.                                 //    Next, please.
  398.                                 lCounter++;
  399.                             }
  400.                         }
  401.                     }
  402.                     lWidgetWidth += 2 * sysInfo.m_iScrollWidth;
  403.  
  404.                     VOID2CX(GetContext(), CPaneCX)->ReleaseNetscapeFont( pDC->GetSafeHdc(), pMyFont );
  405.                     m_pWidget->ReleaseDC(pDC);
  406.                 }
  407.                 else {
  408.                     m_pWidget->ReleaseDC(pDC);
  409.                     DestroyWidget();
  410.                     return;
  411.                 }
  412.  
  413.                 //    Figure the height we desire.
  414.                 //    NOTE:    This algorithm could use some work....
  415.                 lWidgetHeight = GetElementSelectData()->size;
  416.                 //    Catch minimal case.
  417.                 if(lWidgetHeight < 1)    {
  418.                     lWidgetHeight = 1;
  419.                 }
  420.                 lWidgetHeight *= csz.cy;
  421.                 lWidgetHeight += csz.cy / 2;
  422.                 if (GetElement()->width > lWidgetWidth) {
  423.                     lWidgetWidth = GetElement()->width;
  424.                 }
  425.                 if (GetElement()->height > lWidgetHeight) {
  426.                     lWidgetHeight = GetElement()->height;
  427.                 }
  428.                 //    Finally, size the widget to the width and height.
  429.                 //    Don't draw or display it.
  430.                 m_pWidget->MoveWindow(1, 1, CASTINT(lWidgetWidth), CASTINT(lWidgetHeight), FALSE);
  431.             }
  432.             else    {
  433.                 //    No DC, no widget.
  434.                 DestroyWidget();
  435.                 return;
  436.             }
  437.         }
  438.         else if(GetContext()->IsPureDCContext())    {
  439.         }
  440.     }
  441. }
  442.  
  443. //    Copy the current data out of the layout struct into the form
  444. //        widget, or mark that you should represent using the current data.
  445. void CFormSelectMult::UseCurrentData()
  446. {
  447.     //    Switch on context type for proper functionality.
  448.     if(GetContext())    {
  449.         if(GetContext()->IsWindowContext())    {
  450.             //    Only continue if we've a widget.
  451.             if(m_pWidget)    {
  452.                 //    Remove all previous entries.
  453.                 m_pWidget->ResetContent();
  454.  
  455.                 //    Loop through and add all data to the element.
  456.                 LO_LockLayout();
  457.                 lo_FormElementSelectData * selectData = GetElementSelectData();
  458.                 if(selectData)    {
  459.                     lo_FormElementOptionData *pOptionData = (lo_FormElementOptionData *)selectData->options;
  460.                     if(pOptionData)    {
  461.                         char *pCurrent = NULL;
  462.                         int32 lCurrent = 0;
  463.                         while(lCurrent < selectData->option_cnt)    {
  464.                             pCurrent = (char *)pOptionData[lCurrent].text_value;
  465.  
  466.                             //    add it.
  467.                             m_pWidget->AddString(pCurrent ? pCurrent : "");
  468.  
  469.                             //    Should it be selected?
  470.                             if(pOptionData[lCurrent].selected)    {
  471.                                 if(selectData->multiple)    {
  472.                                     //    Multiple selections allowed.
  473.                                     m_pWidget->SetSel(CASTINT(lCurrent));
  474.                                 }
  475.                                 else    {
  476.                                     //    Single selections only.
  477.                                     m_pWidget->SetCurSel(CASTINT(lCurrent));
  478.                                 }
  479.                             }
  480.  
  481.                             //    Next.
  482.                             lCurrent++;
  483.                         }
  484.  
  485.                         //    Go to top of list box.
  486.                         if(lCurrent)    {
  487.                             m_pWidget->SetTopIndex(0);
  488.                         }
  489.                     }
  490.                 }
  491.                 LO_UnlockLayout();
  492.             }
  493.         }
  494.         else if(GetContext()->IsPureDCContext())    {
  495.             //  Whatever is current is current.
  496.         }
  497.     }
  498. }
  499.  
  500. //    Copy the default data out of the layout struct into the form
  501. //        widget, or mark that you should represent using the default data.
  502. void CFormSelectMult::UseDefaultData()
  503. {
  504.     //    Switch on context type for proper functionality.
  505.     if(GetContext())    {
  506.         if(GetContext()->IsWindowContext())    {
  507.             //    Only continue if we've a widget.
  508.             if(m_pWidget)    {
  509.                 //    Remove all previous entries.
  510.                 m_pWidget->ResetContent();
  511.  
  512.                 //    Loop through and add all data to the element.
  513.                 LO_LockLayout();
  514.                 lo_FormElementSelectData * selectData = GetElementSelectData();
  515.                 if(selectData)    {
  516.                     lo_FormElementOptionData *pOptionData = (lo_FormElementOptionData *)selectData->options;
  517.                     if(pOptionData)    {
  518.                         char *pCurrent = NULL;
  519.                         int32 lCurrent = 0;
  520.                         while(lCurrent < selectData->option_cnt)    {
  521.                             pCurrent = (char *)pOptionData[lCurrent].text_value;
  522.  
  523.                             //    add it.
  524.                             m_pWidget->AddString(pCurrent ? pCurrent : "");
  525.  
  526.                             //    Restore default selection.
  527.                             pOptionData[lCurrent].selected = pOptionData[lCurrent].def_selected;
  528.  
  529.                             //    Should it be selected?
  530.                             if(pOptionData[lCurrent].selected)    {
  531.                                 if(selectData->multiple)    {
  532.                                     //    Multiple selections allowed.
  533.                                     m_pWidget->SetSel(CASTINT(lCurrent));
  534.                                 }
  535.                                 else    {
  536.                                     //    Single selections only.
  537.                                     m_pWidget->SetCurSel(CASTINT(lCurrent));
  538.                                 }
  539.                             }
  540.  
  541.                             //    Next.
  542.                             lCurrent++;
  543.                         }
  544.  
  545.                         //    Go to top of list box.
  546.                         if(lCurrent)    {
  547.                             m_pWidget->SetTopIndex(0);
  548.                         }
  549.                     }
  550.                 }
  551.                 LO_UnlockLayout();
  552.             }
  553.         }
  554.         else if(GetContext()->IsPureDCContext())    {
  555.             //    Loop through and set the current data to reflect the default data.
  556.             if(GetElementSelectData())    {
  557.                 lo_FormElementOptionData *pOptionData = (lo_FormElementOptionData *)GetElementSelectData()->options;
  558.                 if(pOptionData)    {
  559.                     int32 lCurrent = 0;
  560.                     while(lCurrent < GetElementSelectData()->option_cnt)    {
  561.                         //    Restore default selection.
  562.                         pOptionData[lCurrent].selected = pOptionData[lCurrent].def_selected;
  563.  
  564.                         //    Next.
  565.                         lCurrent++;
  566.                     }
  567.                 }
  568.             }        
  569.         }
  570.     }
  571. }
  572.  
  573. //    Fill in the layout size information in the layout struct regarding
  574. //        the dimensions of the widget.
  575. void CFormSelectMult::FillSizeInfo()
  576. {
  577.     //    Switch on context type for proper functionality.
  578.     if(GetContext() && GetElement())    {
  579.         if(GetContext()->IsWindowContext())    {
  580.             //    Only do this if we've got a widget at all.
  581.             if(m_pWidget)    {
  582.                 //    Determine our current window position.
  583.                 CRect crRect;
  584.                 m_pWidget->GetWindowRect(crRect);
  585.  
  586.                 //    Munge it a little for layout.
  587.                 //    We'll have to know how to reverse this
  588.                 //        effect in the display routine.
  589.                 GetElement()->width = crRect.Width();
  590.                 GetElement()->height = crRect.Height();
  591.  
  592.                 int32 lLines = 1;
  593.                 if(GetElementSelectData() && GetElementSelectData()->size > 1)    {
  594.                     lLines = GetElementSelectData()->size;
  595.                 }
  596.                 int32 csz_cy = (2 * crRect.Height() / (2 * lLines + 1));    //    This is the recalculation of csz.cy in CreateWidget
  597.                 GetElement()->baseline = crRect.Height() - (csz_cy / 4);
  598.             }
  599.             else    {
  600.                 //    No widget, zero size us with Layout.
  601.                 GetElement()->width = 0;
  602.                 GetElement()->height = 0;
  603.                 GetElement()->baseline = 0;
  604.             }
  605.         }
  606.         else if(GetContext()->IsPureDCContext())    {
  607.             //  Need to figure the size of the select box.
  608.             int32 lWidth = 0;
  609.             int32 lHeight = 0;
  610.             int32 lBaseline = 0;
  611.  
  612.             CDCCX *pDCCX = VOID2CX(GetContext(), CDCCX);
  613.             CyaFont    *pMyFont;
  614.             HDC pDC = pDCCX->GetAttribDC();
  615.             if(pDC) {
  616.                 pDCCX->SelectNetscapeFont( pDC, GetTextAttr(), pMyFont );
  617.                 if (pMyFont) {
  618.                 //  Select the font.
  619.                     SetWidgetFont(pDC, m_pWidget->m_hWnd);
  620.                     SIZE csz;
  621.                     CIntlWin::GetTextExtentPointWithCyaFont(pMyFont, 
  622.                         INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext())),
  623.                         pDC, "hi", 2, &csz);
  624.                     lWidth = csz.cx;
  625.  
  626.                     //  Count the max width by looping through all entries.
  627.                     if(GetElementSelectData())  {
  628.                         lo_FormElementOptionData *pOptionData = (lo_FormElementOptionData *)GetElementSelectData()->options;
  629.                         if(pOptionData) {
  630.                             char *pCurrent = NULL;
  631.                             int32 lCounter = 0;
  632.                             while(lCounter < GetElementSelectData()->option_cnt)    {
  633.                                 pCurrent = (char *)pOptionData[lCounter].text_value;
  634.                                 if(pCurrent && *pCurrent)    {
  635.                                     CIntlWin::GetTextExtentPointWithCyaFont(pMyFont, 
  636.                                         INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(GetContext()->GetContext())),
  637.                                         pDC, pCurrent, XP_STRLEN(pCurrent), &csz);
  638.  
  639.                                     if(csz.cx > lWidth) {
  640.                                         lWidth = csz.cx;
  641.                                     }
  642.                                 }
  643.  
  644.                                 lCounter++;
  645.                             }
  646.                         }
  647.                     }
  648.  
  649.                     //  Add some size information (basically backwards derived from the
  650.                     //      display code for best look).
  651.                     lWidth += 2 * pDCCX->Pix2TwipsX(sysInfo.m_iScrollWidth);
  652.                     lWidth += pMyFont->GetMeanWidth();
  653.  
  654.                     lHeight = GetElementSelectData()->size;
  655.                     if(lHeight < 1) {
  656.                         lHeight = 1;
  657.                     }
  658.                     lHeight *= csz.cy;
  659.                     lHeight += csz.cy / 2;
  660.  
  661.                      // Check and see if we should use preset sizes
  662.                     if (GetElement()->width > lWidth) {
  663.                         lWidth = GetElement()->width;
  664.                     }
  665.                     lBaseline = lHeight - csz.cy / 4;
  666.  
  667.                     pDCCX->ReleaseNetscapeFont( pDC, pMyFont );
  668.                 }
  669.                 else {
  670.                     m_pWidget->ReleaseDC(CDC::FromHandle(pDC));
  671.                     DestroyWidget();
  672.                 }
  673.                 pDCCX->ReleaseContextDC(pDC);
  674.             }
  675.  
  676.             //    Tell Layout what we've figured out.
  677.             GetElement()->width = lWidth;
  678.             GetElement()->height = lHeight;
  679.             GetElement()->baseline = lBaseline;
  680.         }
  681.     }
  682. }
  683.  
  684. //    Copy the current data out of the form element back into the
  685. //        layout struct.
  686. void CFormSelectMult::UpdateCurrentData()
  687. {
  688.     //    Switch on context type for proper functionality.
  689.     if(GetContext())    {
  690.         if(GetContext()->IsWindowContext())    {
  691.             //    Only continue if we've got a widget and data space to fill at all.
  692.             if(m_pWidget && ::IsWindow(m_pWidget->GetSafeHwnd()) && GetElementSelectData())    {
  693.                 lo_FormElementOptionData *pOptionData = (lo_FormElementOptionData *)GetElementSelectData()->options;
  694.                 if(pOptionData)    {
  695.                     //    Turn everything off in the layout structure.
  696.                     int32 lCounter = 0;
  697.                     while(lCounter < GetElementSelectData()->option_cnt)    {
  698.                         //    Turn your head and cough.
  699.                         pOptionData[lCounter].selected = FALSE;
  700.                         //    Next.
  701.                         lCounter++;
  702.                     }
  703.  
  704.                     //    Determine wether multiple selections allowed.
  705.                     if(GetElementSelectData()->multiple)    {
  706.                         //    Get number selected.
  707.                         int32 lNumber = m_pWidget->GetSelCount();
  708.                         if(lNumber > 0)    {
  709.                             //    Need an array to store the indexes of selection.
  710.                             LPINT pIxs = new int[lNumber];
  711.                             if(pIxs)    {
  712.                                 //    Gather the info.
  713.                                 m_pWidget->GetSelItems(CASTINT(lNumber), pIxs);
  714.  
  715.                                 //    Loop through each one.
  716.                                 lCounter = 0;
  717.                                 while(lCounter < lNumber)    {
  718.                                     //    Stick your tongue out and say "aaaaaa....."
  719.                                     pOptionData[pIxs[lCounter]].selected = TRUE;
  720.                                     //    Next.
  721.                                     lCounter++;
  722.                                 }
  723.  
  724.                                 delete [] pIxs;
  725.                             }
  726.                         }
  727.                     }
  728.                     else    {
  729.                         //    Only one selection.
  730.                         int32 lSelected = m_pWidget->GetCurSel();
  731.                         if(lSelected != LB_ERR)    {
  732.                             pOptionData[lSelected].selected = TRUE;
  733.                         }
  734.                     }                    
  735.                 }
  736.             }
  737.         }
  738.         else if(GetContext()->IsPureDCContext())    {
  739.             //  Whatever is current, will be represented.
  740.         }
  741.     }
  742. }
  743.  
  744. HWND CFormSelectMult::GetRaw()
  745. {
  746.     return(m_pWidget ? m_pWidget->m_hWnd : NULL);
  747. }
  748.  
  749.