aboutsummaryrefslogblamecommitdiff
path: root/mapman/src/groupview.cpp
blob: 78811848ae34bb7e6a745803c4793f12154aae05 (plain) (tree)
1
2
3
4
5
6
7
8
9


                         
                        




                             
                                



                      
                    






                        

                        








                                          




                                                                       








                                                                               
                                                                                                                 























                                                                                                                                                                               

                                           

                                                                        
                            







                                   
                              






















                                                                                            






                                                                                                                        












                                                                               
                                                                                                 















                                                    







                                                              










                            
                                                   





                                      
                                                                                                                 







                                      
                                                                                                                 

























                                                              
                                                                                                                 












                                              




                                                                                        



                                                                            
                             









                                                                                   





                                                
























                                                             



























                                                                                                 
#include "groupview.hpp" 
#include "library.hpp"
#include "painter.hpp"
#include "src/utils.hpp"

#include <algorithm>

#include <QTableView>
#include <QStandardItemModel>
#include <QSortFilterProxyModel>
#include <QPushButton>
#include <QLineEdit>
#include <QSpinBox>
#include <QLabel>
#include <QComboBox>
#include <QSplitter>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGraphicsView>
#include <QSpacerItem>
#include <QHeaderView>
#include <QMessageBox>
#include <QFileDialog>
#include <qfiledialog.h>

group_view::group_view() : QMdiSubWindow()
{
    auto sp = new QSplitter(this);
    this->setWidget(sp);
    auto leftpane = new QWidget();
    auto l1 = new QVBoxLayout();
    leftpane->setLayout(l1);
    tv = new QTableView();
    m = new QStandardItemModel(this);
    mf = new QSortFilterProxyModel(this);
    mf->setSourceModel(m);
    mf->setFilterCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
    tv->setModel(mf);
    tv->setColumnHidden(3, true);
    tv->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
    tv->setSelectionBehavior(QAbstractItemView::SelectionBehavior::SelectRows);
    connect(tv->selectionModel(), &QItemSelectionModel::currentRowChanged,
        [this](const QModelIndex &curidx, const QModelIndex &oldidx) {
            if (oldidx.isValid() && curidx.row() == oldidx.row()) return;
            bool dirty = oldidx.isValid() && this->dirty;
            if (oldidx.isValid())
            {
                int64_t oldgid = mf->data(oldidx.siblingAtColumn(3), Qt::ItemDataRole::DisplayRole).toLongLong();
                auto oldgroup = l->get_group(oldgid);
                dirty |= tetitle->text() != QString::fromStdString(oldgroup.title);
                dirty |= teauthor->text() != QString::fromStdString(oldgroup.author);
                dirty |= sbh->value() != oldgroup.hc;
                dirty |= sbv->value() != oldgroup.vc;
            }
            if (dirty)
            {
                if (QMessageBox::question(this, "Unsaved changes", "Changes to map art not saved! Discard and switch to another map art?") != QMessageBox::StandardButton::Yes)
                {
                    int row = oldidx.row();
                    QMetaObject::invokeMethod(this, [this, row]() {
                        QSignalBlocker b(tv->selectionModel());
                        tv->selectRow(row);
                    }, Qt::ConnectionType::QueuedConnection);
                    return;
                }
            }
            this->update_fields();
    });
    l1->addWidget(tv);
    auto l2 = new QHBoxLayout();
    pbadd = new QPushButton("+");
    pbrem = new QPushButton("-");
    tefilter = new QLineEdit();
    tefilter->setPlaceholderText("Filter");
    connect(pbadd, &QPushButton::pressed, this, &group_view::add_group);
    connect(pbrem, &QPushButton::pressed, this, &group_view::rem_group);
    l2->addWidget(tefilter);
    l2->addWidget(pbadd);
    l2->addWidget(pbrem);
    l1->addLayout(l2);
    sp->addWidget(leftpane);

    auto rightpane = new QWidget();
    auto l3 = new QVBoxLayout();
    rightpane->setLayout(l3);
    p = new map_painter(this);
    l3->addWidget(p->view());
    connect(p, &map_painter::map_id_changed, this, &group_view::painter_drop);
    tetitle = new QLineEdit();
    teauthor = new QLineEdit();
    tetitle->setPlaceholderText("Title");
    teauthor->setPlaceholderText("Author(s)");
    l3->addWidget(tetitle);
    l3->addWidget(teauthor);
    auto l4 = new QHBoxLayout();
    sbv = new QSpinBox();
    sbh = new QSpinBox();
    sbv->setValue(1);
    sbv->setMinimum(1);
    sbv->setMaximum(100);
    connect(sbv, QOverload<int>::of(&QSpinBox::valueChanged), this, &group_view::reset_dim);
    sbh->setValue(1);
    sbh->setMinimum(1);
    sbh->setMaximum(100);
    connect(sbh, QOverload<int>::of(&QSpinBox::valueChanged), this, &group_view::reset_dim);
    l4->addWidget(sbh);
    l4->addWidget(new QLabel("x"));
    l4->addWidget(sbv);
    l4->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
    l4->addWidget(new QLabel("Zoom"));
    cbscale = new QComboBox();
    cbscale->addItems({QStringLiteral("100%"), QStringLiteral("200%"), QStringLiteral("300%"), QStringLiteral("400%")});
    connect(cbscale, &QComboBox::currentIndexChanged, this, [this](int idx) {
       p->set_scaling(idx + 1);
    });
    l4->addWidget(cbscale);
    pbapply = new QPushButton("Save");
    connect(pbapply, &QPushButton::pressed, this, &group_view::update_library);

    l4->addWidget(pbapply);
    l3->addLayout(l4);
    sp->addWidget(rightpane);

    sp->setStretchFactor(0, 1);
    sp->setStretchFactor(1, 3);
    sp->setCollapsible(0, false);
    sp->setCollapsible(1, false);
    l = nullptr;
    dirty = false;
    connect(tefilter, &QLineEdit::textChanged, mf, &QSortFilterProxyModel::setFilterFixedString);
    this->setWindowTitle("Map art listings");
    this->setAttribute(Qt::WA_DeleteOnClose, false);
}

group_view::~group_view()
{
    delete p;
}

void group_view::set_library(map_library *lib)
{
    l = lib;
    p->set_map_library(l);
    refresh_list();
}

void group_view::export_group_image(QString fn, int64_t gid)
{
    if (!l || !l->has_group(gid))
        return;
    QImage img = image_of_map_group(l, l->get_group(gid), 1.);
    img.save(fn, "PNG");
}

void group_view::add_group()
{
    map_group_t g {
        std::string(),
        std::string(),
        1, 1,
        {0},
        {false}
    };
    l->new_group(g);
    refresh_list();
    tv->scrollTo(mf->index(mf->rowCount() - 1, 0));
}

void group_view::rem_group()
{
    if (!tv->currentIndex().isValid())
        return;
    int64_t curgid = mf->data(tv->currentIndex().siblingAtColumn(3), Qt::ItemDataRole::DisplayRole).toLongLong();
    l->remove_group(curgid);
    refresh_list();
}

void group_view::update_fields()
{
    if (!tv->currentIndex().isValid())
        return;
    int64_t curgid = mf->data(tv->currentIndex().siblingAtColumn(3), Qt::ItemDataRole::DisplayRole).toLongLong();
    current_group = l->get_group(curgid);
    auto &g = current_group;
    tetitle->setText(QString::fromStdString(g.title));
    teauthor->setText(QString::fromStdString(g.author));
    QSignalBlocker bh(sbh);
    QSignalBlocker bv(sbv);
    sbh->setValue(g.hc);
    sbv->setValue(g.vc);
    update_map_view();
    dirty = false;
}

void group_view::painter_drop(int pos, bool populated, int id)
{
    if (!tv->currentIndex().isValid())
        return;
    auto &g = current_group;
    g.populated[pos] = populated;
    g.ids[pos] = id;
    dirty = true;
}

void group_view::update_library()
{
    if (!tv->currentIndex().isValid())
        return;
    int64_t curgid = mf->data(tv->currentIndex().siblingAtColumn(3), Qt::ItemDataRole::DisplayRole).toLongLong();
    auto &g = current_group;
    g.title = tetitle->text().toStdString();
    g.author = teauthor->text().toStdString();
    g.hc = sbh->value();
    g.vc = sbv->value();
    l->set_group(curgid, g);
    refresh_list();
    dirty = false;
}

void group_view::refresh_list()
{
    int64_t curgid = -1;
    if (tv->currentIndex().isValid() && tv->currentIndex().siblingAtColumn(3).isValid())
    {
        auto idx = tv->currentIndex().siblingAtColumn(3);
        curgid = mf->data(idx, Qt::ItemDataRole::DisplayRole).toLongLong();
    }
    m->clear();
    m->setHorizontalHeaderLabels({"Title", "Author(s)", "Dimension", "id"});
    tv->setColumnHidden(3, true);
    auto gids = l->groups();
    auto idx = QModelIndex();
    for (auto gid : gids)
    {
        map_group_t g = l->get_group(gid);
        QStandardItem *t = new QStandardItem(QString::fromStdString(g.title));
        QStandardItem *a = new QStandardItem(QString::fromStdString(g.author));
        QStandardItem *d = new QStandardItem(QString("%1x%2").arg(g.hc).arg(g.vc));
        QStandardItem *i = new QStandardItem();
        i->setData(QVariant((qlonglong)gid), Qt::ItemDataRole::DisplayRole);
        m->appendRow({t, a, d, i});
        if (gid == curgid)
            idx = mf->mapFromSource(t->index());
    }
    if (idx.isValid())
    {
        tv->setCurrentIndex(idx);
        tv->scrollTo(idx);
    }
    tv->resizeColumnsToContents();
}

void group_view::reset_dim()
{
    p->set_dimension(sbh->value(), sbv->value());
    if (!tv->currentIndex().isValid())
        return;
    auto &g = current_group;
    g.hc = sbh->value();
    g.vc = sbv->value();
    g.ids.resize(g.hc * g.vc);
    g.populated.resize(g.hc * g.vc);
    std::fill(g.populated.begin(), g.populated.end(), false);
    dirty = true;
}

void group_view::update_map_view()
{
    auto &g = current_group;
    p->set_dimension(g.hc, g.vc);
    for (int i = 0; i < g.hc * g.vc; ++i)
        p->set_map_id(i, g.populated[i], g.ids[i]);
}

void group_view::export_current_group()
{
    int64_t curgid = -1;
    if (tv->currentIndex().isValid() && tv->currentIndex().siblingAtColumn(3).isValid())
    {
        auto idx = tv->currentIndex().siblingAtColumn(3);
        curgid = mf->data(idx, Qt::ItemDataRole::DisplayRole).toLongLong();
    }
    if (!~curgid)
        return;
    QString fn = QFileDialog::getSaveFileName(this, "Export Image", QString(), "Images (*.png)");
    if (fn.isEmpty()) return;
    export_group_image(fn, curgid);
}

void group_view::export_all_groups()
{
    QString fp = QFileDialog::getExistingDirectory(this, "Select Output Directory");
    if (fp.isEmpty()) return;
    auto gids = l->groups();
    for (auto gid : gids)
    {
        auto g = l->get_group(gid);
        auto fn = QString("%1/%2_%3.png").arg(fp).arg(gid).arg(QString::fromStdString(g.title));
        export_group_image(fn, gid);
    }
}