Kstars

camera.h
1/*
2 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 SPDX-FileCopyrightText: 2024 Wolfgang Reissenberger <sterne-jaeger@openfuture.de>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6*/
7
8#pragma once
9#include "ui_camera.h"
10#include "ui_limits.h"
11#include "ui_calibrationoptions.h"
12#include "customproperties.h"
13#include "rotatorsettings.h"
14#include "sequencejob.h"
15
16namespace
17{
18
19// Columns in the job table
20enum JobTableColumnIndex
21{
30};
31} // namespace
32
33class DSLRInfo;
34
35namespace Ekos
36{
37
38class Capture;
39class CaptureDeviceAdaptor;
40class CaptureProcess;
41class CaptureModuleState;
42class ScriptsManager;
43class FilterManager;
44class SequenceJob;
45
46class Camera : public QWidget, public Ui::Camera
47{
49 friend class Capture;
50public:
51 typedef enum
52 {
53 NOT_PREVIEW,
54 LOCAL_PREVIEW,
55 REMOTE_PREVIEW
56 } FilenamePreviewType;
57
58 explicit Camera(bool standAlone = false, QWidget *parent = nullptr);
59 ~Camera();
60
61 // ////////////////////////////////////////////////////////////////////
62 // device control
63 // ////////////////////////////////////////////////////////////////////
64 // Gain
65 // This sets and gets the custom properties target gain
66 // it does not access the ccd gain property
67 void setGain(double value);
68 double getGain();
69
70 void setOffset(double value);
71 double getOffset();
72
73 /**
74 * @brief Add new Rotator
75 * @param name name of the new rotator
76 */
77 void setRotator(QString name);
78
79 /**
80 * @brief addDSLRInfo Save DSLR Info the in the database. If the interactive dialog was open, close it.
81 * @param model Camera name
82 * @param maxW Maximum width in pixels
83 * @param maxH Maximum height in pixels
84 * @param pixelW Pixel horizontal size in microns
85 * @param pixelH Pizel vertical size in microns
86 */
87 void addDSLRInfo(const QString &model, uint32_t maxW, uint32_t maxH, double pixelW, double pixelH);
88
89 // ////////////////////////////////////////////////////////////////////
90 // Main capturing actions
91 // ////////////////////////////////////////////////////////////////////
92 /**
93 * @brief Start the execution of the Capture::SequenceJob list #jobs.
94 *
95 * Starting the execution of the Capture::SequenceJob list selects the first job
96 * from the list that may be executed and starts to prepare the job (@see prepareJob()).
97 *
98 * Several factors determine, which of the jobs will be selected:
99 * - First, the list is searched to find the first job that is marked as idle or aborted.
100 * - If none is found, it is checked whether ignoring job progress is set. If yes,
101 * all jobs are are reset (@see reset()) and the first one from the list is selected.
102 * If no, the user is asked whether the jobs should be reset. If the user declines,
103 * starting is aborted.
104 */
105 void start();
106
107 /**
108 * Stops currently running jobs:
109 * CAPTURE_IDLE: capture in idle state waiting for further action (e.g. single sequence
110 * is complete, next one starting)
111 * CAPTURE_COMPLETE: all capture sequences are complete
112 * CAPTURE_ABORT: capture aborted either by user interaction or by a technical error
113 * CAPTURE_SUSPEND: capture suspended and waiting to be restarted
114 * @param targetState status of the job after stop
115 */
116 void stop(CaptureState targetState = CAPTURE_IDLE);
117
118 /**
119 * Aborts all jobs and mark current state as ABORTED. It simply calls stop(CAPTURE_ABORTED)
120 */
121 void abort()
122 {
123 stop(CAPTURE_ABORTED);
124 }
125
126 /**
127 * Aborts all jobs and mark current state as SUSPENDED. It simply calls stop(CAPTURE_SUSPENDED)
128 * The only difference between SUSPENDED and ABORTED it that capture module can automatically resume a suspended
129 * state on its own without external trigger once the right conditions are met. When whatever reason caused the module
130 * to go into suspended state ceases to exist, the capture module automatically resumes. On the other hand, ABORTED state
131 * must be started via an external programmatic or user trigger (e.g. click the start button again).
132 */
133 void suspend()
134 {
135 stop(CAPTURE_SUSPENDED);
136 }
137
138 /** DBUS interface function.
139 * @brief pause Pauses the Sequence Queue progress AFTER the current capture is complete.
140 */
141 void pause();
142
143 /**
144 * @brief toggleSequence Toggle sequence state depending on its current state.
145 * 1. If paused, then resume sequence.
146 * 2. If idle or completed, then start sequence.
147 * 3. Otherwise, abort current sequence.
148 */
149 void toggleSequence();
150
151 /**
152 * Toggle video streaming if supported by the device.
153 * @param enabled Set to true to start video streaming, false to stop it if active.
154 */
155 void toggleVideo(bool enabled);
156
157 /**
158 * @brief restartCamera Restarts the INDI driver associated with a camera. Remote and Local drivers are supported.
159 * @param name Name of camera to restart. If a driver defined multiple cameras, they would be removed and added again
160 * after driver restart.
161 */
162 void restartCamera(const QString &name);
163
164 /**
165 * @brief capturePreview Capture a single preview image
166 */
167 void capturePreview();
168
169 /**
170 * @brief startFraming Like captureOne but repeating.
171 */
172 void startFraming();
173
174 /**
175 * @brief generateDarkFlats Generate a list of dark flat jobs from available flat frames.
176 */
177 void generateDarkFlats();
178
179 /**
180 * @brief setDownloadProgress update the Capture Module and Summary
181 * Screen's estimate of how much time is left in the download
182 */
183 void updateDownloadProgress(double downloadTimeLeft);
184
185 void updateCaptureCountDown(int deltaMillis);
186
187 // ////////////////////////////////////////////////////////////////////
188 // Job handling
189 // ////////////////////////////////////////////////////////////////////
190
191 /**
192 * @brief createJob Create a new job with the settings given in the GUI.
193 * @param jobtype batch, preview, looping or dark flat job.
194 * @param filenamePreview if the job is to generate a preview filename
195 * @return pointer to job created or nullptr otherwise.
196 */
197 SequenceJob *createJob(SequenceJob::SequenceJobType jobtype = SequenceJob::JOBTYPE_BATCH,
198 Camera::FilenamePreviewType filenamePreview = Camera::NOT_PREVIEW);
199
200 /**
201 * @brief removeJob Remove a job sequence from the queue
202 * @param index Row index for job to remove, if left as -1 (default), the currently selected row will be removed.
203 * if no row is selected, the last job shall be removed.
204 * @param true if sequence is removed. False otherwise.
205 */
206 bool removeJob(int index = -1);
207
208 // ////////////////////////////////////////////////////////////////////
209 // Process control
210 // ////////////////////////////////////////////////////////////////////
211 /**
212 * Enables or disables the maximum guiding deviation and sets its value.
213 * @param enable If true, enable the guiding deviation check, otherwise, disable it.
214 * @param value if enable is true, it sets the maximum guiding deviation in arcsecs. If the value is exceeded, the capture operation is aborted until the value falls below the value threshold.
215 */
216 void setMaximumGuidingDeviation(bool enable, double value);
217
218 /**
219 * Enables or disables the in sequence focus and sets Half-Flux-Radius (HFR) limit.
220 * @param enable If true, enable the in sequence auto focus check, otherwise, disable it.
221 * @param HFR if enable is true, it sets HFR in pixels. After each exposure, the HFR is re-measured and if it exceeds the specified value, an autofocus operation will be commanded.
222 */
223 void setInSequenceFocus(bool enable, double HFR);
224
225 /**
226 * Loads the Ekos Sequence Queue file in the Sequence Queue. Jobs are appended to existing jobs.
227 * @param fileURL full URL of the filename
228 * @param targetName override the target in the sequence queue file (necessary for using the target of the scheduler)
229 */
230 bool loadSequenceQueue(const QString &fileURL, QString targetName = "");
231
232 /**
233 * Saves the Sequence Queue to the Ekos Sequence Queue file.
234 * @param fileURL full URL of the filename
235 */
236 bool saveSequenceQueue(const QString &path);
237
238 /**
239 * Aborts any current jobs and remove all sequence queue jobs.
240 */
241 void clearSequenceQueue();
242
243 // shortcuts
244 void loadSequenceQueue();
245 void saveSequenceQueue();
246 void saveSequenceQueueAs();
247
248 QVariantMap getAllSettings() const;
249 void setAllSettings(const QVariantMap &settings);
250
251 // ////////////////////////////////////////////////////////////////////
252 // Optical Train handling
253 // ////////////////////////////////////////////////////////////////////
254 void setupOpticalTrainManager();
255 void refreshOpticalTrain();
256
257 // Utilities for storing stand-alone variables.
258 void storeTrainKey(const QString &key, const QStringList &list);
259 void storeTrainKeyString(const QString &key, const QString &str);
260
261 // ////////////////////////////////////////////////////////////////////
262 // Filter Manager and filters
263 // ////////////////////////////////////////////////////////////////////
264 void setupFilterManager();
265
266 /**
267 * @brief checkFilter Refreshes the filter wheel information in the capture module.
268 */
269 void refreshFilterSettings();
270
271 QSharedPointer<FilterManager> &filterManager()
272 {
273 return m_FilterManager;
274 }
275
276 /**
277 * @brief shortcut for updating the current filter information for the state machine
278 */
279 void updateCurrentFilterPosition();
280
281 /**
282 * @brief Add new Filter Wheel
283 * @param name device name of the new filter wheel
284 */
285 void setFilterWheel(QString name);
286
287 // ////////////////////////////////////////////////////////////////////
288 // Devices and process engine
289 // ////////////////////////////////////////////////////////////////////
290
291 /**
292 * @brief activeJob Shortcut to device adapter
293 */
295 {
296 return m_DeviceAdaptor;
297 }
298 // TODO: remove this when refactoring Capture --> Camera is finished
300 {
301 m_DeviceAdaptor = newDeviceAdaptor;
302 }
303
305 {
306 return m_captureProcess;
307 }
309 {
310 m_captureProcess = newCaptureProcess;
311 }
312
313 // shortcut for the module state
315 {
316 return m_captureModuleState;
317 }
318
320 {
321 m_captureModuleState = newCaptureModuleState;
322 }
323
324 // shortcut for the active job
325 SequenceJob *activeJob() const
326 {
327 return state()->getActiveJob();
328 }
329
330 // Shortcut to the active camera held in the device adaptor
331 ISD::Camera *activeCamera();
332
333 /**
334 * @brief currentScope Retrieve the scope parameters from the optical train.
335 */
336 QJsonObject currentScope();
337
338 /**
339 * @brief currentReducer Retrieve the reducer parameters from the optical train.
340 */
341 double currentReducer();
342
343 /**
344 * @brief currentAperture Determine the current aperture
345 * @return
346 */
347 double currentAperture();
348
349 void setForceTemperature(bool enabled)
350 {
351 cameraTemperatureS->setChecked(enabled);
352 }
353
354 // ////////////////////////////////////////////////////////////////////
355 // sub dialogs
356 // ////////////////////////////////////////////////////////////////////
357
358 void openExposureCalculatorDialog();
359
360 // Script Manager
361 void handleScriptsManager();
362
363 /**
364 * @brief showTemperatureRegulation Toggle temperature regulation dialog which sets temperature ramp and threshold
365 */
366 void showTemperatureRegulation();
367
368 void createDSLRDialog();
369
370 // Observer
371 void showObserverDialog();
372
373 // ////////////////////////////////////////////////////////////////////
374 // Standalone editor
375 // ////////////////////////////////////////////////////////////////////
376 /**
377 * Gets called when the stand-alone editor gets a show event.
378 * Do this initialization here so that if the live capture module was
379 * used after startup, it will have set more recent remembered values.
380 */
381 void onStandAloneShow(QShowEvent* event);
382
383 bool m_standAlone {false};
384 void setStandAloneGain(double value);
385 void setStandAloneOffset(double value);
386
387 CustomProperties *customPropertiesDialog() const
388 {
389 return m_customPropertiesDialog.get();
390 }
391
392
393 // ////////////////////////////////////////////////////////////////////
394 // Access to properties
395 // ////////////////////////////////////////////////////////////////////
396
397 /**
398 * @brief Set the observer name.
399 */
400 void setObserverName(const QString &value)
401 {
402 state()->setObserverName(value);
403 };
404
405 QString getObserverName()
406 {
407 return state()->observerName();
408 }
409
410 QVariantMap &settings()
411 {
412 return m_settings;
413 }
414 void setSettings(const QVariantMap &newSettings)
415 {
416 m_settings = newSettings;
417 }
418
419signals:
420 // communication with other modules
421 void ready();
422 void newExposureProgress(SequenceJob *job);
423 void newDownloadProgress(double);
424 void newImage(SequenceJob *job, const QSharedPointer<FITSData> &data);
425 void captureTarget(QString targetName);
426 void captureComplete(const QVariantMap &metadata);
427 void runAutoFocus(AutofocusReason autofocusReason, const QString &reasonInfo);
428 void resetFocus();
429 void abortFocus();
430 void adaptiveFocus();
431 void settingsUpdated(const QVariantMap &settings);
432 void sequenceChanged(const QJsonArray &sequence);
433 void newLocalPreview(const QString &preview);
434 void dslrInfoRequested(const QString &cameraName);
435 void filterManagerUpdated(ISD::FilterWheel *device);
436 void newFilterStatus(FilterState state);
437 void trainChanged();
438 void newLog(const QString &text);
439
440 // Signals for the Analyze tab.
441 void captureStarting(double exposureSeconds, const QString &filter);
442 void captureAborted(double exposureSeconds);
443
444 // communication with other modules
445 void checkFocus(double);
446
447private slots:
448 // ////////////////////////////////////////////////////////////////////
449 // slots handling device and module events
450 // ////////////////////////////////////////////////////////////////////
451
452 void setVideoStreamEnabled(bool enabled);
453
454 // Cooler
455 void setCoolerToggled(bool enabled);
456
457 // Filter
458 void setFilterStatus(FilterState filterState);
459
460 // Jobs
461 void resetJobs();
462 bool selectJob(QModelIndex i);
463 void editJob(QModelIndex i);
464 void resetJobEdit(bool cancelled = false);
465
466private:
467
468 /**
469 * @brief initCamera Initialize all camera settings
470 */
471 void initCamera();
472 // ////////////////////////////////////////////////////////////////////
473 // Device updates
474 // ////////////////////////////////////////////////////////////////////
475 // Rotator
476 void updateRotatorAngle(double value);
477 void setRotatorReversed(bool toggled);
478
479 /**
480 * @brief updateCCDTemperature Update CCD temperature in capture module.
481 * @param value Temperature in celcius.
482 */
483 void updateCCDTemperature(double value);
484
485 // Auto Focus
486 /**
487 * @brief setFocusStatus Forward the new focus state to the capture module state machine
488 */
489 void setFocusStatus(FocusState newstate);
490
491 /**
492 * @brief updateFocusStatus Handle new focus state
493 */
494 void updateFocusStatus(FocusState newstate);
495
496 // Adaptive Focus
497 /**
498 * @brief focusAdaptiveComplete Forward the new focus state to the capture module state machine
499 */
500 void focusAdaptiveComplete(bool success)
501 {
502 // directly forward it to the state machine
503 state()->updateAdaptiveFocusState(success);
504 }
505
506 /**
507 * @brief Add new Camera
508 * @param device pointer to camera device.
509 * @return True if added successfully, false if duplicate or failed to add.
510 */
511 bool updateCamera();
512
513 /**
514 * @brief checkCamera Refreshes the CCD information in the capture module.
515 */
516 void refreshCameraSettings();
517
518 /**
519 * @brief processCCDNumber Process number properties arriving from CCD. Currently, only CCD and Guider frames are processed.
520 * @param nvp pointer to number property.
521 */
522 void processCameraNumber(INDI::Property prop);
523
524 /**
525 * @brief Slot receiving the update of the current target distance.
526 * @param targetDiff distance to the target in arcseconds.
527 */
528 void updateTargetDistance(double targetDiff);
529
530 // ////////////////////////////////////////////////////////////////////
531 // Capture actions
532 // ////////////////////////////////////////////////////////////////////
533 /**
534 * @brief captureStarted Change the UI after the capturing process
535 * has been started.
536 */
537 void jobStarting();
538
539 /**
540 * @brief addJob Add a new job to the UI. This is used when a job is loaded from a capture sequence file. In
541 * contrast to {@see #createJob()}, the job's attributes are taken from the file and only the UI gehts updated.
542 */
543 void addJob(SequenceJob *job);
544
545 /**
546 * @brief jobEditFinished Editing of an existing job finished, update its
547 * attributes from the UI settings. The job under edit is taken from the
548 * selection in the job table.
549 * @return true if job updated succeeded.
550 */
551 void editJobFinished();
552
553 /**
554 * @brief imageCapturingCompleted Capturing a single frame completed
555 */
556 void imageCapturingCompleted();
557
558 /**
559 * @brief captureStopped Capturing has stopped
560 */
561 void captureStopped();
562
563 /**
564 * @brief processFITSfinished processing new FITS data received from camera finished.
565 * @param success true iff processing was successful
566 */
567 void processingFITSfinished(bool success);
568
569 /**
570 * @brief captureRunning Manage the result when capturing has been started
571 */
572 void captureRunning();
573
574 /**
575 * @brief captureImageStarted Image capturing for the active job has started.
576 */
577 void captureImageStarted();
578
579 /**
580 * @brief jobPreparationStarted Preparation actions for the current active job have beenstarted.
581 */
582 void jobExecutionPreparationStarted();
583
584 /**
585 * @brief jobPrepared Select the job that is currently in preparation.
586 */
587 void jobPrepared(SequenceJob *job);
588
589 /**
590 * @brief Set the name of the target to be captured.
591 */
592 void setTargetName(const QString &newTargetName);
593
594 // ////////////////////////////////////////////////////////////////////
595 // UI controls
596 // ////////////////////////////////////////////////////////////////////
597 void checkFrameType(int index);
598
599 /**
600 * @brief updateStartButtons Update the start and the pause button to new states of capturing
601 * @param start start capturing
602 * @param pause pause capturing
603 */
604 void updateStartButtons(bool start, bool pause = false);
605
606 void setBusy(bool enable);
607
608 /**
609 * @brief Listen to device property changes (temperature, rotator) that are triggered by
610 * SequenceJob.
611 */
612 void updatePrepareState(CaptureState prepareState);
613
614 /**
615 * @brief updateJobTable Update the table row values for the given sequence job. If the job
616 * is null, all rows will be updated
617 * @param job as identifier for the row
618 * @param full if false, then only the status and the counter will be updated.
619 */
620 void updateJobTable(SequenceJob *job, bool full = false);
621
622 /**
623 * @brief updateJobFromUI Update all job attributes from the UI settings.
624 */
625 void updateJobFromUI(SequenceJob *job, Camera::FilenamePreviewType filenamePreview = Camera::NOT_PREVIEW);
626
627 /**
628 * @brief syncGUIToJob Update UI to job settings
629 */
630 void syncGUIToJob(SequenceJob *job);
631
632 void syncFrameType(const QString &name);
633
634 void syncCameraInfo();
635
636 // create a new row in the job table and fill it with the given job's values
637 void createNewJobTableRow(SequenceJob *job);
638
639 /**
640 * @brief Update the style of the job's row, depending on the job's state
641 */
642 void updateRowStyle(SequenceJob *job);
643
644 /**
645 * @brief updateCellStyle Update the cell's style. If active is true, set a bold and italic font and
646 * a regular font otherwise.
647 */
648 void updateCellStyle(QTableWidgetItem *cell, bool active);
649
650 /**
651 * @brief syncControl Sync setting to widget. The value depends on the widget type.
652 * @param settings Map of all settings
653 * @param key name of widget to sync
654 * @param widget pointer of widget to set
655 * @return True if sync successful, false otherwise
656 */
657 bool syncControl(const QVariantMap &settings, const QString &key, QWidget * widget);
658
659 /**
660 * @brief moveJobUp Move the job in the sequence queue one place up or down.
661 */
662 void moveJob(bool up);
663
664
665 void removeJobFromQueue();
666
667 void saveFITSDirectory();
668
669 /**
670 * @brief updateCaptureFormats Update encoding and transfer formats
671 */
672 void updateCaptureFormats();
673
674 /**
675 * @brief updateHFRCheckAlgo Update the in-sequence HFR check algorithm
676 */
677 void updateHFRCheckAlgo();
678
679 /**
680 * Clear in-sequence focus settings. It sets the autofocus HFR to zero so that next autofocus value is remembered for the in-sequence focusing.
681 */
682 void clearAutoFocusHFR();
683
684 // selection of a job
685 void selectedJobChanged(QModelIndex current, QModelIndex previous);
686
687 // Clear Camera Configuration
688 void clearCameraConfiguration();
689
690 // Change filter name in INDI
691 void editFilterName();
692 bool editFilterNameInternal(const QStringList &labels, QStringList &newLabels);
693
694 // ////////////////////////////////////////////////////////////////////
695 // Settings
696 // ////////////////////////////////////////////////////////////////////
697 /**
698 * @brief loadSettings Load setting from Options and set them accordingly.
699 */
700 void loadGlobalSettings();
701
702 /**
703 * @brief syncLimitSettings Update Limits UI from Options
704 */
705 void syncLimitSettings();
706
707 /**
708 * @brief settleSettings Run this function after timeout from debounce timer to update database
709 * and emit settingsChanged signal. This is required so we don't overload output.
710 */
711 void settleSettings();
712
713 /**
714 * @brief syncSettings When checkboxes, comboboxes, or spin boxes are updated, save their values in the
715 * global and per-train settings.
716 */
717 void syncSettings();
718
719 /**
720 * @brief Connect GUI elements to sync settings once updated.
721 */
722 void connectSyncSettings();
723 /**
724 * @brief Stop updating settings when GUI elements are updated.
725 */
726 void disconnectSyncSettings();
727
728 // ////////////////////////////////////////////////////////////////////
729 // helper functions
730 // ////////////////////////////////////////////////////////////////////
731 // check if the upload paths are filled correctly
732 bool checkUploadPaths(FilenamePreviewType filenamePreview);
733
734 // Create a Json job from the current job table row
735 QJsonObject createJsonJob(SequenceJob *job, int currentRow);
736
737 /**
738 * @return Returns true if an ongoing capture is a preview capture.
739 */
740 bool isActiveJobPreview()
741 {
742 return state() && state()->isActiveJobPreview();
743 }
744
745 // Filename preview
746 void generatePreviewFilename();
747 QString previewFilename(FilenamePreviewType previewType = LOCAL_PREVIEW);
748
749 /**
750 * @brief updateJobTableCountCell Update the job counter in the job table of a sigle job
751 */
752 void updateJobTableCountCell(SequenceJob *job, QTableWidgetItem *countCell);
753
754 void cullToDSLRLimits();
755
756 void resetFrameToZero();
757
758 // reset = 0 --> Do not reset
759 // reset = 1 --> Full reset
760 // reset = 2 --> Only update limits if needed
761 void updateFrameProperties(int reset = 0);
762
763 // ////////////////////////////////////////////////////////////////////
764 // Sub dialogs
765 // ////////////////////////////////////////////////////////////////////
766 QSharedPointer<FilterManager> m_FilterManager;
767 std::unique_ptr<Ui::Limits> m_LimitsUI;
768 QPointer<QDialog> m_LimitsDialog;
769 std::unique_ptr<Ui::Calibration> m_CalibrationUI;
770 QPointer<QDialog> m_CalibrationDialog;
771 QPointer<ScriptsManager> m_scriptsManager;
772 QSharedPointer<RotatorSettings> m_RotatorControlPanel;
773 std::unique_ptr<DSLRInfo> m_DSLRInfoDialog;
774
775 // ////////////////////////////////////////////////////////////////////
776 // Module logging
777 // ////////////////////////////////////////////////////////////////////
778 void appendLogText(const QString &text)
779 {
780 emit newLog(text);
781 }
782
783 // ////////////////////////////////////////////////////////////////////
784 // Attributes
785 // ////////////////////////////////////////////////////////////////////
786 QVariantMap m_settings;
787 QVariantMap m_GlobalSettings;
788 std::unique_ptr<CustomProperties> m_customPropertiesDialog;
789 QTimer m_DebounceTimer;
790
791 bool m_standAloneUseCcdGain { true};
792 bool m_standAloneUseCcdOffset { true};
793 bool m_JobUnderEdit { false };
794
795 QUrl m_dirPath;
796
798 QSharedPointer<CaptureProcess> m_captureProcess;
799 QSharedPointer<CaptureModuleState> m_captureModuleState;
800
801 // Controls
802 double GainSpinSpecialValue { INVALID_VALUE };
803 double OffsetSpinSpecialValue { INVALID_VALUE };
804};
805} // namespace Ekos
Camera class controls an INDI Camera device.
Definition indicamera.h:44
Sequence Job is a container for the details required to capture a series of images.
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:79
@ CAPTURE_SUSPENDED
Definition ekos.h:98
@ CAPTURE_ABORTED
Definition ekos.h:99
@ CAPTURE_IDLE
Definition ekos.h:93
Q_OBJECTQ_OBJECT
QObject * parent() const const
virtual bool event(QEvent *event) override
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jun 14 2024 11:55:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.