52 halp_meta(name,
"Value display")
53 halp_meta(c_name,
"Display")
54 halp_meta(category,
"Monitoring")
55 halp_meta(author,
"ossia score")
56 halp_meta(manual_url,
"")
57 halp_meta(description,
"Visualize an input value")
58 halp_meta(uuid,
"3f4a41f2-fa39-420f-ab0f-0af6b8409edb")
59 halp_flag(fully_custom_item);
61 static constexpr int max_log = 100;
70 static std::optional<unsigned char> byteValue(
float value)
noexcept
72 if(value >= 0.f && value <= 255.f && std::trunc(value) == value)
73 return static_cast<unsigned char>(value);
77 static std::optional<unsigned char> byteValue(
const ossia::value& value)
noexcept
79 if(
auto* number = value.target<
int>())
81 if(*number >= 0 && *number <= 255)
82 return static_cast<unsigned char>(*number);
84 else if(
auto* number = value.target<
float>())
85 return byteValue(*number);
86 else if(
auto*
boolean = value.target<
bool>())
87 return static_cast<unsigned char>(*boolean);
91 static void printHexValue(std::string& out,
const ossia::value& value)
96 constexpr char digits[] =
"0123456789abcdef";
97 const auto start = out.size();
98 std::size_t count = 0;
99 auto append = [&](
unsigned char byte) {
101 out.push_back(count % 16 == 0 ?
'\n' :
' ');
102 out.push_back(digits[
byte >> 4]);
103 out.push_back(digits[
byte & 0x0f]);
106 auto appendNumbers = [&](
const auto& numbers) {
107 for(
const auto& number : numbers)
109 auto byte = byteValue(number);
118 if(
auto* bytes = value.target<std::string>())
120 for(
unsigned char byte : *bytes)
123 else if(
auto* numbers = value.target<std::vector<ossia::value>>())
124 valid = appendNumbers(*numbers);
125 else if(
auto* numbers = value.target<ossia::vec2f>())
126 valid = appendNumbers(*numbers);
127 else if(
auto* numbers = value.target<ossia::vec3f>())
128 valid = appendNumbers(*numbers);
129 else if(
auto* numbers = value.target<ossia::vec4f>())
130 valid = appendNumbers(*numbers);
131 else if(
auto byte = byteValue(value))
141 out +=
"[not byte data] ";
155 struct :
raw_port<
"Input", ossia::value_port>
157 halp_meta(description,
"Values to display, including every event in a tick.")
160 struct : halp::spinbox_i32<
"Log", halp::range{1, max_log, 1}>
162 halp_meta(description,
"Number of recent values to retain, newest first.")
165 struct : halp::combobox_t<
"Format", Format>
169 "Ordinary text, indented Pretty text, or Hex bytes. Hex shows raw "
170 "string bytes, including UTF-8 bytes, NUL and high-bit bytes. Numbers "
171 "must be exact integers from 0 to 255; booleans are 00 or 01. Flat "
172 "numeric lists and vectors use one byte per element. Empty strings "
173 "and lists show [empty]. Other values show [not byte data] followed "
174 "by ordinary text; no wrapping, truncation or memory reinterpretation.")
177 std::string_view values[3]{
"Ordinary",
"Pretty",
"Hex"};
178 Format init{Format::Ordinary};
186 struct : halp::val_port<
"values", std::optional<ossia::value>>
188 halp_meta(description,
"Recent values and their sequence number for the display.")
199 boost::container::devector<ossia::value> m_ring;
202 void prepare(halp::setup)
noexcept
210 outputs.values.value.reset();
212 if(!inputs.port.value)
215 const auto& data = inputs.port.value->get_data();
221 const int keep = std::clamp(inputs.log.value, 1, max_log);
223 for(
const ossia::timed_value& tv : data)
225 m_ring.push_back(tv.value);
227 if(std::ssize(m_ring) > keep)
230 while(std::ssize(m_ring) > keep)
233 std::vector<ossia::value> payload;
234 payload.reserve(1 + m_ring.size());
235 payload.push_back(
int(m_next_seq - std::ssize(m_ring)));
236 for(
const auto& v : m_ring)
237 payload.push_back(v);
239 outputs.values.value = ossia::value{std::move(payload)};
245 boost::container::devector<ossia::value> values;
256 int logging()
const noexcept
258 return std::clamp(ossia::convert<int>(log_inlet->value()), 1, max_log);
261 Format format()
const noexcept
264 ?
static_cast<Format
>(ossia::convert<int>(format_inlet->value()))
271 const auto mode = format();
272 for(
const auto& line : this->values)
277 printHexValue(m_buf, line);
286 m_buf.push_back(
'\n');
288 txt_cache = QString::fromUtf8(m_buf.data(), m_buf.size());
294 QGraphicsItem* parent)
297 setAcceptedMouseButtons(Qt::NoButton);
302 auto& value_inlet = *process.inlets()[0];
303 if(
auto* fact = portFactory.
get(value_inlet.concreteKey()))
304 if(
auto* port = fact->makePortItem(value_inlet, doc,
this,
this))
308 if(process.inlets().size() > 2)
309 format_inlet = qobject_cast<Process::ControlInlet*>(process.inlets()[2]);
313 out, &Process::ControlOutlet::valueChanged,
this,
314 [
this](
const ossia::value& v) { on_values(v); });
317 log_inlet, &Process::ControlInlet::valueChanged,
this,
318 [
this](
const ossia::value& v) {
319 while(std::ssize(values) > logging())
326 format_inlet, &Process::ControlInlet::valueChanged,
this,
327 [
this](
const ossia::value&) { rebuildText(); });
330 void on_values(
const ossia::value& v)
332 auto* list = v.target<std::vector<ossia::value>>();
333 if(!list || list->size() < 2)
336 const int base = ossia::convert<int>((*list)[0]);
337 const int n = std::ssize(*list) - 1;
340 if(base + n < m_next_seq)
346 for(
int i = 0; i < n; i++)
348 const int seq = base + i;
351 values.push_front((*list)[i + 1]);
352 m_next_seq = seq + 1;
355 while(std::ssize(values) > logging())
368 void paint_impl(QPainter* p)
const override
370 if(txt_cache.isEmpty())
373 const auto& skin = score::Skin::instance();
374 p->setFont(skin.MonoFontSmall);
375 p->setRenderHint(QPainter::Antialiasing,
true);
376 p->setPen(skin.Light.main.pen1_solid_flat_miter);
377 p->drawText(boundingRect().adjusted(10, 0, 0, 0), txt_cache);
378 p->setRenderHint(QPainter::Antialiasing,
false);
384 using Process::EffectLayerPresenter::EffectLayerPresenter;
385 void fillContextMenu(
386 QMenu& menu, QPoint pos, QPointF scenepos,
389 auto cp = menu.addAction(tr(
"Copy value"));
390 connect(cp, &QAction::triggered,
this, [
this] {
391 auto& v = *
static_cast<Layer*
>(this->m_view);
392 qApp->clipboard()->setText(v.txt_cache);
FactoryType * get(const key_type &k) const noexcept
Get a particular factory from its ConcreteKey.
Definition InterfaceList.hpp:128
void printValue(std::string &out, const ossia::value &v)
Single-line rendering of v, identical to fmt::format("{}", v), appended to out.
Definition ValuePrettyPrint.cpp:153
void prettyPrintValue(std::string &out, const ossia::value &v, int depth, const PrettyPrintOptions &opts)
Appends a multi-line, indented rendering of v to out.
Definition ValuePrettyPrint.cpp:147
Definition ProcessContext.hpp:12
const T & interfaces() const
Access to a specific interface list.
Definition ApplicationContext.hpp:87