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 "PicWindow.h"
27 #pragma comment(lib, "Msimg32.lib")
28 #pragma comment(lib, "shell32.lib")
30 bool CPicWindow::RegisterAndCreateWindow(HWND hParent
)
34 // Fill in the window class structure with default parameters
35 wcx
.cbSize
= sizeof(WNDCLASSEX
);
36 wcx
.style
= CS_HREDRAW
| CS_VREDRAW
;
37 wcx
.lpfnWndProc
= CWindow::stWinMsgHandler
;
40 wcx
.hInstance
= hResource
;
41 wcx
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
42 wcx
.lpszClassName
= _T("TortoiseGitIDiffPicWindow");
43 wcx
.hIcon
= LoadIcon(hResource
, MAKEINTRESOURCE(IDI_TORTOISEIDIFF
));
44 wcx
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+1);
45 wcx
.lpszMenuName
= MAKEINTRESOURCE(IDC_TORTOISEIDIFF
);
46 wcx
.hIconSm
= LoadIcon(wcx
.hInstance
, MAKEINTRESOURCE(IDI_TORTOISEIDIFF
));
48 if (CreateEx(WS_EX_ACCEPTFILES
| WS_EX_CLIENTEDGE
, WS_CHILD
| WS_HSCROLL
| WS_VSCROLL
| WS_VISIBLE
, hParent
))
50 ShowWindow(m_hwnd
, SW_SHOW
);
58 void CPicWindow::PositionTrackBar()
62 HWND slider
= m_AlphaSlider
.GetWindow();
63 if ((pSecondPic
)&&(m_blend
== BLEND_ALPHA
))
65 MoveWindow(slider
, 0, rc
.top
-4+SLIDER_WIDTH
, SLIDER_WIDTH
, rc
.bottom
-rc
.top
-SLIDER_WIDTH
+8, true);
66 ShowWindow(slider
, SW_SHOW
);
67 MoveWindow(hwndAlphaToggleBtn
, 0, rc
.top
-4, SLIDER_WIDTH
, SLIDER_WIDTH
, true);
68 ShowWindow(hwndAlphaToggleBtn
, SW_SHOW
);
72 ShowWindow(slider
, SW_HIDE
);
73 ShowWindow(hwndAlphaToggleBtn
, SW_HIDE
);
77 LRESULT CALLBACK
CPicWindow::WinMsgHandler(HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
84 // create a slider control
86 ShowWindow(m_AlphaSlider
.GetWindow(), SW_HIDE
);
89 RECT rect
; // for client area coordinates
91 hwndTT
= CreateWindowEx(WS_EX_TOPMOST
,
94 WS_POPUP
| TTS_NOPREFIX
| TTS_ALWAYSTIP
,
111 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
113 ::GetClientRect(hwnd
, &rect
);
115 ti
.cbSize
= sizeof(TOOLINFO
);
116 ti
.uFlags
= TTF_TRACK
| TTF_ABSOLUTE
;
118 ti
.hinst
= hResource
;
120 ti
.lpszText
= LPSTR_TEXTCALLBACK
;
121 // ToolTip control will cover the whole window
122 ti
.rect
.left
= rect
.left
;
123 ti
.rect
.top
= rect
.top
;
124 ti
.rect
.right
= rect
.right
;
125 ti
.rect
.bottom
= rect
.bottom
;
127 SendMessage(hwndTT
, TTM_ADDTOOL
, 0, (LPARAM
) (LPTOOLINFO
) &ti
);
128 SendMessage(hwndTT
, TTM_SETMAXTIPWIDTH
, 0, 600);
129 nHSecondScrollPos
= 0;
130 nVSecondScrollPos
= 0;
135 InvalidateRect(*this, NULL
, FALSE
);
148 if ((pSecondPic
)&&((HWND
)lParam
== m_AlphaSlider
.GetWindow()))
150 if (LOWORD(wParam
) == TB_THUMBTRACK
)
152 // while tracking, only redraw after 50 milliseconds
153 ::SetTimer(*this, TIMER_ALPHASLIDER
, 50, NULL
);
156 SetBlendAlpha(m_blend
, SendMessage(m_AlphaSlider
.GetWindow(), TBM_GETPOS
, 0, 0) / 16.0f
);
160 UINT nPos
= HIWORD(wParam
);
161 bool bForceUpdate
= false;
162 if (LOWORD(wParam
) == SB_THUMBTRACK
|| LOWORD(wParam
) == SB_THUMBPOSITION
)
164 // Get true 32-bit scroll position
166 si
.cbSize
= sizeof(SCROLLINFO
);
167 si
.fMask
= SIF_TRACKPOS
;
168 GetScrollInfo(*this, SB_VERT
, &si
);
173 OnVScroll(LOWORD(wParam
), nPos
);
174 if (bLinkedPositions
&& pTheOtherPic
)
176 pTheOtherPic
->OnVScroll(LOWORD(wParam
), nPos
);
178 ::UpdateWindow(*pTheOtherPic
);
184 UINT nPos
= HIWORD(wParam
);
185 bool bForceUpdate
= false;
186 if (LOWORD(wParam
) == SB_THUMBTRACK
|| LOWORD(wParam
) == SB_THUMBPOSITION
)
188 // Get true 32-bit scroll position
190 si
.cbSize
= sizeof(SCROLLINFO
);
191 si
.fMask
= SIF_TRACKPOS
;
192 GetScrollInfo(*this, SB_VERT
, &si
);
197 OnHScroll(LOWORD(wParam
), nPos
);
198 if (bLinkedPositions
&& pTheOtherPic
)
200 pTheOtherPic
->OnHScroll(LOWORD(wParam
), nPos
);
202 ::UpdateWindow(*pTheOtherPic
);
208 OnMouseWheel(GET_KEYSTATE_WPARAM(wParam
), GET_WHEEL_DELTA_WPARAM(wParam
));
213 OnMouseWheel(GET_KEYSTATE_WPARAM(wParam
)|MK_SHIFT
, GET_WHEEL_DELTA_WPARAM(wParam
));
218 ptPanStart
.x
= GET_X_LPARAM(lParam
);
219 ptPanStart
.y
= GET_Y_LPARAM(lParam
);
220 startVScrollPos
= nVScrollPos
;
221 startHScrollPos
= nHScrollPos
;
222 startVSecondScrollPos
= nVSecondScrollPos
;
223 startHSecondScrollPos
= nHSecondScrollPos
;
230 InvalidateRect(*this, NULL
, FALSE
);
237 SendMessage(hwndTT
, TTM_TRACKACTIVATE
, FALSE
, 0);
241 mevt
.cbSize
= sizeof(TRACKMOUSEEVENT
);
242 mevt
.dwFlags
= TME_LEAVE
;
243 mevt
.dwHoverTime
= HOVER_DEFAULT
;
244 mevt
.hwndTrack
= *this;
245 ::TrackMouseEvent(&mevt
);
246 POINT pt
= {((int)(short)LOWORD(lParam
)), ((int)(short)HIWORD(lParam
))};
247 if (pt
.y
< HEADER_HEIGHT
)
249 ClientToScreen(*this, &pt
);
250 if ((abs(m_lastTTPos
.x
- pt
.x
) > 20)||(abs(m_lastTTPos
.y
- pt
.y
) > 10))
255 SendMessage(hwndTT
, TTM_TRACKPOSITION
, 0, MAKELONG(pt
.x
, pt
.y
));
257 ti
.cbSize
= sizeof(TOOLINFO
);
260 SendMessage(hwndTT
, TTM_TRACKACTIVATE
, TRUE
, (LPARAM
)&ti
);
265 SendMessage(hwndTT
, TTM_TRACKACTIVATE
, FALSE
, 0);
269 if ((wParam
& MK_LBUTTON
) &&
270 (ptPanStart
.x
>= 0) &&
274 int xPos
= GET_X_LPARAM(lParam
);
275 int yPos
= GET_Y_LPARAM(lParam
);
277 if (wParam
& MK_CONTROL
)
279 nHSecondScrollPos
= startHSecondScrollPos
+ (ptPanStart
.x
- xPos
);
280 nVSecondScrollPos
= startVSecondScrollPos
+ (ptPanStart
.y
- yPos
);
282 else if (wParam
& MK_SHIFT
)
284 nHScrollPos
= startHScrollPos
+ (ptPanStart
.x
- xPos
);
285 nVScrollPos
= startVScrollPos
+ (ptPanStart
.y
- yPos
);
289 nHSecondScrollPos
= startHSecondScrollPos
+ (ptPanStart
.x
- xPos
);
290 nVSecondScrollPos
= startVSecondScrollPos
+ (ptPanStart
.y
- yPos
);
291 nHScrollPos
= startHScrollPos
+ (ptPanStart
.x
- xPos
);
292 nVScrollPos
= startVScrollPos
+ (ptPanStart
.y
- yPos
);
293 if (!bLinkedPositions
&& pTheOtherPic
)
295 // snap to the other picture borders
296 if (abs(nVScrollPos
-pTheOtherPic
->nVScrollPos
) < 10)
297 nVScrollPos
= pTheOtherPic
->nVScrollPos
;
298 if (abs(nHScrollPos
-pTheOtherPic
->nHScrollPos
) < 10)
299 nHScrollPos
= pTheOtherPic
->nHScrollPos
;
303 InvalidateRect(*this, NULL
, TRUE
);
305 if (pTheOtherPic
&& (bLinkedPositions
) && ((wParam
& MK_SHIFT
)==0))
307 pTheOtherPic
->nHScrollPos
= nHScrollPos
;
308 pTheOtherPic
->nVScrollPos
= nVScrollPos
;
309 pTheOtherPic
->SetupScrollBars();
310 InvalidateRect(*pTheOtherPic
, NULL
, TRUE
);
311 UpdateWindow(*pTheOtherPic
);
318 // we show a hand cursor if the image can be dragged,
319 // and a hand-down cursor if the image is currently dragged
320 if ((*this == (HWND
)wParam
)&&(LOWORD(lParam
)==HTCLIENT
))
323 GetClientRect(&rect
);
324 LONG width
= picture
.m_Width
;
325 LONG height
= picture
.m_Height
;
328 width
= max(width
, pSecondPic
->m_Width
);
329 height
= max(height
, pSecondPic
->m_Height
);
332 if ((GetKeyState(VK_LBUTTON
)&0x8000)||(HIWORD(lParam
) == WM_LBUTTONDOWN
))
334 SetCursor(curHandDown
);
342 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
347 HDROP hDrop
= (HDROP
)wParam
;
348 TCHAR szFileName
[MAX_PATH
] = {0};
349 // we only use the first file dropped (if multiple files are dropped)
350 if (DragQueryFile(hDrop
, 0, szFileName
, _countof(szFileName
)))
352 SetPic(szFileName
, _T(""), bMainPic
);
354 InvalidateRect(*this, NULL
, TRUE
);
360 switch (LOWORD(wParam
))
365 if (bLinkedPositions
&& pTheOtherPic
)
366 pTheOtherPic
->PrevImage();
373 if (bLinkedPositions
&& pTheOtherPic
)
374 pTheOtherPic
->NextImage();
380 bPlaying
= !bPlaying
;
382 if (bLinkedPositions
&& pTheOtherPic
)
383 pTheOtherPic
->Animate(bPlaying
);
387 case ALPHATOGGLEBUTTON_ID
:
389 WORD msg
= HIWORD(wParam
);
392 case BN_DOUBLECLICKED
:
394 SendMessage(hwndAlphaToggleBtn
, BM_SETSTATE
, 1, 0);
395 SetTimer(*this, ID_ALPHATOGGLETIMER
, 1000, NULL
);
399 KillTimer(*this, ID_ALPHATOGGLETIMER
);
408 m_blend
= BLEND_ALPHA
;
410 InvalidateRect(*this, NULL
, TRUE
);
417 InvalidateRect(*this, NULL
, TRUE
);
420 case SELECTBUTTON_ID
:
422 SendMessage(GetParent(m_hwnd
), WM_COMMAND
, MAKEWPARAM(SELECTBUTTON_ID
, SELECTBUTTON_ID
), (LPARAM
)m_hwnd
);
432 case ID_ANIMATIONTIMER
:
435 if (nCurrentFrame
> picture
.GetNumberOfFrames(0))
437 long delay
= picture
.SetActiveFrame(nCurrentFrame
);
438 delay
= max(100, delay
);
439 SetTimer(*this, ID_ANIMATIONTIMER
, delay
, NULL
);
440 InvalidateRect(*this, NULL
, FALSE
);
443 case TIMER_ALPHASLIDER
:
445 SetBlendAlpha(m_blend
, SendMessage(m_AlphaSlider
.GetWindow(), TBM_GETPOS
, 0, 0)/16.0f
);
446 KillTimer(*this, TIMER_ALPHASLIDER
);
449 case ID_ALPHATOGGLETIMER
:
459 LPNMHDR pNMHDR
= (LPNMHDR
)lParam
;
460 if (pNMHDR
->code
== TTN_GETDISPINFO
)
462 if (pNMHDR
->hwndFrom
== m_AlphaSlider
.GetWindow())
464 LPTOOLTIPTEXT lpttt
= (LPTOOLTIPTEXT
) lParam
;
465 lpttt
->hinst
= hResource
;
466 TCHAR stringbuf
[MAX_PATH
] = {0};
467 _stprintf_s(stringbuf
, _T("%i%% alpha"), (int)(SendMessage(m_AlphaSlider
.GetWindow(),TBM_GETPOS
,0,0)/16.0f
*100.0f
));
468 _tcscpy_s(lpttt
->lpszText
, 80, stringbuf
);
470 else if (pNMHDR
->idFrom
== (UINT_PTR
)hwndAlphaToggleBtn
)
472 _stprintf_s(m_wszTip
, (TCHAR
const *)ResString(hResource
, IDS_ALPHABUTTONTT
), (int)(SendMessage(m_AlphaSlider
.GetWindow(),TBM_GETPOS
,0,0)/16.0f
*100.0f
));
473 if (pNMHDR
->code
== TTN_NEEDTEXTW
)
475 NMTTDISPINFOW
* pTTTW
= (NMTTDISPINFOW
*)pNMHDR
;
476 pTTTW
->lpszText
= m_wszTip
;
480 NMTTDISPINFOA
* pTTTA
= (NMTTDISPINFOA
*)pNMHDR
;
481 pTTTA
->lpszText
= m_szTip
;
482 ::WideCharToMultiByte(CP_ACP
, 0, m_wszTip
, -1, m_szTip
, 8192, NULL
, NULL
);
487 BuildInfoString(m_wszTip
, _countof(m_wszTip
), true);
488 if (pNMHDR
->code
== TTN_NEEDTEXTW
)
490 NMTTDISPINFOW
* pTTTW
= (NMTTDISPINFOW
*)pNMHDR
;
491 pTTTW
->lpszText
= m_wszTip
;
495 NMTTDISPINFOA
* pTTTA
= (NMTTDISPINFOA
*)pNMHDR
;
496 pTTTA
->lpszText
= m_szTip
;
497 ::WideCharToMultiByte(CP_ACP
, 0, m_wszTip
, -1, m_szTip
, 8192, NULL
, NULL
);
508 bWindowClosed
= TRUE
;
511 return DefWindowProc(hwnd
, uMsg
, wParam
, lParam
);
517 void CPicWindow::NextImage()
520 if (nCurrentDimension
> picture
.GetNumberOfDimensions())
521 nCurrentDimension
= picture
.GetNumberOfDimensions();
523 if (nCurrentFrame
> picture
.GetNumberOfFrames(0))
524 nCurrentFrame
= picture
.GetNumberOfFrames(0);
525 picture
.SetActiveFrame(nCurrentFrame
>= nCurrentDimension
? nCurrentFrame
: nCurrentDimension
);
526 InvalidateRect(*this, NULL
, FALSE
);
530 void CPicWindow::PrevImage()
533 if (nCurrentDimension
< 1)
534 nCurrentDimension
= 1;
536 if (nCurrentFrame
< 1)
538 picture
.SetActiveFrame(nCurrentFrame
>= nCurrentDimension
? nCurrentFrame
: nCurrentDimension
);
539 InvalidateRect(*this, NULL
, FALSE
);
543 void CPicWindow::Animate(bool bStart
)
547 SendMessage(hwndPlayBtn
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hStop
);
548 SetTimer(*this, ID_ANIMATIONTIMER
, 0, NULL
);
552 SendMessage(hwndPlayBtn
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hPlay
);
553 KillTimer(*this, ID_ANIMATIONTIMER
);
557 void CPicWindow::SetPic(tstring path
, tstring title
, bool bFirst
)
560 picpath
=path
;pictitle
=title
;
561 picture
.SetInterpolationMode(InterpolationModeHighQualityBicubic
);
562 bValid
= picture
.Load(picpath
);
563 nDimensions
= picture
.GetNumberOfDimensions();
565 nFrames
= picture
.GetNumberOfFrames(0);
570 InvalidateRect(*this, NULL
, FALSE
);
574 void CPicWindow::DrawViewTitle(HDC hDC
, RECT
* rect
)
577 hFont
= CreateFont(-MulDiv(pSecondPic
? 8 : 10, GetDeviceCaps(hDC
, LOGPIXELSY
), 72), 0, 0, 0, FW_DONTCARE
, false, false, false, ANSI_CHARSET
, OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, CLEARTYPE_QUALITY
, DEFAULT_PITCH
, _T("MS Shell Dlg"));
578 HFONT hFontOld
= (HFONT
)SelectObject(hDC
, (HGDIOBJ
)hFont
);
581 textrect
.left
= rect
->left
;
582 textrect
.top
= rect
->top
;
583 textrect
.right
= rect
->right
;
584 textrect
.bottom
= rect
->top
+ HEADER_HEIGHT
;
585 if (HasMultipleImages())
586 textrect
.bottom
+= HEADER_HEIGHT
;
589 crBk
= ::GetSysColor(COLOR_SCROLLBAR
);
590 crFg
= ::GetSysColor(COLOR_WINDOWTEXT
);
591 SetBkColor(hDC
, crBk
);
592 ::ExtTextOut(hDC
, 0, 0, ETO_OPAQUE
, &textrect
, NULL
, 0, NULL
);
594 if (GetFocus() == *this)
595 DrawEdge(hDC
, &textrect
, EDGE_BUMP
, BF_RECT
);
597 DrawEdge(hDC
, &textrect
, EDGE_ETCHED
, BF_RECT
);
599 SetTextColor(hDC
, crFg
);
601 // use the path if no title is set.
602 tstring
* title
= pictitle
.empty() ? &picpath
: &pictitle
;
604 tstring realtitle
= *title
;
605 tstring imgnumstring
;
607 if (HasMultipleImages())
609 TCHAR buf
[MAX_PATH
] = {0};
611 _stprintf_s(buf
, (const TCHAR
*)ResString(hResource
, IDS_DIMENSIONSANDFRAMES
), nCurrentFrame
, nFrames
);
613 _stprintf_s(buf
, (const TCHAR
*)ResString(hResource
, IDS_DIMENSIONSANDFRAMES
), nCurrentDimension
, nDimensions
);
618 if (GetTextExtentPoint32(hDC
, realtitle
.c_str(), (int)realtitle
.size(), &stringsize
))
620 int nStringLength
= stringsize
.cx
;
621 int texttop
= pSecondPic
? textrect
.top
+ (HEADER_HEIGHT
/2) - stringsize
.cy
: textrect
.top
+ (HEADER_HEIGHT
/2) - stringsize
.cy
/2;
623 max(textrect
.left
+ ((textrect
.right
-textrect
.left
)-nStringLength
)/2, 1),
628 (UINT
)realtitle
.size(),
632 realtitle
= (pictitle2
.empty() ? picpath2
: pictitle2
);
634 max(textrect
.left
+ ((textrect
.right
-textrect
.left
)-nStringLength
)/2, 1),
635 texttop
+ stringsize
.cy
,
639 (UINT
)realtitle
.size(),
643 if (HasMultipleImages())
645 if (GetTextExtentPoint32(hDC
, imgnumstring
.c_str(), (int)imgnumstring
.size(), &stringsize
))
647 int nStringLength
= stringsize
.cx
;
650 max(textrect
.left
+ ((textrect
.right
-textrect
.left
)-nStringLength
)/2, 1),
651 textrect
.top
+ HEADER_HEIGHT
+ (HEADER_HEIGHT
/2) - stringsize
.cy
/2,
654 imgnumstring
.c_str(),
655 (UINT
)imgnumstring
.size(),
659 SelectObject(hDC
, (HGDIOBJ
)hFontOld
);
663 void CPicWindow::SetupScrollBars()
666 GetClientRect(&rect
);
668 SCROLLINFO si
= {sizeof(si
)};
670 si
.fMask
= SIF_POS
| SIF_PAGE
| SIF_RANGE
| SIF_DISABLENOSCROLL
;
672 long width
= picture
.m_Width
*picscale
/100;
673 long height
= picture
.m_Height
*picscale
/100;
674 if (pSecondPic
&& pTheOtherPic
)
676 width
= max(width
, pSecondPic
->m_Width
*pTheOtherPic
->GetZoom()/100);
677 height
= max(height
, pSecondPic
->m_Height
*pTheOtherPic
->GetZoom()/100);
680 bool bShowHScrollBar
= (nHScrollPos
> 0); // left of pic is left of window
681 bShowHScrollBar
= bShowHScrollBar
|| (width
-nHScrollPos
> rect
.right
); // right of pic is outside right of window
682 bShowHScrollBar
= bShowHScrollBar
|| (width
+nHScrollPos
> rect
.right
); // right of pic is outside right of window
683 bool bShowVScrollBar
= (nVScrollPos
> 0); // top of pic is above window
684 bShowVScrollBar
= bShowVScrollBar
|| (height
-nVScrollPos
+rect
.top
> rect
.bottom
); // bottom of pic is below window
685 bShowVScrollBar
= bShowVScrollBar
|| (height
+nVScrollPos
+rect
.top
> rect
.bottom
); // bottom of pic is below window
687 // if the image is smaller than the window, we don't need the scrollbars
688 ShowScrollBar(*this, SB_HORZ
, bShowHScrollBar
);
689 ShowScrollBar(*this, SB_VERT
, bShowVScrollBar
);
693 si
.nPos
= nVScrollPos
;
694 si
.nPage
= rect
.bottom
-rect
.top
;
695 if (height
< rect
.bottom
-rect
.top
)
700 si
.nMax
= rect
.bottom
+nVScrollPos
-rect
.top
;
704 si
.nMin
= nVScrollPos
;
705 si
.nMax
= int(height
);
713 si
.nMax
= int(max(height
, rect
.bottom
+nVScrollPos
-rect
.top
));
718 si
.nMax
= int(height
-nVScrollPos
);
721 SetScrollInfo(*this, SB_VERT
, &si
, TRUE
);
726 si
.nPos
= nHScrollPos
;
727 si
.nPage
= rect
.right
-rect
.left
;
728 if (width
< rect
.right
-rect
.left
)
733 si
.nMax
= rect
.right
+nHScrollPos
-rect
.left
;
737 si
.nMin
= nHScrollPos
;
738 si
.nMax
= int(width
);
746 si
.nMax
= int(max(width
, rect
.right
+nHScrollPos
-rect
.left
));
751 si
.nMax
= int(width
-nHScrollPos
);
754 SetScrollInfo(*this, SB_HORZ
, &si
, TRUE
);
760 void CPicWindow::OnVScroll(UINT nSBCode
, UINT nPos
)
763 GetClientRect(&rect
);
768 nVScrollPos
= LONG(picture
.GetHeight()*picscale
/100);
780 nVScrollPos
+= (rect
.bottom
-rect
.top
);
783 nVScrollPos
-= (rect
.bottom
-rect
.top
);
785 case SB_THUMBPOSITION
:
794 LONG height
= LONG(picture
.GetHeight()*picscale
/100);
797 height
= max(height
, LONG(pSecondPic
->GetHeight()*picscale
/100));
798 nVSecondScrollPos
= nVScrollPos
;
802 InvalidateRect(*this, NULL
, TRUE
);
805 void CPicWindow::OnHScroll(UINT nSBCode
, UINT nPos
)
808 GetClientRect(&rect
);
813 nHScrollPos
= LONG(picture
.GetWidth()*picscale
/100);
825 nHScrollPos
+= (rect
.right
-rect
.left
);
828 nHScrollPos
-= (rect
.right
-rect
.left
);
830 case SB_THUMBPOSITION
:
839 LONG width
= LONG(picture
.GetWidth()*picscale
/100);
842 width
= max(width
, LONG(pSecondPic
->GetWidth()*picscale
/100));
843 nHSecondScrollPos
= nHScrollPos
;
847 InvalidateRect(*this, NULL
, TRUE
);
850 void CPicWindow::OnMouseWheel(short fwKeys
, short zDelta
)
853 GetClientRect(&rect
);
854 LONG width
= long(picture
.m_Width
*picscale
/100);
855 LONG height
= long(picture
.m_Height
*picscale
/100);
858 width
= max(width
, long(pSecondPic
->m_Width
*picscale
/100));
859 height
= max(height
, long(pSecondPic
->m_Height
*picscale
/100));
861 if ((fwKeys
& MK_SHIFT
)&&(fwKeys
& MK_CONTROL
)&&(pSecondPic
))
863 // ctrl+shift+wheel: change the alpha channel
864 float a
= blendAlpha
;
865 a
-= float(zDelta
)/120.0f
/4.0f
;
870 SetBlendAlpha(m_blend
, a
);
872 else if (fwKeys
& MK_SHIFT
)
874 // shift means scrolling sideways
875 OnHScroll(SB_THUMBPOSITION
, GetHPos()-zDelta
);
876 if ((bLinkedPositions
)&&(pTheOtherPic
))
878 pTheOtherPic
->OnHScroll(SB_THUMBPOSITION
, pTheOtherPic
->GetHPos()-zDelta
);
881 else if (fwKeys
& MK_CONTROL
)
883 // control means adjusting the scale factor
884 Zoom(zDelta
>0, true);
886 InvalidateRect(*this, NULL
, FALSE
);
887 SetWindowPos(*this, NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
|SWP_NOSIZE
|SWP_NOREPOSITION
|SWP_NOMOVE
);
889 if (bLinkedPositions
&& pTheOtherPic
)
891 pTheOtherPic
->nHScrollPos
= nHScrollPos
;
892 pTheOtherPic
->nVScrollPos
= nVScrollPos
;
893 pTheOtherPic
->SetupScrollBars();
894 InvalidateRect(*pTheOtherPic
, NULL
, TRUE
);
895 UpdateWindow(*pTheOtherPic
);
900 OnVScroll(SB_THUMBPOSITION
, GetVPos()-zDelta
);
901 if ((bLinkedPositions
)&&(pTheOtherPic
))
903 pTheOtherPic
->OnVScroll(SB_THUMBPOSITION
, pTheOtherPic
->GetVPos()-zDelta
);
908 void CPicWindow::GetClientRect(RECT
* pRect
)
910 ::GetClientRect(*this, pRect
);
911 pRect
->top
+= HEADER_HEIGHT
;
912 if (HasMultipleImages())
914 pRect
->top
+= HEADER_HEIGHT
;
917 pRect
->left
+= SLIDER_WIDTH
;
920 void CPicWindow::GetClientRectWithScrollbars(RECT
* pRect
)
922 GetClientRect(pRect
);
923 ::GetWindowRect(*this, pRect
);
924 pRect
->right
= pRect
->right
-pRect
->left
;
925 pRect
->bottom
= pRect
->bottom
-pRect
->top
;
928 pRect
->top
+= HEADER_HEIGHT
;
929 if (HasMultipleImages())
931 pRect
->top
+= HEADER_HEIGHT
;
934 pRect
->left
+= SLIDER_WIDTH
;
938 void CPicWindow::SetZoom(int Zoom
, bool centermouse
, bool inzoom
)
940 // Set the interpolation mode depending on zoom
941 int oldPicscale
= picscale
;
942 int oldOtherPicscale
= picscale
;
944 picture
.SetInterpolationMode(InterpolationModeNearestNeighbor
);
946 pSecondPic
->SetInterpolationMode(InterpolationModeNearestNeighbor
);
948 if ((oldPicscale
== 0) || (Zoom
== 0))
953 if (pTheOtherPic
&& !inzoom
)
958 pTheOtherPic
->SetZoomToHeight(picture
.m_Height
*Zoom
/100);
963 pTheOtherPic
->SetZoomToWidth(picture
.m_Width
*Zoom
/100);
967 // adjust the scrollbar positions according to the new zoom and the
968 // mouse position: if possible, keep the pixel where the mouse pointer
969 // is at the same position after the zoom
973 DWORD ptW
= GetMessagePos();
974 cpos
.x
= GET_X_LPARAM(ptW
);
975 cpos
.y
= GET_Y_LPARAM(ptW
);
976 ScreenToClient(*this, &cpos
);
978 GetClientRect(&clientrect
);
979 if ((PtInRect(&clientrect
, cpos
))&&(centermouse
))
981 // the mouse pointer is over our window
982 nHScrollPos
= (nHScrollPos
+ cpos
.x
)*Zoom
/oldPicscale
-cpos
.x
;
983 nVScrollPos
= (nVScrollPos
+ cpos
.y
)*Zoom
/oldPicscale
-cpos
.y
;
984 if (pTheOtherPic
&& bMainPic
)
986 int otherzoom
= pTheOtherPic
->GetZoom();
987 nHSecondScrollPos
= (nHSecondScrollPos
+ cpos
.x
)*otherzoom
/oldOtherPicscale
-cpos
.x
;
988 nVSecondScrollPos
= (nVSecondScrollPos
+ cpos
.y
)*otherzoom
/oldOtherPicscale
-cpos
.y
;
993 nHScrollPos
= (nHScrollPos
+ ((clientrect
.right
-clientrect
.left
)/2))*Zoom
/oldPicscale
-((clientrect
.right
-clientrect
.left
)/2);
994 nVScrollPos
= (nVScrollPos
+ ((clientrect
.bottom
-clientrect
.top
)/2))*Zoom
/oldPicscale
-((clientrect
.bottom
-clientrect
.top
)/2);
995 if (pTheOtherPic
&& bMainPic
)
997 int otherzoom
= pTheOtherPic
->GetZoom();
998 nHSecondScrollPos
= (nHSecondScrollPos
+ ((clientrect
.right
-clientrect
.left
)/2))*otherzoom
/oldOtherPicscale
-((clientrect
.right
-clientrect
.left
)/2);
999 nVSecondScrollPos
= (nVSecondScrollPos
+ ((clientrect
.bottom
-clientrect
.top
)/2))*otherzoom
/oldOtherPicscale
-((clientrect
.bottom
-clientrect
.top
)/2);
1006 InvalidateRect(*this, NULL
, TRUE
);
1009 void CPicWindow::Zoom(bool in
, bool centermouse
)
1013 // Find correct zoom factor and quantize picscale
1022 if (!in
&& picscale
<= 20)
1027 else if ((in
&& picscale
< 100) || (!in
&& picscale
<= 100))
1031 else if ((in
&& picscale
< 200) || (!in
&& picscale
<= 200))
1043 SetZoom(picscale
+zoomFactor
, centermouse
);
1047 SetZoom(picscale
-zoomFactor
, centermouse
);
1051 void CPicWindow::FitImageInWindow()
1055 GetClientRectWithScrollbars(&rect
);
1057 if (rect
.right
-rect
.left
)
1060 if (((rect
.right
- rect
.left
) > picture
.m_Width
+2)&&((rect
.bottom
- rect
.top
)> picture
.m_Height
+2))
1062 // image is smaller than the window
1067 // image is bigger than the window
1068 int xscale
= (rect
.right
-rect
.left
-2)*100/picture
.m_Width
;
1069 int yscale
= (rect
.bottom
-rect
.top
-2)*100/picture
.m_Height
;
1070 Zoom
= min(yscale
, xscale
);
1074 if (((rect
.right
- rect
.left
) > pSecondPic
->m_Width
+2)&&((rect
.bottom
- rect
.top
)> pSecondPic
->m_Height
+2))
1076 // image is smaller than the window
1078 pTheOtherPic
->SetZoom(min(100, Zoom
), false);
1082 // image is bigger than the window
1083 int xscale
= (rect
.right
-rect
.left
-2)*100/pSecondPic
->m_Width
;
1084 int yscale
= (rect
.bottom
-rect
.top
-2)*100/pSecondPic
->m_Height
;
1086 pTheOtherPic
->SetZoom(min(yscale
, xscale
), false);
1088 nHSecondScrollPos
= 0;
1089 nVSecondScrollPos
= 0;
1091 SetZoom(Zoom
, false);
1095 InvalidateRect(*this, NULL
, TRUE
);
1098 void CPicWindow::CenterImage()
1101 GetClientRectWithScrollbars(&rect
);
1102 long width
= picture
.m_Width
*picscale
/100 + 2;
1103 long height
= picture
.m_Height
*picscale
/100 + 2;
1104 if (pSecondPic
&& pTheOtherPic
)
1106 width
= max(width
, pSecondPic
->m_Width
*pTheOtherPic
->GetZoom()/100 + 2);
1107 height
= max(height
, pSecondPic
->m_Height
*pTheOtherPic
->GetZoom()/100 + 2);
1110 bool bPicWidthBigger
= (int(width
) > (rect
.right
-rect
.left
));
1111 bool bPicHeightBigger
= (int(height
) > (rect
.bottom
-rect
.top
));
1112 // set the scroll position so that the image is drawn centered in the window
1113 // if the window is bigger than the image
1114 if (!bPicWidthBigger
)
1116 nHScrollPos
= -((rect
.right
-rect
.left
+4)-int(width
))/2;
1117 nHSecondScrollPos
= nHScrollPos
;
1119 if (!bPicHeightBigger
)
1121 nVScrollPos
= -((rect
.bottom
-rect
.top
+4)-int(height
))/2;
1122 nVSecondScrollPos
= nVScrollPos
;
1127 void CPicWindow::FitWidths(bool bFit
)
1131 SetZoom(GetZoom(), false);
1134 void CPicWindow::FitHeights(bool bFit
)
1138 SetZoom(GetZoom(), false);
1141 void CPicWindow::ShowPicWithBorder(HDC hdc
, const RECT
&bounds
, CPicture
&pic
, int scale
)
1143 ::SetBkColor(hdc
, transparentColor
);
1144 ::ExtTextOut(hdc
, 0, 0, ETO_OPAQUE
, &bounds
, NULL
, 0, NULL
);
1147 picrect
.left
= bounds
.left
- nHScrollPos
;
1148 picrect
.top
= bounds
.top
- nVScrollPos
;
1149 if ((!bLinkedPositions
|| bOverlap
) && (pTheOtherPic
) && (&pic
!= &picture
))
1151 picrect
.left
= bounds
.left
- nHSecondScrollPos
;
1152 picrect
.top
= bounds
.top
- nVSecondScrollPos
;
1154 picrect
.right
= (picrect
.left
+ pic
.m_Width
* scale
/ 100);
1155 picrect
.bottom
= (picrect
.top
+ pic
.m_Height
* scale
/ 100);
1157 if (bFitWidths
&& m_linkedWidth
)
1158 picrect
.right
= picrect
.left
+ m_linkedWidth
;
1159 if (bFitHeights
&& m_linkedHeight
)
1160 picrect
.bottom
= picrect
.top
+ m_linkedHeight
;
1162 pic
.Show(hdc
, picrect
);
1165 border
.left
= picrect
.left
-1;
1166 border
.top
= picrect
.top
-1;
1167 border
.right
= picrect
.right
+1;
1168 border
.bottom
= picrect
.bottom
+1;
1170 HPEN hPen
= CreatePen(PS_SOLID
, 1, GetSysColor(COLOR_3DDKSHADOW
));
1171 HPEN hOldPen
= (HPEN
)SelectObject(hdc
, hPen
);
1172 MoveToEx(hdc
, border
.left
, border
.top
, NULL
);
1173 LineTo(hdc
, border
.left
, border
.bottom
);
1174 LineTo(hdc
, border
.right
, border
.bottom
);
1175 LineTo(hdc
, border
.right
, border
.top
);
1176 LineTo(hdc
, border
.left
, border
.top
);
1177 SelectObject(hdc
, hOldPen
);
1181 void CPicWindow::Paint(HWND hwnd
)
1185 RECT rect
, fullrect
;
1187 GetUpdateRect(hwnd
, &rect
, FALSE
);
1188 if (IsRectEmpty(&rect
))
1191 ::GetClientRect(*this, &fullrect
);
1192 hdc
= BeginPaint(hwnd
, &ps
);
1194 // Exclude the alpha control and button
1195 if ((pSecondPic
)&&(m_blend
== BLEND_ALPHA
))
1196 ExcludeClipRect(hdc
, 0, m_inforect
.top
-4, SLIDER_WIDTH
, m_inforect
.bottom
+4);
1198 CMyMemDC
memDC(hdc
);
1199 if ((pSecondPic
)&&(m_blend
!= BLEND_ALPHA
))
1201 // erase the place where the alpha slider would be
1202 ::SetBkColor(memDC
, transparentColor
);
1203 RECT bounds
= {0, m_inforect
.top
-4, SLIDER_WIDTH
, m_inforect
.bottom
+4};
1204 ::ExtTextOut(memDC
, 0, 0, ETO_OPAQUE
, &bounds
, NULL
, 0, NULL
);
1207 GetClientRect(&rect
);
1210 ShowPicWithBorder(memDC
, rect
, picture
, picscale
);
1213 HDC secondhdc
= CreateCompatibleDC(hdc
);
1214 HBITMAP hBitmap
= CreateCompatibleBitmap(hdc
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
1215 HBITMAP hOldBitmap
= (HBITMAP
)SelectObject(secondhdc
, hBitmap
);
1216 SetWindowOrgEx(secondhdc
, rect
.left
, rect
.top
, NULL
);
1218 if ((pSecondPic
)&&(m_blend
!= BLEND_ALPHA
))
1220 // erase the place where the alpha slider would be
1221 ::SetBkColor(secondhdc
, transparentColor
);
1222 RECT bounds
= {0, m_inforect
.top
-4, SLIDER_WIDTH
, m_inforect
.bottom
+4};
1223 ::ExtTextOut(secondhdc
, 0, 0, ETO_OPAQUE
, &bounds
, NULL
, 0, NULL
);
1226 ShowPicWithBorder(secondhdc
, rect
, *pSecondPic
, pTheOtherPic
->GetZoom());
1228 if (m_blend
== BLEND_ALPHA
)
1230 BLENDFUNCTION blender
;
1231 blender
.AlphaFormat
= 0;
1232 blender
.BlendFlags
= 0;
1233 blender
.BlendOp
= AC_SRC_OVER
;
1234 blender
.SourceConstantAlpha
= (BYTE
)(blendAlpha
*255);
1238 rect
.right
-rect
.left
,
1239 rect
.bottom
-rect
.top
,
1243 rect
.right
-rect
.left
,
1244 rect
.bottom
-rect
.top
,
1247 else if (m_blend
== BLEND_XOR
)
1252 rect
.right
-rect
.left
,
1253 rect
.bottom
-rect
.top
,
1257 //rect.right-rect.left,
1258 //rect.bottom-rect.top,
1260 InvertRect(memDC
, &rect
);
1262 SelectObject(secondhdc
, hOldBitmap
);
1263 DeleteObject(hBitmap
);
1264 DeleteDC(secondhdc
);
1266 else if (bDragging
&& pTheOtherPic
&& !bLinkedPositions
)
1268 // when dragging, show lines indicating the position of the other image
1269 HPEN hPen
= CreatePen(PS_SOLID
, 1, GetSysColor(/*COLOR_ACTIVEBORDER*/COLOR_HIGHLIGHT
));
1270 HPEN hOldPen
= (HPEN
)SelectObject(memDC
, hPen
);
1271 int xpos
= rect
.left
- pTheOtherPic
->nHScrollPos
- 1;
1272 MoveToEx(memDC
, xpos
, rect
.top
, NULL
);
1273 LineTo(memDC
, xpos
, rect
.bottom
);
1274 xpos
= rect
.left
- pTheOtherPic
->nHScrollPos
+ pTheOtherPic
->picture
.m_Width
*pTheOtherPic
->GetZoom()/100 + 1;
1275 if (bFitWidths
&& m_linkedWidth
)
1276 xpos
= rect
.left
+ pTheOtherPic
->m_linkedWidth
+ 1;
1277 MoveToEx(memDC
, xpos
, rect
.top
, NULL
);
1278 LineTo(memDC
, xpos
, rect
.bottom
);
1280 int ypos
= rect
.top
- pTheOtherPic
->nVScrollPos
- 1;
1281 MoveToEx(memDC
, rect
.left
, ypos
, NULL
);
1282 LineTo(memDC
, rect
.right
, ypos
);
1283 ypos
= rect
.top
- pTheOtherPic
->nVScrollPos
+ pTheOtherPic
->picture
.m_Height
*pTheOtherPic
->GetZoom()/100 + 1;
1284 if (bFitHeights
&& m_linkedHeight
)
1285 ypos
= rect
.top
- pTheOtherPic
->m_linkedHeight
+ 1;
1286 MoveToEx(memDC
, rect
.left
, ypos
, NULL
);
1287 LineTo(memDC
, rect
.right
, ypos
);
1289 SelectObject(memDC
, hOldPen
);
1293 int sliderwidth
= 0;
1294 if ((pSecondPic
)&&(m_blend
== BLEND_ALPHA
))
1295 sliderwidth
= SLIDER_WIDTH
;
1296 m_inforect
.left
= rect
.left
+4+sliderwidth
;
1297 m_inforect
.top
= rect
.top
;
1298 m_inforect
.right
= rect
.right
+sliderwidth
;
1299 m_inforect
.bottom
= rect
.bottom
;
1301 SetBkColor(memDC
, transparentColor
);
1304 std::unique_ptr
<TCHAR
[]> infostring(new TCHAR
[8192]);
1305 BuildInfoString(infostring
.get(), 8192, false);
1307 NONCLIENTMETRICS metrics
= {0};
1308 metrics
.cbSize
= sizeof(NONCLIENTMETRICS
);
1310 if (!SysInfo::Instance().IsVistaOrLater())
1312 metrics
.cbSize
-= sizeof(int); // subtract the size of the iPaddedBorderWidth member which is not available on XP
1315 SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, 0, &metrics
, FALSE
);
1316 HFONT hFont
= CreateFontIndirect(&metrics
.lfStatusFont
);
1317 HFONT hFontOld
= (HFONT
)SelectObject(memDC
, (HGDIOBJ
)hFont
);
1318 // find out how big the rectangle for the text has to be
1319 DrawText(memDC
, infostring
.get(), -1, &m_inforect
, DT_EDITCONTROL
| DT_EXPANDTABS
| DT_LEFT
| DT_VCENTER
| DT_CALCRECT
);
1321 // the text should be drawn with a four pixel offset to the window borders
1322 m_inforect
.top
= rect
.bottom
- (m_inforect
.bottom
-m_inforect
.top
) - 4;
1323 m_inforect
.bottom
= rect
.bottom
-4;
1325 // first draw an edge rectangle
1327 edgerect
.left
= m_inforect
.left
-4;
1328 edgerect
.top
= m_inforect
.top
-4;
1329 edgerect
.right
= m_inforect
.right
+4;
1330 edgerect
.bottom
= m_inforect
.bottom
+4;
1331 ::ExtTextOut(memDC
, 0, 0, ETO_OPAQUE
, &edgerect
, NULL
, 0, NULL
);
1332 DrawEdge(memDC
, &edgerect
, EDGE_BUMP
, BF_RECT
| BF_SOFT
);
1334 SetTextColor(memDC
, GetSysColor(COLOR_WINDOWTEXT
));
1335 DrawText(memDC
, infostring
.get(), -1, &m_inforect
, DT_EDITCONTROL
| DT_EXPANDTABS
| DT_LEFT
| DT_VCENTER
);
1336 SelectObject(memDC
, (HGDIOBJ
)hFontOld
);
1337 DeleteObject(hFont
);
1342 SetBkColor(memDC
, ::GetSysColor(COLOR_WINDOW
));
1343 ::ExtTextOut(memDC
, 0, 0, ETO_OPAQUE
, &rect
, NULL
, 0, NULL
);
1345 ResString str
= ResString(hResource
, IDS_INVALIDIMAGEINFO
);
1348 NONCLIENTMETRICS metrics
= {0};
1349 metrics
.cbSize
= sizeof(NONCLIENTMETRICS
);
1350 if (!SysInfo::Instance().IsVistaOrLater())
1352 metrics
.cbSize
-= sizeof(int); // subtract the size of the iPaddedBorderWidth member which is not available on XP
1354 SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, 0, &metrics
, FALSE
);
1355 HFONT hFont
= CreateFontIndirect(&metrics
.lfStatusFont
);
1356 HFONT hFontOld
= (HFONT
)SelectObject(memDC
, (HGDIOBJ
)hFont
);
1358 if (GetTextExtentPoint32(memDC
, str
, (int)_tcslen(str
), &stringsize
))
1360 int nStringLength
= stringsize
.cx
;
1363 max(rect
.left
+ ((rect
.right
-rect
.left
)-nStringLength
)/2, 1),
1364 rect
.top
+ ((rect
.bottom
-rect
.top
) - stringsize
.cy
)/2,
1371 SelectObject(memDC
, (HGDIOBJ
)hFontOld
);
1372 DeleteObject(hFont
);
1374 DrawViewTitle(memDC
, &fullrect
);
1376 EndPaint(hwnd
, &ps
);
1379 bool CPicWindow::CreateButtons()
1381 // Ensure that the common control DLL is loaded.
1382 INITCOMMONCONTROLSEX icex
;
1383 icex
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
1384 icex
.dwICC
= ICC_BAR_CLASSES
| ICC_WIN95_CLASSES
;
1385 InitCommonControlsEx(&icex
);
1387 hwndLeftBtn
= CreateWindowEx(0,
1390 WS_CHILD
| WS_VISIBLE
| BS_PUSHBUTTON
| BS_ICON
| BS_FLAT
,
1393 (HMENU
)LEFTBUTTON_ID
,
1396 if (hwndLeftBtn
== INVALID_HANDLE_VALUE
)
1398 hLeft
= (HICON
)LoadImage(hResource
, MAKEINTRESOURCE(IDI_BACKWARD
), IMAGE_ICON
, 16, 16, LR_LOADTRANSPARENT
);
1399 SendMessage(hwndLeftBtn
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hLeft
);
1400 hwndRightBtn
= CreateWindowEx(0,
1403 WS_CHILD
| WS_VISIBLE
| BS_PUSHBUTTON
| BS_ICON
| BS_FLAT
,
1406 (HMENU
)RIGHTBUTTON_ID
,
1409 if (hwndRightBtn
== INVALID_HANDLE_VALUE
)
1411 hRight
= (HICON
)LoadImage(hResource
, MAKEINTRESOURCE(IDI_FORWARD
), IMAGE_ICON
, 16, 16, LR_LOADTRANSPARENT
);
1412 SendMessage(hwndRightBtn
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hRight
);
1413 hwndPlayBtn
= CreateWindowEx(0,
1416 WS_CHILD
| WS_VISIBLE
| BS_PUSHBUTTON
| BS_ICON
| BS_FLAT
,
1419 (HMENU
)PLAYBUTTON_ID
,
1422 if (hwndPlayBtn
== INVALID_HANDLE_VALUE
)
1424 hPlay
= (HICON
)LoadImage(hResource
, MAKEINTRESOURCE(IDI_START
), IMAGE_ICON
, 16, 16, LR_LOADTRANSPARENT
);
1425 hStop
= (HICON
)LoadImage(hResource
, MAKEINTRESOURCE(IDI_STOP
), IMAGE_ICON
, 16, 16, LR_LOADTRANSPARENT
);
1426 SendMessage(hwndPlayBtn
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hPlay
);
1427 hwndAlphaToggleBtn
= CreateWindowEx(0,
1430 WS_CHILD
| WS_VISIBLE
| BS_PUSHBUTTON
| BS_ICON
| BS_FLAT
| BS_NOTIFY
| BS_PUSHLIKE
,
1433 (HMENU
)ALPHATOGGLEBUTTON_ID
,
1436 if (hwndAlphaToggleBtn
== INVALID_HANDLE_VALUE
)
1438 hAlphaToggle
= (HICON
)LoadImage(hResource
, MAKEINTRESOURCE(IDI_ALPHATOGGLE
), IMAGE_ICON
, 16, 16, LR_LOADTRANSPARENT
);
1439 SendMessage(hwndAlphaToggleBtn
, BM_SETIMAGE
, (WPARAM
)IMAGE_ICON
, (LPARAM
)hAlphaToggle
);
1442 ti
.cbSize
= sizeof(TOOLINFO
);
1443 ti
.uFlags
= TTF_IDISHWND
|TTF_SUBCLASS
;
1445 ti
.hinst
= hResource
;
1446 ti
.uId
= (UINT_PTR
)hwndAlphaToggleBtn
;
1447 ti
.lpszText
= LPSTR_TEXTCALLBACK
;
1448 // ToolTip control will cover the whole window
1453 SendMessage(hwndTT
, TTM_ADDTOOL
, 0, (LPARAM
) (LPTOOLINFO
) &ti
);
1454 ResString
sSelect(hResource
, IDS_SELECT
);
1455 hwndSelectBtn
= CreateWindowEx(0,
1458 WS_CHILD
| WS_VISIBLE
| BS_PUSHBUTTON
,
1461 (HMENU
)SELECTBUTTON_ID
,
1464 if (hwndPlayBtn
== INVALID_HANDLE_VALUE
)
1470 void CPicWindow::PositionChildren()
1473 ::GetClientRect(*this, &rect
);
1474 if (HasMultipleImages())
1476 SetWindowPos(hwndLeftBtn
, HWND_TOP
, rect
.left
+3, rect
.top
+ HEADER_HEIGHT
+ (HEADER_HEIGHT
-16)/2, 16, 16, SWP_FRAMECHANGED
|SWP_SHOWWINDOW
);
1477 SetWindowPos(hwndRightBtn
, HWND_TOP
, rect
.left
+23, rect
.top
+ HEADER_HEIGHT
+ (HEADER_HEIGHT
-16)/2, 16, 16, SWP_FRAMECHANGED
|SWP_SHOWWINDOW
);
1479 SetWindowPos(hwndPlayBtn
, HWND_TOP
, rect
.left
+43, rect
.top
+ HEADER_HEIGHT
+ (HEADER_HEIGHT
-16)/2, 16, 16, SWP_FRAMECHANGED
|SWP_SHOWWINDOW
);
1481 ShowWindow(hwndPlayBtn
, SW_HIDE
);
1485 ShowWindow(hwndLeftBtn
, SW_HIDE
);
1486 ShowWindow(hwndRightBtn
, SW_HIDE
);
1487 ShowWindow(hwndPlayBtn
, SW_HIDE
);
1490 SetWindowPos(hwndSelectBtn
, HWND_TOP
, rect
.right
-100, rect
.bottom
-HEADER_HEIGHT
, 100, HEADER_HEIGHT
, SWP_FRAMECHANGED
|SWP_SHOWWINDOW
);
1492 ShowWindow(hwndSelectBtn
, SW_HIDE
);
1496 bool CPicWindow::HasMultipleImages()
1498 return (((nDimensions
> 1)||(nFrames
> 1))&&(pSecondPic
== NULL
));
1501 void CPicWindow::CreateTrackbar(HWND hwndParent
)
1503 HWND hwndTrack
= CreateWindowEx(
1504 0, // no extended styles
1505 TRACKBAR_CLASS
, // class name
1506 _T("Trackbar Control"), // title (caption)
1507 WS_CHILD
| WS_VISIBLE
| TBS_VERT
| TBS_TOOLTIPS
| TBS_AUTOTICKS
, // style
1510 hwndParent
, // parent window
1511 (HMENU
)TRACKBAR_ID
, // control identifier
1513 NULL
// no WM_CREATE parameter
1516 SendMessage(hwndTrack
, TBM_SETRANGE
,
1517 (WPARAM
) TRUE
, // redraw flag
1518 (LPARAM
) MAKELONG(0, 16)); // min. & max. positions
1519 SendMessage(hwndTrack
, TBM_SETTIPSIDE
,
1523 m_AlphaSlider
.ConvertTrackbarToNice(hwndTrack
);
1526 void CPicWindow::BuildInfoString(TCHAR
* buf
, int size
, bool bTooltip
)
1528 // Unfortunately, we need two different strings for the tooltip
1529 // and the info box. Because the tooltips use a different tab size
1530 // than ExtTextOut(), and to keep the output aligned we therefore
1531 // need two different strings.
1532 // Note: some translations could end up with two identical strings, but
1533 // in English we need two - even if we wouldn't need two in English, some
1534 // translation might then need two again.
1535 if (pSecondPic
&& pTheOtherPic
)
1537 _stprintf_s(buf
, size
,
1538 (TCHAR
const *)ResString(hResource
, bTooltip
? IDS_DUALIMAGEINFOTT
: IDS_DUALIMAGEINFO
),
1539 picture
.GetFileSizeAsText().c_str(), picture
.GetFileSizeAsText(false).c_str(),
1540 picture
.m_Width
, picture
.m_Height
,
1541 picture
.GetHorizontalResolution(), picture
.GetVerticalResolution(),
1542 picture
.m_ColorDepth
,
1544 pSecondPic
->GetFileSizeAsText().c_str(), pSecondPic
->GetFileSizeAsText(false).c_str(),
1545 pSecondPic
->m_Width
, pSecondPic
->m_Height
,
1546 pSecondPic
->GetHorizontalResolution(), pSecondPic
->GetVerticalResolution(),
1547 pSecondPic
->m_ColorDepth
,
1548 (UINT
)pTheOtherPic
->GetZoom());
1552 _stprintf_s(buf
, size
,
1553 (TCHAR
const *)ResString(hResource
, bTooltip
? IDS_IMAGEINFOTT
: IDS_IMAGEINFO
),
1554 picture
.GetFileSizeAsText().c_str(), picture
.GetFileSizeAsText(false).c_str(),
1555 picture
.m_Width
, picture
.m_Height
,
1556 picture
.GetHorizontalResolution(), picture
.GetVerticalResolution(),
1557 picture
.m_ColorDepth
,
1562 void CPicWindow::SetZoomToWidth( long width
)
1564 m_linkedWidth
= width
;
1565 if (picture
.m_Width
)
1567 int zoom
= width
*100/picture
.m_Width
;
1568 SetZoom(zoom
, false, true);
1572 void CPicWindow::SetZoomToHeight( long height
)
1574 m_linkedHeight
= height
;
1575 if (picture
.m_Height
)
1577 int zoom
= height
*100/picture
.m_Height
;
1578 SetZoom(zoom
, false, true);