diff --git a/kstars/indi/indielement.cpp b/kstars/indi/indielement.cpp index 8051d82f4..424380ee5 100644 --- a/kstars/indi/indielement.cpp +++ b/kstars/indi/indielement.cpp @@ -1,664 +1,666 @@ /* INDI Element Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 2004-01-15 INDI element is the most basic unit of the INDI KStars client. */ #include "indielement.h" #include "indiproperty.h" #include "indigroup.h" #include "indidevice.h" #include "kstars.h" #include "ksnotification.h" #include #include #include #include #include #include #include #include #include #include #include #include #include extern const char *libindi_strings_context; /******************************************************************* ** INDI Element *******************************************************************/ INDI_E::INDI_E(INDI_P *gProp, INDI::Property *dProp) { guiProp = gProp; dataProp = dProp; EHBox = new QHBoxLayout; EHBox->setContentsMargins(0, 0, 0, 0); } INDI_E::~INDI_E() { delete (EHBox); delete (label_w); delete (read_w); delete (write_w); delete (spin_w); delete (slider_w); delete (push_w); delete (browse_w); delete (check_w); delete (led_w); delete (hSpacer); } void INDI_E::buildSwitch(QButtonGroup *groupB, ISwitch *sw) { name = sw->name; label = i18nc(libindi_strings_context, sw->label); if (label == "(I18N_EMPTY_MESSAGE)") label = sw->label; sp = sw; if (label.isEmpty()) label = i18nc(libindi_strings_context, sw->name); if (label == "(I18N_EMPTY_MESSAGE)") label = sw->name; if (groupB == nullptr) return; switch (guiProp->getGUIType()) { case PG_BUTTONS: push_w = new QPushButton(label, guiProp->getGroup()->getContainer()); push_w->setCheckable(true); groupB->addButton(push_w); syncSwitch(); guiProp->addWidget(push_w); push_w->show(); if (sw->svp->p == IP_RO) push_w->setEnabled(sw->s == ISS_ON); break; case PG_RADIO: check_w = new QCheckBox(label, guiProp->getGroup()->getContainer()); groupB->addButton(check_w); syncSwitch(); guiProp->addWidget(check_w); check_w->show(); if (sw->svp->p == IP_RO) check_w->setEnabled(sw->s == ISS_ON); break; default: break; } } void INDI_E::buildMenuItem(ISwitch *sw) { buildSwitch(nullptr, sw); } void INDI_E::buildText(IText *itp) { name = itp->name; if (itp->label[0]) label = i18nc(libindi_strings_context, itp->label); if (label == "(I18N_EMPTY_MESSAGE)") label = itp->label; tp = itp; if (label.isEmpty()) label = i18nc(libindi_strings_context, itp->name); if (label == "(I18N_EMPTY_MESSAGE)") label = itp->name; setupElementLabel(); if (tp->text[0]) text = i18nc(libindi_strings_context, tp->text); switch (dataProp->getPermission()) { case IP_RW: setupElementRead(ELEMENT_READ_WIDTH * KStars::Instance()->devicePixelRatio()); setupElementWrite(ELEMENT_WRITE_WIDTH * KStars::Instance()->devicePixelRatio()); break; case IP_RO: setupElementRead(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio()); break; case IP_WO: setupElementWrite(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio()); break; } guiProp->addLayout(EHBox); //pp->PVBox->addLayout(EHBox); } void INDI_E::setupElementLabel() { QPalette palette; label_w = new KSqueezedTextLabel(guiProp->getGroup()->getContainer()); label_w->setMinimumWidth(ELEMENT_LABEL_WIDTH * KStars::Instance()->devicePixelRatio()); label_w->setMaximumWidth(ELEMENT_LABEL_WIDTH * KStars::Instance()->devicePixelRatio()); label_w->setFrameShape(KSqueezedTextLabel::Box); + label_w->setFrameShadow(KSqueezedTextLabel::Sunken); + label_w->setMargin(2); palette.setColor(label_w->backgroundRole(), QColor(224, 232, 238)); label_w->setPalette(palette); label_w->setTextFormat(Qt::RichText); label_w->setAlignment(Qt::AlignCenter); label_w->setWordWrap(true); if (label.length() > MAX_LABEL_LENGTH) { QFont tempFont(label_w->font()); tempFont.setPointSize(tempFont.pointSize() - MED_INDI_FONT); label_w->setFont(tempFont); } label_w->setText(label); EHBox->addWidget(label_w); } void INDI_E::syncSwitch() { QFont buttonFont; switch (guiProp->getGUIType()) { case PG_BUTTONS: if (sp->s == ISS_ON) { push_w->setChecked(true); //push_w->setDown(true); buttonFont = push_w->font(); buttonFont.setBold(true); push_w->setFont(buttonFont); if (sp->svp->p == IP_RO) push_w->setEnabled(true); } else { push_w->setChecked(false); //push_w->setDown(false); buttonFont = push_w->font(); buttonFont.setBold(false); push_w->setFont(buttonFont); if (sp->svp->p == IP_RO) push_w->setEnabled(false); } break; case PG_RADIO: if (sp->s == ISS_ON) { check_w->setChecked(true); if (sp->svp->p == IP_RO) check_w->setEnabled(true); } else { check_w->setChecked(false); if (sp->svp->p == IP_RO) check_w->setEnabled(false); } break; default: break; } } void INDI_E::syncText() { if (tp == nullptr) return; if (tp->tvp->p != IP_WO) { if (tp->text[0]) read_w->setText(i18nc(libindi_strings_context, tp->text)); else read_w->setText(tp->text); } // If write-only else { write_w->setText(tp->text); } } void INDI_E::syncNumber() { char iNumber[MAXINDIFORMAT]; if (np == nullptr || read_w == nullptr) return; numberFormat(iNumber, np->format, np->value); text = iNumber; read_w->setText(text); if (spin_w) { if (np->min != spin_w->minimum()) setMin(); if (np->max != spin_w->maximum()) setMax(); } } void INDI_E::updateTP() { if (tp == nullptr) return; IUSaveText(tp, write_w->text().toHtmlEscaped().toLatin1().constData()); } void INDI_E::updateNP() { if (np == nullptr) return; if (write_w != nullptr) { if (write_w->text().isEmpty()) return; f_scansexa(write_w->text().replace(',', '.').toLatin1().constData(), &(np->value)); return; } if (spin_w != nullptr) np->value = spin_w->value(); } void INDI_E::setText(const QString &newText) { if (tp == nullptr) return; switch (dataProp->getPermission()) { case IP_RO: read_w->setText(newText); break; case IP_WO: case IP_RW: text = newText; IUSaveText(tp, newText.toLatin1().constData()); read_w->setText(newText); write_w->setText(newText); break; } } void INDI_E::buildBLOB(IBLOB *ibp) { name = ibp->name; label = i18nc(libindi_strings_context, ibp->label); if (label == "(I18N_EMPTY_MESSAGE)") label = ibp->label; bp = ibp; if (label.isEmpty()) label = i18nc(libindi_strings_context, ibp->name); if (label == "(I18N_EMPTY_MESSAGE)") label = ibp->name; setupElementLabel(); text = i18n("INDI DATA STREAM"); switch (dataProp->getPermission()) { case IP_RW: setupElementRead(ELEMENT_READ_WIDTH * KStars::Instance()->devicePixelRatio()); setupElementWrite(ELEMENT_WRITE_WIDTH * KStars::Instance()->devicePixelRatio()); setupBrowseButton(); break; case IP_RO: setupElementRead(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio()); break; case IP_WO: setupElementWrite(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio()); setupBrowseButton(); break; } guiProp->addLayout(EHBox); } void INDI_E::buildNumber(INumber *inp) { bool scale = false; char iNumber[MAXINDIFORMAT]; name = inp->name; label = i18nc(libindi_strings_context, inp->label); if (label == "(I18N_EMPTY_MESSAGE)") label = inp->label; np = inp; if (label.isEmpty()) label = i18nc(libindi_strings_context, inp->name); if (label == "(I18N_EMPTY_MESSAGE)") label = inp->name; numberFormat(iNumber, np->format, np->value); text = iNumber; setupElementLabel(); if (np->step != 0 && (np->max - np->min) / np->step <= 100) scale = true; switch (dataProp->getPermission()) { case IP_RW: setupElementRead(ELEMENT_READ_WIDTH * KStars::Instance()->devicePixelRatio()); if (scale) setupElementScale(ELEMENT_WRITE_WIDTH * KStars::Instance()->devicePixelRatio()); else setupElementWrite(ELEMENT_WRITE_WIDTH * KStars::Instance()->devicePixelRatio()); guiProp->addLayout(EHBox); break; case IP_RO: setupElementRead(ELEMENT_READ_WIDTH * KStars::Instance()->devicePixelRatio()); guiProp->addLayout(EHBox); break; case IP_WO: if (scale) setupElementScale(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio()); else setupElementWrite(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio()); guiProp->addLayout(EHBox); break; } } void INDI_E::buildLight(ILight *ilp) { name = ilp->name; label = i18nc(libindi_strings_context, ilp->label); if (label == "(I18N_EMPTY_MESSAGE)") label = ilp->label; lp = ilp; if (label.isEmpty()) label = i18nc(libindi_strings_context, ilp->name); if (label == "(I18N_EMPTY_MESSAGE)") label = ilp->name; led_w = new KLed(guiProp->getGroup()->getContainer()); led_w->setMaximumSize(16, 16); led_w->setLook(KLed::Sunken); syncLight(); EHBox->addWidget(led_w); setupElementLabel(); guiProp->addLayout(EHBox); } void INDI_E::syncLight() { if (lp == nullptr) return; switch (lp->s) { case IPS_IDLE: led_w->setColor(Qt::gray); break; case IPS_OK: led_w->setColor(Qt::green); break; case IPS_BUSY: led_w->setColor(Qt::yellow); break; case IPS_ALERT: led_w->setColor(Qt::red); break; default: break; } } void INDI_E::setupElementScale(int length) { if (np == nullptr) return; int steps = (int)((np->max - np->min) / np->step); spin_w = new QDoubleSpinBox(guiProp->getGroup()->getContainer()); spin_w->setRange(np->min, np->max); spin_w->setSingleStep(np->step); spin_w->setValue(np->value); spin_w->setDecimals(3); slider_w = new QSlider(Qt::Horizontal, guiProp->getGroup()->getContainer()); slider_w->setRange(0, steps); slider_w->setPageStep(1); slider_w->setValue((int)((np->value - np->min) / np->step)); connect(spin_w, SIGNAL(valueChanged(double)), this, SLOT(spinChanged(double))); connect(slider_w, SIGNAL(sliderMoved(int)), this, SLOT(sliderChanged(int))); if (length == ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio()) spin_w->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); else spin_w->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); spin_w->setMinimumWidth((int)(length * 0.45)); slider_w->setMinimumWidth((int)(length * 0.55)); EHBox->addWidget(slider_w); EHBox->addWidget(spin_w); } void INDI_E::spinChanged(double value) { int slider_value = (int)((value - np->min) / np->step); slider_w->setValue(slider_value); } void INDI_E::sliderChanged(int value) { double spin_value = (value * np->step) + np->min; spin_w->setValue(spin_value); } void INDI_E::setMin() { if (spin_w) { spin_w->setMinimum(np->min); spin_w->setValue(np->value); } if (slider_w) { slider_w->setMaximum((int)((np->max - np->min) / np->step)); slider_w->setMinimum(0); slider_w->setPageStep(1); slider_w->setValue((int)((np->value - np->min) / np->step)); } } void INDI_E::setMax() { if (spin_w) { spin_w->setMaximum(np->max); spin_w->setValue(np->value); } if (slider_w) { slider_w->setMaximum((int)((np->max - np->min) / np->step)); slider_w->setMinimum(0); slider_w->setPageStep(1); slider_w->setValue((int)((np->value - np->min) / np->step)); } } void INDI_E::setupElementWrite(int length) { write_w = new QLineEdit(guiProp->getGroup()->getContainer()); write_w->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); write_w->setMinimumWidth(length); write_w->setMaximumWidth(length); write_w->setText(text); //QObject::connect(write_w, SIGNAL(returnPressed(QString)), this, SLOT(updateTP())); QObject::connect(write_w, SIGNAL(returnPressed()), guiProp, SLOT(sendText())); EHBox->addWidget(write_w); } void INDI_E::setupElementRead(int length) { read_w = new QLineEdit(guiProp->getGroup()->getContainer()); read_w->setMinimumWidth(length); read_w->setFocusPolicy(Qt::NoFocus); read_w->setCursorPosition(0); read_w->setAlignment(Qt::AlignCenter); read_w->setReadOnly(true); read_w->setText(text); EHBox->addWidget(read_w); } void INDI_E::setupBrowseButton() { browse_w = new QPushButton(guiProp->getGroup()->getContainer()); browse_w->setIcon(QIcon::fromTheme("document-open")); browse_w->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); browse_w->setMinimumWidth(MIN_SET_WIDTH * KStars::Instance()->devicePixelRatio()); browse_w->setMaximumWidth(MAX_SET_WIDTH * KStars::Instance()->devicePixelRatio()); EHBox->addWidget(browse_w); QObject::connect(browse_w, SIGNAL(clicked()), this, SLOT(browseBlob())); } void INDI_E::browseBlob() { QFile fp; QString filename; QString format; int pos = 0; QUrl currentURL; currentURL = QFileDialog::getOpenFileUrl(); // if user presses cancel if (currentURL.isEmpty()) return; if (currentURL.isValid()) write_w->setText(currentURL.toLocalFile()); fp.setFileName(currentURL.toLocalFile()); if ((pos = filename.lastIndexOf(".")) != -1) format = filename.mid(pos, filename.length()); //qDebug() << "Filename is " << fp.fileName() << endl; if (!fp.open(QIODevice::ReadOnly)) { KSNotification::error( i18n("Cannot open file %1 for reading", filename)); return; } bp->bloblen = bp->size = fp.size(); bp->blob = static_cast(realloc(bp->blob, bp->size)); if (bp->blob == nullptr) { KSNotification::error( i18n("Not enough memory for file %1", filename)); fp.close(); return; } memcpy(bp->blob, fp.readAll().constData(), bp->size); blobDirty = true; } QString INDI_E::getWriteField() { if (write_w) return write_w->text(); else return nullptr; } QString INDI_E::getReadField() { if (read_w) return read_w->text(); else return nullptr; } diff --git a/kstars/indi/indiproperty.cpp b/kstars/indi/indiproperty.cpp index 431c75c8e..3359f89fe 100644 --- a/kstars/indi/indiproperty.cpp +++ b/kstars/indi/indiproperty.cpp @@ -1,674 +1,683 @@ /* INDI Property Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include "indiproperty.h" #include "clientmanager.h" #include "indidevice.h" #include "indielement.h" #include "indigroup.h" #include "kstars.h" #include "Options.h" #include "skymap.h" #include "dialogs/timedialog.h" #include #include #include #include #include #include #include #include #include #include #include extern const char *libindi_strings_context; /******************************************************************* ** INDI Property: contains widgets, labels, and their status *******************************************************************/ INDI_P::INDI_P(INDI_G *ipg, INDI::Property *prop) { pg = ipg; dataProp = prop; name = QString(prop->getName()); PHBox.reset(new QHBoxLayout()); PHBox->setContentsMargins(0, 0, 0, 0); PVBox = new QVBoxLayout(); PVBox->setContentsMargins(0, 0, 0, 0); initGUI(); } INDI_P::~INDI_P() { qDeleteAll(elementList); elementList.clear(); } void INDI_P::updateStateLED() { /* set state light */ switch (dataProp->getState()) { case IPS_IDLE: ledStatus->setColor(Qt::gray); break; case IPS_OK: ledStatus->setColor(Qt::green); break; case IPS_BUSY: ledStatus->setColor(Qt::yellow); break; case IPS_ALERT: ledStatus->setColor(Qt::red); break; default: break; } } /* build widgets for property pp using info in root. */ void INDI_P::initGUI() { QString label = i18nc(libindi_strings_context, dataProp->getLabel()); if (label == "(I18N_EMPTY_MESSAGE)") label = dataProp->getLabel(); /* add to GUI group */ ledStatus.reset(new KLed(pg->getContainer())); ledStatus->setMaximumSize(16, 16); ledStatus->setLook(KLed::Sunken); updateStateLED(); + /* Create a horizontally layout widget around light and label */ + QWidget *labelWidget = new QWidget(); + QHBoxLayout *labelLayout = new QHBoxLayout(); + labelLayout->setContentsMargins(0, 0, 0, 0); + labelWidget->setLayout(labelLayout); + /* #1 First widget is the LED status indicator */ - PHBox->addWidget(ledStatus.get()); + labelLayout->addWidget(ledStatus.get()); if (label.isEmpty()) { label = i18nc(libindi_strings_context, name.toUtf8()); if (label == "(I18N_EMPTY_MESSAGE)") label = name.toUtf8(); labelW.reset(new KSqueezedTextLabel(label, pg->getContainer())); } else labelW.reset(new KSqueezedTextLabel(label, pg->getContainer())); //labelW->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - labelW->setFrameShape(QFrame::StyledPanel); + labelW->setFrameShape(QFrame::Box); + labelW->setFrameShadow(QFrame::Sunken); + labelW->setMargin(2); labelW->setFixedWidth(PROPERTY_LABEL_WIDTH * KStars::Instance()->devicePixelRatio()); labelW->setTextFormat(Qt::RichText); labelW->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); labelW->setWordWrap(true); - PHBox->addWidget(labelW.get()); + labelLayout->addWidget(labelW.get()); + PHBox->addWidget(labelWidget, 0, Qt::AlignTop | Qt::AlignLeft); ledStatus->show(); labelW->show(); // #3 Add the Vertical layout which may contain several elements PHBox->addLayout(PVBox); switch (dataProp->getType()) { case INDI_SWITCH: if (dataProp->getSwitch()->r == ISR_NOFMANY) guiType = PG_RADIO; else if (dataProp->getSwitch()->nsp > 4) guiType = PG_MENU; else guiType = PG_BUTTONS; if (guiType == PG_MENU) buildMenuGUI(); else buildSwitchGUI(); break; case INDI_TEXT: buildTextGUI(); break; case INDI_NUMBER: buildNumberGUI(); break; case INDI_LIGHT: buildLightGUI(); break; case INDI_BLOB: buildBLOBGUI(); break; default: break; } } void INDI_P::buildSwitchGUI() { INDI_E *lp = nullptr; ISwitchVectorProperty *svp = dataProp->getSwitch(); if (svp == nullptr) return; groupB.reset(new QButtonGroup()); if (guiType == PG_BUTTONS) { if (svp->r == ISR_1OFMANY) groupB->setExclusive(true); else groupB->setExclusive(false); } else if (guiType == PG_RADIO) groupB->setExclusive(false); if (svp->p != IP_RO) QObject::connect(groupB.get(), SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(newSwitch(QAbstractButton*))); for (int i = 0; i < svp->nsp; i++) { ISwitch *sp = &(svp->sp[i]); lp = new INDI_E(this, dataProp); lp->buildSwitch(groupB.get(), sp); elementList.append(lp); } horSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); PHBox->addItem(horSpacer); } void INDI_P::buildTextGUI() { INDI_E *lp = nullptr; ITextVectorProperty *tvp = dataProp->getText(); if (tvp == nullptr) return; for (int i = 0; i < tvp->ntp; i++) { IText *tp = &(tvp->tp[i]); lp = new INDI_E(this, dataProp); lp->buildText(tp); elementList.append(lp); } horSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); PHBox->addItem(horSpacer); if (tvp->p == IP_RO) return; // INDI STD, but we use our own controls if (name == "TIME_UTC") setupSetButton(i18n("Time")); else setupSetButton(i18n("Set")); } void INDI_P::buildNumberGUI() { INDI_E *lp = nullptr; INumberVectorProperty *nvp = dataProp->getNumber(); if (nvp == nullptr) return; for (int i = 0; i < nvp->nnp; i++) { INumber *np = &(nvp->np[i]); lp = new INDI_E(this, dataProp); lp->buildNumber(np); elementList.append(lp); } horSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); PHBox->addItem(horSpacer); if (nvp->p == IP_RO) return; setupSetButton(i18n("Set")); } void INDI_P::buildLightGUI() { INDI_E *ep = nullptr; ILightVectorProperty *lvp = dataProp->getLight(); if (lvp == nullptr) return; for (int i = 0; i < lvp->nlp; i++) { ILight *lp = &(lvp->lp[i]); ep = new INDI_E(this, dataProp); ep->buildLight(lp); elementList.append(ep); } horSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); PHBox->addItem(horSpacer); } void INDI_P::buildBLOBGUI() { INDI_E *lp = nullptr; IBLOBVectorProperty *bvp = dataProp->getBLOB(); if (bvp == nullptr) return; for (int i = 0; i < bvp->nbp; i++) { IBLOB *bp = &(bvp->bp[i]); lp = new INDI_E(this, dataProp); lp->buildBLOB(bp); elementList.append(lp); } horSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); PHBox->addItem(horSpacer); enableBLOBC = new QCheckBox(); enableBLOBC->setIcon(QIcon::fromTheme("network-modem")); enableBLOBC->setChecked(true); enableBLOBC->setToolTip(i18n("Enable binary data transfer from this property to KStars and vice-versa.")); PHBox->addWidget(enableBLOBC); connect(enableBLOBC, SIGNAL(stateChanged(int)), this, SLOT(setBLOBOption(int))); if (dataProp->getPermission() != IP_RO) setupSetButton(i18n("Upload")); } void INDI_P::setBLOBOption(int state) { pg->getDevice()->getClientManager()->setBLOBEnabled(state == Qt::Checked, dataProp->getDeviceName(), dataProp->getName()); } void INDI_P::newSwitch(QAbstractButton *button) { ISwitchVectorProperty *svp = dataProp->getSwitch(); QString buttonText = button->text(); if (svp == nullptr) return; buttonText.remove('&'); foreach (INDI_E *el, elementList) { if (el->getLabel() == buttonText) { newSwitch(el->getName()); return; } } } void INDI_P::resetSwitch() { ISwitchVectorProperty *svp = dataProp->getSwitch(); if (svp == nullptr) return; if (menuC.get() != nullptr) { menuC->setCurrentIndex(IUFindOnSwitchIndex(svp)); } } void INDI_P::newSwitch(int index) { ISwitchVectorProperty *svp = dataProp->getSwitch(); if (svp == nullptr) return; if (index >= svp->nsp) return; ISwitch *sp = &(svp->sp[index]); IUResetSwitch(svp); sp->s = ISS_ON; sendSwitch(); } void INDI_P::newSwitch(const QString &name) { ISwitchVectorProperty *svp = dataProp->getSwitch(); if (svp == nullptr) return; ISwitch *sp = IUFindSwitch(svp, name.toLatin1().constData()); if (sp == nullptr) return; if (svp->r == ISR_1OFMANY) { IUResetSwitch(svp); sp->s = ISS_ON; } else { if (svp->r == ISR_ATMOST1) { ISState prev_state = sp->s; IUResetSwitch(svp); sp->s = prev_state; } sp->s = (sp->s == ISS_ON) ? ISS_OFF : ISS_ON; } sendSwitch(); } void INDI_P::sendSwitch() { ISwitchVectorProperty *svp = dataProp->getSwitch(); if (svp == nullptr) return; svp->s = IPS_BUSY; foreach (INDI_E *el, elementList) el->syncSwitch(); updateStateLED(); // Send it to server pg->getDevice()->getClientManager()->sendNewSwitch(svp); } void INDI_P::sendText() { ITextVectorProperty *tvp = nullptr; INumberVectorProperty *nvp = nullptr; switch (dataProp->getType()) { case INDI_TEXT: tvp = dataProp->getText(); if (tvp == nullptr) return; tvp->s = IPS_BUSY; foreach (INDI_E *el, elementList) el->updateTP(); pg->getDevice()->getClientManager()->sendNewText(tvp); break; case INDI_NUMBER: nvp = dataProp->getNumber(); if (nvp == nullptr) return; nvp->s = IPS_BUSY; foreach (INDI_E *el, elementList) el->updateNP(); pg->getDevice()->getClientManager()->sendNewNumber(nvp); break; default: break; } updateStateLED(); } void INDI_P::buildMenuGUI() { QStringList menuOptions; QString oneOption; int onItem = -1; INDI_E *lp = nullptr; ISwitchVectorProperty *svp = dataProp->getSwitch(); if (svp == nullptr) return; menuC.reset(new QComboBox(pg->getContainer())); if (svp->p == IP_RO) connect(menuC.get(), SIGNAL(activated(int)), this, SLOT(resetSwitch())); else connect(menuC.get(), SIGNAL(activated(int)), this, SLOT(newSwitch(int))); for (int i = 0; i < svp->nsp; i++) { ISwitch *tp = &(svp->sp[i]); if (tp->s == ISS_ON) onItem = i; lp = new INDI_E(this, dataProp); lp->buildMenuItem(tp); oneOption = i18nc(libindi_strings_context, lp->getLabel().toUtf8()); if (oneOption == "(I18N_EMPTY_MESSAGE)") oneOption = lp->getLabel().toUtf8(); menuOptions.append(oneOption); elementList.append(lp); } menuC->addItems(menuOptions); menuC->setCurrentIndex(onItem); horSpacer = new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); PHBox->addWidget(menuC.get()); PHBox->addItem(horSpacer); } void INDI_P::setupSetButton(const QString &caption) { setB.reset(new QPushButton(caption, pg->getContainer())); setB->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); setB->setMinimumWidth(MIN_SET_WIDTH * KStars::Instance()->devicePixelRatio()); setB->setMaximumWidth(MAX_SET_WIDTH * KStars::Instance()->devicePixelRatio()); connect(setB.get(), SIGNAL(clicked()), this, SLOT(processSetButton())); PHBox->addWidget(setB.get()); } void INDI_P::addWidget(QWidget *w) { PHBox->addWidget(w); } void INDI_P::addLayout(QHBoxLayout *layout) { PVBox->addLayout(layout); } void INDI_P::updateMenuGUI() { ISwitchVectorProperty *svp = dataProp->getSwitch(); if (svp == nullptr) return; int currentIndex = IUFindOnSwitchIndex(svp); menuC->setCurrentIndex(currentIndex); } void INDI_P::processSetButton() { switch (dataProp->getType()) { case INDI_TEXT: if (!strcmp(dataProp->getName(), "TIME_UTC")) newTime(); else sendText(); break; case INDI_NUMBER: sendText(); break; case INDI_BLOB: sendBlob(); break; default: break; } } void INDI_P::sendBlob() { //int index=0; //bool openingTag=false; IBLOBVectorProperty *bvp = dataProp->getBLOB(); if (bvp == nullptr) return; bvp->s = IPS_BUSY; pg->getDevice()->getClientManager()->startBlob(bvp->device, bvp->name, timestamp()); for (int i = 0; i < elementList.count(); i++) { IBLOB *bp = &(bvp->bp[i]); #if (INDI_VERSION_MINOR >= 4 && INDI_VERSION_RELEASE >= 2) pg->getDevice()->getClientManager()->sendOneBlob(bp); #else pg->getDevice()->getClientManager()->sendOneBlob(bp->name, bp->size, bp->format, bp->blob); #endif } // JM: Why we need dirty here? We should be able to upload multiple time /*foreach(INDI_E *ep, elementList) { if (ep->getBLOBDirty() == true) { if (openingTag == false) { pg->getDevice()->getClientManager()->startBlob(bvp->device, bvp->name, timestamp()); openingTag = true; } IBLOB *bp = &(bvp->bp[index]); ep->setBLOBDirty(false); //qDebug() << "SENDING BLOB " << bp->name << " has size of " << bp->size << " and bloblen of " << bp->bloblen << endl; pg->getDevice()->getClientManager()->sendOneBlob(bp->name, bp->size, bp->format, bp->blob); } index++; }*/ //if (openingTag) pg->getDevice()->getClientManager()->finishBlob(); updateStateLED(); } void INDI_P::newTime() { INDI_E *timeEle; INDI_E *offsetEle; timeEle = getElement("UTC"); offsetEle = getElement("OFFSET"); if (!timeEle || !offsetEle) return; TimeDialog timedialog(KStars::Instance()->data()->ut(), KStars::Instance()->data()->geo(), KStars::Instance(), true); if (timedialog.exec() == QDialog::Accepted) { QTime newTime(timedialog.selectedTime()); QDate newDate(timedialog.selectedDate()); timeEle->setText(QString("%1-%2-%3T%4:%5:%6") .arg(newDate.year()) .arg(newDate.month()) .arg(newDate.day()) .arg(newTime.hour()) .arg(newTime.minute()) .arg(newTime.second())); offsetEle->setText(QString().setNum(KStars::Instance()->data()->geo()->TZ(), 'g', 2)); sendText(); } else return; } INDI_E *INDI_P::getElement(const QString &elementName) { foreach (INDI_E *ep, elementList) { if (ep->getName() == elementName) return ep; } return nullptr; }