• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / score / 35899133125

23 Sep 2026 05:57PM UTC coverage: 41.488% (+1.2%) from 40.337%
35899133125

push

github

jcelerier
3rdparty: follow the merged libossia

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PWVTQ1pm3X2Uz7goFgULtC

123236 of 297041 relevant lines covered (41.49%)

113626.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.2
/src/plugins/score-lib-process/Process/Inspector/ProcessInspectorWidgetDelegateFactory.cpp
1
// This is an open source non-commercial project. Dear PVS-Studio, please check
2
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
#include "ProcessInspectorWidgetDelegateFactory.hpp"
4

5
#include <Process/Commands/Properties.hpp>
6
#include <Process/Dataflow/PortListWidget.hpp>
7
#include <Process/Process.hpp>
8
#include <Process/ProcessList.hpp>
9

10
#include <Effect/EffectLayer.hpp>
11
#include <Inspector/InspectorLayout.hpp>
12

13
#include <score/model/Skin.hpp>
14
#include <score/application/GUIApplicationContext.hpp>
15
#include <score/command/Dispatchers/CommandDispatcher.hpp>
16
#include <score/document/DocumentContext.hpp>
17
#include <score/tools/Bind.hpp>
18
#include <score/widgets/HelpInteraction.hpp>
19
#include <score/widgets/MarginLess.hpp>
20
#include <score/widgets/SetIcons.hpp>
21
#include <score/widgets/TextLabel.hpp>
22
#include <score/widgets/TimeSpinBox.hpp>
23

24
#include <QCheckBox>
25
#include <QFormLayout>
26
#include <QMenu>
27
#include <QScrollArea>
28
#include <QToolButton>
29
#include <QVBoxLayout>
30
#include <QWidget>
31
namespace Process
32
{
33
InspectorWidgetDelegateFactory::~InspectorWidgetDelegateFactory() = default;
20,437✔
34
void InspectorWidgetDelegateFactory::addButtons(
9✔
35
    const Process::ProcessModel&, const score::DocumentContext& doc, QBoxLayout* layout,
36
    QWidget* parent) const
37
{
38
}
9✔
39

40
bool InspectorWidgetDelegateFactory::matchesProcess(
×
41
    const ProcessModel& proc, const score::DocumentContext& doc, QWidget* parent) const
42
{
43
  return matchesProcess(proc);
×
44
}
45

46
QWidget* InspectorWidgetDelegateFactory::make(
10✔
47
    const InspectedObjects& objects, const score::DocumentContext& doc,
48
    QWidget* parent) const
49
{
50
  if(objects.empty())
10✔
51
    return nullptr;
×
52

53
  auto obj = objects.first();
10✔
54
  if(auto p = qobject_cast<const Process::ProcessModel*>(obj))
10✔
55
  {
56
    return makeProcess(*p, doc, parent);
10✔
57
  }
58
  return nullptr;
×
59
}
10✔
60

61
bool InspectorWidgetDelegateFactory::matches(const InspectedObjects& objects) const
66✔
62
{
63
  if(objects.empty())
66✔
64
    return false;
×
65

66
  auto obj = objects.first();
66✔
67
  if(auto p = qobject_cast<const Process::ProcessModel*>(obj))
66✔
68
  {
69
    return matchesProcess(*p);
59✔
70
  }
71
  return false;
7✔
72
}
66✔
73
namespace
74
{
75
class InspectorWidget : public QWidget
76
{
77
  QPointer<ProcessModel> m_proc;
78

79
public:
80
  QHBoxLayout* m_buttons{};
10✔
81
  InspectorWidget(
10✔
82
      ProcessModel& process, const score::DocumentContext& doc, QWidget* w,
83
      QWidget* parent)
84
      : QWidget{parent}
10✔
85
      , m_proc{&process}
10✔
86
  {
10✔
87
    setObjectName("Process::InspectorWidget");
10✔
88
    auto lay = new Inspector::VBoxLayout{this};
10✔
89

90
    const auto& process_factories = doc.app.interfaces<Process::ProcessFactoryList>();
10✔
91
    const auto fact = process_factories.get(process.concreteKey());
10✔
92

93
    const auto proc_name = process.prettyName();
10✔
94
    const auto type_name = fact->prettyName();
10✔
95
    const auto label_text
96
        = proc_name.contains(type_name)
20✔
97
              ? QStringLiteral("Process (%1)").arg(proc_name)
3✔
98
              : QStringLiteral("Process (%1: %2)").arg(type_name, proc_name);
7✔
99
    auto label = new TextLabel{label_text, this};
10✔
100
    score::onSkinChange(label, [label] {
37✔
101
      label->setFont(score::Skin::instance().SectionTitleFont);
27✔
102
    });
27✔
103
    lay->addWidget(label);
10✔
104

105
    QWidget* loop_w{};
10✔
106
    QFormLayout* loop_lay{};
10✔
107

108
    auto initButtonsLayout = [&] {
14✔
109
      m_buttons = new QHBoxLayout;
4✔
110
      m_buttons->setContentsMargins(0, 0, 0, 0);
4✔
111
      lay->addLayout(m_buttons);
4✔
112

113
      loop_w = new QWidget;
4✔
114
      loop_lay = new QFormLayout(loop_w);
4✔
115
      loop_lay->setContentsMargins(1, 1, 1, 1);
4✔
116
      loop_lay->setSpacing(2);
4✔
117
      lay->addWidget(loop_w);
4✔
118
    };
4✔
119

120
    if(!(process.flags() & ProcessFlags::TimeIndependent))
10✔
121
    {
122
      initButtonsLayout();
4✔
123

124
      // Loops
125
      {
126
        auto loop_btn = new QToolButton;
4✔
127
        loop_btn->setIcon(makeIcons(
8✔
128
            QStringLiteral(":/icons/loop_on.png"),
4✔
129
            QStringLiteral(":/icons/loop_hover.png"),
4✔
130
            QStringLiteral(":/icons/loop_off.png"),
4✔
131
            QStringLiteral(":/icons/loop_off.png")));
4✔
132
        score::setHelp(loop_btn, tr("Enable looping for this process"));
4✔
133
        loop_btn->setToolTip(tr("Loop"));
4✔
134

135
        loop_btn->setAutoRaise(true);
4✔
136
        score::setSkinIconSize(loop_btn, 28);
4✔
137
        loop_btn->setCheckable(true);
4✔
138
        loop_btn->setChecked(process.loops());
4✔
139
        connect(loop_btn, &QToolButton::toggled, this, [&](bool b) {
4✔
140
          if(b != process.loops())
×
141
            CommandDispatcher<>{doc.commandStack}.submit<SetLoop>(process, b);
×
142
        });
×
143
        con(process, &ProcessModel::loopsChanged, this, [loop_btn](bool b) {
4✔
144
          if(b != loop_btn->isChecked())
×
145
            loop_btn->setChecked(b);
×
146
        });
×
147
        m_buttons->addWidget(loop_btn);
4✔
148
      }
149

150
      // Start offset
151
      {
152
        auto so = new score::TimeSpinBox;
4✔
153
        so->setMinimumTime({});
4✔
154
        so->setTime(process.startOffset());
4✔
155
        connect(
4✔
156
            so, &score::TimeSpinBox::timeChanged, this, [&](const ossia::time_value& t) {
4✔
157
              if(t != process.startOffset())
×
158
                CommandDispatcher<>{doc.commandStack}.submit<SetStartOffset>(process, t);
×
159
            });
×
160
        con(process, &ProcessModel::startOffsetChanged, this, [so](TimeVal t) {
4✔
161
          if(t != so->time())
×
162
            so->setTime(t);
×
163
        });
×
164
        loop_lay->addRow(tr("Start offset"), so);
4✔
165
      }
166

167
      // Loop duration
168
      {
169
        auto so = new score::TimeSpinBox;
4✔
170
        so->setMinimumTime(TimeVal::fromMsecs(10));
4✔
171
        so->setTime(process.loopDuration());
4✔
172
        connect(
4✔
173
            so, &score::TimeSpinBox::timeChanged, this,
4✔
174
            [&](const ossia::time_value& t) {
4✔
175
          if(t != process.loopDuration())
×
176
            CommandDispatcher<>{doc.commandStack}.submit<SetLoopDuration>(process, t);
×
177
            });
×
178
        con(process, &ProcessModel::loopDurationChanged, this, [so](TimeVal t) {
4✔
179
          if(t != so->time())
×
180
            so->setTime(t);
×
181
        });
×
182
        loop_lay->addRow(tr("Loop duration"), so);
4✔
183
      }
184
    }
4✔
185

186
    auto& layer_factories = doc.app.interfaces<Process::LayerFactoryList>();
10✔
187

188
    if(auto fact = layer_factories.get(process.concreteKey()))
10✔
189
    {
190
      if(process.flags() & ProcessFlags::ScriptEditingSupported)
6✔
191
      {
192
        if(!loop_lay)
×
193
          initButtonsLayout();
×
194

195
        auto uiToggle = new QToolButton{};
×
196
        uiToggle->setIcon(makeIcons(
×
197
            QStringLiteral(":/icons/console_on.png"),
×
198
            QStringLiteral(":/icons/console_on.png"),
×
199
            QStringLiteral(":/icons/console_off.png"),
×
200
            QStringLiteral(":/icons/console_off.png")));
×
201
        score::setHelp(uiToggle, tr("Edit this plug-in script"));
×
202
        uiToggle->setToolTip(tr("Open script editor"));
×
203
        uiToggle->setAutoRaise(true);
×
204
        score::setSkinIconSize(uiToggle, 28);
×
205
        uiToggle->setCheckable(true);
×
206
        uiToggle->setChecked(bool(process.scriptUI));
×
207

208
        connect(
×
209
            uiToggle, &QToolButton::toggled, this, [&process, fact, &doc](bool state) {
×
210
          Process::setupScriptUI(process, *fact, doc, state);
×
211
        });
×
212
        connect(&process, &ProcessModel::scriptUIVisible, uiToggle, [=](bool v) {
×
213
          QSignalBlocker block{uiToggle};
×
214
          uiToggle->setChecked(v);
×
215
        });
×
216
        uiToggle->setContextMenuPolicy(Qt::CustomContextMenu);
×
217
        connect(
×
218
            uiToggle, &QWidget::customContextMenuRequested, uiToggle,
×
219
            [uiToggle, &process, &doc](QPoint pos) {
×
220
          QMenu menu;
×
221
          Process::fillPlacementMenu(
×
222
              menu, process, doc, Process::ProcessUIKind::ScriptEditor);
×
223
          menu.exec(uiToggle->mapToGlobal(pos));
×
224
        });
×
225

226
        m_buttons->addWidget(uiToggle);
×
227
      }
×
228

229
      if(fact->hasExternalUI(process, doc))
6✔
230
      {
231
        if(!loop_lay)
×
232
          initButtonsLayout();
×
233

234
        auto uiToggle = new QToolButton{};
×
235
        uiToggle->setIcon(makeIcons(
×
236
            QStringLiteral(":/icons/new_window_on.png"),
×
237
            QStringLiteral(":/icons/new_window_hover.png"),
×
238
            QStringLiteral(":/icons/new_window_off.png"),
×
239
            QStringLiteral(":/icons/new_window_off.png")));
×
240
        score::setHelp(uiToggle, tr("Show the custom user interface of this plug-in"));
×
241
        uiToggle->setToolTip(tr("Open plug-in"));
×
242
        uiToggle->setAutoRaise(true);
×
243
        score::setSkinIconSize(uiToggle, 28);
×
244
        uiToggle->setCheckable(true);
×
245
        uiToggle->setChecked(bool(process.externalUI));
×
246

247
        connect(
×
248
            uiToggle, &QToolButton::toggled, this, [&process, fact, &doc](bool state) {
×
249
          Process::setupExternalUI(process, *fact, doc, state);
×
250
        });
×
251
        connect(&process, &ProcessModel::externalUIVisible, uiToggle, [=](bool v) {
×
252
          QSignalBlocker block{uiToggle};
×
253
          uiToggle->setChecked(v);
×
254
        });
×
255
        uiToggle->setContextMenuPolicy(Qt::CustomContextMenu);
×
256
        connect(
×
257
            uiToggle, &QWidget::customContextMenuRequested, uiToggle,
×
258
            [uiToggle, &process, &doc](QPoint pos) {
×
259
          QMenu menu;
×
260
          Process::fillPlacementMenu(
×
261
              menu, process, doc, Process::ProcessUIKind::ExternalUI);
×
262
          menu.exec(uiToggle->mapToGlobal(pos));
×
263
        });
×
264

265
        m_buttons->addWidget(uiToggle);
×
266
      }
×
267
    }
6✔
268

269
    if(process.flags() & ProcessFlags::ExternalSourceRefreshable)
10✔
270
    {
271
      if(!loop_lay)
×
272
        initButtonsLayout();
×
273

274
      auto update = new QToolButton{};
×
275
      update->setIcon(makeIcons(
×
276
          QStringLiteral(":/icons/refresh_on.png"),
×
277
          QStringLiteral(":/icons/refresh_hover.png"),
×
278
          QStringLiteral(":/icons/refresh_off.png"),
×
279
          QStringLiteral(":/icons/refresh_disabled.png")));
×
280
      update->setText(tr("Update"));
×
281
      update->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
×
282
      score::setHelp(
×
283
          update, tr("Replace this process with the current version of the file it "
×
284
                     "was taken from"));
285
      update->setToolTip(tr("Update to the new version"));
×
286
      update->setAutoRaise(true);
×
287
      score::setSkinIconSize(update, 28);
×
288
      update->setVisible(process.externalSourceOutOfDate());
×
289
      connect(update, &QToolButton::clicked, this, [&process, &doc] {
×
290
        if(auto cmd = process.refreshFromExternalSource(doc))
×
291
          CommandDispatcher<>{doc.commandStack}.submit(cmd);
×
292
      });
×
293
      con(process, &ProcessModel::externalSourceOutOfDateChanged, this,
×
294
          [update](bool v) { update->setVisible(v); });
×
295

296
      m_buttons->addWidget(update);
×
297
    }
×
298

299
    if(process.flags() & ProcessFlags::CanCreateControls)
10✔
300
    {
301
      if(!loop_lay)
×
302
        initButtonsLayout();
×
303
      auto controlsToggle = new QToolButton{};
×
304
      controlsToggle->setIcon(makeIcons(
×
305
          QStringLiteral(":/icons/control_record_on.png"),
×
306
          QStringLiteral(":/icons/control_record_hover.png"),
×
307
          QStringLiteral(":/icons/control_record_off.png"),
×
308
          QStringLiteral(":/icons/control_record_off.png")));
×
309
      score::setHelp(
×
310
          controlsToggle, tr("Enable the controls changed in the plug-in ui to appear "
×
311
                             "in the main window"));
312
      controlsToggle->setToolTip(tr("Edit controls"));
×
313
      controlsToggle->setAutoRaise(true);
×
314
      score::setSkinIconSize(controlsToggle, 28);
×
315
      controlsToggle->setCheckable(true);
×
316
      controlsToggle->setChecked(false);
×
317
      connect(controlsToggle, &QToolButton::toggled, this, [&process](bool state) {
×
318
        auto& p = const_cast<Process::ProcessModel&>(process);
×
319
        p.setCreatingControls(state);
×
320
      });
×
321
      m_buttons->addWidget(controlsToggle);
×
322
    }
×
323

324
    // Custom widget
325
    // FIXME to be removed, eventually
326
    if(w)
10✔
327
      lay->addWidget(w);
7✔
328

329
    // List of ports
330
    auto scroll = new QScrollArea{};
10✔
331
    scroll->setObjectName("PortListWidgetScrollArea");
10✔
332
    scroll->setFrameShape(QFrame::NoFrame);
10✔
333
    QSizePolicy sz;
10✔
334
    sz.setHorizontalPolicy(QSizePolicy::MinimumExpanding);
10✔
335
    sz.setVerticalPolicy(QSizePolicy::MinimumExpanding);
10✔
336
    sz.setVerticalStretch(255);
10✔
337
    scroll->setSizePolicy(sz);
10✔
338
    scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
10✔
339
    scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
10✔
340
    scroll->setWidgetResizable(true);
10✔
341
    scroll->setWidget(new PortListWidget{process, doc, this});
10✔
342
    lay->addWidget(scroll);
10✔
343
  }
10✔
344

345
  ~InspectorWidget()
10✔
346
  {
10✔
347
    if(m_proc)
5✔
348
    {
349
      m_proc->setCreatingControls(false);
×
350
    }
×
351
  }
10✔
352
};
353
}
354

355
QWidget* InspectorWidgetDelegateFactory::wrap(
10✔
356
    ProcessModel& process, const score::DocumentContext& doc, QWidget* w,
357
    QWidget* parent) const
358
{
359
  auto widg = new InspectorWidget{process, doc, w, parent};
10✔
360
  addButtons(process, doc, widg->m_buttons, widg);
10✔
361
  if(widg->m_buttons)
10✔
362
    widg->m_buttons->addStretch(1);
4✔
363
  return widg;
10✔
364
}
×
365

366
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc