// ltrItemTreeWnd.cpp : implementation file
//
#include "stdafx.h"
#include "grammarIDE.h"
#include "ltrItemTreeWnd.h"
#include "DlgProperties.h"
#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CltrItemTreeWnd
CltrItemTreeWnd::CltrItemTreeWnd(cxtPackage *pPkg)
{
m_pltrTree = NULL;
m_pltrContext = NULL;
m_pltrHilite = NULL;
m_nBaseWidth = 50;
m_nBaseHeight = 25;
m_nLRMargin = 25;
m_nTBMargin = 25;
m_nCenterOffsX = 0;
m_nCenterOffsY = 0;
m_icZoom = AfxGetApp()->LoadIcon(IDI_ZOOMABLE);
m_icUnzoom = AfxGetApp()->LoadIcon(IDI_UNZOOMABLE);
m_pPkg = pPkg;
m_Font.CreatePointFont(90,_T("Verdana"),NULL);
}
CltrItemTreeWnd::~CltrItemTreeWnd()
{
delete m_pltrTree;
}
BEGIN_MESSAGE_MAP(CltrItemTreeWnd, CWnd)
//{{AFX_MSG_MAP(CltrItemTreeWnd)
ON_WM_PAINT()
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_TIMER()
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_ERASEBKGND()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONUP()
ON_WM_INITMENUPOPUP()
ON_COMMAND(ID_LTRCONTEXT_SHOWPROPERTIES, OnLtrcontextShowProps)
ON_UPDATE_COMMAND_UI(ID_LTRCONTEXT_COLLAPSE, OnUpdateLtrcontextCollapseItem)
ON_UPDATE_COMMAND_UI(ID_LTRCONTEXT_EXPAND, OnUpdateLtrcontextExpandItem)
ON_COMMAND(ID_LTRCONTEXT_EXPAND, OnLtrcontextExpandItem)
ON_COMMAND(ID_LTRCONTEXT_COLLAPSE, OnLtrcontextCollapseItem)
ON_COMMAND(ID_LTRCONTEXT_SHOWRAWTOKENSTREAM, OnLtrcontextShowRawTokenStream)
ON_UPDATE_COMMAND_UI(ID_LTRCONTEXT_SHOWPROPERTIES, OnUpdateLtrcontextShowProps)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CltrItemTreeWnd::SetTree(cltrItemBranch *pltrTree)
{
delete m_pltrTree;
m_pltrHilite = NULL;
m_pltrTree = pltrTree;
m_mapItems.reset();
RecalcViewLayout();
Invalidate(TRUE);
}
void CltrItemTreeWnd::CalculateDims(const cltrItemBranch& ltrBranch, int *pnWidth, int *pnHeight) const
{
cltrItemBranch::const_iterator it;
int nBaseHeight = (*pnHeight+1);
int nCurHeight = (*pnHeight+1);
if(ltrBranch.empty())
return;
for(it=ltrBranch.begin();it!=ltrBranch.end();it++)
{
if( (*it)->fIsNode )
(*pnWidth)++;
else
{
if( ((cltrItemBranch*)*it)->fIsExpanded )
{
int nW=0, nH = nBaseHeight;
CalculateDims( *((cltrItemBranch*)(*it)), &nW, &nH);
(*pnWidth)+=nW;
if(nH>=nCurHeight)
nCurHeight=nH;
}
else
(*pnWidth)++;
}
}
if(nCurHeight>=(*pnHeight))
(*pnHeight) = nCurHeight;
}
void CltrItemTreeWnd::RecalcViewLayout()
{
if(m_pltrTree==NULL)
return;
int nWidth=0, nHeight=0;
CRect rcClient;
GetClientRect(&rcClient);
CalculateDims(*m_pltrTree,&nWidth,&nHeight);
nWidth =(nWidth*m_nBaseWidth+2*m_nLRMargin)-rcClient.Width();
nHeight =(nHeight*m_nBaseHeight+2*m_nTBMargin)-rcClient.Height();
if(nWidth<0) { m_nCenterOffsX = (-nWidth)/2; nWidth=0; } else m_nCenterOffsX=0;
if(nHeight<0) { m_nCenterOffsY = (-nHeight)/2; nHeight=0; } else m_nCenterOffsY=0;
SetScrollRange(SB_HORZ,0,nWidth,FALSE);
SetScrollRange(SB_VERT,0,nHeight,FALSE);
Invalidate(TRUE);
}
int CltrItemTreeWnd::DrawBranch(CDC* pDC, bool fInsert, int nHilite, int nX, int nY, cltrItemBranch& ltrBranch)
{
cltrItemBranch::const_iterator it;
eviewstatus vs = vs_visible;
int nPos = 0;
if( (<rBranch) == m_pltrHilite )
nHilite = 2;
for(it=ltrBranch.begin();it!=ltrBranch.end();it++)
{
bool fDrawBranch = false;
int nWidth = 1;
if( !(*it)->fIsNode )
if( ((cltrItemBranch*)(*it))->fIsExpanded )
fDrawBranch = true;
if(fDrawBranch)
nWidth = DrawBranch(pDC,fInsert,(nHilite==2)?1:nHilite,nX+nPos,nY+1,*(cltrItemBranch*)(*it));
if(vs==vs_top || vs==vs_bottom)
{
nPos += nWidth;
continue;
}
vs = DrawItem(pDC,fInsert,(nHilite==2)?1:nHilite,nX+nPos,nY,(*it),nWidth);
nPos += nWidth;
}
return nPos;
}
COLORREF CltrItemTreeWnd::ColorSlide(COLORREF clr1, COLORREF clr2, int nNom, int nDenom) const
{
DWORD dwR1, dwG1, dwB1;
DWORD dwR2, dwG2, dwB2;
DWORD dwR3, dwG3, dwB3;
dwR1 =(clr1&0xffL); dwR2=(clr2&0xffL);
dwG1 =(clr1&0xff00L)>>8L; dwG2=(clr2&0xff00L)>>8L;
dwB1 =(clr1&0xff0000L)>>16L; dwB2=(clr2&0xff0000L)>>16L;
dwR3 =((dwR1*(nDenom-nNom))+(dwR2*nNom))/nDenom;
dwG3 =((dwG1*(nDenom-nNom))+(dwG2*nNom))/nDenom;
dwB3 =((dwB1*(nDenom-nNom))+(dwB2*nNom))/nDenom;
return RGB(dwR3, dwG3, dwB3);
}
void CltrItemTreeWnd::CalculateItemRect(int x, int y, int nWidth, CRect& rcBounds)
{
int nHOffs = GetScrollPos(SB_HORZ);
int nVOffs = GetScrollPos(SB_VERT);
rcBounds=
CRect(
-nHOffs+m_nLRMargin+m_nCenterOffsX+(x*m_nBaseWidth),
-nVOffs+m_nTBMargin+m_nCenterOffsY+(y*m_nBaseHeight),
-nHOffs+m_nLRMargin+m_nCenterOffsX+(x*m_nBaseWidth)+(nWidth*m_nBaseWidth)-5,
-nVOffs+m_nTBMargin+m_nCenterOffsY+(y*m_nBaseHeight)+m_nBaseHeight-5);
}
CltrItemTreeWnd::eviewstatus CltrItemTreeWnd::DrawItem(CDC* pDC, bool fInsert, int nHilite, int nX, int nY, cltrItemNode* pltrItem, int nWidth)
{
CRect rcClient;
CRect rcBounds;
COLORREF clrBack = pltrItem->clrBackground;
if( pltrItem == m_pltrHilite )
nHilite = 2;
CalculateItemRect(nX,nY,nWidth,rcBounds);
GetClientRect(&rcClient);
if(rcBounds.bottom<rcClient.top)
return vs_top;
if(rcBounds.top>rcClient.bottom)
return vs_bottom;
if(rcBounds.right<rcClient.left)
return vs_side;
if(rcBounds.left>rcClient.right)
return vs_side;
if(nHilite==2)
clrBack = ColorSlide(clrBack,0xff8080L,2,3);
if(nHilite==1)
clrBack = ColorSlide(clrBack,0xff8080L,1,5);
pDC->FillSolidRect(rcBounds,clrBack );
pDC->Draw3dRect(rcBounds,pltrItem->clrForeground,pltrItem->clrForeground);
pDC->SetBkMode(TRANSPARENT);
pDC->DrawText(pltrItem->text.c_str(),pltrItem->text.length(),rcBounds,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
if(!pltrItem->fIsNode)
{
pDC->DrawIcon(rcBounds.left-3,rcBounds.bottom-6,
(((cltrItemBranch*)pltrItem)->fIsExpanded)?m_icZoom:m_icUnzoom);
}
if(fInsert)
{
int i;
pltrItem->nX = nX;
pltrItem->nY = nY;
pltrItem->nWidth = nWidth;
for(i=0;i<nWidth;i++)
m_mapItems.insert(nX+i,nY,pltrItem);
}
return vs_visible;
}
void CltrItemTreeWnd::ScrollHandler(bool fHorz, UINT nSBCode, UINT nPos)
{
if(m_pltrTree==NULL)
return;
CRect rcClient;
INT nMin, nMax, nCurPos, nPage, nOldPos, nDelta;
GetClientRect(&rcClient);
GetScrollRange(fHorz?SB_HORZ:SB_VERT,&nMin,&nMax);
nCurPos =GetScrollPos(fHorz?SB_HORZ:SB_VERT);
nOldPos =nCurPos;
nPage =((fHorz?rcClient.Width():rcClient.Height())*3)/4;
switch(nSBCode)
{
case SB_LINEUP:
nCurPos -= 5;
break;
case SB_LINEDOWN:
nCurPos += 5;
break;
case SB_PAGEUP:
nCurPos -= nPage;
break;
case SB_PAGEDOWN:
nCurPos += nPage;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
nCurPos = nPos;
break;
case SB_TOP:
nCurPos = 0;
break;
case SB_BOTTOM:
nCurPos = nMax;
break;
default:
break;
}
if(nCurPos<nMin) nCurPos = nMin;
if(nCurPos>nMax) nCurPos = nMax;
nDelta =nOldPos-nCurPos;
SetScrollPos(fHorz?SB_HORZ:SB_VERT,nCurPos,TRUE);
ScrollWindow(fHorz?nDelta:0,(!fHorz)?nDelta:0);
}
cltrItemNode* CltrItemTreeWnd::FindItemFromCoords(int px, int py)
{
int nHScroll = GetScrollPos(SB_HORZ);
int nVScroll = GetScrollPos(SB_VERT);
int x = (px+nHScroll-m_nLRMargin-m_nCenterOffsX) / m_nBaseWidth;
int y = (py+nVScroll-m_nTBMargin-m_nCenterOffsY) / m_nBaseHeight;
cltrItemNode *pltrItem = m_mapItems.find(x,y);
if(pltrItem==NULL)
return NULL;
CRect rcBounds;
CalculateItemRect(x,y,pltrItem->nWidth,rcBounds);
if(rcBounds.PtInRect(CPoint(px,py)))
return pltrItem;
else
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
// CltrItemTreeWnd message handlers
void CltrItemTreeWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
CGdiObject *pObj = dc.SelectObject(&m_Font);
m_mapItems.reset();
if(m_pltrTree!=NULL)
DrawBranch( &dc,true,0,0,0,*m_pltrTree);
dc.SelectObject(pObj);
}
BOOL CltrItemTreeWnd::OnEraseBkgnd(CDC* pDC)
{
CRect rcClient;
GetClientRect(&rcClient);
pDC->FillSolidRect(rcClient,RGB(255,255,255));
return TRUE;
}
int CltrItemTreeWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
SetFont(&m_Font,TRUE);
return 0;
}
void CltrItemTreeWnd::OnSize(UINT nType, int cx, int cy)
{
KillTimer(ID_TIMER_RECALC);
SetTimer(ID_TIMER_RECALC,75,NULL);
CWnd::OnSize(nType,cx,cy);
}
void CltrItemTreeWnd::OnTimer(UINT_PTR nIDEvent)
{
if(nIDEvent==ID_TIMER_RECALC)
{
RecalcViewLayout();
KillTimer(nIDEvent);
}
CWnd::OnTimer(nIDEvent);
}
void CltrItemTreeWnd::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
{
ScrollHandler(true,nSBCode,nPos);
}
void CltrItemTreeWnd::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar *pScrollBar)
{
ScrollHandler(false,nSBCode,nPos);
}
void CltrItemTreeWnd::OnMouseMove(UINT nFlags, CPoint point)
{
if(m_pltrTree==NULL)
return;
cltrItemNode *pltrItem = FindItemFromCoords(point.x,point.y);
cltrItemBranch *pltrItemB = (cltrItemBranch*)pltrItem;
CClientDC dc(this);
if(pltrItem==NULL || pltrItem->fIsNode)
pltrItemB=NULL;
if(m_pltrHilite!=pltrItem)
{
cltrItemNode *pltrTemp = m_pltrHilite;
CGdiObject *pTemp = dc.SelectObject(&m_Font);
if(pltrTemp!=NULL)
{
m_pltrHilite = NULL;
DrawItem(&dc,false,0,pltrTemp->nX,pltrTemp->nY,pltrTemp,pltrTemp->nWidth);
if(!pltrTemp->fIsNode && ((cltrItemBranch*)pltrTemp)->fIsExpanded)
DrawBranch(&dc,false,0,pltrTemp->nX,pltrTemp->nY+1,*(cltrItemBranch*)pltrTemp);
}
// 1+2*(3+4)-(
if(pltrItem!=NULL)
{
DrawItem(&dc,false,2,pltrItem->nX,pltrItem->nY,pltrItem,pltrItem->nWidth);
if(!pltrItem->fIsNode && ((cltrItemBranch*)pltrItem)->fIsExpanded)
DrawBranch(&dc,false,1,pltrItem->nX,pltrItem->nY+1,*(cltrItemBranch*)pltrItem);
m_pltrHilite = pltrItem;
}
dc.SelectObject(pTemp);
}
}
void CltrItemTreeWnd::OnLButtonUp(UINT nFlags, CPoint point)
{
if(m_pltrTree==NULL)
return;
int nHScroll = GetScrollPos(SB_HORZ);
int nVScroll = GetScrollPos(SB_VERT);
int x = (point.x+nHScroll-m_nLRMargin-m_nCenterOffsX) / m_nBaseWidth;
int y = (point.y+nVScroll-m_nTBMargin-m_nCenterOffsY) / m_nBaseHeight;
cltrItemNode *pltrItem = m_mapItems.find(x,y);
cltrItemBranch *pltrItemB = (cltrItemBranch*)pltrItem;
CClientDC dc(this);
CRect rcItem;
if(pltrItem==NULL || pltrItem->fIsNode)
pltrItemB=NULL;
if(pltrItemB!=NULL)
{
CalculateItemRect(pltrItem->nX, pltrItem->nY, pltrItem->nWidth, rcItem);
if(point.x<(rcItem.left+6) && point.y>=(rcItem.bottom-6))
{
pltrItemB->fIsExpanded = !pltrItemB->fIsExpanded;
RecalcViewLayout();
Invalidate(TRUE);
}
}
}
void CltrItemTreeWnd::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
cltrItemNode *pltrItem = FindItemFromCoords(point.x,point.y);
m_pltrContext = pltrItem;
CMenu menuCtx, *pMenu;
menuCtx.LoadMenu(IDR_CONTEXT);
pMenu =menuCtx.GetSubMenu(1);
MapWindowPoints(NULL,&point,1);
UINT nCmd = pMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RETURNCMD,point.x,point.y,this);
if(nCmd!=0)
{
OnCommand(nCmd,0);
}
m_pltrContext = NULL;
CWnd::OnRButtonUp(nFlags, point);
}
void CltrItemTreeWnd::OnInitMenuPopup(CMenu* pMenu, UINT nIndex, BOOL bSysMenu)
{
if (bSysMenu)
return; // don't support system menu
ASSERT(pMenu != NULL);
// check the enabled state of various menu items
CCmdUI state;
state.m_pMenu = pMenu;
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pParentMenu == NULL);
// determine if menu is popup in top-level menu and set m_pOther to
// it if so (m_pParentMenu == NULL indicates that it is secondary popup)
HMENU hParentMenu;
if (AfxGetThreadState()->m_hTrackingMenu == pMenu->m_hMenu)
state.m_pParentMenu = pMenu; // parent == child for tracking popup
else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
{
CWnd* pParent = GetTopLevelParent();
// child windows don't have menus -- need to go to the top!
if (pParent != NULL &&
(hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
{
int nIndexMax = ::GetMenuItemCount(hParentMenu);
for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
{
if (::GetSubMenu(hParentMenu, nIndex) == pMenu->m_hMenu)
{
// when popup is found, m_pParentMenu is containing menu
state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
break;
}
}
}
}
state.m_nIndexMax = pMenu->GetMenuItemCount();
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
state.m_nID = pMenu->GetMenuItemID(state.m_nIndex);
if (state.m_nID == 0)
continue; // menu separator or invalid cmd - ignore it
ASSERT(state.m_pOther == NULL);
ASSERT(state.m_pMenu != NULL);
if (state.m_nID == (UINT)-1)
{
// possibly a popup menu, route to first item of that popup
state.m_pSubMenu = pMenu->GetSubMenu(state.m_nIndex);
if (state.m_pSubMenu == NULL ||
(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
state.m_nID == (UINT)-1)
{
continue; // first item of popup can't be routed to
}
state.DoUpdate(this, FALSE); // popups are never auto disabled
}
else
{
// normal menu item
// Auto enable/disable if frame window has 'm_bAutoMenuEnable'
// set and command is _not_ a system command.
state.m_pSubMenu = NULL;
state.DoUpdate(this, TRUE && state.m_nID < 0xF000);
}
// adjust for menu deletions and additions
UINT nCount = pMenu->GetMenuItemCount();
if (nCount < state.m_nIndexMax)
{
state.m_nIndex -= (state.m_nIndexMax - nCount);
while (state.m_nIndex < nCount &&
pMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
{
state.m_nIndex++;
}
}
state.m_nIndexMax = nCount;
}
}
void CltrItemTreeWnd::OnLtrcontextShowProps()
{
if(m_pltrContext==NULL)
return;
CDlgProperties dlgProps(m_pPkg,m_pltrContext->papeElem);
dlgProps.DoModal();
}
void CltrItemTreeWnd::OnUpdateLtrcontextShowProps(CCmdUI* pCmdUI)
{
if(m_pltrContext==NULL)
{ pCmdUI->Enable(FALSE); return; }
}
void CltrItemTreeWnd::OnUpdateLtrcontextCollapseItem(CCmdUI* pCmdUI)
{
if(m_pltrContext==NULL)
{ pCmdUI->Enable(FALSE); return; }
if(!m_pltrContext->fIsNode)
pCmdUI->Enable( ((cltrItemBranch*)m_pltrContext)->fIsExpanded );
else
pCmdUI->Enable(FALSE);
}
void CltrItemTreeWnd::OnUpdateLtrcontextExpandItem(CCmdUI* pCmdUI)
{
if(m_pltrContext==NULL)
{ pCmdUI->Enable(FALSE); return; }
if(!m_pltrContext->fIsNode)
pCmdUI->Enable( !((cltrItemBranch*)m_pltrContext)->fIsExpanded );
else
pCmdUI->Enable(FALSE);
}
void CltrItemTreeWnd::OnLtrcontextExpandItem()
{
if(m_pltrContext==NULL)
return;
if(!m_pltrContext->fIsNode)
{
cltrItemBranch* pltrItemB = (cltrItemBranch*)m_pltrContext;
if(!pltrItemB->fIsExpanded)
{
pltrItemB->fIsExpanded = true;
Invalidate(TRUE);
}
}
}
void CltrItemTreeWnd::OnLtrcontextCollapseItem()
{
if(m_pltrContext==NULL)
return;
if(!m_pltrContext->fIsNode)
{
cltrItemBranch* pltrItemB = (cltrItemBranch*)m_pltrContext;
if(pltrItemB->fIsExpanded)
{
pltrItemB->fIsExpanded = false;
Invalidate(TRUE);
}
}
}
void CltrItemTreeWnd::OnLtrcontextShowRawTokenStream()
{
// TODO: Add your command handler code here
CDlgProperties dlgProps(m_pPkg,m_pPkg->patsGetTokenStream());
dlgProps.DoModal();
}