/*
* Oak Video Editor - Non-Linear Video Editor
* Copyright (C) 2025 Olive CE Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "nodevaluetree.h"
#include
#include "oakengine/traverse.h"
#include "oakengine/node.h"
namespace olive
{
/**
* @brief Local mirror of the engine's value-hint triple (type, index, tag)
* carried in the radio buttons' "hint" property.
*/
struct ValueHint {
int type = 0;
int index = -1;
QString tag;
};
}
Q_DECLARE_METATYPE(olive::ValueHint)
namespace olive
{
#define super QTreeWidget
NodeValueTree::NodeValueTree(QWidget *parent)
: super(parent)
{
setColumnWidth(0, 0);
setColumnCount(4);
QSizePolicy p = sizePolicy();
p.setHorizontalStretch(1);
setSizePolicy(p);
static const int k_minimum_rows = 10;
setMinimumHeight(fontMetrics().height() * k_minimum_rows);
retranslate();
}
void NodeValueTree::set_node(const oak::Input &input, const Rational &time)
{
clear();
oak::Node connected_node = input.connected_node();
// WRAPPER-GAP: oakengine_traverse_* (traverse API has no oak:: wrapper)
OakEngineTraverseDb *table_db = oakengine_traverse_generate_table(
connected_node.handle(),
time.numerator(), time.denominator(), time.numerator(),
time.denominator());
int db_index = 0;
int row_count = oakengine_traverse_db_row_count(table_db, db_index);
// WRAPPER-GAP: oakengine_traverse_table_element_index_for_hint
int index = oakengine_traverse_table_element_index_for_hint(
input.node_handle(),
input.input_id().toUtf8().constData(), input.element(), table_db);
for (int i = 0; i < row_count; i++) {
QTreeWidgetItem *item = new QTreeWidgetItem(this);
int type = oakengine_traverse_row_type(table_db, db_index, i);
OakEngineNode *source = oakengine_traverse_row_source(table_db, db_index,
i);
const char *tag = oakengine_traverse_row_tag(table_db, db_index, i);
ValueHint hint;
hint.type = type;
hint.index = row_count - 1 - i;
hint.tag = QString(tag);
QRadioButton *radio = new QRadioButton(this);
radio->setProperty("input", QVariant::fromValue(input));
radio->setProperty("hint", QVariant::fromValue(hint));
if (i == index) {
radio->setChecked(true);
}
connect(radio, &QRadioButton::clicked, this,
&NodeValueTree::radio_button_checked);
setItemWidget(item, 0, radio);
char name_buf[64];
int len = oakengine_node_value_pretty_type_name(type, name_buf, sizeof(name_buf));
if (len > 0 && len < static_cast(sizeof(name_buf))) {
name_buf[len] = '\0';
} else {
snprintf(name_buf, sizeof(name_buf), "Type %d", type);
}
item->setText(1, QString::fromUtf8(name_buf));
const char *vs = oakengine_traverse_row_value_string(table_db, db_index, i);
item->setText(2, vs ? QString(vs) : QString());
if (source) {
item->setText(3, oak::Node(source).label_and_name());
} else {
item->setText(3, QString());
}
}
oakengine_traverse_db_free(table_db);
}
void NodeValueTree::changeEvent(QEvent *event)
{
if (event->type() == QEvent::LanguageChange) {
retranslate();
}
super::changeEvent(event);
}
void NodeValueTree::retranslate()
{
setHeaderLabels({ QString(), tr("Type"), tr("Value"), tr("Source") });
}
void NodeValueTree::radio_button_checked(bool e)
{
if (e) {
QRadioButton *btn = static_cast(sender());
ValueHint hint = btn->property("hint").value();
oak::Input input = btn->property("input").value();
// WRAPPER-GAP: oakengine_node_set_value_hint
oakengine_node_set_value_hint(
input.node_handle(),
input.input_id().toUtf8().constData(), input.element(),
hint.type, hint.index,
hint.tag.isEmpty() ? nullptr : hint.tag.toUtf8().constData());
}
}
}