mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
1697 lines
52 KiB
C++
1697 lines
52 KiB
C++
/* -*- 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 "cxpane.h"
|
|
#ifdef XP_WIN32
|
|
#include "intelli.h"
|
|
#endif
|
|
#include "rdfliner.h"
|
|
|
|
#ifdef ENDER
|
|
#include "netsdoc.h" //ENDER
|
|
#include "edview.h" //ENDER
|
|
#include "edt.h" //ENDER
|
|
#include "embdlist.h"
|
|
|
|
extern char * EDT_NEW_DOC_URL; //ENDER
|
|
#endif //ENDER
|
|
|
|
|
|
// What is CPaneCX?
|
|
// A pane is part of a complete window.
|
|
//
|
|
// There is no relation from a pane to the chrome of a full window.
|
|
// There is no frame, no document, no view, no toolbar, etc.
|
|
// No assumptions should be made, or the pane becomes non-reusable in a
|
|
// window that is yet to be invented.
|
|
//
|
|
// A pane can be put many places:
|
|
// In a dialog.
|
|
// In a navigation tool.
|
|
// In a browser.
|
|
// It is up to the place to provide the chrome. It is up to the pane to
|
|
// provide the HTML.
|
|
|
|
#ifdef XP_WIN32
|
|
#define STR_CPANECX "CPaneCX"
|
|
#else
|
|
#define STR_CPANECX_HI "CPaneCXHi"
|
|
#define STR_CPANECX_LO "CPaneCXLo"
|
|
#endif
|
|
|
|
CPaneCX::CPaneCX(HWND hPane, BOOL bDestroyOnWMDestroy)
|
|
{
|
|
MWContext *pContext = GetContext();
|
|
|
|
m_MM = MM_TEXT;
|
|
|
|
m_bDestroyOnWMDestroy = bDestroyOnWMDestroy;
|
|
m_hPane = NULL;
|
|
m_pPrevProc = NULL;
|
|
m_hOwnDC = NULL;
|
|
m_hClassDC = NULL;
|
|
m_hSubstDC = NULL;
|
|
|
|
m_cxType = Pane;
|
|
pContext->type = MWContextPane;
|
|
|
|
m_pDrawable = NULL;
|
|
m_pOffscreenDrawable = NULL;
|
|
m_pOnscreenDrawable = NULL;
|
|
|
|
m_pResizeReloadTimeout = NULL;
|
|
|
|
m_bDynamicScrollBars = TRUE;
|
|
m_bAlwaysShowScrollBars = FALSE;
|
|
m_bHScrollBarOn = FALSE;
|
|
m_bVScrollBarOn = FALSE;
|
|
#ifdef _WIN32
|
|
m_iWheelDelta = 0;
|
|
#endif
|
|
|
|
#ifdef XP_WIN16
|
|
m_hTextElementSegment = NULL;
|
|
m_lpTextElementHeap = NULL;
|
|
#endif
|
|
|
|
// If a pane was passed in, perform the step manually.
|
|
SetPane(hPane);
|
|
}
|
|
|
|
CPaneCX::~CPaneCX()
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
SetPane(NULL);
|
|
|
|
// Destroy the compositor associated with the context
|
|
MWContext *pContext = GetContext();
|
|
if (pContext && pContext->compositor) {
|
|
CL_DestroyCompositor(pContext->compositor);
|
|
pContext->compositor = NULL;
|
|
}
|
|
|
|
if(m_pOnscreenDrawable) {
|
|
delete m_pOnscreenDrawable;
|
|
m_pOnscreenDrawable = NULL;
|
|
}
|
|
if(m_pOffscreenDrawable) {
|
|
delete m_pOffscreenDrawable;
|
|
m_pOffscreenDrawable = NULL;
|
|
}
|
|
m_pDrawable = NULL;
|
|
|
|
#ifdef XP_WIN16
|
|
if(m_hTextElementSegment) {
|
|
::GlobalFree(m_hTextElementSegment);
|
|
m_hTextElementSegment = NULL;
|
|
m_lpTextElementHeap = NULL;
|
|
}
|
|
#endif
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
// Set current pane for context.
|
|
// Can switch panes from one to another (wow).
|
|
// Can pass in NULL, which detaches current pane.
|
|
HWND CPaneCX::SetPane(HWND hPane)
|
|
{
|
|
HWND hRetval = GetPane();
|
|
|
|
if(hRetval) {
|
|
// Need to release all cached information.
|
|
CacheDCInfo(FALSE);
|
|
|
|
// Need to unsubclass old window.
|
|
BOOL bSub = SubClass(hRetval, FALSE);
|
|
ASSERT(bSub);
|
|
|
|
// Destroy any pending reload.
|
|
if(m_pResizeReloadTimeout) {
|
|
FE_ClearTimeout(m_pResizeReloadTimeout);
|
|
m_pResizeReloadTimeout = NULL;
|
|
}
|
|
}
|
|
|
|
m_hPane = hPane;
|
|
|
|
if(m_hPane) {
|
|
// Need to subclass new window.
|
|
BOOL bSub = SubClass(m_hPane, TRUE);
|
|
ASSERT(bSub);
|
|
|
|
// Need to gather all cached information.
|
|
CacheDCInfo(TRUE);
|
|
|
|
// Reflect current scroll bar state.
|
|
::EnableScrollBar(m_hPane, SB_VERT, ESB_ENABLE_BOTH);
|
|
::EnableScrollBar(m_hPane, SB_HORZ, ESB_ENABLE_BOTH);
|
|
::SetScrollRange(m_hPane, SB_VERT, 0, SCROLL_UNITS, FALSE);
|
|
::SetScrollRange(m_hPane, SB_HORZ, 0, SCROLL_UNITS, FALSE);
|
|
::ShowScrollBar(m_hPane, SB_BOTH, FALSE);
|
|
ShowScrollBars(SB_HORZ, IsHScrollBarOn());
|
|
ShowScrollBars(SB_VERT, IsVScrollBarOn());
|
|
}
|
|
|
|
// Shouldn't have a substituted DC at this point.
|
|
ASSERT(m_hSubstDC == NULL);
|
|
|
|
return(hRetval);
|
|
}
|
|
|
|
void CPaneCX::CacheDCInfo(BOOL bCache)
|
|
{
|
|
if(bCache) {
|
|
// Determine window class name.
|
|
char aClassName[128];
|
|
memset(aClassName, 0, sizeof(aClassName));
|
|
int iLen = GetClassName(GetPane(), aClassName, sizeof(aClassName));
|
|
ASSERT(iLen && iLen < sizeof(aClassName));
|
|
|
|
// Fill in WNDCLASS.
|
|
// This needs to be expanded if we ever attempt to take over
|
|
// windows outside of our instance.
|
|
WNDCLASS PaneClass;
|
|
memset(&PaneClass, 0, sizeof(PaneClass));
|
|
BOOL bClass = GetClassInfo(AfxGetInstanceHandle(), aClassName, &PaneClass);
|
|
ASSERT(bClass);
|
|
|
|
// OwnDC
|
|
if(PaneClass.style & CS_OWNDC) {
|
|
SetOwnDC(TRUE);
|
|
m_hOwnDC = ::GetDC(GetPane());
|
|
}
|
|
else if(PaneClass.style & CS_CLASSDC) {
|
|
SetClassDC(TRUE);
|
|
m_hClassDC = ::GetDC(GetPane());
|
|
}
|
|
else {
|
|
SetOwnDC(FALSE);
|
|
SetClassDC(FALSE);
|
|
}
|
|
}
|
|
else {
|
|
// Any persistent data needs to go.
|
|
ClearFontCache();
|
|
|
|
// OwnDC
|
|
SetOwnDC(FALSE);
|
|
m_hOwnDC = NULL;
|
|
SetClassDC(FALSE);
|
|
m_hClassDC = NULL;
|
|
}
|
|
}
|
|
|
|
BOOL CPaneCX::IsOwnDC() const
|
|
{
|
|
BOOL bRetval = FALSE;
|
|
|
|
if(m_pDrawable && (m_pDrawable == m_pOffscreenDrawable)) {
|
|
bRetval = FALSE;
|
|
}
|
|
else if(m_hSubstDC) {
|
|
// We want substituted DCs to act like OwnDCs
|
|
// until unsubstituted.
|
|
bRetval = TRUE;
|
|
}
|
|
else {
|
|
bRetval = CDCCX::IsOwnDC();
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
BOOL CPaneCX::IsClassDC() const
|
|
{
|
|
BOOL bRetval = FALSE;
|
|
|
|
if(m_pDrawable && (m_pDrawable == m_pOffscreenDrawable)) {
|
|
bRetval = FALSE;
|
|
}
|
|
else {
|
|
bRetval = CDCCX::IsClassDC();
|
|
}
|
|
|
|
return(bRetval);
|
|
}
|
|
|
|
HDC CPaneCX::SubstituteDC(HDC hDC)
|
|
{
|
|
// Flush cached info for old DC (take away any attributes
|
|
// we may have assumed as OwnDC).
|
|
// This could be further optimized if the font code
|
|
// didn't hold onto the DC for the life of a font.
|
|
if(m_hSubstDC) {
|
|
ClearFontCache();
|
|
}
|
|
|
|
HDC hRetval = m_hSubstDC;
|
|
m_hSubstDC = hDC;
|
|
|
|
// Set new mapping mode for new DC.
|
|
if(m_hSubstDC) {
|
|
SetMappingMode(m_hSubstDC);
|
|
}
|
|
return(hRetval);
|
|
}
|
|
|
|
// Return appropriate HDC
|
|
HDC CPaneCX::GetContextDC()
|
|
{
|
|
HDC hRetval = NULL;
|
|
if(m_pDrawable && (m_pDrawable == m_pOffscreenDrawable)) {
|
|
hRetval = m_pDrawable->GetDrawableDC();
|
|
}
|
|
else if(m_hSubstDC) {
|
|
hRetval = m_hSubstDC;
|
|
}
|
|
else if(IsClassDC()) {
|
|
hRetval = m_hClassDC;
|
|
}
|
|
else if(CDCCX::IsOwnDC()) {
|
|
hRetval = m_hOwnDC;
|
|
}
|
|
else if(GetPane()) {
|
|
hRetval = ::GetDC(GetPane());
|
|
SetMappingMode(hRetval);
|
|
}
|
|
|
|
return(hRetval);
|
|
}
|
|
|
|
// Release appropriate HDC
|
|
void CPaneCX::ReleaseContextDC(HDC hDC)
|
|
{
|
|
if(hDC != m_hSubstDC && IsClassDC() == FALSE && CDCCX::IsOwnDC() == FALSE && (!m_pOffscreenDrawable || hDC != m_pOffscreenDrawable->GetDrawableDC())) {
|
|
ASSERT(GetPane());
|
|
::ReleaseDC(GetPane(), hDC);
|
|
}
|
|
}
|
|
|
|
void CPaneCX::DestroyContext()
|
|
{
|
|
if(IsDestroyed() == FALSE) {
|
|
if(m_pResizeReloadTimeout) {
|
|
FE_ClearTimeout(m_pResizeReloadTimeout);
|
|
m_pResizeReloadTimeout = NULL;
|
|
}
|
|
}
|
|
|
|
CDCCX::DestroyContext();
|
|
}
|
|
|
|
void CPaneCX::Initialize(BOOL bOwnDC, RECT *pRect, BOOL bInitialPalette, BOOL bNewMemDC)
|
|
{
|
|
#ifndef MOZ_NGLAYOUT
|
|
MWContext *pContext = GetContext();
|
|
|
|
// Top of the document.
|
|
m_lOrgX = 0;
|
|
m_lOrgY = 0;
|
|
|
|
// Call base.
|
|
CDCCX::Initialize(bOwnDC, pRect, bInitialPalette, bNewMemDC);
|
|
|
|
// Get the DC.
|
|
HDC hDC = GetContextDC();
|
|
SetMappingMode(hDC);
|
|
|
|
// Init compositor.
|
|
CL_Drawable *pOnscreenDrawable = NULL;
|
|
CL_Drawable *pOffscreenDrawable = NULL;
|
|
|
|
m_pOnscreenDrawable = new COnscreenDrawable(hDC, this);
|
|
pOnscreenDrawable = CL_NewDrawable(
|
|
CASTUINT(m_lWidth),
|
|
CASTUINT(m_lHeight),
|
|
CL_WINDOW,
|
|
&wfe_drawable_vtable,
|
|
(void *)m_pOnscreenDrawable);
|
|
|
|
m_pOffscreenDrawable = COffscreenDrawable::AllocateOffscreen(hDC, GetPalette(), this);
|
|
|
|
pOffscreenDrawable = CL_NewDrawable(
|
|
CASTUINT(m_lWidth),
|
|
CASTUINT(m_lHeight),
|
|
CL_BACKING_STORE,
|
|
&wfe_drawable_vtable,
|
|
(void *)m_pOffscreenDrawable);
|
|
|
|
GetContext()->compositor = CL_NewCompositor(
|
|
pOnscreenDrawable,
|
|
pOffscreenDrawable,
|
|
m_lOrgX,
|
|
m_lOrgY,
|
|
m_lWidth,
|
|
m_lHeight,
|
|
20);
|
|
|
|
m_pDrawable = (CDrawable *)m_pOnscreenDrawable;
|
|
|
|
// If a grid cell, select the palette.
|
|
if(IsGridCell() && GetPalette()) {
|
|
::SelectPalette(hDC, GetPalette(), FALSE);
|
|
int iError = ::RealizePalette(hDC);
|
|
}
|
|
|
|
ReleaseContextDC(hDC);
|
|
hDC = NULL;
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
void CPaneCX::SetDrawable(MWContext *pContext, CL_Drawable *pDrawable)
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
if(pDrawable) {
|
|
CDrawable *pFEDrawable = (CDrawable *)CL_GetDrawableClientData(pDrawable);
|
|
m_pDrawable = pFEDrawable;
|
|
}
|
|
else {
|
|
m_pDrawable = m_pOnscreenDrawable;
|
|
}
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
FE_Region CPaneCX::GetDrawingClip()
|
|
{
|
|
if (m_pDrawable) {
|
|
return m_pDrawable->GetClip();
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void CPaneCX::GetDrawingOrigin(int32 *plOrgX, int32 *plOrgY)
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
if(m_pDrawable) {
|
|
m_pDrawable->GetOrigin(plOrgX, plOrgY);
|
|
}
|
|
else {
|
|
*plOrgX = *plOrgY = 0;
|
|
}
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
void CPaneCX::RefreshArea(int32 lLeft, int32 lTop, uint32 ulWidth, uint32 ulHeight)
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
MWContext *pContext = GetContext();
|
|
|
|
// Simple validation, can pass in 0 for all.
|
|
if(ulWidth == 0) {
|
|
ulWidth = GetDocumentWidth() - lLeft;
|
|
}
|
|
if(ulHeight == 0) {
|
|
ulHeight = GetDocumentHeight() - lTop;
|
|
}
|
|
|
|
XP_Rect rect;
|
|
if(pContext->compositor) {
|
|
rect.left = lLeft - m_lOrgX;
|
|
rect.top = lTop - m_lOrgY;
|
|
rect.right = rect.left + ulWidth;
|
|
rect.bottom = rect.top + ulHeight;
|
|
CL_RefreshWindowRect(pContext->compositor, &rect);
|
|
}
|
|
|
|
#ifdef DDRAW
|
|
LTRB tempRect(rect.left, rect.top, rect.right, rect.bottom);
|
|
tempRect.left += GetWindowsXPos();
|
|
tempRect.right += GetWindowsXPos();
|
|
tempRect.top += GetWindowsYPos();
|
|
tempRect.bottom += GetWindowsYPos();
|
|
BltToScreen(tempRect, NULL);
|
|
#endif
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
// Window handle is about to go away; let go of it.
|
|
void CPaneCX::AftWMDestroy(PaneMessage *pMessage)
|
|
{
|
|
SetPane(NULL);
|
|
|
|
// If we are supposed to clean up ourselves, do so now.
|
|
if(m_bDestroyOnWMDestroy) {
|
|
DestroyContext();
|
|
}
|
|
}
|
|
|
|
void CPaneCX::PreWMErasebkgnd(PaneMessage *pMessage)
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
HDC hEraseDC = (HDC)pMessage->wParam;
|
|
HDC hOldSubst = NULL;
|
|
if(hEraseDC != m_hClassDC && hEraseDC != m_hOwnDC) {
|
|
hOldSubst = SubstituteDC(hEraseDC);
|
|
}
|
|
|
|
// Layers may want to handle erasing of background.
|
|
MWContext *pContext = GetContext();
|
|
if(pContext->compositor && CL_GetCompositorEnabled(pContext->compositor)) {
|
|
pMessage->bSetRetval = TRUE;
|
|
pMessage->lRetval = (LPARAM)TRUE;
|
|
}
|
|
else {
|
|
RECT rClip;
|
|
::GetClipBox(hEraseDC, &rClip);
|
|
pMessage->bSetRetval = TRUE;
|
|
pMessage->lRetval = (LPARAM)_EraseBkgnd(hEraseDC, rClip, GetOriginX(), GetOriginY());
|
|
}
|
|
|
|
if(hEraseDC != m_hClassDC && hEraseDC != m_hOwnDC) {
|
|
HDC hUnSubst = SubstituteDC(hOldSubst);
|
|
// Someone forget to unsubst their DC?
|
|
ASSERT(hUnSubst == hEraseDC);
|
|
}
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
void CPaneCX::PreWMPaint(PaneMessage *pMessage)
|
|
{
|
|
pMessage->lRetval = NULL;
|
|
pMessage->bSetRetval = TRUE;
|
|
|
|
// Redirecting output in this fashion not supported yet.
|
|
ASSERT((HDC)pMessage->wParam == NULL);
|
|
|
|
BOOL bBeginPaint = ::GetUpdateRect(GetPane(), NULL, FALSE);
|
|
if(bBeginPaint) {
|
|
PAINTSTRUCT ps;
|
|
HDC hPaintDC = ::BeginPaint(GetPane(), &ps);
|
|
uint32 ulWidth = ps.rcPaint.right - ps.rcPaint.left;
|
|
uint32 ulHeight = ps.rcPaint.bottom - ps.rcPaint.top;
|
|
if(ulWidth && ulHeight) {
|
|
HDC hOldSubst = NULL;
|
|
if(hPaintDC != m_hClassDC && hPaintDC != m_hOwnDC) {
|
|
hOldSubst = SubstituteDC(hPaintDC);
|
|
}
|
|
RefreshArea(ps.rcPaint.left + GetOriginX(), ps.rcPaint.top + GetOriginY(), ulWidth, ulHeight);
|
|
if(hPaintDC != m_hClassDC && hPaintDC != m_hOwnDC) {
|
|
HDC hUnSubst = SubstituteDC(hOldSubst);
|
|
// Someone forget to unsubst their DC?
|
|
ASSERT(hUnSubst == hPaintDC);
|
|
}
|
|
}
|
|
::EndPaint(GetPane(), &ps);
|
|
}
|
|
else {
|
|
// No update area.
|
|
// Possible internal draw request (see RedrawWindow).
|
|
// Not supported until needed.
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
|
|
void CPaneCX::AftWMSize(PaneMessage *pMessage)
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
UINT uSizeType = (UINT)pMessage->wParam;
|
|
int iWidth = LOWORD(pMessage->lParam);
|
|
int iHeight = HIWORD(pMessage->lParam);
|
|
|
|
// Only care if resized visibly.
|
|
if(uSizeType == SIZE_MAXIMIZED || uSizeType == SIZE_RESTORED) {
|
|
BOOL bNiceReload = TRUE;
|
|
|
|
// Let frame contexts decide on their own if they would like to reload.
|
|
if(IsFrameContext()) {
|
|
bNiceReload = FALSE;
|
|
}
|
|
|
|
int iNewWidth = iWidth;
|
|
if(IsVScrollBarOn()) {
|
|
iNewWidth += sysInfo.m_iScrollWidth;
|
|
}
|
|
int iNewHeight = iHeight;
|
|
if(IsHScrollBarOn()) {
|
|
iNewHeight += sysInfo.m_iScrollHeight;
|
|
}
|
|
|
|
/* Resize the compositor's notion of the window area
|
|
* as well as the size of the background layer. This
|
|
* might all be moot, because we might relayout, but
|
|
* that doesn't happen all the time (e.g. HTML dialogs).
|
|
* We want the composited area - without the scrollbars
|
|
*/
|
|
MWContext *pContext = GetContext();
|
|
if (pContext->compositor) {
|
|
CL_Layer *bglayer, *doclayer;
|
|
CL_Compositor *compositor = pContext->compositor;
|
|
|
|
CL_ResizeCompositorWindow(compositor, iNewWidth, iNewHeight);
|
|
doclayer = CL_GetCompositorRoot(compositor);
|
|
if (doclayer) {
|
|
bglayer = CL_GetLayerChildByName(doclayer, LO_BACKGROUND_LAYER_NAME);
|
|
if (bglayer) {
|
|
XP_Rect bbox;
|
|
int32 layerWidth, layerHeight;
|
|
|
|
/* Make sure that the new dimensions are larger than the */
|
|
/* original ones before resizing the layer. We still want */
|
|
/* the layer size to be the maximum of the window and the */
|
|
/* document dimensions. */
|
|
CL_GetLayerBbox(bglayer, &bbox);
|
|
layerWidth = bbox.right - bbox.left;
|
|
layerHeight = bbox.bottom - bbox.top;
|
|
|
|
if (iNewWidth > layerWidth)
|
|
layerWidth = iNewWidth;
|
|
if (iNewHeight > layerHeight)
|
|
layerHeight = iNewHeight;
|
|
|
|
CL_ResizeLayer(bglayer, layerWidth, layerHeight);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_lWidth = (int32)iNewWidth;
|
|
m_lHeight = (int32)iNewHeight;
|
|
|
|
// If we've resized bigger than the page,
|
|
// and we are scrolled, reset our position.
|
|
if((m_lDocWidth > 0) && (m_lDocWidth < m_lWidth) && (m_lOrgX != 0)) {
|
|
m_lOrgX = 0;
|
|
}
|
|
if((m_lDocHeight > 0) &&(m_lDocHeight < m_lHeight) && (m_lOrgY != 0)) {
|
|
m_lOrgY = 0;
|
|
}
|
|
|
|
RealizeScrollBars();
|
|
|
|
if(bNiceReload) {
|
|
#ifdef RELAYOUT_WITHOUT_RELOAD
|
|
LO_RelayoutOnResize(GetDocumentContext(), m_lWidth, m_lHeight, m_lLeftMargin, m_lTopMargin);
|
|
#else
|
|
NiceResizeReload();
|
|
#endif
|
|
}
|
|
}
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
static void resize_reload_timeout(void *closure)
|
|
{
|
|
CPaneCX *cw = VOID2CX(closure, CPaneCX);
|
|
cw->m_pResizeReloadTimeout = NULL;
|
|
cw->NiceReload();
|
|
}
|
|
|
|
// Wait to do the reload for just a wee bit.
|
|
void CPaneCX::NiceResizeReload()
|
|
{
|
|
// If there was already a resize timeout that hasn't fired, cancel it,
|
|
// since that means resize messages are still arriving close together
|
|
if(m_pResizeReloadTimeout) {
|
|
FE_ClearTimeout(m_pResizeReloadTimeout);
|
|
m_pResizeReloadTimeout = NULL;
|
|
}
|
|
|
|
// Can't reload anything
|
|
if(!CanCreateUrlFromHist()) {
|
|
return;
|
|
}
|
|
|
|
m_pResizeReloadTimeout = FE_SetTimeout(resize_reload_timeout, this, 200);
|
|
}
|
|
|
|
int CPaneCX::GetUrl(URL_Struct *pUrl, FO_Present_Types iFormatOut, BOOL bReallyLoading, BOOL bForceNew)
|
|
{
|
|
// Stop any reload timers, no need.
|
|
if(m_pResizeReloadTimeout) {
|
|
FE_ClearTimeout(m_pResizeReloadTimeout);
|
|
m_pResizeReloadTimeout = NULL;
|
|
}
|
|
return(CDCCX::GetUrl(pUrl, iFormatOut, bReallyLoading, bForceNew));
|
|
}
|
|
|
|
void CPaneCX::LayoutNewDocument(MWContext *pContext, URL_Struct *pURL, int32 *pWidth, int32 *pHeight, int32 *pmWidth, int32 *pmHeight)
|
|
{
|
|
m_lOrgY = 0;
|
|
m_lOrgX = 0;
|
|
|
|
// Stop any reload timers, no need.
|
|
if(m_pResizeReloadTimeout) {
|
|
FE_ClearTimeout(m_pResizeReloadTimeout);
|
|
m_pResizeReloadTimeout = NULL;
|
|
}
|
|
|
|
// Call the base.
|
|
CDCCX::LayoutNewDocument(pContext, pURL, pWidth, pHeight, pmWidth, pmHeight);
|
|
|
|
// Initialize Scrollbars for new document.
|
|
ShowScrollBars(SB_BOTH, FALSE);
|
|
m_nPageY = SCROLL_UNITS;
|
|
m_nPageX = SCROLL_UNITS;
|
|
|
|
#ifdef XP_WIN32
|
|
SCROLLINFO siY;
|
|
siY.cbSize = sizeof(SCROLLINFO);
|
|
siY.fMask = SIF_PAGE;
|
|
siY.nPage = 0;
|
|
if(GetPane() && IsVScrollBarOn() == TRUE) {
|
|
::SetScrollInfo(GetPane(), SB_VERT, &siY, FALSE);
|
|
}
|
|
|
|
SCROLLINFO siX;
|
|
siX.cbSize = sizeof(SCROLLINFO);
|
|
siX.fMask = SIF_PAGE;
|
|
siX.nPage = 0;
|
|
if(GetPane() && IsHScrollBarOn() == TRUE) {
|
|
::SetScrollInfo(GetPane(), SB_HORZ, &siX, FALSE);
|
|
}
|
|
#endif
|
|
|
|
if(*pmWidth || *pmHeight) {
|
|
// Layout wants to set these.
|
|
m_lLeftMargin = *pmWidth;
|
|
m_lTopMargin = *pmHeight;
|
|
m_lRightMargin = -1 * *pmWidth;
|
|
m_lBottomMargin = -1 * *pmHeight;
|
|
}
|
|
else {
|
|
// Set these to the old defaults which I'll never understand.
|
|
m_lLeftMargin = LEFT_MARGIN;
|
|
m_lTopMargin = TOP_MARGIN;
|
|
m_lRightMargin = RIGHT_MARGIN;
|
|
m_lBottomMargin = BOTTOM_MARGIN;
|
|
}
|
|
*pmWidth = m_lLeftMargin;
|
|
*pmHeight = m_lTopMargin;
|
|
|
|
// When we report the size to layout, we must always take care to subtract
|
|
// for the size of the scrollbars if we have dynamic or always on
|
|
// scrollers.
|
|
if(DynamicScrollBars() == FALSE && IsHScrollBarOn() == FALSE && IsVScrollBarOn() == FALSE) {
|
|
*pWidth = GetWidth();
|
|
*pHeight = GetHeight();
|
|
}
|
|
else {
|
|
*pWidth = GetWidth() - sysInfo.m_iScrollWidth;
|
|
*pHeight = GetHeight() - sysInfo.m_iScrollHeight;
|
|
}
|
|
}
|
|
|
|
void CPaneCX::FinishedLayout(MWContext *pContext)
|
|
{
|
|
CDCCX::FinishedLayout(pContext);
|
|
|
|
// Have the scroll bars correctly set themselves.
|
|
RealizeScrollBars();
|
|
}
|
|
|
|
void CPaneCX::ShowScrollBars(int iBars, BOOL bShow) {
|
|
// Don't do this if we don't have a view.
|
|
if(GetPane() != NULL) {
|
|
// Turning them off or on?
|
|
if(bShow == FALSE) {
|
|
// Decide which set of scrollers, if any, that we need to take
|
|
// action on, and take that action.
|
|
if(iBars == SB_BOTH) {
|
|
m_bVScrollBarOn = FALSE;
|
|
m_bHScrollBarOn = FALSE;
|
|
::ShowScrollBar(GetPane(), SB_BOTH, FALSE);
|
|
}
|
|
else if((iBars == SB_VERT) && IsVScrollBarOn()) {
|
|
m_bVScrollBarOn = FALSE;
|
|
::ShowScrollBar(GetPane(), SB_VERT, FALSE);
|
|
}
|
|
else if((iBars == SB_HORZ) && IsHScrollBarOn()) {
|
|
m_bHScrollBarOn = FALSE;
|
|
::ShowScrollBar(GetPane(), SB_HORZ, FALSE);
|
|
}
|
|
}
|
|
else {
|
|
// Decide which set of scrollers, if any, that we need to take
|
|
// action on, and take that action.
|
|
if(iBars == SB_BOTH) {
|
|
m_bVScrollBarOn = TRUE;
|
|
m_bHScrollBarOn = TRUE;
|
|
::ShowScrollBar(GetPane(), SB_BOTH, TRUE);
|
|
}
|
|
else if((iBars == SB_VERT) && !IsVScrollBarOn()) {
|
|
m_bVScrollBarOn = TRUE;
|
|
::ShowScrollBar(GetPane(), SB_VERT, TRUE);
|
|
}
|
|
else if((iBars == SB_HORZ) && !IsHScrollBarOn()) {
|
|
m_bHScrollBarOn = TRUE;
|
|
::ShowScrollBar(GetPane(), SB_HORZ, TRUE);
|
|
}
|
|
}
|
|
// We have just shown/hidden a scroll bar.
|
|
// Update the window to avoid flash (reduces overall invalidated
|
|
// rectangle, except when we show/hide both at the same time).
|
|
::UpdateWindow(GetPane());
|
|
}
|
|
}
|
|
|
|
void CPaneCX::RealizeScrollBars(int32 *pX, int32 *pY)
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
XP_ASSERT(0);
|
|
#else
|
|
if(m_lDocHeight && m_lDocWidth) {
|
|
if(AlwaysShowScrollBars()) {
|
|
ShowScrollBars(SB_BOTH, TRUE);
|
|
}
|
|
|
|
// Are we checking for dynamic scroll bars?
|
|
if(DynamicScrollBars() == TRUE) {
|
|
// If the document fits in our client area, or if we have children, turn them off.
|
|
// If the document is larger than our client area, turn them on.
|
|
int iSB = -1;
|
|
BOOL bShow = FALSE;
|
|
BOOL vScrollBar = FALSE;
|
|
BOOL hScrollBar = FALSE;
|
|
if (m_lHeight >= m_lDocHeight && m_lWidth >= m_lDocWidth && (IsVScrollBarOn() == TRUE || IsHScrollBarOn() == TRUE)) {
|
|
ShowScrollBars(SB_BOTH, FALSE);
|
|
}
|
|
else if(m_lHeight < m_lDocHeight && m_lWidth < m_lDocWidth && (IsVScrollBarOn() == FALSE || IsHScrollBarOn() == FALSE)) {
|
|
ShowScrollBars(SB_BOTH, TRUE);
|
|
}
|
|
else {
|
|
if(m_lHeight >= m_lDocHeight && IsVScrollBarOn() == TRUE) {
|
|
ShowScrollBars(SB_VERT, FALSE);
|
|
}
|
|
else if(m_lHeight < m_lDocHeight && IsVScrollBarOn() == FALSE) {
|
|
ShowScrollBars(SB_VERT, TRUE);
|
|
}
|
|
if(m_lWidth >= m_lDocWidth && IsHScrollBarOn() == TRUE) {
|
|
ShowScrollBars(SB_HORZ, FALSE);
|
|
}
|
|
else if(m_lWidth < m_lDocWidth && IsHScrollBarOn() == FALSE) {
|
|
ShowScrollBars(SB_HORZ, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// See if we're going to be changing the values.
|
|
BOOL bRefreshHorz = FALSE;
|
|
BOOL bRefreshVert = FALSE;
|
|
if(pX != NULL && m_lOrgX != *pX) {
|
|
m_lOrgX = *pX;
|
|
bRefreshHorz = TRUE;
|
|
}
|
|
if(pY != NULL && m_lOrgY != *pY) {
|
|
m_lOrgY = *pY;
|
|
bRefreshVert = TRUE;
|
|
}
|
|
|
|
// Make sure that the current origins are within the document iWidth
|
|
// and iHeight.
|
|
// In the event that they are exactly the same, make sure to refresh
|
|
// the scroll bar anyhow (this will happen if you scroll to the
|
|
// bottom of a page, go to a new page, and then go back; your scroll
|
|
// bars are wrong).
|
|
int32 lCalcHeight = m_lDocHeight - m_lHeight + (IsHScrollBarOn() ? sysInfo.m_iScrollHeight : 0);
|
|
if(m_lOrgY >= lCalcHeight && lCalcHeight > 0) {
|
|
m_lOrgY = lCalcHeight; // always show one screen
|
|
bRefreshVert = TRUE;
|
|
}
|
|
int32 lCalcWidth = m_lDocWidth - m_lWidth + (IsVScrollBarOn() ? sysInfo.m_iScrollWidth : 0);
|
|
if(m_lOrgX >= lCalcWidth && lCalcWidth > 0) {
|
|
m_lOrgX = lCalcWidth; // always leave some visible
|
|
bRefreshHorz = TRUE;
|
|
}
|
|
|
|
#ifdef XP_WIN32
|
|
// Special fun for proportional scrollbars.
|
|
SCROLLINFO siY;
|
|
siY.cbSize = sizeof(SCROLLINFO);
|
|
siY.fMask = SIF_PAGE;
|
|
// If the document is longer than a single page
|
|
if(m_lDocHeight > m_lHeight && IsVScrollBarOn() == TRUE) {
|
|
siY.nPage = m_lHeight * SCROLL_UNITS / m_lDocHeight;
|
|
if(GetPane()) {
|
|
::SetScrollInfo(GetPane(), SB_VERT, &siY, FALSE);
|
|
if((UINT)m_nPageY != SCROLL_UNITS - siY.nPage) {
|
|
m_nPageY = SCROLL_UNITS - siY.nPage;
|
|
bRefreshVert = TRUE;
|
|
}
|
|
} else
|
|
bRefreshVert = TRUE;
|
|
}
|
|
else if(IsVScrollBarOn() == TRUE) {
|
|
siY.nPage = SCROLL_UNITS;
|
|
if(GetPane()) {
|
|
::SetScrollInfo(GetPane(), SB_VERT, &siY, FALSE);
|
|
m_nPageY = SCROLL_UNITS;
|
|
}
|
|
}
|
|
|
|
SCROLLINFO siX;
|
|
siX.cbSize = sizeof(SCROLLINFO);
|
|
siX.fMask = SIF_PAGE;
|
|
// If the document is wider than a single screen
|
|
if((m_lDocWidth != 0) && (m_lDocWidth > m_lWidth) && IsHScrollBarOn() == TRUE) {
|
|
siX.nPage = m_lWidth * SCROLL_UNITS / m_lDocWidth;
|
|
if(GetPane()) {
|
|
::SetScrollInfo(GetPane(), SB_HORZ, &siX, FALSE);
|
|
if((UINT)m_nPageX != SCROLL_UNITS - siX.nPage) {
|
|
m_nPageX = SCROLL_UNITS - siX.nPage;
|
|
bRefreshHorz = TRUE;
|
|
}
|
|
} else
|
|
bRefreshHorz = TRUE;
|
|
}
|
|
else if(IsHScrollBarOn() == TRUE) {
|
|
siX.nPage = SCROLL_UNITS;
|
|
if(GetPane()) {
|
|
::SetScrollInfo(GetPane(), SB_HORZ, &siX, FALSE);
|
|
m_nPageX = SCROLL_UNITS;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Figure the thumb position.
|
|
float fYPos = 0.0f;
|
|
float fXPos = 0.0f;
|
|
if(m_lDocHeight != 0) {
|
|
long lScrollHeight = m_lDocHeight - m_lHeight;
|
|
if(lScrollHeight != 0)
|
|
fYPos = (float)m_lOrgY / (float) lScrollHeight;
|
|
else
|
|
fYPos = 1.0f;
|
|
}
|
|
if(m_lDocWidth != 0) {
|
|
long lScrollWidth = m_lDocWidth - m_lWidth;
|
|
if(lScrollWidth != 0)
|
|
fXPos = (float)m_lOrgX / (float) lScrollWidth;
|
|
else
|
|
fXPos = 1.0f;
|
|
}
|
|
|
|
// See if we should turn off the scroll bars.
|
|
|
|
if(m_lDocWidth <= m_lWidth && IsHScrollBarOn() == TRUE && GetPane()) {
|
|
::EnableScrollBar(GetPane(), SB_HORZ, ESB_DISABLE_BOTH);
|
|
}
|
|
else if(IsHScrollBarOn() == TRUE && GetPane()) {
|
|
::EnableScrollBar(GetPane(), SB_HORZ, ESB_ENABLE_BOTH);
|
|
|
|
// only reset if different to avoid flashing on NT and Win16
|
|
int iNewPosX = (int) (fXPos * m_nPageX);
|
|
if(iNewPosX != ::GetScrollPos(GetPane(), SB_HORZ) || bRefreshHorz == TRUE) {
|
|
::SetScrollPos(GetPane(), SB_HORZ, iNewPosX, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
if(m_lDocHeight <= m_lHeight && IsVScrollBarOn() == TRUE && GetPane()) {
|
|
::EnableScrollBar(GetPane(), SB_VERT, ESB_DISABLE_BOTH);
|
|
}
|
|
else if(IsVScrollBarOn() == TRUE && GetPane()) {
|
|
::EnableScrollBar(GetPane(), SB_VERT, ESB_ENABLE_BOTH);
|
|
|
|
// only reset if different to avoid flashing on NT and Win16
|
|
int iNewPosY = (int) (fYPos * m_nPageY);
|
|
if(iNewPosY != ::GetScrollPos(GetPane(), SB_VERT) || bRefreshVert == TRUE) {
|
|
::SetScrollPos(GetPane(), SB_VERT, iNewPosY, TRUE);
|
|
}
|
|
}
|
|
|
|
MWContext *pContext = GetContext();
|
|
if(pContext->compositor) {
|
|
CL_ScrollCompositorWindow(pContext->compositor, m_lOrgX, m_lOrgY);
|
|
}
|
|
}
|
|
#endif /* MOZ_NGLAYOUT */
|
|
}
|
|
|
|
void CPaneCX::SetDocDimension(MWContext *pContext, int iLocation, int32 lWidth, int32 lLength) {
|
|
// Call the base.
|
|
CDCCX::SetDocDimension(pContext, iLocation, lWidth, lLength);
|
|
RealizeScrollBars();
|
|
}
|
|
|
|
void CPaneCX::PreWMVScroll(PaneMessage *pMsg)
|
|
{
|
|
#ifdef XP_WIN16
|
|
UINT uSBCode = (UINT)pMsg->wParam;
|
|
UINT uPos = LOWORD(pMsg->lParam);
|
|
HWND hwndCtrl = (HWND)HIWORD(pMsg->lParam);
|
|
#else
|
|
UINT uSBCode = LOWORD(pMsg->wParam);
|
|
UINT uPos = HIWORD(pMsg->wParam);
|
|
HWND hwndCtrl = (HWND)pMsg->lParam;
|
|
#endif
|
|
|
|
Scroll(SB_VERT, uSBCode, uPos, hwndCtrl);
|
|
|
|
pMsg->lRetval = NULL;
|
|
pMsg->bSetRetval = TRUE;
|
|
}
|
|
|
|
void CPaneCX::PreWMHScroll(PaneMessage *pMsg)
|
|
{
|
|
#ifdef XP_WIN16
|
|
UINT uSBCode = (UINT)pMsg->wParam;
|
|
UINT uPos = LOWORD(pMsg->lParam);
|
|
HWND hwndCtrl = (HWND)HIWORD(pMsg->lParam);
|
|
#else
|
|
UINT uSBCode = LOWORD(pMsg->wParam);
|
|
UINT uPos = HIWORD(pMsg->wParam);
|
|
HWND hwndCtrl = (HWND)pMsg->lParam;
|
|
#endif
|
|
|
|
Scroll(SB_HORZ, uSBCode, uPos, hwndCtrl);
|
|
|
|
pMsg->lRetval = NULL;
|
|
pMsg->bSetRetval = TRUE;
|
|
}
|
|
|
|
void CPaneCX::AftWMMouseActivate(PaneMessage *pMsg)
|
|
{
|
|
BOOL bSetFocus = FALSE;
|
|
if(pMsg->bSetRetval) {
|
|
// Check to see if we need to activate.
|
|
if(pMsg->lRetval == MA_ACTIVATE || pMsg->lRetval == MA_ACTIVATEANDEAT) {
|
|
bSetFocus = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
// Real class didn't handle, take some action.
|
|
pMsg->bSetRetval = TRUE;
|
|
pMsg->lRetval = MA_ACTIVATE;
|
|
bSetFocus = TRUE;
|
|
}
|
|
|
|
if(bSetFocus) {
|
|
if(::GetFocus() != GetPane()) {
|
|
::SetFocus(GetPane());
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(XP_WIN32) && _MSC_VER >= 1100
|
|
void CPaneCX::PreWMMouseWheel(PaneMessage *pMsg)
|
|
{
|
|
// Increase the delta.
|
|
m_iWheelDelta += MOUSEWHEEL_DELTA(pMsg->wParam, pMsg->lParam);
|
|
|
|
// Number of lines to scroll.
|
|
UINT uScroll = intelli.ScrollLines();
|
|
|
|
// Direction.
|
|
BOOL bForward = TRUE;
|
|
if(m_iWheelDelta < 0) {
|
|
bForward = FALSE;
|
|
}
|
|
|
|
// Scroll bar code to use.
|
|
UINT uSBCode = SB_LINEUP;
|
|
|
|
if(m_iWheelDelta / WHEEL_DELTA) {
|
|
if(uScroll == WHEEL_PAGESCROLL) {
|
|
if(bForward) {
|
|
uSBCode = SB_PAGEUP;
|
|
}
|
|
else {
|
|
uSBCode = SB_PAGEDOWN;
|
|
}
|
|
uScroll = 1;
|
|
}
|
|
else {
|
|
if(bForward) {
|
|
uSBCode = SB_LINEUP;
|
|
}
|
|
else {
|
|
uSBCode = SB_LINEDOWN;
|
|
}
|
|
}
|
|
|
|
// Take off scroll increment.
|
|
UINT uLoops = 0;
|
|
while(m_iWheelDelta / WHEEL_DELTA) {
|
|
if(bForward) {
|
|
m_iWheelDelta -= WHEEL_DELTA;
|
|
}
|
|
else {
|
|
m_iWheelDelta += WHEEL_DELTA;
|
|
}
|
|
uLoops++;
|
|
}
|
|
|
|
// Do it.
|
|
if(uLoops) {
|
|
Scroll(SB_VERT, uSBCode, 0, NULL, uScroll * uLoops);
|
|
}
|
|
}
|
|
|
|
pMsg->lRetval = (LPARAM)1;
|
|
pMsg->bSetRetval = TRUE;
|
|
}
|
|
|
|
void CPaneCX::PreWMHackedMouseWheel(PaneMessage *pMsg)
|
|
{
|
|
// Shunt.
|
|
WPARAM wSubst = pMsg->wParam;
|
|
pMsg->wParam = wSubst << 16;
|
|
PreWMMouseWheel(pMsg);
|
|
pMsg->wParam = wSubst;
|
|
}
|
|
#endif
|
|
|
|
void CPaneCX::Scroll(int iBars, UINT uSBCode, UINT uPos, HWND hCtrl, UINT uTimes)
|
|
{
|
|
// Provide a way to keep flow of control but not return early.
|
|
BOOL bContinue = TRUE;
|
|
|
|
if((iBars == SB_VERT || iBars == SB_BOTH) && IsVScrollBarOn() && GetHeight() < GetDocumentHeight()) {
|
|
// Calc an area leaving at least one page.
|
|
// Align the pixel and twips boundary, and check again to see if we're really
|
|
// doing anything.
|
|
// Account for Horiz scroll bar getting in the way.
|
|
int32 lScrollable = GetDocumentHeight() - GetHeight();
|
|
if(IsHScrollBarOn()) {
|
|
lScrollable += sysInfo.m_iScrollHeight;
|
|
}
|
|
if(lScrollable > 0) {
|
|
int32 lOldOrgY = GetOriginY();
|
|
int32 lScrollTwips = 0;
|
|
double fYPos = 0.0f;
|
|
int32 lTrack = 0;
|
|
|
|
// Figure out what we're doing.
|
|
switch(uSBCode) {
|
|
case SB_PAGEUP:
|
|
lScrollTwips = (-1 * GetHeight()) + VSCROLL_LINE;
|
|
break;
|
|
case SB_PAGEDOWN:
|
|
lScrollTwips = GetHeight() - VSCROLL_LINE;
|
|
break;
|
|
case SB_LINEUP:
|
|
lScrollTwips = -1 * VSCROLL_LINE;
|
|
break;
|
|
case SB_LINEDOWN:
|
|
lScrollTwips = VSCROLL_LINE;
|
|
break;
|
|
case SB_THUMBPOSITION:
|
|
case SB_THUMBTRACK:
|
|
// User is dragging the thumb tack.
|
|
// Only move if we've moved more than a single pixel, or the display
|
|
// gets messed up
|
|
fYPos = (double)uPos / (double)GetPageY();
|
|
lTrack = (int32)((fYPos * lScrollable)+0.5);
|
|
break;
|
|
case SB_TOP:
|
|
lScrollTwips = -1 * GetOriginY();
|
|
break;
|
|
case SB_BOTTOM:
|
|
lScrollTwips = lScrollable - GetOriginY();
|
|
break;
|
|
default:
|
|
bContinue = FALSE;
|
|
break;
|
|
}
|
|
|
|
if(bContinue) {
|
|
// Check to see if we need to do further math....
|
|
if(uSBCode != SB_THUMBPOSITION && uSBCode != SB_THUMBTRACK) {
|
|
lTrack = GetOriginY();
|
|
lTrack += lScrollTwips * (int32)uTimes;
|
|
|
|
if (lTrack < 0)
|
|
lTrack = 0;
|
|
else if(lTrack > lScrollable)
|
|
lTrack = lScrollable;
|
|
}
|
|
|
|
// Position the scroll bar on an even pixel boundary
|
|
RealizeScrollBars(NULL, &lTrack);
|
|
|
|
// Figure the distance we actually scrolled.
|
|
int32 lPixAct = lOldOrgY - GetOriginY();
|
|
if(lPixAct) {
|
|
::ScrollWindowEx(GetPane(), 0, (int) lPixAct, NULL, NULL, NULL, NULL, SW_INVALIDATE |
|
|
SW_ERASE | SW_SCROLLCHILDREN);
|
|
::UpdateWindow(GetPane());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset for horizontal test.
|
|
bContinue = TRUE;
|
|
|
|
if((iBars == SB_HORZ || iBars == SB_BOTH) && IsHScrollBarOn() && GetWidth() < GetDocumentWidth()) {
|
|
// Calc an area leaving at least one page.
|
|
// Align the pixel and twips boundary, and check again to see if we're really
|
|
// doing anything.
|
|
// Account for vertical scroller getting in the way.
|
|
int32 lScrollable = GetDocumentWidth() - GetWidth();
|
|
if(IsVScrollBarOn()) {
|
|
lScrollable += sysInfo.m_iScrollWidth;
|
|
}
|
|
if(lScrollable > 0) {
|
|
int32 lOldOrgX = GetOriginX();
|
|
int32 lScrollTwips = 0;
|
|
double fXPos = 0.0f;
|
|
int32 lTrack = 0;
|
|
|
|
// Figure out what we're doing.
|
|
switch(uSBCode) {
|
|
case SB_PAGELEFT:
|
|
lScrollTwips = -1 * GetWidth();
|
|
break;
|
|
case SB_PAGERIGHT:
|
|
lScrollTwips = GetWidth();
|
|
break;
|
|
case SB_LINELEFT:
|
|
case SB_LINERIGHT:
|
|
lScrollTwips = HSCROLL_LINE;
|
|
if(uSBCode == SB_LINELEFT) {
|
|
lScrollTwips *= -1;
|
|
}
|
|
break;
|
|
case SB_THUMBPOSITION:
|
|
case SB_THUMBTRACK:
|
|
// User is dragging the thumb tack.
|
|
// Only move if we've moved more than a single pixel, or the display
|
|
// gets messed up.
|
|
fXPos = (double)uPos / (double)GetPageX();
|
|
lTrack = (int32)((fXPos * lScrollable)+0.5);
|
|
break;
|
|
default:
|
|
bContinue = FALSE;
|
|
break;
|
|
}
|
|
|
|
if(bContinue) {
|
|
// Check to see if we need to do further math....
|
|
if(uSBCode != SB_THUMBPOSITION && uSBCode != SB_THUMBTRACK) {
|
|
lTrack = GetOriginX();
|
|
lTrack += lScrollTwips * (int32)uTimes;
|
|
|
|
if(lTrack > lScrollable)
|
|
lTrack = lScrollable;
|
|
if(lTrack < 0)
|
|
lTrack = 0;
|
|
}
|
|
|
|
// Position the scroll bar.
|
|
RealizeScrollBars(&lTrack);
|
|
|
|
// Figure the distance we actually scrolled.
|
|
int32 lPixAct = lOldOrgX - GetOriginX();
|
|
if(lPixAct) {
|
|
::ScrollWindowEx(GetPane(), (int) lPixAct, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE |
|
|
SW_ERASE | SW_SCROLLCHILDREN);
|
|
::UpdateWindow(GetPane());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPaneCX::GetWindowOffset(int32 *pX, int32 *pY)
|
|
{
|
|
RECT rWindow;
|
|
::GetWindowRect(GetPane(), &rWindow);
|
|
|
|
*pX = rWindow.left;
|
|
*pY = rWindow.top;
|
|
return;
|
|
}
|
|
|
|
void CPaneCX::MakeElementVisible(int32 lX, int32 lY)
|
|
{
|
|
// Figure out if any element is there.
|
|
XY Point;
|
|
Point.x = lX;
|
|
Point.y = lY;
|
|
|
|
LO_Element *pElement = GetLayoutElement(Point, NULL);
|
|
if(pElement == NULL) {
|
|
SetDocPosition(GetContext(), FE_VIEW, lX, lY);
|
|
return;
|
|
}
|
|
|
|
// Figure up the coords of the element.
|
|
LTRB Rect;
|
|
LO_Any *pAny = &(pElement->lo_any);
|
|
Rect.left = pAny->x + pAny->x_offset;
|
|
Rect.top = pAny->y + pAny->y_offset;
|
|
Rect.right = Rect.left + pAny->width;
|
|
Rect.bottom = Rect.top + pAny->height;
|
|
|
|
// Is it currently Fully On Screen?
|
|
// Disregard the Y values (we'll want to scroll exactly on the Y, but perhaps not on the X).
|
|
// To the right?
|
|
if(Rect.left >= GetOriginX()) {
|
|
// To the left?
|
|
if(Rect.right <= GetOriginX() + GetWidth()) {
|
|
// It's on the X view.
|
|
// Use the current X origin.
|
|
lX = GetOriginX();
|
|
SetDocPosition(GetContext(), FE_VIEW, lX, lY);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// X wasn't on screen fully, so we're going to use very exact values when scrolling
|
|
// for whatever effect this gives....
|
|
SetDocPosition(GetContext(), FE_VIEW, lX, lY);
|
|
}
|
|
|
|
void CPaneCX::PreNavCenterQueryPosition(PaneMessage *pMessage)
|
|
{
|
|
/*
|
|
// Only handle if we're a NavCenter HTML Pane.
|
|
if(IsNavCenterHTMLPane()) {
|
|
NAVCENTPOS *pPos = (NAVCENTPOS *)pMessage->lParam;
|
|
|
|
// We like being at the bottom.
|
|
pPos->m_iYDisposition = INT_MAX;
|
|
|
|
// We like being this many units in size.
|
|
pPos->m_iYVector = 100;
|
|
|
|
// Handled.
|
|
pMessage->lRetval = NULL;
|
|
pMessage->bSetRetval = TRUE;
|
|
}
|
|
*/
|
|
}
|
|
|
|
void CPaneCX::PreIdleUpdateCmdUI(PaneMessage *pMsg)
|
|
{
|
|
// Don't want to update CMD UI unless we have a frame parent.
|
|
// This effectively stops CMD UI in the NavCenter HTML pane
|
|
// from messing with the UI state when docked.
|
|
if(IsNavCenterHTMLPane()) {
|
|
// Handled.
|
|
pMsg->lRetval = NULL;
|
|
pMsg->bSetRetval = TRUE;
|
|
}
|
|
}
|
|
|
|
#ifdef XP_WIN16
|
|
HINSTANCE CPaneCX::GetSegment()
|
|
{
|
|
// Form elements on a per context basis receive their own segment.
|
|
HINSTANCE hRetval = NULL;
|
|
|
|
if(NULL == m_hTextElementSegment) {
|
|
m_hTextElementSegment = ::GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, (UINT) 8 * 1024);
|
|
}
|
|
if(m_hTextElementSegment && NULL == m_lpTextElementHeap) {
|
|
// Initialize the segment.
|
|
m_lpTextElementHeap = ::GlobalLock(m_hTextElementSegment);
|
|
if(m_lpTextElementHeap) {
|
|
::LocalInit(HIWORD((LONG)m_lpTextElementHeap), 0, (WORD)(::GlobalSize(m_hTextElementSegment) - 16));
|
|
::UnlockSegment(HIWORD((LONG)m_lpTextElementHeap));
|
|
}
|
|
}
|
|
|
|
if(m_lpTextElementHeap) {
|
|
hRetval = (HINSTANCE)HIWORD((LONG)m_lpTextElementHeap);
|
|
}
|
|
|
|
return(hRetval);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LRESULT
|
|
CALLBACK
|
|
#ifndef _WIN32
|
|
_export
|
|
#endif
|
|
PaneProc(HWND hPane, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
#ifdef XP_WIN32
|
|
const char *pPropName = STR_CPANECX; // Not a UI string.
|
|
#else
|
|
const char *pPropNameHi = STR_CPANECX_HI;
|
|
const char *pPropNameLo = STR_CPANECX_LO;
|
|
#endif
|
|
PaneMessage message(wParam, lParam);
|
|
|
|
// Get the property (which is a this pointer).
|
|
void *pvThis = NULL;
|
|
#ifdef XP_WIN32
|
|
pvThis = (void *)GetProp(hPane, pPropName);
|
|
#else
|
|
pvThis = (void *)MAKELONG(GetProp(hPane, pPropNameLo), GetProp(hPane, pPropNameHi));
|
|
#endif
|
|
if(pvThis) {
|
|
CPaneCX *pThis = VOID2CX(pvThis, CPaneCX);
|
|
|
|
// Messages handled BEFORE calling other window procedure.
|
|
// Make calls here when you don't care about the LRESULT
|
|
// of the normal message handler or don't want the normal
|
|
// message handler being called at all (by marking that
|
|
// the return value has been set).
|
|
switch(uMsg) {
|
|
case WM_PAINT:
|
|
pThis->PreWMPaint(&message);
|
|
break;
|
|
case WM_ERASEBKGND:
|
|
pThis->PreWMErasebkgnd(&message);
|
|
break;
|
|
case WM_VSCROLL:
|
|
pThis->PreWMVScroll(&message);
|
|
break;
|
|
case WM_HSCROLL:
|
|
pThis->PreWMHScroll(&message);
|
|
break;
|
|
/*
|
|
case WM_NAVCENTER_QUERYPOSITION:
|
|
pThis->PreNavCenterQueryPosition(&message);
|
|
break;
|
|
*/
|
|
case WM_IDLEUPDATECMDUI:
|
|
pThis->PreIdleUpdateCmdUI(&message);
|
|
break;
|
|
|
|
#if defined(XP_WIN32) && _MSC_VER >= 1100
|
|
case WM_MOUSEWHEEL:
|
|
pThis->PreWMMouseWheel(&message);
|
|
break;
|
|
#endif
|
|
default:
|
|
// Handle non constant messages here.
|
|
#if defined(XP_WIN32) && _MSC_VER >= 1100
|
|
if(uMsg == msg_MouseWheel) {
|
|
pThis->PreWMHackedMouseWheel(&message);
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
// Call previous window proc.
|
|
if(!message.bSetRetval) {
|
|
WNDPROC pPrevProc = pThis->GetSubclassedProc();
|
|
if(pPrevProc) {
|
|
message.lRetval = CallWindowProc(pPrevProc, hPane, uMsg, wParam, lParam);
|
|
message.bSetRetval = TRUE;
|
|
}
|
|
}
|
|
|
|
// Notifications handled AFTER calling other window procedure.
|
|
// Make calls here when you care about the LRESULT
|
|
// of any above message handler, or want to handle a
|
|
// message if no one else did before the default window
|
|
// procedure is invoked..
|
|
switch(uMsg) {
|
|
case WM_SIZE:
|
|
pThis->AftWMSize(&message);
|
|
break;
|
|
case WM_DESTROY:
|
|
pThis->AftWMDestroy(&message);
|
|
break;
|
|
case WM_MOUSEACTIVATE:
|
|
pThis->AftWMMouseActivate(&message);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Default handler if nothing happened.
|
|
if(!message.bSetRetval) {
|
|
message.lRetval = DefWindowProc(hPane, uMsg, wParam, lParam);
|
|
message.bSetRetval = TRUE;
|
|
}
|
|
}
|
|
else {
|
|
// Either someone subclassed and we need to unsubclass in
|
|
// their stack, or this is getting called before we
|
|
// set the property on the window.
|
|
// Don't crash or do anything stupid, but we currently don't
|
|
// attempt to handle.
|
|
message.lRetval = DefWindowProc(hPane, uMsg, wParam, lParam);
|
|
message.bSetRetval = TRUE;
|
|
}
|
|
|
|
ASSERT(message.bSetRetval);
|
|
return(message.lRetval);
|
|
}
|
|
|
|
// Subclass or unsubclass a window.
|
|
BOOL CPaneCX::SubClass(HWND hWnd, BOOL bSubClass)
|
|
{
|
|
#ifdef MOZ_NGLAYOUT
|
|
// We want all events to go to the WebWidget window embedded in this
|
|
// one and not here at all.
|
|
return TRUE;
|
|
#else
|
|
BOOL bRetval = FALSE;
|
|
#ifdef XP_WIN32
|
|
const char *pPropName = STR_CPANECX; // Not a UI string.
|
|
#else
|
|
const char *pPropNameHi = STR_CPANECX_HI; // Not a UI string.
|
|
const char *pPropNameLo = STR_CPANECX_LO; // Not a UI string.
|
|
#endif
|
|
|
|
if(hWnd) {
|
|
if(bSubClass) {
|
|
ASSERT(!m_pPrevProc);
|
|
|
|
// Make sure no one else is already doing this window.
|
|
// We could add the support by making each property
|
|
// name unique by pid() then ptr, but no need right now.
|
|
if(!
|
|
#ifdef XP_WIN32
|
|
(::GetProp(hWnd, pPropName))
|
|
#else
|
|
(::GetProp(hWnd, pPropNameLo) || ::GetProp(hWnd, pPropNameHi))
|
|
#endif
|
|
) {
|
|
m_pPrevProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)PaneProc);
|
|
if(m_pPrevProc) {
|
|
BOOL bAddProp;
|
|
#ifdef XP_WIN32
|
|
bAddProp = ::SetProp(hWnd, pPropName, (HANDLE)this);
|
|
#else
|
|
bAddProp = ::SetProp(hWnd, pPropNameHi, (HANDLE)HIWORD(this));
|
|
if(bAddProp) {
|
|
bAddProp = ::SetProp(hWnd, pPropNameLo, (HANDLE)LOWORD(this));
|
|
}
|
|
#endif
|
|
if(bAddProp) {
|
|
bRetval = TRUE;
|
|
}
|
|
else {
|
|
LONG lCheck = ::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)m_pPrevProc);
|
|
m_pPrevProc = NULL;
|
|
ASSERT(lCheck == (LONG)PaneProc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
ASSERT(m_pPrevProc);
|
|
|
|
void *pThis = NULL;
|
|
#ifdef XP_WIN32
|
|
pThis = (void *)::RemoveProp(hWnd, pPropName);
|
|
#else
|
|
pThis = (void *)MAKELONG(::RemoveProp(hWnd, pPropNameLo), ::RemoveProp(hWnd, pPropNameHi));
|
|
#endif
|
|
ASSERT(pThis && pThis == (void *)this);
|
|
if(pThis && pThis == (void *)this) {
|
|
LONG lOurProc = ::GetWindowLong(hWnd, GWL_WNDPROC);
|
|
ASSERT(lOurProc && lOurProc == (LONG)PaneProc);
|
|
if(lOurProc && lOurProc == (LONG)PaneProc) {
|
|
LONG lCheck = ::SetWindowLong(hWnd, GWL_WNDPROC, (LONG)m_pPrevProc);
|
|
ASSERT(lCheck && lCheck == (LONG)PaneProc);
|
|
if(lCheck && lCheck == (LONG)PaneProc) {
|
|
bRetval = TRUE;
|
|
}
|
|
}
|
|
m_pPrevProc = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(bRetval);
|
|
#endif
|
|
}
|
|
|
|
|
|
void CPaneCX::DisplayBuiltin(MWContext *pContext, int iLocation, LO_BuiltinStruct *pBuiltin_struct)
|
|
{
|
|
HWND cView = GetPane();
|
|
CWnd* cWnd = NULL;
|
|
char* type = NULL;
|
|
if ( !pBuiltin_struct || !(cWnd = CWnd::FromHandle(cView))){
|
|
XP_ASSERT(FALSE); //very invalid stuff.
|
|
return;
|
|
}
|
|
// Ok, we have the parent window. we need to know where to display it.
|
|
int xPos = pBuiltin_struct->x;
|
|
int yPos = pBuiltin_struct->y;
|
|
int width = pBuiltin_struct->width;
|
|
int height = pBuiltin_struct->height;
|
|
|
|
#ifdef ENDER
|
|
type = LO_GetBuiltInAttribute(pBuiltin_struct, "type"); //it is very possible to have NULL because of bad HTML
|
|
if (!type)
|
|
TRACE("Bad object tag NULL\n");
|
|
if (!type || (XP_STRCMP(type,"builtin/htmlarea") && XP_STRCMP(type,"builtin/attachments"))){ //left to default to tree here
|
|
#endif //ENDER
|
|
|
|
char* url = LO_GetBuiltInAttribute(pBuiltin_struct, "data");
|
|
char* target = LO_GetBuiltInAttribute(pBuiltin_struct, "target");
|
|
if (pBuiltin_struct->FE_Data == NULL ){
|
|
char* templateType = LO_GetBuiltInAttribute(pBuiltin_struct, "template");
|
|
|
|
#ifdef OJI
|
|
CRDFContentView* pWnd = CRDFContentView::DisplayRDFTreeFromSHACK(pContext, cWnd, xPos, yPos, width, height, url == NULL ? "" :url , templateType, pBuiltin_struct->attributes.n, pBuiltin_struct->attributes.names, pBuiltin_struct->attributes.values);
|
|
#else
|
|
CRDFContentView* pWnd = CRDFContentView::DisplayRDFTreeFromSHACK(pContext, cWnd, xPos, yPos, width, height, url == NULL ? "" :url , templateType, pBuiltin_struct->attribute_cnt, pBuiltin_struct->attribute_list, pBuiltin_struct->value_list);
|
|
#endif
|
|
|
|
CRDFOutliner *pOutliner = (CRDFOutliner *)pWnd->GetOutlinerParent()->GetOutliner();
|
|
pOutliner->SetWindowTarget(target);
|
|
pBuiltin_struct->FE_Data = pWnd;
|
|
pBuiltin_struct->htPane = HT_GetPane(pOutliner->GetHTView());
|
|
}
|
|
#ifdef ENDER
|
|
}
|
|
else if (type && !XP_STRCMP(type,"builtin/htmlarea")) { //ENDER
|
|
if (pBuiltin_struct->FE_Data == NULL) {
|
|
//create a new CPaneCX
|
|
CNetscapeDoc* pDoc = new CNetscapeDoc();
|
|
CNetscapeEditView* pWnd = new CNetscapeEditView();
|
|
pWnd->SetEmbedded(TRUE);
|
|
RECT rect;
|
|
rect.left=xPos;
|
|
rect.top=yPos;
|
|
rect.right=xPos+width;
|
|
rect.bottom=yPos+height;
|
|
if (!pWnd->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, rect, cWnd, ID_ENDER, NULL))
|
|
{
|
|
TRACE("Warning: could not create view for frame.\n");
|
|
delete pDoc;
|
|
delete pWnd;
|
|
}
|
|
else
|
|
{
|
|
pBuiltin_struct->FE_Data = pWnd;
|
|
CWinCX* pDontCare = new CWinCX((CGenericDoc *)pDoc,
|
|
((CGenericView *)cWnd)->GetFrame(), (CGenericView *)pWnd);
|
|
if (pDontCare && pDontCare->GetContext())
|
|
{
|
|
pDontCare->GetContext()->is_editor = TRUE;
|
|
pWnd->SetContext(pDontCare);
|
|
pDontCare->Initialize(pDontCare->CDCCX::IsOwnDC(), &rect);
|
|
pDontCare->NormalGetUrl(EDT_NEW_DOC_URL);
|
|
pWnd->UpdateWindow();
|
|
cWnd->InvalidateRect(&rect); //may be redundant, if flashing this is why .mjudge
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (type && !XP_STRCMP(type,"builtin/attachments"))
|
|
{
|
|
if (pBuiltin_struct->FE_Data == NULL)
|
|
{
|
|
CEmbeddedAttachList *pWnd = new CEmbeddedAttachList();
|
|
if (pWnd)
|
|
{
|
|
if (pWnd->Create(cWnd,IDC_ATTACH))
|
|
pBuiltin_struct->FE_Data = pWnd;
|
|
else
|
|
delete pWnd;
|
|
RECT rect;
|
|
rect.left=xPos;
|
|
rect.top=yPos;
|
|
rect.right=xPos+width;
|
|
rect.bottom=yPos+height;
|
|
pWnd->MoveWindow(&rect,TRUE);
|
|
pWnd->ShowWindow(SW_SHOW);
|
|
}
|
|
}
|
|
}
|
|
else if (type)
|
|
TRACE("Bad object tag %s\n",type);
|
|
#endif //ENDER
|
|
}
|
|
|
|
void CPaneCX::FreeBuiltinElement(MWContext *pContext, LO_BuiltinStruct *pBuiltin_struct)
|
|
{
|
|
char* type = NULL;
|
|
if ( !pBuiltin_struct || !pContext ){
|
|
XP_ASSERT(FALSE); //very invalid stuff.
|
|
return;
|
|
}
|
|
|
|
#ifdef ENDER
|
|
type = LO_GetBuiltInAttribute(pBuiltin_struct, "type"); //it is very possible to have NULL because of bad HTML
|
|
if (!type)
|
|
TRACE("Bad object tag NULL\n");
|
|
|
|
if (!type || (XP_STRCMP(type,"builtin/htmlarea") && XP_STRCMP(type,"builtin/attachments"))){ //left to default to tree here
|
|
#endif //ENDER
|
|
CRDFContentView* pWnd = (CRDFContentView*)pBuiltin_struct->FE_Data;
|
|
if (pWnd)
|
|
pWnd->DestroyWindow();
|
|
#ifdef ENDER
|
|
}
|
|
else
|
|
if (type && !XP_STRCMP(type,"builtin/htmlarea")){
|
|
CObject* pObj = (CObject *)pBuiltin_struct->FE_Data;
|
|
if (pObj && pObj->IsKindOf( RUNTIME_CLASS( CNetscapeEditView ))){
|
|
CNetscapeEditView* pWnd = (CNetscapeEditView *)pObj;
|
|
CNetscapeDoc* pDoc = (CNetscapeDoc *)pWnd->GetDocument();
|
|
//warning! do not allow the CWinCX to RE-FREE its frame.
|
|
//we are borrowning the frame from the "browser window or layer"
|
|
//call ClearFrame to "Clear the frame"
|
|
CWinCX *pCX = pWnd->GetContext();
|
|
if (pCX){
|
|
if (pDoc)
|
|
delete pDoc;
|
|
pCX->ClearFrame();
|
|
EDT_DestroyEditBuffer(pCX->GetContext());
|
|
}
|
|
pWnd->DestroyWindow();
|
|
}
|
|
}
|
|
else if (type&& !XP_STRCMP(type,"builtin/attachments"))
|
|
{
|
|
CObject* pObj = (CObject *)pBuiltin_struct->FE_Data;
|
|
if (pObj && pObj->IsKindOf( RUNTIME_CLASS( CEmbeddedAttachList )))
|
|
{
|
|
((CEmbeddedAttachList *)pObj)->DestroyWindow();
|
|
}
|
|
|
|
}
|
|
#endif //ENDER
|
|
}
|