Sync TortoiseIDiff and TortoiseUDiff from TortoiseSVN
[TortoiseGit.git] / src / TortoiseIDiff / MainWindow.cpp
blobb00b3173e9b00df6c465a4f0b9d404f0bb36f95f
1 // TortoiseIDiff - an image diff viewer in TortoiseSVN
3 // Copyright (C) 2006-2013 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "stdafx.h"
20 #include <CommCtrl.h>
21 #include <Commdlg.h>
22 #include "TortoiseIDiff.h"
23 #include "MainWindow.h"
24 #include "AboutDlg.h"
25 #include "TaskbarUUID.h"
27 #pragma comment(lib, "comctl32.lib")
29 tstring CMainWindow::leftpicpath;
30 tstring CMainWindow::leftpictitle;
32 tstring CMainWindow::rightpicpath;
33 tstring CMainWindow::rightpictitle;
35 const UINT TaskBarButtonCreated = RegisterWindowMessage(L"TaskbarButtonCreated");
37 bool CMainWindow::RegisterAndCreateWindow()
39 WNDCLASSEX wcx;
41 // Fill in the window class structure with default parameters
42 wcx.cbSize = sizeof(WNDCLASSEX);
43 wcx.style = CS_HREDRAW | CS_VREDRAW;
44 wcx.lpfnWndProc = CWindow::stWinMsgHandler;
45 wcx.cbClsExtra = 0;
46 wcx.cbWndExtra = 0;
47 wcx.hInstance = hResource;
48 wcx.hCursor = LoadCursor(NULL, IDC_SIZEWE);
49 ResString clsname(hResource, IDS_APP_TITLE);
50 wcx.lpszClassName = clsname;
51 wcx.hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_TORTOISEIDIFF));
52 wcx.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
53 wcx.lpszMenuName = MAKEINTRESOURCE(IDC_TORTOISEIDIFF);
54 wcx.hIconSm = LoadIcon(wcx.hInstance, MAKEINTRESOURCE(IDI_TORTOISEIDIFF));
55 if (RegisterWindow(&wcx))
57 if (Create(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE, NULL))
59 UpdateWindow(m_hwnd);
60 return true;
63 return false;
66 void CMainWindow::PositionChildren(RECT * clientrect /* = NULL */)
68 RECT tbRect;
69 if (clientrect == NULL)
70 return;
71 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
72 GetWindowRect(hwndTB, &tbRect);
73 LONG tbHeight = tbRect.bottom-tbRect.top-1;
74 HDWP hdwp = BeginDeferWindowPos(2);
75 if (bOverlap)
77 SetWindowPos(picWindow1, NULL, clientrect->left, clientrect->top+tbHeight, clientrect->right-clientrect->left, clientrect->bottom-clientrect->top-tbHeight, SWP_SHOWWINDOW);
79 else
81 if (bVertical)
83 RECT child;
84 child.left = clientrect->left;
85 child.top = clientrect->top+tbHeight;
86 child.right = clientrect->right;
87 child.bottom = nSplitterPos-(SPLITTER_BORDER/2);
88 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
89 child.top = nSplitterPos+(SPLITTER_BORDER/2);
90 child.bottom = clientrect->bottom;
91 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
93 else
95 RECT child;
96 child.left = clientrect->left;
97 child.top = clientrect->top+tbHeight;
98 child.right = nSplitterPos-(SPLITTER_BORDER/2);
99 child.bottom = clientrect->bottom;
100 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
101 child.left = nSplitterPos+(SPLITTER_BORDER/2);
102 child.right = clientrect->right;
103 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
106 if (hdwp) EndDeferWindowPos(hdwp);
107 picWindow1.SetTransparentColor(transparentColor);
108 picWindow2.SetTransparentColor(transparentColor);
109 InvalidateRect(*this, NULL, FALSE);
112 LRESULT CALLBACK CMainWindow::WinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
114 if (uMsg == TaskBarButtonCreated)
116 SetUUIDOverlayIcon(hwnd);
118 switch (uMsg)
120 case WM_CREATE:
122 m_hwnd = hwnd;
123 picWindow1.RegisterAndCreateWindow(hwnd);
124 picWindow1.SetPic(leftpicpath, leftpictitle, true);
125 picWindow2.RegisterAndCreateWindow(hwnd);
126 picWindow2.SetPic(rightpicpath, rightpictitle, false);
128 picWindow1.SetOtherPicWindow(&picWindow2);
129 picWindow2.SetOtherPicWindow(&picWindow1);
130 CreateToolbar();
131 // center the splitter
132 RECT rect;
133 GetClientRect(hwnd, &rect);
134 nSplitterPos = (rect.right-rect.left)/2;
135 PositionChildren(&rect);
136 picWindow1.FitImageInWindow();
137 picWindow2.FitImageInWindow();
139 break;
140 case WM_COMMAND:
142 return DoCommand(LOWORD(wParam));
144 break;
145 case WM_PAINT:
147 PAINTSTRUCT ps;
148 HDC hdc;
149 RECT rect;
151 ::GetClientRect(*this, &rect);
152 hdc = BeginPaint(hwnd, &ps);
153 SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
154 ::ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
155 EndPaint(hwnd, &ps);
157 break;
158 case WM_GETMINMAXINFO:
160 MINMAXINFO * mmi = (MINMAXINFO*)lParam;
161 mmi->ptMinTrackSize.x = WINDOW_MINWIDTH;
162 mmi->ptMinTrackSize.y = WINDOW_MINHEIGHT;
163 return 0;
165 break;
166 case WM_SIZE:
168 RECT rect;
169 GetClientRect(hwnd, &rect);
170 if (bVertical)
172 RECT tbRect;
173 GetWindowRect(hwndTB, &tbRect);
174 LONG tbHeight = tbRect.bottom-tbRect.top-1;
175 nSplitterPos = (rect.bottom-rect.top+tbHeight)/2;
177 else
178 nSplitterPos = (rect.right-rect.left)/2;
179 PositionChildren(&rect);
181 break;
182 case WM_SETCURSOR:
184 if ((HWND)wParam == *this)
186 RECT rect;
187 POINT pt;
188 GetClientRect(*this, &rect);
189 GetCursorPos(&pt);
190 ScreenToClient(*this, &pt);
191 if (PtInRect(&rect, pt))
193 if (bVertical)
195 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENS));
196 SetCursor(hCur);
198 else
200 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE));
201 SetCursor(hCur);
203 return TRUE;
206 return DefWindowProc(hwnd, uMsg, wParam, lParam);
208 break;
209 case WM_LBUTTONDOWN:
210 Splitter_OnLButtonDown(hwnd, uMsg, wParam, lParam);
211 break;
212 case WM_LBUTTONUP:
213 Splitter_OnLButtonUp(hwnd, uMsg, wParam, lParam);
214 break;
215 case WM_CAPTURECHANGED:
216 Splitter_CaptureChanged();
217 break;
218 case WM_MOUSEMOVE:
219 Splitter_OnMouseMove(hwnd, uMsg, wParam, lParam);
220 break;
221 case WM_MOUSEWHEEL:
223 // find out if the mouse cursor is over one of the views, and if
224 // it is, pass the mouse wheel message to that view
225 POINT pt;
226 DWORD ptW = GetMessagePos();
227 pt.x = GET_X_LPARAM(ptW);
228 pt.y = GET_Y_LPARAM(ptW);
229 RECT rect;
230 GetWindowRect(picWindow1, &rect);
231 if (PtInRect(&rect, pt))
233 picWindow1.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
235 else
237 GetWindowRect(picWindow2, &rect);
238 if (PtInRect(&rect, pt))
240 picWindow2.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
244 break;
245 case WM_MOUSEHWHEEL:
247 // find out if the mouse cursor is over one of the views, and if
248 // it is, pass the mouse wheel message to that view
249 POINT pt;
250 DWORD ptW = GetMessagePos();
251 pt.x = GET_X_LPARAM(ptW);
252 pt.y = GET_Y_LPARAM(ptW);
253 RECT rect;
254 GetWindowRect(picWindow1, &rect);
255 if (PtInRect(&rect, pt))
257 picWindow1.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
259 else
261 GetWindowRect(picWindow2, &rect);
262 if (PtInRect(&rect, pt))
264 picWindow2.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
268 break;
269 case WM_NOTIFY:
271 LPNMHDR pNMHDR = (LPNMHDR)lParam;
272 if (pNMHDR->code == TTN_GETDISPINFO)
274 LPTOOLTIPTEXT lpttt;
276 lpttt = (LPTOOLTIPTEXT) lParam;
277 lpttt->hinst = hResource;
279 // Specify the resource identifier of the descriptive
280 // text for the given button.
281 TCHAR stringbuf[MAX_PATH] = {0};
282 MENUITEMINFO mii;
283 mii.cbSize = sizeof(MENUITEMINFO);
284 mii.fMask = MIIM_TYPE;
285 mii.dwTypeData = stringbuf;
286 mii.cch = _countof(stringbuf);
287 GetMenuItemInfo(GetMenu(*this), (UINT)lpttt->hdr.idFrom, FALSE, &mii);
288 _tcscpy_s(lpttt->lpszText, 80, stringbuf);
291 break;
292 case WM_DESTROY:
293 bWindowClosed = TRUE;
294 PostQuitMessage(0);
295 break;
296 case WM_CLOSE:
297 ImageList_Destroy(hToolbarImgList);
298 ::DestroyWindow(m_hwnd);
299 break;
300 default:
301 return DefWindowProc(hwnd, uMsg, wParam, lParam);
304 return 0;
307 LRESULT CMainWindow::DoCommand(int id)
309 switch (id)
311 case ID_FILE_OPEN:
313 if (OpenDialog())
315 picWindow1.SetPic(leftpicpath, _T(""), true);
316 picWindow2.SetPic(rightpicpath, _T(""), false);
317 if (bOverlap)
319 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath);
321 else
323 picWindow1.SetSecondPic();
325 RECT rect;
326 GetClientRect(*this, &rect);
327 PositionChildren(&rect);
328 picWindow1.FitImageInWindow();
329 picWindow2.FitImageInWindow();
332 break;
333 case ID_VIEW_IMAGEINFO:
335 bShowInfo = !bShowInfo;
336 HMENU hMenu = GetMenu(*this);
337 UINT uCheck = MF_BYCOMMAND;
338 uCheck |= bShowInfo ? MF_CHECKED : MF_UNCHECKED;
339 CheckMenuItem(hMenu, ID_VIEW_IMAGEINFO, uCheck);
341 picWindow1.ShowInfo(bShowInfo);
342 picWindow2.ShowInfo(bShowInfo);
344 // change the state of the toolbar button
345 TBBUTTONINFO tbi;
346 tbi.cbSize = sizeof(TBBUTTONINFO);
347 tbi.dwMask = TBIF_STATE;
348 tbi.fsState = bShowInfo ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
349 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_IMAGEINFO, (LPARAM)&tbi);
351 break;
352 case ID_VIEW_OVERLAPIMAGES:
354 bOverlap = !bOverlap;
355 HMENU hMenu = GetMenu(*this);
356 UINT uCheck = MF_BYCOMMAND;
357 uCheck |= bOverlap ? MF_CHECKED : MF_UNCHECKED;
358 CheckMenuItem(hMenu, ID_VIEW_OVERLAPIMAGES, uCheck);
359 uCheck |= (m_BlendType == CPicWindow::BLEND_ALPHA) ? MF_CHECKED : MF_UNCHECKED;
360 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
362 // change the state of the toolbar button
363 TBBUTTONINFO tbi;
364 tbi.cbSize = sizeof(TBBUTTONINFO);
365 tbi.dwMask = TBIF_STATE;
366 tbi.fsState = bOverlap ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
367 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_OVERLAPIMAGES, (LPARAM)&tbi);
369 tbi.fsState = (m_BlendType == CPicWindow::BLEND_ALPHA) ? TBSTATE_CHECKED : 0;
370 if (bOverlap)
371 tbi.fsState |= TBSTATE_ENABLED;
372 else
373 tbi.fsState = 0;
374 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
376 if (bOverlap)
377 tbi.fsState = 0;
378 else
379 tbi.fsState = bVertical ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
380 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
382 if (bOverlap)
384 bLinkedPositions = true;
385 picWindow1.LinkPositions(bLinkedPositions);
386 picWindow2.LinkPositions(bLinkedPositions);
387 tbi.fsState = TBSTATE_CHECKED;
389 else
390 tbi.fsState = bLinkedPositions ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
391 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
393 ShowWindow(picWindow2, bOverlap ? SW_HIDE : SW_SHOW);
395 if (bOverlap)
397 picWindow1.StopTimer();
398 picWindow2.StopTimer();
399 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath,
400 picWindow2.GetHPos(), picWindow2.GetVPos());
401 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
403 else
405 picWindow1.SetSecondPic();
407 picWindow1.SetOverlapMode(bOverlap);
408 picWindow2.SetOverlapMode(bOverlap);
411 RECT rect;
412 GetClientRect(*this, &rect);
413 PositionChildren(&rect);
415 return 0;
417 break;
418 case ID_VIEW_BLENDALPHA:
420 if (m_BlendType == CPicWindow::BLEND_ALPHA)
421 m_BlendType = CPicWindow::BLEND_XOR;
422 else
423 m_BlendType = CPicWindow::BLEND_ALPHA;
425 HMENU hMenu = GetMenu(*this);
426 UINT uCheck = MF_BYCOMMAND;
427 uCheck |= (m_BlendType == CPicWindow::BLEND_ALPHA) ? MF_CHECKED : MF_UNCHECKED;
428 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
430 // change the state of the toolbar button
431 TBBUTTONINFO tbi;
432 tbi.cbSize = sizeof(TBBUTTONINFO);
433 tbi.dwMask = TBIF_STATE;
434 tbi.fsState = (m_BlendType == CPicWindow::BLEND_ALPHA) ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
435 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
436 picWindow1.SetBlendAlpha(m_BlendType, picWindow1.GetBlendAlpha());
437 PositionChildren();
439 break;
440 case ID_VIEW_TRANSPARENTCOLOR:
442 static COLORREF customColors[16] = {0};
443 CHOOSECOLOR ccDlg;
444 memset(&ccDlg, 0, sizeof(ccDlg));
445 ccDlg.lStructSize = sizeof(ccDlg);
446 ccDlg.hwndOwner = m_hwnd;
447 ccDlg.rgbResult = transparentColor;
448 ccDlg.lpCustColors = customColors;
449 ccDlg.Flags = CC_RGBINIT | CC_FULLOPEN;
450 if(ChooseColor(&ccDlg))
452 transparentColor = ccDlg.rgbResult;
453 picWindow1.SetTransparentColor(transparentColor);
454 picWindow2.SetTransparentColor(transparentColor);
455 // The color picker takes the focus and we don't get it back.
456 ::SetFocus(picWindow1);
459 break;
460 case ID_VIEW_FITTOGETHER:
462 bFitSizes = !bFitSizes;
463 picWindow1.FitSizes(bFitSizes);
464 picWindow2.FitSizes(bFitSizes);
466 HMENU hMenu = GetMenu(*this);
467 UINT uCheck = MF_BYCOMMAND;
468 uCheck |= bFitSizes ? MF_CHECKED : MF_UNCHECKED;
469 CheckMenuItem(hMenu, ID_VIEW_FITTOGETHER, uCheck);
471 // change the state of the toolbar button
472 TBBUTTONINFO tbi;
473 tbi.cbSize = sizeof(TBBUTTONINFO);
474 tbi.dwMask = TBIF_STATE;
475 tbi.fsState = bFitSizes ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
476 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_FITTOGETHER, (LPARAM)&tbi);
478 break;
479 case ID_VIEW_LINKIMAGESTOGETHER:
481 bLinkedPositions = !bLinkedPositions;
482 picWindow1.LinkPositions(bLinkedPositions);
483 picWindow2.LinkPositions(bLinkedPositions);
485 HMENU hMenu = GetMenu(*this);
486 UINT uCheck = MF_BYCOMMAND;
487 uCheck |= bLinkedPositions ? MF_CHECKED : MF_UNCHECKED;
488 CheckMenuItem(hMenu, ID_VIEW_LINKIMAGESTOGETHER, uCheck);
490 // change the state of the toolbar button
491 TBBUTTONINFO tbi;
492 tbi.cbSize = sizeof(TBBUTTONINFO);
493 tbi.dwMask = TBIF_STATE;
494 tbi.fsState = bLinkedPositions ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
495 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
497 break;
498 case ID_VIEW_ALPHA0:
499 picWindow1.SetBlendAlpha(m_BlendType, 0.0f);
500 break;
501 case ID_VIEW_ALPHA255:
502 picWindow1.SetBlendAlpha(m_BlendType, 1.0f);
503 break;
504 case ID_VIEW_ALPHA127:
505 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
506 break;
507 case ID_VIEW_ALPHATOGGLE:
508 picWindow1.ToggleAlpha();
509 break;
510 case ID_VIEW_FITIMAGESINWINDOW:
512 picWindow2.FitImageInWindow();
513 picWindow1.FitImageInWindow();
515 break;
516 case ID_VIEW_ORININALSIZE:
518 picWindow2.SetZoom(1.0, false);
519 picWindow1.SetZoom(1.0, false);
521 break;
522 case ID_VIEW_ZOOMIN:
524 picWindow1.Zoom(true, false);
525 if ((!bFitSizes)&&(!bOverlap))
526 picWindow2.Zoom(true, false);
528 break;
529 case ID_VIEW_ZOOMOUT:
531 picWindow1.Zoom(false, false);
532 if ((!bFitSizes)&&(!bOverlap))
533 picWindow2.Zoom(false, false);
535 break;
536 case ID_VIEW_ARRANGEVERTICAL:
538 bVertical = !bVertical;
539 RECT rect;
540 GetClientRect(*this, &rect);
541 if (bVertical)
543 RECT tbRect;
544 GetWindowRect(hwndTB, &tbRect);
545 LONG tbHeight = tbRect.bottom-tbRect.top-1;
546 nSplitterPos = (rect.bottom-rect.top+tbHeight)/2;
548 else
550 nSplitterPos = (rect.right-rect.left)/2;
552 HMENU hMenu = GetMenu(*this);
553 UINT uCheck = MF_BYCOMMAND;
554 uCheck |= bVertical ? MF_CHECKED : MF_UNCHECKED;
555 CheckMenuItem(hMenu, ID_VIEW_ARRANGEVERTICAL, uCheck);
556 // change the state of the toolbar button
557 TBBUTTONINFO tbi;
558 tbi.cbSize = sizeof(TBBUTTONINFO);
559 tbi.dwMask = TBIF_STATE;
560 tbi.fsState = bVertical ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
561 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
563 PositionChildren(&rect);
565 break;
566 case ID_ABOUT:
568 CAboutDlg dlg(*this);
569 dlg.DoModal(hInst, IDD_ABOUT, *this);
571 break;
572 case IDM_EXIT:
573 ::PostQuitMessage(0);
574 return 0;
575 break;
576 default:
577 break;
579 return 1;
582 // splitter stuff
583 void CMainWindow::DrawXorBar(HDC hdc, int x1, int y1, int width, int height)
585 static WORD _dotPatternBmp[8] =
587 0x0055, 0x00aa, 0x0055, 0x00aa,
588 0x0055, 0x00aa, 0x0055, 0x00aa
591 HBITMAP hbm;
592 HBRUSH hbr, hbrushOld;
594 hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
595 hbr = CreatePatternBrush(hbm);
597 SetBrushOrgEx(hdc, x1, y1, 0);
598 hbrushOld = (HBRUSH)SelectObject(hdc, hbr);
600 PatBlt(hdc, x1, y1, width, height, PATINVERT);
602 SelectObject(hdc, hbrushOld);
604 DeleteObject(hbr);
605 DeleteObject(hbm);
608 LRESULT CMainWindow::Splitter_OnLButtonDown(HWND hwnd, UINT /*iMsg*/, WPARAM /*wParam*/, LPARAM lParam)
610 POINT pt;
611 HDC hdc;
612 RECT rect;
613 RECT clientrect;
615 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
616 pt.y = (short)HIWORD(lParam);
618 GetClientRect(hwnd, &clientrect);
619 GetWindowRect(hwnd, &rect);
620 POINT zero = {0,0};
621 ClientToScreen(hwnd, &zero);
622 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
624 //convert the mouse coordinates relative to the top-left of
625 //the window
626 ClientToScreen(hwnd, &pt);
627 pt.x -= rect.left;
628 pt.y -= rect.top;
630 //same for the window coordinates - make them relative to 0,0
631 OffsetRect(&rect, -rect.left, -rect.top);
633 if (pt.x < 0)
634 pt.x = 0;
635 if (pt.x > rect.right-4)
636 pt.x = rect.right-4;
637 if (pt.y < 0)
638 pt.y = 0;
639 if (pt.y > rect.bottom-4)
640 pt.y = rect.bottom-4;
642 bDragMode = true;
644 SetCapture(hwnd);
646 hdc = GetWindowDC(hwnd);
647 if (bVertical)
648 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
649 else
650 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
651 ReleaseDC(hwnd, hdc);
653 oldx = pt.x;
654 oldy = pt.y;
656 return 0;
659 void CMainWindow::Splitter_CaptureChanged()
661 bDragMode = false;
664 LRESULT CMainWindow::Splitter_OnLButtonUp(HWND hwnd, UINT /*iMsg*/, WPARAM /*wParam*/, LPARAM lParam)
666 HDC hdc;
667 RECT rect;
668 RECT clientrect;
670 POINT pt;
671 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
672 pt.y = (short)HIWORD(lParam);
674 if (bDragMode == FALSE)
675 return 0;
677 GetClientRect(hwnd, &clientrect);
678 GetWindowRect(hwnd, &rect);
679 POINT zero = {0,0};
680 ClientToScreen(hwnd, &zero);
681 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
683 ClientToScreen(hwnd, &pt);
684 pt.x -= rect.left;
685 pt.y -= rect.top;
687 OffsetRect(&rect, -rect.left, -rect.top);
689 if (pt.x < 0)
690 pt.x = 0;
691 if (pt.x > rect.right-4)
692 pt.x = rect.right-4;
693 if (pt.y < 0)
694 pt.y = 0;
695 if (pt.y > rect.bottom-4)
696 pt.y = rect.bottom-4;
698 hdc = GetWindowDC(hwnd);
699 if (bVertical)
700 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
701 else
702 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
703 ReleaseDC(hwnd, hdc);
705 oldx = pt.x;
706 oldy = pt.y;
708 bDragMode = false;
710 //convert the splitter position back to screen coords.
711 GetWindowRect(hwnd, &rect);
712 pt.x += rect.left;
713 pt.y += rect.top;
715 //now convert into CLIENT coordinates
716 ScreenToClient(hwnd, &pt);
717 GetClientRect(hwnd, &rect);
718 if (bVertical)
719 nSplitterPos = pt.y;
720 else
721 nSplitterPos = pt.x;
723 ReleaseCapture();
725 //position the child controls
726 PositionChildren(&rect);
727 return 0;
730 LRESULT CMainWindow::Splitter_OnMouseMove(HWND hwnd, UINT /*iMsg*/, WPARAM wParam, LPARAM lParam)
732 HDC hdc;
733 RECT rect;
734 RECT clientrect;
736 POINT pt;
738 if (bDragMode == FALSE)
739 return 0;
741 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
742 pt.y = (short)HIWORD(lParam);
744 GetClientRect(hwnd, &clientrect);
745 GetWindowRect(hwnd, &rect);
746 POINT zero = {0,0};
747 ClientToScreen(hwnd, &zero);
748 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
750 //convert the mouse coordinates relative to the top-left of
751 //the window
752 ClientToScreen(hwnd, &pt);
753 pt.x -= rect.left;
754 pt.y -= rect.top;
756 //same for the window coordinates - make them relative to 0,0
757 OffsetRect(&rect, -rect.left, -rect.top);
759 if (pt.x < 0)
760 pt.x = 0;
761 if (pt.x > rect.right-4)
762 pt.x = rect.right-4;
763 if (pt.y < 0)
764 pt.y = 0;
765 if (pt.y > rect.bottom-4)
766 pt.y = rect.bottom-4;
768 if ((wParam & MK_LBUTTON) && ((bVertical && (pt.y != oldy)) || (!bVertical && (pt.x != oldx))))
770 hdc = GetWindowDC(hwnd);
772 if (bVertical)
774 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
775 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
777 else
779 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
780 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
783 ReleaseDC(hwnd, hdc);
785 oldx = pt.x;
786 oldy = pt.y;
789 return 0;
792 bool CMainWindow::OpenDialog()
794 return (DialogBox(hResource, MAKEINTRESOURCE(IDD_OPEN), *this, (DLGPROC)OpenDlgProc)==IDOK);
797 BOOL CALLBACK CMainWindow::OpenDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/)
799 switch (message)
801 case WM_INITDIALOG:
803 // center on the parent window
804 HWND hParentWnd = ::GetParent(hwndDlg);
805 RECT parentrect, childrect, centeredrect;
806 GetWindowRect(hParentWnd, &parentrect);
807 GetWindowRect(hwndDlg, &childrect);
808 centeredrect.left = parentrect.left + ((parentrect.right-parentrect.left-childrect.right+childrect.left)/2);
809 centeredrect.right = centeredrect.left + (childrect.right-childrect.left);
810 centeredrect.top = parentrect.top + ((parentrect.bottom-parentrect.top-childrect.bottom+childrect.top)/2);
811 centeredrect.bottom = centeredrect.top + (childrect.bottom-childrect.top);
812 SetWindowPos(hwndDlg, NULL, centeredrect.left, centeredrect.top, centeredrect.right-centeredrect.left, centeredrect.bottom-centeredrect.top, SWP_SHOWWINDOW);
814 if (!leftpicpath.empty())
815 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, leftpicpath.c_str());
816 SetFocus(hwndDlg);
818 break;
819 case WM_COMMAND:
820 switch (LOWORD(wParam))
822 case IDC_LEFTBROWSE:
824 TCHAR path[MAX_PATH] = {0};
825 if (AskForFile(hwndDlg, path))
827 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path);
830 break;
831 case IDC_RIGHTBROWSE:
833 TCHAR path[MAX_PATH] = {0};
834 if (AskForFile(hwndDlg, path))
836 SetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path);
839 break;
840 case IDOK:
842 TCHAR path[MAX_PATH];
843 if (!GetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path, _countof(path)))
844 *path = 0;
845 leftpicpath = path;
846 if (!GetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path, _countof(path)))
847 *path = 0;
848 rightpicpath = path;
850 // Fall through.
851 case IDCANCEL:
852 EndDialog(hwndDlg, wParam);
853 return TRUE;
856 return FALSE;
859 bool CMainWindow::AskForFile(HWND owner, TCHAR * path)
861 OPENFILENAME ofn = {0}; // common dialog box structure
862 // Initialize OPENFILENAME
863 ofn.lStructSize = sizeof(OPENFILENAME);
864 ofn.hwndOwner = owner;
865 ofn.lpstrFile = path;
866 ofn.nMaxFile = MAX_PATH;
867 ResString sTitle(::hResource, IDS_OPENIMAGEFILE);
868 ofn.lpstrTitle = sTitle;
869 ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_EXPLORER;
870 ofn.hInstance = ::hResource;
871 TCHAR filters[] = _T("Images\0*.wmf;*.jpg;*jpeg;*.bmp;*.gif;*.png;*.ico;*.dib;*.emf\0All (*.*)\0*.*\0\0");
872 ofn.lpstrFilter = filters;
873 ofn.nFilterIndex = 1;
874 // Display the Open dialog box.
875 if (GetOpenFileName(&ofn)==FALSE)
877 return false;
879 return true;
882 bool CMainWindow::CreateToolbar()
884 // Ensure that the common control DLL is loaded.
885 INITCOMMONCONTROLSEX icex;
886 icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
887 icex.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES;
888 InitCommonControlsEx(&icex);
890 hwndTB = CreateWindowEx(0,
891 TOOLBARCLASSNAME,
892 (LPCTSTR)NULL,
893 WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
894 0, 0, 0, 0,
895 *this,
896 (HMENU)IDC_TORTOISEIDIFF,
897 hResource,
898 NULL);
899 if (hwndTB == INVALID_HANDLE_VALUE)
900 return false;
902 SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
904 TBBUTTON tbb[12];
905 // create an imagelist containing the icons for the toolbar
906 hToolbarImgList = ImageList_Create(24, 24, ILC_COLOR32 | ILC_MASK, 12, 4);
907 if (hToolbarImgList == NULL)
908 return false;
909 int index = 0;
910 HICON hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_OVERLAP));
911 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
912 tbb[index].idCommand = ID_VIEW_OVERLAPIMAGES;
913 tbb[index].fsState = TBSTATE_ENABLED;
914 tbb[index].fsStyle = BTNS_BUTTON;
915 tbb[index].dwData = 0;
916 tbb[index++].iString = 0;
918 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_BLEND));
919 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
920 tbb[index].idCommand = ID_VIEW_BLENDALPHA;
921 tbb[index].fsState = 0;
922 tbb[index].fsStyle = BTNS_BUTTON;
923 tbb[index].dwData = 0;
924 tbb[index++].iString = 0;
926 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_LINK));
927 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
928 tbb[index].idCommand = ID_VIEW_LINKIMAGESTOGETHER;
929 tbb[index].fsState = TBSTATE_ENABLED | TBSTATE_CHECKED;
930 tbb[index].fsStyle = BTNS_BUTTON;
931 tbb[index].dwData = 0;
932 tbb[index++].iString = 0;
934 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITTOGETHER));
935 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
936 tbb[index].idCommand = ID_VIEW_FITTOGETHER;
937 tbb[index].fsState = TBSTATE_ENABLED;
938 tbb[index].fsStyle = BTNS_BUTTON;
939 tbb[index].dwData = 0;
940 tbb[index++].iString = 0;
942 tbb[index].iBitmap = 0;
943 tbb[index].idCommand = 0;
944 tbb[index].fsState = TBSTATE_ENABLED;
945 tbb[index].fsStyle = BTNS_SEP;
946 tbb[index].dwData = 0;
947 tbb[index++].iString = 0;
949 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_VERTICAL));
950 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
951 tbb[index].idCommand = ID_VIEW_ARRANGEVERTICAL;
952 tbb[index].fsState = TBSTATE_ENABLED;
953 tbb[index].fsStyle = BTNS_BUTTON;
954 tbb[index].dwData = 0;
955 tbb[index++].iString = 0;
957 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITINWINDOW));
958 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
959 tbb[index].idCommand = ID_VIEW_FITIMAGESINWINDOW;
960 tbb[index].fsState = TBSTATE_ENABLED;
961 tbb[index].fsStyle = BTNS_BUTTON;
962 tbb[index].dwData = 0;
963 tbb[index++].iString = 0;
965 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ORIGSIZE));
966 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
967 tbb[index].idCommand = ID_VIEW_ORININALSIZE;
968 tbb[index].fsState = TBSTATE_ENABLED;
969 tbb[index].fsStyle = BTNS_BUTTON;
970 tbb[index].dwData = 0;
971 tbb[index++].iString = 0;
973 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMIN));
974 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
975 tbb[index].idCommand = ID_VIEW_ZOOMIN;
976 tbb[index].fsState = TBSTATE_ENABLED;
977 tbb[index].fsStyle = BTNS_BUTTON;
978 tbb[index].dwData = 0;
979 tbb[index++].iString = 0;
981 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMOUT));
982 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
983 tbb[index].idCommand = ID_VIEW_ZOOMOUT;
984 tbb[index].fsState = TBSTATE_ENABLED;
985 tbb[index].fsStyle = BTNS_BUTTON;
986 tbb[index].dwData = 0;
987 tbb[index++].iString = 0;
989 tbb[index].iBitmap = 0;
990 tbb[index].idCommand = 0;
991 tbb[index].fsState = TBSTATE_ENABLED;
992 tbb[index].fsStyle = BTNS_SEP;
993 tbb[index].dwData = 0;
994 tbb[index++].iString = 0;
996 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_IMGINFO));
997 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
998 tbb[index].idCommand = ID_VIEW_IMAGEINFO;
999 tbb[index].fsState = TBSTATE_ENABLED;
1000 tbb[index].fsStyle = BTNS_BUTTON;
1001 tbb[index].dwData = 0;
1002 tbb[index++].iString = 0;
1004 SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)hToolbarImgList);
1005 SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM)index, (LPARAM) (LPTBBUTTON) &tbb);
1006 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
1007 ShowWindow(hwndTB, SW_SHOW);
1008 return true;