#include "eenviron.h"
#include "base/locolorselector.h"
#include "globaldefine.h"
#include "tools.h"
#include <QBoxLayout>
#include <QButtonGroup>
#include <QCheckBox>
#include <QFontComboBox>
#include <QLabel>
#include <QLineEdit>
#include <QPainter>
#include <QRadioButton>
#include <QSpinBox>
#include <QTextOption>
#include <QJsonArray>

QJsonObject EEnviron::genProg(const QJsonObject &json, const QString &dstDir, const QString &srcPageDir) {
    auto widget = json["widget"];
    QJsonObject oRes;
    oRes["_type"] = "EnvironmentalMonitoring";
    oRes["name"] = "EnvironmentalMonitoring";
    oRes["id"] = "";
    oRes["timeSpan"] = json["play"]["duration"].toInt();
    oRes["alignType"] = widget["alignType"].toInt();
    oRes["bHumidity"] = widget["bHumidity"].toBool();
    oRes["bNoise"] = widget["bNoise"].toBool();
    oRes["bPM10"] = widget["bPM10"].toBool();
    oRes["bPM25"] = widget["bPM25"].toBool();
    oRes["bTemperature"] = widget["bTemperature"].toBool();
    auto title = widget["labelTitle"].toString();
    oRes["bTitle"] = ! title.isEmpty();
    oRes["bWindDirection"] = widget["bWindDirection"].toBool();
    oRes["bWindSpeed"] = widget["bWindSpeed"].toBool();
    oRes["temperatureCompensation"] = widget["temperatureCompensation"].toInt();
    oRes["temperatureStyle"] = widget["temperatureStyle"].toInt();
    oRes["bgColor"] = widget["cBackground"].toInt();
    oRes["bSingleScroll"] = widget["bPaomadeng"].toBool();
    oRes["iScrollSpeed"] = widget["scrollSpeed"].toInt();

    auto textColor = Tools::int2Color(widget["textColor"].toInt());
    auto font = QFont(widget["fontFamily"].toString(), widget["fontSize"].toInt());
    font.setBold(widget["fontBold"].toBool());
    font.setItalic(widget["fontItalics"].toBool());
    font.setUnderline(widget["fontUnderline"].toBool());

    font.setStyleStrategy(gTextAntialiasing ? QFont::PreferAntialias : QFont::NoAntialias);
    QFontMetricsF metricF(font);
    oRes["spaceWidth"] = metricF.horizontalAdvance(" ");
    QFontMetrics metric(font);
    QColor color(textColor);
    QJsonArray imgs;
    for(auto str : str0_9) Tools::saveImg2(dstDir, metric, font, color, imgs, str, str);
    Tools::saveImg2(dstDir, metric, font, color, imgs, title, "labeltitle");
    Tools::saveImg2(dstDir, metric, font, color, imgs, widget["labelTemperature"].toString(), "labeltemperature");
    Tools::saveImg2(dstDir, metric, font, color, imgs, widget["labelHumidity"].toString(), "labelhumidity");
    Tools::saveImg2(dstDir, metric, font, color, imgs, widget["labelNoise"].toString(), "labelnoise");
    Tools::saveImg2(dstDir, metric, font, color, imgs, widget["labelWindSpeed"].toString(), "labelwindSpeed");
    Tools::saveImg2(dstDir, metric, font, color, imgs, widget["labelWindDirection"].toString(), "labelwindDirection");
    Tools::saveImg2(dstDir, metric, font, color, imgs, widget["labelPM25"].toString(), "labelpm25");
    Tools::saveImg2(dstDir, metric, font, color, imgs, widget["labelPM10"].toString(), "labelpm10");
    Tools::saveImg2(dstDir, metric, font, color, imgs, "℃", "unit_celsius");
    Tools::saveImg2(dstDir, metric, font, color, imgs, "℉", "unit_fahrenheit");
    Tools::saveImg2(dstDir, metric, font, color, imgs, "%", "unit_humidity");
    Tools::saveImg2(dstDir, metric, font, color, imgs, "dB", "unit_noise");
    Tools::saveImg2(dstDir, metric, font, color, imgs, "m/s", "unit_windspeed");
    Tools::saveImg2(dstDir, metric, font, color, imgs, "μg/m³", "unit_pm10");
    Tools::saveImg2(dstDir, metric, font, color, imgs, "μg/m³", "unit_pm25");
    Tools::saveImg2(dstDir, metric, font, color, imgs, "-", "minus_sign");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("north"), "N");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("north")+tr("east")+tr("north"), "NNE");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("east")+tr("north"), "NE");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("east")+tr("east")+tr("north"), "ENE");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("east"), "E");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("east")+tr("east")+tr("south"), "ESE");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("east")+tr("south"), "SE");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("south")+tr("east")+tr("south"), "SSE");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("south"), "S");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("south")+tr("west")+tr("south"), "SSW");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("west")+tr("south"), "SW");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("west")+tr("west")+tr("south"), "WSW");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("west"), "W");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("west")+tr("west")+tr("north"), "WNW");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("west")+tr("north"), "NW");
    Tools::saveImg2(dstDir, metric, font, color, imgs, tr("north")+tr("west")+tr("north"), "NNW");

    QJsonObject arrayPic;
    arrayPic["name"] = "previewTmp";
    QString srcFile = srcPageDir+"/previewTmp.png";
    QFile srcQFile(srcFile);
    if(srcQFile.exists()) {
        QString id = Tools::fileMd5(srcFile);
        srcQFile.copy(dstDir+"/"+id);
        arrayPic["id"] = id;
    }
    imgs.append(arrayPic);
    oRes["iPicCount"] = imgs.size();
    oRes["arrayPics"] = imgs;
    return oRes;
}

EEnviron::EEnviron(EBase *multiWin): EBase(multiWin) {
    mType = EBase::Environ;
    m_attr.labelTemp = tr("Temperature")+":";
    m_attr.labelHum = tr("Humidity")+":";
    m_attr.labelNoise = tr("Noise")+":";
    m_attr.labelWindSpeed = tr("Wind Speed")+":";
    m_attr.labelWindDirectiton = tr("Wind Direction")+":";
    m_attr.labelPm25 = "PM2.5:";
    m_attr.labelPm10 = "PM10:";
    calAttr();
}

EEnviron::EEnviron(const QJsonObject &json, EBase *multiWin): EBase(multiWin){
    mType = EBase::Environ;
    setBaseAttr(json);
    auto widget = json["widget"];
    m_attr.hasTemp = widget["bTemperature"].toBool();
    m_attr.compensation = widget["temperatureCompensation"].toInt();
    m_attr.tempType = widget["temperatureStyle"].toInt();
    m_attr.labelTemp = widget["labelTemperature"].toString();
    m_attr.title = widget["labelTitle"].toString();
    m_attr.hasHum = widget["bHumidity"].toBool();
    m_attr.labelHum = widget["labelHumidity"].toString();
    m_attr.hasNoise = widget["bNoise"].toBool();
    m_attr.labelNoise = widget["labelNoise"].toString();
    m_attr.hasWindSpeed = widget["bWindSpeed"].toBool();
    m_attr.labelWindSpeed = widget["labelWindSpeed"].toString();
    m_attr.hasWindDirection = widget["bWindDirection"].toBool();
    m_attr.labelWindDirectiton = widget["labelWindDirection"].toString();
    m_attr.hasPM25 = widget["bPM25"].toBool();
    m_attr.labelPm25 = widget["labelPM25"].toString();
    m_attr.hasPM10 = widget["bPM10"].toBool();
    m_attr.labelPm10 = widget["labelPM10"].toString();
    m_attr.isSingleLine = widget["bPaomadeng"].toBool();
    m_attr.scrollSpeed = widget["scrollSpeed"].toInt();
    m_attr.backColor = Tools::int2Color(widget["cBackground"].toInt());
    m_attr.align = widget["alignType"].toInt();
    m_attr.font = QFont(widget["fontFamily"].toString(), widget["fontSize"].toInt());
    m_attr.font.setBold(widget["fontBold"].toBool());
    m_attr.font.setItalic(widget["fontItalics"].toBool());
    m_attr.font.setUnderline(widget["fontUnderline"].toBool());
    m_attr.textColor = Tools::int2Color(widget["textColor"].toInt());
    m_attr.playRefresh = json["play"]["refresh"].toInt();
    m_attr.playDuration = json["play"]["duration"].toInt();
    calAttr();
}

void EEnviron::calAttr() {
    item_cnt = 0;
    if(! m_attr.title.isEmpty()) item_cnt++;
    if(m_attr.hasTemp) item_cnt++;
    if(m_attr.hasHum) item_cnt++;
    if(m_attr.hasWindSpeed) item_cnt++;
    if(m_attr.hasWindDirection) item_cnt++;
    if(m_attr.hasNoise) item_cnt++;
    if(m_attr.hasPM25) item_cnt++;
    if(m_attr.hasPM10) item_cnt++;
    m_attr.font.setStyleStrategy(gTextAntialiasing ? QFont::PreferAntialias : QFont::NoAntialias);
    if(m_attr.isSingleLine) {
        scroll_txt = "";
        if(! m_attr.title.isEmpty()) scroll_txt += m_attr.title + " ";
        if(m_attr.hasTemp) scroll_txt += m_attr.labelTemp + QString::number(m_attr.compensation) + (m_attr.tempType==0 ? "℃" : "℉")+" ";
        if(m_attr.hasHum) scroll_txt += m_attr.labelHum + "0% ";
        if(m_attr.hasWindSpeed) scroll_txt += m_attr.labelWindSpeed + "0m/s ";
        if(m_attr.hasWindDirection) scroll_txt += m_attr.labelWindDirectiton + "- ";
        if(m_attr.hasNoise) scroll_txt += m_attr.labelNoise + "0dB ";
        if(m_attr.hasPM25) scroll_txt += m_attr.labelPm25 + "0μg/m³ ";
        if(m_attr.hasPM10) scroll_txt += m_attr.labelPm10 + "0μg/m³ ";
        scroll_width = QFontMetrics(m_attr.font).horizontalAdvance(scroll_txt);
    }
}
void EEnviron::drawText(QPainter *painter, QRectF& rect) {
    QTextOption opt(Qt::AlignLeft | Qt:: AlignVCenter);
    painter->setFont(m_attr.font);
    painter->setPen(m_attr.textColor);
    if(m_attr.isSingleLine) {
        opt.setWrapMode(QTextOption::NoWrap);
        painter->drawText(rect, scroll_txt, opt);
    } else {
        if(m_attr.align==0) opt.setAlignment(Qt::AlignLeft|Qt::AlignVCenter);
        else if(m_attr.align==1) opt.setAlignment(Qt::AlignCenter);
        else if(m_attr.align==2) opt.setAlignment(Qt::AlignRight|Qt::AlignVCenter);
        if(item_cnt > 0) rect.setHeight(rect.height() / item_cnt);
        if(! m_attr.title.isEmpty()) {
            painter->drawText(rect, m_attr.title, opt);
            rect.moveTop(rect.top() + rect.height());
        }
        if(m_attr.hasTemp) {
            painter->drawText(rect, m_attr.labelTemp + QString::number(m_attr.compensation) + (m_attr.tempType == 0 ? "℃" : "℉"), opt);
            rect.moveTop(rect.top() + rect.height());
        }
        if(m_attr.hasHum) {
            painter->drawText(rect, m_attr.labelHum + "0%", opt);
            rect.moveTop(rect.top() + rect.height());
        }
        if(m_attr.hasWindSpeed) {
            painter->drawText(rect, m_attr.labelWindSpeed + "0m/s", opt);
            rect.moveTop(rect.top() + rect.height());
        }
        if(m_attr.hasWindDirection) {
            painter->drawText(rect, m_attr.labelWindDirectiton + "-", opt);
            rect.moveTop(rect.top() + rect.height());
        }
        if(m_attr.hasNoise) {
            painter->drawText(rect, m_attr.labelNoise + "0dB", opt);
            rect.moveTop(rect.top() + rect.height());
        }
        if(m_attr.hasPM25) {
            painter->drawText(rect, m_attr.labelPm25 + "0μg/m³", opt);
            rect.moveTop(rect.top() + rect.height());
        }
        if(m_attr.hasPM10) painter->drawText(rect, m_attr.labelPm10 + "0μg/m³", opt);
    }
}
void EEnviron::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
    if(m_attr.isSingleLine) {
        if(timer_id==0) {
            scroll_off = innerRect().width();
            timer_id = startTimer(m_attr.scrollSpeed, Qt::PreciseTimer);
        }
    } else {
        if(timer_id!=0) {
            killTimer(timer_id);
            timer_id = 0;
        }
    }
    painter->setClipRect(0, 0, mWidth, mHeight);
    painter->fillRect(0, 0, mWidth, mHeight, m_attr.backColor);
    auto inner = innerRect();
    if(m_attr.isSingleLine) {
        inner.moveLeft(scroll_off);
        inner.setWidth(scroll_width);
    }
    drawText(painter, inner);
    painter->setClipping(false);
    EBase::paint(painter, option, widget);
}
void EEnviron::timerEvent(QTimerEvent *e) {
    if(e->timerId() == timer_id) {
        if(isVisible()) {
            if(scroll_off < -scroll_width) scroll_off = mWidth;
            else scroll_off--;
            update();
        } else if(timer_id!=0) {
            killTimer(timer_id);
            timer_id = 0;
        }
    } else EBase::timerEvent(e);
}

QWidget* EEnviron::attrWgt() {
    auto wgtAttr = new QWidget;
    auto vBox = new QVBoxLayout(wgtAttr);
    vBox->setContentsMargins(6, 0, 6, 0);
    vBox->setSpacing(3);

    addBaseAttrWgt(vBox);

    auto hBox = new QHBoxLayout;
    hBox->addWidget(new QLabel(tr("Basic Properties")));

    auto line = new QFrame;
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);
    hBox->addWidget(line, 1);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout;
    hBox->addSpacing(6);

    auto fdTitle = new QLineEdit(m_attr.title);
    fdTitle->setPlaceholderText(tr("Title"));
    connect(fdTitle, &QLineEdit::textChanged, this, [this](const QString &text) {
        m_attr.title = text;
        calAttr();
        update();
    });
    hBox->addWidget(fdTitle);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto wTemp = new QCheckBox(tr("Temperature"));
    wTemp->setChecked(m_attr.hasTemp);
    connect(wTemp, &QCheckBox::toggled, this, [this](bool checked) {
        m_attr.hasTemp = checked;
        calAttr();
        update();
    });
    hBox->addWidget(wTemp);
    hBox->addStretch();

    auto fdIsCelsius = new QRadioButton("℃");
    connect(fdIsCelsius, &QRadioButton::toggled, this, [this](bool checked) {
        m_attr.tempType = checked ? 0 : 1;
        calAttr();
        update();
    });
    hBox->addWidget(fdIsCelsius);

    auto fdIsFahrenheit = new QRadioButton("℉");
    hBox->addWidget(fdIsFahrenheit);
    hBox->addStretch();

    if(m_attr.tempType == 0) fdIsCelsius->setChecked(true);
    else fdIsFahrenheit->setChecked(true);
    auto gTempType = new QButtonGroup(wgtAttr);
    gTempType->addButton(fdIsCelsius);
    gTempType->addButton(fdIsFahrenheit);

    auto fdLabelTemp = new QLineEdit(m_attr.labelTemp);
    fdLabelTemp->setMaximumWidth(100);
    connect(fdLabelTemp, &QLineEdit::textChanged, this, [this](const QString &text) {
        m_attr.labelTemp = text;
        calAttr();
        update();
    });
    hBox->addWidget(fdLabelTemp);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addStretch();

    hBox->addWidget(new QLabel(tr("Compensation")));

    auto fdComp = new QSpinBox();
    fdComp->setRange(-99, 999);
    fdComp->setValue(m_attr.compensation);
    connect(fdComp, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
        m_attr.compensation = value;
        calAttr();
        update();
    });
    hBox->addWidget(fdComp);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdHasHum = new QCheckBox(tr("Humidity")+" (%)");
    fdHasHum->setChecked(m_attr.hasHum);
    connect(fdHasHum, &QCheckBox::toggled, this, [this](bool checked) {
        m_attr.hasHum = checked;
        calAttr();
        update();
    });
    hBox->addWidget(fdHasHum);
    hBox->addStretch();

    auto fdLabelHum = new QLineEdit(m_attr.labelHum);
    fdLabelHum->setMaximumWidth(100);
    connect(fdLabelHum, &QLineEdit::textChanged, this, [this](const QString &text) {
        m_attr.labelHum = text;
        calAttr();
        update();
    });
    hBox->addWidget(fdLabelHum);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdHasWindSpeed = new QCheckBox(tr("Wind speed")+" (m/s)");
    fdHasWindSpeed->setChecked(m_attr.hasWindSpeed);
    connect(fdHasWindSpeed, &QCheckBox::toggled, this, [this](bool checked) {
        m_attr.hasWindSpeed = checked;
        calAttr();
        update();
    });
    hBox->addWidget(fdHasWindSpeed);
    hBox->addStretch();

    auto fdLabelWindSpeed = new QLineEdit(m_attr.labelWindSpeed);
    fdLabelWindSpeed->setMaximumWidth(100);
    connect(fdLabelWindSpeed, &QLineEdit::textChanged, this, [this](const QString &text) {
        m_attr.labelWindSpeed = text;
        calAttr();
        update();
    });
    hBox->addWidget(fdLabelWindSpeed);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdHasWindDirection = new QCheckBox(tr("Wind direction"));
    fdHasWindDirection->setChecked(m_attr.hasWindDirection);
    connect(fdHasWindDirection, &QCheckBox::toggled, this, [this](bool checked) {
        m_attr.hasWindDirection = checked;
        calAttr();
        update();
    });
    hBox->addWidget(fdHasWindDirection);
    hBox->addStretch();

    auto fdLabelWindDirection = new QLineEdit(m_attr.labelWindDirectiton);
    fdLabelWindDirection->setMaximumWidth(100);
    connect(fdLabelWindDirection, &QLineEdit::textChanged, this, [this](const QString &text) {
        m_attr.labelWindDirectiton = text;
        calAttr();
        update();
    });
    hBox->addWidget(fdLabelWindDirection);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdHasNoise = new QCheckBox(tr("Noise")+" (dB)");
    fdHasNoise->setChecked(m_attr.hasNoise);
    connect(fdHasNoise, &QCheckBox::toggled, this, [this](bool checked) {
        m_attr.hasNoise = checked;
        calAttr();
        update();
    });
    hBox->addWidget(fdHasNoise);
    hBox->addStretch();

    auto fdLabelNoise = new QLineEdit(m_attr.labelNoise);
    fdLabelNoise->setMaximumWidth(100);
    connect(fdLabelNoise, &QLineEdit::textChanged, this, [this](const QString &text) {
        m_attr.labelNoise = text;
        calAttr();
        update();
    });
    hBox->addWidget(fdLabelNoise);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdHasPM25 = new QCheckBox("PM2.5 (μg/m³)");
    fdHasPM25->setChecked(m_attr.hasPM25);
    connect(fdHasPM25, &QCheckBox::toggled, this, [this](bool checked) {
        m_attr.hasPM25 = checked;
        calAttr();
        update();
    });
    hBox->addWidget(fdHasPM25);
    hBox->addStretch();

    auto fdLabelPM25 = new QLineEdit(m_attr.labelPm25);
    fdLabelPM25->setMaximumWidth(100);
    connect(fdLabelPM25, &QLineEdit::textChanged, this, [this](const QString &text) {
        m_attr.labelPm25 = text;
        calAttr();
        update();
    });
    hBox->addWidget(fdLabelPM25);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdHasPM10 = new QCheckBox("PM10 (μg/m³)");
    fdHasPM10->setChecked(m_attr.hasPM10);
    connect(fdHasPM10, &QCheckBox::toggled, this, [this](bool checked) {
        m_attr.hasPM10 = checked;
        calAttr();
        update();
    });
    hBox->addWidget(fdHasPM10);
    hBox->addStretch();

    auto fdLabelPM10 = new QLineEdit(m_attr.labelPm10);
    fdLabelPM10->setMaximumWidth(100);
    connect(fdLabelPM10, &QLineEdit::textChanged, this, [this](const QString &text) {
        m_attr.labelPm10 = text;
        calAttr();
        update();
    });
    hBox->addWidget(fdLabelPM10);

    vBox->addLayout(hBox);

    auto wgtAlign = new QWidget();
    auto hBoxAlign = new QHBoxLayout(wgtAlign);
    hBoxAlign->setContentsMargins(6,0,0,0);
    hBoxAlign->addStretch();

    auto fdLeft = new QRadioButton(tr("Left"));
    fdLeft->setChecked(true);
    connect(fdLeft, &QRadioButton::toggled, this, [this](bool checked) {
        if(! checked) return;
        m_attr.align = 0;
        calAttr();
        update();
    });
    hBoxAlign->addWidget(fdLeft);

    auto fdCenter = new QRadioButton(tr("Center"));
    connect(fdCenter, &QRadioButton::toggled, this, [this](bool checked) {
        if(! checked) return;
        m_attr.align = 1;
        calAttr();
        update();
    });
    hBoxAlign->addWidget(fdCenter);

    auto fdRight = new QRadioButton(tr("Right"));
    connect(fdRight, &QRadioButton::toggled, this, [this](bool checked) {
        if(! checked) return;
        m_attr.align = 2;
        calAttr();
        update();
    });
    hBoxAlign->addWidget(fdRight);
    hBoxAlign->addStretch();

    vBox->addWidget(wgtAlign);

    if(m_attr.isSingleLine) wgtAlign->setVisible(false);
    if(m_attr.align == 0) fdLeft->setChecked(true);
    else if(m_attr.align == 1) fdCenter->setChecked(true);
    else if(m_attr.align == 2) fdRight->setChecked(true);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdIsScroll = new QCheckBox(tr("Single scroll"));
    fdIsScroll->setChecked(m_attr.isSingleLine);
    connect(fdIsScroll, &QCheckBox::toggled, this, [this, wgtAlign](bool checked) {
        m_attr.isSingleLine = checked;
        wgtAlign->setVisible(! checked);
        if(timer_id!=0) {
            killTimer(timer_id);
            timer_id = 0;
        }
        calAttr();
        update();
    });
    hBox->addWidget(fdIsScroll);

    hBox->addStretch();

    hBox->addWidget(new QLabel(tr("Speed")));

    auto fdSpeed = new QSpinBox();
    fdSpeed->setRange(1, 999);
    fdSpeed->setValue(m_attr.scrollSpeed);
    connect(fdSpeed, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
        m_attr.scrollSpeed = value;
        if(timer_id!=0) {
            killTimer(timer_id);
            timer_id = 0;
        }
        calAttr();
        update();
    });
    hBox->addWidget(fdSpeed);

    hBox->addWidget(new QLabel(tr("ms/pixel")));
    hBox->addStretch();

    vBox->addLayout(hBox);

    line = new QFrame();
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);
    vBox->addWidget(line);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdFontFamily = new QFontComboBox();
    fdFontFamily->setEditable(false);
    fdFontFamily->setCurrentText(m_attr.font.family());
    connect(fdFontFamily, &QFontComboBox::currentFontChanged, this, [this](const QFont &f) {
        QFont font(f.family(), m_attr.font.pointSize());
        font.setBold(m_attr.font.bold());
        font.setItalic(m_attr.font.italic());
        font.setUnderline(m_attr.font.underline());
        m_attr.font = font;
        calAttr();
        update();
    });
    hBox->addWidget(fdFontFamily);

    auto fdFontSize = new QSpinBox();
    fdFontSize->setRange(4, 9999);
    fdFontSize->setValue(m_attr.font.pointSize());
    connect(fdFontSize, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
        m_attr.font.setPointSize(value);
        calAttr();
        update();
    });
    hBox->addWidget(fdFontSize);
    hBox->addStretch();

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);

    auto fdBold = new QPushButton();
    fdBold->setFixedSize(QSize(30, 30));
    fdBold->setIconSize(QSize(30, 30));
    QIcon icon(":/res/ProgramManager/EditProgram/FontBold_u.png");
    icon.addFile(":/res/ProgramManager/EditProgram/FontBold_s.png", QSize(), QIcon::Normal, QIcon::On);
    fdBold->setIcon(icon);
    fdBold->setCheckable(true);
    fdBold->setFlat(true);
    fdBold->setChecked(m_attr.font.bold());
    connect(fdBold, &QPushButton::toggled, this, [this](bool checked) {
        m_attr.font.setBold(checked);
        calAttr();
        update();
    });
    hBox->addWidget(fdBold);

    auto fdItalic = new QPushButton();
    fdItalic->setFixedSize(QSize(30, 30));
    fdItalic->setIconSize(QSize(30, 30));
    QIcon icon1(":/res/ProgramManager/EditProgram/FontItalics_u.png");
    icon1.addFile(":/res/ProgramManager/EditProgram/FontItalics_s.png", QSize(), QIcon::Normal, QIcon::On);
    fdItalic->setIcon(icon1);
    fdItalic->setCheckable(true);
    fdItalic->setFlat(true);
    fdItalic->setChecked(m_attr.font.italic());
    connect(fdItalic, &QPushButton::toggled, this, [this](bool checked) {
        m_attr.font.setItalic(checked);
        calAttr();
        update();
    });
    hBox->addWidget(fdItalic);

    auto fdUnderline = new QPushButton();
    fdUnderline->setFixedSize(QSize(30, 30));
    fdUnderline->setIconSize(QSize(30, 30));
    QIcon icon2(":/res/ProgramManager/EditProgram/FontUnderline_u.png");
    icon2.addFile(":/res/ProgramManager/EditProgram/FontUnderline_s.png", QSize(), QIcon::Normal, QIcon::On);
    fdUnderline->setIcon(icon2);
    fdUnderline->setCheckable(true);
    fdUnderline->setFlat(true);
    fdUnderline->setChecked(m_attr.font.underline());
    connect(fdUnderline, &QPushButton::toggled, this, [this](bool checked) {
        m_attr.font.setUnderline(checked);
        calAttr();
        update();
    });
    hBox->addWidget(fdUnderline);


    auto fdColor = new LoColorSelector("T", m_attr.textColor);
    fdColor->setFixedWidth(30);
    connect(fdColor, &LoColorSelector::sColorChanged, this, [this](const QColor &color) {
        m_attr.textColor = color;
        calAttr();
        update();
    });
    hBox->addWidget(fdColor);

    auto fdBack = new LoColorSelector(tr("Back Color"), m_attr.backColor);
    connect(fdBack, &LoColorSelector::sColorChanged, this, [this](const QColor &color) {
        m_attr.backColor = color;
        calAttr();
        update();
    });
    hBox->addWidget(fdBack);
    hBox->addStretch();

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addWidget(new QLabel(tr("Play Properties")));

    line = new QFrame();
    line->setFrameShape(QFrame::HLine);
    line->setFrameShadow(QFrame::Sunken);
    hBox->addWidget(line, 1);

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);
    hBox->addWidget(new QLabel(tr("Refresh Cycle")));

    auto fdRefresh = new QSpinBox();
    fdRefresh->setRange(1, 999);
    fdRefresh->setValue(m_attr.playRefresh);
    connect(fdRefresh, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
        m_attr.playRefresh = value;
    });
    hBox->addWidget(fdRefresh);

    hBox->addWidget(new QLabel(tr("min.")));
    hBox->addStretch();

    vBox->addLayout(hBox);

    hBox = new QHBoxLayout();
    hBox->addSpacing(6);
    hBox->addWidget(new QLabel(tr("Play Duration")));

    auto fdDuration = new QSpinBox();
    fdDuration->setRange(1, 99999);
    fdDuration->setValue(m_attr.playDuration);
    connect(fdDuration, (void(QSpinBox::*)(int))&QSpinBox::valueChanged, this, [this](int value) {
        m_attr.playDuration = value;
    });
    hBox->addWidget(fdDuration);

    hBox->addWidget(new QLabel(tr("s")));
    hBox->addStretch();

    vBox->addLayout(hBox);
    vBox->addStretch();
    return wgtAttr;
}

QJsonObject EEnviron::attrJson() const{
    QJsonObject oWidget;
    oWidget["bTemperature"]          = m_attr.hasTemp;
    oWidget["temperatureCompensation"]          = m_attr.compensation;
    oWidget["temperatureStyle"]     = m_attr.tempType;
    oWidget["labelTemperature"]     = m_attr.labelTemp;
    oWidget["labelTitle"]          = m_attr.title;
    oWidget["bHumidity"]          = m_attr.hasHum;
    oWidget["labelHumidity"]          = m_attr.labelHum;
    oWidget["bNoise"]          = m_attr.hasNoise;
    oWidget["labelNoise"]          = m_attr.labelNoise;
    oWidget["bWindSpeed"]          = m_attr.hasWindSpeed;
    oWidget["labelWindSpeed"]          = m_attr.labelWindSpeed;
    oWidget["bWindDirection"]          = m_attr.hasWindDirection;
    oWidget["labelWindDirection"]          = m_attr.labelWindDirectiton;
    oWidget["bPM25"]          = m_attr.hasPM25;
    oWidget["labelPM25"]          = m_attr.labelPm25;
    oWidget["bPM10"]          = m_attr.hasPM10;
    oWidget["labelPM10"]          = m_attr.labelPm10;

    oWidget["bPaomadeng"]          = m_attr.isSingleLine;
    oWidget["scrollSpeed"]          = m_attr.scrollSpeed;
    oWidget["alignType"] = m_attr.align;
    oWidget["fontFamily"] = m_attr.font.family();
    oWidget["fontSize"] = m_attr.font.pointSize();
    oWidget["fontBold"] = m_attr.font.bold();
    oWidget["fontItalics"] = m_attr.font.italic();
    oWidget["fontUnderline"] = m_attr.font.underline();
    oWidget["textColor"] = Tools::color2Int(m_attr.textColor);
    oWidget["cBackground"] = Tools::color2Int(m_attr.backColor);
    oWidget.insert("idDir", QString("env-%1-%2-%3-%4-%5").arg((int) zValue()).arg((int) x()).arg((int) y()).arg((int) mWidth).arg((int) mHeight));

    QJsonObject oRoot;
    addBaseAttr(oRoot);
    oRoot["elementType"] = "Temp";
    oRoot["widget"] = oWidget;
    oRoot["play"] = QJsonObject{
        {"refresh", m_attr.playRefresh},
        {"duration", m_attr.playDuration}
    };
    return  oRoot;
}

bool EEnviron::save(const QString &pageDir) {
    auto inner = innerRect();
    QPixmap img(m_attr.isSingleLine ? scroll_width : inner.width(), inner.height());
    img.fill(m_attr.backColor);
    QPainter painter(&img);
    QRectF arect(0, 0, img.width(), img.height());
    drawText(&painter, arect);
    img.save(pageDir+"/previewTmp.png", "PNG");
    return true;
}