<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "bluetoothlistener.h"
#include "trkdevice.h"

#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtCore/QEventLoop>

#ifdef Q_OS_UNIX
#   include <unistd.h>
#   include <signal.h>
#endif

enum { debug = 0 };

namespace trk {

struct BluetoothListenerPrivate {
    BluetoothListenerPrivate();
    QString device;
    QProcess process;
    Q_PID pid;
    bool printConsoleMessages;
    BluetoothListener::Mode mode;
};

BluetoothListenerPrivate::BluetoothListenerPrivate() :
    pid(0),
    printConsoleMessages(false),
    mode(BluetoothListener::Listen)
{
}

BluetoothListener::BluetoothListener(QObject *parent) :
    QObject(parent),
    d(new BluetoothListenerPrivate)
{
    d->process.setProcessChannelMode(QProcess::MergedChannels);

    connect(&d->process, SIGNAL(readyReadStandardError()),
            this, SLOT(slotStdError()));
    connect(&d->process, SIGNAL(readyReadStandardOutput()),
            this, SLOT(slotStdOutput()));
    connect(&d->process, SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SLOT(slotProcessFinished(int,QProcess::ExitStatus)));
    connect(&d->process, SIGNAL(error(QProcess::ProcessError)),
            this, SLOT(slotProcessError(QProcess::ProcessError)));
}

BluetoothListener::~BluetoothListener()
{
    const int trc = terminateProcess();
    if (debug)
        qDebug() << "~BluetoothListener: terminated" << trc;
    delete d;
}

BluetoothListener::Mode BluetoothListener::mode() const
{
    return d->mode;
}

void BluetoothListener::setMode(Mode m)
{
    d->mode = m;
}

bool BluetoothListener::printConsoleMessages() const
{
    return d->printConsoleMessages;
}

void BluetoothListener::setPrintConsoleMessages(bool p)
{
    d->printConsoleMessages = p;
}

int BluetoothListener::terminateProcess()
{
    enum { TimeOutMS = 200 };
    if (debug)
        qDebug() << "terminateProcess" << d->process.pid() << d->process.state();
    if (d->process.state() == QProcess::NotRunning)
        return -1;
    emitMessage(tr("%1: Stopping listener %2...").arg(d->device).arg(d->process.pid()));
    // When listening, the process should terminate by itself after closing the connection
    if (mode() == Listen && d->process.waitForFinished(TimeOutMS))
        return 0;
#ifdef Q_OS_UNIX
    kill(d->process.pid(), SIGHUP); // Listens for SIGHUP
    if (d->process.waitForFinished(TimeOutMS))
        return 1;
#endif
    d->process.terminate();
    if (d->process.waitForFinished(TimeOutMS))
        return 2;
    d->process.kill();
    return 3;
}

bool BluetoothListener::start(const QString &device, QString *errorMessage)
{
    if (d->process.state() != QProcess::NotRunning) {
        *errorMessage = QLatin1String("Internal error: Still running.");
        return false;
    }
    d->device = device;
    const QString binary = QLatin1String("rfcomm");
    QStringList arguments;
    arguments << QLatin1String("-r")
              << (d->mode == Listen ? QLatin1String("listen") : QLatin1String("watch"))
              << device << QString(QLatin1Char('1'));
    if (debug)
        qDebug() << binary << arguments;
    emitMessage(tr("%1: Starting Bluetooth listener %2...").arg(device, binary));
    d->pid = 0;
    d->process.start(binary, arguments);
    if (!d->process.waitForStarted()) {
        *errorMessage = tr("Unable to run '%1': %2").arg(binary, d->process.errorString());
        return false;
    }
    d->pid = d->process.pid(); // Forgets it after crash/termination
    emitMessage(tr("%1: Bluetooth listener running (%2).").arg(device).arg(d->process.pid()));
    return true;
}

void BluetoothListener::slotStdOutput()
{
    emitMessage(QString::fromLocal8Bit(d->process.readAllStandardOutput()));
}

void BluetoothListener::emitMessage(const QString &m)
{
    if (d->printConsoleMessages || debug)
        qDebug("%s\n", qPrintable(m));
    emit message(m);
}

void BluetoothListener::slotStdError()
{
    emitMessage(QString::fromLocal8Bit(d->process.readAllStandardError()));
}

void BluetoothListener::slotProcessFinished(int ex, QProcess::ExitStatus state)
{
    switch (state) {
    case QProcess::NormalExit:
        emitMessage(tr("%1: Process %2 terminated with exit code %3.")
                    .arg(d->device).arg(d->pid).arg(ex));
        break;
    case QProcess::CrashExit:
        emitMessage(tr("%1: Process %2 crashed.").arg(d->device).arg(d->pid));
        break;
    }
    emit terminated();
}

void BluetoothListener::slotProcessError(QProcess::ProcessError error)
{
    emitMessage(tr("%1: Process error %2: %3")
        .arg(d->device).arg(error).arg(d->process.errorString()));
}

// --------------- AbstractBluetoothStarter
struct AbstractBluetoothStarterPrivate {
    explicit AbstractBluetoothStarterPrivate(const AbstractBluetoothStarter::TrkDevicePtr &d);

    const AbstractBluetoothStarter::TrkDevicePtr trkDevice;
    BluetoothListener *listener;
    QTimer *timer;
    int intervalMS;
    int attempts;
    int n;
    QString device;
    QString errorString;
    AbstractBluetoothStarter::State state;
};

AbstractBluetoothStarterPrivate::AbstractBluetoothStarterPrivate(const AbstractBluetoothStarter::TrkDevicePtr &d) :

    trkDevice(d),
    listener(0),
    timer(0),
    intervalMS(1000),
    attempts(-1),
    n(0),
    device(QLatin1String("/dev/rfcomm0")),
    state(AbstractBluetoothStarter::TimedOut)
{
}

AbstractBluetoothStarter::AbstractBluetoothStarter(const TrkDevicePtr &trkDevice, QObject *parent) :
    QObject(parent),
    d(new AbstractBluetoothStarterPrivate(trkDevice))
{
}

AbstractBluetoothStarter::~AbstractBluetoothStarter()
{
    stopTimer();
    delete d;
}

void AbstractBluetoothStarter::stopTimer()
{
    if (d->timer && d->timer->isActive())
        d->timer->stop();
}

AbstractBluetoothStarter::StartResult AbstractBluetoothStarter::start()
{
    if (state() == Running) {
        d->errorString = QLatin1String("Internal error, attempt to re-start AbstractBluetoothStarter.\n");
        return StartError;
    }
    // Before we instantiate timers, and such, try to open the device,
    // which should succeed if another listener is already running in
    // 'Watch' mode
    if (d->trkDevice->open(d->device , &(d->errorString)))
        return ConnectionSucceeded;
    // Fire up the listener
    d->n = 0;
    d->listener = createListener();
    if (!d->listener->start(d->device, &(d->errorString)))
        return StartError;
    // Start timer
    if (!d->timer) {
        d->timer = new QTimer;
        connect(d->timer, SIGNAL(timeout()), this, SLOT(slotTimer()));
    }
    d->timer->setInterval(d->intervalMS);
    d->timer->setSingleShot(false);
    d->timer->start();
    d->state = Running;
    return Started;
}

AbstractBluetoothStarter::State AbstractBluetoothStarter::state() const
{
    return d->state;
}

int AbstractBluetoothStarter::intervalMS() const
{
    return d->intervalMS;
}

void AbstractBluetoothStarter::setIntervalMS(int i)
{
    d->intervalMS = i;
    if (d->timer)
        d->timer->setInterval(i);
}

int AbstractBluetoothStarter::attempts() const
{
    return d->attempts;
}

void AbstractBluetoothStarter::setAttempts(int a)
{
    d->attempts = a;
}

QString AbstractBluetoothStarter::device() const
{
    return d->device;
}

void AbstractBluetoothStarter::setDevice(const QString &dv)
{
    d->device = dv;
}

QString AbstractBluetoothStarter::errorString() const
{
    return d->errorString;
}

void AbstractBluetoothStarter::slotTimer()
{
    ++d->n;
    // Check for timeout
    if (d->attempts >= 0 && d->n >= d->attempts) {
        stopTimer();
        d->errorString = tr("%1: timed out after %n attempts using an interval of %2ms.", 0, d->n)
                         .arg(d->device).arg(d->intervalMS);
        d->state = TimedOut;
        emit timeout();
    } else {
        // Attempt n to connect?
        if (d->trkDevice->open(d->device , &(d->errorString))) {
            stopTimer();
            const QString msg = tr("%1: Connection attempt %2 succeeded.").arg(d->device).arg(d->n);
            d->listener->emitMessage(msg);
            d->state = Connected;
            emit connected();
        } else {
            const QString msg = tr("%1: Connection attempt %2 failed: %3 (retrying)...")
                                .arg(d->device).arg(d->n).arg(d->errorString);
            d->listener->emitMessage(msg);
        }
    }
}

// -------- ConsoleBluetoothStarter
ConsoleBluetoothStarter::ConsoleBluetoothStarter(const TrkDevicePtr &trkDevice,
                                  QObject *listenerParent,
                                  QObject *parent) :
    AbstractBluetoothStarter(trkDevice, parent),
    m_listenerParent(listenerParent)
{
}

BluetoothListener *ConsoleBluetoothStarter::createListener()
{
    BluetoothListener *rc = new BluetoothListener(m_listenerParent);
    rc->setMode(BluetoothListener::Listen);
    rc->setPrintConsoleMessages(true);
    return rc;
}

bool ConsoleBluetoothStarter::startBluetooth(const TrkDevicePtr &trkDevice,
                                             QObject *listenerParent,
                                             const QString &device,
                                             int attempts,
                                             QString *errorMessage)
{
    // Set up a console starter to print to stdout.
    ConsoleBluetoothStarter starter(trkDevice, listenerParent);
    starter.setDevice(device);
    starter.setAttempts(attempts);
    switch (starter.start()) {
    case Started:
        break;
    case ConnectionSucceeded:
        return true;
    case StartError:
        *errorMessage = starter.errorString();
        return false;
    }
    // Run the starter with an event loop. @ToDo: Implement
    // some asynchronous keypress read to cancel.
    QEventLoop eventLoop;
    connect(&starter, SIGNAL(connected()), &eventLoop, SLOT(quit()));
    connect(&starter, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
    if (starter.state() != AbstractBluetoothStarter::Connected) {
        *errorMessage = starter.errorString();
        return false;
    }
    return true;
}

} // namespace trk
<commit_msg>Fix compilation on Windows<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "bluetoothlistener.h"
#include "trkdevice.h"

#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtCore/QEventLoop>

#ifdef Q_OS_UNIX
#   include <unistd.h>
#   include <signal.h>
#else
#   include <windows.h>
#endif

// Process id helpers.
#ifdef Q_OS_WIN
inline DWORD processId(const QProcess &p)
{
    if (const Q_PID processInfoStruct = p.pid())
        return processInfoStruct->dwProcessId;
    return 0;
}
#else
inline Q_PID processId(const QProcess &p)
{
    return p.pid();
}
#endif

enum { debug = 0 };

namespace trk {

struct BluetoothListenerPrivate {
    BluetoothListenerPrivate();
    QString device;
    QProcess process;
#ifdef Q_OS_WIN
    DWORD pid;
#else
    Q_PID pid;
#endif
    bool printConsoleMessages;
    BluetoothListener::Mode mode;
};

BluetoothListenerPrivate::BluetoothListenerPrivate() :
    pid(0),
    printConsoleMessages(false),
    mode(BluetoothListener::Listen)
{
}

BluetoothListener::BluetoothListener(QObject *parent) :
    QObject(parent),
    d(new BluetoothListenerPrivate)
{
    d->process.setProcessChannelMode(QProcess::MergedChannels);

    connect(&d->process, SIGNAL(readyReadStandardError()),
            this, SLOT(slotStdError()));
    connect(&d->process, SIGNAL(readyReadStandardOutput()),
            this, SLOT(slotStdOutput()));
    connect(&d->process, SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SLOT(slotProcessFinished(int,QProcess::ExitStatus)));
    connect(&d->process, SIGNAL(error(QProcess::ProcessError)),
            this, SLOT(slotProcessError(QProcess::ProcessError)));
}

BluetoothListener::~BluetoothListener()
{
    const int trc = terminateProcess();
    if (debug)
        qDebug() << "~BluetoothListener: terminated" << trc;
    delete d;
}

BluetoothListener::Mode BluetoothListener::mode() const
{
    return d->mode;
}

void BluetoothListener::setMode(Mode m)
{
    d->mode = m;
}

bool BluetoothListener::printConsoleMessages() const
{
    return d->printConsoleMessages;
}

void BluetoothListener::setPrintConsoleMessages(bool p)
{
    d->printConsoleMessages = p;
}

int BluetoothListener::terminateProcess()
{
    enum { TimeOutMS = 200 };
    if (debug)
        qDebug() << "terminateProcess" << d->process.pid() << d->process.state();
    if (d->process.state() == QProcess::NotRunning)
        return -1;
    emitMessage(tr("%1: Stopping listener %2...").arg(d->device).arg(processId(d->process)));
    // When listening, the process should terminate by itself after closing the connection
    if (mode() == Listen && d->process.waitForFinished(TimeOutMS))
        return 0;
#ifdef Q_OS_UNIX
    kill(d->process.pid(), SIGHUP); // Listens for SIGHUP
    if (d->process.waitForFinished(TimeOutMS))
        return 1;
#endif
    d->process.terminate();
    if (d->process.waitForFinished(TimeOutMS))
        return 2;
    d->process.kill();
    return 3;
}

bool BluetoothListener::start(const QString &device, QString *errorMessage)
{
    if (d->process.state() != QProcess::NotRunning) {
        *errorMessage = QLatin1String("Internal error: Still running.");
        return false;
    }
    d->device = device;
    const QString binary = QLatin1String("rfcomm");
    QStringList arguments;
    arguments << QLatin1String("-r")
              << (d->mode == Listen ? QLatin1String("listen") : QLatin1String("watch"))
              << device << QString(QLatin1Char('1'));
    if (debug)
        qDebug() << binary << arguments;
    emitMessage(tr("%1: Starting Bluetooth listener %2...").arg(device, binary));
    d->pid = 0;
    d->process.start(binary, arguments);
    if (!d->process.waitForStarted()) {
        *errorMessage = tr("Unable to run '%1': %2").arg(binary, d->process.errorString());
        return false;
    }
    d->pid = processId(d->process); // Forgets it after crash/termination
    emitMessage(tr("%1: Bluetooth listener running (%2).").arg(device).arg(processId(d->process)));
    return true;
}

void BluetoothListener::slotStdOutput()
{
    emitMessage(QString::fromLocal8Bit(d->process.readAllStandardOutput()));
}

void BluetoothListener::emitMessage(const QString &m)
{
    if (d->printConsoleMessages || debug)
        qDebug("%s\n", qPrintable(m));
    emit message(m);
}

void BluetoothListener::slotStdError()
{
    emitMessage(QString::fromLocal8Bit(d->process.readAllStandardError()));
}

void BluetoothListener::slotProcessFinished(int ex, QProcess::ExitStatus state)
{
    switch (state) {
    case QProcess::NormalExit:
        emitMessage(tr("%1: Process %2 terminated with exit code %3.")
                    .arg(d->device).arg(d->pid).arg(ex));
        break;
    case QProcess::CrashExit:
        emitMessage(tr("%1: Process %2 crashed.").arg(d->device).arg(d->pid));
        break;
    }
    emit terminated();
}

void BluetoothListener::slotProcessError(QProcess::ProcessError error)
{
    emitMessage(tr("%1: Process error %2: %3")
        .arg(d->device).arg(error).arg(d->process.errorString()));
}

// --------------- AbstractBluetoothStarter
struct AbstractBluetoothStarterPrivate {
    explicit AbstractBluetoothStarterPrivate(const AbstractBluetoothStarter::TrkDevicePtr &d);

    const AbstractBluetoothStarter::TrkDevicePtr trkDevice;
    BluetoothListener *listener;
    QTimer *timer;
    int intervalMS;
    int attempts;
    int n;
    QString device;
    QString errorString;
    AbstractBluetoothStarter::State state;
};

AbstractBluetoothStarterPrivate::AbstractBluetoothStarterPrivate(const AbstractBluetoothStarter::TrkDevicePtr &d) :

    trkDevice(d),
    listener(0),
    timer(0),
    intervalMS(1000),
    attempts(-1),
    n(0),
    device(QLatin1String("/dev/rfcomm0")),
    state(AbstractBluetoothStarter::TimedOut)
{
}

AbstractBluetoothStarter::AbstractBluetoothStarter(const TrkDevicePtr &trkDevice, QObject *parent) :
    QObject(parent),
    d(new AbstractBluetoothStarterPrivate(trkDevice))
{
}

AbstractBluetoothStarter::~AbstractBluetoothStarter()
{
    stopTimer();
    delete d;
}

void AbstractBluetoothStarter::stopTimer()
{
    if (d->timer && d->timer->isActive())
        d->timer->stop();
}

AbstractBluetoothStarter::StartResult AbstractBluetoothStarter::start()
{
    if (state() == Running) {
        d->errorString = QLatin1String("Internal error, attempt to re-start AbstractBluetoothStarter.\n");
        return StartError;
    }
    // Before we instantiate timers, and such, try to open the device,
    // which should succeed if another listener is already running in
    // 'Watch' mode
    if (d->trkDevice->open(d->device , &(d->errorString)))
        return ConnectionSucceeded;
    // Fire up the listener
    d->n = 0;
    d->listener = createListener();
    if (!d->listener->start(d->device, &(d->errorString)))
        return StartError;
    // Start timer
    if (!d->timer) {
        d->timer = new QTimer;
        connect(d->timer, SIGNAL(timeout()), this, SLOT(slotTimer()));
    }
    d->timer->setInterval(d->intervalMS);
    d->timer->setSingleShot(false);
    d->timer->start();
    d->state = Running;
    return Started;
}

AbstractBluetoothStarter::State AbstractBluetoothStarter::state() const
{
    return d->state;
}

int AbstractBluetoothStarter::intervalMS() const
{
    return d->intervalMS;
}

void AbstractBluetoothStarter::setIntervalMS(int i)
{
    d->intervalMS = i;
    if (d->timer)
        d->timer->setInterval(i);
}

int AbstractBluetoothStarter::attempts() const
{
    return d->attempts;
}

void AbstractBluetoothStarter::setAttempts(int a)
{
    d->attempts = a;
}

QString AbstractBluetoothStarter::device() const
{
    return d->device;
}

void AbstractBluetoothStarter::setDevice(const QString &dv)
{
    d->device = dv;
}

QString AbstractBluetoothStarter::errorString() const
{
    return d->errorString;
}

void AbstractBluetoothStarter::slotTimer()
{
    ++d->n;
    // Check for timeout
    if (d->attempts >= 0 && d->n >= d->attempts) {
        stopTimer();
        d->errorString = tr("%1: timed out after %n attempts using an interval of %2ms.", 0, d->n)
                         .arg(d->device).arg(d->intervalMS);
        d->state = TimedOut;
        emit timeout();
    } else {
        // Attempt n to connect?
        if (d->trkDevice->open(d->device , &(d->errorString))) {
            stopTimer();
            const QString msg = tr("%1: Connection attempt %2 succeeded.").arg(d->device).arg(d->n);
            d->listener->emitMessage(msg);
            d->state = Connected;
            emit connected();
        } else {
            const QString msg = tr("%1: Connection attempt %2 failed: %3 (retrying)...")
                                .arg(d->device).arg(d->n).arg(d->errorString);
            d->listener->emitMessage(msg);
        }
    }
}

// -------- ConsoleBluetoothStarter
ConsoleBluetoothStarter::ConsoleBluetoothStarter(const TrkDevicePtr &trkDevice,
                                  QObject *listenerParent,
                                  QObject *parent) :
    AbstractBluetoothStarter(trkDevice, parent),
    m_listenerParent(listenerParent)
{
}

BluetoothListener *ConsoleBluetoothStarter::createListener()
{
    BluetoothListener *rc = new BluetoothListener(m_listenerParent);
    rc->setMode(BluetoothListener::Listen);
    rc->setPrintConsoleMessages(true);
    return rc;
}

bool ConsoleBluetoothStarter::startBluetooth(const TrkDevicePtr &trkDevice,
                                             QObject *listenerParent,
                                             const QString &device,
                                             int attempts,
                                             QString *errorMessage)
{
    // Set up a console starter to print to stdout.
    ConsoleBluetoothStarter starter(trkDevice, listenerParent);
    starter.setDevice(device);
    starter.setAttempts(attempts);
    switch (starter.start()) {
    case Started:
        break;
    case ConnectionSucceeded:
        return true;
    case StartError:
        *errorMessage = starter.errorString();
        return false;
    }
    // Run the starter with an event loop. @ToDo: Implement
    // some asynchronous keypress read to cancel.
    QEventLoop eventLoop;
    connect(&starter, SIGNAL(connected()), &eventLoop, SLOT(quit()));
    connect(&starter, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
    if (starter.state() != AbstractBluetoothStarter::Connected) {
        *errorMessage = starter.errorString();
        return false;
    }
    return true;
}

} // namespace trk
<|endoftext|>


<commit_before>#include "KBShortcutsDialog.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include <wx/scrolwin.h>
#include <wx/display.h>
#include "GUI_App.hpp"
#include "wxExtensions.hpp"

#define NOTEBOOK_TOP 1
#define NOTEBOOK_LEFT 2
#define LISTBOOK_TOP 3
#define LISTBOOK_LEFT 4
#define TOOLBOOK 5
#define CHOICEBOOK 6
#define BOOK_TYPE LISTBOOK_LEFT

#if (BOOK_TYPE == NOTEBOOK_TOP) || (BOOK_TYPE == NOTEBOOK_LEFT)
#include <wx/notebook.h>
#elif (BOOK_TYPE == LISTBOOK_TOP) || (BOOK_TYPE == LISTBOOK_LEFT)
#include <wx/listbook.h>
#elif BOOK_TYPE == TOOLBOOK
#include <wx/toolbook.h>
#elif BOOK_TYPE == CHOICEBOOK
#include <wx/choicebk.h>
#endif // BOOK_TYPE

namespace Slic3r {
namespace GUI {

KBShortcutsDialog::KBShortcutsDialog()
    : DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Keyboard Shortcuts")),
      wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) // | wxRESIZE_BORDER)
{
    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));

    // fonts
    const wxFont& font = wxGetApp().normal_font();
    const wxFont& bold_font = wxGetApp().bold_font();
    SetFont(font);

    auto main_sizer = new wxBoxSizer(wxVERTICAL);

    main_sizer->Add(create_header(this, bold_font), 0, wxEXPAND | wxALL, 10);

#if BOOK_TYPE == NOTEBOOK_TOP
    wxNotebook* book = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
#elif BOOK_TYPE == NOTEBOOK_LEFT
    wxNotebook* book = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT);
#elif BOOK_TYPE == LISTBOOK_TOP
    wxListbook* book = new wxListbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLB_TOP);
#elif BOOK_TYPE == LISTBOOK_LEFT
    wxListbook* book = new wxListbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLB_LEFT);
#elif BOOK_TYPE == TOOLBOOK
    wxToolbook* book = new wxToolbook(this, wxID_ANY);
#elif BOOK_TYPE == CHOICEBOOK
    wxChoicebook* book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxCHB_TOP);
#endif // BOOK_TYPE
main_sizer->Add(book, 1, wxEXPAND | wxALL, 10);

    fill_shortcuts();
    for (size_t i = 0; i < m_full_shortcuts.size(); ++i)
    {
        book->AddPage(create_page(book, m_full_shortcuts[i], font, bold_font), m_full_shortcuts[i].first, i == 0);
    }

    wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK);
    this->SetEscapeId(wxID_OK);
    main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 10);

    SetSizer(main_sizer);
    main_sizer->SetSizeHints(this);
}

void KBShortcutsDialog::on_dpi_changed(const wxRect& suggested_rect)
{
    m_logo_bmp.msw_rescale();

    for (wxStaticBitmap* bmp : m_head_bitmaps)
        bmp->SetBitmap(m_logo_bmp.bmp());

    const int em = em_unit();

    msw_buttons_rescale(this, em, { wxID_OK });

    Layout();
    Fit();
    Refresh();
}

void KBShortcutsDialog::fill_shortcuts()
{
    const std::string& ctrl = GUI::shortkey_ctrl_prefix();
    const std::string& alt = GUI::shortkey_alt_prefix();

    Shortcuts commands_shortcuts = {
        // File
        { ctrl + "N", L("New project, clear plater") },
        { ctrl + "O", L("Open project STL/OBJ/AMF/3MF with config, clear plater") },
        { ctrl + "S", L("Save project (3mf)") },
        { ctrl + alt + "S", L("Save project as (3mf)") },
        { ctrl + "R", L("(Re)slice") },
        // File>Import
        { ctrl + "I", L("Import STL/OBJ/AMF/3MF without config, keep plater") },
        { ctrl + "L", L("Import Config from ini/amf/3mf/gcode") },
        { ctrl + alt + "L", L("Load Config from ini/amf/3mf/gcode and merge") },
        // File>Export
        { ctrl + "G", L("Export G-code") },
        { ctrl + "Shift+" + "G", L("Send G-code") },
        { ctrl + "E", L("Export config") },
        // Edit
        { ctrl + "A", L("Select all objects") },
        { "Esc", L("Deselect all") },
        { "Del", L("Delete selected") },
        { ctrl + "Del", L("Delete all") },
        { ctrl + "Z", L("Undo") },
        { ctrl + "Y", L("Redo") },
        { ctrl + "C", L("Copy to clipboard") },
        { ctrl + "V", L("Paste from clipboard") },
        { "F5", L("Reload plater from disk") },
        // Window
        { ctrl + "1", L("Select Plater Tab") },
        { ctrl + "2", L("Select Print Settings Tab") },
        { ctrl + "3", L("Select Filament Settings Tab") },
        { ctrl + "4", L("Select Printer Settings Tab") },
        { ctrl + "5", L("Switch to 3D") },
        { ctrl + "6", L("Switch to Preview") },
        { ctrl + "J", L("Print host upload queue") },
        // View
        { "0-6", L("Camera view") },
#if ENABLE_SHOW_SCENE_LABELS
        { "E", L("Show/Hide object/instance labels") },
#endif // ENABLE_SHOW_SCENE_LABELS
        // Configuration
        { ctrl + "P", L("Preferences") },
        // Help
        { "?", L("Show keyboard shortcuts list") }
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Commands")), commands_shortcuts));

    Shortcuts plater_shortcuts = {
        { "A", L("Arrange") },
        { "Shift+A", L("Arrange selection") },
        { "+", L("Add Instance of the selected object") },
        { "-", L("Remove Instance of the selected object") },
        { ctrl, L("Press to select multiple object\nor move multiple object with mouse") },
        { "Shift+", L("Press to activate selection rectangle") },
        { alt, L("Press to activate deselection rectangle") },
        { L("Arrow Up"), L("Move selection 10 mm in positive Y direction") },
        { L("Arrow Down"), L("Move selection 10 mm in negative Y direction") },
        { L("Arrow Left"), L("Move selection 10 mm in negative X direction") },
        { L("Arrow Right"), L("Move selection 10 mm in positive X direction") },
        { std::string("Shift+") + L("Any arrow"), L("Movement step set to 1 mm") },
        { ctrl + L("Any arrow"), L("Movement in camera space") },
        { L("Page Up"), L("Rotate selection 45 degrees CCW") },
        { L("Page Down"), L("Rotate selection 45 degrees CW") },
        { "M", L("Gizmo move") },
        { "S", L("Gizmo scale") },
        { "R", L("Gizmo rotate") },
        { "C", L("Gizmo cut") },
        { "F", L("Gizmo Place face on bed") },
        { "H", L("Gizmo SLA hollow") },
        { "L", L("Gizmo SLA support points") },
        { "Esc", L("Unselect gizmo or clear selection") },
        { "K", L("Change camera type (perspective, orthographic)") },
        { "B", L("Zoom to Bed") },
        { "Z", L("Zoom to selected object\nor all objects in scene, if none selected") },
        { "I", L("Zoom in") },
        { "O", L("Zoom out") },
        { ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") }
#if ENABLE_RENDER_PICKING_PASS
        // Don't localize debugging texts.
        , { "T", "Toggle picking pass texture rendering on/off" }
#endif // ENABLE_RENDER_PICKING_PASS
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Plater")), plater_shortcuts));

    Shortcuts gizmos_shortcuts = {
        { "Shift+", L("Press to to snap by 5% in Gizmo scale\nor to snap by 1mm in Gizmo move") },
        { "F", L("Scale selection to fit print volume\nin Gizmo scale") },
        { ctrl, L("Press to activate one direction scaling in Gizmo scale") },
        { alt, L("Press to scale (in Gizmo scale) or rotate (in Gizmo rotate)\nselected objects around their own center") },
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Gizmos")), gizmos_shortcuts));

    Shortcuts preview_shortcuts = {
        { L("Arrow Up"), L("Upper Layer") },
        { L("Arrow Down"), L("Lower Layer") },
        { "U", L("Upper Layer") },
        { "D", L("Lower Layer") },
        { "L", L("Show/Hide Legend") }
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Preview")), preview_shortcuts));

    Shortcuts layers_slider_shortcuts = {
        { L("Arrow Up"), L("Move current slider thumb Up") },
        { L("Arrow Down"), L("Move current slider thumb Down") },
        { L("Arrow Left"), L("Set upper thumb to current slider thumb") },
        { L("Arrow Right"), L("Set lower thumb to current slider thumb") },
        { "+", L("Add color change marker for current layer") },
        { "-", L("Delete color change marker for current layer") }
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Layers Slider")), layers_slider_shortcuts));
}

wxPanel* KBShortcutsDialog::create_header(wxWindow* parent, const wxFont& bold_font)
{
    wxPanel* panel = new wxPanel(parent);
    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);

    wxFont header_font = bold_font;
#ifdef __WXOSX__
    header_font.SetPointSize(14);
#else
    header_font.SetPointSize(bold_font.GetPointSize() + 2);
#endif // __WXOSX__

    sizer->AddStretchSpacer();

    // logo
    m_logo_bmp = ScalableBitmap(this, "PrusaSlicer_32px.png", 32);
    m_head_bitmaps.push_back(new wxStaticBitmap(panel, wxID_ANY, m_logo_bmp.bmp()));
    sizer->Add(m_head_bitmaps.back(), 0, wxEXPAND | wxLEFT | wxRIGHT, 10);

    // text
    wxStaticText* text = new wxStaticText(panel, wxID_ANY, _(L("Keyboard shortcuts")));
    text->SetFont(header_font);
    sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL);

    sizer->AddStretchSpacer();

    panel->SetSizer(sizer);
    return panel;
}

wxPanel* KBShortcutsDialog::create_page(wxWindow* parent, const std::pair<wxString, Shortcuts>& shortcuts, const wxFont& font, const wxFont& bold_font)
{
    static const int max_items_per_column = 20;
    int columns_count = 2 * (1 + (int)shortcuts.second.size() / max_items_per_column);

    wxPanel* page = new wxPanel(parent);
#if (BOOK_TYPE == LISTBOOK_TOP) || (BOOK_TYPE == LISTBOOK_LEFT)
    wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, page, " " + shortcuts.first + " ");
    sizer->GetStaticBox()->SetFont(bold_font);
#else
    wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
#endif // BOOK_TYPE

    wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(columns_count, 5, 15);

    for (const auto& [shortcut, description] : shortcuts.second)
    {
        auto key = new wxStaticText(page, wxID_ANY, _(shortcut));
        key->SetFont(bold_font);
        grid_sizer->Add(key, 0, wxALIGN_CENTRE_VERTICAL);

        auto desc = new wxStaticText(page, wxID_ANY, _(description));
        desc->SetFont(font);
        grid_sizer->Add(desc, 0, wxALIGN_CENTRE_VERTICAL);
    }

    sizer->Add(grid_sizer, 1, wxEXPAND | wxALL, 10);
    page->SetSizer(sizer);
    return page;
}

} // namespace GUI
} // namespace Slic3r
<commit_msg>Rework of keyboard shortcut dialog layout -> use wxNotebook on top<commit_after>#include "KBShortcutsDialog.hpp"
#include "I18N.hpp"
#include "libslic3r/Utils.hpp"
#include "GUI.hpp"
#include <wx/scrolwin.h>
#include <wx/display.h>
#include "GUI_App.hpp"
#include "wxExtensions.hpp"

#define NOTEBOOK_TOP 1
#define NOTEBOOK_LEFT 2
#define LISTBOOK_TOP 3
#define LISTBOOK_LEFT 4
#define TOOLBOOK 5
#define CHOICEBOOK 6
#define BOOK_TYPE NOTEBOOK_TOP

#if (BOOK_TYPE == NOTEBOOK_TOP) || (BOOK_TYPE == NOTEBOOK_LEFT)
#include <wx/notebook.h>
#elif (BOOK_TYPE == LISTBOOK_TOP) || (BOOK_TYPE == LISTBOOK_LEFT)
#include <wx/listbook.h>
#elif BOOK_TYPE == TOOLBOOK
#include <wx/toolbook.h>
#elif BOOK_TYPE == CHOICEBOOK
#include <wx/choicebk.h>
#endif // BOOK_TYPE

namespace Slic3r {
namespace GUI {

KBShortcutsDialog::KBShortcutsDialog()
    : DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Keyboard Shortcuts")),
      wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) // | wxRESIZE_BORDER)
{
    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));

    // fonts
    const wxFont& font = wxGetApp().normal_font();
    const wxFont& bold_font = wxGetApp().bold_font();
    SetFont(font);

    auto main_sizer = new wxBoxSizer(wxVERTICAL);

    main_sizer->Add(create_header(this, bold_font), 0, wxEXPAND | wxALL, 10);

#if BOOK_TYPE == NOTEBOOK_TOP
    wxNotebook* book = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
#elif BOOK_TYPE == NOTEBOOK_LEFT
    wxNotebook* book = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_LEFT);
#elif BOOK_TYPE == LISTBOOK_TOP
    wxListbook* book = new wxListbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLB_TOP);
#elif BOOK_TYPE == LISTBOOK_LEFT
    wxListbook* book = new wxListbook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLB_LEFT);
#elif BOOK_TYPE == TOOLBOOK
    wxToolbook* book = new wxToolbook(this, wxID_ANY);
#elif BOOK_TYPE == CHOICEBOOK
    wxChoicebook* book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxCHB_TOP);
#endif // BOOK_TYPE
main_sizer->Add(book, 1, wxEXPAND | wxALL, 10);

    fill_shortcuts();
    for (size_t i = 0; i < m_full_shortcuts.size(); ++i)
    {
        book->AddPage(create_page(book, m_full_shortcuts[i], font, bold_font), m_full_shortcuts[i].first, i == 0);
    }

    wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK);
    this->SetEscapeId(wxID_OK);
    main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 10);

    SetSizer(main_sizer);
    main_sizer->SetSizeHints(this);
}

void KBShortcutsDialog::on_dpi_changed(const wxRect& suggested_rect)
{
    m_logo_bmp.msw_rescale();

    for (wxStaticBitmap* bmp : m_head_bitmaps)
        bmp->SetBitmap(m_logo_bmp.bmp());

    const int em = em_unit();

    msw_buttons_rescale(this, em, { wxID_OK });

    Layout();
    Fit();
    Refresh();
}

void KBShortcutsDialog::fill_shortcuts()
{
    const std::string& ctrl = GUI::shortkey_ctrl_prefix();
    const std::string& alt = GUI::shortkey_alt_prefix();

    Shortcuts commands_shortcuts = {
        // File
        { ctrl + "N", L("New project, clear plater") },
        { ctrl + "O", L("Open project STL/OBJ/AMF/3MF with config, clear plater") },
        { ctrl + "S", L("Save project (3mf)") },
        { ctrl + alt + "S", L("Save project as (3mf)") },
        { ctrl + "R", L("(Re)slice") },
        // File>Import
        { ctrl + "I", L("Import STL/OBJ/AMF/3MF without config, keep plater") },
        { ctrl + "L", L("Import Config from ini/amf/3mf/gcode") },
        { ctrl + alt + "L", L("Load Config from ini/amf/3mf/gcode and merge") },
        // File>Export
        { ctrl + "G", L("Export G-code") },
        { ctrl + "Shift+" + "G", L("Send G-code") },
        { ctrl + "E", L("Export config") },
        // Edit
        { ctrl + "A", L("Select all objects") },
        { "Esc", L("Deselect all") },
        { "Del", L("Delete selected") },
        { ctrl + "Del", L("Delete all") },
        { ctrl + "Z", L("Undo") },
        { ctrl + "Y", L("Redo") },
        { ctrl + "C", L("Copy to clipboard") },
        { ctrl + "V", L("Paste from clipboard") },
        { "F5", L("Reload plater from disk") },
        // Window
        { ctrl + "1", L("Select Plater Tab") },
        { ctrl + "2", L("Select Print Settings Tab") },
        { ctrl + "3", L("Select Filament Settings Tab") },
        { ctrl + "4", L("Select Printer Settings Tab") },
        { ctrl + "5", L("Switch to 3D") },
        { ctrl + "6", L("Switch to Preview") },
        { ctrl + "J", L("Print host upload queue") },
        // View
        { "0-6", L("Camera view") },
#if ENABLE_SHOW_SCENE_LABELS
        { "E", L("Show/Hide object/instance labels") },
#endif // ENABLE_SHOW_SCENE_LABELS
        // Configuration
        { ctrl + "P", L("Preferences") },
        // Help
        { "?", L("Show keyboard shortcuts list") }
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Commands")), commands_shortcuts));

    Shortcuts plater_shortcuts = {
        { "A", L("Arrange") },
        { "Shift+A", L("Arrange selection") },
        { "+", L("Add Instance of the selected object") },
        { "-", L("Remove Instance of the selected object") },
        { ctrl, L("Press to select multiple object\nor move multiple object with mouse") },
        { "Shift+", L("Press to activate selection rectangle") },
        { alt, L("Press to activate deselection rectangle") },
        { L("Arrow Up"), L("Move selection 10 mm in positive Y direction") },
        { L("Arrow Down"), L("Move selection 10 mm in negative Y direction") },
        { L("Arrow Left"), L("Move selection 10 mm in negative X direction") },
        { L("Arrow Right"), L("Move selection 10 mm in positive X direction") },
        { std::string("Shift+") + L("Any arrow"), L("Movement step set to 1 mm") },
        { ctrl + L("Any arrow"), L("Movement in camera space") },
        { L("Page Up"), L("Rotate selection 45 degrees CCW") },
        { L("Page Down"), L("Rotate selection 45 degrees CW") },
        { "M", L("Gizmo move") },
        { "S", L("Gizmo scale") },
        { "R", L("Gizmo rotate") },
        { "C", L("Gizmo cut") },
        { "F", L("Gizmo Place face on bed") },
        { "H", L("Gizmo SLA hollow") },
        { "L", L("Gizmo SLA support points") },
        { "Esc", L("Unselect gizmo or clear selection") },
        { "K", L("Change camera type (perspective, orthographic)") },
        { "B", L("Zoom to Bed") },
        { "Z", L("Zoom to selected object\nor all objects in scene, if none selected") },
        { "I", L("Zoom in") },
        { "O", L("Zoom out") },
        { ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") }
#if ENABLE_RENDER_PICKING_PASS
        // Don't localize debugging texts.
        , { "T", "Toggle picking pass texture rendering on/off" }
#endif // ENABLE_RENDER_PICKING_PASS
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Plater")), plater_shortcuts));

    Shortcuts gizmos_shortcuts = {
        { "Shift+", L("Press to to snap by 5% in Gizmo scale\nor to snap by 1mm in Gizmo move") },
        { "F", L("Scale selection to fit print volume\nin Gizmo scale") },
        { ctrl, L("Press to activate one direction scaling in Gizmo scale") },
        { alt, L("Press to scale (in Gizmo scale) or rotate (in Gizmo rotate)\nselected objects around their own center") },
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Gizmos")), gizmos_shortcuts));

    Shortcuts preview_shortcuts = {
        { L("Arrow Up"), L("Upper Layer") },
        { L("Arrow Down"), L("Lower Layer") },
        { "U", L("Upper Layer") },
        { "D", L("Lower Layer") },
        { "L", L("Show/Hide Legend") }
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Preview")), preview_shortcuts));

    Shortcuts layers_slider_shortcuts = {
        { L("Arrow Up"), L("Move current slider thumb Up") },
        { L("Arrow Down"), L("Move current slider thumb Down") },
        { L("Arrow Left"), L("Set upper thumb to current slider thumb") },
        { L("Arrow Right"), L("Set lower thumb to current slider thumb") },
        { "+", L("Add color change marker for current layer") },
        { "-", L("Delete color change marker for current layer") }
    };

    m_full_shortcuts.push_back(std::make_pair(_(L("Layers Slider")), layers_slider_shortcuts));
}

wxPanel* KBShortcutsDialog::create_header(wxWindow* parent, const wxFont& bold_font)
{
    wxPanel* panel = new wxPanel(parent);
    wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);

    wxFont header_font = bold_font;
#ifdef __WXOSX__
    header_font.SetPointSize(14);
#else
    header_font.SetPointSize(bold_font.GetPointSize() + 2);
#endif // __WXOSX__

    sizer->AddStretchSpacer();

    // logo
    m_logo_bmp = ScalableBitmap(this, "PrusaSlicer_32px.png", 32);
    m_head_bitmaps.push_back(new wxStaticBitmap(panel, wxID_ANY, m_logo_bmp.bmp()));
    sizer->Add(m_head_bitmaps.back(), 0, wxEXPAND | wxLEFT | wxRIGHT, 10);

    // text
    wxStaticText* text = new wxStaticText(panel, wxID_ANY, _(L("Keyboard shortcuts")));
    text->SetFont(header_font);
    sizer->Add(text, 0, wxALIGN_CENTER_VERTICAL);

    sizer->AddStretchSpacer();

    panel->SetSizer(sizer);
    return panel;
}

wxPanel* KBShortcutsDialog::create_page(wxWindow* parent, const std::pair<wxString, Shortcuts>& shortcuts, const wxFont& font, const wxFont& bold_font)
{
    static const int max_items_per_column = 20;
    int columns_count = 2 * (1 + (int)shortcuts.second.size() / max_items_per_column);

    wxPanel* page = new wxPanel(parent);
#if (BOOK_TYPE == LISTBOOK_TOP) || (BOOK_TYPE == LISTBOOK_LEFT)
    wxStaticBoxSizer* sizer = new wxStaticBoxSizer(wxVERTICAL, page, " " + shortcuts.first + " ");
    sizer->GetStaticBox()->SetFont(bold_font);
#else
    wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
#endif // BOOK_TYPE

    wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(columns_count, 5, 15);

    for (const auto& [shortcut, description] : shortcuts.second)
    {
        auto key = new wxStaticText(page, wxID_ANY, _(shortcut));
        key->SetFont(bold_font);
        grid_sizer->Add(key, 0, wxALIGN_CENTRE_VERTICAL);

        auto desc = new wxStaticText(page, wxID_ANY, _(description));
        desc->SetFont(font);
        grid_sizer->Add(desc, 0, wxALIGN_CENTRE_VERTICAL);
    }

    sizer->Add(grid_sizer, 1, wxEXPAND | wxALL, 10);
    page->SetSizer(sizer);
    return page;
}

} // namespace GUI
} // namespace Slic3r
<|endoftext|>


<commit_before>//This is the program that is supposed to pull together the resources of the
  //various pluggins and compile them before runtime

#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <vector>
using namespace std;

//c++17
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

//Can paint in various colors on linux
/* Short Color Reference:
 * -30 - Normal
 * -25 - Blink
 * 1 - Red
 * 2 - Green
 * 3 - Yellow
 * 4 - Blue
 */
#ifdef _WIN32
  void startPaint(const int color) {}
  void endPaint() {}
#else
  void startPaint(const int color)
  {
    cout << "\033[" << color+30 << "m";
  }
  void endPaint()
  {
    cout << "\033[0m";
  }
#endif

//Open a file
void readFile(string filename) //Copy, so can be changed
{
  ifstream file(filename);
  while (!file)
  {
    //Prompt for another file, or not
    char tryAgain;
    startPaint(1);
    cerr << filename << " failed to open. Would you like to try another file? (Y/n) ";
    endPaint();
    cin >> tryAgain;

    //If no, exit program
    if (tryAgain == 'n' || tryAgain == 'N')
    {
      startPaint(1);
      cerr << "No alternate file provided. Cannot continue, closing program.\n";
      endPaint();
      exit(1);
    }

    //Otherwise, get a new file
    cout << "Filename: ";
    cin >> filename;
    file.open(filename);
  }
  file.close(); //temporary ////////////////////////////////////////////////////
}

//Make sure that what the calle is looking at is a real plugin
  //does not check if the plugin works, in any fashion
bool verifyPlugin(fs::file_status entry)
{
  //Just a stack of if statements that need to be true
  if(fs::is_directory(entry)) //Makes sure it's actually a folder
    return true;
  return false;
}

//Get a list of all the availible plugins
vector<string> readPlugins()
{
  //Build a vector<string> of all availible plugins
  vector<string> plugins;
  for (auto& entry : fs::directory_iterator("Plugins/"))
  {
    //Verifies that this is a conforming plugin
    if(verifyPlugin(entry.symlink_status()))
    {
      //Gets the string from the directory_entries, removing "Plugins/"
      string sliceString = entry.path();
      plugins.push_back(sliceString.substr(8)); // 8 = len("Plugins/")
    }
  }

  //Return the result back!
  return plugins;
}

//The help commands=
void help()
{
  string helpScript =
  "-enable <pluginName>  - enables the plugin with specified name\n"
  "-disable <pluginName> - disables the plugin with specified name\n"
  "list \t- lists all plugins\n"
  "-listD\t- lists disabled plugins\n"
  "-listE\t- lists enabled plugins\n"
  "-compile\t- compiles the program\n"
  "-save \t- saves the list of enabled plugins\n"
  "exit \t- exits the program, discarding unsaved changes\n"
  "help \t- lists this menu\n"
  "\n"
  "";

  cout << helpScript;
}

int main()
{
  //Initialize the list of plugins
  vector<string> plugins = readPlugins();

  //Change these two to be sets?
  //Initialize list of plugins that have already been enabled
  vector<string> enabledPlugins;// = readFile(Plugins/enabledPlugins.txt);
  //Initialize list of plugins that have yet to be enabled,
    //the difference of the last two lists
  vector<string> disabledPlugins;// = readFile(Plugins/enabledPlugins.txt);

  //User prompt
  startPaint(3);
  cout << "This is the program that will allow you to choose what plugins to"
          " use, and can compile the program for you.\nFor help, type 'help'\n";
  endPaint();

  //A simple command prompt to interact with the compiler
  string command = "";

  //Write out prompt, in green
  startPaint(2);
  cout << "command: ";
  endPaint();

  //Command prompt, options detailed in the help fuction
  while(cin >> command && command != "exit")
  {
    if (command == "enable")
      cin >> command;

    else if (command == "disable")
      cin >> command;

    else if (command == "list")
      for(string& pluginName : plugins)
        cout << pluginName << endl;

    else if (command == "listD")
      for(string& pluginName : disabledPlugins)
        cout << pluginName << endl;

    else if (command == "listE")
      for(string& pluginName : enabledPlugins)
        cout << pluginName << endl;

    else if (command == "compile") {}

    else if (command == "save") {}

    else if(command == "exit")
    break;

    else if(command == "help")
      help();

    else
      cerr << "Unknown command.\n";

    //Write out prompt, in green
    startPaint(2);
    cout << "command: ";
    endPaint();

    //Clear any extra characters in the cin stream
    cin.ignore(1000,'\n');
    cin.clear();
  }
}
<commit_msg>Added Commands<commit_after>//This is the program that is supposed to pull together the resources of the
  //various pluggins and compile them before runtime

#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <vector>
#include <unordered_set>
using namespace std;

//c++17
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

//Can paint in various colors on linux
/* Short Color Reference:
 * -30 - Normal
 * -25 - Blink
 * 1 - Red
 * 2 - Green
 * 3 - Yellow
 * 4 - Blue
 */
#ifdef _WIN32
  void startPaint(const int color) {}
  void endPaint() {}
#else
  void startPaint(const int color)
  {
    cout << "\033[" << color+30 << "m";
  }
  void endPaint()
  {
    cout << "\033[0m";
  }
#endif

//Open a file
void readFile(string filename) //Copy, so can be changed
{
  ifstream file(filename);
  while (!file)
  {
    //Prompt for another file, or not
    char tryAgain;
    startPaint(1);
    cerr << filename << " failed to open. Would you like to try another file? (Y/n) ";
    endPaint();
    cin >> tryAgain;

    //If no, exit program
    if (tryAgain == 'n' || tryAgain == 'N')
    {
      startPaint(1);
      cerr << "No alternate file provided. Cannot continue, closing program.\n";
      endPaint();
      exit(1);
    }

    //Otherwise, get a new file
    cout << "Filename: ";
    cin >> filename;
    file.open(filename);
  }
  file.close(); //temporary ////////////////////////////////////////////////////
}

//Make sure that what the calle is looking at is a real plugin
  //does not check if the plugin works, in any fashion
bool verifyPlugin(fs::file_status entry)
{
  //Just a stack of if statements that need to be true
  if(fs::is_directory(entry)) //Makes sure it's actually a folder
    return true;
  return false;
}

//Get a list of all the availible plugins
vector<string> readPlugins()
{
  //Build a vector<string> of all availible plugins
  vector<string> plugins;
  for (auto& entry : fs::directory_iterator("Plugins/"))
  {
    //Verifies that this is a conforming plugin
    if(verifyPlugin(entry.symlink_status()))
    {
      //Gets the string from the directory_entries, removing "Plugins/"
      string sliceString = entry.path();
      plugins.push_back(sliceString.substr(8)); // 8 = len("Plugins/")
    }
  }

  //Return the result back!
  return plugins;
}

//The help commands=
void help()
{
  string helpScript =
  "enable <pluginName>  - enables the plugin with specified name\n"
  "disable <pluginName> - disables the plugin with specified name\n"
  "list \t- lists all plugins\n"
  "listD\t- lists disabled plugins\n"
  "listE\t- lists enabled plugins\n"
  "-compile\t- compiles the program\n"
  "-save \t- saves the list of enabled plugins\n"
  "exit \t- exits the program, discarding unsaved changes\n"
  "help \t- lists this menu\n"
  "\n"
  "";

  cout << helpScript;
}

int main()
{
  //Initialize the list of plugins
  vector<string> plugins = readPlugins();

  //Initialize list of plugins that have already been enabled
  unordered_set<string> enabledPlugins;// = readFile(Plugins/enabledPlugins.txt);

  //Initialize list of plugins that have yet to be enabled,
    //the difference of the last two lists
  unordered_set<string> disabledPlugins;// = readFile(Plugins/enabledPlugins.txt);
  for (string pluginName : plugins)
    if(enabledPlugins.count(pluginName) == 0)
      disabledPlugins.insert(pluginName);

  //User prompt
  startPaint(3);
  cout << "This is the program that will allow you to choose what plugins to"
          " use, and can compile the program for you.\nFor help, type 'help'\n";
  endPaint();

  //A simple command prompt to interact with the compiler
  string command = "";

  //Write out prompt, in green
  startPaint(2);
  cout << "command: ";
  endPaint();

  //Command prompt, options detailed in the help fuction
  while(cin >> command && command != "exit")
  {
    if (command == "enable")
    {
        //Get name of plugin
        cin >> command;

        //Check if plugin exists
        bool pluginExists = false;
        for (string pluginName : plugins)
          if (pluginName == command)
          {
            pluginExists = true;
            enabledPlugins.insert(command);
            disabledPlugins.erase(command);
            break;
          }
        if (!pluginExists)
          cerr << "The plugin '" << command << "' is not availible.\n";
    }

    else if (command == "disable")
    {
        //Get name of plugin
        cin >> command;

        //Check if plugin exists
        bool pluginExists = false;
        for (string pluginName : plugins)
          if (pluginName == command)
          {
            pluginExists = true;
            disabledPlugins.insert(command);
            enabledPlugins.erase(command);
            break;
          }
        if (!pluginExists)
          cerr << "The plugin '" << command << "' is not availible.\n";
    }

    else if (command == "list")
    {
      for(string& pluginName : plugins)
        cout << pluginName << endl;
    }

    else if (command == "listD")
    {
      for(string pluginName : disabledPlugins)
        cout << pluginName << endl;
    }

    else if (command == "listE")
    {
      for(string pluginName : enabledPlugins)
        cout << pluginName << endl;
    }

    else if (command == "compile")
    {

    }

    else if (command == "save")
    {

    }

    else if(command == "exit")
    {
        break;
    }

    else if(command == "help")
    {
        help();
    }

    else
    {
        cerr << "Unknown command.\n";
    }

    //Write out prompt, in green
    startPaint(2);
    cout << "command: ";
    endPaint();

    //Clear any extra characters in the cin stream
    cin.ignore(1000,'\n');
    cin.clear();
  }
}
<|endoftext|>


<commit_before>#include "surface_waveletDecomposition.h"

#include "mapHandler.h"

#define NORMALE 5

namespace CGoGN
{

namespace SCHNApps
{

bool Surface_WaveletDecomposition_Plugin::enable()
{
    m_waveletDecompositionDialog = new Dialog_Surface_WaveletDecomposition(m_schnapps);

    m_waveletDecompositionAction = new QAction("Wavelet Decomposition", this);

    m_schnapps->addMenuAction(this, "Surface;Wavelet Decomposition", m_waveletDecompositionAction);

    m_colorPerVertexShader = new CGoGN::Utils::ShaderColorPerVertex();
    registerShader(m_colorPerVertexShader);

    m_positionVBO = new Utils::VBO();
    m_colorVBO = new Utils::VBO();

    m_toDraw = false;

    connect(m_waveletDecompositionAction, SIGNAL(triggered()), this, SLOT(openWaveletDecompositionDialog()));

    connect(m_waveletDecompositionDialog->button_cancel, SIGNAL(clicked()), this, SLOT(closeWaveletDecompositionDialog()));
    connect(m_waveletDecompositionDialog->button_decompose, SIGNAL(clicked()), this, SLOT(decomposeFromDialog()));
    connect(m_waveletDecompositionDialog->button_saveImages, SIGNAL(clicked()), this, SLOT(saveImagesFromDialog()));

    return true;
}

void Surface_WaveletDecomposition_Plugin::disable()
{
    delete m_colorPerVertexShader;
    delete m_positionVBO;
    delete m_colorVBO;

    disconnect(m_waveletDecompositionAction, SIGNAL(triggered()), this, SLOT(openWaveletDecompositionDialog()));

    disconnect(m_waveletDecompositionDialog->button_cancel, SIGNAL(clicked()), this, SLOT(closeWaveletDecompositionDialog()));
    disconnect(m_waveletDecompositionDialog->button_decompose, SIGNAL(clicked()), this, SLOT(decomposeFromDialog()));
    disconnect(m_waveletDecompositionDialog->button_saveImages, SIGNAL(clicked()), this, SLOT(saveImagesFromDialog()));
}

void Surface_WaveletDecomposition_Plugin::drawMap(View* view, MapHandlerGen *map)
{
//    if(m_toDraw && m_schnapps->getSelectedView() == view)
//    {
//        //If VBO are initialized
//        glPolygonMode(GL_FRONT, GL_FILL);
//        glEnable(GL_LIGHTING);
//        glEnable(GL_POLYGON_OFFSET_FILL);
//        m_colorPerVertexShader->setAttributePosition(m_positionVBO);
//        m_colorPerVertexShader->setAttributeColor(m_colorVBO);
//        m_colorPerVertexShader->setOpacity(1.0);
//        map->draw(m_colorPerVertexShader, CGoGN::Algo::Render::GL2::TRIANGLES);
//        glDisable(GL_POLYGON_OFFSET_FILL);
//    }
}

void Surface_WaveletDecomposition_Plugin::openWaveletDecompositionDialog()
{
    m_waveletDecompositionDialog->show();
}

void Surface_WaveletDecomposition_Plugin::closeWaveletDecompositionDialog()
{
    m_waveletDecompositionDialog->close();
}

void Surface_WaveletDecomposition_Plugin::decomposeFromDialog()
{
    QList<QListWidgetItem*> currentItems = m_waveletDecompositionDialog->list_maps->selectedItems();
    if(!currentItems.empty() && m_decomposition)
    {
        const QString& mapName = currentItems[0]->text();

        MapHandler<PFP2>* mh_map = static_cast<MapHandler<PFP2>*>(m_schnapps->getMap(mapName));

        if(mh_map && m_decomposition)
        {
            PFP2::MAP* map = mh_map->getMap();

            //We search the last level of decomposition
            Decomposition* decomposition = m_decomposition;
            while(decomposition->getChild())
            {
                decomposition = decomposition->getChild();
            }

            while(decomposition->getCorrectionX()>2 && decomposition->getCorrectionY()>2)
            {
                //If a decomposition is still feasible
                decomposition = decomposition->addChild();

                Decomposition* parent = decomposition->getParent();

                QImage& image_parent = parent->getImage();

                int image_width = (image_parent.width()+image_parent.width()%2)/2;
                int image_height = (image_parent.height()+image_parent.height()%2)/2;

                //Creation of a new image composed of the even of parent image
                QImage image(image_width, image_height, image_parent.format());

                for(int i = 0; i < image_width; ++i)
                {
                    for(int j = 0; j < image_height; ++j)
                    {
                        image.setPixel(i, j, image_parent.pixel(i*2, j*2));
                    }
                }

                decomposition->setImage(image);

                //Creation of a matrix composed of the difference between odd of parent image and prediction value (linear interpolation)
                QRgb cur_pixel;
                NQRgb hori_pixel, vert_pixel;
                for(int i = 0; i < image_parent.width(); ++i)
                {
                    for(int j = 0; j < image_parent.height(); ++j)
                    {
                        cur_pixel = image_parent.pixel(i, j);

                        hori_pixel = NQRgb();
                        vert_pixel = NQRgb();

                        if(i%2==1)
                        {
                            if(i==image_parent.width()-1)
                            {
                                //Mirror effect at the border of the image
                                hori_pixel.setRed(qRed(cur_pixel) - qRed(image_parent.pixel(i-1,j)));
                                hori_pixel.setGreen(qGreen(cur_pixel) - qGreen(image_parent.pixel(i-1,j)));
                                hori_pixel.setBlue(qBlue(cur_pixel) - qBlue(image_parent.pixel(i-1,j)));
                            }
                            else
                            {
                                hori_pixel.setRed(qRed(cur_pixel) - 0.5*(qRed(image_parent.pixel(i-1,j))+qRed(image_parent.pixel(i+1,j))));
                                hori_pixel.setGreen(qGreen(cur_pixel) - 0.5*(qGreen(image_parent.pixel(i-1,j))+qGreen(image_parent.pixel(i+1,j))));
                                hori_pixel.setBlue(qBlue(cur_pixel) - 0.5*(qBlue(image_parent.pixel(i-1,j))+qBlue(image_parent.pixel(i+1,j))));
                            }
                            //Odd column number
                            if(j%2==1)
                            {
                                //Odd line number
                                if(j==image_parent.height()-1)
                                {
                                    //Mirror effect at the border of the image
                                    vert_pixel.setRed(qRed(cur_pixel) - qRed(image_parent.pixel(i,j-1)));
                                    vert_pixel.setGreen(qGreen(cur_pixel) - qGreen(image_parent.pixel(i,j-1)));
                                    vert_pixel.setBlue(qBlue(cur_pixel) - qBlue(image_parent.pixel(i,j-1)));
                                }
                                else
                                {
                                    vert_pixel.setRed(qRed(cur_pixel) - 0.5*(qRed(image_parent.pixel(i,j-1))+qRed(image_parent.pixel(i,j+1))));
                                    vert_pixel.setGreen(qGreen(cur_pixel) - 0.5*(qGreen(image_parent.pixel(i,j-1))+qGreen(image_parent.pixel(i,j+1))));
                                    vert_pixel.setBlue(qBlue(cur_pixel) - 0.5*(qBlue(image_parent.pixel(i,j-1))+qBlue(image_parent.pixel(i,j+1))));
                                }
                            }
                        }
                        else
                        {
                            if(j%2==1)
                            {
                                //Odd line number
                                if(j==image_parent.height()-1)
                                {
                                    //Mirror effect at the border of the image
                                    vert_pixel.setRed(qRed(cur_pixel) - qRed(image_parent.pixel(i,j-1)));
                                    vert_pixel.setGreen(qGreen(cur_pixel) - qGreen(image_parent.pixel(i,j-1)));
                                    vert_pixel.setBlue(qBlue(cur_pixel) - qBlue(image_parent.pixel(i,j-1)));
                                }
                                else
                                {
                                    vert_pixel.setRed(qRed(cur_pixel) - 0.5*(qRed(image_parent.pixel(i,j-1))+qRed(image_parent.pixel(i,j+1))));
                                    vert_pixel.setGreen(qGreen(cur_pixel) - 0.5*(qGreen(image_parent.pixel(i,j-1))+qGreen(image_parent.pixel(i,j+1))));
                                    vert_pixel.setBlue(qBlue(cur_pixel) - 0.5*(qBlue(image_parent.pixel(i,j-1))+qBlue(image_parent.pixel(i,j+1))));
                                }
                            }
                        }

                        parent->setHorizontalCorrection(i, j, hori_pixel);
                        parent->setVerticalCorrection(i, j, vert_pixel);
                    }
                }
                CGoGNout << "New level of decomposition created" << CGoGNendl;
            }
        }
    }
}

void Surface_WaveletDecomposition_Plugin::saveImagesFromDialog()
{
    QList<QListWidgetItem*> currentItems = m_waveletDecompositionDialog->list_maps->selectedItems();
    if(!currentItems.empty() && m_decomposition)
    {
        const QString& mapName = currentItems[0]->text();

        Decomposition* decomposition = m_decomposition;
        do
        {
            QImage image = decomposition->getImage();
            QString filename("/home/blettere/Projets/Models/Decomposition/");
            filename.append(mapName);
            filename.append("-");
            QString filename2(filename);
            filename.append(QString::number(decomposition->getLevel()));
            filename.append(".png");

            if(!image.save(filename))
            {
                CGoGNerr << "Image '" << filename.toStdString() << "' has not been saved" << CGoGNendl;
            }

            filename2.append(QString::number(decomposition->getLevel()+1));
            filename = filename2;
            filename.append("-horizontalCoherence.png");
            filename2.append("-verticalCoherence.png");

            decomposition = decomposition->getChild();

            if(decomposition)
            {
                QImage image2(decomposition->getCorrectionX(), decomposition->getCorrectionY(), image.format());
                image = QImage(decomposition->getCorrectionX(), decomposition->getCorrectionY(), image2.format());
                NQRgb correction;
                for(int i = 0; i < decomposition->getCorrectionX(); ++i)
                {
                    for(int j = 0; j < decomposition->getCorrectionY(); ++j)
                    {
                        correction = decomposition->getHorizontalCorrection(i, j);
                        image.setPixel(i, j, qRgb(qAbs(correction.getRed()), qAbs(correction.getGreen()), qAbs(correction.getBlue())));
                        correction = decomposition->getVerticalCorrection(i, j);
                        image2.setPixel(i, j, qRgb(qAbs(correction.getRed()), qAbs(correction.getGreen()), qAbs(correction.getBlue())));
                    }
                }

                if(!image.save(filename))
                {
                    CGoGNerr << "Image '" << filename2.toStdString() << "' has not been saved" << CGoGNendl;
                }

                if(!image2.save(filename2))
                {
                    CGoGNerr << "Image '" << filename2.toStdString() << "' has not been saved" << CGoGNendl;
                }
            }
        } while(decomposition);
    }
}

MapHandlerGen* Surface_WaveletDecomposition_Plugin::initializeObject(const QString& view, QString& filename, const bool multiple)
{
    if(!filename.isEmpty())
    {
        QString file = filename.left(filename.lastIndexOf('.'));
        file = file.mid(file.lastIndexOf('/')).remove(0, 1);
        MapHandlerGen* mhg_map = m_schnapps->addMap(file, 2);
        MapHandler<PFP2>* mh_map = static_cast<MapHandler<PFP2>*>(mhg_map);
        PFP2::MAP* map = mh_map->getMap();

        VertexAttribute<PFP2::VEC3, PFP2::MAP> position = mh_map->getAttribute<PFP2::VEC3, VERTEX>("position");
        if(!position.isValid())
        {
            position = mh_map->addAttribute<PFP2::VEC3, VERTEX>("position");
        }

        VertexAttribute <PFP2::VEC3, PFP2::MAP> color = mh_map->getAttribute<PFP2::VEC3, VERTEX>("color");
        if(!color.isValid())
        {
            color = mh_map->addAttribute<PFP2::VEC3, VERTEX>("color");
        }

        QString extension = filename.mid(filename.lastIndexOf('.'));
        extension.toUpper();

        QImage image;
        if(!image.load(filename, extension.toUtf8().constData()))
        {
            CGoGNout << "Image has not been loaded correctly" << CGoGNendl;
            return NULL;
        }

        image = image.convertToFormat(QImage::Format_RGB32);

        int imageX = image.width(), imageY = image.height();

        Algo::Surface::Tilings::Square::Grid<PFP2> grid(*map, imageX-1, imageY-1);
        if(multiple)
        {
            QImage image_parent;
            QString filename_big_parent = filename, filename_parent;

            filename_big_parent.replace(filename_big_parent.size()-5, 1, "0");
            filename_parent.replace(filename_parent.size()-5, 1, file[file.size()-1]);
            //CORRECTION PAIR FAIT PERDRE 1 PIXEL A DROITE

            if(!image_parent.load(filename_big_parent, extension.toUtf8().constData()))
            {
                CGoGNout << "Image has not been loaded correctly" << CGoGNendl;
                return NULL;
            }

            const int level = file[file.size()-1].digitValue();

            grid.embedIntoGrid(position, image_parent.width()-1+(image.width()%2==0?1:0)*level, image_parent.height()-1-(image.height()%2)*level);
        }
        else
        {
            grid.embedIntoGrid(position, imageX-1, imageY-1);
        }

        std::vector<Dart> vDarts = grid.getVertexDarts();

        QRgb pixel;

        for(int i = 0; i < imageX; ++i)
        {
            for(int j = 0; j < imageY; ++j)
            {
                pixel = image.pixel(i,(imageY-j)-1);
                color[vDarts[j*imageX+i]] = PFP2::VEC3(qRed(pixel)/255.f, qGreen(pixel)/255.f, qBlue(pixel)/255.f);
            }
        }

        m_decomposition = new Decomposition(imageX, imageY, 0);

        m_decomposition->setImage(image);

        mh_map->updateBB(position);
        mh_map->notifyAttributeModification(position);
        mh_map->notifyAttributeModification(color);
        mh_map->notifyConnectivityModification();
        m_positionVBO->updateData(position);
        //m_colorVBO->updateData(color);

        m_toDraw = true;

        map->enableQuickTraversal<PFP2::MAP, VERTEX>();

        if(view == m_schnapps->getSelectedView()->getName())
        {
            m_schnapps->getSelectedView()->updateGL();
        }

        return mhg_map;
    }
    return NULL;
}

#ifndef DEBUG
Q_EXPORT_PLUGIN2(Surface_WaveletDecomposition_Plugin, Surface_WaveletDecomposition_Plugin)
#else
Q_EXPORT_PLUGIN2(Surface_WaveletDecomposition_PluginD, Surface_WaveletDecomposition_Plugin)
#endif

} // namespace SCHNApps

} // namespace CGoGN
<commit_msg>[PRESQUE FONCTIONNEL]<commit_after>#include "surface_waveletDecomposition.h"

#include "mapHandler.h"

#define NORMALE 5

namespace CGoGN
{

namespace SCHNApps
{

bool Surface_WaveletDecomposition_Plugin::enable()
{
    m_waveletDecompositionDialog = new Dialog_Surface_WaveletDecomposition(m_schnapps);

    m_waveletDecompositionAction = new QAction("Wavelet Decomposition", this);

    m_schnapps->addMenuAction(this, "Surface;Wavelet Decomposition", m_waveletDecompositionAction);

    m_colorPerVertexShader = new CGoGN::Utils::ShaderColorPerVertex();
    registerShader(m_colorPerVertexShader);

    m_positionVBO = new Utils::VBO();
    m_colorVBO = new Utils::VBO();

    m_toDraw = false;

    connect(m_waveletDecompositionAction, SIGNAL(triggered()), this, SLOT(openWaveletDecompositionDialog()));

    connect(m_waveletDecompositionDialog->button_cancel, SIGNAL(clicked()), this, SLOT(closeWaveletDecompositionDialog()));
    connect(m_waveletDecompositionDialog->button_decompose, SIGNAL(clicked()), this, SLOT(decomposeFromDialog()));
    connect(m_waveletDecompositionDialog->button_saveImages, SIGNAL(clicked()), this, SLOT(saveImagesFromDialog()));

    return true;
}

void Surface_WaveletDecomposition_Plugin::disable()
{
    delete m_colorPerVertexShader;
    delete m_positionVBO;
    delete m_colorVBO;

    disconnect(m_waveletDecompositionAction, SIGNAL(triggered()), this, SLOT(openWaveletDecompositionDialog()));

    disconnect(m_waveletDecompositionDialog->button_cancel, SIGNAL(clicked()), this, SLOT(closeWaveletDecompositionDialog()));
    disconnect(m_waveletDecompositionDialog->button_decompose, SIGNAL(clicked()), this, SLOT(decomposeFromDialog()));
    disconnect(m_waveletDecompositionDialog->button_saveImages, SIGNAL(clicked()), this, SLOT(saveImagesFromDialog()));
}

void Surface_WaveletDecomposition_Plugin::drawMap(View* view, MapHandlerGen *map)
{
//    if(m_toDraw && m_schnapps->getSelectedView() == view)
//    {
//        //If VBO are initialized
//        glPolygonMode(GL_FRONT, GL_FILL);
//        glEnable(GL_LIGHTING);
//        glEnable(GL_POLYGON_OFFSET_FILL);
//        m_colorPerVertexShader->setAttributePosition(m_positionVBO);
//        m_colorPerVertexShader->setAttributeColor(m_colorVBO);
//        m_colorPerVertexShader->setOpacity(1.0);
//        map->draw(m_colorPerVertexShader, CGoGN::Algo::Render::GL2::TRIANGLES);
//        glDisable(GL_POLYGON_OFFSET_FILL);
//    }
}

void Surface_WaveletDecomposition_Plugin::openWaveletDecompositionDialog()
{
    m_waveletDecompositionDialog->show();
}

void Surface_WaveletDecomposition_Plugin::closeWaveletDecompositionDialog()
{
    m_waveletDecompositionDialog->close();
}

void Surface_WaveletDecomposition_Plugin::decomposeFromDialog()
{
    QList<QListWidgetItem*> currentItems = m_waveletDecompositionDialog->list_maps->selectedItems();
    if(!currentItems.empty() && m_decomposition)
    {
        const QString& mapName = currentItems[0]->text();

        MapHandler<PFP2>* mh_map = static_cast<MapHandler<PFP2>*>(m_schnapps->getMap(mapName));

        if(mh_map && m_decomposition)
        {
            PFP2::MAP* map = mh_map->getMap();

            //We search the last level of decomposition
            Decomposition* decomposition = m_decomposition;
            while(decomposition->getChild())
            {
                decomposition = decomposition->getChild();
            }

            while(decomposition->getCorrectionX()>2 && decomposition->getCorrectionY()>2)
            {
                //If a decomposition is still feasible
                decomposition = decomposition->addChild();

                Decomposition* parent = decomposition->getParent();

                QImage& image_parent = parent->getImage();

                int image_width = image_parent.width()/2 + image_parent.width()%2;
                int image_height = image_parent.height()/2 + image_parent.height()%2;

                //Creation of a new image composed of the even of parent image
                QImage image(image_width, image_height, image_parent.format());

                for(int i = 0; i < image_width; ++i)
                {
                    for(int j = 0; j < image_height; ++j)
                    {
                        image.setPixel(i, j, image_parent.pixel(i*2, j*2));
                    }
                }

                decomposition->setImage(image);

                //Creation of a matrix composed of the difference between odd of parent image and prediction value (linear interpolation)
                QRgb cur_pixel;
                NQRgb hori_pixel, vert_pixel;
                for(int i = 0; i < image_parent.width(); ++i)
                {
                    for(int j = 0; j < image_parent.height(); ++j)
                    {
                        cur_pixel = image_parent.pixel(i, j);

                        hori_pixel = NQRgb();
                        vert_pixel = NQRgb();

                        if(i%2==1)
                        {
                            if(i==image_parent.width()-1)
                            {
                                //Mirror effect at the border of the image
                                hori_pixel.setRed(qRed(cur_pixel) - qRed(image_parent.pixel(i-1,j)));
                                hori_pixel.setGreen(qGreen(cur_pixel) - qGreen(image_parent.pixel(i-1,j)));
                                hori_pixel.setBlue(qBlue(cur_pixel) - qBlue(image_parent.pixel(i-1,j)));
                            }
                            else
                            {
                                hori_pixel.setRed(qRed(cur_pixel) - 0.5*(qRed(image_parent.pixel(i-1,j))+qRed(image_parent.pixel(i+1,j))));
                                hori_pixel.setGreen(qGreen(cur_pixel) - 0.5*(qGreen(image_parent.pixel(i-1,j))+qGreen(image_parent.pixel(i+1,j))));
                                hori_pixel.setBlue(qBlue(cur_pixel) - 0.5*(qBlue(image_parent.pixel(i-1,j))+qBlue(image_parent.pixel(i+1,j))));
                            }
                            //Odd column number
                            if(j%2==1)
                            {
                                //Odd line number
                                if(j==image_parent.height()-1)
                                {
                                    //Mirror effect at the border of the image
                                    vert_pixel.setRed(qRed(cur_pixel) - qRed(image_parent.pixel(i,j-1)));
                                    vert_pixel.setGreen(qGreen(cur_pixel) - qGreen(image_parent.pixel(i,j-1)));
                                    vert_pixel.setBlue(qBlue(cur_pixel) - qBlue(image_parent.pixel(i,j-1)));
                                }
                                else
                                {
                                    vert_pixel.setRed(qRed(cur_pixel) - 0.5*(qRed(image_parent.pixel(i,j-1))+qRed(image_parent.pixel(i,j+1))));
                                    vert_pixel.setGreen(qGreen(cur_pixel) - 0.5*(qGreen(image_parent.pixel(i,j-1))+qGreen(image_parent.pixel(i,j+1))));
                                    vert_pixel.setBlue(qBlue(cur_pixel) - 0.5*(qBlue(image_parent.pixel(i,j-1))+qBlue(image_parent.pixel(i,j+1))));
                                }
                            }
                        }
                        else
                        {
                            if(j%2==1)
                            {
                                //Odd line number
                                if(j==image_parent.height()-1)
                                {
                                    //Mirror effect at the border of the image
                                    vert_pixel.setRed(qRed(cur_pixel) - qRed(image_parent.pixel(i,j-1)));
                                    vert_pixel.setGreen(qGreen(cur_pixel) - qGreen(image_parent.pixel(i,j-1)));
                                    vert_pixel.setBlue(qBlue(cur_pixel) - qBlue(image_parent.pixel(i,j-1)));
                                }
                                else
                                {
                                    vert_pixel.setRed(qRed(cur_pixel) - 0.5*(qRed(image_parent.pixel(i,j-1))+qRed(image_parent.pixel(i,j+1))));
                                    vert_pixel.setGreen(qGreen(cur_pixel) - 0.5*(qGreen(image_parent.pixel(i,j-1))+qGreen(image_parent.pixel(i,j+1))));
                                    vert_pixel.setBlue(qBlue(cur_pixel) - 0.5*(qBlue(image_parent.pixel(i,j-1))+qBlue(image_parent.pixel(i,j+1))));
                                }
                            }
                        }

                        parent->setHorizontalCorrection(i, j, hori_pixel);
                        parent->setVerticalCorrection(i, j, vert_pixel);
                    }
                }
                CGoGNout << "New level of decomposition created" << CGoGNendl;
            }
        }
    }
}

void Surface_WaveletDecomposition_Plugin::saveImagesFromDialog()
{
    QList<QListWidgetItem*> currentItems = m_waveletDecompositionDialog->list_maps->selectedItems();
    if(!currentItems.empty() && m_decomposition)
    {
        const QString& mapName = currentItems[0]->text();

        Decomposition* decomposition = m_decomposition;
        do
        {
            QImage image = decomposition->getImage();
            QString filename("/home/blettere/Projets/Models/Decomposition/");
            filename.append(mapName);
            filename.append("-");
            QString filename2(filename);
            filename.append(QString::number(decomposition->getLevel()));
            filename.append(".png");

            if(!image.save(filename))
            {
                CGoGNerr << "Image '" << filename.toStdString() << "' has not been saved" << CGoGNendl;
            }

            filename2.append(QString::number(decomposition->getLevel()+1));
            filename = filename2;
            filename.append("-horizontalCoherence.png");
            filename2.append("-verticalCoherence.png");

            decomposition = decomposition->getChild();

            if(decomposition)
            {
                QImage image2(decomposition->getCorrectionX(), decomposition->getCorrectionY(), image.format());
                image = QImage(decomposition->getCorrectionX(), decomposition->getCorrectionY(), image2.format());
                NQRgb correction;
                for(int i = 0; i < decomposition->getCorrectionX(); ++i)
                {
                    for(int j = 0; j < decomposition->getCorrectionY(); ++j)
                    {
                        correction = decomposition->getHorizontalCorrection(i, j);
                        image.setPixel(i, j, qRgb(qAbs(correction.getRed()), qAbs(correction.getGreen()), qAbs(correction.getBlue())));
                        correction = decomposition->getVerticalCorrection(i, j);
                        image2.setPixel(i, j, qRgb(qAbs(correction.getRed()), qAbs(correction.getGreen()), qAbs(correction.getBlue())));
                    }
                }

                if(!image.save(filename))
                {
                    CGoGNerr << "Image '" << filename2.toStdString() << "' has not been saved" << CGoGNendl;
                }

                if(!image2.save(filename2))
                {
                    CGoGNerr << "Image '" << filename2.toStdString() << "' has not been saved" << CGoGNendl;
                }
            }
        } while(decomposition);
    }
}

MapHandlerGen* Surface_WaveletDecomposition_Plugin::initializeObject(const QString& view, QString& filename, const bool multiple)
{
    if(!filename.isEmpty())
    {
        QString file = filename.left(filename.lastIndexOf('.'));
        file = file.mid(file.lastIndexOf('/')).remove(0, 1);
        MapHandlerGen* mhg_map = m_schnapps->addMap(file, 2);
        MapHandler<PFP2>* mh_map = static_cast<MapHandler<PFP2>*>(mhg_map);
        PFP2::MAP* map = mh_map->getMap();

        VertexAttribute<PFP2::VEC3, PFP2::MAP> position = mh_map->getAttribute<PFP2::VEC3, VERTEX>("position");
        if(!position.isValid())
        {
            position = mh_map->addAttribute<PFP2::VEC3, VERTEX>("position");
        }

        VertexAttribute <PFP2::VEC3, PFP2::MAP> color = mh_map->getAttribute<PFP2::VEC3, VERTEX>("color");
        if(!color.isValid())
        {
            color = mh_map->addAttribute<PFP2::VEC3, VERTEX>("color");
        }

        QString extension = filename.mid(filename.lastIndexOf('.'));
        extension.toUpper();

        QImage image;
        if(!image.load(filename, extension.toUtf8().constData()))
        {
            CGoGNout << "Image has not been loaded correctly" << CGoGNendl;
            return NULL;
        }

        image = image.convertToFormat(QImage::Format_RGB32);

        int imageX = image.width(), imageY = image.height();

        Algo::Surface::Tilings::Square::Grid<PFP2> grid(*map, imageX-1, imageY-1);
        if(multiple)
        {
            QImage image_parent;
            QString filename_parent = filename;

            filename_parent.replace(filename_parent.size()-5, 1, "0");

            if(!image_parent.load(filename_parent, extension.toUtf8().constData()))
            {
                CGoGNout << "Image has not been loaded correctly" << CGoGNendl;
                return NULL;
            }

            //CORRECTION PAIR FAIT PERDRE 1 PIXEL A DROITE
            int shift_counterX = 0, shift_counterY = 0, level_decomposition = 0;
            int image_parentX = image_parent.width(), image_parentY = image_parent.height();

            while(image_parentX != imageX && image_parentY != imageY)
            {
                ++level_decomposition;

                if(image_parentX%2 == 0)
                {
                    shift_counterX += level_decomposition;
                }

                if(image_parentY%2 == 0)
                {
                    shift_counterY += level_decomposition;
                }

                image_parentX = image_parentX/2+image_parentX%2;
                image_parentY = image_parentY/2+image_parentY%2;
            }

            grid.embedIntoGrid(position, image_parent.width()-1, image_parent.height()-1);

            mh_map->updateBB(position);

            grid.embedIntoGrid(position, image_parent.width()-1-shift_counterX, image_parent.height()-1-shift_counterY);

            PFP2::MATRIX44 transform_matrix;
            transform_matrix.identity();

            qglviewer::Vec max = mh_map->getBBmax();
            qglviewer::Vec min = mh_map->getBBmin();

            float width_step_parent = image_parent.width()/(max.x-min.x);
            float height_step_parent = image_parent.height()/(max.y-min.y);

            transform_matrix.setSubVectorV(0, 3, PFP2::VEC4(-width_step_parent*shift_counterX/2, +height_step_parent*shift_counterY/2, 0., 1.));

            grid.transform(position, transform_matrix);
        }
        else
        {
            grid.embedIntoGrid(position, imageX-1, imageY-1);
        }

        std::vector<Dart> vDarts = grid.getVertexDarts();

        QRgb pixel;

        for(int i = 0; i < imageX; ++i)
        {
            for(int j = 0; j < imageY; ++j)
            {
                pixel = image.pixel(i,(imageY-j)-1);
                color[vDarts[j*imageX+i]] = PFP2::VEC3(qRed(pixel)/255.f, qGreen(pixel)/255.f, qBlue(pixel)/255.f);
            }
        }

        m_decomposition = new Decomposition(imageX, imageY, 0);

        m_decomposition->setImage(image);

        mh_map->updateBB(position);
        mh_map->notifyAttributeModification(position);
        mh_map->notifyAttributeModification(color);
        mh_map->notifyConnectivityModification();
        m_positionVBO->updateData(position);
        //m_colorVBO->updateData(color);

        m_toDraw = true;

        map->enableQuickTraversal<PFP2::MAP, VERTEX>();

        if(view == m_schnapps->getSelectedView()->getName())
        {
            m_schnapps->getSelectedView()->updateGL();
        }

        return mhg_map;
    }
    return NULL;
}

#ifndef DEBUG
Q_EXPORT_PLUGIN2(Surface_WaveletDecomposition_Plugin, Surface_WaveletDecomposition_Plugin)
#else
Q_EXPORT_PLUGIN2(Surface_WaveletDecomposition_PluginD, Surface_WaveletDecomposition_Plugin)
#endif

} // namespace SCHNApps

} // namespace CGoGN
<|endoftext|>