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