Limit GUI updates the the main thread
[TortoiseGit.git] / src / TortoiseIDiff / MainWindow.cpp
blob199fb71aebc1cf8c5e06dc80f986f37b6167a796
1 // TortoiseIDiff - an image diff viewer in TortoiseSVN
3 // Copyright (C) 2006-2012 - 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 CreateToolbar();
130 // center the splitter
131 RECT rect;
132 GetClientRect(hwnd, &rect);
133 nSplitterPos = (rect.right-rect.left)/2;
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+tbHeight)/2;
176 else
177 nSplitterPos = (rect.right-rect.left)/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)
383 bLinkedPositions = true;
384 picWindow1.LinkPositions(bLinkedPositions);
385 picWindow2.LinkPositions(bLinkedPositions);
386 tbi.fsState = TBSTATE_CHECKED;
388 else
389 tbi.fsState = bLinkedPositions ? TBSTATE_ENABLED | TBSTATE_CHECKED : TBSTATE_ENABLED;
390 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
392 ShowWindow(picWindow2, bOverlap ? SW_HIDE : SW_SHOW);
394 if (bOverlap)
396 picWindow1.StopTimer();
397 picWindow2.StopTimer();
398 picWindow1.SetSecondPic(picWindow2.GetPic(), rightpictitle, rightpicpath,
399 picWindow2.GetHPos(), picWindow2.GetVPos());
400 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
402 else
404 picWindow1.SetSecondPic();
406 picWindow1.SetOverlapMode(bOverlap);
407 picWindow2.SetOverlapMode(bOverlap);
410 RECT rect;
411 GetClientRect(*this, &rect);
412 PositionChildren(&rect);
414 return 0;
416 break;
417 case ID_VIEW_BLENDALPHA:
419 if (m_BlendType == CPicWindow::BLEND_ALPHA)
420 m_BlendType = CPicWindow::BLEND_XOR;
421 else
422 m_BlendType = CPicWindow::BLEND_ALPHA;
424 HMENU hMenu = GetMenu(*this);
425 UINT uCheck = MF_BYCOMMAND;
426 uCheck |= (m_BlendType == CPicWindow::BLEND_ALPHA) ? MF_CHECKED : MF_UNCHECKED;
427 CheckMenuItem(hMenu, ID_VIEW_BLENDALPHA, uCheck);
429 // change the state of the toolbar button
430 TBBUTTONINFO tbi;
431 tbi.cbSize = sizeof(TBBUTTONINFO);
432 tbi.dwMask = TBIF_STATE;
433 tbi.fsState = (m_BlendType == CPicWindow::BLEND_ALPHA) ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
434 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_BLENDALPHA, (LPARAM)&tbi);
435 picWindow1.SetBlendAlpha(m_BlendType, picWindow1.GetBlendAlpha());
436 PositionChildren();
438 break;
439 case ID_VIEW_TRANSPARENTCOLOR:
441 static COLORREF customColors[16] = {0};
442 CHOOSECOLOR ccDlg;
443 memset(&ccDlg, 0, sizeof(ccDlg));
444 ccDlg.lStructSize = sizeof(ccDlg);
445 ccDlg.hwndOwner = m_hwnd;
446 ccDlg.rgbResult = transparentColor;
447 ccDlg.lpCustColors = customColors;
448 ccDlg.Flags = CC_RGBINIT | CC_FULLOPEN;
449 if(ChooseColor(&ccDlg))
451 transparentColor = ccDlg.rgbResult;
452 picWindow1.SetTransparentColor(transparentColor);
453 picWindow2.SetTransparentColor(transparentColor);
454 // The color picker takes the focus and we don't get it back.
455 ::SetFocus(picWindow1);
458 break;
459 case ID_VIEW_FITTOGETHER:
461 bFitSizes = !bFitSizes;
462 picWindow1.FitSizes(bFitSizes);
463 picWindow2.FitSizes(bFitSizes);
465 HMENU hMenu = GetMenu(*this);
466 UINT uCheck = MF_BYCOMMAND;
467 uCheck |= bFitSizes ? MF_CHECKED : MF_UNCHECKED;
468 CheckMenuItem(hMenu, ID_VIEW_FITTOGETHER, uCheck);
470 // change the state of the toolbar button
471 TBBUTTONINFO tbi;
472 tbi.cbSize = sizeof(TBBUTTONINFO);
473 tbi.dwMask = TBIF_STATE;
474 tbi.fsState = bFitSizes ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
475 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_FITTOGETHER, (LPARAM)&tbi);
477 break;
478 case ID_VIEW_LINKIMAGESTOGETHER:
480 bLinkedPositions = !bLinkedPositions;
481 picWindow1.LinkPositions(bLinkedPositions);
482 picWindow2.LinkPositions(bLinkedPositions);
484 HMENU hMenu = GetMenu(*this);
485 UINT uCheck = MF_BYCOMMAND;
486 uCheck |= bLinkedPositions ? MF_CHECKED : MF_UNCHECKED;
487 CheckMenuItem(hMenu, ID_VIEW_LINKIMAGESTOGETHER, uCheck);
489 // change the state of the toolbar button
490 TBBUTTONINFO tbi;
491 tbi.cbSize = sizeof(TBBUTTONINFO);
492 tbi.dwMask = TBIF_STATE;
493 tbi.fsState = bLinkedPositions ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
494 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_LINKIMAGESTOGETHER, (LPARAM)&tbi);
496 break;
497 case ID_VIEW_ALPHA0:
498 picWindow1.SetBlendAlpha(m_BlendType, 0.0f);
499 break;
500 case ID_VIEW_ALPHA255:
501 picWindow1.SetBlendAlpha(m_BlendType, 1.0f);
502 break;
503 case ID_VIEW_ALPHA127:
504 picWindow1.SetBlendAlpha(m_BlendType, 0.5f);
505 break;
506 case ID_VIEW_ALPHATOGGLE:
507 picWindow1.ToggleAlpha();
508 break;
509 case ID_VIEW_FITIMAGESINWINDOW:
511 picWindow2.FitImageInWindow();
512 picWindow1.FitImageInWindow();
514 break;
515 case ID_VIEW_ORININALSIZE:
517 picWindow2.SetZoom(1.0, false);
518 picWindow1.SetZoom(1.0, false);
520 break;
521 case ID_VIEW_ZOOMIN:
523 picWindow1.Zoom(true, false);
524 if ((!bFitSizes)&&(!bOverlap))
525 picWindow2.Zoom(true, false);
527 break;
528 case ID_VIEW_ZOOMOUT:
530 picWindow1.Zoom(false, false);
531 if ((!bFitSizes)&&(!bOverlap))
532 picWindow2.Zoom(false, false);
534 break;
535 case ID_VIEW_ARRANGEVERTICAL:
537 bVertical = !bVertical;
538 RECT rect;
539 GetClientRect(*this, &rect);
540 if (bVertical)
542 RECT tbRect;
543 GetWindowRect(hwndTB, &tbRect);
544 LONG tbHeight = tbRect.bottom-tbRect.top-1;
545 nSplitterPos = (rect.bottom-rect.top+tbHeight)/2;
547 else
549 nSplitterPos = (rect.right-rect.left)/2;
551 HMENU hMenu = GetMenu(*this);
552 UINT uCheck = MF_BYCOMMAND;
553 uCheck |= bVertical ? MF_CHECKED : MF_UNCHECKED;
554 CheckMenuItem(hMenu, ID_VIEW_ARRANGEVERTICAL, uCheck);
555 // change the state of the toolbar button
556 TBBUTTONINFO tbi;
557 tbi.cbSize = sizeof(TBBUTTONINFO);
558 tbi.dwMask = TBIF_STATE;
559 tbi.fsState = bVertical ? TBSTATE_CHECKED | TBSTATE_ENABLED : TBSTATE_ENABLED;
560 SendMessage(hwndTB, TB_SETBUTTONINFO, ID_VIEW_ARRANGEVERTICAL, (LPARAM)&tbi);
562 PositionChildren(&rect);
564 break;
565 case ID_ABOUT:
567 CAboutDlg dlg(*this);
568 dlg.DoModal(hInst, IDD_ABOUT, *this);
570 break;
571 case IDM_EXIT:
572 ::PostQuitMessage(0);
573 return 0;
574 break;
575 default:
576 break;
578 return 1;
581 // splitter stuff
582 void CMainWindow::DrawXorBar(HDC hdc, int x1, int y1, int width, int height)
584 static WORD _dotPatternBmp[8] =
586 0x0055, 0x00aa, 0x0055, 0x00aa,
587 0x0055, 0x00aa, 0x0055, 0x00aa
590 HBITMAP hbm;
591 HBRUSH hbr, hbrushOld;
593 hbm = CreateBitmap(8, 8, 1, 1, _dotPatternBmp);
594 hbr = CreatePatternBrush(hbm);
596 SetBrushOrgEx(hdc, x1, y1, 0);
597 hbrushOld = (HBRUSH)SelectObject(hdc, hbr);
599 PatBlt(hdc, x1, y1, width, height, PATINVERT);
601 SelectObject(hdc, hbrushOld);
603 DeleteObject(hbr);
604 DeleteObject(hbm);
607 LRESULT CMainWindow::Splitter_OnLButtonDown(HWND hwnd, UINT /*iMsg*/, WPARAM /*wParam*/, LPARAM lParam)
609 POINT pt;
610 HDC hdc;
611 RECT rect;
612 RECT clientrect;
614 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
615 pt.y = (short)HIWORD(lParam);
617 GetClientRect(hwnd, &clientrect);
618 GetWindowRect(hwnd, &rect);
619 POINT zero = {0,0};
620 ClientToScreen(hwnd, &zero);
621 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
623 //convert the mouse coordinates relative to the top-left of
624 //the window
625 ClientToScreen(hwnd, &pt);
626 pt.x -= rect.left;
627 pt.y -= rect.top;
629 //same for the window coordinates - make them relative to 0,0
630 OffsetRect(&rect, -rect.left, -rect.top);
632 if (pt.x < 0)
633 pt.x = 0;
634 if (pt.x > rect.right-4)
635 pt.x = rect.right-4;
636 if (pt.y < 0)
637 pt.y = 0;
638 if (pt.y > rect.bottom-4)
639 pt.y = rect.bottom-4;
641 bDragMode = true;
643 SetCapture(hwnd);
645 hdc = GetWindowDC(hwnd);
646 if (bVertical)
647 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
648 else
649 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
650 ReleaseDC(hwnd, hdc);
652 oldx = pt.x;
653 oldy = pt.y;
655 return 0;
658 void CMainWindow::Splitter_CaptureChanged()
660 bDragMode = false;
663 LRESULT CMainWindow::Splitter_OnLButtonUp(HWND hwnd, UINT /*iMsg*/, WPARAM /*wParam*/, LPARAM lParam)
665 HDC hdc;
666 RECT rect;
667 RECT clientrect;
669 POINT pt;
670 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
671 pt.y = (short)HIWORD(lParam);
673 if (bDragMode == FALSE)
674 return 0;
676 GetClientRect(hwnd, &clientrect);
677 GetWindowRect(hwnd, &rect);
678 POINT zero = {0,0};
679 ClientToScreen(hwnd, &zero);
680 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
682 ClientToScreen(hwnd, &pt);
683 pt.x -= rect.left;
684 pt.y -= rect.top;
686 OffsetRect(&rect, -rect.left, -rect.top);
688 if (pt.x < 0)
689 pt.x = 0;
690 if (pt.x > rect.right-4)
691 pt.x = rect.right-4;
692 if (pt.y < 0)
693 pt.y = 0;
694 if (pt.y > rect.bottom-4)
695 pt.y = rect.bottom-4;
697 hdc = GetWindowDC(hwnd);
698 if (bVertical)
699 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
700 else
701 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
702 ReleaseDC(hwnd, hdc);
704 oldx = pt.x;
705 oldy = pt.y;
707 bDragMode = false;
709 //convert the splitter position back to screen coords.
710 GetWindowRect(hwnd, &rect);
711 pt.x += rect.left;
712 pt.y += rect.top;
714 //now convert into CLIENT coordinates
715 ScreenToClient(hwnd, &pt);
716 GetClientRect(hwnd, &rect);
717 if (bVertical)
718 nSplitterPos = pt.y;
719 else
720 nSplitterPos = pt.x;
722 ReleaseCapture();
724 //position the child controls
725 PositionChildren(&rect);
726 return 0;
729 LRESULT CMainWindow::Splitter_OnMouseMove(HWND hwnd, UINT /*iMsg*/, WPARAM wParam, LPARAM lParam)
731 HDC hdc;
732 RECT rect;
733 RECT clientrect;
735 POINT pt;
737 if (bDragMode == FALSE)
738 return 0;
740 pt.x = (short)LOWORD(lParam); // horizontal position of cursor
741 pt.y = (short)HIWORD(lParam);
743 GetClientRect(hwnd, &clientrect);
744 GetWindowRect(hwnd, &rect);
745 POINT zero = {0,0};
746 ClientToScreen(hwnd, &zero);
747 OffsetRect(&clientrect, zero.x-rect.left, zero.y-rect.top);
749 //convert the mouse coordinates relative to the top-left of
750 //the window
751 ClientToScreen(hwnd, &pt);
752 pt.x -= rect.left;
753 pt.y -= rect.top;
755 //same for the window coordinates - make them relative to 0,0
756 OffsetRect(&rect, -rect.left, -rect.top);
758 if (pt.x < 0)
759 pt.x = 0;
760 if (pt.x > rect.right-4)
761 pt.x = rect.right-4;
762 if (pt.y < 0)
763 pt.y = 0;
764 if (pt.y > rect.bottom-4)
765 pt.y = rect.bottom-4;
767 if ((wParam & MK_LBUTTON) && ((bVertical && (pt.y != oldy)) || (!bVertical && (pt.x != oldx))))
769 hdc = GetWindowDC(hwnd);
771 if (bVertical)
773 DrawXorBar(hdc, clientrect.left, oldy+2, clientrect.right-clientrect.left-2, 4);
774 DrawXorBar(hdc, clientrect.left, pt.y+2, clientrect.right-clientrect.left-2, 4);
776 else
778 DrawXorBar(hdc, oldx+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
779 DrawXorBar(hdc, pt.x+2, clientrect.top, 4, clientrect.bottom-clientrect.top-2);
782 ReleaseDC(hwnd, hdc);
784 oldx = pt.x;
785 oldy = pt.y;
788 return 0;
791 bool CMainWindow::OpenDialog()
793 return (DialogBox(hResource, MAKEINTRESOURCE(IDD_OPEN), *this, (DLGPROC)OpenDlgProc)==IDOK);
796 BOOL CALLBACK CMainWindow::OpenDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/)
798 switch (message)
800 case WM_INITDIALOG:
802 // center on the parent window
803 HWND hParentWnd = ::GetParent(hwndDlg);
804 RECT parentrect, childrect, centeredrect;
805 GetWindowRect(hParentWnd, &parentrect);
806 GetWindowRect(hwndDlg, &childrect);
807 centeredrect.left = parentrect.left + ((parentrect.right-parentrect.left-childrect.right+childrect.left)/2);
808 centeredrect.right = centeredrect.left + (childrect.right-childrect.left);
809 centeredrect.top = parentrect.top + ((parentrect.bottom-parentrect.top-childrect.bottom+childrect.top)/2);
810 centeredrect.bottom = centeredrect.top + (childrect.bottom-childrect.top);
811 SetWindowPos(hwndDlg, NULL, centeredrect.left, centeredrect.top, centeredrect.right-centeredrect.left, centeredrect.bottom-centeredrect.top, SWP_SHOWWINDOW);
813 if (!leftpicpath.empty())
814 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, leftpicpath.c_str());
815 SetFocus(hwndDlg);
817 break;
818 case WM_COMMAND:
819 switch (LOWORD(wParam))
821 case IDC_LEFTBROWSE:
823 TCHAR path[MAX_PATH] = {0};
824 if (AskForFile(hwndDlg, path))
826 SetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path);
829 break;
830 case IDC_RIGHTBROWSE:
832 TCHAR path[MAX_PATH] = {0};
833 if (AskForFile(hwndDlg, path))
835 SetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path);
838 break;
839 case IDOK:
841 TCHAR path[MAX_PATH];
842 if (!GetDlgItemText(hwndDlg, IDC_LEFTIMAGE, path, _countof(path)))
843 *path = 0;
844 leftpicpath = path;
845 if (!GetDlgItemText(hwndDlg, IDC_RIGHTIMAGE, path, _countof(path)))
846 *path = 0;
847 rightpicpath = path;
849 // Fall through.
850 case IDCANCEL:
851 EndDialog(hwndDlg, wParam);
852 return TRUE;
855 return FALSE;
858 bool CMainWindow::AskForFile(HWND owner, TCHAR * path)
860 OPENFILENAME ofn = {0}; // common dialog box structure
861 // Initialize OPENFILENAME
862 ofn.lStructSize = sizeof(OPENFILENAME);
863 ofn.hwndOwner = owner;
864 ofn.lpstrFile = path;
865 ofn.nMaxFile = MAX_PATH;
866 ofn.lpstrTitle = ResString(::hResource, IDS_OPENIMAGEFILE);
867 ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_EXPLORER;
868 ofn.hInstance = ::hResource;
869 TCHAR filters[] = _T("Images\0*.wmf;*.jpg;*jpeg;*.bmp;*.gif;*.png;*.ico;*.dib;*.emf\0All (*.*)\0*.*\0\0");
870 ofn.lpstrFilter = filters;
871 ofn.nFilterIndex = 1;
872 // Display the Open dialog box.
873 if (GetOpenFileName(&ofn)==FALSE)
875 return false;
877 return true;
880 bool CMainWindow::CreateToolbar()
882 // Ensure that the common control DLL is loaded.
883 INITCOMMONCONTROLSEX icex;
884 icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
885 icex.dwICC = ICC_BAR_CLASSES | ICC_WIN95_CLASSES;
886 InitCommonControlsEx(&icex);
888 hwndTB = CreateWindowEx(0,
889 TOOLBARCLASSNAME,
890 (LPCTSTR)NULL,
891 WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
892 0, 0, 0, 0,
893 *this,
894 (HMENU)IDC_TORTOISEIDIFF,
895 hResource,
896 NULL);
897 if (hwndTB == INVALID_HANDLE_VALUE)
898 return false;
900 SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
902 TBBUTTON tbb[12];
903 // create an imagelist containing the icons for the toolbar
904 hToolbarImgList = ImageList_Create(24, 24, ILC_COLOR32 | ILC_MASK, 12, 4);
905 if (hToolbarImgList == NULL)
906 return false;
907 int index = 0;
908 HICON hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_OVERLAP));
909 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
910 tbb[index].idCommand = ID_VIEW_OVERLAPIMAGES;
911 tbb[index].fsState = TBSTATE_ENABLED;
912 tbb[index].fsStyle = BTNS_BUTTON;
913 tbb[index].dwData = 0;
914 tbb[index++].iString = 0;
916 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_BLEND));
917 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
918 tbb[index].idCommand = ID_VIEW_BLENDALPHA;
919 tbb[index].fsState = 0;
920 tbb[index].fsStyle = BTNS_BUTTON;
921 tbb[index].dwData = 0;
922 tbb[index++].iString = 0;
924 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_LINK));
925 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
926 tbb[index].idCommand = ID_VIEW_LINKIMAGESTOGETHER;
927 tbb[index].fsState = TBSTATE_ENABLED | TBSTATE_CHECKED;
928 tbb[index].fsStyle = BTNS_BUTTON;
929 tbb[index].dwData = 0;
930 tbb[index++].iString = 0;
932 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITTOGETHER));
933 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
934 tbb[index].idCommand = ID_VIEW_FITTOGETHER;
935 tbb[index].fsState = TBSTATE_ENABLED;
936 tbb[index].fsStyle = BTNS_BUTTON;
937 tbb[index].dwData = 0;
938 tbb[index++].iString = 0;
940 tbb[index].iBitmap = 0;
941 tbb[index].idCommand = 0;
942 tbb[index].fsState = TBSTATE_ENABLED;
943 tbb[index].fsStyle = BTNS_SEP;
944 tbb[index].dwData = 0;
945 tbb[index++].iString = 0;
947 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_VERTICAL));
948 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
949 tbb[index].idCommand = ID_VIEW_ARRANGEVERTICAL;
950 tbb[index].fsState = TBSTATE_ENABLED;
951 tbb[index].fsStyle = BTNS_BUTTON;
952 tbb[index].dwData = 0;
953 tbb[index++].iString = 0;
955 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_FITINWINDOW));
956 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
957 tbb[index].idCommand = ID_VIEW_FITIMAGESINWINDOW;
958 tbb[index].fsState = TBSTATE_ENABLED;
959 tbb[index].fsStyle = BTNS_BUTTON;
960 tbb[index].dwData = 0;
961 tbb[index++].iString = 0;
963 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ORIGSIZE));
964 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
965 tbb[index].idCommand = ID_VIEW_ORININALSIZE;
966 tbb[index].fsState = TBSTATE_ENABLED;
967 tbb[index].fsStyle = BTNS_BUTTON;
968 tbb[index].dwData = 0;
969 tbb[index++].iString = 0;
971 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMIN));
972 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
973 tbb[index].idCommand = ID_VIEW_ZOOMIN;
974 tbb[index].fsState = TBSTATE_ENABLED;
975 tbb[index].fsStyle = BTNS_BUTTON;
976 tbb[index].dwData = 0;
977 tbb[index++].iString = 0;
979 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_ZOOMOUT));
980 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
981 tbb[index].idCommand = ID_VIEW_ZOOMOUT;
982 tbb[index].fsState = TBSTATE_ENABLED;
983 tbb[index].fsStyle = BTNS_BUTTON;
984 tbb[index].dwData = 0;
985 tbb[index++].iString = 0;
987 tbb[index].iBitmap = 0;
988 tbb[index].idCommand = 0;
989 tbb[index].fsState = TBSTATE_ENABLED;
990 tbb[index].fsStyle = BTNS_SEP;
991 tbb[index].dwData = 0;
992 tbb[index++].iString = 0;
994 hIcon = LoadIcon(hResource, MAKEINTRESOURCE(IDI_IMGINFO));
995 tbb[index].iBitmap = ImageList_AddIcon(hToolbarImgList, hIcon);
996 tbb[index].idCommand = ID_VIEW_IMAGEINFO;
997 tbb[index].fsState = TBSTATE_ENABLED;
998 tbb[index].fsStyle = BTNS_BUTTON;
999 tbb[index].dwData = 0;
1000 tbb[index++].iString = 0;
1002 SendMessage(hwndTB, TB_SETIMAGELIST, 0, (LPARAM)hToolbarImgList);
1003 SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM)index, (LPARAM) (LPTBBUTTON) &tbb);
1004 SendMessage(hwndTB, TB_AUTOSIZE, 0, 0);
1005 ShowWindow(hwndTB, SW_SHOW);
1006 return true;