A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2014 by Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "regdisplaypanel.h"
22#include <QHeaderView>
23#include <QDebug>
24#include <QStandardItemModel>
25
26/**
27 * SocDisplayPanel
28 */
29SocDisplayPanel::SocDisplayPanel(QWidget *parent, IoBackend *io_backend,
30 const soc_desc::soc_ref_t& ref)
31 :QGroupBox(parent), m_soc(ref)
32{
33 Q_UNUSED(io_backend)
34 QVBoxLayout *right_layout = new QVBoxLayout;
35
36 m_name = new QLabel(this);
37 m_name->setTextFormat(Qt::RichText);
38 m_name->setText("<h1>" + QString::fromStdString(m_soc.get()->name) + "</h1>");
39
40 m_desc = new QLabel(this);
41 m_name->setTextFormat(Qt::RichText);
42 m_desc->setText(QString::fromStdString(m_soc.get()->desc));
43 m_desc->setVisible(m_desc->text().size() != 0);
44
45 right_layout->addWidget(m_name, 0);
46 right_layout->addWidget(m_desc, 0);
47 right_layout->addStretch(1);
48
49 setTitle("");
50 setLayout(right_layout);
51}
52
53void SocDisplayPanel::AllowWrite(bool en)
54{
55 Q_UNUSED(en);
56}
57
58QWidget *SocDisplayPanel::GetWidget()
59{
60 return this;
61}
62
63/**
64 * NodeDisplayPanel
65 */
66NodeDisplayPanel::NodeDisplayPanel(QWidget *parent, IoBackend *io_backend,
67 const soc_desc::node_inst_t& ref)
68 :QGroupBox(parent), m_node(ref)
69{
70 BackendHelper helper(io_backend, ref.soc());
71 QVBoxLayout *right_layout = new QVBoxLayout;
72
73 QString dev_name = helper.GetPath(ref);
74
75 QLabel *label_names = new QLabel("<b>" + dev_name + "</b>");
76 label_names->setTextFormat(Qt::RichText);
77
78 QLabel *label_addr = new QLabel("<b>" + QString().sprintf("0x%03x", ref.addr()) + "</b>");
79 label_addr->setTextFormat(Qt::RichText);
80
81 QHBoxLayout *top_layout = new QHBoxLayout;
82 top_layout->addStretch();
83 top_layout->addWidget(label_names);
84 top_layout->addWidget(label_addr);
85 top_layout->addStretch();
86
87 m_name = new QLabel(this);
88 m_name->setTextFormat(Qt::RichText);
89 /* if instance has a title, it overrides node title.*/
90 std::string title = ref.get()->title;
91 if(title.empty())
92 title = ref.node().get()->title;
93 m_name->setText("<h1>" + QString::fromStdString(title) + "</h1>");
94
95 /* put description from the node and from the instance */
96 m_node_desc = new QLabel(this);
97 m_node_desc->setTextFormat(Qt::RichText);
98 m_node_desc->setText(QString::fromStdString(ref.node().get()->desc));
99 m_node_desc->setVisible(m_node_desc->text().size() != 0);
100 m_inst_desc = new QLabel(this);
101 m_inst_desc->setTextFormat(Qt::RichText);
102 m_inst_desc->setText(QString::fromStdString(ref.get()->desc));
103 m_inst_desc->setVisible(m_inst_desc->text().size() != 0);
104
105 right_layout->addWidget(m_name, 0);
106 right_layout->addLayout(top_layout, 0);
107 right_layout->addWidget(m_node_desc, 0);
108 right_layout->addWidget(m_inst_desc, 0);
109 right_layout->addStretch(1);
110
111 setTitle("");
112 setLayout(right_layout);
113}
114
115void NodeDisplayPanel::AllowWrite(bool en)
116{
117 Q_UNUSED(en);
118}
119
120QWidget *NodeDisplayPanel::GetWidget()
121{
122 return this;
123}
124
125/**
126 * RegDisplayPanel
127 */
128
129namespace
130{
131 QString access_string(soc_desc::access_t acc, QString dflt = "")
132 {
133 switch(acc)
134 {
135 case soc_desc::UNSPECIFIED: return dflt;
136 case soc_desc::READ_ONLY: return "Read only";
137 case soc_desc::READ_WRITE: return "Read-write";
138 case soc_desc::WRITE_ONLY: return "Write-only";
139 default: return "";
140 }
141 }
142}
143
144RegDisplayPanel::RegDisplayPanel(QWidget *parent, IoBackend *io_backend,
145 const soc_desc::node_inst_t& ref)
146 :QGroupBox(parent), m_io_backend(io_backend), m_node(ref), m_reg_font(font())
147{
148 bool read_only = m_io_backend->IsReadOnly();
149 BackendHelper helper(m_io_backend, ref.soc());
150
151 QVBoxLayout *right_layout = new QVBoxLayout;
152
153 m_reg_font.setWeight(100);
154 m_reg_font.setKerning(false);
155
156 QString reg_name = helper.GetPath(ref);
157 QStringList names, access;
158 QVector< soc_addr_t > addresses;
159 names.append(reg_name);
160 addresses.append(ref.addr());
161 access.append(access_string(ref.node().reg().get()->access));
162
163 std::vector< soc_desc::variant_ref_t > variants = ref.node().reg().variants();
164 for(size_t i = 0; i < variants.size(); i++)
165 {
166 names.append(reg_name + "/" + QString::fromStdString(variants[i].get()->type));
167 addresses.append(ref.addr() + variants[i].get()->offset);
168 access.append(access_string(ref.node().reg().get()->access, access[0]));
169 }
170
171 QString str;
172 str += "<table align=left>";
173 for(int i = 0; i < names.size(); i++)
174 str += "<tr><td><b>" + names[i] + "</b></td></tr>";
175 str += "</table>";
176 QLabel *label_names = new QLabel;
177 label_names->setTextFormat(Qt::RichText);
178 label_names->setText(str);
179
180 QString str_addr;
181 str_addr += "<table align=left>";
182 for(int i = 0; i < names.size(); i++)
183 str_addr += "<tr><td><b>" + QString().sprintf("0x%03x", addresses[i]) + "</b></td></tr>";
184 str_addr += "</table>";
185 QLabel *label_addr = new QLabel;
186 label_addr->setTextFormat(Qt::RichText);
187 label_addr->setText(str_addr);
188
189 QString str_acc;
190 str_acc += "<table align=left>";
191 for(int i = 0; i < names.size(); i++)
192 str_acc += "<tr><td><b>" + access[i] + "</b></td></tr>";
193 str_acc += "</table>";
194 QLabel *label_access = new QLabel;
195 label_access->setTextFormat(Qt::RichText);
196 label_access->setText(str_acc);
197
198 QHBoxLayout *top_layout = new QHBoxLayout;
199 top_layout->addStretch();
200 top_layout->addWidget(label_names);
201 top_layout->addWidget(label_addr);
202 top_layout->addWidget(label_access);
203 top_layout->addStretch();
204
205 m_raw_val_name = new QLabel;
206 m_raw_val_name->setText("Raw value:");
207 m_raw_val_edit = new RegLineEdit;
208 m_raw_val_edit->SetReadOnly(read_only);
209 m_raw_val_edit->GetLineEdit()->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
210 m_raw_val_edit->GetLineEdit()->setValidator(new SocFieldValidator(m_raw_val_edit));
211 //m_raw_val_edit->EnableSCT(!!(reg.flags & REG_HAS_SCT));
212 m_raw_val_edit->GetLineEdit()->setFont(m_reg_font);
213 QHBoxLayout *raw_val_layout = new QHBoxLayout;
214 raw_val_layout->addStretch();
215 raw_val_layout->addWidget(m_raw_val_name);
216 raw_val_layout->addWidget(m_raw_val_edit);
217 raw_val_layout->addStretch();
218
219 m_value_table = new GrowingTableView();
220 m_value_model = new RegFieldTableModel(m_value_table); // view takes ownership
221 m_value_model->SetRegister(*m_node.node().reg().get());
222 m_value_model->SetReadOnly(read_only);
223 RegFieldProxyModel *proxy_model = new RegFieldProxyModel(this);
224 proxy_model->setSourceModel(m_value_model);
225 m_value_table->setModel(proxy_model);
226 m_value_table->setSortingEnabled(true);
227 m_value_table->sortByColumn(0, Qt::DescendingOrder);
228 m_value_table->verticalHeader()->setVisible(false);
229 m_value_table->resizeColumnsToContents();
230 m_value_table->horizontalHeader()->setStretchLastSection(true);
231 m_value_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
232 // FIXME we cannot use setAlternatingRowColors() because we override the
233 // background color, should it be part of the model ?
234
235 m_table_delegate = new SocFieldCachedItemDelegate(this);
236 m_table_edit_factory = new QItemEditorFactory();
237 SocFieldCachedEditorCreator *m_table_edit_creator = new SocFieldCachedEditorCreator();
238 // FIXME see QTBUG-30392
239 m_table_edit_factory->registerEditor((QVariant::Type)qMetaTypeId< SocFieldCachedValue >(),
240 m_table_edit_creator);
241 m_table_delegate->setItemEditorFactory(m_table_edit_factory);
242 m_value_table->setItemDelegate(m_table_delegate);
243
244 m_sexy_display2 = new Unscroll<YRegDisplay>(this);
245 m_sexy_display2->setFont(m_reg_font);
246 m_sexy_display2->setModel(m_value_model);
247 m_sexy_display2->setWidth(m_node.node().reg().get()->width);
248 m_sexy_display2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
249
250 m_name = new QLabel(this);
251 m_name->setTextFormat(Qt::RichText);
252 m_name->setText("<h1>" + QString::fromStdString(ref.node().get()->title) + "</h1>");
253
254 /* put description from the node, from the instance and register */
255 m_node_desc = new QLabel(this);
256 m_node_desc->setTextFormat(Qt::RichText);
257 m_node_desc->setText(QString::fromStdString(ref.node().get()->desc));
258 m_node_desc->setVisible(m_node_desc->text().size() != 0);
259 m_inst_desc = new QLabel(this);
260 m_inst_desc->setTextFormat(Qt::RichText);
261 m_inst_desc->setText(QString::fromStdString(ref.get()->desc));
262 m_inst_desc->setVisible(m_inst_desc->text().size() != 0);
263 m_desc = new QLabel(this);
264 m_desc->setTextFormat(Qt::RichText);
265 m_desc->setText(QString::fromStdString(m_node.node().reg().get()->desc));
266 m_desc->setVisible(m_desc->text().size() != 0);
267
268 right_layout->addWidget(m_name);
269 right_layout->addWidget(m_desc);
270 right_layout->addLayout(top_layout);
271 right_layout->addWidget(m_node_desc);
272 right_layout->addWidget(m_inst_desc);
273 right_layout->addWidget(m_desc);
274 if(raw_val_layout)
275 right_layout->addLayout(raw_val_layout);
276 right_layout->addWidget(m_sexy_display2);
277 right_layout->addWidget(m_value_table);
278 right_layout->addStretch();
279
280 setTitle("");
281 m_viewport = new QWidget;
282 m_viewport->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
283 m_viewport->setLayout(right_layout);
284 m_scroll = new QScrollArea;
285 m_scroll->setWidget(m_viewport);
286 m_scroll->setWidgetResizable(true);
287 m_scroll->setFrameShape(QFrame::NoFrame);
288 QHBoxLayout *layout = new QHBoxLayout;
289 layout->addWidget(m_scroll, 1);
290 setLayout(layout);
291 AllowWrite(false);
292
293 // load data
294 Reload();
295
296 connect(m_raw_val_edit->GetLineEdit(), SIGNAL(returnPressed()), this,
297 SLOT(OnRawRegValueReturnPressed()));
298 connect(m_value_model, SIGNAL(OnValueModified(int)), this,
299 SLOT(OnRegValueChanged(int)));
300 connect(m_sexy_display2, SIGNAL(clicked(const QModelIndex&)), this,
301 SLOT(OnRegFieldActivated(const QModelIndex&)));
302}
303
304RegDisplayPanel::~RegDisplayPanel()
305{
306 delete m_table_edit_factory;
307}
308
309void RegDisplayPanel::Reload()
310{
311 soc_word_t value;
312 BackendHelper helper(m_io_backend, m_node.soc());
313 bool has_value = helper.ReadRegister(m_node, value);
314
315 if(has_value)
316 {
317 m_raw_val_name->show();
318 m_raw_val_edit->show();
319 m_raw_val_edit->GetLineEdit()->setText(QString().sprintf("0x%08x", value));
320 m_value_model->SetValues(QVector< QVariant >(1, QVariant(value)));
321 }
322 else
323 {
324 m_raw_val_name->hide();
325 m_raw_val_edit->hide();
326 m_value_model->SetValues(QVector< QVariant >());
327 }
328
329 m_value_table->resizeColumnsToContents();
330 m_value_table->horizontalHeader()->setStretchLastSection(true);
331}
332
333void RegDisplayPanel::AllowWrite(bool en)
334{
335 m_allow_write = en;
336 if(m_raw_val_edit)
337 {
338 m_raw_val_edit->SetReadOnly(m_io_backend->IsReadOnly() || !m_allow_write);
339 m_value_model->SetReadOnly(m_io_backend->IsReadOnly() || !m_allow_write);
340 }
341}
342
343IoBackend::WriteMode RegDisplayPanel::EditModeToWriteMode(RegLineEdit::EditMode mode)
344{
345 switch(mode)
346 {
347 case RegLineEdit::Write: return IoBackend::Write;
348 case RegLineEdit::Set: return IoBackend::Set;
349 case RegLineEdit::Clear: return IoBackend::Clear;
350 case RegLineEdit::Toggle: return IoBackend::Toggle;
351 default: return IoBackend::Write;
352 }
353}
354
355void RegDisplayPanel::OnRawRegValueReturnPressed()
356{
357 soc_word_t val;
358 QLineEdit *edit = m_raw_val_edit->GetLineEdit();
359 const SocFieldValidator *validator = dynamic_cast< const SocFieldValidator *>(edit->validator());
360 QValidator::State state = validator->parse(edit->text(), val);
361 if(state != QValidator::Acceptable)
362 return;
363 IoBackend::WriteMode mode = EditModeToWriteMode(m_raw_val_edit->GetMode());
364 BackendHelper helper(m_io_backend, m_node.soc());
365 helper.WriteRegister(m_node, val, mode);
366 // register write can change all fields
367 Reload();
368}
369
370void RegDisplayPanel::OnRegValueChanged(int index)
371{
372 QVariant var = m_value_model->GetValue(index);
373 if(!var.isValid())
374 return;
375 BackendHelper helper(m_io_backend, m_node.soc());
376 helper.WriteRegister(m_node, var.value< soc_word_t >(), IoBackend::Write);
377 // register write can change all fields
378 Reload();
379}
380
381void RegDisplayPanel::OnRegFieldActivated(const QModelIndex& index)
382{
383 Q_UNUSED(index);
384}
385
386QWidget *RegDisplayPanel::GetWidget()
387{
388 return this;
389}
390