Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
855 lines (701 sloc) 30 KB
#include <QtGui>
#include <iostream>
#include "Global.h"
#include "GLCamera.h"
#include "MainWindow.h"
#include "GLModelWidget.h"
#include "PreferencesDialog.h"
#include "ConsoleWidget.h"
#include "pyConsole.h"
#include "ImportExport.h"
#include <QFileDialog>
#include <QColorDialog>
#define DEFAULT_VOXGRID_SZ (8)
MainWindow::MainWindow(const QString& initialFilename, QWidget *parent) :
QMainWindow(parent),
m_appSettings("OpenSource", "Sproxel"),
m_activeFilename(""),
m_project(new SproxelProject())
{
// Project
VoxelGridGroupPtr sprite(new VoxelGridGroup(Imath::V3i(DEFAULT_VOXGRID_SZ, DEFAULT_VOXGRID_SZ, DEFAULT_VOXGRID_SZ),
ColorPalettePtr()));
sprite->setName("unnamed");
m_project->sprites.push_back(sprite);
// Windows
m_glModelWidget = new GLModelWidget(this, &m_appSettings, &m_undoManager, sprite);
setCentralWidget(m_glModelWidget);
// The docking palette widget
m_paletteDocker = new QDockWidget(tr("Palette"), this);
m_paletteDocker->setObjectName("paletteDocker");
m_paletteDocker->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_paletteWidget = new PaletteWidget(this, &m_undoManager);
m_paletteDocker->setWidget(m_paletteWidget);
m_paletteWidget->setPalette(m_project->mainPalette);
addDockWidget(Qt::RightDockWidgetArea, m_paletteDocker);
// The docking project widget
m_projectDocker=new QDockWidget(tr("Project"), this);
m_projectDocker->setObjectName("projectDocker");
m_projectWidget=new ProjectWidget(this, &m_undoManager, &m_appSettings);
m_projectDocker->setWidget(m_projectWidget);
m_projectWidget->setProject(m_project);
addDockWidget(Qt::RightDockWidgetArea, m_projectDocker);
// The docking layers widget
//m_layersDocker = new QDockWidget(tr("Layers"), this);
//m_layersDocker->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
//m_layersWidget = new LayersWidget(this);
//m_layersDocker->setWidget(m_layersWidget);
//addDockWidget(Qt::RightDockWidgetArea, m_layersDocker);
// Connect some window signals together
QObject::connect(m_paletteWidget, SIGNAL(activeColorChanged(Imath::Color4f, int)),
m_glModelWidget, SLOT(setActiveColor(Imath::Color4f, int)));
QObject::connect(m_glModelWidget, SIGNAL(colorSampled(Imath::Color4f, int)),
m_paletteWidget, SLOT(setActiveColor(Imath::Color4f, int)));
QObject::connect(&m_undoManager, SIGNAL(cleanChanged(bool)),
this, SLOT(reactToModified(bool)));
QObject::connect(m_projectWidget, SIGNAL(spriteSelected(VoxelGridGroupPtr)),
m_glModelWidget, SLOT(setSprite(VoxelGridGroupPtr)));
// Toolbar
m_toolbar = new QToolBar("Tools", this);
m_toolbar->setObjectName("toolbar");
m_toolbar->setOrientation(Qt::Vertical);
addToolBar(Qt::LeftToolBarArea, m_toolbar);
// Actions & Menus
menuBar()->show();
m_menuFile = menuBar()->addMenu("Fi&le");
m_actFileNew = new QAction("&New", this);
m_actFileNew->setShortcut(Qt::CTRL + Qt::Key_N);
m_menuFile->addAction(m_actFileNew);
connect(m_actFileNew, SIGNAL(triggered()),
this, SLOT(newGrid()));
m_menuFile->addSeparator();
m_actFileOpen = new QAction("&Open", this);
m_actFileOpen->setShortcut(Qt::CTRL + Qt::Key_O);
m_menuFile->addAction(m_actFileOpen);
connect(m_actFileOpen, SIGNAL(triggered()),
this, SLOT(openFile()));
m_actFileSave = new QAction("&Save", this);
m_actFileSave->setShortcut(Qt::CTRL + Qt::Key_S);
m_menuFile->addAction(m_actFileSave);
connect(m_actFileSave, SIGNAL(triggered()),
this, SLOT(saveFile()));
m_actFileSaveAs = new QAction("Save &As", this);
m_menuFile->addAction(m_actFileSaveAs);
connect(m_actFileSaveAs, SIGNAL(triggered()),
this, SLOT(saveFileAs()));
m_menuFile->addSeparator();
m_actFileImport = new QAction("&Import...", this);
m_menuFile->addAction(m_actFileImport);
connect(m_actFileImport, SIGNAL(triggered()),
this, SLOT(import()));
m_actFileExportGrid = new QAction("&Export...", this);
m_menuFile->addAction(m_actFileExportGrid);
connect(m_actFileExportGrid, SIGNAL(triggered()),
this, SLOT(exportGrid()));
m_menuFile->addSeparator();
m_actQuit = new QAction("&Quit", this);
m_actQuit->setShortcut(Qt::CTRL + Qt::Key_Q);
m_menuFile->addAction(m_actQuit);
connect(m_actQuit, SIGNAL(triggered()),
this, SLOT(close()));
// ------ edit menu
m_menuEdit = menuBar()->addMenu("&Edit");
m_actUndo=m_undoManager.createUndoAction(this, "Undo");
m_actUndo->setShortcut(Qt::CTRL + Qt::Key_Z);
m_menuEdit->addAction(m_actUndo);
m_actRedo=m_undoManager.createRedoAction(this, "Redo");
m_actRedo->setShortcut(Qt::CTRL + Qt::SHIFT + Qt::Key_Z);
m_menuEdit->addAction(m_actRedo);
m_menuEdit->addSeparator();
m_actShiftUp = new QAction("Shift up", this);
m_actShiftUp->setShortcut(Qt::CTRL + Qt::Key_BracketRight);
m_menuEdit->addAction(m_actShiftUp);
connect(m_actShiftUp, SIGNAL(triggered()),
this, SLOT(shiftUp()));
m_actShiftDown = new QAction("Shift down", this);
m_actShiftDown->setShortcut(Qt::CTRL + Qt::Key_BracketLeft);
m_menuEdit->addAction(m_actShiftDown);
connect(m_actShiftDown, SIGNAL(triggered()),
this, SLOT(shiftDown()));
m_actShiftWrap = new QAction("Wrap shift ops", this);
m_actShiftWrap->setCheckable(true);
m_actShiftWrap->setChecked(m_glModelWidget->shiftWrap());
m_menuEdit->addAction(m_actShiftWrap);
connect(m_actShiftWrap, SIGNAL(toggled(bool)),
m_glModelWidget, SLOT(setShiftWrap(bool)));
m_actRotateCw = new QAction("Rotate clockwise", this);
m_actRotateCw->setShortcut(Qt::CTRL + Qt::Key_Greater);
m_menuEdit->addAction(m_actRotateCw);
connect(m_actRotateCw, SIGNAL(triggered()),
this, SLOT(rotateCw()));
m_actRotateCcw = new QAction("Rotate counter-clockwise", this);
m_actRotateCcw->setShortcut(Qt::CTRL + Qt::Key_Less);
m_menuEdit->addAction(m_actRotateCcw);
connect(m_actRotateCcw, SIGNAL(triggered()),
this, SLOT(rotateCcw()));
m_actMirror = new QAction("Mirror", this);
m_actMirror->setShortcut(Qt::CTRL + Qt::Key_M);
m_menuEdit->addAction(m_actMirror);
connect(m_actMirror, SIGNAL(triggered()),
this, SLOT(mirror()));
m_menuEdit->addSeparator();
m_actPreferences = new QAction("Preferences...", this);
m_menuEdit->addAction(m_actPreferences);
connect(m_actPreferences, SIGNAL(triggered()),
this, SLOT(editPreferences()));
// ------ grid menu
m_menuGrid = menuBar()->addMenu("&Grid");
m_actExtendUp = new QAction("Extend grid dimension up", this);
m_actExtendUp->setShortcut(Qt::CTRL + Qt::Key_Plus);
m_menuGrid->addAction(m_actExtendUp);
connect(m_actExtendUp, SIGNAL(triggered()),
this, SLOT(extendUp()));
m_actExtendDown = new QAction("Extend grid dimension down", this);
m_actExtendDown->setShortcut(Qt::CTRL + Qt::Key_Minus);
m_menuGrid->addAction(m_actExtendDown);
connect(m_actExtendDown, SIGNAL(triggered()),
this, SLOT(extendDown()));
m_actContractUp = new QAction("Contract grid dimension from above", this);
m_menuGrid->addAction(m_actContractUp);
connect(m_actContractUp, SIGNAL(triggered()),
this, SLOT(contractUp()));
m_actContractDown = new QAction("Contract grid dimension from below", this);
m_menuGrid->addAction(m_actContractDown);
connect(m_actContractDown, SIGNAL(triggered()),
this, SLOT(contractDown()));
m_menuGrid->addSeparator();
m_actUpRes = new QAction("Double grid resolution", this);
m_menuGrid->addAction(m_actUpRes);
connect(m_actUpRes, SIGNAL(triggered()),
this, SLOT(upRes()));
m_actDownRes = new QAction("Half grid resolution", this);
m_menuGrid->addAction(m_actDownRes);
connect(m_actDownRes, SIGNAL(triggered()),
this, SLOT(downRes()));
// ------ view menu
m_menuView = menuBar()->addMenu("&View");
QAction *action=new QAction(tr("Frame sprite"), this);
action->setShortcut(Qt::Key_Z);
m_menuView->addAction(action);
connect(action, SIGNAL(triggered()),
m_glModelWidget, SLOT(frameFull()));
m_actViewGrid = new QAction("View Grid", this);
m_actViewGrid->setShortcut(Qt::CTRL + Qt::Key_G);
m_actViewGrid->setCheckable(true);
m_actViewGrid->setChecked(m_glModelWidget->drawGrid());
m_menuView->addAction(m_actViewGrid);
connect(m_actViewGrid, SIGNAL(toggled(bool)),
m_glModelWidget, SLOT(setDrawGrid(bool)));
m_actViewVoxgrid = new QAction("Voxel Grid", this);
m_actViewVoxgrid->setShortcut(Qt::Key_G);
m_actViewVoxgrid->setCheckable(true);
m_actViewVoxgrid->setChecked(m_glModelWidget->drawVoxelGrid());
m_menuView->addAction(m_actViewVoxgrid);
connect(m_actViewVoxgrid, SIGNAL(toggled(bool)),
m_glModelWidget, SLOT(setDrawVoxelGrid(bool)));
m_actViewBBox = new QAction("Bounding Box", this);
m_actViewBBox->setShortcut(Qt::CTRL + Qt::Key_B);
m_actViewBBox->setCheckable(true);
m_actViewBBox->setChecked(m_glModelWidget->drawBoundingBox());
m_menuView->addAction(m_actViewBBox);
connect(m_actViewBBox, SIGNAL(toggled(bool)),
m_glModelWidget, SLOT(setDrawBoundingBox(bool)));
action=new QAction("Sprite Bounds", this);
action->setShortcut(Qt::Key_B);
action->setCheckable(true);
action->setChecked(m_glModelWidget->drawSpriteBounds());
m_menuView->addAction(action);
connect(action, SIGNAL(toggled(bool)),
m_glModelWidget, SLOT(setDrawSpriteBounds(bool)));
// ------ window menu
m_menuWindow = menuBar()->addMenu("&Window");
m_menuWindow->addAction(m_toolbar->toggleViewAction());
m_menuWindow->addAction(m_paletteDocker->toggleViewAction());
m_menuWindow->addAction(m_projectDocker->toggleViewAction());
//m_menuWindow->addAction(m_layersDocker->toggleViewAction());
m_menuWindow->addAction(get_python_console_widget()->toggleViewAction());
get_python_console_widget()->toggleViewAction()->setChecked(false);
// ------ toolbar hookups
// Icons from the brilliant icon pack located at : http://pen-art.ru/
m_toolbarActionGroup = new QActionGroup(this);
m_actToolSplat = new QAction("Splat", m_toolbarActionGroup);
m_actToolSplat->setIcon(QIcon(QPixmap(":/icons/splat.png")));
m_actToolSplat->setCheckable(true);
connect(m_actToolSplat, SIGNAL(toggled(bool)), this, SLOT(setToolSplat(bool)));
m_actToolReplace = new QAction("Replace", m_toolbarActionGroup);
m_actToolReplace->setIcon(QIcon(QPixmap(":/icons/pencil.png")));
m_actToolReplace->setCheckable(true);
connect(m_actToolReplace, SIGNAL(toggled(bool)), this, SLOT(setToolReplace(bool)));
m_actToolFlood = new QAction("Flood", m_toolbarActionGroup);
m_actToolFlood->setIcon(QIcon(QPixmap(":/icons/paintBucket.png")));
m_actToolFlood->setCheckable(true);
connect(m_actToolFlood, SIGNAL(toggled(bool)), this, SLOT(setToolFlood(bool)));
m_actToolDropper = new QAction("Dropper", m_toolbarActionGroup);
m_actToolDropper->setIcon(QIcon(QPixmap(":/icons/eyeDropper.png")));
m_actToolDropper->setCheckable(true);
connect(m_actToolDropper, SIGNAL(toggled(bool)), this, SLOT(setToolDropper(bool)));
m_actToolEraser = new QAction("Eraser", m_toolbarActionGroup);
m_actToolEraser->setIcon(QIcon(QPixmap(":/icons/eraser.png")));
m_actToolEraser->setCheckable(true);
connect(m_actToolEraser, SIGNAL(toggled(bool)), this, SLOT(setToolEraser(bool)));
m_actToolSlab = new QAction("Slab", m_toolbarActionGroup);
m_actToolSlab->setIcon(QIcon(QPixmap(":/icons/slab.png")));
m_actToolSlab->setCheckable(true);
connect(m_actToolSlab, SIGNAL(toggled(bool)), this, SLOT(setToolSlab(bool)));
m_actToolLine = new QAction("Line", m_toolbarActionGroup);
m_actToolLine->setIcon(QIcon(QPixmap(":/icons/line.png")));
m_actToolLine->setCheckable(true);
connect(m_actToolLine, SIGNAL(toggled(bool)), this, SLOT(setToolLine(bool)));
m_actToolBox = new QAction("Box", m_toolbarActionGroup);
m_actToolBox->setIcon(QIcon(QPixmap(":/icons/box.png")));
m_actToolBox->setCheckable(true);
connect(m_actToolBox, SIGNAL(toggled(bool)), this, SLOT(setToolBox(bool)));
m_actToolExtrude = new QAction("Extrude", m_toolbarActionGroup);
m_actToolExtrude->setIcon(QIcon(QPixmap(":/icons/extrude.png")));
m_actToolExtrude->setCheckable(true);
connect(m_actToolExtrude, SIGNAL(toggled(bool)), this, SLOT(setToolExtrude(bool)));
//m_actToolRay = new QAction("Ray", this);
m_actToolSplat->setChecked(true);
m_toolbar->addActions(m_toolbarActionGroup->actions());
// Toolbar widgets for slicing
m_toolbar->addSeparator();
m_minSliceBox=new QSpinBox();
m_maxSliceBox=new QSpinBox();
m_toolbar->addWidget(m_maxSliceBox);
m_toolbar->addWidget(m_minSliceBox);
connect(m_glModelWidget, SIGNAL(sliceChanged(int, int, int)), this, SLOT(updateSlice(int, int, int)));
connect(m_minSliceBox, SIGNAL(valueChanged(int)), m_glModelWidget, SLOT(setMinSlice(int)));
connect(m_maxSliceBox, SIGNAL(valueChanged(int)), m_glModelWidget, SLOT(setMaxSlice(int)));
// axis selection
QActionGroup *axisGroup=new QActionGroup(this);
QAction *a=new QAction("X", axisGroup);
a->setCheckable(true);
connect(a, SIGNAL(toggled(bool)), m_glModelWidget, SLOT(setAxisX()));
m_actAxisX=a;
a=new QAction("Y", axisGroup);
a->setCheckable(true);
connect(a, SIGNAL(toggled(bool)), m_glModelWidget, SLOT(setAxisY()));
m_actAxisY=a;
a=new QAction("Z", axisGroup);
a->setCheckable(true);
connect(a, SIGNAL(toggled(bool)), m_glModelWidget, SLOT(setAxisZ()));
m_actAxisZ=a;
m_toolbar->addSeparator();
m_toolbar->addActions(axisGroup->actions());
m_actAxisY->setChecked(true);
// Remaining verbosity
setWindowTitle(BASE_WINDOW_TITLE);
statusBar()->showMessage(tr("Ready"));
// Load up some settings
if (m_appSettings.value("saveUILayout", true).toBool())
{
resize(m_appSettings.value("MainWindow/size", QSize(546, 427)).toSize());
move(m_appSettings.value("MainWindow/position", QPoint(200, 200)).toPoint());
setWindowState((Qt::WindowStates)m_appSettings.value("MainWindow/windowState", Qt::WindowActive).toInt());
restoreState(m_appSettings.value("MainWindow/widgetsState").toByteArray());
m_toolbar->setVisible(m_appSettings.value("toolbar/visibility", true).toBool());
m_paletteDocker->setVisible(m_appSettings.value("paletteWindow/visibility", true).toBool());
m_projectDocker->setVisible(m_appSettings.value("projectWindow/visibility", true).toBool());
//m_layersDocker->setVisible(m_appSettings.value("layersWindow/visibility", true).toBool());
}
// Load the commandline supplied filename
if (initialFilename != "")
{
openFile(initialFilename);
}
// Better way to keep the state in one place
//std::cout << (m_toolbarActionGroup->checkedAction()->text() == "Splat") << std::endl;
//std::cout << qPrintable(m_toolbarActionGroup->checkedAction()->text()) << std::endl;
// Start things off focused on the GLWidget
m_glModelWidget->setFocus();
}
void MainWindow::updateSlice(int mino, int maxo, int range)
{
m_minSliceBox->setRange(0, range);
m_maxSliceBox->setRange(0, range);
m_minSliceBox->setValue(mino);
m_maxSliceBox->setValue(maxo);
}
void MainWindow::closeEvent(QCloseEvent* event)
{
// Confirmation dialog
if (!m_undoManager.isClean())
{
switch (fileModifiedDialog())
{
case QMessageBox::Save: saveFile(); event->accept(); break;
case QMessageBox::Discard: event->accept(); break;
case QMessageBox::Cancel: event->ignore(); break;
default: event->ignore(); break;
}
}
else
{
event->accept();
}
m_glModelWidget->saveSettings();
// Save some window settings on exit (if requested)
if (m_appSettings.value("saveUILayout", true).toBool())
{
m_appSettings.setValue("MainWindow/size", size());
m_appSettings.setValue("MainWindow/position", pos());
m_appSettings.setValue("MainWindow/windowState", (int)windowState());
m_appSettings.setValue("MainWindow/widgetsState", saveState());
m_appSettings.setValue("toolbar/visibility", m_toolbar->isVisible());
m_appSettings.setValue("paletteWindow/visibility", m_paletteDocker->isVisible());
m_appSettings.setValue("projectWindow/visibility", m_projectDocker->isVisible());
//m_appSettings.setValue("layersWindow/visibility", m_layersDocker->isVisible());
}
if (event->isAccepted()) close_python_console();
}
void MainWindow::keyPressEvent(QKeyEvent* event)
{
const bool altDown = event->modifiers() & Qt::AltModifier;
const bool ctrlDown = event->modifiers() & Qt::ControlModifier;
//const bool shiftDown = event->modifiers() & Qt::ShiftModifier;
if (altDown && event->key() == Qt::Key_X)
{
m_actAxisX->setChecked(true);
}
else if (altDown && event->key() == Qt::Key_Y)
{
m_actAxisY->setChecked(true);
}
else if (altDown && event->key() == Qt::Key_Z)
{
m_actAxisZ->setChecked(true);
}
else if (ctrlDown && event->key() == Qt::Key_C)
{
QColor color = QColorDialog::getColor(Qt::white, this);
m_paletteWidget->setActiveColor(Imath::Color4f((float)color.red()/255.0f,
(float)color.green()/255.0f,
(float)color.blue()/255.0f,
(float)color.alpha()/255.0f),
-1);
}
else if (ctrlDown && event->key() == Qt::Key_F)
{
// Frame the full extents no matter what
m_glModelWidget->frame(true);
}
else if (event->key() == Qt::Key_F)
{
// Frame the data if it exists
m_glModelWidget->frame(false);
}
else if (event->key() == Qt::Key_X)
{
m_paletteWidget->swapColors();
}
//else if (event->key() == Qt::Key_D)
//{
// m_paletteWidget->setDefaultColors();
//}
else if (event->key() == Qt::Key_Q) m_actToolSplat->setChecked(true);
else if (event->key() == Qt::Key_W) m_actToolReplace->setChecked(true);
else if (event->key() == Qt::Key_E) m_actToolFlood->setChecked(true);
else if (event->key() == Qt::Key_R) m_actToolDropper->setChecked(true);
else if (event->key() == Qt::Key_T) m_actToolEraser->setChecked(true);
else if (event->key() == Qt::Key_Y) m_actToolSlab->setChecked(true);
else if (event->key() == Qt::Key_U) m_actToolLine->setChecked(true);
else if (event->key() == Qt::Key_I) m_actToolBox->setChecked(true);
else if (event->key() == Qt::Key_O) m_actToolExtrude->setChecked(true);
else if (event->key() >= Qt::Key_Left && event->key() <= Qt::Key_PageDown)
{
m_glModelWidget->handleArrows(event);
}
else if (event->key() == Qt::Key_Space)
{
// It's okay to call setVoxelColor once on the model widget, but any more requires an internal wrapper
m_glModelWidget->setVoxelColor(m_glModelWidget->activeVoxel(),
m_glModelWidget->activeColor(),
m_glModelWidget->activeIndex());
m_glModelWidget->updateGL();
}
else if (event->key() == Qt::Key_Delete)
{
// It's okay to call setVoxelColor once on the model widget, but any more requires an internal wrapper
m_glModelWidget->setVoxelColor(m_glModelWidget->activeVoxel(),
Imath::Color4f(0.0f, 0.0f, 0.0f, 0.0f),
0);
m_glModelWidget->updateGL();
}
}
int MainWindow::fileModifiedDialog()
{
QMessageBox msgBox;
msgBox.setText("The document has been modified.");
msgBox.setInformativeText("Do you want to save your changes?");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
return msgBox.exec();
}
void MainWindow::newGrid()
{
// Confirmation dialog
if (!m_undoManager.isClean())
{
switch (fileModifiedDialog())
{
case QMessageBox::Save: saveFile(); break;
case QMessageBox::Discard: break;
case QMessageBox::Cancel: return; break;
}
}
NewGridDialog dlg(this);
dlg.setModal(true);
if (dlg.exec())
{
m_activeFilename = "";
m_undoManager.clear();
setWindowTitle(BASE_WINDOW_TITLE + " - " + m_activeFilename); // TODO: Functionize (resetWindowTitle)
// create new project
m_project=new SproxelProject();
VoxelGridGroupPtr sprite(new VoxelGridGroup(dlg.getVoxelSize(),
dlg.isIndexed()?m_project->mainPalette:ColorPalettePtr()));
sprite->setName("unnamed");
m_project->sprites.push_back(sprite);
m_glModelWidget->setSprite(sprite);
m_paletteWidget->setPalette(m_project->mainPalette);
m_projectWidget->setProject(m_project);
}
}
void MainWindow::saveFile()
{
if (m_undoManager.isClean())
return;
if (m_activeFilename == "")
return saveFileAs();
bool success = save_project(m_activeFilename, m_project);
if (success)
m_undoManager.setClean();
else
QMessageBox::critical(this, "Sproxel Error", QString("Error saving project to file ")+m_activeFilename);
}
void MainWindow::saveFileAs()
{
QFileDialog fd(this, "Save voxel file as...");
fd.setFilter(tr("Sproxel project (*.sxl)"));
fd.setAcceptMode(QFileDialog::AcceptSave);
fd.exec();
QStringList qsl = fd.selectedFiles();
if (qsl.isEmpty()) return;
if (QFileInfo(qsl[0]).isDir()) return; // It returns the directory if you press Cancel
QString filename = qsl[0];
QString activeFilter = fd.selectedNameFilter();
// Switch on save type
bool success = false;
if (!filename.endsWith(".sxl", Qt::CaseInsensitive))
filename.append(".sxl");
success = save_project(filename, m_project);
if (success)
{
m_undoManager.setClean();
m_activeFilename = filename;
setWindowTitle(BASE_WINDOW_TITLE + " - " + m_activeFilename); // TODO: Functionize (resetWindowTitle)
}
else
QMessageBox::critical(this, "Sproxel Error", QString("Error saving project to file ")+filename);
}
void MainWindow::openFile()
{
QString filename = QFileDialog::getOpenFileName(this,
tr("Select file to Open..."),
QString(),
tr("Sproxel projects (*.sxl)"));
if (filename.isEmpty())
return;
openFile(filename);
}
void MainWindow::openFile(QString filename)
{
// Confirmation dialog
if (!m_undoManager.isClean())
{
switch (fileModifiedDialog())
{
case QMessageBox::Save: saveFile(); break;
case QMessageBox::Discard: break;
case QMessageBox::Cancel: return; break;
}
}
bool success = false;
SproxelProjectPtr project=load_project(filename);
if (project) { m_project=project; success=true; }
if (success)
{
m_undoManager.clear();
if (m_project->sprites.empty())
{
VoxelGridGroupPtr sprite(new VoxelGridGroup(
Imath::V3i(DEFAULT_VOXGRID_SZ, DEFAULT_VOXGRID_SZ, DEFAULT_VOXGRID_SZ),
ColorPalettePtr()));
sprite->setName("unnamed");
m_project->sprites.push_back(sprite);
}
m_glModelWidget->setSprite(m_project->sprites[0]);
m_paletteWidget->setPalette(m_project->mainPalette);
m_projectWidget->setProject(m_project);
m_activeFilename = filename;
setWindowTitle(BASE_WINDOW_TITLE + " - " + m_activeFilename); // TODO: Functionize (resetWindowTitle)
if (m_appSettings.value("frameOnOpen", false).toBool())
m_glModelWidget->frame(true);
}
else
QMessageBox::critical(this, "Sproxel Error", QString("Error loading project from file ")+filename);
}
void MainWindow::import()
{
const QList<Importer*> &importers=get_importers();
QStringList filters;
filters.reserve(importers.size());
foreach (Importer *imp, importers) filters += imp->name()+" ("+imp->filter()+")";
QFileDialog fd(this, "Import file...");
fd.setNameFilters(filters);
fd.setAcceptMode(QFileDialog::AcceptOpen);
fd.setFileMode(QFileDialog::ExistingFiles);
if (!fd.exec()) return;
QStringList files=fd.selectedFiles();
if (files.isEmpty()) return;
QString activeFilter=fd.selectedNameFilter();
Importer *activeImporter=NULL;
for (int i=0; i<filters.size(); ++i)
if (filters[i]==activeFilter) { activeImporter=importers[i]; break; }
if (!activeImporter) return;
foreach (const QString &filename, files)
{
if (QFileInfo(filename).isDir()) continue;
activeImporter->doImport(filename, &m_undoManager, m_project, m_glModelWidget->getSprite());
}
}
void MainWindow::exportGrid()
{
const QList<Exporter*> &exporters=get_exporters();
QStringList filters;
filters.reserve(exporters.size());
foreach (Exporter *exp, exporters) filters += exp->name()+" ("+exp->filter()+")";
QFileDialog fd(this, "Export file...");
fd.setNameFilters(filters);
fd.setAcceptMode(QFileDialog::AcceptSave);
fd.selectNameFilter(m_appSettings.value("lastExportFilter", QString()).toString());
fd.selectFile(m_appSettings.value("lastExportFile", QString()).toString());
if (!fd.exec()) return;
QStringList files=fd.selectedFiles();
if (files.isEmpty()) return;
QString filename=files[0];
if (QFileInfo(filename).isDir()) return;
QString activeFilter=fd.selectedNameFilter();
Exporter *activeExporter=NULL;
for (int i=0; i<filters.size(); ++i)
if (filters[i]==activeFilter) { activeExporter=exporters[i]; break; }
if (!activeExporter) return;
if (!activeExporter->doExport(filename, m_project, m_glModelWidget->getSprite()))
QMessageBox::critical(this, "Sproxel Error", QString("Failed to export ")+filename);
m_appSettings.setValue("lastExportFile", filename);
m_appSettings.setValue("lastExportFilter", activeFilter);
}
void MainWindow::editPreferences()
{
PreferencesDialog dlg(this, &m_appSettings);
dlg.setModal(true);
QObject::connect(&dlg, SIGNAL(preferenceChanged()), m_glModelWidget, SLOT(updateGL()));
dlg.exec();
}
// Trampoline functions because QSignalMapper can't do complex args
// Search for QBoundMethod for a custom approach, but I'm too lazy to include it for now.
void MainWindow::shiftUp()
{
m_glModelWidget->shiftVoxels(m_glModelWidget->currentAxis(),
true, m_glModelWidget->shiftWrap());
}
void MainWindow::shiftDown()
{
m_glModelWidget->shiftVoxels(m_glModelWidget->currentAxis(),
false, m_glModelWidget->shiftWrap());
}
void MainWindow::rotateCw()
{
m_glModelWidget->rotateVoxels(m_glModelWidget->currentAxis(), 1);
}
void MainWindow::rotateCcw()
{
m_glModelWidget->rotateVoxels(m_glModelWidget->currentAxis(), -1);
}
void MainWindow::mirror()
{
m_glModelWidget->mirrorVoxels(m_glModelWidget->currentAxis());
}
void MainWindow::extendUp()
{
Imath::V3i sizeInc(0,0,0);
switch (m_glModelWidget->currentAxis())
{
case X_AXIS: sizeInc.x += 1; break;
case Y_AXIS: sizeInc.y += 1; break;
case Z_AXIS: sizeInc.z += 1; break;
}
m_glModelWidget->resizeAndShiftVoxelGrid(sizeInc, Imath::V3i(0,0,0));
}
void MainWindow::extendDown()
{
Imath::V3i shift(0,0,0);
Imath::V3i sizeInc(0,0,0);
switch (m_glModelWidget->currentAxis())
{
case X_AXIS: sizeInc.x += 1; shift.x += 1; break;
case Y_AXIS: sizeInc.y += 1; shift.y += 1; break;
case Z_AXIS: sizeInc.z += 1; shift.z += 1; break;
}
m_glModelWidget->resizeAndShiftVoxelGrid(sizeInc, shift);
}
void MainWindow::contractUp()
{
Imath::V3i sizeInc(0,0,0);
switch (m_glModelWidget->currentAxis())
{
case X_AXIS: sizeInc.x -= 1; break;
case Y_AXIS: sizeInc.y -= 1; break;
case Z_AXIS: sizeInc.z -= 1; break;
}
m_glModelWidget->resizeAndShiftVoxelGrid(sizeInc, Imath::V3i(0,0,0));
}
void MainWindow::contractDown()
{
Imath::V3i shift(0,0,0);
Imath::V3i sizeInc(0,0,0);
switch (m_glModelWidget->currentAxis())
{
case X_AXIS: sizeInc.x -= 1; shift.x -= 1; break;
case Y_AXIS: sizeInc.y -= 1; shift.y -= 1; break;
case Z_AXIS: sizeInc.z -= 1; shift.z -= 1; break;
}
m_glModelWidget->resizeAndShiftVoxelGrid(sizeInc, shift);
}
void MainWindow::upRes() { m_glModelWidget->reresVoxelGrid(2.0f); }
void MainWindow::downRes() { m_glModelWidget->reresVoxelGrid(0.5f); }
void MainWindow::setToolSplat(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_SPLAT); }
void MainWindow::setToolFlood(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_FLOOD); }
void MainWindow::setToolRay(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_RAY); }
void MainWindow::setToolDropper(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_DROPPER); }
void MainWindow::setToolEraser(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_ERASER); }
void MainWindow::setToolReplace(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_REPLACE); }
void MainWindow::setToolSlab(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_SLAB); }
void MainWindow::setToolLine(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_LINE); }
void MainWindow::setToolBox(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_BOX); }
void MainWindow::setToolExtrude(bool stat) { if (stat) m_glModelWidget->setActiveTool(TOOL_EXTRUDE); }
void MainWindow::reactToModified(bool clean)
{
QString current = windowTitle();
if (!clean)
{
if (current.endsWith("*"))
return;
setWindowTitle(current + "*");
}
else
{
current.chop(1);
setWindowTitle(current);
}
}