text:
#include "toonzqt/dvdialog.h"

// TnzQt includes
#include "toonzqt/checkbox.h"
#include "toonzqt/lineedit.h"
#include "toonzqt/fxsettings.h"

// TnzLib includes
#include "toonz/txsheethandle.h"
#include "toonz/txshsimplelevel.h"
#include "toonz/palettecmd.h"
#include "toonz/preferences.h"
#include "toonz/toonzfolders.h"

// Qt includes
#include <QFrame>
#include <QLayout>
#include <QLabel>
#include <QPushButton>
#include <QApplication>
#include <QStyle>
#include <QButtonGroup>
#include <QPainter>
#include <QRadioButton>
#include <QThread>
#include <QDesktopWidget>
#include <QCheckBox>

// boost includes
#include <boost/algorithm/cxx11/any_of.hpp>

using namespace DVGui;

QString DialogTitle = "OpenToonz 1.4";

//=============================================================================
namespace {
QPixmap getMsgBoxPixmap(MsgType type) {
  int iconSize =
      QApplication::style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
  QIcon msgBoxIcon;

  switch (type) {
  case DVGui::INFORMATION:
    msgBoxIcon =
        QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
    break;
  case DVGui::WARNING:
    msgBoxIcon =
        QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning);
    break;
  case DVGui::CRITICAL:
    msgBoxIcon =
        QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
    break;
  case DVGui::QUESTION:
    msgBoxIcon =
        QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion);
    break;
  default:
    break;
  }

  if (!msgBoxIcon.isNull()) return msgBoxIcon.pixmap(iconSize, iconSize);
  return QPixmap();
}

//-----------------------------------------------------------------------------

QString getMsgBoxTitle(MsgType type) {
  QString title = DialogTitle + " - ";

  switch (type) {
  case DVGui::INFORMATION:
    title.append(QObject::tr("Information"));
    break;
  case DVGui::WARNING:
    title.append(QObject::tr("Warning"));
    break;
  case DVGui::CRITICAL:
    title.append(QObject::tr("Critical"));
    break;
  case DVGui::QUESTION:
    title.append(QObject::tr("Question"));
    break;
  default:
    break;
  }
  return title;
}

//-----------------------------------------------------------------------------
}  // namespace
//-----------------------------------------------------------------------------

//=============================================================================
// Separator
//-----------------------------------------------------------------------------

Separator::Separator(QString name, QWidget *parent, bool isHorizontal)
    : QFrame(parent), m_name(name), m_isHorizontal(isHorizontal) {
  //	if(m_name.isEmpty())
  //		setMinimumSize(1,1);
  //	else
  setMinimumSize(1, 15);
}

//-----------------------------------------------------------------------------

Separator::~Separator() {}

//-----------------------------------------------------------------------------

void Separator::paintEvent(QPaintEvent *) {
  QPainter p(this);
  ParamsPage *page = dynamic_cast<ParamsPage *>(parentWidget());
  if (!page)
    p.setPen(palette().alternateBase().color());
  else
    p.setPen(page->getTextColor());

  QRect contents(contentsRect());

  int textWidth = p.fontMetrics().width(m_name);

  p.drawText(contents.left(), 10, m_name);

  // make the line semi-transparent
  QColor lineColor = palette().alternateBase().color();
  lineColor.setAlpha(128);

  p.setPen(lineColor);
  int h = contents.height();
  if (m_isHorizontal) {
    int y     = contents.center().y();
    int space = (textWidth == 0) ? 0 : 8;
    p.drawLine(textWidth + space, y, contents.width(), y);
  } else {
    double w       = width();
    int space      = (textWidth == 0) ? 0 : 2;
    int x0         = (w > textWidth) ? w * 0.5 : (double)textWidth * 0.5;
    int textHeghit = (space == 0) ? 0 : p.fontMetrics().height();
    p.drawLine(x0, textHeghit + space, x0, contents.bottom());
  }
}

//=============================================================================
/*! \class DVGui::Dialog
                \brief The Dialog class is the base class of dialog windows.

                Inherits \b QDialog.

                A dialog window is a top-level window, defined in \b QDialog,
this class provides
                a collection of functions to manage \b QDialog widget
visualization.
                Dialog window can be modal or modeless, from this it depends
dialog visualization.
                You set your dialog to modal or modeless directly in
constructor, with \b bool
                hasButton, in fact if the dialog has button then is modal too.

                If dialog is \b modal it's composed of two part, two \b QFrame;
the first, \b main
                \b part at top of dialog, contains a vertical box layout \b
QVBoxLayout, the second,
                \b button \b part at bottom, contains an horizontal box layout
\b QHBoxLayout.
                Else if dialog is modeless it is composed only of first part, to
be more precise,
                it is composed of a \b QFrame containing a vertical box layout
\b QVBoxLayout.

                The first part of dialog can be implemented using different
objects. You can manage
                directly vertical box layout, insert widget addWidget(), or
layout addLayout(), set
                border and spacing, using setTopMargin() and setTopSpacing(), or
insert a spece,
                addSpacing().
\n	If you need an horizontal layout you can use an implemented horizontal
box layout;
                the function beginHLayout() initialize the horizontal box
layout, a collection of
                function permit to insert object in this layout; at the end you
must recall
                endVLayout(), this add horizontal layout to first part of
dialog.
                This struct permit you to allign the object you insert.
\n	If you need vertical layout you can use an implemented vertical box
layout composed
                of two column, the function beginVLayout() initialize the
vertical box layout,
                a collection of function permit to insert object in this layout.
                All this functions insert a pair of object in two vertical
layout and permit
                to allign the objects, all pairs you insert are tabulated.
                At the end you must recall endVLayout(), this add vertical
layout to first part of
                dialog.

                The second part of dialog may be implemented if dialog is modal.
                It's possible insert one, two or three widget in its horizontal
box layout using
                addButtonBarWidget(), or clear all widget using
clearButtonBar(). You can also
                set margin and spacing with setButtonBarMargin() and
setButtonBarSpacing() functions.
*/
//-----------------------------------------------------------------------------

namespace {
QString settingsPath;
};

Dialog::Dialog(QWidget *parent, bool hasButton, bool hasFixedSize,
               const QString &name)
    : QDialog(parent, Qt::CustomizeWindowHint | Qt::WindowTitleHint |
                          Qt::WindowCloseButtonHint)
    , m_hasButton(hasButton)
    , m_mainHLayout(0)
    , m_leftVLayout(0)
    , m_rightVLayout(0)
    , m_isMainVLayout(false)
    , m_isMainHLayout(false)
    , m_layoutSpacing(5)
    , m_layoutMargin(0)
    , m_labelWidth(100)
    , m_name() {
  QVBoxLayout *mainLayout = new QVBoxLayout;
  mainLayout->setMargin(0);
  mainLayout->setSpacing(0);
  m_mainFrame = new QFrame(this);
  m_mainFrame->setObjectName("dialogMainFrame");
  m_mainFrame->setMinimumHeight(41);
  m_mainFrame->setFrameStyle(QFrame::StyledPanel);
  m_topLayout = new QVBoxLayout;
  m_topLayout->setMargin(12);
  m_topLayout->setSpacing(m_layoutSpacing);
  m_topLayout->setAlignment(Qt::AlignCenter);
  m_mainFrame->setLayout(m_topLayout);

  mainLayout->addWidget(m_mainFrame);

  if (m_hasButton) {
    // The dialog is modal
    setModal(true);

    m_buttonFrame = new QFrame(this);
    m_buttonFrame->setObjectName("dialogButtonFrame");
    m_buttonFrame->setFrameStyle(QFrame::StyledPanel);
    m_buttonFrame->setFixedHeight(45);

    m_buttonLayout = new QHBoxLayout;
    m_buttonLayout->setMargin(0);
    m_buttonLayout->setSpacing(20);
    m_buttonLayout->setAlignment(Qt::AlignHCenter);

    QVBoxLayout *buttonFrameLayout = new QVBoxLayout;
    buttonFrameLayout->setAlignment(Qt::AlignVCenter);
    buttonFrameLayout->addLayout(m_buttonLayout);
    m_buttonFrame->setLayout(buttonFrameLayout);

    mainLayout->addWidget(m_buttonFrame);
  }

  if (hasFixedSize)
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
  else
    mainLayout->setSizeConstraint(QLayout::SetMinimumSize);

  setLayout(mainLayout);
// this->setGeometry(30, 30, 300, 300);
#ifdef MACOSX
  setWindowFlags(Qt::Tool);
#endif

  if (settingsPath.isEmpty()) {
    TFilePath savePath =
        ToonzFolder::getMyModuleDir() + TFilePath("popups.ini");
    settingsPath = QString::fromStdWString(savePath.getWideString());
  }

  QSettings settings(settingsPath, QSettings::IniFormat);

  if (name == QString()) return;
  m_name      = name + "DialogGeometry";
  QString geo = settings.value(m_name).toString();
  if (geo != QString()) {
    QStringList values = geo.split(" ");
    assert(values.size() == 4);
    // Ensure that the dialog is visible in the screen.
    // The dialog opens with some offset to bottom-right direction
    // if a flag Qt::WindowMaximizeButtonHint is set. (e.g. PencilTestPopup)
    // Therefore, if the dialog is moved to the bottom-end of the screen,
    // it will be got out of the screen on the next launch.
    // The following position adjustment will also prevent such behavior.

    // try and get active screen
    if (parent != NULL) {
      m_currentScreen = QApplication::desktop()->screenNumber(parent);
    }
    QRect screen = QApplication::desktop()->availableGeometry(m_currentScreen);
    int x        = values.at(0).toInt();
    int y        = values.at(1).toInt();

    // make sure that the window is visible on the screen
    // all popups will popup on the active window the first time
    // so popups moved to other monitors will be moved back
    // when restarting OpenToonz.

    // This may be somewhat annoying if a user REALLY wants the popup
    // on another monitor by default, but this is better than
    // a user thinking the program is broken because they didn't notice
    // the popup on another monitor
    if (x > screen.right() - 50) x = screen.right() - 50;
    if (x < screen.left()) x = screen.left();
    if (y > screen.bottom() - 90) y = screen.bottom() - 90;
    if (y < screen.top()) y = screen.top();
    setGeometry(x, y, values.at(2).toInt(), values.at(3).toInt());
    settings.setValue(m_name, QString::number(x) + " " + QString::number(y) +
                                  " " + QString::number(values.at(2).toInt()) +
                                  " " + QString::number(values.at(3).toInt()));
  }
}

//-----------------------------------------------------------------------------

Dialog::~Dialog() {
  if (m_name == QString()) return;

  QRect r = geometry();
  QSettings settings(settingsPath, QSettings::IniFormat);
  settings.setValue(m_name, QString::number(r.left()) + " " +
                                QString::number(r.top()) + " " +
                                QString::number(r.width()) + " " +
                                QString::number(r.height()));
}

//---------------------------------------------------------------------------------

void Dialog::resizeEvent(QResizeEvent *e) {
  if (Preferences::instance()->getCurrentLanguage() != "English") {
    QSize t = this->size();
    for (QLabel *s : m_labelList) s->setFixedWidth(t.width() * .35);
  }
}

//-----------------------------------------------------------------------------

//! By default, QDialogs always reset position/size upon hide events. However,
//! we want to prevent such behaviour on Toonz Dialogs - this method is
//! reimplemented
//! for this purpose.
void Dialog::hideEvent(QHideEvent *event) {
  int x = pos().rx();
  int y = pos().ry();
  // make sure the dialog is actually visible on a screen
  int screenCount = QApplication::desktop()->screenCount();
  int currentScreen;
  for (int i = 0; i < screenCount; i++) {
    if (QApplication::desktop()->screenGeometry(i).contains(pos())) {
      currentScreen = i;
      break;
    } else {
      // if not - put it back on the main window
      currentScreen = m_currentScreen;
    }
  }
  QRect screen = QApplication::desktop()->availableGeometry(currentScreen);

  if (x > screen.right() - 50) x = screen.right() - 50;
  if (x < screen.left()) x = screen.left();
  if (y > screen.bottom() - 90) y = screen.bottom() - 90;
  if (y < screen.top()) y = screen.top();
  move(QPoint(x, y));
  resize(size());
  QRect r = geometry();
  QSettings settings(settingsPath, QSettings::IniFormat);
  settings.setValue(m_name, QString::number(r.left()) + " " +
                                QString::number(r.top()) + " " +
                                QString::number(r.width()) + " " +
                                QString::number(r.height()));
  emit dialogClosed();
}

//-----------------------------------------------------------------------------
/*! Create the new layouts (2 Vertical) for main part of dialog.
 */
void Dialog::beginVLayout() {
  m_isMainVLayout = true;

  m_leftVLayout = new QVBoxLayout;
  m_leftVLayout->setMargin(m_layoutMargin);
  m_leftVLayout->setSpacing(m_layoutSpacing);

  m_rightVLayout = new QVBoxLayout;
  m_rightVLayout->setMargin(m_layoutMargin);
  m_rightVLayout->setSpacing(m_layoutSpacing);
}

//-----------------------------------------------------------------------------
/*! Add to main part of dialog the Vertical Layouts ,insert them in a orizontal
                layout to form two column, set Vertical Layouts to 0 .
*/
void Dialog::endVLayout() {
  if (!m_leftVLayout || !m_rightVLayout) return;
  m_isMainVLayout = false;

  QHBoxLayout *layout = new QHBoxLayout;
  layout->setMargin(m_layoutMargin);
  layout->setSpacing(m_layoutSpacing);
  layout->setSizeConstraint(QLayout::SetFixedSize);

  layout->addLayout(m_leftVLayout);
  layout->setAlignment(m_leftVLayout, Qt::AlignLeft);
  layout->addLayout(m_rightVLayout);
  layout->setAlignment(m_rightVLayout, Qt::AlignLeft);

  addLayout(layout);

  m_leftVLayout  = 0;
  m_rightVLayout = 0;
}

//-----------------------------------------------------------------------------
/*! Create a new Horizontal Layout for main part of dialog.
 */
void Dialog::beginHLayout() {
  m_isMainHLayout = true;
  m_mainHLayout   = new QHBoxLayout;
  m_mainHLayout->setMargin(m_layoutMargin);
  m_mainHLayout->setSpacing(m_layoutSpacing);
}

//-----------------------------------------------------------------------------
/*! Add to main part of dialog the Horizontal Layout  and set it to 0.
 */
void Dialog::endHLayout() {
  m_isMainHLayout = false;
  if (!m_mainHLayout) return;
  addLayout(m_mainHLayout);
  m_mainHLayout = 0;
}

//-----------------------------------------------------------------------------
/*! Add a widget \b widget to main part of dialog. If vertical layout is
                initialized add widget in right column if \b isRight is true,
   otherwise in
                left column. \b isRight by default is true.
*/
void Dialog::addWidget(QWidget *widget, bool isRight) {
  if (m_isMainVLayout) {
    assert(m_leftVLayout && m_rightVLayout);
    QWidget *w = new QWidget();
    int h      = widget->height() + m_layoutSpacing;
    if (isRight) {
      m_leftVLayout->addSpacing(h);
      m_rightVLayout->addWidget(widget);
    } else {
      m_leftVLayout->addWidget(widget, 1, Qt::AlignRight);
      m_rightVLayout->addSpacing(h);
    }
    return;
  } else if (m_isMainHLayout) {
    assert(m_mainHLayout);
    m_mainHLayout->addWidget(widget);
    return;
  }
  m_topLayout->addWidget(widget);
}

//-----------------------------------------------------------------------------
/*! Add a pair [widget,widget] to main part of dialog.
\n	If vertical and horizontal layout are not initialized create an
horizontal
                box layout containing the two widgets and recall \b addLayout().
                If vertical layout is current add the pair to vertical layout of
main part,
                \b firstW on first column and \b secondW on second column.
                Else if horizontal layout is current create an horizontal box
layout containing
                \b firstW and \b secondW and add it to horizontal layout.
*/
void Dialog::addWidgets(QWidget *firstW, QWidget *secondW) {
  if (m_isMainVLayout) {
    assert(m_leftVLayout && m_rightVLayout);
    m_leftVLayout->addWidget(firstW);
    m_rightVLayout->addWidget(secondW);
    return;
  }
  QHBoxLayout *pairLayout = new QHBoxLayout;
  pairLayout->setMargin(m_layoutMargin);
  pairLayout->setSpacing(m_layoutSpacing);
  pairLayout->addWidget(firstW);
  pairLayout->addWidget(secondW);

  if (m_isMainHLayout) {
    assert(m_mainHLayout);
    m_mainHLayout->addLayout(pairLayout);
    return;
  }
  addLayout(pairLayout);
}

//-----------------------------------------------------------------------------
/*! Add a pair [label,widget] to main part of dialog, label is created from
                \b QString \b nameLabel.
\n	Recall \b addWidgets(QWdiget* firstW, QWdiget* secondW).
*/
void Dialog::addWidget(QString labelName, QWidget *widget) {
  QLabel *label = new QLabel(labelName);
  m_labelList.push_back(label);
  label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
  label->setFixedSize(m_labelWidth, widget->height());
  addWidgets(label, widget);
}

//-----------------------------------------------------------------------------
/*! Add a layout \b layout to main part of dialog. If vertical layout is
                initialized add widget in right column if \b isRight is true,
   otherwise in
                left column. \b isRight by default is true.
*/
void Dialog::addLayout(QLayout *layout, bool isRight) {
  if (m_isMainVLayout) {
    assert(m_leftVLayout && m_rightVLayout);
    int h = layout->itemAt(0)->widget()->height() + m_layoutSpacing;
    if (isRight) {
      m_leftVLayout->addSpacing(h);
      m_rightVLayout->addLayout(layout);
    } else {
      m_leftVLayout->addLayout(layout);
      m_rightVLayout->addSpacing(h);
    }
    return;
  } else if (m_isMainHLayout) {
    assert(m_mainHLayout);
    m_mainHLayout->addLayout(layout);
    return;
  }
  m_topLayout->addLayout(layout);
}

//-----------------------------------------------------------------------------
/*! Add a pair [widget,layout] to main part of dialog.
\n	If vertical and horizontal layout are not initialized create an
horizontal
                box layout containing \b widget and \b layout and recall \b
addLayout().
                If vertical layout is current add the pair [label,layout] to
vertical layout
                of main part, label on first column and layout on second column.
                Else if horizontal layout is current create an horizontal box
layout containing
                \b widget and \b layout and add it to horizontal layout.
*/
void Dialog::addWidgetLayout(QWidget *widget, QLayout *layout) {
  layout->setMargin(m_layoutMargin);
  layout->setSpacing(m_layoutSpacing);

  if (m_isMainVLayout) {
    assert(m_leftVLayout && m_rightVLayout);
    m_leftVLayout->addWidget(widget);
    m_rightVLayout->addLayout(layout);
    return;
  }

  QHBoxLayout *pairLayout = new QHBoxLayout;
  pairLayout->setMargin(m_layoutMargin);
  pairLayout->setSpacing(m_layoutSpacing);
  pairLayout->addWidget(widget);
  pairLayout->addLayout(layout);

  if (m_isMainHLayout) {
    assert(m_mainHLayout);
    m_mainHLayout->addLayout(pairLayout);
    return;
  }

  addLayout(pairLayout);
}

//-----------------------------------------------------------------------------
/*! Add a pair [label,layout] to main part of dialog, label is created from
                \b QString \b nameLabel.
\n	Recall \b addWidgetLayout(QWdiget* widget, QWdiget* layout).
*/
void Dialog::addLayout(QString labelName, QLayout *layout) {
  QLabel *label = new QLabel(labelName);
  m_labelList.push_back(label);
  label->setFixedWidth(m_labelWidth);
  label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
  addWidgetLayout(label, layout);
}

//-----------------------------------------------------------------------------
/*! Add a pair [layout,layout] to main part of dialog.
\n	If vertical and horizontal layout are not initialized create an
horizontal
                box layout containing the two layouts and recall \b addLayout().
                If vertical layout is current add the pair [layout,layout] to
vertical layout
                of main part, \b firstL on first column and \b secondL on second
column.
                Else if horizontal layout is current create an horizontal box
layout containing
                \b firstL and \b secondL and add it to horizontal layout.
*/
void Dialog::addLayouts(QLayout *firstL, QLayout *secondL) {
  firstL->setMargin(m_layoutMargin);
  firstL->setSpacing(m_layoutSpacing);
  secondL->setMargin(m_layoutMargin);
  secondL->setSpacing(m_layoutSpacing);

  if (m_isMainVLayout) {
    assert(m_leftVLayout && m_rightVLayout);
    m_leftVLayout->addLayout(firstL);
    m_rightVLayout->addLayout(secondL);
    return;
  }

  QHBoxLayout *pairLayout = new QHBoxLayout;
  pairLayout->setMargin(m_layoutMargin);
  pairLayout->setSpacing(m_layoutSpacing);
  pairLayout->addLayout(firstL);
  pairLayout->addLayout(secondL);

  if (m_isMainHLayout) {
    assert(m_mainHLayout);
    m_mainHLayout->addLayout(pairLayout);
    return;
  }

  addLayout(pairLayout);
}

//-----------------------------------------------------------------------------
/*! Add spacing \b spacing to main part of dialog.
 */
void Dialog::addSpacing(int spacing) {
  if (m_isMainVLayout) {
    assert(m_leftVLayout && m_rightVLayout);
    m_leftVLayout->addSpacing(spacing);
    m_rightVLayout->addSpacing(spacing);
    return;
  } else if (m_isMainHLayout) {
    assert(m_mainHLayout);
    m_mainHLayout->addSpacing(spacing);
    return;
  }
  m_topLayout->addSpacing(spacing);
}

//-----------------------------------------------------------------------------
/*! Add a separator \b Separator to main part of dialog.
                If vertical layout is initialized add an horizontal separator.
                If horizontal layout is initialized add a vertical separator.
*/
void Dialog::addSeparator(QString name) {
  Separator *separator = new Separator(name);
  if (m_isMainVLayout) {
    assert(m_leftVLayout && m_rightVLayout);
    endVLayout();
    addWidget(separator);
    beginVLayout();
    return;
  } else if (m_isMainHLayout) {
    assert(m_mainHLayout);
    separator->setOrientation(false);
    m_mainHLayout->addWidget(separator);
    return;
  }
  addWidget(separator);
}

//-----------------------------------------------------------------------------
/*! Set the alignement of the main layout
 */
void Dialog::setAlignment(Qt::Alignment alignment) {
  m_mainFrame->layout()->setAlignment(alignment);
}

//-----------------------------------------------------------------------------
/*! Set to \b spacing spacing of main part of dialog.
 */
void Dialog::setTopSpacing(int spacing) {
  m_layoutSpacing = spacing;
  m_topLayout->setSpacing(spacing);
}
//-----------------------------------------------------------------------------

void Dialog::setLabelWidth(int labelWidth) { m_labelWidth = labelWidth; }

//-----------------------------------------------------------------------------
/*! Set to \b spacing spacing of all layout inserted in main part of dialog,
                horizontal layout and vertical layout.
*/
void Dialog::setLayoutInsertedSpacing(int spacing) {
  m_layoutSpacing = spacing;
}

//-----------------------------------------------------------------------------
/*! Return the spacing of all layout inserted in main part of dialog,
                horizontal layout and vertical layout.
*/
int Dialog::getLayoutInsertedSpacing() { return m_layoutSpacing; }

//-----------------------------------------------------------------------------
/*! Set to \b margin margin of main part of dialog.
 */
void Dialog::setTopMargin(int margin) { m_topLayout->setMargin(margin); }

//-----------------------------------------------------------------------------
/*! Set to \b margin margin of button part of dialog.
 */
void Dialog::setButtonBarMargin(int margin) {
  m_buttonLayout->setMargin(margin);
}

//-----------------------------------------------------------------------------
/*! Set to \b spacing spacing of button part of dialog.
 */
void Dialog::setButtonBarSpacing(int spacing) {
  m_buttonLayout->setSpacing(spacing);
}

//-----------------------------------------------------------------------------
/*! Add a widget to the button part of dialog.
 */
void Dialog::addButtonBarWidget(QWidget *widget) {
  widget->setMinimumSize(65, 25);
  assert(m_hasButton);
  if (m_hasButton) {
    m_buttonLayout->addWidget(widget);
    m_buttonBarWidgets.push_back(widget);
  }
}

//-----------------------------------------------------------------------------
/*! Remove all widget from the button part of dialog.
 */
void Dialog::clearButtonBar() {
  for (int i = 0; i < (int)m_buttonBarWidgets.size(); i++) {
    m_buttonLayout->removeWidget(m_buttonBarWidgets[i]);
  }
  m_buttonBarWidgets.clear();
}

//-----------------------------------------------------------------------------
/*! Add two widget to the button part of dialog.
 */
void Dialog::addButtonBarWidget(QWidget *first, QWidget *second) {
  first->setMinimumSize(65, 25);
  second->setMinimumSize(65, 25);
  assert(m_hasButton);
  if (m_hasButton) {
    m_buttonLayout->addWidget(first);
    m_buttonLayout->addWidget(second);
  }
}

//-----------------------------------------------------------------------------
/*! Add three widget to the button part of dialog.
 */
void Dialog::addButtonBarWidget(QWidget *first, QWidget *second,
                                QWidget *third) {
  first->setMinimumSize(65, 25);
  second->setMinimumSize(65, 25);
  third->setMinimumSize(65, 25);
  assert(m_hasButton);
  if (m_hasButton) {
    m_buttonLayout->addWidget(first);
    m_buttonLayout->addWidget(second);
    m_buttonLayout->addWidget(third);
  }
}

//-----------------------------------------------------------------------------
/*! Add four widget to the button part of dialog.
 */
void Dialog::addButtonBarWidget(QWidget *first, QWidget *second, QWidget *third,
                                QWidget *fourth) {
  first->setMinimumSize(65, 25);
  second->setMinimumSize(65, 25);
  third->setMinimumSize(65, 25);
  assert(m_hasButton);
  if (m_hasButton) {
    m_buttonLayout->addWidget(first);
    m_buttonLayout->addWidget(second);
    m_buttonLayout->addWidget(third);
    m_buttonLayout->addWidget(fourth);
  }
}

//=============================================================================

MessageAndCheckboxDialog::MessageAndCheckboxDialog(
    QWidget *parent, bool hasButton, bool hasFixedSize, const QString &name,
    Qt::CheckState checkButtonState)
    : Dialog(parent, hasButton, hasFixedSize, name)
    , m_checked(checkButtonState) {}

//=============================================================================

void MessageAndCheckboxDialog::onButtonPressed(int id) { done(id); }

//=============================================================================

void MessageAndCheckboxDialog::onCheckboxChanged(int checked) {
  m_checked = checked;
}

//=============================================================================

RadioButtonDialog::RadioButtonDialog(const QString &labelText,
                                     const QList<QString> &radioButtonList,
                                     QWidget *parent, Qt::WindowFlags f)
    : Dialog(parent, true, true), m_result(1) {
  setWindowTitle(tr("OpenToonz"));

  setMinimumSize(20, 20);

  beginVLayout();

  QLabel *label = new QLabel(labelText);
  label->setAlignment(Qt::AlignLeft);
  label->setFixedHeight(2 * WidgetHeight);
  addWidget(label);

  QButtonGroup *buttonGroup = new QButtonGroup(this);
  int i;
  for (i = 0; i < radioButtonList.count(); i++) {
    QRadioButton *radioButton = new QRadioButton(radioButtonList.at(i));
    if (i == m_result - 1) radioButton->setChecked(true);
    radioButton->setFixedHeight(WidgetHeight);
    buttonGroup->addButton(radioButton);
    buttonGroup->setId(radioButton, i);
    addWidget(radioButton);
  }

  bool ret = connect(buttonGroup, SIGNAL(buttonClicked(int)),
                     SLOT(onButtonClicked(int)));

  endVLayout();

  QPushButton *applyButton = new QPushButton(QObject::tr("Apply"));
  ret = ret && connect(applyButton, SIGNAL(pressed()), this, SLOT(onApply()));
  QPushButton *cancelButton = new QPushButton(QObject::tr("Cancel"));
  ret = ret && connect(cancelButton, SIGNAL(pressed()), this, SLOT(onCancel()));

  addButtonBarWidget(applyButton, cancelButton);

  assert(ret);
}

//-----------------------------------------------------------------------------

void RadioButtonDialog::onButtonClicked(int id) {
  // Add "1" because "0" is cancel button.
  m_result = id + 1;
}

//-----------------------------------------------------------------------------

void RadioButtonDialog::onCancel() { done(0); }

//-----------------------------------------------------------------------------

void RadioButtonDialog::onApply() { done(m_result); }

//=============================================================================

int DVGui::RadioButtonMsgBox(MsgType type, const QString &labelText,
                             const QList<QString> &radioButtonList,
                             QWidget *parent) {
  RadioButtonDialog *dialog =
      new RadioButtonDialog(labelText, radioButtonList, parent);
  QString msgBoxTitle = getMsgBoxTitle(DVGui::WARNING);
  dialog->setWindowTitle(msgBoxTitle);
  return dialog->exec();
}

//=============================================================================

ProgressDialog::ProgressDialog(const QString &labelText,
                               const QString &cancelButtonText, int minimum,
                               int maximum, QWidget *parent, Qt::WindowFlags f)
    : Dialog(parent, true, true), m_isCanceled(false) {
  setWindowTitle(tr("OpenToonz"));

  setMinimumSize(20, 20);

  beginVLayout();

  m_label = new QLabel(this);
  m_label->setText(labelText);
  addWidget(m_label);

  m_progressBar = new QProgressBar(this);
  m_progressBar->setRange(minimum, maximum);
  m_progressBar->setMinimumWidth(250);
  addWidget(m_progressBar);

  endVLayout();

  if (!cancelButtonText.isEmpty())
    setCancelButton(new QPushButton(cancelButtonText));
}

//-----------------------------------------------------------------------------

void ProgressDialog::setLabelText(const QString &text) {
  m_label->setText(text);
}

//-----------------------------------------------------------------------------

void ProgressDialog::setCancelButton(QPushButton *cancelButton) {
  m_cancelButton = cancelButton;
  bool ret = connect(cancelButton, SIGNAL(pressed()), this, SLOT(onCancel()));
  ret =
      ret && connect(cancelButton, SIGNAL(pressed()), this, SIGNAL(canceled()));
  assert(ret);
  addButtonBarWidget(m_cancelButton);
}

//-----------------------------------------------------------------------------

int ProgressDialog::maximum() { return m_progressBar->maximum(); }
//-----------------------------------------------------------------------------

void ProgressDialog::setMaximum(int maximum) {
  m_progressBar->setMaximum(maximum);
}

//-----------------------------------------------------------------------------

int ProgressDialog::minimum() { return m_progressBar->minimum(); }
//-----------------------------------------------------------------------------

void ProgressDialog::setMinimum(int minimum) {
  m_progressBar->setMinimum(minimum);
}

//-----------------------------------------------------------------------------

int ProgressDialog::value() { return m_progressBar->value(); }

//-----------------------------------------------------------------------------

void ProgressDialog::setValue(int progress) {
  m_progressBar->setValue(progress);
  if (isModal()) qApp->processEvents();
}

//-----------------------------------------------------------------------------

void ProgressDialog::reset() { m_progressBar->reset(); }

//-----------------------------------------------------------------------------

bool ProgressDialog::wasCanceled() const { return m_isCanceled; }

//-----------------------------------------------------------------------------

void ProgressDialog::onCancel() {
  m_isCanceled = true;
  reset();
  hide();
}

//=============================================================================

int DVGui::MsgBox(MsgType type, const QString &text,
                  const std::vector<QString> &buttons, int defaultButtonIndex,
                  QWidget *parent) {
  Dialog dialog(parent, true);
  dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
  dialog.setAlignment(Qt::AlignLeft);
  QString msgBoxTitle = getMsgBoxTitle(type);

  dialog.setWindowTitle(msgBoxTitle);

  QLabel *mainTextLabel = new QLabel(text, &dialog);
  QPixmap iconPixmap    = getMsgBoxPixmap(type);
  if (!iconPixmap.isNull()) {
    QLabel *iconLabel = new QLabel(&dialog);
    iconLabel->setPixmap(iconPixmap);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(iconLabel);
    mainLayout->addSpacing(16);
    mainLayout->addWidget(mainTextLabel);
    dialog.addLayout(mainLayout);
  } else
    dialog.addWidget(mainTextLabel);

  // ButtonGroup: is used only to retrieve the clicked button
  QButtonGroup *buttonGroup = new QButtonGroup(&dialog);

  for (int i = 0; i < (int)buttons.size(); i++) {
    QPushButton *button = new QPushButton(buttons[i], &dialog);
    if (defaultButtonIndex == i)
      button->setDefault(true);
    else
      button->setDefault(false);
    dialog.addButtonBarWidget(button);

    buttonGroup->addButton(button, i + 1);
  }

  QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), &dialog,
                   SLOT(done(int)));

  dialog.raise();

  return dialog.exec();
}

//-----------------------------------------------------------------------------

void DVGui::MsgBoxInPopup(MsgType type, const QString &text) {
  // this function must be called by the main thread only
  // (only the main thread should access directly the GUI)
  // (note: working thread can and should call MsgBox(type,text) instead; see
  // tmsgcore.h)

  Q_ASSERT(QApplication::instance()->thread() == QThread::currentThread());

  // a working thread can trigger a call to this function (by the main thread)
  // also when a popup is already open
  // therefore we need a messageQueue
  // note: no mutex are needed because only the main thread call this function
  static QList<QPair<MsgType, QString>> messageQueue;
  static bool popupIsOpen = false;

  messageQueue.append(qMakePair(type, text));
  if (popupIsOpen) return;
  popupIsOpen = true;

  Dialog dialog(0, true);

  dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
  dialog.setAlignment(Qt::AlignLeft);
  QLabel *mainTextLabel = new QLabel("", &dialog);
  mainTextLabel->setMinimumWidth(400);
  QLabel *iconLabel = new QLabel(&dialog);

  QHBoxLayout *mainLayout = new QHBoxLayout;
  mainLayout->addWidget(iconLabel);
  mainLayout->addStretch();
  mainLayout->addWidget(mainTextLabel);
  mainLayout->addStretch();
  dialog.addLayout(mainLayout);

  // ButtonGroup: is used only to retrieve the clicked button
  QButtonGroup *buttonGroup = new QButtonGroup(&dialog);
  QPushButton *button       = new QPushButton(QPushButton::tr("OK"), &dialog);
  button->setDefault(true);
  dialog.addButtonBarWidget(button);
  buttonGroup->addButton(button, 1);
  QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), &dialog,
                   SLOT(done(int)));

  while (!messageQueue.empty()) {
    MsgType type1 = messageQueue.first().first;
    QString text1 = messageQueue.first().second;
    messageQueue.pop_front();

    mainTextLabel->setText(text1);

    QString msgBoxTitle = getMsgBoxTitle(type1);
    dialog.setWindowTitle(msgBoxTitle);

    QPixmap iconPixmap = getMsgBoxPixmap(type1);
    if (!iconPixmap.isNull()) {
      iconLabel->setPixmap(iconPixmap);
      iconLabel->setVisible(true);
    } else {
      iconLabel->setVisible(false);
    }

    dialog.raise();
    dialog.exec();

  }  // loop: open the next dialog in the queue
  popupIsOpen = false;
}

//-----------------------------------------------------------------------------

int DVGui::MsgBox(const QString &text, const QString &button1Text,
                  const QString &button2Text, const QString &button3Text,
                  int defaultButtonIndex, QWidget *parent) {
  Dialog dialog(parent, true);
  dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
  dialog.setAlignment(Qt::AlignLeft);
  QString msgBoxTitle = getMsgBoxTitle(QUESTION);
  dialog.setWindowTitle(msgBoxTitle);

  QLabel *mainTextLabel = new QLabel(text, &dialog);
  QPixmap iconPixmap    = getMsgBoxPixmap(QUESTION);
  if (!iconPixmap.isNull()) {
    QLabel *iconLabel = new QLabel(&dialog);
    iconLabel->setPixmap(iconPixmap);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(iconLabel);
    mainLayout->addSpacing(16);
    mainLayout->addWidget(mainTextLabel);
    dialog.addLayout(mainLayout);
  } else
    dialog.addWidget(mainTextLabel);

  // ButtonGroup: is used only to retrieve the clicked button
  QButtonGroup *buttonGroup = new QButtonGroup(&dialog);

  QPushButton *button1 = new QPushButton(button1Text, &dialog);
  button1->setDefault(false);
  if (defaultButtonIndex == 0) button1->setDefault(true);
  dialog.addButtonBarWidget(button1);
  buttonGroup->addButton(button1, 1);

  QPushButton *button2 = new QPushButton(button2Text, &dialog);
  button2->setDefault(false);
  if (defaultButtonIndex == 1) button2->setDefault(true);
  dialog.addButtonBarWidget(button2);
  buttonGroup->addButton(button2, 2);

  QPushButton *button3 = new QPushButton(button3Text, &dialog);
  button3->setDefault(false);
  if (defaultButtonIndex == 2) button3->setDefault(true);
  dialog.addButtonBarWidget(button3);
  buttonGroup->addButton(button3, 3);

  QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), &dialog,
                   SLOT(done(int)));
  dialog.raise();
  return dialog.exec();
}

//-----------------------------------------------------------------------------

int DVGui::MsgBox(const QString &text, const QString &button1Text,
                  const QString &button2Text, const QString &button3Text,
                  const QString &button4Text, int defaultButtonIndex,
                  QWidget *parent) {
  Dialog dialog(parent, true);
  dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
  dialog.setAlignment(Qt::AlignLeft);
  QString msgBoxTitle = getMsgBoxTitle(QUESTION);
  dialog.setWindowTitle(msgBoxTitle);

  QLabel *mainTextLabel = new QLabel(text, &dialog);
  QPixmap iconPixmap    = getMsgBoxPixmap(QUESTION);
  if (!iconPixmap.isNull()) {
    QLabel *iconLabel = new QLabel(&dialog);
    iconLabel->setPixmap(iconPixmap);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(iconLabel);
    mainLayout->addSpacing(16);
    mainLayout->addWidget(mainTextLabel);
    dialog.addLayout(mainLayout);
  } else
    dialog.addWidget(mainTextLabel);

  // ButtonGroup: is used only to retrieve the clicked button
  QButtonGroup *buttonGroup = new QButtonGroup(&dialog);

  QPushButton *button1 = new QPushButton(button1Text, &dialog);
  button1->setDefault(false);
  if (defaultButtonIndex == 0) button1->setDefault(true);
  dialog.addButtonBarWidget(button1);
  buttonGroup->addButton(button1, 1);

  QPushButton *button2 = new QPushButton(button2Text, &dialog);
  button2->setDefault(false);
  if (defaultButtonIndex == 1) button2->setDefault(true);
  dialog.addButtonBarWidget(button2);
  buttonGroup->addButton(button2, 2);

  QPushButton *button3 = new QPushButton(button3Text, &dialog);
  button3->setDefault(false);
  if (defaultButtonIndex == 2) button3->setDefault(true);
  dialog.addButtonBarWidget(button3);
  buttonGroup->addButton(button3, 3);

  QPushButton *button4 = new QPushButton(button4Text, &dialog);
  button4->setDefault(false);
  if (defaultButtonIndex == 3) button4->setDefault(true);
  dialog.addButtonBarWidget(button4);
  buttonGroup->addButton(button4, 4);

  QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), &dialog,
                   SLOT(done(int)));
  dialog.raise();
  return dialog.exec();
}

//-----------------------------------------------------------------------------

int DVGui::MsgBox(const QString &text, const QString &button1,
                  const QString &button2, int defaultButtonIndex,
                  QWidget *parent) {
  Dialog dialog(parent, true);
  dialog.setWindowFlags(dialog.windowFlags() | Qt::WindowStaysOnTopHint);
  std::vector<QString> buttons;
  buttons.push_back(button1);
  buttons.push_back(button2);
  return DVGui::MsgBox(DVGui::QUESTION, text, buttons, defaultButtonIndex,
                       parent);
}

//-----------------------------------------------------------------------------

Dialog *DVGui::createMsgBox(MsgType type, const QString &text,
                            const QStringList &buttons, int defaultButtonIndex,
                            QWidget *parent) {
  Dialog *dialog = new Dialog(parent, true);
  dialog->setWindowFlags(dialog->windowFlags() | Qt::WindowStaysOnTopHint);
  dialog->setAlignment(Qt::AlignLeft);
  QString msgBoxTitle = getMsgBoxTitle(type);

  dialog->setWindowTitle(msgBoxTitle);

  QLabel *mainTextLabel = new QLabel(text, dialog);
  mainTextLabel->setObjectName("Label");
  QPixmap iconPixmap = getMsgBoxPixmap(type);
  if (!iconPixmap.isNull()) {
    QLabel *iconLabel = new QLabel(dialog);
    iconLabel->setPixmap(iconPixmap);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(iconLabel);
    mainLayout->addSpacing(16);
    mainLayout->addWidget(mainTextLabel);
    dialog->addLayout(mainLayout);
  } else
    dialog->addWidget(mainTextLabel);

  // ButtonGroup: is used only to retrieve the clicked button
  QButtonGroup *buttonGroup = new QButtonGroup(dialog);

  for (int i = 0; i < (int)buttons.size(); i++) {
    QPushButton *button = new QPushButton(buttons[i], dialog);
    if (defaultButtonIndex == i)
      button->setDefault(true);
    else
      button->setDefault(false);
    dialog->addButtonBarWidget(button);

    buttonGroup->addButton(button, i + 1);
  }

  QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), dialog,
                   SLOT(done(int)));

  return dialog;
}

//-----------------------------------------------------------------------------

MessageAndCheckboxDialog *DVGui::createMsgandCheckbox(
    MsgType type, const QString &text, const QString &checkBoxText,
    const QStringList &buttons, int defaultButtonIndex,
    Qt::CheckState defaultCheckBoxState, QWidget *parent) {
  MessageAndCheckboxDialog *dialog = new MessageAndCheckboxDialog(
      parent, true, true, "", defaultCheckBoxState);
  dialog->setWindowFlags(dialog->windowFlags() | Qt::WindowStaysOnTopHint);
  dialog->setAlignment(Qt::AlignLeft);
  QString msgBoxTitle = getMsgBoxTitle(type);

  dialog->setWindowTitle(msgBoxTitle);

  QLabel *mainTextLabel = new QLabel(text, dialog);
  mainTextLabel->setObjectName("Label");
  QPixmap iconPixmap = getMsgBoxPixmap(type);
  if (!iconPixmap.isNull()) {
    QLabel *iconLabel = new QLabel(dialog);
    iconLabel->setPixmap(iconPixmap);

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(iconLabel);
    mainLayout->addSpacing(16);
    mainLayout->addWidget(mainTextLabel);
    dialog->addLayout(mainLayout);
  } else
    dialog->addWidget(mainTextLabel);

  // ButtonGroup: is used only to retrieve the clicked button
  QButtonGroup *buttonGroup = new QButtonGroup(dialog);

  for (int i = 0; i < (int)buttons.size(); i++) {
    QPushButton *button = new QPushButton(buttons[i], dialog);
    if (defaultButtonIndex == i)
      button->setDefault(true);
    else
      button->setDefault(false);
    dialog->addButtonBarWidget(button);

    buttonGroup->addButton(button, i + 1);
  }

  QCheckBox *dialogCheckBox   = new QCheckBox(checkBoxText, dialog);
  QHBoxLayout *checkBoxLayout = new QHBoxLayout;
  checkBoxLayout->addWidget(dialogCheckBox);
  checkBoxLayout->addStretch(0);
  dialog->addLayout(checkBoxLayout);

  dialogCheckBox->setCheckState(defaultCheckBoxState);

  QObject::connect(dialogCheckBox, SIGNAL(stateChanged(int)), dialog,
                   SLOT(onCheckboxChanged(int)));
  QObject::connect(buttonGroup, SIGNAL(buttonPressed(int)), dialog,
                   SLOT(onButtonPressed(int)));

  return dialog;
}

//-----------------------------------------------------------------------------

QString DVGui::getText(const QString &title, const QString &labelText,
                       const QString &text, bool *ok) {
  Dialog dialog(0, true);

  dialog.setWindowTitle(title);
  dialog.setWindowFlags(Qt::WindowStaysOnTopHint | Qt::WindowTitleHint |
                        Qt::CustomizeWindowHint);

  QVBoxLayout *layout = new QVBoxLayout(&dialog);
  dialog.addLayout(layout);

  QLabel *label = new QLabel(labelText, &dialog);
  layout->addWidget(label);

  LineEdit *nameFld = new LineEdit(text, &dialog);
  layout->addWidget(nameFld);

  QPushButton *okBtn = new QPushButton(QObject::tr("OK"), &dialog);
  okBtn->setDefault(true);
  QPushButton *cancelBtn = new QPushButton(QObject::tr("Cancel"), &dialog);
  QObject::connect(okBtn, SIGNAL(clicked()), &dialog, SLOT(accept()));
  QObject::connect(cancelBtn, SIGNAL(clicked()), &dialog, SLOT(reject()));

  dialog.addButtonBarWidget(okBtn, cancelBtn);

  int ret = dialog.exec();
  if (ok) *ok = (ret == QDialog::Accepted);

  return nameFld->text();
}

//-----------------------------------------------------------------------------

namespace {
bool isStyleIdInPalette(int styleId, const TPalette *palette) {
  if (palette->getStyleCount() == 0) return false;
  int i;
  for (i = 0; i < palette->getPageCount(); i++) {
    const TPalette::Page *page = palette->getPage(i);
    if (!page) return false;  // La pagina dovrebbe esserci sempre
    int j;
    for (j = 0; j < page->getStyleCount(); j++)
      if (page->getStyleId(j) == styleId) return true;
  }
  return false;
}
}  // namespace

//-----------------------------------------------------------------------------

int DVGui::eraseStylesInDemand(TPalette *palette,
                               const TXsheetHandle *xsheetHandle,
                               TPalette *newPalette) {
  // Verifico se gli stili della paletta sono usati : eraseStylesInDemand()
  std::vector<int> styleIds;
  int h;
  for (h = 0; h < palette->getPageCount(); h++) {
    TPalette::Page *page = palette->getPage(h);
    if (!page) continue;  // La pagina dovrebbe esserci sempre
    int k;
    for (k = 0; k < page->getStyleCount(); k++) {
      int styleId = page->getStyleId(k);
      bool isStyleIdInNewPalette =
          (!newPalette) ? false : isStyleIdInPalette(styleId, newPalette);
      if (styleId > 0 && !isStyleIdInNewPalette) styleIds.push_back(styleId);
    }
  }

  return eraseStylesInDemand(palette, styleIds, xsheetHandle);
}

//-----------------------------------------------------------------------------

int DVGui::eraseStylesInDemand(TPalette *palette, std::vector<int> styleIds,
                               const TXsheetHandle *xsheetHandle) {
  struct locals {
    static bool isRasterLevel(const TXshSimpleLevel *level) {
      return level->getType() == TZP_XSHLEVEL ||
             level->getType() == OVL_XSHLEVEL;
    }
  };  // locals

  // Search xsheet levels attached to the palette
  std::set<TXshSimpleLevel *> levels;
  int row, column;
  findPaletteLevels(levels, row, column, palette, xsheetHandle->getXsheet());

  bool someStyleIsUsed =
      !levels.empty() ||
      styleIds.empty();  // I guess this is wrong... but I'm not touching it
  if (someStyleIsUsed) someStyleIsUsed = areStylesUsed(levels, styleIds);

  if (!someStyleIsUsed) return 1;

  // At least a style is selected and present in some level - ask user if and
  // how styles
  // should be deleted

  QString question = QObject::tr(
                         "Styles you are going to delete are used to paint "
                         "lines and areas in the animation level.\n") +
                     QObject::tr("How do you want to proceed?");

  int ret = DVGui::MsgBox(question, QObject::tr("Delete Styles Only"),
                          QObject::tr("Delete Styles, Lines and Areas"),
                          QObject::tr("Cancel"), 0);
  if (ret != 2) return (ret == 0 || ret == 3) ? 0 : 1;

  // Inform the user that case 2 will not produce an undo if a raster-based
  // level is detected
  if (boost::algorithm::any_of(levels, locals::isRasterLevel)) {
    std::vector<QString> buttons(2);
    buttons[0] = QObject::tr("Ok"), buttons[1] = QObject::tr("Cancel");

    if (DVGui::MsgBox(DVGui::WARNING,
                      QObject::tr("Deletion of Lines and Areas from "
                                  "raster-based levels is not undoable.\n"
                                  "Are you sure?"),
                      buttons) != 1)
      return 0;
  }

  QApplication::setOverrideCursor(Qt::WaitCursor);
  PaletteCmd::eraseStyles(levels, styleIds);
  QApplication::restoreOverrideCursor();

  return (assert(ret == 2), ret);  // return 2 ?     :D
}

//-----------------------------------------------------------------------------

void DVGui::setDialogTitle(const QString &dialogTitle) {
  DialogTitle = dialogTitle;
}

//-----------------------------------------------------------------------------

max_stars_repo_name: otakuto/opentoonz

max_issues_repo_name: otakuto/opentoonz

max_forks_repo_name: otakuto/opentoonz


text:
#pragma once

#include <deque>

#include <memory>
#include <boost/interprocess/shared_memory_object.hpp>

#include <string>
#include <vector>

class SharedMemoryPipeManager
{
public:
	static void createNamedPipe(const std::string& name);
	SharedMemoryPipeManager() {}
	~SharedMemoryPipeManager();
private:
};

class SharedMemoryPipe;
typedef std::shared_ptr<SharedMemoryPipe> SharedMemoryPipePtr;

class SharedMemoryPipe
{
public:
	//make a pair of pipes which are just within this process.
	static std::pair<SharedMemoryPipePtr,SharedMemoryPipePtr> makeInMemoryPair();

	SharedMemoryPipe(const std::string& name, bool server);

	void process();

	void write(const std::string& msg);
	void read(std::vector<std::string>& msg);
private:

	SharedMemoryPipe();

	typedef std::shared_ptr<boost::interprocess::shared_memory_object> ShmPtr;
	ShmPtr in_, out_;

	typedef std::shared_ptr<boost::interprocess::mapped_region> MappedRegionPtr;
	MappedRegionPtr in_region_, out_region_;

	uint8_t* in_addr_, *out_addr_;

	std::vector<std::shared_ptr<std::vector<uint8_t>>> buffers_;

	std::deque<std::string> in_queue_, out_queue_;
};

ext: hpp

max_stars_repo_name: gamobink/anura

max_issues_repo_name: gamobink/anura

max_forks_repo_name: gamobink/anura


text:
//==================================================================
// Author       : Pointner Sebastian
// Company      : Johannes Kepler University
// Name         : SMT Macro Placer
// Workfile     : macrocircuit.hpp
//
// Date         : 22. December 2019
// Compiler     : gcc version 9.2.0 (GCC)
// Copyright    : Johannes Kepler University
// Description  : SoC Macro Circuit
//==================================================================
#ifndef MACROCIRCUIT_HPP
#define MACROCIRCUIT_HPP

#include <vector>
#include <string>
#include <fstream>
#include <cstdio>
#include <map>
#include <unordered_map>
#include <thread>
#include <chrono>
#include <mutex>
#include <cmath>

#include <z3++.h>

#include <boost/filesystem.hpp>

#include <object.hpp>
#include <components.hpp>
#include <lefdefIO.h>
#include <tree.hpp>
#include <evaluate.hpp>
#include <logger.hpp>
#include <timer.hpp>
#include <supplement.hpp>
#include <bookshelf.hpp>
#include <layout.hpp>
#include <partitioning.hpp>
#include <parquet.hpp>
#include <encoding_utils.hpp>
#include <utils.hpp>
#include <def_utils.hpp>
#include <database.hpp>
#include <plotter.hpp>
#include <hlclient.hpp>

namespace Placer {

class Evaluate;
class Partitioning;
class ParquetFrontend;

/**
 * @class MacroCircuit
 * @brief Top Class for MacroCircuit Placement
 */
class MacroCircuit: public virtual Object {
public:

    MacroCircuit();

    virtual ~MacroCircuit();

    void build_circuit();
    void partitioning();
    void encode();
    void place();

    void dump_all();
    void dump_best();

    void save_all();
    void save_best();

    void results_to_db();

    void create_statistics();

    void dump(std::ostream & stream = std::cout);

private:
    friend class Evaluate;

    // Microsoft Z3
    z3::optimize* m_z3_opt;

    Circuit::Circuit* m_circuit;
    std::vector<Macro*> m_macros;
    std::vector<MacroDefinition> m_macro_definitions;

    std::vector<Cell*> m_cells;

    std::vector<Terminal*> m_terminals;

    std::vector<Partition*> m_partitons;

    std::vector<Component*> m_components;
    Tree* m_tree;
    Evaluate* m_eval;
    Utils::Logger* m_logger;
    Utils::Timer* m_timer;
    Utils::Database* m_db;
    Utils::DefUtils* m_def_utils;
    Supplement* m_supplement;
    Bookshelf* m_bookshelf;
    Partitioning* m_partitioning;
    ParquetFrontend* m_parquet;
    EncodingUtils* m_encode;
    Plotter* m_plotter;
    HLClient* m_hl_client;

    std::map<std::string, Macro*> m_id2macro;
    std::map<std::string, Terminal*> m_id2terminal;
    std::map<std::string, Cell*> m_id2cell;
    size_t m_solutions;
    size_t m_estimated_area;

    Layout* m_layout;

    double m_standard_cell_height;

    void build_circuit_lefdef();
    void build_circuit_bookshelf();

    bool is_macro(LefDefParser::defiComponent const & macro);
    bool is_standard_cell(LefDefParser::defiComponent const & cell);

    /**
     * Thread Functions
     */
    void add_terminals();
    void add_macros();
    void add_cells();
    void area_estimator();

    void add_cell(LefDefParser::defiComponent const & cmp);

    void build_tree_from_lefdef();
    void init_tree(eInputFormat const type);

    void create_macro_definitions();

    void write_def(std::string const & name, size_t const solution);
    void write_lef(std::string const & name);

    Tree* get_tree();
    Layout* get_layout();
    size_t get_solutions();

    /**
     * SMT Encoding
     */
    void encode_smt();
    void encode_parquet();

    void config_z3();
    void run_encoding();

    void encode_components_inside_die(eRotation const type);
    void encode_components_non_overlapping(eRotation const type);
    void encode_terminals_on_frontier();
    void encode_terminals_non_overlapping();
    void encode_terminals_center_edge();
    void encode_hpwl_length();
    void encode_layout_on_grid();
    void encode_components_on_grid();
    void encode_terminals_on_grid();

    z3::expr m_components_non_overlapping;
    z3::expr m_components_inside_die;
    z3::expr m_terminals_on_frontier;
    z3::expr m_terminals_non_overlapping;
    z3::expr m_terminals_center_edge;
    z3::expr m_hpwl_cost_function;
    z3::expr m_layout_on_grid;
    z3::expr m_terminals_on_grid;
    z3::expr m_components_on_grid;
    z3::expr_vector m_hpwl_edges;

    z3::expr manhattan_distance(z3::expr const & from_x,
                                z3::expr const & from_y,
                                z3::expr const & to_x,
                                z3::expr const & to_y);

    /**
     * SMT Solving
     */
    void solve_z3_api();
    void solve_z3_no_api();
    void solve_optimathsat_no_api();
    void process_results(z3::model const & m);
    void dump_smt_instance();
    void process_key_value_results(std::map<std::string, std::vector<size_t>> & solution, size_t const id);

};

} /* namespace Placer */

#endif /* MACROCIRCUIT_HPP */


text:
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <string>

#include <boost/filesystem.hpp>
#include <fmt/ostream.h>
#include <gsl/span>
#include <range/v3/action/transform.hpp>
#include <range/v3/algorithm/stable_sort.hpp>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/iota.hpp>
#include <range/v3/view/stride.hpp>
#include <tbb/task_scheduler_init.h>

#include "binary_freq_collection.hpp"
#include "filesystem.hpp"
#include "forward_index_builder.hpp"
#include "pisa_config.hpp"
#include "sharding.hpp"
#include "temporary_directory.hpp"

using namespace boost::filesystem;
using namespace pisa;
using namespace pisa::literals;

using posting_vector_type = std::vector<std::pair<Term_Id, Document_Id>>;
using iterator_type = decltype(std::declval<posting_vector_type>().begin());
using index_type = invert::Inverted_Index<iterator_type>;

[[nodiscard]] auto next_plaintext_record(std::istream &in) -> std::optional<Document_Record>
{
    pisa::Plaintext_Record record;
    if (in >> record) {
        return std::make_optional<Document_Record>(
            std::move(record.trecid()), std::move(record.content()), std::move(record.url()));
    }
    return std::nullopt;
}

TEST_CASE("mapping_from_files", "[invert][unit]")
{
    std::istringstream full("D00\nD01\nD02\nD03\nD04\nD05\nD06\nD07\nD08\nD09\nD010\nD11");
    std::vector<std::unique_ptr<std::istream>> shards;
    shards.push_back(std::make_unique<std::istringstream>("D00\nD01\nD02"));
    shards.push_back(std::make_unique<std::istringstream>("D02\nD03\nD04"));
    shards.push_back(std::make_unique<std::istringstream>("D06\nD07\nD08\nD09\nD010\nD11"));
    auto stream_pointers =
        ranges::views::transform(shards, [](auto const &s) { return s.get(); }) | ranges::to_vector;
    REQUIRE(mapping_from_files(&full, gsl::span<std::istream *>(stream_pointers)).as_vector()
            == std::vector<Shard_Id>{0_s, 0_s, 0_s, 1_s, 1_s, 0_s, 2_s, 2_s, 2_s, 2_s, 2_s, 2_s});
}

TEST_CASE("create_random_mapping", "[invert][unit]")
{
    uint64_t seed = 88887;
    auto mapping = pisa::create_random_mapping(1000u, 13u, seed);
    VecMap<Shard_Id, int> counts(13, 0);
    VecMap<Document_Id> documents;
    for (auto &&[doc, shard] : mapping.entries()) {
        counts[shard] += 1;
        documents.push_back(doc);
    }
    std::sort(documents.begin(), documents.end());

    REQUIRE(documents.as_vector()
            == ranges::to_vector(ranges::views::iota(Document_Id{}, Document_Id{1000u})));
    REQUIRE(counts.as_vector()
            == std::vector<int>{77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 76});
}

auto round_robin_mapping(int document_count, int shard_count)
{
    VecMap<Document_Id, Shard_Id> mapping(document_count);
    Shard_Id shard = 0_s;
    for (auto doc : ranges::views::iota(0_d, Document_Id{document_count})) {
        mapping[doc] = shard++;
        if (shard == Shard_Id{shard_count}) {
            shard = 0_s;
        }
    }
    return mapping;
}

void build_fwd_index(std::string const &output)
{
    tbb::task_scheduler_init init;
    std::string input(PISA_SOURCE_DIR "/test/test_data/clueweb1k.plaintext");
    std::ifstream is(input);
    pisa::Forward_Index_Builder builder;
    builder.build(
        is,
        output,
        next_plaintext_record,
        [](std::string &&term) -> std::string { return std::forward<std::string>(term); },
        pisa::parse_plaintext_content,
        20'000,
        2);
}

template <typename Container>
auto shard_elements(Container const &container, Shard_Id shard_id, int shard_count)
{
    Container elems;
    for (auto const &val :
         ranges::views::drop(container, shard_id.as_int()) | ranges::views::stride(shard_count)) {
        elems.push_back(val);
    }
    return elems;
}

TEST_CASE("copy_sequence", "[invert][unit]")
{
    GIVEN("A test forward index")
    {
        Temporary_Directory dir;
        std::string fwd_basename = (dir.path() / "fwd").string();
        std::string output = (dir.path() / "copy").string();
        int document_count = 1'000;
        build_fwd_index(fwd_basename);

        WHEN("All sequences are copied")
        {
            {
                std::ifstream is(fwd_basename);
                std::ofstream os(output);
                for ([[maybe_unused]] auto _ : ranges::views::ints(0, document_count)) {
                    copy_sequence(is, os);
                }
            }

            THEN("Files are identical")
            {
                auto actual = io::load_data(output);
                auto expected = io::load_data(fwd_basename);
                expected.resize(actual.size());
                REQUIRE(actual == expected);
            }
        }
    }
}

TEST_CASE("Rearrange sequences", "[invert][integration]")
{
    GIVEN("A test forward index")
    {
        Temporary_Directory dir;
        std::string fwd_basename = (dir.path() / "fwd").string();
        std::string output_basename = (dir.path() / "shards").string();
        int document_count = 1'000;
        build_fwd_index(fwd_basename);

        WHEN("Rearrange the sequences in a round-robin manner")
        {
            auto mapping = round_robin_mapping(document_count, 13);
            REQUIRE(mapping.size() == document_count);
            rearrange_sequences(fwd_basename, output_basename, mapping);
            auto shard_ids = ranges::views::iota(0_s, 13_s);

            THEN("Sequences are properly rearranged")
            {
                auto full = binary_collection(fwd_basename.c_str());
                auto full_iter = ++full.begin();
                std::vector<std::vector<std::uint32_t>> expected;
                std::transform(
                    full_iter, full.end(), std::back_inserter(expected), [](auto const &seq) {
                        return std::vector<std::uint32_t>(seq.begin(), seq.end());
                    });
                auto sorted_mapping = mapping.entries().collect();
                ranges::stable_sort(sorted_mapping, [](auto const &lhs, auto const &rhs) {
                    return std::make_pair(lhs.second, lhs.first)
                           < std::make_pair(rhs.second, rhs.first);
                });
                expected = ranges::views::transform(
                               sorted_mapping,
                               [&](auto &&entry) { return expected[entry.first.as_int()]; })
                           | ranges::to_vector;

                auto pos = expected.begin();
                for (auto shard : shard_ids) {
                    // std::vector<std::vector<std::uint32_t>> actual;
                    spdlog::info("Testing shard {}", shard.as_int());
                    spdlog::default_logger()->flush();
                    auto shard_coll = binary_collection(
                        fmt::format("{}.{:03d}", output_basename, shard.as_int()).c_str());
                    size_t doc = 0u;
                    CAPTURE(shard);
                    CAPTURE(doc);
                    for (auto iter = ++shard_coll.begin(); iter != shard_coll.end();
                         ++iter, ++pos) {
                        auto seq = *iter;
                        REQUIRE(*pos == std::vector<std::uint32_t>(seq.begin(), seq.end()));
                    }
                }
            }
        }
    }
}

TEST_CASE("partition_fwd_index", "[invert][integration]")
{
    tbb::task_scheduler_init init;
    GIVEN("A test forward index")
    {
        Temporary_Directory dir;
        std::string fwd_basename = (dir.path() / "fwd").string();
        std::string output_basename = (dir.path() / "shards").string();
        int document_count = 1'000;
        build_fwd_index(fwd_basename);

        WHEN("Partition the forward index in a round-robin manner")
        {
            auto mapping = round_robin_mapping(document_count, 13);
            REQUIRE(mapping.size() == document_count);
            partition_fwd_index(fwd_basename, output_basename, mapping);
            auto shard_ids = ranges::views::iota(0_s, 13_s);

            THEN("Document titles are correctly partitioned")
            {
                auto original_titles =
                    io::read_string_vector(fmt::format("{}.documents", fwd_basename));
                for (auto shard_id : shard_ids) {
                    auto expected_titles = shard_elements(original_titles, shard_id, 13);
                    auto actual_titles = io::read_string_vector(
                        fmt::format("{}.{:03d}.documents", output_basename, shard_id.as_int()));
                    REQUIRE(actual_titles == expected_titles);
                }
            }
            AND_THEN("Documents are identical wrt terms")
            {
                auto full = binary_collection(fwd_basename.c_str());
                auto full_iter = ++full.begin();
                auto full_terms = io::read_string_vector(fmt::format("{}.terms", fwd_basename));
                std::vector<binary_collection> shards;
                std::vector<typename binary_collection::const_iterator> shard_iterators;
                std::vector<std::vector<std::string>> shard_terms;
                shards.reserve(13);
                shard_iterators.reserve(13);
                shard_terms.reserve(13);
                for (auto shard : shard_ids) {
                    shards.push_back(binary_collection(
                        fmt::format("{}.{:03d}", output_basename, shard.as_int()).c_str()));
                    shard_terms.push_back(io::read_string_vector(
                        fmt::format("{}.{:03d}.terms", output_basename, shard.as_int()).c_str()));
                    shard_iterators.push_back(++shards.back().begin());
                    shards.back();
                }
                Shard_Id shard = 0_s;
                for (auto doc : ranges::views::iota(0_d, Document_Id{document_count})) {
                    CAPTURE(doc);
                    auto full_seq = *full_iter;
                    auto shard_seq = *shard_iterators[shard.as_int()];
                    std::vector<std::string> expected_documents(full_seq.size());
                    std::vector<std::string> actual_documents(shard_seq.size());
                    std::transform(full_seq.begin(),
                                   full_seq.end(),
                                   expected_documents.begin(),
                                   [&](auto const &id) { return full_terms[id]; });
                    std::transform(shard_seq.begin(),
                                   shard_seq.end(),
                                   actual_documents.begin(),
                                   [&](auto const &id) { return shard_terms[shard.as_int()][id]; });
                    REQUIRE(actual_documents == expected_documents);
                    ++full_iter;
                    ++shard_iterators[shard.as_int()];
                    shard += 1_s;
                    if (shard == 13_s) {
                        shard = 0_s;
                    }
                }
            }
        }
    }
}

ext: cpp

max_stars_repo_name: JMMackenzie/pisa-multi-query

max_issues_repo_name: JMMackenzie/pisa-multi-query

max_forks_repo_name: JMMackenzie/pisa-multi-query


text:
#include <bits/types/FILE.h>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <string>
#include <tgmath.h>
#include "image_ppm.h"
#include <filesystem>
#include <Eigen/Dense>

using namespace std;
using namespace Eigen;

typedef Matrix<u_char, Dynamic, Dynamic> MatrixImg;
typedef Matrix<double, Dynamic, Dynamic> TempMatrixImg;
typedef Vector<u_char,Dynamic> ImgLine;
typedef Vector<double,Dynamic> TempImgLine;
//typedef Matrix<ImgLine,Dynamic,Dynamic> FlattenedImages;

unsigned char max(u_char a, u_char b){
    if (a<b) return b;
    else return a;
}

unsigned char min(u_char a, u_char b){
    if (a>b) return b;
    else return a;
}

double max(double a, double b){
    if (a<b) return b;
    else return a;
}

double min(double a, double b){
    if (a>b) return b;
    else return a;
}

int max(int a, int b){
    if (a<b) return b;
    else return a;
}

int min(int a, int b){
    if (a>b) return b;
    else return a;
}

vector<double> projectOnEigenSpace(vector<TempImgLine> eigenfaces, TempImgLine imToProj,int K){
    vector<double> res = vector<double>();
    for (int i=0;i<K;i++){
        res.push_back(eigenfaces[i].dot(imToProj));
    }
    return res;
}

ImgLine octToVec(OCTET* im, int nH, int nW){
    ImgLine res(nH*nW);
    for (int i=0; i<nH*nW;i++){
        res(i)=im[i];
    }
    return res;
}

double eigenProjsDistance(vector<double> proj1, vector<double> proj2){

    double res =0.0;
    for (int i=0; i<min(proj1.size(),proj2.size());i++){
        res+=(proj1[i]-proj2[i])*(proj1[i]-proj2[i]);
    }
    return res;
}

int main(int argc, char* argv[]){

    //recup eigenfaces

    vector<TempImgLine> eigenfaces;
    int K =200; int nH;int nW;

    for (int i=0; i<K;i++){
        OCTET* im;
        char name[50];
        sprintf(name,"out/eigenfaces/im%d.pgm",i);
        lire_nb_lignes_colonnes_image_pgm(name,&nH,&nW);
        allocation_tableau(im,OCTET,nH*nW);
        lire_image_pgm(name,im,nH*nW);
        TempImgLine eigenFace(nH*nW) ;
        double sum=0.0;
        for (int j=0;j<nH*nW;j++){
            eigenFace(j)=im[j]-127;
            sum+=(double)(im[j]-127)*(double)(im[j]-127);
        }
        for (int j=0;j<nH*nW;j++){
            eigenFace(j)=eigenFace(j)/sqrt(sum);
            }
        eigenfaces.push_back(eigenFace);
        free(im);
    }

    string dirIn = string(argv[1]);

    //vector<vector<int*>> histos = vector<vector<int*>>();

    vector<vector<vector<double>>> registre = vector<vector<vector<double>>>();

    int countDirs =0;
    for (auto & dir : std::filesystem::directory_iterator(dirIn)){
        registre.push_back(vector<vector<double>>());
        int countFile=0;
        for (auto & file : std::filesystem::directory_iterator(dir.path())){
            OCTET* img;
            lire_nb_lignes_colonnes_image_pgm(file.path().c_str(),&nH,&nW);
            TempImgLine imgLine(nH*nW);
            allocation_tableau(img,OCTET, nH*nW);
            lire_image_pgm(file.path().c_str(),img,nH*nW);
            double sumIm=0.0;
            for (int i=0;i<nH*nW;i++){sumIm+=(double)(img[i]-127)*(double)(img[i]-127);}
            for (int i=0; i<nH*nW;i++){imgLine(i)=(double)(img[i]-127)/sumIm;}
            registre[countDirs].push_back(projectOnEigenSpace(eigenfaces,imgLine,K));

            countFile++;
        }
        countDirs++;
    }

    for (double threshold=0.0;threshold<0.0000005;threshold+=0.00000001){
        int VP=0,VN=0,FP=0,FN=0;

        for (int i=0;i<registre.size();i++){
            for (int j=0; j<registre[i].size();j++){
                for (int ip=0;ip<registre.size();ip++){
                    for (int jp=0;jp<registre[ip].size();jp++){
                        if (!(i==ip && j==jp)){
                            //cout<<eigenProjsDistance(registre[i][j],registre[ip][jp])<<endl;
                            if (eigenProjsDistance(registre[i][j],registre[ip][jp])<threshold){
                                if (i==ip){
                                    VP++;
                                }
                                else{
                                    FP++;
                                }
                            }

                        else{
                                if (i==ip){
                                    FN++;
                                }
                                else{
                                    VN++;
                                }
                            }

                        }
                    }
                }
            }
        }

        double sensitivite = (double)((double)VP/(double)(VP+FN));
        double antispecificite = 1.0-(double)((double)VN/(double)(VN+FP));
        double distance = antispecificite*antispecificite + (1-sensitivite)*(1-sensitivite);
        cout<<antispecificite<<" "<<sensitivite<<" "<<distance<<" "<<threshold<<endl;
    }

}

max_stars_repo_name: JPhilippot/FaceRecognition

max_issues_repo_name: JPhilippot/FaceRecognition

max_forks_repo_name: JPhilippot/FaceRecognition


text:
#include "TimeSectionFormatter.h"

#include "ReadContext.h"
#include "WriteContext.h"
#include "Exceptions.h"
#include "Pointer.h"
#include "FormattedReader.h"
#include "FormattedWriter.h"
#include "Field.h"
#include "TeaFileDescription.h"
#include "ItemDescription.h"
#include "TimeScale.h"
#include "Time.h"

#include <sstream>
using std::ostringstream;
#include <algorithm>
using std::copy_if;
#include <functional>
using std::mem_fun;
#include <boost/foreach.hpp>

namespace teatime {

void TimeSectionFormatter::Read(ReadContext *rc)
{
  // time scale
  auto r = rc->Reader();
  auto epoch  = r->ReadInt64();
  auto ticksPerDay = r->ReadInt64();

  TimeScale scale(epoch, ticksPerDay);
  rc->Description()->Scale(scale);

  if(scale != TimeScale::Master())
  {
    throw TimeScaleMismatchException(); // API limitation: Only TeaFiles that have the scale of TimeScale::Master() can be read!
  }

  auto id = rc->Description()->Item();

  // time fields
  bool isFirstTimeField = true;
  int32 timeFieldsCount = r->ReadInt32();
  while(timeFieldsCount--)
  {
    int32 offset = r->ReadInt32();
    if (id != 0)
    {
      auto f = id->GetFieldByOffset(offset);
      f->IsTime(true);
      f->IsEventTime(isFirstTimeField);
      isFirstTimeField = false;
    }
  };
}

void TimeSectionFormatter::Write(WriteContext *wc)
{
  if (wc->Description() == 0) return;
  if (wc->Description()->Item() == 0) return;

  auto id = wc->Description()->Item();
  int n = wc->Description()->Item()->FieldCount();
  vector<shared_ptr<const Field>> timeFields;
  for(int i=0; i < n; i++)
  {
    auto f = id->GetField(i);
    if(f->IsTime())
    {
      timeFields.push_back(f);
    }
  }
  if(timeFields.empty()) return; // do not write time section if no time field exists

  // time format
  wc->Writer()->WriteInt64(TimeScale::Master().Epoch());
  wc->Writer()->WriteInt64(TimeScale::Master().TicksPerDay());

  // time fields
  wc->Writer()->WriteInt32(static_cast<int32>(timeFields.size())); // cast:this number is in the range of 0 ... 1, 2.
  BOOST_FOREACH(shared_ptr<const Field> f, timeFields)
  {
    wc->Writer()->WriteInt32(f->Offset());
  }
}

}

max_stars_repo_name: jrrpanix/TeaFiles

max_issues_repo_name: jrrpanix/TeaFiles

max_forks_repo_name: jrrpanix/TeaFiles


text:
///////////////////////////////////////////////////////////////
//  Copyright 2012 John Maddock. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_

#ifndef BOOST_MP_INTEGER_HPP
#define BOOST_MP_INTEGER_HPP

#include <boost/multiprecision/cpp_int.hpp>

namespace boost{
namespace multiprecision{

template <class Integer, class I2>
typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer>::type
   multiply(Integer& result, const I2& a, const I2& b)
{
   return result = static_cast<Integer>(a) * static_cast<Integer>(b);
}
template <class Integer, class I2>
typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer>::type
   add(Integer& result, const I2& a, const I2& b)
{
   return result = static_cast<Integer>(a) + static_cast<Integer>(b);
}
template <class Integer, class I2>
typename enable_if_c<is_integral<Integer>::value && is_integral<I2>::value, Integer>::type
   subtract(Integer& result, const I2& a, const I2& b)
{
   return result = static_cast<Integer>(a) - static_cast<Integer>(b);
}

template <class Integer>
typename enable_if_c<is_integral<Integer>::value>::type divide_qr(const Integer& x, const Integer& y, Integer& q, Integer& r)
{
   q = x / y;
   r = x % y;
}

template <class I1, class I2>
typename enable_if_c<is_integral<I1>::value && is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
{
   return static_cast<I2>(x % val);
}

namespace detail{
//
// Figure out the kind of integer that has twice as many bits as some builtin
// integer type I.  Use a native type if we can (including types which may not
// be recognised by boost::int_t because they're larger than long long),
// otherwise synthesize a cpp_int to do the job.
//
template <class I>
struct double_integer
{
   static const unsigned int_t_digits =
      2 * sizeof(I) <= sizeof(long long) ? std::numeric_limits<I>::digits * 2 : 1;

   typedef typename mpl::if_c<
      2 * sizeof(I) <= sizeof(long long),
      typename mpl::if_c<
         is_signed<I>::value,
         typename boost::int_t<int_t_digits>::least,
         typename boost::uint_t<int_t_digits>::least
      >::type,
      typename mpl::if_c<
         2 * sizeof(I) <= sizeof(double_limb_type),
         typename mpl::if_c<
            is_signed<I>::value,
            signed_double_limb_type,
            double_limb_type
         >::type,
         number<cpp_int_backend<sizeof(I)*CHAR_BIT*2, sizeof(I)*CHAR_BIT*2, (is_signed<I>::value ? signed_magnitude : unsigned_magnitude), unchecked, void> >
      >::type
   >::type type;
};

}

template <class I1, class I2, class I3>
typename enable_if_c<is_integral<I1>::value && is_integral<I2>::value && is_integral<I3>::value, I1>::type
   powm(const I1& a, I2 b, I3 c)
{
   typedef typename detail::double_integer<I1>::type double_type;

   I1 x(1), y(a);
   double_type result;

   while(b > 0)
   {
      if(b & 1)
      {
         multiply(result, x, y);
         x = integer_modulus(result, c);
      }
      multiply(result, y, y);
      y = integer_modulus(result, c);
      b >>= 1;
   }
   return x % c;
}

template <class Integer>
typename enable_if_c<is_integral<Integer>::value, unsigned>::type lsb(const Integer& val)
{
   if(val <= 0)
   {
      if(val == 0)
      {
         BOOST_THROW_EXCEPTION(std::range_error("No bits were set in the operand."));
      }
      else
      {
         BOOST_THROW_EXCEPTION(std::range_error("Testing individual bits in negative values is not supported - results are undefined."));
      }
   }
   unsigned index = 0;
   Integer mask = 1;

   while(((mask & val) == 0) && (index < sizeof(Integer) * CHAR_BIT))
   {
      ++index;
      mask <<= 1;
   }
   return index;
}

template <class Integer>
typename enable_if_c<is_integral<Integer>::value, bool>::type bit_test(const Integer& val, unsigned index)
{
   Integer mask = 1;
   if(index >= sizeof(Integer) * CHAR_BIT)
      return 0;
   if(index)
      mask <<= index;
   return val & mask ? true : false;
}

template <class Integer>
typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_set(Integer& val, unsigned index)
{
   Integer mask = 1;
   if(index >= sizeof(Integer) * CHAR_BIT)
      return val;
   if(index)
      mask <<= index;
   val |= mask;
   return val;
}

template <class Integer>
typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_unset(Integer& val, unsigned index)
{
   Integer mask = 1;
   if(index >= sizeof(Integer) * CHAR_BIT)
      return val;
   if(index)
      mask <<= index;
   val &= ~mask;
   return val;
}

template <class Integer>
typename enable_if_c<is_integral<Integer>::value, Integer&>::type bit_flip(Integer& val, unsigned index)
{
   Integer mask = 1;
   if(index >= sizeof(Integer) * CHAR_BIT)
      return val;
   if(index)
      mask <<= index;
   val ^= mask;
   return val;
}

}} // namespaces

#endif


text:
// Copyright (c) 2011-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "nftadddialog.h"
#include "forms/ui_nftadddialog.h"
#include "addressbookpage.h"
#include "addresstablemodel.h"
#include "bitcoinunits.h"
#include "guiutil.h"
#include "util.h"
#include "optionsmodel.h"
#include "walletmodel.h"
#include "validation.h"
#include "rpcpog.h"
#include <QAction>
#include <QCursor>
#include <QItemSelection>
#include <QMessageBox>
#include <QScrollBar>
#include <QTextDocument>
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <QListView>
#include <QStandardItem>

NFTAddDialog::NFTAddDialog(const PlatformStyle *platformStyle, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::NFTAddDialog),
    model(0),
    platformStyle(platformStyle)
{
    ui->setupUi(this);
	// Add/Edit NFT section
	ui->cmbNFTType->clear();
	ui->cmbNFTType->addItem("Digital Goods (MP3, PNG, GIF, JPEG, PDF)");
	ui->cmbNFTType->addItem("Social Media (Tweet, Post, URL)");
	ui->cmbNFTType->addItem("Orphan (Child to be sponsored)");
	ui->txtMinimumBidAmount->setValidator( new QIntValidator(0, 100000000, this) );
	ui->txtReserveAmount->setValidator( new QIntValidator(0, 100000000, this) );
	ui->txtBuyItNowAmount->setValidator( new QIntValidator(0, 100000000, this) );
	std::string sCPK = DefaultRecAddress("Christian-Public-Key");
	ui->txtOwnerAddress->setText(GUIUtil::TOQS(sCPK));
}

void NFTAddDialog::UpdateDisplay(std::string sAction, uint256 nftHash)
{
	// Action == CREATE or EDIT
	msMode = sAction;
	if (sAction == "CREATE")
	{
		ui->lblAction->setText(GUIUtil::TOQS("Add new NFT"));
		clear();
	}
	else if (sAction == "EDIT")
	{
		ui->lblAction->setText(GUIUtil::TOQS("Edit NFT"));
		NFT n = GetSpecificNFT(nftHash);
		if (!n.found)
		{
			 QMessageBox::warning(this, tr("NFT Not Found"), GUIUtil::TOQS("Sorry, we cannot find this nft " + nftHash.GetHex()), QMessageBox::Ok, QMessageBox::Ok);
			 return;
		}
		ui->lblAction->setText(GUIUtil::TOQS("Edit NFT " + nftHash.GetHex()));
		ui->txtName->setText(GUIUtil::TOQS(n.sName));
		ui->txtDescription->setPlainText(GUIUtil::TOQS(n.sDescription));
		ui->txtLoQualityURL->setText(GUIUtil::TOQS(n.sLoQualityURL));
		ui->txtHiQualityURL->setText(GUIUtil::TOQS(n.sHiQualityURL));  // User has to set this every time they edit.
		ui->txtReserveAmount->setText(GUIUtil::TOQS(RoundToString((double)n.nReserveAmount/COIN, 2)));
		ui->txtBuyItNowAmount->setText(GUIUtil::TOQS(RoundToString((double)n.nBuyItNowAmount/COIN, 2)));
		ui->txtMinimumBidAmount->setText(GUIUtil::TOQS(RoundToString((double)n.nMinimumBidAmount/COIN, 2)));
		ui->chkMarketable->setChecked(n.fMarketable);
		ui->chkDeleted->setChecked(n.fDeleted);
		ui->cmbNFTType->setCurrentIndex(ui->cmbNFTType->findText(GUIUtil::TOQS(n.sType)));
	}
	std::string sInfo = "Note: It costs 100 BBP to create or edit an NFT.";
	ui->txtInfo->setText(GUIUtil::TOQS(sInfo));
}

void NFTAddDialog::setModel(WalletModel *model)
{
    this->model = model;
}

NFTAddDialog::~NFTAddDialog()
{
    delete ui;
}

void NFTAddDialog::clear()
{
    ui->txtName->setText("");
	ui->txtDescription->setPlainText("");
    ui->txtLoQualityURL->setText("");
	ui->txtHiQualityURL->setText("");
	ui->txtMinimumBidAmount->setText("");
	ui->txtReserveAmount->setText("");
	ui->txtBuyItNowAmount->setText("");
	ui->chkDeleted->setChecked(false);
	ui->chkMarketable->setChecked(false);
}

void NFTAddDialog::on_btnSubmit_clicked()
{
	NFT n;

	n.sName = GUIUtil::FROMQS(ui->txtName->text());
	n.sCPK = GUIUtil::FROMQS(ui->txtOwnerAddress->text());
	n.nMinimumBidAmount = cdbl(GUIUtil::FROMQS(ui->txtMinimumBidAmount->text()), 2) * COIN;
	n.nReserveAmount = cdbl(GUIUtil::FROMQS(ui->txtReserveAmount->text()), 2) * COIN;
	n.nBuyItNowAmount = cdbl(GUIUtil::FROMQS(ui->txtBuyItNowAmount->text()), 2) * COIN;
	std::string sError1;
	n.sLoQualityURL = SanitizeString(GUIUtil::FROMQS(ui->txtLoQualityURL->text()), SAFE_CHARS_URL);
	n.sHiQualityURL = RSAEncryptHQURL(SanitizeString(GUIUtil::FROMQS(ui->txtHiQualityURL->text()), SAFE_CHARS_URL), sError1);
	n.sDescription = GUIUtil::FROMQS(ui->txtDescription->toPlainText());
	n.fMarketable = ui->chkMarketable->checkState();
	n.fDeleted = ui->chkDeleted->checkState();
	std::string sError;
	if (n.sName.length() < 3)
		sError += "NFT Name must be populated. ";
	if (n.sDescription.length() < 5)
		sError += "NFT Description must be populated. ";

	if (!ValidateAddress2(n.sCPK))
		sError += "NFT Owner Address is invalid. ";
	if (n.sLoQualityURL.length() < 10 || n.sHiQualityURL.length() < 10)
		sError += "You must enter an asset URL. ";
	//combobox->itemData(combobox->currentIndex())
	n.sType = GUIUtil::FROMQS(ui->cmbNFTType->currentText());
	if (n.sType.empty())
		sError += "NFT Type must be chosen. ";

	if (n.sName.length() > 128)
		sError += "NFT Name must be < 128 chars.";
	if (n.sDescription.length() > 512)
		sError += "NFT Description must be < 512 chars.";
	if (n.sLoQualityURL.length() > 512 || n.sHiQualityURL.length() > 1024)
		sError += "URL Length must be < 512 (lo) and 1024 (hi) chars.";

	CAmount nBalance = GetRPCBalance();

	if (nBalance < (100*COIN))
		sError += "Sorry balance too low to create an NFT. ";

    std::string sTXID;
	bool fCreated = ProcessNFT(n, msMode, n.sCPK, 0, false, sError);

	std::string sNarr = (sError.empty()) ? "Successfully " + msMode + "(ed) NFT " + sTXID + ".

Thank you for using BiblePay Non Fungible Tokens." : sError;

 	QMessageBox::warning(this, tr("NFT Add Result"), GUIUtil::TOQS(sNarr), QMessageBox::Ok, QMessageBox::Ok);
	if (sError.empty())
	{
		clear();
	}
}

max_stars_repo_name: biblepay/biblepay

max_issues_repo_name: biblepay/biblepay

max_forks_repo_name: biblepay/biblepay


text:
#include "tsdf_volume.h"

#include <iostream>
#include <fstream>
#include <cmath>
#include <Eigen/Geometry>
#include <opencv2/highgui/highgui.hpp>

TSDFVolume::TSDFVolume(const Vec3i &dimensions, const Vec3f &size, const Mat3f &K, const float truncationDistance, size_t frameNumber) :
    m_dim(dimensions),
    m_gridSize(m_dim[0] * m_dim[1] * m_dim[2]),
    m_size(size),
    m_voxelSize(Vec3f(m_size.cwiseQuotient(m_dim.cast<float>()))),
    m_tsdf(0),
    m_weights(0),
    m_colorR(0),
    m_colorG(0),
    m_colorB(0),
    m_weightsColor(0),
    m_delta(truncationDistance),
    m_deltaInv(1.0f / truncationDistance),
    m_K(K),
    m_frameNumber(frameNumber)
{
    init();
}

TSDFVolume::~TSDFVolume()
{
    release();
}

bool TSDFVolume::init()
{
    try
    {
        // allocate and initialize memory
        m_tsdf = new float[m_gridSize];
        std::fill_n(m_tsdf, m_gridSize, -1.0f);

        m_weights = new float[m_gridSize];
        std::fill_n(m_weights, m_gridSize, 0.0f);

        unsigned char defaultColor = 127; //0;
        m_colorR = new unsigned char[m_gridSize];
        std::fill_n(m_colorR, m_gridSize, defaultColor);
        m_colorG = new unsigned char[m_gridSize];
        std::fill_n(m_colorG, m_gridSize, defaultColor);
        m_colorB = new unsigned char[m_gridSize];
        std::fill_n(m_colorB, m_gridSize, defaultColor);

        m_weightsColor = new float[m_gridSize];
        std::fill_n(m_weightsColor, m_gridSize, 0.0f);
    }
    catch (...)
    {
        release();
        return false;
    }
    return true;
}

void TSDFVolume::release()
{
    delete[] m_tsdf;
    m_tsdf = 0;
    delete[] m_weights;
    m_weights = 0;
    delete[] m_colorR;
    m_colorR = 0;
    delete[] m_colorG;
    m_colorG = 0;
    delete[] m_colorB;
    m_colorB = 0;
    delete[] m_weightsColor;
    m_weightsColor = 0;
}

float TSDFVolume::truncate(float sdf) const
{
    float tsdf = sdf;
    if (tsdf > m_delta)
        tsdf = m_delta;
    else if (tsdf < -m_delta)
        tsdf = -m_delta;
    return tsdf * m_deltaInv;   // normalize tsdf value to interval [-1.0,...,1.0]
}

void TSDFVolume::integrate(const Mat4f &pose, const cv::Mat &color, const cv::Mat &depth, const cv::Mat &normals)
{
    Mat3f R = pose.topLeftCorner(3,3);
    Vec3f t = pose.topRightCorner(3,1);

    const float* ptrDepth = (float*)depth.data;
    unsigned char* ptrColor = 0;
    if (!color.empty())
        ptrColor = (unsigned char*)color.data;
    int h = depth.rows;
    int w = depth.cols;
    float fx = m_K(0, 0);
    float fy = m_K(1, 1);
    float cx = m_K(0, 2);
    float cy = m_K(1, 2);

    // project each voxel into output image
    for (size_t z = 0; z < m_dim[2]; ++z)
    {
        for (size_t y = 0; y < m_dim[1]; ++y)
        {
            for (size_t x = 0; x < m_dim[0]; ++x)
            {
                size_t off = z*m_dim[0]*m_dim[1] + y*m_dim[0] + x;

                // transform voxel into view
                Vec3i vx(x, y, z);
                Vec3f pt = voxelToWorld(vx);
                Vec3f ptTf = R * pt + t;

                // check if voxel is behind the camera
                float distVoxel = ptTf[2];
                if (distVoxel <= 0.0f)
                    continue;

                // project point into camera and round to nearest integer to avoid smearing out of object boundaries to the background
                float zInv = 1.0f / ptTf[2];
                float uf = (fx * ptTf[0] * zInv) + cx;
                float vf = (fy * ptTf[1] * zInv) + cy;
                int u = static_cast<int>(uf + 0.5f);
                int v = static_cast<int>(vf + 0.5f);

                if (u >= 0 && u < w && v >= 0 && v < h)
                {
                    size_t idx = v*w + u;
                    size_t idx3 = idx * 3;
                    float depthIn = ptrDepth[idx];
                    if (depthIn == 0.0f || std::isnan(depthIn))
                    {
                        continue;
                    }

                    // compute tsdf value
                    float sdfVal = ptTf[2] - depthIn;

                    // truncate tsdf value
                    float tsdfVal = truncate(sdfVal);

                    // compute weight
                    float wTsdf = 0.0f;
                    if (sdfVal <= 0)//-m_delta)
                    {
                        wTsdf = 1.0f;
                    }
                    else if (sdfVal <= m_delta)
                    {
                        // constant weighting function
                        // wTsdf = 1.0f;
                        // linear weighting function
                        //  wTsdf = (tsdfVal + 1.0f) / 2.0f;
                        wTsdf = 1.0f - tsdfVal;
                    }

                    float wTsdfNew = 0.0f;
                    if (wTsdf > 0.0f)
                    {
                        // average weight
                        float wTsdfOld = m_weights[off];
                        float tsdfOld = m_tsdf[off];
                        // average tsdf value
                        wTsdfNew = wTsdfOld + wTsdf;
                        float tsdfNew = (tsdfOld * wTsdfOld + tsdfVal * wTsdf) / wTsdfNew;
                        m_tsdf[off] = tsdfNew;

                        m_weights[off] = wTsdfNew;
                    }

#if 1
                    // separate weighting for colors
                    float wColorOld = m_weightsColor[off];
                    if (sdfVal <= m_delta || wColorOld == 0.0f)
                    {
                        float wColor = wTsdf;
                        float wColorNew;
                        Vec3b c(ptrColor[idx3], ptrColor[idx3+1], ptrColor[idx3+2]);
                        unsigned char cR = c[2];
                        unsigned char cG = c[1];
                        unsigned char cB = c[0];
                        if (wColorOld == 0.0f)
                        {
                            wColorNew = wColor;
                        }
                        else
                        {
                            // compute color averaging weights
                            wColorNew = wColorOld + wColor;
                            float w0 = wColorOld / wColorNew;
                            float w1 = 1.0f - w0;
                            // compute average color
                            cR = (unsigned char)(m_colorR[off] * w0 + cR * w1);
                            cG = (unsigned char)(m_colorG[off] * w0 + cG * w1);
                            cB = (unsigned char)(m_colorB[off] * w0 + cB * w1);
                        }
                        m_weightsColor[off] = wColorNew;

                        // voxel color
                        m_colorR[off] = cR;
                        m_colorG[off] = cG;
                        m_colorB[off] = cB;
                    }
#endif
                }
            }
        }
    }
}

float TSDFVolume::interpolate3(float x, float y, float z) const
{
    Vec3f pt(x, y, z);
    Vec3f voxel = (pt + m_size.cast<float>()*0.5f).cwiseQuotient(m_voxelSize);
    return interpolate3voxel(voxel[0], voxel[1], voxel[2]);
}

float TSDFVolume::interpolate3voxel(float x, float y, float z) const
{
    Vec3f voxel(x, y, z);
    if (voxel[0] < 0.0f || voxel[0] > m_dim[0] - 1 ||
            voxel[1] < 0.0f || voxel[1] > m_dim[1] - 1 ||
            voxel[2] < 0.0f || voxel[2] > m_dim[2] - 1)
        return -1.0f;

    // tri-linear interpolation
    const int x0 = static_cast<int>(voxel[0]);
    const int y0 = static_cast<int>(voxel[1]);
    const int z0 = static_cast<int>(voxel[2]);
    const int x1 = x0 + 1;
    const int y1 = y0 + 1;
    const int z1 = z0 + 1;

    if (x1 >= m_dim[0] || y1 >= m_dim[1] || z1 >= m_dim[2])
        return m_tsdf[z0 * m_dim[0] * m_dim[1] + y0 * m_dim[0] + x0];

    const float xd = voxel[0] - x0;
    const float yd = voxel[1] - y0;
    const float zd = voxel[2] - z0;

    const float sdf000 = m_tsdf[z0 * m_dim[0] * m_dim[1] + y0 * m_dim[0] + x0];
    const float sdf010 = m_tsdf[z0 * m_dim[0] * m_dim[1] + y1 * m_dim[0] + x0];
    const float sdf001 = m_tsdf[z1 * m_dim[0] * m_dim[1] + y0 * m_dim[0] + x0];
    const float sdf011 = m_tsdf[z1 * m_dim[0] * m_dim[1] + y1 * m_dim[0] + x0];
    const float sdf100 = m_tsdf[z0 * m_dim[0] * m_dim[1] + y0 * m_dim[0] + x1];
    const float sdf110 = m_tsdf[z0 * m_dim[0] * m_dim[1] + y1 * m_dim[0] + x1];
    const float sdf101 = m_tsdf[z1 * m_dim[0] * m_dim[1] + y0 * m_dim[0] + x1];
    const float sdf111 = m_tsdf[z1 * m_dim[0] * m_dim[1] + y1 * m_dim[0] + x1];

    const float c00 = sdf000 * (1.0f - xd) + sdf100 * xd;
    const float c10 = sdf010 * (1.0f - xd) + sdf110 * xd;
    const float c01 = sdf001 * (1.0f - xd) + sdf101 * xd;
    const float c11 = sdf011 * (1.0f - xd) + sdf111 * xd;

    const float c0 = c00 * (1.0f - yd) + c10 * yd;
    const float c1 = c01 * (1.0f - yd) + c11 * yd;

    return c0 * (1.0f - zd) + c1 * zd;
}

bool TSDFVolume::load(const std::string &filename)
{
    std::ifstream inFile(filename.c_str(), std::ios::binary);
    if (!inFile.is_open())
        return false;

    release();

    inFile.read((char*)m_dim.data(), sizeof(int) * 3);
    m_gridSize = m_dim[0] * m_dim[1] * m_dim[2];
    inFile.read((char*)m_size.data(), sizeof(double) * 3);
    inFile.read((char*)&m_delta, sizeof(float));
    m_deltaInv = 1.0f / m_delta;

    bool ok = init();

    inFile.read((char*)m_tsdf, sizeof(float) * m_gridSize);
    inFile.read((char*)m_weights, sizeof(float) * m_gridSize);

    inFile.read((char*)m_colorR, sizeof(unsigned char) * m_gridSize);
    inFile.read((char*)m_colorG, sizeof(unsigned char) * m_gridSize);
    inFile.read((char*)m_colorB, sizeof(unsigned char) * m_gridSize);
    inFile.read((char*)m_weightsColor, sizeof(float) * m_gridSize);

    inFile.close();

    return ok;
}

bool TSDFVolume::save(const std::string &filename)
{
    std::ofstream outFile(filename.c_str(), std::ios::binary);
    if (!outFile.is_open())
        return false;

    outFile.write((const char*)m_dim.data(), sizeof(int) * 3);
    outFile.write((const char*)m_size.data(), sizeof(double) * 3);
    outFile.write((const char*)&m_delta, sizeof(float));
    outFile.write((const char*)m_tsdf, sizeof(float) * m_gridSize);
    outFile.write((const char*)m_weights, sizeof(float) * m_gridSize);

    outFile.write((const char*)m_colorR, sizeof(unsigned char) * m_gridSize);
    outFile.write((const char*)m_colorG, sizeof(unsigned char) * m_gridSize);
    outFile.write((const char*)m_colorB, sizeof(unsigned char) * m_gridSize);
    outFile.write((const char*)m_weightsColor, sizeof(float) * m_gridSize);

    outFile.close();
}

Vec3f TSDFVolume::surfaceNormal(int i, int j, int k)
{
    Vec3f n = Vec3f::Zero();
    if (i < 0 || j < 0 || k < 0 ||
            i >= m_dim[0]-1 || j >= m_dim[1]-1 || k >= m_dim[2]-1)
        return n;

    size_t idx0 = k * m_dim[0] * m_dim[1] + j * m_dim[0] + i;
    size_t idx1 = k * m_dim[0] * m_dim[1] + j * m_dim[0] + (i+1);
    size_t idx2 = k * m_dim[0] * m_dim[1] + (j+1) * m_dim[0] + i;
    size_t idx3 = (k+1) * m_dim[0] * m_dim[1] + j * m_dim[0] + i;

    float sdf0 = m_tsdf[idx0];
    n[0] = m_tsdf[idx1] - sdf0;
    n[1] = m_tsdf[idx2] - sdf0;
    n[2] = m_tsdf[idx3] - sdf0;
    if (n.norm() != 0.0f)
        n.normalize();
    return n;
}

void TSDFVolume::bbox(Vec3 &min, Vec3 &max) const
{
    min = Vec3(-m_size[0]*0.5, -m_size[1]*0.5, -m_size[2]*0.5);
    max = Vec3(m_size[0]*0.5, m_size[1]*0.5, m_size[2]*0.5);
}

void TSDFVolume::setSize(const Vec3f &size)
{
    m_size = size;
    m_voxelSize = m_size.cwiseQuotient(m_dim.cast<float>());
}

Vec3f TSDFVolume::size() const
{
    return m_size;
}

Vec3i TSDFVolume::dimensions() const
{
    return m_dim;
}

Vec3f TSDFVolume::voxelToWorld(const Vec3i &voxel) const
{
    Vec3f pt = voxel.cast<float>().cwiseProduct(m_voxelSize) - m_size*0.5f;
    return pt;
}

Vec3f TSDFVolume::voxelToWorld(int i, int j, int k) const
{
    return voxelToWorld(Vec3i(i, j, k));
}

Vec3f TSDFVolume::voxelToWorld(const Vec3f &voxel) const
{
    Vec3f pt = voxel.cwiseProduct(m_voxelSize) - m_size*0.5f;
    return pt;
}

Vec3i TSDFVolume::worldToVoxel(const Vec3f &pt) const
{
    Vec3f voxelSizeInv(1.0 / m_voxelSize[0], 1.0 / m_voxelSize[1], 1.0 / m_voxelSize[2]);
    Vec3f voxelF = (pt + 0.5f * m_size).cwiseProduct(voxelSizeInv);
    Vec3i voxelIdx = voxelF.cast<int>();
    return voxelIdx;
}

Vec3f TSDFVolume::worldToVoxelF(const Vec3f &pt) const
{
    Vec3f voxelSizeInv(1.0 / m_voxelSize[0], 1.0 / m_voxelSize[1], 1.0 / m_voxelSize[2]);
    Vec3f voxelF = (pt + 0.5f * m_size).cwiseProduct(voxelSizeInv);
    return voxelF;
}