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);
26aac89519SKatayama Hirofumi MZ     m_ptHit.x = m_ptHit.y = -1;
273fa95ab9SKatayama Hirofumi MZ }
28c2c66affSColin Finck 
293fa95ab9SKatayama Hirofumi MZ SelectionModel::~SelectionModel()
303fa95ab9SKatayama Hirofumi MZ {
31*ed9973f8SKatayama Hirofumi MZ     ClearColorImage();
32*ed9973f8SKatayama 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 {
74aac89519SKatayama Hirofumi MZ     CRect rc = { MAXLONG, MAXLONG, 0, 0 };
75aac89519SKatayama Hirofumi MZ     for (INT i = 0; i < m_iPtSP; ++i)
76aac89519SKatayama Hirofumi MZ     {
77aac89519SKatayama Hirofumi MZ         POINT& pt = m_ptStack[i];
78aac89519SKatayama Hirofumi MZ         rc.left = min(pt.x, rc.left);
79aac89519SKatayama Hirofumi MZ         rc.top = min(pt.y, rc.top);
80aac89519SKatayama Hirofumi MZ         rc.right = max(pt.x, rc.right);
81aac89519SKatayama Hirofumi MZ         rc.bottom = max(pt.y, rc.bottom);
82aac89519SKatayama Hirofumi MZ     }
83aac89519SKatayama Hirofumi MZ     rc.right += 1;
84aac89519SKatayama Hirofumi MZ     rc.bottom += 1;
85aac89519SKatayama Hirofumi MZ 
86e8c7e300SKatayama Hirofumi MZ     m_rc = m_rcOld = rc;
87aac89519SKatayama Hirofumi MZ 
88*ed9973f8SKatayama Hirofumi MZ     ClearMaskImage();
89aac89519SKatayama Hirofumi MZ 
90e8c7e300SKatayama Hirofumi MZ     ShiftPtStack(-m_rcOld.left, -m_rcOld.top);
91e8c7e300SKatayama Hirofumi MZ 
92aac89519SKatayama Hirofumi MZ     HDC hdcMem = ::CreateCompatibleDC(NULL);
93aac89519SKatayama Hirofumi MZ     m_hbmMask = ::CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
94aac89519SKatayama Hirofumi MZ     HGDIOBJ hbmOld = ::SelectObject(hdcMem, m_hbmMask);
95e8c7e300SKatayama Hirofumi MZ     ::FillRect(hdcMem, &rc, (HBRUSH)::GetStockObject(BLACK_BRUSH));
96aac89519SKatayama Hirofumi MZ     HGDIOBJ hPenOld = ::SelectObject(hdcMem, GetStockObject(NULL_PEN));
97aac89519SKatayama Hirofumi MZ     HGDIOBJ hbrOld = ::SelectObject(hdcMem, GetStockObject(WHITE_BRUSH));
98aac89519SKatayama Hirofumi MZ     ::Polygon(hdcMem, m_ptStack, m_iPtSP);
99aac89519SKatayama Hirofumi MZ     ::SelectObject(hdcMem, hbrOld);
100aac89519SKatayama Hirofumi MZ     ::SelectObject(hdcMem, hPenOld);
101aac89519SKatayama Hirofumi MZ     ::SelectObject(hdcMem, hbmOld);
102aac89519SKatayama Hirofumi MZ     ::DeleteDC(hdcMem);
103e8c7e300SKatayama Hirofumi MZ 
104e8c7e300SKatayama Hirofumi MZ     ShiftPtStack(+m_rcOld.left, +m_rcOld.top);
105c2c66affSColin Finck }
106c2c66affSColin Finck 
107c2c66affSColin Finck void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
108c2c66affSColin Finck {
109e8c7e300SKatayama Hirofumi MZ     if (::IsRectEmpty(&m_rcOld))
110e8c7e300SKatayama Hirofumi MZ         return;
111aac89519SKatayama Hirofumi MZ 
112aac89519SKatayama Hirofumi MZ     HGDIOBJ hPenOld = ::SelectObject(hDCImage, ::GetStockObject(NULL_PEN));
113aac89519SKatayama Hirofumi MZ     HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::CreateSolidBrush(crBg));
114aac89519SKatayama Hirofumi MZ     ::Polygon(hDCImage, m_ptStack, m_iPtSP);
115aac89519SKatayama Hirofumi MZ     ::DeleteObject(::SelectObject(hDCImage, hbrOld));
116aac89519SKatayama Hirofumi MZ     ::SelectObject(hDCImage, hPenOld);
117c2c66affSColin Finck }
118c2c66affSColin Finck 
119c2c66affSColin Finck void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
120c2c66affSColin Finck {
121e8c7e300SKatayama Hirofumi MZ     if (::IsRectEmpty(&m_rcOld))
122e8c7e300SKatayama Hirofumi MZ         return;
123e8c7e300SKatayama Hirofumi MZ 
124e8c7e300SKatayama Hirofumi MZ     Rect(hDCImage, m_rcOld.left, m_rcOld.top, m_rcOld.right, m_rcOld.bottom, crBg, crBg, 0, 1);
125c2c66affSColin Finck }
126c2c66affSColin Finck 
1277aadc1e1SKatayama Hirofumi MZ void SelectionModel::DrawBackground(HDC hDCImage)
1287aadc1e1SKatayama Hirofumi MZ {
1297aadc1e1SKatayama Hirofumi MZ     if (toolsModel.GetActiveTool() == TOOL_FREESEL)
1307aadc1e1SKatayama Hirofumi MZ         DrawBackgroundPoly(hDCImage, paletteModel.GetBgColor());
1317aadc1e1SKatayama Hirofumi MZ     else
1327aadc1e1SKatayama Hirofumi MZ         DrawBackgroundRect(hDCImage, paletteModel.GetBgColor());
1337aadc1e1SKatayama Hirofumi MZ }
1347aadc1e1SKatayama Hirofumi MZ 
135e8c7e300SKatayama Hirofumi MZ void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent)
136c2c66affSColin Finck {
137e8c7e300SKatayama Hirofumi MZ     CRect rc = m_rc;
138aac89519SKatayama Hirofumi MZ     if (::IsRectEmpty(&rc))
139aac89519SKatayama Hirofumi MZ         return;
140aac89519SKatayama Hirofumi MZ 
141aac89519SKatayama Hirofumi MZ     BITMAP bm;
142e8c7e300SKatayama Hirofumi MZ     if (!GetObject(m_hbmColor, sizeof(BITMAP), &bm))
143e8c7e300SKatayama Hirofumi MZ         return;
144aac89519SKatayama Hirofumi MZ 
145aac89519SKatayama Hirofumi MZ     COLORREF keyColor = (bBgTransparent ? crBg : CLR_INVALID);
146aac89519SKatayama Hirofumi MZ 
147aac89519SKatayama Hirofumi MZ     HDC hMemDC = CreateCompatibleDC(hDCImage);
148aac89519SKatayama Hirofumi MZ     HGDIOBJ hbmOld = SelectObject(hMemDC, m_hbmColor);
149aac89519SKatayama Hirofumi MZ     ColorKeyedMaskBlt(hDCImage, rc.left, rc.top, rc.Width(), rc.Height(),
150aac89519SKatayama Hirofumi MZ                       hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, m_hbmMask, keyColor);
151aac89519SKatayama Hirofumi MZ     SelectObject(hMemDC, hbmOld);
152aac89519SKatayama Hirofumi MZ     DeleteDC(hMemDC);
153aac89519SKatayama Hirofumi MZ }
154aac89519SKatayama Hirofumi MZ 
155aac89519SKatayama Hirofumi MZ void SelectionModel::GetSelectionContents(HDC hDCImage)
156aac89519SKatayama Hirofumi MZ {
157*ed9973f8SKatayama Hirofumi MZ     ClearColorImage();
158aac89519SKatayama Hirofumi MZ 
159aac89519SKatayama Hirofumi MZ     HDC hMemDC = ::CreateCompatibleDC(NULL);
160aac89519SKatayama Hirofumi MZ     m_hbmColor = CreateColorDIB(m_rc.Width(), m_rc.Height(), RGB(255, 255, 255));
161aac89519SKatayama Hirofumi MZ     HGDIOBJ hbmOld = ::SelectObject(hMemDC, m_hbmColor);
162aac89519SKatayama Hirofumi MZ     ::BitBlt(hMemDC, 0, 0, m_rc.Width(), m_rc.Height(), hDCImage, m_rc.left, m_rc.top, SRCCOPY);
163aac89519SKatayama Hirofumi MZ     ::SelectObject(hMemDC, hbmOld);
164aac89519SKatayama Hirofumi MZ     ::DeleteDC(hMemDC);
165aac89519SKatayama Hirofumi MZ }
166aac89519SKatayama Hirofumi MZ 
167e8c7e300SKatayama Hirofumi MZ BOOL SelectionModel::IsLanded() const
168e8c7e300SKatayama Hirofumi MZ {
169e8c7e300SKatayama Hirofumi MZ     return !m_hbmColor;
170e8c7e300SKatayama Hirofumi MZ }
171e8c7e300SKatayama Hirofumi MZ 
172aac89519SKatayama Hirofumi MZ BOOL SelectionModel::TakeOff()
173aac89519SKatayama Hirofumi MZ {
174e8c7e300SKatayama Hirofumi MZ     if (!IsLanded() || ::IsRectEmpty(&m_rc))
175aac89519SKatayama Hirofumi MZ         return FALSE;
176aac89519SKatayama Hirofumi MZ 
177*ed9973f8SKatayama Hirofumi MZ     // The background color is needed for transparency of selection
178e8c7e300SKatayama Hirofumi MZ     m_rgbBack = paletteModel.GetBgColor();
179*ed9973f8SKatayama Hirofumi MZ 
180*ed9973f8SKatayama Hirofumi MZ     // Get the contents of the selection area
181e8c7e300SKatayama Hirofumi MZ     GetSelectionContents(imageModel.GetDC());
182aac89519SKatayama Hirofumi MZ 
183*ed9973f8SKatayama Hirofumi MZ     // RectSel doesn't need the mask image
184e8c7e300SKatayama Hirofumi MZ     if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
185*ed9973f8SKatayama Hirofumi MZ         ClearMaskImage();
186e8c7e300SKatayama Hirofumi MZ 
187*ed9973f8SKatayama Hirofumi MZ     // Save the selection area
188e8c7e300SKatayama Hirofumi MZ     m_rcOld = m_rc;
189c2c66affSColin Finck 
190bfd42c67SKatayama Hirofumi MZ     imageModel.NotifyImageChanged();
191aac89519SKatayama Hirofumi MZ     return TRUE;
192c2c66affSColin Finck }
193c2c66affSColin Finck 
194aac89519SKatayama Hirofumi MZ void SelectionModel::Landing()
195c2c66affSColin Finck {
196e8c7e300SKatayama Hirofumi MZ     if (IsLanded() && !m_bShow)
197e8c7e300SKatayama Hirofumi MZ     {
198e8c7e300SKatayama Hirofumi MZ         imageModel.NotifyImageChanged();
199aac89519SKatayama Hirofumi MZ         return;
200e8c7e300SKatayama Hirofumi MZ     }
201aac89519SKatayama Hirofumi MZ 
202e8c7e300SKatayama Hirofumi MZ     m_bShow = FALSE;
203aac89519SKatayama Hirofumi MZ 
2047aadc1e1SKatayama Hirofumi MZ     if (m_bContentChanged ||
2057aadc1e1SKatayama Hirofumi MZ         (!::EqualRect(m_rc, m_rcOld) && !::IsRectEmpty(m_rc) && !::IsRectEmpty(m_rcOld)))
206e8c7e300SKatayama Hirofumi MZ     {
2072b623c1dSKatayama Hirofumi MZ         imageModel.PushImageForUndo();
208e8c7e300SKatayama Hirofumi MZ 
209e8c7e300SKatayama Hirofumi MZ         canvasWindow.m_drawing = FALSE;
210e8c7e300SKatayama Hirofumi MZ         toolsModel.OnDrawOverlayOnImage(imageModel.GetDC());
211e8c7e300SKatayama Hirofumi MZ     }
212e8c7e300SKatayama Hirofumi MZ 
213e8c7e300SKatayama Hirofumi MZ     HideSelection();
214c2c66affSColin Finck }
215c2c66affSColin Finck 
2169afcbea2SKatayama Hirofumi MZ void SelectionModel::InsertFromHBITMAP(HBITMAP hbmColor, INT x, INT y, HBITMAP hbmMask)
217c2c66affSColin Finck {
218aac89519SKatayama Hirofumi MZ     ::DeleteObject(m_hbmColor);
219b5335fb9SKatayama Hirofumi MZ     m_hbmColor = hbmColor;
220c2c66affSColin Finck 
221aac89519SKatayama Hirofumi MZ     m_rc.left = x;
222aac89519SKatayama Hirofumi MZ     m_rc.top = y;
2239afcbea2SKatayama Hirofumi MZ     m_rc.right = x + GetDIBWidth(hbmColor);
2249afcbea2SKatayama Hirofumi MZ     m_rc.bottom = y + GetDIBHeight(hbmColor);
2259afcbea2SKatayama Hirofumi MZ 
2269afcbea2SKatayama Hirofumi MZ     if (hbmMask)
2279afcbea2SKatayama Hirofumi MZ     {
2289afcbea2SKatayama Hirofumi MZ         ::DeleteObject(m_hbmMask);
229b5335fb9SKatayama Hirofumi MZ         m_hbmMask = hbmMask;
2309afcbea2SKatayama Hirofumi MZ     }
2319afcbea2SKatayama Hirofumi MZ     else
2329afcbea2SKatayama Hirofumi MZ     {
233*ed9973f8SKatayama Hirofumi MZ         ClearMaskImage();
2349afcbea2SKatayama Hirofumi MZ     }
2359f56e67bSKatayama Hirofumi MZ 
2367aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
237c2c66affSColin Finck }
238c2c66affSColin Finck 
239c2c66affSColin Finck void SelectionModel::FlipHorizontally()
240c2c66affSColin Finck {
241aac89519SKatayama Hirofumi MZ     TakeOff();
242aac89519SKatayama Hirofumi MZ 
243aac89519SKatayama Hirofumi MZ     HDC hdcMem = ::CreateCompatibleDC(NULL);
244aac89519SKatayama Hirofumi MZ     if (m_hbmMask)
245aac89519SKatayama Hirofumi MZ     {
246aac89519SKatayama Hirofumi MZ         ::SelectObject(hdcMem, m_hbmMask);
247aac89519SKatayama Hirofumi MZ         ::StretchBlt(hdcMem, m_rc.Width() - 1, 0, -m_rc.Width(), m_rc.Height(),
248aac89519SKatayama Hirofumi MZ                      hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
249aac89519SKatayama Hirofumi MZ     }
250aac89519SKatayama Hirofumi MZ     if (m_hbmColor)
251aac89519SKatayama Hirofumi MZ     {
252aac89519SKatayama Hirofumi MZ         ::SelectObject(hdcMem, m_hbmColor);
253aac89519SKatayama Hirofumi MZ         ::StretchBlt(hdcMem, m_rc.Width() - 1, 0, -m_rc.Width(), m_rc.Height(),
254aac89519SKatayama Hirofumi MZ                      hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
255aac89519SKatayama Hirofumi MZ     }
256aac89519SKatayama Hirofumi MZ     ::DeleteDC(hdcMem);
257aac89519SKatayama Hirofumi MZ 
2587aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
259c2c66affSColin Finck }
260c2c66affSColin Finck 
261c2c66affSColin Finck void SelectionModel::FlipVertically()
262c2c66affSColin Finck {
263aac89519SKatayama Hirofumi MZ     TakeOff();
264aac89519SKatayama Hirofumi MZ 
265aac89519SKatayama Hirofumi MZ     HDC hdcMem = ::CreateCompatibleDC(NULL);
266aac89519SKatayama Hirofumi MZ     if (m_hbmMask)
267aac89519SKatayama Hirofumi MZ     {
268aac89519SKatayama Hirofumi MZ         ::SelectObject(hdcMem, m_hbmMask);
269aac89519SKatayama Hirofumi MZ         ::StretchBlt(hdcMem, 0, m_rc.Height() - 1, m_rc.Width(), -m_rc.Height(),
270aac89519SKatayama Hirofumi MZ                      hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
271aac89519SKatayama Hirofumi MZ     }
272aac89519SKatayama Hirofumi MZ     if (m_hbmColor)
273aac89519SKatayama Hirofumi MZ     {
274aac89519SKatayama Hirofumi MZ         ::SelectObject(hdcMem, m_hbmColor);
275aac89519SKatayama Hirofumi MZ         ::StretchBlt(hdcMem, 0, m_rc.Height() - 1, m_rc.Width(), -m_rc.Height(),
276aac89519SKatayama Hirofumi MZ                      hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
277aac89519SKatayama Hirofumi MZ     }
278aac89519SKatayama Hirofumi MZ     ::DeleteDC(hdcMem);
279aac89519SKatayama Hirofumi MZ 
2807aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
281c2c66affSColin Finck }
282c2c66affSColin Finck 
283c2c66affSColin Finck void SelectionModel::RotateNTimes90Degrees(int iN)
284c2c66affSColin Finck {
2852d909190SKatayama Hirofumi MZ     HBITMAP hbm;
286aac89519SKatayama Hirofumi MZ     HGDIOBJ hbmOld;
287aac89519SKatayama Hirofumi MZ     HDC hdcMem = ::CreateCompatibleDC(NULL);
288aac89519SKatayama Hirofumi MZ 
2892d909190SKatayama Hirofumi MZ     switch (iN)
290c2c66affSColin Finck     {
2917aadc1e1SKatayama Hirofumi MZ         case 1: /* rotate 90 degrees */
2927aadc1e1SKatayama Hirofumi MZ         case 3: /* rotate 270 degrees */
293aac89519SKatayama Hirofumi MZ             TakeOff();
2947aadc1e1SKatayama Hirofumi MZ 
295aac89519SKatayama Hirofumi MZ             if (m_hbmColor)
296aac89519SKatayama Hirofumi MZ             {
297aac89519SKatayama Hirofumi MZ                 hbmOld = ::SelectObject(hdcMem, m_hbmColor);
298aac89519SKatayama Hirofumi MZ                 hbm = Rotate90DegreeBlt(hdcMem, m_rc.Width(), m_rc.Height(), iN == 1, FALSE);
299aac89519SKatayama Hirofumi MZ                 ::SelectObject(hdcMem, hbmOld);
300aac89519SKatayama Hirofumi MZ                 ::DeleteObject(m_hbmColor);
301aac89519SKatayama Hirofumi MZ                 m_hbmColor = hbm;
302aac89519SKatayama Hirofumi MZ             }
303aac89519SKatayama Hirofumi MZ             if (m_hbmMask)
304aac89519SKatayama Hirofumi MZ             {
305aac89519SKatayama Hirofumi MZ                 hbmOld = ::SelectObject(hdcMem, m_hbmMask);
306aac89519SKatayama Hirofumi MZ                 hbm = Rotate90DegreeBlt(hdcMem, m_rc.Width(), m_rc.Height(), iN == 1, TRUE);
307aac89519SKatayama Hirofumi MZ                 ::SelectObject(hdcMem, hbmOld);
308aac89519SKatayama Hirofumi MZ                 ::DeleteObject(m_hbmMask);
309aac89519SKatayama Hirofumi MZ                 m_hbmMask = hbm;
310aac89519SKatayama Hirofumi MZ             }
3117aadc1e1SKatayama Hirofumi MZ 
3127aadc1e1SKatayama Hirofumi MZ             SwapWidthAndHeight();
3132d909190SKatayama Hirofumi MZ             break;
314aac89519SKatayama Hirofumi MZ 
3157aadc1e1SKatayama Hirofumi MZ         case 2: /* rotate 180 degrees */
316aac89519SKatayama Hirofumi MZ             TakeOff();
3177aadc1e1SKatayama Hirofumi MZ 
318aac89519SKatayama Hirofumi MZ             if (m_hbmColor)
319aac89519SKatayama Hirofumi MZ             {
320aac89519SKatayama Hirofumi MZ                 hbmOld = ::SelectObject(hdcMem, m_hbmColor);
321aac89519SKatayama Hirofumi MZ                 ::StretchBlt(hdcMem, m_rc.Width() - 1, m_rc.Height() - 1, -m_rc.Width(), -m_rc.Height(),
322aac89519SKatayama Hirofumi MZ                              hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
323aac89519SKatayama Hirofumi MZ                 ::SelectObject(hdcMem, hbmOld);
324aac89519SKatayama Hirofumi MZ             }
325aac89519SKatayama Hirofumi MZ             if (m_hbmMask)
326aac89519SKatayama Hirofumi MZ             {
327aac89519SKatayama Hirofumi MZ                 hbmOld = ::SelectObject(hdcMem, m_hbmMask);
328aac89519SKatayama Hirofumi MZ                 ::StretchBlt(hdcMem, m_rc.Width() - 1, m_rc.Height() - 1, -m_rc.Width(), -m_rc.Height(),
329aac89519SKatayama Hirofumi MZ                              hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
330aac89519SKatayama Hirofumi MZ                 ::SelectObject(hdcMem, hbmOld);
331aac89519SKatayama Hirofumi MZ             }
3322d909190SKatayama Hirofumi MZ             break;
333c2c66affSColin Finck     }
334aac89519SKatayama Hirofumi MZ 
335aac89519SKatayama Hirofumi MZ     ::DeleteDC(hdcMem);
3367aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
337c2c66affSColin Finck }
338c2c66affSColin Finck 
339b5335fb9SKatayama Hirofumi MZ static void AttachHBITMAP(HBITMAP *phbm, HBITMAP hbmNew)
340b5335fb9SKatayama Hirofumi MZ {
341b5335fb9SKatayama Hirofumi MZ     if (hbmNew == NULL)
342b5335fb9SKatayama Hirofumi MZ         return;
343b5335fb9SKatayama Hirofumi MZ     ::DeleteObject(*phbm);
344b5335fb9SKatayama Hirofumi MZ     *phbm = hbmNew;
345b5335fb9SKatayama Hirofumi MZ }
346b5335fb9SKatayama Hirofumi MZ 
347dfd06ee8SKatayama Hirofumi MZ void SelectionModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY)
348dfd06ee8SKatayama Hirofumi MZ {
349dfd06ee8SKatayama Hirofumi MZ     if (nStretchPercentX == 100 && nStretchPercentY == 100 && nSkewDegX == 0 && nSkewDegY == 0)
350dfd06ee8SKatayama Hirofumi MZ         return;
351dfd06ee8SKatayama Hirofumi MZ 
352aac89519SKatayama Hirofumi MZ     TakeOff();
353dfd06ee8SKatayama Hirofumi MZ 
354b5335fb9SKatayama Hirofumi MZ     INT oldWidth = m_rc.Width(), oldHeight = m_rc.Height();
355dfd06ee8SKatayama Hirofumi MZ     INT newWidth = oldWidth * nStretchPercentX / 100;
356dfd06ee8SKatayama Hirofumi MZ     INT newHeight = oldHeight * nStretchPercentY / 100;
357dfd06ee8SKatayama Hirofumi MZ 
358b5335fb9SKatayama Hirofumi MZ     HBITMAP hbmColor = m_hbmColor, hbmMask = m_hbmMask;
3599afcbea2SKatayama Hirofumi MZ 
360b5335fb9SKatayama Hirofumi MZ     if (hbmMask == NULL)
361b5335fb9SKatayama Hirofumi MZ         hbmMask = CreateMonoBitmap(oldWidth, oldHeight, TRUE);
3629afcbea2SKatayama Hirofumi MZ 
363dfd06ee8SKatayama Hirofumi MZ     if (oldWidth != newWidth || oldHeight != newHeight)
364dfd06ee8SKatayama Hirofumi MZ     {
365b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmColor, CopyDIBImage(hbmColor, newWidth, newHeight));
366b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmMask, CopyMonoImage(hbmMask, newWidth, newHeight));
367dfd06ee8SKatayama Hirofumi MZ     }
368dfd06ee8SKatayama Hirofumi MZ 
369b5335fb9SKatayama Hirofumi MZ     HGDIOBJ hbmOld;
370aac89519SKatayama Hirofumi MZ     HDC hDC = ::CreateCompatibleDC(NULL);
371aac89519SKatayama Hirofumi MZ 
372dfd06ee8SKatayama Hirofumi MZ     if (nSkewDegX)
373dfd06ee8SKatayama Hirofumi MZ     {
374b5335fb9SKatayama Hirofumi MZ         hbmOld = ::SelectObject(hDC, hbmColor);
375b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmColor, SkewDIB(hDC, hbmColor, nSkewDegX, FALSE));
376b5335fb9SKatayama Hirofumi MZ         ::SelectObject(hDC, hbmMask);
377b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmMask, SkewDIB(hDC, hbmMask, nSkewDegX, FALSE, TRUE));
3789afcbea2SKatayama Hirofumi MZ         ::SelectObject(hDC, hbmOld);
379dfd06ee8SKatayama Hirofumi MZ     }
380dfd06ee8SKatayama Hirofumi MZ 
381dfd06ee8SKatayama Hirofumi MZ     if (nSkewDegY)
382dfd06ee8SKatayama Hirofumi MZ     {
383b5335fb9SKatayama Hirofumi MZ         hbmOld = ::SelectObject(hDC, hbmColor);
384b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmColor, SkewDIB(hDC, hbmColor, nSkewDegY, TRUE));
385b5335fb9SKatayama Hirofumi MZ         ::SelectObject(hDC, hbmMask);
386b5335fb9SKatayama Hirofumi MZ         AttachHBITMAP(&hbmMask, SkewDIB(hDC, hbmMask, nSkewDegY, TRUE, TRUE));
3879afcbea2SKatayama Hirofumi MZ         ::SelectObject(hDC, hbmOld);
388dfd06ee8SKatayama Hirofumi MZ     }
389dfd06ee8SKatayama Hirofumi MZ 
390aac89519SKatayama Hirofumi MZ     ::DeleteDC(hDC);
391aac89519SKatayama Hirofumi MZ 
392b5335fb9SKatayama Hirofumi MZ     InsertFromHBITMAP(hbmColor, m_rc.left, m_rc.top, hbmMask);
393b5335fb9SKatayama Hirofumi MZ 
394aac89519SKatayama Hirofumi MZ     m_bShow = TRUE;
3957aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
396dfd06ee8SKatayama Hirofumi MZ }
397dfd06ee8SKatayama Hirofumi MZ 
398e8c7e300SKatayama Hirofumi MZ HBITMAP SelectionModel::CopyBitmap()
399c2c66affSColin Finck {
40096c7fe4cSKatayama Hirofumi MZ     if (m_hbmColor == NULL)
40196c7fe4cSKatayama Hirofumi MZ         GetSelectionContents(imageModel.GetDC());
402e8c7e300SKatayama Hirofumi MZ     return CopyDIBImage(m_hbmColor);
403c2c66affSColin Finck }
404c2c66affSColin Finck 
405b5536e44SKatayama Hirofumi MZ int SelectionModel::PtStackSize() const
406c2c66affSColin Finck {
407c2c66affSColin Finck     return m_iPtSP;
408c2c66affSColin Finck }
409c2c66affSColin Finck 
410c2c66affSColin Finck void SelectionModel::DrawFramePoly(HDC hDCImage)
411c2c66affSColin Finck {
412aac89519SKatayama Hirofumi MZ     /* draw the freehand selection inverted/xored */
413aac89519SKatayama Hirofumi MZ     Poly(hDCImage, m_ptStack, m_iPtSP, 0, 0, 2, 0, FALSE, TRUE);
414c2c66affSColin Finck }
415c2c66affSColin Finck 
416aac89519SKatayama Hirofumi MZ void SelectionModel::SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo)
417c2c66affSColin Finck {
418aac89519SKatayama Hirofumi MZ     m_rc.left = min(ptFrom.x, ptTo.x);
419aac89519SKatayama Hirofumi MZ     m_rc.top = min(ptFrom.y, ptTo.y);
420aac89519SKatayama Hirofumi MZ     m_rc.right = max(ptFrom.x, ptTo.x);
421aac89519SKatayama Hirofumi MZ     m_rc.bottom = max(ptFrom.y, ptTo.y);
422c2c66affSColin Finck }
423c2c66affSColin Finck 
424cb98e91bSKatayama Hirofumi MZ void SelectionModel::Dragging(HITTEST hit, POINT pt)
425c2c66affSColin Finck {
426aac89519SKatayama Hirofumi MZ     switch (hit)
427c2c66affSColin Finck     {
428aac89519SKatayama Hirofumi MZ         case HIT_NONE:
429c2c66affSColin Finck             break;
430aac89519SKatayama Hirofumi MZ         case HIT_UPPER_LEFT:
431aac89519SKatayama Hirofumi MZ             m_rc.left += pt.x - m_ptHit.x;
432aac89519SKatayama Hirofumi MZ             m_rc.top += pt.y - m_ptHit.y;
433c2c66affSColin Finck             break;
434aac89519SKatayama Hirofumi MZ         case HIT_UPPER_CENTER:
435aac89519SKatayama Hirofumi MZ             m_rc.top += pt.y - m_ptHit.y;
436c2c66affSColin Finck             break;
437aac89519SKatayama Hirofumi MZ         case HIT_UPPER_RIGHT:
438aac89519SKatayama Hirofumi MZ             m_rc.right += pt.x - m_ptHit.x;
439aac89519SKatayama Hirofumi MZ             m_rc.top += pt.y - m_ptHit.y;
440c2c66affSColin Finck             break;
441aac89519SKatayama Hirofumi MZ         case HIT_MIDDLE_LEFT:
442aac89519SKatayama Hirofumi MZ             m_rc.left += pt.x - m_ptHit.x;
443c2c66affSColin Finck             break;
444aac89519SKatayama Hirofumi MZ         case HIT_MIDDLE_RIGHT:
445aac89519SKatayama Hirofumi MZ             m_rc.right += pt.x - m_ptHit.x;
446c2c66affSColin Finck             break;
447aac89519SKatayama Hirofumi MZ         case HIT_LOWER_LEFT:
448aac89519SKatayama Hirofumi MZ             m_rc.left += pt.x - m_ptHit.x;
449aac89519SKatayama Hirofumi MZ             m_rc.bottom += pt.y - m_ptHit.y;
450c2c66affSColin Finck             break;
451aac89519SKatayama Hirofumi MZ         case HIT_LOWER_CENTER:
452aac89519SKatayama Hirofumi MZ             m_rc.bottom += pt.y - m_ptHit.y;
453c2c66affSColin Finck             break;
454aac89519SKatayama Hirofumi MZ         case HIT_LOWER_RIGHT:
455aac89519SKatayama Hirofumi MZ             m_rc.right += pt.x - m_ptHit.x;
456aac89519SKatayama Hirofumi MZ             m_rc.bottom += pt.y - m_ptHit.y;
457aac89519SKatayama Hirofumi MZ             break;
458aac89519SKatayama Hirofumi MZ         case HIT_BORDER:
459aac89519SKatayama Hirofumi MZ         case HIT_INNER:
460aac89519SKatayama Hirofumi MZ             OffsetRect(&m_rc, pt.x - m_ptHit.x, pt.y - m_ptHit.y);
461c2c66affSColin Finck             break;
462c2c66affSColin Finck     }
463aac89519SKatayama Hirofumi MZ     m_ptHit = pt;
464c2c66affSColin Finck }
465c2c66affSColin Finck 
466*ed9973f8SKatayama Hirofumi MZ void SelectionModel::ClearMaskImage()
467361a2ce4SKatayama Hirofumi MZ {
468aac89519SKatayama Hirofumi MZ     if (m_hbmMask)
469aac89519SKatayama Hirofumi MZ     {
470aac89519SKatayama Hirofumi MZ         ::DeleteObject(m_hbmMask);
471aac89519SKatayama Hirofumi MZ         m_hbmMask = NULL;
472aac89519SKatayama Hirofumi MZ     }
473aac89519SKatayama Hirofumi MZ }
474aac89519SKatayama Hirofumi MZ 
475*ed9973f8SKatayama Hirofumi MZ void SelectionModel::ClearColorImage()
476aac89519SKatayama Hirofumi MZ {
477aac89519SKatayama Hirofumi MZ     if (m_hbmColor)
478aac89519SKatayama Hirofumi MZ     {
479aac89519SKatayama Hirofumi MZ         ::DeleteObject(m_hbmColor);
480aac89519SKatayama Hirofumi MZ         m_hbmColor = NULL;
481aac89519SKatayama Hirofumi MZ     }
482aac89519SKatayama Hirofumi MZ }
483aac89519SKatayama Hirofumi MZ 
484e8c7e300SKatayama Hirofumi MZ void SelectionModel::HideSelection()
485e8c7e300SKatayama Hirofumi MZ {
4867aadc1e1SKatayama Hirofumi MZ     m_bShow = m_bContentChanged = FALSE;
487*ed9973f8SKatayama Hirofumi MZ     ClearColorImage();
488*ed9973f8SKatayama Hirofumi MZ     ClearMaskImage();
489e8c7e300SKatayama Hirofumi MZ     ::SetRectEmpty(&m_rc);
490e8c7e300SKatayama Hirofumi MZ     ::SetRectEmpty(&m_rcOld);
491e8c7e300SKatayama Hirofumi MZ     imageModel.NotifyImageChanged();
492e8c7e300SKatayama Hirofumi MZ }
493e8c7e300SKatayama Hirofumi MZ 
494e8c7e300SKatayama Hirofumi MZ void SelectionModel::DeleteSelection()
495aac89519SKatayama Hirofumi MZ {
496aac89519SKatayama Hirofumi MZ     if (!m_bShow)
497aac89519SKatayama Hirofumi MZ         return;
498aac89519SKatayama Hirofumi MZ 
499e8c7e300SKatayama Hirofumi MZ     TakeOff();
500e8c7e300SKatayama Hirofumi MZ     imageModel.PushImageForUndo();
5017aadc1e1SKatayama Hirofumi MZ     DrawBackground(imageModel.GetDC());
502e8c7e300SKatayama Hirofumi MZ 
503e8c7e300SKatayama Hirofumi MZ     HideSelection();
504361a2ce4SKatayama Hirofumi MZ }
5057aadc1e1SKatayama Hirofumi MZ 
5067aadc1e1SKatayama Hirofumi MZ void SelectionModel::InvertSelection()
5077aadc1e1SKatayama Hirofumi MZ {
5087aadc1e1SKatayama Hirofumi MZ     TakeOff();
5097aadc1e1SKatayama Hirofumi MZ 
5107aadc1e1SKatayama Hirofumi MZ     BITMAP bm;
5117aadc1e1SKatayama Hirofumi MZ     ::GetObject(m_hbmColor, sizeof(bm), &bm);
5127aadc1e1SKatayama Hirofumi MZ 
5137aadc1e1SKatayama Hirofumi MZ     HDC hdc = ::CreateCompatibleDC(NULL);
5147aadc1e1SKatayama Hirofumi MZ     HGDIOBJ hbmOld = ::SelectObject(hdc, m_hbmColor);
5157aadc1e1SKatayama Hirofumi MZ     RECT rc = { 0, 0, bm.bmWidth, bm.bmHeight };
5167aadc1e1SKatayama Hirofumi MZ     ::InvertRect(hdc, &rc);
5177aadc1e1SKatayama Hirofumi MZ     ::SelectObject(hdc, hbmOld);
5187aadc1e1SKatayama Hirofumi MZ     ::DeleteDC(hdc);
5197aadc1e1SKatayama Hirofumi MZ 
5207aadc1e1SKatayama Hirofumi MZ     NotifyContentChanged();
5217aadc1e1SKatayama Hirofumi MZ }
5227aadc1e1SKatayama Hirofumi MZ 
5237aadc1e1SKatayama Hirofumi MZ void SelectionModel::NotifyContentChanged()
5247aadc1e1SKatayama Hirofumi MZ {
5257aadc1e1SKatayama Hirofumi MZ     m_bContentChanged = TRUE;
5267aadc1e1SKatayama Hirofumi MZ     imageModel.NotifyImageChanged();
5277aadc1e1SKatayama Hirofumi MZ }
5287aadc1e1SKatayama Hirofumi MZ 
5297aadc1e1SKatayama Hirofumi MZ void SelectionModel::SwapWidthAndHeight()
5307aadc1e1SKatayama Hirofumi MZ {
5317aadc1e1SKatayama Hirofumi MZ     INT cx = m_rc.Width();
5327aadc1e1SKatayama Hirofumi MZ     INT cy = m_rc.Height();
5337aadc1e1SKatayama Hirofumi MZ     m_rc.right = m_rc.left + cy;
5347aadc1e1SKatayama Hirofumi MZ     m_rc.bottom = m_rc.top + cx;
5357aadc1e1SKatayama Hirofumi MZ }
536bbb33a6eSKatayama Hirofumi MZ 
537bbb33a6eSKatayama Hirofumi MZ HBITMAP SelectionModel::LockBitmap()
538bbb33a6eSKatayama Hirofumi MZ {
539bbb33a6eSKatayama Hirofumi MZ     HBITMAP hbm = m_hbmColor;
540bbb33a6eSKatayama Hirofumi MZ     m_hbmColor = NULL;
541bbb33a6eSKatayama Hirofumi MZ     return hbm;
542bbb33a6eSKatayama Hirofumi MZ }
543bbb33a6eSKatayama Hirofumi MZ 
544bbb33a6eSKatayama Hirofumi MZ void SelectionModel::UnlockBitmap(HBITMAP hbmLocked)
545bbb33a6eSKatayama Hirofumi MZ {
546bbb33a6eSKatayama Hirofumi MZ     m_hbmColor = hbmLocked;
547bbb33a6eSKatayama Hirofumi MZ }
548*ed9973f8SKatayama Hirofumi MZ 
549*ed9973f8SKatayama Hirofumi MZ void SelectionModel::StretchSelection(BOOL bShrink)
550*ed9973f8SKatayama Hirofumi MZ {
551*ed9973f8SKatayama Hirofumi MZ     if (!m_bShow)
552*ed9973f8SKatayama Hirofumi MZ         return;
553*ed9973f8SKatayama Hirofumi MZ 
554*ed9973f8SKatayama Hirofumi MZ     TakeOff();
555*ed9973f8SKatayama Hirofumi MZ 
556*ed9973f8SKatayama Hirofumi MZ     INT cx = m_rc.Width(), cy = m_rc.Height();
557*ed9973f8SKatayama Hirofumi MZ 
558*ed9973f8SKatayama Hirofumi MZ     if (bShrink)
559*ed9973f8SKatayama Hirofumi MZ         m_rc.InflateRect(-cx / 4, -cy / 4);
560*ed9973f8SKatayama Hirofumi MZ     else
561*ed9973f8SKatayama Hirofumi MZ         m_rc.InflateRect(+cx / 2, +cy / 2);
562*ed9973f8SKatayama Hirofumi MZ 
563*ed9973f8SKatayama Hirofumi MZ     // The selection area must exist there
564*ed9973f8SKatayama Hirofumi MZ     if (m_rc.Width() <= 0)
565*ed9973f8SKatayama Hirofumi MZ         m_rc.right = m_rc.left + 1;
566*ed9973f8SKatayama Hirofumi MZ     if (m_rc.Height() <= 0)
567*ed9973f8SKatayama Hirofumi MZ         m_rc.bottom = m_rc.top + 1;
568*ed9973f8SKatayama Hirofumi MZ 
569*ed9973f8SKatayama Hirofumi MZ     imageModel.NotifyImageChanged();
570*ed9973f8SKatayama Hirofumi MZ }
571