home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / central / mforms.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  98.6 KB  |  3,629 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. // mforms.cp - contains all the form widgets.
  20.  
  21. // macfe
  22. #include "Netscape_Constants.h"
  23. #include "mforms.h"
  24. #include "uprefd.h"
  25. #include "macgui.h"
  26. #include "macutil.h"
  27. #include "resgui.h"
  28. #include "ufilemgr.h"
  29. #include "uerrmgr.h"
  30. #include "xpassert.h"
  31. #include "UFormElementFactory.h"
  32. #include "CBrowserContext.h"
  33. #include "CBrowserWindow.h"
  34. #include "CHTMLView.h"
  35. #include "CWindowMediator.h"
  36. #include "uintl.h"
  37.  
  38. // xp
  39. #include "proto.h"
  40. #include "lo_ele.h"
  41. #include "xlate.h"
  42. #include "shist.h"
  43. #include "libevent.h"
  44. #include "layers.h" // mjc
  45. #include "prefapi.h"
  46. #include "intl_csi.h"
  47.  
  48. // PP
  49. //#include <LTextSelection.h>
  50. //#include <LTextModel.h>
  51. //#include <LEventHandler.h>
  52. #include <PP_KeyCodes.h>
  53. #include <UTextTraits.h>
  54. #include <LArray.h>
  55. #include <LCommander.h>
  56.  
  57. #include "CSimpleTextView.h"
  58.  
  59. #include "UUnicodeTextHandler.h"
  60. #include "UUTF8TextHandler.h"
  61. #include "UFixedFontSwitcher.h"
  62. #include "UPropFontSwitcher.h"
  63. #include "UFontSwitcher.h"
  64. #include "CMochaHacks.h"
  65. #include <UGAColorRamp.h>
  66. #include <UGraphicsUtilities.h>
  67.  
  68. // macros
  69. #define FEDATAPANE    ((FormFEData *)formElem->element_data->ele_minimal.FE_Data)->fPane    
  70. #define FEDATAHOST     ((FormFEData *)formElem->element_data->ele_minimal.FE_Data)->fHost
  71. #define FEDATACOMMANDER ((FormFEData *)formElem->element_data->ele_minimal.FE_Data)->fCommander
  72.  
  73. // debugging
  74. //#define DEBUG_FORMS
  75. #ifdef DEBUG_FORMS
  76. void TraceForm(char * what, LO_FormElementStruct *formElem);
  77. void TraceForm(char * what, LO_FormElementStruct *formElem)
  78. {
  79.     XP_TRACE(("Routine: %s, formEle %d, type  %d, FE_Data %d \n",
  80.          what, (Int32)formElem, (Int32)formElem->type,
  81.          (Int32)formElem->element_data->ele_minimal.FE_Data));
  82. }
  83. #define XP_TRACEFORM(ROUTINE, FORM) TraceForm(ROUTINE, FORM)
  84. #else
  85. #define XP_TRACEFORM(ROUTINE, FORM)
  86. #endif
  87.  
  88. inline  FormFEData *GetFEData(LO_FormElementStruct *formElem) { return ((FormFEData *)formElem->element_data->ele_minimal.FE_Data); }
  89. inline    LPane *GetFEDataPane( LO_FormElementStruct *formElem) { return FEDATAPANE; } 
  90. inline  void  SetFEDataPane(LO_FormElementStruct *formElem, LPane *p) { FEDATAPANE = p; }
  91.  
  92. static void    FocusFormElementTimer(    LO_FormElementStruct * formElement );
  93. static void    BlurFormElementTimer(    LO_FormElementStruct * formElement );
  94.  
  95. static void MochaFocusCallback(MWContext * pContext, LO_Element * lo_element, int32 lType, void * whatever, ETEventStatus status);
  96. static void MochaChangedCallback(MWContext * pContext, LO_Element * lo_element, int32 lType, void * whatever, ETEventStatus status);
  97.  
  98. static void MochaClick( MWContext* context, LO_Element* ele, CMochaEventCallback * cb );
  99. static void MochaMouseUp( MWContext* context, LO_Element* ele, CMochaEventCallback * cb );
  100. //static void MochaKeyPress( MWContext* context, LO_Element* ele, CMochaEventCallback * cb, EventRecord inKeyEvent );
  101.  
  102. void    FE_RaiseWindow(MWContext* inContext);
  103. void    FE_LowerWindow( MWContext* inContext);
  104.  
  105. // Drawing setup
  106. // Sets up the colors for drawing forms
  107. StSetupFormDrawing::StSetupFormDrawing( LPane* formElement )
  108. {
  109.     fForm = formElement;
  110.  
  111.     UGraphics::SetWindowColor( fForm->GetMacPort(), wTextColor, CPrefs::GetColor( CPrefs::Black ) );
  112.     UGraphics::SetWindowColor( fForm->GetMacPort(), wContentColor, CPrefs::GetColor( CPrefs::White ) );
  113. }
  114.  
  115. StSetupFormDrawing::~StSetupFormDrawing()
  116. {
  117. // FIX ME! Why do we do this?
  118.     CHTMLView*        view = (CHTMLView*)fForm->GetSuperView();
  119.     
  120.     UGraphics::SetWindowColor( fForm->GetMacPort(), wTextColor, CPrefs::GetColor( CPrefs::Black ) );
  121.     if (view)
  122.         UGraphics::SetWindowColor( fForm->GetMacPort(), wContentColor, view->GetBackgroundColor() );
  123. }
  124.  
  125. /*-----------------------------------------------------------------------------
  126.     FormFEData
  127.   -----------------------------------------------------------------------------*/
  128. FormFEData::FormFEData()
  129. {
  130.     fPane = NULL;
  131.     fHost = NULL;
  132. }
  133.  
  134. FormFEData::~FormFEData()
  135. {
  136.     // Schedule the form element to be 
  137.     // destroyed at idle time
  138.     if (fHost != NULL)
  139.     {
  140.         fHost->MarkForDeath();
  141.         fHost->SetFEData(NULL);
  142.         
  143.     }        
  144.  
  145.     fPane        = NULL;
  146.     fHost         = NULL;
  147.     fCommander     = NULL;            
  148. }
  149.  
  150.  
  151.  
  152.  
  153. #pragma mark == FormsPopup ==
  154.  
  155. /*-----------------------------------------------------------------------------
  156.     Forms Popup
  157.     Displays a FORM_TYPE_SELECT_ONE structure
  158. -----------------------------------------------------------------------------*/
  159.  
  160. FormsPopup::FormsPopup (CGAPopupMenu * target, lo_FormElementSelectData_struct * selections)
  161. :    StdPopup (target), LFormElement()
  162. {
  163.     fSelections = selections;
  164.     fFocusState = FocusState_None;
  165.     fSavedFocus = nil;
  166.     fOldValue = -1;
  167.     target->SetMaxValue(selections->option_cnt);
  168.     SetReflectOnChange(true);
  169. }
  170.  
  171. short
  172. FormsPopup::GetCount ()
  173. {
  174.     return fSelections->option_cnt;
  175. }
  176.  
  177. CStr255
  178. FormsPopup::GetText (short item)
  179. {
  180.     lo_FormElementOptionData *options = nil;
  181.     PA_LOCK (options, lo_FormElementOptionData*, fSelections->options);
  182.     CStr255 text;
  183.     PA_LOCK (text, char*, options[item-1].text_value);
  184.     PA_UNLOCK (options[item-1].text_value);
  185.     PA_UNLOCK (fSelections->options);
  186.     
  187.     if (text == "")
  188.         text = " ";
  189.     return text;
  190. }
  191.  
  192.  
  193. /*
  194.     FormsPopup::ExecuteSelf
  195.     
  196.     2 important things here when we're handling a click...
  197.     
  198.     1) if the value of the popup changes, we call MochaChanged
  199.     2) popups have onFocus and onBlur handlers in Javascript, so
  200.        we fake giving the popup focus, even though they really
  201.        don't get focus on Macs.  So we give it focus real quick,
  202.        then take it away after the click is handled.  Yippee.
  203.  
  204. */
  205. void    
  206. FormsPopup::ExecuteSelf(MessageT     inMessage, 
  207.                         void*        ioParam        )
  208. {
  209.     fTarget->SetNeedCustomDrawFlag(NeedCustomPopup());
  210.     // we're only interested in clicks
  211.     if (inMessage == msg_Click)
  212.     {
  213.         fOldValue = fTarget->GetValue();
  214.         mExecuteHost = true;
  215.         // Temporarily give focus to the popup in Javascript land
  216.         if (this != sTargetedFormElement)
  217.         {
  218.             // If we aren't targeted form element, set sTargetedFormElement
  219.             // to popup menu and blur currently targeted form element
  220.             if (sTargetedFormElement != NULL) {
  221.                 fSavedFocus = sTargetedFormElement;
  222.                 sTargetedFormElement->MochaFocus(false);
  223.             }
  224.             // 97-06-14 pkc -- set fFocusState to execute correct code on callback
  225.             fFocusState = FocusState_FirstCall;
  226.             // focus popup menu
  227.             MochaFocus(true);
  228.         }
  229.         else {
  230.             // 97-06-14 pkc -- set fFocusState to execute correct code on callback
  231.             fFocusState = FocusState_FirstCall;
  232.             // focus popup menu
  233.             MochaFocus(true);
  234.         }            
  235.     }
  236.     else {
  237.         StdPopup::ExecuteSelf(inMessage, ioParam);        
  238.     }
  239. }
  240. //
  241. // do ScriptCode Menu Trick on IM:MacTbxEss Page3-46
  242. //
  243. //    Good for most encoding except
  244. //        Greek, Turkish, and UTF8
  245. //
  246. void    
  247. FormsPopup::SetMenuItemText(MenuHandle aquiredMenu, int item, CStr255& itemText)
  248. {
  249.     StdPopup::SetMenuItemText( aquiredMenu, item, itemText);
  250.     if (! NeedDrawTextInOurOwn())
  251.     {        
  252.         // do ScriptCode Menu Trick on IM:MacTbxEss Page3-46
  253.         CCharSet charset;
  254.         if(CPrefs::GetFont(GetWinCSID(), &charset))
  255.         {
  256.             ::SetItemCmd (aquiredMenu, item, 0x1c );
  257.             ::SetItemIcon (aquiredMenu, item, charset.fFallbackFontScriptID );
  258.         }
  259.     }
  260. }
  261. //
  262. //    Decide wheather we use override SetMenuItemText or PopUpMenuSelect
  263. //
  264. Boolean    FormsPopup::NeedDrawTextInOurOwn() const
  265. {
  266.     return (fContext &&
  267.         (GetWinCSID() == CS_UTF8));
  268. }
  269. void     FormsPopup::DrawTruncTextBox (CStr255 text, const Rect& box)
  270. {
  271.     if(GetWinCSID() == CS_UTF8)
  272.     {
  273.         /*
  274.         Truncates the text before drawing.
  275.         Does not word wrap.
  276.         */
  277.         FontInfo fontInfo;
  278.         UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  279.         UFontSwitcher *fs = UPropFontSwitcher::Instance();
  280.         
  281.         th->GetFontInfo (fs, &fontInfo);
  282.         MoveTo (box.left, box.bottom - fontInfo.descent -1);
  283.         // ÑÑÑ╩Fix me 
  284.         //    UTF8 vresion does not truncate for now.
  285.         // TruncString (box.right - box.left, text, truncEnd);       
  286.         
  287.         th->DrawString (fs,  text);
  288.     }
  289.     else
  290.     {
  291.          StdPopup::DrawTruncTextBox(text, box);
  292.     }
  293. }
  294.  
  295. Boolean    FormsPopup::NeedCustomPopup() const
  296. {
  297.     XP_Bool    useGrayscaleFormControls = false;
  298.     int        prefResult = PREF_GetBoolPref("browser.mac.use_grayscale_form_controls", &useGrayscaleFormControls);
  299.  
  300.     return (prefResult != PREF_NOERROR || !useGrayscaleFormControls || NeedDrawTextInOurOwn());
  301. }
  302.  
  303. // 97-06-14 pkc -- state machine callback hack to handle onFocus correctly
  304. void FormsPopup::PostMochaFocusCallback()
  305. {
  306.     if (fFocusState == FocusState_FirstCall) {
  307.         //
  308.         // Call through to handle the click, and let 
  309.         // Javascript know if the value changed
  310.         //
  311.         Assert_(fTarget != NULL);
  312.         
  313.         if (fOldValue != fTarget->GetValue()) {
  314.             fFocusState = FocusState_SecondCall;
  315.             MochaChanged();
  316.         }
  317.         else {
  318.             // Restore original focus state
  319.             // First, blur popup menu
  320.             // 97-06-14 pkc -- set fFocusState to execute correct code on callback
  321.             fFocusState = FocusState_ThirdCall;
  322.             MochaFocus(false, false);
  323.             // 97-06-20 pkc -- set sTargetedFormElement to NULL becuase popup menus
  324.             // aren't really targeted
  325.             sTargetedFormElement = NULL;
  326.         }
  327.     }
  328.     else if (fFocusState == FocusState_SecondCall) {
  329.         // Restore original focus state
  330.         // First, blur popup menu
  331.         // 97-06-14 pkc -- set fFocusState to execute correct code on callback
  332.         fFocusState = FocusState_ThirdCall;
  333.         MochaFocus(false, false);
  334.         // 97-06-20 pkc -- set sTargetedFormElement to NULL becuase popup menus
  335.         // aren't really targeted
  336.         sTargetedFormElement = NULL;
  337.     }
  338.     else if (fFocusState == FocusState_ThirdCall) {
  339.         // Restore original focus state
  340.         // Now focus previously focused element if there was one
  341.         if (fSavedFocus != NULL) {
  342.             fSavedFocus->MochaFocus(true);
  343.             fSavedFocus = NULL;
  344.         }
  345.     }
  346. }
  347.  
  348. #pragma mark == LFormElement ==
  349.  
  350. int16 LFormElement::GetWinCSID() const
  351. {
  352.     INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(fContext);
  353.  
  354.     return INTL_GetCSIWinCSID(csi);
  355. }
  356.  
  357. #pragma mark == CWhiteEditField ==
  358.  
  359. CWhiteEditField::CWhiteEditField(LStream *inStream)
  360.     :     CTSMEditField(inStream), LFormElement()
  361. {
  362. }
  363.  
  364. // Draws background to white
  365. void
  366. CWhiteEditField::DrawSelf()
  367. {
  368.     Rect    frame;
  369.     CalcLocalFrameRect(frame);
  370.  
  371.     ::InsetRect(&frame, 1,1);
  372.     ::EraseRect(&frame);
  373.  
  374.     CTSMEditField::DrawSelf();    
  375.  
  376.     ::InsetRect(&frame, -1,-1);
  377.     UGraphics::FrameRectSubtle(frame, true);    
  378. }
  379.  
  380.  
  381. void
  382. CWhiteEditField::BeTarget()
  383. {
  384.     CTSMEditField::BeTarget();
  385.     MochaFocus(true);
  386. }
  387.  
  388. void
  389. CWhiteEditField::DontBeTarget()
  390. {    
  391.     
  392.     MochaFocus(false);  // this must go first because
  393.                         // it might indirectly set us to be the target again,
  394.                         // which would be wrong.
  395.                         
  396.     CTSMEditField::DontBeTarget();
  397. }
  398.  
  399. void
  400. CWhiteEditField::UserChangedText()
  401. {
  402.     CTSMEditField::UserChangedText();
  403.     MochaChanged();
  404. }
  405.  
  406. void    
  407. CWhiteEditField::ClickSelf(    const SMouseDownEvent& event)
  408. {
  409.     SInt16 oldSelStart, oldSelEnd;
  410.     
  411.     oldSelStart = (**mTextEditH).selStart;
  412.     oldSelEnd    = (**mTextEditH).selEnd;
  413.     
  414.     CTSMEditField::ClickSelf(event);
  415.     
  416.     if (oldSelStart != (**mTextEditH).selStart    ||
  417.         oldSelEnd != (**mTextEditH).selEnd)
  418.     {    
  419.         MochaSelect();
  420.     }    
  421. }
  422.  
  423. Boolean 
  424. CWhiteEditField::HandleKeyPress(const EventRecord& inKeyEvent)
  425. {
  426.     if (keyUp == inKeyEvent.what) return true; // ignore key ups for now
  427.     else return CTSMEditField::HandleKeyPress(inKeyEvent);
  428. }
  429.  
  430.  
  431. #pragma mark == CFormLittleText ==
  432.  
  433. //---------------------------------------------------------------------------
  434. // class CFormLittleText
  435. //---------------------------------------------------------------------------
  436.  
  437. CFormLittleText::CFormLittleText(LStream *inStream) : CWhiteEditField(inStream)
  438. {
  439.     fDoBroadcast = FALSE;
  440.     fLOForm = NULL;
  441. #ifdef LAYERS
  442.     // add an attachment which will intercept key events and dispatch them to layers
  443.     CLayerKeyPressDispatchAttachment* led = new CLayerKeyPressDispatchAttachment;
  444.     AddAttachment(led);
  445. #endif
  446. }
  447.  
  448. void CFormLittleText::BroadcastValueMessage()
  449. {
  450.     BroadcastMessage(msg_SubmitText, (void*) this);
  451. }
  452.  
  453. void CFormLittleText::SetVisibleChars(Int16 visChars)
  454. {
  455.     FocusDraw();
  456.     UTextTraits::SetPortTextTraits(mTextTraitsID);
  457.     FontInfo fInfo;
  458.     ::GetFontInfo(&fInfo);
  459.     
  460.     ResizeFrameTo(::CharWidth('a') * visChars + 6, fInfo.ascent + fInfo.descent+ fInfo.leading + 4, FALSE);    
  461. }
  462.  
  463. // Key events are intercepted by an attachment, routed through layers and return
  464. // to the front end (through FE_HandleLayerEvent) if javascript lets us have the event. 
  465. // CHTMLView::HandleKeyPressLayer calls this.
  466. Boolean CFormLittleText::HandleKeyPress(const EventRecord& inKeyEvent)
  467. {
  468.     Boolean handled = false;
  469.     if (keyUp == inKeyEvent.what) return true; // ignore key ups for now
  470.     
  471.     char c = inKeyEvent.message & charCodeMask;
  472.  
  473.     if (fDoBroadcast && ((c == char_Enter) || (c == char_Return)))
  474.     {
  475.         BroadcastValueMessage();
  476.         handled = true;
  477.     }
  478.     else
  479.     {
  480.         handled = CWhiteEditField::HandleKeyPress(inKeyEvent);
  481.     }
  482.     return handled;
  483. }
  484.  
  485. void CFormLittleText::FindCommandStatus(
  486.                                 CommandT            inCommand,
  487.                                 Boolean                &outEnabled,
  488.                                 Boolean                &outUsesMark,
  489.                                 Char16                &outMark,
  490.                                 Str255                outName)
  491. {
  492.     if ( inCommand == cmd_Cut || inCommand == cmd_Copy )
  493.     {
  494.         lo_FormElementTextData* textData;
  495.         if ( fLOForm )
  496.         {
  497.             textData = (lo_FormElementTextData*)fLOForm->element_data;
  498.             if ( textData && textData->type == FORM_TYPE_PASSWORD )
  499.             {
  500.                 outEnabled = FALSE;
  501.                 return;
  502.             }
  503.         }
  504.     }
  505.     CWhiteEditField::FindCommandStatus( inCommand, outEnabled, outUsesMark, outMark, outName );
  506. }
  507.  
  508. void CFormLittleText::BeTarget()
  509. {
  510. // FIX ME!
  511. //    ((CHyperView*)mSuperView)->ShowView(this);
  512.     CHTMLView* theHTMLView = dynamic_cast<CHTMLView*>(GetSuperView());
  513.     if (theHTMLView)
  514.         theHTMLView->ShowView(*this);
  515.  
  516.     CWhiteEditField::BeTarget();
  517. }
  518. StringPtr CFormLittleText::GetDescriptor(
  519.                                 Str255                outDescriptor) const
  520. {
  521.     if(fContext && (CS_UTF8 == GetWinCSID()))
  522.     {
  523.         Str255 nonUTF8Str;
  524.         StringPtr nonUTF8text;
  525.         nonUTF8text = CWhiteEditField::GetDescriptor(nonUTF8Str);
  526.         int16 font_csid = ScriptToEncoding(FontToScript((**UTextTraits::LoadTextTraits(mTextTraitsID)).fontNumber));
  527.         char* utf8text = (char*) INTL_ConvertLineWithoutAutoDetect(font_csid, CS_UTF8, nonUTF8text+ 1, nonUTF8text[0] );
  528.         if(utf8text)
  529.         {
  530.             int len = XP_STRLEN(utf8text);
  531.             if(len > 254)
  532.                 len = 254;
  533.             outDescriptor[0] = len;
  534.             XP_MEMCPY((outDescriptor + 1), utf8text, len );
  535.             XP_FREE(utf8text);            
  536.             return outDescriptor;
  537.         }        
  538.         else
  539.         {
  540.             outDescriptor[0] = 0;    // somehow we cannot get Descriptor
  541.             return outDescriptor;
  542.         }
  543.     } else {
  544.         return CWhiteEditField::GetDescriptor(outDescriptor);
  545.     }
  546. }
  547. void CFormLittleText::SetDescriptor(
  548.                                 ConstStr255Param    inDescriptor)
  549. {
  550.     if(fContext && (CS_UTF8 == GetWinCSID()))
  551.     {
  552.         // Find out the font csid
  553.         int16 font_csid = ScriptToEncoding(FontToScript((**UTextTraits::LoadTextTraits(mTextTraitsID)).fontNumber));
  554.         // Convert the UTF8 text into non-UTF8 text
  555.         char* nonUTF8text = (char*) INTL_ConvertLineWithoutAutoDetect(CS_UTF8, font_csid, (unsigned char*)inDescriptor+ 1, inDescriptor[0] );
  556.         if(nonUTF8text)
  557.         {
  558.             int len = XP_STRLEN(nonUTF8text);
  559.             if(len > 254) len = 254;
  560.             Str255 nonUTF8Str;
  561.             nonUTF8Str[0] = len;
  562.             XP_MEMCPY((nonUTF8Str + 1), nonUTF8text, len );
  563.             XP_FREE(nonUTF8text);
  564.             CWhiteEditField::SetDescriptor(nonUTF8Str);
  565.         }
  566.         else
  567.         {
  568.             CWhiteEditField::SetDescriptor("\p");    // Somehow we failed. set it to null string            
  569.         }
  570.     } else {
  571.         CWhiteEditField::SetDescriptor(inDescriptor);
  572.     }
  573. }
  574.  
  575. #pragma mark == CFormBigText ==
  576.  
  577. //---------------------------------------------------------------------------
  578. // class CFormBigText
  579. //---------------------------------------------------------------------------
  580.  
  581. CFormBigText::CFormBigText(LStream *inStream)
  582.     :    CSimpleTextView(inStream),
  583.         LFormElement()
  584. {
  585.  
  586. #ifdef LAYERS
  587.     // add an attachment which will intercept key events and dispatch them to layers
  588.     CLayerKeyPressDispatchAttachment* led = new CLayerKeyPressDispatchAttachment;
  589.     AddAttachment(led);
  590. #endif
  591. }
  592.  
  593. CFormBigText::~CFormBigText()
  594. {
  595.     PostAction(NULL);
  596. }
  597.  
  598. void CFormBigText::DrawSelf()
  599. {
  600.     Rect    frame;
  601.     CalcLocalFrameRect(frame);
  602.     
  603.     ::InsetRect(&frame, 1,1);
  604.     ::EraseRect(&frame);
  605.  
  606.     CSimpleTextView::DrawSelf();
  607. }
  608.  
  609. Boolean CFormBigText::ObeyCommand(CommandT inCommand, void* ioParam)
  610. {
  611.     Boolean cmdHandled = true;
  612.     
  613.     switch (inCommand)
  614.     {
  615.     case msg_TabSelect:
  616.         if (!IsEnabled())
  617.         {
  618.             cmdHandled = false;
  619.             break;
  620.         }
  621.         inCommand = cmd_SelectAll;
  622.         //    fall through to default ...
  623.         
  624.     default:
  625.         cmdHandled = CSimpleTextView::ObeyCommand(inCommand, ioParam);
  626.         break;
  627.     }
  628.     return cmdHandled;
  629. }
  630.  
  631. Boolean CFormBigText::FocusDraw(LPane* /*inSubPane*/)
  632. {
  633. //    CSimpleTextView::SetMultiScript(fContext && (GetWinCSID() == CS_UTF8));
  634.     if (CSimpleTextView::FocusDraw())
  635.     {
  636.         UGraphics::SetBack(CPrefs::White);
  637.         return TRUE;
  638.     }
  639.     else
  640.         return FALSE;
  641. }
  642.  
  643. void CFormBigText::BeTarget()
  644. {
  645. // Show scrollbar inside the hyperview
  646. // FIX ME!
  647. //    ((CHyperView*)(mSuperView->GetSuperView()))->ShowView(mSuperView);
  648.     if (GetSuperView())
  649.     {
  650.         CHTMLView* theHTMLView = dynamic_cast<CHTMLView*>(GetSuperView()->GetSuperView());
  651.         if (theHTMLView)
  652.             theHTMLView->ShowView(*GetSuperView());
  653.     }
  654.  
  655.     CSimpleTextView::BeTarget();
  656.     MochaFocus(true);
  657. //    CSimpleTextView::SetMultiScript(fContext && (GetWinCSID() == CS_UTF8));
  658. }
  659.  
  660.  
  661.  
  662.  
  663. void 
  664. CFormBigText::DontBeTarget()
  665. {
  666.     MochaFocus(false);
  667.     CSimpleTextView::DontBeTarget();
  668. }
  669.  
  670.  
  671. void CFormBigText::ClickSelf(const    SMouseDownEvent& event)    // to call MochaSelect
  672. {
  673.  
  674.     SInt32    selStart     = 0;
  675.     SInt32    selEnd        = 0;
  676.     
  677. //    GetSelection( &selStart, &selEnd );
  678. //    SInt32 theOldRange = selEnd - selStart;
  679.  
  680.     CSimpleTextView::ClickSelf(event);
  681.  
  682. //    GetSelection( &selStart, &selEnd );
  683. //    SInt32 theNewRange = selEnd - selStart;
  684.     
  685. //    if (theOldRange != theNewRange)
  686. //        MochaSelect();
  687.         
  688.     }
  689.  
  690. // The textengine sends us a message when the text changes
  691. /*
  692. void CFormBigText::ListenToMessage(MessageT inMessage, void *ioParam)    // to call MochaChanged
  693. {
  694. //    if (inMessage == msg_CumulativeRangeChanged)
  695. //        MochaChanged();
  696.         
  697. //    CSimpleTextView::ListenToMessage(inMessage, ioParam);
  698. }    
  699. */
  700.  
  701.  
  702. //  VText's text engine used to broadcast stuff if something changed. WASTE
  703. //  does not do this, however there is a UserChangedText method in the CWASTEEdit
  704. //  class that is called when the text is changed. I hope this will suffice...
  705.  
  706.  
  707. void
  708. CFormBigText::UserChangedText()
  709.     {
  710.     
  711.         MochaChanged();
  712.     
  713.     }
  714.     
  715.  
  716. // Key events are intercepted by an attachment, routed through layers and return
  717. // to the front end (through FE_HandleLayerEvent) if javascript lets us have the event. 
  718. // CHTMLView::HandleKeyPressLayer calls this.
  719. Boolean CFormBigText::HandleKeyPress(const EventRecord& inKeyEvent)
  720. {    
  721.     Boolean handled = false;
  722.     char c = inKeyEvent.message & charCodeMask;
  723.     
  724.     if (keyUp == inKeyEvent.what) handled = true; // ignore key ups for now
  725.     else handled = CSimpleTextView::HandleKeyPress(inKeyEvent);
  726.     return handled;
  727. }
  728.  
  729.     
  730. #pragma mark == CFormList ==
  731.  
  732. //---------------------------------------------------------------------------
  733. // class CFormList
  734. //---------------------------------------------------------------------------
  735.  
  736. // We use the CallerLDEF approach from the March 1995 Develop article "An Object-Oriented
  737. // Approach to Hierarchical Lists." The author of the article is Jan Bruyndonckx.
  738.  
  739. CFormList::CFormList(LStream * inStream) : LListBox(inStream), LFormElement()
  740. {
  741.     fLongestItem = 36;
  742.     ::LAddColumn(1, 0, mMacListH);
  743.     SetReflectOnChange(true);
  744.     
  745.     (*mMacListH)->refCon = (long) callerLDEFUPP ;    // put address of callback in refCon
  746.      (*mMacListH)->userHandle = (Handle) this ;    // keep a pointer to ourself
  747.  
  748. }
  749.  
  750. CFormList::~CFormList()
  751. {
  752.     Rect theNullRect = { 0, 0, 0, 0 };
  753.  
  754.     ControlHandle& theScrollBar = (*mMacListH)->vScroll;
  755.     if (theScrollBar != NULL)
  756.         (*theScrollBar)->contrlRect = theNullRect;
  757.  
  758.     theScrollBar = (*mMacListH)->hScroll;
  759.     if (theScrollBar != NULL)
  760.         (*theScrollBar)->contrlRect = theNullRect;
  761.  
  762.     // we're not necessarily destroyed because our
  763.     // superview is, so we need to explicitly kill
  764.     // the focus box.
  765.     if (mFocusBox != NULL)
  766.         delete mFocusBox;
  767. }
  768.  
  769. ListDefUPP CFormList::callerLDEFUPP = NewListDefProc (LDefProc) ;    // create UPP for LDEF callback
  770.  
  771. // ÑÑ Misc
  772.  
  773. void CFormList::SetSelectMultiple(Boolean multipleSel)
  774. {
  775.     if (multipleSel)
  776.         (*mMacListH)->selFlags = lUseSense;
  777.     else
  778.         (*mMacListH)->selFlags = lOnlyOne;
  779. }
  780.  
  781. // Add an item to the list. Figure out its length so we can shrinkToFit
  782. void CFormList::AddItem( const cstring& itemName, SInt16 rowNum )
  783. {
  784.     Point aCell;
  785.     
  786.     aCell.h = 0;
  787.     aCell.v = rowNum;
  788.     ::LSetCell( itemName.data(), itemName.length(), aCell, mMacListH );
  789.     long newLength;
  790.     if(GetWinCSID() == CS_UTF8)
  791.     {
  792.         UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  793.           UFontSwitcher *fs = UPropFontSwitcher::Instance();
  794.         newLength = th->TextWidth(fs,    (char*)itemName.data(), (int)itemName.length());
  795.     } else {
  796.         newLength = ::TextWidth( itemName.data(), 0, itemName.length());
  797.     }
  798.     newLength += 26;
  799.     if ( newLength > fLongestItem )
  800.         fLongestItem = newLength;
  801. }
  802.  
  803.  
  804. void CFormList::SetTextTraits()
  805. {
  806.     UTextTraits::SetPortTextTraits(mTextTraitsID);    
  807. }
  808.  
  809. void CFormList::SyncRows( UInt16 nRows )
  810. {
  811.     if ( (**mMacListH).dataBounds.bottom > nRows )
  812.         ::LDelRow( (**mMacListH).dataBounds.bottom - nRows, nRows, mMacListH );
  813.     else
  814.         ::LAddRow( nRows - (**mMacListH).dataBounds.bottom, (**mMacListH).dataBounds.bottom, mMacListH );
  815. }
  816.  
  817.  
  818. void
  819. CFormList::BeTarget()
  820. {
  821.     LListBox::BeTarget();
  822.     MochaFocus(true);
  823. }
  824.     
  825.     
  826. void
  827. CFormList::DontBeTarget()
  828. {
  829.     LListBox::DontBeTarget();
  830.     MochaFocus(false);    
  831. }
  832.  
  833.  
  834. // Selecting items
  835. void CFormList::SetSelect(int item, Boolean selected)
  836. {
  837.     FocusDraw();
  838.     Point aCell;
  839.     SetPt(&aCell, 0, item);
  840.     ::LSetSelect(selected,aCell,mMacListH);
  841. }
  842.  
  843. void CFormList::SelectNone()
  844. {
  845.     Cell c;
  846.     SInt16    total = (*mMacListH)->dataBounds.bottom;
  847.  
  848.     c.h = 0;
  849.     
  850.     FocusDraw();
  851.         
  852.     ::LSetDrawingMode(false, mMacListH);
  853.     // Just a friendly reminder, List Mangler cell
  854.     // coords are zero based.
  855.     for (c.v = 0; c.v < total; c.v++)
  856.         ::LSetSelect(false, c, mMacListH);
  857.         
  858.     ::LSetDrawingMode(true, mMacListH);
  859.     
  860.     Refresh();
  861. }
  862.  
  863.  
  864. /*
  865. void
  866. CFormList::Reset(    lo_FormElementSelectData    *    selectData
  867.                     Boolean                            resetSelection,
  868.                     Boolean                            resetOptions    )
  869. {                    
  870.     lo_FormElementOptionData * mother;
  871.     
  872.     PA_LOCK(mother, lo_FormElementOptionData *, selectData->options);        
  873.     for (int i=0; i<selectData->option_cnt; i++)
  874.     {
  875.         char * itemName = NULL;
  876.         Boolean select;
  877.         
  878.         PA_LOCK(itemName, char*, mother[i].text_value);
  879.         myList->AddItem (itemName, 0);
  880.         PA_UNLOCK(mother[i].text_value);
  881.         
  882.         if (fromDefaults)
  883.             select = mother[i].def_selected;
  884.         else
  885.             select = mother[i].selected;
  886.             
  887.         if (select)
  888.             SetSelect(i, select);
  889.     }
  890. }
  891. */
  892.  
  893. // Are they selected
  894. Boolean CFormList::IsSelected(int item)
  895. {
  896.     Point theCell;
  897.     SetPt(&theCell, 0, item);
  898.     return (::LGetSelect(FALSE,&theCell,mMacListH));
  899. }
  900.  
  901.  
  902. // Resizes the list to the width of the longest item, and visRows
  903. void CFormList::ShrinkToFit( Int32 visRows )
  904. {
  905.     // We need to adjust the height for CS_UTF8
  906.     if(GetWinCSID() == CS_UTF8)
  907.     {
  908.         FontInfo        info;
  909.         UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  910.           UFontSwitcher *fs = UPropFontSwitcher::Instance();
  911.         th->GetFontInfo(fs, &info );        
  912.          (*mMacListH)->cellSize.v = info.ascent + info.descent + info.leading;
  913.     }    
  914.     ResizeFrameTo(fLongestItem, visRows * (*mMacListH)->cellSize.v+2, FALSE); // Must get a scroller in there
  915.     // We need to resize our cell to fill the whole list
  916.     Rect displayRect;
  917.     CalcLocalFrameRect(displayRect);
  918.     ::InsetRect(&displayRect, 1, 1);
  919.     displayRect.right -= 15;    // To account for the scrollbar
  920.     (**mMacListH).cellSize.h = displayRect.right - displayRect.left;
  921.  
  922. }
  923.  
  924. // Sets background to white
  925. Boolean CFormList::FocusDraw(LPane* /*inSubPane*/)
  926. {
  927.     if (LListBox::FocusDraw())
  928.     {
  929.         UGraphics::SetBack(CPrefs::White);
  930.         return TRUE;
  931.     }
  932.     else
  933.     {
  934.         return FALSE;
  935.     }
  936. }
  937.  
  938. extern Boolean gIsPrinting;
  939.  
  940.  
  941. // white background
  942. void CFormList::DrawSelf()
  943. {
  944.     Rect    frame;
  945.     
  946.     CalcLocalFrameRect(frame);
  947.     ::EraseRect(&frame);
  948.     LListBox::DrawSelf();    
  949. }
  950.  
  951. void CFormList::MakeSelection( LArray& list )
  952. {
  953.     Cell    look = { 0, 0 };
  954.  
  955.     while ( ::LGetSelect( TRUE, &look, mMacListH ) )
  956.     {
  957.         list.InsertItemsAt( 1, 1, &look );
  958.         ::LNextCell( TRUE, TRUE, &look, mMacListH );
  959.     }
  960. }
  961.  
  962. Boolean CFormList::CheckSelection( LArray& list )
  963. {
  964.     Cell    look = { 0, 0 };
  965.     Cell    tmp;
  966.  
  967.     while ( ::LGetSelect( TRUE, &look, mMacListH ) )
  968.     {
  969.         if ( !list.FetchItemAt( 1, &tmp ) )
  970.             return TRUE;
  971.         if ( tmp.v != look.v || tmp.h != tmp.h )
  972.             return TRUE;
  973.         list.RemoveItemsAt( 1, 1 );
  974.         ::LNextCell( TRUE, TRUE, &look, mMacListH );
  975.     }
  976.     if ( list.GetCount() > 0 )
  977.         return TRUE;
  978.     return FALSE;
  979. }    
  980.  
  981.     
  982. Boolean    
  983. CFormList::HandleKeyPress(const EventRecord    &inKeyEvent)
  984. {
  985.     char c = inKeyEvent.message & charCodeMask;
  986.     
  987.     if (keyUp == inKeyEvent.what) return true; // ignore key ups for now
  988.     
  989.     Boolean result = LListBox::HandleKeyPress(inKeyEvent);
  990.     
  991.     // there's no easy way to know if the selection changed
  992.     // because multiple items can be selected.
  993.     //
  994.     // We could basically copy LListBox into here and
  995.     // recongnize the selection to be changing.
  996.     //
  997.     // For now, however, we'll slime it and assume that
  998.     // the selection changes.  
  999.     
  1000.     MochaChanged();
  1001.     
  1002.     return result;
  1003. }
  1004.  
  1005. void CFormList::ClickSelf( const SMouseDownEvent& event )
  1006. {
  1007.     StTempFormBlur    formBlur;
  1008.     
  1009.     LArray        list( sizeof( Cell ) );
  1010.     Boolean        single;
  1011.     Cell        selCell;
  1012.     Boolean        changed;
  1013.     
  1014.     single = ( (**mMacListH).selFlags & lOnlyOne ) != 0;
  1015.  
  1016.     if ( !single )
  1017.         this->MakeSelection( list );
  1018.     else
  1019.         this->GetLastSelectedCell( selCell );
  1020.     
  1021.     LListBox::ClickSelf( event );
  1022.     
  1023.     if ( !single )
  1024.         changed = this->CheckSelection( list );
  1025.     else
  1026.     {
  1027.         Cell    tmp;
  1028.         this->GetLastSelectedCell( tmp );
  1029.         if ( tmp.h != selCell.h || tmp.v != selCell.v )
  1030.             changed = TRUE;
  1031.         else
  1032.             changed = FALSE;
  1033.     }
  1034.     
  1035.     if ( changed )
  1036.     {
  1037.         // Same deal as HandleKeyPress...
  1038.         MochaChanged();
  1039.     }
  1040. }
  1041.  
  1042.  
  1043.  
  1044. //----------------------------------------------------------------------------
  1045.  
  1046. void CFormList::DrawElement (const short lMessage, 
  1047.                                   const Boolean lSelect,
  1048.                                   const Rect *lRect,
  1049.                                   const void *lElement, 
  1050.                                   const short lDataLen)
  1051.  
  1052. // Member function for responding to LDEF calls.
  1053. // Calls DrawElementSelf to draw a list element.
  1054.  
  1055. {
  1056.   switch (lMessage) {
  1057.  
  1058.    case lDrawMsg :
  1059.             ::EraseRect (lRect) ;
  1060.             if (lDataLen == 0)
  1061.                 break ;
  1062.  
  1063.             DrawElementSelf (lRect, lElement, lDataLen) ;
  1064.             
  1065.                if (!lSelect)
  1066.                    break ;
  1067.  
  1068.    case lHiliteMsg :
  1069.                LMSetHiliteMode( 0 );
  1070.                ::InvertRect (lRect) ;
  1071.                break ;
  1072.   }
  1073. }
  1074.  
  1075. //----------------------------------------------------------------------------
  1076.  
  1077. void CFormList::DrawElementSelf (const Rect *lRect, 
  1078.                                       const void *lElement, 
  1079.                                       const short lDataLen)
  1080.  
  1081. // Draw contents of a single list element on the screen.
  1082. // Default version just draws text; override for other types of data.
  1083.  
  1084. {
  1085.  if(fContext && (GetWinCSID() == CS_UTF8))
  1086.   {
  1087.        UFontSwitcher *fs = UPropFontSwitcher::Instance();
  1088.        UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  1089.      FontInfo fi;
  1090.      th->GetFontInfo(fs, &fi);    
  1091.      ::MoveTo (lRect->left+2, lRect->bottom - fi.descent) ;    
  1092.        th->DrawText(fs, (char*) lElement, (int)lDataLen);
  1093.   }
  1094.   else
  1095.   {
  1096.      FontInfo fi;
  1097.      GetFontInfo(&fi);    
  1098.      ::MoveTo (lRect->left+2, lRect->bottom - fi.descent) ;    
  1099.       ::DrawText (lElement, 0, lDataLen) ;
  1100.   }
  1101. }
  1102.  
  1103. // ---------------------------------------------------------------------------
  1104. //        Ñ ActivateSelf
  1105. // ---------------------------------------------------------------------------
  1106.  
  1107. void CFormList::ActivateSelf()
  1108. {
  1109.     // 97-06-07 pkc -- Only call ActivateSelf when we're visible because layout/layers
  1110.     // puts us in a strange spot originally. When the form element is shown, then it's
  1111.     // coordinates reflect its true position.
  1112.     if (IsVisible())
  1113.         LListBox::ActivateSelf();
  1114. }
  1115.  
  1116.  
  1117. // ---------------------------------------------------------------------------
  1118. //        Ñ DeactivateSelf
  1119. // ---------------------------------------------------------------------------
  1120.  
  1121. void CFormList::DeactivateSelf()
  1122. {
  1123.     // 97-06-07 pkc -- Only call DectivateSelf when we're visible because layout/layers
  1124.     // puts us in a strange spot originally. When the form element is shown, then it's
  1125.     // coordinates reflect its true position.
  1126.     if (IsVisible())
  1127.         LListBox::DeactivateSelf();
  1128. }
  1129.  
  1130. //----------------------------------------------------------------------------
  1131. // 'self' matches the previously saved 'this'.
  1132.  
  1133. pascal void LDefProc    (short             lMessage,
  1134.                                 Boolean         lSelect, 
  1135.                                 Rect             *lRect,
  1136.                                 Cell             /*lCell*/,
  1137.                                 unsigned short     lDataOffset,
  1138.                                 unsigned short     lDataLen,
  1139.                                 ListHandle        lHandle)
  1140.                                 
  1141. // Custom list definition function procedure for CCustomListBox.
  1142. // Called by the LDEF stub; returns control back to class method
  1143. // DrawElement to do the actual drawing.
  1144.  
  1145. {
  1146.   // ignore init and dispose messages
  1147.   if ((lMessage == lInitMsg)     ||
  1148.         (lMessage == lCloseMsg))
  1149.        return ;
  1150.  
  1151.   // restore the application's A5, so that we can access global
  1152.   // variables.
  1153.   long savedA5 = ::SetCurrentA5() ;
  1154.   
  1155.   // get the pointer back to 'this'.  As the function is no method,
  1156.   // and 'this' is a keyword, use 'self' instead.
  1157.   CFormList *self = (CFormList*) (*lHandle)->userHandle ;
  1158.  
  1159.   Handle h = (*self->mMacListH)->cells ;
  1160.   char saveState = ::HGetState (h) ;
  1161.   ::HLock (h) ;
  1162.  
  1163.   void *lElement = (void*) (*h + lDataOffset) ;
  1164.   self->DrawElement (lMessage, lSelect, lRect, lElement, lDataLen) ;
  1165.  
  1166.   ::HSetState (h, saveState) ;
  1167.   ::SetA5 (savedA5) ;
  1168. }
  1169.  
  1170. //----------------------------------------------------------------------------
  1171.  
  1172.  
  1173.  
  1174. #pragma mark == CFormButton ==
  1175.  
  1176. //---------------------------------------------------------------------------
  1177. // class CFormButton
  1178. //---------------------------------------------------------------------------
  1179.  
  1180. CFormButton::CFormButton(LStream * inStream) : LStdButton(inStream)
  1181. {
  1182.     SetReflectOnChange(true);
  1183. #ifdef LAYERS
  1184.     // add an attachment which will intercept clicks and dispatch them to layers
  1185.     CLayerClickDispatchAttachment* led = new CLayerClickDispatchAttachment;
  1186.     AddAttachment(led);
  1187. #endif
  1188. }
  1189.  
  1190. // ÑÑ Misc
  1191.  
  1192. void CFormButton::SetDescriptor(ConstStr255Param    inDescriptor)
  1193. {
  1194.     LStdButton::SetDescriptor(inDescriptor);
  1195.     if (FocusDraw()) {
  1196.         UTextTraits::SetPortTextTraits(mTextTraitsID);    // Set the right fontage
  1197.         // Resize to text width    
  1198.         Int32 width;
  1199.         if(fContext && (GetWinCSID() == CS_UTF8))        
  1200.         {    
  1201.             UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  1202.             UFontSwitcher *fs = UPropFontSwitcher::Instance();
  1203.             width = th->StringWidth(fs , (unsigned char*)inDescriptor);
  1204.         }
  1205.         else
  1206.         {    
  1207.             width = StringWidth(inDescriptor);
  1208.         }                
  1209.         ResizeFrameTo(width + 16, mFrameSize.height, FALSE);
  1210.     }
  1211. }
  1212.  
  1213. void CFormButton::BroadcastValueMessage()
  1214. {
  1215.     if (mValueMessage != cmd_Nothing) {
  1216.         Int32    value = mValue;
  1217.         BroadcastMessage(mValueMessage, (void*) this);
  1218.     }
  1219. }
  1220.  
  1221. // This gets the mouse up and sends it to javascript in the event that
  1222. // a mouse down is cancelled; hot spot tracking normally eats the mouse up
  1223. // so this won't be called otherwise. We won't get the mouse up if it occurred
  1224. // outside the pane.
  1225. void CFormButton::EventMouseUp(const EventRecord& /*inEvent*/)
  1226. {
  1227.     CMochaHacks::SendEvent(fContext, EVENT_MOUSEUP, fLayoutElement);
  1228. }
  1229.  
  1230. void CFormButton::ClickSelfLayer(const SMouseDownEvent    &inMouseDown)
  1231. {
  1232.     LStdButton::ClickSelf(inMouseDown);
  1233. }
  1234.  
  1235. /*
  1236.  * CFormButtonHotSpotResultMochaCallback
  1237.  * callback for HotSpotResult
  1238.  * crappy inline implementation, because the whole callback thing is crappy
  1239.  */
  1240. class CFormButtonHotSpotResultMochaCallback : public CMochaEventCallback
  1241. {
  1242. public:
  1243.     CFormButtonHotSpotResultMochaCallback( CFormButton * button, Int16 inHotSpot, int32 inEventType)
  1244.         : fButton(button), fHotSpot(inHotSpot), fEventType(inEventType) {}
  1245.  
  1246.     virtual void Complete(MWContext * context, 
  1247.                 LO_Element * element, int32 /*type*/, ETEventStatus status)
  1248.     {
  1249.         if (status == EVENT_OK)
  1250.         {
  1251.             if (fEventType == EVENT_MOUSEUP)
  1252.                 MochaClick(context, element, new CFormButtonHotSpotResultMochaCallback(fButton, fHotSpot, EVENT_CLICK));
  1253.         }
  1254.         if (fEventType == EVENT_CLICK)
  1255.         {
  1256.             // if event wasn't ok, set message to one that won't be sent, so button
  1257.             // will unhighlight but perform no action.
  1258.             MessageT saveMsg = fButton->GetValueMessage();
  1259.             if (status != EVENT_OK) fButton->SetValueMessage(msg_AnyMessage);
  1260.             try
  1261.             {
  1262.                 fButton->HotSpotResultCallback( fHotSpot );
  1263.             }
  1264.             catch (...) {}
  1265.             if (status != EVENT_OK) fButton->SetValueMessage(saveMsg);
  1266.         }
  1267.     }
  1268.  
  1269. private:
  1270.     int32 fEventType; // the javascript event type, defined in libevent.h
  1271.     Int16 fHotSpot;
  1272.     CFormButton * fButton;
  1273. };
  1274.  
  1275. void
  1276. CFormButton::HotSpotResultCallback(Int16 inHotSpot)
  1277. {
  1278.     if (!IsMarkedForDeath())
  1279.     {
  1280.         LStdButton::HotSpotResult( inHotSpot );
  1281.     }
  1282. }
  1283.  
  1284. // This will actually get processed through the callback (see above method )
  1285. // Sends a mouse up to javascript, and if javascript lets us process the event, the callback sends
  1286. // a click to javascript.
  1287. void
  1288. CFormButton::HotSpotResult(Int16 inHotSpot)
  1289. {
  1290.     MWContext*        myContext = fContext;
  1291.     LO_Element*        myEle = fLayoutElement;
  1292.     
  1293.     MochaMouseUp(fContext, fLayoutElement, new CFormButtonHotSpotResultMochaCallback(this, inHotSpot, EVENT_MOUSEUP));
  1294. }
  1295.  
  1296. //
  1297. //    Addition function for UTF8
  1298. //    
  1299. void
  1300. CFormButton::HotSpotAction(
  1301.     Int16        inHotSpot,
  1302.     Boolean        inCurrInside,
  1303.     Boolean        inPrevInside)
  1304. {
  1305.     if(fContext && (GetWinCSID() == CS_UTF8))    
  1306.     {
  1307.         if (inCurrInside != inPrevInside) {        
  1308.             FocusDraw();
  1309.             Rect    frame;
  1310.             CalcLocalFrameRect(frame);
  1311.             short   weight = (frame.bottom-frame.top) / 2;
  1312.             StColorPenState::Normalize();
  1313.             ::InvertRoundRect(&frame,weight,weight);
  1314.         }
  1315.     }
  1316.     else
  1317.     {
  1318.         LStdButton::HotSpotAction(inHotSpot, inCurrInside, inPrevInside);
  1319.     }
  1320. }
  1321.  
  1322. Boolean
  1323. CFormButton::TrackHotSpot(
  1324.     Int16    inHotSpot,
  1325.     Point     inPoint,
  1326.     Int16 inModifiers)
  1327. {
  1328.     if(fContext && (GetWinCSID() == CS_UTF8))    
  1329.     {
  1330.                                         // For the initial mouse down, the
  1331.                                         // mouse is currently inside the HotSpot
  1332.                                         // when it was previously outside
  1333.         Boolean        currInside = true;
  1334.         Boolean        prevInside = false;
  1335.         HotSpotAction(inHotSpot, currInside, prevInside);
  1336.         
  1337.                                         // Track the mouse while it is down
  1338.         Point    currPt = inPoint;
  1339.         while (StillDown()) {
  1340.             GetMouse(&currPt);            // Must keep track if mouse moves from
  1341.             prevInside = currInside;    // In-to-Out or Out-To-In
  1342.             currInside = PointInHotSpot(currPt, inHotSpot);
  1343.             HotSpotAction(inHotSpot, currInside, prevInside);
  1344.         }
  1345.         
  1346.         EventRecord    macEvent;            // Get location from MouseUp event
  1347.         if (GetOSEvent(mUpMask, &macEvent)) {
  1348.             currPt = macEvent.where;
  1349.             GlobalToLocal(&currPt);
  1350.         }
  1351.  
  1352.         this->DrawSelf();
  1353.                                         // Check if MouseUp occurred in HotSpot
  1354.         return PointInHotSpot(currPt, inHotSpot);
  1355.     }
  1356.     else
  1357.     {
  1358.         return LStdButton::TrackHotSpot(inHotSpot, inPoint, inModifiers);
  1359.     }
  1360. }
  1361.  
  1362. void
  1363. CFormButton::DrawTitle()
  1364. {
  1365.     Rect frame;
  1366.     CalcLocalFrameRect(frame);    
  1367.     Str255    outText;
  1368.     this->GetDescriptor(outText);
  1369.     if(!IsEnabled())
  1370.     {
  1371.         RGBColor color = { 0, 0, 0 };
  1372.         ::RGBForeColor(&color);
  1373.         ::TextMode(grayishTextOr);
  1374.     }
  1375.     
  1376.     //    ÑÑÑ To Be Test    
  1377.     UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  1378.     UFontSwitcher *fs = UPropFontSwitcher::Instance();
  1379.     
  1380.     FontInfo info;    
  1381.     th->GetFontInfo(fs, &info);
  1382.     ::MoveTo((frame.right + frame.left - 
  1383.             th->StringWidth(fs ,outText) ) / 2,
  1384.              (frame.top + frame.bottom + info.ascent ) / 2);
  1385.     th->DrawString(fs, outText);    
  1386. }
  1387. void
  1388. CFormButton::DrawSelf()
  1389. {
  1390.     if(fContext && (GetWinCSID() == CS_UTF8))
  1391.     {
  1392.         // Do whatever a control shoul do.
  1393.         Rect    frame;
  1394.         CalcLocalFrameRect(frame);
  1395.         short   weight = (frame.bottom-frame.top) / 2;
  1396.         StColorPenState::Normalize();
  1397.         ::FillRoundRect(&frame,weight,weight, &UQDGlobals::GetQDGlobals()->white);
  1398.         ::FrameRoundRect(&frame,weight,weight);
  1399.         DrawTitle();
  1400.     }
  1401.     else
  1402.     {
  1403.         LStdButton::DrawSelf();        
  1404.     }
  1405. }
  1406.  
  1407. #pragma mark == CGAFormPushButton ==
  1408.  
  1409. //---------------------------------------------------------------------------
  1410. // class CGAFormPushButton
  1411. //---------------------------------------------------------------------------
  1412.  
  1413. CGAFormPushButton::CGAFormPushButton(LStream * inStream) : LGAPushButton(inStream)
  1414. {
  1415.     SetReflectOnChange(true);
  1416. #ifdef LAYERS
  1417.     // add an attachment which will intercept clicks and dispatch them to layers
  1418.     AddAttachment(new CLayerClickDispatchAttachment);
  1419. #endif
  1420. }
  1421.  
  1422. // ÑÑ Misc
  1423.  
  1424. void CGAFormPushButton::SetDescriptor(ConstStr255Param    inDescriptor)
  1425. {
  1426.     super::SetDescriptor(inDescriptor);
  1427.     if (FocusDraw())
  1428.     {
  1429.         UTextTraits::SetPortTextTraits(mTextTraitsID);    // Set the right fontage
  1430.         // Resize to text width    
  1431.         Int32 width;
  1432.  
  1433.         if(fContext && (GetWinCSID() == CS_UTF8))        
  1434.         {    
  1435.             UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  1436.             UFontSwitcher *fs = UPropFontSwitcher::Instance();
  1437.             width = th->StringWidth(fs , (unsigned char*)inDescriptor);
  1438.         }
  1439.         else
  1440.         {    
  1441.             width = StringWidth(inDescriptor);
  1442.         }                
  1443.         ResizeFrameTo(width + 16, mFrameSize.height, FALSE);
  1444.     }
  1445. }
  1446.  
  1447. void CGAFormPushButton::BroadcastValueMessage()
  1448. {
  1449.     if (mValueMessage != cmd_Nothing) {
  1450.         Int32    value = mValue;
  1451.         BroadcastMessage(mValueMessage, (void*) this);
  1452.     }
  1453. }
  1454.  
  1455. // This gets the mouse up and sends it to javascript in the event that
  1456. // a mouse down is cancelled; hot spot tracking normally eats the mouse up
  1457. // so this won't be called otherwise. We won't get the mouse up if it occurred
  1458. // outside the pane.
  1459. void CGAFormPushButton::EventMouseUp(const EventRecord& /*inEvent*/)
  1460. {
  1461.     CMochaHacks::SendEvent(fContext, EVENT_MOUSEUP, fLayoutElement);
  1462. }
  1463.  
  1464. void CGAFormPushButton::ClickSelfLayer(const SMouseDownEvent &inMouseDown)
  1465. {
  1466.     super::ClickSelf(inMouseDown);
  1467. }
  1468.  
  1469. /*
  1470.  * CGAFormPushButtonHotSpotResultMochaCallback
  1471.  * callback for HotSpotResult
  1472.  * crappy inline implementation, because the whole callback thing is crappy
  1473.  */
  1474. class CGAFormPushButtonHotSpotResultMochaCallback : public CMochaEventCallback
  1475. {
  1476. public:
  1477.     CGAFormPushButtonHotSpotResultMochaCallback( CGAFormPushButton * button, Int16 inHotSpot, int32 inEventType)
  1478.         : fButton(button), fHotSpot(inHotSpot), fEventType(inEventType) {}
  1479.  
  1480.     virtual void Complete(MWContext * context, 
  1481.                 LO_Element * element, int32 /*type*/, ETEventStatus status)
  1482.     {
  1483.         if (status == EVENT_OK)
  1484.         {
  1485.             if (fEventType == EVENT_MOUSEUP)
  1486.                 MochaClick(context, element, new CGAFormPushButtonHotSpotResultMochaCallback(fButton, fHotSpot, EVENT_CLICK));
  1487.         }
  1488.         if (fEventType == EVENT_CLICK)
  1489.         {
  1490.             // if event wasn't ok, set message to one that won't be sent, so button
  1491.             // will unhighlight but perform no action.
  1492.             MessageT saveMsg = fButton->GetValueMessage();
  1493.             if (status != EVENT_OK) fButton->SetValueMessage(msg_AnyMessage);
  1494.             try
  1495.             {
  1496.                 fButton->HotSpotResultCallback( fHotSpot );
  1497.             }
  1498.             catch (...) {}
  1499.             if (status != EVENT_OK) fButton->SetValueMessage(saveMsg);
  1500.         }
  1501.     }
  1502.  
  1503. private:
  1504.     int32 fEventType; // the javascript event type, defined in libevent.h
  1505.     Int16 fHotSpot;
  1506.     CGAFormPushButton * fButton;
  1507. };
  1508.  
  1509. void
  1510. CGAFormPushButton::HotSpotResultCallback(Int16 inHotSpot)
  1511. {
  1512.     if (!IsMarkedForDeath())
  1513.     {
  1514.         super::HotSpotResult( inHotSpot );
  1515.     }
  1516. }
  1517.  
  1518. // This will actually get processed through the callback (see above method )
  1519. // Sends a mouse up to javascript, and if javascript lets us process the event, the callback sends
  1520. // a click to javascript.
  1521. void
  1522. CGAFormPushButton::HotSpotResult(Int16 inHotSpot)
  1523. {
  1524.     MWContext*        myContext = fContext;
  1525.     LO_Element*        myEle = fLayoutElement;
  1526.     
  1527.     MochaMouseUp(fContext, fLayoutElement, new CGAFormPushButtonHotSpotResultMochaCallback(this, inHotSpot, EVENT_MOUSEUP));
  1528. }
  1529.  
  1530. void
  1531. CGAFormPushButton::DrawButtonTitle    ( Int16    inDepth )
  1532. {
  1533.     if(! (fContext && (GetWinCSID() == CS_UTF8)))
  1534.     {
  1535.         super::DrawButtonTitle(inDepth);
  1536.         return;
  1537.     }
  1538.  
  1539.     StColorPenState    theColorPenState;
  1540.     StColorPenState::Normalize ();
  1541.     StTextState            theTextState;
  1542.     RGBColor                textColor;
  1543.     
  1544.     // Ñ Get some loal variables setup including the rect for the title
  1545.     ResIDT    textTID = GetTextTraitsID ();
  1546.     Rect    titleRect;
  1547.     
  1548.     // Ñ Get the port setup with the text traits
  1549.     UTextTraits::SetPortTextTraits ( textTID );
  1550.     
  1551.     // Ñ Save off a reference to the fore color used to draw the title
  1552.     ::GetForeColor ( &textColor );
  1553.     
  1554.     // Ñ We always want to have the title be centered
  1555.     Int16    titleJust = teCenter;
  1556.     
  1557.     // Ñ Calculate the title rect
  1558.     CalcTitleRect ( titleRect );
  1559.     
  1560.     // Ñ Get the title
  1561.     Str255 controlTitle;
  1562.     GetDescriptor ( controlTitle );
  1563.  
  1564.     // Ñ Handle drawing based on the current depth of the device
  1565.     if ( inDepth < 4 )
  1566.     {
  1567.         // Ñ If the control is dimmed then we use the grayishTextOr 
  1568.         // transfer mode to draw the text
  1569.         if ( !IsEnabled ())
  1570.         {
  1571.             ::RGBForeColor ( &UGAColorRamp::GetBlackColor () );
  1572.             ::TextMode ( grayishTextOr );
  1573.         }
  1574.         else if ( IsEnabled () && IsHilited () )
  1575.         {
  1576.             // Ñ When we are hilited we simply draw the title in white
  1577.             ::RGBForeColor ( &UGAColorRamp::GetWhiteColor () );
  1578.         }
  1579.         
  1580.         // Ñ Now get the actual title drawn with all the appropriate settings
  1581.         UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  1582.         UFontSwitcher *fs = UPropFontSwitcher::Instance();
  1583.         
  1584.         FontInfo info;    
  1585.         th->GetFontInfo(fs, &info);
  1586.         ::MoveTo((titleRect.right + titleRect.left - 
  1587.                 th->StringWidth(fs ,controlTitle) ) / 2,
  1588.                  (titleRect.top + titleRect.bottom + info.ascent  - info.descent) / 2);
  1589.         th->DrawString(fs, controlTitle);    
  1590.     
  1591.     }
  1592.     else if ( inDepth >= 4 ) 
  1593.     {
  1594.         // Ñ If control is selected we always draw the text in the title
  1595.         // hilite color, if requested
  1596.         if ( IsHilited ())
  1597.             ::RGBForeColor ( &UGAColorRamp::GetWhiteColor() );
  1598.         
  1599.         // Ñ If the control is dimmed then we have to do our own version of the
  1600.         // grayishTextOr as it does not appear to work correctly across
  1601.         // multiple devices
  1602.         if ( !IsEnabled () || !IsActive ())
  1603.         {
  1604.             textColor = UGraphicsUtilities::Lighten ( &textColor );
  1605.             ::TextMode ( srcOr );
  1606.             ::RGBForeColor ( &textColor );
  1607.         }
  1608.  
  1609.         // Ñ Now get the actual title drawn with all the appropriate settings
  1610.                                                             
  1611.         UMultiFontTextHandler *th = UUTF8TextHandler::Instance();
  1612.         UFontSwitcher *fs = UPropFontSwitcher::Instance();
  1613.         
  1614.         FontInfo info;    
  1615.         th->GetFontInfo(fs, &info);
  1616.         ::MoveTo((titleRect.right + titleRect.left - 
  1617.                 th->StringWidth(fs ,controlTitle) ) / 2,
  1618.                  (titleRect.top + titleRect.bottom + info.ascent  - info.descent) / 2);
  1619.         th->DrawString(fs, controlTitle);    
  1620.     }
  1621.     
  1622. }    //    CGAFormPushButton::DrawButtonTitle
  1623.  
  1624. #pragma mark == CFormRadio ==
  1625.  
  1626. //---------------------------------------------------------------------------
  1627. // class CFormRadio
  1628. //---------------------------------------------------------------------------
  1629. RgnHandle CFormRadio::sRadioRgn = NULL;
  1630. CFormRadio::CFormRadio(LStream * inStream) : LStdRadioButton(inStream), LFormElement(), CLayerClickCallbackMixin()
  1631. {
  1632.     SetReflectOnChange(true);
  1633. #ifdef LAYERS
  1634.     // add an attachment which will intercept clicks and dispatch them to layers
  1635.     CLayerClickDispatchAttachment* led = new CLayerClickDispatchAttachment;
  1636.     AddAttachment(led);
  1637. #endif
  1638. }
  1639.  
  1640. void CFormRadio::SetupClip()
  1641. {
  1642.     if (sRadioRgn == NULL)    // Allocate the clip region
  1643.     {
  1644.         sRadioRgn = ::NewRgn();
  1645.         Rect r;
  1646.         r.top = r.left = 0;
  1647.         r.bottom = r.right = 12;
  1648.         OpenRgn();
  1649.         ::FrameOval(&r);
  1650.         ::CloseRgn(sRadioRgn);
  1651.     }
  1652.     ::OffsetRgn(sRadioRgn,     // Position the clip region. Offset was calculated by trial and error
  1653.                 (*mMacControlH)->contrlRect.left -(*sRadioRgn)->rgnBBox.left + 2, 
  1654.                 (*mMacControlH)->contrlRect.top -(*sRadioRgn)->rgnBBox.top);
  1655. }
  1656.  
  1657. void CFormRadio::DrawSelf()
  1658. {
  1659.     SetupClip();
  1660.     StSetupFormDrawing colorEnv(this);
  1661.  
  1662.     StClipRgnState    theClip;
  1663.     theClip.ClipToIntersectionRgn(sRadioRgn);
  1664.  
  1665.     LStdRadioButton::DrawSelf();
  1666. }
  1667.  
  1668.  
  1669. void CFormRadio::ClickSelfLayer(const SMouseDownEvent    &inMouseDown)
  1670. {
  1671.     LStdRadioButton::ClickSelf(inMouseDown);
  1672. }
  1673.  
  1674. Boolean CFormRadio::TrackHotSpot(Int16    inHotSpot,Point inPoint, Int16 inModifiers)
  1675. {
  1676.     SetupClip();
  1677.     StSetupFormDrawing colorEnv(this);
  1678.  
  1679.     StClipRgnState    theClip;
  1680.     theClip.ClipToIntersectionRgn(sRadioRgn);
  1681.  
  1682.     return LStdRadioButton::TrackHotSpot(inHotSpot, inPoint, inModifiers);
  1683. }
  1684.  
  1685. void CFormRadio::SetValue(Int32    inValue)
  1686. {
  1687.     SetupClip();
  1688.     StSetupFormDrawing colorEnv(this);
  1689.  
  1690.     StClipRgnState    theClip;
  1691.     theClip.ClipToIntersectionRgn(sRadioRgn);
  1692.  
  1693.     LStdRadioButton::SetValue(inValue);
  1694. }
  1695.  
  1696. /*
  1697.  * CFormRadioHotSpotResultMochaCallback
  1698.  * callback for HotSpotResult
  1699.  * crappy inline implementation, because the whole callback thing is crappy
  1700.  */
  1701. class CFormRadioHotSpotResultMochaCallback : public CMochaEventCallback
  1702. {
  1703. public:
  1704.     CFormRadioHotSpotResultMochaCallback( CFormRadio * radio, 
  1705.                                     Int16 inHotSpot,
  1706.                                     LO_FormElementStruct* oldRadio,
  1707.                                     Int16         savedValue,
  1708.                                     int32 inEventType)
  1709.         : fRadio(radio), 
  1710.         fHotSpot(inHotSpot),
  1711.         fOldRadio(oldRadio),
  1712.         fSavedValue(savedValue),
  1713.         fEventType(inEventType)
  1714.     {}
  1715.  
  1716.     void    Complete(MWContext * context, 
  1717.                 LO_Element * element, int32 /*type*/, ETEventStatus status)
  1718.     {
  1719.         if (status == EVENT_CANCEL)
  1720.         {
  1721.             if (fEventType == EVENT_CLICK)
  1722.                 fRadio->HotSpotResultCallback( fHotSpot , fOldRadio, fSavedValue, context);
  1723.         } else if (status == EVENT_OK)
  1724.         {
  1725.             if (fEventType == EVENT_MOUSEUP)
  1726.                 MochaClick(context, 
  1727.                             element, 
  1728.                             new CFormRadioHotSpotResultMochaCallback(fRadio, fHotSpot, fOldRadio, fSavedValue, EVENT_CLICK));
  1729.         }
  1730.     }
  1731.  
  1732. private:
  1733.     int32                    fEventType;
  1734.     Int16                    fHotSpot;    // No clue what these arguments mean, I am just saving
  1735.     CFormRadio *            fRadio;        // them for the calllback
  1736.     LO_FormElementStruct*    fOldRadio;
  1737.     Int16                    fSavedValue;
  1738. };
  1739.  
  1740.  
  1741. void
  1742. CFormRadio::HotSpotResultCallback(Int16 /*inHotSpot*/, 
  1743.                                 LO_FormElementStruct* oldRadio,
  1744.                                 Int16 savedValue,
  1745.                                 MWContext * context)
  1746. {
  1747.     if (!IsMarkedForDeath())
  1748.     {
  1749.         SetValue(savedValue);
  1750.         ReflectData();
  1751.         
  1752.         if (oldRadio != NULL)
  1753.         {
  1754.             LO_FormRadioSet(context, oldRadio);
  1755.                 
  1756.             LControl* control = dynamic_cast<LControl*>(GetFEDataPane(oldRadio));
  1757.             ThrowIfNil_(control);
  1758.             
  1759.             control->SetValue(true);
  1760.             control->Refresh();
  1761.         }
  1762.     }
  1763. }
  1764.  
  1765. void
  1766. CFormRadio::HotSpotResult(Int16 inHotSpot)
  1767. {
  1768.     MWContext*    myContext     = fContext;
  1769.     LO_Element*    myEle         = fLayoutElement;
  1770.     Int16         savedValue    = GetValue();
  1771.  
  1772.     LO_FormElementStruct*    oldRadio = NULL;
  1773.     
  1774.     // Change the value, call JavaScript, if it cancels 
  1775.     // the click, then change the value back.
  1776.     LStdRadioButton::HotSpotResult( inHotSpot );
  1777.     ReflectData();
  1778.     oldRadio = LO_FormRadioSet(myContext, (LO_FormElementStruct*) myEle);
  1779.  
  1780.     // Adding another callback loop to do a mouse up for xp consistency.
  1781.     // Cancelling the mouse up will have no effect on the state
  1782.     // of the radio element after the mouse down, but will prevent a click from being sent.
  1783.     MochaMouseUp( myContext, myEle, new CFormRadioHotSpotResultMochaCallback( this, inHotSpot, oldRadio, savedValue, EVENT_MOUSEUP));
  1784. }
  1785.  
  1786. // This gets the mouse up and sends it to javascript in the event that
  1787. // a mouse down is cancelled; hot spot tracking normally eats the mouse up
  1788. // so this won't be called otherwise. We won't get the mouse up if it occurred
  1789. // outside the pane.
  1790. void CFormRadio::EventMouseUp(const EventRecord& /*inEvent*/)
  1791. {
  1792.     CMochaHacks::SendEvent(fContext, EVENT_MOUSEUP, fLayoutElement);
  1793. }
  1794.  
  1795. #pragma mark == CGAFormRadio ==
  1796.  
  1797. // ---------------------------------------------------------------------------
  1798. //        Ñ CGAFormRadio
  1799. // ---------------------------------------------------------------------------
  1800.  
  1801. CGAFormRadio::CGAFormRadio(
  1802.     LStream* inStream)
  1803.     :    super(inStream)
  1804. {
  1805.     SetReflectOnChange(true);
  1806. #ifdef LAYERS
  1807.     // add an attachment which will intercept clicks and dispatch them to layers
  1808.     AddAttachment(new CLayerClickDispatchAttachment);
  1809. #endif
  1810. }
  1811.  
  1812. // ---------------------------------------------------------------------------
  1813. //        Ñ DrawSelf
  1814. // ---------------------------------------------------------------------------
  1815.  
  1816. void
  1817. CGAFormRadio::DrawSelf()
  1818. {
  1819.     StSetupFormDrawing colorEnv(this);
  1820.  
  1821.     super::DrawSelf();
  1822. }
  1823.  
  1824. // ---------------------------------------------------------------------------
  1825. //        Ñ ClickSelfLayer
  1826. // ---------------------------------------------------------------------------
  1827.  
  1828. void
  1829. CGAFormRadio::ClickSelfLayer(
  1830.     const SMouseDownEvent& inMouseDown)
  1831. {
  1832.     super::ClickSelf(inMouseDown);
  1833. }
  1834.  
  1835. // ---------------------------------------------------------------------------
  1836. //        Ñ TrackHotSpot
  1837. // ---------------------------------------------------------------------------
  1838.  
  1839. Boolean
  1840. CGAFormRadio::TrackHotSpot(
  1841.     Int16    inHotSpot,
  1842.     Point    inPoint,
  1843.     Int16 inModifiers)
  1844. {
  1845.     StSetupFormDrawing colorEnv(this);
  1846.  
  1847.     return super::TrackHotSpot(inHotSpot, inPoint, inModifiers);
  1848. }
  1849.  
  1850. // ---------------------------------------------------------------------------
  1851. //        Ñ SetValue
  1852. // ---------------------------------------------------------------------------
  1853.  
  1854. void
  1855. CGAFormRadio::SetValue(
  1856.     Int32    inValue)
  1857. {
  1858.     StSetupFormDrawing colorEnv(this);
  1859.  
  1860.     super::SetValue(inValue);
  1861. }
  1862.  
  1863. /*
  1864.  * CGAFormRadioHotSpotResultMochaCallback
  1865.  * callback for HotSpotResult
  1866.  * crappy inline implementation, because the whole callback thing is crappy
  1867.  */
  1868. class CGAFormRadioHotSpotResultMochaCallback : public CMochaEventCallback
  1869. {
  1870. public:
  1871.     CGAFormRadioHotSpotResultMochaCallback( CGAFormRadio * radio, 
  1872.                                     Int16 inHotSpot,
  1873.                                     LO_FormElementStruct* oldRadio,
  1874.                                     Int16         savedValue,
  1875.                                     int32 inEventType)
  1876.         : fRadio(radio), 
  1877.         fHotSpot(inHotSpot),
  1878.         fOldRadio(oldRadio),
  1879.         fSavedValue(savedValue),
  1880.         fEventType(inEventType)
  1881.     {}
  1882.  
  1883.     void    Complete(MWContext * context, 
  1884.                 LO_Element * element, int32 /*type*/, ETEventStatus status)
  1885.     {
  1886.         if (status == EVENT_CANCEL)
  1887.         {
  1888.             if (fEventType == EVENT_CLICK)
  1889.                 fRadio->HotSpotResultCallback( fHotSpot , fOldRadio, fSavedValue, context);
  1890.         } else if (status == EVENT_OK)
  1891.         {
  1892.             if (fEventType == EVENT_MOUSEUP)
  1893.                 MochaClick(context, 
  1894.                             element, 
  1895.                             new CGAFormRadioHotSpotResultMochaCallback(fRadio, fHotSpot, fOldRadio, fSavedValue, EVENT_CLICK));
  1896.         }
  1897.     }
  1898.  
  1899. private:
  1900.     int32                    fEventType;
  1901.     Int16                    fHotSpot;    // No clue what these arguments mean, I am just saving
  1902.     CGAFormRadio*            fRadio;        // them for the calllback
  1903.     LO_FormElementStruct*    fOldRadio;
  1904.     Int16                    fSavedValue;
  1905. };
  1906.  
  1907. // ---------------------------------------------------------------------------
  1908. //        Ñ HotSpotResultCallback
  1909. // ---------------------------------------------------------------------------
  1910.  
  1911. void
  1912. CGAFormRadio::HotSpotResultCallback(
  1913.     Int16                    /*inHotSpot*/, 
  1914.     LO_FormElementStruct*    oldRadio,
  1915.     Int16                    savedValue,
  1916.     MWContext*                context)
  1917. {
  1918.     if (!IsMarkedForDeath())
  1919.     {
  1920.         SetValue(savedValue);
  1921.         ReflectData();
  1922.         
  1923.         if (oldRadio != NULL)
  1924.         {
  1925.             LO_FormRadioSet(context, oldRadio);
  1926.                 
  1927.             LControl* control = dynamic_cast<LControl*>(GetFEDataPane(oldRadio));
  1928.             ThrowIfNil_(control);
  1929.  
  1930.             control->SetValue(true);
  1931.             control->Refresh();
  1932.         }
  1933.     }
  1934. }
  1935.  
  1936. // ---------------------------------------------------------------------------
  1937. //        Ñ HotSpotResult
  1938. // ---------------------------------------------------------------------------
  1939.  
  1940. void
  1941. CGAFormRadio::HotSpotResult(
  1942.     Int16 inHotSpot)
  1943. {
  1944.     MWContext*    myContext     = fContext;
  1945.     LO_Element*    myEle         = fLayoutElement;
  1946.     Int16         savedValue    = GetValue();
  1947.  
  1948.     LO_FormElementStruct*    oldRadio = NULL;
  1949.     
  1950.     // Change the value, call JavaScript, if it cancels 
  1951.     // the click, then change the value back.
  1952.     super::HotSpotResult( inHotSpot );
  1953.     ReflectData();
  1954.     oldRadio = LO_FormRadioSet(myContext, (LO_FormElementStruct*) myEle);
  1955.  
  1956.     // Adding another callback loop to do a mouse up for xp consistency.
  1957.     // Cancelling the mouse up will have no effect on the state
  1958.     // of the radio element after the mouse down, but will prevent a click from being sent.
  1959.     MochaMouseUp( myContext, myEle, new CGAFormRadioHotSpotResultMochaCallback(this, inHotSpot, oldRadio, savedValue, EVENT_MOUSEUP));
  1960. }
  1961.  
  1962. // ---------------------------------------------------------------------------
  1963. //        Ñ EventMouseUp
  1964. // ---------------------------------------------------------------------------
  1965.  
  1966. // This gets the mouse up and sends it to javascript in the event that
  1967. // a mouse down is cancelled; hot spot tracking normally eats the mouse up
  1968. // so this won't be called otherwise. We won't get the mouse up if it occurred
  1969. // outside the pane.
  1970. void
  1971. CGAFormRadio::EventMouseUp(const EventRecord& /*inEvent*/)
  1972. {
  1973.     CMochaHacks::SendEvent(fContext, EVENT_MOUSEUP, fLayoutElement);
  1974. }
  1975.  
  1976. #pragma mark == CFormCheckbox ==
  1977.  
  1978. //---------------------------------------------------------------------------
  1979. // class CFormCheckbox
  1980. //---------------------------------------------------------------------------
  1981. RgnHandle CFormCheckbox::sCheckboxRgn = NULL;
  1982. CFormCheckbox::CFormCheckbox(LStream * inStream) : LStdCheckBox(inStream), CLayerClickCallbackMixin() {
  1983.     SetReflectOnChange(true);
  1984. #ifdef LAYERS
  1985.     // add an attachment which will intercept clicks and dispatch them to layers
  1986.     CLayerClickDispatchAttachment* led = new CLayerClickDispatchAttachment;
  1987.     AddAttachment(led);
  1988. #endif
  1989. }
  1990.  
  1991. void CFormCheckbox::SetupClip()
  1992. {
  1993.     if (sCheckboxRgn == NULL)    // Allocate the clip region
  1994.     {
  1995.         sCheckboxRgn = ::NewRgn();
  1996.         Rect r;
  1997.         r.top = r.left = 0;
  1998.         r.bottom = r.right = 12;
  1999.         OpenRgn();
  2000.         ::FrameRect(&r);
  2001.         ::CloseRgn(sCheckboxRgn);
  2002.     }
  2003.     ::OffsetRgn(sCheckboxRgn,     // Position the clip region
  2004.                 (*mMacControlH)->contrlRect.left -(*sCheckboxRgn)->rgnBBox.left+2, 
  2005.                 (*mMacControlH)->contrlRect.top -(*sCheckboxRgn)->rgnBBox.top);    
  2006. }
  2007.  
  2008.  
  2009. void CFormCheckbox::DrawSelf()
  2010. {
  2011.     SetupClip();    
  2012.     StSetupFormDrawing colorEnv(this);
  2013.  
  2014.     StClipRgnState    theClip;
  2015.     theClip.ClipToIntersectionRgn(sCheckboxRgn);
  2016.  
  2017.     LStdCheckBox::DrawSelf();
  2018. }
  2019.  
  2020.  
  2021. void CFormCheckbox::ClickSelfLayer(const SMouseDownEvent    &inMouseDown)
  2022. {
  2023.     LStdCheckBox::ClickSelf(inMouseDown);
  2024. }
  2025.  
  2026.  
  2027. Boolean CFormCheckbox::TrackHotSpot(Int16    inHotSpot,Point inPoint, Int16 inModifiers)
  2028. {
  2029.     SetupClip();    
  2030.     StSetupFormDrawing colorEnv(this);
  2031.  
  2032.     StClipRgnState    theClip;
  2033.     theClip.ClipToIntersectionRgn(sCheckboxRgn);
  2034.     
  2035.     return LStdCheckBox::TrackHotSpot(inHotSpot, inPoint, inModifiers);
  2036. }
  2037.  
  2038. void CFormCheckbox::SetValue(Int32    inValue)
  2039. {
  2040.     SetupClip();
  2041.     StSetupFormDrawing colorEnv(this);
  2042.  
  2043.     StClipRgnState    theClip;
  2044.     theClip.ClipToIntersectionRgn(sCheckboxRgn);
  2045.  
  2046.     LStdCheckBox::SetValue(inValue);
  2047. }
  2048.  
  2049. /*
  2050.  * CFormCheckboxHotSpotResultMochaCallback
  2051.  * callback for HotSpotResult
  2052.  * crappy inline implementation, because the whole callback thing is crappy
  2053.  */
  2054. class CFormCheckboxHotSpotResultMochaCallback : public CMochaEventCallback
  2055. {
  2056. public:
  2057.     CFormCheckboxHotSpotResultMochaCallback( CFormCheckbox* checkBox, 
  2058.                                     Int16 inHotSpot,
  2059.                                     Int16 inSavedValue,
  2060.                                     int32 inEventType )
  2061.         : fCheckbox(checkBox), fHotSpot(inHotSpot), fSavedValue(inSavedValue), fEventType(inEventType)
  2062.     {}
  2063.  
  2064.     virtual void Complete(MWContext * context, 
  2065.                 LO_Element * element, int32 /*type*/, ETEventStatus status)
  2066.     {
  2067.         // call HotSpotResultCallback if mocha wants us to cancel action
  2068.         if (status == EVENT_CANCEL)
  2069.         {
  2070.             if (fEventType == EVENT_CLICK)
  2071.                 fCheckbox->HotSpotResultCallback( fHotSpot, fSavedValue );
  2072.         } else if (status == EVENT_OK)
  2073.         {
  2074.             if (fEventType == EVENT_MOUSEUP)
  2075.                 MochaClick(context, element, new CFormCheckboxHotSpotResultMochaCallback(fCheckbox, fHotSpot, fSavedValue, EVENT_CLICK));
  2076.         }
  2077.     }
  2078.  
  2079. private:
  2080.     int32                    fEventType;
  2081.     Int16                    fHotSpot;    // No clue what these arguments mean, I am just saving
  2082.     CFormCheckbox *            fCheckbox;        // them for the calllback
  2083.     Int16                    fSavedValue;
  2084. };
  2085.  
  2086.  
  2087. void
  2088. CFormCheckbox::HotSpotResultCallback( Int16 /*inHotSpot*/, Int16 savedValue )
  2089. {
  2090.     // Reset to the old value
  2091.     if (!IsMarkedForDeath())
  2092.     {
  2093.         SetValue(savedValue);
  2094.         ReflectData();
  2095.     }
  2096. }
  2097.  
  2098. void CFormCheckbox::HotSpotResult(Int16 inHotSpot)
  2099. {
  2100.     MWContext*    myContext = fContext;
  2101.     LO_Element*    myEle = fLayoutElement;
  2102.  
  2103.     Int16 savedValue = GetValue();
  2104.     
  2105.     // Change the value, call JavaScript, if it cancels 
  2106.     // the click, then change the value back.
  2107.  
  2108.     LStdCheckBox::HotSpotResult(inHotSpot);
  2109.     ReflectData();
  2110.     
  2111.     //
  2112.     // Call the JavaScript onClick handler,
  2113.     // which may cancel the click
  2114.     //
  2115.     
  2116.     // Adding another callback loop to do a mouse up for xp consistency.
  2117.     // Cancelling the mouse up will have no effect on the state
  2118.     // of the checkbox after the mouse down, but will prevent a click from being sent.
  2119.     MochaMouseUp( myContext, myEle, new CFormCheckboxHotSpotResultMochaCallback( this, inHotSpot, savedValue, EVENT_MOUSEUP));
  2120. }
  2121.  
  2122. // This gets the mouse up and sends it to javascript in the event that
  2123. // a mouse down is cancelled; hot spot tracking normally eats the mouse up
  2124. // so this won't be called otherwise. We won't get the mouse up if it occurred
  2125. // outside the pane.
  2126. void CFormCheckbox::EventMouseUp(const EventRecord& /*inEvent*/)
  2127. {
  2128.     CMochaHacks::SendEvent(fContext, EVENT_MOUSEUP, fLayoutElement);
  2129. }
  2130.  
  2131. #pragma mark == CGAFormCheckbox ==
  2132.  
  2133. // ---------------------------------------------------------------------------
  2134. //        Ñ CGAFormCheckbox
  2135. // ---------------------------------------------------------------------------
  2136.  
  2137. CGAFormCheckbox::CGAFormCheckbox(
  2138.     LStream* inStream)
  2139.     :    super(inStream)
  2140. {
  2141.     SetReflectOnChange(true);
  2142. #ifdef LAYERS
  2143.     // add an attachment which will intercept clicks and dispatch them to layers
  2144.     AddAttachment(new CLayerClickDispatchAttachment);
  2145. #endif
  2146. }
  2147.  
  2148. // ---------------------------------------------------------------------------
  2149. //        Ñ DrawSelf
  2150. // ---------------------------------------------------------------------------
  2151.  
  2152. void
  2153. CGAFormCheckbox::DrawSelf()
  2154. {
  2155.     StSetupFormDrawing colorEnv(this);
  2156.  
  2157.     super::DrawSelf();
  2158. }
  2159.  
  2160. // ---------------------------------------------------------------------------
  2161. //        Ñ ClickSelfLayer
  2162. // ---------------------------------------------------------------------------
  2163.  
  2164. void
  2165. CGAFormCheckbox::ClickSelfLayer(
  2166.     const SMouseDownEvent& inMouseDown)
  2167. {
  2168.     super::ClickSelf(inMouseDown);
  2169. }
  2170.  
  2171. // ---------------------------------------------------------------------------
  2172. //        Ñ TrackHotSpot
  2173. // ---------------------------------------------------------------------------
  2174.  
  2175. Boolean
  2176. CGAFormCheckbox::TrackHotSpot(
  2177.     Int16    inHotSpot,
  2178.     Point    inPoint,
  2179.     Int16 inModifiers)
  2180. {
  2181.     StSetupFormDrawing colorEnv(this);
  2182.  
  2183.     return super::TrackHotSpot(inHotSpot, inPoint, inModifiers);
  2184. }
  2185.  
  2186. // ---------------------------------------------------------------------------
  2187. //        Ñ SetValue
  2188. // ---------------------------------------------------------------------------
  2189.  
  2190. void
  2191. CGAFormCheckbox::SetValue(
  2192.     Int32    inValue)
  2193. {
  2194.     StSetupFormDrawing colorEnv(this);
  2195.  
  2196.     super::SetValue(inValue);
  2197. }
  2198.  
  2199. /*
  2200.  * CGAFormCheckboxHotSpotResultMochaCallback
  2201.  * callback for HotSpotResult
  2202.  * crappy inline implementation, because the whole callback thing is crappy
  2203.  */
  2204. class CGAFormCheckboxHotSpotResultMochaCallback : public CMochaEventCallback
  2205. {
  2206. public:
  2207.     CGAFormCheckboxHotSpotResultMochaCallback( CGAFormCheckbox* checkBox, 
  2208.                                     Int16 inHotSpot,
  2209.                                     Int16 inSavedValue,
  2210.                                     int32 inEventType )
  2211.         : fCheckbox(checkBox), fHotSpot(inHotSpot), fSavedValue(inSavedValue), fEventType(inEventType)
  2212.     {}
  2213.  
  2214.     virtual void Complete(MWContext * context, 
  2215.                 LO_Element * element, int32 /*type*/, ETEventStatus status)
  2216.     {
  2217.         // call HotSpotResultCallback if mocha wants us to cancel action
  2218.         if (status == EVENT_CANCEL)
  2219.         {
  2220.             if (fEventType == EVENT_CLICK)
  2221.                 fCheckbox->HotSpotResultCallback( fHotSpot, fSavedValue );
  2222.         } else if (status == EVENT_OK)
  2223.         {
  2224.             if (fEventType == EVENT_MOUSEUP)
  2225.                 MochaClick(context, element, new CGAFormCheckboxHotSpotResultMochaCallback(fCheckbox, fHotSpot, fSavedValue, EVENT_CLICK));
  2226.         }
  2227.     }
  2228.  
  2229. private:
  2230.     int32                    fEventType;
  2231.     Int16                    fHotSpot;    // No clue what these arguments mean, I am just saving
  2232.     CGAFormCheckbox*        fCheckbox;        // them for the calllback
  2233.     Int16                    fSavedValue;
  2234. };
  2235.  
  2236. // ---------------------------------------------------------------------------
  2237. //        Ñ HotSpotResultCallback
  2238. // ---------------------------------------------------------------------------
  2239.  
  2240. void
  2241. CGAFormCheckbox::HotSpotResultCallback(
  2242.     Int16                    inHotSpot, 
  2243.     Int16                    savedValue)
  2244. {
  2245. #pragma unused(inHotSpot)
  2246.  
  2247.     // Reset to the old value
  2248.     if (!IsMarkedForDeath())
  2249.     {
  2250.         SetValue(savedValue);
  2251.         ReflectData();
  2252.     }
  2253. }
  2254.  
  2255. // ---------------------------------------------------------------------------
  2256. //        Ñ HotSpotResult
  2257. // ---------------------------------------------------------------------------
  2258.  
  2259. void
  2260. CGAFormCheckbox::HotSpotResult(
  2261.     Int16 inHotSpot)
  2262. {
  2263.     MWContext*    myContext = fContext;
  2264.     LO_Element*    myEle = fLayoutElement;
  2265.  
  2266.     Int16 savedValue = GetValue();
  2267.     
  2268.     // Change the value, call JavaScript, if it cancels 
  2269.     // the click, then change the value back.
  2270.  
  2271.     super::HotSpotResult(inHotSpot);
  2272.     ReflectData();
  2273.     
  2274.     //
  2275.     // Call the JavaScript onClick handler,
  2276.     // which may cancel the click
  2277.     //
  2278.     
  2279.     // Adding another callback loop to do a mouse up for xp consistency.
  2280.     // Cancelling the mouse up will have no effect on the state
  2281.     // of the checkbox after the mouse down, but will prevent a click from being sent.
  2282.     MochaMouseUp( myContext, myEle, new CGAFormCheckboxHotSpotResultMochaCallback( this, inHotSpot, savedValue, EVENT_MOUSEUP));
  2283. }
  2284.  
  2285. // ---------------------------------------------------------------------------
  2286. //        Ñ EventMouseUp
  2287. // ---------------------------------------------------------------------------
  2288.  
  2289. // This gets the mouse up and sends it to javascript in the event that
  2290. // a mouse down is cancelled; hot spot tracking normally eats the mouse up
  2291. // so this won't be called otherwise. We won't get the mouse up if it occurred
  2292. // outside the pane.
  2293. void
  2294. CGAFormCheckbox::EventMouseUp(const EventRecord& /*inEvent*/)
  2295. {
  2296.     CMochaHacks::SendEvent(fContext, EVENT_MOUSEUP, fLayoutElement);
  2297. }
  2298.  
  2299. #pragma mark == CFormFile ==
  2300.  
  2301. //
  2302. // class CFormFile
  2303. // 
  2304.  
  2305. CFormFile::CFormFile(LStream * inStream) : LView(inStream), LFormElement()
  2306. {
  2307.     fHasFile = FALSE;
  2308.  
  2309.     SetReflectOnChange(true);    
  2310. }
  2311.  
  2312. void CFormFile::FinishCreateSelf()
  2313. {
  2314.     fEditField = (CFormFileEditField *)FindPaneByID(CFormFileEditField::class_ID);
  2315.     fButton = (LStdButton*)FindPaneByID('ffib');
  2316.     ThrowIfNil_(fButton);
  2317.     ThrowIfNil_(fEditField);
  2318.     fButton->AddListener(this);
  2319. }
  2320.  
  2321. void CFormFile::SetVisibleChars(Int16 numOfChars)
  2322. {
  2323. // Resize the edit field to the proper number of characters.
  2324.     FocusDraw();    // Algorithm copied from CFormLittleText::SetVisibleChars
  2325.     UTextTraits::SetPortTextTraits(fEditField->mTextTraitsID);
  2326.     FontInfo fInfo;
  2327.     ::GetFontInfo(&fInfo);
  2328.     fEditField->ResizeFrameTo(::CharWidth('a') * numOfChars + 6, fInfo.ascent + fInfo.descent+ fInfo.leading + 4, FALSE);    
  2329. // Move the button so that it does not overlap    
  2330.     SPoint32 location;
  2331.     SDimension16 size;
  2332.     fEditField->GetFrameLocation(location);
  2333.     fEditField->GetFrameSize(size);
  2334.     fButton->PlaceInSuperFrameAt(location.h+size.width + 2 - mFrameLocation.h, 0, FALSE);
  2335. // Resize ourselves
  2336.     fButton->GetFrameLocation(location);
  2337.     fButton->GetFrameSize(size);
  2338.     ResizeFrameTo(location.h+size.width + 2, size.height, FALSE);
  2339. // Reset ourselves
  2340.     fHasFile = FALSE;
  2341.     fEditField->SetDescriptor(CStr255::sEmptyString);
  2342. }
  2343.  
  2344. void CFormFile::GetFontInfo(Int32& width, Int32& height, Int32& baseline)
  2345. {
  2346.     FocusDraw();    // Algorithm copied from CFormLittleText::SetVisibleChars
  2347.     UTextTraits::SetPortTextTraits(fEditField->mTextTraitsID);
  2348.     FontInfo fInfo;
  2349.     ::GetFontInfo(&fInfo);
  2350.     SPoint32 location;
  2351.     fEditField->GetFrameLocation(location);
  2352.     width = mFrameSize.width;
  2353.     height = mFrameSize.height;
  2354.     baseline = fInfo.ascent+3 + location.v - mFrameLocation.v;    // Looking for the baseline of the text field
  2355. }
  2356.  
  2357. Boolean CFormFile::GetFileSpec(FSSpec & spec)
  2358. {
  2359.     if (!fHasFile)
  2360.         return FALSE;
  2361.     else
  2362.     {
  2363.         spec = fSpec;
  2364.         return TRUE;
  2365.     }
  2366. }
  2367.  
  2368. void CFormFile::SetFileSpec(FSSpec & spec)
  2369. {
  2370.     fSpec = spec;
  2371.     fHasFile = TRUE;
  2372.     fEditField->FocusDraw();
  2373.     fEditField->SetDescriptor(fSpec.name);    // Make sure that all text is selected
  2374.     ::TESetSelect(0, 32767, fEditField->mTextEditH);
  2375.     
  2376.  
  2377.     MochaChanged();
  2378. }
  2379.  
  2380. void CFormFile::ListenToMessage(MessageT inMessage, void */*ioParam*/)
  2381. {
  2382.     switch (inMessage)    {
  2383.         case 2001:
  2384.         {
  2385.             StandardFileReply myReply;
  2386.             SFTypeList myTypes;
  2387.             UDesktop::Deactivate();    // Always bracket this
  2388.             StandardGetFile(NULL, -1, myTypes, &myReply);
  2389.             UDesktop::Activate();
  2390.             if (myReply.sfGood)
  2391.             {
  2392.                 if (!CFileMgr::FileHasDataFork(myReply.sfFile))
  2393.                     ErrorManager::PlainAlert(SUBMIT_FILE_WITH_DATA_FK);
  2394.                 else
  2395.                     SetFileSpec(myReply.sfFile);    
  2396.             }
  2397.         }
  2398.         break;
  2399.         case 2002:    // User has deleted the text
  2400.             fHasFile = FALSE;
  2401.             MochaChanged();
  2402.         default:
  2403.             break;
  2404.     }
  2405. }
  2406.  
  2407. #pragma mark == CFormFileEditField ==
  2408.  
  2409. //
  2410. // CFormFileEditField
  2411. //
  2412.  
  2413. CFormFileEditField::CFormFileEditField(LStream * inStream) : LEditField (inStream)
  2414. {
  2415.     mKeyFilter = UKeyFilters::AlphaNumericField;
  2416. }
  2417.  
  2418. void CFormFileEditField::ClickSelf(const SMouseDownEvent    &/*inMouseDown*/)
  2419. {
  2420.     SwitchTarget(this);
  2421.     ::TESetSelect(0, 32767, mTextEditH);
  2422. }
  2423.  
  2424.  
  2425. void
  2426. CFormFileEditField::DrawSelf()
  2427. {
  2428.     Rect    frame;
  2429.     CalcLocalFrameRect(frame);
  2430.  
  2431.     ::InsetRect(&frame, 1,1);
  2432.     ::EraseRect(&frame);
  2433.  
  2434.     LEditField::DrawSelf();    
  2435.  
  2436.     ::InsetRect(&frame, -1,-1);
  2437.     UGraphics::FrameRectSubtle(frame, true);    
  2438. }
  2439.  
  2440.  
  2441. void CFormFileEditField::FindCommandStatus(CommandT    inCommand,
  2442.                             Boolean        &outEnabled,
  2443.                             Boolean        &outUsesMark,
  2444.                             Char16        &outMark,
  2445.                             Str255        outName)
  2446. {
  2447.     switch (inCommand) {
  2448.     
  2449.         case cmd_Cut:                // Cut, Copy, and Clear enabled
  2450.         case cmd_Copy:                //   if something is selected
  2451.         case cmd_Clear:
  2452.             outEnabled = ((**mTextEditH).selStart != (**mTextEditH).selEnd);
  2453.             break;
  2454.                     
  2455.         case cmd_Paste: {
  2456.             outEnabled = FALSE;
  2457.             break;
  2458.         }
  2459.         
  2460.         case cmd_SelectAll:            // Check if any characters are present
  2461.             outEnabled = (**mTextEditH).teLength > 0;
  2462.             break;
  2463.             
  2464.         default:
  2465.             LCommander::FindCommandStatus(inCommand, outEnabled,
  2466.                                     outUsesMark, outMark, outName);
  2467.             break;
  2468.     }
  2469. }
  2470.  
  2471. // Copied from LEditField::HandleKeyPress.
  2472. // Filter everything byt delete
  2473. Boolean    CFormFileEditField::HandleKeyPress(const EventRecord&    inKeyEvent)
  2474. {
  2475.     Boolean        keyHandled = true;
  2476.     EKeyStatus    theKeyStatus = keyStatus_Input;
  2477.     Int16        theKey = inKeyEvent.message & charCodeMask;
  2478.     
  2479.     if (inKeyEvent.modifiers & cmdKey) {    // Always pass up when the command
  2480.         theKeyStatus = keyStatus_PassUp;    //   key is down
  2481.     
  2482.     } else if (mKeyFilter != nil) {
  2483.         theKeyStatus = (*mKeyFilter)(mTextEditH, inKeyEvent.message,
  2484.                                         inKeyEvent.message & charCodeMask, inKeyEvent.modifiers);
  2485.     }
  2486.     switch(theKeyStatus)
  2487.     {
  2488.         case keyStatus_TEDelete:
  2489.             return LEditField::HandleKeyPress(inKeyEvent);
  2490.         default:
  2491.             return LCommander::HandleKeyPress(inKeyEvent);    // Bypass the edit field
  2492.     }
  2493.     return FALSE;
  2494. }
  2495.  
  2496. void CFormFileEditField::UserChangedText()
  2497. {
  2498.     ((CFormFile *)mSuperView)->ListenToMessage(2002, NULL);
  2499. }
  2500.  
  2501.  
  2502.  
  2503. static LArray*    gDeadFormElementsList     = NULL;
  2504. static void*    gKillFormElementsTimer     = 0;    // timer ID
  2505.  
  2506. static void
  2507. KillFormElementsTimer(    void */*ignore*/ )
  2508. {
  2509.     Assert_(gDeadFormElementsList != NULL);
  2510.     
  2511.     LArrayIterator     iterator(*gDeadFormElementsList);
  2512.     LPane*            pane;
  2513.     
  2514.     while (iterator.Next(&pane)) {
  2515.         delete pane;
  2516.     }
  2517.  
  2518.     gDeadFormElementsList->RemoveItemsAt(
  2519.                                 gDeadFormElementsList->GetCount(), 
  2520.                                 LArray::index_First);
  2521.                                 
  2522.     gKillFormElementsTimer = 0;                                
  2523. }
  2524.  
  2525.  
  2526. // Switch focus to an input element
  2527.  
  2528. void
  2529. FE_FocusInputElement(    MWContext    *    context,
  2530.                         LO_Element    *    element)
  2531. {
  2532.     
  2533.     Assert_(context != NULL);
  2534.     
  2535.     // If element is NULL, we are to give focus to
  2536.     // the window itself, bringing it to front if
  2537.     // necessary...
  2538.     //
  2539.     if (element == NULL)
  2540.     {
  2541.         FE_RaiseWindow(context);
  2542.     }
  2543.     else
  2544.     {
  2545.         LO_FormElementStruct * formElem;
  2546.         LFormElement         * toFocus;
  2547.         FormFEData             * feData;
  2548.  
  2549.         Assert_(element->type == LO_FORM_ELE);
  2550.         
  2551.             
  2552.         formElem     = (LO_FormElementStruct *) element;
  2553.         feData        = GetFEData(formElem);
  2554.         if ( feData == NULL) {
  2555.             return;
  2556.         }
  2557.  
  2558.     // Can't call SwitchTarget, because the Mocha script calling
  2559.     // this callback may have been invoked by a target switch
  2560.     // that is in progress, but not complete.
  2561.     //
  2562.     // So we set a timer to do it for us...
  2563.  
  2564.             
  2565.         toFocus = feData->fHost;
  2566.  
  2567.         if (toFocus != NULL)
  2568.         {
  2569.             // limitation of 1 timer per form element
  2570.             if (toFocus->fTimer != 0)
  2571.                 FE_ClearTimeout(toFocus->fTimer);
  2572.             
  2573.             toFocus->fTimer = FE_SetTimeout((TimeoutCallbackFunction)FocusFormElementTimer, (void*)formElem, 0);
  2574.         }
  2575.         
  2576.     //    toFocus     = (LCommander *) GetFEDataPane(formElement);
  2577.     //    Assert_(toFocus != NULL);
  2578.     //    LCommander::SwitchTarget(toFocus);
  2579.     
  2580.     }
  2581. }
  2582.  
  2583. // Take focus away from a input element and give it
  2584. // to its commander
  2585. void
  2586. FE_BlurInputElement(    MWContext    *    context,
  2587.                         LO_Element    *    element)
  2588. {
  2589.     // If element is NULL, we blur focus from the window,
  2590.     // but only if the window contains the current target,
  2591.     // as denoted by the result of IsOnDuty()
  2592.     //
  2593.     // When we blur focus, we send focus to nothing...
  2594.     //
  2595.     if (element == NULL)
  2596.     {
  2597.         FE_LowerWindow(context);
  2598.     }
  2599.     else
  2600.     {
  2601.         LO_FormElementStruct     * formElem;
  2602.         LFormElement            * unFocus;
  2603.         FormFEData                * feData;
  2604.             
  2605.         Assert_(context != NULL && element != NULL);
  2606.         Assert_(element->type == LO_FORM_ELE);
  2607.         
  2608.         formElem    = (LO_FormElementStruct *) element;
  2609.         feData         = GetFEData(formElem);
  2610.         if (feData == NULL) { 
  2611.             return;
  2612.         }
  2613.         
  2614.         unFocus = feData->fHost;
  2615.         
  2616.     // Can't call SwitchTarget, because the Mocha script calling
  2617.     // this callback may have been invoked by a target switch
  2618.     // that is in progress, but not complete.
  2619.     //
  2620.     // So we set a timer to do it for us...
  2621.  
  2622.         if (unFocus != NULL)
  2623.         {
  2624.             // limitation of 1 timer per form element
  2625.             if (unFocus->fTimer != 0)
  2626.                 FE_ClearTimeout(unFocus->fTimer);
  2627.                 
  2628.             unFocus->fTimer = FE_SetTimeout((TimeoutCallbackFunction)BlurFormElementTimer, (void*)formElem, 0);    
  2629.         }
  2630.         
  2631.     /*    if (LCommander::GetTarget() == unFocus)
  2632.             LCommander::SwitchTarget(unFocus->GetSuperCommander());
  2633.         else
  2634.             Assert_(false);
  2635.     */        
  2636.     }
  2637. }
  2638.  
  2639.  
  2640. //
  2641. // Timer callback to switch the target
  2642. // to a given form element
  2643. //
  2644. static void
  2645. FocusFormElementTimer(    LO_FormElementStruct * formElem )
  2646. {
  2647.     Assert_(formElem != NULL);
  2648.     Assert_(GetFEData(formElem) != NULL);
  2649.     
  2650.     if ( !GetFEData( formElem ) )
  2651.         return;
  2652.     
  2653.     // Having no element_data would be a BAD THING 
  2654.     if (!formElem->element_data)
  2655.         return;
  2656.     
  2657.     LCommander        *    commander = FEDATACOMMANDER;
  2658.     LFormElement    *    element = FEDATAHOST;
  2659.         
  2660.     element->fTimer = 0;
  2661.     
  2662.     if (commander != NULL)
  2663.         LCommander::SwitchTarget(commander);
  2664. }
  2665.  
  2666. //
  2667. // Timer callback to take focus from
  2668. // a form element.
  2669. //
  2670. static void
  2671. BlurFormElementTimer(    LO_FormElementStruct * formElem )
  2672. {
  2673.     Assert_(formElem != NULL);
  2674.     Assert_(GetFEData(formElem) != NULL);
  2675.     
  2676.     if ( !GetFEData( formElem ) )
  2677.         return;
  2678.     
  2679.     // Having no element_data would be a BAD THING
  2680.     if (!formElem->element_data)
  2681.         return;
  2682.     
  2683.     LCommander        *    commander = FEDATACOMMANDER;
  2684.     LFormElement    *    element = FEDATAHOST;
  2685.             
  2686.     element->fTimer = 0;
  2687.     
  2688.     if (commander != NULL)
  2689.     {
  2690.     
  2691.         if (LCommander::GetTarget() == commander)
  2692.             LCommander::SwitchTarget(commander->GetSuperCommander());
  2693.         else
  2694.             Assert_(false);
  2695.     }
  2696. }
  2697.  
  2698.  
  2699. //
  2700. // "Select" the data in an input element.
  2701. //    For now this only applies to text fields
  2702. // 
  2703. void
  2704. FE_SelectInputElement(    MWContext    *    window,
  2705.                         LO_Element    *    element)
  2706. {
  2707.     LO_FormElementStruct * formElement;    
  2708.     
  2709.     Assert_(window != NULL && element != NULL);
  2710.     Assert_(element->type == LO_FORM_ELE);
  2711.         
  2712.     formElement = (LO_FormElementStruct *) element;
  2713.  
  2714.     switch (formElement->element_data->type) 
  2715.     {
  2716.         // LEditFields - just call SelectAll
  2717.         case FORM_TYPE_TEXT:
  2718.         case FORM_TYPE_PASSWORD:
  2719.         case FORM_TYPE_ISINDEX:
  2720.         case FORM_TYPE_READONLY:
  2721.         {
  2722.             if ( !GetFEData( formElement ) )
  2723.                 return;
  2724.             if ( !GetFEDataPane( formElement ) )
  2725.                 return;
  2726.             LEditField    *editField = (LEditField *) GetFEDataPane(formElement);
  2727.             editField->SelectAll();
  2728.             break;
  2729.         }
  2730.         
  2731.         // Text engine - select all
  2732.         case FORM_TYPE_TEXTAREA:
  2733.             if ( !GetFEData( formElement ) )
  2734.                 return;
  2735.             if ( !GetFEDataPane( formElement ) )
  2736.                 return;
  2737.  
  2738.             LPane         *scroller = GetFEDataPane(formElement);            
  2739.             CSimpleTextView    *textEdit = (CSimpleTextView*) scroller->FindPaneByID(formBigTextID);    Assert_(textEdit != NULL);
  2740.             textEdit->SelectAll();
  2741.             
  2742.             break;
  2743.                     
  2744. /*    These are not selectable
  2745.  
  2746.         case FORM_TYPE_FILE:
  2747.         case FORM_TYPE_SELECT_ONE:
  2748.         case FORM_TYPE_SELECT_MULT:
  2749.         case FORM_TYPE_RADIO:
  2750.         case FORM_TYPE_CHECKBOX:    
  2751.         case FORM_TYPE_HIDDEN:
  2752.         case FORM_TYPE_KEYGEN:    
  2753.         case FORM_TYPE_SUBMIT:
  2754.         case FORM_TYPE_RESET:
  2755.         case FORM_TYPE_BUTTON:
  2756.         case FORM_TYPE_IMAGE:
  2757.         case FORM_TYPE_JOT:
  2758.         case FORM_TYPE_OBJECT:
  2759. */
  2760.         default: break;
  2761.     }        
  2762. }    
  2763.  
  2764.  
  2765. //
  2766. // Notification that a input element's data has changed.
  2767. // Grab the data from XP using ResetFormElement and
  2768. // then redraw...
  2769. //
  2770. void
  2771. FE_ChangeInputElement(    MWContext    *    window,
  2772.                         LO_Element    *    element)
  2773. {
  2774.     LO_FormElementStruct    *    formElement;
  2775.     
  2776.     Assert_(window != NULL && element != NULL);
  2777.     Assert_(element->type == LO_FORM_ELE);
  2778.     
  2779.     Try_
  2780.     {
  2781.         LO_LockLayout();     // prevent race condition with mocha thread    
  2782.         // reflect back from Layout
  2783.         formElement = (LO_FormElementStruct *) element;
  2784.         UFormElementFactory::ResetFormElementData(formElement, true, false, false);
  2785.         // pkc -- If we're setting a radio button, call LO_FormRadioSet
  2786.         // to turn off other radio buttons.
  2787.         // WHY AREN'T WE USING LRadioGroup?!?!?!?!?!?!?!?!?!?!?!?!?!?!?
  2788.         if ( formElement->element_data->type == FORM_TYPE_RADIO &&
  2789.              ((lo_FormElementToggleData *)(formElement->element_data))->toggled )
  2790.             LO_FormRadioSet(window, formElement);
  2791.     }
  2792.     Catch_(inErr)
  2793.     {
  2794.         LO_UnlockLayout();
  2795.         Throw_(inErr);
  2796.     }
  2797.     EndCatch_
  2798.         LO_UnlockLayout();
  2799. }                                        
  2800.  
  2801.  
  2802. // 
  2803. // Initiate a form submission through a given input element
  2804. //
  2805. void
  2806. FE_SubmitInputElement(    MWContext    *    window,
  2807.                         LO_Element    *    element)
  2808. {
  2809.     LO_FormElementStruct    *    formElement;
  2810.     URL_Struct                 *     url;
  2811.     LO_FormSubmitData        *    submitData;
  2812.     History_entry            *     currentHistoryPosition;
  2813.     
  2814.     Assert_(window != NULL && element != NULL);    
  2815.     
  2816.     // I get an element->type of LO_IMAGE when going to VeriSign
  2817.     Assert_(element->type == LO_FORM_ELE || element->type == LO_IMAGE);
  2818.     
  2819.     formElement = (LO_FormElementStruct *) element;
  2820.     
  2821.     //
  2822.     // Call the LO module to figure out the form's context
  2823.     //
  2824.     submitData = LO_SubmitForm(window, formElement);
  2825.     if (submitData == NULL)    
  2826.         return;
  2827.     
  2828.     url =  NET_CreateURLStruct((char *)submitData->action, NET_DONT_RELOAD);
  2829.     currentHistoryPosition = SHIST_GetCurrent( &window->hist );
  2830.     
  2831.     if (currentHistoryPosition && currentHistoryPosition->address)
  2832.         url->referer = XP_STRDUP(currentHistoryPosition->address);
  2833.     
  2834.     NET_AddLOSubmitDataToURLStruct(submitData, url);
  2835.  
  2836.     CBrowserContext* theNSContext = ExtractBrowserContext(window);
  2837.     Assert_(theNSContext != NULL);
  2838.     theNSContext->SwitchLoadURL(url, FO_CACHE_AND_PRESENT);
  2839.     
  2840.     LO_FreeSubmitData(submitData);
  2841. }    
  2842.  
  2843.  
  2844. //
  2845. // Simulate a "hot-spot" click on an input element.
  2846. // Applies only to buttons.
  2847. //
  2848. void
  2849. FE_ClickInputElement(    MWContext    *    window,
  2850.                         LO_Element    *    element)
  2851. {
  2852.  
  2853.     LO_FormElementStruct    *    formElement;
  2854.     
  2855.     Assert_(window != NULL && element != NULL);
  2856.     Assert_(element->type == LO_FORM_ELE);
  2857.  
  2858.     formElement = (LO_FormElementStruct *) element;
  2859.     switch (formElement->element_data->type) 
  2860.     {
  2861.         case FORM_TYPE_SUBMIT:
  2862.         case FORM_TYPE_RESET:
  2863.         case FORM_TYPE_BUTTON:
  2864.             if ( !GetFEData( formElement ) )
  2865.                 return;
  2866.             if ( !GetFEDataPane( formElement ) )
  2867.                 return;
  2868.  
  2869.             LControl    *control = (LControl *) GetFEDataPane(formElement);    
  2870.             control->SimulateHotSpotClick(0);
  2871.             break;
  2872.                     
  2873. /*    These are not programmatically "clickable"
  2874.  
  2875.         case FORM_TYPE_TEXT:
  2876.         case FORM_TYPE_PASSWORD:
  2877.         case FORM_TYPE_ISINDEX:
  2878.         case FORM_TYPE_TEXTAREA:
  2879.         case FORM_TYPE_FILE:
  2880.         case FORM_TYPE_SELECT_ONE:
  2881.         case FORM_TYPE_SELECT_MULT:
  2882.         case FORM_TYPE_RADIO:
  2883.         case FORM_TYPE_CHECKBOX:    
  2884.         case FORM_TYPE_HIDDEN:
  2885.         case FORM_TYPE_KEYGEN:    
  2886.         case FORM_TYPE_IMAGE:
  2887.         case FORM_TYPE_JOT:
  2888.         case FORM_TYPE_OBJECT:
  2889. */
  2890.         default:    break;
  2891.     }
  2892. }
  2893.  
  2894. void MochaFocusCallback(    MWContext * /* pContext */,
  2895.                             LO_Element * /* lo_element */,
  2896.                             int32 /* lType */,
  2897.                             void * whatever,
  2898.                             ETEventStatus status    )
  2899. {
  2900.     if (status == EVENT_OK && whatever)
  2901.     {
  2902.         LFormElement* element = reinterpret_cast<LFormElement*>(whatever);
  2903.         element->ClearInFocusCallAlready();
  2904.         // 97-06-14 pkc -- call virtual callback method
  2905.         element->PostMochaFocusCallback();
  2906.     }
  2907. }
  2908.  
  2909.  
  2910. void
  2911. LFormElement::MochaFocus(     Boolean doFocus,
  2912.                             Boolean switchTarget)
  2913. {
  2914.     // Don't do anything if we're really dead
  2915.     if (IsMarkedForDeath()) 
  2916.         return;
  2917.         
  2918.     // ick ick ick ick ick
  2919.     //
  2920.     // Here's the deal...
  2921.     // PowerPlant doesn't change sTarget before
  2922.     // calling it's DontBeTarget method, so if that
  2923.     // method does something to change the target,
  2924.     // you recurse.
  2925.     //        
  2926.     if (fInFocusCallAlready && doFocus == fPreviousFocus)
  2927.     {
  2928.         fPreviousFocus = doFocus;
  2929.         return;
  2930.     }
  2931.     else
  2932.     {
  2933.         fPreviousFocus = doFocus;
  2934.     }
  2935.         
  2936.     if (!XP_IsContextInList(fContext))
  2937.         return;
  2938.         
  2939.     fInFocusCallAlready = true;
  2940.     
  2941.     if (doFocus) 
  2942.     {
  2943.         if (switchTarget)
  2944.             sTargetedFormElement = this;
  2945.         
  2946.         // ET_SendEvent now takes a JSEvent struct instead of an int type
  2947.         JSEvent* event = XP_NEW_ZAP(JSEvent);
  2948.         if (event)
  2949.         {
  2950.             event->type = EVENT_FOCUS;
  2951.             event->layer_id = fLayoutElement->lo_form.layer_id;
  2952.             ET_SendEvent( fContext, fLayoutElement, event, MochaFocusCallback, this );
  2953.         }
  2954.     }
  2955.     else
  2956.     {
  2957.         if (switchTarget)
  2958.             sTargetedFormElement = NULL;
  2959.         
  2960.         if (fMochaChanged)
  2961.         {
  2962.             // fReflectOnChange denotes when LM_SendOnChange should be called.
  2963.             // If it is true, the call is made immediately when the data changes.
  2964.             // If false, the call is made here, when focus is lost.
  2965.             // 
  2966.             // The only reason for this flag is that some form elements are not
  2967.             // focusable and therefore must immediately reflect state changes.
  2968.             
  2969.             if (!fReflectOnChange)
  2970.                 ReflectData();
  2971.                 
  2972.             fMochaChanged = false;    // important to do this first to avoid recursion
  2973.  
  2974.             // ET_SendEvent now takes a JSEvent struct instead of an int type
  2975.             JSEvent* event = XP_NEW_ZAP(JSEvent);
  2976.             if (event)
  2977.             {
  2978.                 event->type = EVENT_CHANGE;
  2979.                 event->layer_id = fLayoutElement->lo_form.layer_id;
  2980.                 ET_SendEvent( fContext, fLayoutElement, event, MochaFocusCallback, this );
  2981.             }
  2982.         }
  2983.         
  2984.         // Don't do anything if the onChange handler killed this form element
  2985.         if (!IsMarkedForDeath())
  2986.         {
  2987.             // ET_SendEvent now takes a JSEvent struct instead of an int type
  2988.             JSEvent* event = XP_NEW_ZAP(JSEvent);
  2989.             if (event)
  2990.             {
  2991.                 event->type = EVENT_BLUR;
  2992.                 event->layer_id = fLayoutElement->lo_form.layer_id;
  2993.                 ET_SendEvent( fContext, fLayoutElement, event, MochaFocusCallback, this );
  2994.             }
  2995.         }
  2996.     }
  2997.  
  2998. //    97-06-03 pkc -- this is now set top false in MochaFocusCallback
  2999. //    fInFocusCallAlready = false;
  3000.  }
  3001.  
  3002.  
  3003. #pragma global_optimizer off
  3004.  
  3005. StTempFormBlur::StTempFormBlur()
  3006. {
  3007.     fSavedFocus = LFormElement::GetTargetedElement();
  3008.     
  3009.     if ( fSavedFocus )
  3010.     {
  3011.         // 97.08.18 pchen -- fix bug #79140
  3012.         // If fSavedFocus is an LCommander, call SwitchTarget on it's
  3013.         // supercommander to "unfocus" form element.
  3014.         LCommander* commander = dynamic_cast<LCommander*>(fSavedFocus);
  3015.         if (commander)
  3016.         {
  3017.             LCommander* super = commander->GetSuperCommander();
  3018.             if (super)
  3019.             {
  3020.                 LCommander::SwitchTarget(super);
  3021.                 fSavedFocus = NULL;
  3022.             }
  3023.         }
  3024.         else
  3025.             fSavedFocus->MochaFocus(false, false);
  3026.     }
  3027. }
  3028.  
  3029.  
  3030. StTempFormBlur::~StTempFormBlur()
  3031. {
  3032.     if ( fSavedFocus )
  3033.         fSavedFocus->MochaFocus(true, false);
  3034.         
  3035.     fSavedFocus = NULL;    
  3036. }
  3037.  
  3038.  
  3039. LFormElement* LFormElement::sTargetedFormElement = NULL;
  3040.  
  3041.  
  3042. void
  3043. LFormElement:: MochaSelect()
  3044. {    
  3045.     // don't do anything if we're dead
  3046.     if (IsMarkedForDeath()) return;
  3047.     
  3048.     // ET_SendEvent now takes a JSEvent struct instead of an int type
  3049.     JSEvent* event = XP_NEW_ZAP(JSEvent);
  3050.     if (event)
  3051.     {
  3052.         event->type = EVENT_SELECT;
  3053.         event->layer_id = fLayoutElement->lo_form.layer_id;
  3054.         ET_SendEvent( fContext, fLayoutElement, event, NULL, NULL );
  3055.     }
  3056. }
  3057.  
  3058. void MochaChangedCallback(    MWContext * /* pContext */,
  3059.                             LO_Element * /* lo_element */,
  3060.                             int32 /* lType */,
  3061.                             void * whatever,
  3062.                             ETEventStatus status    )
  3063. {
  3064.     if (status == EVENT_OK && whatever)
  3065.     {
  3066.         LFormElement* element = reinterpret_cast<LFormElement*>(whatever);
  3067.         // 97-06-14 pkc -- call PostMochaFocusCallback to handle FormsPopup special case
  3068.         element->PostMochaFocusCallback();
  3069.     }
  3070. }
  3071.  
  3072. Boolean HasKeyEventCapture(MWContext* context);
  3073.  
  3074. // Returns whether the context or any of its parents is capturing key events.
  3075. Boolean HasKeyEventCapture(MWContext* context)
  3076. {
  3077.     MWContext *mwcx;
  3078.     uint32 mask = EVENT_KEYDOWN | EVENT_KEYUP | EVENT_KEYPRESS;
  3079.     
  3080.     if (context->event_bit & mask) return true;
  3081.  
  3082.     if (context->is_grid_cell) 
  3083.     {
  3084.         mwcx = context;
  3085.         while (mwcx->grid_parent != NULL) 
  3086.         {
  3087.             mwcx = mwcx->grid_parent;
  3088.             if (mwcx->event_bit & mask) return true;
  3089.         }
  3090.     }
  3091.     return false;
  3092. }
  3093.  
  3094. void
  3095. LFormElement::MochaChanged()
  3096. {
  3097.     // don't do anything if we're dead OR we don't have a fLayoutElement which
  3098.     // can be the case when we are creating a text area and the text engine sends
  3099.     // a message that the newly created area has changed before we get a chance to
  3100.     // assign it a fLayoutElement
  3101.     if (IsMarkedForDeath() || fLayoutElement == NULL)
  3102.         return;
  3103.     
  3104.     //
  3105.     // If fReflectOnChange is false,
  3106.     // we will reflect the data when the
  3107.     // element loses focus.
  3108.     //
  3109.     // If true, we must reflect it now
  3110.     //    
  3111.     if (fReflectOnChange) 
  3112.     {
  3113.         fMochaChanged = false;
  3114.         ReflectData(); 
  3115.  
  3116.         // ET_SendEvent now takes a JSEvent struct instead of an int type
  3117.         JSEvent* event = XP_NEW_ZAP(JSEvent);
  3118.         if (event)
  3119.         {
  3120.             event->type = EVENT_CHANGE;
  3121.             event->layer_id = fLayoutElement->lo_form.layer_id;
  3122. //            ET_SendEvent( fContext, fLayoutElement, event, NULL, NULL );
  3123.             // 97-06-14 pkc -- Use MochaChangedCallback to handle FormsPopup special case
  3124.             ET_SendEvent( fContext, fLayoutElement, event, MochaChangedCallback, this );
  3125.         }
  3126.     }
  3127.     else
  3128.     {
  3129.         // if the form element is a text entry form and there is a key event handler for
  3130.         // any containing context or for the form, reflect the data.
  3131.         LO_FormElementData* data = fLayoutElement->lo_form.element_data;
  3132.         if (data != NULL &&
  3133.             (data->type == FORM_TYPE_TEXTAREA ||
  3134.              data->type == FORM_TYPE_TEXT ||
  3135.              data->type == FORM_TYPE_PASSWORD) &&
  3136.             (fLayoutElement->lo_form.event_handler_present || HasKeyEventCapture(fContext)))
  3137.         {
  3138.             ReflectData();
  3139.         }
  3140.         fMochaChanged = true;     
  3141.     }
  3142. }
  3143.  
  3144.  
  3145. void
  3146. LFormElement::MochaSubmit()    
  3147. {    
  3148.     // don't do anything if we're dead
  3149.     if (IsMarkedForDeath()) return;
  3150.     
  3151.     StTempFormBlur    tempBlur;
  3152.     // ET_SendEvent now takes a JSEvent struct instead of an int type
  3153.     JSEvent* event = XP_NEW_ZAP(JSEvent);
  3154.     if (event)
  3155.     {
  3156.         event->type = EVENT_SUBMIT;
  3157.         event->layer_id = fLayoutElement->lo_form.layer_id;
  3158.         ET_SendEvent( fContext, fLayoutElement, event, NULL, NULL );
  3159.     }
  3160. }
  3161.     
  3162. void
  3163. MochaClick( MWContext* context, LO_Element* ele, CMochaEventCallback * cb )    
  3164. {    
  3165.     StTempFormBlur tempBlur;
  3166.     JSEvent* event = XP_NEW_ZAP(JSEvent);
  3167.     if (event)
  3168.     {
  3169.         LO_FormElementStruct* form = (LO_FormElementStruct *)ele;
  3170.         CHTMLView* view = dynamic_cast<CHTMLView*>(GetFEDataPane(form)->GetSuperView());
  3171.         ThrowIfNil_(view);
  3172.         SPoint32 formPos = {CL_GetLayerXOrigin(form->layer), CL_GetLayerYOrigin(form->layer)};
  3173.         Point screenPt;
  3174.         view->ImageToAvailScreenPoint(formPos, screenPt);
  3175.         event->type = EVENT_CLICK;
  3176.         event->which = 1;
  3177.         event->x = CL_GetLayerXOffset(form->layer);
  3178.         event->y = CL_GetLayerYOffset(form->layer);
  3179.         event->docx = CL_GetLayerXOrigin(form->layer);
  3180.         event->docy = CL_GetLayerYOrigin(form->layer);
  3181.         event->screenx = screenPt.h;
  3182.         event->screeny = screenPt.v;
  3183.         event->layer_id = form->layer_id;
  3184.         event->modifiers = CMochaHacks::MochaModifiersFromKeyboard();
  3185.         ET_SendEvent( context, ele, event, CMochaEventCallback::MochaCallback, cb);
  3186.     }
  3187.     //cb->SendEvent(context, ele, EVENT_CLICK);
  3188. }
  3189.  
  3190. // EventMouseUp
  3191. void
  3192. MochaMouseUp( MWContext* context, LO_Element* ele, CMochaEventCallback * cb )    
  3193. {    
  3194.     JSEvent* event = XP_NEW_ZAP(JSEvent);
  3195.     if (event)
  3196.     {
  3197.         LO_FormElementStruct* form = (LO_FormElementStruct *)ele;
  3198.         CHTMLView* view = dynamic_cast<CHTMLView*>(GetFEDataPane(form)->GetSuperView());
  3199.         ThrowIfNil_(view);
  3200.         SPoint32 formPos = {CL_GetLayerXOrigin(form->layer), CL_GetLayerYOrigin(form->layer)};
  3201.         Point screenPt;
  3202.         view->ImageToAvailScreenPoint(formPos, screenPt);
  3203.         event->type = EVENT_MOUSEUP;
  3204.         event->which = 1;
  3205.         event->x = CL_GetLayerXOffset(form->layer);
  3206.         event->y = CL_GetLayerYOffset(form->layer);
  3207.         event->docx = CL_GetLayerXOrigin(form->layer);
  3208.         event->docy = CL_GetLayerYOrigin(form->layer);
  3209.         event->screenx = screenPt.h;
  3210.         event->screeny = screenPt.v;
  3211.         event->layer_id = form->layer_id;
  3212.         event->modifiers = CMochaHacks::MochaModifiersFromKeyboard();
  3213.         ET_SendEvent( context, ele, event, CMochaEventCallback::MochaCallback, cb);
  3214.     }
  3215.     //cb->SendEvent(context, ele, EVENT_MOUSEUP);
  3216. }
  3217.  
  3218. #pragma global_optimizer on
  3219.  
  3220.  
  3221. void
  3222. LFormElement::ReflectData()    // reflect to XP data structures
  3223. {
  3224.     if (!XP_IsContextInList(fContext))
  3225.         return;
  3226.     
  3227.     UFormElementFactory::GetFormElementValue(&(fLayoutElement->lo_form), false);
  3228. }
  3229.  
  3230.  
  3231. LFormElement::LFormElement()
  3232. {
  3233.     fTimer                        = 0; 
  3234.     fLayoutElement                 = NULL; 
  3235.     fContext                     = NULL; 
  3236.     fPane                        = NULL;
  3237.     fReflectOnChange             = false; 
  3238.     fInFocusCallAlready         = false; 
  3239.     fMarkedForDeath             = false;
  3240.     fPreviousFocus = false;
  3241. }
  3242.  
  3243. void
  3244. LFormElement::InitFormElement(MWContext * context, LO_FormElementStruct *lo_element)  
  3245. {
  3246.      fContext = context;
  3247.      fLayoutElement = (LO_Element *) lo_element;
  3248. }
  3249.  
  3250. /*
  3251.     LFormElement::MarkForDeath()
  3252.  
  3253.     Adds the form element's pane to the list of form elements to be destroyed
  3254.     at idle time.  This is necessary because JavaScript invoked from a widget
  3255.     class may clear the document, killing the widget in the process, but the
  3256.     widget may do more processing after the call to JavaScript returns, so
  3257.     we can't realyl kill it until sometime later, like idle time.
  3258. */
  3259. void
  3260. LFormElement::MarkForDeath()
  3261. {
  3262.     fMarkedForDeath = true;
  3263.     
  3264.     // Hide the element's pane, and add it to death row
  3265.     if (fPane != NULL)
  3266.     {    
  3267.         fPane->Hide();
  3268.         
  3269.         if (gDeadFormElementsList == NULL)
  3270.         {
  3271.             gDeadFormElementsList = new LArray;
  3272.             if (gDeadFormElementsList == NULL) return;    // leak me
  3273.         }
  3274.  
  3275.         gDeadFormElementsList->InsertItemsAt(1, LArray::index_First, &fPane);
  3276.             
  3277.         // set a timer to kill the elements in the list    
  3278.         if (gKillFormElementsTimer == 0) {
  3279.             gKillFormElementsTimer = FE_SetTimeout(KillFormElementsTimer, 0, 0);
  3280.         }
  3281.     }
  3282. }
  3283.  
  3284.  
  3285. /*
  3286.     LFormElement::~LFormElement()
  3287.  
  3288.     If this form element is the targeted form element, clear that field.
  3289.     
  3290.     If this form element has been marked for death earlier, it removes
  3291.     itself (actually its pane) from the gDeadFormElementsList.
  3292.     
  3293.     The key thing to remember with the mark for death is that it is
  3294.     actually the element's pane that gets kiled.  If the LPane and LFormElement
  3295.     are different objects, the pane is responsible for killing the form element,
  3296.     which then takes the pane out of the dead list (it's all very sick).
  3297. */
  3298. LFormElement::~LFormElement()
  3299. {
  3300.     if (this == sTargetedFormElement)
  3301.         sTargetedFormElement = NULL;
  3302.         
  3303.     if (fTimer != 0)
  3304.     {
  3305.         FE_ClearTimeout(fTimer);
  3306.         fTimer = 0;
  3307.     }
  3308.     
  3309.     if (fMarkedForDeath)
  3310.         gDeadFormElementsList->Remove(&fPane);
  3311.     
  3312.     // Since all of our form element pane classes mixin this class,
  3313.     // we should set fPane and fHost in fFEData to NULL
  3314.     if (fFEData)
  3315.     {
  3316.         if (fFEData->fPane == fPane)
  3317.             fFEData->fPane = NULL;
  3318.     
  3319.         if (fFEData->fHost == this)
  3320.             fFEData->fHost = NULL;
  3321.     }
  3322. }
  3323.  
  3324.  
  3325.  
  3326.  
  3327. /*
  3328.     FE_RaiseWindow
  3329.     
  3330.     Moves window belonging to inContext to the front
  3331.     of its layer within the window list.
  3332.     
  3333.     pkc (2/13/97) -- if there is no window associated with
  3334.     context, then we need to highlight frame.
  3335. */
  3336. void FE_RaiseWindow(MWContext* inContext)
  3337. {
  3338.     CBrowserContext* theNSContext = ExtractBrowserContext(inContext);
  3339.     Assert_(theNSContext != NULL);
  3340.  
  3341.     CBrowserWindow* theTargetWindow = NULL;
  3342.     CMediatedWindow* theIterWindow = NULL;
  3343.     CWindowIterator theWindowIterator(WindowType_Browser);
  3344.     while (theWindowIterator.Next(theIterWindow))
  3345.         {
  3346.         CBrowserWindow* theBrowserWindow = dynamic_cast<CBrowserWindow*>(theIterWindow);
  3347.         if (theBrowserWindow->GetWindowContext() == theNSContext)
  3348.             {
  3349.             theTargetWindow = theBrowserWindow;
  3350.             break;
  3351.             }
  3352.         }
  3353.         
  3354.     if (theTargetWindow != NULL)
  3355.         theTargetWindow->Select();
  3356.     else if (theNSContext->IsGridChild())
  3357.     {
  3358.         // context associated with a frame, call SwitchTarget on
  3359.         // CHTMLView in context to focus frame
  3360.         CHTMLView* theView = ExtractHyperView(inContext);
  3361.         if (theView)
  3362.             LCommander::SwitchTarget(theView);
  3363.     }
  3364. }
  3365.  
  3366.  
  3367. /*
  3368.     FE_LowerWindow
  3369.     
  3370.     Moves window belonging to inContext to the back
  3371.     of its layer within the window list.
  3372. */
  3373. void
  3374. FE_LowerWindow( MWContext*    inContext)
  3375. {
  3376.     CBrowserContext* theNSContext = ExtractBrowserContext(inContext);
  3377.     Assert_(theNSContext != NULL);
  3378.  
  3379.     // window.blur() in a frame context should blur the window.
  3380.     CBrowserWindow* theTargetWindow = CBrowserWindow::WindowForContext(theNSContext);
  3381.         
  3382.     if (theTargetWindow != NULL)
  3383.     {
  3384.         if (theTargetWindow->IsZLocked()) return;
  3385.         // context is associated with a window
  3386.         LWindow* theBehind = NULL;
  3387.         if (theTargetWindow->HasAttribute(windAttr_Floating))
  3388.                     theBehind = UDesktop::FetchBottomFloater();
  3389.         else if (theTargetWindow->HasAttribute(windAttr_Modal))
  3390.                     theBehind = UDesktop::FetchBottomModal();
  3391.         else theBehind = CWindowMediator::GetWindowMediator()->FetchBottomWindow(false);
  3392.         
  3393.         if (theBehind != theTargetWindow)
  3394.         {
  3395.             if (UDesktop::FetchTopRegular() == theTargetWindow)
  3396.                 theTargetWindow->Deactivate();
  3397.             ::SendBehind(theTargetWindow->GetMacPort(), (theBehind != NULL) ? theBehind->GetMacPort() : NULL);
  3398.             // The following hack is based on UDesktop::Resume() and fixes a case where the
  3399.             // window just sent to the back would be activated, when there is a floating
  3400.             // window present.
  3401.             LWindow* theTopWindow = UDesktop::FetchTopRegular();
  3402.             if (theTopWindow != NULL)
  3403.             {
  3404.                 theTopWindow->Activate();
  3405.                 LMSetCurActivate(nil);     // Suppress any Activate event
  3406.             }
  3407.         }
  3408.     }
  3409. }
  3410.  
  3411. // A word about events...
  3412.  
  3413. // We send a mouse down event to javascript via layers before any click processing 
  3414. // can occur. If layers/javascript lets us have the event, it arrives back at the
  3415. // front end and we resume click processing where it left off. The usual powerplant
  3416. // tracking mechanisms go into action, and when the mouse button is released,
  3417. // we send a mouse up event to javascript which takes a similar path. Only when
  3418. // the mouse up event comes back to us do we fire a click event.
  3419.  
  3420. // The reason why we use this model is to have some degree of platform consistency
  3421. // for event handling in a script:
  3422. // A script should be able to cancel mouse down and not get a click (but still
  3423. // get a mouse up. Alternatively, a script should be able to cancel mouse up and
  3424. // not get a click. The mac differs slightly from windows in that if you cancel a
  3425. // mouse down in the button, and the mouse up occurs outside the button, you won't
  3426. // get a mouse up.
  3427.  
  3428. // This can be summarized in the following diagram, where x means an event that
  3429. // was sent but cancelled, s means an event that was sent, and - means an event
  3430. // that was never sent.
  3431.  
  3432. // Mac                event order ->
  3433. //            down        up        click
  3434. //            x            s*            -         * if inside element
  3435. //
  3436. //            s            x            -
  3437. //
  3438. // Win
  3439. //
  3440. //            x            s            -
  3441. //
  3442. //            s            x            -
  3443.  
  3444. // Events may be synthesized in the backend; synthesizing a mouse down event
  3445. // on the mac will immediately trigger a mouse up event if the mouse is already
  3446. // up. It's not easy to rearchitect the front end so that we can leave a widget
  3447. // in a clicked state and explicitly release it later, because much of the
  3448. // powerplant control code for tracking the mouse is done modally.
  3449.                                     
  3450. // In an ideal xp world we would have total control over event sequencing, and
  3451. // be able to synthesize any events that a user could generate. The front ends
  3452. // haven't been architected this way so we have to compromise.
  3453.  
  3454. // NOTE: this behavior has been implemented for buttons, radio buttons, and
  3455. // checkboxes. Radio buttons and checkboxes send mouse up events which can be
  3456. // cancelled, but cancelling them just leaves the form element in the same state
  3457. // and prevents a click from being sent. The reason why we need to send a mouse
  3458. // up event for these toggle items is for xp consistency.
  3459.  
  3460. // 1997-03-06 mjc
  3461.  
  3462. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  3463. //    CLayerClickDispatchAttachment
  3464. //  Dispatches mouse down events to layers.
  3465. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  3466.  
  3467. CLayerClickDispatchAttachment::CLayerClickDispatchAttachment()
  3468.     :    LAttachment(msg_Click, false)
  3469. {
  3470. }
  3471.  
  3472. void CLayerClickDispatchAttachment::ExecuteSelf(
  3473.     MessageT            inMessage,
  3474.     void*                ioParam)
  3475. {
  3476.     Assert_(inMessage == msg_Click);
  3477.     mOwningControl = dynamic_cast<LControl*>(GetOwnerHost());
  3478.     Assert_(mOwningControl != NULL);
  3479.     
  3480.     MouseDown(*(SMouseDownEvent*)ioParam);
  3481. }
  3482.  
  3483. // Dispatches a mouse down to layers. The event comes back to the front end through
  3484. // FE_HandleLayerEvent if javascript lets us have it.
  3485. void 
  3486. CLayerClickDispatchAttachment::MouseDown(const SMouseDownEvent& inMouseDown)
  3487. {
  3488.     // get the compositor from the form element which is in the usercon of the control
  3489.  
  3490.     LO_FormElementStruct* formElem = (LO_FormElementStruct*) mOwningControl->GetUserCon();
  3491.     
  3492.     CL_Compositor* compositor = CL_GetLayerCompositor(formElem->layer);
  3493.  
  3494.     // ALERT: ignore mouse down if part of a multi-click. We don't need to handle multi
  3495.     // clicks on a form element.
  3496.     if (mOwningControl->GetClickCount() > 1) return;
  3497.     
  3498.     if (compositor != NULL) 
  3499.     {
  3500.         CL_Event        event;
  3501.         fe_EventStruct    fe_event;
  3502.         
  3503.         //SPoint32        firstP;
  3504.         //Point            where = inMouseDown.wherePort;
  3505.         //mOwningControl->GetSuperView()->PortToLocalPoint(where);
  3506.         //mOwningControl->GetSuperView()->LocalToImagePoint(where, firstP);
  3507.         
  3508.         fe_event.event.mouseDownEvent = inMouseDown;
  3509.         event.type = CL_EVENT_MOUSE_BUTTON_DOWN;
  3510.         event.fe_event = (void *)&fe_event;
  3511.         event.fe_event_size = sizeof(fe_EventStruct);
  3512.         //event.x = firstP.h;
  3513.         //event.y = firstP.v;
  3514.         // Set the event coordinates to the button layer origin even though we have the
  3515.         // actual click coordinates, to be consistent with coordinates sent for mouse up
  3516.         // and click events on form buttons, when we don't have the click coordinates.
  3517.         event.x = CL_GetLayerXOrigin(formElem->layer);
  3518.         event.y = CL_GetLayerYOrigin(formElem->layer);
  3519.         event.which = 1; // which button is down (0 = none, 1 onwards starts from the left)
  3520.         event.modifiers = CMochaHacks::MochaModifiers(inMouseDown.macEvent.modifiers);
  3521.         event.data = 1; // number of clicks
  3522.  
  3523.         CL_DispatchEvent(compositor, &event);
  3524.     }
  3525. }
  3526.  
  3527. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  3528. //    CLayerKeyPressDispatchAttachment
  3529. //  Dispatches key events to layers.
  3530. // ╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤╤
  3531.  
  3532. CLayerKeyPressDispatchAttachment::CLayerKeyPressDispatchAttachment()
  3533.     :    LAttachment(msg_KeyPress, false)
  3534. {
  3535. }
  3536.  
  3537. void CLayerKeyPressDispatchAttachment::ExecuteSelf(
  3538.     MessageT            inMessage,
  3539.     void*                ioParam)
  3540. {
  3541.     Assert_(inMessage == msg_KeyPress);
  3542.     mOwner = dynamic_cast<LFormElement*>(GetOwnerHost());
  3543.     Assert_(mOwner != NULL);
  3544.     
  3545.     KeyPress(*(EventRecord*)ioParam);
  3546. }
  3547.  
  3548. // Dispatches a key event over a form. The event comes back to the front end through
  3549. // FE_HandleLayerEvent if javascript lets us have it.
  3550. void 
  3551. CLayerKeyPressDispatchAttachment::KeyPress(const EventRecord& inKeyEvent)
  3552. {
  3553.     Boolean executeHost = true;
  3554.     LO_FormElementStruct* formElem = (LO_FormElementStruct*)mOwner->GetLayoutElement();
  3555.     Assert_(formElem != NULL);
  3556.     
  3557.     // To determine if we need to dispatch the key event to layers or not, check
  3558.     // the context and its parents to see if they have handlers for any key events,
  3559.     // and check if the form element has a key handler.
  3560.     
  3561.     if (formElem->event_handler_present ||
  3562.         HasKeyEventCapture(mOwner->GetContext()))
  3563.     {
  3564.         // In order to determine which element gets the key event when the event comes back to
  3565.         // the front end, the form's parent layer gets key focus, and we pass in the layer
  3566.         // coordinates (i.e. image coordinates). Layers hands to the FE the parent layer and 
  3567.         // an event whose x,y are now the coordinates of the element relative to that layer.
  3568.         //
  3569.         // The layers are organized in a tree:
  3570.         //
  3571.         //               |---- _BACKGROUND
  3572.         //               |    
  3573.         //    _DOCUMENT--|---- _BODY ------- _CONTENT
  3574.         //               |    
  3575.         //               |---- LAYER1 ----|----_BACKGROUND
  3576.         //                              |
  3577.         //                              |----_CONTENT
  3578.         //                                |
  3579.         //                                |----FORM ELEMENT #1 LAYER (cutout)
  3580.         
  3581.         CL_Compositor* compositor = CL_GetLayerCompositor(formElem->layer);
  3582.         CL_GrabKeyEvents(compositor, CL_GetLayerParent(formElem->layer));
  3583.         
  3584.         if (compositor != NULL &&
  3585.             !CL_IsKeyEventGrabber(compositor, NULL))
  3586.         {
  3587.             CL_Event        event;
  3588.             fe_EventStruct    fe_event;
  3589.             
  3590.             Char16        theChar = inKeyEvent.message & charCodeMask;
  3591.             
  3592.             event.data = 0;
  3593.             switch (inKeyEvent.what)
  3594.             {
  3595.                 case keyDown:
  3596.                     event.type = CL_EVENT_KEY_DOWN;
  3597.                     break;
  3598.                 case autoKey:
  3599.                     event.type = CL_EVENT_KEY_DOWN;
  3600.                     event.data = 1; // repeating
  3601.                     break;
  3602.                 case keyUp:
  3603.                     event.type = CL_EVENT_KEY_UP;
  3604.                     break;
  3605.             }
  3606.             fe_event.event.macEvent = inKeyEvent;
  3607.             event.fe_event = (void *)&fe_event;
  3608.             event.fe_event_size = sizeof(fe_EventStruct);
  3609.             // event x, y must be form location in document coordinates.
  3610.             event.x = CL_GetLayerXOrigin(formElem->layer);
  3611.             event.y = CL_GetLayerYOrigin(formElem->layer);
  3612.             event.which = theChar;
  3613.             event.modifiers = CMochaHacks::MochaModifiers(inKeyEvent.modifiers);
  3614.  
  3615.             CL_DispatchEvent(compositor, &event);
  3616.             executeHost = false;
  3617.         }
  3618.     }
  3619.     else
  3620.     {
  3621.         if (inKeyEvent.what != keyUp)
  3622.         {
  3623.             CHTMLView::SetLastFormKeyPressDispatchTime(inKeyEvent.when);
  3624.             executeHost = true;
  3625.         }
  3626.     }
  3627.     mExecuteHost = executeHost;
  3628. }
  3629.