Krita Source Code Documentation
Loading...
Searching...
No Matches
recorderdocker_dock.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2019 Shi Yan <billconan@gmail.net>
3 * SPDX-FileCopyrightText: 2020 Dmitrii Utkin <loentar@gmail.com>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-only
6 */
7
9#include "recorder_config.h"
10#include "recorder_writer.h"
11#include "recorder_const.h"
12#include "ui_recorderdocker.h"
14#include "recorder_export.h"
17
18#include <klocalizedstring.h>
19#include <kis_action_registry.h>
20#include <kis_canvas2.h>
21#include <kis_icon_utils.h>
22#include <kis_statusbar.h>
23#include <KisDocument.h>
24#include <KisViewManager.h>
25#include <KoDocumentInfo.h>
26#include <kactioncollection.h>
27#include <KisPart.h>
28#include <KisKineticScroller.h>
29#include "KisMainWindow.h"
30#include "KoFileDialog.h"
31
32#include <QFileInfo>
33#include <QPointer>
34#include <QMessageBox>
35#include <QTimer>
36#include <QRegularExpression>
37
38namespace
39{
40const QString keyActionRecordToggle = "recorder_record_toggle";
41const QString keyActionExport = "recorder_export";
42
43const QString activeColorGreen(" color='#5cab25'");
44const QString inactiveColorGreen(" color='#b4e196'");
45const QString activeColorOrange(" color='#ca8f14'");
46const QString inactiveColorOrange(" color='#ffe5af'");
47const QString activeColorRed(" color='#da4453'");
48const QString inactiveColorRed(" color='#f2c4c9'");
49const QString inactiveColorGray(" color='#3e3e3e'");
50
51const QColor textColorOrange(0xff, 0xe5, 0xaf);
52const QColor buttonColorOrange(0xca, 0x8f, 0x14);
53const QColor textColorRed(0xf2, 0xc4, 0xc9);
54const QColor buttonColorRed(0xda, 0x44, 0x53);
55
56}
57
58
60{
61public:
63 QScopedPointer<Ui::RecorderDocker> ui;
68
69 QAction *recordToggleAction = nullptr;
70 QAction *exportAction = nullptr;
71
73 QString prefix;
75 double captureInterval = 0.;
77 int quality = 0;
78 int compression = 0;
79 int resolution = 0;
80 bool realTimeCaptureMode = false;
82 bool recordAutomatically = false;
83 bool paused = true;
86
89
90 QMap<QString, bool> enabledIds;
91
93 : q(q_ptr)
94 , ui(new Ui::RecorderDocker())
95 , writer(es)
96 , statusBarLabel(new QLabel())
97 , statusBarWarningLabel(new QLabel())
98 {
100 statusBarWarningLabel->setPixmap(KisIconUtils::loadIcon("warning").pixmap(16, 16));
101 statusBarWarningLabel->hide();
102 warningTimer.setInterval(10000);
103 warningTimer.setSingleShot(true);
104 pausedTimer.setSingleShot(true);
105 connect(&warningTimer, SIGNAL(timeout()), q, SLOT(onWarningTimeout()));
106 connect(&pausedTimer, SIGNAL(timeout()), q, SLOT(onPausedTimeout()));
107 }
108
110 {
111 RecorderConfig config(true);
114 format = config.format();
115 quality = config.quality();
116 compression = config.compression();
117 resolution = config.resolution();
121 q->exportSettings->lockFps = true;
123 }
126
128 }
129
131 {
132 RecorderExportConfig config(true);
133 q->exportSettings->fps = config.fps();
134 }
135
137 int index = 0;
138 QString title;
139 QString hint;
140 int minValue = 0;
141 int maxValue = 0;
142 QString suffix;
143 int factor = 0;
144 switch (format) {
146 index = 0;
147 title = i18nc("Title for label. JPEG Quality level", "Quality:");
148 hint = i18nc("@tooltip", "Greater value will produce a larger file and a better quality. Doesn't affect CPU consumption.\nValues lower than 50 are not recommended due to high artifacts.");
149 minValue = 1;
150 maxValue = 100;
151 suffix = "%";
152 factor = quality;
153 break;
155 index = 1;
156 title = i18nc("Title for label. PNG Compression level", "Compression:");
157 hint = i18nc("@tooltip", "Greater value will produce a smaller file but will require more from your CPU. Doesn't affect quality.\nCompression set to 0 is not recommended due to high disk space consumption.\nValues above 3 are not recommended due to high performance impact.");
158 minValue = 0;
159 maxValue = 5;
160 suffix = "";
161 factor = compression;
162 break;
163 }
164
165 ui->comboFormat->setCurrentIndex(index);
166 ui->labelQuality->setText(title);
167 ui->spinQuality->setToolTip(hint);
168 QSignalBlocker blocker(ui->spinQuality);
169 ui->spinQuality->setMinimum(minValue);
170 ui->spinQuality->setMaximum(maxValue);
171 ui->spinQuality->setValue(factor);
172 ui->spinQuality->setSuffix(suffix);
173 }
174
176 QString title;
177 double minValue = 0;
178 double maxValue = 0;
179 double value = 0;
180 int decimals = 0;
181 QString suffix;
182 QSignalBlocker blocker(ui->spinRate);
183
185 title = i18nc("Title for label. Video frames per second", "Video FPS:");
186 minValue = 1;
187 maxValue = 60;
188 decimals = 0;
190 suffix = "";
191 disconnect(ui->spinRate, SIGNAL(valueChanged(double)), q, SLOT(onCaptureIntervalChanged(double)));
192 connect(ui->spinRate, SIGNAL(valueChanged(double)), q, SLOT(onVideoFPSChanged(double)));
193 } else {
194 title = i18nc("Title for label. Capture rate", "Capture interval:");
195 minValue = 0.10;
196 maxValue = 100.0;
197 decimals = 1;
199 suffix = " sec.";
200 disconnect(ui->spinRate, SIGNAL(valueChanged(double)), q, SLOT(onVideoFPSChanged(double)));
201 connect(ui->spinRate, SIGNAL(valueChanged(double)), q, SLOT(onCaptureIntervalChanged(double)));
202 }
203
204 ui->labelRate->setText(title);
205 ui->spinRate->setDecimals(decimals);
206 ui->spinRate->setMinimum(minValue);
207 ui->spinRate->setMaximum(maxValue);
208 ui->spinRate->setSuffix(suffix);
209 ui->spinRate->setValue(value);
210 }
211
213 {
214 outputDirectory = snapshotDirectory % QDir::separator() % prefix % QDir::separator();
215 writer.setup({
217 format,
218 quality,
224 }
225
226 QString getPrefix()
227 {
228 return !canvas ? ""
229 : canvas->imageView()->document()->documentInfo()->aboutInfo("creation-date").remove(QRegularExpression("[^0-9]"));
230 }
231
232 void updateComboResolution(quint32 width, quint32 height)
233 {
234 const QStringList titles = {
235 i18nc("Use original resolution for the frames when recording the canvas", "Original"),
236 i18nc("Use the resolution two times smaller than the original resolution for the frames when recording the canvas", "Half"),
237 i18nc("Use the resolution four times smaller than the original resolution for the frames when recording the canvas", "Quarter")
238 };
239
240 QStringList items;
241 for (int index = 0, len = titles.length(); index < len; ++index) {
242 int divider = 1 << index;
243 items += QString("%1 (%2x%3)").arg(titles[index])
244 .arg((width / divider) & ~1)
245 .arg((height / divider) & ~1);
246 }
247 QSignalBlocker blocker(ui->comboResolution);
248 const int currentIndex = ui->comboResolution->currentIndex();
249 ui->comboResolution->clear();
250 ui->comboResolution->addItems(items);
251 ui->comboResolution->setCurrentIndex(currentIndex);
252 }
253
254 void updateRecordStatus(bool isRecording)
255 {
256 recordToggleAction->setChecked(isRecording);
257 recordToggleAction->setEnabled(true);
258
259 QSignalBlocker blocker(ui->buttonRecordToggle);
260 ui->buttonRecordToggle->setChecked(isRecording);
261 ui->buttonRecordToggle->setIcon(KisIconUtils::loadIcon(isRecording ? "media-playback-stop" : "media-record"));
262 ui->buttonRecordToggle->setText(isRecording ? i18nc("Stop recording the canvas", "Stop")
263 : i18nc("Start recording the canvas", "Record"));
264 ui->buttonRecordToggle->setEnabled(true);
265
266 ui->widgetSettings->setEnabled(!isRecording);
267
268 statusBarLabel->setVisible(isRecording);
269
270 if (!canvas)
271 return;
272
273 KisStatusBar *statusBar = canvas->viewManager()->statusBar();
274 if (isRecording) {
276 statusBar->addExtraWidget(statusBarLabel);
278 } else {
281 }
282 }
283
285 {
286 auto threads = writer.recorderThreads.get();
287 auto threadsInUse = writer.recorderThreads.getUsed();
288 QString label("<font style='letter-spacing:-4px'>");
289 QString activeColor;
290 QString inactiveColor;
291 for (unsigned int threadNr = 1; threadNr <= ThreadSystemValue::MaxThreadCount ; threadNr++)
292 {
293 if (threadNr > threads) {
294 activeColor = inactiveColorGray;
295 inactiveColor = inactiveColorGray;
296 } else if (threadNr > ThreadSystemValue::MaxRecordThreadCount) {
297 activeColor = activeColorRed;
298 inactiveColor = inactiveColorRed;
299 } else if (threadNr > ThreadSystemValue::IdealRecordThreadCount) {
300 activeColor = activeColorOrange;
301 inactiveColor = inactiveColorOrange;
302 } else {
303 activeColor = activeColorGreen;
304 inactiveColor = inactiveColorGreen;
305 }
306 label.append(QString("<font%1>▍</font>")
307 .arg(threadNr <= threadsInUse ? activeColor : inactiveColor));
308 }
309 // don't remove empty <font></font> tag else label will jump a few pixels around
310 label.append(QString("</font><font> %1 </font><font%2>●</font>")
311 .arg(i18nc("Recording symbol", "REC"))
312 .arg(paused ? "" : activeColorRed));
313 statusBarLabel->setText(label);
314 statusBarLabel->setToolTip(paused ? i18n("Recorder is paused") : QString(i18n("Active recording with %1 of %2 available threads")).arg(threadsInUse).arg(threads));
315 }
316
317 void showWarning(const QString &hint) {
318 if (statusBarWarningLabel->isHidden()) {
319 statusBarWarningLabel->setToolTip(hint);
320 statusBarWarningLabel->show();
321 warningTimer.start();
322 }
323 }
324
326 {
327 QString toolTipText;
328 auto threads = writer.recorderThreads.get();
330 // Number of threads exceeds ideal thread count
331 // -> switch color of threads slider and spin wheel to red
332 QPalette pal;
333 pal.setColor(QPalette::Text, textColorRed);
334 pal.setColor(QPalette::Button, buttonColorRed);
335 ui->spinThreads->setPalette(pal);
336 ui->sliderThreads->setPalette(pal);
337 toolTipText = QString(
338 i18n("Set the number of recording threads.\nThe number of threads exceeds the ideal max number of your hardware setup.\nPlease be aware, that a number greater than %1 probably won't give you any performance boost.")
340 } else if (threads > ThreadSystemValue::IdealRecordThreadCount) {
341 // Number of threads exceeds ideal recorder thread count
342 // -> switch color of threads slider and spin wheel to orange
343 QPalette pal;
344 pal.setColor(QPalette::Text, textColorOrange);
345 pal.setColor(QPalette::Button, buttonColorOrange);
346 ui->spinThreads->setPalette(pal);
347 ui->sliderThreads->setPalette(pal);
348 toolTipText = QString(
349 i18n("Set the number of recording threads.\nAccording to your hardware setup you should record with no more than %1 threads.\nYou can play around with one or two more threads, but keep an eye on your overall system performance.")
351 } else {
352 ui->spinThreads->setPalette(threadsSpinPalette);
353 ui->sliderThreads->setPalette(threadsSliderPalette);
354 toolTipText = i18n("Set the number of threads to be used for recording.");
355 }
356 ui->spinThreads->setToolTip(toolTipText);
357 ui->sliderThreads->setToolTip(toolTipText);
358 }
359};
360
362 : QDockWidget(i18nc("Title of the docker", "Recorder"))
363 , exportSettings(new RecorderExportSettings())
364 , d(new Private(*exportSettings, this))
365{
366 QWidget* page = new QWidget(this);
367 d->ui->setupUi(page);
368
369 d->ui->buttonManageRecordings->setIcon(KisIconUtils::loadIcon("configure-thicker"));
370 d->ui->buttonBrowse->setIcon(KisIconUtils::loadIcon("folder"));
371 d->ui->buttonRecordToggle->setIcon(KisIconUtils::loadIcon("media-record"));
372 d->ui->buttonExport->setIcon(KisIconUtils::loadIcon("document-export-16"));
373 d->ui->sliderThreads->setTickPosition(QSlider::TickPosition::TicksBelow);
374 d->ui->sliderThreads->setMinimum(1);
375 d->ui->sliderThreads->setMaximum(ThreadSystemValue::MaxThreadCount);
376 d->ui->spinThreads->setMinimum(1);
377 d->ui->spinThreads->setMaximum(ThreadSystemValue::MaxThreadCount);
378 d->threadsSpinPalette = d->ui->spinThreads->palette();
379 d->threadsSliderPalette = d->ui->sliderThreads->palette();
380
381 d->loadSettings();
383 d->updateThreadUi();
384
385 d->ui->editDirectory->setText(d->snapshotDirectory);
386 d->ui->spinQuality->setValue(d->quality);
387 d->ui->spinThreads->setValue(d->writer.recorderThreads.get());
388 d->ui->comboResolution->setCurrentIndex(d->resolution);
389 d->ui->checkBoxRealTimeCaptureMode->setChecked(d->realTimeCaptureMode);
390 d->ui->checkBoxRecordIsolateMode->setChecked(d->recordIsolateLayerMode);
391 d->ui->checkBoxAutoRecord->setChecked(d->recordAutomatically);
392
394 d->recordToggleAction = actionRegistry->makeQAction(keyActionRecordToggle, this);
395 d->exportAction = actionRegistry->makeQAction(keyActionExport, this);
396
397 connect(d->recordToggleAction, SIGNAL(toggled(bool)), d->ui->buttonRecordToggle, SLOT(setChecked(bool)));
398 connect(d->exportAction, SIGNAL(triggered()), d->ui->buttonExport, SIGNAL(clicked()));
399 connect(d->ui->buttonRecordToggle, SIGNAL(toggled(bool)), d->ui->buttonExport, SLOT(setDisabled(bool)));
401 d->ui->buttonExport->setDisabled(true);
402
403 // Need to register toolbar actions before attaching canvas else it wont appear after restart.
404 // Is there any better way to do this?
405 connect(KisPart::instance(), SIGNAL(sigMainWindowIsBeingCreated(KisMainWindow *)),
407
408 connect(d->ui->buttonManageRecordings, SIGNAL(clicked()), this, SLOT(onManageRecordingsButtonClicked()));
409 connect(d->ui->buttonBrowse, SIGNAL(clicked()), this, SLOT(onSelectRecordFolderButtonClicked()));
410 connect(d->ui->comboFormat, SIGNAL(currentIndexChanged(int)), this, SLOT(onFormatChanged(int)));
411 connect(d->ui->spinQuality, SIGNAL(valueChanged(int)), this, SLOT(onQualityChanged(int)));
412 connect(d->ui->spinThreads, SIGNAL(valueChanged(int)), this, SLOT(onThreadsChanged(int)));
413 connect(d->ui->comboResolution, SIGNAL(currentIndexChanged(int)), this, SLOT(onResolutionChanged(int)));
414 connect(d->ui->checkBoxRealTimeCaptureMode, SIGNAL(toggled(bool)), this, SLOT(onRealTimeCaptureModeToggled(bool)));
415 connect(d->ui->checkBoxRecordIsolateMode, SIGNAL(toggled(bool)), this, SLOT(onRecordIsolateLayerModeToggled(bool)));
416 connect(d->ui->checkBoxAutoRecord, SIGNAL(toggled(bool)), this, SLOT(onAutoRecordToggled(bool)));
417 connect(d->ui->buttonRecordToggle, SIGNAL(toggled(bool)), this, SLOT(onRecordButtonToggled(bool)));
418 connect(d->ui->buttonExport, SIGNAL(clicked()), this, SLOT(onExportButtonClicked()));
419
420 connect(&d->writer.recorderThreads, SIGNAL(notifyInUseChange(bool)), this, SLOT(onActiveRecording(bool)));
421 connect(&d->writer.recorderThreads, SIGNAL(notifyInUseChange(bool)), this, SLOT(onUpdateRecIndicator()));
422 connect(&d->writer, SIGNAL(started()), this, SLOT(onWriterStarted()));
423 connect(&d->writer, SIGNAL(stopped()), this, SLOT(onWriterStopped()));
424 connect(&d->writer, SIGNAL(frameWriteFailed()), this, SLOT(onWriterFrameWriteFailed()));
425 connect(&d->writer, SIGNAL(recorderStopWarning()), this, SLOT(onRecorderStopWarning()));
426 connect(&d->writer, SIGNAL(lowPerformanceWarning()), this, SLOT(onLowPerformanceWarning()));
427
428
429 QScroller *scroller = KisKineticScroller::createPreconfiguredScroller(d->ui->scrollArea);
430 if (scroller) {
431 connect(scroller, SIGNAL(stateChanged(QScroller::State)),
432 this, SLOT(slotScrollerStateChanged(QScroller::State)));
433 }
434
435 // The system is not efficient enough for the RealTime Recording Feature
437 {
438 d->ui->checkBoxRealTimeCaptureMode->setCheckState(Qt::Unchecked);
439 d->ui->checkBoxRealTimeCaptureMode->setDisabled(true);
440 d->ui->checkBoxRealTimeCaptureMode->setToolTip(
441 i18n("Your system is not efficient enough for this feature"));
442 }
443
444 setWidget(page);
445}
446
448{
449 delete d;
450 delete exportSettings;
451}
452
454{
455 setEnabled(canvas != nullptr);
456
457 if (d->canvas == canvas)
458 return;
459
460 d->canvas = dynamic_cast<KisCanvas2*>(canvas);
462
463 if (!d->canvas)
464 return;
465
466 KisDocument *document = d->canvas->imageView()->document();
467 d->updateComboResolution(document->image()->width(), document->image()->height());
468
469 d->prefix = d->getPrefix();
470 bool wasToggled = false;
471 if (d->recordAutomatically && !d->enabledIds.contains(document->linkedResourcesStorageId())) {
472 wasToggled = onRecordButtonToggled(true);
473 }
474 if (!wasToggled) { // onRecordButtonToggled(true) may call these, don't call them twice.
476 d->updateUiFormat();
477 }
479
480 bool enabled = d->enabledIds.value(document->linkedResourcesStorageId(), false);
481 d->writer.setEnabled(enabled);
482 d->updateRecordStatus(enabled);
483}
484
486{
487 d->updateRecordStatus(false);
488 d->recordToggleAction->setChecked(false);
489 setEnabled(false);
490 d->writer.stop();
491 d->writer.setCanvas(nullptr);
492 d->canvas = nullptr;
493 d->enabledIds.clear();
494}
495
497{
498 KisKActionCollection *actionCollection = window->viewManager()->actionCollection();
499 actionCollection->addAction(keyActionRecordToggle, d->recordToggleAction);
500 actionCollection->addAction(keyActionExport, d->exportAction);
501}
502
504{
505 QSignalBlocker blocker(d->ui->buttonRecordToggle);
506 d->recordToggleAction->setChecked(checked);
507
508 if (!d->canvas)
509 return false;
510
511 const QString &id = d->canvas->imageView()->document()->linkedResourcesStorageId();
512
513 bool wasEmpty = !d->enabledIds.values().contains(true);
514
515 d->enabledIds[id] = checked;
516
517 bool isEmpty = !d->enabledIds.values().contains(true);
518
519 d->writer.setEnabled(checked);
520
521 if (isEmpty == wasEmpty) {
522 d->updateRecordStatus(checked);
523 return false;
524 }
525
526
527 d->ui->buttonRecordToggle->setEnabled(false);
528
529 if (checked) {
531 d->updateUiFormat();
532 d->writer.start();
533
534 // Calculate Rec symbol activity timeout depending on the capture interval
535 // The pausedTimer interval is set to a slightly greater value than the capture interval
536 // to avoid flickering for ongoing painting. This is also the reason for the min and max
537 // values 305 and 2005 (instead of 300 and 2000, respectively).
538 if (d->realTimeCaptureMode) {
539 d->pausedTimer.setInterval(qBound(305, static_cast<int>(1000.0/static_cast<double>(exportSettings->fps)) + 5,2005));
540 } else {
541 d->pausedTimer.setInterval(qBound(305, static_cast<int>(qMax(d->captureInterval, .1) * 1000.0) + 5, 2005));
542 }
543 } else {
544 d->writer.stop();
545 d->warningTimer.stop();
546 d->pausedTimer.stop();
547 d->statusBarWarningLabel->hide();
548 d->paused = true;
549 }
550
551 return true;
552}
553
555{
556 if (!d->canvas)
557 return;
558
559 KisDocument *document = d->canvas->imageView()->document();
560
561 exportSettings->videoFileName = QFileInfo(document->caption().trimmed()).completeBaseName();
565
566 RecorderExport exportDialog(exportSettings, this);
567 exportDialog.setup();
568 exportDialog.exec();
569
571 d->ui->spinRate->setValue(exportSettings->fps);
572}
573
575{
576 RecorderSnapshotsManager snapshotsManager(this);
577 snapshotsManager.execFor(d->snapshotDirectory);
578}
579
580
582{
583 KoFileDialog dialog(this, KoFileDialog::OpenDirectory, "SelectRecordingsDirectory");
584 dialog.setCaption(i18n("Select a Directory for Recordings"));
585 dialog.setDefaultDir(d->ui->editDirectory->text());
586 QString directory = dialog.filename();
587 if (!directory.isEmpty()) {
588 d->ui->editDirectory->setText(directory);
589 RecorderConfig(false).setSnapshotDirectory(directory);
590 d->loadSettings();
591 }
592}
593
600
602{
603 d->recordAutomatically = checked;
605 d->loadSettings();
606}
607
619
621{
622 d->captureInterval = interval;
623 RecorderConfig(false).setCaptureInterval(interval);
624 d->loadSettings();
625}
632
634{
635 switch (d->format) {
637 d->quality = value;
639 d->loadSettings();
640 break;
644 d->loadSettings();
645 break;
646 }
647}
648
650{
651 d->format = static_cast<RecorderFormat>(format);
652 d->updateUiFormat();
653
655 d->loadSettings();
656}
657
659{
660 d->resolution = resolution;
661 RecorderConfig(false).setResolution(resolution);
662 d->loadSettings();
663}
664
666{
667 d->writer.recorderThreads.set(threads);
668 RecorderConfig(false).setThreads(threads);
669 d->loadSettings();
670 d->updateThreadUi();
671}
672
677
682
687
688void RecorderDockerDock::onActiveRecording(bool valueWasIncreased)
689{
690 if (!valueWasIncreased)
691 return;
692
693 d->paused = false;
694 d->pausedTimer.start();
695}
696
702
704{
705 QMessageBox::warning(this, i18nc("@title:window", "Recorder"),
706 i18n("The recorder has been stopped due to failure while writing a frame. Please check free disk space and start the recorder again."));
707}
708
710{
711 QMessageBox::warning(this, i18nc("@title:window", "Recorder"),
712 i18n("Krita was unable to stop the recorder probably. Please try to restart Krita."));
713}
715{
716 if (d->realTimeCaptureMode) {
717 d->showWarning(i18n("Low performance warning. The recorder is not able to write all the frames in time during Real Time Capture mode.\nTry to reduce the frame rate for the ffmpeg export or reduce the scaling filtering in the canvas acceleration settings."));
718 } else {
719 d->showWarning(i18n("Low performance warning. The recorder is not able to write all the frames in time.\nTry to increase the capture interval or reduce the scaling filtering in the canvas acceleration settings."));
720 }
721}
722
727
729{
731}
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
QAction * makeQAction(const QString &name, QObject *parent=0)
static KisActionRegistry * instance()
A container for a set of QAction objects.
Q_INVOKABLE QAction * addAction(const QString &name, QAction *action)
Main window for Krita.
KisViewManager * viewManager
static KisPart * instance()
Definition KisPart.cpp:131
void removeExtraWidget(QWidget *widget)
void addExtraWidget(QWidget *widget)
virtual KisKActionCollection * actionCollection() const
double captureInterval() const
QString snapshotDirectory() const
void setFormat(RecorderFormat value)
void setRealTimeCaptureMode(bool value)
bool recordIsolateLayerMode() const
RecorderFormat format() const
int resolution() const
void setRecordAutomatically(bool value)
void setResolution(int value)
void setCaptureInterval(double value)
void setSnapshotDirectory(const QString &value)
void setRecordIsolateLayerMode(bool value)
void setCompression(int value)
bool recordAutomatically() const
void setQuality(int value)
bool realTimeCaptureMode() const
int compression() const
void setThreads(int value)
int quality() const
void showWarning(const QString &hint)
Private(const RecorderExportSettings &es, RecorderDockerDock *q_ptr)
QScopedPointer< Ui::RecorderDocker > ui
void updateRecordStatus(bool isRecording)
RecorderDockerDock *const q
void updateComboResolution(quint32 width, quint32 height)
void slotScrollerStateChanged(QScroller::State state)
RecorderExportSettings *const exportSettings
void onCaptureIntervalChanged(double interval)
void setCanvas(KoCanvasBase *canvas) override
void onThreadsChanged(int threads)
void onVideoFPSChanged(double interval)
void onQualityChanged(int value)
void onRecordIsolateLayerModeToggled(bool checked)
void onRealTimeCaptureModeToggled(bool checked)
void onResolutionChanged(int resolution)
bool onRecordButtonToggled(bool checked)
void onAutoRecordToggled(bool checked)
void onActiveRecording(bool valueWasIncreased)
void onMainWindowIsBeingCreated(KisMainWindow *window)
void onFormatChanged(int format)
void execFor(const QString &snapshotsDirectory)
void start(bool toggleEnabled=true)
void setCanvas(QPointer< KisCanvas2 > canvas)
bool stop(bool toggleEnabled=true)
void setEnabled(bool enabled)
void setup(const RecorderWriterSettings &settings)
ThreadCounter recorderThreads
unsigned int getUsed() const
unsigned int get() const
bool set(int value)
QIcon loadIcon(const QString &name)
KRITAWIDGETUTILS_EXPORT void updateCursor(QWidget *source, QScroller::State state)
KRITAWIDGETUTILS_EXPORT QScroller * createPreconfiguredScroller(QAbstractScrollArea *target)
const unsigned int IdealRecordThreadCount
const unsigned int MaxThreadCount
const unsigned int MaxRecordThreadCount
RecorderFormat