58#include <QtConcurrent>
61#include <OpenFlipper/widgets/snapshotDialog/SnapshotDialog.hh>
65 #include <ACG/Utils/VSToolsT.hh>
68#include <ACG/Scenegraph/MaterialNode.hh>
79 statusBar_->showMessage(tr(
"Stereo enabled"));
80 stereoButton_->setIcon( QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"stereo.png") );
82 statusBar_->showMessage(tr(
"Stereo disabled"));
83 stereoButton_->setIcon( QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+
"mono.png") );
88 for (
unsigned int i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
95 QColor backCol((
int)bc[0], (
int)bc[1], (
int)bc[2], (
int)bc[3]);
96 QColor c = QColorDialog::getColor(backCol,
this);
98 if (c != backCol && c.isValid())
99 for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets(); ++i )
101 ((
double) c.greenF()) ,
102 ((
double) c.blueF()) ,
112 QColor backCol((
int)bc[0], (
int)bc[1], (
int)bc[2], (
int)bc[3]);
113 QColor c = QColorDialog::getColor(backCol,
this);
115 if (c != backCol && c.isValid())
117 ((
double) c.greenF()) ,
118 ((
double) c.blueF()) ,
133 _state ? (*it)->slotShowWheels() : (*it)->slotHideWheels();
189 emit statusMessage(QString(tr(
"getCoordsysProjection(): Could not find coordsys node. Assuming default orthographic projection.")));
208 emit statusMessage(QString(tr(
"slotContextSwitchCoordsysProjection(): Could not find coordsys node, thus its projection mode will not be toggled.")));
211 for (
unsigned int i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
230 int enabledCount = 0;
242 for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
254 int enabledCount = 0;
266 for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
279 int enabledCount = 0;
291 for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
303 int enabledCount = 0;
315 for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
327 int enabledCount = 0;
339 for ( uint i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
355 QString number = QString::number(counter);
356 while ( number.size() < 7 )
357 number =
"0" + number;
359 QString suggest = fi.baseName() +
"." + number +
".";
361 QString format=
"png";
363 if (fi.completeSuffix() ==
"ppm")
366 if (fi.completeSuffix() ==
"jpg")
371 QFileDialog dialog(
this);
372 dialog.setFileMode(QFileDialog::AnyFile);
373 dialog.setDefaultSuffix(
"png");
374 dialog.setNameFilter(tr(
"Images (*.png *.ppm *.jpg)"));
375 dialog.setFileMode(QFileDialog::AnyFile);
376 dialog.setOption(QFileDialog::DontConfirmOverwrite,
false);
377 dialog.setDirectory( fi.path() );
378 dialog.selectFile( suggest );
379 dialog.setAcceptMode(QFileDialog::AcceptSave);
380 dialog.setWindowTitle(tr(
"Save Snapshot"));
383 QString newName = dialog.selectedFiles()[0];
385 if (newName != fi.path() + OpenFlipper::Options::dirSeparator() + suggest)
395static QString suggestSnapshotFilename(QString mostRecentPath) {
396 if (mostRecentPath.isEmpty()) {
397 mostRecentPath = QString(
"%1%2snap.0000000.png")
399 .arg(QDir::separator());
402 QFileInfo fi(mostRecentPath);
403 QString path = fi.path();
405 if (!fi.exists() && QFileInfo(path).isWritable()) {
407 std::cout <<
"suggestSnapshotFilename(): mostRecentPath feasible as "
408 "file name. Using it." << std::endl;
410 return mostRecentPath;
413 if (!QFileInfo(path).isWritable()) {
415 std::cout <<
"suggestSnapshotFilename(): Most recent path invalid. "
416 "Doesn't exist. Returning empty string." << std::endl;
421 QString base_name = fi.completeBaseName();
422 QString suffix = fi.suffix();
424 if (suffix.isEmpty())
427 QRegularExpression base_name_re(
"(\\D*)(\\d+)?(.*)");
429 QRegularExpressionMatch match = base_name_re.match(base_name);
430 if (match.capturedStart() < 0) {
432 std::cout <<
"suggestSnapshotFilename(): Regexp didn't match. This "
433 "should be impossible." << std::endl;
438 QString pre = match.captured(1),
439 num = match.captured(2),
440 post = match.captured(3);
443 std::cout << (QString(
"suggestSnapshotFilename(): Decomposition of "
444 "\"%1\": \"%2\", \"%3\", \"%4\"")
448 .arg(post)).toStdString() << std::endl;
451 if (pre.isEmpty() && num.isEmpty() && post.isEmpty()) {
455 size_t num_len = num.length();
457 int file_no = num.toInt(&num_is_int);
463 size_t sanity_counter = 0;
464 for (; sanity_counter < 100000; ++file_no, ++sanity_counter) {
465 QString suggested_file_name =
466 QString(
"%1%2%3%4%5.%6")
468 .arg(QDir::separator())
470 .arg(file_no, num_len, 10, QLatin1Char(
'0'))
474 QFileInfo suggested_fi(suggested_file_name);
475 if (!suggested_fi.exists()){
477 std::cout <<
"suggestSnapshotFilename(): Found a feasible file "
478 "name. Returning it." << std::endl;
480 return suggested_file_name;
485 std::cout <<
"suggestSnapshotFilename(): No luck incrementing file_no. "
486 "Aborting, returning empty string." << std::endl;
498 connect(&dialog, SIGNAL(resizeApplication(
int,
int)),
this, SIGNAL(resizeApplication(
int,
int)) );
500 bool ok = dialog.exec();
503 QString newName = dialog.filename->text();
510 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
511 QScreen* screen = window()->screen();
512 QPixmap pic = screen->grabWindow( winId() );
514 QPixmap pic = QPixmap::grabWindow( winId() );
517 QPainter painter (&pic);
526 (*iter)->snapshot(fillImage, (*iter)->glWidth() , (*iter)->glHeight());
528 QPoint localPos = QPoint((*iter)->pos().x(),(*iter)->pos().y());
529 QPointF pos =
glView_->mapTo(
this,localPos);
530 painter.drawImage(pos,fillImage);
537 emit resizeApplication(w,h);
543 #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
544 QScreen* screen = window()->screen();
545 QPixmap pix = screen->grabWindow( winId() );
547 QPixmap pix = QPixmap::grabWindow( winId() );
551 QImage* pic =
new QImage( pix.toImage() );
552 writeImageAsynchronously(pic, suggestSnapshotFilename(
snapshotName_));
556 bool comments_visible_only,
bool comments_targeted_only,
557 bool store_material_info,
int snapshot_width,
int snapshot_height,
558 bool snapshot_transparent,
bool hide_coord_sys,
559 int snapshot_multisampling,
bool store_view) {
561 if (snapshot_height < 0) {
564 snapshot_height =
static_cast<int>(round(
565 static_cast<double>(snapshot_width) / w * h));
569 if (store_comments) {
571 comments_visible_only,
572 comments_targeted_only).join(
"\n");
576 if (ACG::SceneGraph::Material::support_json_serialization() &&
578 store_material_info) {
580 comments_visible_only,
581 comments_targeted_only).join(
"\n");
587 case QtMultiViewLayout::SingleView:
592 snapshot_width, snapshot_height,
593 snapshot_transparent, hide_coord_sys,
594 snapshot_multisampling);
596 if (!comments.isEmpty())
597 finalImage.setText(
"Mesh Comments", comments);
598 if (!materials.isEmpty())
599 finalImage.setText(
"Mesh Materials", materials);
603 window_size = QSize(-width(), -height());
605 window_size = QSize (width(), height());
607 int splitter_size = 0;
615 finalImage.setText(
"View", view);
617 finalImage.save(file_name);
621 case QtMultiViewLayout::DoubleView:
623 int w = snapshot_height;
630 img[0],
static_cast<int>(relSizeW * w),
631 snapshot_width, snapshot_transparent,
634 img[1],
static_cast<int>(relSizeW * w),
635 snapshot_width, snapshot_transparent,
638 QImage finalImage(img[0].width() + img[1].width() +2, img[0].height(),
639 QImage::Format_ARGB32_Premultiplied);
641 QPainter painter(&finalImage);
643 painter.fillRect(0,0,finalImage.width(),
644 finalImage.height(), QBrush(Qt::gray));
646 painter.drawImage(QRectF( 0, 0, img[0].width(), img[0].height()),img[0],
647 QRectF( 0, 0, img[0].width(), img[0].height()) );
648 painter.drawImage(QRectF(img[0].width()+2, 0, img[1].width(), img[1].height()),img[1],
649 QRectF( 0, 0, img[1].width(), img[1].height()) );
651 if (!comments.isEmpty())
652 finalImage.setText(
"Mesh Comments", comments);
653 finalImage.save(file_name);
658 case QtMultiViewLayout::Grid:
664 QImage img0,img1,img2,img3;
667 (
int)((double)snapshot_width * relSizeW),
668 (int)((
double)snapshot_height * relSizeH),
669 snapshot_transparent, hide_coord_sys);
671 (
int)((double)snapshot_width * (1.0 - relSizeW)),
672 (
int)((double)snapshot_height * relSizeH),
673 snapshot_transparent, hide_coord_sys);
675 (
int)((double)snapshot_width * relSizeW),
676 (int)((
double)snapshot_height * (1.0 - relSizeH)),
677 snapshot_transparent, hide_coord_sys);
679 (
int)((double)snapshot_width * (1.0 - relSizeW)),
680 (
int)((double)snapshot_height * (1.0 - relSizeH)),
681 snapshot_transparent, hide_coord_sys);
683 QImage finalImage(img0.width() + img1.width()+2,
684 img0.height() + img2.height()+2,
685 QImage::Format_ARGB32_Premultiplied);
687 QPainter painter(&finalImage);
689 painter.fillRect(0,0,finalImage.width(), finalImage.height(), QBrush(Qt::gray));
691 painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
692 QRectF( 0, 0, img0.width(), img0.height()) );
693 painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
694 QRectF( 0, 0, img1.width(), img1.height()) );
695 painter.drawImage(QRectF( 0,img0.height()+2, img2.width(), img2.height()),img2,
696 QRectF( 0, 0, img2.width(), img2.height()) );
697 painter.drawImage(QRectF(img0.width()+2, img0.height()+2, img3.width(), img3.height()),img3,
698 QRectF( 0, 0, img3.width(), img3.height()) );
700 if (!comments.isEmpty())
701 finalImage.setText(
"Mesh Comments", comments);
702 finalImage.save(file_name);
706 case QtMultiViewLayout::HSplit:
714 QImage img0,img1,img2,img3;
717 (
int)((double)snapshot_width * relSizeW), snapshot_height,
718 snapshot_transparent, hide_coord_sys);
720 (
int)((double)snapshot_width * (1.0 - relSizeW)),
721 relSizeH1 * (
double)snapshot_height,
722 snapshot_transparent, hide_coord_sys);
724 (
int)((double)snapshot_width * (1.0 - relSizeW)),
725 relSizeH2 * (
double)snapshot_height,
726 snapshot_transparent, hide_coord_sys);
728 (
int)((double)snapshot_width * (1.0 - relSizeW)),
729 relSizeH3 * (
double)snapshot_height,
730 snapshot_transparent, hide_coord_sys);
732 QImage finalImage(img0.width() + img1.width() +2, img0.height(), QImage::Format_ARGB32_Premultiplied);
734 QPainter painter(&finalImage);
736 painter.fillRect(0,0,finalImage.width(), finalImage.height(), QBrush(Qt::gray));
738 painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
739 QRectF( 0, 0, img0.width(), img0.height()) );
740 painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
741 QRectF( 0, 0, img1.width(), img1.height()) );
742 painter.drawImage(QRectF(img0.width()+2, img1.height()+2, img2.width(), img2.height()),img2,
743 QRectF( 0, 0, img2.width(), img2.height()) );
744 painter.drawImage(QRectF(img0.width()+2, img1.height()+img2.height()+4, img3.width(),img3.height()),img3,
745 QRectF( 0, 0, img3.width(), img3.height()) );
747 if (!comments.isEmpty())
748 finalImage.setText(
"Mesh Comments", comments);
749 finalImage.save(file_name);
765 if (!ACG::SceneGraph::Material::support_json_serialization())
766 dialog.metaData_storeMatInfo_cb->setVisible(
false);
768 bool ok = dialog.exec();
771 QString newName = dialog.filename->text();
777 const bool storeComments = dialog.metaData_storeComments_cb->isChecked();
778 const bool comments_visible_only =
779 dialog.metaData_comments_visibleOnly_cb->isChecked();
780 const bool comments_targeted_only =
781 dialog.metaData_comments_targetedOnly_cb->isChecked();
782 const bool store_material_info =
783 dialog.metaData_storeMatInfo_cb->isChecked();
784 const int snapshot_width = dialog.snapWidth->value();
785 const int snapshot_height = dialog.snapHeight->value();
786 const bool snapshot_transparent = dialog.transparent->isChecked();
787 const bool hide_coord_sys = dialog.hideCoordsys->isChecked();
788 const int snapshot_multisampling =
789 dialog.multisampling->isChecked() ?
790 dialog.num_samples->value() : 1;
791 const bool store_view = dialog.metaData_storeView_cb->isChecked();
794 comments_targeted_only, store_material_info, snapshot_width,
795 snapshot_height, snapshot_transparent, hide_coord_sys,
796 snapshot_multisampling, store_view);
806 case QtMultiViewLayout::SingleView:
808 QImage* finalImage =
new QImage();
812 writeImageAsynchronously(finalImage, suggestSnapshotFilename(
snapshotName_));
816 case QtMultiViewLayout::DoubleView:
823 QImage* finalImage =
new QImage(img[0].width() + img[1].width() +2, img[0].height(), QImage::Format_ARGB32_Premultiplied);
825 QPainter painter(finalImage);
827 painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
829 painter.drawImage(QRectF( 0, 0, img[0].width(), img[0].height()),img[0],
830 QRectF( 0, 0, img[0].width(), img[0].height()) );
831 painter.drawImage(QRectF(img[0].width()+2, 0, img[1].width(), img[1].height()),img[1],
832 QRectF( 0, 0, img[1].width(), img[1].height()) );
834 writeImageAsynchronously(finalImage, suggestSnapshotFilename(
snapshotName_));
839 case QtMultiViewLayout::Grid:
841 QImage img0,img1,img2,img3;
848 QImage* finalImage =
new QImage(img0.width() + img1.width() + 2, img0.height() + img2.height() + 2, QImage::Format_ARGB32_Premultiplied);
850 QPainter painter(finalImage);
852 painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
854 painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
855 QRectF( 0, 0, img0.width(), img0.height()) );
856 painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
857 QRectF( 0, 0, img1.width(), img1.height()) );
858 painter.drawImage(QRectF( 0, img0.height()+2, img2.width(), img2.height()),img2,
859 QRectF( 0, 0, img2.width(), img2.height()) );
860 painter.drawImage(QRectF(img0.width()+2, img0.height()+2, img3.width(), img3.height()),img3,
861 QRectF( 0, 0, img3.width(), img3.height()) );
863 writeImageAsynchronously(finalImage, suggestSnapshotFilename(
snapshotName_));
867 case QtMultiViewLayout::HSplit:
869 QImage img0,img1,img2,img3;
876 QImage* finalImage =
new QImage(img0.width() + img1.width() + 2, img0.height(), QImage::Format_ARGB32_Premultiplied);
878 QPainter painter(finalImage);
880 painter.fillRect(0,0,finalImage->width(), finalImage->height(), QBrush(Qt::gray));
882 painter.drawImage(QRectF( 0, 0, img0.width(), img0.height()),img0,
883 QRectF( 0, 0, img0.width(), img0.height()) );
884 painter.drawImage(QRectF(img0.width()+2, 0, img1.width(), img1.height()),img1,
885 QRectF( 0, 0, img1.width(), img1.height()) );
886 painter.drawImage(QRectF(img0.width()+2, img1.height()+2, img2.width(), img2.height()),img2,
887 QRectF( 0, 0, img2.width(), img2.height()) );
888 painter.drawImage(QRectF(img0.width()+2, img1.height()+img2.height()+4, img3.width(),img3.height()),img3,
889 QRectF( 0, 0, img3.width(), img3.height()) );
891 writeImageAsynchronously(finalImage, suggestSnapshotFilename(
snapshotName_));
905void writeImageQImage(QImage* _image,
const QString& _name) {
911void CoreWidget::writeImageAsynchronously(QImage* _image,
const QString& _name) {
913 QFuture<void>* future =
new QFuture<void>();
914 *future = QtConcurrent::run(writeImageQImage, _image, _name);
915 QFutureWatcher<void>* watcher =
new QFutureWatcher<void>();
916 watcher->setFuture(*future);
918 watcher_garbage_.insert(std::pair<QFutureWatcher<void>*,QFuture<void>*>(watcher, future));
920 connect(watcher, SIGNAL(finished()),
this, SLOT(delete_garbage()));
925void CoreWidget::delete_garbage() {
927 QObject* obj = QObject::sender();
928 QFutureWatcher<void>* watcher =
dynamic_cast<QFutureWatcher<void>*
>(obj);
935 std::map<QFutureWatcher<void>*,QFuture<void>*>::iterator f;
936 f = watcher_garbage_.find(watcher);
937 if(f != watcher_garbage_.end()) {
940 watcher_garbage_.erase(f);
957 QSize windowSize(0, 0);
958 int splitterWidth = 0;
959 QSize viewportSize(0, 0);
961 view, &windowSize, &splitterWidth, &viewportSize);
963 if (windowSize.height() != 0 && windowSize.width() != 0) {
964 if (windowSize.width() < 0) {
975 if (splitterWidth > 0) {
977 if (splitter_sizes.size() < 2) {
978 std::cerr <<
"The tool splitter has less than two children. This "
979 "shouldn't happen." << std::endl;
982 "Core/Gui/ToolBoxes/ToolBoxOnTheRight",
true).toBool()
985 const int diff = splitterWidth - splitter_sizes[primary_idx];
986 splitter_sizes[primary_idx] += diff;
987 splitter_sizes[1-primary_idx] -= diff;
996 if (viewportSize.width() > 0 && viewportSize.height() > 0) {
1001 for (
int i = 0; i < 2; ++i) {
1003 if (cur_viewport_size != viewportSize) {
1004 std::cout <<
"Stored viewport size is " << viewportSize.width()
1005 <<
" x " << viewportSize.height() <<
". Actual size is "
1006 << cur_viewport_size.width() <<
" x "
1007 << cur_viewport_size.height() <<
". Resizing window."
1011 QSize diff = viewportSize - cur_viewport_size;
1012 resize(size() + diff);
1013 const QSize new_viewport_size =
1015 diff = viewportSize - new_viewport_size;
1016 if (diff.width() != 0) {
1017 std::cout <<
"New viewport size is "
1018 << new_viewport_size.width()
1019 <<
" x " << new_viewport_size.height() <<
"."
1020 <<
" Moving splitter by " << diff.width() <<
"."
1024 if (splitter_sizes.size() < 2) {
1025 std::cerr <<
"The tool splitter has less than two children. This "
1026 "shouldn't happen." << std::endl;
1029 "Core/Gui/ToolBoxes/ToolBoxOnTheRight",
true).toBool()
1032 splitter_sizes[primary_idx] += diff.width();
1033 splitter_sizes[1-primary_idx] -= diff.width();
1052 if (splitterWidth != -1)
1061 sizes.push_back(size.width() - splitterWidth);
1062 sizes.push_back(splitterWidth);
1066 sizes.push_back(splitterWidth);
1067 sizes.push_back(size.width() - splitterWidth);
1076 if (size == QSize(0,0))
1083 resizeApplication(size.width(),size.height());
1093 size = QSize (width(),height());
1095 int splitter_size = 0;
1101 const bool make_c_string = (QApplication::keyboardModifiers() & Qt::ControlModifier);
1103 size, splitter_size, make_c_string);
1112 emit log(
LOGERR, tr(
"CoordSys Node not found"));
1121 for (
unsigned int i = 0 ; i < OpenFlipper::Options::examinerWidgets() ; ++i )
1129 if (_action->data().toInt() != PluginFunctions::VIEW_FREE)
DLLEXPORT OpenFlipperQSettings & OpenFlipperSettings()
QSettings object containing all program settings of OpenFlipper.
void hide()
Hide Node: set status to HideNode.
void show()
Show node: set status to Active.
ChildIter find(BaseNode *_node)
ProjectionMode
projection mode
@ PERSPECTIVE_PROJECTION
perspective
@ ORTHOGRAPHIC_PROJECTION
orthographic
void setProjectionMode(const ProjectionMode _mode)
set mode to either ORTHOGRAPHIC_PROJECTION or PERSPECTIVE_PROJECTION
ProjectionMode getProjectionMode() const
get current projection mode
void setEnabled(bool _enabled)
Enabled/Disables gl cursor painting.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void setValue(const QString &key, const QVariant &value)
Wrapper function which makes it possible to enable Debugging output with -DOPENFLIPPER_SETTINGS_DEBUG...
MultiViewMode mode() const
Retruns current layout modes.
void animation(bool _state)
set 2-sided lighting on/off
ACG::Vec4f backgroundColor()
Get current background color.
void twoSidedLighting(bool _state)
set 2-sided lighting on/off
void mipmapping(bool _state)
set mipmapping on/off
void snapshotCounter(const int _counter)
bool backFaceCulling()
Get current state of backface culling.
void multisampling(bool _state)
set multisampling on/off
void snapshotBaseFileName(const QString &_fname)
@ NORMAL_NAVIGATION
Normal mode.
@ FIRSTPERSON_NAVIGATION
First person mode.
Viewer::ViewerProperties & viewerProperties(int _id)
Get the viewer properties Use this functions to get basic viewer properties such as backgroundcolor o...
QStringList collectObjectMaterials(bool visibleOnly, bool targetedOnly)
QStringList collectObjectComments(bool visibleOnly, bool targetedOnly)
int viewers()
Get the number of viewers.
void setFixedView(int _mode, int _viewer)
Set a fixed View for a viewer.
void allowRotation(bool _mode, int _viewer)
unsigned int activeExaminer()
Get the id of the examiner which got the last mouse events.
ACG::SceneGraph::BaseNode * getSceneGraphRootNode()
get scenegraph root node