mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-26 02:02:33 +00:00
425 lines
12 KiB
C++
425 lines
12 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.
|
|
*/
|
|
|
|
// gridedge.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "gridedge.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGridEdge
|
|
|
|
// Returns the rectangle, in pixels, of where to position the edge,
|
|
// The coordinates are relative to the owning context's view
|
|
static void
|
|
GetGridEdgeRect(LO_EdgeStruct* pEdge, CWinCX* pOwnerCX, CRect &rect)
|
|
{
|
|
int32 lAlign = pEdge->x + pEdge->x_offset;
|
|
int32 lLeft = pOwnerCX->Twips2PixX(lAlign);
|
|
|
|
lAlign = pEdge->y + pEdge->y_offset;
|
|
int32 lTop = pOwnerCX->Twips2PixY(lAlign);
|
|
|
|
lAlign = pEdge->x + pEdge->x_offset + pEdge->width;
|
|
int32 lRight = pOwnerCX->Twips2PixX(lAlign);
|
|
|
|
lAlign = pEdge->y + pEdge->y_offset + pEdge->height;
|
|
int32 lBottom = pOwnerCX->Twips2PixY(lAlign);
|
|
|
|
rect.left = CASTINT(lLeft);
|
|
rect.top = CASTINT(lTop);
|
|
rect.right = CASTINT(lRight);
|
|
rect.bottom = CASTINT(lBottom);
|
|
}
|
|
|
|
CGridEdge::CGridEdge(LO_EdgeStruct *pEdge, CWinCX *pOwnerCX)
|
|
{
|
|
// Set our members.
|
|
m_pEdge = pEdge;
|
|
m_pCX = pOwnerCX;
|
|
|
|
// Not currently tracking.
|
|
m_bTracking = FALSE;
|
|
|
|
m_bParentClipChildren = FALSE;
|
|
|
|
// We need to create a window for ourselves.
|
|
CRect crRect;
|
|
|
|
GetGridEdgeRect(m_pEdge, m_pCX, crRect);
|
|
|
|
DWORD dwEdgeStyle = WS_CHILD | WS_CLIPSIBLINGS;
|
|
if(pEdge->visible) {
|
|
// Make it visible.
|
|
dwEdgeStyle |= WS_VISIBLE;
|
|
}
|
|
|
|
CreateEx(0, NULL, "GridEdge", dwEdgeStyle,
|
|
crRect.left, crRect.top,
|
|
crRect.right - crRect.left,
|
|
crRect.bottom - crRect.top,
|
|
m_pCX->GetPane(), (HMENU) 0, NULL);
|
|
}
|
|
|
|
CGridEdge::~CGridEdge()
|
|
{
|
|
// If we were tracking, then let our clipped region go, etc.
|
|
if(m_bTracking == TRUE) {
|
|
// Release capture.
|
|
ReleaseCapture();
|
|
|
|
// Release the bounds established on the mouse.
|
|
::ClipCursor(NULL);
|
|
|
|
// Invert the tracker (return screen to normal state).
|
|
InvertTracker();
|
|
}
|
|
|
|
// Destroy our window.
|
|
DestroyWindow();
|
|
|
|
// Clear our members.
|
|
m_pEdge = NULL;
|
|
m_pCX = NULL;
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CGridEdge, CWnd)
|
|
//{{AFX_MSG_MAP(CGridEdge)
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_SETCURSOR()
|
|
ON_WM_PAINT()
|
|
ON_WM_LBUTTONDBLCLK()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CGridEdge message handlers
|
|
|
|
void CGridEdge::UpdateEdge(LO_EdgeStruct *pEdge) {
|
|
// Update what our edge is.
|
|
m_pEdge = pEdge;
|
|
|
|
// See if our visibility is a concern.
|
|
if(m_pEdge->visible && IsWindowVisible() == FALSE) {
|
|
ShowWindow(SW_SHOW);
|
|
}
|
|
else if(!m_pEdge->visible && IsWindowVisible()) {
|
|
ShowWindow(SW_HIDE);
|
|
}
|
|
|
|
// Position the window properly
|
|
CRect crRect;
|
|
|
|
GetGridEdgeRect(m_pEdge, m_pCX, crRect);
|
|
MoveWindow(crRect);
|
|
}
|
|
|
|
void CGridEdge::InvertTracker() {
|
|
// Get our frame context's DC (need to draw over children). The tracker
|
|
// coordinates are already in the frame window's coordinate system
|
|
if(m_pCX->GetFrame()->GetFrameWnd() != NULL) {
|
|
CDC *pDC = m_pCX->GetFrame()->GetFrameWnd()->GetDC();
|
|
|
|
// Invert a brush pattern.
|
|
#ifdef XP_WIN16
|
|
pDC->PatBlt(m_crTracker.left, m_crTracker.top, m_crTracker.Width(),
|
|
m_crTracker.Height(), DSTINVERT);
|
|
#else
|
|
CBrush *pBrush = CDC::GetHalftoneBrush();
|
|
HBRUSH hOldBrush = NULL;
|
|
if(pBrush != NULL) {
|
|
hOldBrush = (HBRUSH)SelectObject(pDC->m_hDC, pBrush->m_hObject);
|
|
}
|
|
|
|
pDC->PatBlt(m_crTracker.left, m_crTracker.top,
|
|
m_crTracker.Width(), m_crTracker.Height(), PATINVERT);
|
|
|
|
if(hOldBrush != NULL) {
|
|
SelectObject(pDC->m_hDC, hOldBrush);
|
|
}
|
|
#endif
|
|
|
|
m_pCX->GetFrame()->GetFrameWnd()->ReleaseDC(pDC);
|
|
}
|
|
}
|
|
|
|
void CGridEdge::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
// Only do something if we can resize.
|
|
if(CanResize() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// Capture mouse events.
|
|
SetCapture();
|
|
|
|
// Bound the mouse to a rectangle that is acceptable for use to perform a resize.
|
|
// Layout knows how big this should be, and it's stored in left_top_bound and
|
|
// right_bottom_bound (how these are interpreted depends on whether it's a vertical
|
|
// or horizontal edge)
|
|
CRect crRect;
|
|
|
|
// Start with the grid edge rect, and then use the bounds that layout has
|
|
GetGridEdgeRect(m_pEdge, m_pCX, crRect);
|
|
|
|
if(m_pEdge->is_vertical) {
|
|
crRect.left = CASTINT(m_pCX->Twips2PixX(m_pEdge->left_top_bound));
|
|
crRect.right = CASTINT(m_pCX->Twips2PixX(m_pEdge->right_bottom_bound));
|
|
|
|
} else {
|
|
crRect.top = CASTINT(m_pCX->Twips2PixY(m_pEdge->left_top_bound));
|
|
crRect.bottom = CASTINT(m_pCX->Twips2PixY(m_pEdge->right_bottom_bound));
|
|
}
|
|
|
|
::ClientToScreen(m_pCX->GetPane(), &crRect.TopLeft());
|
|
::ClientToScreen(m_pCX->GetPane(), &crRect.BottomRight());
|
|
|
|
TRACE("Clipping cursor to (%d,%d)(%d,%d)\n", crRect.left, crRect.top,
|
|
crRect.right, crRect.bottom);
|
|
::ClipCursor(crRect);
|
|
|
|
// Mark the point at which the mouse went down.
|
|
// This can be used to calculate the relative distance of the movement of the tracker.
|
|
m_cpLBDown = point;
|
|
|
|
// Set tracking state.
|
|
m_bTracking = TRUE;
|
|
|
|
// Update our tracker with our current coordinates. Tracker coordinates must be in the
|
|
// frame window's coordinate system
|
|
GetClientRect(m_crTracker);
|
|
MapWindowPoints(m_pCX->GetFrame()->GetFrameWnd(), m_crTracker);
|
|
|
|
// Save the current tracker bounds for later
|
|
m_crOriginalTracker = m_crTracker;
|
|
|
|
// Turn off clipping of children on the parent window before we
|
|
// start dragging. This is so we can draw the tracker directly on
|
|
// the parent window (and probably over its child windows).
|
|
CWnd *pWnd = m_pCX->GetFrame()->GetFrameWnd();
|
|
if(pWnd) {
|
|
DWORD dwStyle = ::GetWindowLong(pWnd->m_hWnd, GWL_STYLE);
|
|
m_bParentClipChildren = ((dwStyle & WS_CLIPCHILDREN) != 0);
|
|
::SetWindowLong(pWnd->m_hWnd, GWL_STYLE, (dwStyle & ~WS_CLIPCHILDREN));
|
|
}
|
|
|
|
// Invert the tracker.
|
|
InvertTracker();
|
|
}
|
|
|
|
void CGridEdge::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
// Only do something if we can resize.
|
|
if(CanResize() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// Release capture.
|
|
ReleaseCapture();
|
|
|
|
// Release the bounds established on the mouse.
|
|
::ClipCursor(NULL);
|
|
|
|
// Invert the tracker (return screen to normal state).
|
|
InvertTracker();
|
|
|
|
// Turn clipping children back on if our parent had it.
|
|
CWnd *pWnd = m_pCX->GetFrame()->GetFrameWnd();
|
|
if(pWnd && m_bParentClipChildren) {
|
|
DWORD dwStyle = ::GetWindowLong(pWnd->m_hWnd, GWL_STYLE);
|
|
::SetWindowLong(pWnd->m_hWnd, GWL_STYLE, (dwStyle|WS_CLIPCHILDREN));
|
|
}
|
|
|
|
// Set that we are no longer tracking.
|
|
m_bTracking = FALSE;
|
|
|
|
// Convert tracker from the frame window's coordinate system to the
|
|
// owning context view's coordinate system
|
|
CPoint cpPoint;
|
|
m_pCX->GetViewOffsetInFrame(cpPoint);
|
|
m_crTracker.left -= cpPoint.x;
|
|
m_crTracker.top -= cpPoint.y;
|
|
|
|
// Report to layout the new position of the tracker.
|
|
// Make sure we didn't pass any limits.
|
|
if(m_pEdge->is_vertical) {
|
|
// Check the left argument.
|
|
if(m_crTracker.left > m_pEdge->right_bottom_bound) {
|
|
m_crTracker.left = CASTINT(m_pEdge->right_bottom_bound);
|
|
}
|
|
if(m_crTracker.left < m_pEdge->left_top_bound) {
|
|
m_crTracker.left = CASTINT(m_pEdge->left_top_bound);
|
|
}
|
|
}
|
|
else {
|
|
// Check the top argument.
|
|
if(m_crTracker.top > m_pEdge->right_bottom_bound) {
|
|
m_crTracker.top = CASTINT(m_pEdge->right_bottom_bound);
|
|
}
|
|
if(m_crTracker.top < m_pEdge->left_top_bound) {
|
|
m_crTracker.top = CASTINT(m_pEdge->left_top_bound);
|
|
}
|
|
}
|
|
|
|
// Restore our tracker to its original value, in case layout does nothing.
|
|
CRect crTemp = m_crTracker;
|
|
m_crTracker = m_crOriginalTracker;
|
|
|
|
LO_MoveGridEdge(m_pCX->GetContext(), m_pEdge, crTemp.left, crTemp.top);
|
|
}
|
|
|
|
void CGridEdge::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
// Only do this if we can resize.
|
|
if(CanResize() == FALSE) {
|
|
return;
|
|
}
|
|
|
|
// If we're currently tracking, simply update the coords.
|
|
if(m_bTracking == TRUE) {
|
|
// Turn off the tracker.
|
|
InvertTracker();
|
|
|
|
// Figure out which direction we're allowing this to be updated.
|
|
if(m_pEdge->is_vertical) {
|
|
// Can go left to right.
|
|
m_crTracker.left = CASTINT(m_crOriginalTracker.left + m_pCX->Pix2TwipsX(point.x - m_cpLBDown.x));
|
|
m_crTracker.right = m_crTracker.left + m_crOriginalTracker.Width();
|
|
}
|
|
else {
|
|
// Can go top to bottom.
|
|
m_crTracker.top = CASTINT(m_crOriginalTracker.top + m_pCX->Pix2TwipsY(point.y - m_cpLBDown.y));
|
|
m_crTracker.bottom = m_crTracker.top + m_crOriginalTracker.Height();
|
|
}
|
|
|
|
// Turn on the tracker.
|
|
InvertTracker();
|
|
return;
|
|
}
|
|
|
|
static HCURSOR hcurLast = NULL;
|
|
static HCURSOR hcurDestroy = NULL;
|
|
static UINT uLastCursorID = 0;
|
|
UINT uCursorID;
|
|
|
|
// Decide which cursor we want to load.
|
|
if(m_pEdge->is_vertical == FALSE) {
|
|
// Horizontal.
|
|
uCursorID = AFX_IDC_VSPLITBAR;
|
|
}
|
|
else {
|
|
// Vertical.
|
|
uCursorID = AFX_IDC_HSPLITBAR;
|
|
}
|
|
|
|
// Only if not already loaded.
|
|
HCURSOR hcurToDestroy = NULL;
|
|
if(uCursorID != uLastCursorID) {
|
|
HINSTANCE hInst =
|
|
#ifdef _AFXDLL
|
|
AfxFindResourceHandle(MAKEINTRESOURCE(uCursorID), RT_GROUP_CURSOR);
|
|
#else
|
|
AfxGetResourceHandle();
|
|
#endif
|
|
|
|
// Load in another cursor.
|
|
hcurToDestroy = hcurDestroy;
|
|
|
|
hcurDestroy = hcurLast = ::LoadCursor(hInst, MAKEINTRESOURCE(uCursorID));
|
|
uLastCursorID = uCursorID;
|
|
}
|
|
|
|
// Set the cursor.
|
|
::SetCursor(hcurLast);
|
|
|
|
// Destroy the previous cursor if need be.
|
|
if(hcurToDestroy != NULL) {
|
|
::DestroyCursor(hcurToDestroy);
|
|
}
|
|
}
|
|
|
|
BOOL CGridEdge::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
|
|
{
|
|
if (nHitTest == HTCLIENT && pWnd == this && !m_bTracking && CanResize()) {
|
|
return TRUE; // we will handle it in the mouse move
|
|
}
|
|
|
|
return CWnd::OnSetCursor(pWnd, nHitTest, message);
|
|
}
|
|
|
|
void CGridEdge::OnPaint()
|
|
{
|
|
CPaintDC dc(this); // device context for painting
|
|
|
|
// The area we're drawing.
|
|
CRect crRect;
|
|
GetClientRect(crRect);
|
|
|
|
// Draw it as the button face if no other color available.
|
|
if(m_pEdge && m_pEdge->bg_color) {
|
|
WFE_FillSolidRect((CDC *)&dc, crRect,
|
|
RGB(m_pEdge->bg_color->red, m_pEdge->bg_color->green, m_pEdge->bg_color->blue));
|
|
}
|
|
else {
|
|
WFE_FillSolidRect((CDC *)&dc, crRect, sysInfo.m_clrBtnFace);
|
|
}
|
|
|
|
// Draw the border edges if appropriate. We can't really do much unless the edge
|
|
// is at least 3 pixels wide/high
|
|
if (m_pEdge->visible) {
|
|
if (m_pEdge->is_vertical) {
|
|
if (m_pEdge->width >= 3) {
|
|
int nLeft = m_pEdge->width >= 6 ? crRect.left + 1 : crRect.left;
|
|
|
|
dc.PatBlt(nLeft, crRect.top, 1, crRect.Height(), WHITENESS);
|
|
HBRUSH hOldBrush = (HBRUSH)::SelectObject(dc.m_hDC, ::GetStockObject(GRAY_BRUSH));
|
|
dc.PatBlt(crRect.right - 2, crRect.top, 1, crRect.Height(), PATCOPY);
|
|
::SelectObject(dc.m_hDC, hOldBrush);
|
|
dc.PatBlt(crRect.right - 1, crRect.top, 1, crRect.Height(), BLACKNESS);
|
|
}
|
|
|
|
} else {
|
|
if (m_pEdge->height >= 3) {
|
|
int nTop = m_pEdge->height >= 6 ? crRect.top + 1 : crRect.top;
|
|
|
|
dc.PatBlt(crRect.left, nTop, crRect.Width(), 1, WHITENESS);
|
|
HBRUSH hOldBrush = (HBRUSH)::SelectObject(dc.m_hDC, ::GetStockObject(GRAY_BRUSH));
|
|
dc.PatBlt(crRect.left, crRect.bottom - 2, crRect.Width(), 1, PATCOPY);
|
|
::SelectObject(dc.m_hDC, hOldBrush);
|
|
dc.PatBlt(crRect.left, crRect.bottom - 1, crRect.Width(), 1, BLACKNESS);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CGridEdge::OnLButtonDblClk(UINT nFlags, CPoint point)
|
|
{
|
|
// Treat same as button down.
|
|
OnLButtonDown(nFlags, point);
|
|
}
|