Fixed issue #3107: Clean: Allow to remove orphaned submodules (i.e., clean -f -f)
[TortoiseGit.git] / src / TortoiseIDiff / MainWindow.cpp
blobdf87d4ba57f7a0b721f3225a2b92756ea97414b3
1 // TortoiseIDiff - an image diff viewer in TortoiseSVN
3 // Copyright (C) 2015-2017 - TortoiseGit
4 // Copyright (C) 2006-2013, 2015 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include <CommCtrl.h>
22 #include <Commdlg.h>
23 #include "TortoiseIDiff.h"
24 #include "MainWindow.h"
25 #include "AboutDlg.h"
26 #include "TaskbarUUID.h"
27 #include "PathUtils.h"
29 #pragma comment(lib, "comctl32.lib")
31 tstring CMainWindow::leftpicpath;
32 tstring CMainWindow::leftpictitle;
34 tstring CMainWindow::rightpicpath;
35 tstring CMainWindow::rightpictitle;
37 const UINT TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
39 bool CMainWindow::RegisterAndCreateWindow()
41 WNDCLASSEX wcx;
43 // Fill in the window class structure with default parameters
44 wcx.cbSize = sizeof(WNDCLASSEX);
45 wcx.style = CS_HREDRAW | CS_VREDRAW;
46 wcx.lpfnWndProc = CWindow::stWinMsgHandler;
47 wcx.cbClsExtra = 0;
48 wcx.cbWndExtra = 0;
49 wcx.hInstance = hResource;
50 wcx.hCursor = LoadCursor(nullptr, IDC_SIZEWE);
51 ResString clsname(hResource, IDS_APP_TITLE);
52 wcx.lpszClassName = clsname;
53 wcx.hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_TORTOISEIDIFF));
54 wcx.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
55 if (selectionPaths.empty())
56 wcx.lpszMenuName = MAKEINTRESOURCE(IDC_TORTOISEIDIFF);
57 else
58 wcx.lpszMenuName = MAKEINTRESOURCE(IDC_TORTOISEIDIFF2);
59 wcx.hIconSm = LoadIcon(wcx.hInstance, MAKEINTRESOURCE(IDI_TORTOISEIDIFF));
60 if (RegisterWindow(&wcx))
62 if (Create(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE, nullptr))
64 UpdateWindow(m_hwnd);
65 return true;
68 return false;
71 void CMainWindow::PositionChildren(RECT * clientrect /* = nullptr */)
73 RECT tbRect;
74 if (!clientrect)
75 return;
76 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
77 GetWindowRect(hwndTB, &tbRect);
78 LONG tbHeight = tbRect.bottom-tbRect.top-1;
79 HDWP hdwp = BeginDeferWindowPos(3);
80 if (bOverlap && selectionPaths.empty())
82 SetWindowPos(picWindow1, nullptr, clientrect->left, clientrect->top + tbHeight, clientrect->right - clientrect->left, clientrect->bottom - clientrect->top - tbHeight, SWP_SHOWWINDOW);
84 else
86 if (bVertical)
88 if (selectionPaths.size() != 3)
90 // two image windows
91 RECT child;
92 child.left = clientrect->left;
93 child.top = clientrect->top+tbHeight;
94 child.right = clientrect->right;
95 child.bottom = nSplitterPos-(SPLITTER_BORDER/2);
96 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
97 child.top = nSplitterPos+(SPLITTER_BORDER/2);
98 child.bottom = clientrect->bottom;
99 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
101 else
103 // three image windows
104 RECT child;
105 child.left = clientrect->left;
106 child.top = clientrect->top+tbHeight;
107 child.right = clientrect->right;
108 child.bottom = nSplitterPos-(SPLITTER_BORDER/2);
109 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
110 child.top = nSplitterPos+(SPLITTER_BORDER/2);
111 child.bottom = nSplitterPos2-(SPLITTER_BORDER/2);
112 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
113 child.top = nSplitterPos2+(SPLITTER_BORDER/2);
114 child.bottom = clientrect->bottom;
115 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow3, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
118 else
120 if (selectionPaths.size() != 3)
122 // two image windows
123 RECT child;
124 child.left = clientrect->left;
125 child.top = clientrect->top+tbHeight;
126 child.right = nSplitterPos-(SPLITTER_BORDER/2);
127 child.bottom = clientrect->bottom;
128 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
129 child.left = nSplitterPos+(SPLITTER_BORDER/2);
130 child.right = clientrect->right;
131 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
133 else
135 // three image windows
136 RECT child;
137 child.left = clientrect->left;
138 child.top = clientrect->top+tbHeight;
139 child.right = nSplitterPos-(SPLITTER_BORDER/2);
140 child.bottom = clientrect->bottom;
141 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
142 child.left = nSplitterPos+(SPLITTER_BORDER/2);
143 child.right = nSplitterPos2-(SPLITTER_BORDER/2);
144 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
145 child.left = nSplitterPos2+(SPLITTER_BORDER/2);
146 child.right = clientrect->right;
147 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow3, nullptr, child.left, child.top, child.right - child.left, child.bottom - child.top, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
151 if (hdwp) EndDeferWindowPos(hdwp);
152 picWindow1.SetTransparentColor(transparentColor);
153 picWindow2.SetTransparentColor(transparentColor);
154 picWindow3.SetTransparentColor(transparentColor);
155 InvalidateRect(*this, nullptr, FALSE);
158 LRESULT CALLBACK CMainWindow::WinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
160 if (uMsg == TaskBarButtonCreated)
162 SetUUIDOverlayIcon(hwnd);
164 switch (uMsg)
166 case WM_CREATE:
168 m_hwnd = hwnd;
169 picWindow1.RegisterAndCreateWindow(hwnd);
170 picWindow2.RegisterAndCreateWindow(hwnd);
171 if (selectionPaths.empty())
173 picWindow1.SetPic(leftpicpath, leftpictitle, true);
174 picWindow2.SetPic(rightpicpath, rightpictitle, false);
176 picWindow1.SetOtherPicWindow(&picWindow2);
177 picWindow2.SetOtherPicWindow(&picWindow1);
179 else
181 picWindow3.RegisterAndCreateWindow(hwnd);
183 picWindow1.SetPic(selectionPaths[FileTypeMine], selectionTitles[FileTypeMine], false);
184 picWindow2.SetPic(selectionPaths[FileTypeBase], selectionTitles[FileTypeBase], false);
185 picWindow3.SetPic(selectionPaths[FileTypeTheirs], selectionTitles[FileTypeTheirs], false);
188 picWindow1.SetSelectionMode(!selectionPaths.empty());
189 picWindow2.SetSelectionMode(!selectionPaths.empty());
190 picWindow3.SetSelectionMode(!selectionPaths.empty());
192 CreateToolbar();
193 // center the splitter
194 RECT rect;
195 GetClientRect(hwnd, &rect);
196 if (selectionPaths.size() != 3)
198 nSplitterPos = (rect.right-rect.left)/2;
199 nSplitterPos2 = 0;
201 else
203 nSplitterPos = (rect.right-rect.left)/3;
204 nSplitterPos2 = (rect.right-rect.left)*2/3;
207 PositionChildren(&rect);
208 picWindow1.FitImageInWindow();
209 picWindow2.FitImageInWindow();
210 picWindow3.FitImageInWindow();
212 break;
213 case WM_COMMAND:
215 return DoCommand(LOWORD(wParam), lParam);
217 break;
218 case WM_PAINT:
220 PAINTSTRUCT ps;
221 HDC hdc;
222 RECT rect;
224 ::GetClientRect(*this, &rect);
225 hdc = BeginPaint(hwnd, &ps);
226 SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
227 ::ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, nullptr, 0, nullptr);
228 EndPaint(hwnd, &ps);
230 break;
231 case WM_GETMINMAXINFO:
233 MINMAXINFO * mmi = (MINMAXINFO*)lParam;
234 mmi->ptMinTrackSize.x = WINDOW_MINWIDTH;
235 mmi->ptMinTrackSize.y = WINDOW_MINHEIGHT;
236 return 0;
238 break;
239 case WM_SIZE:
241 RECT rect;
242 GetClientRect(hwnd, &rect);
243 if (bVertical)
245 RECT tbRect;
246 GetWindowRect(hwndTB, &tbRect);
247 LONG tbHeight = tbRect.bottom-tbRect.top-1;
248 if (selectionPaths.size() != 3)
250 nSplitterPos = (rect.bottom-rect.top)/2+tbHeight;
251 nSplitterPos2 = 0;
253 else
255 nSplitterPos = (rect.bottom-rect.top)/3+tbHeight;
256 nSplitterPos2 = (rect.bottom-rect.top)*2/3+tbHeight;
259 else
261 if (selectionPaths.size() != 3)
263 nSplitterPos = (rect.right-rect.left)/2;
264 nSplitterPos2 = 0;
266 else
268 nSplitterPos = (rect.right-rect.left)/3;
269 nSplitterPos2 = (rect.right-rect.left)*2/3;
272 PositionChildren(&rect);
274 break;
275 case WM_SETCURSOR:
277 if ((HWND)wParam == *this)
279 RECT rect;
280 POINT pt;
281 GetClientRect(*this, &rect);
282 GetCursorPos(&pt);
283 ScreenToClient(*this, &pt);
284 if (PtInRect(&rect, pt))
286 if (bVertical)
288 HCURSOR hCur = LoadCursor(nullptr, IDC_SIZENS);
289 SetCursor(hCur);
291 else
293 HCURSOR hCur = LoadCursor(nullptr, IDC_SIZEWE);
294 SetCursor(hCur);
296 return TRUE;
299 return DefWindowProc(hwnd, uMsg, wParam, lParam);
301 break;
302 case WM_LBUTTONDOWN:
303 Splitter_OnLButtonDown(hwnd, uMsg, wParam, lParam);
304 break;
305 case WM_LBUTTONUP:
306 Splitter_OnLButtonUp(hwnd, uMsg, wParam, lParam);
307 break;
308 case WM_CAPTURECHANGED:
309 Splitter_CaptureChanged();
310 break;
311 case WM_MOUSEMOVE:
312 Splitter_OnMouseMove(hwnd, uMsg, wParam, lParam);
313 break;
314 case WM_MOUSEWHEEL:
316 // find out if the mouse cursor is over one of the views, and if
317 // it is, pass the mouse wheel message to that view
318 POINT pt;
319 DWORD ptW = GetMessagePos();
320 pt.x = GET_X_LPARAM(ptW);
321 pt.y = GET_Y_LPARAM(ptW);
322 RECT rect;
323 GetWindowRect(picWindow1, &rect);
324 if (PtInRect(&rect, pt))
326 picWindow1.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
328 else
330 GetWindowRect(picWindow2, &rect);
331 if (PtInRect(&rect, pt))
333 picWindow2.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
335 else
337 GetWindowRect(picWindow3, &rect);
338 if (PtInRect(&rect, pt))
340 picWindow3.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
345 break;
346 case WM_MOUSEHWHEEL:
348 // find out if the mouse cursor is over one of the views, and if
349 // it is, pass the mouse wheel message to that view
350 POINT pt;
351 DWORD ptW = GetMessagePos();
352 pt.x = GET_X_LPARAM(ptW);
353 pt.y = GET_Y_LPARAM(ptW);
354 RECT rect;
355 GetWindowRect(picWindow1, &rect);
356 if (PtInRect(&rect, pt))
358 picWindow1.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
360 else
362 GetWindowRect(picWindow2, &rect);
363 if (PtInRect(&rect, pt))
365 picWindow2.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
367 else
369 GetWindowRect(picWindow3, &rect);
370 if (PtInRect(&rect, pt))
372 picWindow3.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
377 break;
378 case WM_NOTIFY:
380 LPNMHDR pNMHDR = (LPNMHDR)lParam;
381 if (pNMHDR->code == TTN_GETDISPINFO)
383 LPTOOLTIPTEXT lpttt;
385 lpttt = (LPTOOLTIPTEXT) lParam;
386 lpttt->hinst = hResource;
388 // Specify the resource identifier of the descriptive
389 // text for the given button.
390 TCHAR stringbuf[MAX_PATH] = {0};
391 MENUITEMINFO mii;
392 mii.cbSize = sizeof(MENUITEMINFO);
393 mii.fMask = MIIM_TYPE;
394 mii.dwTypeData = stringbuf;
395 mii.cch = _countof(stringbuf);
396 GetMenuItemInfo(GetMenu(*this), (UINT)lpttt->hdr.idFrom, FALSE, &mii);
397 wcscpy_s(lpttt->lpszText, 80, stringbuf);
400 break;
401 case WM_DESTROY:
402 bWindowClosed = TRUE;
403 PostQuitMessage(0);
404 break;
405 case WM_CLOSE:
406 ImageList_Destroy(hToolbarImgList);
407 ::DestroyWindow(m_hwnd);
408 break;
409 default:
410 return DefWindowProc(hwnd, uMsg, wParam, lParam);
413 return 0;
416 LRESULT CMainWindow::DoCommand(int id, LPARAM lParam)
418 switch (id)
420 case ID_FILE_OPEN:
422 if (OpenDialog())
424 picWindow1.SetPic(leftpicpath, L"", true);
425 picWindow2.SetPic(rightpicpath, L"", false);
426 if (bOverlap)
428 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath);
430 else
432 picWindow1.SetSecondPic();
434 RECT rect;
435 GetClientRect(*this, &rect);
436 PositionChildren(&rect);
437 picWindow1.FitImageInWindow();
438 picWindow2.FitImageInWindow();
441 break;
442 case ID_VIEW_IMAGEINFO:
444 bShowInfo = !bShowInfo;
445 HMENU hMenu = GetMenu(*this);
446 UINT uCheck = MF_BYCOMMAND;
447 uCheck |= bShowInfo ? MF_CHECKED : MF_UNCHECKED;
448 CheckMenuItem(hMenu, ID_VIEW_IMAGEINFO, uCheck);
450 picWindow1.ShowInfo(bShowInfo);
451 picWindow2.ShowInfo(bShowInfo);
452 picWindow3.ShowInfo(bShowInfo);
454 // change the state of the toolbar button
455 TBBUTTONINFO tbi;
456 tbi.cbSize = sizeof(TBBUTTONINFO);
457 tbi.dwMask = TBIF_STATE;
458 tbi.fsState = bShowInfo ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
459 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_IMAGEINFO, (LPARAM)&tbi);
461 break;
462 case ID_VIEW_OVERLAPIMAGES:
464 bOverlap = !bOverlap;
465 HMENU hMenu = GetMenu(*this);
466 UINT uCheck = MF_BYCOMMAND;
467 uCheck |= bOverlap ? MF_CHECKED : MF_UNCHECKED;
468 CheckMenuItem(hMenu, ID_VIEW_OVERLAPIMAGES, uCheck);
469 uCheck |= ((m_BlendType == CPicWindow::BLEND_ALPHA) && bOverlap) ? MF_CHECKED : MF_UNCHECKED;
470 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
471 UINT uEnabled = MF_BYCOMMAND;
472 uEnabled |= bOverlap ? MF_ENABLED : MF_DISABLED | MF_GRAYED;
473 EnableMenuItem(hMenu, ID_VIEW_BLENDALPHA, uEnabled);
475 // change the state of the toolbar button
476 TBBUTTONINFO tbi;
477 tbi.cbSize = sizeof(TBBUTTONINFO);
478 tbi.dwMask = TBIF_STATE;
479 tbi.fsState = bOverlap ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
480 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_OVERLAPIMAGES, (LPARAM)&tbi);
482 tbi.fsState = ((m_BlendType == CPicWindow::BLEND_ALPHA) && bOverlap) ? TBSTATE_CHECKED : 0;
483 if (bOverlap)
484 tbi.fsState |= TBSTATE_ENABLED;
485 else
486 tbi.fsState = 0;
487 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
489 if (bOverlap)
490 tbi.fsState = 0;
491 else
492 tbi.fsState = bVertical ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
493 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
495 if (bOverlap)
497 bLinkedPositions = true;
498 picWindow1.LinkPositions(bLinkedPositions);
499 picWindow2.LinkPositions(bLinkedPositions);
500 tbi.fsState = TBSTATE_CHECKED;
502 else
503 tbi.fsState = bLinkedPositions ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
504 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
506 ShowWindow(picWindow2, bOverlap ? SW_HIDE : SW_SHOW);
508 if (bOverlap)
510 picWindow1.StopTimer();
511 picWindow2.StopTimer();
512 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath,
513 picWindow2.GetHPos(), picWindow2.GetVPos());
514 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
516 else
518 picWindow1.SetSecondPic();
520 picWindow1.SetOverlapMode(bOverlap);
521 picWindow2.SetOverlapMode(bOverlap);
524 RECT rect;
525 GetClientRect(*this, &rect);
526 PositionChildren(&rect);
528 return 0;
530 break;
531 case ID_VIEW_BLENDALPHA:
533 if (m_BlendType == CPicWindow::BLEND_ALPHA)
534 m_BlendType = CPicWindow::BLEND_XOR;
535 else
536 m_BlendType = CPicWindow::BLEND_ALPHA;
538 HMENU hMenu = GetMenu(*this);
539 UINT uCheck = MF_BYCOMMAND;
540 uCheck |= ((m_BlendType == CPicWindow::BLEND_ALPHA) && bOverlap) ? MF_CHECKED : MF_UNCHECKED;
541 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
542 UINT uEnabled = MF_BYCOMMAND;
543 uEnabled |= bOverlap ? MF_ENABLED : MF_DISABLED | MF_GRAYED;
544 EnableMenuItem(hMenu, ID_VIEW_BLENDALPHA, uEnabled);
546 // change the state of the toolbar button
547 TBBUTTONINFO tbi;
548 tbi.cbSize = sizeof(TBBUTTONINFO);
549 tbi.dwMask = TBIF_STATE;
550 tbi.fsState = ((m_BlendType == CPicWindow::BLEND_ALPHA) && bOverlap) ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
551 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
552 picWindow1.SetBlendAlpha(m_BlendType, picWindow1.GetBlendAlpha());
553 PositionChildren();
555 break;
556 case ID_VIEW_TRANSPARENTCOLOR:
558 static COLORREF customColors[16] = {0};
559 CHOOSECOLOR ccDlg = { 0 };
560 ccDlg.lStructSize = sizeof(ccDlg);
561 ccDlg.hwndOwner = m_hwnd;
562 ccDlg.rgbResult = transparentColor;
563 ccDlg.lpCustColors = customColors;
564 ccDlg.Flags = CC_RGBINIT | CC_FULLOPEN;
565 if(ChooseColor(&ccDlg))
567 transparentColor = ccDlg.rgbResult;
568 picWindow1.SetTransparentColor(transparentColor);
569 picWindow2.SetTransparentColor(transparentColor);
570 picWindow3.SetTransparentColor(transparentColor);
571 // The color picker takes the focus and we don't get it back.
572 ::SetFocus(picWindow1);
575 break;
576 case ID_VIEW_FITIMAGEWIDTHS:
578 bFitWidths = !bFitWidths;
579 picWindow1.FitWidths(bFitWidths);
580 picWindow2.FitWidths(bFitWidths);
581 picWindow3.FitWidths(bFitWidths);
583 HMENU hMenu = GetMenu(*this);
584 UINT uCheck = MF_BYCOMMAND;
585 uCheck |= bFitWidths ? MF_CHECKED : MF_UNCHECKED;
586 CheckMenuItem(hMenu, ID_VIEW_FITIMAGEWIDTHS, uCheck);
588 // change the state of the toolbar button
589 TBBUTTONINFO tbi;
590 tbi.cbSize = sizeof(TBBUTTONINFO);
591 tbi.dwMask = TBIF_STATE;
592 tbi.fsState = bFitWidths ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
593 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_FITIMAGEWIDTHS, (LPARAM)&tbi);
595 break;
596 case ID_VIEW_FITIMAGEHEIGHTS:
598 bFitHeights = !bFitHeights;
599 picWindow1.FitHeights(bFitHeights);
600 picWindow2.FitHeights(bFitHeights);
601 picWindow3.FitHeights(bFitHeights);
603 HMENU hMenu = GetMenu(*this);
604 UINT uCheck = MF_BYCOMMAND;
605 uCheck |= bFitHeights ? MF_CHECKED : MF_UNCHECKED;
606 CheckMenuItem(hMenu, ID_VIEW_FITIMAGEHEIGHTS, uCheck);
608 // change the state of the toolbar button
609 TBBUTTONINFO tbi;
610 tbi.cbSize = sizeof(TBBUTTONINFO);
611 tbi.dwMask = TBIF_STATE;
612 tbi.fsState = bFitHeights ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
613 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_FITIMAGEHEIGHTS, (LPARAM)&tbi);
615 break;
616 case ID_VIEW_LINKIMAGESTOGETHER:
618 bLinkedPositions = !bLinkedPositions;
619 picWindow1.LinkPositions(bLinkedPositions);
620 picWindow2.LinkPositions(bLinkedPositions);
621 picWindow3.LinkPositions(bLinkedPositions);
623 HMENU hMenu = GetMenu(*this);
624 UINT uCheck = MF_BYCOMMAND;
625 uCheck |= bLinkedPositions ? MF_CHECKED : MF_UNCHECKED;
626 CheckMenuItem(hMenu, ID_VIEW_LINKIMAGESTOGETHER, uCheck);
628 // change the state of the toolbar button
629 TBBUTTONINFO tbi;
630 tbi.cbSize = sizeof(TBBUTTONINFO);
631 tbi.dwMask = TBIF_STATE;
632 tbi.fsState = bLinkedPositions ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
633 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
635 break;
636 case ID_VIEW_ALPHA0:
637 picWindow1.SetBlendAlpha(m_BlendType, 0.0f);
638 break;
639 case ID_VIEW_ALPHA255:
640 picWindow1.SetBlendAlpha(m_BlendType, 1.0f);
641 break;
642 case ID_VIEW_ALPHA127:
643 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
644 break;
645 case ID_VIEW_ALPHATOGGLE:
646 picWindow1.ToggleAlpha();
647 break;
648 case ID_VIEW_FITIMAGESINWINDOW:
650 picWindow1.FitImageInWindow();
651 picWindow2.FitImageInWindow();
652 picWindow3.FitImageInWindow();
654 break;
655 case ID_VIEW_ORININALSIZE:
657 picWindow1.SetZoom(100, false);
658 picWindow2.SetZoom(100, false);
659 picWindow3.SetZoom(100, false);
660 picWindow1.CenterImage();
661 picWindow2.CenterImage();
662 picWindow3.CenterImage();
664 break;
665 case ID_VIEW_ZOOMIN:
667 picWindow1.Zoom(true, false);
668 if ((!(bFitWidths || bFitHeights))&&(!bOverlap))
670 picWindow2.Zoom(true, false);
671 picWindow3.Zoom(true, false);
674 break;
675 case ID_VIEW_ZOOMOUT:
677 picWindow1.Zoom(false, false);
678 if ((!(bFitWidths || bFitHeights))&&(!bOverlap))
680 picWindow2.Zoom(false, false);
681 picWindow3.Zoom(false, false);
684 break;
685 case ID_VIEW_ARRANGEVERTICAL:
687 bVertical = !bVertical;
688 RECT rect;
689 GetClientRect(*this, &rect);
690 if (bVertical)
692 RECT tbRect;
693 GetWindowRect(hwndTB, &tbRect);
694 LONG tbHeight = tbRect.bottom-tbRect.top-1;
695 if (selectionPaths.size() != 3)
697 nSplitterPos = (rect.bottom-rect.top)/2+tbHeight;
698 nSplitterPos2 = 0;
700 else
702 nSplitterPos = (rect.bottom-rect.top)/3+tbHeight;
703 nSplitterPos2 = (rect.bottom-rect.top)*2/3+tbHeight;
706 else
708 if (selectionPaths.size() != 3)
710 nSplitterPos = (rect.right-rect.left)/2;
711 nSplitterPos2 = 0;
713 else
715 nSplitterPos = (rect.right-rect.left)/3;
716 nSplitterPos2 = (rect.right-rect.left)*2/3;
719 HMENU hMenu = GetMenu(*this);
720 UINT uCheck = MF_BYCOMMAND;
721 uCheck |= bVertical ? MF_CHECKED : MF_UNCHECKED;
722 CheckMenuItem(hMenu, ID_VIEW_ARRANGEVERTICAL, uCheck);
723 // change the state of the toolbar button
724 TBBUTTONINFO tbi;
725 tbi.cbSize = sizeof(TBBUTTONINFO);
726 tbi.dwMask = TBIF_STATE;
727 tbi.fsState = bVertical ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
728 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
730 PositionChildren(&rect);
732 break;
733 case ID_ABOUT:
735 CAboutDlg dlg(*this);
736 dlg.DoModal(hInst, IDD_ABOUT, *this);
738 break;
739 case SELECTBUTTON_ID:
741 HWND hSource = (HWND)lParam;
742 FileType resolveWith;
743 if (picWindow1 == hSource)
744 resolveWith = FileTypeMine;
745 else if (picWindow2 == hSource)
746 resolveWith = FileTypeBase;
747 else if (picWindow3 == hSource)
748 resolveWith = FileTypeTheirs;
749 else
750 break;
752 if (selectionResult.empty())
754 PostQuitMessage(resolveWith);
755 break;
758 CopyFile(selectionPaths[resolveWith].c_str(), selectionResult.c_str(), FALSE);
760 CAutoBuf projectRoot;
761 if (git_repository_discover(projectRoot, CUnicodeUtils::GetUTF8(selectionResult.c_str()), FALSE, nullptr) < 0 && strstr(projectRoot->ptr, "/.git/"))
763 PostQuitMessage(resolveWith);
764 break;
767 CAutoRepository repository(projectRoot->ptr);
768 if (!repository)
770 PostQuitMessage(resolveWith);
771 break;
774 CStringA subpath = CUnicodeUtils::GetUTF8(selectionResult.c_str()).Mid((int)strlen(git_repository_workdir(repository)));
776 CAutoIndex index;
777 if (git_repository_index(index.GetPointer(), repository) || (git_index_get_bypath(index, subpath, 1) == nullptr && git_index_get_bypath(index, subpath, 2) == nullptr))
779 PostQuitMessage(resolveWith);
780 break;
783 CString sTemp;
784 sTemp.Format(ResString(hResource, IDS_MARKASRESOLVED), (LPCTSTR)CPathUtils::GetFileNameFromPath(selectionResult.c_str()));
785 if (MessageBox(m_hwnd, sTemp, L"TortoiseGitMerge", MB_YESNO | MB_ICONQUESTION) != IDYES)
786 break;
788 CString cmd;
789 cmd.Format(L"\"%sTortoiseGitProc.exe\" /command:resolve /path:\"%s\" /closeonend:1 /noquestion /skipcheck /silent", (LPCTSTR)CPathUtils::GetAppDirectory(), selectionResult.c_str());
790 if (resolveMsgWnd)
791 cmd.AppendFormat(L" /resolvemsghwnd:%I64d /resolvemsgwparam:%I64d /resolvemsglparam:%I64d", (__int64)resolveMsgWnd, (__int64)resolveMsgWParam, (__int64)resolveMsgLParam);
793 STARTUPINFO startup = { 0 };
794 PROCESS_INFORMATION process = { 0 };
795 startup.cb = sizeof(startup);
797 if (!CreateProcess(nullptr, cmd.GetBuffer(), nullptr, nullptr, FALSE, CREATE_UNICODE_ENVIRONMENT, nullptr, nullptr, &startup, &process))
799 cmd.ReleaseBuffer();
800 PostQuitMessage(resolveWith);
801 break;
803 cmd.ReleaseBuffer();
805 AllowSetForegroundWindow(process.dwProcessId);
807 CloseHandle(process.hThread);
808 CloseHandle(process.hProcess);
810 PostQuitMessage(resolveWith);
812 break;
813 case IDM_EXIT:
814 ::PostQuitMessage(0);
815 return 0;
816 break;
817 default:
818 break;
820 return 1;
823 // splitter stuff
824 void CMainWindow::DrawXorBar(HDC hdc, int x1, int y1, int width, int height)
826 static WORD _dotPatternBmp[8] =
828 0x0055, 0x00aa, 0x0055, 0x00aa,
829 0x0055, 0x00aa, 0x0055, 0x00aa
832 HBITMAP hbm;
833 HBRUSH hbr, hbrushOld;
835 hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
836 hbr = CreatePatternBrush(hbm);
838 SetBrushOrgEx(hdc, x1, y1, 0);
839 hbrushOld = (HBRUSH)SelectObject(hdc, hbr);
841 PatBlt(hdc, x1, y1, width, height, PATINVERT);
843 SelectObject(hdc, hbrushOld);
845 DeleteObject(hbr);
846 DeleteObject(hbm);
849 LRESULT CMainWindow::Splitter_OnLButtonDown(HWND hwnd, UINT /*iMsg*/, WPARAM /*wParam*/, LPARAM lParam)
851 POINT pt;
852 HDC hdc;
853 RECT rect;
854 RECT clientrect;
856 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
857 pt.y = (short)HIWORD(lParam);
859 GetClientRect(hwnd, &clientrect);
860 GetWindowRect(hwnd, &rect);
861 POINT zero = {0,0};
862 ClientToScreen(hwnd, &zero);
863 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
865 ClientToScreen(hwnd, &pt);
866 // find out which drag bar is used
867 bDrag2 = false;
868 if (!selectionPaths.empty())
870 RECT pic2Rect;
871 GetWindowRect(picWindow2, &pic2Rect);
872 if (bVertical)
874 if (pic2Rect.bottom <= pt.y)
875 bDrag2 = true;
877 else
879 if (pic2Rect.right <= pt.x)
880 bDrag2 = true;
884 //convert the mouse coordinates relative to the top-left of
885 //the window
886 pt.x -= rect.left;
887 pt.y -= rect.top;
889 //same for the window coordinates - make them relative to 0,0
890 OffsetRect(&rect, -rect.left, -rect.top);
892 if (pt.x < 0)
893 pt.x = 0;
894 if (pt.x > rect.right-4)
895 pt.x = rect.right-4;
896 if (pt.y < 0)
897 pt.y = 0;
898 if (pt.y > rect.bottom-4)
899 pt.y = rect.bottom-4;
901 bDragMode = true;
903 SetCapture(hwnd);
905 hdc = GetWindowDC(hwnd);
906 if (bVertical)
907 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
908 else
909 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
910 ReleaseDC(hwnd, hdc);
912 oldx = pt.x;
913 oldy = pt.y;
915 return 0;
918 void CMainWindow::Splitter_CaptureChanged()
920 bDragMode = false;
923 LRESULT CMainWindow::Splitter_OnLButtonUp(HWND hwnd, UINT /*iMsg*/, WPARAM /*wParam*/, LPARAM lParam)
925 HDC hdc;
926 RECT rect;
927 RECT clientrect;
929 POINT pt;
930 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
931 pt.y = (short)HIWORD(lParam);
933 if (bDragMode == FALSE)
934 return 0;
936 GetClientRect(hwnd, &clientrect);
937 GetWindowRect(hwnd, &rect);
938 POINT zero = {0,0};
939 ClientToScreen(hwnd, &zero);
940 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
942 ClientToScreen(hwnd, &pt);
943 pt.x -= rect.left;
944 pt.y -= rect.top;
946 OffsetRect(&rect, -rect.left, -rect.top);
948 if (pt.x < 0)
949 pt.x = 0;
950 if (pt.x > rect.right-4)
951 pt.x = rect.right-4;
952 if (pt.y < 0)
953 pt.y = 0;
954 if (pt.y > rect.bottom-4)
955 pt.y = rect.bottom-4;
957 hdc = GetWindowDC(hwnd);
958 if (bVertical)
959 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
960 else
961 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
962 ReleaseDC(hwnd, hdc);
964 oldx = pt.x;
965 oldy = pt.y;
967 bDragMode = false;
969 //convert the splitter position back to screen coords.
970 GetWindowRect(hwnd, &rect);
971 pt.x += rect.left;
972 pt.y += rect.top;
974 //now convert into CLIENT coordinates
975 ScreenToClient(hwnd, &pt);
976 GetClientRect(hwnd, &rect);
977 #define MINWINSIZE 10
978 if (bVertical)
980 if (bDrag2)
982 if (pt.y < (nSplitterPos+MINWINSIZE))
983 pt.y = nSplitterPos+MINWINSIZE;
984 nSplitterPos2 = pt.y;
986 else
988 if (pt.y > (nSplitterPos2-MINWINSIZE))
989 pt.y = nSplitterPos2-MINWINSIZE;
990 nSplitterPos = pt.y;
993 else
995 if (bDrag2)
997 if (pt.x < (nSplitterPos+MINWINSIZE))
998 pt.x = nSplitterPos+MINWINSIZE;
999 nSplitterPos2 = pt.x;
1001 else
1003 if (pt.x > (nSplitterPos2-MINWINSIZE))
1004 pt.x = nSplitterPos2-MINWINSIZE;
1005 nSplitterPos = pt.x;
1009 ReleaseCapture();
1011 //position the child controls
1012 PositionChildren(&rect);
1013 return 0;
1016 LRESULT CMainWindow::Splitter_OnMouseMove(HWND hwnd, UINT /*iMsg*/, WPARAM wParam, LPARAM lParam)
1018 RECT rect;
1019 RECT clientrect;
1021 POINT pt;
1023 if (bDragMode == FALSE)
1024 return 0;
1026 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
1027 pt.y = (short)HIWORD(lParam);
1029 GetClientRect(hwnd, &clientrect);
1030 GetWindowRect(hwnd, &rect);
1031 POINT zero = {0,0};
1032 ClientToScreen(hwnd, &zero);
1033 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
1035 //convert the mouse coordinates relative to the top-left of
1036 //the window
1037 ClientToScreen(hwnd, &pt);
1038 pt.x -= rect.left;
1039 pt.y -= rect.top;
1041 //same for the window coordinates - make them relative to 0,0
1042 OffsetRect(&rect, -rect.left, -rect.top);
1044 if (pt.x < 0)
1045 pt.x = 0;
1046 if (pt.x > rect.right-4)
1047 pt.x = rect.right-4;
1048 if (pt.y < 0)
1049 pt.y = 0;
1050 if (pt.y > rect.bottom-4)
1051 pt.y = rect.bottom-4;
1053 if ((wParam & MK_LBUTTON) && ((bVertical && (pt.y != oldy)) || (!bVertical && (pt.x != oldx))))
1055 HDC hdc = GetWindowDC(hwnd);
1057 if (bVertical)
1059 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
1060 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
1062 else
1064 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
1065 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
1068 ReleaseDC(hwnd, hdc);
1070 oldx = pt.x;
1071 oldy = pt.y;
1074 return 0;
1077 bool CMainWindow::OpenDialog()
1079 return (DialogBox(hResource, MAKEINTRESOURCE(IDD_OPEN), *this, (DLGPROC)OpenDlgProc)==IDOK);
1082 BOOL CALLBACK CMainWindow::OpenDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/)
1084 switch (message)
1086 case WM_INITDIALOG:
1088 // center on the parent window
1089 HWND hParentWnd = ::GetParent(hwndDlg);
1090 RECT parentrect, childrect, centeredrect;
1091 GetWindowRect(hParentWnd, &parentrect);
1092 GetWindowRect(hwndDlg, &childrect);
1093 centeredrect.left = parentrect.left + ((parentrect.right-parentrect.left-childrect.right+childrect.left)/2);
1094 centeredrect.right = centeredrect.left + (childrect.right-childrect.left);
1095 centeredrect.top = parentrect.top + ((parentrect.bottom-parentrect.top-childrect.bottom+childrect.top)/2);
1096 centeredrect.bottom = centeredrect.top + (childrect.bottom-childrect.top);
1097 SetWindowPos(hwndDlg, nullptr, centeredrect.left, centeredrect.top, centeredrect.right - centeredrect.left, centeredrect.bottom - centeredrect.top, SWP_SHOWWINDOW);
1099 if (!leftpicpath.empty())
1100 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, leftpicpath.c_str());
1101 SetFocus(hwndDlg);
1103 break;
1104 case WM_COMMAND:
1105 switch (LOWORD(wParam))
1107 case IDC_LEFTBROWSE:
1109 TCHAR path[MAX_PATH] = {0};
1110 if (AskForFile(hwndDlg, path))
1112 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path);
1115 break;
1116 case IDC_RIGHTBROWSE:
1118 TCHAR path[MAX_PATH] = {0};
1119 if (AskForFile(hwndDlg, path))
1121 SetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path);
1124 break;
1125 case IDOK:
1127 TCHAR path[MAX_PATH] = { 0 };
1128 if (!GetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path, _countof(path)))
1129 *path = 0;
1130 leftpicpath = path;
1131 if (!GetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path, _countof(path)))
1132 *path = 0;
1133 rightpicpath = path;
1135 // Fall through.
1136 case IDCANCEL:
1137 EndDialog(hwndDlg, wParam);
1138 return TRUE;
1141 return FALSE;
1144 bool CMainWindow::AskForFile(HWND owner, TCHAR * path)
1146 OPENFILENAME ofn = {0}; // common dialog box structure
1147 // Initialize OPENFILENAME
1148 ofn.lStructSize = sizeof(OPENFILENAME);
1149 ofn.hwndOwner = owner;
1150 ofn.lpstrFile = path;
1151 ofn.nMaxFile = MAX_PATH;
1152 ResString sTitle(::hResource, IDS_OPENIMAGEFILE);
1153 ofn.lpstrTitle = sTitle;
1154 ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_EXPLORER;
1155 ofn.hInstance = ::hResource;
1156 TCHAR filters[] = L"Images\0*.wmf;*.jpg;*jpeg;*.bmp;*.gif;*.png;*.ico;*.dib;*.emf\0All (*.*)\0*.*\0\0";
1157 ofn.lpstrFilter = filters;
1158 ofn.nFilterIndex = 1;
1159 // Display the Open dialog box.
1160 if (GetOpenFileName(&ofn)==FALSE)
1162 return false;
1164 return true;
1167 bool CMainWindow::CreateToolbar()
1169 // Ensure that the common control DLL is loaded.
1170 INITCOMMONCONTROLSEX icex;
1171 icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
1172 icex.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES;
1173 InitCommonControlsEx(&icex);
1175 hwndTB = CreateWindowEx(0,
1176 TOOLBARCLASSNAME,
1177 (LPCTSTR)nullptr,
1178 WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
1179 0, 0, 0, 0,
1180 *this,
1181 (HMENU)IDC_TORTOISEIDIFF,
1182 hResource,
1183 nullptr);
1184 if (hwndTB == INVALID_HANDLE_VALUE)
1185 return false;
1187 SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
1189 TBBUTTON tbb[13];
1190 // create an imagelist containing the icons for the toolbar
1191 hToolbarImgList = ImageList_Create(24, 24, ILC_COLOR32 | ILC_MASK, 12, 4);
1192 if (!hToolbarImgList)
1193 return false;
1194 int index = 0;
1195 HICON hIcon = nullptr;
1196 if (selectionPaths.empty())
1198 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_OVERLAP));
1199 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1200 tbb[index].idCommand = ID_VIEW_OVERLAPIMAGES;
1201 tbb[index].fsState = TBSTATE_ENABLED;
1202 tbb[index].fsStyle = BTNS_BUTTON;
1203 tbb[index].dwData = 0;
1204 tbb[index++].iString = 0;
1206 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_BLEND));
1207 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1208 tbb[index].idCommand = ID_VIEW_BLENDALPHA;
1209 tbb[index].fsState = 0;
1210 tbb[index].fsStyle = BTNS_BUTTON;
1211 tbb[index].dwData = 0;
1212 tbb[index++].iString = 0;
1214 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_LINK));
1215 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1216 tbb[index].idCommand = ID_VIEW_LINKIMAGESTOGETHER;
1217 tbb[index].fsState = TBSTATE_ENABLED | TBSTATE_CHECKED;
1218 tbb[index].fsStyle = BTNS_BUTTON;
1219 tbb[index].dwData = 0;
1220 tbb[index++].iString = 0;
1222 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITWIDTHS));
1223 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1224 tbb[index].idCommand = ID_VIEW_FITIMAGEWIDTHS;
1225 tbb[index].fsState = TBSTATE_ENABLED;
1226 tbb[index].fsStyle = BTNS_BUTTON;
1227 tbb[index].dwData = 0;
1228 tbb[index++].iString = 0;
1230 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITHEIGHTS));
1231 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1232 tbb[index].idCommand = ID_VIEW_FITIMAGEHEIGHTS;
1233 tbb[index].fsState = TBSTATE_ENABLED;
1234 tbb[index].fsStyle = BTNS_BUTTON;
1235 tbb[index].dwData = 0;
1236 tbb[index++].iString = 0;
1238 tbb[index].iBitmap = 0;
1239 tbb[index].idCommand = 0;
1240 tbb[index].fsState = TBSTATE_ENABLED;
1241 tbb[index].fsStyle = BTNS_SEP;
1242 tbb[index].dwData = 0;
1243 tbb[index++].iString = 0;
1245 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_VERTICAL));
1246 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1247 tbb[index].idCommand = ID_VIEW_ARRANGEVERTICAL;
1248 tbb[index].fsState = TBSTATE_ENABLED;
1249 tbb[index].fsStyle = BTNS_BUTTON;
1250 tbb[index].dwData = 0;
1251 tbb[index++].iString = 0;
1253 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITINWINDOW));
1254 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1255 tbb[index].idCommand = ID_VIEW_FITIMAGESINWINDOW;
1256 tbb[index].fsState = TBSTATE_ENABLED;
1257 tbb[index].fsStyle = BTNS_BUTTON;
1258 tbb[index].dwData = 0;
1259 tbb[index++].iString = 0;
1261 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ORIGSIZE));
1262 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1263 tbb[index].idCommand = ID_VIEW_ORININALSIZE;
1264 tbb[index].fsState = TBSTATE_ENABLED;
1265 tbb[index].fsStyle = BTNS_BUTTON;
1266 tbb[index].dwData = 0;
1267 tbb[index++].iString = 0;
1269 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMIN));
1270 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1271 tbb[index].idCommand = ID_VIEW_ZOOMIN;
1272 tbb[index].fsState = TBSTATE_ENABLED;
1273 tbb[index].fsStyle = BTNS_BUTTON;
1274 tbb[index].dwData = 0;
1275 tbb[index++].iString = 0;
1277 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMOUT));
1278 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1279 tbb[index].idCommand = ID_VIEW_ZOOMOUT;
1280 tbb[index].fsState = TBSTATE_ENABLED;
1281 tbb[index].fsStyle = BTNS_BUTTON;
1282 tbb[index].dwData = 0;
1283 tbb[index++].iString = 0;
1285 tbb[index].iBitmap = 0;
1286 tbb[index].idCommand = 0;
1287 tbb[index].fsState = TBSTATE_ENABLED;
1288 tbb[index].fsStyle = BTNS_SEP;
1289 tbb[index].dwData = 0;
1290 tbb[index++].iString = 0;
1292 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_IMGINFO));
1293 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
1294 tbb[index].idCommand = ID_VIEW_IMAGEINFO;
1295 tbb[index].fsState = TBSTATE_ENABLED;
1296 tbb[index].fsStyle = BTNS_BUTTON;
1297 tbb[index].dwData = 0;
1298 tbb[index++].iString = 0;
1300 SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)hToolbarImgList);
1301 SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM)index, (LPARAM) (LPTBBUTTON) &tbb);
1302 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
1303 ShowWindow(hwndTB, SW_SHOW);
1304 return true;
1307 void CMainWindow::SetSelectionImage( FileType ft, const std::wstring& path, const std::wstring& title )
1309 selectionPaths[ft] = path;
1310 selectionTitles[ft] = title;