diff --git a/kstars/indi/indielement.cpp b/kstars/indi/indielement.cpp index 7dbec2675..424380ee5 100644 --- a/kstars/indi/indielement.cpp +++ b/kstars/indi/indielement.cpp @@ -1,665 +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 QLabel(guiProp->getGroup()->getContainer()); - label_w->setFixedWidth(ELEMENT_LABEL_WIDTH * KStars::Instance()->devicePixelRatio()); - label_w->setMinimumHeight(ELEMENT_LABEL_HEIGHT * KStars::Instance()->devicePixelRatio()); - label_w->setFrameShape(QLabel::Box); - label_w->setFrameShadow(QLabel::Sunken); + 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/indielement.h b/kstars/indi/indielement.h index 2947593d8..7061d6af1 100644 --- a/kstars/indi/indielement.h +++ b/kstars/indi/indielement.h @@ -1,146 +1,134 @@ /* 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. */ #pragma once #include "indicommon.h" #include #include #include /* Forward declaration */ class QLineEdit; class QDoubleSpinBox; class QPushButton; class QHBoxLayout; class QSpacerItem; class QCheckBox; class QButtonGroup; class QSlider; class KLed; -class QLabel; +class KSqueezedTextLabel; class INDI_P; /** * @class INDI_E * INDI_E represents an INDI GUI element (Number, Text, Switch, Light, or BLOB) within an INDI property. * It is the most basic GUI representation of property elements. * * @author Jasem Mutlaq */ class INDI_E : public QObject { - Q_OBJECT - public: - INDI_E(INDI_P *gProp, INDI::Property *dProp); - ~INDI_E(); - - const QString &getLabel() - { - return label; - } - const QString &getName() - { - return name; - } - - QString getWriteField(); - QString getReadField(); - - void buildSwitch(QButtonGroup *groupB, ISwitch *sw); - void buildMenuItem(ISwitch *sw); - void buildText(IText *itp); - void buildNumber(INumber *inp); - void buildLight(ILight *ilp); - void buildBLOB(IBLOB *ibp); - - // Updates GUI from data in INDI properties - void syncSwitch(); - void syncText(); - void syncNumber(); - void syncLight(); - - // Save GUI data in INDI properties - void updateTP(); - void updateNP(); - - void setText(const QString &newText); - - void setMin(); - void setMax(); - - void setupElementLabel(); - void setupElementRead(int length); - void setupElementWrite(int length); - void setupElementScale(int length); - void setupBrowseButton(); - - bool getBLOBDirty() - { - return blobDirty; - } - void setBLOBDirty(bool isDirty) - { - blobDirty = isDirty; - } - - public slots: - void spinChanged(double value); - void sliderChanged(int value); - void browseBlob(); - - private: - /// Name - QString name; - /// Label is the name by default, unless specified - QString label; - /// Parent DATA property - INDI::Property *dataProp { nullptr }; - /// Parent GUI property - INDI_P *guiProp { nullptr }; - /// Horizontal layout - QHBoxLayout *EHBox { nullptr }; - /// Label widget - QLabel *label_w { nullptr }; - /// Read field widget - QLineEdit *read_w { nullptr }; - /// Write field widget - QLineEdit *write_w { nullptr }; - /// Light led widget - KLed *led_w { nullptr }; - /// Spinbox widget - QDoubleSpinBox *spin_w { nullptr }; - /// Slider widget - QSlider *slider_w { nullptr }; - /// Push button widget - QPushButton *push_w { nullptr }; - /// Browse button widget - QPushButton *browse_w { nullptr }; - /// Check box widget - QCheckBox *check_w { nullptr }; - /// Horizontal spacer widget - QSpacerItem *hSpacer { nullptr }; - - ISwitch *sp { nullptr }; - INumber *np { nullptr }; - IText *tp { nullptr }; - ILight *lp { nullptr }; - IBLOB *bp { nullptr }; - - bool blobDirty { false }; - /// Current text - QString text; + Q_OBJECT + public: + INDI_E(INDI_P *gProp, INDI::Property *dProp); + ~INDI_E(); + + const QString &getLabel() { return label; } + const QString &getName() { return name; } + + QString getWriteField(); + QString getReadField(); + + void buildSwitch(QButtonGroup *groupB, ISwitch *sw); + void buildMenuItem(ISwitch *sw); + void buildText(IText *itp); + void buildNumber(INumber *inp); + void buildLight(ILight *ilp); + void buildBLOB(IBLOB *ibp); + + // Updates GUI from data in INDI properties + void syncSwitch(); + void syncText(); + void syncNumber(); + void syncLight(); + + // Save GUI data in INDI properties + void updateTP(); + void updateNP(); + + void setText(const QString &newText); + + void setMin(); + void setMax(); + + void setupElementLabel(); + void setupElementRead(int length); + void setupElementWrite(int length); + void setupElementScale(int length); + void setupBrowseButton(); + + bool getBLOBDirty() { return blobDirty; } + void setBLOBDirty(bool isDirty) { blobDirty = isDirty; } + + public slots: + void spinChanged(double value); + void sliderChanged(int value); + void browseBlob(); + +private: + /// Name + QString name; + /// Label is the name by default, unless specified + QString label; + /// Parent DATA property + INDI::Property *dataProp { nullptr }; + /// Parent GUI property + INDI_P *guiProp { nullptr }; + /// Horizontal layout + QHBoxLayout *EHBox { nullptr }; + /// Label widget + KSqueezedTextLabel *label_w { nullptr }; + /// Read field widget + QLineEdit *read_w { nullptr }; + /// Write field widget + QLineEdit *write_w { nullptr }; + /// Light led widget + KLed *led_w { nullptr }; + /// Spinbox widget + QDoubleSpinBox *spin_w { nullptr }; + /// Slider widget + QSlider *slider_w { nullptr }; + /// Push button widget + QPushButton *push_w { nullptr }; + /// Browse button widget + QPushButton *browse_w { nullptr }; + /// Check box widget + QCheckBox *check_w { nullptr }; + /// Horizontal spacer widget + QSpacerItem *hSpacer { nullptr }; + + ISwitch *sp { nullptr }; + INumber *np { nullptr }; + IText *tp { nullptr }; + ILight *lp { nullptr }; + IBLOB *bp { nullptr }; + + bool blobDirty { false }; + /// Current text + QString text; }; diff --git a/kstars/indi/indiproperty.cpp b/kstars/indi/indiproperty.cpp index 4c6d40e29..3359f89fe 100644 --- a/kstars/indi/indiproperty.cpp +++ b/kstars/indi/indiproperty.cpp @@ -1,680 +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 */ 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 QLabel(label, pg->getContainer())); + labelW.reset(new KSqueezedTextLabel(label, pg->getContainer())); } else - labelW.reset(new QLabel(label, pg->getContainer())); + labelW.reset(new KSqueezedTextLabel(label, pg->getContainer())); //labelW->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); labelW->setFrameShape(QFrame::Box); labelW->setFrameShadow(QFrame::Sunken); labelW->setMargin(2); labelW->setFixedWidth(PROPERTY_LABEL_WIDTH * KStars::Instance()->devicePixelRatio()); - labelW->setMinimumHeight(PROPERTY_LABEL_HEIGHT * KStars::Instance()->devicePixelRatio()); labelW->setTextFormat(Qt::RichText); labelW->setAlignment(Qt::AlignVCenter | Qt::AlignLeft); labelW->setWordWrap(true); 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; } diff --git a/kstars/indi/indiproperty.h b/kstars/indi/indiproperty.h index 58c042a19..b98fd6b38 100644 --- a/kstars/indi/indiproperty.h +++ b/kstars/indi/indiproperty.h @@ -1,149 +1,134 @@ /* 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. */ #pragma once #include "indicommon.h" #include #include namespace INDI { class Property; } class INDI_G; class INDI_E; class QAbstractButton; class QButtonGroup; class QCheckBox; class QComboBox; class QHBoxLayout; class QPushButton; class QSpacerItem; class QVBoxLayout; -class QLabel; class KLed; +class KSqueezedTextLabel; /** * @class INDI_P * INDI_P represents a single INDI property (Switch, Text, Number, Light, or BLOB). It handles building the GUI and updating the property status and/or value as new data * arrive from INDI Serve. It also sends any changes in the property value back to INDI server via the ClientManager. * * @author Jasem Mutlaq */ class INDI_P : public QObject { - Q_OBJECT - public: - INDI_P(INDI_G *ipg, INDI::Property *prop); - ~INDI_P(); - - /* Draw state LED */ - void updateStateLED(); - - /* Update menu gui */ - void updateMenuGUI(); - - void initGUI(); - - /* First step in adding a new GUI element */ - //void addGUI(XMLEle *root); - - /* Set Property's parent group */ - //void setGroup(INDI_G *parentGroup) { pg = parentGroup; } - - void buildSwitchGUI(); - void buildMenuGUI(); - void buildTextGUI(); - void buildNumberGUI(); - void buildLightGUI(); - void buildBLOBGUI(); - - /** Setup the 'set' button in the property */ - void setupSetButton(const QString &caption); - - void newTime(); - - PGui getGUIType() - { - return guiType; - } - - INDI_G *getGroup() - { - return pg; - } - - QHBoxLayout *getContainer() - { - return PHBox.get(); - } - - const QString &getName() - { - return name; - } - - void addWidget(QWidget *w); - void addLayout(QHBoxLayout *layout); - - INDI_E *getElement(const QString &elementName); - - QList getElements() - { - return elementList; - } - - public slots: - void processSetButton(); - void newSwitch(QAbstractButton *button); - void newSwitch(int index); - void newSwitch(const QString &name); - void resetSwitch(); - - void sendBlob(); - void sendSwitch(); - void sendText(); - - void setBLOBOption(int state); - - private: - INDI::Property *dataProp { nullptr }; - /// Parent group - INDI_G *pg { nullptr }; - QCheckBox *enableBLOBC { nullptr }; - /// Label widget - std::unique_ptr labelW; - /// Set button - std::unique_ptr setB; - /// Status LED - std::unique_ptr ledStatus; - /// GUI type - PGui guiType; - /// Horizontal spacer - QSpacerItem *horSpacer { nullptr }; - /// Horizontal container - std::unique_ptr PHBox; - /// Vertical container - QVBoxLayout *PVBox { nullptr }; - /// Group button for radio and check boxes (Elements) - std::unique_ptr groupB; - /// Combo box for menu - std::unique_ptr menuC; - QString name; - /// List of elements - QList elementList; + Q_OBJECT + public: + INDI_P(INDI_G *ipg, INDI::Property *prop); + ~INDI_P(); + + /* Draw state LED */ + void updateStateLED(); + + /* Update menu gui */ + void updateMenuGUI(); + + void initGUI(); + + /* First step in adding a new GUI element */ + //void addGUI(XMLEle *root); + + /* Set Property's parent group */ + //void setGroup(INDI_G *parentGroup) { pg = parentGroup; } + + void buildSwitchGUI(); + void buildMenuGUI(); + void buildTextGUI(); + void buildNumberGUI(); + void buildLightGUI(); + void buildBLOBGUI(); + + /** Setup the 'set' button in the property */ + void setupSetButton(const QString &caption); + + void newTime(); + + PGui getGUIType() { return guiType; } + + INDI_G *getGroup() { return pg; } + + QHBoxLayout *getContainer() { return PHBox.get(); } + + const QString &getName() { return name; } + + void addWidget(QWidget *w); + void addLayout(QHBoxLayout *layout); + + INDI_E *getElement(const QString &elementName); + + QList getElements() { return elementList; } + + public slots: + void processSetButton(); + void newSwitch(QAbstractButton *button); + void newSwitch(int index); + void newSwitch(const QString &name); + void resetSwitch(); + + void sendBlob(); + void sendSwitch(); + void sendText(); + + void setBLOBOption(int state); + + private: + INDI::Property *dataProp { nullptr }; + /// Parent group + INDI_G *pg { nullptr }; + QCheckBox *enableBLOBC { nullptr }; + /// Label widget + std::unique_ptr labelW; + /// Set button + std::unique_ptr setB; + /// Status LED + std::unique_ptr ledStatus; + /// GUI type + PGui guiType; + /// Horizontal spacer + QSpacerItem *horSpacer { nullptr }; + /// Horizontal container + std::unique_ptr PHBox; + /// Vertical container + QVBoxLayout *PVBox { nullptr }; + /// Group button for radio and check boxes (Elements) + std::unique_ptr groupB; + /// Combo box for menu + std::unique_ptr menuC; + QString name; + /// List of elements + QList elementList; };