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.
22 #include "TortoiseIDiff.h"
23 #include "MainWindow.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()
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
;
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
))
66 void CMainWindow::PositionChildren(RECT
* clientrect
/* = NULL */)
69 if (clientrect
== NULL
)
71 SendMessage(hwndTB
, TB_AUTOSIZE
, 0, 0);
72 GetWindowRect(hwndTB
, &tbRect
);
73 LONG tbHeight
= tbRect
.bottom
-tbRect
.top
-1;
74 HDWP hdwp
= BeginDeferWindowPos(2);
77 SetWindowPos(picWindow1
, NULL
, clientrect
->left
, clientrect
->top
+tbHeight
, clientrect
->right
-clientrect
->left
, clientrect
->bottom
-clientrect
->top
-tbHeight
, SWP_SHOWWINDOW
);
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
);
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
);
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
);
131 // center the splitter
133 GetClientRect(hwnd
, &rect
);
134 nSplitterPos
= (rect
.right
-rect
.left
)/2;
135 PositionChildren(&rect
);
136 picWindow1
.FitImageInWindow();
137 picWindow2
.FitImageInWindow();
142 return DoCommand(LOWORD(wParam
));
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
);
158 case WM_GETMINMAXINFO
:
160 MINMAXINFO
* mmi
= (MINMAXINFO
*)lParam
;
161 mmi
->ptMinTrackSize
.x
= WINDOW_MINWIDTH
;
162 mmi
->ptMinTrackSize
.y
= WINDOW_MINHEIGHT
;
169 GetClientRect(hwnd
, &rect
);
173 GetWindowRect(hwndTB
, &tbRect
);
174 LONG tbHeight
= tbRect
.bottom
-tbRect
.top
-1;
175 nSplitterPos
= (rect
.bottom
-rect
.top
+tbHeight
)/2;
178 nSplitterPos
= (rect
.right
-rect
.left
)/2;
179 PositionChildren(&rect
);
184 if ((HWND
)wParam
== *this)
188 GetClientRect(*this, &rect
);
190 ScreenToClient(*this, &pt
);
191 if (PtInRect(&rect
, pt
))
195 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_SIZENS
));
200 HCURSOR hCur
= LoadCursor(NULL
, MAKEINTRESOURCE(IDC_SIZEWE
));
206 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
210 Splitter_OnLButtonDown(hwnd
, uMsg
, wParam
, lParam
);
213 Splitter_OnLButtonUp(hwnd
, uMsg
, wParam
, lParam
);
215 case WM_CAPTURECHANGED
:
216 Splitter_CaptureChanged();
219 Splitter_OnMouseMove(hwnd
, uMsg
, wParam
, lParam
);
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
226 DWORD ptW
= GetMessagePos();
227 pt
.x
= GET_X_LPARAM(ptW
);
228 pt
.y
= GET_Y_LPARAM(ptW
);
230 GetWindowRect(picWindow1
, &rect
);
231 if (PtInRect(&rect
, pt
))
233 picWindow1
.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam
), GET_WHEEL_DELTA_WPARAM(wParam
));
237 GetWindowRect(picWindow2
, &rect
);
238 if (PtInRect(&rect
, pt
))
240 picWindow2
.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam
), GET_WHEEL_DELTA_WPARAM(wParam
));
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
250 DWORD ptW
= GetMessagePos();
251 pt
.x
= GET_X_LPARAM(ptW
);
252 pt
.y
= GET_Y_LPARAM(ptW
);
254 GetWindowRect(picWindow1
, &rect
);
255 if (PtInRect(&rect
, pt
))
257 picWindow1
.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam
)|MK_SHIFT
, GET_WHEEL_DELTA_WPARAM(wParam
));
261 GetWindowRect(picWindow2
, &rect
);
262 if (PtInRect(&rect
, pt
))
264 picWindow2
.OnMouseWheel(GET_KEYSTATE_WPARAM(wParam
)|MK_SHIFT
, GET_WHEEL_DELTA_WPARAM(wParam
));
271 LPNMHDR pNMHDR
= (LPNMHDR
)lParam
;
272 if (pNMHDR
->code
== TTN_GETDISPINFO
)
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};
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
);
293 bWindowClosed
= TRUE
;
297 ImageList_Destroy(hToolbarImgList
);
298 ::DestroyWindow(m_hwnd
);
301 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
307 LRESULT
CMainWindow::DoCommand(int id
)
315 picWindow1
.SetPic(leftpicpath
, _T(""), true);
316 picWindow2
.SetPic(rightpicpath
, _T(""), false);
319 picWindow1
.SetSecondPic(picWindow2
.GetPic(), rightpictitle
, rightpicpath
);
323 picWindow1
.SetSecondPic();
326 GetClientRect(*this, &rect
);
327 PositionChildren(&rect
);
328 picWindow1
.FitImageInWindow();
329 picWindow2
.FitImageInWindow();
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
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
);
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
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;
371 tbi
.fsState
|= TBSTATE_ENABLED
;
374 SendMessage(hwndTB
, TB_SETBUTTONINFO
, ID_VIEW_BLENDALPHA
, (LPARAM
)&tbi
);
379 tbi
.fsState
= bVertical
? TBSTATE_ENABLED
| TBSTATE_CHECKED
: TBSTATE_ENABLED
;
380 SendMessage(hwndTB
, TB_SETBUTTONINFO
, ID_VIEW_ARRANGEVERTICAL
, (LPARAM
)&tbi
);
384 bLinkedPositions
= true;
385 picWindow1
.LinkPositions(bLinkedPositions
);
386 picWindow2
.LinkPositions(bLinkedPositions
);
387 tbi
.fsState
= TBSTATE_CHECKED
;
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
);
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
);
405 picWindow1
.SetSecondPic();
407 picWindow1
.SetOverlapMode(bOverlap
);
408 picWindow2
.SetOverlapMode(bOverlap
);
412 GetClientRect(*this, &rect
);
413 PositionChildren(&rect
);
418 case ID_VIEW_BLENDALPHA
:
420 if (m_BlendType
== CPicWindow::BLEND_ALPHA
)
421 m_BlendType
= CPicWindow::BLEND_XOR
;
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
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());
440 case ID_VIEW_TRANSPARENTCOLOR
:
442 static COLORREF customColors
[16] = {0};
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
);
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
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
);
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
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
);
499 picWindow1
.SetBlendAlpha(m_BlendType
, 0.0f
);
501 case ID_VIEW_ALPHA255
:
502 picWindow1
.SetBlendAlpha(m_BlendType
, 1.0f
);
504 case ID_VIEW_ALPHA127
:
505 picWindow1
.SetBlendAlpha(m_BlendType
, 0.5f
);
507 case ID_VIEW_ALPHATOGGLE
:
508 picWindow1
.ToggleAlpha();
510 case ID_VIEW_FITIMAGESINWINDOW
:
512 picWindow2
.FitImageInWindow();
513 picWindow1
.FitImageInWindow();
516 case ID_VIEW_ORININALSIZE
:
518 picWindow2
.SetZoom(1.0, false);
519 picWindow1
.SetZoom(1.0, false);
524 picWindow1
.Zoom(true, false);
525 if ((!bFitSizes
)&&(!bOverlap
))
526 picWindow2
.Zoom(true, false);
529 case ID_VIEW_ZOOMOUT
:
531 picWindow1
.Zoom(false, false);
532 if ((!bFitSizes
)&&(!bOverlap
))
533 picWindow2
.Zoom(false, false);
536 case ID_VIEW_ARRANGEVERTICAL
:
538 bVertical
= !bVertical
;
540 GetClientRect(*this, &rect
);
544 GetWindowRect(hwndTB
, &tbRect
);
545 LONG tbHeight
= tbRect
.bottom
-tbRect
.top
-1;
546 nSplitterPos
= (rect
.bottom
-rect
.top
+tbHeight
)/2;
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
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
);
568 CAboutDlg
dlg(*this);
569 dlg
.DoModal(hInst
, IDD_ABOUT
, *this);
573 ::PostQuitMessage(0);
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
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
);
608 LRESULT
CMainWindow::Splitter_OnLButtonDown(HWND hwnd
, UINT
/*iMsg*/, WPARAM
/*wParam*/, LPARAM lParam
)
615 pt
.x
= (short)LOWORD(lParam
); // horizontal position of cursor
616 pt
.y
= (short)HIWORD(lParam
);
618 GetClientRect(hwnd
, &clientrect
);
619 GetWindowRect(hwnd
, &rect
);
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
626 ClientToScreen(hwnd
, &pt
);
630 //same for the window coordinates - make them relative to 0,0
631 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
635 if (pt
.x
> rect
.right
-4)
639 if (pt
.y
> rect
.bottom
-4)
640 pt
.y
= rect
.bottom
-4;
646 hdc
= GetWindowDC(hwnd
);
648 DrawXorBar(hdc
, clientrect
.left
, pt
.y
+2, clientrect
.right
-clientrect
.left
-2, 4);
650 DrawXorBar(hdc
, pt
.x
+2, clientrect
.top
, 4, clientrect
.bottom
-clientrect
.top
-2);
651 ReleaseDC(hwnd
, hdc
);
659 void CMainWindow::Splitter_CaptureChanged()
664 LRESULT
CMainWindow::Splitter_OnLButtonUp(HWND hwnd
, UINT
/*iMsg*/, WPARAM
/*wParam*/, LPARAM lParam
)
671 pt
.x
= (short)LOWORD(lParam
); // horizontal position of cursor
672 pt
.y
= (short)HIWORD(lParam
);
674 if (bDragMode
== FALSE
)
677 GetClientRect(hwnd
, &clientrect
);
678 GetWindowRect(hwnd
, &rect
);
680 ClientToScreen(hwnd
, &zero
);
681 OffsetRect(&clientrect
, zero
.x
-rect
.left
, zero
.y
-rect
.top
);
683 ClientToScreen(hwnd
, &pt
);
687 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
691 if (pt
.x
> rect
.right
-4)
695 if (pt
.y
> rect
.bottom
-4)
696 pt
.y
= rect
.bottom
-4;
698 hdc
= GetWindowDC(hwnd
);
700 DrawXorBar(hdc
, clientrect
.left
, oldy
+2, clientrect
.right
-clientrect
.left
-2, 4);
702 DrawXorBar(hdc
, oldx
+2, clientrect
.top
, 4, clientrect
.bottom
-clientrect
.top
-2);
703 ReleaseDC(hwnd
, hdc
);
710 //convert the splitter position back to screen coords.
711 GetWindowRect(hwnd
, &rect
);
715 //now convert into CLIENT coordinates
716 ScreenToClient(hwnd
, &pt
);
717 GetClientRect(hwnd
, &rect
);
725 //position the child controls
726 PositionChildren(&rect
);
730 LRESULT
CMainWindow::Splitter_OnMouseMove(HWND hwnd
, UINT
/*iMsg*/, WPARAM wParam
, LPARAM lParam
)
738 if (bDragMode
== FALSE
)
741 pt
.x
= (short)LOWORD(lParam
); // horizontal position of cursor
742 pt
.y
= (short)HIWORD(lParam
);
744 GetClientRect(hwnd
, &clientrect
);
745 GetWindowRect(hwnd
, &rect
);
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
752 ClientToScreen(hwnd
, &pt
);
756 //same for the window coordinates - make them relative to 0,0
757 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
761 if (pt
.x
> rect
.right
-4)
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
);
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);
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
);
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*/)
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());
820 switch (LOWORD(wParam
))
824 TCHAR path
[MAX_PATH
] = {0};
825 if (AskForFile(hwndDlg
, path
))
827 SetDlgItemText(hwndDlg
, IDC_LEFTIMAGE
, path
);
831 case IDC_RIGHTBROWSE
:
833 TCHAR path
[MAX_PATH
] = {0};
834 if (AskForFile(hwndDlg
, path
))
836 SetDlgItemText(hwndDlg
, IDC_RIGHTIMAGE
, path
);
842 TCHAR path
[MAX_PATH
];
843 if (!GetDlgItemText(hwndDlg
, IDC_LEFTIMAGE
, path
, _countof(path
)))
846 if (!GetDlgItemText(hwndDlg
, IDC_RIGHTIMAGE
, path
, _countof(path
)))
852 EndDialog(hwndDlg
, wParam
);
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
)
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,
893 WS_CHILD
| WS_BORDER
| WS_VISIBLE
| TBSTYLE_FLAT
| TBSTYLE_TOOLTIPS
,
896 (HMENU
)IDC_TORTOISEIDIFF
,
899 if (hwndTB
== INVALID_HANDLE_VALUE
)
902 SendMessage(hwndTB
, TB_BUTTONSTRUCTSIZE
, (WPARAM
) sizeof(TBBUTTON
), 0);
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
)
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
);