1459 lines
34 KiB
C++
1459 lines
34 KiB
C++
#include "device.h"
|
|
#include <qapplication.h>
|
|
#include <qdialog.h>
|
|
#include <qpushbutton.h>
|
|
#include <qtooltip.h>
|
|
#include <qcheckbox.h>
|
|
#include <qlabel.h>
|
|
#include <qlineedit.h>
|
|
#include <qlayout.h>
|
|
#include <qwhatsthis.h>
|
|
#include <qvalidator.h>
|
|
#include <qptrstack.h>
|
|
#include <stdio.h>
|
|
#include <qpixmap.h>
|
|
#include <qtimer.h>
|
|
#include <qvaluelist.h>
|
|
#include <qradiobutton.h>
|
|
#include <qbuttongroup.h>
|
|
#include <qlistbox.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "utils.h"
|
|
|
|
static const char *rPix[] = {
|
|
"10 10 2 1",
|
|
" c None",
|
|
"X c #0000CC",
|
|
"XX ",
|
|
"XXXX ",
|
|
"XXXXXX ",
|
|
"XXXXXXXX ",
|
|
"XXXXXXXXXX",
|
|
"XXXXXXXXXX",
|
|
"XXXXXXXX ",
|
|
"XXXXXX ",
|
|
"XXXX ",
|
|
"XX ",
|
|
};
|
|
|
|
static const char *dPix[] = {
|
|
"10 10 2 1",
|
|
" c None",
|
|
"X c #0000CC",
|
|
"XXXXXXXXXX",
|
|
"XXXXXXXXXX",
|
|
" XXXXXXXX ",
|
|
" XXXXXXXX ",
|
|
" XXXXXX ",
|
|
" XXXXXX ",
|
|
" XXXX ",
|
|
" XXXX ",
|
|
" XX ",
|
|
" XX ",
|
|
};
|
|
|
|
/*
|
|
static const char *grPix[] = {
|
|
"16 12 4 1",
|
|
" c None",
|
|
"/ c #CC0000",
|
|
"- c #0000CC",
|
|
"X c #000000",
|
|
"XXXXXXXXXXXXXXXX",
|
|
"X X",
|
|
"X X",
|
|
"X - X",
|
|
"X ---- X",
|
|
"X -- ----- X",
|
|
"X ---- ----X",
|
|
"X----- -X",
|
|
"X-- X",
|
|
"X X",
|
|
"X X",
|
|
"XXXXXXXXXXXXXXXX",
|
|
};
|
|
|
|
static const char *gnPix[] = {
|
|
"16 12 4 1",
|
|
" c None",
|
|
"/ c #CC0000",
|
|
"- c #0000CC",
|
|
"X c #000000",
|
|
"X//XXXXXXXXXX//X",
|
|
"X // // X",
|
|
"X // // X",
|
|
"X // - // X",
|
|
"X //--// X",
|
|
"X ////---- X",
|
|
"X ----// ----X",
|
|
"X-----//// -X",
|
|
"X-- // // X",
|
|
"X // // X",
|
|
"X // // X",
|
|
"XX//XXXXXXXX//XX",
|
|
};
|
|
*/
|
|
|
|
static int lineEditFrameWidth = 0;
|
|
|
|
LineInput::LineInput(QWidget *parent, QString &labelTxt, const char *var) : QHBox(parent, var), value("") {
|
|
QBoxLayout *l = dynamic_cast<QBoxLayout *>(layout());
|
|
|
|
l->setAutoAdd(false);
|
|
|
|
label = new QLabel(labelTxt, this);
|
|
label->setAlignment(Qt::AlignRight);
|
|
l->addWidget(label);
|
|
|
|
le = new QLineEdit(this, var);
|
|
connect(le, SIGNAL(returnPressed()), this, SLOT(handleReturn()));
|
|
connect(le, SIGNAL(lostFocus()), this, SLOT(focusLost()));
|
|
QFont monospace("Courier");
|
|
monospace.setStyleHint(QFont::TypeWriter);
|
|
le->setFont(monospace);
|
|
l->addWidget(le);
|
|
|
|
l->setSpacing(6);
|
|
}
|
|
|
|
void LineInput::setLength(int l) {
|
|
QFontMetrics fm = le->fontMetrics();
|
|
if (l==0) {
|
|
l = 9;
|
|
}
|
|
if (l <= 9) {
|
|
le->setAlignment(Qt::AlignRight);
|
|
} else {
|
|
le->setAlignment(Qt::AlignLeft);
|
|
}
|
|
lineEditFrameWidth = le->frameWidth();
|
|
le->setFixedWidth(fm.width("0") * l + 2 * lineEditFrameWidth + 4);
|
|
}
|
|
|
|
int LineInput::stdWidth() {
|
|
QBoxLayout *l = dynamic_cast<QBoxLayout *>(layout());
|
|
setLength(0);
|
|
l->activate();
|
|
return label->width() + l->spacing() + 2 * l->margin() + le->width();
|
|
}
|
|
|
|
void LineInput::handleReturn() {
|
|
QString c(name());
|
|
if (le->text().isEmpty()) {
|
|
c.append(" \"\"");
|
|
} else {
|
|
c.append(" ");
|
|
c.append(le->text());
|
|
}
|
|
sendCmd(c.latin1());
|
|
value = le->text();
|
|
changed();
|
|
}
|
|
|
|
void LineInput::focusLost() {
|
|
if (value.compare(le->text()) != 0) {
|
|
handleReturn();
|
|
}
|
|
}
|
|
|
|
void LineInput::setValue(const QString &value) {
|
|
if ((this->value.compare(le->text()) == 0) && this->value.compare(value) != 0) {
|
|
le->setText(value);
|
|
this->value = value;
|
|
}
|
|
}
|
|
|
|
void LineInput::setEraseColor(const QColor & color) {
|
|
QHBox::setEraseColor(color);
|
|
label->setEraseColor(color);
|
|
label->setEraseColor(color);
|
|
}
|
|
|
|
RdOnly::RdOnly(QWidget *parent, QString &labelTxt, QString &val, const char *var) : QHBox(parent, var) {
|
|
QBoxLayout *l = dynamic_cast<QBoxLayout *>(layout());
|
|
|
|
l->setAutoAdd(false);
|
|
label = new QLabel(labelTxt, this);
|
|
value = new QLabel(val, this);
|
|
QFont monospace("Courier");
|
|
monospace.setStyleHint(QFont::TypeWriter);
|
|
value->setFont(monospace);
|
|
label->setAlignment(Qt::AlignRight);
|
|
value->setAlignment(Qt::AlignRight);
|
|
l->addWidget(label);
|
|
l->addWidget(value);
|
|
l->setSpacing(6);
|
|
len = 9;
|
|
}
|
|
|
|
void RdOnly::setLength(int l) {
|
|
QFontMetrics fm = value->fontMetrics();
|
|
if (l==0) {
|
|
l = 9;
|
|
}
|
|
len = l;
|
|
if (l <= 9) {
|
|
value->setAlignment(Qt::AlignRight);
|
|
} else {
|
|
value->setAlignment(Qt::AlignLeft);
|
|
}
|
|
value->setFixedWidth(fm.width("0") * l + 2 * lineEditFrameWidth + 4);
|
|
}
|
|
|
|
void RdOnly::setValue(const QString &val) {
|
|
bool ok;
|
|
double f;
|
|
int p, i;
|
|
QString v, ve;
|
|
|
|
if (val.length() <= len) {
|
|
// length is ok
|
|
value->setText(val);
|
|
return;
|
|
}
|
|
f = val.stripWhiteSpace().toDouble(&ok);
|
|
if (!ok) {
|
|
// it's not a number
|
|
value->setText(val);
|
|
return;
|
|
}
|
|
// try to reduce the length by reducing the precision
|
|
for (p = 6; p > 0; p--) {
|
|
v.setNum(f, 'g', p);
|
|
i = v.find('e');
|
|
if (i >= 0) {
|
|
i++;
|
|
if (v[i] == '-') {
|
|
i++;
|
|
} else if (v[i] == '+') {
|
|
// skip + in exponent
|
|
v.remove(i,1);
|
|
}
|
|
if (v[i] == '0') {
|
|
// skip leading 0 in exponent
|
|
v.remove(i,1);
|
|
}
|
|
}
|
|
if (v.length() <= len) {
|
|
value->setText(v);
|
|
return;
|
|
}
|
|
}
|
|
value->setText(v);
|
|
}
|
|
|
|
CheckBox::CheckBox(const QString &label, QWidget *parent, const char *var)
|
|
: QCheckBox(label, parent, var) {
|
|
connect(this, SIGNAL(clicked()), this, SLOT(handleReturn()));
|
|
}
|
|
|
|
void CheckBox::handleReturn() {
|
|
QString c(name());
|
|
if (isOn()) {
|
|
c.append(" 1");
|
|
} else {
|
|
c.append(" 0");
|
|
}
|
|
sendCmd(c.latin1());
|
|
changed();
|
|
}
|
|
|
|
void CheckBox::setValue(const QString &value) {
|
|
if (value[0] == '0' || value[0] <= ' ') {
|
|
if (isOn()) {
|
|
setChecked(false);
|
|
}
|
|
} else {
|
|
if (!isOn()) {
|
|
setChecked(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
ClickButton::ClickButton(QWidget *parent, const char *var)
|
|
: QPushButton(parent, var) {
|
|
dx = 0;
|
|
}
|
|
|
|
void ClickButton::handleReturn() {
|
|
setFocus();
|
|
sendCmd(name());
|
|
changed();
|
|
}
|
|
|
|
void ClickButton::setLabel(const QString &label) {
|
|
QFontMetrics fm = fontMetrics();
|
|
if (dx == 0) {
|
|
setText("BUTTON");
|
|
dx = (width() - fm.width("BUTTON")) / 3;
|
|
}
|
|
setText(label);
|
|
setMaximumWidth(fm.width(text()) + dx);
|
|
}
|
|
|
|
RadioButton::RadioButton(const QString &label, QWidget *parent,
|
|
const QString &cmdArg, const char *value) : QRadioButton(label, parent, value)
|
|
{
|
|
cmd = cmdArg;
|
|
connect(this, SIGNAL(clicked()), this , SLOT(handleClick()));
|
|
}
|
|
|
|
void RadioButton::handleClick() {
|
|
QString c(cmd);
|
|
c.append(" ");
|
|
c.append(name());
|
|
sendCmd(c.latin1());
|
|
clearOthers(name());
|
|
changed();
|
|
setFocus();
|
|
}
|
|
|
|
void RadioButton::setValue(const QString &value) {
|
|
setChecked(value.compare(name()) == 0);
|
|
}
|
|
|
|
void ColorMenu::init() {
|
|
const QPixmap *pixmap;
|
|
int i;
|
|
|
|
setEditable(true);
|
|
listBox()->setRowMode(QListBox::FitToHeight);
|
|
insertItem(QString("auto"), 0);
|
|
for (i=1; i < 16; i++) {
|
|
pixmap = thisPixmap(i);
|
|
if (pixmap == NULL) {
|
|
i = -1;
|
|
break;
|
|
}
|
|
insertItem(*pixmap, i);
|
|
}
|
|
connect(this, SIGNAL(activated(int)),
|
|
this, SLOT(handleAct(int)));
|
|
}
|
|
|
|
ColorMenu::ColorMenu(QString &color, QWidget *parent)
|
|
: QComboBox(parent, "settings")
|
|
{
|
|
init();
|
|
setCurrentItem(0);
|
|
setCurrentText(color);
|
|
}
|
|
|
|
ColorMenu::ColorMenu(QWidget *parent, const char *var)
|
|
: QComboBox(parent, var)
|
|
{
|
|
init();
|
|
nochange = true;
|
|
setCurrentItem(0);
|
|
setCurrentText("");
|
|
nochange = false;
|
|
setLength(0);
|
|
value = "";
|
|
connect(this, SIGNAL(textChanged(const QString &)),
|
|
this, SLOT(handleChange(const QString &)));
|
|
}
|
|
|
|
void ColorMenu::handleAct(int index) {
|
|
QString text;
|
|
|
|
// printf("*** handleAct %d\n", index);
|
|
if (index > 0 && index < 16) {
|
|
Convert2ColorName(index, text);
|
|
nochange = true;
|
|
setCurrentItem(0);
|
|
nochange = false;
|
|
value = text;
|
|
setCurrentText(text);
|
|
}
|
|
// printf("*** handleAct end\n");
|
|
}
|
|
|
|
void ColorMenu::setValue(const QString &text) {
|
|
if (value.compare(currentText()) == 0 && value.compare(text) != 0) {
|
|
// printf("*** setValue %s -> %s\n", value.latin1(), text.latin1());
|
|
nochange = true;
|
|
setCurrentItem(0);
|
|
value = text;
|
|
setCurrentText(text);
|
|
nochange = false;
|
|
}
|
|
}
|
|
|
|
void ColorMenu::handleChange(const QString &text) {
|
|
QString c(name());
|
|
int index;
|
|
|
|
// printf("*** nochange %d empty %d\n", nochange, (text == ""));
|
|
if (nochange || text == "") return;
|
|
index = Convert2ColorIndex(text);
|
|
if (index < -1) return; // not a valid text
|
|
value = text;
|
|
// printf("*** handleChange %s\n", text.latin1());
|
|
c.append(" ");
|
|
c.append(text);
|
|
sendCmd(c.latin1());
|
|
changed();
|
|
}
|
|
|
|
int ColorMenu::getColorIndex() {
|
|
int index = Convert2ColorIndex(currentText());
|
|
if (index < -1) {
|
|
index = -1;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
void ColorMenu::setLength(int min, int max) {
|
|
QFontMetrics fm = fontMetrics();
|
|
if (min == 0) {
|
|
min = 10;
|
|
}
|
|
if (max < min) {
|
|
max = min;
|
|
}
|
|
setMinimumWidth(fm.width("0") * min + 8);
|
|
setMaximumWidth(fm.width("0") * max + 8);
|
|
}
|
|
|
|
Menu::Menu(const QString &label, QWidget *parent, const char *var)
|
|
: QComboBox(parent, var)
|
|
{
|
|
connect(this, SIGNAL(activated(const QString &)),
|
|
this, SLOT(handleAct(const QString &)));
|
|
}
|
|
|
|
void Menu::handleAct(const QString &value) {
|
|
QString c(name());
|
|
|
|
c.append(" ");
|
|
c.append(value);
|
|
sendCmd(c.latin1());
|
|
changed();
|
|
}
|
|
|
|
void Menu::setValue(const QString &value) {
|
|
setCurrentText(value);
|
|
}
|
|
|
|
/*
|
|
GraphButton::GraphButton(QWidget *parent, const char *name)
|
|
: QPushButton(parent, name)
|
|
{
|
|
setFlat(true);
|
|
setPixmap(QPixmap(grPix));
|
|
connect(this, SIGNAL(clicked()), this, SLOT(handleClick()));
|
|
setFixedSize(24,20);
|
|
hide();
|
|
}
|
|
|
|
void GraphButton::handleClick() {
|
|
selectItem(name());
|
|
changed();
|
|
}
|
|
*/
|
|
|
|
bool PathStartsWith(QString &path, const char *name) {
|
|
if (path.startsWith(name)) {
|
|
int l = strlen(name);
|
|
// if (path.length(name) == l || path[l] == '/') return true;
|
|
if (path[l] == 0 || path[l] == '/') return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Group::init() {
|
|
indent = 0;
|
|
isSelectMenu = false;
|
|
colDiv = 1;
|
|
}
|
|
|
|
Group::Group(Device *p, const char *name, bool selectMenu)
|
|
: QVBox(p->viewport(), name)
|
|
, items(101,false)
|
|
{
|
|
//title = new QLabel("Title", this);
|
|
//boxLayout->addWidget(title);
|
|
parentGroup = 0;
|
|
device = p;
|
|
init();
|
|
arrow = 0;
|
|
shown=true;
|
|
title = 0;
|
|
isSelectMenu = selectMenu;
|
|
autoclose = false;
|
|
}
|
|
|
|
Group::Group(Group *p, const QString &tit, const char *name)
|
|
: QVBox(p->device->viewport(), name)
|
|
, items(101,false)
|
|
{
|
|
QFont bold;
|
|
QBoxLayout *lay;
|
|
|
|
parentGroup = p;
|
|
device = p->device;
|
|
init();
|
|
isSelectMenu = p->isSelectMenu;
|
|
if (tit.isEmpty()) {
|
|
arrow = 0;
|
|
shown = true;
|
|
} else {
|
|
title = new QLabel(tit, this);
|
|
lay = dynamic_cast<QBoxLayout *>(layout());
|
|
lay->setAutoAdd(false);
|
|
lay->add(title);
|
|
lay->addStretch(1);
|
|
setFrameStyle(QFrame::MenuBarPanel);
|
|
|
|
indent = p->indent + 20;
|
|
arrow = new QPushButton(this, "arrow");
|
|
arrow->setFlat(true);
|
|
SetEraseColor(arrow, topLevelWidget(), true);
|
|
arrow->setPixmap(QPixmap(rPix));
|
|
arrow->setFixedSize(16, 16);
|
|
bold = font();
|
|
bold.setWeight(75);
|
|
setFont(bold);
|
|
connect(arrow, SIGNAL(clicked()), this, SLOT(toggle()));
|
|
shown=false;
|
|
}
|
|
}
|
|
|
|
void Group::showIt(bool yes) {
|
|
shown = yes;
|
|
if (arrow) { // && arrow->isShown()) {
|
|
if (shown) {
|
|
arrow->setPixmap(QPixmap(dPix));
|
|
} else {
|
|
arrow->setPixmap(QPixmap(rPix));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Group::newline() {
|
|
device->x = indent;
|
|
device->y = device->nextY;
|
|
}
|
|
|
|
void Group::add(Item *item, QWidget *w) {
|
|
int frac, offs, hei, wid;
|
|
QFont font;
|
|
|
|
if (w == 0) w = item->w;
|
|
if (wStyle != item->wStyle) {
|
|
switch (item->wStyle) {
|
|
case 0:
|
|
item->normalFont = w->font();
|
|
case 'W': // remove warning style
|
|
case 'A': // remove warning style
|
|
// case 'G': // remove graph settings style
|
|
w->setEraseColor(eraseColor());
|
|
break;
|
|
case 'H': // remove header style
|
|
w->setFont(item->normalFont);
|
|
}
|
|
switch (wStyle) {
|
|
case 'W': // warning: yellow background
|
|
w->setEraseColor(QColor(255,255,0));
|
|
break;
|
|
case 'A': // warning: orange background
|
|
w->setEraseColor(QColor(255,127,0));
|
|
break;
|
|
// case 'G': // graph settings: grey background
|
|
// w->setEraseColor(QColor(150,150,150));
|
|
// break;
|
|
case 'H': // header style
|
|
font = item->normalFont;
|
|
font.setWeight(QFont::Normal);
|
|
if (font.pointSize() > 0) {
|
|
font.setPointSize(font.pointSize() * 6 / 4);
|
|
} else {
|
|
font.setPixelSize(font.pixelSize() * 6 / 4);
|
|
}
|
|
w->setFont(font);
|
|
}
|
|
item->wStyle = wStyle;
|
|
}
|
|
wStyle = 0;
|
|
//printf("%s: add %s/%s %d\n", name(), w->className(), w->name(), sameRow);
|
|
if (!sameRow) {
|
|
frac = (device->x - indent) % (device->columnWidth / colDiv);
|
|
device->x -= frac;
|
|
if (frac > device->xspace / 2) {
|
|
device->x += device->columnWidth / colDiv;
|
|
}
|
|
}
|
|
if (item->w->layout()) {
|
|
item->w->layout()->activate();
|
|
}
|
|
w->resize(w->sizeHint());
|
|
wid = w->width();
|
|
hei = w->height();
|
|
if (device->x + wid > device->visibleWidth()) {
|
|
newline();
|
|
}
|
|
device->x += device->xspace;
|
|
if (hei >= device->lineHeight) {
|
|
offs = 0;
|
|
device->nextY = QMAX(device->nextY, device->y + hei + device->yspace);
|
|
} else {
|
|
offs = (device->lineHeight - hei) / 2;
|
|
device->nextY = QMAX(device->nextY, device->y + device->lineHeight + device->yspace);
|
|
}
|
|
device->addChild(item->w, device->x, device->y + offs);
|
|
device->x += wid;
|
|
device->maxWid = QMAX(device->maxWid, device->x);
|
|
item->w->show();
|
|
item->used = true;
|
|
sameRow = false;
|
|
tight = false;
|
|
if (!tip.isEmpty()) {
|
|
QToolTip::add(item->w, tip);
|
|
tip="";
|
|
}
|
|
}
|
|
|
|
void Group::initItem(Item *item, QWidget *w, const char *line, bool activate) {
|
|
if (activate) {
|
|
connect(w, SIGNAL(sendCmd(const char *)), device->com, SLOT(sendCmd(const char *)));
|
|
connect(w, SIGNAL(changed()), device, SLOT(update()));
|
|
}
|
|
if (item->w) delete item->w;
|
|
item->w = w;
|
|
items.replace(line, item);
|
|
}
|
|
|
|
void Group::toggle() {
|
|
if (shown) {
|
|
if (autoclose) {
|
|
autocloseAll(); // close containing groups
|
|
} else {
|
|
}
|
|
autoclose = false;
|
|
}
|
|
showIt(!shown);
|
|
device->update(false);
|
|
}
|
|
|
|
Item *Group::findItem(const char *name) {
|
|
Item *item;
|
|
item = items.find(name);
|
|
if (!item) {
|
|
item = new Item();
|
|
item->grp = this;
|
|
}
|
|
return item;
|
|
}
|
|
|
|
void Group::hideContents() {
|
|
Item *item;
|
|
Group *g;
|
|
|
|
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
|
|
if (item->used) {
|
|
g = dynamic_cast<Group *>(item->w);
|
|
if (g) {
|
|
if (g->shown) {
|
|
g->hideContents();
|
|
}
|
|
g->arrow->hide();
|
|
}
|
|
item->w->hide();
|
|
/*
|
|
if (item->graphButton) {
|
|
item->graphButton->hide();
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
void Group::updateLayout(QStringList::Iterator &sit) {
|
|
QString lineQ;
|
|
int lwid=0;
|
|
LineInput *lineInp;
|
|
CheckBox *cb;
|
|
QLabel *label;
|
|
RdOnly *rdonly;
|
|
Menu *menu=0;
|
|
ColorMenu *colorMenu=0;
|
|
ClickButton *pb;
|
|
QString tit("");
|
|
QPtrStack<Group> stack;
|
|
Group *grp;
|
|
QString value;
|
|
const char *line;
|
|
Item *item;
|
|
Item *rightItem = 0;
|
|
int labelNum=0;
|
|
char labelCode[8];
|
|
const char *arg;
|
|
RadioButton *rb;
|
|
QString radioName("");
|
|
QString radioLine("");
|
|
int i;
|
|
int menuItem;
|
|
int yline;
|
|
bool autocloseOnRadio = false;
|
|
// obsolete graph: char groupName[256];
|
|
|
|
device->x = indent;
|
|
tip="";
|
|
sameRow = false;
|
|
tight = false;
|
|
wStyle = 0;
|
|
|
|
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
|
|
item->used = false;
|
|
}
|
|
for (; sit != device->code.end(); ++sit) {
|
|
lineQ = (*sit);
|
|
line = lineQ.latin1();
|
|
if (line[0] != '-') {
|
|
if (line[0]) {
|
|
if (printit()) printf("%s\n", line);
|
|
}
|
|
continue;
|
|
}
|
|
arg = line+2;
|
|
//printf("L %s\n", line);
|
|
switch (line[1]) {
|
|
case '-': // no line break for next item
|
|
tight = true;
|
|
if (line[2] != '-') {
|
|
sameRow = true;
|
|
}
|
|
break;
|
|
case 'P': // line break
|
|
newline();
|
|
break;
|
|
case 'W': // custom width
|
|
lwid = atoi(arg);
|
|
break;
|
|
case 'T': // group title
|
|
tit = arg;
|
|
break;
|
|
case 'H': // help (tool tip)
|
|
if (!tip.isEmpty()) {
|
|
tip.append("\n");
|
|
}
|
|
tip.append(arg);
|
|
break;
|
|
case '>': // add last item to group title line (experimental)
|
|
rightItem = item;
|
|
break;
|
|
/*
|
|
case 's': // auto open (for stick group), will be obsolete
|
|
if (device->openGroups == "") {
|
|
device->openGroups = "sticks";
|
|
device->update();
|
|
}
|
|
break;
|
|
*/
|
|
case 'G': // group
|
|
item = findItem(line);
|
|
grp = dynamic_cast<Group *>(item->w);
|
|
if (grp == 0) {
|
|
grp = new Group(this, tit, arg);
|
|
initItem(item, grp, line);
|
|
} else {
|
|
grp->title->setText(tit);
|
|
}
|
|
if (device->openGroup != "" && PathStartsWith(device->openGroup, arg)) {
|
|
grp->autoclose = false;
|
|
if (device->openGroup == arg) {
|
|
device->openGroup = ""; // opening finished
|
|
}
|
|
if (!grp->shown) grp->showIt(true);
|
|
device->update(false);
|
|
}
|
|
|
|
if (arg[0] != '-' || grp->shown) {
|
|
newline();
|
|
sameRow = true;
|
|
device->x += 14;
|
|
add(item, grp->title);
|
|
if (shown && grp->arrow) {
|
|
yline = device->y + 2;
|
|
device->addChild(grp->arrow, indent + 2, yline);
|
|
grp->arrow->show();
|
|
}
|
|
/*
|
|
if (device->doJump && !grp->shown) {
|
|
// open automatically group tree in visibleGr (clicked on graph icon)
|
|
snprintf(groupName, sizeof groupName, " %s ", grp->name());
|
|
if (device->visibleGr.find(groupName) >= 0) {
|
|
grp->showIt(true);
|
|
grp->closeLater = true;
|
|
//printf("open %s\n", groupName);
|
|
}
|
|
}
|
|
*/
|
|
|
|
if (rightItem) {
|
|
// device->addChild(rightItem->w, device->x + device->xspace, device->y);
|
|
rightItem = 0;
|
|
} else {
|
|
newline();
|
|
}
|
|
}
|
|
tit="";
|
|
++sit;
|
|
grp->updateLayout(sit);
|
|
newline();
|
|
if (grp->shown) {
|
|
grp->setLineWidth(1);
|
|
grp->setFrameStyle(QFrame::Box | QFrame::Sunken);
|
|
grp->setFixedSize(device->width(), device->y - yline);
|
|
device->y += 4;
|
|
device->nextY += 4;
|
|
} else {
|
|
grp->setFrameStyle(QFrame::MenuBarPanel);
|
|
grp->setFixedSize(device->width(), grp->title->height());
|
|
}
|
|
grp->update();
|
|
if (sit == device->code.end()) --sit;
|
|
break;
|
|
case 'V': // value for next item
|
|
value = arg;
|
|
break;
|
|
case 'i': // readonly
|
|
item = findItem(line);
|
|
rdonly = dynamic_cast<RdOnly *>(item->w);
|
|
if (rdonly == 0) {
|
|
rdonly = new RdOnly(device->viewport(), tit, value, arg);
|
|
initItem(item, rdonly, line);
|
|
} else {
|
|
rdonly->label->setText(tit);
|
|
}
|
|
if (tight) {
|
|
rdonly->label->setMinimumWidth(0);
|
|
rdonly->value->setMinimumWidth(0);
|
|
} else {
|
|
rdonly->label->setMinimumWidth(device->labelWidth);
|
|
rdonly->value->setMinimumWidth(device->leWidth);
|
|
}
|
|
add(item);
|
|
lwid = 0;
|
|
rdonly->setValue(value);
|
|
value="";
|
|
break;
|
|
case 'I': // text input
|
|
item = findItem(line);
|
|
lineInp = dynamic_cast<LineInput *>(item->w);
|
|
if (lineInp == 0) {
|
|
lineInp = new LineInput(device->viewport(), tit, arg);
|
|
initItem(item, lineInp, line, true);
|
|
} else {
|
|
lineInp->label->setText(tit);
|
|
}
|
|
lineInp->setLength(lwid);
|
|
if (tight) {
|
|
lineInp->label->setMinimumWidth(0);
|
|
} else {
|
|
lineInp->label->setMinimumWidth(device->labelWidth);
|
|
}
|
|
add(item);
|
|
lwid = 0;
|
|
lineInp->setValue(value);
|
|
value="";
|
|
break;
|
|
case 'S': // set style
|
|
wStyle = arg[0];
|
|
break;
|
|
case 'D': // divide column (typically -D2: double number of columns)
|
|
colDiv = atoi(arg);
|
|
break;
|
|
case 'L': // label
|
|
snprintf(labelCode, sizeof labelCode, "%d", labelNum);
|
|
labelNum++;
|
|
item = findItem(labelCode);
|
|
label = dynamic_cast<QLabel *>(item->w);
|
|
if (label == 0) {
|
|
label = new QLabel(arg, device->viewport());
|
|
initItem(item, label, labelCode);
|
|
} else {
|
|
label->setText(arg);
|
|
}
|
|
add(item);
|
|
break;
|
|
case 'M': // menu (experimental ?)
|
|
if (arg[0] == 0) { // end of menu
|
|
if (menu) {
|
|
for (i=menu->count(); i<menuItem; i++) {
|
|
menu->removeItem(i);
|
|
}
|
|
}
|
|
menu=0;
|
|
value = "";
|
|
break;
|
|
}
|
|
item = findItem(line);
|
|
menu = dynamic_cast<Menu *>(item->w);
|
|
if (menu == 0) {
|
|
menu = new Menu(tit, device->viewport(), arg);
|
|
initItem(item, menu, line, true);
|
|
}
|
|
menuItem = 0;
|
|
add(item);
|
|
break;
|
|
case 'm': // menu item
|
|
if (menu) {
|
|
if (menuItem < menu->count()) {
|
|
if (menu->text(menuItem).compare(value) != 0) {
|
|
menu->changeItem(arg, menuItem);
|
|
}
|
|
} else {
|
|
menu->insertItem(arg, menuItem);
|
|
}
|
|
menuItem++;
|
|
}
|
|
break;
|
|
case 'c': // pen style menu
|
|
item = findItem(line);
|
|
colorMenu = dynamic_cast<ColorMenu *>(item->w);
|
|
if (colorMenu == 0) {
|
|
colorMenu = new ColorMenu(device->viewport(), arg);
|
|
initItem(item, colorMenu, line, true);
|
|
}
|
|
colorMenu->setValue(value);
|
|
colorMenu->setLength(lwid);
|
|
add(item);
|
|
case 'a': // autoclose on radio button (experimental?)
|
|
//device->closeGroup = this;
|
|
autocloseOnRadio = true;
|
|
//closeLater = true;
|
|
break;
|
|
case 'R': // radio button group
|
|
radioName = arg;
|
|
device->selectCmd = radioName;
|
|
device->selectCmd.append(" ");
|
|
device->selectCmd.append(value);
|
|
break;
|
|
case 'r': // radio button
|
|
if (radioName.isEmpty()) break;
|
|
radioLine = radioName + line;
|
|
line = radioLine.latin1();
|
|
item = findItem(line);
|
|
if (tit == "") {
|
|
tit = arg;
|
|
}
|
|
rb = dynamic_cast<RadioButton *>(item->w);
|
|
if (rb == 0) {
|
|
rb = new RadioButton(tit, device->viewport(), radioName, arg);
|
|
if (isSelectMenu) {
|
|
initItem(item, rb, line, false);
|
|
connect(rb, SIGNAL(sendCmd(const char *)), device, SLOT(setSelectCmd(const char *)));
|
|
connect(rb, SIGNAL(clearOthers(const QString &)), this, SIGNAL(clearRadioButtons(const QString &)));
|
|
connect(this, SIGNAL(clearRadioButtons(const QString &)), rb, SLOT(setValue(const QString &)));
|
|
} else {
|
|
initItem(item, rb, line, true);
|
|
// if (device->closeGroup) {
|
|
// connect(rb, SIGNAL(clicked()), device->closeGroup, SLOT(toggle()));
|
|
// }
|
|
if (autocloseOnRadio) {
|
|
connect(rb, SIGNAL(clicked()), device, SLOT(closeMarkedGroups()));
|
|
}
|
|
}
|
|
} else {
|
|
rb->setText(tit);
|
|
}
|
|
if (sameRow) {
|
|
rb->setMinimumWidth(0);
|
|
} else {
|
|
rb->setMinimumWidth(device->labelWidth / 2);
|
|
}
|
|
add(item);
|
|
rb->setChecked(value.compare(arg) == 0);
|
|
tit="";
|
|
break;
|
|
case 'B': // push button
|
|
item = findItem(line);
|
|
pb = dynamic_cast<ClickButton *>(item->w);
|
|
if (pb == 0) {
|
|
pb = new ClickButton(device->viewport(), arg);
|
|
pb->setLabel(tit);
|
|
switch (arg[0]) {
|
|
case 'C':
|
|
initItem(item, pb, line, false);
|
|
connect(pb, SIGNAL(clicked()), device, SLOT(switchLayout()));
|
|
break;
|
|
case 'D':
|
|
initItem(item, pb, line, false);
|
|
connect(pb, SIGNAL(clicked()), device, SLOT(selectIt()));
|
|
pb->setDefault(true);
|
|
break;
|
|
case 'S':
|
|
initItem(item, pb, line, false);
|
|
connect(pb, SIGNAL(sendCmd(const char *)), device, SLOT(openGrps(const char *)));
|
|
connect(pb, SIGNAL(changed()), device, SLOT(update()));
|
|
connect(pb, SIGNAL(clicked()), pb, SLOT(handleReturn()));
|
|
break;
|
|
default:
|
|
initItem(item, pb, line, true);
|
|
connect(pb, SIGNAL(clicked()), pb, SLOT(handleReturn()));
|
|
break;
|
|
}
|
|
}
|
|
add(item);
|
|
pb->setLabel(tit);
|
|
tit="";
|
|
break;
|
|
case 'C': // check box
|
|
item = findItem(line);
|
|
cb = dynamic_cast<CheckBox *>(item->w);
|
|
if (cb == 0) {
|
|
cb = new CheckBox(tit, device->viewport(), arg);
|
|
initItem(item, cb, line, true);
|
|
if (autocloseOnRadio) {
|
|
connect(cb, SIGNAL(clicked()), device, SLOT(closeMarkedGroups()));
|
|
}
|
|
} else {
|
|
cb->setText(tit);
|
|
}
|
|
add(item);
|
|
cb->setValue(value);
|
|
value="";
|
|
tit="";
|
|
break;
|
|
/*
|
|
case 'X': // make graphic button
|
|
if (item) {
|
|
if (item->graphButton == 0) {
|
|
item->graphButton = new GraphButton(this, arg);
|
|
connect(item->graphButton, SIGNAL(selectItem(const char *)),
|
|
device, SLOT(selectGraphItem(const char *)));
|
|
}
|
|
if (device->graphOn) {
|
|
device->addChild(item->graphButton, device->x, device->y);
|
|
device->x += device->graphButtonWidth;
|
|
item->graphButton->show();
|
|
arg = strrchr(arg, ' ');
|
|
if (arg) {
|
|
tip = "go to graph settings for this item (";
|
|
tip.append(arg + 3);
|
|
tip.append(")");
|
|
QToolTip::add(item->graphButton, tip);
|
|
tip = "";
|
|
}
|
|
} else {
|
|
item->graphButton->hide();
|
|
}
|
|
}
|
|
break;
|
|
*/
|
|
case 'g': // graph descriptor
|
|
if (device->graphDesc == "") {
|
|
device->graphDesc = arg;
|
|
} else if (device->graphDesc != arg) {
|
|
device->graphDesc = arg;
|
|
device->rebuildTime = DoubleTime() + 1;
|
|
// printf("*** desc changed\n");
|
|
// a graph rebuild will become necessary
|
|
} else if (device->rebuildTime != 0
|
|
&& DoubleTime() > device->rebuildTime) {
|
|
// but we do not rebuild before the descriptor was two times the
|
|
// same in succession and at least 1 second has passed
|
|
device->rebuildTime = 0;
|
|
device->updateInterval = 0.5;
|
|
// printf("*** rebuild\n");
|
|
QTimer::singleShot(1, device, SLOT(rebuild()));
|
|
}
|
|
break;
|
|
/*
|
|
case 'J': // jump to me
|
|
if (device->doJump) {
|
|
device->doJump = false;
|
|
device->yJump = device->y;
|
|
}
|
|
break;
|
|
*/
|
|
case 'E': // end of nested group
|
|
goto END;
|
|
default:
|
|
if (printit()) printf("%s\n", line);
|
|
}
|
|
}
|
|
END:
|
|
// if (device->closeGroup == this) {
|
|
// device->closeGroup = 0;
|
|
// }
|
|
/* graph obsolete
|
|
if (device->closeGr && shown && closeLater) {
|
|
// check if group is to be closed
|
|
snprintf(groupName, sizeof groupName, " %s ", name());
|
|
if (device->visibleGr.find(groupName) < 0) {
|
|
closeLater = false;
|
|
showIt(false);
|
|
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
|
|
item->used = false;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
|
|
if (!item->used) {
|
|
grp = dynamic_cast<Group *>(item->w);
|
|
if (grp) {
|
|
grp->hideContents();
|
|
grp->arrow->hide();
|
|
}
|
|
item->w->hide();
|
|
/*
|
|
if (item->graphButton) {
|
|
item->graphButton->hide();
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
|
|
void Group::appendTo(QString &c) {
|
|
Group *g;
|
|
Item *item;
|
|
|
|
c.append(" ");
|
|
c.append(name());
|
|
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
|
|
g = dynamic_cast<Group *>(item->w);
|
|
if (g) {
|
|
if (g->shown) {
|
|
g->appendTo(c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Group::autocloseAll() {
|
|
Group *g;
|
|
Item *item;
|
|
|
|
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
|
|
g = dynamic_cast<Group *>(item->w);
|
|
if (g) {
|
|
g->autocloseAll();
|
|
if (g->shown && g->autoclose) {
|
|
printf("autoclose %s\n", g->name());
|
|
g->toggle();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Group::openGroup(QString &path) {
|
|
Group *g;
|
|
Item *item;
|
|
|
|
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
|
|
g = dynamic_cast<Group *>(item->w);
|
|
if (g && PathStartsWith(path, g->name())) {
|
|
if (!g->shown) {
|
|
g->toggle();
|
|
// g->autoclose = true;
|
|
}
|
|
if (path == g->name()) {
|
|
return g->shown;
|
|
}
|
|
return g->openGroup(path);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Group* Group::findGroup(QString &path) {
|
|
Group *g;
|
|
Item *item;
|
|
|
|
for (QDictIterator<Item> it(items); (item = it.current()); ++it) {
|
|
g = dynamic_cast<Group *>(item->w);
|
|
if (g) {
|
|
if (PathStartsWith(path, g->name())) {
|
|
if (path == g->name()) return g;
|
|
return g->findGroup(path);
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
Device::Device(QWidget* parent)
|
|
: QScrollView(parent)
|
|
{
|
|
LineInput *lineInp;
|
|
|
|
SetEraseColor(viewport(), topLevelWidget());
|
|
setFrameStyle(0);
|
|
xspace=6;
|
|
yspace=4;
|
|
QString tit("This is a very long label");
|
|
lineInp = new LineInput(this, tit, "test");
|
|
lineInp->setLength(0);
|
|
columnWidth = lineInp->stdWidth() + xspace;
|
|
leWidth = lineInp->le->width();
|
|
labelWidth = lineInp->label->width();
|
|
// graphButtonWidth = 24;
|
|
lineHeight = QMAX(lineInp->le->sizeHint().height(), lineInp->label->sizeHint().height());
|
|
delete lineInp;
|
|
/*
|
|
gButton = new GraphButton(this, "g-0");
|
|
graphOn = false;
|
|
visibleGr = "";
|
|
doJump = false;
|
|
yJump = 0;
|
|
*/
|
|
updateMode = update_idle;
|
|
stopUpdate = false;
|
|
//selectState = select_idle;
|
|
rebuildTime = 0;
|
|
//enableClipper(true);
|
|
}
|
|
|
|
void Device::init(Command *command, SeaSet *initSet) {
|
|
|
|
set = initSet;
|
|
com = command;
|
|
device = new Group(this, "main");
|
|
select = new Group(this, "select", true);
|
|
mainGroup = device;
|
|
addChild(mainGroup, 0, 0);
|
|
y = yspace;
|
|
update(false);
|
|
/*
|
|
QToolTip::add(gButton, "graph settings");
|
|
connect(gButton, SIGNAL(clicked()), this, SLOT(graphToggle()));
|
|
*/
|
|
|
|
updateInterval = 5.0;
|
|
QTimer *timer = new QTimer(this);
|
|
connect(timer, SIGNAL(timeout()), this, SLOT(timedUpdate()));
|
|
timer->start(10);
|
|
}
|
|
|
|
void Device::rebuild() {
|
|
restart(graphDesc);
|
|
}
|
|
|
|
/*
|
|
void Device::graphToggle() {
|
|
if (graphOn) {
|
|
QToolTip::add(gButton, "graph settings");
|
|
columnWidth -= graphButtonWidth;
|
|
graphOn = false;
|
|
gButton->setPixmap(QPixmap(grPix));
|
|
visibleGr = "";
|
|
closeGr = true;
|
|
} else {
|
|
QToolTip::add(gButton, "close graph settings");
|
|
columnWidth += graphButtonWidth;
|
|
graphOn = true;
|
|
gButton->setPixmap(QPixmap(gnPix));
|
|
}
|
|
visibleGr = "";
|
|
update(false);
|
|
}
|
|
*/
|
|
|
|
void Device::switchLayout() {
|
|
mainGroup->hideContents();
|
|
if (mainGroup == select) {
|
|
mainGroup = device;
|
|
} else {
|
|
mainGroup = select;
|
|
}
|
|
update(false);
|
|
}
|
|
|
|
void Device::selectIt() {
|
|
mainGroup->hideContents();
|
|
com->sendCmd(selectCmd.latin1());
|
|
mainGroup = device;
|
|
update(false);
|
|
QTimer::singleShot(100,this,SLOT(update()));
|
|
}
|
|
|
|
void Device::setSelectCmd(const char *cmd) {
|
|
selectCmd = cmd;
|
|
}
|
|
|
|
void Device::resizeEvent(QResizeEvent *e) {
|
|
if (e->size().width() != e->oldSize().width()) {
|
|
if (e->size().width() > 10 || e->oldSize().width() > 10) {
|
|
if (updateInterval > 0) {
|
|
updateInterval = 0;
|
|
QTimer::singleShot(100,this,SLOT(update()));
|
|
}
|
|
}
|
|
}
|
|
QScrollView::resizeEvent(e);
|
|
}
|
|
|
|
/*
|
|
void Device::selectGraphItem(const char *id) {
|
|
//printf("SELECT %s\n", id);
|
|
visibleGr = "";
|
|
if (id) {
|
|
visibleGr = " ";
|
|
visibleGr.append(id);
|
|
closeGr = true;
|
|
doJump = true;
|
|
}
|
|
update(false);
|
|
}
|
|
*/
|
|
|
|
void Device::timedUpdate() {
|
|
double now;
|
|
|
|
if (updateMode == update_start) {
|
|
// printf("*** update start\n");
|
|
updateStart();
|
|
updateMode = update_complete;
|
|
tmot.start();
|
|
}
|
|
if (updateMode == update_complete) {
|
|
if (tmot.elapsed() > 10000) {
|
|
set->sc->reconnect();
|
|
tmot.start();
|
|
printf("timeout -> reconnect\n");
|
|
updateMode = update_idle;
|
|
}
|
|
if (set->sc->handleBuffer(0) <= 0) return;
|
|
// printf("*** update complete\n");
|
|
if (set->sc->getResponse() < 0) {
|
|
set->sc->reconnect();
|
|
printf("timeout -> reconnected\n");
|
|
updateMode = update_idle;
|
|
return;
|
|
}
|
|
updateComplete();
|
|
updateMode = update_idle;
|
|
return;
|
|
}
|
|
if (mainGroup == select && lastUpdate > 0) {
|
|
return;
|
|
}
|
|
now = DoubleTime();
|
|
if (updateInterval == 0) {
|
|
updateInterval = 0.5;
|
|
// printf("*** immediate update\n");
|
|
} else {
|
|
if (now < lastUpdate + updateInterval) {
|
|
return;
|
|
}
|
|
if (updateInterval < 0.99) {
|
|
updateInterval += 0.1;
|
|
} else {
|
|
updateInterval *= 2;
|
|
}
|
|
if (updateInterval >= 10) {
|
|
updateInterval = 10;
|
|
}
|
|
// printf("*** next update in %g sec\n", updateInterval);
|
|
}
|
|
if (isHidden() || height() < 3) {
|
|
lastUpdate = now;
|
|
return;
|
|
}
|
|
updateMode = update_start;
|
|
}
|
|
|
|
void Device::activate() {
|
|
double now;
|
|
|
|
if (mainGroup == select) return;
|
|
now = DoubleTime();
|
|
if (now > lastUpdate) {
|
|
update(false);
|
|
// lastUpdate = now;
|
|
}
|
|
}
|
|
|
|
void Device::closeMarkedGroups() {
|
|
mainGroup->autocloseAll();
|
|
//selectState = select_idle;
|
|
}
|
|
|
|
void Device::openGrps(const char *groups) {
|
|
Group *g;
|
|
bool openit;
|
|
|
|
openGroup = groups + 1; // skip first letter S in button name
|
|
g = mainGroup->findGroup(openGroup);
|
|
openit = !g || !g->shown;
|
|
mainGroup->autocloseAll();
|
|
if (openit) {
|
|
if (!mainGroup->openGroup(openGroup)) {
|
|
update(false);
|
|
return;
|
|
}
|
|
}
|
|
openGroup = "";
|
|
update(false);
|
|
}
|
|
|
|
void Device::update(bool refresh) {
|
|
if (refresh) {
|
|
updateInterval = 0.5;
|
|
stopUpdate = true;
|
|
}
|
|
lastUpdate = 0;
|
|
}
|
|
|
|
void Device::updateStart() {
|
|
QString c("layout");
|
|
|
|
lastUpdate = DoubleTime();
|
|
code.clear();
|
|
mainGroup->appendTo(c);
|
|
/*
|
|
if (graphOn && !visibleGr.isEmpty()) {
|
|
if (doJump) {
|
|
c.append(visibleGr);
|
|
} else {
|
|
int i = visibleGr.findRev(' ');
|
|
if (i >= 0) {
|
|
c.append(visibleGr.mid(i));
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
// printf("*** SEND %s\n", c.latin1());
|
|
set->sc->sendCommand(c.latin1());
|
|
//printf("%s\n", c.latin1());
|
|
}
|
|
|
|
void Device::updateComplete() {
|
|
QString line;
|
|
|
|
while (set->sc->getLine(line) > 0) {
|
|
code.append(line);
|
|
}
|
|
|
|
if (stopUpdate) {
|
|
stopUpdate = false;
|
|
return;
|
|
}
|
|
|
|
QStringList::Iterator it = code.begin();
|
|
y = yspace;
|
|
nextY = yspace;
|
|
maxWid = 0;
|
|
|
|
/* graph obsolete:
|
|
addChild(gButton, this->visibleWidth() - graphButtonWidth, 2);
|
|
gButton->show();
|
|
*/
|
|
// closeGroup = 0;
|
|
mainGroup->updateLayout(it);
|
|
resizeContents(maxWid, y);
|
|
|
|
/*
|
|
if (yJump > 0) {
|
|
ensureVisible(0, yJump);
|
|
yJump = 0;
|
|
}
|
|
*/
|
|
}
|