ReactOS 0.4.16-dev-125-g798ea90
selectionmodel.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: PAINT for ReactOS
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Keep track of selection parameters, notify listeners
5 * COPYRIGHT: Copyright 2015 Benedikt Freisen <b.freisen@gmx.net>
6 * Copyright 2019 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7 */
8
9#include "precomp.h"
10
12
13/* FUNCTIONS ********************************************************/
14
16 : m_hbmColor(NULL)
17 , m_hbmMask(NULL)
18 , m_rgbBack(RGB(255, 255, 255))
19 , m_bShow(FALSE)
20 , m_bContentChanged(FALSE)
21{
24 m_ptHit = { -1, -1 };
25}
26
28{
31}
32
34{
35 if (m_rcOld.IsRectEmpty())
36 return;
37
38 HGDIOBJ hbrOld = ::SelectObject(hDCImage, ::GetStockObject(DC_BRUSH));
39 ::SetDCBrushColor(hDCImage, crBg);
42 ::SelectObject(hDCImage, hbrOld);
43}
44
46{
47 if (m_rcOld.IsRectEmpty())
48 return;
49
50 Rect(hDCImage, m_rcOld.left, m_rcOld.top, m_rcOld.right, m_rcOld.bottom, crBg, crBg, 0, 1);
51}
52
54{
56 DrawBackgroundPoly(hDCImage, crBg);
57 else
58 DrawBackgroundRect(hDCImage, crBg);
59}
60
61void
62SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent, const CRect& rc,
64{
65 if (rc.IsRectEmpty())
66 return;
67
68 BITMAP bm;
69 if (!GetObjectW(hbm, sizeof(BITMAP), &bm))
70 return;
71
72 COLORREF keyColor = (bBgTransparent ? crBg : CLR_INVALID);
73
74 HDC hMemDC = CreateCompatibleDC(hDCImage);
75 HGDIOBJ hbmOld = SelectObject(hMemDC, hbm);
76 ColorKeyedMaskBlt(hDCImage, rc.left, rc.top, rc.Width(), rc.Height(),
77 hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, m_hbmMask, keyColor);
78 SelectObject(hMemDC, hbmOld);
79 DeleteDC(hMemDC);
80}
81
82void SelectionModel::setMask(const CRect& rc, HBITMAP hbmMask)
83{
84 if (m_hbmMask)
86
87 m_hbmMask = hbmMask;
88 m_rc = m_rcOld = rc;
89}
90
92{
93 HBITMAP hbmWhole = imageModel.LockBitmap();
94 HBITMAP hbmPart = getSubImage(hbmWhole, (IsLanded() ? m_rc : m_rcOld));
95 imageModel.UnlockBitmap(hbmWhole);
96 if (!hbmPart)
97 return NULL;
98
99 CRect rc = { 0, 0, m_rc.Width(), m_rc.Height() };
100
103 HGDIOBJ hbmOld = ::SelectObject(hdcMem, hbmNew);
105 ::SelectObject(hdcMem, hbmOld);
107
108 ::DeleteObject(hbmPart);
109 return hbmNew;
110}
111
113{
114 return !m_hbmColor;
115}
116
118{
119 if (!IsLanded() || m_rc.IsRectEmpty())
120 return FALSE;
121
122 // The background color is needed for transparency of selection
124
125 // Get the contents of the selection area
128
129 // RectSel doesn't need the mask image
132
133 // Save the selection area
134 m_rcOld = m_rc;
135
137 return TRUE;
138}
139
141{
142 if (IsLanded() && !m_bShow)
143 {
145 return;
146 }
147
148 if (m_bContentChanged ||
150 {
151 CRect rc;
154
157 }
158
160}
161
163{
165 m_hbmColor = hbmColor;
166
167 m_rc.left = x;
168 m_rc.top = y;
169 m_rc.right = x + GetDIBWidth(hbmColor);
170 m_rc.bottom = y + GetDIBHeight(hbmColor);
171
172 if (hbmMask)
173 {
175 m_hbmMask = hbmMask;
176 }
177 else
178 {
180 }
181
183}
184
186{
187 TakeOff();
188
190 if (m_hbmMask)
191 {
194 hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
195 }
196 if (m_hbmColor)
197 {
200 hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
201 }
203
205}
206
208{
209 TakeOff();
210
212 if (m_hbmMask)
213 {
216 hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
217 }
218 if (m_hbmColor)
219 {
222 hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
223 }
225
227}
228
230{
231 HBITMAP hbm;
232 HGDIOBJ hbmOld;
234
235 switch (iN)
236 {
237 case 1: /* rotate 90 degrees */
238 case 3: /* rotate 270 degrees */
239 TakeOff();
240
241 if (m_hbmColor)
242 {
245 ::SelectObject(hdcMem, hbmOld);
247 m_hbmColor = hbm;
248 }
249 if (m_hbmMask)
250 {
253 ::SelectObject(hdcMem, hbmOld);
255 m_hbmMask = hbm;
256 }
257
259 break;
260
261 case 2: /* rotate 180 degrees */
262 TakeOff();
263
264 if (m_hbmColor)
265 {
268 hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
269 ::SelectObject(hdcMem, hbmOld);
270 }
271 if (m_hbmMask)
272 {
275 hdcMem, 0, 0, m_rc.Width(), m_rc.Height(), SRCCOPY);
276 ::SelectObject(hdcMem, hbmOld);
277 }
278 break;
279 }
280
283}
284
285static void AttachHBITMAP(HBITMAP *phbm, HBITMAP hbmNew)
286{
287 if (hbmNew == NULL)
288 return;
289 ::DeleteObject(*phbm);
290 *phbm = hbmNew;
291}
292
293void SelectionModel::StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY)
294{
295 if (nStretchPercentX == 100 && nStretchPercentY == 100 && nSkewDegX == 0 && nSkewDegY == 0)
296 return;
297
298 TakeOff();
299
300 INT oldWidth = m_rc.Width(), oldHeight = m_rc.Height();
301 INT newWidth = oldWidth * nStretchPercentX / 100;
302 INT newHeight = oldHeight * nStretchPercentY / 100;
303
304 HBITMAP hbmColor = m_hbmColor, hbmMask = m_hbmMask;
305
306 if (hbmMask == NULL)
307 hbmMask = CreateMonoBitmap(oldWidth, oldHeight, TRUE);
308
309 if (oldWidth != newWidth || oldHeight != newHeight)
310 {
311 AttachHBITMAP(&hbmColor, CopyDIBImage(hbmColor, newWidth, newHeight));
312 AttachHBITMAP(&hbmMask, CopyMonoImage(hbmMask, newWidth, newHeight));
313 }
314
315 HGDIOBJ hbmOld;
317
318 if (nSkewDegX)
319 {
320 hbmOld = ::SelectObject(hDC, hbmColor);
321 AttachHBITMAP(&hbmColor, SkewDIB(hDC, hbmColor, nSkewDegX, FALSE));
322 ::SelectObject(hDC, hbmMask);
323 AttachHBITMAP(&hbmMask, SkewDIB(hDC, hbmMask, nSkewDegX, FALSE, TRUE));
324 ::SelectObject(hDC, hbmOld);
325 }
326
327 if (nSkewDegY)
328 {
329 hbmOld = ::SelectObject(hDC, hbmColor);
330 AttachHBITMAP(&hbmColor, SkewDIB(hDC, hbmColor, nSkewDegY, TRUE));
331 ::SelectObject(hDC, hbmMask);
332 AttachHBITMAP(&hbmMask, SkewDIB(hDC, hbmMask, nSkewDegY, TRUE, TRUE));
333 ::SelectObject(hDC, hbmOld);
334 }
335
337
338 InsertFromHBITMAP(hbmColor, m_rc.left, m_rc.top, hbmMask);
339
340 m_bShow = TRUE;
342}
343
344void SelectionModel::SetRectFromPoints(const POINT& ptFrom, const POINT& ptTo)
345{
346 m_rc = CRect(ptFrom, ptTo);
348}
349
351{
352 switch (hit)
353 {
354 case HIT_NONE:
355 break;
356 case HIT_UPPER_LEFT:
357 m_rc.left += pt.x - m_ptHit.x;
358 m_rc.top += pt.y - m_ptHit.y;
359 break;
360 case HIT_UPPER_CENTER:
361 m_rc.top += pt.y - m_ptHit.y;
362 break;
363 case HIT_UPPER_RIGHT:
364 m_rc.right += pt.x - m_ptHit.x;
365 m_rc.top += pt.y - m_ptHit.y;
366 break;
367 case HIT_MIDDLE_LEFT:
368 m_rc.left += pt.x - m_ptHit.x;
369 break;
370 case HIT_MIDDLE_RIGHT:
371 m_rc.right += pt.x - m_ptHit.x;
372 break;
373 case HIT_LOWER_LEFT:
374 m_rc.left += pt.x - m_ptHit.x;
375 m_rc.bottom += pt.y - m_ptHit.y;
376 break;
377 case HIT_LOWER_CENTER:
378 m_rc.bottom += pt.y - m_ptHit.y;
379 break;
380 case HIT_LOWER_RIGHT:
381 m_rc.right += pt.x - m_ptHit.x;
382 m_rc.bottom += pt.y - m_ptHit.y;
383 break;
384 case HIT_BORDER:
385 case HIT_INNER:
386 m_rc.OffsetRect(pt.x - m_ptHit.x, pt.y - m_ptHit.y);
387 break;
388 }
389 m_ptHit = pt;
390}
391
393{
394 if (m_hbmMask)
395 {
397 m_hbmMask = NULL;
398 }
399}
400
402{
403 if (m_hbmColor)
404 {
407 }
408}
409
411{
418}
419
421{
422 if (!m_bShow)
423 return;
424
425 TakeOff();
428
430}
431
433{
434 TakeOff();
435
436 BITMAP bm;
437 ::GetObjectW(m_hbmColor, sizeof(bm), &bm);
438
441 RECT rc = { 0, 0, bm.bmWidth, bm.bmHeight };
442 ::InvertRect(hdc, &rc);
443 ::SelectObject(hdc, hbmOld);
445
447}
448
450{
453}
454
456{
457 INT cx = m_rc.Width(), cy = m_rc.Height();
458 m_rc.right = m_rc.left + cy;
459 m_rc.bottom = m_rc.top + cx;
460}
461
463{
464 if (!m_bShow)
465 return HIT_NONE;
466
467 CRect rcSelection = m_rc;
468 canvasWindow.ImageToCanvas(rcSelection);
469 rcSelection.InflateRect(GRIP_SIZE, GRIP_SIZE);
470 return getSizeBoxHitTest(ptCanvas, &rcSelection);
471}
472
474{
475 if (!m_bShow)
476 return;
477
478 CRect rcSelection = m_rc;
479 canvasWindow.ImageToCanvas(rcSelection);
480 rcSelection.InflateRect(GRIP_SIZE, GRIP_SIZE);
481 drawSizeBoxes(hCanvasDC, &rcSelection, TRUE);
482}
483
485{
486 if (!m_bShow)
487 return;
488
489 TakeOff();
490 m_rc.OffsetRect(xDelta, yDelta);
491 canvasWindow.Invalidate();
492}
493
495{
496 if (!m_bShow)
497 return;
498
499 TakeOff();
500
501 INT cx = m_rc.Width(), cy = m_rc.Height();
502
503 if (bShrink)
504 m_rc.InflateRect(-cx / 4, -cy / 4);
505 else
506 m_rc.InflateRect(+cx / 2, +cy / 2);
507
508 // The selection area must exist there
509 if (m_rc.Width() <= 0)
510 m_rc.right = m_rc.left + 1;
511 if (m_rc.Height() <= 0)
512 m_rc.bottom = m_rc.top + 1;
513
515}
static HDC hDC
Definition: 3dtext.c:33
static HBITMAP CopyDIBImage(HBITMAP hbm, INT cx=0, INT cy=0)
Definition: dib.h:19
ToolsModel toolsModel
Definition: toolsmodel.cpp:10
#define GRIP_SIZE
Definition: precomp.h:43
SelectionModel selectionModel
HITTEST
Definition: precomp.h:55
@ HIT_NONE
Definition: precomp.h:56
@ HIT_BORDER
Definition: precomp.h:65
@ HIT_LOWER_RIGHT
Definition: precomp.h:64
@ HIT_LOWER_CENTER
Definition: precomp.h:63
@ HIT_UPPER_LEFT
Definition: precomp.h:57
@ HIT_INNER
Definition: precomp.h:66
@ HIT_LOWER_LEFT
Definition: precomp.h:62
@ HIT_UPPER_CENTER
Definition: precomp.h:58
@ HIT_UPPER_RIGHT
Definition: precomp.h:59
@ HIT_MIDDLE_RIGHT
Definition: precomp.h:61
@ HIT_MIDDLE_LEFT
Definition: precomp.h:60
CCanvasWindow canvasWindow
Definition: canvas.cpp:10
BOOL m_drawing
Definition: canvas.h:43
VOID ImageToCanvas(POINT &pt)
Definition: canvas.cpp:40
void SetRectEmpty() noexcept
Definition: atltypes.h:431
void InflateRect(int x, int y) noexcept
Definition: atltypes.h:323
void OffsetRect(int x, int y) noexcept
Definition: atltypes.h:403
void NormalizeRect() noexcept
Definition: atltypes.h:387
BOOL UnionRect(LPCRECT lpRect1, LPCRECT lpRect2) noexcept
Definition: atltypes.h:456
int Width() const noexcept
Definition: atltypes.h:461
int Height() const noexcept
Definition: atltypes.h:318
BOOL IsRectEmpty() const noexcept
Definition: atltypes.h:351
BOOL EqualRect(LPCRECT lpRect) const noexcept
Definition: atltypes.h:312
HBITMAP LockBitmap()
Definition: history.cpp:345
void PushImageForUndo()
Definition: history.cpp:127
void NotifyImageChanged()
Definition: history.cpp:23
void UnlockBitmap(HBITMAP hbmLocked)
Definition: history.cpp:354
HDC GetDC()
Definition: history.cpp:271
COLORREF GetBgColor() const
HBITMAP m_hbmColor
void DrawBackground(HDC hDCImage, COLORREF crBg)
void DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
void RotateNTimes90Degrees(int iN)
void StretchSkew(int nStretchPercentX, int nStretchPercentY, int nSkewDegX, int nSkewDegY)
HBITMAP GetSelectionContents()
void DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent, const CRect &rc, HBITMAP hbm)
void InsertFromHBITMAP(HBITMAP hbmColor, INT x=0, INT y=0, HBITMAP hbmMask=NULL)
COLORREF m_rgbBack
void NotifyContentChanged()
void moveSelection(INT xDelta, INT yDelta)
void drawFrameOnCanvas(HDC hCanvasDC)
void Dragging(HITTEST hit, POINT pt)
void setMask(const CRect &rc, HBITMAP hbmMask)
HITTEST hitTest(POINT ptCanvas)
BOOL IsLanded() const
void SetRectFromPoints(const POINT &ptFrom, const POINT &ptTo)
void DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
void StretchSelection(BOOL bShrink)
void OnDrawOverlayOnImage(HDC hdc)
Definition: mouse.cpp:1186
TOOLTYPE GetActiveTool() const
Definition: toolsmodel.cpp:134
HBITMAP getSubImage(HBITMAP hbmWhole, const RECT &rcPartial)
Definition: dib.cpp:409
HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical, BOOL bMono)
Definition: dib.cpp:351
HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight, BOOL bMono)
Definition: dib.cpp:312
HBITMAP CopyMonoImage(HBITMAP hbm, INT cx, INT cy)
Definition: dib.cpp:87
int GetDIBHeight(HBITMAP hBitmap)
Definition: dib.cpp:144
HBITMAP CreateMonoBitmap(int width, int height, BOOL bWhite)
Definition: dib.cpp:45
HBITMAP CreateColorDIB(int width, int height, COLORREF rgb)
Definition: dib.cpp:65
int GetDIBWidth(HBITMAP hBitmap)
Definition: dib.cpp:136
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define pt(x, y)
Definition: drawing.c:79
BOOL ColorKeyedMaskBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, int nSrcWidth, int nSrcHeight, HBITMAP hbmMask, COLORREF keyColor)
Definition: drawing.cpp:287
#define RGB(r, g, b)
Definition: precomp.h:71
unsigned int BOOL
Definition: ntddk_ex.h:94
pKey DeleteObject()
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
ImageModel imageModel
Definition: history.cpp:11
HDC hdc
Definition: main.c:9
static HBITMAP
Definition: button.c:44
static HDC
Definition: imagelist.c:88
_In_ HBITMAP hbm
Definition: ntgdi.h:2776
PaletteModel paletteModel
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
_Out_opt_ int * cx
Definition: commctrl.h:585
SelectionModel selectionModel
static void AttachHBITMAP(HBITMAP *phbm, HBITMAP hbmNew)
VOID drawSizeBoxes(HDC hdc, LPCRECT prcBase, BOOL bDrawFrame, LPCRECT prcPaint)
Definition: sizebox.cpp:103
HITTEST getSizeBoxHitTest(POINT pt, LPCRECT prcBase)
Definition: sizebox.cpp:80
Definition: bl.h:1331
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
LONG right
Definition: windef.h:308
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
LONG left
Definition: windef.h:306
@ TOOL_FREESEL
Definition: toolsmodel.h:12
@ TOOL_RECTSEL
Definition: toolsmodel.h:13
int32_t INT
Definition: typedefs.h:58
HDC hdcMem
Definition: welcome.c:104
COLORREF WINAPI SetDCBrushColor(_In_ HDC hdc, _In_ COLORREF crColor)
Definition: dc.c:905
DWORD COLORREF
Definition: windef.h:300
HGDIOBJ WINAPI GetStockObject(_In_ int)
int WINAPI GetObjectW(_In_ HANDLE h, _In_ int c, _Out_writes_bytes_opt_(c) LPVOID pv)
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1546
BOOL WINAPI MaskBlt(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int, _In_ HDC, _In_ int, _In_ int, _In_ HBITMAP, _In_ int, _In_ int, _In_ DWORD)
HDC WINAPI CreateCompatibleDC(_In_opt_ HDC hdc)
BOOL WINAPI StretchBlt(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int, _In_opt_ HDC, _In_ int, _In_ int, _In_ int, _In_ int, _In_ DWORD)
#define CLR_INVALID
Definition: wingdi.h:883
#define SRCCOPY
Definition: wingdi.h:333
#define PATCOPY
Definition: wingdi.h:335
BOOL WINAPI DeleteDC(_In_ HDC)
#define MAKEROP4(f, b)
Definition: wingdi.h:2946
BOOL WINAPI InvertRect(_In_ HDC, _In_ LPCRECT)