330{
331 wxPaintDC dc(this);
332
334
337 const auto x = rect.GetX();
338 const auto y = rect.GetY();
339 const auto width = rect.GetWidth();
340 const auto height = rect.GetHeight();
341
343 gc->SetPen(wxTransparentColor);
344 gc->DrawRectangle(x, y, width, height);
345
347
348
349
350
351 constexpr auto drawLegend = false;
352 if (drawLegend)
354 gc->SetBrush(*wxTRANSPARENT_BRUSH);
356 gc->DrawRectangle(x, y, width, height);
357 } };
358
360 {
362 {
363 const auto text =
XO(
"awaiting playback");
364 const wxDCFontChanger changer { dc,
365 { 16, wxFONTFAMILY_DEFAULT,
366 wxFONTSTYLE_NORMAL,
367 wxFONTWEIGHT_NORMAL } };
368 const auto textWidth = dc.GetTextExtent(text.Translation()).GetWidth();
369 const auto textHeight =
370 dc.GetTextExtent(text.Translation()).GetHeight();
371 dc.SetTextForeground(wxColor { 128, 128, 128 });
372 dc.DrawText(
373 text.Translation(), (width - textWidth) / 2,
374 (height - textHeight) / 2);
375 }
376 return;
377 }
378
379 const auto& segments =
mHistory->GetSegments();
380 const auto elapsedTimeSinceFirstPacket =
381 std::chrono::duration<float>(
mSync->now -
mSync->start).count();
383 const auto dbPerPixel = rangeDb / height;
384
385 for (const auto& segment : segments)
386 {
392
393 mX.resize(segment.size());
394 auto lastInvisibleLeft = 0;
395 auto firstInvisibleRight = 0;
396 std::transform(
397 segment.begin(), segment.end(),
mX.begin(), [&](
const auto& packet) {
398 const auto x = GetDisplayPixel(
399 elapsedTimeSinceFirstPacket -
400 (packet.time - mSync->firstPacketTime),
401 width);
402 if (x < 0)
403 ++lastInvisibleLeft;
404 if (x < width)
405 ++firstInvisibleRight;
406 return x;
407 });
408 lastInvisibleLeft = std::max<int>(--lastInvisibleLeft, 0);
409 firstInvisibleRight = std::min<int>(++firstInvisibleRight,
mX.size());
410
411 mX.erase(
mX.begin() + firstInvisibleRight,
mX.end());
412 mX.erase(
mX.begin(),
mX.begin() + lastInvisibleLeft);
413
415 continue;
416
417 auto segmentIndex = lastInvisibleLeft;
422 std::for_each(
mX.begin(),
mX.end(), [&](
auto x) {
423 const auto& packet = segment[segmentIndex++];
424 const auto elapsedSincePacket = elapsedTimeSinceFirstPacket -
425 (packet.time - mSync->firstPacketTime);
426 mTarget.emplace_back(x, -packet.target / dbPerPixel);
427 mActual.emplace_back(x, -packet.follower / dbPerPixel);
428 mInput.emplace_back(x, -packet.input / dbPerPixel);
429 mOutput.emplace_back(x, -packet.output / dbPerPixel);
430 });
431
434
436 {
439 outputGc->SetPen({ wxColor {
outputColor.GetRGB() }, 2 });
441 }
442
444 {
445
446
448
449 actualGc->SetPen(
453 {
454
455
457
458 wxGraphicsGradientStops stops;
459 const auto xLeft =
mActual.front().m_x;
460 const auto xRight =
mActual.back().m_x;
461 const auto span = xRight - xLeft;
462 for (
auto i = 0; i <
mActual.size(); ++i)
463 {
465 const auto actualIsBelow = diff < 0;
466 const auto w =
std::min(1.0, std::abs(diff) * dbPerPixel / 6);
470 .GetRGB();
471 stops.Add(color, (
mActual[i].m_x - xLeft) / span);
472 }
473 wxGraphicsPenInfo penInfo;
474 penInfo
475 .LinearGradient(
478
479 actualGc->SetPen(actualGc->CreatePen(penInfo));
481 }
482 }
483
485 {
487 targetGc->SetPen(
490 }
491 }
492}
std::vector< wxPoint2DDouble > mOutput
std::vector< wxPoint2DDouble > mTarget
std::vector< wxPoint2DDouble > mInput
std::vector< wxPoint2DDouble > mActual
wxColor GetColorMix(const wxColor &a, const wxColor &b, double aWeight)
static const wxColour targetCompressionColor
static const wxColour actualCompressionColor
float GetGraphDbRange(int height)
static constexpr auto targetCompressionLineWidth
std::unique_ptr< wxGraphicsContext > MakeGraphicsContext(const wxPaintDC &dc)
static const wxColour attackColor
wxRect GetPanelRect(const wxPanelWrapper &panel)
static const wxColour releaseColor
static const wxColour inputColor
static const wxColour lineColor
wxGraphicsBrush GetGraphBackgroundBrush(wxGraphicsContext &gc, int height)
static const wxColour outputColor
void FillUpTo(std::vector< wxPoint2DDouble > lines, const wxColor &color, wxGraphicsContext &gc, const wxRect &rect)
void DrawLegend(size_t height, wxPaintDC &dc, wxGraphicsContext &gc)
bool MayUsePenGradients()
int GetActualCompressionLineWidth()
void InsertCrossings(std::vector< wxPoint2DDouble > &A, std::vector< wxPoint2DDouble > &B)
"finally" as in The C++ Programming Language, 4th ed., p. 358 Useful for defining ad-hoc RAII actions...