// P4PaneView.cpp : implementation file
//
#include "stdafx.h"
#include "p4win.h"
#include "P4PaneView.h"
#include "P4PaneContent.h"
#include "MainFrm.h"
#include "ImageList.h"
#include <afxpriv.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CP4PaneView
const int ID_CAPTION = 222;
IMPLEMENT_DYNCREATE(CP4PaneView, CView)
BEGIN_MESSAGE_MAP(CP4PaneView, CView)
ON_WM_SETFOCUS()
ON_WM_SIZE()
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
ON_WM_CREATE()
ON_MESSAGE( WM_FINDPATTERN, OnFindPattern )
ON_BN_CLICKED( ID_CAPTION, LButtonClk )
ON_BN_DOUBLECLICKED( ID_CAPTION, LButtonDblClk )
ON_WM_SYSCOLORCHANGE()
ON_MESSAGE( WM_ACTIVATEMODELESS, OnActivateModeless )
END_MESSAGE_MAP()
CP4PaneView::CP4PaneView()
: m_content(0)
{
}
CP4PaneView::~CP4PaneView() {}
void CP4PaneView::SetBranchWnd(CWnd *wnd) { m_content->SetBranchWnd(wnd); }
void CP4PaneView::SetChangeWnd(CWnd *wnd) { m_content->SetChangeWnd(wnd); }
void CP4PaneView::SetClientWnd(CWnd *wnd) { m_content->SetClientWnd(wnd); }
void CP4PaneView::SetDepotWnd(CWnd *wnd) { m_content->SetDepotWnd(wnd); }
void CP4PaneView::SetJobWnd(CWnd *wnd) { m_content->SetJobWnd(wnd); }
void CP4PaneView::SetLabelWnd(CWnd *wnd) { m_content->SetLabelWnd(wnd); }
void CP4PaneView::SetOldChgWnd(CWnd *wnd) { m_content->SetOldChgWnd(wnd); }
void CP4PaneView::SetUserWnd(CWnd *wnd) { m_content->SetUserWnd(wnd); }
void CP4PaneView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// for some reason, list views end up with client edge style set
// and we don't want it for any views
ModifyStyleEx(WS_EX_CLIENTEDGE, 0);
// want tooltips for caption
m_reBar.SetBarStyle(CBRS_ALIGN_TOP |CBRS_TOOLTIPS);
// don't want separator bar between caption and toolbar bands
m_reBar.ModifyStyle(RBS_BANDBORDERS, 0);
// put dropdown arrows on dropdown buttons
m_toolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
// set owner to mainframe so tooltips status bar messages will work
m_toolBar.SetOwner(AfxGetApp()->m_pMainWnd);
// make it flat and transparent so it looks good on XP
m_toolBar.ModifyStyle(0, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT);
// get rid of extra space around buttons
m_toolBar.SetBorders();
// set style to get tooltips working
m_toolBar.SetBarStyle(CBRS_ALIGN_TOP | CBRS_TOOLTIPS | CBRS_FLYBY);
// created non-visible so styles could be set before showing, so show now
m_toolBar.ShowWindow(SW_SHOW);
// set image list(s) for the toolbar
m_toolBar.GetToolBarCtrl().SetImageList(
TheApp()->GetToolBarImageList());
m_toolBar.GetToolBarCtrl().SetDisabledImageList(
TheApp()->GetToolBarImageList()->GetDisabled());
// must set button size before adding buttons
CSize sizeImage(18, 16);
CSize sizeButton(18 + 7, 16 + 7);
m_toolBar.SetSizes(sizeButton, sizeImage);
// add the buttons to the toolbar
SetToolBarButtons();
// make the caption control transparent so the rebar will
// draw the background under it
m_captionCtrl.ModifyStyleEx(0, WS_EX_TRANSPARENT);
// put the bands into the rebar
// the ' ' text for the caption provides a little space on the left
m_reBar.AddBar(&m_captionCtrl, _T(" "), NULL, RBBS_NOGRIPPER);
m_reBar.AddBar(&m_toolBar, NULL, NULL, RBBS_NOGRIPPER|RBBS_FIXEDBMP);
// determine how tall the bar should be to fit the taller of
// the caption band or the toolbar band
CRect r;
r.SetRectEmpty();
m_reBar.CalcInsideRect(r, TRUE);
m_barHeight = max(16 + 7, GetSystemMetrics(SM_CYCAPTION));
m_barHeight -= r.Height();
m_contentTop = m_barHeight + GetSystemMetrics(SM_CYEDGE);
// set up min/max sizes and ideal sizes for pieces of the rebar
REBARBANDINFO rbbi;
rbbi.cbSize = sizeof(rbbi);
// set title band so it will be as wide as possible
// and with a min size of one, it will never disappear
// since the caption control will use the standard caption
// font, it should be as tall as a standard caption.
rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_SIZE;
rbbi.cxMinChild = 1;
rbbi.cyMinChild = GetSystemMetrics(SM_CYCAPTION);
rbbi.cx = rbbi.cxIdeal = 20000; // want to be really big!
m_reBar.GetReBarCtrl().SetBandInfo(0, &rbbi);
// set max size for toolbar band to it's actual size
// and min size to same so it won't be crowded out by
// caption.
m_toolBar.GetWindowRect(&r);
rbbi.fMask = RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_SIZE;
rbbi.cxMinChild = r.Width();
rbbi.cyMinChild = 16 + 7;
rbbi.cx = rbbi.cxIdeal = r.Width();
m_reBar.GetReBarCtrl().SetBandInfo(1, &rbbi);
// reposition the bars, now that their sizes have been set
GetClientRect(&r);
r.bottom = m_barHeight;
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 1,
reposDefault, NULL, &r);
// and reposition the content, allowing space for the rebar edge
GetContentWnd()->MoveWindow(0,m_contentTop,
r.Width(),r.Height() - m_contentTop,TRUE);
EnableToolTips();
if (GET_P4REGPTR( )->SwapButtonPosition())
SwapButtonPosition();
}
void CP4PaneView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// don't do other sizing until created
if(!IsWindow(m_toolBar.m_hWnd) || !m_reBar.GetReBarCtrl().GetBandCount())
return;
// put toolbar at top, list below it
CRect r;
r.SetRect(0, 0, cx, m_barHeight);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 1,
reposDefault, NULL, &r);
// RepositionBars won't leave space between the rebar and the content
// so we need to re-move the content to make space needed for the border
GetContentWnd()->MoveWindow(0, m_contentTop, cx, cy - m_contentTop, TRUE);
}
void CP4PaneView::OnDraw(CDC* pDC)
{
// just draw an edget between the toolbar and the content
CRect r;
GetClientRect(&r);
r.bottom = r.top + m_contentTop;
pDC->DrawEdge(&r, EDGE_RAISED, BF_RECT);
}
void CP4PaneView::OnSetFocus(CWnd* pOldWnd)
{
CView::OnSetFocus(pOldWnd);
if(GetContentWnd() && IsWindow(GetContentWnd()->m_hWnd))
GetContentWnd()->SetFocus();
}
BOOL CP4PaneView::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
if(GetContentWnd()->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return CView::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
BOOL CP4PaneView::OnToolTipText( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
{
// first, check for special case of caption control
// and handle it here
TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
UINT nID =pNMHDR->idFrom;
if (pTTT->uFlags & TTF_IDISHWND)
{
// idFrom is actually the HWND of the tool
nID = ::GetDlgCtrlID((HWND)nID);
if(nID == ID_CAPTION)
{
m_captionCtrl.GetWindowText(m_captionTxt);
pTTT->lpszText = (LPTSTR)(LPCTSTR)m_captionTxt;
pTTT->hinst = NULL;
return TRUE;
}
}
// for other cases, just pass it along to mainframe
CMainFrame *mainFrame = (CMainFrame *) AfxGetApp()->m_pMainWnd;
return mainFrame->OnToolTipText(id, pNMHDR, pResult);
}
int CP4PaneView::GetSelectedItem()
{
CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
ASSERT(pList);
if(pList)
return pList->GetSelectedItem();
return 0;
}
void CP4PaneView::OnEditPaste( const CString &Name )
{
CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
ASSERT(pList);
if(pList)
pList->OnEditPaste(Name);
}
CString CP4PaneView::GetSelectedItemText( )
{
CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
ASSERT(pList);
if(pList)
return pList->GetSelectedItemText();
return "";
}
HTREEITEM CP4PaneView::GetSelectedItem(int index)
{
CMultiSelTreeCtrl * pTree = DYNAMIC_DOWNCAST(CMultiSelTreeCtrl, GetContentWnd());
ASSERT(pTree);
if(pTree)
return pTree->GetSelectedItem(index);
return 0;
}
CString CP4PaneView::GetItemText(HTREEITEM curr_item)
{
CMultiSelTreeCtrl * pTree = DYNAMIC_DOWNCAST(CMultiSelTreeCtrl, GetContentWnd());
ASSERT(pTree);
if(pTree)
return pTree->GetItemText(curr_item);
return "";
}
void CP4PaneView::SetCaption()
{
m_captionCtrl.SetWindowText(m_content->GetCaption());
// Getting this updated is a bit complicated since the caption
// control is transparent (to allow the rebar background to
// show through). First, redraw the rebar, then the caption control.
m_reBar.InvalidateRect(NULL);
m_reBar.UpdateWindow();
m_captionCtrl.InvalidateRect(NULL);
m_captionCtrl.UpdateWindow();
}
int CP4PaneView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
if(!m_reBar.Create(this))
return -1;
if(!m_toolBar.Create(this,WS_CHILD | CBRS_ALIGN_TOP))
return -1;
if(!m_captionCtrl.Create(_T(""),WS_CHILD|WS_VISIBLE|BS_OWNERDRAW|BS_NOTIFY,
CRect(0,0,1,1),this,ID_CAPTION))
return -1;
if(!CreateContent())
return -1;
LOGFONT lf;
m_reBar.GetFont()->GetLogFont(&lf);
m_inactiveFont.CreateFontIndirect(&lf);
lf.lfWeight = FW_BOLD;
m_activeFont.CreateFontIndirect(&lf);
// Register that we accept Exploder files
try
{
m_DropTarget.Register(this);
}
catch(...)
{
return 0;
}
return 0;
}
void CP4PaneView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
if(GetContentWnd() && IsWindow(GetContentWnd()->m_hWnd))
{
// force UI update right away, so if activation is caused by
// click on toolbar dropdown, it can be enabled before the
// toolbar gets the click message. Without this, it takes
// one click to activate and another to drop down.
m_toolBar.SendMessage(WM_IDLEUPDATECMDUI, (WPARAM)TRUE, 0);
if(bActivate)
{
m_captionCtrl.SetFont(&m_activeFont);
}
else
{
m_captionCtrl.SetFont(&m_inactiveFont);
}
// The size of the caption text will change with the font change
// so force an update
SetCaption();
}
CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
}
DROPEFFECT CP4PaneView::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
MapWindowPoints(GetContentWnd(), &point, 1);
return m_content->OnDragEnter(pDataObject, dwKeyState, point);
}
void CP4PaneView::OnDragLeave()
{
m_content->OnDragLeave();
}
DROPEFFECT CP4PaneView::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point)
{
MapWindowPoints(GetContentWnd(), &point, 1);
return m_content->OnDragOver(pDataObject, dwKeyState, point);
}
BOOL CP4PaneView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)
{
MapWindowPoints(GetContentWnd(), &point, 1);
return m_content->OnDrop(pDataObject, dropEffect, point);
}
void CP4PaneView::SwapButtonPosition()
{
// swap the bands
m_reBar.GetReBarCtrl().MoveBand(1, 0);
// for some inexplicable reason, MoveBand doesn't update the bar
// immediately. It takes some other action to make it actually update
// and this seems like the least disruptive thing to do:
m_reBar.GetReBarCtrl().ShowBand(0, FALSE);
m_reBar.GetReBarCtrl().ShowBand(0, TRUE);
}
// This is required in order to make the LButtonDblClk() work!
void CP4PaneView::LButtonClk()
{
SetFocus();
}
void CP4PaneView::LButtonDblClk()
{
// by default, do nothing
}
LRESULT CP4PaneView::OnFindPattern(WPARAM wParam, LPARAM lParam)
{
CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
ASSERT(pList);
if(pList)
return pList->OnFindPattern(wParam, lParam);
return Default();
}
IMPLEMENT_DYNCREATE(CCaptionTextControl, CButton)
BEGIN_MESSAGE_MAP(CCaptionTextControl, CButton)
ON_WM_CTLCOLOR_REFLECT()
END_MESSAGE_MAP()
HBRUSH CCaptionTextControl::CtlColor(CDC* pDC, UINT /*nCtlColor*/)
{
// we don't want any background drawn; we're supposed to be transparent
pDC->SetBkMode(TRANSPARENT);
return (HBRUSH)GetStockObject(NULL_BRUSH);
}
void CCaptionTextControl::DrawItem(LPDRAWITEMSTRUCT di)
{
// Just draw the text. If it's too long, it will be shortened, since
// we're using the DT_END_ELLIPSIS style. This also means the string
// passed to DrawText may be modified, so we use a temp copy.
CDC dc;
dc.Attach(di->hDC);
const int maxCaption = 256;
TCHAR txt[maxCaption];
GetWindowText(txt,maxCaption);
txt[maxCaption-1] = 0;
TCHAR mtxt[maxCaption];
lstrcpy(mtxt,txt);
dc.DrawText(mtxt, lstrlen(mtxt), &di->rcItem, DT_END_ELLIPSIS | DT_SINGLELINE|DT_VCENTER | DT_MODIFYSTRING);
m_textTruncated = lstrcmp(mtxt,txt) != 0;
dc.Detach();
}
int CCaptionTextControl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
// CWnd implementation won't do us any good, so we have to handle
// this.
// watch out! sometimes get called with null pointer
if(pTI == 0)
return -1;
// don't want to show tooltip if nothing is hidden
// the tooltip is only there to show truncated text
if(!m_textTruncated)
return -1;
// we want to show a tooltip, so set up for the normal callback
pTI->hwnd = GetParent()->GetParent()->m_hWnd; // our parent
pTI->uId = (UINT_PTR)m_hWnd; // us
pTI->uFlags |= TTF_IDISHWND; // uId is HWND, not ID
pTI->lpszText = LPSTR_TEXTCALLBACK;
return 1;
}
DROPEFFECT CP4OleDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState,
CPoint point)
{
// We need special handling of autoscrolling because we want
// it to behave as though the CP4PaneView's content window is
// doing the autoscroll. Without this, it looks like you are
// dragging over the caption to autoscroll the content.
// This code is only slightly modified from the base implementation,
// as needed to get the correct window's client rect for determining
// the autoscroll inset region. Also, code for synchronized
// scrolling of splitters has been stripped out.
ASSERT_VALID(this);
ASSERT_VALID(pWnd);
// if it's not a CP4PaneView, just use the default handler
CP4PaneView * pView = DYNAMIC_DOWNCAST(CP4PaneView,pWnd);
if(!pView)
return COleDropTarget::OnDragScroll(pWnd, dwKeyState, point);
DROPEFFECT dropEffect = pView->OnDragScroll(dwKeyState, point);
// DROPEFFECT_SCROLL means do the default
if (dropEffect != DROPEFFECT_SCROLL)
return dropEffect;
// get client rectangle of destination window
CRect rectClient;
pView->GetContentWnd()->GetClientRect(&rectClient);
pView->GetContentWnd()->MapWindowPoints(pView, &rectClient);
CRect rect = rectClient;
// hit-test against inset region
UINT nTimerID = 0xffff;
rect.InflateRect(-nScrollInset, -nScrollInset);
if (rectClient.PtInRect(point) && !rect.PtInRect(point))
{
// determine which way to scroll along both X & Y axis
if (point.x < rect.left)
nTimerID = MAKEWORD(SB_LINEUP, HIBYTE(nTimerID));
else if (point.x >= rect.right)
nTimerID = MAKEWORD(SB_LINEDOWN, HIBYTE(nTimerID));
if (point.y < rect.top)
nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEUP);
else if (point.y >= rect.bottom)
nTimerID = MAKEWORD(LOBYTE(nTimerID), SB_LINEDOWN);
ASSERT(nTimerID != 0xffff);
// we don't do synchronized splitter scrolling, so this part is
// somewhat simplified
BOOL bEnableScroll = pView->OnScroll(nTimerID, 0, FALSE);
if (!bEnableScroll)
nTimerID = 0xffff;
}
if (nTimerID == 0xffff)
{
if (m_nTimerID != 0xffff)
{
// send fake OnDragEnter when transition from scroll->normal
COleDataObject dataObject;
dataObject.Attach(m_lpDataObject, FALSE);
OnDragEnter(pWnd, &dataObject, dwKeyState, point);
m_nTimerID = 0xffff;
}
return DROPEFFECT_NONE;
}
// save tick count when timer ID changes
DWORD dwTick = GetTickCount();
if (nTimerID != m_nTimerID)
{
m_dwLastTick = dwTick;
m_nScrollDelay = nScrollDelay;
}
// scroll if necessary
if (dwTick - m_dwLastTick > m_nScrollDelay)
{
pView->OnScroll(nTimerID, 0, TRUE);
m_dwLastTick = dwTick;
m_nScrollDelay = nScrollInterval;
}
if (m_nTimerID == 0xffff)
{
// send fake OnDragLeave when transitioning from normal->scroll
OnDragLeave(pWnd);
}
m_nTimerID = nTimerID;
// check for force link
if ((dwKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_LINK;
// check for force copy
else if ((dwKeyState & MK_CONTROL) == MK_CONTROL)
dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_COPY;
// check for force move
else if ((dwKeyState & MK_ALT) == MK_ALT ||
(dwKeyState & MK_SHIFT) == MK_SHIFT)
dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
// default -- recommended action is move
else
dropEffect = DROPEFFECT_SCROLL|DROPEFFECT_MOVE;
return dropEffect;
}
void CP4PaneView::OnSysColorChange()
{
CView::OnSysColorChange();
m_toolBar.GetToolBarCtrl().SetImageList(
TheApp()->GetToolBarImageList());
m_toolBar.GetToolBarCtrl().SetDisabledImageList(
TheApp()->GetToolBarImageList()->GetDisabled());
CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
if(pList)
pList->SetImageList(TheApp()->GetViewImageList(), LVSIL_SMALL);
CMultiSelTreeCtrl * pTree = DYNAMIC_DOWNCAST(CMultiSelTreeCtrl, GetContentWnd());
if(pTree)
pTree->SetImageList(TheApp()->GetViewImageList(), TVSIL_NORMAL);
}
LRESULT CP4PaneView::OnActivateModeless(WPARAM wParam, LPARAM lParam)
{
CP4ListCtrl * pList = DYNAMIC_DOWNCAST(CP4ListCtrl, GetContentWnd());
if(pList)
pList->SendMessage(WM_ACTIVATEMODELESS, WA_ACTIVE, NULL);
else
{
CMultiSelTreeCtrl * pTree = DYNAMIC_DOWNCAST(CMultiSelTreeCtrl, GetContentWnd());
if(pTree)
pTree->SendMessage(WM_ACTIVATEMODELESS, WA_ACTIVE, NULL);
}
return 0;
}
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #1 | 19924 | YourUncleBob |
Populate -o //guest/perforce_software/p4win/... //guest/YourUncleBob/p4win/..... |
||
| //guest/perforce_software/p4win/main/gui/P4PaneView.cpp | |||||
| #1 | 16169 | perforce_software | Move files to follow new path scheme for branches. | ||
| //guest/perforce_software/p4win/gui/P4PaneView.cpp | |||||
| #1 | 8562 | Matt Attaway |
These feet never stop running. Initial commit of the P4Win source code. To the best of our knowledge this compiles and runs using the 2013.3 P4 API and VS 2010. Expect a few changes as we refine the build process. Please post any build issues to the forums. |
||