mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 22:25:30 +00:00
898 lines
27 KiB
C++
Executable File
898 lines
27 KiB
C++
Executable File
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "fmabstra.h"
|
|
#include "fmbutton.h"
|
|
#include "fmfile.h"
|
|
#include "fmradio.h"
|
|
#include "fmselmul.h"
|
|
#include "fmselone.h"
|
|
#include "fmtext.h"
|
|
#include "fmtxarea.h"
|
|
#ifdef ENDER
|
|
#include "fmhtml.h" //ENDER
|
|
#endif
|
|
#include "fmrdonly.h"
|
|
|
|
#include "windowsx.h"
|
|
|
|
// Class to define common base functionality of all form elements
|
|
// in the front end in an object oriented manner.
|
|
|
|
// Static control ID unique for each instance of this class.
|
|
UINT CFormElement::m_uNextControlID = 0;
|
|
|
|
// Function to create and/or retrieve a CFormElement from
|
|
// a layout form struct.
|
|
CFormElement *CFormElement::GetFormElement(CAbstractCX *pCX, LO_FormElementStruct *pFormElement)
|
|
{
|
|
CFormElement *pRetval = NULL;
|
|
|
|
// Ensure we have enough information with which to continue.
|
|
if(pCX == NULL) {
|
|
return(pRetval);
|
|
}
|
|
else if(pFormElement == NULL) {
|
|
return(pRetval);
|
|
}
|
|
|
|
pRetval = GetFormElement(pCX, pFormElement->element_data);
|
|
|
|
// Look at the form element structure to see if one already exists.
|
|
if(pRetval == NULL && pFormElement->element_data != NULL) {
|
|
// We need to create a new form class.
|
|
TRY {
|
|
switch(pFormElement->element_data->type) {
|
|
case FORM_TYPE_TEXT:
|
|
case FORM_TYPE_PASSWORD:
|
|
pRetval = (CFormElement *)new CFormText();
|
|
break;
|
|
case FORM_TYPE_CHECKBOX:
|
|
case FORM_TYPE_RADIO:
|
|
pRetval = (CFormElement *)new CFormRadio();
|
|
break;
|
|
case FORM_TYPE_BUTTON:
|
|
case FORM_TYPE_RESET:
|
|
case FORM_TYPE_SUBMIT:
|
|
pRetval = (CFormElement *)new CFormButton();
|
|
break;
|
|
case FORM_TYPE_SELECT_ONE:
|
|
pRetval = (CFormElement *)new CFormSelectOne();
|
|
break;
|
|
case FORM_TYPE_SELECT_MULT:
|
|
pRetval = (CFormElement *)new CFormSelectMult();
|
|
break;
|
|
case FORM_TYPE_TEXTAREA:
|
|
pRetval = (CFormElement *)new CFormTextarea();
|
|
break;
|
|
#ifdef ENDER
|
|
case FORM_TYPE_HTMLAREA:
|
|
pRetval = (CFormElement *)new CFormHtmlarea();
|
|
break;
|
|
#endif
|
|
|
|
case FORM_TYPE_FILE:
|
|
pRetval = (CFormElement *)new CFormFile();
|
|
break;
|
|
case FORM_TYPE_READONLY:
|
|
pRetval = (CFormElement *)new CFormReadOnly();
|
|
break;
|
|
default:
|
|
// What exactly are we doing here?
|
|
TRACE("Unimplemented form type (%d) requested.\n", (int)pFormElement->element_data->type);
|
|
pRetval = NULL;
|
|
break;
|
|
}
|
|
}
|
|
CATCH(CException, e) {
|
|
pRetval = NULL;
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
// Set up and/or update the relevant information in the class.
|
|
if(pRetval != NULL) {
|
|
pRetval->SetContext(pCX);
|
|
pRetval->SetElement(pFormElement);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
// Only retrieve the form element class, do not create.
|
|
CFormElement *CFormElement::GetFormElement(CAbstractCX *pCX, LO_FormElementData *pFormData)
|
|
{
|
|
CFormElement *pRetval = NULL;
|
|
|
|
// Ensure we have enough information with which to continue.
|
|
if(pFormData == NULL) {
|
|
return(pRetval);
|
|
}
|
|
else if(pFormData->type == FORM_TYPE_KEYGEN) {
|
|
// Doesn't have minimal data.
|
|
return(pRetval);
|
|
}
|
|
|
|
// Look at the form element structure to see if one already exists.
|
|
if(pFormData->ele_minimal.FE_Data != NULL) {
|
|
// Already there, return it.
|
|
pRetval = (CFormElement *)pFormData->ele_minimal.FE_Data;
|
|
}
|
|
|
|
// Set up and/or update the relevant information in the class, if possible.
|
|
if(pCX && pRetval != NULL) {
|
|
pRetval->SetContext(pCX);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
|
|
// Construction simply clears all members.
|
|
CFormElement::CFormElement()
|
|
{
|
|
// No LO form element.
|
|
SetElement(NULL);
|
|
|
|
// No context.
|
|
SetContext(NULL);
|
|
|
|
// By default, we have no widget allocated, and we are using default data.
|
|
m_bUseCurrentData = FALSE;
|
|
m_bWidgetPresent = FALSE;
|
|
}
|
|
|
|
// Destruction cleans out all members.
|
|
CFormElement::~CFormElement()
|
|
{
|
|
// No LO form anymore.
|
|
// FreeFormElement must be used to delete the class.
|
|
// This assert knows that FreeFormElement calls SetElement(NULL).
|
|
ASSERT(GetElement() == NULL);
|
|
|
|
// No context anymore.
|
|
SetContext(NULL);
|
|
}
|
|
|
|
// How to set the LO form element.
|
|
// This may change during the lifetime of an instance, so use this to update all referencing values.
|
|
void CFormElement::SetElement(LO_FormElementStruct *pFormElement)
|
|
{
|
|
// Simply copy.
|
|
m_pFormElement = pFormElement;
|
|
|
|
// Ensure its FE_Data points to us.
|
|
if(GetElementMinimalData()) {
|
|
GetElementMinimalData()->FE_Data = (void *)this;
|
|
}
|
|
}
|
|
|
|
// Return the owning LO element.
|
|
LO_FormElementStruct *CFormElement::GetElement() const
|
|
{
|
|
return(m_pFormElement);
|
|
}
|
|
|
|
LO_FormElementData *CFormElement::GetElementData() const
|
|
{
|
|
LO_FormElementData *pRetval = NULL;
|
|
if(GetElement()) {
|
|
pRetval = GetElement()->element_data;
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
// Careful when using, may return incorrect structure if not correct
|
|
// form type.
|
|
lo_FormElementTextData *CFormElement::GetElementTextData() const
|
|
{
|
|
lo_FormElementTextData *pRetval = NULL;
|
|
if(GetElementData()) {
|
|
ASSERT(
|
|
GetElementData()->type == FORM_TYPE_TEXT ||
|
|
GetElementData()->type == FORM_TYPE_PASSWORD ||
|
|
GetElementData()->type == FORM_TYPE_FILE
|
|
);
|
|
pRetval = &(GetElementData()->ele_text);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
// Careful when using, may return incorrect structure if not correct
|
|
// form type.
|
|
lo_FormElementTextareaData *CFormElement::GetElementTextareaData() const
|
|
{
|
|
lo_FormElementTextareaData *pRetval = NULL;
|
|
if(GetElementData()) {
|
|
ASSERT(
|
|
GetElementData()->type == FORM_TYPE_TEXTAREA
|
|
);
|
|
pRetval = &(GetElementData()->ele_textarea);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
|
|
#ifdef ENDER
|
|
// Careful when using, may return incorrect structure if not correct
|
|
// form type.
|
|
lo_FormElementTextareaData *CFormElement::GetElementHtmlareaData() const
|
|
{
|
|
lo_FormElementTextareaData *pRetval = NULL;
|
|
if(GetElementData()) {
|
|
ASSERT(
|
|
GetElementData()->type == FORM_TYPE_HTMLAREA
|
|
);
|
|
pRetval = &(GetElementData()->ele_textarea);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
#endif
|
|
|
|
// Always safe to use.
|
|
lo_FormElementMinimalData *CFormElement::GetElementMinimalData() const
|
|
{
|
|
lo_FormElementMinimalData *pRetval = NULL;
|
|
if(GetElementData()) {
|
|
pRetval = &(GetElementData()->ele_minimal);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
// Careful when using, may return incorrect structure if not correct
|
|
// form type.
|
|
lo_FormElementToggleData *CFormElement::GetElementToggleData() const
|
|
{
|
|
lo_FormElementToggleData *pRetval = NULL;
|
|
if(GetElementData()) {
|
|
ASSERT(
|
|
GetElementData()->type == FORM_TYPE_RADIO ||
|
|
GetElementData()->type == FORM_TYPE_CHECKBOX
|
|
);
|
|
pRetval = &(GetElementData()->ele_toggle);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
// Careful when using, may return incorrect structure if not correct
|
|
// form type.
|
|
lo_FormElementSelectData *CFormElement::GetElementSelectData() const
|
|
{
|
|
lo_FormElementSelectData *pRetval = NULL;
|
|
if(GetElementData()) {
|
|
ASSERT(
|
|
GetElementData()->type == FORM_TYPE_SELECT_ONE ||
|
|
GetElementData()->type == FORM_TYPE_SELECT_MULT
|
|
);
|
|
pRetval = &(GetElementData()->ele_select);
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
void *CFormElement::GetElementFEData() const
|
|
{
|
|
void *pRetval = NULL;
|
|
if(GetElementMinimalData()) {
|
|
pRetval = GetElementMinimalData()->FE_Data;
|
|
}
|
|
|
|
return(pRetval);
|
|
}
|
|
|
|
// Set the owning context.
|
|
void CFormElement::SetContext(CAbstractCX *pCX)
|
|
{
|
|
// Simply copy.
|
|
m_pCX = pCX;
|
|
|
|
// If we're printing, we know (or assume), that
|
|
// any form data has been set to the last context's current
|
|
// state, so we don't want to just throw it all away by
|
|
// calling UseDefaultData in GetFormElementInfo.
|
|
// This does not apply to metafiles until they serialize the form data also.
|
|
if(GetContext() && GetContext()->IsPrintContext()) {
|
|
m_bUseCurrentData = TRUE;
|
|
}
|
|
}
|
|
|
|
// Return the owning context.
|
|
CAbstractCX *CFormElement::GetContext() const
|
|
{
|
|
return(m_pCX);
|
|
}
|
|
|
|
// Update the coordinates of display from the layout
|
|
// element and display if need be.
|
|
void CFormElement::DisplayFormElement(LTRB& Rect)
|
|
{
|
|
// Class which need to handle this should know how in the derivation.
|
|
// Call the base class after your implementation.
|
|
|
|
// In any event, make sure that the widget is visible.
|
|
// Again, call the base class after your implementation.
|
|
HWND hRaw = GetRaw();
|
|
if(hRaw) {
|
|
BOOL bVisible = ::IsWindowVisible(hRaw);
|
|
|
|
/* If window is visible, but should be invisible, then make it disappear */
|
|
if (m_pFormElement->ele_attrmask & LO_ELE_INVISIBLE) {
|
|
if (bVisible) {
|
|
::ShowWindow(hRaw, SW_HIDE);
|
|
}
|
|
}
|
|
/* If window is invisible, but should be visible, then draw it */
|
|
else {
|
|
if (!bVisible) {
|
|
::ShowWindow(hRaw, SW_SHOWNA);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is called by LAYOUT when a form element should interpret a newline as
|
|
// hitting the submit button in a form. This is done mainly on single line
|
|
// edit fields.
|
|
void CFormElement::FormTextIsSubmit()
|
|
{
|
|
HWND hRaw = GetRaw();
|
|
if(hRaw) {
|
|
CNetscapeEdit *pEdit = (CNetscapeEdit *)CEdit::FromHandlePermanent(hRaw);
|
|
pEdit->SetSubmit(TRUE);
|
|
}
|
|
}
|
|
|
|
// Free the form element.
|
|
// The form data is passed in, because layout has already
|
|
// disassociated it with the form struct.
|
|
// No need to override really....
|
|
void CFormElement::FreeFormElement(LO_FormElementData *pFormData)
|
|
{
|
|
// Cause all widgets to be deallocated if not already.
|
|
DestroyWidget();
|
|
|
|
// NOTE: m_pFormElement at this point can not be guaranteed to be valid.
|
|
// Do not use it or members which access it.
|
|
SetElement(NULL);
|
|
|
|
// We're done.
|
|
// Set the FE data to be null, since we're deleting it.
|
|
if(pFormData) {
|
|
pFormData->ele_minimal.FE_Data = NULL;
|
|
}
|
|
delete this;
|
|
}
|
|
|
|
// Layout calls this to determine the size of a form element.
|
|
void CFormElement::GetFormElementInfo()
|
|
{
|
|
// Avoid creating lots of widgets, see if we already have one.
|
|
if(IsWidgetPresent() == FALSE) {
|
|
// Not present, we have to create it on our own.
|
|
// Be sure to check ShouldUseCurrentData to see if you should use the
|
|
// current or default data from the Layout struct when
|
|
// filling in the information (however, the actual size
|
|
// calculation of the widget should be done with default
|
|
// data always).
|
|
CreateWidget();
|
|
|
|
if(ShouldUseCurrentData()) {
|
|
UseCurrentData();
|
|
}
|
|
else {
|
|
UseDefaultData();
|
|
|
|
// First time creations should by default fill in the
|
|
// current data with the default data, so that
|
|
// MOCHA has some data to play with.
|
|
UpdateCurrentData();
|
|
}
|
|
}
|
|
|
|
// A widget should be present, so that we can check cached
|
|
// size values in the future.
|
|
m_bWidgetPresent = TRUE;
|
|
|
|
// Get widget information into the layout structure.
|
|
FillSizeInfo();
|
|
}
|
|
|
|
// Retrieve the data from the form element, and possibly
|
|
// delete the form element widget.
|
|
void CFormElement::GetFormElementValue(BOOL bTurnOff)
|
|
{
|
|
// Collect data from the widgets.
|
|
UpdateCurrentData();
|
|
|
|
if(bTurnOff) {
|
|
// If we have to turn off, then mark that we should use current data in the future
|
|
// when we have to recreate ourselves, and mark that our widget is gone.
|
|
m_bUseCurrentData = TRUE;
|
|
m_bWidgetPresent = FALSE;
|
|
|
|
// Get rid of the widgets.
|
|
DestroyWidget();
|
|
}
|
|
}
|
|
|
|
// Reset the form element to its default value.
|
|
void CFormElement::ResetFormElement()
|
|
{
|
|
// Just use the default data in the LAYOUT struct.
|
|
UseDefaultData();
|
|
|
|
// Update (write over) any modified current (now old) data.
|
|
UpdateCurrentData();
|
|
}
|
|
|
|
// Toggle the form element's state.
|
|
void CFormElement::SetFormElementToggle(BOOL bState)
|
|
{
|
|
HWND hRaw = GetRaw();
|
|
if(hRaw) {
|
|
// Set state if not already reflected.
|
|
if(Button_GetCheck(hRaw) != bState) {
|
|
Button_SetCheck(hRaw, bState);
|
|
}
|
|
UpdateCurrentData();
|
|
}
|
|
}
|
|
|
|
// Give focus to the form element.
|
|
void CFormElement::FocusInputElement()
|
|
{
|
|
HWND hRaw = GetRaw();
|
|
if(hRaw && GetContext() && GetElement()) {
|
|
FEU_MakeElementVisible(GetContext()->GetContext(), (LO_Any *)GetElement());
|
|
::SetFocus(hRaw);
|
|
}
|
|
}
|
|
|
|
// Do not give focus to the form element.
|
|
void CFormElement::BlurInputElement()
|
|
{
|
|
HWND hRaw = GetRaw();
|
|
if(hRaw) {
|
|
// Only blur focus if we already have it and we can give it to our parent.
|
|
if(hRaw == ::GetFocus() && ::GetParent(hRaw)) {
|
|
::SetFocus(::GetParent(hRaw));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Select the form element's data.
|
|
void CFormElement::SelectInputElement()
|
|
{
|
|
HWND hRaw = GetRaw();
|
|
if(hRaw) {
|
|
Edit_SetSel(hRaw, 0, -1);
|
|
}
|
|
}
|
|
|
|
// Change the value of the form element.
|
|
void CFormElement::ChangeInputElement()
|
|
{
|
|
// All we really need to do is update ourselves so that we reflect the
|
|
// current data.
|
|
UseCurrentData();
|
|
|
|
if(GetElementMinimalData()) {
|
|
if(GetElementMinimalData()->type == FORM_TYPE_RADIO) {
|
|
if(GetContext() && GetContext()->GetContext()) {
|
|
lo_FormElementToggleData * tog_data;
|
|
tog_data = (lo_FormElementToggleData *) GetElement()->element_data;
|
|
if(tog_data->toggled) {
|
|
// If we are supposed to be on, turn off everyone else
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
LO_FormRadioSet(GetContext()->GetDocumentContext(), GetElement());
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enable the form element (Editable to the user).
|
|
void CFormElement::EnableInputElement()
|
|
{
|
|
HWND hRaw = GetRaw();
|
|
if(hRaw) {
|
|
::EnableWindow(hRaw, TRUE);
|
|
}
|
|
}
|
|
|
|
// Disable the form element (Read only to the user).
|
|
void CFormElement::DisableInputElement()
|
|
{
|
|
HWND hRaw = GetRaw();
|
|
if(hRaw) {
|
|
::EnableWindow(hRaw, FALSE);
|
|
}
|
|
}
|
|
|
|
// Return a unique control ID each time called.
|
|
UINT CFormElement::GetDynamicControlID()
|
|
{
|
|
// Handle wrap.
|
|
if(m_uNextControlID == 0) {
|
|
m_uNextControlID = DYNAMIC_RESOURCE;
|
|
}
|
|
|
|
return(m_uNextControlID++);
|
|
}
|
|
|
|
#ifdef XP_WIN16
|
|
// Call this to get the segment for edit fields under 16 bit windows.
|
|
// This is so they are taken out of the precious DGROUP.
|
|
HINSTANCE CFormElement::GetSegment()
|
|
{
|
|
HINSTANCE hRetval = NULL;
|
|
|
|
// Only if we have a context, and it has widgets.
|
|
if(GetContext() && GetContext()->IsWindowContext()) {
|
|
CPaneCX *pPaneCX = VOID2CX(GetContext(), CPaneCX);
|
|
hRetval = pPaneCX->GetSegment();
|
|
}
|
|
|
|
return(hRetval);
|
|
}
|
|
#endif
|
|
|
|
extern "C" void FE_RaiseWindow(MWContext *pContext) {
|
|
// Make sure this is possible.
|
|
if(pContext && ABSTRACTCX(pContext) && !ABSTRACTCX(pContext)->IsDestroyed()
|
|
&& ABSTRACTCX(pContext)->IsFrameContext() && PANECX(pContext)->GetPane()
|
|
&& WINCX(pContext)->GetFrame() && WINCX(pContext)->GetFrame()->GetFrameWnd()) {
|
|
CWinCX *pWinCX = WINCX(pContext);
|
|
CFrameWnd *pFrameWnd = pWinCX->GetFrame()->GetFrameWnd();
|
|
|
|
// Bring the frame to the top first.
|
|
if(pFrameWnd->IsIconic()) {
|
|
pFrameWnd->ShowWindow(SW_RESTORE);
|
|
}
|
|
::SetWindowPos(pFrameWnd->GetSafeHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
|
#ifdef XP_WIN32
|
|
pFrameWnd->SetForegroundWindow();
|
|
#endif
|
|
|
|
// Now, set focus to the view being raised,
|
|
// possibly a frame cell.
|
|
pWinCX->
|
|
GetFrame()->
|
|
GetFrameWnd()->
|
|
SetActiveView(pWinCX->GetView(), TRUE);
|
|
}
|
|
}
|
|
|
|
extern "C" void FE_LowerWindow(MWContext *pContext) {
|
|
// Make sure this is possible.
|
|
if(pContext && ABSTRACTCX(pContext) && !ABSTRACTCX(pContext)->IsDestroyed()
|
|
&& ABSTRACTCX(pContext)->IsFrameContext() && PANECX(pContext)->GetPane()
|
|
&& WINCX(pContext)->GetFrame() && WINCX(pContext)->GetFrame()->GetFrameWnd()) {
|
|
CWinCX *pWinCX = WINCX(pContext);
|
|
CFrameWnd *pFrameWnd = pWinCX->GetFrame()->GetFrameWnd();
|
|
|
|
MWContext *pTravContext = NULL;
|
|
CWinCX *pTravWinCX = NULL;
|
|
CFrameWnd *pTravFrameWnd = NULL;
|
|
HWND pTopBottommostHwnd = NULL;
|
|
HWND pTravHwnd;
|
|
XP_Bool LowerWindow;
|
|
|
|
// We don't have a good way to do this. Look through the global
|
|
// context list for always lowered windows.
|
|
XP_List *pTraverse = XP_GetGlobalContextList();
|
|
while (pTravContext = (MWContext *)XP_ListNextObject(pTraverse)) {
|
|
if(pTravContext && ABSTRACTCX(pTravContext) &&
|
|
!ABSTRACTCX(pTravContext)->IsDestroyed() &&
|
|
ABSTRACTCX(pTravContext)->IsFrameContext() &&
|
|
WINCX(pTravContext)->GetFrame() &&
|
|
WINCX(pTravContext)->GetFrame()->GetFrameWnd()) {
|
|
|
|
// Find each always lowered window.
|
|
pTravWinCX = WINCX(pTravContext);
|
|
pTravFrameWnd = pTravWinCX->GetFrame()->GetFrameWnd();
|
|
if (((CGenericFrame*)pTravFrameWnd)->IsBottommost()) {
|
|
if (!pTopBottommostHwnd)
|
|
pTopBottommostHwnd = pTravFrameWnd->GetSafeHwnd();
|
|
else {
|
|
//Ugly! See if any of the other bottommost windows are above
|
|
//this one. If so, use them.
|
|
LowerWindow = FALSE;
|
|
pTravHwnd = pTopBottommostHwnd;
|
|
while (pTravHwnd = GetNextWindow(pTravHwnd, GW_HWNDPREV)) {
|
|
if (pTravHwnd == pTravFrameWnd->GetSafeHwnd())
|
|
LowerWindow = TRUE;
|
|
}
|
|
if (LowerWindow)
|
|
pTopBottommostHwnd = pTravFrameWnd->GetSafeHwnd();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pTopBottommostHwnd)
|
|
// Place the frame above the top bottommost window..
|
|
::SetWindowPos(pFrameWnd->GetSafeHwnd(), GetNextWindow(pTopBottommostHwnd, GW_HWNDPREV), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
else
|
|
// Push the frame to the bottom.
|
|
::SetWindowPos(pFrameWnd->GetSafeHwnd(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
// Remove focus.
|
|
::SetFocus(NULL);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Mocha-betties demand attention --- give them the focus
|
|
//
|
|
extern "C" void FE_FocusInputElement(MWContext * pContext, LO_Element * pElement)
|
|
{
|
|
// They may intend the actual context.
|
|
if(pElement == NULL) {
|
|
TRACE("Focusing context\n");
|
|
FE_RaiseWindow(pContext);
|
|
return;
|
|
}
|
|
else if(pElement->type == LO_FORM_ELE) {
|
|
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(pContext), &(pElement->lo_form));
|
|
if(pFormClass != NULL) {
|
|
pFormClass->FocusInputElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Mocha-betties are sulking and don't want anyone looking at them --- just give
|
|
// focus to our parent (if we have the focus to begin with)
|
|
//
|
|
extern "C" void FE_BlurInputElement(MWContext * pContext, LO_Element * pElement)
|
|
{
|
|
// They may intend the actual context.
|
|
if(pElement == NULL) {
|
|
TRACE("Blurring context\n");
|
|
FE_LowerWindow(pContext);
|
|
return;
|
|
}
|
|
else if(pElement->type == LO_FORM_ELE) {
|
|
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(pContext), &(pElement->lo_form));
|
|
if(pFormClass != NULL) {
|
|
pFormClass->BlurInputElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Mocha-betties want to be the ones that are selected
|
|
//
|
|
extern "C" void FE_SelectInputElement(MWContext * pContext, LO_Element * pElement)
|
|
{
|
|
// Get our front end form element, and have it do its thang.
|
|
ASSERT(pElement && pElement->type == LO_FORM_ELE);
|
|
if(pElement && pElement->type == LO_FORM_ELE) {
|
|
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(pContext), &(pElement->lo_form));
|
|
if(pFormClass != NULL) {
|
|
pFormClass->SelectInputElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mocha-betties have decided to change the value of a form element
|
|
// deal with it
|
|
extern "C" void FE_ChangeInputElement(MWContext * pContext, LO_Element * pElement)
|
|
{
|
|
// Get our front end form element, and have it do its thang.
|
|
ASSERT(pElement && pElement->type == LO_FORM_ELE);
|
|
if(pElement && pElement->type == LO_FORM_ELE) {
|
|
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(pContext), &(pElement->lo_form));
|
|
if(pFormClass != NULL) {
|
|
pFormClass->ChangeInputElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
// FE_ClickAnyElement() is based on FE_ClickInputElement(), and should replace the latter.
|
|
// If haveXY != 0, the xx, yy will be used for click. otherwise click the center of element.
|
|
//
|
|
// xx, yy are element coordinates, This function take care of :
|
|
// lo_any.x_offset, pWinCX->GetOriginX(), ClientToScreen(), and ScreenToClient()
|
|
extern "C" int FE_ClickAnyElement(MWContext * pContext, LO_Element * pElement, int haveXY, int32 xx, int32 yy )
|
|
{
|
|
if(pElement && ABSTRACTCX(pContext) && ABSTRACTCX(pContext)->IsWindowContext()) {
|
|
HWND hRaw = NULL;
|
|
CPaneCX *pPaneCX = PANECX(pContext);
|
|
// Get our front end form element, and have it do its thang.
|
|
// This differs only in that they are child windows and therefore, the destination window
|
|
// for the events differ.
|
|
if(pElement->type == LO_FORM_ELE) {
|
|
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(pContext), &(pElement->lo_form));
|
|
if(pFormClass != NULL) {
|
|
hRaw = pFormClass->GetRaw();
|
|
}
|
|
}
|
|
else {
|
|
// The destination for the click is the view.
|
|
hRaw = pPaneCX->GetPane();
|
|
}
|
|
|
|
if(hRaw) {
|
|
|
|
if( ! haveXY ) {
|
|
// Emulate a mouse click in the center of the element.
|
|
xx = pElement->lo_any.x + pElement->lo_any.width / 2;
|
|
yy = pElement->lo_any.y + pElement->lo_any.height / 2;
|
|
}
|
|
|
|
// Mouse coordinates are relative to the widget, not absolute to the screen.
|
|
// We may have some problems if the destination is not viewable.
|
|
|
|
// Figure the coordinates of the element according to context (view).
|
|
xx += pElement->lo_any.x_offset - pPaneCX->GetOriginX();
|
|
yy += pElement->lo_any.y_offset - pPaneCX->GetOriginY();
|
|
|
|
// Adjust for coords to the widget.
|
|
CPoint pCoords(CASTINT(xx), CASTINT(yy));
|
|
::ClientToScreen(pPaneCX->GetPane(), &pCoords);
|
|
::ScreenToClient(hRaw, &pCoords);
|
|
// Fire.
|
|
::SendMessage(hRaw, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(pCoords.x, pCoords.y));
|
|
::SendMessage(hRaw, WM_LBUTTONUP, 0, MAKELPARAM(pCoords.x, pCoords.y));
|
|
return( 1 );
|
|
}
|
|
} // if(pElement && ABSTRACTCX(pCon
|
|
return( 0 );
|
|
} // FE_ClickAnyElement()
|
|
|
|
extern "C" void FE_ClickInputElement(MWContext * pContext, LO_Element * pElement)
|
|
{
|
|
if(pElement && ABSTRACTCX(pContext) && ABSTRACTCX(pContext)->IsWindowContext()) {
|
|
HWND hRaw = NULL;
|
|
CPaneCX *pPaneCX = PANECX(pContext);
|
|
// Get our front end form element, and have it do its thang.
|
|
// This differs only in that they are child windows and therefore, the destination window
|
|
// for the events differ.
|
|
if(pElement->type == LO_FORM_ELE) {
|
|
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(pContext), &(pElement->lo_form));
|
|
if(pFormClass != NULL) {
|
|
hRaw = pFormClass->GetRaw();
|
|
}
|
|
}
|
|
else {
|
|
// The destination for the click is the view.
|
|
hRaw = pPaneCX->GetPane();
|
|
}
|
|
|
|
if(hRaw) {
|
|
// Emulate a mouse click in the center of the element.
|
|
// Mouse coordinates are relative to the widget, not absolute to the screen.
|
|
// We may have some problems if the destination is not viewable.
|
|
|
|
// Figure the coordinates of the element according to context (view).
|
|
LTRB Rect;
|
|
Rect.left = pElement->lo_any.x + pElement->lo_any.x_offset - pPaneCX->GetOriginX();
|
|
Rect.top = pElement->lo_any.y + pElement->lo_any.y_offset - pPaneCX->GetOriginY();
|
|
Rect.right = Rect.left + pElement->lo_any.width;
|
|
Rect.bottom = Rect.top + pElement->lo_any.height;
|
|
// Adjust for coords to the widget.
|
|
CPoint pCoords(CASTINT(Rect.left), CASTINT(Rect.top));
|
|
::ClientToScreen(pPaneCX->GetPane(), &pCoords);
|
|
::ScreenToClient(hRaw, &pCoords);
|
|
// Center target.
|
|
pCoords.x += CASTINT(Rect.Width() / 2);
|
|
pCoords.y += CASTINT(Rect.Height() / 2);
|
|
// Fire.
|
|
::SendMessage(hRaw, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(pCoords.x, pCoords.y));
|
|
::SendMessage(hRaw, WM_LBUTTONUP, 0, MAKELPARAM(pCoords.x, pCoords.y));
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void FE_EnableInputElement(MWContext *pContext, LO_Element *pElement)
|
|
{
|
|
// Get our front end form element, and have it do its thang.
|
|
ASSERT(pElement && pElement->type == LO_FORM_ELE);
|
|
if(pElement && pElement->type == LO_FORM_ELE) {
|
|
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(pContext), &(pElement->lo_form));
|
|
if(pFormClass != NULL) {
|
|
pFormClass->EnableInputElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
extern "C" void FE_DisableInputElement(MWContext *pContext, LO_Element *pElement)
|
|
{
|
|
// Get our front end form element, and have it do its thang.
|
|
ASSERT(pElement && pElement->type == LO_FORM_ELE);
|
|
if(pElement && pElement->type == LO_FORM_ELE) {
|
|
CFormElement *pFormClass = CFormElement::GetFormElement(ABSTRACTCX(pContext), &(pElement->lo_form));
|
|
if(pFormClass != NULL) {
|
|
pFormClass->DisableInputElement();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFormElement::MoveWindow(HWND hWnd, int32 lX, int32 lY)
|
|
{
|
|
if(hWnd && ::GetParent(hWnd)) {
|
|
// Is a window, needs a widget/window representation.
|
|
// All we need to do is to make sure that the widget is
|
|
// at the correct location as requested by layout.
|
|
// Figure the XY layout wants.
|
|
|
|
// Determine widget offset into the client window.
|
|
RECT crWidget;
|
|
::GetWindowRect(hWnd, &crWidget);
|
|
|
|
POINT ptLT;
|
|
ptLT.x = crWidget.left;
|
|
ptLT.y = crWidget.top;
|
|
::ScreenToClient(::GetParent(hWnd), &ptLT);
|
|
|
|
// Only move the widget if not already there.
|
|
// No need to cause the widget to redraw.
|
|
if(ptLT.x != lX || ptLT.y != lY) {
|
|
::MoveWindow(hWnd, CASTINT(lX), CASTINT(lY),
|
|
crWidget.right - crWidget.left,
|
|
crWidget.bottom - crWidget.top,
|
|
TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void CFormElement::SetWidgetFont(HDC hdc, HWND hWidget)
|
|
{
|
|
// this is just a trick to get the HFONT from the dc.
|
|
if (hWidget) {
|
|
HFONT hFont = (HFONT)::SelectObject(hdc,
|
|
(HFONT) GetStockObject(SYSTEM_FONT));
|
|
// now select the correct font into the DC.
|
|
::SelectObject(hdc, hFont);
|
|
|
|
#ifdef XP_WIN32
|
|
// Win95 systems need to keep their previous margins, or things get changed (margins)
|
|
// upon switching fonts.
|
|
// MS Knowledge Base article ID: Q138419
|
|
DWORD dwMargins = 0;
|
|
if(sysInfo.IsWin4_32()) {
|
|
dwMargins = ::SendMessage(hWidget, EM_GETMARGINS, 0L, 0L);
|
|
}
|
|
#endif
|
|
::SendMessage(hWidget, WM_SETFONT, (WPARAM)hFont, TRUE);
|
|
#ifdef XP_WIN32
|
|
if(sysInfo.IsWin4_32()) {
|
|
::SendMessage(
|
|
hWidget,
|
|
EM_SETMARGINS,
|
|
EC_LEFTMARGIN | EC_RIGHTMARGIN,
|
|
MAKELPARAM(LOWORD(dwMargins), HIWORD(dwMargins)));
|
|
}
|
|
#endif
|
|
}
|
|
}
|