// SizingControlBar.cpp : implementation file // #include "stdafx.h" #include "afxpriv.h" // for CDockContext #include "resource.h" #include "piecebar.h" #include "library.h" #include "pieceinf.h" #include "project.h" #include "globals.h" #include "lc_application.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////// // CPiecesBar int PiecesSortFunc(const PieceInfo* a, const PieceInfo* b, void* SortData) { if (a->IsSubPiece()) { if (b->IsSubPiece()) { return strcmp(a->m_strDescription, b->m_strDescription); } else { return 1; } } else { if (b->IsSubPiece()) { return -1; } else { return strcmp(a->m_strDescription, b->m_strDescription); } } return 0; } CPiecesBar::CPiecesBar() { int i = AfxGetApp()->GetProfileInt("Settings", "Piecebar Options", 0); m_bSubParts = (i & PIECEBAR_SUBPARTS) != 0; m_bNumbers = (i & PIECEBAR_PARTNUMBERS) != 0; m_sizeMin = CSize(222, 200); m_sizeHorz = CSize(200, 200); m_sizeVert = CSize(226, -1); m_sizeFloat = CSize(226, 270); m_bTracking = FALSE; m_bInRecalcNC = FALSE; m_cxEdge = 5; m_bDragShowContent = FALSE; m_nPreviewHeight = AfxGetApp()->GetProfileInt("Settings", "Preview Height", 93); m_bNoContext = FALSE; } CPiecesBar::~CPiecesBar() { AfxGetApp()->WriteProfileInt("Settings", "Preview Height", m_nPreviewHeight); SaveState(); } BEGIN_MESSAGE_MAP(CPiecesBar, CControlBar) //{{AFX_MSG_MAP(CPiecesBar) ON_WM_PAINT() ON_WM_NCPAINT() ON_WM_WINDOWPOSCHANGED() ON_WM_NCCALCSIZE() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_NCLBUTTONDOWN() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONDBLCLK() ON_WM_RBUTTONDOWN() ON_WM_CAPTURECHANGED() ON_WM_NCHITTEST() ON_WM_SETCURSOR() ON_WM_SIZE() ON_WM_CREATE() ON_WM_CONTEXTMENU() //}}AFX_MSG_MAP ON_LBN_SELCHANGE(IDW_COLORSLIST, OnSelChangeColor) ON_MESSAGE(WM_LC_SPLITTER_MOVED, OnSplitterMoved) END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////// // CPiecesBar message handlers BOOL CPiecesBar::Create(LPCTSTR lpszWindowName, CWnd* pParentWnd, CSize sizeDefault, BOOL bHasGripper, UINT nID, DWORD dwStyle) { ASSERT_VALID(pParentWnd); // must have a parent ASSERT (!((dwStyle & CBRS_SIZE_FIXED) && (dwStyle & CBRS_SIZE_DYNAMIC))); // save the style SetBarStyle(dwStyle & CBRS_ALL); CString wndclass = ::AfxRegisterWndClass(CS_DBLCLKS, ::LoadCursor(NULL, IDC_ARROW), ::GetSysColorBrush(COLOR_BTNFACE), 0); dwStyle &= ~CBRS_ALL; dwStyle &= WS_VISIBLE | WS_CHILD; if (!CWnd::Create(wndclass, lpszWindowName, dwStyle, CRect(0,0,0,0), pParentWnd, nID)) return FALSE; if (sizeDefault.cx < m_sizeMin.cx) sizeDefault.cx = m_sizeMin.cx; if (sizeDefault.cy < m_sizeMin.cy) sizeDefault.cy = m_sizeMin.cy; m_sizeHorz = sizeDefault; m_sizeVert = sizeDefault; m_sizeFloat = sizeDefault; LoadState(); m_bHasGripper = bHasGripper; m_cyGripper = m_bHasGripper ? 12 : 0; return TRUE; } void CPiecesBar::SaveState() { CWinApp* pApp = AfxGetApp(); TCHAR* szSection = _T("PiecesBar"); pApp->WriteProfileInt(szSection, _T("HorzCX"), m_sizeHorz.cx); pApp->WriteProfileInt(szSection, _T("HorzCY"), m_sizeHorz.cy); pApp->WriteProfileInt(szSection, _T("VertCX"), m_sizeVert.cx); pApp->WriteProfileInt(szSection, _T("VertCY"), m_sizeVert.cy); pApp->WriteProfileInt(szSection, _T("FloatCX"), m_sizeFloat.cx); pApp->WriteProfileInt(szSection, _T("FloatCY"), m_sizeFloat.cy); } void CPiecesBar::LoadState() { CWinApp* pApp = AfxGetApp(); TCHAR* szSection = _T("PiecesBar"); m_sizeHorz.cx = (int)pApp->GetProfileInt(szSection, _T("HorzCX"), m_sizeHorz.cx); m_sizeHorz.cy = (int)pApp->GetProfileInt(szSection, _T("HorzCY"), m_sizeHorz.cy); m_sizeVert.cx = (int)pApp->GetProfileInt(szSection, _T("VertCX"), m_sizeVert.cx); m_sizeVert.cy = (int)pApp->GetProfileInt(szSection, _T("VertCY"), m_sizeVert.cy); m_sizeFloat.cx = (int)pApp->GetProfileInt(szSection, _T("FloatCX"), m_sizeFloat.cx); m_sizeFloat.cy = (int)pApp->GetProfileInt(szSection, _T("FloatCY"), m_sizeFloat.cy); } BOOL CPiecesBar::IsHorzDocked() const { return (m_nDockBarID == AFX_IDW_DOCKBAR_TOP || m_nDockBarID == AFX_IDW_DOCKBAR_BOTTOM); } BOOL CPiecesBar::IsVertDocked() const { return (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT || m_nDockBarID == AFX_IDW_DOCKBAR_RIGHT); } CSize CPiecesBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz) { CRect rc; m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_TOP)->GetWindowRect(rc); int nHorzDockBarWidth = bStretch ? 32767 : rc.Width() + 4; m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_LEFT)->GetWindowRect(rc); int nVertDockBarHeight = bStretch ? 32767 : rc.Height() + 4; if (bHorz) return CSize(nHorzDockBarWidth, m_sizeHorz.cy); else return CSize(m_sizeVert.cx, nVertDockBarHeight); } CSize CPiecesBar::CalcDynamicLayout(int nLength, DWORD dwMode) { if (dwMode & (LM_HORZDOCK | LM_VERTDOCK)) { if (nLength == -1) GetDockingFrame()->DelayRecalcLayout(); return CControlBar::CalcDynamicLayout(nLength,dwMode); } if (dwMode & LM_MRUWIDTH) return m_sizeFloat; if (dwMode & LM_COMMIT) { m_sizeFloat.cx = nLength; return m_sizeFloat; } if (dwMode & LM_LENGTHY) return CSize(m_sizeFloat.cx, m_sizeFloat.cy = max(m_sizeMin.cy, nLength)); else return CSize(max(m_sizeMin.cx, nLength), m_sizeFloat.cy); } void CPiecesBar::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos) { CControlBar::OnWindowPosChanged(lpwndpos); // Find on which side are we docked m_nDockBarID = GetParent()->GetDlgCtrlID(); if (!m_bInRecalcNC) { m_bInRecalcNC = TRUE; // Force recalc the non-client area SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); m_bInRecalcNC = FALSE; } } BOOL CPiecesBar::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { if ((nHitTest != HTSIZE) || m_bTracking) return CControlBar::OnSetCursor(pWnd, nHitTest, message); if (IsHorzDocked()) ::SetCursor(::LoadCursor(NULL, IDC_SIZENS)); else ::SetCursor(::LoadCursor(NULL, IDC_SIZEWE)); return TRUE; } ///////////////////////////////////////////////////////////////////////// // Mouse Handling // void CPiecesBar::OnLButtonDown(UINT nFlags, CPoint point) { if (m_pDockBar != NULL) { // start the drag ASSERT(m_pDockContext != NULL); ClientToScreen(&point); m_pDockContext->StartDrag(point); } else CWnd::OnLButtonDown(nFlags, point); } void CPiecesBar::OnLButtonDblClk(UINT nFlags, CPoint point) { if (m_pDockBar != NULL) { // toggle docking ASSERT(m_pDockContext != NULL); m_pDockContext->ToggleDocking(); } else CWnd::OnLButtonDblClk(nFlags, point); } void CPiecesBar::OnNcLButtonDown(UINT nHitTest, CPoint point) { if (m_bTracking) return; if ((nHitTest == HTSIZE) && !IsFloating()) StartTracking(); else CControlBar::OnNcLButtonDown(nHitTest, point); } void CPiecesBar::OnLButtonUp(UINT nFlags, CPoint point) { if (m_bTracking) StopTracking(TRUE); CControlBar::OnLButtonUp(nFlags, point); } void CPiecesBar::OnRButtonDown(UINT nFlags, CPoint point) { if (m_bTracking) StopTracking(FALSE); CControlBar::OnRButtonDown(nFlags, point); } void CPiecesBar::OnMouseMove(UINT nFlags, CPoint point) { if (m_bTracking) { ASSERT (!IsFloating()); CPoint pt = point; ClientToScreen(&pt); OnTrackUpdateSize(pt); } CControlBar::OnMouseMove(nFlags, point); } void CPiecesBar::OnCaptureChanged(CWnd *pWnd) { if (m_bTracking && pWnd != this) StopTracking(FALSE); // cancel tracking CControlBar::OnCaptureChanged(pWnd); } void CPiecesBar::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) { UNREFERENCED_PARAMETER(bCalcValidRects); // Compute the rectangle of the mobile edge GetWindowRect(m_rectBorder); m_rectBorder.OffsetRect(-m_rectBorder.left, -m_rectBorder.top); m_rectBorder.DeflateRect(1, 1); m_rectGripper = m_rectBorder; m_rectGripper.DeflateRect(5, 5); m_rectGripper.right -= m_cxEdge; m_rectGripper.bottom -= m_cxEdge; CRect rc = lpncsp->rgrc[0]; DWORD dwBorderStyle = m_dwStyle | CBRS_BORDER_ANY; switch(m_nDockBarID) { case AFX_IDW_DOCKBAR_TOP: dwBorderStyle &= ~CBRS_BORDER_BOTTOM; rc.DeflateRect(m_cyGripper + 2, 2, 2, m_cxEdge + 2); m_rectBorder.top = m_rectBorder.bottom - m_cxEdge; break; case AFX_IDW_DOCKBAR_BOTTOM: dwBorderStyle &= ~CBRS_BORDER_TOP; rc.DeflateRect(m_cyGripper + 2, m_cxEdge + 2, 2, 2); m_rectBorder.bottom = m_rectBorder.top + m_cxEdge; m_rectGripper.OffsetRect(0, m_cxEdge); break; case AFX_IDW_DOCKBAR_LEFT: dwBorderStyle &= ~CBRS_BORDER_RIGHT; rc.DeflateRect(2, m_cyGripper + 2, m_cxEdge + 2, 6); m_rectBorder.left = m_rectBorder.right - m_cxEdge; break; case AFX_IDW_DOCKBAR_RIGHT: dwBorderStyle &= ~CBRS_BORDER_LEFT; rc.DeflateRect(m_cxEdge + 2, m_cyGripper + 2, 2, 6); m_rectBorder.right = m_rectBorder.left + m_cxEdge; m_rectGripper.OffsetRect(m_cxEdge, 0); break; default: m_rectBorder.SetRectEmpty(); break; } lpncsp->rgrc[0] = rc; SetBarStyle(dwBorderStyle); } void CPiecesBar::OnNcPaint() { // get window DC that is clipped to the non-client area CWindowDC dc(this); CRect rectClient; GetClientRect(rectClient); CRect rectWindow; GetWindowRect(rectWindow); ScreenToClient(rectWindow); rectClient.OffsetRect(-rectWindow.left, -rectWindow.top); dc.ExcludeClipRect(rectClient); // draw borders in non-client area rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top); DrawBorders(&dc, rectWindow); // erase parts not drawn dc.IntersectClipRect(rectWindow); // erase NC background the hard way HBRUSH hbr = (HBRUSH)GetClassLong(m_hWnd, GCL_HBRBACKGROUND); ::FillRect(dc.m_hDC, rectWindow, hbr); // paint the mobile edge dc.Draw3dRect(m_rectBorder, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); if (m_bHasGripper) { // paint the gripper CRect gripper = m_rectGripper; if (IsHorzDocked()) { // gripper at left gripper.right = gripper.left + 3; dc.Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); gripper.OffsetRect(3, 0); dc.Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); } else if (IsVertDocked()) { // gripper at top gripper.bottom = gripper.top + 3; dc.Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); gripper.OffsetRect(0, 3); dc.Draw3dRect(gripper, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); } } ReleaseDC(&dc); } void CPiecesBar::OnPaint() { // overridden to skip border painting based on clientrect CPaintDC dc(this); } LRESULT CPiecesBar::OnNcHitTest(CPoint point) { if (IsFloating()) return CControlBar::OnNcHitTest(point); CRect rc; GetWindowRect(rc); point.Offset(-rc.left, -rc.top); if (m_rectBorder.PtInRect(point)) return HTSIZE; else return HTCLIENT; } ///////////////////////////////////////////////////////////////////////// // CPiecesBar implementation helpers void CPiecesBar::StartTracking() { SetCapture(); // make sure no updates are pending RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); m_bDragShowContent = QueryDragFullWindows(); if (!m_bDragShowContent) m_pDockSite->LockWindowUpdate(); m_sizeOld = IsHorzDocked() ? m_sizeHorz : m_sizeVert; CRect rect; GetWindowRect(&rect); m_ptOld = m_rectBorder.CenterPoint() + rect.TopLeft(); m_sizeMax = CalcMaxSize(); m_bTracking = TRUE; if (!m_bDragShowContent) OnTrackInvertTracker(); } void CPiecesBar::StopTracking(BOOL bAccept) { if (!m_bDragShowContent) { OnTrackInvertTracker(); m_pDockSite->UnlockWindowUpdate(); } m_bTracking = FALSE; ReleaseCapture(); if (!bAccept) // resize canceled? { // restore old size if (IsHorzDocked()) m_sizeHorz = m_sizeOld; else m_sizeVert = m_sizeOld; } m_pDockSite->DelayRecalcLayout(); } void CPiecesBar::OnTrackUpdateSize(CPoint& point) { BOOL bHorz = IsHorzDocked(); CSize sizeNew = m_sizeOld; if ((m_nDockBarID == AFX_IDW_DOCKBAR_TOP) || (m_nDockBarID == AFX_IDW_DOCKBAR_LEFT)) sizeNew += point - m_ptOld; else sizeNew -= point - m_ptOld; // check limits sizeNew.cx = max(m_sizeMin.cx, sizeNew.cx); sizeNew.cy = max(m_sizeMin.cy, sizeNew.cy); sizeNew.cx = min(m_sizeMax.cx, sizeNew.cx); sizeNew.cy = min(m_sizeMax.cy, sizeNew.cy); if ((sizeNew.cy == m_sizeHorz.cy) && bHorz || (sizeNew.cx == m_sizeVert.cx) && !bHorz) return; // no size change if (!m_bDragShowContent) OnTrackInvertTracker(); if (bHorz) m_sizeHorz = sizeNew; else m_sizeVert = sizeNew; if (!m_bDragShowContent) OnTrackInvertTracker(); else m_pDockSite->DelayRecalcLayout(); } CSize CPiecesBar::CalcMaxSize() { // the control bar cannot grow with more than the size of // remaining client area of the frame CRect rect; m_pDockSite->GetClientRect(&rect); CSize size = rect.Size(); CWnd* pBar; if (IsHorzDocked()) { if (pBar = m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_TOP)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } if (pBar = m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_BOTTOM)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } if (pBar = m_pDockSite->GetControlBar(AFX_IDW_STATUS_BAR)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } } else { if (pBar = m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_LEFT)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } if (pBar = m_pDockSite->GetControlBar(AFX_IDW_DOCKBAR_RIGHT)) { pBar->GetWindowRect(&rect); size -= rect.Size(); } } size -= CSize(4, 4); size += IsHorzDocked() ? m_sizeHorz : m_sizeVert; return size; } void CPiecesBar::OnTrackInvertTracker() { ASSERT_VALID(this); ASSERT(m_bTracking); CRect rect = m_rectBorder; CRect rectBar, rectFrame; GetWindowRect(rectBar); rect.OffsetRect(rectBar.TopLeft()); m_pDockSite->GetWindowRect(rectFrame); rect.OffsetRect(-rectFrame.left, -rectFrame.top); switch (m_nDockBarID) { case AFX_IDW_DOCKBAR_TOP: rect.OffsetRect(0, m_sizeHorz.cy - m_sizeOld.cy); break; case AFX_IDW_DOCKBAR_BOTTOM: rect.OffsetRect(0, m_sizeOld.cy - m_sizeHorz.cy); break; case AFX_IDW_DOCKBAR_LEFT: rect.OffsetRect(m_sizeVert.cx - m_sizeOld.cx, 0); break; case AFX_IDW_DOCKBAR_RIGHT: rect.OffsetRect(m_sizeOld.cx - m_sizeVert.cx, 0); break; } if (IsVertDocked()) rect.bottom -= 4; rect.DeflateRect(1, 1); CDC *pDC = m_pDockSite->GetDCEx(NULL, DCX_WINDOW|DCX_CACHE|DCX_LOCKWINDOWUPDATE); CBrush* pBrush = CDC::GetHalftoneBrush(); HBRUSH hOldBrush = NULL; if (pBrush != NULL) hOldBrush = (HBRUSH)::SelectObject(pDC->m_hDC, pBrush->m_hObject); pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT); if (hOldBrush != NULL) ::SelectObject(pDC->m_hDC, hOldBrush); m_pDockSite->ReleaseDC(pDC); } BOOL CPiecesBar::QueryDragFullWindows() const { TCHAR sDragfullWindows[2]; DWORD cbDragfullWindows = sizeof(DWORD); DWORD dwType; HKEY hKey; BOOL bRet = FALSE; RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\desktop"), 0, KEY_QUERY_VALUE, &hKey); if (!FAILED(RegQueryValueEx(hKey, _T("DragfullWindows"), NULL, &dwType, (LPBYTE)&sDragfullWindows, &cbDragfullWindows))) if (!_tcscmp(sDragfullWindows, _T("1"))) bRet = TRUE; RegCloseKey(hKey); return bRet; } void CPiecesBar::OnSize(UINT nType, int cx, int cy) { CControlBar::OnSize(nType, cx, cy); if (!IsWindow(m_wndColorsList.m_hWnd)) return; int off = 31; m_wndColorsList.SetWindowPos (NULL, (cx-210)/2, cy-off, 212, 26, SWP_NOZORDER); off += 30; m_wndPiecesCombo.SetWindowPos (NULL, 5, cy-off, cx-10, 140, SWP_NOZORDER); m_wndSplitter.SetWindowPos (NULL, 5, m_nPreviewHeight+6, cx-10, 4, SWP_NOZORDER); m_PiecesTree.SetWindowPos (NULL, 5, m_nPreviewHeight+10, cx-10, cy-off-15-m_nPreviewHeight, SWP_NOZORDER); m_wndPiecePreview.SetWindowPos (NULL, 5, 5, cx-10, m_nPreviewHeight, 0); m_wndPiecePreview.EnableWindow (TRUE); m_wndPiecePreview.ShowWindow (SW_SHOW); m_wndSplitter.ShowWindow (SW_SHOW); m_wndPiecesCombo.ShowWindow(SW_SHOW); } void CPiecesBar::OnUpdateCmdUI(CFrameWnd * pTarget, BOOL bDisableIfNoHndler) { // CWnd::OnUpdateCmdUI(pTarget, FALSE); // int nID = ID_PIECE_GROUP02; // int sta = m_wndGroupsBar.GetToolBarCtrl().GetState(nID) & ~TBSTATE_ENABLED; // if (bEnable) // sta |= TBSTATE_ENABLED|TBSTATE_CHECKED; // m_wndGroupsBar.GetToolBarCtrl().SetState(nID, sta); UpdateDialogControls(pTarget, FALSE); } int CPiecesBar::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CControlBar::OnCreate(lpCreateStruct) == -1) return -1; m_PiecesTree.Create(WS_VISIBLE|WS_TABSTOP|WS_BORDER|TVS_SHOWSELALWAYS|TVS_HASBUTTONS|TVS_HASLINES|TVS_LINESATROOT|TVS_INFOTIP, CRect(0,0,0,0), this, IDW_PIECESTREE); m_wndColorsList.Create(LBS_MULTICOLUMN|LBS_NOINTEGRALHEIGHT|LBS_NOTIFY| LBS_OWNERDRAWFIXED|WS_VISIBLE|WS_TABSTOP|WS_CHILD|WS_BORDER, CRect (0,0,0,0), this, IDW_COLORSLIST); for (int i = 0; i < LC_MAXCOLORS; i++) m_wndColorsList.AddString(""); m_wndPiecesCombo.Create(CBS_DROPDOWN|CBS_SORT|CBS_HASSTRINGS|WS_VISIBLE|WS_CHILD| WS_VSCROLL|WS_TABSTOP, CRect (0,0,0,0), this, IDW_PIECESCOMBO); // Create a font for the combobox LOGFONT logFont; memset(&logFont, 0, sizeof(logFont)); if (!::GetSystemMetrics(SM_DBCSENABLED)) { logFont.lfHeight = -10; logFont.lfWeight = 0; logFont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS; lstrcpy(logFont.lfFaceName, "MS Sans Serif"); if (m_Font.CreateFontIndirect(&logFont)) m_wndPiecesCombo.SetFont(&m_Font); } else { m_Font.Attach(::GetStockObject(SYSTEM_FONT)); m_wndPiecesCombo.SetFont(&m_Font); } m_wndPiecePreview.Create (NULL, NULL, WS_BORDER|WS_CHILD|WS_VISIBLE, CRect(0, 0, 0, 0), this, IDW_PIECEPREVIEW); CreateWindow("STATIC", "", WS_VISIBLE|WS_CHILD|SS_ETCHEDFRAME, 0, 0, 0, 0, m_hWnd, (HMENU)IDW_PIECEBAR_SPLITTER, AfxGetInstanceHandle(), NULL); // y-splitter m_wndSplitter.BindWithControl(this, IDW_PIECEBAR_SPLITTER); m_wndSplitter.SetMinHeight(0, 0); m_wndSplitter.AttachAsAbovePane(IDW_PIECEPREVIEW); m_wndSplitter.AttachAsBelowPane(IDW_PIECESTREE); m_wndSplitter.RecalcLayout(); return 0; } void CPiecesBar::OnSelChangeColor() { int i = m_wndColorsList.GetCurSel(); if (i == LB_ERR) return; lcGetActiveProject()->HandleNotify(LC_COLOR_CHANGED, (i % 2 == 0) ? (i/2) : (((i-1)/2)+14)); m_wndPiecePreview.PostMessage (WM_PAINT); } LONG CPiecesBar::OnSplitterMoved(UINT lParam, LONG wParam) { UNREFERENCED_PARAMETER(wParam); if (lParam == 0) m_bNoContext = TRUE; else m_nPreviewHeight += lParam; return TRUE; } void CPiecesBar::OnContextMenu(CWnd* pWnd, CPoint point) { UNREFERENCED_PARAMETER(pWnd); if (m_bNoContext) m_bNoContext = FALSE; else { CMenu menuPopups; menuPopups.LoadMenu(IDR_POPUPS); CMenu* pMenu = menuPopups.GetSubMenu(0); if (pMenu) { bool CategorySelected = false; CRect r; m_PiecesTree.GetWindowRect(&r); if (r.PtInRect(point)) { HTREEITEM Item = m_PiecesTree.GetSelectedItem(); if (Item != NULL) { PiecesLibrary *Lib = lcGetPiecesLibrary(); CString CategoryName = m_PiecesTree.GetItemText(Item); int CategoryIndex = Lib->FindCategoryIndex((const char*)CategoryName); if (CategoryIndex != -1) CategorySelected = true; } pMenu->EnableMenuItem(ID_PIECEBAR_NEWCATEGORY, MF_BYCOMMAND | MF_ENABLED); } else { pMenu->EnableMenuItem(ID_PIECEBAR_NEWCATEGORY, MF_BYCOMMAND | MF_GRAYED); } pMenu->EnableMenuItem(ID_PIECEBAR_REMOVECATEGORY, MF_BYCOMMAND | (CategorySelected ? MF_ENABLED : MF_GRAYED)); pMenu->EnableMenuItem(ID_PIECEBAR_EDITCATEGORY, MF_BYCOMMAND | (CategorySelected ? MF_ENABLED : MF_GRAYED)); pMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd()); } } } void CPiecesBar::SelectPiece(const char* Category, PieceInfo* Info) { HTREEITEM Item = m_PiecesTree.GetChildItem(TVI_ROOT); const char* PieceName = Info->m_strDescription; // Find the category and make sure it's expanded. while (Item != NULL) { CString Name = m_PiecesTree.GetItemText(Item); if (Name == Category) { m_PiecesTree.Expand(Item, TVE_EXPAND); break; } Item = m_PiecesTree.GetNextSiblingItem(Item); } if (Item == NULL) return; // Expand the piece group if it's patterned. if (Info->IsPatterned()) { PieceInfo* Parent; // Find the parent of this patterned piece and expand it. char ParentName[9]; strcpy(ParentName, Info->m_strName); *strchr(ParentName, 'P') = '\0'; Parent = lcGetPiecesLibrary()->FindPieceInfo(ParentName); if (Parent) { Item = m_PiecesTree.GetChildItem(Item); while (Item != NULL) { CString Name = m_PiecesTree.GetItemText(Item); if (Name == Parent->m_strDescription) { m_PiecesTree.Expand(Item, TVE_EXPAND); // If both descriptions begin with the same text, only show the difference. if (!strncmp(Info->m_strDescription, Parent->m_strDescription, strlen(Parent->m_strDescription))) PieceName = Info->m_strDescription + strlen(Parent->m_strDescription) + 1; break; } Item = m_PiecesTree.GetNextSiblingItem(Item); } } } // Find the piece. Item = m_PiecesTree.GetChildItem(Item); while (Item != NULL) { CString Name = m_PiecesTree.GetItemText(Item); if (Name == PieceName) { m_PiecesTree.SelectItem(Item); return; } Item = m_PiecesTree.GetNextSiblingItem(Item); } } void CPiecesBar::UpdatePiecesTree(const char* OldCategory, const char* NewCategory) { if (OldCategory && NewCategory) { HTREEITEM Item = m_PiecesTree.GetChildItem(TVI_ROOT); while (Item != NULL) { CString Name = m_PiecesTree.GetItemText(Item); if (Name == OldCategory) break; Item = m_PiecesTree.GetNextSiblingItem(Item); } if (Item == NULL) return; m_PiecesTree.SetItemText(Item, NewCategory); m_PiecesTree.EnsureVisible(Item); if (m_PiecesTree.GetItemState(Item, TVIS_EXPANDED) & TVIS_EXPANDED) { m_PiecesTree.Expand(Item, TVE_COLLAPSE | TVE_COLLAPSERESET); m_PiecesTree.Expand(Item, TVE_EXPAND); } } else if (NewCategory) { HTREEITEM Item; Item = m_PiecesTree.InsertItem(TVIF_CHILDREN|TVIF_PARAM|TVIF_TEXT, NewCategory, 0, 0, 0, 0, 0, TVI_ROOT, TVI_SORT); m_PiecesTree.EnsureVisible(Item); } else if (OldCategory) { HTREEITEM Item = m_PiecesTree.GetChildItem(TVI_ROOT); while (Item != NULL) { CString Name = m_PiecesTree.GetItemText(Item); if (Name == OldCategory) break; Item = m_PiecesTree.GetNextSiblingItem(Item); } if (Item == NULL) return; m_PiecesTree.DeleteItem(Item); } } void CPiecesBar::UpdatePiecesTree(bool SearchOnly) { PiecesLibrary *Lib = lcGetPiecesLibrary(); if (SearchOnly) { HTREEITEM Item = m_PiecesTree.GetChildItem(TVI_ROOT); while (Item != NULL) { CString Name = m_PiecesTree.GetItemText(Item); if (Name == "Search Results") break; Item = m_PiecesTree.GetNextSiblingItem(Item); } if (Item == NULL) { Item = m_PiecesTree.InsertItem(TVIF_CHILDREN|TVIF_PARAM|TVIF_TEXT, "Search Results", 0, 0, 0, 0, 0, TVI_ROOT, TVI_LAST); } m_PiecesTree.Expand(Item, TVE_COLLAPSE | TVE_COLLAPSERESET); m_PiecesTree.EnsureVisible(Item); m_PiecesTree.Expand(Item, TVE_EXPAND); } else { m_PiecesTree.SetRedraw(FALSE); m_PiecesTree.DeleteAllItems(); for (int i = 0; i < Lib->GetNumCategories(); i++) { if (Lib->GetCategoryName(i) == "Search Results") continue; m_PiecesTree.InsertItem(TVIF_CHILDREN|TVIF_PARAM|TVIF_TEXT, Lib->GetCategoryName(i), 0, 0, 0, 0, 0, TVI_ROOT, TVI_SORT); } m_PiecesTree.InsertItem(TVIF_CHILDREN|TVIF_PARAM|TVIF_TEXT, "Search Results", 0, 0, 0, 0, 0, TVI_ROOT, TVI_LAST); m_PiecesTree.SetRedraw(TRUE); m_PiecesTree.Invalidate(); } } void CPiecesBar::RefreshPiecesTree() { HTREEITEM Item = m_PiecesTree.GetChildItem(TVI_ROOT); while (Item != NULL) { if ((m_PiecesTree.GetItemState(Item, TVIF_STATE) & TVIS_EXPANDED) != 0) { m_PiecesTree.Expand(Item, TVE_COLLAPSE | TVE_COLLAPSERESET); m_PiecesTree.Expand(Item, TVE_EXPAND); } Item = m_PiecesTree.GetNextSiblingItem(Item); } } BOOL CPiecesBar::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { if (wParam == IDW_PIECESTREE) { LPNMTREEVIEW Notify = (LPNMTREEVIEW)lParam; if (Notify->hdr.code == TVN_SELCHANGED) { PieceInfo* Info = (PieceInfo*)Notify->itemNew.lParam; if (Info != NULL) { lcGetActiveProject()->SetCurrentPiece(Info); m_wndPiecePreview.SetPieceInfo(Info); m_wndPiecePreview.PostMessage(WM_PAINT); } } else if (Notify->hdr.code == TVN_BEGINDRAG) { PieceInfo* Info = (PieceInfo*)Notify->itemNew.lParam; if (Info != NULL) { lcGetActiveProject()->BeginPieceDrop(Info); // Force a cursor update. CFrameWnd* pFrame = (CFrameWnd*)AfxGetMainWnd(); CView* pView = pFrame->GetActiveView(); pView->PostMessage(WM_LC_SET_CURSOR, 0, 0); } } else if (Notify->hdr.code == TVN_GETINFOTIP) { LPNMTVGETINFOTIP Tip = (LPNMTVGETINFOTIP)lParam; HTREEITEM Item = Tip->hItem; PieceInfo* Info = (PieceInfo*)m_PiecesTree.GetItemData(Item); if (Info != NULL) { _snprintf(Tip->pszText, Tip->cchTextMax, "%s (%s)", Info->m_strDescription, Info->m_strName); } } else if (Notify->hdr.code == TVN_ITEMEXPANDING) { if (Notify->action == TVE_EXPAND) { m_PiecesTree.SetRedraw(FALSE); PiecesLibrary *Lib = lcGetPiecesLibrary(); // Remove all children. HTREEITEM Item = Notify->itemNew.hItem; if (m_PiecesTree.ItemHasChildren(Item)) { HTREEITEM NextItem; HTREEITEM ChildItem = m_PiecesTree.GetChildItem(Item); while (ChildItem != NULL) { NextItem = m_PiecesTree.GetNextItem(ChildItem, TVGN_NEXT); m_PiecesTree.DeleteItem(ChildItem); ChildItem = NextItem; } } // Check if we're expanding a category item. if (Notify->itemNew.lParam == NULL) { HTREEITEM CategoryItem = Notify->itemNew.hItem; CString CategoryName = m_PiecesTree.GetItemText(CategoryItem); int CategoryIndex = Lib->FindCategoryIndex((const char*)CategoryName); PtrArray SinglePieces, GroupedPieces; if (CategoryIndex != -1) { int i; Lib->GetCategoryEntries(CategoryIndex, true, SinglePieces, GroupedPieces); // Merge and sort the arrays. SinglePieces += GroupedPieces; SinglePieces.Sort(PiecesSortFunc, NULL); for (i = 0; i < SinglePieces.GetSize(); i++) { PieceInfo* Info = SinglePieces[i]; if (!m_bSubParts && Info->IsSubPiece()) continue; if (GroupedPieces.FindIndex(Info) == -1) m_PiecesTree.InsertItem(TVIF_PARAM|TVIF_TEXT, Info->m_strDescription, 0, 0, 0, 0, (LPARAM)Info, CategoryItem, TVI_LAST); else m_PiecesTree.InsertItem(TVIF_CHILDREN|TVIF_PARAM|TVIF_TEXT, Info->m_strDescription, 0, 0, 0, 0, (LPARAM)Info, CategoryItem, TVI_LAST); } } if (CategoryName == "Search Results") { // Let the user know if the search is empty. if ((SinglePieces.GetSize() == 0) && (GroupedPieces.GetSize() == 0)) { m_PiecesTree.InsertItem(TVIF_PARAM|TVIF_TEXT, "No pieces found", 0, 0, 0, 0, 0, CategoryItem, TVI_SORT); } } } else { PieceInfo* Parent = (PieceInfo*)Notify->itemNew.lParam; HTREEITEM CategoryItem = m_PiecesTree.GetParentItem(Notify->itemNew.hItem); CString CategoryName = m_PiecesTree.GetItemText(CategoryItem); int CategoryIndex = Lib->FindCategoryIndex((const char*)CategoryName); PtrArray Pieces; Lib->GetPatternedPieces(Parent, Pieces); Pieces.Sort(PiecesSortFunc, NULL); HTREEITEM ParentItem = Notify->itemNew.hItem; for (int i = 0; i < Pieces.GetSize(); i++) { PieceInfo* Info = Pieces[i]; if (!m_bSubParts && Info->IsSubPiece()) continue; if (CategoryIndex != -1) { if (!Lib->PieceInCategory(Info, Lib->GetCategoryKeywords(CategoryIndex))) continue; } // If both descriptions begin with the same text, only show the difference. if (!strncmp(Info->m_strDescription, Parent->m_strDescription, strlen(Parent->m_strDescription))) m_PiecesTree.InsertItem(TVIF_PARAM|TVIF_TEXT, Info->m_strDescription + strlen(Parent->m_strDescription) + 1, 0, 0, 0, 0, (LPARAM)Info, ParentItem, TVI_LAST); else m_PiecesTree.InsertItem(TVIF_PARAM|TVIF_TEXT, Info->m_strDescription, 0, 0, 0, 0, (LPARAM)Info, ParentItem, TVI_LAST); } } m_PiecesTree.SetRedraw(TRUE); m_PiecesTree.Invalidate(); } else if (Notify->action == TVE_COLLAPSE) { m_PiecesTree.Expand(Notify->itemNew.hItem, TVE_COLLAPSE | TVE_COLLAPSERESET); } } } return CControlBar::OnNotify(wParam, lParam, pResult); }