synced TortoiseIDiff with TortoiseSVN (rev. 22327)
[TortoiseGit.git] / src / TortoiseIDiff / MainWindow.cpp
blob5f79ed3eb0f02d69db32912188d3dcb4a2d7f264
1 // TortoiseIDiff - an image diff viewer in TortoiseSVN
3 // Copyright (C) 2006 - 2011 - 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 wcx.lpszClassName = ResString(hResource, IDS_APP_TITLE);
50 wcx.hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_TORTOISEIDIFF));
51 wcx.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
52 wcx.lpszMenuName = MAKEINTRESOURCE(IDC_TORTOISEIDIFF);
53 wcx.hIconSm = LoadIcon(wcx.hInstance, MAKEINTRESOURCE(IDI_TORTOISEIDIFF));
54 if (RegisterWindow(&wcx))
56 if (Create(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE, NULL))
58 UpdateWindow(m_hwnd);
59 return true;
62 return false;
65 void CMainWindow::PositionChildren(RECT * clientrect /* = NULL */)
67 RECT tbRect;
68 if (clientrect == NULL)
69 return;
70 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
71 GetWindowRect(hwndTB, &tbRect);
72 LONG tbHeight = tbRect.bottom-tbRect.top-1;
73 HDWP hdwp = BeginDeferWindowPos(2);
74 if (bOverlap)
76 SetWindowPos(picWindow1, NULL, clientrect->left, clientrect->top+tbHeight, clientrect->right-clientrect->left, clientrect->bottom-clientrect->top-tbHeight, SWP_SHOWWINDOW);
78 else
80 if (bVertical)
82 RECT child;
83 child.left = clientrect->left;
84 child.top = clientrect->top+tbHeight;
85 child.right = clientrect->right;
86 child.bottom = nSplitterPos-(SPLITTER_BORDER/2);
87 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
88 child.top = nSplitterPos+(SPLITTER_BORDER/2);
89 child.bottom = clientrect->bottom;
90 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
92 else
94 RECT child;
95 child.left = clientrect->left;
96 child.top = clientrect->top+tbHeight;
97 child.right = nSplitterPos-(SPLITTER_BORDER/2);
98 child.bottom = clientrect->bottom;
99 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
100 child.left = nSplitterPos+(SPLITTER_BORDER/2);
101 child.right = clientrect->right;
102 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
105 if (hdwp) EndDeferWindowPos(hdwp);
106 picWindow1.SetTransparentColor(transparentColor);
107 picWindow2.SetTransparentColor(transparentColor);
108 InvalidateRect(*this, NULL, FALSE);
111 LRESULT CALLBACK CMainWindow::WinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
113 if (uMsg == TaskBarButtonCreated)
115 SetUUIDOverlayIcon(hwnd);
117 switch (uMsg)
119 case WM_CREATE:
121 m_hwnd = hwnd;
122 picWindow1.RegisterAndCreateWindow(hwnd);
123 picWindow1.SetPic(leftpicpath, leftpictitle, true);
124 picWindow2.RegisterAndCreateWindow(hwnd);
125 picWindow2.SetPic(rightpicpath, rightpictitle, false);
127 picWindow1.SetOtherPicWindow(&picWindow2);
128 picWindow2.SetOtherPicWindow(&picWindow1);
129 // center the splitter
130 RECT rect;
131 GetClientRect(hwnd, &rect);
132 nSplitterPos = (rect.right-rect.left-SPLITTER_BORDER)/2;
133 CreateToolbar();
134 PositionChildren(&rect);
135 picWindow1.FitImageInWindow();
136 picWindow2.FitImageInWindow();
138 break;
139 case WM_COMMAND:
141 return DoCommand(LOWORD(wParam));
143 break;
144 case WM_PAINT:
146 PAINTSTRUCT ps;
147 HDC hdc;
148 RECT rect;
150 ::GetClientRect(*this, &rect);
151 hdc = BeginPaint(hwnd, &ps);
152 SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
153 ::ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
154 EndPaint(hwnd, &ps);
156 break;
157 case WM_GETMINMAXINFO:
159 MINMAXINFO * mmi = (MINMAXINFO*)lParam;
160 mmi->ptMinTrackSize.x = WINDOW_MINWIDTH;
161 mmi->ptMinTrackSize.y = WINDOW_MINHEIGHT;
162 return 0;
164 break;
165 case WM_SIZE:
167 RECT rect;
168 GetClientRect(hwnd, &rect);
169 if (bVertical)
171 RECT tbRect;
172 GetWindowRect(hwndTB, &tbRect);
173 LONG tbHeight = tbRect.bottom-tbRect.top-1;
174 nSplitterPos = (rect.bottom-rect.top-SPLITTER_BORDER+tbHeight)/2;
176 else
177 nSplitterPos = (rect.right-rect.left-SPLITTER_BORDER)/2;
178 PositionChildren(&rect);
180 break;
181 case WM_SETCURSOR:
183 if ((HWND)wParam == *this)
185 RECT rect;
186 POINT pt;
187 GetClientRect(*this, &rect);
188 GetCursorPos(&pt);
189 ScreenToClient(*this, &pt);
190 if (PtInRect(&rect, pt))
192 if (bVertical)
194 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENS));
195 SetCursor(hCur);
197 else
199 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE));
200 SetCursor(hCur);
202 return TRUE;
205 return DefWindowProc(hwnd, uMsg, wParam, lParam);
207 break;
208 case WM_LBUTTONDOWN:
209 Splitter_OnLButtonDown(hwnd, uMsg, wParam, lParam);
210 break;
211 case WM_LBUTTONUP:
212 Splitter_OnLButtonUp(hwnd, uMsg, wParam, lParam);
213 break;
214 case WM_CAPTURECHANGED:
215 Splitter_CaptureChanged();
216 break;
217 case WM_MOUSEMOVE:
218 Splitter_OnMouseMove(hwnd, uMsg, wParam, lParam);
219 break;
220 case WM_MOUSEWHEEL:
222 // find out if the mouse cursor is over one of the views, and if
223 // it is, pass the mouse wheel message to that view
224 POINT pt;
225 DWORD ptW = GetMessagePos();
226 pt.x = GET_X_LPARAM(ptW);
227 pt.y = GET_Y_LPARAM(ptW);
228 RECT rect;
229 GetWindowRect(picWindow1, &rect);
230 if (PtInRect(&rect, pt))
232 picWindow1.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
234 else
236 GetWindowRect(picWindow2, &rect);
237 if (PtInRect(&rect, pt))
239 picWindow2.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
243 break;
244 case WM_MOUSEHWHEEL:
246 // find out if the mouse cursor is over one of the views, and if
247 // it is, pass the mouse wheel message to that view
248 POINT pt;
249 DWORD ptW = GetMessagePos();
250 pt.x = GET_X_LPARAM(ptW);
251 pt.y = GET_Y_LPARAM(ptW);
252 RECT rect;
253 GetWindowRect(picWindow1, &rect);
254 if (PtInRect(&rect, pt))
256 picWindow1.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
258 else
260 GetWindowRect(picWindow2, &rect);
261 if (PtInRect(&rect, pt))
263 picWindow2.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
267 break;
268 case WM_NOTIFY:
270 LPNMHDR pNMHDR = (LPNMHDR)lParam;
271 if (pNMHDR->code == TTN_GETDISPINFO)
273 LPTOOLTIPTEXT lpttt;
275 lpttt = (LPTOOLTIPTEXT) lParam;
276 lpttt->hinst = hResource;
278 // Specify the resource identifier of the descriptive
279 // text for the given button.
280 TCHAR stringbuf[MAX_PATH] = {0};
281 MENUITEMINFO mii;
282 mii.cbSize = sizeof(MENUITEMINFO);
283 mii.fMask = MIIM_TYPE;
284 mii.dwTypeData = stringbuf;
285 mii.cch = _countof(stringbuf);
286 GetMenuItemInfo(GetMenu(*this), (UINT)lpttt->hdr.idFrom, FALSE, &mii);
287 _tcscpy_s(lpttt->lpszText, 80, stringbuf);
290 break;
291 case WM_DESTROY:
292 bWindowClosed = TRUE;
293 PostQuitMessage(0);
294 break;
295 case WM_CLOSE:
296 ImageList_Destroy(hToolbarImgList);
297 ::DestroyWindow(m_hwnd);
298 break;
299 default:
300 return DefWindowProc(hwnd, uMsg, wParam, lParam);
303 return 0;
306 LRESULT CMainWindow::DoCommand(int id)
308 switch (id)
310 case ID_FILE_OPEN:
312 if (OpenDialog())
314 picWindow1.SetPic(leftpicpath, _T(""), true);
315 picWindow2.SetPic(rightpicpath, _T(""), false);
316 if (bOverlap)
318 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath);
320 else
322 picWindow1.SetSecondPic();
324 RECT rect;
325 GetClientRect(*this, &rect);
326 PositionChildren(&rect);
327 picWindow1.FitImageInWindow();
328 picWindow2.FitImageInWindow();
331 break;
332 case ID_VIEW_IMAGEINFO:
334 bShowInfo = !bShowInfo;
335 HMENU hMenu = GetMenu(*this);
336 UINT uCheck = MF_BYCOMMAND;
337 uCheck |= bShowInfo ? MF_CHECKED : MF_UNCHECKED;
338 CheckMenuItem(hMenu, ID_VIEW_IMAGEINFO, uCheck);
340 picWindow1.ShowInfo(bShowInfo);
341 picWindow2.ShowInfo(bShowInfo);
343 // change the state of the toolbar button
344 TBBUTTONINFO tbi;
345 tbi.cbSize = sizeof(TBBUTTONINFO);
346 tbi.dwMask = TBIF_STATE;
347 tbi.fsState = bShowInfo ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
348 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_IMAGEINFO, (LPARAM)&tbi);
350 break;
351 case ID_VIEW_OVERLAPIMAGES:
353 bOverlap = !bOverlap;
354 HMENU hMenu = GetMenu(*this);
355 UINT uCheck = MF_BYCOMMAND;
356 uCheck |= bOverlap ? MF_CHECKED : MF_UNCHECKED;
357 CheckMenuItem(hMenu, ID_VIEW_OVERLAPIMAGES, uCheck);
358 uCheck |= (m_BlendType == CPicWindow::BLEND_ALPHA) ? MF_CHECKED : MF_UNCHECKED;
359 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
361 // change the state of the toolbar button
362 TBBUTTONINFO tbi;
363 tbi.cbSize = sizeof(TBBUTTONINFO);
364 tbi.dwMask = TBIF_STATE;
365 tbi.fsState = bOverlap ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
366 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_OVERLAPIMAGES, (LPARAM)&tbi);
368 tbi.fsState = (m_BlendType == CPicWindow::BLEND_ALPHA) ? TBSTATE_CHECKED : 0;
369 if (bOverlap)
370 tbi.fsState |= TBSTATE_ENABLED;
371 else
372 tbi.fsState = 0;
373 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
375 if (bOverlap)
376 tbi.fsState = 0;
377 else
378 tbi.fsState = bVertical ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
379 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
381 if (bOverlap)
382 tbi.fsState = 0;
383 else
384 tbi.fsState = bVertical ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
385 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
387 ShowWindow(picWindow2, bOverlap ? SW_HIDE : SW_SHOW);
389 if (bOverlap)
391 picWindow1.StopTimer();
392 picWindow2.StopTimer();
393 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath,
394 picWindow2.GetHPos(), picWindow2.GetVPos());
395 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
397 else
399 picWindow1.SetSecondPic();
401 picWindow1.SetOverlapMode(bOverlap);
402 picWindow2.SetOverlapMode(bOverlap);
405 RECT rect;
406 GetClientRect(*this, &rect);
407 PositionChildren(&rect);
409 return 0;
411 break;
412 case ID_VIEW_BLENDALPHA:
414 if (m_BlendType == CPicWindow::BLEND_ALPHA)
415 m_BlendType = CPicWindow::BLEND_XOR;
416 else
417 m_BlendType = CPicWindow::BLEND_ALPHA;
419 HMENU hMenu = GetMenu(*this);
420 UINT uCheck = MF_BYCOMMAND;
421 uCheck |= (m_BlendType == CPicWindow::BLEND_ALPHA) ? MF_CHECKED : MF_UNCHECKED;
422 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
424 // change the state of the toolbar button
425 TBBUTTONINFO tbi;
426 tbi.cbSize = sizeof(TBBUTTONINFO);
427 tbi.dwMask = TBIF_STATE;
428 tbi.fsState = (m_BlendType == CPicWindow::BLEND_ALPHA) ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
429 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
430 picWindow1.SetBlendAlpha(m_BlendType, picWindow1.GetBlendAlpha());
431 PositionChildren();
433 break;
434 case ID_VIEW_TRANSPARENTCOLOR:
436 static COLORREF customColors[16] = {0};
437 CHOOSECOLOR ccDlg;
438 memset(&ccDlg, 0, sizeof(ccDlg));
439 ccDlg.lStructSize = sizeof(ccDlg);
440 ccDlg.hwndOwner = m_hwnd;
441 ccDlg.rgbResult = transparentColor;
442 ccDlg.lpCustColors = customColors;
443 ccDlg.Flags = CC_RGBINIT | CC_FULLOPEN;
444 if(ChooseColor(&ccDlg))
446 transparentColor = ccDlg.rgbResult;
447 picWindow1.SetTransparentColor(transparentColor);
448 picWindow2.SetTransparentColor(transparentColor);
449 // The color picker takes the focus and we don't get it back.
450 ::SetFocus(picWindow1);
453 break;
454 case ID_VIEW_FITTOGETHER:
456 bFitSizes = !bFitSizes;
457 picWindow1.FitSizes(bFitSizes);
458 picWindow2.FitSizes(bFitSizes);
460 HMENU hMenu = GetMenu(*this);
461 UINT uCheck = MF_BYCOMMAND;
462 uCheck |= bFitSizes ? MF_CHECKED : MF_UNCHECKED;
463 CheckMenuItem(hMenu, ID_VIEW_FITTOGETHER, uCheck);
465 // change the state of the toolbar button
466 TBBUTTONINFO tbi;
467 tbi.cbSize = sizeof(TBBUTTONINFO);
468 tbi.dwMask = TBIF_STATE;
469 tbi.fsState = bFitSizes ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
470 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_FITTOGETHER, (LPARAM)&tbi);
472 break;
473 case ID_VIEW_LINKIMAGESTOGETHER:
475 bLinkedPositions = !bLinkedPositions;
476 picWindow1.LinkPositions(bLinkedPositions);
477 picWindow2.LinkPositions(bLinkedPositions);
479 HMENU hMenu = GetMenu(*this);
480 UINT uCheck = MF_BYCOMMAND;
481 uCheck |= bLinkedPositions ? MF_CHECKED : MF_UNCHECKED;
482 CheckMenuItem(hMenu, ID_VIEW_LINKIMAGESTOGETHER, uCheck);
484 // change the state of the toolbar button
485 TBBUTTONINFO tbi;
486 tbi.cbSize = sizeof(TBBUTTONINFO);
487 tbi.dwMask = TBIF_STATE;
488 tbi.fsState = bLinkedPositions ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
489 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
491 break;
492 case ID_VIEW_ALPHA0:
493 picWindow1.SetBlendAlpha(m_BlendType, 0.0f);
494 break;
495 case ID_VIEW_ALPHA255:
496 picWindow1.SetBlendAlpha(m_BlendType, 1.0f);
497 break;
498 case ID_VIEW_ALPHA127:
499 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
500 break;
501 case ID_VIEW_ALPHATOGGLE:
502 picWindow1.ToggleAlpha();
503 break;
504 case ID_VIEW_FITIMAGESINWINDOW:
506 picWindow1.FitImageInWindow();
507 picWindow2.FitImageInWindow();
509 break;
510 case ID_VIEW_ORININALSIZE:
512 picWindow1.SetZoom(1.0, false);
513 picWindow2.SetZoom(1.0, false);
515 break;
516 case ID_VIEW_ZOOMIN:
518 picWindow1.Zoom(true, false);
519 if ((!bFitSizes)&&(!bOverlap))
520 picWindow2.Zoom(true, false);
522 break;
523 case ID_VIEW_ZOOMOUT:
525 picWindow1.Zoom(false, false);
526 if ((!bFitSizes)&&(!bOverlap))
527 picWindow2.Zoom(false, false);
529 break;
530 case ID_VIEW_ARRANGEVERTICAL:
532 bVertical = !bVertical;
533 RECT rect;
534 GetClientRect(*this, &rect);
535 if (bVertical)
537 RECT tbRect;
538 GetWindowRect(hwndTB, &tbRect);
539 LONG tbHeight = tbRect.bottom-tbRect.top-1;
540 nSplitterPos = (rect.bottom-rect.top-SPLITTER_BORDER+tbHeight)/2;
542 else
544 nSplitterPos = (rect.right-rect.left-SPLITTER_BORDER)/2;
546 HMENU hMenu = GetMenu(*this);
547 UINT uCheck = MF_BYCOMMAND;
548 uCheck |= bVertical ? MF_CHECKED : MF_UNCHECKED;
549 CheckMenuItem(hMenu, ID_VIEW_ARRANGEVERTICAL, uCheck);
550 // change the state of the toolbar button
551 TBBUTTONINFO tbi;
552 tbi.cbSize = sizeof(TBBUTTONINFO);
553 tbi.dwMask = TBIF_STATE;
554 tbi.fsState = bVertical ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
555 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
557 PositionChildren(&rect);
559 break;
560 case ID_ABOUT:
562 CAboutDlg dlg(*this);
563 dlg.DoModal(hInst, IDD_ABOUT, *this);
565 break;
566 case IDM_EXIT:
567 ::PostQuitMessage(0);
568 return 0;
569 break;
570 default:
571 break;
573 return 1;
576 // splitter stuff
577 void CMainWindow::DrawXorBar(HDC hdc, int x1, int y1, int width, int height)
579 static WORD _dotPatternBmp[8] =
581 0x0055, 0x00aa, 0x0055, 0x00aa,
582 0x0055, 0x00aa, 0x0055, 0x00aa
585 HBITMAP hbm;
586 HBRUSH hbr, hbrushOld;
588 hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
589 hbr = CreatePatternBrush(hbm);
591 SetBrushOrgEx(hdc, x1, y1, 0);
592 hbrushOld = (HBRUSH)SelectObject(hdc, hbr);
594 PatBlt(hdc, x1, y1, width, height, PATINVERT);
596 SelectObject(hdc, hbrushOld);
598 DeleteObject(hbr);
599 DeleteObject(hbm);
602 LRESULT CMainWindow::Splitter_OnLButtonDown(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
604 POINT pt;
605 HDC hdc;
606 RECT rect;
607 RECT clientrect;
609 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
610 pt.y = (short)HIWORD(lParam);
612 GetClientRect(hwnd, &clientrect);
613 GetWindowRect(hwnd, &rect);
614 POINT zero = {0,0};
615 ClientToScreen(hwnd, &zero);
616 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
618 //convert the mouse coordinates relative to the top-left of
619 //the window
620 ClientToScreen(hwnd, &pt);
621 pt.x -= rect.left;
622 pt.y -= rect.top;
624 //same for the window coordinates - make them relative to 0,0
625 OffsetRect(&rect, -rect.left, -rect.top);
627 if (pt.x < 0)
628 pt.x = 0;
629 if (pt.x > rect.right-4)
630 pt.x = rect.right-4;
631 if (pt.y < 0)
632 pt.y = 0;
633 if (pt.y > rect.bottom-4)
634 pt.y = rect.bottom-4;
636 bDragMode = true;
638 SetCapture(hwnd);
640 hdc = GetWindowDC(hwnd);
641 if (bVertical)
642 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
643 else
644 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
645 ReleaseDC(hwnd, hdc);
647 oldx = pt.x;
648 oldy = pt.y;
650 return 0;
653 void CMainWindow::Splitter_CaptureChanged()
655 bDragMode = false;
658 LRESULT CMainWindow::Splitter_OnLButtonUp(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
660 HDC hdc;
661 RECT rect;
662 RECT clientrect;
664 POINT pt;
665 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
666 pt.y = (short)HIWORD(lParam);
668 if (bDragMode == FALSE)
669 return 0;
671 GetClientRect(hwnd, &clientrect);
672 GetWindowRect(hwnd, &rect);
673 POINT zero = {0,0};
674 ClientToScreen(hwnd, &zero);
675 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
677 ClientToScreen(hwnd, &pt);
678 pt.x -= rect.left;
679 pt.y -= rect.top;
681 OffsetRect(&rect, -rect.left, -rect.top);
683 if (pt.x < 0)
684 pt.x = 0;
685 if (pt.x > rect.right-4)
686 pt.x = rect.right-4;
687 if (pt.y < 0)
688 pt.y = 0;
689 if (pt.y > rect.bottom-4)
690 pt.y = rect.bottom-4;
692 hdc = GetWindowDC(hwnd);
693 if (bVertical)
694 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
695 else
696 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
697 ReleaseDC(hwnd, hdc);
699 oldx = pt.x;
700 oldy = pt.y;
702 bDragMode = false;
704 //convert the splitter position back to screen coords.
705 GetWindowRect(hwnd, &rect);
706 pt.x += rect.left;
707 pt.y += rect.top;
709 //now convert into CLIENT coordinates
710 ScreenToClient(hwnd, &pt);
711 GetClientRect(hwnd, &rect);
712 if (bVertical)
713 nSplitterPos = pt.y;
714 else
715 nSplitterPos = pt.x;
717 ReleaseCapture();
719 //position the child controls
720 PositionChildren(&rect);
721 return 0;
724 LRESULT CMainWindow::Splitter_OnMouseMove(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
726 HDC hdc;
727 RECT rect;
728 RECT clientrect;
730 POINT pt;
732 if (bDragMode == FALSE)
733 return 0;
735 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
736 pt.y = (short)HIWORD(lParam);
738 GetClientRect(hwnd, &clientrect);
739 GetWindowRect(hwnd, &rect);
740 POINT zero = {0,0};
741 ClientToScreen(hwnd, &zero);
742 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
744 //convert the mouse coordinates relative to the top-left of
745 //the window
746 ClientToScreen(hwnd, &pt);
747 pt.x -= rect.left;
748 pt.y -= rect.top;
750 //same for the window coordinates - make them relative to 0,0
751 OffsetRect(&rect, -rect.left, -rect.top);
753 if (pt.x < 0)
754 pt.x = 0;
755 if (pt.x > rect.right-4)
756 pt.x = rect.right-4;
757 if (pt.y < 0)
758 pt.y = 0;
759 if (pt.y > rect.bottom-4)
760 pt.y = rect.bottom-4;
762 if ((wParam & MK_LBUTTON) && ((bVertical && (pt.y != oldy)) || (!bVertical && (pt.x != oldx))))
764 hdc = GetWindowDC(hwnd);
766 if (bVertical)
768 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
769 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
771 else
773 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
774 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
777 ReleaseDC(hwnd, hdc);
779 oldx = pt.x;
780 oldy = pt.y;
783 return 0;
786 bool CMainWindow::OpenDialog()
788 return (DialogBox(hResource, MAKEINTRESOURCE(IDD_OPEN), *this, (DLGPROC)OpenDlgProc)==IDOK);
791 BOOL CALLBACK CMainWindow::OpenDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
793 switch (message)
795 case WM_INITDIALOG:
797 // center on the parent window
798 HWND hParentWnd = ::GetParent(hwndDlg);
799 RECT parentrect, childrect, centeredrect;
800 GetWindowRect(hParentWnd, &parentrect);
801 GetWindowRect(hwndDlg, &childrect);
802 centeredrect.left = parentrect.left + ((parentrect.right-parentrect.left-childrect.right+childrect.left)/2);
803 centeredrect.right = centeredrect.left + (childrect.right-childrect.left);
804 centeredrect.top = parentrect.top + ((parentrect.bottom-parentrect.top-childrect.bottom+childrect.top)/2);
805 centeredrect.bottom = centeredrect.top + (childrect.bottom-childrect.top);
806 SetWindowPos(hwndDlg, NULL, centeredrect.left, centeredrect.top, centeredrect.right-centeredrect.left, centeredrect.bottom-centeredrect.top, SWP_SHOWWINDOW);
808 if (leftpicpath.size())
809 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, leftpicpath.c_str());
810 SetFocus(hwndDlg);
812 break;
813 case WM_COMMAND:
814 switch (LOWORD(wParam))
816 case IDC_LEFTBROWSE:
818 TCHAR path[MAX_PATH] = {0};
819 if (AskForFile(hwndDlg, path))
821 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path);
824 break;
825 case IDC_RIGHTBROWSE:
827 TCHAR path[MAX_PATH] = {0};
828 if (AskForFile(hwndDlg, path))
830 SetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path);
833 break;
834 case IDOK:
836 TCHAR path[MAX_PATH];
837 if (!GetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path, _countof(path)))
838 *path = 0;
839 leftpicpath = path;
840 if (!GetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path, _countof(path)))
841 *path = 0;
842 rightpicpath = path;
844 // Fall through.
845 case IDCANCEL:
846 EndDialog(hwndDlg, wParam);
847 return TRUE;
850 return FALSE;
853 bool CMainWindow::AskForFile(HWND owner, TCHAR * path)
855 OPENFILENAME ofn = {0}; // common dialog box structure
856 // Initialize OPENFILENAME
857 ofn.lStructSize = sizeof(OPENFILENAME);
858 ofn.hwndOwner = owner;
859 ofn.lpstrFile = path;
860 ofn.nMaxFile = MAX_PATH;
861 ofn.lpstrTitle = ResString(::hResource, IDS_OPENIMAGEFILE);
862 ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_EXPLORER;
863 ofn.hInstance = ::hResource;
864 TCHAR filters[] = _T("Images\0*.wmf;*.jpg;*jpeg;*.bmp;*.gif;*.png;*.ico;*.dib;*.emf\0All (*.*)\0*.*\0\0");
865 ofn.lpstrFilter = filters;
866 ofn.nFilterIndex = 1;
867 // Display the Open dialog box.
868 if (GetOpenFileName(&ofn)==FALSE)
870 return false;
872 return true;
875 bool CMainWindow::CreateToolbar()
877 // Ensure that the common control DLL is loaded.
878 INITCOMMONCONTROLSEX icex;
879 icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
880 icex.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES;
881 InitCommonControlsEx(&icex);
883 hwndTB = CreateWindowEx(0,
884 TOOLBARCLASSNAME,
885 (LPCTSTR)NULL,
886 WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
887 0, 0, 0, 0,
888 *this,
889 (HMENU)IDC_TORTOISEIDIFF,
890 hResource,
891 NULL);
892 if (hwndTB == INVALID_HANDLE_VALUE)
893 return false;
895 SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
897 TBBUTTON tbb[12];
898 // create an imagelist containing the icons for the toolbar
899 hToolbarImgList = ImageList_Create(24, 24, ILC_COLOR32 | ILC_MASK, 12, 4);
900 if (hToolbarImgList == NULL)
901 return false;
902 int index = 0;
903 HICON hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_OVERLAP));
904 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
905 tbb[index].idCommand = ID_VIEW_OVERLAPIMAGES;
906 tbb[index].fsState = TBSTATE_ENABLED;
907 tbb[index].fsStyle = BTNS_BUTTON;
908 tbb[index].dwData = 0;
909 tbb[index++].iString = 0;
911 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_BLEND));
912 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
913 tbb[index].idCommand = ID_VIEW_BLENDALPHA;
914 tbb[index].fsState = 0;
915 tbb[index].fsStyle = BTNS_BUTTON;
916 tbb[index].dwData = 0;
917 tbb[index++].iString = 0;
919 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_LINK));
920 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
921 tbb[index].idCommand = ID_VIEW_LINKIMAGESTOGETHER;
922 tbb[index].fsState = TBSTATE_ENABLED | TBSTATE_CHECKED;
923 tbb[index].fsStyle = BTNS_BUTTON;
924 tbb[index].dwData = 0;
925 tbb[index++].iString = 0;
927 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITTOGETHER));
928 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
929 tbb[index].idCommand = ID_VIEW_FITTOGETHER;
930 tbb[index].fsState = TBSTATE_ENABLED;
931 tbb[index].fsStyle = BTNS_BUTTON;
932 tbb[index].dwData = 0;
933 tbb[index++].iString = 0;
935 tbb[index].iBitmap = 0;
936 tbb[index].idCommand = 0;
937 tbb[index].fsState = TBSTATE_ENABLED;
938 tbb[index].fsStyle = BTNS_SEP;
939 tbb[index].dwData = 0;
940 tbb[index++].iString = 0;
942 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_VERTICAL));
943 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
944 tbb[index].idCommand = ID_VIEW_ARRANGEVERTICAL;
945 tbb[index].fsState = TBSTATE_ENABLED;
946 tbb[index].fsStyle = BTNS_BUTTON;
947 tbb[index].dwData = 0;
948 tbb[index++].iString = 0;
950 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITINWINDOW));
951 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
952 tbb[index].idCommand = ID_VIEW_FITIMAGESINWINDOW;
953 tbb[index].fsState = TBSTATE_ENABLED;
954 tbb[index].fsStyle = BTNS_BUTTON;
955 tbb[index].dwData = 0;
956 tbb[index++].iString = 0;
958 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ORIGSIZE));
959 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
960 tbb[index].idCommand = ID_VIEW_ORININALSIZE;
961 tbb[index].fsState = TBSTATE_ENABLED;
962 tbb[index].fsStyle = BTNS_BUTTON;
963 tbb[index].dwData = 0;
964 tbb[index++].iString = 0;
966 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMIN));
967 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
968 tbb[index].idCommand = ID_VIEW_ZOOMIN;
969 tbb[index].fsState = TBSTATE_ENABLED;
970 tbb[index].fsStyle = BTNS_BUTTON;
971 tbb[index].dwData = 0;
972 tbb[index++].iString = 0;
974 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMOUT));
975 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
976 tbb[index].idCommand = ID_VIEW_ZOOMOUT;
977 tbb[index].fsState = TBSTATE_ENABLED;
978 tbb[index].fsStyle = BTNS_BUTTON;
979 tbb[index].dwData = 0;
980 tbb[index++].iString = 0;
982 tbb[index].iBitmap = 0;
983 tbb[index].idCommand = 0;
984 tbb[index].fsState = TBSTATE_ENABLED;
985 tbb[index].fsStyle = BTNS_SEP;
986 tbb[index].dwData = 0;
987 tbb[index++].iString = 0;
989 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_IMGINFO));
990 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
991 tbb[index].idCommand = ID_VIEW_IMAGEINFO;
992 tbb[index].fsState = TBSTATE_ENABLED;
993 tbb[index].fsStyle = BTNS_BUTTON;
994 tbb[index].dwData = 0;
995 tbb[index++].iString = 0;
997 SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)hToolbarImgList);
998 SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM)index, (LPARAM) (LPTBBUTTON) &tbb);
999 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
1000 ShowWindow(hwndTB, SW_SHOW);
1001 return true;