From 8d0493f30c96814468fb9c49c7f4b581a524dd78 Mon Sep 17 00:00:00 2001 From: Vladimir Sadovnikov Date: Mon, 15 Jul 2024 23:36:54 +0300 Subject: [PATCH] Added header support by tk::LedMeter --- CHANGELOG | 1 + .../tk/widgets/specific/LedMeter.h | 10 +- src/main/widgets/specific/LedMeter.cpp | 206 ++++++++++++++---- src/test/mtest/widgets/specific/ledmeter.cpp | 15 +- 4 files changed, 188 insertions(+), 44 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 24ed02bd..f9116a34 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ === 1.0.23 === * Added header support by tk::LedMeterChannel. +* Added header support by tk::LedMeter. * Updated build scripts. === 1.0.22 === diff --git a/include/lsp-plug.in/tk/widgets/specific/LedMeter.h b/include/lsp-plug.in/tk/widgets/specific/LedMeter.h index b03ddc87..c2439fcc 100644 --- a/include/lsp-plug.in/tk/widgets/specific/LedMeter.h +++ b/include/lsp-plug.in/tk/widgets/specific/LedMeter.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2023 Linux Studio Plugins Project - * (C) 2023 Vladimir Sadovnikov + * Copyright (C) 2024 Linux Studio Plugins Project + * (C) 2024 Vladimir Sadovnikov * * This file is part of lsp-tk-lib * Created on: 25 сент. 2020 г. @@ -41,8 +41,10 @@ namespace lsp prop::Integer sBorder; prop::Integer sAngle; prop::String sEstText; + prop::String sEstHeader; prop::Boolean sSGroups; prop::Boolean sTextVisible; + prop::Boolean sHeaderVisible; prop::Color sColor; prop::Integer sMinChannelWidth; LSP_TK_STYLE_DEF_END @@ -67,8 +69,10 @@ namespace lsp prop::Integer sBorder; prop::Integer sAngle; prop::String sEstText; + prop::String sEstHeader; prop::Boolean sSGroups; prop::Boolean sTextVisible; + prop::Boolean sHeaderVisible; prop::Color sColor; prop::Integer sMinChannelWidth; @@ -105,8 +109,10 @@ namespace lsp LSP_TK_PROPERTY(Integer, border, &sBorder) LSP_TK_PROPERTY(Integer, angle, &sAngle) LSP_TK_PROPERTY(String, estimation_text, &sEstText) + LSP_TK_PROPERTY(String, estimation_header, &sEstHeader) LSP_TK_PROPERTY(Boolean, stereo_groups, &sSGroups) LSP_TK_PROPERTY(Boolean, text_visible, &sTextVisible) + LSP_TK_PROPERTY(Boolean, header_visible, &sHeaderVisible) LSP_TK_PROPERTY(Color, color, &sColor) LSP_TK_PROPERTY(Integer, min_channel_width, &sMinChannelWidth) diff --git a/src/main/widgets/specific/LedMeter.cpp b/src/main/widgets/specific/LedMeter.cpp index 79eced15..4aeb8897 100644 --- a/src/main/widgets/specific/LedMeter.cpp +++ b/src/main/widgets/specific/LedMeter.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2023 Linux Studio Plugins Project - * (C) 2023 Vladimir Sadovnikov + * Copyright (C) 2024 Linux Studio Plugins Project + * (C) 2024 Vladimir Sadovnikov * * This file is part of lsp-tk-lib * Created on: 25 сент. 2020 г. @@ -37,6 +37,7 @@ namespace lsp sAngle.bind("angle", this); sSGroups.bind("stereo_groups", this); sTextVisible.bind("text.visible", this); + sHeaderVisible.bind("header.visible", this); sColor.bind("color", this); sMinChannelWidth.bind("channel.width.min", this); // Configure @@ -46,6 +47,7 @@ namespace lsp sAngle.set(0); sSGroups.set(true); sTextVisible.set(false); + sHeaderVisible.set(false); sColor.set("#000000"); sMinChannelWidth.set(16); // Override @@ -64,8 +66,10 @@ namespace lsp sBorder(&sProperties), sAngle(&sProperties), sEstText(&sProperties), + sEstHeader(&sProperties), sSGroups(&sProperties), sTextVisible(&sProperties), + sHeaderVisible(&sProperties), sColor(&sProperties), sMinChannelWidth(&sProperties) { @@ -122,12 +126,15 @@ namespace lsp sBorder.bind("border", &sStyle); sAngle.bind("angle", &sStyle); sEstText.bind(&sStyle, pDisplay->dictionary()); + sEstHeader.bind(&sStyle, pDisplay->dictionary()); sSGroups.bind("stereo_groups", &sStyle); sTextVisible.bind("text.visible", &sStyle); + sHeaderVisible.bind("header.visible", &sStyle); sColor.bind("color", &sStyle); sMinChannelWidth.bind("channel.width.min", &sStyle); sEstText.set_raw("+99.9"); + sEstHeader.set_raw("+99.9"); return STATUS_OK; } @@ -148,8 +155,12 @@ namespace lsp query_resize(); if (sEstText.is(prop) && (sTextVisible.get())) query_resize(); + if (sEstHeader.is(prop) && (sHeaderVisible.get())) + query_resize(); if (sTextVisible.is(prop)) query_resize(); + if (sHeaderVisible.is(prop)) + query_resize(); if (sMinChannelWidth.is(prop)) query_resize(); } @@ -179,17 +190,27 @@ namespace lsp ssize_t angle = sAngle.get(); ssize_t minw = lsp_max(ceilf(seg_size)*2, sMinChannelWidth.get() * scaling); bool has_text = sTextVisible.get(); + bool has_header = sHeaderVisible.get(); - ws::text_parameters_t tp; + ws::text_parameters_t tp_text, tp_header; ws::font_parameters_t fp; + LSPString text; + if (has_text) { - LSPString text; sEstText.format(&text); sFont.get_parameters(pDisplay, fscaling, &fp); - sFont.get_text_parameters(pDisplay, &tp, fscaling, &text); - tp.Height = lsp_max(tp.Height, fp.Height); + sFont.get_text_parameters(pDisplay, &tp_text, fscaling, &text); + tp_text.Height = lsp_max(tp_text.Height, fp.Height); + } + + if (has_header) + { + sEstHeader.format(&text); + sFont.get_parameters(pDisplay, fscaling, &fp); + sFont.get_text_parameters(pDisplay, &tp_header, fscaling, &text); + tp_header.Height = lsp_max(tp_header.Height, fp.Height); } if (angle & 1) @@ -208,11 +229,23 @@ namespace lsp // Estimate place for text if (has_text) { - r->nMinHeight += border + tp.Height; - r->nMinWidth = lsp_max(r->nMinWidth, tp.Width); + r->nMinHeight += border + tp_text.Height; + r->nMinWidth = lsp_max(r->nMinWidth, tp_text.Width); + if ((pack) && (list.size() >= 2)) + { + r->nMinHeight += tp_text.Height; + r->nMinWidth = lsp_max(r->nMinWidth, seg_size * 2); + } + } + + // Estimate place for header + if (has_header) + { + r->nMinHeight += border + tp_header.Height; + r->nMinWidth = lsp_max(r->nMinWidth, tp_header.Width); if ((pack) && (list.size() >= 2)) { - r->nMinHeight += tp.Height; + r->nMinHeight += tp_header.Height; r->nMinWidth = lsp_max(r->nMinWidth, seg_size * 2); } } @@ -239,12 +272,25 @@ namespace lsp // Estimate place for text if (has_text) { - r->nMinWidth += border + tp.Width; - r->nMinHeight = lsp_max(r->nMinHeight, tp.Height); + r->nMinWidth += border + tp_text.Width; + r->nMinHeight = lsp_max(r->nMinHeight, tp_text.Height); if ((pack) && (list.size() >= 2)) { - r->nMinHeight = lsp_max(r->nMinHeight, tp.Height * 2); + r->nMinHeight = lsp_max(r->nMinHeight, tp_text.Height * 2); + r->nMinHeight = lsp_max(r->nMinHeight, seg_size * 2); + } + } + + // Estimate place for header + if (has_header) + { + r->nMinWidth += border + tp_header.Width; + r->nMinHeight = lsp_max(r->nMinHeight, tp_header.Height); + + if ((pack) && (list.size() >= 2)) + { + r->nMinHeight = lsp_max(r->nMinHeight, tp_header.Height * 2); r->nMinHeight = lsp_max(r->nMinHeight, seg_size * 2); } } @@ -285,11 +331,12 @@ namespace lsp ssize_t border = (sBorder.get() > 0) ? lsp_max(1.0f, sBorder.get() * scaling) : 0; ssize_t angle = sAngle.get(); bool has_text = sTextVisible.get(); + bool has_header = sHeaderVisible.get(); bool pack = (sSGroups.get()) && (list.size() >= 2); - ws::text_parameters_t tp; + ws::text_parameters_t tp_text, tp_header; ws::font_parameters_t fp; - ws::rectangle_t xr, xtext; + ws::rectangle_t xr, xtext, xheader; sAAll.nLeft = 0; sAAll.nTop = 0; @@ -306,33 +353,62 @@ namespace lsp xtext.nWidth = 0; xtext.nHeight = 0; + xheader.nLeft = 0; + xheader.nTop = 0; + xheader.nWidth = 0; + xheader.nHeight = 0; + // Compute the amount of space used for text ssize_t led_size = (angle & 1) ? xr.nHeight : xr.nWidth; + LSPString text; if (has_text) { - LSPString text; sEstText.format(&text); sFont.get_parameters(pDisplay, fscaling, &fp); - sFont.get_text_parameters(pDisplay, &tp, fscaling, &text); - tp.Height = lsp_max(tp.Height, fp.Height); + sFont.get_text_parameters(pDisplay, &tp_text, fscaling, &text); + tp_text.Height = lsp_max(tp_text.Height, fp.Height); if (angle & 1) // Vertical { - xtext.nHeight = tp.Height; + xtext.nHeight = tp_text.Height; if ((pack) && (list.size() >= 2)) - xtext.nHeight += tp.Height; + xtext.nHeight += tp_text.Height; led_size -= (border + xtext.nHeight); } else // Horizontal { - xtext.nWidth = tp.Width; + xtext.nWidth = tp_text.Width; led_size -= (border + xtext.nWidth); } } else - tp.Height = 0; + tp_text.Height = 0; + + if (has_header) + { + sEstHeader.format(&text); + sFont.get_parameters(pDisplay, fscaling, &fp); + sFont.get_text_parameters(pDisplay, &tp_header, fscaling, &text); + tp_header.Height = lsp_max(tp_header.Height, fp.Height); + + if (angle & 1) // Vertical + { + xheader.nHeight = tp_header.Height; + if ((pack) && (list.size() >= 2)) + xheader.nHeight += tp_header.Height; + + led_size -= (border + xheader.nHeight); + } + else // Horizontal + { + xheader.nWidth = tp_header.Width; + led_size -= (border + xheader.nWidth); + } + } + else + tp_header.Height = 0; // Compute overall areas ssize_t segments = led_size / seg_size; @@ -354,14 +430,20 @@ namespace lsp sAAll.nWidth -= hgap; sAAll.nHeight -= vgap; - xr.nLeft = sAAll.nLeft + border; - xr.nTop = sAAll.nTop + border; + xheader.nLeft = sAAll.nLeft + border; + xheader.nTop = sAAll.nTop + border; + xheader.nWidth = (pack) ? hsegsize * 2 : hsegsize; + + xr.nLeft = xheader.nLeft; + xr.nTop = xheader.nTop; xr.nWidth = hsegsize; - xr.nHeight = sAAll.nTop + sAAll.nHeight - xr.nTop - border - ((has_text) ? xtext.nHeight + border : 0); + xr.nHeight = led_size; + if (has_header) + xr.nTop += xheader.nHeight + border; xtext.nTop = xr.nTop + xr.nHeight + border; xtext.nLeft = xr.nLeft; - xtext.nWidth = (pack) ? hsegsize * 2 : hsegsize; + xtext.nWidth = xheader.nWidth; break; } @@ -378,9 +460,15 @@ namespace lsp xtext.nWidth = (pack) ? hsegsize * 2 : hsegsize; xr.nLeft = xtext.nLeft; - xr.nTop = xtext.nTop + ((has_text) ? xtext.nHeight + border : 0); + xr.nTop = xtext.nTop; xr.nWidth = hsegsize; - xr.nHeight = sAAll.nTop + sAAll.nHeight - xr.nTop - border; + xr.nHeight = led_size; + if (has_text) + xr.nTop += xtext.nHeight + border; + + xheader.nLeft = xr.nLeft; + xheader.nTop = xr.nTop + xr.nHeight + border; + xheader.nWidth = xtext.nWidth; break; } @@ -392,10 +480,16 @@ namespace lsp sAAll.nWidth -= vgap; sAAll.nHeight -= hgap; - xr.nLeft = sAAll.nLeft + border; - xr.nTop = sAAll.nTop + border; - xr.nWidth = sAAll.nLeft + sAAll.nWidth - xr.nLeft - border - ((has_text) ? xtext.nWidth + border : 0); + xheader.nLeft = sAAll.nLeft + border; + xheader.nTop = sAAll.nTop + border; + xheader.nHeight = hsegsize; + + xr.nLeft = xheader.nLeft; + xr.nTop = xheader.nTop; + xr.nWidth = led_size; xr.nHeight = hsegsize; + if (has_header) + xr.nLeft += xheader.nWidth + border; xtext.nLeft = xr.nLeft + xr.nWidth + border; xtext.nTop = xr.nTop; @@ -416,10 +510,16 @@ namespace lsp xtext.nTop = sAAll.nTop + border; xtext.nHeight = hsegsize; - xr.nLeft = xtext.nLeft + ((has_text) ? xtext.nWidth + border : 0); + xr.nLeft = xtext.nLeft; xr.nTop = xtext.nTop; - xr.nWidth = sAAll.nLeft + sAAll.nWidth - xr.nLeft - border; + xr.nWidth = led_size; xr.nHeight = hsegsize; + if (has_text) + xr.nLeft += xtext.nWidth + border; + + xheader.nLeft = xr.nLeft + xr.nWidth + border; + xheader.nTop = xr.nTop; + xheader.nHeight = hsegsize; break; } @@ -435,21 +535,34 @@ namespace lsp LedMeterChannel *c = list.uget(i); if (i >= hlimit) - xr.nWidth = xtext.nWidth; - xtext.nHeight = tp.Height; + { + if (has_text) + xr.nWidth = lsp_max(xr.nWidth, xtext.nWidth); + if (has_header) + xr.nWidth = lsp_max(xr.nWidth, xheader.nWidth); + } + xtext.nHeight = tp_text.Height; + xheader.nHeight = tp_header.Height; // Update position of meter and text c->sAMeter = xr; c->sAText = xtext; + c->sAHeader = xheader; xr.nLeft += hsegsize; if (i & 1) { xtext.nLeft += hsegsize << 1; - xtext.nTop -= tp.Height; + xtext.nTop -= tp_text.Height; + + xheader.nLeft += hsegsize << 1; + xheader.nTop -= tp_header.Height; } else - xtext.nTop += tp.Height; + { + xtext.nTop += tp_text.Height; + xheader.nTop += tp_header.Height; + } } } else @@ -459,13 +572,16 @@ namespace lsp LedMeterChannel *c = list.uget(i); // Update position of meter and text - xtext.nHeight = tp.Height; + xtext.nHeight = tp_text.Height; + xheader.nHeight = tp_header.Height; c->sAMeter = xr; c->sAText = xtext; + c->sAHeader = xheader; xr.nLeft += hsegsize; xtext.nLeft += hsegsize; + xheader.nLeft += hsegsize; } } } @@ -477,15 +593,21 @@ namespace lsp if (i >= hlimit) { xtext.nHeight = hsegsize << 1; - xr.nHeight = xtext.nHeight; + xheader.nHeight = hsegsize << 1; + if (has_text) + xr.nHeight = lsp_max(xr.nHeight, xtext.nHeight); + if (has_header) + xr.nHeight = lsp_max(xr.nHeight, xheader.nHeight); } // Update position of meter and text c->sAMeter = xr; c->sAText = xtext; + c->sAHeader = xheader; xr.nTop += hsegsize; xtext.nTop += hsegsize; + xheader.nTop += hsegsize; } } @@ -499,6 +621,7 @@ namespace lsp float fscaling = lsp_max(0.0f, scaling * sFontScaling.get()); float bright = sBrightness.get(); bool has_text = sTextVisible.get(); + bool has_header = sHeaderVisible.get(); ssize_t angle = sAngle.get(); lsp::Color col; @@ -516,6 +639,8 @@ namespace lsp c->draw_meter(s, angle, scaling, mbright); if (has_text) c->draw_label(s, &sFont, fscaling, mbright); + if (has_header) + c->draw_header(s, &sFont, fscaling, mbright); // Commit pending redraw request c->commit_redraw(); @@ -556,7 +681,8 @@ namespace lsp // Update coordinates x -= sSize.nLeft; y -= sSize.nTop; - bool has_text = sTextVisible.get(); + bool has_text = sTextVisible.get(); + bool has_header = sHeaderVisible.get(); // Find widget for (size_t i=0, n=vVisible.size(); isAText, x, y))) return c; + if ((has_header) && (Position::inside(&c->sAHeader, x, y))) + return c; } return NULL; diff --git a/src/test/mtest/widgets/specific/ledmeter.cpp b/src/test/mtest/widgets/specific/ledmeter.cpp index de7b4d1d..889b6e79 100644 --- a/src/test/mtest/widgets/specific/ledmeter.cpp +++ b/src/test/mtest/widgets/specific/ledmeter.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2020 Linux Studio Plugins Project - * (C) 2020 Vladimir Sadovnikov + * Copyright (C) 2024 Linux Studio Plugins Project + * (C) 2024 Vladimir Sadovnikov * * This file is part of lsp-tk-lib * Created on: 27 сент. 2020 г. @@ -249,7 +249,7 @@ MTEST_BEGIN("tk.widgets.specific", ledmeter) void add_channels(tk::LedMeter *lm, size_t &vid, lltl::parray &vh, lltl::parray &widgets) { tk::LedMeterChannel *lc = NULL; - LSPString id; + LSPString id, ch_id; static const float hue[] = { 0.0f, 0.5f, 0.25f, 0.75f, 0.0f}; @@ -261,12 +261,17 @@ MTEST_BEGIN("tk.widgets.specific", ledmeter) MTEST_ASSERT(widgets.push(lc)); MTEST_ASSERT(lm->add(lc) == STATUS_OK); + ch_id.fmt_ascii("ch%d", int(i)); + lc->text_visible()->set(true); lc->peak_visible()->set(true); + lc->header_visible()->set(true); lc->value()->set_all(-1.2f, -7.2f, 2.4f); lc->peak()->set(0.0f); lc->angle()->set(1 + i*2); + lc->header_value()->set(0.0f); lc->constraints()->set_min_height(128); + lc->header()->set_raw(&ch_id); lsp::Color c; tk::ColorRange *cr; @@ -410,6 +415,7 @@ MTEST_BEGIN("tk.widgets.specific", ledmeter) MTEST_ASSERT(grid->add(lm, 1, 2) == STATUS_OK); lm->text_visible()->set(true); + lm->header_visible()->set(true); lm->angle()->set(i*2); add_channels(lm, vid, vh, widgets); } @@ -424,6 +430,7 @@ MTEST_BEGIN("tk.widgets.specific", ledmeter) MTEST_ASSERT(grid->add(lm, 1, 2) == STATUS_OK); lm->text_visible()->set(true); + lm->header_visible()->set(true); lm->stereo_groups()->set(false); lm->angle()->set(i*2); lm->constraints()->set_width(5*12 + lm->border()->get()); @@ -440,6 +447,7 @@ MTEST_BEGIN("tk.widgets.specific", ledmeter) MTEST_ASSERT(grid->add(lm) == STATUS_OK); lm->text_visible()->set(true); + lm->header_visible()->set(true); lm->angle()->set(i*2 + 1); add_channels(lm, vid, vh, widgets); } @@ -454,6 +462,7 @@ MTEST_BEGIN("tk.widgets.specific", ledmeter) MTEST_ASSERT(grid->add(lm) == STATUS_OK); lm->text_visible()->set(true); + lm->header_visible()->set(true); lm->stereo_groups()->set(false); lm->angle()->set(i*2 + 1); add_channels(lm, vid, vh, widgets);