From b2262885845456847effdbd8bf0cc56e91eac895 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Tue, 17 May 2016 20:46:28 -0400 Subject: [PATCH] Implemented the H slider. --- windows/colordialog.cpp | 137 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/windows/colordialog.cpp b/windows/colordialog.cpp index 474a8616..f2f52ed7 100644 --- a/windows/colordialog.cpp +++ b/windows/colordialog.cpp @@ -1,6 +1,8 @@ // 16 may 2016 #include "uipriv_windows.hpp" +// TODO should the d2dscratch programs capture mouse? + struct colorDialog { HWND hwnd; @@ -282,7 +284,7 @@ static void updateDialog(struct colorDialog *c, HWND whichChanged) // TODO TRUE? invalidateRect(c->svChooser, NULL, TRUE); -//TODO invalidateRect(c->hSlider, NULL, TRUE); + invalidateRect(c->hSlider, NULL, TRUE); //TODO invalidateRect(c->preview, NULL, TRUE); //TODO invalidateRect(c->opacitySlider, NULL, TRUE); @@ -449,7 +451,7 @@ static void drawSVChooser(struct colorDialog *c, ID2D1RenderTarget *rt) bprop.opacity = 1.0; // the marker should always be opaque hr = rt->CreateSolidColorBrush(&mcolor, &bprop, &markerBrush); if (hr != S_OK) - logHRESULT(L"error creating brush for SV chooser", hr); + logHRESULT(L"error creating brush for SV chooser marker", hr); rt->DrawEllipse(&mparam, markerBrush, 2, NULL); markerBrush->Release(); } @@ -482,6 +484,136 @@ static LRESULT CALLBACK svChooserSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LP return DefSubclassProc(hwnd, uMsg, wParam, lParam); } +// the gradient stuff also comes from http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx +#define nStops (30) +#define degPerStop (360 / nStops) +#define stopIncr (1.0 / ((double) nStops)) + +static void drawHSlider(struct colorDialog *c, ID2D1RenderTarget *rt) +{ + D2D1_SIZE_F size; + D2D1_RECT_F rect; + D2D1_GRADIENT_STOP stops[nStops]; + double r, g, b; + int i; + double h; + ID2D1GradientStopCollection *collection; + D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lprop; + D2D1_BRUSH_PROPERTIES bprop; + ID2D1LinearGradientBrush *brush; + double hypot, leg; + D2D1_POINT_2F center; + D2D1_MATRIX_3X2_F oldtf, rotate; + D2D1_COLOR_F mcolor; + ID2D1SolidColorBrush *markerBrush; + HRESULT hr; + + size = rt->GetSize(); + rect.left = size.width / 6; // leftmost sixth for arrow + rect.top = 0; + rect.right = size.width; + rect.bottom = size.height; + + for (i = 0; i < nStops; i++) { + h = ((double) (i * degPerStop)) / 360.0; + if (i == (nStops - 1)) + h = 0; + hsv2RGB(h, 1.0, 1.0, &r, &g, &b); + stops[i].position = ((double) i) * stopIncr; + stops[i].color.r = r; + stops[i].color.g = g; + stops[i].color.b = b; + stops[i].color.a = 1.0; + } + // and pin the last one + stops[i - 1].position = 1.0; + + hr = rt->CreateGradientStopCollection(stops, nStops, + // note that in this case this gamma is explicitly specified by the original + D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, + &collection); + if (hr != S_OK) + logHRESULT(L"error creating stop collection for H slider gradient", hr); + ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); + lprop.startPoint.x = (rect.right - rect.left) / 2; + lprop.startPoint.y = 0; + lprop.endPoint.x = (rect.right - rect.left) / 2; + lprop.endPoint.y = size.height; + ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); + bprop.opacity = 1.0; + bprop.transform._11 = 1; + bprop.transform._22 = 1; + hr = rt->CreateLinearGradientBrush(&lprop, &bprop, + collection, &brush); + if (hr != S_OK) + logHRESULT(L"error creating gradient brush for H slider", hr); + rt->FillRectangle(&rect, brush); + brush->Release(); + collection->Release(); + + // now draw a black arrow + // to avoid needing a geometry, this will just be a rotated square + center.x = 0; + center.y = c->h * size.height; + // compute the length of each side; the diagonal of the square is 2 * offset to gradient + hypot = rect.left; + // a^2 + a^2 = c^2 -> 2a^2 = c^2 + // a = sqrt(c^2/2) + hypot *= hypot; + hypot /= 2; + leg = sqrt(hypot); + rect.left = -leg; + rect.top = center.y - leg; + rect.right = leg; + rect.bottom = center.y + leg; + + // now we need to rotate the render target 45° (either way works) about the center point + rt->GetTransform(&oldtf); + rotate = oldtf * D2D1::Matrix3x2F::Rotation(45, center); + rt->SetTransform(&rotate); + + // and draw + mcolor.r = 0.0; + mcolor.g = 0.0; + mcolor.b = 0.0; + mcolor.a = 1.0; + hr = rt->CreateSolidColorBrush(&mcolor, &bprop, &markerBrush); + if (hr != S_OK) + logHRESULT(L"error creating brush for H slider marker", hr); + rt->FillRectangle(&rect, markerBrush); + markerBrush->Release(); + + // clean up + rt->SetTransform(&oldtf); +} + +static LRESULT CALLBACK hSliderSubProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + ID2D1RenderTarget *rt; + struct colorDialog *c; + D2D1_POINT_2F *pos; + D2D1_SIZE_F *size; + + c = (struct colorDialog *) dwRefData; + switch (uMsg) { + case msgD2DScratchPaint: + rt = (ID2D1RenderTarget *) lParam; + drawHSlider(c, rt); + return 0; + case msgD2DScratchLButtonDown: + pos = (D2D1_POINT_2F *) wParam; + size = (D2D1_SIZE_F *) lParam; + c->h = pos->y / size->height; + updateDialog(c, NULL); + return 0; + case WM_NCDESTROY: + if (RemoveWindowSubclass(hwnd, hSliderSubProc, uIdSubclass) == FALSE) + logLastError(L"error removing color dialog H slider subclass"); + break; + } + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + // TODO extract into d2dscratch.cpp, use in font dialog HWND replaceWithD2DScratch(HWND parent, int id, SUBCLASSPROC subproc, void *data) { @@ -608,6 +740,7 @@ static struct colorDialog *beginColorDialog(HWND hwnd, LPARAM lParam) c->editHex = getDlgItem(c->hwnd, rcHex); c->svChooser = replaceWithD2DScratch(c->hwnd, rcColorSVChooser, svChooserSubProc, c); + c->hSlider = replaceWithD2DScratch(c->hwnd, rcColorHSlider, hSliderSubProc, c); fixupControlPositions(c);