2 * PROJECT: PAINT for ReactOS
4 * FILE: base/applications/mspaint/selectionmodel.cpp
5 * PURPOSE: Keep track of selection parameters, notify listeners
6 * PROGRAMMERS: Benedikt Freisen
9 /* INCLUDES *********************************************************/
13 /* FUNCTIONS ********************************************************/
15 SelectionModel::SelectionModel()
20 m_hDC
= CreateCompatibleDC(NULL
);
23 void SelectionModel::ResetPtStack()
25 if (m_ptStack
!= NULL
)
26 HeapFree(GetProcessHeap(), 0, m_ptStack
);
31 void SelectionModel::PushToPtStack(LONG x
, LONG y
)
33 if (m_iPtSP
% 1024 == 0)
36 m_ptStack
= (POINT
*) HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS
, m_ptStack
, sizeof(POINT
) * (m_iPtSP
+ 1024));
38 m_ptStack
= (POINT
*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS
, sizeof(POINT
) * 1024);
40 m_ptStack
[m_iPtSP
].x
= x
;
41 m_ptStack
[m_iPtSP
].y
= y
;
45 void SelectionModel::CalculateBoundingBoxAndContents(HDC hDCImage
)
48 m_rcSrc
.left
= m_rcSrc
.top
= MAXLONG
;
49 m_rcSrc
.right
= m_rcSrc
.bottom
= 0;
50 for (i
= 0; i
< m_iPtSP
; i
++)
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
;
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
;
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
++)
76 m_ptStackCopy
[i
].x
= m_ptStack
[i
].x
- m_rcSrc
.left
;
77 m_ptStackCopy
[i
].y
= m_ptStack
[i
].y
- m_rcSrc
.top
;
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
));
88 void SelectionModel::CalculateContents(HDC hDCImage
)
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
);
99 void SelectionModel::DrawBackgroundPoly(HDC hDCImage
, COLORREF crBg
)
101 Poly(hDCImage
, m_ptStack
, m_iPtSP
, crBg
, crBg
, 1, 2, TRUE
, FALSE
);
104 void SelectionModel::DrawBackgroundRect(HDC hDCImage
, COLORREF crBg
)
106 Rect(hDCImage
, m_rcSrc
.left
, m_rcSrc
.top
, m_rcSrc
.right
, m_rcSrc
.bottom
, crBg
, crBg
, 0, 1);
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
);
112 void SelectionModel::DrawSelection(HDC hDCImage
, COLORREF crBg
, BOOL 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
));
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
);
122 void SelectionModel::DrawSelectionStretched(HDC hDCImage
)
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
);
127 void SelectionModel::ScaleContentsToFit()
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
);
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
);
146 SelectObject(m_hDC
, m_hBm
);
150 void SelectionModel::InsertFromHBITMAP(HBITMAP hBm
)
155 DeleteObject(SelectObject(m_hDC
, m_hBm
= (HBITMAP
) CopyImage(hBm
,
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
);
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
);
173 void SelectionModel::FlipHorizontally()
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();
184 void SelectionModel::FlipVertically()
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();
195 void SelectionModel::RotateNTimes90Degrees(int iN
)
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
);
206 NotifyRefreshNeeded();
209 HBITMAP
SelectionModel::GetBitmap()
214 int SelectionModel::PtStackSize()
219 void SelectionModel::DrawFramePoly(HDC hDCImage
)
221 Poly(hDCImage
, m_ptStack
, m_iPtSP
, 0, 0, 2, 0, FALSE
, TRUE
); /* draw the freehand selection inverted/xored */
224 void SelectionModel::SetSrcAndDestRectFromPoints(const POINT
& ptFrom
, const POINT
& ptTo
)
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
);
232 void SelectionModel::SetSrcRectSizeToZero()
234 m_rcSrc
.right
= m_rcSrc
.left
;
235 m_rcSrc
.bottom
= m_rcSrc
.top
;
238 BOOL
SelectionModel::IsSrcRectSizeNonzero()
240 return (RECT_WIDTH(m_rcSrc
) != 0) && (RECT_HEIGHT(m_rcSrc
) != 0);
243 void SelectionModel::ModifyDestRect(POINT
& ptDelta
, int iAction
)
249 case ACTION_MOVE
: /* move selection */
250 ptDeltaUsed
.x
= ptDelta
.x
;
251 ptDeltaUsed
.y
= ptDelta
.y
;
252 OffsetRect(&m_rcDest
, ptDeltaUsed
.x
, ptDeltaUsed
.y
);
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
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
299 ptDelta
.x
-= ptDeltaUsed
.x
;
300 ptDelta
.y
-= ptDeltaUsed
.y
;
303 LONG
SelectionModel::GetDestRectWidth()
305 return m_rcDest
.right
- m_rcDest
.left
;
308 LONG
SelectionModel::GetDestRectHeight()
310 return m_rcDest
.bottom
- m_rcDest
.top
;
313 LONG
SelectionModel::GetDestRectLeft()
315 return m_rcDest
.left
;
318 LONG
SelectionModel::GetDestRectTop()
323 void SelectionModel::DrawTextToolText(HDC hDCImage
, COLORREF crFg
, COLORREF crBg
, BOOL bBgTransparent
)
325 Text(hDCImage
, m_rcDest
.left
, m_rcDest
.top
, m_rcDest
.right
, m_rcDest
.bottom
, crFg
, crBg
, textToolText
, hfontTextFont
, bBgTransparent
);
328 void SelectionModel::NotifyRefreshNeeded()
330 selectionWindow
.SendMessage(WM_SELECTIONMODELREFRESHNEEDED
);