Fixed issue #157: SVN Rebase doesn't fast-forward
[TortoiseGit.git] / src / TortoiseIDiff / MainWindow.cpp
blobe722a6a56e157b47637c369ebb07427e39e90d12
1 // TortoiseIDiff - an image diff viewer in TortoiseSVN
3 // Copyright (C) 2006 - 2009 - 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"
26 #pragma comment(lib, "comctl32.lib")
28 tstring CMainWindow::leftpicpath;
29 tstring CMainWindow::leftpictitle;
31 tstring CMainWindow::rightpicpath;
32 tstring CMainWindow::rightpictitle;
34 bool CMainWindow::RegisterAndCreateWindow()
36 WNDCLASSEX wcx;
38 // Fill in the window class structure with default parameters
39 wcx.cbSize = sizeof(WNDCLASSEX);
40 wcx.style = CS_HREDRAW | CS_VREDRAW;
41 wcx.lpfnWndProc = CWindow::stWinMsgHandler;
42 wcx.cbClsExtra = 0;
43 wcx.cbWndExtra = 0;
44 wcx.hInstance = hResource;
45 wcx.hCursor = LoadCursor(NULL, IDC_SIZEWE);
46 wcx.lpszClassName = ResString(hResource, IDS_APP_TITLE);
47 wcx.hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_TORTOISEIDIFF));
48 wcx.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
49 wcx.lpszMenuName = MAKEINTRESOURCE(IDC_TORTOISEIDIFF);
50 wcx.hIconSm = LoadIcon(wcx.hInstance, MAKEINTRESOURCE(IDI_TORTOISEIDIFF));
51 if (RegisterWindow(&wcx))
53 if (Create(WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE, NULL))
55 ShowWindow(m_hwnd, SW_SHOW);
56 UpdateWindow(m_hwnd);
57 return true;
60 return false;
63 void CMainWindow::PositionChildren(RECT * clientrect /* = NULL */)
65 RECT tbRect;
66 if (clientrect == NULL)
67 return;
68 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
69 GetWindowRect(hwndTB, &tbRect);
70 LONG tbHeight = tbRect.bottom-tbRect.top-1;
71 HDWP hdwp = BeginDeferWindowPos(2);
72 if (bOverlap)
74 SetWindowPos(picWindow1, NULL, clientrect->left, clientrect->top+tbHeight, clientrect->right-clientrect->left, clientrect->bottom-clientrect->top-tbHeight, SWP_SHOWWINDOW);
76 else
78 if (bVertical)
80 RECT child;
81 child.left = clientrect->left;
82 child.top = clientrect->top+tbHeight;
83 child.right = clientrect->right;
84 child.bottom = nSplitterPos-(SPLITTER_BORDER/2);
85 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
86 child.top = nSplitterPos+(SPLITTER_BORDER/2);
87 child.bottom = clientrect->bottom;
88 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
90 else
92 RECT child;
93 child.left = clientrect->left;
94 child.top = clientrect->top+tbHeight;
95 child.right = nSplitterPos-(SPLITTER_BORDER/2);
96 child.bottom = clientrect->bottom;
97 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow1, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
98 child.left = nSplitterPos+(SPLITTER_BORDER/2);
99 child.right = clientrect->right;
100 if (hdwp) hdwp = DeferWindowPos(hdwp, picWindow2, NULL, child.left, child.top, child.right-child.left, child.bottom-child.top, SWP_FRAMECHANGED|SWP_SHOWWINDOW);
103 if (hdwp) EndDeferWindowPos(hdwp);
104 picWindow1.SetTransparentColor(transparentColor);
105 picWindow2.SetTransparentColor(transparentColor);
106 InvalidateRect(*this, NULL, FALSE);
109 LRESULT CALLBACK CMainWindow::WinMsgHandler(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
111 switch (uMsg)
113 case WM_CREATE:
115 m_hwnd = hwnd;
116 picWindow1.RegisterAndCreateWindow(hwnd);
117 picWindow1.SetPic(leftpicpath, leftpictitle, true);
118 picWindow2.RegisterAndCreateWindow(hwnd);
119 picWindow2.SetPic(rightpicpath, rightpictitle, false);
121 picWindow1.SetOtherPicWindow(&picWindow2);
122 picWindow2.SetOtherPicWindow(&picWindow1);
123 // center the splitter
124 RECT rect;
125 GetClientRect(hwnd, &rect);
126 nSplitterPos = (rect.right-rect.left-SPLITTER_BORDER)/2;
127 CreateToolbar();
128 PositionChildren(&rect);
129 picWindow1.FitImageInWindow();
130 picWindow2.FitImageInWindow();
132 break;
133 case WM_COMMAND:
135 return DoCommand(LOWORD(wParam));
137 break;
138 case WM_PAINT:
140 PAINTSTRUCT ps;
141 HDC hdc;
142 RECT rect;
144 ::GetClientRect(*this, &rect);
145 hdc = BeginPaint(hwnd, &ps);
146 SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
147 ::ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
148 EndPaint(hwnd, &ps);
150 break;
151 case WM_GETMINMAXINFO:
153 MINMAXINFO * mmi = (MINMAXINFO*)lParam;
154 mmi->ptMinTrackSize.x = WINDOW_MINWIDTH;
155 mmi->ptMinTrackSize.y = WINDOW_MINHEIGHT;
156 return 0;
158 break;
159 case WM_SIZE:
161 RECT rect;
162 GetClientRect(hwnd, &rect);
163 if (bVertical)
165 RECT tbRect;
166 GetWindowRect(hwndTB, &tbRect);
167 LONG tbHeight = tbRect.bottom-tbRect.top-1;
168 nSplitterPos = (rect.bottom-rect.top-SPLITTER_BORDER+tbHeight)/2;
170 else
171 nSplitterPos = (rect.right-rect.left-SPLITTER_BORDER)/2;
172 PositionChildren(&rect);
174 break;
175 case WM_SETCURSOR:
177 if ((HWND)wParam == *this)
179 RECT rect;
180 POINT pt;
181 GetClientRect(*this, &rect);
182 GetCursorPos(&pt);
183 ScreenToClient(*this, &pt);
184 if (PtInRect(&rect, pt))
186 if (bVertical)
188 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENS));
189 SetCursor(hCur);
191 else
193 HCURSOR hCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE));
194 SetCursor(hCur);
196 return TRUE;
199 return DefWindowProc(hwnd, uMsg, wParam, lParam);
201 break;
202 case WM_LBUTTONDOWN:
203 Splitter_OnLButtonDown(hwnd, uMsg, wParam, lParam);
204 break;
205 case WM_LBUTTONUP:
206 Splitter_OnLButtonUp(hwnd, uMsg, wParam, lParam);
207 break;
208 case WM_MOUSEMOVE:
209 Splitter_OnMouseMove(hwnd, uMsg, wParam, lParam);
210 break;
211 case WM_MOUSEWHEEL:
213 // find out if the mouse cursor is over one of the views, and if
214 // it is, pass the mouse wheel message to that view
215 POINT pt;
216 DWORD ptW = GetMessagePos();
217 pt.x = GET_X_LPARAM(ptW);
218 pt.y = GET_Y_LPARAM(ptW);
219 RECT rect;
220 GetWindowRect(picWindow1, &rect);
221 if (PtInRect(&rect, pt))
223 picWindow1.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
225 else
227 GetWindowRect(picWindow2, &rect);
228 if (PtInRect(&rect, pt))
230 picWindow2.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));
234 break;
235 case WM_MOUSEHWHEEL:
237 // find out if the mouse cursor is over one of the views, and if
238 // it is, pass the mouse wheel message to that view
239 POINT pt;
240 DWORD ptW = GetMessagePos();
241 pt.x = GET_X_LPARAM(ptW);
242 pt.y = GET_Y_LPARAM(ptW);
243 RECT rect;
244 GetWindowRect(picWindow1, &rect);
245 if (PtInRect(&rect, pt))
247 picWindow1.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
249 else
251 GetWindowRect(picWindow2, &rect);
252 if (PtInRect(&rect, pt))
254 picWindow2.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam)|MK_SHIFT, GET_WHEEL_DELTA_WPARAM(wParam));
258 break;
259 case WM_NOTIFY:
261 LPNMHDR pNMHDR = (LPNMHDR)lParam;
262 if (pNMHDR->code == TTN_GETDISPINFO)
264 LPTOOLTIPTEXT lpttt;
266 lpttt = (LPTOOLTIPTEXT) lParam;
267 lpttt->hinst = hResource;
269 // Specify the resource identifier of the descriptive
270 // text for the given button.
271 TCHAR stringbuf[MAX_PATH] = {0};
272 MENUITEMINFO mii;
273 mii.cbSize = sizeof(MENUITEMINFO);
274 mii.fMask = MIIM_TYPE;
275 mii.dwTypeData = stringbuf;
276 mii.cch = sizeof(stringbuf)/sizeof(TCHAR);
277 GetMenuItemInfo(GetMenu(*this), (UINT)lpttt->hdr.idFrom, FALSE, &mii);
278 lpttt->lpszText = stringbuf;
281 break;
282 case WM_DESTROY:
283 bWindowClosed = TRUE;
284 PostQuitMessage(0);
285 break;
286 case WM_CLOSE:
287 ImageList_Destroy(hToolbarImgList);
288 ::DestroyWindow(m_hwnd);
289 break;
290 default:
291 return DefWindowProc(hwnd, uMsg, wParam, lParam);
294 return 0;
297 LRESULT CMainWindow::DoCommand(int id)
299 switch (id)
301 case ID_FILE_OPEN:
303 if (OpenDialog())
305 picWindow1.SetPic(leftpicpath, _T(""), true);
306 picWindow2.SetPic(rightpicpath, _T(""), false);
307 if (bOverlap)
309 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath);
311 else
313 picWindow1.SetSecondPic();
315 RECT rect;
316 GetClientRect(*this, &rect);
317 PositionChildren(&rect);
318 picWindow1.FitImageInWindow();
319 picWindow2.FitImageInWindow();
322 break;
323 case ID_VIEW_IMAGEINFO:
325 bShowInfo = !bShowInfo;
326 HMENU hMenu = GetMenu(*this);
327 UINT uCheck = MF_BYCOMMAND;
328 uCheck |= bShowInfo ? MF_CHECKED : MF_UNCHECKED;
329 CheckMenuItem(hMenu, ID_VIEW_IMAGEINFO, uCheck);
331 picWindow1.ShowInfo(bShowInfo);
332 picWindow2.ShowInfo(bShowInfo);
334 // change the state of the toolbar button
335 TBBUTTONINFO tbi;
336 tbi.cbSize = sizeof(TBBUTTONINFO);
337 tbi.dwMask = TBIF_STATE;
338 tbi.fsState = bShowInfo ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
339 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_IMAGEINFO, (LPARAM)&tbi);
341 break;
342 case ID_VIEW_OVERLAPIMAGES:
344 bOverlap = !bOverlap;
345 HMENU hMenu = GetMenu(*this);
346 UINT uCheck = MF_BYCOMMAND;
347 uCheck |= bOverlap ? MF_CHECKED : MF_UNCHECKED;
348 CheckMenuItem(hMenu, ID_VIEW_OVERLAPIMAGES, uCheck);
349 uCheck |= (m_BlendType == CPicWindow::BLEND_ALPHA) ? MF_CHECKED : MF_UNCHECKED;
350 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
352 // change the state of the toolbar button
353 TBBUTTONINFO tbi;
354 tbi.cbSize = sizeof(TBBUTTONINFO);
355 tbi.dwMask = TBIF_STATE;
356 tbi.fsState = bOverlap ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
357 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_OVERLAPIMAGES, (LPARAM)&tbi);
359 tbi.fsState = (m_BlendType == CPicWindow::BLEND_ALPHA) ? TBSTATE_CHECKED : 0;
360 if (bOverlap)
361 tbi.fsState |= TBSTATE_ENABLED;
362 else
363 tbi.fsState = 0;
364 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
366 if (bOverlap)
367 tbi.fsState = 0;
368 else
369 tbi.fsState = bVertical ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
370 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
372 ShowWindow(picWindow2, bOverlap ? SW_HIDE : SW_SHOW);
374 if (bOverlap)
376 picWindow1.StopTimer();
377 picWindow2.StopTimer();
378 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath,
379 picWindow2.GetHPos(), picWindow2.GetVPos());
380 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
382 else
384 picWindow1.SetSecondPic();
388 RECT rect;
389 GetClientRect(*this, &rect);
390 PositionChildren(&rect);
392 if ((bFitSizes)&&(bOverlap))
394 picWindow1.FitSizes(bFitSizes);
396 return 0;
398 break;
399 case ID_VIEW_BLENDALPHA:
401 if (m_BlendType == CPicWindow::BLEND_ALPHA)
402 m_BlendType = CPicWindow::BLEND_XOR;
403 else
404 m_BlendType = CPicWindow::BLEND_ALPHA;
406 HMENU hMenu = GetMenu(*this);
407 UINT uCheck = MF_BYCOMMAND;
408 uCheck |= (m_BlendType == CPicWindow::BLEND_ALPHA) ? MF_CHECKED : MF_UNCHECKED;
409 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
411 // change the state of the toolbar button
412 TBBUTTONINFO tbi;
413 tbi.cbSize = sizeof(TBBUTTONINFO);
414 tbi.dwMask = TBIF_STATE;
415 tbi.fsState = (m_BlendType == CPicWindow::BLEND_ALPHA) ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
416 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
417 picWindow1.SetBlendAlpha(m_BlendType, picWindow1.GetBlendAlpha());
418 PositionChildren();
420 break;
421 case ID_VIEW_TRANSPARENTCOLOR:
423 static COLORREF customColors[16] = {0};
424 CHOOSECOLOR ccDlg;
425 memset(&ccDlg, 0, sizeof(ccDlg));
426 ccDlg.lStructSize = sizeof(ccDlg);
427 ccDlg.hwndOwner = m_hwnd;
428 ccDlg.rgbResult = transparentColor;
429 ccDlg.lpCustColors = customColors;
430 ccDlg.Flags = CC_RGBINIT | CC_FULLOPEN;
431 if(ChooseColor(&ccDlg))
433 transparentColor = ccDlg.rgbResult;
434 picWindow1.SetTransparentColor(transparentColor);
435 picWindow2.SetTransparentColor(transparentColor);
436 // The color picker takes the focus and we don't get it back.
437 ::SetFocus(picWindow1);
440 break;
441 case ID_VIEW_FITTOGETHER:
443 bFitSizes = !bFitSizes;
444 picWindow1.FitSizes(bFitSizes);
445 picWindow2.FitSizes(bFitSizes);
447 HMENU hMenu = GetMenu(*this);
448 UINT uCheck = MF_BYCOMMAND;
449 uCheck |= bFitSizes ? MF_CHECKED : MF_UNCHECKED;
450 CheckMenuItem(hMenu, ID_VIEW_FITTOGETHER, uCheck);
452 // change the state of the toolbar button
453 TBBUTTONINFO tbi;
454 tbi.cbSize = sizeof(TBBUTTONINFO);
455 tbi.dwMask = TBIF_STATE;
456 tbi.fsState = bFitSizes ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
457 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_FITTOGETHER, (LPARAM)&tbi);
459 break;
460 case ID_VIEW_LINKIMAGESTOGETHER:
462 bLinkedPositions = !bLinkedPositions;
463 picWindow1.LinkPositions(bLinkedPositions);
464 picWindow2.LinkPositions(bLinkedPositions);
466 HMENU hMenu = GetMenu(*this);
467 UINT uCheck = MF_BYCOMMAND;
468 uCheck |= bLinkedPositions ? MF_CHECKED : MF_UNCHECKED;
469 CheckMenuItem(hMenu, ID_VIEW_LINKIMAGESTOGETHER, 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 = bLinkedPositions ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
476 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
478 break;
479 case ID_VIEW_ALPHA0:
480 picWindow1.SetBlendAlpha(m_BlendType, 0.0f);
481 break;
482 case ID_VIEW_ALPHA255:
483 picWindow1.SetBlendAlpha(m_BlendType, 1.0f);
484 break;
485 case ID_VIEW_ALPHA127:
486 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
487 break;
488 case ID_VIEW_ALPHATOGGLE:
489 picWindow1.ToggleAlpha();
490 break;
491 case ID_VIEW_FITIMAGESINWINDOW:
493 picWindow1.FitImageInWindow();
494 picWindow2.FitImageInWindow();
496 break;
497 case ID_VIEW_ORININALSIZE:
499 picWindow1.SetZoom(1.0, false);
500 picWindow2.SetZoom(1.0, false);
502 break;
503 case ID_VIEW_ZOOMIN:
505 picWindow1.Zoom(true, false);
506 if (!bFitSizes)
507 picWindow2.Zoom(true, false);
509 break;
510 case ID_VIEW_ZOOMOUT:
512 picWindow1.Zoom(false, false);
513 if (!bFitSizes)
514 picWindow2.Zoom(false, false);
516 break;
517 case ID_VIEW_ARRANGEVERTICAL:
519 bVertical = !bVertical;
520 RECT rect;
521 GetClientRect(*this, &rect);
522 if (bVertical)
524 RECT tbRect;
525 GetWindowRect(hwndTB, &tbRect);
526 LONG tbHeight = tbRect.bottom-tbRect.top-1;
527 nSplitterPos = (rect.bottom-rect.top-SPLITTER_BORDER+tbHeight)/2;
529 else
531 nSplitterPos = (rect.right-rect.left-SPLITTER_BORDER)/2;
533 HMENU hMenu = GetMenu(*this);
534 UINT uCheck = MF_BYCOMMAND;
535 uCheck |= bVertical ? MF_CHECKED : MF_UNCHECKED;
536 CheckMenuItem(hMenu, ID_VIEW_ARRANGEVERTICAL, uCheck);
537 // change the state of the toolbar button
538 TBBUTTONINFO tbi;
539 tbi.cbSize = sizeof(TBBUTTONINFO);
540 tbi.dwMask = TBIF_STATE;
541 tbi.fsState = bVertical ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
542 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
544 PositionChildren(&rect);
546 break;
547 case ID_ABOUT:
549 CAboutDlg dlg(*this);
550 dlg.DoModal(hInst, IDD_ABOUT, *this);
552 break;
553 case IDM_EXIT:
554 ::PostQuitMessage(0);
555 return 0;
556 break;
557 default:
558 break;
560 return 1;
563 // splitter stuff
564 void CMainWindow::DrawXorBar(HDC hdc, int x1, int y1, int width, int height)
566 static WORD _dotPatternBmp[8] =
568 0x0055, 0x00aa, 0x0055, 0x00aa,
569 0x0055, 0x00aa, 0x0055, 0x00aa
572 HBITMAP hbm;
573 HBRUSH hbr, hbrushOld;
575 hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
576 hbr = CreatePatternBrush(hbm);
578 SetBrushOrgEx(hdc, x1, y1, 0);
579 hbrushOld = (HBRUSH)SelectObject(hdc, hbr);
581 PatBlt(hdc, x1, y1, width, height, PATINVERT);
583 SelectObject(hdc, hbrushOld);
585 DeleteObject(hbr);
586 DeleteObject(hbm);
589 LRESULT CMainWindow::Splitter_OnLButtonDown(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
591 POINT pt;
592 HDC hdc;
593 RECT rect;
594 RECT clientrect;
596 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
597 pt.y = (short)HIWORD(lParam);
599 GetClientRect(hwnd, &clientrect);
600 GetWindowRect(hwnd, &rect);
601 POINT zero = {0,0};
602 ClientToScreen(hwnd, &zero);
603 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
605 //convert the mouse coordinates relative to the top-left of
606 //the window
607 ClientToScreen(hwnd, &pt);
608 pt.x -= rect.left;
609 pt.y -= rect.top;
611 //same for the window coordinates - make them relative to 0,0
612 OffsetRect(&rect, -rect.left, -rect.top);
614 if (pt.x < 0)
615 pt.x = 0;
616 if (pt.x > rect.right-4)
617 pt.x = rect.right-4;
618 if (pt.y < 0)
619 pt.y = 0;
620 if (pt.y > rect.bottom-4)
621 pt.y = rect.bottom-4;
623 bDragMode = true;
625 SetCapture(hwnd);
627 hdc = GetWindowDC(hwnd);
628 if (bVertical)
629 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
630 else
631 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
632 ReleaseDC(hwnd, hdc);
634 oldx = pt.x;
635 oldy = pt.y;
637 return 0;
641 LRESULT CMainWindow::Splitter_OnLButtonUp(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
643 HDC hdc;
644 RECT rect;
645 RECT clientrect;
647 POINT pt;
648 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
649 pt.y = (short)HIWORD(lParam);
651 if (bDragMode == FALSE)
652 return 0;
654 GetClientRect(hwnd, &clientrect);
655 GetWindowRect(hwnd, &rect);
656 POINT zero = {0,0};
657 ClientToScreen(hwnd, &zero);
658 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
660 ClientToScreen(hwnd, &pt);
661 pt.x -= rect.left;
662 pt.y -= rect.top;
664 OffsetRect(&rect, -rect.left, -rect.top);
666 if (pt.x < 0)
667 pt.x = 0;
668 if (pt.x > rect.right-4)
669 pt.x = rect.right-4;
670 if (pt.y < 0)
671 pt.y = 0;
672 if (pt.y > rect.bottom-4)
673 pt.y = rect.bottom-4;
675 hdc = GetWindowDC(hwnd);
676 if (bVertical)
677 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
678 else
679 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
680 ReleaseDC(hwnd, hdc);
682 oldx = pt.x;
683 oldy = pt.y;
685 bDragMode = false;
687 //convert the splitter position back to screen coords.
688 GetWindowRect(hwnd, &rect);
689 pt.x += rect.left;
690 pt.y += rect.top;
692 //now convert into CLIENT coordinates
693 ScreenToClient(hwnd, &pt);
694 GetClientRect(hwnd, &rect);
695 if (bVertical)
696 nSplitterPos = pt.y;
697 else
698 nSplitterPos = pt.x;
700 ReleaseCapture();
702 //position the child controls
703 PositionChildren(&rect);
704 return 0;
707 LRESULT CMainWindow::Splitter_OnMouseMove(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
709 HDC hdc;
710 RECT rect;
711 RECT clientrect;
713 POINT pt;
715 if (bDragMode == FALSE)
716 return 0;
718 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
719 pt.y = (short)HIWORD(lParam);
721 GetClientRect(hwnd, &clientrect);
722 GetWindowRect(hwnd, &rect);
723 POINT zero = {0,0};
724 ClientToScreen(hwnd, &zero);
725 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
727 //convert the mouse coordinates relative to the top-left of
728 //the window
729 ClientToScreen(hwnd, &pt);
730 pt.x -= rect.left;
731 pt.y -= rect.top;
733 //same for the window coordinates - make them relative to 0,0
734 OffsetRect(&rect, -rect.left, -rect.top);
736 if (pt.x < 0)
737 pt.x = 0;
738 if (pt.x > rect.right-4)
739 pt.x = rect.right-4;
740 if (pt.y < 0)
741 pt.y = 0;
742 if (pt.y > rect.bottom-4)
743 pt.y = rect.bottom-4;
745 if ((wParam & MK_LBUTTON) && ((bVertical && (pt.y != oldy)) || (!bVertical && (pt.x != oldx))))
747 hdc = GetWindowDC(hwnd);
749 if (bVertical)
751 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
752 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
754 else
756 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
757 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
760 ReleaseDC(hwnd, hdc);
762 oldx = pt.x;
763 oldy = pt.y;
766 return 0;
769 bool CMainWindow::OpenDialog()
771 return (DialogBox(hResource, MAKEINTRESOURCE(IDD_OPEN), *this, (DLGPROC)OpenDlgProc)==IDOK);
774 BOOL CALLBACK CMainWindow::OpenDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
776 switch (message)
778 case WM_INITDIALOG:
780 // center on the parent window
781 HWND hParentWnd = ::GetParent(hwndDlg);
782 RECT parentrect, childrect, centeredrect;
783 GetWindowRect(hParentWnd, &parentrect);
784 GetWindowRect(hwndDlg, &childrect);
785 centeredrect.left = parentrect.left + ((parentrect.right-parentrect.left-childrect.right+childrect.left)/2);
786 centeredrect.right = centeredrect.left + (childrect.right-childrect.left);
787 centeredrect.top = parentrect.top + ((parentrect.bottom-parentrect.top-childrect.bottom+childrect.top)/2);
788 centeredrect.bottom = centeredrect.top + (childrect.bottom-childrect.top);
789 SetWindowPos(hwndDlg, NULL, centeredrect.left, centeredrect.top, centeredrect.right-centeredrect.left, centeredrect.bottom-centeredrect.top, SWP_SHOWWINDOW);
790 SetFocus(hwndDlg);
792 break;
793 case WM_COMMAND:
794 switch (LOWORD(wParam))
796 case IDC_LEFTBROWSE:
798 TCHAR path[MAX_PATH] = {0};
799 if (AskForFile(hwndDlg, path))
801 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path);
804 break;
805 case IDC_RIGHTBROWSE:
807 TCHAR path[MAX_PATH] = {0};
808 if (AskForFile(hwndDlg, path))
810 SetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path);
813 break;
814 case IDOK:
816 TCHAR path[MAX_PATH];
817 if (!GetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path, MAX_PATH))
818 *path = 0;
819 leftpicpath = path;
820 if (!GetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path, MAX_PATH))
821 *path = 0;
822 rightpicpath = path;
824 // Fall through.
825 case IDCANCEL:
826 EndDialog(hwndDlg, wParam);
827 return TRUE;
830 return FALSE;
833 bool CMainWindow::AskForFile(HWND owner, TCHAR * path)
835 OPENFILENAME ofn = {0}; // common dialog box structure
836 // Initialize OPENFILENAME
837 ofn.lStructSize = sizeof(OPENFILENAME);
838 ofn.hwndOwner = owner;
839 ofn.lpstrFile = path;
840 ofn.nMaxFile = MAX_PATH;
841 ofn.lpstrTitle = ResString(::hResource, IDS_OPENIMAGEFILE);
842 ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_EXPLORER;
843 ofn.hInstance = ::hResource;
844 TCHAR filters[] = _T("Images\0*.wmf;*.jpg;*jpeg;*.bmp;*.gif;*.png;*.ico;*.dib;*.emf\0All (*.*)\0*.*\0\0");
845 ofn.lpstrFilter = filters;
846 ofn.nFilterIndex = 1;
847 // Display the Open dialog box.
848 if (GetOpenFileName(&ofn)==FALSE)
850 return false;
852 return true;
855 bool CMainWindow::CreateToolbar()
857 // Ensure that the common control DLL is loaded.
858 INITCOMMONCONTROLSEX icex;
859 icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
860 icex.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES;
861 InitCommonControlsEx(&icex);
863 hwndTB = CreateWindowEx(0,
864 TOOLBARCLASSNAME,
865 (LPCTSTR)NULL,
866 WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
867 0, 0, 0, 0,
868 *this,
869 (HMENU)IDC_TORTOISEIDIFF,
870 hResource,
871 NULL);
872 if (hwndTB == INVALID_HANDLE_VALUE)
873 return false;
875 SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
877 TBBUTTON tbb[12];
878 // create an imagelist containing the icons for the toolbar
879 hToolbarImgList = ImageList_Create(24, 24, ILC_COLOR32 | ILC_MASK, 12, 4);
880 if (hToolbarImgList == NULL)
881 return false;
882 int index = 0;
883 HICON hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_OVERLAP));
884 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
885 tbb[index].idCommand = ID_VIEW_OVERLAPIMAGES;
886 tbb[index].fsState = TBSTATE_ENABLED;
887 tbb[index].fsStyle = BTNS_BUTTON;
888 tbb[index].dwData = 0;
889 tbb[index++].iString = 0;
891 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_BLEND));
892 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
893 tbb[index].idCommand = ID_VIEW_BLENDALPHA;
894 tbb[index].fsState = 0;
895 tbb[index].fsStyle = BTNS_BUTTON;
896 tbb[index].dwData = 0;
897 tbb[index++].iString = 0;
899 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_LINK));
900 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
901 tbb[index].idCommand = ID_VIEW_LINKIMAGESTOGETHER;
902 tbb[index].fsState = TBSTATE_ENABLED | TBSTATE_CHECKED;
903 tbb[index].fsStyle = BTNS_BUTTON;
904 tbb[index].dwData = 0;
905 tbb[index++].iString = 0;
907 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITTOGETHER));
908 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
909 tbb[index].idCommand = ID_VIEW_FITTOGETHER;
910 tbb[index].fsState = TBSTATE_ENABLED;
911 tbb[index].fsStyle = BTNS_BUTTON;
912 tbb[index].dwData = 0;
913 tbb[index++].iString = 0;
915 tbb[index].iBitmap = 0;
916 tbb[index].idCommand = 0;
917 tbb[index].fsState = TBSTATE_ENABLED;
918 tbb[index].fsStyle = BTNS_SEP;
919 tbb[index].dwData = 0;
920 tbb[index++].iString = 0;
922 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_VERTICAL));
923 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
924 tbb[index].idCommand = ID_VIEW_ARRANGEVERTICAL;
925 tbb[index].fsState = TBSTATE_ENABLED;
926 tbb[index].fsStyle = BTNS_BUTTON;
927 tbb[index].dwData = 0;
928 tbb[index++].iString = 0;
930 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITINWINDOW));
931 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
932 tbb[index].idCommand = ID_VIEW_FITIMAGESINWINDOW;
933 tbb[index].fsState = TBSTATE_ENABLED;
934 tbb[index].fsStyle = BTNS_BUTTON;
935 tbb[index].dwData = 0;
936 tbb[index++].iString = 0;
938 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ORIGSIZE));
939 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
940 tbb[index].idCommand = ID_VIEW_ORININALSIZE;
941 tbb[index].fsState = TBSTATE_ENABLED;
942 tbb[index].fsStyle = BTNS_BUTTON;
943 tbb[index].dwData = 0;
944 tbb[index++].iString = 0;
946 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMIN));
947 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
948 tbb[index].idCommand = ID_VIEW_ZOOMIN;
949 tbb[index].fsState = TBSTATE_ENABLED;
950 tbb[index].fsStyle = BTNS_BUTTON;
951 tbb[index].dwData = 0;
952 tbb[index++].iString = 0;
954 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMOUT));
955 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
956 tbb[index].idCommand = ID_VIEW_ZOOMOUT;
957 tbb[index].fsState = TBSTATE_ENABLED;
958 tbb[index].fsStyle = BTNS_BUTTON;
959 tbb[index].dwData = 0;
960 tbb[index++].iString = 0;
962 tbb[index].iBitmap = 0;
963 tbb[index].idCommand = 0;
964 tbb[index].fsState = TBSTATE_ENABLED;
965 tbb[index].fsStyle = BTNS_SEP;
966 tbb[index].dwData = 0;
967 tbb[index++].iString = 0;
969 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_IMGINFO));
970 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
971 tbb[index].idCommand = ID_VIEW_IMAGEINFO;
972 tbb[index].fsState = TBSTATE_ENABLED;
973 tbb[index].fsStyle = BTNS_BUTTON;
974 tbb[index].dwData = 0;
975 tbb[index++].iString = 0;
977 SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)hToolbarImgList);
978 SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM)index, (LPARAM) (LPTBBUTTON) &tbb);
979 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
980 ShowWindow(hwndTB, SW_SHOW);
981 return true;