11#include "kstarsdata.h"
12#include "auxiliary/ksmessagebox.h"
13#include "ekos/manager.h"
14#include "ekos/auxiliary/darklibrary.h"
15#include "ekos/auxiliary/filtermanager.h"
16#include "ekos/auxiliary/opticaltrainmanager.h"
17#include "ekos/auxiliary/opticaltrainsettings.h"
18#include "ekos/auxiliary/profilesettings.h"
19#include "ekos/auxiliary/rotatorutils.h"
20#include "capturedeviceadaptor.h"
21#include "cameraprocess.h"
22#include "sequencequeue.h"
23#include "scriptsmanager.h"
24#include "dslrinfodialog.h"
25#include "ui_dslrinfo.h"
26#include "exposurecalculator/exposurecalculatordialog.h"
28#include "indi/driverinfo.h"
29#include "indi/indirotator.h"
30#include "oal/observeradd.h"
32#include <ekos_capture_debug.h>
37#define KEY_FORMATS "formatsList"
38#define KEY_GAIN_KWD "ccdGainKeyword"
39#define KEY_OFFSET_KWD "ccdOffsetKeyword"
40#define KEY_TEMPERATURE "ccdTemperatures"
41#define KEY_TIMESTAMP "timestamp"
42#define KEY_FILTERS "filtersList"
43#define KEY_ISOS "isoList"
44#define KEY_INDEX "isoIndex"
45#define KEY_GAIN_KWD "ccdGainKeyword"
46#define KEY_OFFSET_KWD "ccdOffsetKeyword"
49const QStringList standAloneKeys = {KEY_FORMATS, KEY_GAIN_KWD, KEY_OFFSET_KWD,
50 KEY_TEMPERATURE, KEY_TIMESTAMP, KEY_FILTERS,
51 KEY_ISOS, KEY_INDEX, KEY_GAIN_KWD, KEY_OFFSET_KWD
53QVariantMap copyStandAloneSettings(
const QVariantMap &settings)
55 QVariantMap foundSettings;
56 for (
const auto &k : standAloneKeys)
58 auto v = settings.find(k);
59 if (v != settings.end())
60 foundSettings[k] = *v;
69Camera::Camera(
int id,
bool standAlone,
QWidget *parent)
70 :
QWidget{parent}, m_standAlone(standAlone)
74 m_cameraState.reset(
new CameraState());
75 m_DeviceAdaptor.reset(
new CaptureDeviceAdaptor());
76 m_cameraProcess.reset(
new CameraProcess(state(), m_DeviceAdaptor));
78 m_customPropertiesDialog.reset(
new CustomProperties());
79 m_LimitsDialog =
new QDialog(
this);
80 m_LimitsUI.reset(
new Ui::Limits());
81 m_LimitsUI->setupUi(m_LimitsDialog);
83 m_CalibrationDialog =
new QDialog(
this);
84 m_CalibrationUI.reset(
new Ui::Calibration());
85 m_CalibrationUI->setupUi(m_CalibrationDialog);
87 m_scriptsManager =
new ScriptsManager(
this);
92 auto title =
i18n(
"Capture Sequence Editor: %1", m_LimitsDialog->windowTitle());
93 m_LimitsDialog->setWindowTitle(title);
94 title =
i18n(
"Capture Sequence Editor: %1", m_scriptsManager->windowTitle());
95 m_scriptsManager->setWindowTitle(title);
99 m_DebounceTimer.setInterval(500);
100 m_DebounceTimer.setSingleShot(
true);
103 targetDriftLabel->setVisible(
false);
104 targetDrift->setVisible(
false);
105 targetDriftUnit->setVisible(
false);
106 avgDownloadTime->setVisible(
false);
107 avgDownloadLabel->setVisible(
false);
108 secLabel->setVisible(
false);
109 darkB->setChecked(Options::autoDark());
149 addToQueueB->setToolTip(
i18n(
"Add job to sequence queue"));
150 removeFromQueueB->setToolTip(
i18n(
"Remove job from sequence queue"));
152 if (Options::remoteCaptureDirectory().isEmpty() ==
false)
154 fileRemoteDirT->setText(Options::remoteCaptureDirectory());
157 if(!Options::captureDirectory().isEmpty())
158 fileDirectoryT->setText(Options::captureDirectory());
167 for (
auto &button : qButtons)
168 button->setAutoDefault(false);
172 refreshOpticalTrain();
177 qDeleteAll(state()->allJobs());
178 state()->allJobs().clear();
181void Camera::initCamera()
183 KStarsData::Instance()->
userdb()->GetAllDSLRInfos(state()->DSLRInfos());
184 state()->getSequenceQueue()->loadOptions();
186 if (state()->DSLRInfos().count() > 0)
188 qCDebug(KSTARS_EKOS_CAPTURE) <<
"DSLR Cameras Info:";
189 qCDebug(KSTARS_EKOS_CAPTURE) << state()->DSLRInfos();
192 setupOpticalTrainManager();
195 state()->getMeridianFlipState();
212 restartCamera(activeCamera()->getDeviceName());
217 static_cast<void(Camera::*)()
>(&Camera::saveSequenceQueue));
220 &Camera::selectedJobChanged);
224 resetJobEdit(m_JobUnderEdit);
249 connect(m_FilterManager.get(), &FilterManager::ready,
this, &Camera::updateCurrentFilterPosition);
254 state()->updateHFRThreshold();
255 generatePreviewFilename();
266 m_CalibrationUI->captureCalibrationParkMount->setChecked(false);
271 m_CalibrationUI->captureCalibrationWall->setChecked(false);
281 if (devices()->getActiveCamera())
283 QVariantMap auxInfo = devices()->getActiveCamera()->getDriverInfo()->getAuxInfo();
284 auxInfo[
QString(
"%1_TC").
arg(devices()->getActiveCamera()->getDeviceName())] = toggled;
285 devices()->getActiveCamera()->getDriverInfo()->setAuxInfo(auxInfo);
290 if (devices()->getActiveCamera())
291 devices()->getActiveCamera()->setTemperature(cameraTemperatureN->value());
295 if (devices()->getActiveCamera())
296 devices()->getActiveCamera()->setCoolerControl(
true);
300 if (devices()->getActiveCamera())
301 devices()->getActiveCamera()->setCoolerControl(
false);
307 placeholderFormatT->setText(KSUtils::getDefaultPath(
"PlaceholderFormat"));
311 &Camera::checkFrameType);
316 if (checked == false)
317 state()->getRefocusState()->setInSequenceFocus(false);
323 connect(m_cameraState.get(), &CameraState::newLimitFocusHFR,
this, [
this](
double hfr)
325 m_LimitsUI->hFRDeviation->setValue(hfr);
328 state()->getCaptureDelayTimer().setSingleShot(
true);
329 connect(&state()->getCaptureDelayTimer(), &
QTimer::timeout, m_cameraProcess.get(), &CameraProcess::captureImage);
332 state()->getCaptureTimeout().setSingleShot(
true);
334 &CameraProcess::processCaptureTimeout);
340 fileRemoteDirT->setEnabled(index != 0);
345 customPropertiesDialog()->show();
346 customPropertiesDialog()->raise();
349 connect(customPropertiesDialog(), &CustomProperties::valueChanged,
this, [&]()
351 const double newGain = getGain();
352 if (captureGainN && newGain >= 0)
353 captureGainN->setValue(newGain);
354 const int newOffset = getOffset();
356 captureOffsetN->setValue(newOffset);
360 connect(m_cameraState.data(), &CameraState::newStatus, captureStatusWidget, &LedStatusWidget::setCaptureState);
365 loadGlobalSettings();
366 connectSyncSettings();
370 updateHFRCheckAlgo();
373 updateHFRCheckAlgo();
376 updateHFRCheckAlgo();
383 generatePreviewFilename();
388 generatePreviewFilename();
392 &Camera::generatePreviewFilename);
395 generatePreviewFilename();
396 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Changed target to" << targetNameT->text() <<
"because of user edit";
399 placeholderFormatT->setText(Options::placeholderFormat());
402 generatePreviewFilename();
406 connect(m_cameraState.data(), &CameraState::captureBusy,
this, &Camera::setBusy);
407 connect(m_cameraState.data(), &CameraState::startCapture,
this, &Camera::start);
408 connect(m_cameraState.data(), &CameraState::abortCapture,
this, &Camera::abort);
409 connect(m_cameraState.data(), &CameraState::suspendCapture,
this, &Camera::suspend);
410 connect(m_cameraState.data(), &CameraState::newLog,
this, &Camera::appendLogText);
411 connect(m_cameraState.data(), &CameraState::sequenceChanged,
this, &Camera::sequenceChanged);
412 connect(m_cameraState.data(), &CameraState::updatePrepareState,
this, &Camera::updatePrepareState);
413 connect(m_cameraState.data(), &CameraState::newFocusStatus,
this, &Camera::updateFocusStatus);
414 connect(m_cameraState.data(), &CameraState::runAutoFocus,
this, &Camera::runAutoFocus);
415 connect(m_cameraState.data(), &CameraState::resetFocus,
this, &Camera::resetFocus);
416 connect(m_cameraState.data(), &CameraState::adaptiveFocus,
this, &Camera::adaptiveFocus);
417 connect(m_cameraState.data(), &CameraState::newMeridianFlipStage,
this, &Camera::updateMeridianFlipStage);
418 connect(m_cameraState.data(), &CameraState::guideAfterMeridianFlip,
this, &Camera::guideAfterMeridianFlip);
419 connect(m_cameraState.data(), &CameraState::newStatus,
this, &Camera::updateCameraStatus);
420 connect(m_cameraState.data(), &CameraState::meridianFlipStarted,
this, &Camera::meridianFlipStarted);
422 connect(m_cameraProcess.data(), &CameraProcess::refreshCamera,
this, &Camera::updateCamera);
423 connect(m_cameraProcess.data(), &CameraProcess::sequenceChanged,
this, &Camera::sequenceChanged);
424 connect(m_cameraProcess.data(), &CameraProcess::addJob,
this, &Camera::addJob);
425 connect(m_cameraProcess.data(), &CameraProcess::newExposureProgress,
this, &Camera::newExposureProgress);
426 connect(m_cameraProcess.data(), &CameraProcess::newDownloadProgress,
this, &Camera::updateDownloadProgress);
427 connect(m_cameraProcess.data(), &CameraProcess::newImage,
this, &Camera::newImage);
428 connect(m_cameraProcess.data(), &CameraProcess::captureComplete,
this, &Camera::captureComplete);
429 connect(m_cameraProcess.data(), &CameraProcess::updateCaptureCountDown,
this, &Camera::updateCaptureCountDown);
430 connect(m_cameraProcess.data(), &CameraProcess::processingFITSfinished,
this, &Camera::processingFITSfinished);
431 connect(m_cameraProcess.data(), &CameraProcess::captureStopped,
this, &Camera::captureStopped);
432 connect(m_cameraProcess.data(), &CameraProcess::darkFrameCompleted,
this, &Camera::imageCapturingCompleted);
433 connect(m_cameraProcess.data(), &CameraProcess::updateMeridianFlipStage,
this, &Camera::updateMeridianFlipStage);
434 connect(m_cameraProcess.data(), &CameraProcess::syncGUIToJob,
this, &Camera::syncGUIToJob);
435 connect(m_cameraProcess.data(), &CameraProcess::refreshCameraSettings,
this, &Camera::refreshCameraSettings);
436 connect(m_cameraProcess.data(), &CameraProcess::updateFrameProperties,
this, &Camera::updateFrameProperties);
437 connect(m_cameraProcess.data(), &CameraProcess::rotatorReverseToggled,
this, &Camera::setRotatorReversed);
438 connect(m_cameraProcess.data(), &CameraProcess::refreshFilterSettings,
this, &Camera::refreshFilterSettings);
439 connect(m_cameraProcess.data(), &CameraProcess::suspendGuiding,
this, &Camera::suspendGuiding);
440 connect(m_cameraProcess.data(), &CameraProcess::resumeGuiding,
this, &Camera::resumeGuiding);
441 connect(m_cameraProcess.data(), &CameraProcess::driverTimedout,
this, &Camera::driverTimedout);
442 connect(m_cameraProcess.data(), &CameraProcess::createJob, [
this](SequenceJob::SequenceJobType jobType)
445 process()->jobCreated(createJob(jobType));
447 connect(m_cameraProcess.data(), &CameraProcess::updateJobTable,
this, &Camera::updateJobTable);
448 connect(m_cameraProcess.data(), &CameraProcess::newLog,
this, &Camera::appendLogText);
449 connect(m_cameraProcess.data(), &CameraProcess::stopCapture,
this, &Camera::stop);
450 connect(m_cameraProcess.data(), &CameraProcess::jobStarting,
this, &Camera::jobStarting);
451 connect(m_cameraProcess.data(), &CameraProcess::abortFocus,
this, &Camera::abortFocus);
452 connect(m_cameraProcess.data(), &CameraProcess::cameraReady,
this, &Camera::ready);
453 connect(m_cameraProcess.data(), &CameraProcess::captureAborted,
this, &Camera::captureAborted);
454 connect(m_cameraProcess.data(), &CameraProcess::captureRunning,
this, &Camera::captureRunning);
455 connect(m_cameraProcess.data(), &CameraProcess::captureImageStarted,
this, &Camera::captureImageStarted);
456 connect(m_cameraProcess.data(), &CameraProcess::jobExecutionPreparationStarted,
this,
457 &Camera::jobExecutionPreparationStarted);
458 connect(m_cameraProcess.data(), &CameraProcess::jobPrepared,
this, &Camera::jobPrepared);
459 connect(m_cameraProcess.data(), &CameraProcess::captureTarget,
this, &Camera::setTargetName);
460 connect(m_cameraProcess.data(), &CameraProcess::downloadingFrame,
this, [
this]()
462 captureStatusWidget->setStatus(i18n(
"Downloading..."), Qt::yellow);
466 connect(m_cameraState.data(), &CameraState::executeActiveJob, m_cameraProcess.data(),
467 &CameraProcess::executeJob);
468 connect(m_cameraState.data(), &CameraState::captureStarted, m_cameraProcess.data(),
469 &CameraProcess::captureStarted);
470 connect(m_cameraState.data(), &CameraState::checkFocus,
this, &Camera::checkFocus);
473 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::newCCDTemperatureValue,
this,
475 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::CameraConnected,
this, [
this](
bool connected)
477 CaptureSettingsGroup->setEnabled(connected);
478 fileSettingsGroup->setEnabled(connected);
479 sequenceBox->setEnabled(connected);
480 for (auto &oneChild : sequenceControlsButtonGroup->buttons())
481 oneChild->setEnabled(connected);
484 trainLayout->setEnabled(true);
486 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::FilterWheelConnected,
this, [
this](
bool connected)
488 FilterPosLabel->setEnabled(connected);
489 FilterPosCombo->setEnabled(connected);
490 filterManagerB->setEnabled(connected);
492 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::newRotator,
this, &Camera::setRotator);
493 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::newRotatorAngle,
this, &Camera::updateRotatorAngle,
495 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::newFilterWheel,
this, &Camera::setFilterWheel);
498 connect(m_cameraState.data(), &CameraState::newFilterPosition,
499 m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::setFilterPosition);
500 connect(m_cameraState.data(), &CameraState::abortFastExposure,
501 m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::abortFastExposure);
504 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::scopeStatusChanged,
505 m_cameraState.data(), &CameraState::setScopeState);
506 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::pierSideChanged,
507 m_cameraState.data(), &CameraState::setPierSide);
508 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::scopeParkStatusChanged,
509 m_cameraState.data(), &CameraState::setScopeParkState);
510 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::domeStatusChanged,
511 m_cameraState.data(), &CameraState::setDomeState);
512 connect(m_DeviceAdaptor.data(), &CaptureDeviceAdaptor::dustCapStatusChanged,
513 m_cameraState.data(), &CameraState::dustCapStateChanged);
516void Camera::updateRotatorAngle(
double value)
518 IPState RState = devices()->rotator()->absoluteAngleState();
519 if (RState == IPS_OK)
520 m_RotatorControlPanel->updateRotator(value);
522 m_RotatorControlPanel->updateGauge(value);
525void Camera::setRotatorReversed(
bool toggled)
527 m_RotatorControlPanel->reverseDirection->setEnabled(
true);
528 m_RotatorControlPanel->reverseDirection->blockSignals(
true);
529 m_RotatorControlPanel->reverseDirection->setChecked(toggled);
530 m_RotatorControlPanel->reverseDirection->blockSignals(
false);
533void Camera::updateCCDTemperature(
double value)
535 if (cameraTemperatureS->isEnabled() ==
false && devices()->getActiveCamera())
537 if (devices()->getActiveCamera()->getPermission(
"CCD_TEMPERATURE") != IP_RO)
538 process()->checkCamera();
541 temperatureOUT->setText(
QString(
"%L1º").arg(value, 0,
'f', 1));
543 if (cameraTemperatureN->cleanText().isEmpty())
544 cameraTemperatureN->setValue(value);
547void Camera::setFocusStatus(FocusState newstate)
550 state()->updateFocusState(newstate);
553void Camera::updateFocusStatus(FocusState newstate)
555 if ((state()->getRefocusState()->isRefocusing()
556 || state()->getRefocusState()->isInSequenceFocus()) && activeJob()
557 && activeJob()->getStatus() == JOB_BUSY)
562 appendLogText(
i18n(
"Focus complete."));
563 captureStatusWidget->setStatus(
i18n(
"Focus complete."),
Qt::yellow);
567 captureStatusWidget->setStatus(
i18n(
"Autofocus failed."),
Qt::darkRed);
576void Camera::updateCamera(
bool isValid)
578 auto isConnected = activeCamera() && activeCamera()->isConnected();
579 CaptureSettingsGroup->setEnabled(isConnected);
580 fileSettingsGroup->setEnabled(isConnected);
581 sequenceBox->setEnabled(isConnected);
582 for (
auto &oneChild : sequenceControlsButtonGroup->buttons())
583 oneChild->setEnabled(isConnected);
587 auto name = activeCamera()->getDeviceName();
588 opticalTrainCombo->setToolTip(
QString(
"%1 @ %2").arg(name, currentScope()[
"name"].
toString()));
589 emit settingsUpdated(getAllSettings());
590 emit refreshCamera(m_cameraId,
true);
593 emit refreshCamera(m_cameraId,
false);
597void Camera::refreshCameraSettings()
601 auto camera = activeCamera();
602 auto targetChip = devices()->getActiveChip();
604 if (!m_standAlone && (!camera || !targetChip || !targetChip->getCCD() || targetChip->isCapturing()))
610 if (camera->hasCoolerControl())
612 coolerOnB->setEnabled(
true);
613 coolerOffB->setEnabled(
true);
614 coolerOnB->setChecked(camera->isCoolerOn());
615 coolerOffB->setChecked(!camera->isCoolerOn());
619 coolerOnB->setEnabled(
false);
620 coolerOnB->setChecked(
false);
621 coolerOffB->setEnabled(
false);
622 coolerOffB->setChecked(
false);
625 updateFrameProperties();
627 updateCaptureFormats();
629 customPropertiesDialog()->setCCD(camera);
631 liveVideoB->setEnabled(camera->hasVideoStream());
632 if (camera->hasVideoStream())
633 setVideoStreamEnabled(camera->isStreamingEnabled());
641 connect(camera, &ISD::Camera::error, m_cameraProcess.data(), &CameraProcess::processCaptureError,
649 DarkLibrary::Instance()->checkCamera();
652void Camera::processCameraNumber(INDI::Property prop)
654 if (devices()->getActiveCamera() ==
nullptr)
657 if ((prop.isNameMatch(
"CCD_FRAME") && state()->useGuideHead() ==
false) ||
658 (prop.isNameMatch(
"GUIDER_FRAME") && state()->useGuideHead()))
659 updateFrameProperties();
660 else if ((prop.isNameMatch(
"CCD_INFO") && state()->useGuideHead() ==
false) ||
661 (prop.isNameMatch(
"GUIDER_INFO") && state()->useGuideHead()))
662 updateFrameProperties(1);
663 else if (prop.isNameMatch(
"CCD_TRANSFER_FORMAT") || prop.isNameMatch(
"CCD_CAPTURE_FORMAT"))
664 updateCaptureFormats();
665 else if (prop.isNameMatch(
"CCD_CONTROLS"))
667 auto nvp = prop.getNumber();
668 auto gain = nvp->findWidgetByName(
"Gain");
671 auto offset = nvp->findWidgetByName(
"Offset");
675 else if (prop.isNameMatch(
"CCD_GAIN"))
677 auto nvp = prop.getNumber();
678 currentGainLabel->setText(
QString::number(nvp->at(0)->getValue(),
'f', 0));
680 else if (prop.isNameMatch(
"CCD_OFFSET"))
682 auto nvp = prop.getNumber();
683 currentOffsetLabel->setText(
QString::number(nvp->at(0)->getValue(),
'f', 0));
688void Camera::updateTargetDistance(
double targetDiff)
691 targetDriftLabel->setVisible(
true);
692 targetDrift->setVisible(
true);
693 targetDriftUnit->setVisible(
true);
695 targetDrift->setText(
QString(
"%L1").arg(targetDiff, 0,
'd', 1));
706 return CCDFrameTypeNames[
type];
712 return CCDFrameTypeNames[
type];
714 return QString(
"%1 %2").
arg(filter).
arg(CCDFrameTypeNames[type]);
720 return CCDFrameTypeNames[
type];
725void Camera::captureRunning()
727 emit captureStarting(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(),
728 activeJob()->getCoreProperty(SequenceJob::SJ_Filter).
toString());
729 if (isActiveJobPreview())
730 frameInfoLabel->setText(
"Expose (-/-):");
732 frameInfoLabel->setText(
QString(
"%1 (%L3/%L4):").arg(frameLabel(activeJob()->getFrameType(),
733 activeJob()->getCoreProperty(SequenceJob::SJ_Filter).
toString()))
734 .arg(activeJob()->getCompleted()).arg(activeJob()->getCoreProperty(
735 SequenceJob::SJ_Count).toInt()));
738 avgDownloadTime->setVisible(
true);
739 avgDownloadLabel->setVisible(
true);
740 secLabel->setVisible(
true);
742 avgDownloadTime->setText(
QString(
"%L1").arg(state()->averageDownloadTime(), 0,
'd', 2));
745 if (state()->isLooping() ==
false && activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
746 appendLogText(
i18n(
"Capturing %1-second %2 image...",
747 QString(
"%L1").arg(activeJob()->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(), 0,
'f', 3),
748 activeJob()->getCoreProperty(SequenceJob::SJ_Filter).
toString()));
751void Camera::captureImageStarted()
753 if (devices()->filterWheel() !=
nullptr)
757 process()->updateFilterInfo();
758 updateCurrentFilterPosition();
762 if (activeJob()->getCalibrationStage() == SequenceJobState::CAL_CALIBRATION)
763 captureStatusWidget->setStatus(
i18n(
"Calibrating..."),
Qt::yellow);
766void Camera::jobExecutionPreparationStarted()
768 if (activeJob() ==
nullptr)
771 qWarning(KSTARS_EKOS_CAPTURE) <<
"jobExecutionPreparationStarted with null state()->getActiveJob().";
774 if (activeJob()->jobType() == SequenceJob::JOBTYPE_PREVIEW)
775 updateStartButtons(
true,
false);
780 int index = state()->allJobs().indexOf(job);
782 queueTable->selectRow(index);
784 if (activeJob()->jobType() != SequenceJob::JOBTYPE_PREVIEW)
787 imgProgress->setEnabled(
true);
788 imgProgress->setMaximum(activeJob()->getCoreProperty(SequenceJob::SJ_Count).toInt());
789 imgProgress->setValue(activeJob()->getCompleted());
793void Camera::setTargetName(
const QString &newTargetName)
796 if (activeJob() ==
nullptr)
799 targetNameT->setText(newTargetName);
800 auto rows = queueTable->selectionModel()->selectedRows();
804 int pos = rows.constFirst().row();
806 if (state()->allJobs().size() > pos)
807 state()->allJobs().at(pos)->setCoreProperty(SequenceJob::SJ_TargetName, newTargetName);
810 emit captureTarget(newTargetName);
814void Camera::jobStarting()
816 if (m_LimitsUI->enforceAutofocusHFR->isChecked() && state()->getRefocusState()->isAutoFocusReady() ==
false)
817 appendLogText(
i18n(
"Warning: in-sequence focusing is selected but autofocus process was not started."));
818 if (m_LimitsUI->enforceAutofocusOnTemperature->isChecked()
819 && state()->getRefocusState()->isAutoFocusReady() ==
false)
820 appendLogText(
i18n(
"Warning: temperature delta check is selected but autofocus process was not started."));
822 updateStartButtons(
true,
false);
826void Camera::capturePreview()
828 process()->capturePreview();
831void Camera::startFraming()
833 process()->capturePreview(
true);
836void Camera::generateDarkFlats()
838 const auto existingJobs = state()->allJobs().size();
839 uint8_t jobsAdded = 0;
841 for (
int i = 0; i < existingJobs; i++)
843 if (state()->allJobs().at(i)->getFrameType() != FRAME_FLAT)
846 syncGUIToJob(state()->allJobs().at(i));
848 captureTypeS->setCurrentIndex(FRAME_DARK);
849 createJob(SequenceJob::JOBTYPE_DARKFLAT);
855 appendLogText(
i18np(
"One dark flats job was created.",
"%1 dark flats jobs were created.", jobsAdded));
859void Camera::updateDownloadProgress(
double downloadTimeLeft,
const QString &devicename)
861 frameRemainingTime->setText(state()->imageCountDown().
toString(
"hh:mm:ss"));
862 emit newDownloadProgress(downloadTimeLeft, devicename);
865void Camera::updateCaptureCountDown(
int deltaMillis)
867 state()->imageCountDownAddMSecs(deltaMillis);
868 state()->sequenceCountDownAddMSecs(deltaMillis);
869 frameRemainingTime->setText(state()->imageCountDown().
toString(
"hh:mm:ss"));
870 if (!isActiveJobPreview())
871 jobRemainingTime->setText(state()->sequenceCountDown().
toString(
"hh:mm:ss"));
873 jobRemainingTime->setText(
"--:--:--");
879 createNewJobTableRow(job);
882void Camera::editJobFinished()
884 if (queueTable->currentRow() < 0)
885 qCWarning(KSTARS_EKOS_CAPTURE()) <<
"Editing finished, but no row selected!";
887 int currentRow = queueTable->currentRow();
888 SequenceJob *job = state()->allJobs().at(currentRow);
889 updateJobFromUI(job);
892 updateJobTable(job,
true);
895 QJsonObject jsonJob = createJsonJob(job, currentRow);
896 state()->getSequence().replace(currentRow, jsonJob);
897 emit sequenceChanged(state()->getSequence());
900 appendLogText(
i18n(
"Job #%1 changes applied.", currentRow + 1));
903void Camera::imageCapturingCompleted()
911 if (state()->isLooping())
919 if (devices()->getActiveCamera()->isFastExposureEnabled() ==
false)
920 DarkLibrary::Instance()->disconnect(
this);
923 if (thejob->getCoreProperty(SequenceJob::SJ_Exposure).toDouble() >= 1)
924 KSNotification::event(
QLatin1String(
"EkosCaptureImageReceived"),
i18n(
"Captured image received"),
925 KSNotification::Capture);
928 if (thejob->jobType() == SequenceJob::JOBTYPE_PREVIEW)
932 imgProgress->setValue(thejob->getCompleted());
935void Camera::captureStopped()
937 imgProgress->reset();
938 imgProgress->setEnabled(
false);
940 frameRemainingTime->setText(
"--:--:--");
941 jobRemainingTime->setText(
"--:--:--");
942 frameInfoLabel->setText(
i18n(
"Expose (-/-):"));
945 auto captureState = state()->getCaptureState();
946 if (captureState == CAPTURE_ABORTED || captureState == CAPTURE_SUSPENDED || captureState == CAPTURE_COMPLETE)
947 updateStartButtons(
false,
false);
950void Camera::processingFITSfinished(
bool success)
953 if (success ==
false)
957 if (devices()->getActiveCamera()
958 && devices()->getActiveCamera()->getUploadMode() != ISD::Camera::UPLOAD_LOCAL)
959 previewB->setEnabled(
true);
961 imageCapturingCompleted();
964void Camera::checkFrameType(
int index)
966 calibrationB->setEnabled(index != FRAME_LIGHT);
967 generateDarkFlatsB->setEnabled(index != FRAME_LIGHT);
970void Camera::updateStartButtons(
bool start,
bool pause)
976 startB->setToolTip(
i18n(
"Stop Sequence"));
982 startB->setToolTip(
i18n(pause ?
"Resume Sequence" :
"Start Sequence"));
984 pauseB->setEnabled(start && !pause);
987void Camera::setBusy(
bool enable)
989 previewB->setEnabled(!enable);
990 loopB->setEnabled(!enable);
991 opticalTrainCombo->setEnabled(!enable);
992 trainB->setEnabled(!enable);
999void Camera::updatePrepareState(CaptureState prepareState)
1001 state()->setCaptureState(prepareState);
1003 if (activeJob() ==
nullptr)
1005 qWarning(KSTARS_EKOS_CAPTURE) <<
"updatePrepareState with null activeJob().";
1010 switch (prepareState)
1013 appendLogText(
i18n(
"Setting temperature to %1 °C...", activeJob()->getTargetTemperature()));
1014 captureStatusWidget->setStatus(
i18n(
"Set Temp to %1 °C...", activeJob()->getTargetTemperature()),
1018 appendLogText(
i18n(
"Waiting for guide drift below %1\"...", Options::startGuideDeviation()));
1019 captureStatusWidget->setStatus(
i18n(
"Wait for Guider < %1\"...", Options::startGuideDeviation()),
Qt::yellow);
1023 appendLogText(
i18n(
"Setting camera to %1 degrees E of N...", activeJob()->getTargetRotation()));
1024 captureStatusWidget->setStatus(
i18n(
"Set Camera to %1 deg...", activeJob()->getTargetRotation()),
1034SequenceJob *Camera::createJob(SequenceJob::SequenceJobType jobtype, FilenamePreviewType filenamePreview)
1038 updateJobFromUI(job, filenamePreview);
1041 if (jobtype == SequenceJob::JOBTYPE_PREVIEW || filenamePreview != Camera::NOT_PREVIEW)
1045 if (checkUploadPaths(filenamePreview) ==
false)
1049 state()->allJobs().append(job);
1052 createNewJobTableRow(job);
1057bool Camera::removeJob(
int index)
1059 if (state()->getCaptureState() != CAPTURE_IDLE && state()->getCaptureState() != CAPTURE_ABORTED
1060 && state()->getCaptureState() != CAPTURE_COMPLETE)
1069 if (index < 0 || index >= state()->allJobs().count())
1072 queueTable->removeRow(index);
1073 QJsonArray seqArray = state()->getSequence();
1075 state()->setSequence(seqArray);
1076 emit sequenceChanged(seqArray);
1078 if (state()->allJobs().empty())
1083 state()->removeCapturedFrameCount(job->getSignature(), job->getCompleted());
1085 state()->allJobs().removeOne(job);
1086 if (job == activeJob())
1087 state()->setActiveJob(
nullptr);
1091 if (queueTable->rowCount() == 0)
1092 removeFromQueueB->setEnabled(
false);
1094 if (queueTable->rowCount() == 1)
1096 queueUpB->setEnabled(
false);
1097 queueDownB->setEnabled(
false);
1100 if (index < queueTable->rowCount())
1101 queueTable->selectRow(index);
1102 else if (queueTable->rowCount() > 0)
1103 queueTable->selectRow(queueTable->rowCount() - 1);
1105 if (queueTable->rowCount() == 0)
1107 queueSaveAsB->setEnabled(
false);
1108 queueSaveB->setEnabled(
false);
1109 resetB->setEnabled(
false);
1112 state()->setDirty(
true);
1117void Camera::loadSequenceQueue()
1121 "Ekos Sequence Queue (*.esq)");
1125 if (fileURL.
isValid() ==
false)
1128 KSNotification::sorry(message,
i18n(
"Invalid URL"));
1137void Camera::saveSequenceQueue()
1139 QUrl backupCurrent = state()->sequenceURL();
1141 if (state()->sequenceURL().toLocalFile().startsWith(
QLatin1String(
"/tmp/"))
1142 || state()->sequenceURL().toLocalFile().contains(
"/Temp"))
1143 state()->setSequenceURL(
QUrl(
""));
1146 if (state()->dirty() ==
false && !state()->sequenceURL().isEmpty())
1149 if (state()->sequenceURL().isEmpty())
1152 "Save Ekos Sequence Queue"),
1154 "Ekos Sequence Queue (*.esq)"));
1156 if (state()->sequenceURL().isEmpty())
1158 state()->setSequenceURL(backupCurrent);
1164 if (state()->sequenceURL().toLocalFile().endsWith(
QLatin1String(
".esq")) ==
false)
1165 state()->setSequenceURL(
QUrl(
"file:" + state()->sequenceURL().toLocalFile() +
".esq"));
1169 if (state()->sequenceURL().
isValid())
1172 if ((process()->saveSequenceQueue(state()->sequenceURL().toLocalFile(), !m_standAlone)) ==
false)
1174 KSNotification::error(
i18n(
"Failed to save sequence queue"),
i18n(
"Save"));
1178 state()->setDirty(
false);
1182 QString message =
i18n(
"Invalid URL: %1", state()->sequenceURL().url());
1183 KSNotification::sorry(message,
i18n(
"Invalid URL"));
1188void Camera::saveSequenceQueueAs()
1190 state()->setSequenceURL(
QUrl(
""));
1191 saveSequenceQueue();
1194void Camera::updateJobTable(
SequenceJob *job,
bool full)
1199 while (iter.hasNext())
1200 updateJobTable(iter.next(), full);
1205 int row = state()->allJobs().indexOf(job);
1206 if (row >= 0 && row < queueTable->rowCount())
1208 updateRowStyle(job);
1211 status->setText(job->getStatusString());
1212 updateJobTableCountCell(job, count);
1216 bool isDarkFlat = job->jobType() == SequenceJob::JOBTYPE_DARKFLAT;
1219 if (FilterPosCombo->findText(job->getCoreProperty(SequenceJob::SJ_Filter).toString()) >= 0 &&
1220 (captureTypeS->currentIndex() == FRAME_LIGHT || captureTypeS->currentIndex() == FRAME_FLAT
1222 filter->setText(job->getCoreProperty(SequenceJob::SJ_Filter).toString());
1227 exp->
setText(
QString(
"%L1").arg(job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(), 0,
'f',
1228 captureExposureN->decimals()));
1231 type->setText(isDarkFlat ?
i18n(
"Dark Flat") : CCDFrameTypeNames[job->getFrameType()]);
1234 QPoint binning = job->getCoreProperty(SequenceJob::SJ_Binning).toPoint();
1238 if (job->getCoreProperty(SequenceJob::SJ_ISOIndex).toInt() != -1)
1239 iso->
setText(captureISOS->itemText(job->getCoreProperty(SequenceJob::SJ_ISOIndex).toInt()));
1240 else if (job->getCoreProperty(SequenceJob::SJ_Gain).toDouble() >= 0)
1246 if (job->getCoreProperty(SequenceJob::SJ_Offset).toDouble() >= 0)
1253 if (queueTable->rowCount() > 0)
1255 queueSaveAsB->setEnabled(
true);
1256 queueSaveB->setEnabled(
true);
1257 resetB->setEnabled(
true);
1258 state()->setDirty(
true);
1261 if (queueTable->rowCount() > 1)
1263 queueUpB->setEnabled(
true);
1264 queueDownB->setEnabled(
true);
1270void Camera::updateJobFromUI(
SequenceJob *job, FilenamePreviewType filenamePreview)
1272 job->setCoreProperty(SequenceJob::SJ_Format, captureFormatS->currentText());
1273 job->setCoreProperty(SequenceJob::SJ_Encoding, captureEncodingS->currentText());
1276 job->setISO(captureISOS->currentIndex());
1278 job->setCoreProperty(SequenceJob::SJ_Gain, getGain());
1279 job->setCoreProperty(SequenceJob::SJ_Offset, getOffset());
1281 if (cameraTemperatureN->isEnabled())
1283 job->setCoreProperty(SequenceJob::SJ_EnforceTemperature, cameraTemperatureS->isChecked());
1284 job->setTargetTemperature(cameraTemperatureN->value());
1287 job->setScripts(m_scriptsManager->getScripts());
1288 job->setUploadMode(
static_cast<ISD::Camera::UploadMode
>(fileUploadModeS->currentIndex()));
1291 job->setFlatFieldDuration(m_CalibrationUI->captureCalibrationDurationManual->isChecked() ? DURATION_MANUAL :
1294 int action = ACTION_NONE;
1295 if (m_CalibrationUI->captureCalibrationParkMount->isChecked())
1296 action |= ACTION_PARK_MOUNT;
1297 if (m_CalibrationUI->captureCalibrationParkDome->isChecked())
1298 action |= ACTION_PARK_DOME;
1299 if (m_CalibrationUI->captureCalibrationWall->isChecked())
1301 bool azOk =
false, altOk =
false;
1302 auto wallAz = m_CalibrationUI->azBox->createDms(&azOk);
1303 auto wallAlt = m_CalibrationUI->altBox->createDms(&altOk);
1307 action = (action & ~ACTION_PARK_MOUNT) | ACTION_WALL;
1309 wallSkyPoint.
setAz(wallAz);
1310 wallSkyPoint.
setAlt(wallAlt);
1311 job->setWallCoord(wallSkyPoint);
1315 if (m_CalibrationUI->captureCalibrationUseADU->isChecked())
1317 job->setCoreProperty(SequenceJob::SJ_TargetADU, m_CalibrationUI->captureCalibrationADUValue->value());
1318 job->setCoreProperty(SequenceJob::SJ_TargetADUTolerance,
1319 m_CalibrationUI->captureCalibrationADUTolerance->value());
1320 job->setCoreProperty(SequenceJob::SJ_SkyFlat, m_CalibrationUI->captureCalibrationSkyFlats->isChecked());
1323 job->setCalibrationPreAction(action);
1325 job->setFrameType(
static_cast<CCDFrameType
>(qMax(0, captureTypeS->currentIndex())));
1327 if (FilterPosCombo->currentIndex() != -1 && (m_standAlone || devices()->filterWheel() !=
nullptr))
1328 job->setTargetFilter(FilterPosCombo->currentIndex() + 1, FilterPosCombo->currentText());
1330 job->setCoreProperty(SequenceJob::SJ_Exposure, captureExposureN->value());
1332 job->setCoreProperty(SequenceJob::SJ_Count, captureCountN->value());
1334 job->setCoreProperty(SequenceJob::SJ_Binning,
QPoint(captureBinHN->value(), captureBinVN->value()));
1337 job->setCoreProperty(SequenceJob::SJ_Delay, captureDelayN->value() * 1000);
1340 job->setCustomProperties(customPropertiesDialog()->getCustomProperties());
1342 job->setCoreProperty(SequenceJob::SJ_ROI,
QRect(captureFrameXN->value(), captureFrameYN->value(),
1343 captureFrameWN->value(),
1344 captureFrameHN->value()));
1345 job->setCoreProperty(SequenceJob::SJ_RemoteDirectory, fileRemoteDirT->text());
1346 job->setCoreProperty(SequenceJob::SJ_LocalDirectory, fileDirectoryT->text());
1347 job->setCoreProperty(SequenceJob::SJ_TargetName, targetNameT->text());
1348 job->setCoreProperty(SequenceJob::SJ_PlaceholderFormat, placeholderFormatT->text());
1349 job->setCoreProperty(SequenceJob::SJ_PlaceholderSuffix, formatSuffixN->value());
1351 job->setCoreProperty(SequenceJob::SJ_DitherPerJobFrequency, m_LimitsUI->guideDitherPerJobFrequency->value());
1353 auto placeholderPath = PlaceholderPath();
1354 placeholderPath.updateFullPrefix(job, placeholderFormatT->text());
1356 QString signature = placeholderPath.generateSequenceFilename(*job,
1357 filenamePreview != Camera::REMOTE_PREVIEW,
true, 1,
1358 ".fits",
"",
false,
true);
1359 job->setCoreProperty(SequenceJob::SJ_Signature, signature);
1367 qWarning(KSTARS_EKOS_CAPTURE) <<
"syncGuiToJob with null job.";
1372 const auto roi = job->getCoreProperty(SequenceJob::SJ_ROI).toRect();
1374 captureFormatS->setCurrentText(job->getCoreProperty(SequenceJob::SJ_Format).toString());
1375 captureEncodingS->setCurrentText(job->getCoreProperty(SequenceJob::SJ_Encoding).toString());
1376 captureExposureN->setValue(job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble());
1377 captureBinHN->setValue(job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().x());
1378 captureBinVN->setValue(job->getCoreProperty(SequenceJob::SJ_Binning).toPoint().y());
1379 captureFrameXN->setValue(roi.x());
1380 captureFrameYN->setValue(roi.y());
1381 captureFrameWN->setValue(roi.width());
1382 captureFrameHN->setValue(roi.height());
1383 FilterPosCombo->setCurrentIndex(job->getTargetFilter() - 1);
1384 captureTypeS->setCurrentIndex(job->getFrameType());
1385 captureCountN->setValue(job->getCoreProperty(SequenceJob::SJ_Count).toInt());
1386 captureDelayN->setValue(job->getCoreProperty(SequenceJob::SJ_Delay).toInt() / 1000);
1387 targetNameT->setText(job->getCoreProperty(SequenceJob::SJ_TargetName).toString());
1388 fileDirectoryT->setText(job->getCoreProperty(SequenceJob::SJ_LocalDirectory).toString());
1389 fileUploadModeS->setCurrentIndex(job->getUploadMode());
1390 fileRemoteDirT->setEnabled(fileUploadModeS->currentIndex() != 0);
1391 fileRemoteDirT->setText(job->getCoreProperty(SequenceJob::SJ_RemoteDirectory).toString());
1392 placeholderFormatT->setText(job->getCoreProperty(SequenceJob::SJ_PlaceholderFormat).toString());
1393 formatSuffixN->setValue(job->getCoreProperty(SequenceJob::SJ_PlaceholderSuffix).toUInt());
1396 cameraTemperatureS->setChecked(job->getCoreProperty(SequenceJob::SJ_EnforceTemperature).toBool());
1397 if (job->getCoreProperty(SequenceJob::SJ_EnforceTemperature).toBool())
1398 cameraTemperatureN->setValue(job->getTargetTemperature());
1401 m_LimitsUI->guideDitherPerJobFrequency->setValue(job->getCoreProperty(
1402 SequenceJob::SJ_DitherPerJobFrequency).toInt());
1403 syncLimitSettings();
1406 calibrationB->setEnabled(job->getFrameType() != FRAME_LIGHT);
1407 generateDarkFlatsB->setEnabled(job->getFrameType() != FRAME_LIGHT);
1409 if (job->getFlatFieldDuration() == DURATION_MANUAL)
1410 m_CalibrationUI->captureCalibrationDurationManual->setChecked(
true);
1412 m_CalibrationUI->captureCalibrationUseADU->setChecked(
true);
1415 const auto action = job->getCalibrationPreAction();
1416 if (action & ACTION_WALL)
1418 m_CalibrationUI->azBox->setText(job->getWallCoord().az().toDMSString());
1419 m_CalibrationUI->altBox->setText(job->getWallCoord().alt().toDMSString());
1421 m_CalibrationUI->captureCalibrationWall->setChecked(action & ACTION_WALL);
1422 m_CalibrationUI->captureCalibrationParkMount->setChecked(action & ACTION_PARK_MOUNT);
1423 m_CalibrationUI->captureCalibrationParkDome->setChecked(action & ACTION_PARK_DOME);
1426 switch (job->getFlatFieldDuration())
1428 case DURATION_MANUAL:
1429 m_CalibrationUI->captureCalibrationDurationManual->setChecked(
true);
1433 m_CalibrationUI->captureCalibrationUseADU->setChecked(
true);
1434 m_CalibrationUI->captureCalibrationADUValue->setValue(job->getCoreProperty(SequenceJob::SJ_TargetADU).toUInt());
1435 m_CalibrationUI->captureCalibrationADUTolerance->setValue(job->getCoreProperty(
1436 SequenceJob::SJ_TargetADUTolerance).toUInt());
1437 m_CalibrationUI->captureCalibrationSkyFlats->setChecked(job->getCoreProperty(SequenceJob::SJ_SkyFlat).toBool());
1441 m_scriptsManager->setScripts(job->getScripts());
1444 customPropertiesDialog()->setCustomProperties(job->getCustomProperties());
1447 captureISOS->setCurrentIndex(job->getCoreProperty(SequenceJob::SJ_ISOIndex).toInt());
1449 double gain = getGain();
1451 captureGainN->setValue(gain);
1453 captureGainN->setValue(GainSpinSpecialValue);
1455 double offset = getOffset();
1457 captureOffsetN->setValue(offset);
1459 captureOffsetN->setValue(OffsetSpinSpecialValue);
1462 generatePreviewFilename();
1464 if (m_RotatorControlPanel)
1466 if (job->getTargetRotation() != Ekos::INVALID_VALUE)
1469 m_RotatorControlPanel->setCameraPA(job->getTargetRotation());
1477 if (Options::alignCheckFrequency() == 0)
1479 targetDriftLabel->setVisible(
false);
1480 targetDrift->setVisible(
false);
1481 targetDriftUnit->setVisible(
false);
1485void Camera::syncFrameType(
const QString &name)
1487 if (!activeCamera() || name != activeCamera()->getDeviceName())
1492 captureTypeS->
clear();
1495 captureTypeS->setEnabled(
false);
1498 captureTypeS->setEnabled(
true);
1499 captureTypeS->addItems(frameTypes);
1500 ISD::CameraChip *tChip = devices()->getActiveCamera()->getChip(ISD::CameraChip::PRIMARY_CCD);
1501 captureTypeS->setCurrentIndex(tChip->getFrameType());
1505void Camera::syncCameraInfo()
1507 if (!activeCamera())
1510 const QString timestamp = KStarsData::Instance()->
lt().
toString(
"yyyy-MM-dd hh:mm");
1511 storeTrainKeyString(KEY_TIMESTAMP, timestamp);
1513 if (activeCamera()->hasCooler())
1515 cameraTemperatureS->setEnabled(
true);
1516 cameraTemperatureN->setEnabled(
true);
1518 if (activeCamera()->getPermission(
"CCD_TEMPERATURE") != IP_RO)
1520 double min, max, step;
1521 setTemperatureB->setEnabled(
true);
1522 cameraTemperatureN->setReadOnly(
false);
1523 cameraTemperatureS->setEnabled(
true);
1524 temperatureRegulationB->setEnabled(
true);
1525 activeCamera()->getMinMaxStep(
"CCD_TEMPERATURE",
"CCD_TEMPERATURE_VALUE", &min, &max, &step);
1526 cameraTemperatureN->setMinimum(min);
1527 cameraTemperatureN->setMaximum(max);
1528 cameraTemperatureN->setSingleStep(1);
1529 bool isChecked = activeCamera()->getDriverInfo()->getAuxInfo().value(
QString(
"%1_TC").arg(activeCamera()->getDeviceName()),
1531 cameraTemperatureS->setChecked(isChecked);
1537 isChecked ?
"1" :
"0" } );
1538 storeTrainKey(KEY_TEMPERATURE, temperatureList);
1542 setTemperatureB->setEnabled(
false);
1543 cameraTemperatureN->setReadOnly(
true);
1544 cameraTemperatureS->setEnabled(
false);
1545 cameraTemperatureS->setChecked(
false);
1546 temperatureRegulationB->setEnabled(
false);
1550 storeTrainKey(KEY_TEMPERATURE, temperatureList);
1553 double temperature = 0;
1554 if (activeCamera()->getTemperature(&temperature))
1556 temperatureOUT->setText(
QString(
"%L1º").arg(temperature, 0,
'f', 1));
1557 if (cameraTemperatureN->cleanText().isEmpty())
1558 cameraTemperatureN->setValue(temperature);
1563 cameraTemperatureS->setEnabled(
false);
1564 cameraTemperatureN->setEnabled(
false);
1565 temperatureRegulationB->setEnabled(
false);
1566 cameraTemperatureN->clear();
1567 temperatureOUT->clear();
1568 setTemperatureB->setEnabled(
false);
1571 auto isoList = devices()->getActiveChip()->getISOList();
1572 captureISOS->blockSignals(
true);
1573 captureISOS->setEnabled(
false);
1574 captureISOS->clear();
1577 if (isoList.isEmpty())
1579 captureISOS->setEnabled(
false);
1580 if (settings().contains(KEY_ISOS))
1582 settings().remove(KEY_ISOS);
1583 m_DebounceTimer.start();
1585 if (settings().contains(KEY_INDEX))
1587 settings().remove(KEY_INDEX);
1588 m_DebounceTimer.start();
1593 captureISOS->setEnabled(
true);
1594 captureISOS->addItems(isoList);
1595 const int isoIndex = devices()->getActiveChip()->getISOIndex();
1596 captureISOS->setCurrentIndex(isoIndex);
1599 storeTrainKey(KEY_ISOS, isoList);
1600 storeTrainKeyString(KEY_INDEX,
QString(
"%1").arg(isoIndex));
1604 double pixelX = 0, pixelY = 0;
1605 bool rc = devices()->getActiveChip()->getImageInfo(w, h, pixelX, pixelY, bbp);
1606 bool isModelInDB = state()->isModelinDSLRInfo(
QString(activeCamera()->getDeviceName()));
1609 if (rc ==
true && (pixelX == 0.0 || pixelY == 0.0 || isModelInDB ==
false))
1613 if (isModelInDB ==
false)
1620 process()->syncDSLRToTargetChip(model);
1624 captureISOS->blockSignals(
false);
1627 if (activeCamera()->hasGain())
1629 double min, max, step, value, targetCustomGain;
1630 activeCamera()->getGainMinMaxStep(&min, &max, &step);
1633 GainSpinSpecialValue = min - step;
1634 captureGainN->setRange(GainSpinSpecialValue, max);
1635 captureGainN->setSpecialValueText(
i18n(
"--"));
1636 captureGainN->setEnabled(
true);
1637 captureGainN->setSingleStep(step);
1638 activeCamera()->getGain(&value);
1641 targetCustomGain = getGain();
1645 if (targetCustomGain > 0)
1646 captureGainN->setValue(targetCustomGain);
1648 captureGainN->setValue(GainSpinSpecialValue);
1650 captureGainN->setReadOnly(activeCamera()->getGainPermission() == IP_RO);
1654 if (captureGainN->value() != GainSpinSpecialValue)
1655 setGain(captureGainN->value());
1662 captureGainN->setEnabled(
false);
1663 currentGainLabel->clear();
1667 if (activeCamera()->hasOffset())
1669 double min, max, step, value, targetCustomOffset;
1670 activeCamera()->getOffsetMinMaxStep(&min, &max, &step);
1673 OffsetSpinSpecialValue = min - step;
1674 captureOffsetN->setRange(OffsetSpinSpecialValue, max);
1675 captureOffsetN->setSpecialValueText(
i18n(
"--"));
1676 captureOffsetN->setEnabled(
true);
1677 captureOffsetN->setSingleStep(step);
1678 activeCamera()->getOffset(&value);
1681 targetCustomOffset = getOffset();
1685 if (targetCustomOffset > 0)
1686 captureOffsetN->setValue(targetCustomOffset);
1688 captureOffsetN->setValue(OffsetSpinSpecialValue);
1690 captureOffsetN->setReadOnly(activeCamera()->getOffsetPermission() == IP_RO);
1694 if (captureOffsetN->value() != OffsetSpinSpecialValue)
1695 setOffset(captureOffsetN->value());
1702 captureOffsetN->setEnabled(
false);
1703 currentOffsetLabel->clear();
1707void Camera::createNewJobTableRow(
SequenceJob *job)
1709 int currentRow = queueTable->rowCount();
1710 queueTable->insertRow(currentRow);
1746 queueTable->setItem(currentRow, JOBTABLE_COL_STATUS, status);
1747 queueTable->setItem(currentRow, JOBTABLE_COL_FILTER, filter);
1748 queueTable->setItem(currentRow, JOBTABLE_COL_COUNTS, count);
1749 queueTable->setItem(currentRow, JOBTABLE_COL_EXP, exp);
1750 queueTable->setItem(currentRow, JOBTABLE_COL_TYPE, type);
1751 queueTable->setItem(currentRow, JOBTABLE_COL_BINNING, bin);
1752 queueTable->setItem(currentRow, JOBTABLE_COL_ISO, iso);
1753 queueTable->setItem(currentRow, JOBTABLE_COL_OFFSET, offset);
1756 updateJobTable(job,
true);
1759 QJsonObject jsonJob = createJsonJob(job, currentRow);
1760 state()->getSequence().append(jsonJob);
1761 emit sequenceChanged(state()->getSequence());
1763 removeFromQueueB->setEnabled(
true);
1772 int row = state()->allJobs().indexOf(job);
1773 if (row >= 0 && row < queueTable->rowCount())
1775 updateCellStyle(queueTable->item(row, JOBTABLE_COL_STATUS), job->getStatus() == JOB_BUSY);
1776 updateCellStyle(queueTable->item(row, JOBTABLE_COL_FILTER), job->getStatus() == JOB_BUSY);
1777 updateCellStyle(queueTable->item(row, JOBTABLE_COL_COUNTS), job->getStatus() == JOB_BUSY);
1778 updateCellStyle(queueTable->item(row, JOBTABLE_COL_EXP), job->getStatus() == JOB_BUSY);
1779 updateCellStyle(queueTable->item(row, JOBTABLE_COL_TYPE), job->getStatus() == JOB_BUSY);
1780 updateCellStyle(queueTable->item(row, JOBTABLE_COL_BINNING), job->getStatus() == JOB_BUSY);
1781 updateCellStyle(queueTable->item(row, JOBTABLE_COL_ISO), job->getStatus() == JOB_BUSY);
1782 updateCellStyle(queueTable->item(row, JOBTABLE_COL_OFFSET), job->getStatus() == JOB_BUSY);
1788 if (cell ==
nullptr)
1792 font.setBold(active);
1793 font.setItalic(active);
1797bool Camera::syncControl(
const QVariantMap &settings,
const QString &key,
QWidget *widget)
1808 if ((pSB = qobject_cast<QSpinBox *>(widget)))
1810 const int value = settings[key].toInt(&ok);
1817 else if ((pDSB = qobject_cast<QDoubleSpinBox *>(widget)))
1819 const double value = settings[key].toDouble(&ok);
1824 if (pDSB == captureGainN)
1826 if (captureGainN->value() != GainSpinSpecialValue)
1827 setGain(captureGainN->value());
1831 else if (pDSB == captureOffsetN)
1833 if (captureOffsetN->value() != OffsetSpinSpecialValue)
1834 setOffset(captureOffsetN->value());
1841 else if ((pCB = qobject_cast<QCheckBox *>(widget)))
1843 const bool value = settings[key].toBool();
1848 else if ((pRadioButton = qobject_cast<QRadioButton *>(widget)))
1850 const bool value = settings[key].toBool();
1852 pRadioButton->
click();
1856 else if ((pComboBox = qobject_cast<QComboBox *>(widget)))
1858 const QString value = settings[key].toString();
1862 else if ((pSplitter = qobject_cast<QSplitter *>(widget)))
1868 else if ((pRadioButton = qobject_cast<QRadioButton *>(widget)))
1870 const bool value = settings[key].toBool();
1872 pRadioButton->
click();
1875 else if ((pLineEdit = qobject_cast<QLineEdit *>(widget)))
1877 const auto value = settings[key].toString();
1880 if (pLineEdit == fileRemoteDirT)
1881 generatePreviewFilename();
1888void Camera::moveJob(
bool up)
1890 int currentRow = queueTable->currentRow();
1891 int destinationRow =
up ? currentRow - 1 : currentRow + 1;
1893 int columnCount = queueTable->columnCount();
1895 if (currentRow < 0 || destinationRow < 0 || destinationRow >= queueTable->rowCount())
1898 for (
int i = 0; i < columnCount; i++)
1903 queueTable->setItem(destinationRow, i, selectedLine);
1904 queueTable->setItem(currentRow, i, counterpart);
1907 SequenceJob * job = state()->allJobs().takeAt(currentRow);
1909 state()->allJobs().removeOne(job);
1910 state()->allJobs().insert(destinationRow, job);
1912 QJsonArray seqArray = state()->getSequence();
1913 QJsonObject currentJob = seqArray[currentRow].toObject();
1914 seqArray.
replace(currentRow, seqArray[destinationRow]);
1915 seqArray.
replace(destinationRow, currentJob);
1916 emit sequenceChanged(seqArray);
1918 queueTable->selectRow(destinationRow);
1920 state()->setDirty(
true);
1923void Camera::removeJobFromQueue()
1925 int currentRow = queueTable->currentRow();
1928 currentRow = queueTable->rowCount() - 1;
1930 removeJob(currentRow);
1933 if (queueTable->rowCount() == 0)
1936 if (currentRow > queueTable->rowCount())
1937 queueTable->selectRow(queueTable->rowCount() - 1);
1939 queueTable->selectRow(currentRow);
1942void Camera::saveFITSDirectory()
1945 m_dirPath.toLocalFile());
1952void Camera::updateCaptureFormats()
1956 captureTypeS->
clear();
1959 captureTypeS->setEnabled(
false);
1962 captureTypeS->setEnabled(
true);
1963 captureTypeS->addItems(frameTypes);
1964 captureTypeS->setCurrentIndex(devices()->getActiveChip()->getFrameType());
1968 captureFormatS->blockSignals(
true);
1969 captureFormatS->clear();
1970 const auto list = activeCamera()->getCaptureFormats();
1971 captureFormatS->addItems(list);
1972 storeTrainKey(KEY_FORMATS, list);
1974 captureFormatS->setCurrentText(activeCamera()->getCaptureFormat());
1975 captureFormatS->blockSignals(
false);
1978 captureEncodingS->blockSignals(
true);
1979 captureEncodingS->clear();
1980 captureEncodingS->addItems(activeCamera()->getEncodingFormats());
1981 captureEncodingS->setCurrentText(activeCamera()->getEncodingFormat());
1982 captureEncodingS->blockSignals(
false);
1985void Camera::updateHFRCheckAlgo()
1988 const bool threshold = (m_LimitsUI->hFRCheckAlgorithm->currentIndex() != HFR_CHECK_FIXED);
1989 m_LimitsUI->hFRThresholdPercentage->setEnabled(threshold);
1990 m_LimitsUI->limitFocusHFRThresholdLabel->setEnabled(threshold);
1991 m_LimitsUI->limitFocusHFRPercentLabel->setEnabled(threshold);
1992 state()->updateHFRThreshold();
1995void Camera::clearAutoFocusHFR()
1997 if (Options::hFRCheckAlgorithm() == HFR_CHECK_FIXED)
2000 m_LimitsUI->hFRDeviation->setValue(0);
2010void Camera::clearCameraConfiguration()
2016 devices()->getActiveCamera()->setConfig(PURGE_CONFIG);
2017 KStarsData::Instance()->
userdb()->DeleteDSLRInfo(devices()->getActiveCamera()->getDeviceName());
2019 QStringList shutterfulCCDs = Options::shutterfulCCDs();
2020 QStringList shutterlessCCDs = Options::shutterlessCCDs();
2023 if (shutterfulCCDs.
contains(devices()->getActiveCamera()->getDeviceName()))
2025 shutterfulCCDs.
removeOne(devices()->getActiveCamera()->getDeviceName());
2026 Options::setShutterfulCCDs(shutterfulCCDs);
2028 if (shutterlessCCDs.
contains(devices()->getActiveCamera()->getDeviceName()))
2030 shutterlessCCDs.
removeOne(devices()->getActiveCamera()->getDeviceName());
2031 Options::setShutterlessCCDs(shutterlessCCDs);
2035 if (captureISOS && captureISOS->count() > 0)
2041 KSMessageBox::Instance()->questionYesNo(
i18n(
"Reset %1 configuration to default?",
2042 devices()->getActiveCamera()->getDeviceName()),
2043 i18n(
"Confirmation"), 30);
2046void Camera::editFilterName()
2051 for (
int index = 0; index < FilterPosCombo->count(); index++)
2052 labels << FilterPosCombo->itemText(index);
2054 if (editFilterNameInternal(labels, newLabels))
2056 FilterPosCombo->
clear();
2057 FilterPosCombo->addItems(newLabels);
2062 if (devices()->filterWheel() ==
nullptr || state()->getCurrentFilterPosition() < 1)
2065 QStringList labels = filterManager()->getFilterLabels();
2067 if (editFilterNameInternal(labels, newLabels))
2068 filterManager()->setFilterNames(newLabels);
2079 for (uint8_t i = 0; i < labels.
count(); i++)
2081 QLabel *existingLabel =
new QLabel(
QString(
"%1. <b>%2</b>").arg(i + 1).arg(labels[i]), &filterDialog);
2083 newLabelEdits.
append(newLabel);
2084 formLayout->
addRow(existingLabel, newLabel);
2087 QString title = m_standAlone ?
2088 "Edit Filter Names" : devices()->filterWheel()->getDeviceName();
2099 for (uint8_t i = 0; i < labels.
count(); i++)
2100 results << newLabelEdits[i]->text();
2101 newLabels = results;
2107void Camera::loadGlobalSettings()
2112 QVariantMap settings;
2114 for (
auto &oneWidget : findChildren<
QComboBox*>())
2116 if (oneWidget->objectName() ==
"opticalTrainCombo")
2119 key = oneWidget->objectName();
2120 value = Options::self()->property(key.
toLatin1());
2121 if (value.
isValid() && oneWidget->count() > 0)
2123 oneWidget->setCurrentText(value.
toString());
2124 settings[key] = value;
2127 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Option" << key <<
"not found!";
2133 key = oneWidget->objectName();
2134 value = Options::self()->property(key.
toLatin1());
2138 settings[key] = value;
2141 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Option" << key <<
"not found!";
2145 for (
auto &oneWidget : findChildren<
QSpinBox*>())
2147 key = oneWidget->objectName();
2148 value = Options::self()->property(key.
toLatin1());
2152 settings[key] = value;
2155 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Option" << key <<
"not found!";
2159 for (
auto &oneWidget : findChildren<
QCheckBox*>())
2161 key = oneWidget->objectName();
2162 value = Options::self()->property(key.
toLatin1());
2165 oneWidget->setChecked(value.
toBool());
2166 settings[key] = value;
2169 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Option" << key <<
"not found!";
2173 for (
auto &oneWidget : findChildren<
QGroupBox*>())
2175 if (oneWidget->isCheckable())
2177 key = oneWidget->objectName();
2178 value = Options::self()->property(key.
toLatin1());
2181 oneWidget->setChecked(value.
toBool());
2182 settings[key] = value;
2185 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Option" << key <<
"not found!";
2192 key = oneWidget->objectName();
2193 value = Options::self()->property(key.
toLatin1());
2196 oneWidget->setChecked(value.
toBool());
2197 settings[key] = value;
2202 for (
auto &oneWidget : findChildren<
QLineEdit*>())
2204 if (oneWidget->objectName() ==
"qt_spinbox_lineedit" || oneWidget->isReadOnly())
2206 key = oneWidget->objectName();
2207 value = Options::self()->property(key.
toLatin1());
2210 oneWidget->setText(value.
toString());
2211 settings[key] = value;
2214 m_GlobalSettings = settings;
2215 setSettings(settings);
2218bool Camera::checkUploadPaths(FilenamePreviewType filenamePreview)
2221 if (filenamePreview != NOT_PREVIEW)
2224 if (fileUploadModeS->currentIndex() != ISD::Camera::UPLOAD_CLIENT && fileRemoteDirT->text().isEmpty())
2226 KSNotification::error(
i18n(
"You must set remote directory for Local & Both modes."));
2230 if (fileUploadModeS->currentIndex() != ISD::Camera::UPLOAD_LOCAL && fileDirectoryT->text().isEmpty())
2232 KSNotification::error(
i18n(
"You must set local directory for Client & Both modes."));
2245 bool isDarkFlat = job->jobType() == SequenceJob::JOBTYPE_DARKFLAT;
2246 jsonJob.
insert(
"Filter", FilterPosCombo->currentText());
2247 jsonJob.
insert(
"Count", queueTable->item(currentRow, JOBTABLE_COL_COUNTS)->text());
2248 jsonJob.
insert(
"Exp", queueTable->item(currentRow, JOBTABLE_COL_EXP)->text());
2249 jsonJob.
insert(
"Type", isDarkFlat ?
i18n(
"Dark Flat") : queueTable->item(currentRow, JOBTABLE_COL_TYPE)->text());
2250 jsonJob.
insert(
"Bin", queueTable->item(currentRow, JOBTABLE_COL_BINNING)->text());
2251 jsonJob.
insert(
"ISO/Gain", queueTable->item(currentRow, JOBTABLE_COL_ISO)->text());
2252 jsonJob.
insert(
"Offset", queueTable->item(currentRow, JOBTABLE_COL_OFFSET)->text());
2257void Camera::generatePreviewFilename()
2259 if (state()->isCaptureRunning() ==
false)
2261 placeholderFormatT->setToolTip(previewFilename( Camera::LOCAL_PREVIEW ));
2262 emit newLocalPreview(placeholderFormatT->toolTip());
2264 if (fileUploadModeS->currentIndex() != 0)
2265 fileRemoteDirT->setToolTip(previewFilename( Camera::REMOTE_PREVIEW ));
2269QString Camera::previewFilename(FilenamePreviewType previewType)
2275 if (previewType == Camera::LOCAL_PREVIEW)
2277 if(!fileDirectoryT->text().endsWith(separator) && !placeholderFormatT->text().startsWith(separator))
2278 placeholderFormatT->setText(separator + placeholderFormatT->text());
2279 m_format = fileDirectoryT->text() + placeholderFormatT->text() + formatSuffixN->prefix() +
2280 formatSuffixN->cleanText();
2282 else if (previewType == Camera::REMOTE_PREVIEW)
2283 m_format = fileRemoteDirT->text();
2291 else if (state()->sequenceURL().toLocalFile().isEmpty() && m_format.
contains(
"%f"))
2292 previewText = (
"Save the sequence file to show filename preview");
2296 SequenceJob *m_job = createJob(SequenceJob::JOBTYPE_PREVIEW, previewType);
2297 if (m_job ==
nullptr)
2301 if (state()->sequenceURL().toLocalFile().isEmpty())
2307 previewSeq = state()->sequenceURL().toLocalFile();
2308 auto m_placeholderPath = PlaceholderPath(previewSeq);
2311 if (captureEncodingS->currentText() ==
"FITS")
2312 extension =
".fits";
2313 else if (captureEncodingS->currentText() ==
"XISF")
2314 extension =
".xisf";
2316 extension =
".[NATIVE]";
2317 previewText = m_placeholderPath.generateSequenceFilename(*m_job, previewType == Camera::LOCAL_PREVIEW,
true, 1,
2318 extension,
"",
false);
2321 m_job->deleteLater();
2325 if (previewType == Camera::REMOTE_PREVIEW)
2326 previewText.
replace(separator,
"/");
2333 countCell->
setText(
QString(
"%L1/%L2").arg(job->getCompleted()).
arg(job->getCoreProperty(SequenceJob::SJ_Count).toInt()));
2336void Camera::addDSLRInfo(
const QString &model, uint32_t maxW, uint32_t maxH,
double pixelW,
double pixelH)
2339 auto pos = std::find_if(state()->DSLRInfos().
begin(), state()->DSLRInfos().
end(), [model](
const auto & oneDSLRInfo)
2341 return (oneDSLRInfo[
"Model"] == model);
2344 if (pos != state()->DSLRInfos().
end())
2346 KStarsData::Instance()->
userdb()->DeleteDSLRInfo(model);
2347 state()->DSLRInfos().removeOne(*pos);
2351 oneDSLRInfo[
"Model"] = model;
2352 oneDSLRInfo[
"Width"] = maxW;
2353 oneDSLRInfo[
"Height"] = maxH;
2354 oneDSLRInfo[
"PixelW"] = pixelW;
2355 oneDSLRInfo[
"PixelH"] = pixelH;
2357 KStarsData::Instance()->
userdb()->AddDSLRInfo(oneDSLRInfo);
2358 KStarsData::Instance()->
userdb()->GetAllDSLRInfos(state()->DSLRInfos());
2360 updateFrameProperties();
2361 process()->resetFrame();
2362 process()->syncDSLRToTargetChip(model);
2365 if (m_DSLRInfoDialog)
2366 m_DSLRInfoDialog.reset();
2371 process()->startNextPendingJob();
2374void Camera::stop(CaptureState targetState)
2376 process()->stopCapturing(targetState);
2381 process()->pauseCapturing();
2382 updateStartButtons(
false,
true);
2385void Camera::toggleSequence()
2387 const CaptureState capturestate = state()->getCaptureState();
2388 if (capturestate == CAPTURE_PAUSE_PLANNED || capturestate == CAPTURE_PAUSED)
2389 updateStartButtons(
true,
false);
2391 process()->toggleSequence();
2394void Camera::toggleVideo(
bool enabled)
2396 process()->toggleVideo(enabled);
2399void Camera::restartCamera(
const QString &name)
2401 process()->restartCamera(name);
2404void Camera::cullToDSLRLimits()
2406 QString model(devices()->getActiveCamera()->getDeviceName());
2409 auto pos = std::find_if(state()->DSLRInfos().
begin(),
2412 return (oneDSLRInfo[
"Model"] == model);
2415 if (pos != state()->DSLRInfos().
end())
2417 if (captureFrameWN->maximum() == 0 || captureFrameWN->maximum() > (*pos)[
"Width"].toInt())
2419 captureFrameWN->setValue((*pos)[
"Width"].toInt());
2420 captureFrameWN->setMaximum((*pos)[
"Width"].toInt());
2423 if (captureFrameHN->maximum() == 0 || captureFrameHN->maximum() > (*pos)[
"Height"].toInt())
2425 captureFrameHN->setValue((*pos)[
"Height"].toInt());
2426 captureFrameHN->setMaximum((*pos)[
"Height"].toInt());
2431void Camera::resetFrameToZero()
2433 captureFrameXN->setMinimum(0);
2434 captureFrameXN->setMaximum(0);
2435 captureFrameXN->setValue(0);
2437 captureFrameYN->setMinimum(0);
2438 captureFrameYN->setMaximum(0);
2439 captureFrameYN->setValue(0);
2441 captureFrameWN->setMinimum(0);
2442 captureFrameWN->setMaximum(0);
2443 captureFrameWN->setValue(0);
2445 captureFrameHN->setMinimum(0);
2446 captureFrameHN->setMaximum(0);
2447 captureFrameHN->setValue(0);
2450void Camera::updateFrameProperties(
int reset)
2452 if (!devices()->getActiveCamera())
2455 int binx = 1, biny = 1;
2456 double min, max, step;
2457 int xstep = 0, ystep = 0;
2460 QString exposureProp = state()->useGuideHead() ?
QString(
"GUIDER_EXPOSURE") :
QString(
"CCD_EXPOSURE");
2461 QString exposureElem = state()->useGuideHead() ?
QString(
"GUIDER_EXPOSURE_VALUE") :
2462 QString(
"CCD_EXPOSURE_VALUE");
2463 devices()->setActiveChip(state()->useGuideHead() ?
2464 devices()->getActiveCamera()->getChip(
2465 ISD::CameraChip::GUIDE_CCD) :
2466 devices()->getActiveCamera()->getChip(
ISD::CameraChip::PRIMARY_CCD));
2468 captureFrameWN->setEnabled(devices()->getActiveChip()->canSubframe());
2469 captureFrameHN->setEnabled(devices()->getActiveChip()->canSubframe());
2470 captureFrameXN->setEnabled(devices()->getActiveChip()->canSubframe());
2471 captureFrameYN->setEnabled(devices()->getActiveChip()->canSubframe());
2473 captureBinHN->setEnabled(devices()->getActiveChip()->canBin());
2474 captureBinVN->setEnabled(devices()->getActiveChip()->canBin());
2477 exposureValues << 0.01 << 0.02 << 0.05 << 0.1 << 0.2 << 0.25 << 0.5 << 1 << 1.5 << 2 << 2.5 << 3 << 5 << 6 << 7 << 8 << 9 <<
2478 10 << 20 << 30 << 40 << 50 << 60 << 120 << 180 << 300 << 600 << 900 << 1200 << 1800;
2480 if (devices()->getActiveCamera()->getMinMaxStep(exposureProp, exposureElem, &min, &max, &step))
2483 captureExposureN->setDecimals(6);
2485 captureExposureN->setDecimals(3);
2486 for(
int i = 0; i < exposureValues.
count(); i++)
2488 double value = exposureValues.
at(i);
2489 if(value < min || value > max)
2497 exposureValues.
append(max);
2500 captureExposureN->setRecommendedValues(exposureValues);
2501 state()->setExposureRange(exposureValues.
first(), exposureValues.
last());
2503 if (devices()->getActiveCamera()->getMinMaxStep(frameProp,
"WIDTH", &min, &max, &step))
2512 xstep =
static_cast<int>(max * 0.05);
2514 xstep =
static_cast<int>(step);
2516 if (min >= 0 && max > 0)
2518 captureFrameWN->setMinimum(
static_cast<int>(min));
2519 captureFrameWN->setMaximum(
static_cast<int>(max));
2520 captureFrameWN->setSingleStep(xstep);
2526 if (devices()->getActiveCamera()->getMinMaxStep(frameProp,
"HEIGHT", &min, &max, &step))
2535 ystep =
static_cast<int>(max * 0.05);
2537 ystep =
static_cast<int>(step);
2539 if (min >= 0 && max > 0)
2541 captureFrameHN->setMinimum(
static_cast<int>(min));
2542 captureFrameHN->setMaximum(
static_cast<int>(max));
2543 captureFrameHN->setSingleStep(ystep);
2549 if (devices()->getActiveCamera()->getMinMaxStep(frameProp,
"X", &min, &max, &step))
2560 if (min >= 0 && max > 0)
2562 captureFrameXN->setMinimum(
static_cast<int>(min));
2563 captureFrameXN->setMaximum(
static_cast<int>(max));
2564 captureFrameXN->setSingleStep(
static_cast<int>(step));
2570 if (devices()->getActiveCamera()->getMinMaxStep(frameProp,
"Y", &min, &max, &step))
2581 if (min >= 0 && max > 0)
2583 captureFrameYN->setMinimum(
static_cast<int>(min));
2584 captureFrameYN->setMaximum(
static_cast<int>(max));
2585 captureFrameYN->setSingleStep(
static_cast<int>(step));
2592 if (state()->useGuideHead() ==
false)
2595 const QString ccdGainKeyword = devices()->getActiveCamera()->getProperty(
"CCD_GAIN") ?
"CCD_GAIN" :
"CCD_CONTROLS";
2596 storeTrainKeyString(KEY_GAIN_KWD, ccdGainKeyword);
2598 const QString ccdOffsetKeyword = devices()->getActiveCamera()->getProperty(
"CCD_OFFSET") ?
"CCD_OFFSET" :
"CCD_CONTROLS";
2599 storeTrainKeyString(KEY_OFFSET_KWD, ccdOffsetKeyword);
2601 if (reset == 1 || state()->frameSettings().contains(devices()->getActiveChip()) ==
false)
2603 QVariantMap settings;
2607 settings[
"w"] = captureFrameWN->maximum();
2608 settings[
"h"] = captureFrameHN->maximum();
2609 settings[
"binx"] = captureBinHN->value();
2610 settings[
"biny"] = captureBinVN->value();
2612 state()->frameSettings()[devices()->getActiveChip()] = settings;
2614 else if (reset == 2 && state()->frameSettings().contains(devices()->getActiveChip()))
2616 QVariantMap settings = state()->frameSettings()[devices()->getActiveChip()];
2619 x = settings[
"x"].toInt();
2620 y = settings[
"y"].toInt();
2621 w = settings[
"w"].toInt();
2622 h = settings[
"h"].toInt();
2625 x = qBound(captureFrameXN->minimum(), x, captureFrameXN->maximum() - 1);
2626 y = qBound(captureFrameYN->minimum(), y, captureFrameYN->maximum() - 1);
2627 w = qBound(captureFrameWN->minimum(), w, captureFrameWN->maximum());
2628 h = qBound(captureFrameHN->minimum(), h, captureFrameHN->maximum());
2634 settings[
"binx"] = captureBinHN->value();
2635 settings[
"biny"] = captureBinVN->value();
2637 state()->frameSettings()[devices()->getActiveChip()] = settings;
2640 if (state()->frameSettings().contains(devices()->getActiveChip()))
2642 QVariantMap settings = state()->frameSettings()[devices()->getActiveChip()];
2643 int x = settings[
"x"].toInt();
2644 int y = settings[
"y"].toInt();
2645 int w = settings[
"w"].toInt();
2646 int h = settings[
"h"].toInt();
2648 if (devices()->getActiveChip()->canBin())
2650 devices()->getActiveChip()->getMaxBin(&binx, &biny);
2651 captureBinHN->setMaximum(binx);
2652 captureBinVN->setMaximum(biny);
2654 captureBinHN->setValue(settings[
"binx"].toInt());
2655 captureBinVN->setValue(settings[
"biny"].toInt());
2659 captureBinHN->setValue(1);
2660 captureBinVN->setValue(1);
2664 captureFrameXN->setValue(x);
2666 captureFrameYN->setValue(y);
2668 captureFrameWN->setValue(w);
2670 captureFrameHN->setValue(h);
2676void Camera::setGain(
double value)
2680 setStandAloneGain(value);
2683 if (!devices()->getActiveCamera())
2687 process()->updateGain(value, customProps);
2688 customPropertiesDialog()->setCustomProperties(customProps);
2692double Camera::getGain()
2694 return devices()->cameraGain(customPropertiesDialog()->getCustomProperties());
2697void Camera::setOffset(
double value)
2701 setStandAloneOffset(value);
2704 if (!devices()->getActiveCamera())
2709 process()->updateOffset(value, customProps);
2710 customPropertiesDialog()->setCustomProperties(customProps);
2713double Camera::getOffset()
2715 return devices()->cameraOffset(customPropertiesDialog()->getCustomProperties());
2718void Camera::setRotator(
QString name)
2722 rotatorB->setEnabled(
false);
2723 if (Rotator && !m_RotatorControlPanel.isNull())
2724 m_RotatorControlPanel->close();
2729 Manager::Instance()->getRotatorController(name, m_RotatorControlPanel);
2730 m_RotatorControlPanel->initRotator(opticalTrainCombo->currentText(), devices().data(),
2734 m_RotatorControlPanel->show();
2735 m_RotatorControlPanel->raise();
2737 rotatorB->setEnabled(
true);
2739 else if (Options::astrometryUseRotator())
2741 RotatorUtils::Instance()->initRotatorUtils(opticalTrainCombo->currentText());
2745void Camera::setMaximumGuidingDeviation(
bool enable,
double value)
2747 m_LimitsUI->enforceGuideDeviation->setChecked(enable);
2749 m_LimitsUI->guideDeviation->setValue(value);
2752void Camera::setInSequenceFocus(
bool enable,
double HFR)
2754 m_LimitsUI->enforceAutofocusHFR->setChecked(enable);
2756 m_LimitsUI->hFRDeviation->setValue(HFR);
2759bool Camera::loadSequenceQueue(
const QString &fileURL,
QString targetName)
2761 QFile sFile(fileURL);
2764 QString message =
i18n(
"Unable to open file %1", fileURL);
2765 KSNotification::sorry(message,
i18n(
"Could Not Open File"));
2769 state()->clearCapturedFramesMap();
2770 clearSequenceQueue();
2773 const bool result = process()->loadSequenceQueue(fileURL, targetName, !m_standAlone);
2775 if (result ==
false)
2779 setObserverName(state()->observerName());
2782 if (state()->allJobs().size() > 0)
2783 syncGUIToJob(state()->allJobs().first());
2786 queueSaveB->setToolTip(
"Save to " + sFile.fileName());
2791bool Camera::saveSequenceQueue(
const QString &path)
2794 return process()->saveSequenceQueue(path);
2797void Camera::updateCameraStatus(CaptureState status)
2800 emit newStatus(status, (activeCamera() ==
nullptr ?
"" : activeCamera()->getDeviceName()));
2803void Camera::clearSequenceQueue()
2805 state()->setActiveJob(
nullptr);
2806 while (queueTable->rowCount() > 0)
2807 queueTable->removeRow(0);
2808 qDeleteAll(state()->allJobs());
2809 state()->allJobs().clear();
2811 while (state()->getSequence().count())
2812 state()->getSequence().pop_back();
2813 emit sequenceChanged(state()->getSequence());
2816QVariantMap Camera::getAllSettings()
const
2818 QVariantMap settings;
2822 for (
auto &oneWidget : findChildren<
QLineEdit*>())
2824 auto name = oneWidget->objectName();
2825 if (name ==
"qt_spinbox_lineedit")
2827 settings.insert(name, oneWidget->text());
2831 for (
auto &oneWidget : findChildren<
QComboBox*>())
2832 settings.
insert(oneWidget->objectName(), oneWidget->currentText());
2836 settings.
insert(oneWidget->objectName(), oneWidget->value());
2839 for (
auto &oneWidget : findChildren<
QSpinBox*>())
2840 settings.
insert(oneWidget->objectName(), oneWidget->value());
2843 for (
auto &oneWidget : findChildren<
QCheckBox*>())
2844 settings.
insert(oneWidget->objectName(), oneWidget->isChecked());
2847 for (
auto &oneWidget : findChildren<
QGroupBox*>())
2848 if (oneWidget->isCheckable())
2849 settings.
insert(oneWidget->objectName(), oneWidget->isChecked());
2853 settings.
insert(oneWidget->objectName(), oneWidget->isChecked());
2858void Camera::setAllSettings(
const QVariantMap &settings,
const QVariantMap *standAloneSettings)
2862 disconnectSyncSettings();
2864 for (
auto &name : settings.keys())
2867 auto comboBox = findChild<QComboBox*>(name);
2870 syncControl(settings, name, comboBox);
2875 auto doubleSpinBox = findChild<QDoubleSpinBox*>(name);
2878 syncControl(settings, name, doubleSpinBox);
2883 auto spinBox = findChild<QSpinBox*>(name);
2886 syncControl(settings, name, spinBox);
2891 auto checkbox = findChild<QCheckBox*>(name);
2894 syncControl(settings, name, checkbox);
2899 auto groupbox = findChild<QGroupBox*>(name);
2900 if (groupbox && groupbox->isCheckable())
2902 syncControl(settings, name, groupbox);
2907 auto radioButton = findChild<QRadioButton*>(name);
2910 syncControl(settings, name, radioButton);
2915 auto lineEdit = findChild<QLineEdit*>(name);
2918 syncControl(settings, name, lineEdit);
2924 for (
auto &key : settings.keys())
2926 auto value = settings[key];
2928 Options::self()->setProperty(key.
toLatin1(), value);
2930 m_settings[key] = value;
2931 m_GlobalSettings[key] = value;
2934 if (standAloneSettings && standAloneSettings->size() > 0)
2936 for (
const auto &k : standAloneSettings->keys())
2937 m_settings[k] = (*standAloneSettings)[k];
2940 emit settingsUpdated(getAllSettings());
2945 const int id = OpticalTrainManager::Instance()->id(opticalTrainCombo->currentText());
2946 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
2947 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Capture, m_settings);
2948 Options::setCaptureTrainID(
id);
2951 connectSyncSettings();
2954void Camera::setupOpticalTrainManager()
2956 connect(OpticalTrainManager::Instance(), &OpticalTrainManager::updated,
this, &Camera::refreshOpticalTrain);
2959 OpticalTrainManager::Instance()->openEditor(opticalTrainCombo->currentText());
2963 ProfileSettings::Instance()->setOneSetting(ProfileSettings::CaptureOpticalTrain,
2964 OpticalTrainManager::Instance()->
id(opticalTrainCombo->itemText(index)));
2965 refreshOpticalTrain();
2966 emit trainChanged();
2970void Camera::refreshOpticalTrain()
2972 opticalTrainCombo->blockSignals(
true);
2973 opticalTrainCombo->clear();
2974 opticalTrainCombo->addItems(OpticalTrainManager::Instance()->getTrainNames());
2975 trainB->setEnabled(
true);
2977 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::CaptureOpticalTrain);
2978 if (m_standAlone || trainID.
isValid())
2980 auto id = m_standAlone ? Options::captureTrainID() : trainID.toUInt();
2981 Options::setCaptureTrainID(
id);
2984 if (OpticalTrainManager::Instance()->exists(
id) ==
false)
2986 qCWarning(KSTARS_EKOS_CAPTURE) <<
"Optical train doesn't exist for id" << id;
2987 id = OpticalTrainManager::Instance()->id(opticalTrainCombo->itemText(0));
2990 auto name = OpticalTrainManager::Instance()->name(
id);
2992 opticalTrainCombo->setCurrentText(name);
2994 process()->refreshOpticalTrain(name);
3000 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
3001 auto settings = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::Capture);
3002 if (settings.isValid())
3004 auto map = settings.toJsonObject().toVariantMap();
3005 if (map != m_settings)
3007 QVariantMap standAloneSettings = copyStandAloneSettings(m_settings);
3009 setAllSettings(map, &standAloneSettings);
3013 setSettings(m_GlobalSettings);
3016 opticalTrainCombo->blockSignals(
false);
3019void Camera::syncLimitSettings()
3021 m_LimitsUI->enforceStartGuiderDrift->setChecked(Options::enforceStartGuiderDrift());
3022 m_LimitsUI->startGuideDeviation->setValue(Options::startGuideDeviation());
3023 m_LimitsUI->enforceGuideDeviation->setChecked(Options::enforceGuideDeviation());
3024 m_LimitsUI->guideDeviation->setValue(Options::guideDeviation());
3025 m_LimitsUI->guideDeviationReps->setValue(
static_cast<int>(Options::guideDeviationReps()));
3026 m_LimitsUI->enforceAutofocusHFR->setChecked(Options::enforceAutofocusHFR());
3027 m_LimitsUI->hFRThresholdPercentage->setValue(Options::hFRThresholdPercentage());
3028 m_LimitsUI->hFRDeviation->setValue(Options::hFRDeviation());
3029 m_LimitsUI->inSequenceCheckFrames->setValue(Options::inSequenceCheckFrames());
3030 m_LimitsUI->hFRCheckAlgorithm->setCurrentIndex(Options::hFRCheckAlgorithm());
3031 m_LimitsUI->enforceAutofocusOnTemperature->setChecked(Options::enforceAutofocusOnTemperature());
3032 m_LimitsUI->maxFocusTemperatureDelta->setValue(Options::maxFocusTemperatureDelta());
3033 m_LimitsUI->enforceRefocusEveryN->setChecked(Options::enforceRefocusEveryN());
3034 m_LimitsUI->refocusEveryN->setValue(
static_cast<int>(Options::refocusEveryN()));
3035 m_LimitsUI->refocusAfterMeridianFlip->setChecked(Options::refocusAfterMeridianFlip());
3038void Camera::settleSettings()
3040 state()->setDirty(
true);
3041 emit settingsUpdated(getAllSettings());
3043 const int id = OpticalTrainManager::Instance()->id(opticalTrainCombo->currentText());
3044 OpticalTrainSettings::Instance()->setOpticalTrainID(
id);
3045 OpticalTrainSettings::Instance()->setOneSetting(OpticalTrainSettings::Capture, m_settings);
3046 Options::setCaptureTrainID(
id);
3049void Camera::syncSettings()
3062 if ( (dsb = qobject_cast<QDoubleSpinBox*>(sender())))
3065 value = dsb->
value();
3068 else if ( (sb = qobject_cast<QSpinBox*>(sender())))
3071 value = sb->
value();
3073 else if ( (cb = qobject_cast<QCheckBox*>(sender())))
3078 else if ( (gb = qobject_cast<QGroupBox*>(sender())))
3083 else if ( (rb = qobject_cast<QRadioButton*>(sender())))
3089 settings().remove(key);
3094 else if ( (cbox = qobject_cast<QComboBox*>(sender())))
3099 else if ( (le = qobject_cast<QLineEdit*>(sender())))
3108 settings()[key] = value;
3109 m_GlobalSettings[key] = value;
3111 Options::self()->setProperty(key.
toLatin1(), value);
3112 m_DebounceTimer.start();
3116void Camera::connectSyncSettings()
3119 for (
auto &oneWidget : findChildren<
QComboBox*>())
3121 if (oneWidget != opticalTrainCombo)
3122 connect(oneWidget, QOverload<int>::of(&
QComboBox::activated), this, &Camera::syncSettings);
3126 connect(oneWidget, QOverload<double>::of(&
QDoubleSpinBox::valueChanged), this, &Camera::syncSettings);
3129 for (
auto &oneWidget : findChildren<
QSpinBox*>())
3130 connect(oneWidget, QOverload<int>::of(&
QSpinBox::valueChanged), this, &Camera::syncSettings);
3133 for (
auto &oneWidget : findChildren<
QCheckBox*>())
3137 for (
auto &oneWidget : findChildren<
QGroupBox*>())
3138 if (oneWidget->isCheckable())
3146 for (
auto &oneWidget : findChildren<
QLineEdit*>())
3148 if (oneWidget->objectName() ==
"qt_spinbox_lineedit" || oneWidget->isReadOnly())
3154void Camera::disconnectSyncSettings()
3157 for (
auto &oneWidget : findChildren<
QComboBox*>())
3158 disconnect(oneWidget, QOverload<int>::of(&
QComboBox::activated), this, &Camera::syncSettings);
3162 disconnect(oneWidget, QOverload<double>::of(&
QDoubleSpinBox::valueChanged), this, &Camera::syncSettings);
3165 for (
auto &oneWidget : findChildren<
QSpinBox*>())
3166 disconnect(oneWidget, QOverload<int>::of(&
QSpinBox::valueChanged), this, &Camera::syncSettings);
3169 for (
auto &oneWidget : findChildren<
QCheckBox*>())
3170 disconnect(oneWidget, &
QCheckBox::toggled, this, &Camera::syncSettings);
3173 for (
auto &oneWidget : findChildren<
QGroupBox*>())
3174 if (oneWidget->isCheckable())
3175 disconnect(oneWidget, &
QGroupBox::toggled, this, &Camera::syncSettings);
3179 disconnect(oneWidget, &
QRadioButton::toggled, this, &Camera::syncSettings);
3182 for (
auto &oneWidget : findChildren<
QLineEdit*>())
3184 if (oneWidget->objectName() ==
"qt_spinbox_lineedit")
3192 if (!m_settings.contains(key) || m_settings[key].toStringList() != list)
3194 m_settings[key] =
list;
3195 m_DebounceTimer.start();
3199void Camera::storeTrainKeyString(
const QString &key,
const QString &str)
3201 if (!m_settings.contains(key) || m_settings[key].toString() != str)
3203 m_settings[key] = str;
3204 m_DebounceTimer.start();
3208void Camera::setupFilterManager()
3211 if (filterManager())
3212 filterManager()->disconnect(
this);
3215 Manager::Instance()->createFilterManager(devices()->filterWheel());
3218 Manager::Instance()->getFilterManager(devices()->filterWheel()->getDeviceName(), m_FilterManager);
3220 devices()->setFilterManager(filterManager());
3222 connect(filterManager().
get(), &FilterManager::updated,
this, [
this]()
3224 emit filterManagerUpdated(devices()->filterWheel());
3228 connect(filterManager().
get(), &FilterManager::newStatus,
this, &Camera::newFilterStatus);
3232 filterManager()->refreshFilterModel();
3233 filterManager()->show();
3234 filterManager()->raise();
3237 connect(filterManager().
get(), &FilterManager::failed,
this, [
this]()
3241 appendLogText(
i18n(
"Filter operation failed."));
3247 connect(filterManager().
get(), &FilterManager::newStatus,
this, &Camera::setFilterStatus);
3249 connect(filterManager().
get(), &FilterManager::labelsChanged,
this, [
this]()
3251 FilterPosCombo->clear();
3252 FilterPosCombo->addItems(filterManager()->getFilterLabels());
3253 FilterPosCombo->setCurrentIndex(filterManager()->getFilterPosition() - 1);
3254 updateCurrentFilterPosition();
3255 storeTrainKey(KEY_FILTERS, filterManager()->getFilterLabels());
3258 connect(filterManager().
get(), &FilterManager::positionChanged,
this, [
this]()
3260 FilterPosCombo->setCurrentIndex(filterManager()->getFilterPosition() - 1);
3261 updateCurrentFilterPosition();
3265void Camera::clearFilterManager()
3268 if (filterManager())
3269 filterManager()->disconnect(
this);
3272 filterManager().clear();
3273 devices()->setFilterManager(filterManager());
3276void Camera::refreshFilterSettings()
3278 FilterPosCombo->clear();
3280 if (!devices()->filterWheel())
3282 FilterPosLabel->setEnabled(
false);
3283 FilterPosCombo->setEnabled(
false);
3284 filterEditB->setEnabled(
false);
3285 filterManagerB->setEnabled(
false);
3287 clearFilterManager();
3291 FilterPosLabel->setEnabled(
true);
3292 FilterPosCombo->setEnabled(
true);
3293 filterEditB->setEnabled(
true);
3294 filterManagerB->setEnabled(
true);
3296 setupFilterManager();
3298 process()->updateFilterInfo();
3300 const auto labels = process()->filterLabels();
3301 FilterPosCombo->addItems(labels);
3304 storeTrainKey(KEY_FILTERS, labels);
3306 updateCurrentFilterPosition();
3308 filterEditB->setEnabled(state()->getCurrentFilterPosition() > 0);
3309 filterManagerB->setEnabled(state()->getCurrentFilterPosition() > 0);
3311 FilterPosCombo->setCurrentIndex(state()->getCurrentFilterPosition() - 1);
3314void Camera::updateCurrentFilterPosition()
3316 const QString currentFilterText = FilterPosCombo->itemText(m_FilterManager->getFilterPosition() - 1);
3317 state()->setCurrentFilterPosition(m_FilterManager->getFilterPosition(),
3319 m_FilterManager->getFilterLock(currentFilterText));
3323void Camera::setFilterWheel(
QString name)
3329 if (devices()->filterWheel() && devices()->filterWheel()->getDeviceName() == name)
3331 refreshFilterSettings();
3335 auto isConnected = devices()->filterWheel() && devices()->filterWheel()->isConnected();
3336 FilterPosLabel->setEnabled(isConnected);
3337 FilterPosCombo->setEnabled(isConnected);
3338 filterManagerB->setEnabled(isConnected);
3340 refreshFilterSettings();
3342 if (devices()->filterWheel())
3343 emit settingsUpdated(getAllSettings());
3348 return m_DeviceAdaptor->getActiveCamera();
3353 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::CaptureOpticalTrain);
3354 if (activeCamera() && trainID.
isValid())
3356 auto id = trainID.
toUInt();
3357 auto name = OpticalTrainManager::Instance()->name(
id);
3358 return OpticalTrainManager::Instance()->getScope(name);
3364double Camera::currentReducer()
3366 QVariant trainID = ProfileSettings::Instance()->getOneSetting(ProfileSettings::CaptureOpticalTrain);
3367 if (activeCamera() && trainID.
isValid())
3369 auto id = trainID.
toUInt();
3370 auto name = OpticalTrainManager::Instance()->name(
id);
3371 return OpticalTrainManager::Instance()->getReducer(name);
3377double Camera::currentAperture()
3379 auto scope = currentScope();
3381 double focalLength = scope[
"focal_length"].toDouble(-1);
3382 double aperture = scope[
"aperture"].toDouble(-1);
3383 double focalRatio = scope[
"focal_ratio"].toDouble(-1);
3386 if (aperture < 0 && focalRatio > 0)
3387 aperture = focalLength * focalRatio;
3392void Camera::updateMeridianFlipStage(MeridianFlipState::MFStage stage)
3395 if (state()->getMeridianFlipState()->getMeridianFlipStage() != stage)
3399 case MeridianFlipState::MF_READY:
3400 if (state()->getCaptureState() == CAPTURE_PAUSED)
3407 case MeridianFlipState::MF_INITIATED:
3408 captureStatusWidget->setStatus(
i18n(
"Meridian Flip..."),
Qt::yellow);
3409 KSNotification::event(
QLatin1String(
"MeridianFlipStarted"),
i18n(
"Meridian flip started"), KSNotification::Capture);
3412 case MeridianFlipState::MF_COMPLETED:
3413 captureStatusWidget->setStatus(
i18n(
"Flip complete."),
Qt::yellow);
3422void Camera::openExposureCalculatorDialog()
3424 qCInfo(KSTARS_EKOS_CAPTURE) <<
"Instantiating an Exposure Calculator";
3427 double preferredSkyQuality = 20.5;
3429 auto scope = currentScope();
3430 double focalRatio = scope[
"focal_ratio"].toDouble(-1);
3432 auto reducedFocalLength = currentReducer() * scope[
"focal_length"].toDouble(-1);
3433 auto aperture = currentAperture();
3434 auto reducedFocalRatio = (focalRatio > 0 || aperture == 0) ? focalRatio : reducedFocalLength / aperture;
3436 if (devices()->getActiveCamera() !=
nullptr)
3438 qCInfo(KSTARS_EKOS_CAPTURE) <<
"set ExposureCalculator preferred camera to active camera id: "
3439 << devices()->getActiveCamera()->getDeviceName();
3443 preferredSkyQuality,
3445 devices()->getActiveCamera()->getDeviceName()));
3447 anExposureCalculatorDialog->show();
3450void Camera::handleScriptsManager()
3456 m_scriptsManager->setScripts(old_scripts);
3459void Camera::showTemperatureRegulation()
3461 if (!devices()->getActiveCamera())
3464 double currentRamp, currentThreshold;
3465 if (!devices()->getActiveCamera()->getTemperatureRegulation(currentRamp, currentThreshold))
3468 double rMin, rMax, rStep, tMin, tMax, tStep;
3470 devices()->getActiveCamera()->getMinMaxStep(
"CCD_TEMP_RAMP",
"RAMP_SLOPE", &rMin, &rMax, &rStep);
3471 devices()->getActiveCamera()->getMinMaxStep(
"CCD_TEMP_RAMP",
"RAMP_THRESHOLD", &tMin, &tMax, &tStep);
3473 QLabel rampLabel(
i18nc(
"Maximum temperature variation over time when regulating.",
"Ramp (°C/min):"));
3480 "<p>Maximum temperature change per minute when cooling or warming the camera. Set zero to disable."
3481 "<p>This setting is read from and stored in the INDI camera driver configuration."
3484 QLabel thresholdLabel(
i18nc(
"Temperature threshold above which regulation triggers.",
"Threshold (°C):"));
3489 thresholdSpin.
setValue(currentThreshold);
3491 "<p>Maximum difference between camera and target temperatures triggering regulation."
3492 "<p>This setting is read from and stored in the INDI camera driver configuration."
3496 layout.
addRow(&rampLabel, &rampSpin);
3497 layout.
addRow(&thresholdLabel, &thresholdSpin);
3503 dialog->setWindowTitle(
i18nc(
"@title:window",
"Set Temperature Regulation"));
3505 dialog->setLayout(&layout);
3506 dialog->setMinimumWidth(300);
3510 if (devices()->getActiveCamera())
3511 devices()->getActiveCamera()->setTemperatureRegulation(rampSpin.
value(), thresholdSpin.
value());
3515void Camera::createDSLRDialog()
3517 m_DSLRInfoDialog.reset(
new DSLRInfo(
this, devices()->getActiveCamera()));
3519 connect(m_DSLRInfoDialog.get(), &DSLRInfo::infoChanged,
this, [
this]()
3521 if (devices()->getActiveCamera())
3522 addDSLRInfo(QString(devices()->getActiveCamera()->getDeviceName()),
3523 m_DSLRInfoDialog->sensorMaxWidth,
3524 m_DSLRInfoDialog->sensorMaxHeight,
3525 m_DSLRInfoDialog->sensorPixelW,
3526 m_DSLRInfoDialog->sensorPixelH);
3529 m_DSLRInfoDialog->show();
3531 emit dslrInfoRequested(devices()->getActiveCamera()->getDeviceName());
3534void Camera::showObserverDialog()
3539 for (
auto &o : m_observerList)
3540 observers <<
QString(
"%1 %2").arg(o->
name(), o->surname());
3542 QDialog observersDialog(
this);
3543 observersDialog.setWindowTitle(
i18nc(
"@title:window",
"Select Current Observer"));
3547 QComboBox observerCombo(&observersDialog);
3548 observerCombo.addItems(observers);
3549 observerCombo.setCurrentText(getObserverName());
3553 manageObserver.setFixedSize(
QSize(32, 32));
3556 manageObserver.setToolTip(
i18n(
"Manage Observers"));
3565 for (
auto &o : m_observerList)
3566 observers <<
QString(
"%1 %2").arg(o->
name(), o->surname());
3568 observerCombo.
clear();
3569 observerCombo.addItems(observers);
3570 observerCombo.setCurrentText(getObserverName());
3576 layout->addWidget(&observerCombo);
3577 layout->addWidget(&manageObserver);
3579 observersDialog.setLayout(layout);
3581 observersDialog.exec();
3582 setObserverName(observerCombo.currentText());
3585void Camera::onStandAloneShow(
QShowEvent *event)
3587 OpticalTrainSettings::Instance()->setOpticalTrainID(Options::captureTrainID());
3588 auto oneSetting = OpticalTrainSettings::Instance()->getOneSetting(OpticalTrainSettings::Capture);
3589 setSettings(oneSetting.toJsonObject().toVariantMap());
3594 captureGainN->setValue(GainSpinSpecialValue);
3595 captureOffsetN->setValue(OffsetSpinSpecialValue);
3597 m_standAloneUseCcdGain =
true;
3598 m_standAloneUseCcdOffset =
true;
3599 if (m_settings.contains(KEY_GAIN_KWD) && m_settings[KEY_GAIN_KWD].toString() ==
"CCD_CONTROLS")
3600 m_standAloneUseCcdGain =
false;
3601 if (m_settings.contains(KEY_OFFSET_KWD) && m_settings[KEY_OFFSET_KWD].toString() ==
"CCD_CONTROLS")
3602 m_standAloneUseCcdOffset =
false;
3608 if (captureGainN->value() != GainSpinSpecialValue)
3609 setGain(captureGainN->value());
3617 if (captureOffsetN->value() != OffsetSpinSpecialValue)
3618 setOffset(captureOffsetN->value());
3624void Camera::setStandAloneGain(
double value)
3628 if (m_standAloneUseCcdGain)
3633 ccdGain[
"GAIN"] = value;
3634 propertyMap[
"CCD_GAIN"] = ccdGain;
3638 propertyMap[
"CCD_GAIN"].
remove(
"GAIN");
3639 if (propertyMap[
"CCD_GAIN"].size() == 0)
3640 propertyMap.
remove(
"CCD_GAIN");
3648 ccdGain[
"Gain"] = value;
3649 propertyMap[
"CCD_CONTROLS"] = ccdGain;
3653 propertyMap[
"CCD_CONTROLS"].
remove(
"Gain");
3654 if (propertyMap[
"CCD_CONTROLS"].size() == 0)
3655 propertyMap.
remove(
"CCD_CONTROLS");
3659 m_customPropertiesDialog->setCustomProperties(propertyMap);
3662void Camera::setStandAloneOffset(
double value)
3666 if (m_standAloneUseCcdOffset)
3671 ccdOffset[
"OFFSET"] = value;
3672 propertyMap[
"CCD_OFFSET"] = ccdOffset;
3676 propertyMap[
"CCD_OFFSET"].
remove(
"OFFSET");
3677 if (propertyMap[
"CCD_OFFSET"].size() == 0)
3678 propertyMap.
remove(
"CCD_OFFSET");
3686 ccdOffset[
"Offset"] = value;
3687 propertyMap[
"CCD_CONTROLS"] = ccdOffset;
3691 propertyMap[
"CCD_CONTROLS"].
remove(
"Offset");
3692 if (propertyMap[
"CCD_CONTROLS"].size() == 0)
3693 propertyMap.
remove(
"CCD_CONTROLS");
3697 m_customPropertiesDialog->setCustomProperties(propertyMap);
3700void Camera::setVideoStreamEnabled(
bool enabled)
3704 liveVideoB->setChecked(
true);
3709 liveVideoB->setChecked(
false);
3715void Camera::setCoolerToggled(
bool enabled)
3717 auto isToggled = (!enabled && coolerOnB->isChecked()) || (enabled && coolerOffB->isChecked());
3719 coolerOnB->blockSignals(
true);
3720 coolerOnB->setChecked(enabled);
3721 coolerOnB->blockSignals(
false);
3723 coolerOffB->blockSignals(
true);
3724 coolerOffB->setChecked(!enabled);
3725 coolerOffB->blockSignals(
false);
3728 appendLogText(enabled ?
i18n(
"Cooler is on") :
i18n(
"Cooler is off"));
3731void Camera::setFilterStatus(FilterState filterState)
3733 if (filterState != state()->getFilterManagerState())
3734 qCDebug(KSTARS_EKOS_CAPTURE) <<
"Filter state changed from" << Ekos::getFilterStatusString(
3735 state()->getFilterManagerState()) <<
"to" << Ekos::getFilterStatusString(filterState);
3736 if (state()->getCaptureState() == CAPTURE_CHANGING_FILTER)
3738 switch (filterState)
3741 appendLogText(
i18n(
"Changing focus offset by %1 steps...",
3742 filterManager()->getTargetFilterOffset()));
3746 appendLogText(
i18n(
"Changing filter to %1...",
3747 FilterPosCombo->itemText(filterManager()->getTargetFilterPosition() - 1)));
3750 case FILTER_AUTOFOCUS:
3751 appendLogText(
i18n(
"Auto focus on filter change..."));
3752 clearAutoFocusHFR();
3756 if (state()->getFilterManagerState() == FILTER_CHANGE)
3758 appendLogText(
i18n(
"Filter set to %1.",
3759 FilterPosCombo->itemText(filterManager()->getTargetFilterPosition() - 1)));
3767 state()->setFilterManagerState(filterState);
3769 captureStatusWidget->setFilterState(filterState);
3772void Camera::resetJobs()
3778 if (m_JobUnderEdit ==
true)
3780 SequenceJob * job = state()->allJobs().at(queueTable->currentRow());
3784 updateJobTable(job);
3790 nullptr,
i18n(
"Are you sure you want to reset status of all jobs?"),
i18n(
"Reset job status"),
3799 updateJobTable(job);
3804 state()->clearCapturedFramesMap();
3807 state()->setIgnoreJobProgress(Options::alwaysResetSequenceWhenStarting());
3810 startB->setEnabled(
true);
3815 if (i.
row() < 0 || (i.
row() + 1) > state()->allJobs().size())
3820 if (job ==
nullptr || job->jobType() == SequenceJob::JOBTYPE_DARKFLAT)
3825 if (state()->isBusy())
3828 if (state()->allJobs().size() >= 2)
3830 queueUpB->setEnabled(i.
row() > 0);
3831 queueDownB->setEnabled(i.
row() + 1 < state()->allJobs().size());
3840 if (selectJob(i) ==
false)
3843 appendLogText(
i18n(
"Editing job #%1...", i.
row() + 1));
3846 addToQueueB->setToolTip(
i18n(
"Apply job changes."));
3847 removeFromQueueB->setToolTip(
i18n(
"Cancel job changes."));
3850 previewB->setDefault(
false);
3851 addToQueueB->setDefault(
true);
3853 m_JobUnderEdit =
true;
3857void Camera::resetJobEdit(
bool cancelled)
3859 if (cancelled ==
true)
3860 appendLogText(
i18n(
"Editing job canceled."));
3862 m_JobUnderEdit =
false;
3865 addToQueueB->setToolTip(
i18n(
"Add job to sequence queue"));
3866 removeFromQueueB->setToolTip(
i18n(
"Remove job from sequence queue"));
3868 addToQueueB->setDefault(
false);
3869 previewB->setDefault(
true);
CameraChip class controls a particular chip in camera.
Camera class controls an INDI Camera device.
Rotator class handles control of INDI Rotator devices.
bool GetAllObservers(QList< OAL::Observer * > &observer_list)
Updates the passed reference of observer_list with all observers The original content of the list is ...
const KStarsDateTime & lt() const
static KStars * Instance()
KStarsData * data() const
Dialog to add new observers.
Sequence Job is a container for the details required to capture a series of images.
The sky coordinates of a point in the sky.
void setAlt(dms alt)
Sets Alt, the Altitude.
void setAz(dms az)
Sets Az, the Azimuth.
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
Ekos is an advanced Astrophotography tool for Linux.
@ CAPTURE_SETTING_ROTATOR
@ CAPTURE_SETTING_TEMPERATURE
ISD is a collection of INDI Standard Devices.
QString name(GameStandardAction id)
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
bool isValid(QStringView ifopt)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QAction * up(const QObject *recvr, const char *slot, QObject *parent)
const QList< QKeySequence > & begin()
QString label(StandardShortcut id)
NETWORKMANAGERQT_EXPORT NetworkManager::Status status()
void doubleClicked(const QModelIndex &index)
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
void currentIndexChanged(int index)
void setCurrentText(const QString &text)
void currentTextChanged(const QString &text)
QString toString(QStringView format, QCalendar cal) const const
QString toNativeSeparators(const QString &pathName)
void setMaximum(double max)
void setMinimum(double min)
void setSingleStep(double val)
void setValue(double val)
void valueChanged(double d)
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, Options options)
QUrl getOpenFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
QUrl getSaveFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
bool isChecked() const const
QIcon fromTheme(const QString &name)
void currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
void removeAt(qsizetype i)
void replace(qsizetype i, const QJsonValue &value)
iterator insert(QLatin1StringView key, const QJsonValue &value)
void setText(const QString &)
void textChanged(const QString &text)
void textEdited(const QString &text)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype count() const const
bool isEmpty() const const
void prepend(parameter_type value)
void removeAt(qsizetype i)
bool removeOne(const AT &t)
size_type remove(const Key &key)
bool disconnect(const QMetaObject::Connection &connection)
bool restoreState(const QByteArray &state)
QString arg(Args &&... args) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
QString left(qsizetype n) const const
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QTextStream & bin(QTextStream &stream)
void setText(const QString &text)
void setTextAlignment(Qt::Alignment alignment)
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)
bool isEmpty() const const
bool isValid() const const
QString toLocalFile() const const
QString url(FormattingOptions options) const const
bool isValid() const const
void setValue(QVariant &&value)
bool toBool() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
QString toString() const const
uint toUInt(bool *ok) const const