RepoBrowser: added Extension column
[TortoiseGit.git] / src / TortoiseProc / RepositoryBrowser.cpp
blob01eecfd145a3803697dcae183ab265a033b6bd88
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2009-2012 - TortoiseGit
4 // Copyright (C) 2012 Sven Strickroth <email@cs-ware.de>
5 // Copyright (C) 2003-2012 - TortoiseSVN
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software Foundation,
19 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 // RepositoryBrowser.cpp : implementation file
24 #include "stdafx.h"
25 #include "TortoiseProc.h"
26 #include "RepositoryBrowser.h"
27 #include "LogDlg.h"
28 #include "AppUtils.h"
29 #include "IconMenu.h"
30 #include "UnicodeUtils.h"
31 #include "SysImageList.h"
32 #include <sys/stat.h>
33 #include "SysInfo.h"
34 #include "registry.h"
35 #include "PathUtils.h"
37 void SetSortArrowA(CListCtrl * control, int nColumn, bool bAscending)
39 if (control == NULL)
40 return;
42 // set the sort arrow
43 CHeaderCtrl * pHeader = control->GetHeaderCtrl();
44 HDITEM HeaderItem = {0};
45 HeaderItem.mask = HDI_FORMAT;
46 for (int i = 0; i < pHeader->GetItemCount(); ++i)
48 pHeader->GetItem(i, &HeaderItem);
49 HeaderItem.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP);
50 pHeader->SetItem(i, &HeaderItem);
52 if (nColumn >= 0)
54 pHeader->GetItem(nColumn, &HeaderItem);
55 HeaderItem.fmt |= (bAscending ? HDF_SORTUP : HDF_SORTDOWN);
56 pHeader->SetItem(nColumn, &HeaderItem);
60 class CRepoListCompareFunc
62 public:
63 CRepoListCompareFunc(CListCtrl* pList, int col, bool desc)
64 : m_col(col)
65 , m_desc(desc)
66 , m_pList(pList)
69 static int CALLBACK StaticCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
71 return ((CRepoListCompareFunc *) lParamSort)->Compare(lParam1, lParam2);
74 int Compare(LPARAM lParam1, LPARAM lParam2)
76 CShadowFilesTree * pLeft = (CShadowFilesTree *)m_pList->GetItemData(lParam1);
77 CShadowFilesTree * pRight = (CShadowFilesTree *)m_pList->GetItemData(lParam2);
79 int result = 0;
80 switch(m_col)
82 case CRepositoryBrowser::eCol_Name:
83 result = SortStrCmp(pLeft->m_sName, pRight->m_sName);
84 if (result != 0)
85 break;
86 case CRepositoryBrowser::eCol_Extension:
87 result = m_pList->GetItemText(static_cast<int>(lParam1), 1).CompareNoCase(m_pList->GetItemText(static_cast<int>(lParam2), 1));
88 if (result == 0) // if extensions are the same, use the filename to sort
89 result = SortStrCmp(pRight->m_sName, pRight->m_sName);
90 if (result != 0)
91 break;
92 case CRepositoryBrowser::eCol_FileSize:
93 if (pLeft->m_iSize > pRight->m_iSize)
94 result = 1;
95 else if (pLeft->m_iSize < pRight->m_iSize)
96 result = -1;
97 else // fallback
98 result = SortStrCmp(pLeft->m_sName, pRight->m_sName);
101 if (m_desc)
102 result = -result;
104 if (pLeft->m_bFolder != pRight->m_bFolder)
106 if (pRight->m_bFolder)
107 result = 1;
108 else
109 result = -1;
112 return result;
114 int SortStrCmp(CString &left, CString &right)
116 if (CRepositoryBrowser::s_bSortLogical)
117 return StrCmpLogicalW(left, right);
118 return StrCmpI(left, right);
121 int m_col;
122 bool m_desc;
123 CListCtrl* m_pList;
126 // CRepositoryBrowser dialog
128 bool CRepositoryBrowser::s_bSortLogical = true;
130 IMPLEMENT_DYNAMIC(CRepositoryBrowser, CResizableStandAloneDialog)
132 CRepositoryBrowser::CRepositoryBrowser(CString rev, CWnd* pParent /*=NULL*/)
133 : CResizableStandAloneDialog(CRepositoryBrowser::IDD, pParent)
134 , m_currSortCol(0)
135 , m_currSortDesc(false)
136 , m_sRevision(rev)
140 CRepositoryBrowser::~CRepositoryBrowser()
144 void CRepositoryBrowser::DoDataExchange(CDataExchange* pDX)
146 CDialog::DoDataExchange(pDX);
147 DDX_Control(pDX, IDC_REPOTREE, m_RepoTree);
148 DDX_Control(pDX, IDC_REPOLIST, m_RepoList);
152 BEGIN_MESSAGE_MAP(CRepositoryBrowser, CResizableStandAloneDialog)
153 ON_NOTIFY(TVN_SELCHANGED, IDC_REPOTREE, &CRepositoryBrowser::OnTvnSelchangedRepoTree)
154 ON_WM_CONTEXTMENU()
155 ON_NOTIFY(LVN_COLUMNCLICK, IDC_REPOLIST, &CRepositoryBrowser::OnLvnColumnclickRepoList)
156 ON_NOTIFY(NM_DBLCLK, IDC_REPOLIST, &CRepositoryBrowser::OnNMDblclk_RepoList)
157 ON_BN_CLICKED(IDC_BUTTON_REVISION, &CRepositoryBrowser::OnBnClickedButtonRevision)
158 ON_WM_SETCURSOR()
159 ON_WM_MOUSEMOVE()
160 ON_WM_LBUTTONDOWN()
161 ON_WM_LBUTTONUP()
162 END_MESSAGE_MAP()
165 // CRepositoryBrowser message handlers
167 BOOL CRepositoryBrowser::OnInitDialog()
169 CResizableStandAloneDialog::OnInitDialog();
170 CAppUtils::MarkWindowAsUnpinnable(m_hWnd);
172 AddAnchor(IDC_STATIC, TOP_LEFT);
173 AddAnchor(IDC_BUTTON_REVISION, TOP_LEFT, TOP_RIGHT);
174 AddAnchor(IDC_REPOTREE, TOP_LEFT, BOTTOM_LEFT);
175 AddAnchor(IDC_REPOLIST, TOP_LEFT, BOTTOM_RIGHT);
176 AddAnchor(IDHELP, BOTTOM_RIGHT);
177 AddAnchor(IDOK, BOTTOM_RIGHT);
178 AddAnchor(IDCANCEL, BOTTOM_RIGHT);
180 CRepositoryBrowser::s_bSortLogical = !CRegDWORD(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\NoStrCmpLogical", 0, false, HKEY_CURRENT_USER);
181 if (CRepositoryBrowser::s_bSortLogical)
182 CRepositoryBrowser::s_bSortLogical = !CRegDWORD(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\NoStrCmpLogical", 0, false, HKEY_LOCAL_MACHINE);
184 CString temp;
185 temp.LoadString(IDS_STATUSLIST_COLFILENAME);
186 m_RepoList.InsertColumn(eCol_Name, temp, 0, 150);
187 temp.LoadString(IDS_STATUSLIST_COLEXT);
188 m_RepoList.InsertColumn(eCol_Extension, temp, 0, 100);
189 temp.LoadString(IDS_LOG_SIZE);
190 m_RepoList.InsertColumn(eCol_FileSize, temp, 0, 100);
192 // set up the list control
193 // set the extended style of the list control
194 // the style LVS_EX_FULLROWSELECT interferes with the background watermark image but it's more important to be able to select in the whole row.
195 CRegDWORD regFullRowSelect(_T("Software\\TortoiseGit\\FullRowSelect"), TRUE);
196 DWORD exStyle = LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER | LVS_EX_INFOTIP | LVS_EX_SUBITEMIMAGES;
197 if (DWORD(regFullRowSelect))
198 exStyle |= LVS_EX_FULLROWSELECT;
199 m_RepoList.SetExtendedStyle(exStyle);
200 m_RepoList.SetImageList(&SYS_IMAGE_LIST(), LVSIL_SMALL);
202 m_RepoTree.SetImageList(&SYS_IMAGE_LIST(), TVSIL_NORMAL);
203 if (SysInfo::Instance().IsVistaOrLater())
205 DWORD exStyle = TVS_EX_FADEINOUTEXPANDOS | TVS_EX_AUTOHSCROLL | TVS_EX_DOUBLEBUFFER;
206 m_RepoTree.SetExtendedStyle(exStyle, exStyle);
209 SetWindowTheme(m_RepoTree.GetSafeHwnd(), L"Explorer", NULL);
210 SetWindowTheme(m_RepoList.GetSafeHwnd(), L"Explorer", NULL);
212 m_nIconFolder = SYS_IMAGE_LIST().GetDirIconIndex();
213 m_nOpenIconFolder = SYS_IMAGE_LIST().GetDirOpenIconIndex();
215 EnableSaveRestore(L"Reposbrowser");
217 DWORD xPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RepobrowserDivider"), 0);
218 if (xPos == 0)
220 RECT rc;
221 GetDlgItem(IDC_REPOTREE)->GetClientRect(&rc);
222 xPos = rc.right - rc.left;
224 bDragMode = true;
225 HandleDividerMove(CPoint(xPos + 20, 10), false);
227 CString sWindowTitle;
228 GetWindowText(sWindowTitle);
229 CAppUtils::SetWindowTitle(m_hWnd, g_Git.m_CurrentDir, sWindowTitle);
231 Refresh();
233 m_RepoList.SetFocus();
235 return FALSE;
238 void CRepositoryBrowser::OnOK()
240 SaveDividerPosition();
241 CResizableStandAloneDialog::OnOK();
244 void CRepositoryBrowser::OnCancel()
246 SaveDividerPosition();
247 CResizableStandAloneDialog::OnCancel();
250 void CRepositoryBrowser::OnNMDblclk_RepoList(NMHDR *pNMHDR, LRESULT *pResult)
252 UNREFERENCED_PARAMETER(pNMHDR);
253 *pResult = 0;
255 LPNMITEMACTIVATE pNmItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
256 if (pNmItemActivate->iItem < 0)
257 return;
259 CShadowFilesTree * pItem = (CShadowFilesTree *)m_RepoList.GetItemData(pNmItemActivate->iItem);
260 if (pItem == NULL || !pItem->m_bFolder)
261 return;
263 FillListCtrlForShadowTree(pItem);
264 m_RepoTree.SelectItem(pItem->m_hTree);
267 void CRepositoryBrowser::Refresh()
269 m_RepoTree.DeleteAllItems();
270 m_RepoList.DeleteAllItems();
271 m_TreeRoot.m_ShadowTree.clear();
272 m_TreeRoot.m_sName = "";
273 m_TreeRoot.m_bFolder = true;
275 TVINSERTSTRUCT tvinsert = {0};
276 tvinsert.hParent = TVI_ROOT;
277 tvinsert.hInsertAfter = TVI_ROOT;
278 tvinsert.itemex.mask = TVIF_DI_SETITEM | TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
279 tvinsert.itemex.pszText = L"/";
280 tvinsert.itemex.lParam = (LPARAM)&m_TreeRoot;
281 tvinsert.itemex.iImage = m_nIconFolder;
282 tvinsert.itemex.iSelectedImage = m_nOpenIconFolder;
283 m_TreeRoot.m_hTree= m_RepoTree.InsertItem(&tvinsert);
285 ReadTree(&m_TreeRoot);
286 m_RepoTree.Expand(m_TreeRoot.m_hTree, TVE_EXPAND);
287 FillListCtrlForShadowTree(&m_TreeRoot);
288 m_RepoTree.SelectItem(m_TreeRoot.m_hTree);
291 int CRepositoryBrowser::ReadTreeRecursive(git_repository &repo, git_tree * tree, CShadowFilesTree * treeroot)
293 size_t count = git_tree_entrycount(tree);
295 for (int i = 0; i < count; i++)
297 const git_tree_entry *entry = git_tree_entry_byindex(tree, i);
298 if (entry == NULL)
299 continue;
300 int mode = git_tree_entry_attributes(entry);
302 CString base = CUnicodeUtils::GetUnicode(git_tree_entry_name(entry), CP_UTF8);
304 git_object *object = NULL;
305 git_tree_entry_2object(&object, &repo, entry);
306 if (object == NULL)
307 continue;
309 CShadowFilesTree * pNextTree = &treeroot->m_ShadowTree[base];
310 pNextTree->m_sName = base;
311 pNextTree->m_pParent = treeroot;
313 if (mode & S_IFDIR)
315 pNextTree->m_bFolder = true;
317 TVINSERTSTRUCT tvinsert = {0};
318 tvinsert.hParent = treeroot->m_hTree;
319 tvinsert.hInsertAfter = TVI_SORT;
320 tvinsert.itemex.mask = TVIF_DI_SETITEM | TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_STATE;
321 tvinsert.itemex.pszText = base.GetBuffer(base.GetLength());
322 tvinsert.itemex.lParam = (LPARAM)pNextTree;
323 tvinsert.itemex.iImage = m_nIconFolder;
324 tvinsert.itemex.iSelectedImage = m_nOpenIconFolder;
325 pNextTree->m_hTree = m_RepoTree.InsertItem(&tvinsert);
326 base.ReleaseBuffer();
328 ReadTreeRecursive(repo, (git_tree*)object, pNextTree);
330 else
332 const git_oid * oid = git_object_id(object);
334 git_blob * blob;
335 git_blob_lookup(&blob, &repo, oid);
336 if (blob == NULL)
337 continue;
339 pNextTree->m_iSize = git_blob_rawsize(blob);
340 git_blob_free(blob);
343 git_object_free(object);
346 return 0;
349 int CRepositoryBrowser::ReadTree(CShadowFilesTree * treeroot)
351 CStringA gitdir = CUnicodeUtils::GetMulti(g_Git.m_CurrentDir, CP_UTF8);
352 git_repository *repository = NULL;
353 git_commit *commit = NULL;
354 git_tree * tree = NULL;
355 int ret = 0;
358 ret = git_repository_open(&repository, gitdir.GetBuffer());
359 if(ret)
360 break;
362 CGitHash hash = g_Git.GetHash(m_sRevision);
363 ret = git_commit_lookup(&commit, repository, (git_oid *) hash.m_hash);
364 if(ret)
365 break;
367 ret = git_commit_tree(&tree, commit);
368 if(ret)
369 break;
371 ret = ReadTreeRecursive(*repository, tree, treeroot);
372 if(ret)
373 break;
375 this->GetDlgItem(IDC_BUTTON_REVISION)->SetWindowText(m_sRevision);
376 } while(0);
378 if (tree)
379 git_tree_free(tree);
381 if (commit)
382 git_commit_free(commit);
384 if (repository)
385 git_repository_free(repository);
387 return ret;
390 void CRepositoryBrowser::OnTvnSelchangedRepoTree(NMHDR *pNMHDR, LRESULT *pResult)
392 LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
393 *pResult = 0;
395 FillListCtrlForTreeNode(pNMTreeView->itemNew.hItem);
398 void CRepositoryBrowser::FillListCtrlForTreeNode(HTREEITEM treeNode)
400 m_RepoList.DeleteAllItems();
402 CShadowFilesTree* pTree = (CShadowFilesTree*)(m_RepoTree.GetItemData(treeNode));
403 if (pTree == NULL)
405 ASSERT(FALSE);
406 return;
408 FillListCtrlForShadowTree(pTree);
411 void CRepositoryBrowser::FillListCtrlForShadowTree(CShadowFilesTree* pTree)
413 for (TShadowFilesTreeMap::iterator itShadowTree = pTree->m_ShadowTree.begin(); itShadowTree != pTree->m_ShadowTree.end(); ++itShadowTree)
415 int icon = m_nIconFolder;
416 if (!(*itShadowTree).second.m_bFolder)
417 icon = SYS_IMAGE_LIST().GetFileIconIndex((*itShadowTree).second.m_sName);
419 int indexItem = m_RepoList.InsertItem(m_RepoList.GetItemCount(), (*itShadowTree).second.m_sName, icon);
421 m_RepoList.SetItemData(indexItem, (DWORD_PTR)&(*itShadowTree).second);
422 if (!(*itShadowTree).second.m_bFolder)
424 CString temp;
426 temp = CPathUtils::GetFileExtFromPath((*itShadowTree).second.m_sName);
427 m_RepoList.SetItemText(indexItem, eCol_Extension, temp);
429 StrFormatByteSize((*itShadowTree).second.m_iSize, temp.GetBuffer(20), 20);
430 temp.ReleaseBuffer();
431 m_RepoList.SetItemText(indexItem, eCol_FileSize, temp);
435 CRepoListCompareFunc compareFunc(&m_RepoList, m_currSortCol, m_currSortDesc);
436 m_RepoList.SortItemsEx(&CRepoListCompareFunc::StaticCompare, (DWORD_PTR)&compareFunc);
438 SetSortArrowA(&m_RepoList, m_currSortCol, !m_currSortDesc);
441 void CRepositoryBrowser::OnContextMenu(CWnd* pWndFrom, CPoint point)
443 if (pWndFrom == &m_RepoList)
444 OnContextMenu_RepoList(point);
447 void CRepositoryBrowser::OnContextMenu_RepoList(CPoint point)
449 TShadowFilesTreeList selectedLeafs;
450 selectedLeafs.reserve(m_RepoList.GetSelectedCount());
451 POSITION pos = m_RepoList.GetFirstSelectedItemPosition();
452 while (pos)
454 selectedLeafs.push_back((CShadowFilesTree *)m_RepoList.GetItemData(m_RepoList.GetNextSelectedItem(pos)));
457 CIconMenu popupMenu;
458 popupMenu.CreatePopupMenu();
460 bool bAddSeparator = false;
462 if (selectedLeafs.size() == 1)
464 CString temp;
465 temp.LoadString(IDS_MENULOG);
466 popupMenu.AppendMenuIcon(eCmd_ViewLog, temp, IDI_LOG);
467 bAddSeparator = true;
470 eCmd cmd = (eCmd)popupMenu.TrackPopupMenuEx(TPM_LEFTALIGN|TPM_RETURNCMD, point.x, point.y, this, 0);
471 switch(cmd)
473 case eCmd_ViewLog:
475 CString sCmd;
476 sCmd.Format(_T("/command:log /path:\"%s%s\""), g_Git.m_CurrentDir, selectedLeafs.at(0)->GetFullName());
477 CAppUtils::RunTortoiseProc(sCmd);
479 break;
483 BOOL CRepositoryBrowser::PreTranslateMessage(MSG* pMsg)
485 if (pMsg->message == WM_KEYDOWN)
487 switch (pMsg->wParam)
489 case VK_F5:
491 Refresh();
493 break;
497 return CResizableStandAloneDialog::PreTranslateMessage(pMsg);
500 void CRepositoryBrowser::OnLvnColumnclickRepoList(NMHDR *pNMHDR, LRESULT *pResult)
502 LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
503 if (pResult)
504 *pResult = 0;
506 if (m_currSortCol == pNMLV->iSubItem)
507 m_currSortDesc = !m_currSortDesc;
508 else
510 m_currSortCol = pNMLV->iSubItem;
511 m_currSortDesc = false;
514 CRepoListCompareFunc compareFunc(&m_RepoList, m_currSortCol, m_currSortDesc);
515 m_RepoList.SortItemsEx(&CRepoListCompareFunc::StaticCompare, (DWORD_PTR)&compareFunc);
517 SetSortArrowA(&m_RepoList, m_currSortCol, !m_currSortDesc);
520 void CRepositoryBrowser::OnBnClickedButtonRevision()
522 // use the git log to allow selection of a version
523 CLogDlg dlg;
524 // tell the dialog to use mode for selecting revisions
525 dlg.SetSelect(true);
526 // only one revision must be selected however
527 dlg.SingleSelection(true);
528 if (dlg.DoModal() == IDOK)
530 // get selected hash if any
531 m_sRevision = dlg.GetSelectedHash();
532 Refresh();
536 void CRepositoryBrowser::SaveDividerPosition()
538 RECT rc;
539 GetDlgItem(IDC_REPOTREE)->GetClientRect(&rc);
540 CRegDWORD xPos = CRegDWORD(_T("Software\\TortoiseGit\\TortoiseProc\\ResizableState\\RepobrowserDivider"));
541 xPos = rc.right - rc.left;
544 void CRepositoryBrowser::HandleDividerMove(CPoint point, bool bDraw)
546 RECT rect, tree, list, treelist, treelistclient;
548 // create an union of the tree and list control rectangle
549 GetDlgItem(IDC_REPOLIST)->GetWindowRect(&list);
550 GetDlgItem(IDC_REPOTREE)->GetWindowRect(&tree);
551 UnionRect(&treelist, &tree, &list);
552 treelistclient = treelist;
553 ScreenToClient(&treelistclient);
555 ClientToScreen(&point);
556 GetClientRect(&rect);
557 ClientToScreen(&rect);
559 CPoint point2 = point;
560 if (point2.x < treelist.left + REPOBROWSER_CTRL_MIN_WIDTH)
561 point2.x = treelist.left + REPOBROWSER_CTRL_MIN_WIDTH;
562 if (point2.x > treelist.right - REPOBROWSER_CTRL_MIN_WIDTH)
563 point2.x = treelist.right - REPOBROWSER_CTRL_MIN_WIDTH;
565 point.x -= rect.left;
566 point.y -= treelist.top;
568 OffsetRect(&treelist, -treelist.left, -treelist.top);
570 if (point.x < treelist.left+REPOBROWSER_CTRL_MIN_WIDTH)
571 point.x = treelist.left+REPOBROWSER_CTRL_MIN_WIDTH;
572 if (point.x > treelist.right-REPOBROWSER_CTRL_MIN_WIDTH)
573 point.x = treelist.right-REPOBROWSER_CTRL_MIN_WIDTH;
575 if (bDraw)
577 CDC * pDC = GetDC();
578 DrawXorBar(pDC, oldx + 2, treelistclient.top, 4, treelistclient.bottom - treelistclient.top - 2);
579 ReleaseDC(pDC);
582 oldx = point.x;
583 oldy = point.y;
585 //position the child controls
586 GetDlgItem(IDC_REPOTREE)->GetWindowRect(&treelist);
587 treelist.right = point2.x - 2;
588 ScreenToClient(&treelist);
589 RemoveAnchor(IDC_REPOTREE);
590 GetDlgItem(IDC_REPOTREE)->MoveWindow(&treelist);
591 GetDlgItem(IDC_REPOLIST)->GetWindowRect(&treelist);
592 treelist.left = point2.x + 2;
593 ScreenToClient(&treelist);
594 RemoveAnchor(IDC_REPOLIST);
595 GetDlgItem(IDC_REPOLIST)->MoveWindow(&treelist);
597 AddAnchor(IDC_REPOTREE, TOP_LEFT, BOTTOM_LEFT);
598 AddAnchor(IDC_REPOLIST, TOP_LEFT, BOTTOM_RIGHT);
601 void CRepositoryBrowser::OnMouseMove(UINT nFlags, CPoint point)
603 if (bDragMode == FALSE)
604 return;
606 RECT rect, tree, list, treelist, treelistclient;
607 // create an union of the tree and list control rectangle
608 GetDlgItem(IDC_REPOLIST)->GetWindowRect(&list);
609 GetDlgItem(IDC_REPOTREE)->GetWindowRect(&tree);
610 UnionRect(&treelist, &tree, &list);
611 treelistclient = treelist;
612 ScreenToClient(&treelistclient);
614 //convert the mouse coordinates relative to the top-left of
615 //the window
616 ClientToScreen(&point);
617 GetClientRect(&rect);
618 ClientToScreen(&rect);
619 point.x -= rect.left;
620 point.y -= treelist.top;
622 //same for the window coordinates - make them relative to 0,0
623 OffsetRect(&treelist, -treelist.left, -treelist.top);
625 if (point.x < treelist.left + REPOBROWSER_CTRL_MIN_WIDTH)
626 point.x = treelist.left + REPOBROWSER_CTRL_MIN_WIDTH;
627 if (point.x > treelist.right - REPOBROWSER_CTRL_MIN_WIDTH)
628 point.x = treelist.right - REPOBROWSER_CTRL_MIN_WIDTH;
630 if ((nFlags & MK_LBUTTON) && (point.x != oldx))
632 CDC * pDC = GetDC();
634 if (pDC)
636 DrawXorBar(pDC, oldx + 2, treelistclient.top, 4, treelistclient.bottom - treelistclient.top - 2);
637 DrawXorBar(pDC, point.x + 2, treelistclient.top, 4, treelistclient.bottom - treelistclient.top - 2);
639 ReleaseDC(pDC);
642 oldx = point.x;
643 oldy = point.y;
646 CStandAloneDialogTmpl<CResizableDialog>::OnMouseMove(nFlags, point);
649 void CRepositoryBrowser::OnLButtonDown(UINT nFlags, CPoint point)
651 RECT rect, tree, list, treelist, treelistclient;
653 // create an union of the tree and list control rectangle
654 GetDlgItem(IDC_REPOLIST)->GetWindowRect(&list);
655 GetDlgItem(IDC_REPOTREE)->GetWindowRect(&tree);
656 UnionRect(&treelist, &tree, &list);
657 treelistclient = treelist;
658 ScreenToClient(&treelistclient);
660 //convert the mouse coordinates relative to the top-left of
661 //the window
662 ClientToScreen(&point);
663 GetClientRect(&rect);
664 ClientToScreen(&rect);
665 point.x -= rect.left;
666 point.y -= treelist.top;
668 //same for the window coordinates - make them relative to 0,0
669 OffsetRect(&treelist, -treelist.left, -treelist.top);
671 if (point.x < treelist.left + REPOBROWSER_CTRL_MIN_WIDTH)
672 return CStandAloneDialogTmpl < CResizableDialog>::OnLButtonDown(nFlags, point);
673 if (point.x > treelist.right - 3)
674 return CStandAloneDialogTmpl < CResizableDialog>::OnLButtonDown(nFlags, point);
675 if (point.x > treelist.right - REPOBROWSER_CTRL_MIN_WIDTH)
676 point.x = treelist.right - REPOBROWSER_CTRL_MIN_WIDTH;
678 if ((point.y < treelist.top + 3) || (point.y > treelist.bottom - 3))
679 return CStandAloneDialogTmpl<CResizableDialog>::OnLButtonDown(nFlags, point);
681 bDragMode = true;
683 SetCapture();
685 CDC * pDC = GetDC();
686 DrawXorBar(pDC, point.x + 2, treelistclient.top, 4, treelistclient.bottom - treelistclient.top - 2);
687 ReleaseDC(pDC);
689 oldx = point.x;
690 oldy = point.y;
692 CStandAloneDialogTmpl<CResizableDialog>::OnLButtonDown(nFlags, point);
695 void CRepositoryBrowser::OnLButtonUp(UINT nFlags, CPoint point)
697 if (bDragMode == FALSE)
698 return;
700 HandleDividerMove(point, true);
702 bDragMode = false;
703 ReleaseCapture();
705 CStandAloneDialogTmpl<CResizableDialog>::OnLButtonUp(nFlags, point);
708 void CRepositoryBrowser::OnCaptureChanged(CWnd *pWnd)
710 bDragMode = false;
712 __super::OnCaptureChanged(pWnd);
715 void CRepositoryBrowser::DrawXorBar(CDC * pDC, int x1, int y1, int width, int height)
717 static WORD _dotPatternBmp[8] =
719 0x0055, 0x00aa, 0x0055, 0x00aa,
720 0x0055, 0x00aa, 0x0055, 0x00aa
723 HBITMAP hbm;
724 HBRUSH hbr, hbrushOld;
726 hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
727 hbr = CreatePatternBrush(hbm);
729 pDC->SetBrushOrg(x1, y1);
730 hbrushOld = (HBRUSH)pDC->SelectObject(hbr);
732 PatBlt(pDC->GetSafeHdc(), x1, y1, width, height, PATINVERT);
734 pDC->SelectObject(hbrushOld);
736 DeleteObject(hbr);
737 DeleteObject(hbm);
740 BOOL CRepositoryBrowser::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
742 if (pWnd == this)
744 RECT rect;
745 POINT pt;
746 GetClientRect(&rect);
747 GetCursorPos(&pt);
748 ScreenToClient(&pt);
749 if (PtInRect(&rect, pt))
751 ClientToScreen(&pt);
752 // are we right of the tree control?
753 GetDlgItem(IDC_REPOTREE)->GetWindowRect(&rect);
754 if ((pt.x > rect.right) && (pt.y >= rect.top + 3) && (pt.y <= rect.bottom - 3))
756 // but left of the list control?
757 GetDlgItem(IDC_REPOLIST)->GetWindowRect(&rect);
758 if (pt.x < rect.left)
760 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE));
761 SetCursor(hCur);
762 return TRUE;
767 return CStandAloneDialogTmpl<CResizableDialog>::OnSetCursor(pWnd, nHitTest, message);