[MSPAINT] Add const to SelectionModel::SetSrcAndDestRectFromPoints parameters
[reactos.git] / base / applications / mspaint / selectionmodel.cpp
1 /*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL
4 * FILE: base/applications/mspaint/selectionmodel.cpp
5 * PURPOSE: Keep track of selection parameters, notify listeners
6 * PROGRAMMERS: Benedikt Freisen
7 */
8
9 /* INCLUDES *********************************************************/
10
11 #include "precomp.h"
12
13 /* FUNCTIONS ********************************************************/
14
15 SelectionModel::SelectionModel()
16 {
17 m_ptStack = NULL;
18 m_iPtSP = 0;
19
20 m_hDC = CreateCompatibleDC(NULL);
21 }
22
23 void SelectionModel::ResetPtStack()
24 {
25 if (m_ptStack != NULL)
26 HeapFree(GetProcessHeap(), 0, m_ptStack);
27 m_ptStack = NULL;
28 m_iPtSP = 0;
29 }
30
31 void SelectionModel::PushToPtStack(LONG x, LONG y)
32 {
33 if (m_iPtSP % 1024 == 0)
34 {
35 if (m_ptStack)
36 m_ptStack = (POINT*) HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, m_ptStack, sizeof(POINT) * (m_iPtSP + 1024));
37 else
38 m_ptStack = (POINT*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * 1024);
39 }
40 m_ptStack[m_iPtSP].x = x;
41 m_ptStack[m_iPtSP].y = y;
42 m_iPtSP++;
43 }
44
45 void SelectionModel::CalculateBoundingBoxAndContents(HDC hDCImage)
46 {
47 int i;
48 m_rcSrc.left = m_rcSrc.top = MAXLONG;
49 m_rcSrc.right = m_rcSrc.bottom = 0;
50 for (i = 0; i < m_iPtSP; i++)
51 {
52 if (m_ptStack[i].x < m_rcSrc.left)
53 m_rcSrc.left = m_ptStack[i].x;
54 if (m_ptStack[i].y < m_rcSrc.top)
55 m_rcSrc.top = m_ptStack[i].y;
56 if (m_ptStack[i].x > m_rcSrc.right)
57 m_rcSrc.right = m_ptStack[i].x;
58 if (m_ptStack[i].y > m_rcSrc.bottom)
59 m_rcSrc.bottom = m_ptStack[i].y;
60 }
61 m_rcSrc.right += 1;
62 m_rcSrc.bottom += 1;
63 m_rcDest.left = m_rcSrc.left;
64 m_rcDest.top = m_rcSrc.top;
65 m_rcDest.right = m_rcSrc.right;
66 m_rcDest.bottom = m_rcSrc.bottom;
67
68 if (m_iPtSP > 1)
69 {
70 DeleteObject(m_hMask);
71 m_hMask = CreateBitmap(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 1, 1, NULL);
72 DeleteObject(SelectObject(m_hDC, m_hMask));
73 POINT *m_ptStackCopy = (POINT*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * m_iPtSP);
74 for (i = 0; i < m_iPtSP; i++)
75 {
76 m_ptStackCopy[i].x = m_ptStack[i].x - m_rcSrc.left;
77 m_ptStackCopy[i].y = m_ptStack[i].y - m_rcSrc.top;
78 }
79 Poly(m_hDC, m_ptStackCopy, m_iPtSP, 0x00ffffff, 0x00ffffff, 1, 2, TRUE, FALSE);
80 HeapFree(GetProcessHeap(), 0, m_ptStackCopy);
81 SelectObject(m_hDC, m_hBm = CreateDIBWithProperties(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc)));
82 imageModel.ResetToPrevious();
83 MaskBlt(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), hDCImage, m_rcSrc.left,
84 m_rcSrc.top, m_hMask, 0, 0, MAKEROP4(SRCCOPY, WHITENESS));
85 }
86 }
87
88 void SelectionModel::CalculateContents(HDC hDCImage)
89 {
90 DeleteObject(m_hMask);
91 m_hMask = CreateBitmap(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 1, 1, NULL);
92 DeleteObject(SelectObject(m_hDC, m_hMask));
93 Rect(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 0x00ffffff, 0x00ffffff, 1, 2);
94 SelectObject(m_hDC, m_hBm = CreateDIBWithProperties(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc)));
95 BitBlt(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), hDCImage, m_rcSrc.left,
96 m_rcSrc.top, SRCCOPY);
97 }
98
99 void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
100 {
101 Poly(hDCImage, m_ptStack, m_iPtSP, crBg, crBg, 1, 2, TRUE, FALSE);
102 }
103
104 void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
105 {
106 Rect(hDCImage, m_rcSrc.left, m_rcSrc.top, m_rcSrc.right, m_rcSrc.bottom, crBg, crBg, 0, 1);
107 }
108
109 extern BOOL
110 ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, HBITMAP hbmMask, int xMask, int yMask, DWORD dwRop, COLORREF keyColor);
111
112 void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent)
113 {
114 if (!bBgTransparent)
115 MaskBlt(hDCImage, m_rcDest.left, m_rcDest.top, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest),
116 m_hDC, 0, 0, m_hMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
117 else
118 ColorKeyedMaskBlt(hDCImage, m_rcDest.left, m_rcDest.top, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest),
119 m_hDC, 0, 0, m_hMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND), crBg);
120 }
121
122 void SelectionModel::DrawSelectionStretched(HDC hDCImage)
123 {
124 StretchBlt(hDCImage, m_rcDest.left, m_rcDest.top, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC, 0, 0, GetDIBWidth(m_hBm), GetDIBHeight(m_hBm), SRCCOPY);
125 }
126
127 void SelectionModel::ScaleContentsToFit()
128 {
129 HDC hTempDC;
130 HBITMAP hTempBm;
131 hTempDC = CreateCompatibleDC(m_hDC);
132 hTempBm = CreateDIBWithProperties(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest));
133 SelectObject(hTempDC, hTempBm);
134 SelectObject(m_hDC, m_hBm);
135 StretchBlt(hTempDC, 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC, 0, 0,
136 GetDIBWidth(m_hBm), GetDIBHeight(m_hBm), SRCCOPY);
137 DeleteObject(m_hBm);
138 m_hBm = hTempBm;
139 hTempBm = CreateBitmap(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), 1, 1, NULL);
140 SelectObject(hTempDC, hTempBm);
141 SelectObject(m_hDC, m_hMask);
142 StretchBlt(hTempDC, 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC, 0, 0,
143 GetDIBWidth(m_hMask), GetDIBHeight(m_hMask), SRCCOPY);
144 DeleteObject(m_hMask);
145 m_hMask = hTempBm;
146 SelectObject(m_hDC, m_hBm);
147 DeleteDC(hTempDC);
148 }
149
150 void SelectionModel::InsertFromHBITMAP(HBITMAP hBm)
151 {
152 HDC hTempDC;
153 HBITMAP hTempMask;
154
155 DeleteObject(SelectObject(m_hDC, m_hBm = (HBITMAP) CopyImage(hBm,
156 IMAGE_BITMAP, 0, 0,
157 LR_COPYRETURNORG)));
158
159 SetRectEmpty(&m_rcSrc);
160 m_rcDest.left = m_rcDest.top = 0;
161 m_rcDest.right = m_rcDest.left + GetDIBWidth(m_hBm);
162 m_rcDest.bottom = m_rcDest.top + GetDIBHeight(m_hBm);
163
164 hTempDC = CreateCompatibleDC(m_hDC);
165 hTempMask = CreateBitmap(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), 1, 1, NULL);
166 SelectObject(hTempDC, hTempMask);
167 Rect(hTempDC, m_rcDest.left, m_rcDest.top, m_rcDest.right, m_rcDest.bottom, 0x00ffffff, 0x00ffffff, 1, 1);
168 DeleteObject(m_hMask);
169 m_hMask = hTempMask;
170 DeleteDC(hTempDC);
171 }
172
173 void SelectionModel::FlipHorizontally()
174 {
175 SelectObject(m_hDC, m_hMask);
176 StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, 0, -RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC,
177 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
178 SelectObject(m_hDC, m_hBm);
179 StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, 0, -RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC,
180 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
181 NotifyRefreshNeeded();
182 }
183
184 void SelectionModel::FlipVertically()
185 {
186 SelectObject(m_hDC, m_hMask);
187 StretchBlt(m_hDC, 0, RECT_HEIGHT(m_rcDest) - 1, RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
188 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
189 SelectObject(m_hDC, m_hBm);
190 StretchBlt(m_hDC, 0, RECT_HEIGHT(m_rcDest) - 1, RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
191 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
192 NotifyRefreshNeeded();
193 }
194
195 void SelectionModel::RotateNTimes90Degrees(int iN)
196 {
197 if (iN == 2)
198 {
199 SelectObject(m_hDC, m_hMask);
200 StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, RECT_HEIGHT(m_rcDest) - 1, -RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
201 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
202 SelectObject(m_hDC, m_hBm);
203 StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, RECT_HEIGHT(m_rcDest) - 1, -RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
204 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
205 }
206 NotifyRefreshNeeded();
207 }
208
209 HBITMAP SelectionModel::GetBitmap()
210 {
211 return m_hBm;
212 }
213
214 int SelectionModel::PtStackSize()
215 {
216 return m_iPtSP;
217 }
218
219 void SelectionModel::DrawFramePoly(HDC hDCImage)
220 {
221 Poly(hDCImage, m_ptStack, m_iPtSP, 0, 0, 2, 0, FALSE, TRUE); /* draw the freehand selection inverted/xored */
222 }
223
224 void SelectionModel::SetSrcAndDestRectFromPoints(const POINT& ptFrom, const POINT& ptTo)
225 {
226 m_rcDest.left = m_rcSrc.left = min(ptFrom.x, ptTo.x);
227 m_rcDest.top = m_rcSrc.top = min(ptFrom.y, ptTo.y);
228 m_rcDest.right = m_rcSrc.right = max(ptFrom.x, ptTo.x);
229 m_rcDest.bottom = m_rcSrc.bottom = max(ptFrom.y, ptTo.y);
230 }
231
232 void SelectionModel::SetSrcRectSizeToZero()
233 {
234 m_rcSrc.right = m_rcSrc.left;
235 m_rcSrc.bottom = m_rcSrc.top;
236 }
237
238 BOOL SelectionModel::IsSrcRectSizeNonzero()
239 {
240 return (RECT_WIDTH(m_rcSrc) != 0) && (RECT_HEIGHT(m_rcSrc) != 0);
241 }
242
243 void SelectionModel::ModifyDestRect(POINT& ptDelta, int iAction)
244 {
245 POINT ptDeltaUsed;
246
247 switch (iAction)
248 {
249 case ACTION_MOVE: /* move selection */
250 ptDeltaUsed.x = ptDelta.x;
251 ptDeltaUsed.y = ptDelta.y;
252 OffsetRect(&m_rcDest, ptDeltaUsed.x, ptDeltaUsed.y);
253 break;
254 case ACTION_RESIZE_TOP_LEFT: /* resize at upper left corner */
255 ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
256 ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
257 m_rcDest.left += ptDeltaUsed.x;
258 m_rcDest.top += ptDeltaUsed.y;
259 break;
260 case ACTION_RESIZE_TOP: /* resize at top edge */
261 ptDeltaUsed.x = ptDelta.x;
262 ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
263 m_rcDest.top += ptDeltaUsed.y;
264 break;
265 case ACTION_RESIZE_TOP_RIGHT: /* resize at upper right corner */
266 ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
267 ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
268 m_rcDest.top += ptDeltaUsed.y;
269 m_rcDest.right += ptDeltaUsed.x;
270 break;
271 case ACTION_RESIZE_LEFT: /* resize at left edge */
272 ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
273 ptDeltaUsed.y = ptDelta.y;
274 m_rcDest.left += ptDeltaUsed.x;
275 break;
276 case ACTION_RESIZE_RIGHT: /* resize at right edge */
277 ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
278 ptDeltaUsed.y = ptDelta.y;
279 m_rcDest.right += ptDeltaUsed.x;
280 break;
281 case ACTION_RESIZE_BOTTOM_LEFT: /* resize at lower left corner */
282 ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
283 ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
284 m_rcDest.left += ptDeltaUsed.x;
285 m_rcDest.bottom += ptDeltaUsed.y;
286 break;
287 case ACTION_RESIZE_BOTTOM: /* resize at bottom edge */
288 ptDeltaUsed.x = ptDelta.x;
289 ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
290 m_rcDest.bottom += ptDeltaUsed.y;
291 break;
292 case ACTION_RESIZE_BOTTOM_RIGHT: /* resize at lower right corner */
293 ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
294 ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
295 m_rcDest.right += ptDeltaUsed.x;
296 m_rcDest.bottom += ptDeltaUsed.y;
297 break;
298 }
299 ptDelta.x -= ptDeltaUsed.x;
300 ptDelta.y -= ptDeltaUsed.y;
301 }
302
303 LONG SelectionModel::GetDestRectWidth()
304 {
305 return m_rcDest.right - m_rcDest.left;
306 }
307
308 LONG SelectionModel::GetDestRectHeight()
309 {
310 return m_rcDest.bottom - m_rcDest.top;
311 }
312
313 LONG SelectionModel::GetDestRectLeft()
314 {
315 return m_rcDest.left;
316 }
317
318 LONG SelectionModel::GetDestRectTop()
319 {
320 return m_rcDest.top;
321 }
322
323 void SelectionModel::DrawTextToolText(HDC hDCImage, COLORREF crFg, COLORREF crBg, BOOL bBgTransparent)
324 {
325 Text(hDCImage, m_rcDest.left, m_rcDest.top, m_rcDest.right, m_rcDest.bottom, crFg, crBg, textToolText, hfontTextFont, bBgTransparent);
326 }
327
328 void SelectionModel::NotifyRefreshNeeded()
329 {
330 selectionWindow.SendMessage(WM_SELECTIONMODELREFRESHNEEDED);
331 }