mirror of https://github.com/CGAL/cgal
870 lines
20 KiB
C++
870 lines
20 KiB
C++
#include "config.h"
|
|
#include "Polyhedron_type.h"
|
|
#include "Textured_polyhedron_type.h"
|
|
#include "Scene.h"
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
#include <QString>
|
|
#include <QTextStream>
|
|
#include <QFileInfo>
|
|
#include <QGLWidget>
|
|
#include <QMessageBox>
|
|
#include <QEvent>
|
|
#include <QMouseEvent>
|
|
#include <QPainter>
|
|
#include <QColorDialog>
|
|
#include <QApplication>
|
|
|
|
#include "Scene_rendering.h"
|
|
#include "Scene_nef_rendering.h"
|
|
|
|
namespace {
|
|
void CGALglcolor(QColor c)
|
|
{
|
|
::glColor4f(c.red()/255.0, c.green()/255.0, c.blue()/255.0, c.alpha()/255.0);
|
|
}
|
|
}
|
|
|
|
const QColor Scene::defaultColor = QColor(100, 100, 255);
|
|
|
|
Scene::Scene(QObject* parent)
|
|
: QAbstractListModel(parent),
|
|
selected_item(-1),
|
|
item_A(-1),
|
|
item_B(-1),
|
|
viewEdges(true)
|
|
{
|
|
// generate checkboard
|
|
texture.GenerateCheckerBoard(2048,2048,128,0,0,0,250,250,255);
|
|
}
|
|
|
|
Scene::~Scene()
|
|
{
|
|
for(Polyhedra::iterator
|
|
poly_it = polyhedra.begin(),
|
|
poly_end = polyhedra.end();
|
|
poly_it != poly_end; ++poly_it)
|
|
{
|
|
this->destroyEntry(*poly_it);
|
|
}
|
|
polyhedra.clear();
|
|
}
|
|
|
|
int
|
|
Scene::numberOfPolyhedra() const
|
|
{
|
|
return polyhedra.size();
|
|
}
|
|
|
|
void
|
|
Scene::destroyEntry(Scene::Polyhedron_entry& entry)
|
|
{
|
|
if(entry.display_list_built) {
|
|
::glDeleteLists(entry.display_list,1);
|
|
if(entry.polyhedron_ptr.which() == NEF_ENTRY) {
|
|
if(::glIsList(entry.display_list_for_edges)) {
|
|
::glDeleteLists(entry.display_list_for_edges, 1);
|
|
}
|
|
}
|
|
}
|
|
this->destroy_entry_ptr(entry.polyhedron_ptr);
|
|
}
|
|
|
|
|
|
void
|
|
Scene::destroy_entry_ptr(Polyhedron_ptr ptr)
|
|
{
|
|
switch(ptr.which())
|
|
{
|
|
case POLYHEDRON_ENTRY:
|
|
{
|
|
Polyhedron** p = boost::get<Polyhedron*>(&ptr);
|
|
Q_ASSERT(p != NULL);
|
|
this->destroy_polyhedron(*p);
|
|
break;
|
|
}
|
|
case TEX_POLYHEDRON_ENTRY:
|
|
{
|
|
Textured_polyhedron** p = boost::get<Textured_polyhedron*>(&ptr);
|
|
Q_ASSERT(p != NULL);
|
|
this->destroy_tex_polyhedron(*p);
|
|
break;
|
|
}
|
|
#ifdef CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case NEF_ENTRY:
|
|
{
|
|
Nef_polyhedron** p = boost::get<Nef_polyhedron*>(&ptr);
|
|
Q_ASSERT(p != NULL);
|
|
this->destroy_nef_polyhedron(*p);
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int
|
|
Scene::open(QString filename)
|
|
{
|
|
QTextStream cerr(stderr);
|
|
cerr << QString("Opening file \"%1\"...").arg(filename);
|
|
|
|
QApplication::setOverrideCursor(QCursor(::Qt::WaitCursor));
|
|
|
|
QFileInfo fileinfo(filename);
|
|
std::ifstream in(filename.toUtf8());
|
|
|
|
if(!in || !fileinfo.isFile() || ! fileinfo.isReadable()) {
|
|
QMessageBox::critical(qobject_cast<QWidget*>(QObject::parent()),
|
|
tr("Cannot open file"),
|
|
tr("File %1 is not a readable file.").arg(filename));
|
|
QApplication::restoreOverrideCursor();
|
|
cerr << QString("\n");
|
|
return -1;
|
|
}
|
|
|
|
// allocate new polyhedron
|
|
Polyhedron* poly = this->new_polyhedron();
|
|
this->load_polyhedron(poly, in);
|
|
if(!in)
|
|
{
|
|
QMessageBox::critical(qobject_cast<QWidget*>(QObject::parent()),
|
|
tr("Cannot read file"),
|
|
tr("File %1 is not a valid OFF file.").arg(filename));
|
|
QApplication::restoreOverrideCursor();
|
|
cerr << QString("\n");
|
|
destroy_polyhedron(poly);
|
|
|
|
return -1;
|
|
}
|
|
|
|
addPolyhedron(poly, fileinfo.baseName());
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
cerr << " Ok.\n";
|
|
return polyhedra.size() - 1;
|
|
}
|
|
|
|
bool Scene::save(int index,
|
|
QString filename)
|
|
{
|
|
QTextStream cerr(stderr);
|
|
cerr << QString("Saving file \"%1\"...").arg(filename);
|
|
|
|
Polyhedron_entry entry = polyhedra[index];
|
|
Polyhedron** p = boost::get<Polyhedron*>(&entry.polyhedron_ptr);
|
|
if(!p) {
|
|
return false;
|
|
}
|
|
Polyhedron* poly = *p;
|
|
|
|
QApplication::setOverrideCursor(QCursor(::Qt::WaitCursor));
|
|
|
|
QFileInfo fileinfo(filename);
|
|
std::ofstream out(filename.toUtf8());
|
|
|
|
if(!out || !fileinfo.isFile() || ! fileinfo.isWritable())
|
|
{
|
|
QMessageBox::critical(qobject_cast<QWidget*>(QObject::parent()),
|
|
tr("Cannot open file"),
|
|
tr("File %1 is not a writable file.").arg(filename));
|
|
QApplication::restoreOverrideCursor();
|
|
cerr << QString("\n");
|
|
return false;
|
|
}
|
|
|
|
this->save_polyhedron(poly, out);
|
|
cerr << QString("ok\n");
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
return true;
|
|
}
|
|
|
|
void Scene::addEntry(Polyhedron_ptr p,
|
|
QString name,
|
|
QColor color,
|
|
bool activated,
|
|
RenderingMode mode)
|
|
{
|
|
Polyhedron_entry entry;
|
|
entry.polyhedron_ptr = p;
|
|
entry.name = name;
|
|
entry.color = color;
|
|
entry.activated = activated;
|
|
entry.rendering_mode = mode;
|
|
polyhedra.push_back(entry);
|
|
|
|
selected_item = -1;
|
|
emit updated_bbox();
|
|
emit updated();
|
|
QAbstractListModel::reset();
|
|
}
|
|
|
|
void Scene::addPolyhedron(Polyhedron* p,
|
|
QString name,
|
|
QColor color,
|
|
bool activated,
|
|
RenderingMode mode)
|
|
{
|
|
addEntry(p, name, color, activated, mode);
|
|
}
|
|
|
|
void Scene::addTexPolyhedron(Textured_polyhedron* p,
|
|
QString name,
|
|
QColor color,
|
|
bool activated,
|
|
RenderingMode mode)
|
|
{
|
|
addEntry(p, name, color, activated, mode);
|
|
}
|
|
|
|
#ifdef CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
void Scene::addNefPolyhedron(Nef_polyhedron* p,
|
|
QString name,
|
|
QColor color,
|
|
bool activated,
|
|
RenderingMode mode)
|
|
{
|
|
addEntry(p, name, color, activated, mode);
|
|
}
|
|
#endif // CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
|
|
int
|
|
Scene::erase(int polyhedron_index)
|
|
{
|
|
if(polyhedron_index < 0 || polyhedron_index >= polyhedra.size())
|
|
return -1;
|
|
|
|
Polyhedron_entry& entry = polyhedra[polyhedron_index];
|
|
this->destroyEntry(entry);
|
|
polyhedra.removeAt(polyhedron_index);
|
|
|
|
selected_item = -1;
|
|
emit updated();
|
|
QAbstractListModel::reset();
|
|
|
|
if(--polyhedron_index >= 0)
|
|
return polyhedron_index;
|
|
if(!polyhedra.isEmpty())
|
|
return 0;
|
|
return -1;
|
|
}
|
|
|
|
Scene::Polyhedron_ptr
|
|
Scene::copy_polyhedron_ptr(Polyhedron_ptr ptr)
|
|
{
|
|
switch(ptr.which())
|
|
{
|
|
#ifdef CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case NEF_ENTRY:
|
|
return copy_nef_polyhedron(boost::get<Nef_polyhedron*>(ptr));
|
|
#endif // CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case TEX_POLYHEDRON_ENTRY:
|
|
return copy_tex_polyhedron(boost::get<Textured_polyhedron*>(ptr));
|
|
default: // POLYHEDRON_ENTRY
|
|
return copy_polyhedron(boost::get<Polyhedron*>(ptr));
|
|
}
|
|
}
|
|
|
|
int
|
|
Scene::duplicate(int polyhedron_index)
|
|
{
|
|
if(polyhedron_index < 0 || polyhedron_index >= polyhedra.size())
|
|
return -1;
|
|
|
|
const Polyhedron_entry& entry = polyhedra[polyhedron_index];
|
|
Polyhedron_ptr ptr = copy_polyhedron_ptr(entry.polyhedron_ptr);
|
|
addEntry(ptr,
|
|
tr("%1 (copy)").arg(entry.name),
|
|
entry.color,
|
|
entry.activated);
|
|
|
|
return polyhedra.size() - 1;
|
|
}
|
|
|
|
void Scene::initializeGL()
|
|
{
|
|
glTexImage2D(GL_TEXTURE_2D,
|
|
0,
|
|
GL_RGB,
|
|
texture.GetWidth(),
|
|
texture.GetHeight(),
|
|
0,
|
|
GL_RGB,
|
|
GL_UNSIGNED_BYTE,
|
|
texture.GetData());
|
|
}
|
|
|
|
// workaround for Qt-4.2.
|
|
#if QT_VERSION < 0x040300
|
|
# define lighter light
|
|
#endif
|
|
|
|
void
|
|
Scene::draw(bool with_names)
|
|
{
|
|
for(int index = 0; index < polyhedra.size(); ++index)
|
|
{
|
|
if(with_names) {
|
|
::glPushName(index);
|
|
}
|
|
Polyhedron_entry& entry = polyhedra[index];
|
|
if(entry.activated)
|
|
{
|
|
if(entry.rendering_mode == Fill)
|
|
{
|
|
::glEnable(GL_LIGHTING);
|
|
::glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
|
|
if(index == selected_item)
|
|
CGALglcolor(entry.color.lighter(120));
|
|
else
|
|
CGALglcolor(entry.color);
|
|
|
|
switch(entry.polyhedron_ptr.which())
|
|
{
|
|
case NEF_ENTRY:
|
|
draw(entry);
|
|
break;
|
|
case POLYHEDRON_ENTRY:
|
|
draw(entry);
|
|
break;
|
|
case TEX_POLYHEDRON_ENTRY:
|
|
{
|
|
glEnable(GL_TEXTURE_2D);
|
|
|
|
glEnable(GL_TEXTURE_2D);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
|
|
Textured_polyhedron* p = boost::get<Textured_polyhedron*>(entry.polyhedron_ptr);
|
|
gl_render_tex_polyhedron_facets(p);
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|
|
}
|
|
|
|
}
|
|
if(viewEdges || entry.rendering_mode == Wireframe)
|
|
{
|
|
::glDisable(GL_LIGHTING);
|
|
::glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
|
|
if(index == selected_item)
|
|
CGALglcolor(Qt::black);
|
|
else
|
|
CGALglcolor(entry.color.lighter(50));
|
|
|
|
switch(entry.polyhedron_ptr.which())
|
|
{
|
|
#ifdef CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case NEF_ENTRY:
|
|
CGALglcolor(Qt::black);
|
|
gl_render_nef_edges(boost::get<Nef_polyhedron*>(entry.polyhedron_ptr));
|
|
break;
|
|
#endif // CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case POLYHEDRON_ENTRY:
|
|
draw(entry);
|
|
}
|
|
}
|
|
}
|
|
if(with_names) {
|
|
::glPopName();
|
|
}
|
|
}
|
|
}
|
|
|
|
// workaround for Qt-4.2 (see above)
|
|
#undef lighter
|
|
|
|
void
|
|
Scene::draw(Polyhedron_entry& entry)
|
|
{
|
|
if(!entry.display_list_built)
|
|
{
|
|
entry.display_list = ::glGenLists(1);
|
|
if(entry.display_list == 0)
|
|
{
|
|
std::cerr << "Unable to create display list" << std::endl;
|
|
return;
|
|
}
|
|
|
|
// draw the mesh in a display list
|
|
::glNewList(entry.display_list,GL_COMPILE_AND_EXECUTE);
|
|
this->gl_render_facets(entry.polyhedron_ptr);
|
|
::glEndList();
|
|
entry.display_list_built = true;
|
|
}
|
|
|
|
::glCallList(entry.display_list);
|
|
}
|
|
|
|
|
|
|
|
void Scene::gl_render_facets(Polyhedron_ptr ptr)
|
|
{
|
|
switch(ptr.which())
|
|
{
|
|
#ifdef CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case NEF_ENTRY:
|
|
{
|
|
Nef_polyhedron* p = boost::get<Nef_polyhedron*>(ptr);
|
|
glEnable(GL_LIGHTING);
|
|
gl_render_nef_facets(p);
|
|
glDisable(GL_LIGHTING);
|
|
CGALglcolor(Qt::black);
|
|
gl_render_nef_vertices(p);
|
|
glEnable(GL_LIGHTING);
|
|
break;
|
|
}
|
|
#endif // CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case POLYHEDRON_ENTRY:
|
|
{
|
|
Polyhedron* p = boost::get<Polyhedron*>(ptr);
|
|
gl_render_polyhedron_facets(p);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
Scene::rowCount(const QModelIndex & parent) const
|
|
{
|
|
if (parent.isValid())
|
|
return 0;
|
|
else
|
|
return polyhedra.size();
|
|
}
|
|
|
|
int
|
|
Scene::columnCount(const QModelIndex & parent) const
|
|
{
|
|
if (parent.isValid())
|
|
return 0;
|
|
else
|
|
return NumberOfColumns;
|
|
}
|
|
|
|
QVariant
|
|
Scene::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
if(index.row() < 0 || index.row() >= polyhedra.size())
|
|
return QVariant();
|
|
|
|
if(role == ::Qt::ToolTipRole)
|
|
{
|
|
switch(polyhedra[index.row()].polyhedron_ptr.which())
|
|
{
|
|
case POLYHEDRON_ENTRY:
|
|
return polyhedronToolTip(index.row());
|
|
#ifdef CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case NEF_ENTRY:
|
|
return nefPolyhedronToolTip(index.row());
|
|
#endif // CGAL_POLYHEDRON_DEMO_USE_NEF
|
|
case TEX_POLYHEDRON_ENTRY:
|
|
return texPolyhedronToolTip(index.row());
|
|
}
|
|
}
|
|
switch(index.column())
|
|
{
|
|
case ColorColumn:
|
|
if(role == ::Qt::DisplayRole || role == ::Qt::EditRole)
|
|
return polyhedra.value(index.row()).color;
|
|
else if(role == ::Qt::DecorationRole)
|
|
return polyhedra.value(index.row()).color;
|
|
break;
|
|
case NameColumn:
|
|
if(role == ::Qt::DisplayRole || role == ::Qt::EditRole)
|
|
return polyhedra.value(index.row()).name;
|
|
if(role == ::Qt::FontRole &&
|
|
polyhedra.value(index.row()).polyhedron_ptr.which() == NEF_ENTRY)
|
|
{
|
|
QFont font;
|
|
font.setItalic(!font.italic());
|
|
return font;
|
|
}
|
|
break;
|
|
case RenderingModeColumn:
|
|
if(role == ::Qt::DisplayRole) {
|
|
if(polyhedra.value(index.row()).rendering_mode == Scene::Wireframe)
|
|
return tr("wire");
|
|
else return tr("fill");
|
|
}
|
|
else if(role == ::Qt::EditRole) {
|
|
return static_cast<int>(polyhedra.value(index.row()).rendering_mode);
|
|
}
|
|
else if(role == ::Qt::TextAlignmentRole) {
|
|
return ::Qt::AlignCenter;
|
|
}
|
|
break;
|
|
case ABColumn:
|
|
if(role == ::Qt::DisplayRole) {
|
|
if(index.row() == item_A)
|
|
return "A";
|
|
if(index.row() == item_B)
|
|
return "B";
|
|
}
|
|
else if(role == ::Qt::TextAlignmentRole) {
|
|
return ::Qt::AlignCenter;
|
|
}
|
|
break;
|
|
case ActivatedColumn:
|
|
if(role == ::Qt::DisplayRole || role == ::Qt::EditRole)
|
|
return polyhedra.value(index.row()).activated;
|
|
break;
|
|
default:
|
|
return QVariant();
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
QVariant
|
|
Scene::headerData ( int section, ::Qt::Orientation orientation, int role ) const
|
|
{
|
|
if(orientation == ::Qt::Horizontal) {
|
|
if (role == ::Qt::DisplayRole)
|
|
{
|
|
switch(section)
|
|
{
|
|
case NameColumn:
|
|
return tr("Name");
|
|
break;
|
|
case ColorColumn:
|
|
return tr("Color");
|
|
break;
|
|
case RenderingModeColumn:
|
|
return tr("Mode");
|
|
case ABColumn:
|
|
return tr("A/B");
|
|
break;
|
|
case ActivatedColumn:
|
|
return tr("View");
|
|
break;
|
|
default:
|
|
return QVariant();
|
|
}
|
|
}
|
|
else if(role == ::Qt::ToolTipRole) {
|
|
if(section == RenderingModeColumn) {
|
|
return tr("Rendering mode (fill/fireframe)");
|
|
}
|
|
else if(section == ABColumn) {
|
|
return tr("Selection A/Selection B");
|
|
}
|
|
}
|
|
}
|
|
return QAbstractListModel::headerData(section, orientation, role);
|
|
}
|
|
|
|
Qt::ItemFlags
|
|
Scene::flags ( const QModelIndex & index ) const
|
|
{
|
|
if (index.isValid() && index.column() == NameColumn) {
|
|
return QAbstractListModel::flags(index) | ::Qt::ItemIsEditable;
|
|
}
|
|
else {
|
|
return QAbstractListModel::flags(index);
|
|
}
|
|
}
|
|
|
|
bool
|
|
Scene::setData(const QModelIndex &index,
|
|
const QVariant &value,
|
|
int role)
|
|
{
|
|
if( role != ::Qt::EditRole || !index.isValid() )
|
|
return false;
|
|
|
|
if(index.row() < 0 || index.row() >= polyhedra.size())
|
|
return false;
|
|
|
|
Polyhedron_entry& entry = polyhedra[index.row()];
|
|
switch(index.column())
|
|
{
|
|
case NameColumn:
|
|
entry.name = value.toString();
|
|
emit dataChanged(index, index);
|
|
return true;
|
|
break;
|
|
case ColorColumn:
|
|
entry.color = value.value<QColor>();
|
|
emit dataChanged(index, index);
|
|
return true;
|
|
break;
|
|
case RenderingModeColumn:
|
|
entry.rendering_mode = static_cast<RenderingMode>(value.toInt());
|
|
emit dataChanged(index, index);
|
|
return true;
|
|
break;
|
|
case ActivatedColumn:
|
|
entry.activated = value.toBool();
|
|
emit dataChanged(index, index);
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Polyhedron* Scene::polyhedron(int index) const
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return NULL;
|
|
else
|
|
{
|
|
if(polyhedra[index].polyhedron_ptr.which() == POLYHEDRON_ENTRY) {
|
|
return boost::get<Polyhedron*>(polyhedra[index].polyhedron_ptr);
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
Textured_polyhedron* Scene::texPolyhedron(int index) const
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return NULL;
|
|
else
|
|
{
|
|
if(polyhedra[index].polyhedron_ptr.which() == TEX_POLYHEDRON_ENTRY) {
|
|
return boost::get<Textured_polyhedron*>(polyhedra[index].polyhedron_ptr);
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Nef_polyhedron* Scene::nefPolyhedron(int index) const
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return 0;
|
|
else
|
|
{
|
|
if(polyhedra[index].polyhedron_ptr.which() == NEF_ENTRY) {
|
|
return boost::get<Nef_polyhedron*>(polyhedra[index].polyhedron_ptr);
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
Scene::Entry_type Scene::polyhedronType(int index) const
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return POLYHEDRON_ENTRY;
|
|
return static_cast<Entry_type>(polyhedra[index].polyhedron_ptr.which());
|
|
}
|
|
|
|
QString Scene::polyhedronName(int index) const
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return QString();
|
|
else
|
|
return polyhedra[index].name;
|
|
}
|
|
|
|
QColor Scene::polyhedronColor(int index) const
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return QColor();
|
|
else
|
|
return polyhedra[index].color;
|
|
}
|
|
|
|
bool Scene::isPolyhedronActivated(int index) const
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return false;
|
|
else
|
|
return polyhedra[index].activated;
|
|
}
|
|
|
|
void Scene::setPolyhedronActivated(int index, bool b)
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return;
|
|
polyhedra[index].activated = b;
|
|
emit dataChanged(QAbstractItemModel::createIndex(index, ActivatedColumn),
|
|
QAbstractItemModel::createIndex(index, ActivatedColumn));
|
|
}
|
|
|
|
Scene::RenderingMode Scene::polyhedronRenderingMode(int index) const
|
|
{
|
|
if( index < 0 || index >= polyhedra.size() )
|
|
return RenderingMode();
|
|
else
|
|
return polyhedra[index].rendering_mode;
|
|
}
|
|
|
|
int Scene::selectionAindex() const {
|
|
return item_A;
|
|
}
|
|
|
|
int Scene::selectionBindex() const {
|
|
return item_B;
|
|
}
|
|
|
|
QItemSelection Scene::createSelection(int i)
|
|
{
|
|
return QItemSelection(QAbstractItemModel::createIndex(i, 0),
|
|
QAbstractItemModel::createIndex(i, LastColumn));
|
|
}
|
|
|
|
void Scene::polyhedronChanged(int i)
|
|
{
|
|
if(i < 0 || i >= polyhedra.size())
|
|
return;
|
|
|
|
polyhedra[i].display_list_built = false;
|
|
emit dataChanged(QAbstractItemModel::createIndex(i, 0),
|
|
QAbstractItemModel::createIndex(i, LastColumn));
|
|
}
|
|
|
|
void Scene::polyhedronChanged(Polyhedron*)
|
|
{
|
|
for(int i = 0; i < polyhedra.size(); ++i) {
|
|
polyhedra[i].display_list_built = false;
|
|
}
|
|
emit dataChanged(QAbstractItemModel::createIndex(0, 0),
|
|
QAbstractItemModel::createIndex(polyhedra.size() - 1, LastColumn));
|
|
}
|
|
|
|
bool SceneDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
|
const QStyleOptionViewItem &option,
|
|
const QModelIndex &index)
|
|
{
|
|
Scene *scene = static_cast<Scene*>(model);
|
|
Q_ASSERT(scene);
|
|
switch(index.column()) {
|
|
case Scene::ActivatedColumn:
|
|
if (event->type() == QEvent::MouseButtonPress) {
|
|
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
|
|
if(mouseEvent->button() == ::Qt::LeftButton) {
|
|
int x = mouseEvent->pos().x() - option.rect.x();
|
|
if(x >= (option.rect.width() - size)/2 &&
|
|
x <= (option.rect.width() + size)/2) {
|
|
model->setData(index, ! model->data(index).toBool() );
|
|
}
|
|
}
|
|
return false; //so that the selection can change
|
|
}
|
|
return true;
|
|
break;
|
|
case Scene::ColorColumn:
|
|
if (event->type() == QEvent::MouseButtonPress) {
|
|
QColor color = QColorDialog::getColor(::Qt::green, 0);
|
|
if (color.isValid()) {
|
|
model->setData(index, color );
|
|
}
|
|
}
|
|
else if(event->type() == QEvent::MouseButtonDblClick) {
|
|
return true; // block double-click
|
|
}
|
|
return false;
|
|
break;
|
|
case Scene::RenderingModeColumn:
|
|
if (event->type() == QEvent::MouseButtonPress) {
|
|
Scene::RenderingMode rendering_mode =
|
|
static_cast<Scene::RenderingMode>(model->data(index, ::Qt::EditRole).toInt());
|
|
if(rendering_mode == Scene::Wireframe)
|
|
model->setData(index, static_cast<int>(Scene::Fill));
|
|
else
|
|
model->setData(index, static_cast<int>(Scene::Wireframe));
|
|
}
|
|
else if(event->type() == QEvent::MouseButtonDblClick) {
|
|
return true; // block double-click
|
|
}
|
|
return false;
|
|
break;
|
|
case Scene::ABColumn:
|
|
if (event->type() == QEvent::MouseButtonPress) {
|
|
if(index.row() == scene->item_B) {
|
|
scene->item_A = index.row();
|
|
scene->item_B = -1;
|
|
}
|
|
else if(index.row() == scene->item_A) {
|
|
scene->item_B = index.row();
|
|
scene->item_A = -1;
|
|
}
|
|
else if(scene->item_A == -1) {
|
|
scene->item_A = index.row();
|
|
}
|
|
else {
|
|
scene->item_B = index.row();
|
|
}
|
|
scene->dataChanged(scene->createIndex(Scene::ABColumn, 0),
|
|
scene->createIndex(Scene::ABColumn, scene->rowCount()));
|
|
}
|
|
return false;
|
|
break;
|
|
default:
|
|
return QItemDelegate::editorEvent(event, model, option, index);
|
|
}
|
|
}
|
|
|
|
void SceneDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
|
const QModelIndex &index) const
|
|
{
|
|
if (index.column() != Scene::ActivatedColumn) {
|
|
QItemDelegate::paint(painter, option, index);
|
|
} else {
|
|
const QAbstractItemModel *model = index.model();
|
|
QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ?
|
|
(option.state & QStyle::State_Active) ? QPalette::Normal : QPalette::Inactive : QPalette::Disabled;
|
|
|
|
if (option.state & QStyle::State_Selected)
|
|
painter->fillRect(option.rect, option.palette.color(cg, QPalette::Highlight));
|
|
|
|
bool checked = model->data(index, ::Qt::DisplayRole).toBool();
|
|
int width = option.rect.width();
|
|
int height = option.rect.height();
|
|
size = (std::min)(width, height);
|
|
int x = option.rect.x() + (option.rect.width() / 2) - (size / 2);;
|
|
int y = option.rect.y() + (option.rect.height() / 2) - (size / 2);
|
|
if(checked) {
|
|
painter->drawPixmap(x, y, checkOnPixmap.scaled(QSize(size, size),
|
|
::Qt::KeepAspectRatio,
|
|
::Qt::SmoothTransformation));
|
|
}
|
|
else {
|
|
painter->drawPixmap(x, y, checkOffPixmap.scaled(QSize(size, size),
|
|
::Qt::KeepAspectRatio,
|
|
::Qt::SmoothTransformation));
|
|
}
|
|
drawFocus(painter, option, option.rect); // since we draw the grid ourselves
|
|
}
|
|
}
|
|
|
|
void Scene::setPolyhedronA(int i)
|
|
{
|
|
item_A = i;
|
|
if(item_A == item_B)
|
|
{
|
|
item_B = -1;
|
|
}
|
|
emit dataChanged(QAbstractItemModel::createIndex(0, ABColumn),
|
|
QAbstractItemModel::createIndex(polyhedra.size()-1, ABColumn));
|
|
}
|
|
|
|
void Scene::setPolyhedronB(int i)
|
|
{
|
|
item_B = i;
|
|
if(item_A == item_B)
|
|
{
|
|
item_A = -1;
|
|
}
|
|
emit updated();
|
|
emit dataChanged(QAbstractItemModel::createIndex(0, ABColumn),
|
|
QAbstractItemModel::createIndex(polyhedra.size()-1, ABColumn));
|
|
}
|