// once again, this is based on the Microsoft sample above static void drawOpacitySlider(struct colorDialog *c, ID2D1RenderTarget *rt) { D2D1_SIZE_F size; D2D1_RECT_F rect; D2D1_GRADIENT_STOP stops[2]; ID2D1GradientStopCollection *collection; D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lprop; D2D1_BRUSH_PROPERTIES bprop; ID2D1LinearGradientBrush *brush; double hypot; D2D1_POINT_2F center; HRESULT hr; size = realGetSize(rt); rect.left = 0; rect.top = 0; rect.right = size.width; rect.bottom = size.height * (5.0 / 6.0); // bottommost sixth for arrow drawGrid(rt, &rect); stops[0].position = 0.0; stops[0].color.r = 0.0; stops[0].color.g = 0.0; stops[0].color.b = 0.0; stops[0].color.a = 1.0; stops[1].position = 1.0; stops[1].color.r = 1.0; // this is the XAML color Transparent, as in the source stops[1].color.g = 1.0; stops[1].color.b = 1.0; stops[1].color.a = 0.0; hr = rt->CreateGradientStopCollection(stops, 2, // 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 opacity slider gradient", hr); ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); lprop.startPoint.x = 0; lprop.startPoint.y = (rect.bottom - rect.top) / 2; lprop.endPoint.x = size.width; lprop.endPoint.y = (rect.bottom - rect.top) / 2; 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 opacity slider", hr); rt->FillRectangle(&rect, brush); brush->Release(); collection->Release(); // now draw a black arrow center.x = (1 - c->a) * size.width; center.y = size.height; hypot = size.height - rect.bottom; drawArrow(rt, center, hypot); }
//----------------------------------------------------------------------------- void D2DDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { if (renderTarget == 0) return; D2DGraphicsPath* d2dPath = dynamic_cast<D2DGraphicsPath*> (_path); if (d2dPath == 0) return; ID2D1PathGeometry* path = d2dPath->getPath (evenOdd ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING); if (path) { D2DApplyClip ac (this); ID2D1Geometry* geometry = 0; if (t) { ID2D1TransformedGeometry* tg = 0; D2D1_MATRIX_3X2_F matrix; matrix._11 = (FLOAT)t->m11; matrix._12 = (FLOAT)t->m12; matrix._21 = (FLOAT)t->m21; matrix._22 = (FLOAT)t->m22; matrix._31 = (FLOAT)t->dx; matrix._32 = (FLOAT)t->dy; getD2DFactory ()->CreateTransformedGeometry (path, matrix, &tg); geometry = tg; } else { geometry = path; geometry->AddRef (); } ID2D1GradientStopCollection* collection = 0; D2D1_GRADIENT_STOP gradientStops[2]; gradientStops[0].position = (FLOAT)gradient.getColor1Start (); gradientStops[1].position = (FLOAT)gradient.getColor2Start (); gradientStops[0].color = D2D1::ColorF (gradient.getColor1 ().red/255.f, gradient.getColor1 ().green/255.f, gradient.getColor1 ().blue/255.f, gradient.getColor1 ().alpha/255.f * currentState.globalAlpha); gradientStops[1].color = D2D1::ColorF (gradient.getColor2 ().red/255.f, gradient.getColor2 ().green/255.f, gradient.getColor2 ().blue/255.f, gradient.getColor2 ().alpha/255.f * currentState.globalAlpha); if (SUCCEEDED (getRenderTarget ()->CreateGradientStopCollection (gradientStops, 2, &collection))) { ID2D1LinearGradientBrush* brush = 0; D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES properties; properties.startPoint = makeD2DPoint (startPoint); properties.endPoint = makeD2DPoint (endPoint); if (SUCCEEDED (getRenderTarget ()->CreateLinearGradientBrush (properties, collection, &brush))) { getRenderTarget ()->SetTransform (D2D1::Matrix3x2F::Translation ((FLOAT)getOffset ().x, (FLOAT)getOffset ().y)); getRenderTarget ()->FillGeometry (geometry, brush); getRenderTarget ()->SetTransform (D2D1::Matrix3x2F::Identity ()); brush->Release (); } collection->Release (); } geometry->Release (); } }
//----------------------------------------------------------------------------- void D2DDrawContext::fillLinearGradient (CGraphicsPath* _path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd, CGraphicsTransform* t) { if (renderTarget == 0) return; bool halfPointOffset = currentState.drawMode.integralMode () ? ((((int32_t)currentState.frameWidth) % 2) != 0) : false; D2DApplyClip ac (this, halfPointOffset); if (ac.isEmpty ()) return; D2DGraphicsPath* d2dPath = dynamic_cast<D2DGraphicsPath*> (_path); if (d2dPath == 0) return; ID2D1Geometry* path = d2dPath->createPath (evenOdd ? D2D1_FILL_MODE_ALTERNATE : D2D1_FILL_MODE_WINDING, this, t); if (path) { ID2D1GradientStopCollection* collection = createGradientStopCollection (gradient); if (collection) { ID2D1LinearGradientBrush* brush = 0; D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES properties; properties.startPoint = makeD2DPoint (startPoint); properties.endPoint = makeD2DPoint (endPoint); if (SUCCEEDED (getRenderTarget ()->CreateLinearGradientBrush (properties, collection, &brush))) { getRenderTarget ()->FillGeometry (path, brush); brush->Release (); } collection->Release (); } path->Release (); } }
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; D2D1_POINT_2F center; HRESULT hr; size = realGetSize(rt); 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 center.x = 0; center.y = c->h * size.height; hypot = rect.left; drawArrow(rt, center, hypot); }
// this interesting approach comes from http://blogs.msdn.com/b/wpfsdk/archive/2006/10/26/uncommon-dialogs--font-chooser-and-color-picker-dialogs.aspx static void drawSVChooser(struct colorDialog *c, ID2D1RenderTarget *rt) { D2D1_SIZE_F size; D2D1_RECT_F rect; double rTop, gTop, bTop; D2D1_GRADIENT_STOP stops[2]; ID2D1GradientStopCollection *collection; D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES lprop; D2D1_BRUSH_PROPERTIES bprop; ID2D1LinearGradientBrush *brush; ID2D1LinearGradientBrush *opacity; ID2D1Layer *layer; D2D1_LAYER_PARAMETERS layerparams; D2D1_ELLIPSE mparam; D2D1_COLOR_F mcolor; ID2D1SolidColorBrush *markerBrush; HRESULT hr; size = realGetSize(rt); rect.left = 0; rect.top = 0; rect.right = size.width; rect.bottom = size.height; drawGrid(rt, &rect); // first, draw a vertical gradient from the current hue at max S/V to black // the source example draws it upside down; let's do so too just to be safe hsv2RGB(c->h, 1.0, 1.0, &rTop, &gTop, &bTop); stops[0].position = 0; stops[0].color.r = 0.0; stops[0].color.g = 0.0; stops[0].color.b = 0.0; stops[0].color.a = 1.0; stops[1].position = 1; stops[1].color.r = rTop; stops[1].color.g = gTop; stops[1].color.b = bTop; stops[1].color.a = 1.0; hr = rt->CreateGradientStopCollection(stops, 2, D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, &collection); if (hr != S_OK) logHRESULT(L"error making gradient stop collection for first gradient in SV chooser", hr); ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); lprop.startPoint.x = size.width / 2; lprop.startPoint.y = size.height; lprop.endPoint.x = size.width / 2; lprop.endPoint.y = 0; // TODO decide what to do about the duplication of this ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); bprop.opacity = c->a; // note this part; we also use it below for the layer bprop.transform._11 = 1; bprop.transform._22 = 1; hr = rt->CreateLinearGradientBrush(&lprop, &bprop, collection, &brush); if (hr != S_OK) logHRESULT(L"error making gradient brush for first gradient in SV chooser", hr); rt->FillRectangle(&rect, brush); brush->Release(); collection->Release(); // second, create an opacity mask for the third step: a horizontal gradientthat goes from opaque to translucent stops[0].position = 0; stops[0].color.r = 0.0; stops[0].color.g = 0.0; stops[0].color.b = 0.0; stops[0].color.a = 1.0; stops[1].position = 1; stops[1].color.r = 0.0; stops[1].color.g = 0.0; stops[1].color.b = 0.0; stops[1].color.a = 0.0; hr = rt->CreateGradientStopCollection(stops, 2, D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, &collection); if (hr != S_OK) logHRESULT(L"error making gradient stop collection for opacity mask gradient in SV chooser", hr); ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); lprop.startPoint.x = 0; lprop.startPoint.y = size.height / 2; lprop.endPoint.x = size.width; lprop.endPoint.y = size.height / 2; ZeroMemory(&bprop, sizeof (D2D1_BRUSH_PROPERTIES)); bprop.opacity = 1.0; bprop.transform._11 = 1; bprop.transform._22 = 1; hr = rt->CreateLinearGradientBrush(&lprop, &bprop, collection, &opacity); if (hr != S_OK) logHRESULT(L"error making gradient brush for opacity mask gradient in SV chooser", hr); collection->Release(); // finally, make a vertical gradient from white at the top to black at the bottom (right side up this time) and with the previous opacity mask stops[0].position = 0; stops[0].color.r = 1.0; stops[0].color.g = 1.0; stops[0].color.b = 1.0; stops[0].color.a = 1.0; stops[1].position = 1; stops[1].color.r = 0.0; stops[1].color.g = 0.0; stops[1].color.b = 0.0; stops[1].color.a = 1.0; hr = rt->CreateGradientStopCollection(stops, 2, D2D1_GAMMA_2_2, D2D1_EXTEND_MODE_CLAMP, &collection); if (hr != S_OK) logHRESULT(L"error making gradient stop collection for second gradient in SV chooser", hr); ZeroMemory(&lprop, sizeof (D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES)); lprop.startPoint.x = size.width / 2; lprop.startPoint.y = 0; lprop.endPoint.x = size.width / 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 making gradient brush for second gradient in SV chooser", hr); // oh but wait we can't use FillRectangle() with an opacity mask // and we can't use FillGeometry() with both an opacity mask and a non-bitmap // layers it is! hr = rt->CreateLayer(&size, &layer); if (hr != S_OK) logHRESULT(L"error making layer for second gradient in SV chooser", hr); ZeroMemory(&layerparams, sizeof (D2D1_LAYER_PARAMETERS)); layerparams.contentBounds = rect; // TODO make sure these are right layerparams.geometricMask = NULL; layerparams.maskAntialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE; layerparams.maskTransform._11 = 1; layerparams.maskTransform._22 = 1; layerparams.opacity = c->a; // here's the other use of c->a to note layerparams.opacityBrush = opacity; layerparams.layerOptions = D2D1_LAYER_OPTIONS_NONE; rt->PushLayer(&layerparams, layer); rt->FillRectangle(&rect, brush); rt->PopLayer(); layer->Release(); brush->Release(); collection->Release(); opacity->Release(); // and now we just draw the marker ZeroMemory(&mparam, sizeof (D2D1_ELLIPSE)); mparam.point.x = c->s * size.width; mparam.point.y = (1 - c->v) * size.height; mparam.radiusX = 7; mparam.radiusY = 7; // TODO make the color contrast? mcolor.r = 1.0; mcolor.g = 1.0; mcolor.b = 1.0; mcolor.a = 1.0; 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 marker", hr); rt->DrawEllipse(&mparam, markerBrush, 2, NULL); markerBrush->Release(); }