#include <string>\r
#include <algorithm>\r
#include <cstdio>\r
+#include <array>\r
#include "FreeImagePlus.h"\r
#include "CImgWindow.hpp"\r
#include "WinIMergeLib.h"\r
T* m_data;\r
};\r
\r
+struct DiffInfo\r
+{\r
+ enum OP_TYPE\r
+ {\r
+ OP_NONE = 0, OP_1STONLY, OP_2NDONLY, OP_3RDONLY, OP_DIFF, OP_TRIVIAL\r
+ };\r
+ DiffInfo(int op, int x, int y) : op(op), pt(x, y) {}\r
+ int op;\r
+ Point<int> pt;\r
+};\r
+\r
class CImgMergeWindow : public IImgMergeWindow\r
{\r
+ struct EventListenerInfo \r
+ {\r
+ EventListenerInfo(EventListenerFunc func, void *userdata) : func(func), userdata(userdata) {}\r
+ EventListenerFunc func;\r
+ void *userdata;\r
+ };\r
+\r
public:\r
CImgMergeWindow() : \r
m_nImages(0)\r
, m_selDiffColor(RGB(0xff, 0x40, 0x40))\r
, m_diffColor(RGB(0xff, 0xff, 0x40))\r
, m_currentDiffIndex(-1)\r
- {}\r
+ {\r
+ memset(m_ChildWndProc, 0, sizeof(m_ChildWndProc));\r
+ }\r
\r
~CImgMergeWindow()\r
{\r
return !!bSucceeded;\r
}\r
\r
+ void AddEventListener(EventListenerFunc func, void *userdata)\r
+ {\r
+ m_listener.push_back(EventListenerInfo(func, userdata));\r
+ }\r
+\r
bool SetWindowRect(const RECT& rc)\r
{\r
MoveWindow(m_hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);\r
return true;\r
}\r
\r
+ int GetActivePane() const\r
+ {\r
+ for (int i = 0; i < m_nImages; ++i)\r
+ if (m_imgWindow[i].IsFocused())\r
+ return i;\r
+ return -1;\r
+ }\r
+\r
+ void SetActivePane(int pane)\r
+ {\r
+ m_imgWindow[pane].SetFocus();\r
+ }\r
+\r
bool GetHorizontalSplit() const\r
{\r
return m_bHorizontalSplit;\r
return true;\r
}\r
\r
+ bool FirstConflict()\r
+ {\r
+ for (int i = 0; m_diffInfos.size(); ++i)\r
+ if (m_diffInfos[i].op == DiffInfo::OP_DIFF)\r
+ m_currentDiffIndex = i;\r
+ RefreshImages();\r
+ ScrollToDiff(m_currentDiffIndex);\r
+ return true;\r
+ }\r
+\r
+ bool LastConflict()\r
+ {\r
+ for (int i = m_diffInfos.size() - 1; i >= 0; --i)\r
+ if (m_diffInfos[i].op == DiffInfo::OP_DIFF)\r
+ m_currentDiffIndex = i;\r
+ RefreshImages();\r
+ ScrollToDiff(m_currentDiffIndex);\r
+ return true;\r
+ }\r
+\r
+ bool NextConflict()\r
+ {\r
+ for (int i = m_currentDiffIndex + 1; i < m_diffInfos.size(); ++i)\r
+ if (m_diffInfos[i].op == DiffInfo::OP_DIFF)\r
+ m_currentDiffIndex = i;\r
+ RefreshImages();\r
+ ScrollToDiff(m_currentDiffIndex);\r
+ return true;\r
+ }\r
+\r
+ bool PrevConflict()\r
+ {\r
+ for (int i = m_currentDiffIndex - 1; i >= 0; --i)\r
+ if (m_diffInfos[i].op == DiffInfo::OP_DIFF)\r
+ m_currentDiffIndex = i;\r
+ RefreshImages();\r
+ ScrollToDiff(m_currentDiffIndex);\r
+ return true;\r
+ }\r
+\r
void CompareImages()\r
{\r
if (m_nImages <= 1)\r
{\r
CompareImages2(0, 1, m_diff01);\r
CompareImages2(2, 1, m_diff21);\r
+ CompareImages2(0, 2, m_diff02);\r
Make3WayDiff(m_diff01, m_diff21, m_diff);\r
- m_diffCount = MarkDiffIndex(m_diff);\r
+ m_diffCount = MarkDiffIndex3way(m_diff01, m_diff21, m_diff02, m_diff);\r
}\r
}\r
RefreshImages();\r
\r
void ScrollToDiff(int diffIndex)\r
{\r
- if (diffIndex >= 0 && diffIndex < m_diffPositions.size())\r
+ if (diffIndex >= 0 && diffIndex < m_diffInfos.size())\r
{\r
for (int i = 0; i < m_nImages; ++i)\r
- m_imgWindow[i].ScrollTo(m_diffPositions[diffIndex].x * m_diffBlockSize, m_diffPositions[diffIndex].y * m_diffBlockSize);\r
+ m_imgWindow[i].ScrollTo(m_diffInfos[diffIndex].pt.x * m_diffBlockSize, m_diffInfos[diffIndex].pt.y * m_diffBlockSize);\r
}\r
}\r
\r
}\r
if (m_showDifferences)\r
{\r
- if (m_nImages == 2)\r
- {\r
- MarkDiff(0, m_diff);\r
- MarkDiff(1, m_diff);\r
- }\r
- else if (m_nImages == 3)\r
- {\r
- MarkDiff(0, m_diff);\r
- MarkDiff(1, m_diff);\r
- MarkDiff(1, m_diff);\r
- MarkDiff(2, m_diff);\r
- }\r
+ for (int i = 0; i < m_nImages; ++i)\r
+ MarkDiff(i, m_diff);\r
}\r
for (int i = 0; i < m_nImages; ++i)\r
m_imgWindow[i].Invalidate();\r
for (int i = 0; i < nImages; ++i)\r
{\r
m_imgWindow[i].Create(m_hInstance, m_hWnd);\r
- for (int j = 0; j < nImages; ++j)\r
- {\r
- if (i != j)\r
- m_imgWindow[i].AddSibling(&m_imgWindow[j]);\r
- }\r
+ m_ChildWndProc[i] = (WNDPROC)SetWindowLongPtr(m_imgWindow[i].GetHWND(), GWLP_WNDPROC, (LONG_PTR)&ChildWndProc);\r
}\r
CompareImages();\r
std::vector<RECT> rects = CalcChildImgWindowRect(m_hWnd, nImages, m_bHorizontalSplit);\r
m_diff01.resize(nBlocksX, nBlocksY);\r
m_diff21.clear();\r
m_diff21.resize(nBlocksX, nBlocksY);\r
+ m_diff02.clear();\r
+ m_diff02.resize(nBlocksX, nBlocksY);\r
}\r
- m_diffPositions.clear();\r
+ m_diffInfos.clear();\r
}\r
\r
void InitializeDiffImages()\r
int MarkDiffIndex(Array2D<unsigned>& diff)\r
{\r
int diffCount = 0;\r
- for (unsigned bx = 0; bx < diff.width(); ++bx)\r
+ for (unsigned by = 0; by < diff.height(); ++by)\r
{\r
- for (unsigned by = 0; by < diff.height(); ++by)\r
+ for (unsigned bx = 0; bx < diff.width(); ++bx)\r
{\r
if (diff(bx, by) == -1)\r
{\r
- m_diffPositions.push_back(Point<int>(bx, by));\r
+ m_diffInfos.push_back(DiffInfo(DiffInfo::OP_DIFF, bx, by));\r
++diffCount;\r
FloodFill8Directions(diff, bx, by, diffCount);\r
}\r
return diffCount;\r
}\r
\r
+ int MarkDiffIndex3way(Array2D<unsigned>& diff01, Array2D<unsigned>& diff21, Array2D<unsigned>& diff02, Array2D<unsigned>& diff3)\r
+ {\r
+ int diffCount = MarkDiffIndex(diff3);\r
+ std::vector<std::array<int, 4>> counter(m_diffInfos.size());\r
+ for (unsigned by = 0; by < diff3.height(); ++by)\r
+ {\r
+ for (unsigned bx = 0; bx < diff3.width(); ++bx)\r
+ {\r
+ int diffIndex = diff3(bx, by);\r
+ if (diffIndex == 0)\r
+ continue;\r
+ --diffIndex;\r
+ if (diff21(bx, by) == 0)\r
+ ++counter[diffIndex][0];\r
+ else if (diff02(bx, by) == 0)\r
+ ++counter[diffIndex][1];\r
+ else if (diff01(bx, by) == 0)\r
+ ++counter[diffIndex][2];\r
+ else\r
+ ++counter[diffIndex][3];\r
+ }\r
+ }\r
+ \r
+ for (int i = 0; i < m_diffInfos.size(); ++i)\r
+ {\r
+ int op;\r
+ if (counter[i][0] != 0 && counter[i][1] == 0 && counter[i][2] == 0 && counter[i][3] == 0)\r
+ op = DiffInfo::OP_1STONLY;\r
+ else if (counter[i][0] == 0 && counter[i][1] != 0 && counter[i][2] == 0 && counter[i][3] == 0)\r
+ op = DiffInfo::OP_2NDONLY;\r
+ else if (counter[i][0] == 0 && counter[i][1] == 0 && counter[i][2] != 0 && counter[i][3] == 0)\r
+ op = DiffInfo::OP_3RDONLY;\r
+ else\r
+ op = DiffInfo::OP_DIFF;\r
+ m_diffInfos[i].op = op;\r
+ }\r
+ return diffCount;\r
+ }\r
+\r
void Make3WayDiff(const Array2D<unsigned>& diff01, const Array2D<unsigned>& diff21, Array2D<unsigned>& diff3)\r
{\r
diff3 = diff01;\r
for (unsigned bx = 0; bx < diff.width(); ++bx)\r
{\r
unsigned diffIndex = diff(bx, by);\r
- if (diffIndex != 0)\r
+ if (diffIndex != 0 && (\r
+ (pane == 0 && m_diffInfos[diffIndex - 1].op != DiffInfo::OP_3RDONLY) ||\r
+ (pane == 1) ||\r
+ (pane == 2 && m_diffInfos[diffIndex - 1].op != DiffInfo::OP_1STONLY)\r
+ ))\r
{\r
COLORREF color = (diffIndex - 1 == m_currentDiffIndex) ? m_selDiffColor : m_diffColor;\r
unsigned bsy = (h - by * m_diffBlockSize < m_diffBlockSize) ? (h - by * m_diffBlockSize) : m_diffBlockSize;\r
scanline_dst[x * 4 + 0] ^= scanline_src[x * 4 + 0];\r
scanline_dst[x * 4 + 1] ^= scanline_src[x * 4 + 1];\r
scanline_dst[x * 4 + 2] ^= scanline_src[x * 4 + 2];\r
- //scanline_dst[x * 4 + 3] ^= scanline_src[x * 4 + 3];\r
}\r
} \r
}\r
\r
void OnDestroy()\r
{\r
+ for (int i = 0; i < m_nImages; ++i)\r
+ {\r
+ if (m_ChildWndProc[i])\r
+ {\r
+ SetWindowLongPtr(m_imgWindow[i].GetHWND(), GWLP_WNDPROC, (LONG_PTR)m_ChildWndProc[i]);\r
+ m_ChildWndProc[i] = NULL;\r
+ }\r
+ }\r
}\r
\r
LRESULT OnWndMsg(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)\r
case WM_CREATE:\r
OnCreate(hwnd, (LPCREATESTRUCT)lParam);\r
break;\r
+ case WM_COMMAND:\r
+ PostMessage(GetParent(m_hWnd), iMsg, wParam, lParam);\r
+ break;\r
case WM_SIZE:\r
OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam));\r
break;\r
return lResult;\r
}\r
\r
+ static LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)\r
+ {\r
+ Event evt;\r
+ int i;\r
+ CImgMergeWindow *pImgWnd = (CImgMergeWindow *)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);\r
+ for (i = 0; i < pImgWnd->m_nImages; ++i)\r
+ if (pImgWnd->m_imgWindow[i].GetHWND() == hwnd)\r
+ break;\r
+ evt.pane = i;\r
+ evt.flags = (unsigned)wParam; \r
+ evt.x = (int)(short)LOWORD(lParam);\r
+ evt.y = (int)(short)HIWORD(lParam);\r
+ switch(iMsg)\r
+ {\r
+ case WM_LBUTTONDOWN:\r
+ evt.eventType = LBUTTONDOWN; goto NEXT;\r
+ case WM_LBUTTONUP:\r
+ evt.eventType = LBUTTONUP; goto NEXT;\r
+ case WM_LBUTTONDBLCLK:\r
+ evt.eventType = LBUTTONDBLCLK; goto NEXT;\r
+ case WM_RBUTTONDOWN:\r
+ evt.eventType = RBUTTONDOWN; goto NEXT;\r
+ case WM_RBUTTONUP:\r
+ evt.eventType = RBUTTONUP; goto NEXT;\r
+ case WM_RBUTTONDBLCLK:\r
+ evt.eventType = RBUTTONDBLCLK; goto NEXT;\r
+ case WM_MOUSEMOVE:\r
+ evt.eventType = MOUSEMOVE; goto NEXT;\r
+ case WM_MOUSEWHEEL:\r
+ evt.flags = GET_KEYSTATE_WPARAM(wParam);\r
+ evt.eventType = MOUSEWHEEL;\r
+ evt.delta = GET_WHEEL_DELTA_WPARAM(wParam);\r
+ goto NEXT;\r
+ case WM_CONTEXTMENU:\r
+ evt.eventType = CONTEXTMENU; goto NEXT;\r
+ case WM_SIZE:\r
+ evt.eventType = SIZE; evt.width = LOWORD(lParam); evt.height = HIWORD(wParam); goto NEXT;\r
+ case WM_HSCROLL:\r
+ evt.eventType = HSCROLL;goto NEXT;\r
+ case WM_VSCROLL:\r
+ evt.eventType = VSCROLL; goto NEXT;\r
+ case WM_SETFOCUS:\r
+ evt.eventType = SETFOCUS; goto NEXT;\r
+ case WM_KILLFOCUS:\r
+ evt.eventType = KILLFOCUS; goto NEXT;\r
+ NEXT:\r
+ {\r
+ std::vector<EventListenerInfo>::iterator it;\r
+ for (it = pImgWnd->m_listener.begin(); it != pImgWnd->m_listener.end(); ++it)\r
+ {\r
+ evt.userdata = (*it).userdata;\r
+ (*it).func(evt);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+ switch (iMsg)\r
+ {\r
+ case WM_HSCROLL:\r
+ case WM_VSCROLL:\r
+ case WM_MOUSEWHEEL:\r
+ for (int j = 0; j < pImgWnd->m_nImages; ++j)\r
+ {\r
+ if (j != i)\r
+ (pImgWnd->m_ChildWndProc[j])(pImgWnd->m_imgWindow[j].GetHWND(), iMsg, wParam, lParam);\r
+ }\r
+ break;\r
+ }\r
+ return (pImgWnd->m_ChildWndProc[i])(hwnd, iMsg, wParam, lParam);\r
+ }\r
+\r
int m_nImages;\r
HWND m_hWnd;\r
HINSTANCE m_hInstance;\r
fipImage m_imgOrig32[3];\r
fipWinImage m_imgDiff[3];\r
CImgWindow m_imgWindow[3];\r
+ WNDPROC m_ChildWndProc[3];\r
+ std::vector<EventListenerInfo> m_listener;\r
std::wstring m_filename[3];\r
int m_nDraggingSplitter;\r
bool m_bHorizontalSplit;\r
int m_currentPage[3];\r
int m_currentDiffIndex;\r
int m_diffCount;\r
- Array2D<unsigned> m_diff, m_diff01, m_diff21;\r
- std::vector<Point<int> > m_diffPositions;\r
+ Array2D<unsigned> m_diff, m_diff01, m_diff21, m_diff02;\r
+ std::vector<DiffInfo> m_diffInfos;\r
};\r
, m_nVScrollPos(0)\r
, m_nHScrollPos(0)\r
, m_zoom(1.0)\r
- , m_inEvent(false)\r
, m_useBackColor(true)\r
{\r
memset(&m_backColor, 0xff, sizeof(m_backColor));\r
DestroyWindow(m_hWnd);\r
m_fip = NULL;\r
m_hWnd = NULL;\r
- m_siblings.clear();\r
return true;\r
}\r
\r
MoveWindow(m_hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);\r
}\r
\r
+ void SetFocus()\r
+ {\r
+ ::SetFocus(m_hWnd);\r
+ }\r
+\r
+ bool IsFocused() const\r
+ {\r
+ return m_hWnd == GetFocus();\r
+ }\r
+\r
void ScrollTo(int x, int y)\r
{\r
SCROLLINFO sih = {0}, siv = {0};\r
m_nVScrollPos = siv.nMax - siv.nPage;\r
}\r
\r
- ScrollWindow(m_hWnd, sih.nPos - m_nHScrollPos, siv.nPos - m_nVScrollPos, NULL, NULL);\r
+ RECT rcClip = {rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1};\r
+ ScrollWindow(m_hWnd, sih.nPos - m_nHScrollPos, siv.nPos - m_nVScrollPos, NULL, &rcClip);\r
CalcScrollBarRange();\r
InvalidateRect(m_hWnd, NULL, TRUE);\r
}\r
CalcScrollBarRange();\r
}\r
\r
- void AddSibling(CImgWindow *pImgWindow)\r
- {\r
- m_siblings.push_back(pImgWindow);\r
- }\r
-\r
private:\r
\r
ATOM MyRegisterClass(HINSTANCE hInstance)\r
rcImg.bottom = static_cast<int>(m_fip->getHeight() * m_zoom - m_nVScrollPos);\r
}\r
m_fip->drawEx(hdc, rcImg, false, m_useBackColor ? &m_backColor : NULL);\r
+ if (GetFocus() == m_hWnd)\r
+ {\r
+ DrawFocusRect(hdc, &rc);\r
+ }\r
+ else\r
+ {\r
+ HPEN hPen = (HPEN)GetStockObject(WHITE_PEN);\r
+ HBRUSH hBrush = (HBRUSH)GetStockObject(NULL_BRUSH);\r
+ HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);\r
+ HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);\r
+ Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);\r
+ SelectObject(hdc, hOldPen);\r
+ SelectObject(hdc, hOldBrush);\r
+ }\r
}\r
EndPaint(m_hWnd, &ps);\r
}\r
\r
void OnHScroll(UINT nSBCode, UINT nPos)\r
{\r
- if (m_inEvent)\r
- return;\r
-\r
SCROLLINFO si = {0};\r
si.cbSize = sizeof SCROLLINFO;\r
si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE | SIF_TRACKPOS;\r
m_nHScrollPos = 0;\r
if (m_nHScrollPos > si.nMax - static_cast<int>(si.nPage))\r
m_nHScrollPos = si.nMax - si.nPage;\r
- ScrollWindow(m_hWnd, si.nPos - m_nHScrollPos, 0, NULL, NULL);\r
+ RECT rc;\r
+ GetClientRect(m_hWnd, &rc);\r
+ RECT rcClip = {rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1};\r
+ ScrollWindow(m_hWnd, si.nPos - m_nHScrollPos, 0, NULL, &rcClip);\r
CalcScrollBarRange();\r
-\r
- m_inEvent = true;\r
- std::vector<CImgWindow *>::iterator it;\r
- for (it = m_siblings.begin(); it != m_siblings.end(); ++it)\r
- (*it)->OnHScroll(nSBCode, nPos);\r
- m_inEvent = false;\r
}\r
\r
void OnVScroll(UINT nSBCode, UINT nPos)\r
{\r
- if (m_inEvent)\r
- return;\r
-\r
SCROLLINFO si = {0};\r
si.cbSize = sizeof SCROLLINFO;\r
si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE | SIF_TRACKPOS;\r
m_nVScrollPos = 0;\r
if (m_nVScrollPos > si.nMax - static_cast<int>(si.nPage))\r
m_nVScrollPos = si.nMax - si.nPage;\r
- ScrollWindow(m_hWnd, 0, si.nPos - m_nVScrollPos, NULL, NULL);\r
+ RECT rc;\r
+ GetClientRect(m_hWnd, &rc);\r
+ RECT rcClip = {rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1};\r
+ ScrollWindow(m_hWnd, 0, si.nPos - m_nVScrollPos, NULL, &rcClip);\r
CalcScrollBarRange();\r
-\r
- m_inEvent = true;\r
- std::vector<CImgWindow *>::iterator it;\r
- for (it = m_siblings.begin(); it != m_siblings.end(); ++it)\r
- (*it)->OnVScroll(nSBCode, nPos);\r
- m_inEvent = false;\r
}\r
\r
void OnLButtonDown(UINT nFlags, int x, int y)\r
{\r
+ SetFocus();\r
}\r
\r
- void OnMouseWheel(UINT nFlags, short zDelta)\r
+ void OnRButtonDown(UINT nFlags, int x, int y)\r
{\r
- if (m_inEvent)\r
- return;\r
+ SetFocus();\r
+ }\r
\r
- const bool ctrlDown = (GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0;\r
- if (!ctrlDown)\r
+ void OnMouseWheel(UINT nFlags, short zDelta)\r
+ {\r
+ if (!(nFlags & MK_CONTROL))\r
{ \r
RECT rc;\r
GetClientRect(m_hWnd, &rc);\r
- if (rc.bottom - rc.top < m_fip->getHeight() * m_zoom)\r
+ if (!(nFlags & MK_SHIFT))\r
{\r
- SCROLLINFO si = {0};\r
- si.cbSize = sizeof SCROLLINFO;\r
- si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE | SIF_TRACKPOS;\r
- GetScrollInfo(m_hWnd, SB_VERT, &si);\r
- m_nVScrollPos += - zDelta / (WHEEL_DELTA / 16);\r
- if (m_nVScrollPos < 0)\r
- m_nVScrollPos = 0;\r
- if (m_nVScrollPos > si.nMax - static_cast<int>(si.nPage))\r
- m_nVScrollPos = si.nMax - si.nPage;\r
- ScrollWindow(m_hWnd, 0, si.nPos - m_nVScrollPos, NULL, NULL);\r
- CalcScrollBarRange();\r
+ if (rc.bottom - rc.top < m_fip->getHeight() * m_zoom)\r
+ {\r
+ SCROLLINFO si = {0};\r
+ si.cbSize = sizeof SCROLLINFO;\r
+ si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE | SIF_TRACKPOS;\r
+ GetScrollInfo(m_hWnd, SB_VERT, &si);\r
+ m_nVScrollPos += - zDelta / (WHEEL_DELTA / 16);\r
+ if (m_nVScrollPos < 0)\r
+ m_nVScrollPos = 0;\r
+ if (m_nVScrollPos > si.nMax - static_cast<int>(si.nPage))\r
+ m_nVScrollPos = si.nMax - si.nPage;\r
+ RECT rcClip = {rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1};\r
+ ScrollWindow(m_hWnd, 0, si.nPos - m_nVScrollPos, NULL, &rcClip);\r
+ CalcScrollBarRange();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (rc.right - rc.left < m_fip->getWidth() * m_zoom)\r
+ {\r
+ SCROLLINFO si = {0};\r
+ si.cbSize = sizeof SCROLLINFO;\r
+ si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE | SIF_TRACKPOS;\r
+ GetScrollInfo(m_hWnd, SB_HORZ, &si);\r
+ m_nHScrollPos += - zDelta / (WHEEL_DELTA / 16);\r
+ if (m_nHScrollPos < 0)\r
+ m_nHScrollPos = 0;\r
+ if (m_nHScrollPos > si.nMax - static_cast<int>(si.nPage))\r
+ m_nHScrollPos = si.nMax - si.nPage;\r
+ RECT rcClip = {rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1};\r
+ ScrollWindow(m_hWnd, si.nPos - m_nHScrollPos, 0, NULL, &rcClip);\r
+ CalcScrollBarRange();\r
+ }\r
}\r
}\r
else\r
else\r
SetZoom(m_zoom * 0.8);\r
}\r
+ }\r
\r
- m_inEvent = true;\r
- std::vector<CImgWindow *>::iterator it;\r
- for (it = m_siblings.begin(); it != m_siblings.end(); ++it)\r
- (*it)->OnMouseWheel(nFlags, zDelta);\r
- m_inEvent = false;\r
+ void OnSetFocus(HWND hwndOld)\r
+ {\r
+ InvalidateRect(m_hWnd, NULL, TRUE);\r
+ }\r
+\r
+ void OnKillFocus(HWND hwndNew)\r
+ {\r
+ InvalidateRect(m_hWnd, NULL, TRUE);\r
}\r
\r
LRESULT OnWndMsg(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)\r
case WM_LBUTTONDOWN:\r
OnLButtonDown((UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam));\r
break;\r
+ case WM_RBUTTONDOWN:\r
+ OnRButtonDown((UINT)(wParam), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam));\r
+ break;\r
case WM_MOUSEWHEEL:\r
OnMouseWheel(GET_KEYSTATE_WPARAM(wParam), GET_WHEEL_DELTA_WPARAM(wParam));\r
break;\r
+ case WM_SETFOCUS:\r
+ OnSetFocus((HWND)wParam);\r
+ break;\r
+ case WM_KILLFOCUS:\r
+ OnKillFocus((HWND)wParam);\r
+ break;\r
+ case WM_COMMAND:\r
+ PostMessage(GetParent(m_hWnd), iMsg, wParam, lParam);\r
+ break;\r
case WM_SIZE:\r
OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam));\r
break;\r
int m_nVScrollPos;\r
int m_nHScrollPos;\r
double m_zoom;\r
- std::vector<CImgWindow *> m_siblings;\r
- bool m_inEvent;\r
bool m_useBackColor;\r
RGBQUAD m_backColor;\r
};
\ No newline at end of file
CheckMenuItem(hMenu, ID_VIEW_USEBACKCOLOR, m_pImgMergeWindow->GetUseBackColor() ? MF_CHECKED : MF_UNCHECKED);\r
}\r
\r
+void OnChildPaneEvent(const IImgMergeWindow::Event& evt)\r
+{\r
+ if (evt.eventType == IImgMergeWindow::CONTEXTMENU)\r
+ {\r
+ HMENU hPopup = LoadMenu(m_hInstance, MAKEINTRESOURCE(IDR_POPUPMENU));\r
+ HMENU hSubMenu = GetSubMenu(hPopup, 0);\r
+ TrackPopupMenu(hSubMenu, TPM_LEFTALIGN, evt.x, evt.y, 0, m_hWnd, NULL); \r
+ }\r
+}\r
+\r
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\r
{\r
switch (message) \r
{\r
case WM_CREATE:\r
m_pImgMergeWindow = WinIMerge_CreateWindow(hInstDLL, hWnd);\r
+ m_pImgMergeWindow->AddEventListener(OnChildPaneEvent, NULL);\r
UpdateMenuState(hWnd);\r
break;\r
case WM_SIZE:\r
case ID_MERGE_LASTDIFFERENCE:\r
m_pImgMergeWindow->LastDiff();\r
break;\r
+ case ID_MERGE_NEXTCONFLICT:\r
+ m_pImgMergeWindow->NextConflict();\r
+ break;\r
+ case ID_MERGE_PREVIOUSCONFLICT:\r
+ m_pImgMergeWindow->PrevConflict();\r
+ break;\r
case ID_HELP_ABOUT:\r
MessageBoxW(hWnd, \r
L"WinIMerge\n\n"\r
L"See http://freeimage.sourceforge.net for details.\n"\r
L"FreeImage is used under the GNU GPL version.\n", L"WinIMerge", MB_OK | MB_ICONINFORMATION);\r
break;\r
+ case ID_POPUP_CURPANE_PREVIOUSPAGE:\r
+ {\r
+ int nActivePane = m_pImgMergeWindow->GetActivePane();\r
+ m_pImgMergeWindow->SetCurrentPage(nActivePane, m_pImgMergeWindow->GetCurrentPage(nActivePane) - 1);\r
+ break;\r
+ }\r
+ case ID_POPUP_CURPANE_NEXTPAGE:\r
+ {\r
+ int nActivePane = m_pImgMergeWindow->GetActivePane();\r
+ m_pImgMergeWindow->SetCurrentPage(nActivePane, m_pImgMergeWindow->GetCurrentPage(nActivePane) + 1);\r
+ break;\r
+ }\r
default:\r
return DefWindowProc(hWnd, message, wParam, lParam);\r
}\r
MENUITEM "&Previous Difference\tAlt+Up", ID_MERGE_PREVIOUSDIFFERENCE\r
MENUITEM "&First Difference\tAlt+Home", ID_MERGE_FIRSTDIFFERENCE\r
MENUITEM "&Last Difference\tAlt+End", ID_MERGE_LASTDIFFERENCE\r
+ MENUITEM "Next Conflict\tAlt+Shift+Down", ID_MERGE_NEXTCONFLICT\r
+ MENUITEM "Previous Conflict\tAlt+Shift+Up", ID_MERGE_PREVIOUSCONFLICT\r
END\r
POPUP "&Help"\r
BEGIN\r
END\r
END\r
\r
+IDR_POPUPMENU MENU\r
+BEGIN\r
+ POPUP "popup"\r
+ BEGIN\r
+ MENUITEM "Current Pane: &Previous Page", ID_POPUP_CURPANE_PREVIOUSPAGE\r
+ MENUITEM "Current Pane: &Next Page", ID_POPUP_CURPANE_NEXTPAGE\r
+ END\r
+END\r
+\r
\r
/////////////////////////////////////////////////////////////////////////////\r
//\r
\r
IDC_WINIMERGE ACCELERATORS\r
BEGIN\r
- VK_DOWN, ID_MERGE_NEXTDIFFERENCE, VIRTKEY, ALT, NOINVERT\r
- VK_UP, ID_MERGE_PREVIOUSDIFFERENCE, VIRTKEY, ALT, NOINVERT\r
VK_HOME, ID_MERGE_FIRSTDIFFERENCE, VIRTKEY, ALT, NOINVERT\r
VK_END, ID_MERGE_LASTDIFFERENCE, VIRTKEY, ALT, NOINVERT\r
+ VK_DOWN, ID_MERGE_NEXTDIFFERENCE, VIRTKEY, ALT, NOINVERT\r
+ VK_UP, ID_MERGE_PREVIOUSDIFFERENCE, VIRTKEY, ALT, NOINVERT\r
+ VK_DOWN, ID_MERGE_NEXTCONFLICT, VIRTKEY, SHIFT, ALT, NOINVERT\r
+ VK_UP, ID_MERGE_PREVIOUSCONFLICT, VIRTKEY, SHIFT, ALT, NOINVERT\r
END\r
\r
#endif // \89p\8cê (\95Ä\8d\91) resources\r
enum OVERLAY_MODE {\r
OVERLAY_NONE = 0, OVERLAY_XOR, OVERLAY_ALPHABLEND\r
};\r
+ enum EVENT_TYPE {\r
+ LBUTTONDOWN = 0, LBUTTONUP, LBUTTONDBLCLK, \r
+ RBUTTONDOWN, RBUTTONUP, RBUTTONDBLCLK,\r
+ MOUSEMOVE, MOUSEWHEEL, CONTEXTMENU,\r
+ SIZE, HSCROLL, VSCROLL, SETFOCUS, KILLFOCUS\r
+ };\r
+ struct Event\r
+ {\r
+ void *userdata;\r
+ int pane;\r
+ EVENT_TYPE eventType;\r
+ int x;\r
+ int y;\r
+ unsigned flags;\r
+ int delta;\r
+ int width;\r
+ int height;\r
+ };\r
+ typedef void (*EventListenerFunc)(const Event& evt);\r
virtual bool OpenImages(const wchar_t *filename1, const wchar_t *filename2) = 0;\r
virtual bool OpenImages(const wchar_t *filename1, const wchar_t *filename2, const wchar_t *filename3) = 0;\r
virtual bool SetWindowRect(const RECT& rc) = 0;\r
+ virtual int GetActivePane() const = 0;\r
+ virtual void SetActivePane(int pane) = 0;\r
virtual bool GetHorizontalSplit() const = 0;\r
virtual void SetHorizontalSplit(bool horizontalSplit) = 0;\r
virtual int GetCurrentPage(int pane) const = 0;\r
virtual bool LastDiff() = 0;\r
virtual bool NextDiff() = 0;\r
virtual bool PrevDiff() = 0;\r
+ virtual bool FirstConflict() = 0;\r
+ virtual bool LastConflict() = 0;\r
+ virtual bool NextConflict() = 0;\r
+ virtual bool PrevConflict() = 0;\r
virtual HWND GetHWND() const = 0;\r
+ virtual void AddEventListener(EventListenerFunc func, void *userdata) = 0;\r
};\r
\r
extern "C"\r
#define IDI_WINIMERGE 108\r
#define IDC_WINIMERGE 110\r
#define IDR_MAINFRAME 128\r
+#define IDR_POPUPMENU 130\r
#define ID_VIEW_ZOOM_25 32780\r
#define ID_VIEW_ZOOM_50 32781\r
#define ID_VIEW_ZOOM_100 32782\r
#define ID_MERGE_PREVIOUSDIFFERENCE 32797\r
#define ID_MERGE_FIRSTDIFFERENCE 32798\r
#define ID_MERGE_LASTDIFFERENCE 32799\r
-#define ID_EDIT_COPY 32800\r
-#define ID_EDIT_CUT 32801\r
-#define ID_EDIT_PASTE 32802\r
-#define ID_EDIT_SELECTALL 32803\r
+#define ID_MERGE_NEXTCONFLICT 32800\r
+#define ID_MERGE_PREVIOUSCONFLICT 32801\r
+#define ID_EDIT_COPY 32802\r
+#define ID_EDIT_CUT 32803\r
+#define ID_EDIT_PASTE 32804\r
+#define ID_EDIT_SELECTALL 32805\r
#define ID_HELP_ABOUT 32809\r
#define ID_VIEW_DIFFBLOCKSIZE_1 32811\r
#define ID_VIEW_DIFFBLOCKSIZE_2 32812\r
#define ID_VIEW_PAGE_NEXTPAGE 32821\r
#define ID_VIEW_PAGE_PREVPAGE 32822\r
#define ID_VIEW_USEBACKCOLOR 32823\r
+#define ID_POPUP_CURPANE_NEXTPAGE 32824\r
+#define ID_POPUP_CURPANE_PREVIOUSPAGE 32825\r
#define IDC_STATIC -1\r
\r
// Next default values for new objects\r
#ifdef APSTUDIO_INVOKED\r
#ifndef APSTUDIO_READONLY_SYMBOLS\r
#define _APS_NO_MFC 1\r
-#define _APS_NEXT_RESOURCE_VALUE 130\r
-#define _APS_NEXT_COMMAND_VALUE 32824\r
+#define _APS_NEXT_RESOURCE_VALUE 131\r
+#define _APS_NEXT_COMMAND_VALUE 32828\r
#define _APS_NEXT_CONTROL_VALUE 1000\r
#define _APS_NEXT_SYMED_VALUE 111\r
#endif\r