gecko-dev/cmd/winfe/gridedge.cpp
1998-03-28 02:44:41 +00:00

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);
}