gecko-dev/cmd/macfe/gui/CHTMLClickRecord.cp

324 строки
8.7 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.
*/
// CHTMLClickRecord.cp
#include "CHTMLClickRecord.h"
#include "CNSContext.h"
#include "CContextMenuAttachment.h"
#include "CApplicationEventAttachment.h"
#include "layers.h"
#include "mimages.h"
#include "proto.h"
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
CHTMLClickRecord::CHTMLClickRecord(
Point inLocalWhere,
const SPoint32& inImageWhere,
CNSContext* inContext,
LO_Element* inElementelement,
CL_Layer* inLayer)
:
mLocalWhere(inLocalWhere),
mImageWhere(inImageWhere),
mElement(inElementelement),
mAnchorData(NULL),
mContext(inContext),
mLayer(inLayer),
mClickKind(eWaiting),
mClickIsInSelection(false)
{
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// Figures out everything (anchors, click kind) about the current cursor position
// called only once -- this is completely horrible
void CHTMLClickRecord::Recalc(void)
{
if (mElement == NULL)
{
mClickKind = eNone;
return;
}
switch (mElement->type)
{
case LO_IMAGE:
mClickKind = CalcImageClick();
break;
case LO_TEXT:
mClickKind = CalcTextClick();
break;
case LO_EDGE:
mClickKind = CalcEdgeClick();
break;
default:
mClickKind = eNone;
break;
}
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
EClickKind CHTMLClickRecord::CalcImageClick(void)
{
EClickKind theKind;
// Get the image URL
PA_LOCK(mImageURL, char *, (char*)mElement->lo_image.image_url);
PA_UNLOCK(loImage->image_url);
// find with layer coordinates (mImageWhere) not local coordinates
theKind = FindImagePart ( *mContext, &mElement->lo_image, &mImageWhere,
&mClickURL, &mWindowTarget, mAnchorData );
// is this image in the selection? ¥¥¥ THIS DOESN'T WORK because layout doesn't
// mark images as in the selection...one day...
//mClickIsInSelection = (mElement->lo_image.image_attr->attrmask & LO_ELE_SELECTED) != 0;
return theKind;
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
EClickKind CHTMLClickRecord::CalcTextClick(void)
{
EClickKind theKind = eNone;
if (mElement->lo_text.anchor_href)
{
theKind = eTextAnchor;
PA_LOCK(mClickURL, char*, (char*)mElement->lo_text.anchor_href->anchor);
PA_UNLOCK(mElement->lo_text.anchor_href->anchor);
PA_LOCK(mWindowTarget, char *,(char*)mElement->lo_text.anchor_href->target);
PA_UNLOCK(mElement->lo_text.anchor_href->target);
}
// is this click in the selection?
mClickIsInSelection = (mElement->lo_text.ele_attrmask & LO_ELE_SELECTED) != 0;
return theKind;
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// ¥
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
EClickKind CHTMLClickRecord::CalcEdgeClick(void)
{
EClickKind theKind = eNone;
if (mElement->lo_edge.movable)
{
theKind = eEdge;
mIsVerticalEdge = mElement->lo_edge.is_vertical;
mEdgeLowerBound = mElement->lo_edge.left_top_bound;
mEdgeUpperBound = mElement->lo_edge.right_bottom_bound;
}
return theKind;
}
Boolean CHTMLClickRecord::IsClickOnAnchor(void) const
{
return ((mClickKind != eNone) && (mClickKind != eEdge));
}
Boolean CHTMLClickRecord::IsClickOnEdge(void) const
{
return (mClickKind == eEdge);
}
#if 0
void CClickRecord::ResetNamedWindow()
{
fWindowTarget = "";
}
#endif
// Pixels hang below their points, and thus the pixels equal to
// the top/left points are inside, but equal to the bottom/right
// of the bounding box are outside.
Boolean CHTMLClickRecord::PixelReallyInElement(
const SPoint32& inImagePoint,
LO_Element* inElement)
{
// account for image border
Int32 borderWidth = 0;
if (inElement->type == LO_IMAGE)
borderWidth = inElement->lo_image.border_width;
Int32 realX = inElement->lo_any.x + inElement->lo_any.x_offset;
Int32 realY = inElement->lo_any.y + inElement->lo_any.y_offset;
return
realY <= inImagePoint.v
&& inImagePoint.v < (realY + inElement->lo_any.height + (2 * borderWidth))
&& realX <= inImagePoint.h
&& inImagePoint.h < (realX + inElement->lo_any.width + (2 * borderWidth));
}
//-----------------------------------
EClickState CHTMLClickRecord::WaitForMouseAction(
const SMouseDownEvent& inMouseDown,
LAttachable* inAttachable,
Int32 inDelay,
Boolean inExecuteContextMenuAttachment)
//-----------------------------------
{
// ¥ The new way. Give a context menu attachment a chance to
// execute. If this returns true ("execute host"), there is no attachment,
// so do things the old way. If it returns false, assume the popup has been
// handled. This can go away if the browser folkies decide to use
// the attachment mechanism.
CContextMenuAttachment::SExecuteParams params;
params.inMouseDown = &inMouseDown;
params.outResult = eMouseUndefined;
if (inExecuteContextMenuAttachment)
{
inAttachable->ExecuteAttachments(
CContextMenuAttachment::msg_ContextMenu,
(void*)&params);
}
if (params.outResult != eMouseUndefined)
return (EClickState)params.outResult;
// ¥ The old way.
return WaitForMouseAction(
inMouseDown.whereLocal,
inMouseDown.macEvent.when,
inDelay);
} // CHTMLClickRecord::WaitForMouseAction
//-----------------------------------
EClickState CHTMLClickRecord::WaitForMouseAction(
const Point& inInitialPoint,
Int32 inWhen,
Int32 inDelay)
//-----------------------------------
{
if (CApplicationEventAttachment::CurrentEventHasModifiers(controlKey))
{
return eMouseTimeout;
}
// Spin on mouse down and wait for either the user to start
// dragging or for the popup delay to expire or for mouse up
// (in which case we just fall through)
while (::StillDown())
{
Point theCurrentPoint;
::GetMouse(&theCurrentPoint);
if ((abs(theCurrentPoint.h - inInitialPoint.h) >= kMouseHysteresis) ||
(abs(theCurrentPoint.v - inInitialPoint.v) >= kMouseHysteresis))
return eMouseDragging;
Int32 now = ::TickCount();
if (abs( now - inWhen ) > inDelay)
return eMouseTimeout;
}
return eMouseUpEarly;
} // CHTMLClickRecord::WaitForMouseAction
//-----------------------------------
void CHTMLClickRecord::CalculatePosition()
// Snarfed from mclick.cp
// Figures out everything (anchors, click kind) about the current cursor position
// called only once -- this is completely horrible
//
// Figure all this out even if the click is in the selection because we'll still
// need it if the selection click isn't a drag.
//-----------------------------------
{
if ( mClickKind != eWaiting )
return;
if ( !mElement )
{
mClickKind = eNone;
return;
}
if ( mElement->type == LO_IMAGE )
{
// ¥ click in the image. Complicated case:
mClickKind = FindImagePart(*mContext, &mElement->lo_image, &mImageWhere, &mImageURL, &mWindowTarget, mAnchorData);
}
else if ( mElement->type == LO_TEXT && mElement->lo_text.anchor_href )
{
if ( mElement->lo_text.anchor_href )
{
mClickKind = eTextAnchor;
PA_LOCK( mClickURL, char*, (char*)mElement->lo_text.anchor_href->anchor );
PA_UNLOCK( mElement->lo_text.anchor_href->anchor );
PA_LOCK( mWindowTarget, char *,(char*)mElement->lo_text.anchor_href->target );
PA_UNLOCK( mElement->lo_text.anchor_href->target );
}
else
mClickKind = eNone;
}
else if ( mElement->type == LO_EDGE && mElement->lo_edge.movable )
{
mClickKind = eEdge;
mIsVerticalEdge = mElement->lo_edge.is_vertical;
mEdgeLowerBound = mElement->lo_edge.left_top_bound;
mEdgeUpperBound = mElement->lo_edge.right_bottom_bound;
}
else
mClickKind = eNone;
}
Boolean CHTMLClickRecord::IsAnchor()
{
CalculatePosition();
return ((mClickKind != eNone) && (mClickKind != eEdge));
}
Boolean CHTMLClickRecord::IsEdge()
{
CalculatePosition();
return (mClickKind == eEdge);
}