home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / medit.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  23.3 KB  |  827 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. // medit.cpp : implementation file
  20. //
  21.  
  22. #include "stdafx.h"
  23.  
  24. #include "medit.h"
  25. #include "fmabstra.h"
  26. #include "libevent.h"
  27.  
  28. #ifdef _DEBUG
  29. #undef THIS_FILE
  30. static char BASED_CODE THIS_FILE[] = __FILE__;
  31. #endif
  32.  
  33. #define EDIT_ID 25000
  34.  
  35. BEGIN_MESSAGE_MAP(CNetscapeEdit, CGenericEdit)
  36.     //{{AFX_MSG_MAP(CNetscapeEdit)
  37.     ON_WM_CHAR()
  38.     ON_WM_KEYDOWN()
  39.     ON_WM_KEYUP()
  40.     ON_WM_GETDLGCODE()
  41.     ON_WM_SETFOCUS()
  42.     ON_WM_KILLFOCUS()
  43.     ON_WM_CREATE()
  44.     //}}AFX_MSG_MAP
  45. END_MESSAGE_MAP()
  46.  
  47. IMPLEMENT_DYNAMIC(CNetscapeEdit, CGenericEdit)
  48.  
  49.  
  50. #ifndef _AFXDLL
  51. #define new DEBUG_NEW  // MSVC Debugging new...goes to regular new in release mode
  52. #endif
  53.  
  54. /////////////////////////////////////////////////////////////////////////////////////
  55. /////////////////////////////////////////////////////////////////////////////////////
  56. /////////////////////////////////////////////////////////////////////////////////////
  57. /////////////////////////////////////////////////////////////////////////////////////
  58. /////////////////////////////////////////////////////////////////////////////////////
  59. CNetscapeEdit::CNetscapeEdit()
  60. {
  61.     m_Context = NULL;
  62.     m_Form = NULL;
  63.     m_Submit = FALSE;
  64.     m_callBase = FALSE;
  65. #ifdef DEBUG
  66.     m_bOnCreateCalled = FALSE;
  67. #endif
  68. }
  69.  
  70. int CNetscapeEdit::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  71. {
  72. #ifdef DEBUG
  73.     m_bOnCreateCalled = TRUE;
  74. #endif
  75.  
  76.     if (CGenericEdit::OnCreate(lpCreateStruct) == -1)
  77.         return -1;
  78.     
  79.     return 0;
  80. }
  81.  
  82. //
  83. // Make sure we have a valid context
  84. // We might nto be in a form so don't barf if we don't have a form
  85. //
  86. BOOL CNetscapeEdit::SetContext(MWContext * context, LO_FormElementStruct * form)
  87. {
  88.  
  89.     if(!context)
  90.         return(FALSE);
  91.  
  92.     m_Context = context;
  93.     m_Form    = form;
  94.  
  95.     return(TRUE);
  96.  
  97. }
  98.  
  99. LO_FormElementStruct *CNetscapeEdit::GetFormElement()
  100. {
  101.     return(m_Form);
  102. }
  103.  
  104.  
  105. UINT CNetscapeEdit::OnGetDlgCode()
  106. {
  107.     return CEdit::OnGetDlgCode() | DLGC_WANTARROWS | DLGC_WANTALLKEYS;
  108. }
  109.  
  110. #ifdef XP_WIN16
  111. //
  112. // The creator of this form element should have created a segment for
  113. //   us to live in before we got here.  Tell Windows to use that 
  114. //   segment rather than the application's so that we don't run out of
  115. //   DGROUP space
  116. //
  117. BOOL CNetscapeEdit::PreCreateWindow( CREATESTRUCT& cs )
  118. {
  119.     ASSERT(m_hInstance);
  120.  
  121.     if(!m_hInstance)
  122.         return(TRUE);
  123.  
  124.     cs.hInstance = m_hInstance;
  125.     return(TRUE);
  126. }
  127. #endif  
  128.  
  129. //
  130. // Called when the 'submit' event has been processed
  131. //
  132. static void
  133. edit_submit_closure(MWContext * pContext, LO_Element * pEle, int32 event,
  134.                      void * pObj, ETEventStatus status)
  135. {
  136.     if(status != EVENT_OK || !pEle || !pContext)
  137.         return;
  138.     FE_SubmitInputElement(pContext, pEle);
  139. }
  140.  
  141. //
  142. // If the user has hit return load the url
  143. // Otherwise pass the key on to the base library
  144. //
  145. void CNetscapeEdit::OnChar(UINT nChar, UINT nCnt, UINT nFlags)
  146. {
  147.     BOOL bJsWantsEvent = m_Form->event_handler_present ||
  148.     LM_EventCaptureCheck(m_Context, EVENT_KEYDOWN | EVENT_KEYUP | EVENT_KEYPRESS);
  149.  
  150.     // Check if we generated this event.  If so, the base.  If not, call JS
  151.     if (m_callBase || !bJsWantsEvent) {
  152.  
  153.     if(nChar == '\r') {       // the user hit return
  154.  
  155. #ifdef DEBUG
  156.         if(!m_bOnCreateCalled) {
  157.             TRACE("Bug 88020 still present\n");
  158. #if defined (DEBUG_blythe) || defined(DEBUG_ftang) || defined(DEBUG_bstell) || defined(DEBUG_nhotta) || defined(DEBUG_jliu)
  159.             ASSERT(0);
  160. #endif
  161.         }
  162. #endif
  163.  
  164.         if(m_Submit) { // if we are the only element, return == submit
  165.  
  166.         // if the text is different throw out the old text and add the
  167.         //   new text into the layout structure
  168.         UpdateAndCheckForChange();
  169.  
  170.         // we are about to submit so tell libmocha about it first
  171.         //   do the submit in our closure if libmocha says its OK
  172.         JSEvent *event;
  173.         event = XP_NEW_ZAP(JSEvent);
  174.         event->type = EVENT_SUBMIT;
  175.         event->layer_id = m_Form->layer_id;
  176.  
  177.         ET_SendEvent(m_Context, (LO_Element *)m_Form, event, 
  178.                  edit_submit_closure, this);
  179.  
  180.         return;
  181.         } 
  182.         else {
  183.  
  184.         // we aren't auto-submitting, but the user still hit return
  185.         //   they prolly mean that we should check to see if we should
  186.         //   send a change event
  187.         if(!(GetStyle() & ES_MULTILINE))
  188.             UpdateAndCheckForChange();
  189.  
  190.         }
  191.  
  192.         } // wasn't the return key
  193.     
  194. //#ifdef  NO_TAB_NAVIGATION 
  195. /*
  196.     // let the CGenericView to handle the Tab, to step through Form elements
  197.     // and links, even links inside a form.
  198.     if(nChar == VK_TAB) {
  199.         // if the high order bit is set (i.e. its negative) the shift 
  200.         //   key is being held down
  201.         BOOL bShift = GetKeyState(VK_SHIFT) < 0 ? TRUE : FALSE;
  202.  
  203.         //  Determine our form element.
  204.         if(m_Context)   {
  205.             CFormElement *pMe = CFormElement::GetFormElement(ABSTRACTCX(m_Context), m_Form);
  206.             if(pMe) {
  207.                 //  We're handling tabbing between form elements.
  208.                 pMe->Tab(bShift);
  209.                 return;
  210.             }
  211.         }
  212.     }                                              
  213.     CEdit::OnChar(nChar, nCnt, nFlags);
  214. */
  215. //#endif    /* NO_TAB_NAVIGATION */
  216.  
  217.     CEdit::OnChar(nChar, nCnt, nFlags);
  218.     //If m_callBase is set, this event is a callback from a JS event and
  219.     //we have to update the value of the edit field to reflect new values.
  220.     if (bJsWantsEvent) {
  221.         UpdateEditField();
  222.     }
  223.     return;
  224.     }
  225.  
  226.     // Give the event to JS.  They'll call the base when they get back.
  227.     //
  228.     // Grab key events for this layer's parent.
  229.     CL_GrabKeyEvents(m_Context->compositor, CL_GetLayerParent(m_Form->layer));
  230.  
  231.     /* 
  232.      * If there's a compositor and someone has keyboard focus.
  233.      * Note that if noone has event focus, we don't really need
  234.      * to dispatch the event.
  235.      */
  236.     if (m_Context->compositor && 
  237.         !CL_IsKeyEventGrabber(m_Context->compositor, NULL)) {
  238.         CL_Event event;
  239.         fe_EventStruct fe_event;
  240.  
  241.     fe_event.fe_modifiers = nCnt;        
  242.     fe_event.nChar = nChar;        
  243.     fe_event.uFlags = nFlags;
  244.     fe_event.x = 1;
  245.  
  246.         event.type = CL_EVENT_KEY_DOWN;
  247.         event.which = nChar;
  248.     event.fe_event = (void *)&fe_event;
  249.     event.fe_event_size = sizeof(fe_EventStruct);
  250.         event.modifiers = (GetKeyState(VK_SHIFT) < 0 ? EVENT_SHIFT_MASK : 0) 
  251.             | (GetKeyState(VK_CONTROL) < 0 ? EVENT_CONTROL_MASK : 0) 
  252.             | (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0); 
  253.         event.x = CL_GetLayerXOrigin(m_Form->layer);
  254.         event.y = CL_GetLayerYOrigin(m_Form->layer);
  255.     event.data = nFlags>>14 & 1;//Bit represeting key repetition
  256.  
  257.         CL_DispatchEvent(m_Context->compositor, &event);
  258.     }
  259.  
  260. }
  261.  
  262. //
  263. // We just got focus --- maybe libmocha cares
  264. //
  265. void CNetscapeEdit::OnSetFocus(CWnd * pWnd)
  266. {
  267.     CEdit::OnSetFocus(pWnd);
  268.     if(m_Context && m_Form) {
  269.  
  270.         // set tab_focus to this element
  271.         CWinCX *pWinCX = WINCX(m_Context);
  272.  
  273. //    if ((LO_Element *)m_Form == pWinCX->getLastTabFocusElement())
  274. //        return;
  275.  
  276.         pWinCX->setFormElementTabFocus( (LO_Element *)m_Form );
  277.     CL_GrabKeyEvents(m_Context->compositor, CL_GetLayerParent(m_Form->layer));
  278.  
  279.         // send the event to libmocha --- do any further processing
  280.         //   in our closure routine
  281.     JSEvent *event;
  282.     event = XP_NEW_ZAP(JSEvent);
  283.     event->type = EVENT_FOCUS;
  284.     event->layer_id = m_Form->layer_id;
  285.  
  286.         ET_SendEvent(m_Context, (LO_Element *)m_Form, event, 
  287.                      NULL, this);
  288.     }
  289. }
  290.  
  291.  
  292. lo_FormElementTextData *CNetscapeEdit::GetTextData()    {
  293.     lo_FormElementTextData *pRetval = NULL;
  294.  
  295.     if(m_Form && m_Form->element_data)    {
  296.         switch(m_Form->element_data->type)    {
  297.             case FORM_TYPE_READONLY:
  298.                 break;
  299.             default:
  300.                 pRetval = &(m_Form->element_data->ele_text);
  301.                 break;
  302.         }
  303.     }
  304.  
  305.     return(pRetval);
  306. }
  307.  
  308.  
  309. //
  310. // We just lost focus --- maybe libmocha cares
  311. //
  312. // If the current value is different from the value that we have previously
  313. //   stored call SendOnChange() for this element before calling BlurElement();
  314. //
  315. void CNetscapeEdit::OnKillFocus(CWnd * pWnd)
  316. {
  317.     // Call base class and be done with the message processing first
  318.     CEdit::OnKillFocus(pWnd);
  319.     
  320.     // if the text is different throw out the old text and add the
  321.     //   new text into the layout structure
  322.     UpdateAndCheckForChange();
  323.  
  324.     // Send the blur message.
  325.     JSEvent *event;
  326.     event = XP_NEW_ZAP(JSEvent);
  327.     event->type = EVENT_BLUR;
  328.     event->layer_id = m_Form->layer_id;
  329.  
  330.     ET_SendEvent(m_Context, (LO_Element *) m_Form, event, 
  331.                  NULL, this);
  332.  
  333. }
  334.  
  335. void CNetscapeEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  336. {
  337.     if(m_Form->event_handler_present ||
  338.         LM_EventCaptureCheck(m_Context, EVENT_KEYDOWN | EVENT_KEYUP | EVENT_KEYPRESS)) {
  339.     UpdateEditField();
  340.     }
  341.     
  342.     CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
  343. }
  344.  
  345. void CNetscapeEdit::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  346. {
  347.     BOOL bJsWantsEvent = m_Form->event_handler_present ||
  348.     LM_EventCaptureCheck(m_Context, EVENT_KEYDOWN | EVENT_KEYUP | EVENT_KEYPRESS);
  349.  
  350.     // Check if we generated this event.  If so, the base.  If not, call JS
  351.     if (m_callBase || !bJsWantsEvent) {
  352.         CEdit::OnKeyUp(nChar, nRepCnt, nFlags);
  353.     return;
  354.     }
  355.  
  356.     //    Don't continue if this context is destroyed.
  357.     if(!m_Context || ABSTRACTCX(m_Context)->IsDestroyed())    {
  358.         return;
  359.     }
  360.     
  361.     // Grab key events for this layer's parent.
  362.     CL_GrabKeyEvents(m_Context->compositor, CL_GetLayerParent(m_Form->layer));
  363.  
  364.     /* 
  365.      * If there's a compositor and someone has keyboard focus.
  366.      * Note that if noone has event focus, we don't really need
  367.      * to dispatch the event.
  368.      */
  369.     if (m_Context->compositor && 
  370.         !CL_IsKeyEventGrabber(m_Context->compositor, NULL)) {
  371.         CL_Event event;
  372.         fe_EventStruct fe_event;
  373.     BYTE kbstate[256];
  374.     WORD asciiChar = 0;
  375.      
  376.     GetKeyboardState(kbstate);
  377. #ifdef WIN32    
  378.     ToAscii(nChar, nFlags & 0xff, kbstate, &asciiChar, 0);
  379. #else
  380.     ToAscii(nChar, nFlags & 0xff, kbstate, (DWORD*)&asciiChar, 0);
  381. #endif
  382.  
  383.     fe_event.fe_modifiers = nRepCnt;        
  384.     fe_event.nChar = nChar;        
  385.     fe_event.uFlags = nFlags;
  386.     fe_event.x = 1;
  387.         
  388.         event.type = CL_EVENT_KEY_UP;
  389.     event.fe_event = (void *)&fe_event;
  390.     event.fe_event_size = sizeof(fe_EventStruct);
  391.         event.which = asciiChar;
  392.         event.modifiers = (GetKeyState(VK_SHIFT) < 0 ? EVENT_SHIFT_MASK : 0) 
  393.             | (GetKeyState(VK_CONTROL) < 0 ? EVENT_CONTROL_MASK : 0) 
  394.             | (GetKeyState(VK_MENU) < 0 ? EVENT_ALT_MASK : 0); 
  395.         event.x = CL_GetLayerXOrigin(m_Form->layer);
  396.         event.y = CL_GetLayerYOrigin(m_Form->layer);
  397.         
  398.         CL_DispatchEvent(m_Context->compositor, &event);
  399.     }
  400. }
  401.  
  402. // This function returns true if it has to update the value of the field 
  403. // and false if it does not.
  404. XP_Bool CNetscapeEdit::UpdateEditField()
  405. {
  406.     // find out what the current text is
  407.     CString csText;
  408.     GetWindowText(csText);
  409.  
  410.     // if the text is different throw out the old text and add the
  411.     //   new text into the layout structure
  412.     lo_FormElementTextData * textData = GetTextData();
  413.  
  414.     if(!textData)
  415.     return FALSE;
  416.     
  417.     //
  418.     // This if() statement has two parts.  If there used to not be
  419.     //   any text and there is some now we will send a change message
  420.     //   Or, if there already was text but it was different we also
  421.     //   want to send a change event
  422.     if((!textData->current_text && !csText.IsEmpty()) ||
  423.        (textData->current_text && csText != (char *) textData->current_text))
  424.     {
  425.         LO_UpdateTextData(textData, (const char *)csText);
  426.         return TRUE;
  427.     }
  428.  
  429.     return FALSE;
  430. }
  431.  
  432. //
  433. // See if our value has changed since the last time we checked.
  434. //   If it has, send a change event to Mocha
  435. //
  436. void CNetscapeEdit::UpdateAndCheckForChange()
  437. {
  438.  
  439.     if(UpdateEditField())
  440.     {
  441.     JSEvent *event;
  442.     event = XP_NEW_ZAP(JSEvent);
  443.     event->type = EVENT_CHANGE;
  444.     event->layer_id = m_Form->layer_id;
  445.  
  446.     ET_SendEvent(m_Context, (LO_Element *) m_Form, event, 
  447.              NULL, this);
  448.     }
  449. }
  450.  
  451. void CNetscapeEdit::OnEditKeyEvent(CL_EventType type, UINT nChar, UINT nRepCnt, UINT nFlags) {
  452.     m_callBase = TRUE;
  453.     if (type == CL_EVENT_KEY_DOWN)
  454.     SendMessage(WM_CHAR, nChar, MAKELONG(nRepCnt, nFlags));
  455.     else if (type == CL_EVENT_KEY_UP)
  456.     SendMessage(WM_KEYUP, nChar, MAKELONG(nRepCnt, nFlags));
  457.     m_callBase = FALSE;
  458. }
  459.  
  460. //////////////////////////////////////////////////////////////////////////
  461. //////////////////////////////////////////////////////////////////////////
  462.  
  463. BEGIN_MESSAGE_MAP(CMochaListBox, CListBox)
  464.     //{{AFX_MSG_MAP(CMochaListBox)
  465.     ON_WM_SETFOCUS()
  466.     ON_WM_KILLFOCUS()
  467.     ON_WM_CHAR()
  468. #if defined(MSVC4)
  469.     ON_CONTROL_REFLECT(LBN_SELCHANGE, OnSelChange)
  470. #endif    // MSVC4
  471.     //}}AFX_MSG_MAP
  472. END_MESSAGE_MAP()
  473.  
  474. void CMochaListBox::SetContext(MWContext * context, LO_FormElementStruct * form)
  475. {
  476.     m_Context = context;
  477.     m_Form    = form;
  478. }
  479.  
  480. void CMochaListBox::OnSetFocus(CWnd * pWnd)
  481. {
  482.     CListBox::OnSetFocus(pWnd); 
  483.  
  484.     // set tab_focus to this element
  485.     CWinCX *pWinCX = WINCX(m_Context);
  486. //    if ((LO_Element *)m_Form == pWinCX->getLastTabFocusElement())
  487. //    return;
  488.     pWinCX->setFormElementTabFocus( (LO_Element *)m_Form );
  489.     CL_GrabKeyEvents(m_Context->compositor, CL_GetLayerParent(m_Form->layer));
  490.  
  491.     JSEvent *event;
  492.     event = XP_NEW_ZAP(JSEvent);
  493.     event->type = EVENT_FOCUS;
  494.     event->layer_id = m_Form->layer_id;
  495.  
  496.     ET_SendEvent(m_Context, (LO_Element *) m_Form, event, 
  497.                  NULL, this);
  498. }
  499.  
  500. //
  501. // If the current value is different from the value that we have previously
  502. //   stored call SendOnChange() for this element before calling BlurElement();
  503. //
  504. void CMochaListBox::CheckForChange()
  505. {
  506.  
  507.     // get the base form element
  508.     lo_FormElementSelectData     * pSelectData     = NULL;
  509.     pSelectData = (lo_FormElementSelectData *) m_Form->element_data;
  510.     if(!pSelectData)
  511.         return;
  512.  
  513.     // get the option state
  514.     lo_FormElementOptionData     * pOptionData     = NULL;
  515.     pOptionData = (lo_FormElementOptionData *) pSelectData->options;
  516.     if(!pOptionData)
  517.         return;
  518.  
  519.     BOOL bChanged = FALSE;
  520.     for(int i = 0; i < pSelectData->option_cnt; i++) {
  521.  
  522.         int iIsSelected = GetSel(i);
  523.         
  524.         // see if we have found a selection which is not the current
  525.         //   selection
  526.         if(pOptionData[i].selected && (iIsSelected < 1)) {
  527.             pOptionData[i].selected = FALSE;
  528.             bChanged = TRUE;
  529.         }
  530.  
  531.         // see if item #i has gone from being unselected to being selected
  532.         if(!pOptionData[i].selected && (iIsSelected > 0)) {
  533.             pOptionData[i].selected = TRUE;
  534.             bChanged = TRUE;
  535.         }
  536.  
  537.     }
  538.  
  539.     // only send change message if things have changed
  540.     if(bChanged) {
  541.     JSEvent *event;
  542.     event = XP_NEW_ZAP(JSEvent);
  543.     event->type = EVENT_CHANGE;
  544.     event->layer_id = m_Form->layer_id;
  545.  
  546.         ET_SendEvent(m_Context, (LO_Element *) m_Form, event,
  547.                  NULL, this);
  548.     }
  549.  
  550. }
  551.  
  552. //
  553. // We just lost focus --- maybe libmocha cares
  554. //
  555. void CMochaListBox::OnKillFocus(CWnd * pWnd)
  556. {
  557.     // let MFC do its thing
  558.     CListBox::OnKillFocus(pWnd);
  559.     
  560.     // see if we have changed and fire a change event if necessary
  561.     CheckForChange();
  562.  
  563.     // we have lost focus so whether the value changed or not we 
  564.     //   should tell the mocha library
  565.     JSEvent *event;
  566.     event = XP_NEW_ZAP(JSEvent);
  567.     event->type = EVENT_BLUR;
  568.     event->layer_id = m_Form->layer_id;
  569.  
  570.     ET_SendEvent(m_Context, (LO_Element *) m_Form, event, NULL, this);
  571. }
  572.  
  573. #if defined(MSVC4)
  574. void CMochaListBox::OnSelChange() 
  575. {
  576.     // The OnKillFocus() handler takes care of leaving a control, but Mocha
  577.     // also wants to know about a selection change in a combobox or listbox.
  578.     CheckForChange();
  579. }
  580. #else
  581. // In Win16 and MFC prior to 4.0, only the parent of a control could get
  582. // notification messages.
  583. BOOL CMochaListBox::OnChildNotify(UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  584. {
  585.     if (nMsg == WM_COMMAND) {
  586.         if (GET_WM_COMMAND_CMD(wParam, lParam) == LBN_SELCHANGE) {
  587.             CheckForChange();
  588.             return TRUE;
  589.         }
  590.     }
  591.  
  592.     return CListBox::OnChildNotify(nMsg, wParam, lParam, pResult);
  593. }
  594. #endif
  595.  
  596.  
  597. //////////////////////////////////////////////////////////////////////////
  598. //////////////////////////////////////////////////////////////////////////
  599.  
  600. BEGIN_MESSAGE_MAP(CMochaComboBox, CComboBox)
  601.     //{{AFX_MSG_MAP(CMochaComboBox)
  602.     ON_WM_SETFOCUS()
  603.     ON_WM_KILLFOCUS()
  604.     ON_WM_CHAR()
  605. #if defined(MSVC4)
  606.     ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelChange)
  607. #endif    // MSVC4
  608.     //}}AFX_MSG_MAP
  609. END_MESSAGE_MAP()
  610.  
  611. void CMochaComboBox::SetContext(MWContext * context, LO_FormElementStruct * form)
  612. {
  613.     m_Context = context;
  614.     m_Form    = form;
  615. }
  616.  
  617. void CMochaComboBox::OnSetFocus(CWnd * pWnd)
  618. {
  619.     CComboBox::OnSetFocus(pWnd); 
  620.  
  621.     // set tab_focus to this element
  622.     CWinCX *pWinCX = WINCX(m_Context);
  623. //    if ((LO_Element *)m_Form == pWinCX->getLastTabFocusElement())
  624. //    return;
  625.     pWinCX->setFormElementTabFocus( (LO_Element *)m_Form );
  626.     CL_GrabKeyEvents(m_Context->compositor, CL_GetLayerParent(m_Form->layer));
  627.  
  628.     JSEvent *event;
  629.     event = XP_NEW_ZAP(JSEvent);
  630.     event->type = EVENT_FOCUS;
  631.     event->layer_id = m_Form->layer_id;
  632.  
  633.     ET_SendEvent(m_Context, (LO_Element *) m_Form, event, NULL, this);
  634. }
  635.  
  636. //
  637. // If the current value is different from the value that we have previously
  638. //   stored call SendOnChange() for this element before calling BlurElement();
  639. //
  640. void CMochaComboBox::CheckForChange()
  641. {
  642.  
  643.     // get the base form element
  644.     lo_FormElementSelectData     * pSelectData     = NULL;
  645.     pSelectData = (lo_FormElementSelectData *) m_Form->element_data;
  646.     if(!pSelectData)
  647.         return;
  648.  
  649.     // get the option state
  650.     lo_FormElementOptionData     * pOptionData     = NULL;
  651.     pOptionData = (lo_FormElementOptionData *) pSelectData->options;
  652.     if(!pOptionData) 
  653.         return;
  654.  
  655.     // index of single selection
  656.     int iCurSelection = GetCurSel();  
  657.     if(iCurSelection == LB_ERR) 
  658.         return;
  659.  
  660.     BOOL bChanged = FALSE;
  661.     for(int i = 0; i < pSelectData->option_cnt; i++) {
  662.         
  663.         // see if we have found a selection which is not the current
  664.         //   selection
  665.         if(pOptionData[i].selected && i != iCurSelection) {
  666.             pOptionData[i].selected = FALSE;
  667.             bChanged = TRUE;
  668.         }
  669.  
  670.         // see if item #i has gone from being unselected to being selected
  671.         if(!pOptionData[i].selected && i == iCurSelection) {
  672.             pOptionData[i].selected = TRUE;
  673.             bChanged = TRUE;
  674.         }
  675.  
  676.     }
  677.  
  678.     // only send change message if things have changed
  679.     if(bChanged) {
  680.     JSEvent *event;
  681.     event = XP_NEW_ZAP(JSEvent);
  682.     event->type = EVENT_CHANGE;
  683.     event->layer_id = m_Form->layer_id;
  684.  
  685.         ET_SendEvent(m_Context, (LO_Element *) m_Form, event, 
  686.                      NULL, this);
  687.     }
  688.  
  689. }
  690.  
  691. //
  692. // We just lost focus --- maybe libmocha cares
  693. //
  694. void CMochaComboBox::OnKillFocus(CWnd * pWnd)
  695. {
  696.     CComboBox::OnKillFocus(pWnd);
  697.     
  698.     CheckForChange();
  699.  
  700.     // we have lost focus so whether the value changed or not we should tell the
  701.     //   mocha library
  702.     JSEvent *event;
  703.     event = XP_NEW_ZAP(JSEvent);
  704.     event->type = EVENT_BLUR;
  705.     event->layer_id = m_Form->layer_id;
  706.  
  707.     ET_SendEvent(m_Context, (LO_Element *) m_Form, event, NULL, this);
  708. }
  709.  
  710. #if defined(MSVC4)
  711. void CMochaComboBox::OnSelChange() 
  712. {
  713.     // The OnKillFocus() handler takes care of leaving a control, but Mocha
  714.     // also wants to know about a selection change in a combobox or listbox.
  715.     CheckForChange();
  716. }
  717. #else
  718. // In Win16 and MFC prior to 4.0, only the parent of a control could get
  719. // notification messages.
  720. BOOL CMochaComboBox::OnChildNotify(UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
  721. {
  722.     if (nMsg == WM_COMMAND) {
  723.         if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
  724.             CheckForChange();
  725.             return TRUE;
  726.         }
  727.     }
  728.  
  729.     return CComboBox::OnChildNotify(nMsg, wParam, lParam, pResult);
  730. }
  731. #endif    // MSVC4
  732.  
  733.  
  734. BOOL FirstCharMatch( char * searchFor, lo_FormElementSelectData  *pSelectData, int oldSel, int *newSel  )
  735. {
  736.     char    *pCurrent = NULL;
  737.     int        ii;
  738.     
  739.     if( searchFor == NULL ) 
  740.         return( FALSE);
  741.  
  742.  
  743.     // get the option state
  744.     lo_FormElementOptionData     * pOptionData     = NULL;
  745.      pOptionData = (lo_FormElementOptionData *) pSelectData->options;
  746.     if(!pOptionData) 
  747.         return(FALSE);
  748.  
  749.     // index of single selection
  750.     BOOL bChanged = FALSE;
  751.     ii = oldSel + 1;        // start with current selection.
  752.     if( ii == pSelectData->option_cnt )
  753.         ii = 0;                // fold back to the begining of the list.
  754.     while( ! bChanged && ii != oldSel ) {
  755.         
  756.         pCurrent = (char *)pOptionData[ii].text_value;
  757.         if( pCurrent && (toupper(*pCurrent) == toupper(* searchFor)) ) {   // todo multi byte
  758.             bChanged = TRUE;
  759.             *newSel = ii;
  760.             break;                // ii is the index to select.
  761.         }
  762.  
  763.         ii++;
  764.         if( ii == pSelectData->option_cnt )
  765.             ii = 0;                // fold back to the begining of the list.
  766.     }
  767.  
  768.     return( bChanged );
  769. }
  770.  
  771. void CMochaComboBox::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
  772. {
  773.     CComboBox::OnChar(nChar, nRepCnt, nFlags);  // call base class 
  774.  
  775.     // refer to void CFormSelectOne::CreateWidget() in fmdelone.cpp
  776.     // combo boxes are created with CBS_OWNERDRAWFIXED, for i18n support.
  777.     // First-char-searching in list doesn't work any more.
  778.     // Need to do it here.
  779.     
  780.     int        newSel;
  781.     char  searchFor[2];
  782.     searchFor[0] = nChar;
  783.     searchFor[1] = '\0';
  784.  
  785.     // get the base form element
  786.     lo_FormElementSelectData     * pSelectData     = NULL;
  787.     pSelectData = (lo_FormElementSelectData *) m_Form->element_data;
  788.     if(!pSelectData)
  789.         return;
  790.  
  791.     int iCurSelection = GetCurSel();  
  792.     if(iCurSelection == LB_ERR) 
  793.         return;
  794.  
  795.     BOOL changed = FirstCharMatch( searchFor, pSelectData, iCurSelection, &newSel );
  796.     if( changed )
  797.         CComboBox::SetCurSel( newSel );
  798.  
  799. }
  800.  
  801. void CMochaListBox::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
  802. {
  803.     
  804.     CListBox::OnChar(nChar, nRepCnt, nFlags);
  805.     int        newSel;
  806.     char  searchFor[2];
  807.     searchFor[0] = nChar;
  808.     searchFor[1] = '\0';
  809.  
  810.     // get the base form element
  811.     lo_FormElementSelectData     * pSelectData     = NULL;
  812.     pSelectData = (lo_FormElementSelectData *) m_Form->element_data;
  813.     if(!pSelectData)
  814.         return;
  815.  
  816.     int iCurSelection = GetCurSel();  
  817.     if(iCurSelection == LB_ERR) 
  818.         return;
  819.  
  820.     BOOL changed = FirstCharMatch( searchFor, pSelectData, iCurSelection, &newSel );
  821.     if( changed ) {
  822.         CListBox::SetSel( -1, FALSE );    // clear all selections.
  823.         CListBox::SetSel( newSel );
  824.     }
  825.  
  826. }
  827.