[MSPAINT_NEW] refactoring: move selection management to a dedicated SelectionModel (WIP)

svn path=/trunk/; revision=68382
This commit is contained in:
Benedikt Freisen 2015-07-09 09:48:01 +00:00
parent b0451457d7
commit 3116acb259
10 changed files with 528 additions and 335 deletions

View file

@ -18,6 +18,7 @@ list(APPEND SOURCE
registry.cpp
scrollbox.cpp
selection.cpp
selectionmodel.cpp
sizebox.cpp
textedit.cpp
toolbox.cpp

View file

@ -21,7 +21,6 @@ typedef struct tagSTRETCHSKEW {
/* VARIABLES declared in main.c *************************************/
extern HDC hDrawingDC;
extern HDC hSelDC;
extern int *bmAddress;
extern BITMAPINFO bitmapinfo;
@ -39,10 +38,9 @@ extern POINT last;
class ToolsModel;
extern ToolsModel toolsModel;
extern RECT rectSel_src;
extern RECT rectSel_dest;
extern HBITMAP hSelBm;
extern HBITMAP hSelMask;
class SelectionModel;
extern SelectionModel selectionModel;
extern HWND hwndEditCtl;
extern LOGFONT lfTextFont;
extern HFONT hfontTextFont;
@ -114,5 +112,3 @@ extern CTextEditWindow textEditWindow;
extern POINT pointStack[256];
extern short pointSP;
extern POINT *ptStack;
extern int ptSP;

View file

@ -13,7 +13,6 @@
/* FUNCTIONS ********************************************************/
HDC hDrawingDC;
HDC hSelDC;
int *bmAddress;
BITMAPINFO bitmapinfo;
int imgXRes = 400;
@ -31,10 +30,8 @@ POINT last;
ToolsModel toolsModel;
RECT rectSel_src;
RECT rectSel_dest;
HBITMAP hSelBm;
HBITMAP hSelMask;
SelectionModel selectionModel;
LOGFONT lfTextFont;
HFONT hfontTextFont;
HWND hwndEditCtl;
@ -205,7 +202,7 @@ _tWinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPTSTR lpszArgument
hDC = imageArea.GetDC();
hDrawingDC = CreateCompatibleDC(hDC);
hSelDC = CreateCompatibleDC(hDC);
selectionModel.SetDC(CreateCompatibleDC(hDC));
imageArea.ReleaseDC(hDC);
SelectObject(hDrawingDC, CreatePen(PS_SOLID, 0, paletteModel.GetFgColor()));
SelectObject(hDrawingDC, CreateSolidBrush(paletteModel.GetBgColor()));

View file

@ -15,44 +15,42 @@
void
placeSelWin()
{
selectionWindow.MoveWindow(rectSel_dest.left * toolsModel.GetZoom() / 1000, rectSel_dest.top * toolsModel.GetZoom() / 1000,
RECT_WIDTH(rectSel_dest) * toolsModel.GetZoom() / 1000 + 6, RECT_HEIGHT(rectSel_dest) * toolsModel.GetZoom() / 1000 + 6, TRUE);
selectionWindow.MoveWindow(selectionModel.GetDestRectLeft() * toolsModel.GetZoom() / 1000, selectionModel.GetDestRectTop() * toolsModel.GetZoom() / 1000,
selectionModel.GetDestRectWidth() * toolsModel.GetZoom() / 1000 + 6, selectionModel.GetDestRectHeight() * toolsModel.GetZoom() / 1000 + 6, TRUE);
selectionWindow.BringWindowToTop();
imageArea.InvalidateRect(NULL, FALSE);
}
void
regularize(LONG x0, LONG y0, LONG *x1, LONG *y1)
regularize(LONG x0, LONG y0, LONG& x1, LONG& y1)
{
if (abs(*x1 - x0) >= abs(*y1 - y0))
*y1 = y0 + (*y1 > y0 ? abs(*x1 - x0) : -abs(*x1 - x0));
if (abs(x1 - x0) >= abs(y1 - y0))
y1 = y0 + (y1 > y0 ? abs(x1 - x0) : -abs(x1 - x0));
else
*x1 = x0 + (*x1 > x0 ? abs(*y1 - y0) : -abs(*y1 - y0));
x1 = x0 + (x1 > x0 ? abs(y1 - y0) : -abs(y1 - y0));
}
void
roundTo8Directions(LONG x0, LONG y0, LONG *x1, LONG *y1)
roundTo8Directions(LONG x0, LONG y0, LONG& x1, LONG& y1)
{
if (abs(*x1 - x0) >= abs(*y1 - y0))
if (abs(x1 - x0) >= abs(y1 - y0))
{
if (abs(*y1 - y0) * 5 < abs(*x1 - x0) * 2)
*y1 = y0;
if (abs(y1 - y0) * 5 < abs(x1 - x0) * 2)
y1 = y0;
else
*y1 = y0 + (*y1 > y0 ? abs(*x1 - x0) : -abs(*x1 - x0));
y1 = y0 + (y1 > y0 ? abs(x1 - x0) : -abs(x1 - x0));
}
else
{
if (abs(*x1 - x0) * 5 < abs(*y1 - y0) * 2)
*x1 = x0;
if (abs(x1 - x0) * 5 < abs(y1 - y0) * 2)
x1 = x0;
else
*x1 = x0 + (*x1 > x0 ? abs(*y1 - y0) : -abs(*y1 - y0));
x1 = x0 + (x1 > x0 ? abs(y1 - y0) : -abs(y1 - y0));
}
}
POINT pointStack[256];
short pointSP;
POINT *ptStack = NULL;
int ptSP = 0;
void
startPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
@ -65,12 +63,8 @@ startPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
{
case TOOL_FREESEL:
selectionWindow.ShowWindow(SW_HIDE);
if (ptStack != NULL)
HeapFree(GetProcessHeap(), 0, ptStack);
ptStack = (POINT*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * 1024);
ptSP = 0;
ptStack[0].x = x;
ptStack[0].y = y;
selectionModel.ResetPtStack();
selectionModel.PushToPtStack(x, y);
break;
case TOOL_LINE:
case TOOL_RECT:
@ -82,8 +76,7 @@ startPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_TEXT:
imageModel.CopyPrevious();
selectionWindow.ShowWindow(SW_HIDE);
rectSel_src.right = rectSel_src.left;
rectSel_src.bottom = rectSel_src.top;
selectionModel.SetSrcRectSizeToZero();
break;
case TOOL_RUBBER:
imageModel.CopyPrevious();
@ -134,15 +127,11 @@ whilePaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
switch (toolsModel.GetActiveTool())
{
case TOOL_FREESEL:
if (ptSP == 0)
if (selectionModel.PtStackSize() == 1)
imageModel.CopyPrevious();
ptSP++;
if (ptSP % 1024 == 0)
ptStack = (POINT*) HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, ptStack, sizeof(POINT) * (ptSP + 1024));
ptStack[ptSP].x = max(0, min(x, imageModel.GetWidth()));
ptStack[ptSP].y = max(0, min(y, imageModel.GetHeight()));
selectionModel.PushToPtStack(max(0, min(x, imageModel.GetWidth())), max(0, min(y, imageModel.GetHeight())));
imageModel.ResetToPrevious();
Poly(hdc, ptStack, ptSP + 1, 0, 0, 2, 0, FALSE, TRUE); /* draw the freehand selection inverted/xored */
selectionModel.DrawFramePoly(hdc);
break;
case TOOL_RECTSEL:
case TOOL_TEXT:
@ -151,10 +140,7 @@ whilePaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
imageModel.ResetToPrevious();
temp.x = max(0, min(x, imageModel.GetWidth()));
temp.y = max(0, min(y, imageModel.GetHeight()));
rectSel_dest.left = rectSel_src.left = min(start.x, temp.x);
rectSel_dest.top = rectSel_src.top = min(start.y, temp.y);
rectSel_dest.right = rectSel_src.right = max(start.x, temp.x);
rectSel_dest.bottom = rectSel_src.bottom = max(start.y, temp.y);
selectionModel.SetSrcAndDestRectFromPoints(start, temp);
RectSel(hdc, start.x, start.y, temp.x, temp.y);
break;
}
@ -173,7 +159,7 @@ whilePaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_LINE:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
roundTo8Directions(start.x, start.y, &x, &y);
roundTo8Directions(start.x, start.y, x, y);
Line(hdc, start.x, start.y, x, y, fg, toolsModel.GetLineWidth());
break;
case TOOL_BEZIER:
@ -197,7 +183,7 @@ whilePaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_RECT:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
Rect(hdc, start.x, start.y, x, y, fg, bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
case TOOL_SHAPE:
@ -206,20 +192,20 @@ whilePaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
pointStack[pointSP].y = y;
if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y,
&pointStack[pointSP].x, &pointStack[pointSP].y);
pointStack[pointSP].x, pointStack[pointSP].y);
if (pointSP + 1 >= 2)
Poly(hdc, pointStack, pointSP + 1, fg, bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), FALSE, FALSE);
break;
case TOOL_ELLIPSE:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
Ellp(hdc, start.x, start.y, x, y, fg, bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
case TOOL_RRECT:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
RRect(hdc, start.x, start.y, x, y, fg, bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
}
@ -235,79 +221,30 @@ endPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
{
case TOOL_FREESEL:
{
POINT *ptStackCopy;
int i;
rectSel_src.left = rectSel_src.top = MAXLONG;
rectSel_src.right = rectSel_src.bottom = 0;
for (i = 0; i <= ptSP; i++)
selectionModel.CalculateBoundingBoxAndContents(hdc);
if (selectionModel.PtStackSize() > 1)
{
if (ptStack[i].x < rectSel_src.left)
rectSel_src.left = ptStack[i].x;
if (ptStack[i].y < rectSel_src.top)
rectSel_src.top = ptStack[i].y;
if (ptStack[i].x > rectSel_src.right)
rectSel_src.right = ptStack[i].x;
if (ptStack[i].y > rectSel_src.bottom)
rectSel_src.bottom = ptStack[i].y;
}
rectSel_src.right += 1;
rectSel_src.bottom += 1;
rectSel_dest.left = rectSel_src.left;
rectSel_dest.top = rectSel_src.top;
rectSel_dest.right = rectSel_src.right;
rectSel_dest.bottom = rectSel_src.bottom;
if (ptSP != 0)
{
DeleteObject(hSelMask);
hSelMask = CreateBitmap(RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src), 1, 1, NULL);
DeleteObject(SelectObject(hSelDC, hSelMask));
ptStackCopy = (POINT*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * (ptSP + 1));
for (i = 0; i <= ptSP; i++)
{
ptStackCopy[i].x = ptStack[i].x - rectSel_src.left;
ptStackCopy[i].y = ptStack[i].y - rectSel_src.top;
}
Poly(hSelDC, ptStackCopy, ptSP + 1, 0x00ffffff, 0x00ffffff, 1, 2, TRUE, FALSE);
HeapFree(GetProcessHeap(), 0, ptStackCopy);
SelectObject(hSelDC, hSelBm = CreateDIBWithProperties(RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src)));
imageModel.ResetToPrevious();
MaskBlt(hSelDC, 0, 0, RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src), hDrawingDC, rectSel_src.left,
rectSel_src.top, hSelMask, 0, 0, MAKEROP4(SRCCOPY, WHITENESS));
Poly(hdc, ptStack, ptSP + 1, bg, bg, 1, 2, TRUE, FALSE);
selectionModel.DrawBackgroundPoly(hdc, bg);
imageModel.CopyPrevious();
MaskBlt(hDrawingDC, rectSel_src.left, rectSel_src.top, RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src), hSelDC, 0,
0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
selectionModel.DrawSelection(hdc);
placeSelWin();
selectionWindow.ShowWindow(SW_SHOW);
/* force refresh of selection contents */
selectionWindow.SendMessage(WM_LBUTTONDOWN, 0, 0);
selectionWindow.SendMessage(WM_MOUSEMOVE, 0, 0);
selectionWindow.SendMessage(WM_LBUTTONUP, 0, 0);
ForceRefreshSelectionContents();
}
HeapFree(GetProcessHeap(), 0, ptStack);
ptStack = NULL;
selectionModel.ResetPtStack();
break;
}
case TOOL_RECTSEL:
imageModel.ResetToPrevious();
if ((RECT_WIDTH(rectSel_src) != 0) && (RECT_HEIGHT(rectSel_src) != 0))
if (selectionModel.IsSrcRectSizeNonzero())
{
DeleteObject(hSelMask);
hSelMask = CreateBitmap(RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src), 1, 1, NULL);
DeleteObject(SelectObject(hSelDC, hSelMask));
Rect(hSelDC, 0, 0, RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src), 0x00ffffff, 0x00ffffff, 1, 2);
SelectObject(hSelDC, hSelBm = CreateDIBWithProperties(RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src)));
imageModel.ResetToPrevious();
BitBlt(hSelDC, 0, 0, RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src), hDrawingDC, rectSel_src.left,
rectSel_src.top, SRCCOPY);
Rect(hdc, rectSel_src.left, rectSel_src.top, rectSel_src.right,
rectSel_src.bottom, bg, bg, 0, TRUE);
selectionModel.CalculateContents(hdc);
selectionModel.DrawBackgroundRect(hdc, bg);
imageModel.CopyPrevious();
BitBlt(hDrawingDC, rectSel_src.left, rectSel_src.top, RECT_WIDTH(rectSel_src), RECT_HEIGHT(rectSel_src), hSelDC, 0,
0, SRCCOPY);
selectionModel.DrawSelection(hdc);
placeSelWin();
selectionWindow.ShowWindow(SW_SHOW);
@ -316,7 +253,7 @@ endPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
break;
case TOOL_TEXT:
imageModel.ResetToPrevious();
if ((RECT_WIDTH(rectSel_src) != 0) && (RECT_HEIGHT(rectSel_src) != 0))
if (selectionModel.IsSrcRectSizeNonzero())
{
imageModel.CopyPrevious();
@ -335,7 +272,7 @@ endPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_LINE:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
roundTo8Directions(start.x, start.y, &x, &y);
roundTo8Directions(start.x, start.y, x, y);
Line(hdc, start.x, start.y, x, y, fg, toolsModel.GetLineWidth());
break;
case TOOL_BEZIER:
@ -346,7 +283,7 @@ endPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_RECT:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
Rect(hdc, start.x, start.y, x, y, fg, bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
case TOOL_SHAPE:
@ -355,7 +292,7 @@ endPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
pointStack[pointSP].y = y;
if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y,
&pointStack[pointSP].x, &pointStack[pointSP].y);
pointStack[pointSP].x, pointStack[pointSP].y);
pointSP++;
if (pointSP >= 2)
{
@ -376,13 +313,13 @@ endPaintingL(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_ELLIPSE:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
Ellp(hdc, start.x, start.y, x, y, fg, bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
case TOOL_RRECT:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
RRect(hdc, start.x, start.y, x, y, fg, bg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
}
@ -468,7 +405,7 @@ whilePaintingR(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_LINE:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
roundTo8Directions(start.x, start.y, &x, &y);
roundTo8Directions(start.x, start.y, x, y);
Line(hdc, start.x, start.y, x, y, bg, toolsModel.GetLineWidth());
break;
case TOOL_BEZIER:
@ -492,7 +429,7 @@ whilePaintingR(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_RECT:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
Rect(hdc, start.x, start.y, x, y, bg, fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
case TOOL_SHAPE:
@ -501,20 +438,20 @@ whilePaintingR(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
pointStack[pointSP].y = y;
if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y,
&pointStack[pointSP].x, &pointStack[pointSP].y);
pointStack[pointSP].x, pointStack[pointSP].y);
if (pointSP + 1 >= 2)
Poly(hdc, pointStack, pointSP + 1, bg, fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle(), FALSE, FALSE);
break;
case TOOL_ELLIPSE:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
Ellp(hdc, start.x, start.y, x, y, bg, fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
case TOOL_RRECT:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
RRect(hdc, start.x, start.y, x, y, bg, fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
}
@ -538,7 +475,7 @@ endPaintingR(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_LINE:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
roundTo8Directions(start.x, start.y, &x, &y);
roundTo8Directions(start.x, start.y, x, y);
Line(hdc, start.x, start.y, x, y, bg, toolsModel.GetLineWidth());
break;
case TOOL_BEZIER:
@ -549,7 +486,7 @@ endPaintingR(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_RECT:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
Rect(hdc, start.x, start.y, x, y, bg, fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
case TOOL_SHAPE:
@ -558,7 +495,7 @@ endPaintingR(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
pointStack[pointSP].y = y;
if ((pointSP > 0) && (GetAsyncKeyState(VK_SHIFT) < 0))
roundTo8Directions(pointStack[pointSP - 1].x, pointStack[pointSP - 1].y,
&pointStack[pointSP].x, &pointStack[pointSP].y);
pointStack[pointSP].x, pointStack[pointSP].y);
pointSP++;
if (pointSP >= 2)
{
@ -579,13 +516,13 @@ endPaintingR(HDC hdc, LONG x, LONG y, COLORREF fg, COLORREF bg)
case TOOL_ELLIPSE:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
Ellp(hdc, start.x, start.y, x, y, bg, fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
case TOOL_RRECT:
imageModel.ResetToPrevious();
if (GetAsyncKeyState(VK_SHIFT) < 0)
regularize(start.x, start.y, &x, &y);
regularize(start.x, start.y, x, y);
RRect(hdc, start.x, start.y, x, y, bg, fg, toolsModel.GetLineWidth(), toolsModel.GetShapeStyle());
break;
}

View file

@ -30,6 +30,7 @@
#include "palettemodel.h"
#include "scrollbox.h"
#include "selection.h"
#include "selectionmodel.h"
#include "sizebox.h"
#include "textedit.h"
#include "toolbox.h"

View file

@ -10,21 +10,9 @@
#include "precomp.h"
/* DEFINES **********************************************************/
#define ACTION_MOVE 0
#define ACTION_RESIZE_TOP_LEFT 1
#define ACTION_RESIZE_TOP 2
#define ACTION_RESIZE_TOP_RIGHT 3
#define ACTION_RESIZE_LEFT 4
#define ACTION_RESIZE_RIGHT 5
#define ACTION_RESIZE_BOTTOM_LEFT 6
#define ACTION_RESIZE_BOTTOM 7
#define ACTION_RESIZE_BOTTOM_RIGHT 8
/* FUNCTIONS ********************************************************/
LPCTSTR cursors[9] = { /* action to mouse cursor lookup table */
const LPCTSTR CSelectionWindow::m_lpszCursorLUT[9] = { /* action to mouse cursor lookup table */
IDC_SIZEALL,
IDC_SIZENWSE, IDC_SIZENS, IDC_SIZENESW,
@ -32,13 +20,6 @@ LPCTSTR cursors[9] = { /* action to mouse cursor lookup table */
IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE
};
BOOL moving = FALSE;
int action = ACTION_MOVE;
POINTS pos;
POINTS frac;
POINT delta;
DWORD system_selection_color;
BOOL
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)
{
@ -81,32 +62,31 @@ ForceRefreshSelectionContents()
}
}
int
identifyCorner(short x, short y, short w, short h)
int CSelectionWindow::IdentifyCorner(int iXPos, int iYPos, int iWidth, int iHeight)
{
if (y < 3)
if (iYPos < 3)
{
if (x < 3)
if (iXPos < 3)
return ACTION_RESIZE_TOP_LEFT;
if ((x < w / 2 + 2) && (x >= w / 2 - 1))
if ((iXPos < iWidth / 2 + 2) && (iXPos >= iWidth / 2 - 1))
return ACTION_RESIZE_TOP;
if (x >= w - 3)
if (iXPos >= iWidth - 3)
return ACTION_RESIZE_TOP_RIGHT;
}
if ((y < h / 2 + 2) && (y >= h / 2 - 1))
if ((iYPos < iHeight / 2 + 2) && (iYPos >= iHeight / 2 - 1))
{
if (x < 3)
if (iXPos < 3)
return ACTION_RESIZE_LEFT;
if (x >= w - 3)
if (iXPos >= iWidth - 3)
return ACTION_RESIZE_RIGHT;
}
if (y >= h - 3)
if (iYPos >= iHeight - 3)
{
if (x < 3)
if (iXPos < 3)
return ACTION_RESIZE_BOTTOM_LEFT;
if ((x < w / 2 + 2) && (x >= w / 2 - 1))
if ((iXPos < iWidth / 2 + 2) && (iXPos >= iWidth / 2 - 1))
return ACTION_RESIZE_BOTTOM;
if (x >= w - 3)
if (iXPos >= iWidth - 3)
return ACTION_RESIZE_BOTTOM_RIGHT;
}
return 0;
@ -114,13 +94,13 @@ identifyCorner(short x, short y, short w, short h)
LRESULT CSelectionWindow::OnPaint(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (!moving)
if (!m_bMoving)
{
HDC hDC = GetDC();
DefWindowProc(WM_PAINT, wParam, lParam);
SelectionFrame(hDC, 1, 1, RECT_WIDTH(rectSel_dest) * toolsModel.GetZoom() / 1000 + 5,
RECT_HEIGHT(rectSel_dest) * toolsModel.GetZoom() / 1000 + 5,
system_selection_color);
SelectionFrame(hDC, 1, 1, selectionModel.GetDestRectWidth() * toolsModel.GetZoom() / 1000 + 5,
selectionModel.GetDestRectHeight() * toolsModel.GetZoom() / 1000 + 5,
m_dwSystemSelectionColor);
ReleaseDC(hDC);
}
return 0;
@ -134,8 +114,10 @@ LRESULT CSelectionWindow::OnEraseBkgnd(UINT nMsg, WPARAM wParam, LPARAM lParam,
LRESULT CSelectionWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_bMoving = FALSE;
m_iAction = ACTION_MOVE;
/* update the system selection color */
system_selection_color = GetSysColor(COLOR_HIGHLIGHT);
m_dwSystemSelectionColor = GetSysColor(COLOR_HIGHLIGHT);
SendMessage(WM_PAINT, 0, MAKELPARAM(0, 0));
return 0;
}
@ -143,7 +125,7 @@ LRESULT CSelectionWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL
LRESULT CSelectionWindow::OnSysColorChange(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
/* update the system selection color */
system_selection_color = GetSysColor(COLOR_HIGHLIGHT);
m_dwSystemSelectionColor = GetSysColor(COLOR_HIGHLIGHT);
SendMessage(WM_PAINT, 0, MAKELPARAM(0, 0));
return 0;
}
@ -156,14 +138,14 @@ LRESULT CSelectionWindow::OnSetCursor(UINT nMsg, WPARAM wParam, LPARAM lParam, B
LRESULT CSelectionWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
pos.x = GET_X_LPARAM(lParam);
pos.y = GET_Y_LPARAM(lParam);
delta.x = 0;
delta.y = 0;
m_ptPos.x = GET_X_LPARAM(lParam);
m_ptPos.y = GET_Y_LPARAM(lParam);
m_ptDelta.x = 0;
m_ptDelta.y = 0;
SetCapture();
if (action != ACTION_MOVE)
SetCursor(LoadCursor(NULL, cursors[action]));
moving = TRUE;
if (m_iAction != ACTION_MOVE)
SetCursor(LoadCursor(NULL, m_lpszCursorLUT[m_iAction]));
m_bMoving = TRUE;
scrlClientWindow.InvalidateRect(NULL, TRUE);
imageArea.SendMessage(WM_PAINT, 0, 0);
return 0;
@ -171,127 +153,66 @@ LRESULT CSelectionWindow::OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam,
LRESULT CSelectionWindow::OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (moving)
if (m_bMoving)
{
TCHAR sizeStr[100];
POINT deltaUsed;
imageModel.ResetToPrevious();
frac.x += GET_X_LPARAM(lParam) - pos.x;
frac.y += GET_Y_LPARAM(lParam) - pos.y;
delta.x += frac.x * 1000 / toolsModel.GetZoom();
delta.y += frac.y * 1000 / toolsModel.GetZoom();
m_ptFrac.x += GET_X_LPARAM(lParam) - m_ptPos.x;
m_ptFrac.y += GET_Y_LPARAM(lParam) - m_ptPos.y;
m_ptDelta.x += m_ptFrac.x * 1000 / toolsModel.GetZoom();
m_ptDelta.y += m_ptFrac.y * 1000 / toolsModel.GetZoom();
if (toolsModel.GetZoom() < 1000)
{
frac.x = 0;
frac.y = 0;
m_ptFrac.x = 0;
m_ptFrac.y = 0;
}
else
{
frac.x -= (frac.x * 1000 / toolsModel.GetZoom()) * toolsModel.GetZoom() / 1000;
frac.y -= (frac.y * 1000 / toolsModel.GetZoom()) * toolsModel.GetZoom() / 1000;
m_ptFrac.x -= (m_ptFrac.x * 1000 / toolsModel.GetZoom()) * toolsModel.GetZoom() / 1000;
m_ptFrac.y -= (m_ptFrac.y * 1000 / toolsModel.GetZoom()) * toolsModel.GetZoom() / 1000;
}
switch (action)
{
case ACTION_MOVE: /* move selection */
deltaUsed.x = delta.x;
deltaUsed.y = delta.y;
OffsetRect(&rectSel_dest, deltaUsed.x, deltaUsed.y);
break;
case ACTION_RESIZE_TOP_LEFT: /* resize at upper left corner */
deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
rectSel_dest.left += deltaUsed.x;
rectSel_dest.top += deltaUsed.y;
break;
case ACTION_RESIZE_TOP: /* resize at top edge */
deltaUsed.x = delta.x;
deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
rectSel_dest.top += deltaUsed.y;
break;
case ACTION_RESIZE_TOP_RIGHT: /* resize at upper right corner */
deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
deltaUsed.y = min(delta.y, RECT_HEIGHT(rectSel_dest) - 1);
rectSel_dest.top += deltaUsed.y;
rectSel_dest.right += deltaUsed.x;
break;
case ACTION_RESIZE_LEFT: /* resize at left edge */
deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
deltaUsed.y = delta.y;
rectSel_dest.left += deltaUsed.x;
break;
case ACTION_RESIZE_RIGHT: /* resize at right edge */
deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
deltaUsed.y = delta.y;
rectSel_dest.right += deltaUsed.x;
break;
case ACTION_RESIZE_BOTTOM_LEFT: /* resize at lower left corner */
deltaUsed.x = min(delta.x, RECT_WIDTH(rectSel_dest) - 1);
deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
rectSel_dest.left += deltaUsed.x;
rectSel_dest.bottom += deltaUsed.y;
break;
case ACTION_RESIZE_BOTTOM: /* resize at bottom edge */
deltaUsed.x = delta.x;
deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
rectSel_dest.bottom += deltaUsed.y;
break;
case ACTION_RESIZE_BOTTOM_RIGHT: /* resize at lower right corner */
deltaUsed.x = max(delta.x, -(RECT_WIDTH(rectSel_dest) - 1));
deltaUsed.y = max(delta.y, -(RECT_HEIGHT(rectSel_dest) - 1));
rectSel_dest.right += deltaUsed.x;
rectSel_dest.bottom += deltaUsed.y;
break;
}
delta.x -= deltaUsed.x;
delta.y -= deltaUsed.y;
selectionModel.ModifyDestRect(m_ptDelta, m_iAction);
_stprintf(sizeStr, _T("%d x %d"), RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest));
_stprintf(sizeStr, _T("%d x %d"), selectionModel.GetDestRectWidth(), selectionModel.GetDestRectHeight());
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) sizeStr);
if (toolsModel.GetActiveTool() == TOOL_TEXT)
{
Text(hDrawingDC, rectSel_dest.left, rectSel_dest.top, rectSel_dest.right, rectSel_dest.bottom, paletteModel.GetFgColor(), paletteModel.GetBgColor(), textToolText, hfontTextFont, toolsModel.IsBackgroundTransparent());
selectionModel.DrawTextToolText(hDrawingDC, paletteModel.GetFgColor(), paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
}
else
{
if (action != ACTION_MOVE)
StretchBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0, GetDIBWidth(hSelBm), GetDIBHeight(hSelBm), SRCCOPY);
if (m_iAction != ACTION_MOVE)
selectionModel.DrawSelectionStretched(hDrawingDC);
else
if (toolsModel.IsBackgroundTransparent() == 0)
MaskBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest),
hSelDC, 0, 0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
else
{
ColorKeyedMaskBlt(hDrawingDC, rectSel_dest.left, rectSel_dest.top, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest),
hSelDC, 0, 0, hSelMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND), paletteModel.GetBgColor());
}
selectionModel.DrawSelection(hDrawingDC, paletteModel.GetBgColor(), toolsModel.IsBackgroundTransparent());
}
imageArea.InvalidateRect(NULL, FALSE);
imageArea.SendMessage(WM_PAINT, 0, 0);
pos.x = GET_X_LPARAM(lParam);
pos.y = GET_Y_LPARAM(lParam);
m_ptPos.x = GET_X_LPARAM(lParam);
m_ptPos.y = GET_Y_LPARAM(lParam);
}
else
{
int w = RECT_WIDTH(rectSel_dest) * toolsModel.GetZoom() / 1000 + 6;
int h = RECT_HEIGHT(rectSel_dest) * toolsModel.GetZoom() / 1000 + 6;
pos.x = GET_X_LPARAM(lParam);
pos.y = GET_Y_LPARAM(lParam);
int w = selectionModel.GetDestRectWidth() * toolsModel.GetZoom() / 1000 + 6;
int h = selectionModel.GetDestRectHeight() * toolsModel.GetZoom() / 1000 + 6;
m_ptPos.x = GET_X_LPARAM(lParam);
m_ptPos.y = GET_Y_LPARAM(lParam);
SendMessage(hStatusBar, SB_SETTEXT, 2, (LPARAM) NULL);
action = identifyCorner(pos.x, pos.y, w, h);
if (action != ACTION_MOVE)
SetCursor(LoadCursor(NULL, cursors[action]));
m_iAction = IdentifyCorner(m_ptPos.x, m_ptPos.y, w, h);
if (m_iAction != ACTION_MOVE)
SetCursor(LoadCursor(NULL, m_lpszCursorLUT[m_iAction]));
}
return 0;
}
LRESULT CSelectionWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (moving)
if (m_bMoving)
{
moving = FALSE;
m_bMoving = FALSE;
ReleaseCapture();
if (action != ACTION_MOVE)
if (m_iAction != ACTION_MOVE)
{
if (toolsModel.GetActiveTool() == TOOL_TEXT)
{
@ -299,25 +220,7 @@ LRESULT CSelectionWindow::OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, B
}
else
{
HDC hTempDC;
HBITMAP hTempBm;
hTempDC = CreateCompatibleDC(hSelDC);
hTempBm = CreateDIBWithProperties(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest));
SelectObject(hTempDC, hTempBm);
SelectObject(hSelDC, hSelBm);
StretchBlt(hTempDC, 0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0,
GetDIBWidth(hSelBm), GetDIBHeight(hSelBm), SRCCOPY);
DeleteObject(hSelBm);
hSelBm = hTempBm;
hTempBm = CreateBitmap(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), 1, 1, NULL);
SelectObject(hTempDC, hTempBm);
SelectObject(hSelDC, hSelMask);
StretchBlt(hTempDC, 0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC, 0, 0,
GetDIBWidth(hSelMask), GetDIBHeight(hSelMask), SRCCOPY);
DeleteObject(hSelMask);
hSelMask = hTempBm;
SelectObject(hSelDC, hSelBm);
DeleteDC(hTempDC);
selectionModel.ScaleContentsToFit();
}
}
placeSelWin();

View file

@ -30,6 +30,17 @@ public:
LRESULT OnLButtonDown(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnMouseMove(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonUp(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
private:
static const LPCTSTR m_lpszCursorLUT[9];
BOOL m_bMoving;
int m_iAction;
POINT m_ptPos;
POINT m_ptFrac;
POINT m_ptDelta;
DWORD m_dwSystemSelectionColor;
int IdentifyCorner(int iXPos, int iYPos, int iWidth, int iHeight);
};
void ForceRefreshSelectionContents();

View file

@ -0,0 +1,328 @@
/*
* PROJECT: PAINT for ReactOS
* LICENSE: LGPL
* FILE: base/applications/mspaint_new/selectionmodel.cpp
* PURPOSE: Keep track of selection parameters, notify listeners
* PROGRAMMERS: Benedikt Freisen
*/
/* INCLUDES *********************************************************/
#include "precomp.h"
/* FUNCTIONS ********************************************************/
SelectionModel::SelectionModel()
{
m_ptStack = NULL;
m_iPtSP = 0;
}
void SelectionModel::SetDC(HDC hDC)
{
m_hDC = hDC;
}
void SelectionModel::ResetPtStack()
{
if (m_ptStack != NULL)
HeapFree(GetProcessHeap(), 0, m_ptStack);
m_ptStack = NULL;
m_iPtSP = 0;
}
void SelectionModel::PushToPtStack(LONG x, LONG y)
{
if (m_iPtSP % 1024 == 0)
{
if (m_ptStack)
m_ptStack = (POINT*) HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, m_ptStack, sizeof(POINT) * (m_iPtSP + 1024));
else
m_ptStack = (POINT*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * 1024);
}
m_ptStack[m_iPtSP].x = x;
m_ptStack[m_iPtSP].y = y;
m_iPtSP++;
}
void SelectionModel::CalculateBoundingBoxAndContents(HDC hDCImage)
{
int i;
m_rcSrc.left = m_rcSrc.top = MAXLONG;
m_rcSrc.right = m_rcSrc.bottom = 0;
for (i = 0; i < m_iPtSP; i++)
{
if (m_ptStack[i].x < m_rcSrc.left)
m_rcSrc.left = m_ptStack[i].x;
if (m_ptStack[i].y < m_rcSrc.top)
m_rcSrc.top = m_ptStack[i].y;
if (m_ptStack[i].x > m_rcSrc.right)
m_rcSrc.right = m_ptStack[i].x;
if (m_ptStack[i].y > m_rcSrc.bottom)
m_rcSrc.bottom = m_ptStack[i].y;
}
m_rcSrc.right += 1;
m_rcSrc.bottom += 1;
m_rcDest.left = m_rcSrc.left;
m_rcDest.top = m_rcSrc.top;
m_rcDest.right = m_rcSrc.right;
m_rcDest.bottom = m_rcSrc.bottom;
if (m_iPtSP > 1)
{
DeleteObject(m_hMask);
m_hMask = CreateBitmap(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 1, 1, NULL);
DeleteObject(SelectObject(m_hDC, m_hMask));
POINT *m_ptStackCopy = (POINT*) HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, sizeof(POINT) * m_iPtSP);
for (i = 0; i < m_iPtSP; i++)
{
m_ptStackCopy[i].x = m_ptStack[i].x - m_rcSrc.left;
m_ptStackCopy[i].y = m_ptStack[i].y - m_rcSrc.top;
}
Poly(m_hDC, m_ptStackCopy, m_iPtSP, 0x00ffffff, 0x00ffffff, 1, 2, TRUE, FALSE);
HeapFree(GetProcessHeap(), 0, m_ptStackCopy);
SelectObject(m_hDC, m_hBm = CreateDIBWithProperties(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc)));
imageModel.ResetToPrevious();
MaskBlt(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), hDCImage, m_rcSrc.left,
m_rcSrc.top, m_hMask, 0, 0, MAKEROP4(SRCCOPY, WHITENESS));
}
}
void SelectionModel::CalculateContents(HDC hDCImage)
{
DeleteObject(m_hMask);
m_hMask = CreateBitmap(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 1, 1, NULL);
DeleteObject(SelectObject(m_hDC, m_hMask));
Rect(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), 0x00ffffff, 0x00ffffff, 1, 2);
SelectObject(m_hDC, m_hBm = CreateDIBWithProperties(RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc)));
BitBlt(m_hDC, 0, 0, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), hDCImage, m_rcSrc.left,
m_rcSrc.top, SRCCOPY);
}
void SelectionModel::DrawBackgroundPoly(HDC hDCImage, COLORREF crBg)
{
Poly(hDCImage, m_ptStack, m_iPtSP, crBg, crBg, 1, 2, TRUE, FALSE);
}
void SelectionModel::DrawBackgroundRect(HDC hDCImage, COLORREF crBg)
{
Rect(hDCImage, m_rcSrc.left, m_rcSrc.top, m_rcSrc.right, m_rcSrc.bottom, crBg, crBg, 0, TRUE);
}
extern BOOL
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);
void SelectionModel::DrawSelection(HDC hDCImage, COLORREF crBg, BOOL bBgTransparent)
{
MaskBlt(hDCImage, m_rcSrc.left, m_rcSrc.top, RECT_WIDTH(m_rcSrc), RECT_HEIGHT(m_rcSrc), m_hDC, 0,
0, m_hMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
if (!bBgTransparent)
MaskBlt(hDCImage, m_rcDest.left, m_rcDest.top, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest),
m_hDC, 0, 0, m_hMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND));
else
ColorKeyedMaskBlt(hDCImage, m_rcDest.left, m_rcDest.top, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest),
m_hDC, 0, 0, m_hMask, 0, 0, MAKEROP4(SRCCOPY, SRCAND), crBg);
}
void SelectionModel::DrawSelectionStretched(HDC hDCImage)
{
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);
}
void SelectionModel::ScaleContentsToFit()
{
HDC hTempDC;
HBITMAP hTempBm;
hTempDC = CreateCompatibleDC(m_hDC);
hTempBm = CreateDIBWithProperties(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest));
SelectObject(hTempDC, hTempBm);
SelectObject(m_hDC, m_hBm);
StretchBlt(hTempDC, 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC, 0, 0,
GetDIBWidth(m_hBm), GetDIBHeight(m_hBm), SRCCOPY);
DeleteObject(m_hBm);
m_hBm = hTempBm;
hTempBm = CreateBitmap(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), 1, 1, NULL);
SelectObject(hTempDC, hTempBm);
SelectObject(m_hDC, m_hMask);
StretchBlt(hTempDC, 0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC, 0, 0,
GetDIBWidth(m_hMask), GetDIBHeight(m_hMask), SRCCOPY);
DeleteObject(m_hMask);
m_hMask = hTempBm;
SelectObject(m_hDC, m_hBm);
DeleteDC(hTempDC);
}
void SelectionModel::InsertFromHBITMAP(HBITMAP hBm)
{
HDC hTempDC;
HBITMAP hTempMask;
DeleteObject(SelectObject(m_hDC, m_hBm = (HBITMAP) CopyImage(hBm,
IMAGE_BITMAP, 0, 0,
LR_COPYRETURNORG)));
SetRectEmpty(&m_rcSrc);
m_rcDest.left = m_rcDest.top = 0;
m_rcDest.right = m_rcDest.left + GetDIBWidth(m_hBm);
m_rcDest.bottom = m_rcDest.top + GetDIBHeight(m_hBm);
hTempDC = CreateCompatibleDC(m_hDC);
hTempMask = CreateBitmap(RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), 1, 1, NULL);
SelectObject(hTempDC, hTempMask);
Rect(hTempDC, m_rcDest.left, m_rcDest.top, m_rcDest.right, m_rcDest.bottom, 0x00ffffff, 0x00ffffff, 1, 1);
DeleteObject(m_hMask);
m_hMask = hTempMask;
DeleteDC(hTempDC);
}
void SelectionModel::FlipHorizontally()
{
SelectObject(m_hDC, m_hMask);
StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, 0, -RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
SelectObject(m_hDC, m_hBm);
StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, 0, -RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
}
void SelectionModel::FlipVertically()
{
SelectObject(m_hDC, m_hMask);
StretchBlt(m_hDC, 0, RECT_HEIGHT(m_rcDest) - 1, RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
SelectObject(m_hDC, m_hBm);
StretchBlt(m_hDC, 0, RECT_HEIGHT(m_rcDest) - 1, RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
}
void SelectionModel::RotateNTimes90Degrees(int iN)
{
if (iN == 2)
{
SelectObject(m_hDC, m_hMask);
StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, RECT_HEIGHT(m_rcDest) - 1, -RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
SelectObject(m_hDC, m_hBm);
StretchBlt(m_hDC, RECT_WIDTH(m_rcDest) - 1, RECT_HEIGHT(m_rcDest) - 1, -RECT_WIDTH(m_rcDest), -RECT_HEIGHT(m_rcDest), m_hDC,
0, 0, RECT_WIDTH(m_rcDest), RECT_HEIGHT(m_rcDest), SRCCOPY);
}
}
HBITMAP SelectionModel::GetBitmap()
{
return m_hBm;
}
int SelectionModel::PtStackSize()
{
return m_iPtSP;
}
void SelectionModel::DrawFramePoly(HDC hDCImage)
{
Poly(hDCImage, m_ptStack, m_iPtSP, 0, 0, 2, 0, FALSE, TRUE); /* draw the freehand selection inverted/xored */
}
void SelectionModel::SetSrcAndDestRectFromPoints(POINT& ptFrom, POINT& ptTo)
{
m_rcDest.left = m_rcSrc.left = min(ptFrom.x, ptTo.x);
m_rcDest.top = m_rcSrc.top = min(ptFrom.y, ptTo.y);
m_rcDest.right = m_rcSrc.right = max(ptFrom.x, ptTo.x);
m_rcDest.bottom = m_rcSrc.bottom = max(ptFrom.y, ptTo.y);
}
void SelectionModel::SetSrcRectSizeToZero()
{
m_rcSrc.right = m_rcSrc.left;
m_rcSrc.bottom = m_rcSrc.top;
}
BOOL SelectionModel::IsSrcRectSizeNonzero()
{
return (RECT_WIDTH(m_rcSrc) != 0) && (RECT_HEIGHT(m_rcSrc) != 0);
}
void SelectionModel::ModifyDestRect(POINT& ptDelta, int iAction)
{
POINT ptDeltaUsed;
switch (iAction)
{
case ACTION_MOVE: /* move selection */
ptDeltaUsed.x = ptDelta.x;
ptDeltaUsed.y = ptDelta.y;
OffsetRect(&m_rcDest, ptDeltaUsed.x, ptDeltaUsed.y);
break;
case ACTION_RESIZE_TOP_LEFT: /* resize at upper left corner */
ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
m_rcDest.left += ptDeltaUsed.x;
m_rcDest.top += ptDeltaUsed.y;
break;
case ACTION_RESIZE_TOP: /* resize at top edge */
ptDeltaUsed.x = ptDelta.x;
ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
m_rcDest.top += ptDeltaUsed.y;
break;
case ACTION_RESIZE_TOP_RIGHT: /* resize at upper right corner */
ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
ptDeltaUsed.y = min(ptDelta.y, RECT_HEIGHT(m_rcDest) - 1);
m_rcDest.top += ptDeltaUsed.y;
m_rcDest.right += ptDeltaUsed.x;
break;
case ACTION_RESIZE_LEFT: /* resize at left edge */
ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
ptDeltaUsed.y = ptDelta.y;
m_rcDest.left += ptDeltaUsed.x;
break;
case ACTION_RESIZE_RIGHT: /* resize at right edge */
ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
ptDeltaUsed.y = ptDelta.y;
m_rcDest.right += ptDeltaUsed.x;
break;
case ACTION_RESIZE_BOTTOM_LEFT: /* resize at lower left corner */
ptDeltaUsed.x = min(ptDelta.x, RECT_WIDTH(m_rcDest) - 1);
ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
m_rcDest.left += ptDeltaUsed.x;
m_rcDest.bottom += ptDeltaUsed.y;
break;
case ACTION_RESIZE_BOTTOM: /* resize at bottom edge */
ptDeltaUsed.x = ptDelta.x;
ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
m_rcDest.bottom += ptDeltaUsed.y;
break;
case ACTION_RESIZE_BOTTOM_RIGHT: /* resize at lower right corner */
ptDeltaUsed.x = max(ptDelta.x, -(RECT_WIDTH(m_rcDest) - 1));
ptDeltaUsed.y = max(ptDelta.y, -(RECT_HEIGHT(m_rcDest) - 1));
m_rcDest.right += ptDeltaUsed.x;
m_rcDest.bottom += ptDeltaUsed.y;
break;
}
ptDelta.x -= ptDeltaUsed.x;
ptDelta.y -= ptDeltaUsed.y;
}
LONG SelectionModel::GetDestRectWidth()
{
return m_rcDest.right - m_rcDest.left;
}
LONG SelectionModel::GetDestRectHeight()
{
return m_rcDest.bottom - m_rcDest.top;
}
LONG SelectionModel::GetDestRectLeft()
{
return m_rcDest.left;
}
LONG SelectionModel::GetDestRectTop()
{
return m_rcDest.top;
}
void SelectionModel::DrawTextToolText(HDC hDCImage, COLORREF crFg, COLORREF crBg, BOOL bBgTransparent)
{
Text(hDCImage, m_rcDest.left, m_rcDest.top, m_rcDest.right, m_rcDest.bottom, crFg, crBg, textToolText, hfontTextFont, bBgTransparent);
}

View file

@ -0,0 +1,65 @@
/*
* PROJECT: PAINT for ReactOS
* LICENSE: LGPL
* FILE: base/applications/mspaint_new/selectionmodel.h
* PURPOSE: Keep track of selection parameters, notify listeners
* PROGRAMMERS: Benedikt Freisen
*/
/* DEFINES **********************************************************/
#define ACTION_MOVE 0
#define ACTION_RESIZE_TOP_LEFT 1
#define ACTION_RESIZE_TOP 2
#define ACTION_RESIZE_TOP_RIGHT 3
#define ACTION_RESIZE_LEFT 4
#define ACTION_RESIZE_RIGHT 5
#define ACTION_RESIZE_BOTTOM_LEFT 6
#define ACTION_RESIZE_BOTTOM 7
#define ACTION_RESIZE_BOTTOM_RIGHT 8
/* CLASSES **********************************************************/
class SelectionModel
{
private:
HDC m_hDC;
RECT m_rcSrc;
RECT m_rcDest;
HBITMAP m_hBm;
HBITMAP m_hMask;
POINT *m_ptStack;
int m_iPtSP;
// void NotifySelectionChanging();
// void NotifySelectionChanged();
public:
SelectionModel();
void SetDC(HDC hDC);
void ResetPtStack();
void PushToPtStack(LONG x, LONG y);
void CalculateBoundingBoxAndContents(HDC hDCImage);
void CalculateContents(HDC hDCImage);
void DrawBackgroundPoly(HDC hDCImage, COLORREF crBg);
void DrawBackgroundRect(HDC hDCImage, COLORREF crBg);
void DrawSelection(HDC hDCImage, COLORREF crBg = 0, BOOL bBgTransparent = FALSE);
void DrawSelectionStretched(HDC hDCImage);
void ScaleContentsToFit();
void InsertFromHBITMAP(HBITMAP hBm);
void FlipHorizontally();
void FlipVertically();
void RotateNTimes90Degrees(int iN);
HBITMAP GetBitmap();
int PtStackSize();
void DrawFramePoly(HDC hDCImage);
void SetSrcAndDestRectFromPoints(POINT& ptFrom, POINT& ptTo);
void SetSrcRectSizeToZero();
BOOL IsSrcRectSizeNonzero();
void ModifyDestRect(POINT& ptDelta, int iAction);
LONG GetDestRectWidth();
LONG GetDestRectHeight();
LONG GetDestRectLeft();
LONG GetDestRectTop();
void DrawTextToolText(HDC hDCImage, COLORREF crFg, COLORREF crBg, BOOL bBgTransparent = FALSE);
};

View file

@ -107,29 +107,12 @@ void CMainWindow::UpdateApplicationProperties(HBITMAP bitmap, LPTSTR newfilename
void CMainWindow::InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window)
{
HDC hTempDC;
HBITMAP hTempMask;
HWND hToolbar = FindWindowEx(toolBoxContainer.m_hWnd, NULL, TOOLBARCLASSNAME, NULL);
SendMessage(hToolbar, TB_CHECKBUTTON, ID_RECTSEL, MAKELPARAM(TRUE, 0));
toolBoxContainer.SendMessage(WM_COMMAND, ID_RECTSEL);
DeleteObject(SelectObject(hSelDC, hSelBm = (HBITMAP) CopyImage(bitmap,
IMAGE_BITMAP, 0, 0,
LR_COPYRETURNORG)));
imageModel.CopyPrevious();
SetRectEmpty(&rectSel_src);
rectSel_dest.left = rectSel_dest.top = 0;
rectSel_dest.right = rectSel_dest.left + GetDIBWidth(hSelBm);
rectSel_dest.bottom = rectSel_dest.top + GetDIBHeight(hSelBm);
hTempDC = CreateCompatibleDC(hSelDC);
hTempMask = CreateBitmap(RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), 1, 1, NULL);
SelectObject(hTempDC, hTempMask);
Rect(hTempDC, rectSel_dest.left, rectSel_dest.top, rectSel_dest.right, rectSel_dest.bottom, 0x00ffffff, 0x00ffffff, 1, 1);
DeleteObject(hSelMask);
hSelMask = hTempMask;
DeleteDC(hTempDC);
selectionModel.InsertFromHBITMAP(bitmap);
placeSelWin();
selectionWindow.ShowWindow(SW_SHOW);
@ -159,8 +142,6 @@ LRESULT CMainWindow::OnCreate(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHa
{
SendMessage(WM_SETICON, ICON_BIG, (LPARAM) LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON)));
SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) LoadIcon(hProgInstance, MAKEINTRESOURCE(IDI_APPICON)));
ptStack = NULL;
ptSP = 0;
return 0;
}
@ -392,7 +373,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
case IDM_EDITCOPY:
OpenClipboard();
EmptyClipboard();
SetClipboardData(CF_BITMAP, CopyImage(hSelBm, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG));
SetClipboardData(CF_BITMAP, CopyImage(selectionModel.GetBitmap(), IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG));
CloseClipboard();
break;
case IDM_EDITCUT:
@ -411,20 +392,8 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
break;
case IDM_EDITDELETESELECTION:
{
/* remove selection window and already painted content using undo(),
paint Rect for rectangular selections and Poly for freeform selections */
/* remove selection window and already painted content using undo */
imageModel.Undo();
if (toolsModel.GetActiveTool() == TOOL_RECTSEL)
{
imageModel.CopyPrevious();
Rect(hDrawingDC, rectSel_dest.left, rectSel_dest.top, rectSel_dest.right,
rectSel_dest.bottom, paletteModel.GetBgColor(), paletteModel.GetBgColor(), 0, TRUE);
}
if (toolsModel.GetActiveTool() == TOOL_FREESEL)
{
imageModel.CopyPrevious();
Poly(hDrawingDC, ptStack, ptSP + 1, 0, 0, 2, 0, FALSE, TRUE);
}
break;
}
case IDM_EDITSELECTALL:
@ -440,7 +409,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
}
case IDM_EDITCOPYTO:
if (GetSaveFileName(&ofn) != 0)
SaveDIBToFile(hSelBm, ofn.lpstrFile, hDrawingDC, NULL, NULL, fileHPPM, fileVPPM);
SaveDIBToFile(selectionModel.GetBitmap(), ofn.lpstrFile, hDrawingDC, NULL, NULL, fileHPPM, fileVPPM);
break;
case IDM_EDITPASTEFROM:
if (GetOpenFileName(&ofn) != 0)
@ -480,12 +449,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
case 1: /* flip horizontally */
if (selectionWindow.IsWindowVisible())
{
SelectObject(hSelDC, hSelMask);
StretchBlt(hSelDC, RECT_WIDTH(rectSel_dest) - 1, 0, -RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC,
0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), SRCCOPY);
SelectObject(hSelDC, hSelBm);
StretchBlt(hSelDC, RECT_WIDTH(rectSel_dest) - 1, 0, -RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), hSelDC,
0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), SRCCOPY);
selectionModel.FlipHorizontally();
ForceRefreshSelectionContents();
}
else
@ -499,12 +463,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
case 2: /* flip vertically */
if (selectionWindow.IsWindowVisible())
{
SelectObject(hSelDC, hSelMask);
StretchBlt(hSelDC, 0, RECT_HEIGHT(rectSel_dest) - 1, RECT_WIDTH(rectSel_dest), -RECT_HEIGHT(rectSel_dest), hSelDC,
0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), SRCCOPY);
SelectObject(hSelDC, hSelBm);
StretchBlt(hSelDC, 0, RECT_HEIGHT(rectSel_dest) - 1, RECT_WIDTH(rectSel_dest), -RECT_HEIGHT(rectSel_dest), hSelDC,
0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), SRCCOPY);
selectionModel.FlipVertically();
ForceRefreshSelectionContents();
}
else
@ -520,12 +479,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
case 4: /* rotate 180 degrees */
if (selectionWindow.IsWindowVisible())
{
SelectObject(hSelDC, hSelMask);
StretchBlt(hSelDC, RECT_WIDTH(rectSel_dest) - 1, RECT_HEIGHT(rectSel_dest) - 1, -RECT_WIDTH(rectSel_dest), -RECT_HEIGHT(rectSel_dest), hSelDC,
0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), SRCCOPY);
SelectObject(hSelDC, hSelBm);
StretchBlt(hSelDC, RECT_WIDTH(rectSel_dest) - 1, RECT_HEIGHT(rectSel_dest) - 1, -RECT_WIDTH(rectSel_dest), -RECT_HEIGHT(rectSel_dest), hSelDC,
0, 0, RECT_WIDTH(rectSel_dest), RECT_HEIGHT(rectSel_dest), SRCCOPY);
selectionModel.RotateNTimes90Degrees(2);
ForceRefreshSelectionContents();
}
else
@ -561,7 +515,7 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
toolsModel.SetBackgroundTransparent(!toolsModel.IsBackgroundTransparent());
break;
case IDM_IMAGECROP:
imageModel.Insert((HBITMAP) CopyImage(hSelBm, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG));
imageModel.Insert((HBITMAP) CopyImage(selectionModel.GetBitmap(), IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG));
break;
case IDM_VIEWTOOLBOX: