/* ** Draws the meter on the double buffer ** */ bool MeterRoundLine::Draw(Gfx::Canvas& canvas) { if (!Meter::Draw(canvas)) return false; Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); // Calculate the center of for the line int x = GetX(); int y = GetY(); double cx = x + m_W / 2.0; double cy = y + m_H / 2.0; double lineStart = ((m_CntrlLineStart) ? m_LineStartShift * m_Value : 0) + m_LineStart; double lineLength = ((m_CntrlLineLength) ? m_LineLengthShift * m_Value : 0) + m_LineLength; // Calculate the end point of the line double angle = ((m_CntrlAngle) ? m_RotationAngle * m_Value : m_RotationAngle) + m_StartAngle; double e_cos = cos(angle); double e_sin = sin(angle); REAL sx = (REAL)(e_cos * lineStart + cx); REAL sy = (REAL)(e_sin * lineStart + cy); REAL ex = (REAL)(e_cos * lineLength + cx); REAL ey = (REAL)(e_sin * lineLength + cy); if (m_Solid) { REAL startAngle = (REAL)(fmod(CONVERT_TO_DEGREES(m_StartAngle), 360.0)); REAL sweepAngle = (REAL)(CONVERT_TO_DEGREES(m_RotationAngle * m_Value)); // Calculate the start point of the line double s_cos = cos(m_StartAngle); double s_sin = sin(m_StartAngle); //Create a path to surround the arc GraphicsPath path; path.AddArc((REAL)(cx - lineStart), (REAL)(cy - lineStart), (REAL)(lineStart * 2.0), (REAL)(lineStart * 2.0), startAngle, sweepAngle); path.AddLine((REAL)(lineStart * s_cos + cx), (REAL)(lineStart * s_sin + cy), (REAL)(lineLength * s_cos + cx), (REAL)(lineLength * s_sin + cy)); path.AddArc((REAL)(cx - lineLength), (REAL)(cy - lineLength), (REAL)(lineLength * 2.0), (REAL)(lineLength * 2.0), startAngle, sweepAngle); path.AddLine(ex, ey, sx, sy); SolidBrush solidBrush(m_LineColor); graphics.FillPath(&solidBrush, &path); } else { Pen pen(m_LineColor, (REAL)m_LineWidth); graphics.DrawLine(&pen, sx, sy, ex, ey); } canvas.EndGdiplusContext(); return true; }
/* ** Draws a bevel inside the given area */ void Meter::DrawBevel(Gfx::Canvas& canvas, const D2D1_RECT_F& rect, const D2D1_COLOR_F& light, const D2D1_COLOR_F& dark) { const FLOAT l = rect.left; const FLOAT r = rect.right - 1.0f; const FLOAT t = rect.top; const FLOAT b = rect.bottom - 1.0f; canvas.DrawLine(light, l, t, l, b, 2.0f); canvas.DrawLine(light, l, t, r, t, 2.0f); canvas.DrawLine(light, l + 1.0f, t + 1.0f, l + 1.0f, b - 1.0f, 2.0f); canvas.DrawLine(light, l + 1.0f, t + 1.0f, r - 1.0f, t + 1.0f, 2.0f); canvas.DrawLine(dark, l, b, r, b, 2.0f); canvas.DrawLine(dark, r, t, r, b, 2.0f); canvas.DrawLine(dark, l + 1.0f, b - 1.0f, r - 1.0f, b - 1.0f, 2.0f); canvas.DrawLine(dark, r - 1.0f, t + 1.0f, r - 1.0f, b - 1.0f, 2.0f); }
/* ** Draws the meter on the double buffer ** */ bool MeterButton::Draw(Gfx::Canvas& canvas) { if (!Meter::Draw(canvas)) return false; if (m_Bitmaps[m_State] == nullptr) return false; // Unable to continue Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); Gdiplus::Rect meterRect = GetMeterRectPadding(); // Blit the image graphics.DrawCachedBitmap(m_Bitmaps[m_State], meterRect.X, meterRect.Y); canvas.EndGdiplusContext(); return true; }
/* ** Draws the solid background & bevel if such are defined */ bool Meter::Draw(Gfx::Canvas& canvas) { if (IsHidden()) return false; canvas.SetAntiAliasing(m_AntiAlias); if (m_SolidColor.a != 0.0f || m_SolidColor2.a != 0.0f) { const FLOAT x = (FLOAT)GetX(); const FLOAT y = (FLOAT)GetY(); const D2D1_RECT_F r = D2D1::RectF(x, y, x + (FLOAT)m_W, y + (FLOAT)m_H); if (m_SolidColor.r == m_SolidColor2.r && m_SolidColor.g == m_SolidColor2.g && m_SolidColor.b == m_SolidColor2.b && m_SolidColor.a == m_SolidColor2.a) { canvas.FillRectangle(r, m_SolidColor); } else { canvas.FillGradientRectangle(r, m_SolidColor, m_SolidColor2, (FLOAT)m_SolidAngle); } } if (m_SolidBevel != BEVELTYPE_NONE) { D2D1_COLOR_F lightColor = D2D1::ColorF(D2D1::ColorF::White); D2D1_COLOR_F darkColor = D2D1::ColorF(D2D1::ColorF::Black); if (m_SolidBevel == BEVELTYPE_DOWN) { lightColor = D2D1::ColorF(D2D1::ColorF::Black); darkColor = D2D1::ColorF(D2D1::ColorF::White); } // The bevel is drawn outside the meter const FLOAT x = (FLOAT)GetX(); const FLOAT y = (FLOAT)GetY(); const D2D1_RECT_F rect = D2D1::RectF(x - 2.0f, y - 2.0f, x + (FLOAT)m_W + 2.0f, y + (FLOAT)m_H + 2.0f); DrawBevel(canvas, rect, lightColor, darkColor); } return true; }
/* ** Draws the meter on the double buffer ** */ bool MeterButton::Draw(Gfx::Canvas& canvas) { if (!Meter::Draw(canvas)) return false; const auto image = m_Image.GetImage(); D2D1_RECT_F meterRect = GetMeterRectPadding(); if (image) { canvas.DrawBitmap( image, D2D1::RectF( meterRect.left, meterRect.top, meterRect.left + (FLOAT)m_W, meterRect.top + (FLOAT)m_H), m_BitmapsRects[m_State]); } return true; }
/* ** Draws the string or calculates it's size ** */ bool MeterString::DrawString(Gfx::Canvas& canvas, RectF* rect) { if (!m_TextFormat->IsInitialized()) return false; LPCWSTR string = m_String.c_str(); UINT stringLen = (UINT)m_String.length(); canvas.SetTextAntiAliasing(m_AntiAlias); m_TextFormat->SetTrimming( m_ClipType == CLIP_ON || (m_ClipType == CLIP_AUTO && (m_NeedsClipping || (m_WDefined && m_HDefined)))); Gdiplus::Rect meterRect = GetMeterRectPadding(); if (rect) { rect->X = (REAL)meterRect.X; rect->Y = (REAL)meterRect.Y; if (canvas.MeasureTextW(string, stringLen, *m_TextFormat, *rect) && m_ClipType == CLIP_AUTO) { // Set initial clipping m_NeedsClipping = false; REAL w, h; bool updateSize = true; if (m_WDefined) { w = (REAL)meterRect.Width; h = rect->Height; m_NeedsClipping = true; } else if (m_HDefined) { if (m_ClipStringW == -1) { // Text does not fit in defined height, clip it if (rect->Height > (REAL)meterRect.Height) { m_NeedsClipping = true; } rect->Height = (REAL)meterRect.Height; updateSize = false; } else { if (rect->Width > (REAL)m_ClipStringW) { w = (REAL)m_ClipStringW; m_NeedsClipping = true; } else { w = rect->Width; } h = (REAL)meterRect.Height; } } else { if (m_ClipStringW == -1) { // Clip text if already larger than ClipStringH if (m_ClipStringH != -1 && rect->Height > (REAL)m_ClipStringH) { m_NeedsClipping = true; rect->Height = (REAL)m_ClipStringH; } updateSize = false; } else { if (rect->Width > (REAL)m_ClipStringW) { w = (REAL)m_ClipStringW; m_NeedsClipping = true; } else { w = rect->Width; } h = rect->Height; } } if (updateSize) { UINT lines = 0; RectF layout((REAL)meterRect.X, (REAL)meterRect.Y, w, h); if (canvas.MeasureTextLinesW(string, stringLen, *m_TextFormat, layout, lines) && lines != 0) { rect->Width = w; rect->Height = layout.Height; if (m_HDefined || (m_ClipStringH != -1 && rect->Height > (REAL)m_ClipStringH)) { rect->Height = m_HDefined ? (REAL)meterRect.Height : (REAL)m_ClipStringH; } } } } } else { RectF rcDest((REAL)meterRect.X, (REAL)meterRect.Y, (REAL)meterRect.Width, (REAL)meterRect.Height); m_Rect = rcDest; if (m_Angle != 0.0f) { const float baseX = (float)Meter::GetX(); canvas.RotateTransform(CONVERT_TO_DEGREES(m_Angle), baseX, (REAL)meterRect.Y, -baseX, -(REAL)meterRect.Y); } if (m_Effect != EFFECT_NONE) { SolidBrush solidBrush(m_EffectColor); RectF rcEffect(rcDest); if (m_Effect == EFFECT_SHADOW) { rcEffect.Offset(1, 1); canvas.DrawTextW(string, (UINT)stringLen, *m_TextFormat, rcEffect, solidBrush); } else //if (m_Effect == EFFECT_BORDER) { rcEffect.Offset(0, 1); canvas.DrawTextW(string, (UINT)stringLen, *m_TextFormat, rcEffect, solidBrush); rcEffect.Offset(1, -1); canvas.DrawTextW(string, (UINT)stringLen, *m_TextFormat, rcEffect, solidBrush); rcEffect.Offset(-1, -1); canvas.DrawTextW(string, (UINT)stringLen, *m_TextFormat, rcEffect, solidBrush); rcEffect.Offset(-1, 1); canvas.DrawTextW(string, (UINT)stringLen, *m_TextFormat, rcEffect, solidBrush); } } SolidBrush solidBrush(m_Color); canvas.DrawTextW(string, (UINT)stringLen, *m_TextFormat, rcDest, solidBrush); if (m_Angle != 0.0f) { canvas.ResetTransform(); } } return true; }
/* ** Draws the solid background & bevel if such are defined */ bool Meter::Draw(Gfx::Canvas& canvas) { if (IsHidden()) return false; canvas.SetAntiAliasing(m_AntiAlias); if (m_SolidColor.GetA() != 0 || m_SolidColor2.GetA() != 0) { int x = GetX(); int y = GetY(); Rect r(x, y, m_W, m_H); if (m_SolidColor.GetValue() == m_SolidColor2.GetValue()) { SolidBrush solid(m_SolidColor); canvas.FillRectangle(r, solid); } else { Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); if (!m_AntiAlias) { // Fix the tiling issue in some GradientAngle values graphics.SetPixelOffsetMode(PixelOffsetModeHalf); } LinearGradientBrush gradient(r, m_SolidColor, m_SolidColor2, m_SolidAngle, TRUE); graphics.FillRectangle(&gradient, r); if (!m_AntiAlias) { graphics.SetPixelOffsetMode(PixelOffsetModeDefault); } canvas.EndGdiplusContext(); } } if (m_SolidBevel != BEVELTYPE_NONE) { Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); int x = GetX(); int y = GetY(); Color lightColor(255, 255, 255, 255); Color darkColor(255, 0, 0, 0); if (m_SolidBevel == BEVELTYPE_DOWN) { lightColor.SetValue(Color::MakeARGB(255, 0, 0, 0)); darkColor.SetValue(Color::MakeARGB(255, 255, 255, 255)); } Pen light(lightColor); Pen dark(darkColor); // The bevel is drawn outside the meter Rect rect(x - 2, y - 2, m_W + 4, m_H + 4); DrawBevel(graphics, rect, light, dark); canvas.EndGdiplusContext(); } return true; }
/* ** Draws the meter on the double buffer ** */ bool MeterImage::Draw(Gfx::Canvas& canvas) { if (!Meter::Draw(canvas)) return false; if (m_Image.IsLoaded()) { // Copy the image over the doublebuffer Bitmap* drawBitmap = m_Image.GetImage(); int imageW = drawBitmap->GetWidth(); int imageH = drawBitmap->GetHeight(); if (imageW == 0 || imageH == 0 || m_W == 0 || m_H == 0) return true; int x = GetX(); int y = GetY(); int drawW = m_W; int drawH = m_H; if (drawW == imageW && drawH == imageH && m_ScaleMargins.left == 0 && m_ScaleMargins.top == 0 && m_ScaleMargins.right == 0 && m_ScaleMargins.bottom == 0) { canvas.DrawBitmap(drawBitmap, Rect(x, y, drawW, drawH), Rect(0, 0, imageW, imageH)); } else if (m_DrawMode == DRAWMODE_TILE) { Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); ImageAttributes imgAttr; imgAttr.SetWrapMode(WrapModeTile); Rect r(x, y, drawW, drawH); graphics.DrawImage(drawBitmap, r, 0, 0, drawW, drawH, UnitPixel, &imgAttr); canvas.EndGdiplusContext(); } else if (m_DrawMode == DRAWMODE_KEEPRATIO || m_DrawMode == DRAWMODE_KEEPRATIOANDCROP) { int cropX = 0; int cropY = 0; int cropW = imageW; int cropH = imageH; if (m_WDefined && m_HDefined) { REAL imageRatio = imageW / (REAL)imageH; REAL meterRatio = m_W / (REAL)m_H; if (imageRatio != meterRatio) { if (m_DrawMode == DRAWMODE_KEEPRATIO) { if (imageRatio > meterRatio) { drawH = m_W * imageH / imageW; y += (m_H - drawH) / 2; } else { drawW = m_H * imageW / imageH; x += (m_W - drawW) / 2; } } else { if (imageRatio > meterRatio) { cropW = (int)(imageH * meterRatio); cropX = (imageW - cropW) / 2; } else { cropH = (int)(imageW / meterRatio); cropY = (imageH - cropH) / 2; } } } } Rect r(x, y, drawW, drawH); canvas.DrawBitmap(drawBitmap, r, Rect(cropX, cropY, cropW, cropH)); } else { const RECT& m = m_ScaleMargins; if (m.top > 0) { if (m.left > 0) { // Top-Left Rect r(x, y, m.left, m.top); canvas.DrawBitmap(drawBitmap, r, Rect(0, 0, m.left, m.top)); } // Top Rect r(x + m.left, y, drawW - m.left - m.right, m.top); canvas.DrawBitmap(drawBitmap, r, Rect(m.left, 0, imageW - m.left - m.right, m.top)); if (m.right > 0) { // Top-Right Rect r(x + drawW - m.right, y, m.right, m.top); canvas.DrawBitmap(drawBitmap, r, Rect(imageW - m.right, 0, m.right, m.top)); } } if (m.left > 0) { // Left Rect r(x, y + m.top, m.left, drawH - m.top - m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(0, m.top, m.left, imageH - m.top - m.bottom)); } // Center Rect r(x + m.left, y + m.top, drawW - m.left - m.right, drawH - m.top - m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(m.left, m.top, imageW - m.left - m.right, imageH - m.top - m.bottom)); if (m.right > 0) { // Right Rect r(x + drawW - m.right, y + m.top, m.right, drawH - m.top - m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(imageW - m.right, m.top, m.right, imageH - m.top - m.bottom)); } if (m.bottom > 0) { if (m.left > 0) { // Bottom-Left Rect r(x, y + drawH - m.bottom, m.left, m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(0, imageH - m.bottom, m.left, m.bottom)); } // Bottom Rect r(x + m.left, y + drawH - m.bottom, drawW - m.left - m.right, m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(m.left, imageH - m.bottom, imageW - m.left - m.right, m.bottom)); if (m.right > 0) { // Bottom-Right Rect r(x + drawW - m.right, y + drawH - m.bottom, m.right, m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(imageW - m.right, imageH - m.bottom, m.right, m.bottom)); } } } } return true; }
/* ** Draws the meter on the double buffer ** */ bool MeterHistogram::Draw(Gfx::Canvas& canvas) { if (!Meter::Draw(canvas) || (m_Measures.size() >= 1 && !m_PrimaryValues) || (m_Measures.size() >= 2 && !m_SecondaryValues)) return false; Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); Measure* secondaryMeasure = (m_Measures.size() >= 2) ? m_Measures[1] : nullptr; GraphicsPath primaryPath; GraphicsPath secondaryPath; GraphicsPath bothPath; Bitmap* primaryBitmap = m_PrimaryImage.GetImage(); Bitmap* secondaryBitmap = m_SecondaryImage.GetImage(); Bitmap* bothBitmap = m_OverlapImage.GetImage(); Gdiplus::Rect meterRect = GetMeterRectPadding(); // Default values (GraphStart=Right, GraphOrientation=Vertical) int i; int startValue = 0; int* endValueLHS = &i; int* endValueRHS = &meterRect.Width; int step = 1; int endValue = -1; //(should be 0, but need to simulate <=) // GraphStart=Left, GraphOrientation=Vertical if (!m_GraphHorizontalOrientation) { if (m_GraphStartLeft) { startValue = meterRect.Width - 1; endValueLHS = &endValue; endValueRHS = &i; step = -1; } } else { if (!m_Flip) { endValueRHS = &meterRect.Height; } else { startValue = meterRect.Height - 1; endValueLHS = &endValue; endValueRHS = &i; step = -1; } } // Horizontal or Vertical graph if (m_GraphHorizontalOrientation) { for (i = startValue; *endValueLHS < *endValueRHS; i += step) { double value = (m_MaxPrimaryValue == 0.0) ? 0.0 : m_PrimaryValues[(i + (m_MeterPos % meterRect.Height)) % meterRect.Height] / m_MaxPrimaryValue; value -= m_MinPrimaryValue; int primaryBarHeight = (int)(meterRect.Width * value); primaryBarHeight = min(meterRect.Width, primaryBarHeight); primaryBarHeight = max(0, primaryBarHeight); if (secondaryMeasure) { value = (m_MaxSecondaryValue == 0.0) ? 0.0 : m_SecondaryValues[(i + m_MeterPos) % meterRect.Height] / m_MaxSecondaryValue; value -= m_MinSecondaryValue; int secondaryBarHeight = (int)(meterRect.Width * value); secondaryBarHeight = min(meterRect.Width, secondaryBarHeight); secondaryBarHeight = max(0, secondaryBarHeight); // Check which measured value is higher int bothBarHeight = min(primaryBarHeight, secondaryBarHeight); // Cache image/color rectangle for the both lines { Rect& r = m_GraphStartLeft ? Rect(meterRect.X, meterRect.Y + startValue + (step * i), bothBarHeight, 1) : Rect(meterRect.X + meterRect.Width - bothBarHeight, meterRect.Y + startValue + (step * i), bothBarHeight, 1); bothPath.AddRectangle(r); // cache } // Cache the image/color rectangle for the rest if (secondaryBarHeight > primaryBarHeight) { Rect& r = m_GraphStartLeft ? Rect(meterRect.X + bothBarHeight, meterRect.Y + startValue + (step * i), secondaryBarHeight - bothBarHeight, 1) : Rect(meterRect.X + meterRect.Width - secondaryBarHeight, meterRect.Y + startValue + (step * i), secondaryBarHeight - bothBarHeight, 1); secondaryPath.AddRectangle(r); // cache } else { Rect& r = m_GraphStartLeft ? Rect(meterRect.X + bothBarHeight, meterRect.Y + startValue + (step * i), primaryBarHeight - bothBarHeight, 1) : Rect(meterRect.X + meterRect.Width - primaryBarHeight, meterRect.Y + startValue + (step * i), primaryBarHeight - bothBarHeight, 1); primaryPath.AddRectangle(r); // cache } } else { Rect& r = m_GraphStartLeft ? Rect(meterRect.X, meterRect.Y + startValue + (step * i), primaryBarHeight, 1) : Rect(meterRect.X + meterRect.Width - primaryBarHeight, meterRect.Y + startValue + (step * i), primaryBarHeight, 1); primaryPath.AddRectangle(r); // cache } } } else // GraphOrientation=Vertical { for (i = startValue; *endValueLHS < *endValueRHS; i += step) { double value = (m_MaxPrimaryValue == 0.0) ? 0.0 : m_PrimaryValues[(i + m_MeterPos) % meterRect.Width] / m_MaxPrimaryValue; value -= m_MinPrimaryValue; int primaryBarHeight = (int)(meterRect.Height * value); primaryBarHeight = min(meterRect.Height, primaryBarHeight); primaryBarHeight = max(0, primaryBarHeight); if (secondaryMeasure) { value = (m_MaxSecondaryValue == 0.0) ? 0.0 : m_SecondaryValues[(i + m_MeterPos) % meterRect.Width] / m_MaxSecondaryValue; value -= m_MinSecondaryValue; int secondaryBarHeight = (int)(meterRect.Height * value); secondaryBarHeight = min(meterRect.Height, secondaryBarHeight); secondaryBarHeight = max(0, secondaryBarHeight); // Check which measured value is higher int bothBarHeight = min(primaryBarHeight, secondaryBarHeight); // Cache image/color rectangle for the both lines { Rect& r = m_Flip ? Rect(meterRect.X + startValue + (step * i), meterRect.Y, 1, bothBarHeight) : Rect(meterRect.X + startValue + (step * i), meterRect.Y + meterRect.Height - bothBarHeight, 1, bothBarHeight); bothPath.AddRectangle(r); // cache } // Cache the image/color rectangle for the rest if (secondaryBarHeight > primaryBarHeight) { Rect& r = m_Flip ? Rect(meterRect.X + startValue + (step * i), meterRect.Y + bothBarHeight, 1, secondaryBarHeight - bothBarHeight) : Rect(meterRect.X + startValue + (step * i), meterRect.Y + meterRect.Height - secondaryBarHeight, 1, secondaryBarHeight - bothBarHeight); secondaryPath.AddRectangle(r); // cache } else { Rect& r = m_Flip ? Rect(meterRect.X + startValue + (step * i), meterRect.Y + bothBarHeight, 1, primaryBarHeight - bothBarHeight) : Rect(meterRect.X + startValue + (step * i), meterRect.Y + meterRect.Height - primaryBarHeight, 1, primaryBarHeight - bothBarHeight); primaryPath.AddRectangle(r); // cache } } else { Rect& r = m_Flip ? Rect(meterRect.X + startValue + (step * i), meterRect.Y, 1, primaryBarHeight) : Rect(meterRect.X + startValue + (step * i), meterRect.Y + meterRect.Height - primaryBarHeight, 1, primaryBarHeight); primaryPath.AddRectangle(r); // cache } } } // Draw cached rectangles if (primaryBitmap) { Rect r(meterRect.X, meterRect.Y, primaryBitmap->GetWidth(), primaryBitmap->GetHeight()); graphics.SetClip(&primaryPath); graphics.DrawImage(primaryBitmap, r, 0, 0, r.Width, r.Height, UnitPixel); graphics.ResetClip(); } else { SolidBrush brush(m_PrimaryColor); graphics.FillPath(&brush, &primaryPath); } if (secondaryMeasure) { if (secondaryBitmap) { Rect r(meterRect.X, meterRect.Y, secondaryBitmap->GetWidth(), secondaryBitmap->GetHeight()); graphics.SetClip(&secondaryPath); graphics.DrawImage(secondaryBitmap, r, 0, 0, r.Width, r.Height, UnitPixel); graphics.ResetClip(); } else { SolidBrush brush(m_SecondaryColor); graphics.FillPath(&brush, &secondaryPath); } if (bothBitmap) { Rect r(meterRect.X, meterRect.Y, bothBitmap->GetWidth(), bothBitmap->GetHeight()); graphics.SetClip(&bothPath); graphics.DrawImage(bothBitmap, r, 0, 0, r.Width, r.Height, UnitPixel); graphics.ResetClip(); } else { SolidBrush brush(m_OverlapColor); graphics.FillPath(&brush, &bothPath); } } canvas.EndGdiplusContext(); return true; }
/* ** Draws the meter on the double buffer ** */ bool MeterBitmap::Draw(Gfx::Canvas& canvas) { if (!Meter::Draw(canvas)) return false; int newY, newX; if (m_FrameCount == 0 || !m_Image.IsLoaded()) return false; // Unable to continue Bitmap* bitmap = m_Image.GetImage(); int x = GetX(); int y = GetY(); if (m_Extend) { int value = (int)m_Value; value = max(0, value); // Only positive integers are supported int transitionValue = (int)m_TransitionStartValue; transitionValue = max(0, transitionValue); // Only positive integers are supported // Calc the number of numbers int numOfNums = 0; if (m_Digits > 0) { numOfNums = m_Digits; } else { int tmpValue = value; do { ++numOfNums; if (m_FrameCount == 1) { tmpValue /= 2; } else { tmpValue /= m_FrameCount; } } while (tmpValue > 0); } // Blit the images int offset; if (m_Align == ALIGN_RIGHT) { offset = 0; } else if (m_Align == ALIGN_CENTER) { offset = numOfNums * (m_W + m_Separation) / 2; } else { offset = numOfNums * (m_W + m_Separation); } do { offset = offset - (m_W + m_Separation); int realFrames = (m_FrameCount / (m_TransitionFrameCount + 1)); int frame = (value % realFrames) * (m_TransitionFrameCount + 1); // If transition is ongoing the pick the correct frame if (m_TransitionStartTicks > 0) { int diffTicks = (int)(System::GetTickCount64() - m_TransitionStartTicks); int range = ((value % realFrames) - (transitionValue % realFrames)) * (m_TransitionFrameCount + 1); if (range < 0) { range += m_FrameCount; } int frameAdjustment = range * diffTicks / ((m_TransitionFrameCount + 1) * m_MeterWindow->GetTransitionUpdate()); if (frameAdjustment > range) { m_TransitionStartTicks = 0; // The transition is over. Draw with the real value. } else { frame = (transitionValue % realFrames) * (m_TransitionFrameCount + 1); frame += frameAdjustment; frame %= m_FrameCount; } } // LogDebugF(L"[%u] Value: %f Frame: %i (Transition = %s)", GetTickCount(), m_Value, frame, m_TransitionStartTicks > 0 ? L"true" : L"false"); if (bitmap->GetHeight() > bitmap->GetWidth()) { newX = 0; newY = m_H * frame; } else { newX = m_W * frame; newY = 0; } canvas.DrawBitmap(bitmap, Rect(x + offset, y, m_W, m_H), Rect(newX, newY, m_W, m_H)); if (m_FrameCount == 1) { value /= 2; transitionValue /= 2; } else { value /= realFrames; transitionValue /= realFrames; } --numOfNums; } while (numOfNums > 0); } else { int frame = 0; int realFrames = (m_FrameCount / (m_TransitionFrameCount + 1)); if (m_ZeroFrame) { // Use the first frame only if the value is zero if (m_Value > 0) { frame = (int)(m_Value * (realFrames - 1)) * (m_TransitionFrameCount + 1); } } else { // Select the correct frame linearly frame = (int)(m_Value * realFrames) * (m_TransitionFrameCount + 1); } // If transition is ongoing the pick the correct frame if (m_TransitionStartTicks > 0) { int diffTicks = (int)(System::GetTickCount64() - m_TransitionStartTicks); if (diffTicks > ((m_TransitionFrameCount + 1) * m_MeterWindow->GetTransitionUpdate())) { m_TransitionStartTicks = 0; // The transition is over. Draw with the real value. } else { double range = (m_Value - m_TransitionStartValue); double adjustment = range * diffTicks / ((m_TransitionFrameCount + 1) * m_MeterWindow->GetTransitionUpdate()); double frameAdjustment = adjustment * m_FrameCount; frame = (int)(m_TransitionStartValue * realFrames) * (m_TransitionFrameCount + 1); frame += (int)frameAdjustment; frame %= m_FrameCount; frame = max(0, frame); } } // LogDebugF(L"[%u] Value: %f Frame: %i (Transition = %s)", GetTickCount(), m_Value, frame, m_TransitionStartTicks > 0 ? L"true" : L"false"); if (bitmap->GetHeight() > bitmap->GetWidth()) { newX = 0; newY = frame * m_H; } else { newX = frame * m_W; newY = 0; } canvas.DrawBitmap(bitmap, Rect(x, y, m_W, m_H), Rect(newX, newY, m_W, m_H)); } return true; }
/* ** Draws the meter on the double buffer ** */ bool MeterBar::Draw(Gfx::Canvas& canvas) { if (!Meter::Draw(canvas)) return false; const D2D1_RECT_F rect = GetMeterRectPadding(); const FLOAT width = rect.right - rect.left; const FLOAT height = rect.bottom - rect.top; const FLOAT border = (FLOAT)m_Border; Gfx::D2DBitmap* drawBitmap = m_Image.GetImage(); if (m_Orientation == VERTICAL) { const FLOAT barSize = height - 2.0f * border; FLOAT size = barSize * (FLOAT)m_Value; size = min(barSize, size); size = max(0.0f, size); if (drawBitmap) { if (m_Flip) { if (border > 0.0f) { const auto d = Gfx::Util::ToRectF(rect.left, rect.top, width, border); const auto s = Gfx::Util::ToRectF(0.0f, 0.0f, width, border); canvas.DrawBitmap(drawBitmap, d, s); const auto d2 = Gfx::Util::ToRectF(rect.left, rect.top + size + border, width, border); const auto s2 = Gfx::Util::ToRectF(0.0f, height - border, width, border); canvas.DrawBitmap(drawBitmap, d2, s2); } const auto d = Gfx::Util::ToRectF(rect.left, rect.top + border, width, size); const auto s = Gfx::Util::ToRectF(0.0f, border, width, size); canvas.DrawBitmap(drawBitmap, d, s); } else { if (border > 0.0f) { const auto d = Gfx::Util::ToRectF(rect.left, rect.bottom - size - 2.0f * border, width, border); const auto s = Gfx::Util::ToRectF(0.0f, 0.0f, width, border); canvas.DrawBitmap(drawBitmap, d, s); const auto d2 = Gfx::Util::ToRectF(rect.left, rect.bottom - border, width, border); const auto s2 = Gfx::Util::ToRectF(0.0f, height - border, width, border); canvas.DrawBitmap(drawBitmap, d2, s2); } const auto d = Gfx::Util::ToRectF(rect.left, rect.bottom - size - border, width, size); const auto s = Gfx::Util::ToRectF(0.0f, height - size - border, width, size); canvas.DrawBitmap(drawBitmap, d, s); } } else { if (m_Flip) { const auto r = Gfx::Util::ToRectF(rect.left, rect.top, width, size); canvas.FillRectangle(r, m_Color); } else { const auto r = Gfx::Util::ToRectF(rect.left, rect.bottom - size, width, size); canvas.FillRectangle(r, m_Color); } } } else { const FLOAT barSize = width - 2.0f * border; FLOAT size = barSize * (FLOAT)m_Value; size = min(barSize, size); size = max(0.0f, size); if (drawBitmap) { if (m_Flip) { if (border > 0.0f) { const auto d = Gfx::Util::ToRectF(rect.right - size - 2.0f * border, rect.top, border, height); const auto s = Gfx::Util::ToRectF(0.0f, 0.0f, border, height); canvas.DrawBitmap(drawBitmap, d, s); const auto d2 = Gfx::Util::ToRectF(rect.right - border, rect.top, border, height); const auto s2 = Gfx::Util::ToRectF(width - border, 0.0f, border, height); canvas.DrawBitmap(drawBitmap, d2, s2); } const auto d = Gfx::Util::ToRectF(rect.right - size - border, rect.top, size, height); const auto s = Gfx::Util::ToRectF(width - size - border, 0.0f, size, height); canvas.DrawBitmap(drawBitmap, d, s); } else { if (border > 0.0f) { const auto d = Gfx::Util::ToRectF(rect.left, rect.top, border, height); const auto s = Gfx::Util::ToRectF(0.0f, 0.0f, border, height); canvas.DrawBitmap(drawBitmap, d, s); const auto d2 = Gfx::Util::ToRectF(rect.left + size + border, rect.top, border, height); const auto s2 = Gfx::Util::ToRectF(width - border, 0.0f, border, height); canvas.DrawBitmap(drawBitmap, d2, s2); } const auto d = Gfx::Util::ToRectF(rect.left + border, rect.top, size, height); const auto s = Gfx::Util::ToRectF(border, 0.0f, size, height); canvas.DrawBitmap(drawBitmap, d, s); } } else { if (m_Flip) { const auto r = Gfx::Util::ToRectF(rect.right - size, rect.top, size, height); canvas.FillRectangle(r, m_Color); } else { const auto r = Gfx::Util::ToRectF(rect.left, rect.top, size, height); canvas.FillRectangle(r, m_Color); } } } return true; }
/* ** Draws the meter on the double buffer ** */ bool MeterLine::Draw(Gfx::Canvas& canvas) { int maxSize = m_GraphHorizontalOrientation ? m_H : m_W; if (!Meter::Draw(canvas) || maxSize <= 0) return false; Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); double maxValue = 0.0; int counter = 0; // Find the maximum value if (m_Autoscale) { double newValue = 0; counter = 0; for (auto i = m_AllValues.cbegin(); i != m_AllValues.cend(); ++i) { double scale = m_ScaleValues[counter]; for (auto j = (*i).cbegin(); j != (*i).cend(); ++j) { double val = (*j) * scale; newValue = max(newValue, val); } ++counter; } // Scale the value up to nearest power of 2 if (newValue > DBL_MAX / 2.0) { maxValue = DBL_MAX; } else { maxValue = 2.0; while (maxValue < newValue) { maxValue *= 2.0; } } } else { for (auto i = m_Measures.cbegin(); i != m_Measures.cend(); ++i) { double val = (*i)->GetMaxValue(); maxValue = max(maxValue, val); } if (maxValue == 0.0) { maxValue = 1.0; } } int x = GetX(); int y = GetY(); // Draw the horizontal lines if (m_HorizontalLines) { // Calc the max number of lines we should draw int maxLines = m_H / 4; // one line per 4 pixels is max int numOfLines; // Check the highest power of 2 that fits in maxLines int power = 2; while (power < maxLines) { power *= 2; } numOfLines = ((int)maxValue % power) + 1; Pen pen(m_HorizontalColor); REAL Y; for (int j = 0; j < numOfLines; ++j) { Y = (REAL)((j + 1) * m_H / (numOfLines + 1)); Y = y + m_H - Y - 1; graphics.DrawLine(&pen, (REAL)x, Y, (REAL)(x + m_W - 1), Y); // GDI+ } } // Draw all the lines if (m_GraphHorizontalOrientation) { const REAL W = m_W - 1.0f; counter = 0; for (auto i = m_AllValues.cbegin(); i != m_AllValues.cend(); ++i) { // Draw a line REAL X, oldX; const double scale = m_ScaleValues[counter] * W / maxValue; int pos = m_CurrentPos; auto calcX = [&](REAL& _x) { _x = (REAL)((*i)[pos] * scale); _x = min(_x, W); _x = max(_x, 0.0f); _x = x + (m_GraphStartLeft ? _x : W - _x); }; calcX(oldX); // Cache all lines GraphicsPath path; if (!m_Flip) { for (int j = y + 1, R = y + m_H; j < R; ++j) { ++pos; pos %= m_H; calcX(X); path.AddLine(oldX, (REAL)(j - 1), X, (REAL)j); oldX = X; } } else { for (int j = y + m_H, R = y + 1; j > R; --j) { ++pos; pos %= m_H; calcX(X); path.AddLine(oldX, (REAL)(j - 1), X, (REAL)(j - 2)); oldX = X; } } // Draw cached lines Pen pen(m_Colors[counter], (REAL)m_LineWidth); pen.SetLineJoin(LineJoinBevel); graphics.DrawPath(&pen, &path); ++counter; } } else { const REAL H = m_H - 1.0f; counter = 0; for (auto i = m_AllValues.cbegin(); i != m_AllValues.cend(); ++i) { // Draw a line REAL Y, oldY; const double scale = m_ScaleValues[counter] * H / maxValue; int pos = m_CurrentPos; auto calcY = [&](REAL& _y) { _y = (REAL)((*i)[pos] * scale); _y = min(_y, H); _y = max(_y, 0.0f); _y = y + (m_Flip ? _y : H - _y); }; calcY(oldY); // Cache all lines GraphicsPath path; if (!m_GraphStartLeft) { for (int j = x + 1, R = x + m_W; j < R; ++j) { ++pos; pos %= m_W; calcY(Y); path.AddLine((REAL)(j - 1), oldY, (REAL)j, Y); oldY = Y; } } else { for (int j = x + m_W, R = x + 1; j > R; --j) { ++pos; pos %= m_W; calcY(Y); path.AddLine((REAL)(j - 1), oldY, (REAL)(j - 2), Y); oldY = Y; } } // Draw cached lines Pen pen(m_Colors[counter], (REAL)m_LineWidth); pen.SetLineJoin(LineJoinBevel); graphics.DrawPath(&pen, &path); ++counter; } } canvas.EndGdiplusContext(); return true; }
/* ** Draws the meter on the double buffer ** */ bool MeterImage::Draw(Gfx::Canvas& canvas) { if (!Meter::Draw(canvas)) return false; if (m_Image.IsLoaded()) { // Copy the image over the doublebuffer Bitmap* drawBitmap = m_Image.GetImage(); int imageW = drawBitmap->GetWidth(); int imageH = drawBitmap->GetHeight(); if (imageW == 0 || imageH == 0 || m_W == 0 || m_H == 0) return true; Gdiplus::Rect meterRect = GetMeterRectPadding(); int drawW = meterRect.Width; int drawH = meterRect.Height; bool hasMask = (m_Skin->GetUseD2D() && m_MaskImage.IsLoaded()); if (hasMask) { Bitmap* maskBitmap = m_MaskImage.GetImage(); imageW = maskBitmap->GetWidth(); imageH = maskBitmap->GetHeight(); int imageMW = drawBitmap->GetWidth(); int imageMH = drawBitmap->GetHeight(); int cropX = 0; int cropY = 0; int cropW = imageMW; int cropH = imageMH; REAL imageratio = imageMW / (REAL)imageMH; REAL meterRatio = meterRect.Width / (REAL)meterRect.Height; if (imageratio != meterRatio) { if (imageratio > meterRatio) { cropW = (int)(imageMH * meterRatio); cropX = (imageMW - cropW) / 2; } else { cropH = (int)(imageMW / meterRatio); cropY = (imageMH - cropH) / 2; } } canvas.DrawMaskedBitmap(drawBitmap, maskBitmap, meterRect, Rect(0, 0, imageW, imageH), Gdiplus::Rect(cropX, cropY, cropW, cropH)); } else if (drawW == imageW && drawH == imageH && m_ScaleMargins.left == 0 && m_ScaleMargins.top == 0 && m_ScaleMargins.right == 0 && m_ScaleMargins.bottom == 0) { canvas.DrawBitmap(drawBitmap, Rect(meterRect.X, meterRect.Y, drawW, drawH), Rect(0, 0, imageW, imageH)); } else if (m_DrawMode == DRAWMODE_TILE) { Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); ImageAttributes imgAttr; imgAttr.SetWrapMode(WrapModeTile); Rect r(meterRect.X, meterRect.Y, drawW, drawH); graphics.DrawImage(drawBitmap, r, 0, 0, drawW, drawH, UnitPixel, &imgAttr); canvas.EndGdiplusContext(); } else if (m_DrawMode == DRAWMODE_KEEPRATIO || m_DrawMode == DRAWMODE_KEEPRATIOANDCROP) { int cropX = 0; int cropY = 0; int cropW = imageW; int cropH = imageH; if (m_WDefined && m_HDefined) { REAL imageRatio = imageW / (REAL)imageH; REAL meterRatio = meterRect.Width / (REAL)meterRect.Height; if (imageRatio != meterRatio) { if (m_DrawMode == DRAWMODE_KEEPRATIO) { if (imageRatio > meterRatio) { drawH = meterRect.Width * imageH / imageW; meterRect.Y += (meterRect.Height - drawH) / 2; } else { drawW = meterRect.Height * imageW / imageH; meterRect.X += (meterRect.Width - drawW) / 2; } } else { if (imageRatio > meterRatio) { cropW = (int)(imageH * meterRatio); cropX = (imageW - cropW) / 2; } else { cropH = (int)(imageW / meterRatio); cropY = (imageH - cropH) / 2; } } } } Rect r(meterRect.X, meterRect.Y, drawW, drawH); canvas.DrawBitmap(drawBitmap, r, Rect(cropX, cropY, cropW, cropH)); } else { const RECT& m = m_ScaleMargins; if (m.top > 0) { if (m.left > 0) { // Top-Left Rect r(meterRect.X, meterRect.Y, m.left, m.top); canvas.DrawBitmap(drawBitmap, r, Rect(0, 0, m.left, m.top)); } // Top Rect r(meterRect.X + m.left, meterRect.Y, drawW - m.left - m.right, m.top); canvas.DrawBitmap(drawBitmap, r, Rect(m.left, 0, imageW - m.left - m.right, m.top)); if (m.right > 0) { // Top-Right Rect r(meterRect.X + drawW - m.right, meterRect.Y, m.right, m.top); canvas.DrawBitmap(drawBitmap, r, Rect(imageW - m.right, 0, m.right, m.top)); } } if (m.left > 0) { // Left Rect r(meterRect.X, meterRect.Y + m.top, m.left, drawH - m.top - m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(0, m.top, m.left, imageH - m.top - m.bottom)); } // Center Rect r(meterRect.X + m.left, meterRect.Y + m.top, drawW - m.left - m.right, drawH - m.top - m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(m.left, m.top, imageW - m.left - m.right, imageH - m.top - m.bottom)); if (m.right > 0) { // Right Rect r(meterRect.X + drawW - m.right, meterRect.Y + m.top, m.right, drawH - m.top - m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(imageW - m.right, m.top, m.right, imageH - m.top - m.bottom)); } if (m.bottom > 0) { if (m.left > 0) { // Bottom-Left Rect r(meterRect.X, meterRect.Y + drawH - m.bottom, m.left, m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(0, imageH - m.bottom, m.left, m.bottom)); } // Bottom Rect r(meterRect.X + m.left, meterRect.Y + drawH - m.bottom, drawW - m.left - m.right, m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(m.left, imageH - m.bottom, imageW - m.left - m.right, m.bottom)); if (m.right > 0) { // Bottom-Right Rect r(meterRect.X + drawW - m.right, meterRect.Y + drawH - m.bottom, m.right, m.bottom); canvas.DrawBitmap(drawBitmap, r, Rect(imageW - m.right, imageH - m.bottom, m.right, m.bottom)); } } } } return true; }
/* ** Draws the meter on the double buffer ** */ bool MeterSegmentedLine::Draw(Gfx::Canvas& canvas) { int maxSize = m_DataWidth; if (!Meter::Draw(canvas) || maxSize <= 0) return false; Gdiplus::Graphics& graphics = canvas.BeginGdiplusContext(); double maxValue = 0.0; int counter = 0; // Find the maximum value if (m_Autoscale) { double newValue = 0; counter = 0; for (auto i = m_AllValues.cbegin(); i != m_AllValues.cend(); ++i) { double scale = m_ScaleValues[counter]; for (auto j = (*i).cbegin(); j != (*i).cend(); ++j) { double val = (*j) * scale; newValue = max(newValue, val); } ++counter; } // Scale the value up to nearest power of 2 if (newValue > DBL_MAX / 2.0) { maxValue = DBL_MAX; } else { maxValue = 2.0; while (maxValue < newValue) { maxValue *= 2.0; } } } else { for (auto i = m_Measures.cbegin(); i != m_Measures.cend(); ++i) { double val = (*i)->GetMaxValue(); maxValue = max(maxValue, val); } if (maxValue == 0.0) { maxValue = 1.0; } } Gdiplus::Rect meterRect = GetMeterRectPadding(); // Draw all the lines const REAL H = meterRect.Height - 1.0f; counter = 0; auto pointsBuffer = m_Points.cbegin(); for (auto i = m_AllValues.cbegin(); i != m_AllValues.cend(); ++i) { // Draw a line REAL Y, oldY; const double scale = m_ScaleValues[counter] * H / maxValue; int pos = m_CurrentPos; auto calcY = [&](REAL& _y, REAL stepSize, int currPos) //TODO: move this lambda elsewhere { _y = 0; switch (m_CurveFitMethod) { //first value case 0: _y = (REAL)((*i)[currPos]); break; //maximum value case 1: for (int ind = 0; ind < stepSize; ind++) _y = max(_y, (REAL)((*i)[(currPos + ind) % m_DataWidth])); break; //arithmetic mean case 2: for (int ind = 0; ind < stepSize; ind++) _y += (REAL)((*i)[(currPos + ind) % m_DataWidth]); _y /= stepSize; break; default: _y = (REAL)((*i)[currPos]); } _y *= scale; _y = min(_y, H); _y = max(_y, 0.0f); _y = meterRect.Y + (H - _y); }; // Cache all lines GraphicsPath path; int segmentInd = 0, step, divider; //compute y values step = m_SegmentDividers[m_SegmentDividers.size() - 1]; divider = m_Segments.size() > 0 ? m_W - m_Segments[m_Segments.size() - 1] : m_W; for (int j = 0; j < m_W; ++j) { calcY(Y, step, pos - pos % step); (*pointsBuffer)[j] = Y; if (segmentInd < m_Segments.size() && j >= divider) { segmentInd++; step = m_SegmentDividers[m_SegmentDividers.size() - segmentInd - 1]; divider = segmentInd != m_Segments.size() ? m_W - m_Segments[m_Segments.size() - segmentInd - 1] : m_W; } pos += step; pos %= m_DataWidth; } //draw y values segmentInd = 0; divider = m_Segments.size() > 0 ? m_W - m_Segments[m_Segments.size() - segmentInd - 1] : m_W; if (!m_GraphStartLeft) { for (int j = 1; j < m_W; ++j) { if (segmentInd < m_Segments.size() && j >= divider) { segmentInd++; path.SetMarker(); path.StartFigure(); divider = segmentInd != m_Segments.size() ? m_W - m_Segments[m_Segments.size() - segmentInd - 1] : m_W; } path.AddLine((REAL)(meterRect.X + j - 1), (*pointsBuffer)[j - 1], (REAL)(meterRect.X + j), (*pointsBuffer)[j]); } } else { for (int j = 1; j < m_W; ++j) { if (segmentInd < m_Segments.size() && j >= divider) { segmentInd++; path.SetMarker(); path.StartFigure(); divider = segmentInd != m_Segments.size() ? m_W - m_Segments[m_Segments.size() - segmentInd - 1] : m_W; } path.AddLine((REAL)(meterRect.X + meterRect.Width - j), (*pointsBuffer)[j - 1], (REAL)(meterRect.X + meterRect.Width - j - 1), (*pointsBuffer)[j]); } } // Draw cached lines GraphicsPathIterator pathIter(&path); GraphicsPath subPath; for (auto color = m_Colors[counter].rbegin(); color != m_Colors[counter].rend(); ++color) { pathIter.NextMarker(&subPath); Pen pen(*color, (REAL)m_LineWidth); pen.SetLineJoin(LineJoinRound); graphics.DrawPath(&pen, &subPath); } ++counter; ++pointsBuffer; } canvas.EndGdiplusContext(); return true; }
/* ** Draws the meter on the double buffer ** */ bool CMeterBar::Draw(Gfx::Canvas& canvas) { if (!CMeter::Draw(canvas)) return false; int x = GetX(); int y = GetY(); Bitmap* drawBitmap = m_Image.GetImage(); if (m_Orientation == VERTICAL) { int barSize = m_H - 2 * m_Border; int size = (int)(barSize * m_Value); size = min(barSize, size); size = max(0, size); if (drawBitmap) { if (m_Flip) { if (m_Border > 0) { Rect r2(x, y, m_W, m_Border); canvas.DrawBitmap(drawBitmap, r2, Rect(0, 0, m_W, m_Border)); r2.Y = y + size + m_Border; canvas.DrawBitmap(drawBitmap, r2, Rect(0, m_H - m_Border, m_W, m_Border)); } Rect r(x, y + m_Border, m_W, size); canvas.DrawBitmap(drawBitmap, r, Rect(0, m_Border, m_W, size)); } else { if (m_Border > 0) { Rect r2(x, y + m_H - size - 2 * m_Border, m_W, m_Border); canvas.DrawBitmap(drawBitmap, r2, Rect(0, 0, m_W, m_Border)); r2.Y = y + m_H - m_Border; canvas.DrawBitmap(drawBitmap, r2, Rect(0, m_H - m_Border, m_W, m_Border)); } Rect r(x, y + m_H - size - m_Border, m_W, size); canvas.DrawBitmap(drawBitmap, r, Rect(0, m_H - size - m_Border, m_W, size)); } } else { SolidBrush brush(m_Color); if (m_Flip) { Rect r(x, y, m_W, size); canvas.FillRectangle(r, brush); } else { Rect r(x, y + m_H - size, m_W, size); canvas.FillRectangle(r, brush); } } } else { int barSize = m_W - 2 * m_Border; int size = (int)(barSize * m_Value); size = min(barSize, size); size = max(0, size); if (drawBitmap) { if (m_Flip) { if (m_Border > 0) { Rect r2(x + m_W - size - 2 * m_Border, y, m_Border, m_H); canvas.DrawBitmap(drawBitmap, r2, Rect(0, 0, m_Border, m_H)); r2.X = x + m_W - m_Border; canvas.DrawBitmap(drawBitmap, r2, Rect(m_W - m_Border, 0, m_Border, m_H)); } Rect r(x + m_W - size - m_Border, y, size, m_H); canvas.DrawBitmap(drawBitmap, r, Rect(m_W - size - m_Border, 0, size, m_H)); } else { if (m_Border > 0) { Rect r2(x, y, m_Border, m_H); canvas.DrawBitmap(drawBitmap, r2, Rect(0, 0, m_Border, m_H)); r2.X = x + size + m_Border; canvas.DrawBitmap(drawBitmap, r2, Rect(m_W - m_Border, 0, m_Border, m_H)); } Rect r(x + m_Border, y, size, m_H); canvas.DrawBitmap(drawBitmap, r, Rect(m_Border, 0, size, m_H)); } } else { SolidBrush brush(m_Color); if (m_Flip) { Rect r(x + m_W - size, y, size, m_H); canvas.FillRectangle(r, brush); } else { Rect r(x, y, size, m_H); canvas.FillRectangle(r, brush); } } } return true; }