1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:    PAINT for ReactOS
38f1f1c7aSStanislav Motylkov  * LICENSE:    LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4c2c66affSColin Finck  * PURPOSE:    Keep track of selection parameters, notify listeners
5f5200e6cSStanislav Motylkov  * COPYRIGHT:  Copyright 2015 Benedikt Freisen <b.freisen@gmx.net>
68f1f1c7aSStanislav Motylkov  *             Copyright 2019 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck #include "precomp.h"
10c2c66affSColin Finck 
1129e147beSKatayama Hirofumi MZ SelectionModel selectionModel;
1229e147beSKatayama Hirofumi MZ 
13c2c66affSColin Finck /* FUNCTIONS ********************************************************/
14c2c66affSColin Finck 
15c2c66affSColin Finck SelectionModel::SelectionModel()
16aac89519SKatayama Hirofumi MZ     : m_hbmColor(NULL)
17aac89519SKatayama Hirofumi MZ     , m_hbmMask(NULL)
183fa95ab9SKatayama Hirofumi MZ     , m_ptStack(NULL)
193fa95ab9SKatayama Hirofumi MZ     , m_iPtSP(0)
2017bdf554SKatayama Hirofumi MZ     , m_rgbBack(RGB(255, 255, 255))
21aac89519SKatayama Hirofumi MZ     , m_bShow(FALSE)
227aadc1e1SKatayama Hirofumi MZ     , m_bContentChanged(FALSE)
23c2c66affSColin Finck {
24aac89519SKatayama Hirofumi MZ     ::SetRectEmpty(&m_rc);
25e8c7e300SKatayama Hirofumi MZ     ::SetRectEmpty(&m_rcOld);
26e5792200SKatayama Hirofumi MZ     m_ptHit = { -1, -1 };
273fa95ab9SKatayama Hirofumi MZ }
28c2c66affSColin Finck 
293fa95ab9SKatayama Hirofumi MZ SelectionModel::~SelectionModel()
303fa95ab9SKatayama Hirofumi MZ {
31ed9973f8SKatayama Hirofumi MZ     ClearColorImage();
32ed9973f8SKatayama Hirofumi MZ     ClearMaskImage();
333fa95ab9SKatayama Hirofumi MZ     ResetPtStack();
34c2c66affSColin Finck }
35c2c66affSColin Finck 
36c2c66affSColin Finck void SelectionModel::ResetPtStack()
37c2c66affSColin Finck {
38aac89519SKatayama Hirofumi MZ     if (m_ptStack)
39aac89519SKatayama Hirofumi MZ     {
40aac89519SKatayama Hirofumi MZ         free(m_ptStack);
41c2c66affSColin Finck         m_ptStack = NULL;
42aac89519SKatayama Hirofumi MZ     }
43c2c66affSColin Finck     m_iPtSP = 0;
44c2c66affSColin Finck }
45c2c66affSColin Finck 
46aac89519SKatayama Hirofumi MZ void SelectionModel::PushToPtStack(POINT pt)
47c2c66affSColin Finck {
48aac89519SKatayama Hirofumi MZ #define GROW_COUNT 256
49aac89519SKatayama Hirofumi MZ     if (m_iPtSP % GROW_COUNT == 0)
50c2c66affSColin Finck     {
51aac89519SKatayama Hirofumi MZ         INT nNewCount = m_iPtSP + GROW_COUNT;
52aac89519SKatayama Hirofumi MZ         LPPOINT pptNew = (LPPOINT)realloc(m_ptStack, sizeof(POINT) * nNewCount);
53aac89519SKatayama Hirofumi MZ         if (pptNew == NULL)
54aac89519SKatayama Hirofumi MZ             return;
55aac89519SKatayama Hirofumi MZ         m_ptStack = pptNew;
56c2c66affSColin Finck     }
57aac89519SKatayama Hirofumi MZ     m_ptStack[m_iPtSP] = pt;
58c2c66affSColin Finck     m_iPtSP++;
59aac89519SKatayama Hirofumi MZ #undef GROW_COUNT
60c2c66affSColin Finck }
61c2c66affSColin Finck 
62e8c7e300SKatayama Hirofumi MZ void SelectionModel::ShiftPtStack(INT dx, INT dy)
63c2c66affSColin Finck {
64aac89519SKatayama Hirofumi MZ     for (INT i = 0; i < m_iPtSP; ++i)
65aac89519SKatayama Hirofumi MZ     {
66aac89519SKatayama Hirofumi MZ         POINT& pt = m_ptStack[i];
67e8c7e300SKatayama Hirofumi MZ         pt.x += dx;
68e8c7e300SKatayama Hirofumi MZ         pt.y += dy;
69c2c66affSColin Finck     }
70c2c66affSColin Finck }
71c2c66affSColin Finck 
72aac89519SKatayama Hirofumi MZ void SelectionModel::BuildMaskFromPtStack()
73c2c66affSColin Finck {
74e5792200SKatayama Hirofumi MZ     CRect rc;
75e5792200SKatayama Hirofumi MZ     getBoundaryOfPtStack(rc, m_iPtSP, m_ptStack);
76aac89519SKatayama Hirofumi MZ 
77e8c7e300SKatayama Hirofumi MZ     m_rc = m_rcOld = rc;
78aac89519SKatayama Hirofumi MZ 
79ed9973f8SKatayama Hirofumi MZ     ClearMaskImage();
80aac89519SKatayama Hirofumi MZ 
81e8c7e300SKatayama Hirofumi MZ     ShiftPtStack(-m_rcOld.left, -m_rcOld.top);
82e8c7e300SKatayama Hirofumi MZ 
83aac89519SKatayama Hirofumi MZ     HDC hdcMem = ::CreateCompatibleDC(NULL);
84aac89519SKatayama Hirofumi MZ     m_hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
85aac89519SKatayama Hirofumi MZ     HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmMask);
86e8c7e300SKatayama Hirofumi MZ     ::FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
87aac89519SKatayama Hirofumi MZ     HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN));
88aac89519SKatayama Hirofumi MZ     HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH));
89aac89519SKatayama Hirofumi MZ     ::Polygon(hdcMem, m_ptStack, m_iPtSP);
90aac89519SKatayama Hirofumi MZ     ::SelectObject(hdcMem, hbrOld);
91aac89519SKatayama Hirofumi MZ     ::SelectObject(hdcMem, hPenOld);
92aac89519SKatayama Hirofumi MZ     ::SelectObject(hdcMem, hbmOld);
93aac89519SKatayama Hirofumi MZ     ::DeleteDC(hdcMem);
94e8c7e300SKatayama Hirofumi MZ 
95e8c7e300SKatayama Hirofumi MZ     ShiftPtStack(+m_rcOld.left, +m_rcOld.top);
96c2c66affSColin Finck }
97c2c66affSColin Finck 
98c2c66affSColin Finck void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
99c2c66affSColin Finck {
100e8c7e300SKatayama Hirofumi MZ     if (::IsRectEmpty(&m_rcOld))
101e8c7e300SKatayama Hirofumi MZ         return;
102aac89519SKatayama Hirofumi MZ 
103aac89519SKatayama Hirofumi MZ     HGDIOBJ hPenOld = ::SelectObject(hDCImage, ::GetStockObject(NULL_PEN));
104aac89519SKatayama Hirofumi MZ     HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::CreateSolidBrush(crBg));
105aac89519SKatayama Hirofumi MZ     ::Polygon(hDCImage, m_ptStack, m_iPtSP);
106aac89519SKatayama Hirofumi MZ     ::DeleteObject(::SelectObject(hDCImage, hbrOld));
107aac89519SKatayama Hirofumi MZ     ::SelectObject(hDCImage, hPenOld);
108c2c66affSColin Finck }
109c2c66affSColin Finck 
110c2c66affSColin Finck void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
111c2c66affSColin Finck {
112e8c7e300SKatayama Hirofumi MZ     if (::IsRectEmpty(&m_rcOld))
113e8c7e300SKatayama Hirofumi MZ         return;
114e8c7e300SKatayama Hirofumi MZ 
115e8c7e300SKatayama Hirofumi MZ     Rect(hDCImage, m_rcOld.left, m_rcOld.top, m_rcOld.right, m_rcOld.bottom, crBg, crBg, 0, 1);
116c2c66affSColin Finck }
117c2c66affSColin Finck 
1187aadc1e1SKatayama Hirofumi MZ void SelectionModel::DrawBackground(HDC hDCImage)
1197aadc1e1SKatayama Hirofumi MZ {
1207aadc1e1SKatayama Hirofumi MZ     if (toolsModel.GetActiveTool() == TOOL_FREESEL)
1217aadc1e1SKatayama Hirofumi MZ         DrawBackgroundPoly(hDCImage, paletteModel.GetBgColor());
1227aadc1e1SKatayama Hirofumi MZ     else
1237aadc1e1SKatayama Hirofumi MZ         DrawBackgroundRect(hDCImage, paletteModel.GetBgColor());
1247aadc1e1SKatayama Hirofumi MZ }
1257aadc1e1SKatayama Hirofumi MZ 
126e8c7e300SKatayama Hirofumi MZ void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent)
127c2c66affSColin Finck {
128e8c7e300SKatayama Hirofumi MZ     CRect rc = m_rc;
129aac89519SKatayama Hirofumi MZ     if (::IsRectEmpty(&rc))
130aac89519SKatayama Hirofumi MZ         return;
131aac89519SKatayama Hirofumi MZ 
132aac89519SKatayama Hirofumi MZ     BITMAP bm;
133640d67d1SKatayama Hirofumi MZ     if (!GetObjectW(m_hbmColor, sizeof(BITMAP), &bm))
134e8c7e300SKatayama Hirofumi MZ         return;
135aac89519SKatayama Hirofumi MZ 
136aac89519SKatayama Hirofumi MZ     COLORREF keyColor = (bBgTransparent ? crBg : CLR_INVALID);
137aac89519SKatayama Hirofumi MZ 
138aac89519SKatayama Hirofumi MZ     HDC hMemDC = CreateCompatibleDC(hDCImage);
139aac89519SKatayama Hirofumi MZ     HGDIOBJ hbmOld = SelectObject(hMemDC, m_hbmColor);
140aac89519SKatayama Hirofumi MZ     ColorKeyedMaskBlt(hDCImage, rc.left, rc.top, rc.Width(), rc.Height(),
141aac89519SKatayama Hirofumi MZ                       hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, m_hbmMask, keyColor);
142aac89519SKatayama Hirofumi MZ     SelectObject(hMemDC, hbmOld);
143aac89519SKatayama Hirofumi MZ     DeleteDC(hMemDC);
144aac89519SKatayama Hirofumi MZ }
145aac89519SKatayama Hirofumi MZ 
146d7ece626SKatayama Hirofumi MZ HBITMAP SelectionModel::GetSelectionContents()
147aac89519SKatayama Hirofumi MZ {
148d7ece626SKatayama Hirofumi MZ     if (m_hbmColor)
149d7ece626SKatayama Hirofumi MZ         return CopyDIBImage(m_hbmColor, m_rc.Width(), m_rc.Height());
150aac89519SKatayama Hirofumi MZ 
151764e5505SKatayama Hirofumi MZ     HBITMAP hbmWhole = imageModel.LockBitmap();
152764e5505SKatayama Hirofumi MZ     HBITMAP hbmPart = getSubImage(hbmWhole, m_rc);
153764e5505SKatayama Hirofumi MZ     imageModel.UnlockBitmap(hbmWhole);
154764e5505SKatayama Hirofumi MZ     return hbmPart;
155aac89519SKatayama Hirofumi MZ }
156aac89519SKatayama Hirofumi MZ 
157e8c7e300SKatayama Hirofumi MZ BOOL SelectionModel::IsLanded() const
158e8c7e300SKatayama Hirofumi MZ {
159e8c7e300SKatayama Hirofumi MZ     return !m_hbmColor;
160e8c7e300SKatayama Hirofumi MZ }
161e8c7e300SKatayama Hirofumi MZ 
162aac89519SKatayama Hirofumi MZ BOOL SelectionModel::TakeOff()
163aac89519SKatayama Hirofumi MZ {
164e8c7e300SKatayama Hirofumi MZ     if (!IsLanded() || ::IsRectEmpty(&m_rc))
165aac89519SKatayama Hirofumi MZ         return FALSE;
166aac89519SKatayama Hirofumi MZ 
167ed9973f8SKatayama Hirofumi MZ     // The background color is needed for transparency of selection
168e8c7e300SKatayama Hirofumi MZ     m_rgbBack = paletteModel.GetBgColor();
169ed9973f8SKatayama Hirofumi MZ 
170ed9973f8SKatayama Hirofumi MZ     // Get the contents of the selection area
171d7ece626SKatayama Hirofumi MZ     ClearColorImage();
172d7ece626SKatayama Hirofumi MZ     m_hbmColor = GetSelectionContents();
173aac89519SKatayama Hirofumi MZ 
174ed9973f8SKatayama Hirofumi MZ     // RectSel doesn't need the mask image
175e8c7e300SKatayama Hirofumi MZ     if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
176ed9973f8SKatayama Hirofumi MZ         ClearMaskImage();
177e8c7e300SKatayama Hirofumi MZ 
178ed9973f8SKatayama Hirofumi MZ     // Save the selection area
179e8c7e300SKatayama Hirofumi MZ     m_rcOld = m_rc;
180c2c66affSColin Finck 
181cbc63d87SKatayama Hirofumi MZ     if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
182cbc63d87SKatayama Hirofumi MZ     {
183cbc63d87SKatayama Hirofumi MZ         imageModel.PushImageForUndo();
184cbc63d87SKatayama Hirofumi MZ         selectionModel.DrawBackgroundRect(imageModel.GetDC(), selectionModel.m_rgbBack);
185cbc63d87SKatayama Hirofumi MZ     }
186cbc63d87SKatayama Hirofumi MZ     else if (toolsModel.GetActiveTool() == TOOL_FREESEL)
187cbc63d87SKatayama Hirofumi MZ     {
188cbc63d87SKatayama Hirofumi MZ         imageModel.PushImageForUndo();
189cbc63d87SKatayama Hirofumi MZ         selectionModel.DrawBackgroundPoly(imageModel.GetDC(), selectionModel.m_rgbBack);
190cbc63d87SKatayama Hirofumi MZ     }
191cbc63d87SKatayama Hirofumi MZ 
192bfd42c67SKatayama Hirofumi MZ     imageModel.NotifyImageChanged();
193aac89519SKatayama Hirofumi MZ     return TRUE;
194c2c66affSColin Finck }
195c2c66affSColin Finck 
196aac89519SKatayama Hirofumi MZ void SelectionModel::Landing()
197c2c66affSColin Finck {
198e8c7e300SKatayama Hirofumi MZ     if (IsLanded() && !m_bShow)
199e8c7e300SKatayama Hirofumi MZ     {
200e8c7e300SKatayama Hirofumi MZ         imageModel.NotifyImageChanged();
201aac89519SKatayama Hirofumi MZ         return;
202e8c7e300SKatayama Hirofumi MZ     }
203aac89519SKatayama Hirofumi MZ 
204e8c7e300SKatayama Hirofumi MZ     m_bShow = FALSE;
205aac89519SKatayama Hirofumi MZ 
2067aadc1e1SKatayama Hirofumi MZ     if (m_bContentChanged ||
2077aadc1e1SKatayama Hirofumi MZ         (!::EqualRect(m_rc, m_rcOld) && !::IsRectEmpty(m_rc) && !::IsRectEmpty(m_rcOld)))
208e8c7e300SKatayama Hirofumi MZ     {
2092b623c1dSKatayama Hirofumi MZ         imageModel.PushImageForUndo();
210e8c7e300SKatayama Hirofumi MZ 
211e8c7e300SKatayama Hirofumi MZ         canvasWindow.m_drawing = FALSE;
212e8c7e300SKatayama Hirofumi MZ         toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
213e8c7e300SKatayama Hirofumi MZ     }
214e8c7e300SKatayama Hirofumi MZ 
215e8c7e300SKatayama Hirofumi MZ     HideSelection();
216c2c66affSColin Finck }
217c2c66affSColin Finck 
2189afcbea2SKatayama Hirofumi MZ void SelectionModel::InsertFromHBITMAP(HBITMAP hbmColor, INT x, INT y, HBITMAP hbmMask)
219c2c66affSColin Finck {
220aac89519SKatayama Hirofumi MZ     ::DeleteObject(m_hbmColor);
221b5335fb9SKatayama Hirofumi MZ     m_hbmColor = hbmColor;
222c2c66affSColin Finck 
223aac89519SKatayama Hirofumi MZ     m_rc.left = x;
224aac89519SKatayama Hirofumi MZ     m_rc.top = y;
2259afcbea2SKatayama Hirofumi MZ     m_rc.right = x + GetDIBWidth(hbmColor);
2269afcbea2SKatayama Hirofumi MZ     m_rc.bottom = y + GetDIBHeight(hbmColor);
2279afcbea2SKatayama Hirofumi MZ 
2289afcbea2SKatayama Hirofumi MZ     if (hbmMask)
2299afcbea2SKatayama Hirofumi MZ     {
2309afcbea2SKatayama Hirofumi MZ         ::DeleteObject(m_hbmMask);
231b5335fb9SKatayama Hirofumi MZ         m_hbmMask = hbmMask;
2329afcbea2SKatayama Hirofumi MZ     }
2339afcbea2SKatayama Hirofumi MZ     else
2349afcbea2SKatayama Hirofumi MZ     {
235ed9973f8SKatayama Hirofumi MZ         ClearMaskImage();
2369afcbea2SKatayama Hirofumi MZ     }
2379f56e67bSKatayama Hirofumi MZ 
2387aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
239c2c66affSColin Finck }
240c2c66affSColin Finck 
241c2c66affSColin Finck void SelectionModel::FlipHorizontally()
242c2c66affSColin Finck {
243aac89519SKatayama Hirofumi MZ     TakeOff();
244aac89519SKatayama Hirofumi MZ 
245aac89519SKatayama Hirofumi MZ     HDC hdcMem = ::CreateCompatibleDC(NULL);
246aac89519SKatayama Hirofumi MZ     if (m_hbmMask)
247aac89519SKatayama Hirofumi MZ     {
248aac89519SKatayama Hirofumi MZ         ::SelectObject(hdcMem, m_hbmMask);
249aac89519SKatayama Hirofumi MZ         ::StretchBlt(hdcMem, m_rc.Width() - 1, 0, -m_rc.Width(), m_rc.Height(),
250aac89519SKatayama Hirofumi MZ                      hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
251aac89519SKatayama Hirofumi MZ     }
252aac89519SKatayama Hirofumi MZ     if (m_hbmColor)
253aac89519SKatayama Hirofumi MZ     {
254aac89519SKatayama Hirofumi MZ         ::SelectObject(hdcMem, m_hbmColor);
255aac89519SKatayama Hirofumi MZ         ::StretchBlt(hdcMem, m_rc.Width() - 1, 0, -m_rc.Width(), m_rc.Height(),
256aac89519SKatayama Hirofumi MZ                      hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
257aac89519SKatayama Hirofumi MZ     }
258aac89519SKatayama Hirofumi MZ     ::DeleteDC(hdcMem);
259aac89519SKatayama Hirofumi MZ 
2607aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
261c2c66affSColin Finck }
262c2c66affSColin Finck 
263c2c66affSColin Finck void SelectionModel::FlipVertically()
264c2c66affSColin Finck {
265aac89519SKatayama Hirofumi MZ     TakeOff();
266aac89519SKatayama Hirofumi MZ 
267aac89519SKatayama Hirofumi MZ     HDC hdcMem = ::CreateCompatibleDC(NULL);
268aac89519SKatayama Hirofumi MZ     if (m_hbmMask)
269aac89519SKatayama Hirofumi MZ     {
270aac89519SKatayama Hirofumi MZ         ::SelectObject(hdcMem, m_hbmMask);
271aac89519SKatayama Hirofumi MZ         ::StretchBlt(hdcMem, 0, m_rc.Height() - 1, m_rc.Width(), -m_rc.Height(),
272aac89519SKatayama Hirofumi MZ                      hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
273aac89519SKatayama Hirofumi MZ     }
274aac89519SKatayama Hirofumi MZ     if (m_hbmColor)
275aac89519SKatayama Hirofumi MZ     {
276aac89519SKatayama Hirofumi MZ         ::SelectObject(hdcMem, m_hbmColor);
277aac89519SKatayama Hirofumi MZ         ::StretchBlt(hdcMem, 0, m_rc.Height() - 1, m_rc.Width(), -m_rc.Height(),
278aac89519SKatayama Hirofumi MZ                      hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
279aac89519SKatayama Hirofumi MZ     }
280aac89519SKatayama Hirofumi MZ     ::DeleteDC(hdcMem);
281aac89519SKatayama Hirofumi MZ 
2827aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
283c2c66affSColin Finck }
284c2c66affSColin Finck 
285c2c66affSColin Finck void SelectionModel::RotateNTimes90Degrees(int iN)
286c2c66affSColin Finck {
2872d909190SKatayama Hirofumi MZ     HBITMAP hbm;
288aac89519SKatayama Hirofumi MZ     HGDIOBJ hbmOld;
289aac89519SKatayama Hirofumi MZ     HDC hdcMem = ::CreateCompatibleDC(NULL);
290aac89519SKatayama Hirofumi MZ 
2912d909190SKatayama Hirofumi MZ     switch (iN)
292c2c66affSColin Finck     {
2937aadc1e1SKatayama Hirofumi MZ         case 1: /* rotate 90 degrees */
2947aadc1e1SKatayama Hirofumi MZ         case 3: /* rotate 270 degrees */
295aac89519SKatayama Hirofumi MZ             TakeOff();
2967aadc1e1SKatayama Hirofumi MZ 
297aac89519SKatayama Hirofumi MZ             if (m_hbmColor)
298aac89519SKatayama Hirofumi MZ             {
299aac89519SKatayama Hirofumi MZ                 hbmOld = ::SelectObject(hdcMem, m_hbmColor);
300aac89519SKatayama Hirofumi MZ                 hbm = Rotate90DegreeBlt(hdcMem, m_rc.Width(), m_rc.Height(), iN == 1, FALSE);
301aac89519SKatayama Hirofumi MZ                 ::SelectObject(hdcMem, hbmOld);
302aac89519SKatayama Hirofumi MZ                 ::DeleteObject(m_hbmColor);
303aac89519SKatayama Hirofumi MZ                 m_hbmColor = hbm;
304aac89519SKatayama Hirofumi MZ             }
305aac89519SKatayama Hirofumi MZ             if (m_hbmMask)
306aac89519SKatayama Hirofumi MZ             {
307aac89519SKatayama Hirofumi MZ                 hbmOld = ::SelectObject(hdcMem, m_hbmMask);
308aac89519SKatayama Hirofumi MZ                 hbm = Rotate90DegreeBlt(hdcMem, m_rc.Width(), m_rc.Height(), iN == 1, TRUE);
309aac89519SKatayama Hirofumi MZ                 ::SelectObject(hdcMem, hbmOld);
310aac89519SKatayama Hirofumi MZ                 ::DeleteObject(m_hbmMask);
311aac89519SKatayama Hirofumi MZ                 m_hbmMask = hbm;
312aac89519SKatayama Hirofumi MZ             }
3137aadc1e1SKatayama Hirofumi MZ 
3147aadc1e1SKatayama Hirofumi MZ             SwapWidthAndHeight();
3152d909190SKatayama Hirofumi MZ             break;
316aac89519SKatayama Hirofumi MZ 
3177aadc1e1SKatayama Hirofumi MZ         case 2: /* rotate 180 degrees */
318aac89519SKatayama Hirofumi MZ             TakeOff();
3197aadc1e1SKatayama Hirofumi MZ 
320aac89519SKatayama Hirofumi MZ             if (m_hbmColor)
321aac89519SKatayama Hirofumi MZ             {
322aac89519SKatayama Hirofumi MZ                 hbmOld = ::SelectObject(hdcMem, m_hbmColor);
323aac89519SKatayama Hirofumi MZ                 ::StretchBlt(hdcMem, m_rc.Width() - 1, m_rc.Height() - 1, -m_rc.Width(), -m_rc.Height(),
324aac89519SKatayama Hirofumi MZ                              hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
325aac89519SKatayama Hirofumi MZ                 ::SelectObject(hdcMem, hbmOld);
326aac89519SKatayama Hirofumi MZ             }
327aac89519SKatayama Hirofumi MZ             if (m_hbmMask)
328aac89519SKatayama Hirofumi MZ             {
329aac89519SKatayama Hirofumi MZ                 hbmOld = ::SelectObject(hdcMem, m_hbmMask);
330aac89519SKatayama Hirofumi MZ                 ::StretchBlt(hdcMem, m_rc.Width() - 1, m_rc.Height() - 1, -m_rc.Width(), -m_rc.Height(),
331aac89519SKatayama Hirofumi MZ                              hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
332aac89519SKatayama Hirofumi MZ                 ::SelectObject(hdcMem, hbmOld);
333aac89519SKatayama Hirofumi MZ             }
3342d909190SKatayama Hirofumi MZ             break;
335c2c66affSColin Finck     }
336aac89519SKatayama Hirofumi MZ 
337aac89519SKatayama Hirofumi MZ     ::DeleteDC(hdcMem);
3387aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
339c2c66affSColin Finck }
340c2c66affSColin Finck 
341b5335fb9SKatayama Hirofumi MZ static void AttachHBITMAP(HBITMAP *phbm, HBITMAP hbmNew)
342b5335fb9SKatayama Hirofumi MZ {
343b5335fb9SKatayama Hirofumi MZ     if (hbmNew == NULL)
344b5335fb9SKatayama Hirofumi MZ         return;
345b5335fb9SKatayama Hirofumi MZ     ::DeleteObject(*phbm);
346b5335fb9SKatayama Hirofumi MZ     *phbm = hbmNew;
347b5335fb9SKatayama Hirofumi MZ }
348b5335fb9SKatayama Hirofumi MZ 
349dfd06ee8SKatayama Hirofumi MZ void SelectionModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY)
350dfd06ee8SKatayama Hirofumi MZ {
351dfd06ee8SKatayama Hirofumi MZ     if (nStretchPercentX == 100 && nStretchPercentY == 100 && nSkewDegX == 0 && nSkewDegY == 0)
352dfd06ee8SKatayama Hirofumi MZ         return;
353dfd06ee8SKatayama Hirofumi MZ 
354aac89519SKatayama Hirofumi MZ     TakeOff();
355dfd06ee8SKatayama Hirofumi MZ 
356b5335fb9SKatayama Hirofumi MZ     INT oldWidth = m_rc.Width(), oldHeight = m_rc.Height();
357dfd06ee8SKatayama Hirofumi MZ     INT newWidth = oldWidth * nStretchPercentX / 100;
358dfd06ee8SKatayama Hirofumi MZ     INT newHeight = oldHeight * nStretchPercentY / 100;
359dfd06ee8SKatayama Hirofumi MZ 
360b5335fb9SKatayama Hirofumi MZ     HBITMAP hbmColor = m_hbmColor, hbmMask = m_hbmMask;
3619afcbea2SKatayama Hirofumi MZ 
362b5335fb9SKatayama Hirofumi MZ     if (hbmMask == NULL)
363b5335fb9SKatayama Hirofumi MZ         hbmMask = CreateMonoBitmap(oldWidth, oldHeight, TRUE);
3649afcbea2SKatayama Hirofumi MZ 
365dfd06ee8SKatayama Hirofumi MZ     if (oldWidth != newWidth || oldHeight != newHeight)
366dfd06ee8SKatayama Hirofumi MZ     {
367b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmColor, CopyDIBImage(hbmColor, newWidth, newHeight));
368b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmMask, CopyMonoImage(hbmMask, newWidth, newHeight));
369dfd06ee8SKatayama Hirofumi MZ     }
370dfd06ee8SKatayama Hirofumi MZ 
371b5335fb9SKatayama Hirofumi MZ     HGDIOBJ hbmOld;
372aac89519SKatayama Hirofumi MZ     HDC hDC = ::CreateCompatibleDC(NULL);
373aac89519SKatayama Hirofumi MZ 
374dfd06ee8SKatayama Hirofumi MZ     if (nSkewDegX)
375dfd06ee8SKatayama Hirofumi MZ     {
376b5335fb9SKatayama Hirofumi MZ         hbmOld = ::SelectObject(hDC, hbmColor);
377b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmColor, SkewDIB(hDC, hbmColor, nSkewDegX, FALSE));
378b5335fb9SKatayama Hirofumi MZ         ::SelectObject(hDC, hbmMask);
379b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmMask, SkewDIB(hDC, hbmMask, nSkewDegX, FALSE, TRUE));
3809afcbea2SKatayama Hirofumi MZ         ::SelectObject(hDC, hbmOld);
381dfd06ee8SKatayama Hirofumi MZ     }
382dfd06ee8SKatayama Hirofumi MZ 
383dfd06ee8SKatayama Hirofumi MZ     if (nSkewDegY)
384dfd06ee8SKatayama Hirofumi MZ     {
385b5335fb9SKatayama Hirofumi MZ         hbmOld = ::SelectObject(hDC, hbmColor);
386b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmColor, SkewDIB(hDC, hbmColor, nSkewDegY, TRUE));
387b5335fb9SKatayama Hirofumi MZ         ::SelectObject(hDC, hbmMask);
388b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmMask, SkewDIB(hDC, hbmMask, nSkewDegY, TRUE, TRUE));
3899afcbea2SKatayama Hirofumi MZ         ::SelectObject(hDC, hbmOld);
390dfd06ee8SKatayama Hirofumi MZ     }
391dfd06ee8SKatayama Hirofumi MZ 
392aac89519SKatayama Hirofumi MZ     ::DeleteDC(hDC);
393aac89519SKatayama Hirofumi MZ 
394b5335fb9SKatayama Hirofumi MZ     InsertFromHBITMAP(hbmColor, m_rc.left, m_rc.top, hbmMask);
395b5335fb9SKatayama Hirofumi MZ 
396aac89519SKatayama Hirofumi MZ     m_bShow = TRUE;
3977aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
398dfd06ee8SKatayama Hirofumi MZ }
399dfd06ee8SKatayama Hirofumi MZ 
400b5536e44SKatayama Hirofumi MZ int SelectionModel::PtStackSize() const
401c2c66affSColin Finck {
402c2c66affSColin Finck     return m_iPtSP;
403c2c66affSColin Finck }
404c2c66affSColin Finck 
405c2c66affSColin Finck void SelectionModel::DrawFramePoly(HDC hDCImage)
406c2c66affSColin Finck {
407aac89519SKatayama Hirofumi MZ     /* draw the freehand selection inverted/xored */
408aac89519SKatayama Hirofumi MZ     Poly(hDCImage, m_ptStack, m_iPtSP, 0, 0, 2, 0, FALSE, TRUE);
409c2c66affSColin Finck }
410c2c66affSColin Finck 
411aac89519SKatayama Hirofumi MZ void SelectionModel::SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo)
412c2c66affSColin Finck {
413aac89519SKatayama Hirofumi MZ     m_rc.left = min(ptFrom.x, ptTo.x);
414aac89519SKatayama Hirofumi MZ     m_rc.top = min(ptFrom.y, ptTo.y);
415aac89519SKatayama Hirofumi MZ     m_rc.right = max(ptFrom.x, ptTo.x);
416aac89519SKatayama Hirofumi MZ     m_rc.bottom = max(ptFrom.y, ptTo.y);
417c2c66affSColin Finck }
418c2c66affSColin Finck 
419cb98e91bSKatayama Hirofumi MZ void SelectionModel::Dragging(HITTEST hit, POINT pt)
420c2c66affSColin Finck {
421aac89519SKatayama Hirofumi MZ     switch (hit)
422c2c66affSColin Finck     {
423aac89519SKatayama Hirofumi MZ         case HIT_NONE:
424c2c66affSColin Finck             break;
425aac89519SKatayama Hirofumi MZ         case HIT_UPPER_LEFT:
426aac89519SKatayama Hirofumi MZ             m_rc.left += pt.x - m_ptHit.x;
427aac89519SKatayama Hirofumi MZ             m_rc.top += pt.y - m_ptHit.y;
428c2c66affSColin Finck             break;
429aac89519SKatayama Hirofumi MZ         case HIT_UPPER_CENTER:
430aac89519SKatayama Hirofumi MZ             m_rc.top += pt.y - m_ptHit.y;
431c2c66affSColin Finck             break;
432aac89519SKatayama Hirofumi MZ         case HIT_UPPER_RIGHT:
433aac89519SKatayama Hirofumi MZ             m_rc.right += pt.x - m_ptHit.x;
434aac89519SKatayama Hirofumi MZ             m_rc.top += pt.y - m_ptHit.y;
435c2c66affSColin Finck             break;
436aac89519SKatayama Hirofumi MZ         case HIT_MIDDLE_LEFT:
437aac89519SKatayama Hirofumi MZ             m_rc.left += pt.x - m_ptHit.x;
438c2c66affSColin Finck             break;
439aac89519SKatayama Hirofumi MZ         case HIT_MIDDLE_RIGHT:
440aac89519SKatayama Hirofumi MZ             m_rc.right += pt.x - m_ptHit.x;
441c2c66affSColin Finck             break;
442aac89519SKatayama Hirofumi MZ         case HIT_LOWER_LEFT:
443aac89519SKatayama Hirofumi MZ             m_rc.left += pt.x - m_ptHit.x;
444aac89519SKatayama Hirofumi MZ             m_rc.bottom += pt.y - m_ptHit.y;
445c2c66affSColin Finck             break;
446aac89519SKatayama Hirofumi MZ         case HIT_LOWER_CENTER:
447aac89519SKatayama Hirofumi MZ             m_rc.bottom += pt.y - m_ptHit.y;
448c2c66affSColin Finck             break;
449aac89519SKatayama Hirofumi MZ         case HIT_LOWER_RIGHT:
450aac89519SKatayama Hirofumi MZ             m_rc.right += pt.x - m_ptHit.x;
451aac89519SKatayama Hirofumi MZ             m_rc.bottom += pt.y - m_ptHit.y;
452aac89519SKatayama Hirofumi MZ             break;
453aac89519SKatayama Hirofumi MZ         case HIT_BORDER:
454aac89519SKatayama Hirofumi MZ         case HIT_INNER:
455aac89519SKatayama Hirofumi MZ             OffsetRect(&m_rc, pt.x - m_ptHit.x, pt.y - m_ptHit.y);
456c2c66affSColin Finck             break;
457c2c66affSColin Finck     }
458aac89519SKatayama Hirofumi MZ     m_ptHit = pt;
459c2c66affSColin Finck }
460c2c66affSColin Finck 
461ed9973f8SKatayama Hirofumi MZ void SelectionModel::ClearMaskImage()
462361a2ce4SKatayama Hirofumi MZ {
463aac89519SKatayama Hirofumi MZ     if (m_hbmMask)
464aac89519SKatayama Hirofumi MZ     {
465aac89519SKatayama Hirofumi MZ         ::DeleteObject(m_hbmMask);
466aac89519SKatayama Hirofumi MZ         m_hbmMask = NULL;
467aac89519SKatayama Hirofumi MZ     }
468aac89519SKatayama Hirofumi MZ }
469aac89519SKatayama Hirofumi MZ 
470ed9973f8SKatayama Hirofumi MZ void SelectionModel::ClearColorImage()
471aac89519SKatayama Hirofumi MZ {
472aac89519SKatayama Hirofumi MZ     if (m_hbmColor)
473aac89519SKatayama Hirofumi MZ     {
474aac89519SKatayama Hirofumi MZ         ::DeleteObject(m_hbmColor);
475aac89519SKatayama Hirofumi MZ         m_hbmColor = NULL;
476aac89519SKatayama Hirofumi MZ     }
477aac89519SKatayama Hirofumi MZ }
478aac89519SKatayama Hirofumi MZ 
479e8c7e300SKatayama Hirofumi MZ void SelectionModel::HideSelection()
480e8c7e300SKatayama Hirofumi MZ {
4817aadc1e1SKatayama Hirofumi MZ     m_bShow = m_bContentChanged = FALSE;
482ed9973f8SKatayama Hirofumi MZ     ClearColorImage();
483ed9973f8SKatayama Hirofumi MZ     ClearMaskImage();
484e8c7e300SKatayama Hirofumi MZ     ::SetRectEmpty(&m_rc);
485e8c7e300SKatayama Hirofumi MZ     ::SetRectEmpty(&m_rcOld);
486e8c7e300SKatayama Hirofumi MZ     imageModel.NotifyImageChanged();
487e8c7e300SKatayama Hirofumi MZ }
488e8c7e300SKatayama Hirofumi MZ 
489e8c7e300SKatayama Hirofumi MZ void SelectionModel::DeleteSelection()
490aac89519SKatayama Hirofumi MZ {
491aac89519SKatayama Hirofumi MZ     if (!m_bShow)
492aac89519SKatayama Hirofumi MZ         return;
493aac89519SKatayama Hirofumi MZ 
494e8c7e300SKatayama Hirofumi MZ     TakeOff();
495e8c7e300SKatayama Hirofumi MZ     imageModel.PushImageForUndo();
4967aadc1e1SKatayama Hirofumi MZ     DrawBackground(imageModel.GetDC());
497e8c7e300SKatayama Hirofumi MZ 
498e8c7e300SKatayama Hirofumi MZ     HideSelection();
499361a2ce4SKatayama Hirofumi MZ }
5007aadc1e1SKatayama Hirofumi MZ 
5017aadc1e1SKatayama Hirofumi MZ void SelectionModel::InvertSelection()
5027aadc1e1SKatayama Hirofumi MZ {
5037aadc1e1SKatayama Hirofumi MZ     TakeOff();
5047aadc1e1SKatayama Hirofumi MZ 
5057aadc1e1SKatayama Hirofumi MZ     BITMAP bm;
506640d67d1SKatayama Hirofumi MZ     ::GetObjectW(m_hbmColor, sizeof(bm), &bm);
5077aadc1e1SKatayama Hirofumi MZ 
5087aadc1e1SKatayama Hirofumi MZ     HDC hdc = ::CreateCompatibleDC(NULL);
5097aadc1e1SKatayama Hirofumi MZ     HGDIOBJ hbmOld = ::SelectObject(hdc, m_hbmColor);
5107aadc1e1SKatayama Hirofumi MZ     RECT rc = { 0, 0, bm.bmWidth, bm.bmHeight };
5117aadc1e1SKatayama Hirofumi MZ     ::InvertRect(hdc, &rc);
5127aadc1e1SKatayama Hirofumi MZ     ::SelectObject(hdc, hbmOld);
5137aadc1e1SKatayama Hirofumi MZ     ::DeleteDC(hdc);
5147aadc1e1SKatayama Hirofumi MZ 
5157aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
5167aadc1e1SKatayama Hirofumi MZ }
5177aadc1e1SKatayama Hirofumi MZ 
5187aadc1e1SKatayama Hirofumi MZ void SelectionModel::NotifyContentChanged()
5197aadc1e1SKatayama Hirofumi MZ {
5207aadc1e1SKatayama Hirofumi MZ     m_bContentChanged = TRUE;
5217aadc1e1SKatayama Hirofumi MZ     imageModel.NotifyImageChanged();
5227aadc1e1SKatayama Hirofumi MZ }
5237aadc1e1SKatayama Hirofumi MZ 
5247aadc1e1SKatayama Hirofumi MZ void SelectionModel::SwapWidthAndHeight()
5257aadc1e1SKatayama Hirofumi MZ {
5264a52a4b0SKatayama Hirofumi MZ     INT cx = m_rc.Width(), cy = m_rc.Height();
5277aadc1e1SKatayama Hirofumi MZ     m_rc.right = m_rc.left + cy;
5287aadc1e1SKatayama Hirofumi MZ     m_rc.bottom = m_rc.top + cx;
5297aadc1e1SKatayama Hirofumi MZ }
530bbb33a6eSKatayama Hirofumi MZ 
531c2bb5aa0SKatayama Hirofumi MZ HITTEST SelectionModel::hitTest(POINT ptCanvas)
532c2bb5aa0SKatayama Hirofumi MZ {
533c2bb5aa0SKatayama Hirofumi MZ     if (!m_bShow)
534c2bb5aa0SKatayama Hirofumi MZ         return HIT_NONE;
535c2bb5aa0SKatayama Hirofumi MZ 
536c2bb5aa0SKatayama Hirofumi MZ     RECT rcSelection = m_rc;
537c2bb5aa0SKatayama Hirofumi MZ     canvasWindow.ImageToCanvas(rcSelection);
538c2bb5aa0SKatayama Hirofumi MZ     ::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE);
539c2bb5aa0SKatayama Hirofumi MZ     return getSizeBoxHitTest(ptCanvas, &rcSelection);
540c2bb5aa0SKatayama Hirofumi MZ }
541c2bb5aa0SKatayama Hirofumi MZ 
5424a52a4b0SKatayama Hirofumi MZ void SelectionModel::drawFrameOnCanvas(HDC hCanvasDC)
5434a52a4b0SKatayama Hirofumi MZ {
5444a52a4b0SKatayama Hirofumi MZ     if (!m_bShow)
5454a52a4b0SKatayama Hirofumi MZ         return;
5464a52a4b0SKatayama Hirofumi MZ 
5474a52a4b0SKatayama Hirofumi MZ     RECT rcSelection = m_rc;
5484a52a4b0SKatayama Hirofumi MZ     canvasWindow.ImageToCanvas(rcSelection);
5494a52a4b0SKatayama Hirofumi MZ 
5504a52a4b0SKatayama Hirofumi MZ     ::InflateRect(&rcSelection, GRIP_SIZE, GRIP_SIZE);
5514a52a4b0SKatayama Hirofumi MZ     drawSizeBoxes(hCanvasDC, &rcSelection, TRUE);
5524a52a4b0SKatayama Hirofumi MZ }
5534a52a4b0SKatayama Hirofumi MZ 
554*f935132fSKatayama Hirofumi MZ void SelectionModel::moveSelection(INT xDelta, INT yDelta)
555*f935132fSKatayama Hirofumi MZ {
556*f935132fSKatayama Hirofumi MZ     if (!m_bShow)
557*f935132fSKatayama Hirofumi MZ         return;
558*f935132fSKatayama Hirofumi MZ 
559*f935132fSKatayama Hirofumi MZ     TakeOff();
560*f935132fSKatayama Hirofumi MZ     ::OffsetRect(&m_rc, xDelta, yDelta);
561*f935132fSKatayama Hirofumi MZ     canvasWindow.Invalidate();
562*f935132fSKatayama Hirofumi MZ }
563*f935132fSKatayama Hirofumi MZ 
564ed9973f8SKatayama Hirofumi MZ void SelectionModel::StretchSelection(BOOL bShrink)
565ed9973f8SKatayama Hirofumi MZ {
566ed9973f8SKatayama Hirofumi MZ     if (!m_bShow)
567ed9973f8SKatayama Hirofumi MZ         return;
568ed9973f8SKatayama Hirofumi MZ 
569ed9973f8SKatayama Hirofumi MZ     TakeOff();
570ed9973f8SKatayama Hirofumi MZ 
571ed9973f8SKatayama Hirofumi MZ     INT cx = m_rc.Width(), cy = m_rc.Height();
572ed9973f8SKatayama Hirofumi MZ 
573ed9973f8SKatayama Hirofumi MZ     if (bShrink)
574ed9973f8SKatayama Hirofumi MZ         m_rc.InflateRect(-cx / 4, -cy / 4);
575ed9973f8SKatayama Hirofumi MZ     else
576ed9973f8SKatayama Hirofumi MZ         m_rc.InflateRect(+cx / 2, +cy / 2);
577ed9973f8SKatayama Hirofumi MZ 
578ed9973f8SKatayama Hirofumi MZ     // The selection area must exist there
579ed9973f8SKatayama Hirofumi MZ     if (m_rc.Width() <= 0)
580ed9973f8SKatayama Hirofumi MZ         m_rc.right = m_rc.left + 1;
581ed9973f8SKatayama Hirofumi MZ     if (m_rc.Height() <= 0)
582ed9973f8SKatayama Hirofumi MZ         m_rc.bottom = m_rc.top + 1;
583ed9973f8SKatayama Hirofumi MZ 
584ed9973f8SKatayama Hirofumi MZ     imageModel.NotifyImageChanged();
585ed9973f8SKatayama Hirofumi MZ }
586