diff --git a/widgets/rendererWidget/TextBrowserWidget.cc b/widgets/rendererWidget/TextBrowserWidget.cc new file mode 100644 index 0000000000000000000000000000000000000000..18c2e2d353a26463429120f6418afb4a102cdf74 --- /dev/null +++ b/widgets/rendererWidget/TextBrowserWidget.cc @@ -0,0 +1,379 @@ + +/*===========================================================================*\ +* * +* OpenFlipper * +* Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * +* www.openflipper.org * +* * +*--------------------------------------------------------------------------- * +* This file is part of OpenFlipper. * +* * +* OpenFlipper is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, either version 3 of * +* the License, or (at your option) any later version with the * +* following exceptions: * +* * +* If other files instantiate templates or use macros * +* or inline functions from this file, or you compile this file and * +* link it with other files to produce an executable, this file does * +* not by itself cause the resulting executable to be covered by the * +* GNU Lesser General Public License. This exception does not however * +* invalidate any other reasons why the executable file might be * +* covered by the GNU Lesser General Public License. * +* * +* OpenFlipper is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU LesserGeneral Public * +* License along with OpenFlipper. If not, * +* see . * +* * +\*===========================================================================*/ + +/*===========================================================================*\ +* * +* $Revision: 17080 $ * +* $LastChangedBy: moeller $ * +* $Date: 2013-07-19 12:58:31 +0200 (Fri, 19 Jul 2013) $ * +* * +\*===========================================================================*/ + + +#if QT_VERSION >= 0x050000 + #include +#else + #include +#endif + +#include "TextBrowserWidget.hh" + +#include + +QString const TextBrowserWidget::startRenderObjectTag_ = "name:"; +QString const TextBrowserWidget::startVertexShaderTag_ = "--vertex-shader--"; +QString const TextBrowserWidget::endVertexShaderTag_ = "--end-vertex-shader--"; +QString const TextBrowserWidget::startGeometryShaderTag_ = "--geometry-shader--"; +QString const TextBrowserWidget::endGeometryShaderTag_ = "--end-geometry-shader--"; +QString const TextBrowserWidget::startFragmentShaderTag_ = "--fragment-shader--"; +QString const TextBrowserWidget::endFragmentShaderTag_ = "--end-fragment-shader--"; + + +TextBrowserWidget::TextBrowserWidget(QWidget *parent) : QPlainTextEdit(parent) { + sideArea_ = new TextBrowserSideArea(this); + updateTextBrowserSideAreaWidth(); + + connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateTextBrowserSideAreaWidth())); + connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateFolds())); + connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(updateTextBrowserSideArea(QRect,int))); + + setReadOnly(true); +} + + + +int TextBrowserWidget::sideAreaWidth() { + int digits = 1; + int max = qMax(1, blockCount()); + while (max >= 10) { + max /= 10; + ++digits; + } + + int space = 3 + fontMetrics().width(QLatin1Char('9')) * digits; + + return space; +} + + + +void TextBrowserWidget::updateTextBrowserSideAreaWidth() { + setViewportMargins(sideAreaWidth(), 0, 0, 0); +} + +void TextBrowserWidget::updateTextBrowserSideArea(const QRect &rect, int dy) { + if (dy) + sideArea_->scroll(0, dy); + else + sideArea_->update(0, rect.y(), sideArea_->width(), rect.height()); + + if (rect.contains(viewport()->rect())) + updateTextBrowserSideAreaWidth(); +} + + + +void TextBrowserWidget::resizeEvent(QResizeEvent *e) { + QPlainTextEdit::resizeEvent(e); + + QRect cr = contentsRect(); + sideArea_->setGeometry(QRect(cr.left(), cr.top(), sideAreaWidth(), cr.height())); +} + +void TextBrowserWidget::sideAreaPaintEvent(QPaintEvent *event) { + + QPainter painter(sideArea_); + painter.fillRect(event->rect(), Qt::lightGray); + painter.setPen(Qt::black); + + QTextBlock block = firstVisibleBlock(); + + int blockNumber = block.blockNumber(); + int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); + int bottom = top + (int) blockBoundingRect(block).height(); + + Fold found_fold; + while (block.isValid() && top <= event->rect().bottom()) { + if (block.isVisible() && bottom >= event->rect().top()) { + if (getFold(block.position(), found_fold)) { + if (found_fold.type == SHADER) { + int fold_first_block = document()->findBlock(found_fold.start).blockNumber(); + QString text = block.text(); + // only draw line numbers on actual shader code + if (text.contains(TextBrowserWidget::startVertexShaderTag_) || + text.contains(TextBrowserWidget::endVertexShaderTag_) || + text.contains(TextBrowserWidget::startGeometryShaderTag_) || + text.contains(TextBrowserWidget::endGeometryShaderTag_) || + text.contains(TextBrowserWidget::startFragmentShaderTag_) || + text.contains(TextBrowserWidget::endFragmentShaderTag_)) { + if (found_fold.folded) + painter.drawText(0, top, sideArea_->width(), fontMetrics().height(),Qt::AlignRight, "+"); + else + painter.drawText(0, top, sideArea_->width(), fontMetrics().height(),Qt::AlignRight, "-"); + } else { + QString number = QString::number(blockNumber - fold_first_block); + painter.drawText(0, top, sideArea_->width(), fontMetrics().height(),Qt::AlignRight, number); + } + } else { + if (found_fold.folded) + painter.drawText(0, top, sideArea_->width(), fontMetrics().height(),Qt::AlignRight, "+"); + else + painter.drawText(0, top, sideArea_->width(), fontMetrics().height(),Qt::AlignRight, "-"); + } + } else + painter.drawText(0, top, sideArea_->width(), fontMetrics().height(),Qt::AlignRight, " "); + } + + block = block.next(); + top = bottom; + bottom = top + (int) blockBoundingRect(block).height(); + ++blockNumber; + } +} + +bool TextBrowserWidget::getFold(int _position, Fold& _fold) { + std::map::iterator it = blockPosToFold_.find(_position); + if (it != blockPosToFold_.end()) { + _fold = folds_[it->second]; + return true; + } else + return false; +} + +void TextBrowserWidget::mouseDoubleClickEvent(QMouseEvent* e) { + QTextBlock block = firstVisibleBlock(); + int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top(); + int bottom = top + (int) blockBoundingRect(block).height(); + const int y = e->y(); + // find the block that was clicked and toggle the folding + while (block.isValid()) { + if (top <= y && y <= bottom) { + toggleFold(block.position()); + break; + } + + block = block.next(); + top = bottom; + bottom = top + (int) blockBoundingRect(block).height(); + } +} + +void TextBrowserWidget::foldAll() { + for (std::vector::iterator it = folds_.begin(); it != folds_.end(); ++it) { + fold(*it); + } +} + +void TextBrowserWidget::unfoldAll() { + for (std::vector::iterator it = folds_.begin(); it != folds_.end(); ++it) { + unfold(*it); + } +} + +void TextBrowserWidget::fold(Fold& _fold) { + if (_fold.folded) + return; + + QTextBlock startBlock = document()->findBlock(_fold.start); + QTextBlock endBlock = document()->findBlock(_fold.end); + + startBlock = startBlock.next(); + while (startBlock.isValid() && startBlock != endBlock) { + startBlock.setVisible(false); + startBlock = startBlock.next(); + } + if (_fold.type == RENDEROBJECT) + endBlock.setVisible(false); + + _fold.folded = true; + document()->markContentsDirty(_fold.start, _fold.end - _fold.start); +} + +void TextBrowserWidget::unfold(Fold& _fold) { + if (!_fold.folded) + return; + + QTextBlock startBlock = document()->findBlock(_fold.start); + QTextBlock endBlock = document()->findBlock(_fold.end); + + startBlock = startBlock.next(); + while (startBlock.isValid() && startBlock != endBlock) { + startBlock.setVisible(true); + startBlock = startBlock.next(); + } + if (_fold.type == RENDEROBJECT) + endBlock.setVisible(true); + + _fold.folded = false; + document()->markContentsDirty(_fold.start, _fold.end-_fold.start); +} + +void TextBrowserWidget::toggleFold(int _position) { + for (std::vector::iterator it = folds_.begin(); it != folds_.end(); ++it) { + if (it->contains(_position)) { + if (it->folded) + unfold(*it); + else + fold(*it); + + break; + } + } +} + +void TextBrowserWidget::updateFolds() { + folds_.clear(); + + // search for all vertex shader + QTextCursor startCursor = document()->find(TextBrowserWidget::startVertexShaderTag_, 0, QTextDocument::FindWholeWords); + QTextCursor endCursor = document()->find(TextBrowserWidget::endVertexShaderTag_, 0, QTextDocument::FindWholeWords); + + while (!startCursor.isNull() && !endCursor.isNull()) { + startCursor.movePosition(QTextCursor::StartOfLine); + endCursor.movePosition(QTextCursor::EndOfLine); + folds_.push_back(Fold(startCursor.position(),endCursor.position(),SHADER)); + + // map block position to fold + int startPos = startCursor.position(); + const int endPos = endCursor.position(); + for (; startPos < endPos; ++startPos) { + QTextBlock block = document()->findBlock(startPos); + blockPosToFold_[block.position()] = folds_.size() - 1; + } + + bool moved = startCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + moved = endCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + + startCursor = document()->find(TextBrowserWidget::startVertexShaderTag_, startCursor, QTextDocument::FindWholeWords); + endCursor = document()->find(TextBrowserWidget::endVertexShaderTag_, endCursor, QTextDocument::FindWholeWords); + } + + // search for all geometry shader + startCursor = document()->find(TextBrowserWidget::startGeometryShaderTag_, 0, QTextDocument::FindWholeWords); + endCursor = document()->find(TextBrowserWidget::endGeometryShaderTag_, 0, QTextDocument::FindWholeWords); + + while (!startCursor.isNull() && !endCursor.isNull()) { + startCursor.movePosition(QTextCursor::StartOfLine); + endCursor.movePosition(QTextCursor::EndOfLine); + folds_.push_back(Fold(startCursor.position(),endCursor.position(),SHADER)); + + // map block position to fold + int startPos = startCursor.position(); + const int endPos = endCursor.position(); + for (; startPos < endPos; ++startPos) { + QTextBlock block = document()->findBlock(startPos); + blockPosToFold_[block.position()] = folds_.size() - 1; + } + + bool moved = startCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + moved = endCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + + startCursor = document()->find(TextBrowserWidget::startGeometryShaderTag_, startCursor, QTextDocument::FindWholeWords); + endCursor = document()->find(TextBrowserWidget::endGeometryShaderTag_, endCursor, QTextDocument::FindWholeWords); + } + + // search for all fragment shader + startCursor = document()->find(TextBrowserWidget::startFragmentShaderTag_, 0, QTextDocument::FindWholeWords); + endCursor = document()->find(TextBrowserWidget::endFragmentShaderTag_, 0, QTextDocument::FindWholeWords); + + while (!startCursor.isNull() && !endCursor.isNull()) { + startCursor.movePosition(QTextCursor::StartOfLine); + endCursor.movePosition(QTextCursor::EndOfLine); + folds_.push_back(Fold(startCursor.position(),endCursor.position(),SHADER)); + + // map block position to fold + int startPos = startCursor.position(); + const int endPos = endCursor.position(); + for (; startPos < endPos; ++startPos) { + QTextBlock block = document()->findBlock(startPos); + blockPosToFold_[block.position()] = folds_.size() - 1; + } + + bool moved = startCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + moved = endCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + + startCursor = document()->find(TextBrowserWidget::startFragmentShaderTag_, startCursor, QTextDocument::FindWholeWords); + endCursor = document()->find(TextBrowserWidget::endFragmentShaderTag_, endCursor, QTextDocument::FindWholeWords); + } + + // search for all render objects + startCursor = document()->find(TextBrowserWidget::startRenderObjectTag_, 0, QTextDocument::FindWholeWords); + endCursor = document()->find(TextBrowserWidget::startVertexShaderTag_, 0, QTextDocument::FindWholeWords); + + while (!startCursor.isNull() && !endCursor.isNull()) { + startCursor.movePosition(QTextCursor::StartOfLine); + // vertex shader does not belong to this fold + endCursor.movePosition(QTextCursor::Up); + endCursor.movePosition(QTextCursor::EndOfLine); + folds_.push_back(Fold(startCursor.position(),endCursor.position(),RENDEROBJECT)); + + // map block position to fold + int startPos = startCursor.position(); + const int endPos = endCursor.position(); + for (; startPos < endPos; ++startPos) { + QTextBlock block = document()->findBlock(startPos); + blockPosToFold_[block.position()] = folds_.size() - 1; + } + + bool moved = startCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + // skip to after the vertex shader starts + moved = endCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + moved = endCursor.movePosition(QTextCursor::Down); + if (!moved) + break; + + startCursor = document()->find(TextBrowserWidget::startRenderObjectTag_, startCursor, QTextDocument::FindWholeWords); + endCursor = document()->find(TextBrowserWidget::startVertexShaderTag_, endCursor, QTextDocument::FindWholeWords); + } + + // fold shader blocks + foldAll(); +} diff --git a/widgets/rendererWidget/TextBrowserWidget.hh b/widgets/rendererWidget/TextBrowserWidget.hh new file mode 100644 index 0000000000000000000000000000000000000000..0f4e3199a7d973095e2576bdde09d2fd1910c9af --- /dev/null +++ b/widgets/rendererWidget/TextBrowserWidget.hh @@ -0,0 +1,157 @@ +/*===========================================================================*\ +* * +* OpenFlipper * +* Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen * +* www.openflipper.org * +* * +*--------------------------------------------------------------------------- * +* This file is part of OpenFlipper. * +* * +* OpenFlipper is free software: you can redistribute it and/or modify * +* it under the terms of the GNU Lesser General Public License as * +* published by the Free Software Foundation, either version 3 of * +* the License, or (at your option) any later version with the * +* following exceptions: * +* * +* If other files instantiate templates or use macros * +* or inline functions from this file, or you compile this file and * +* link it with other files to produce an executable, this file does * +* not by itself cause the resulting executable to be covered by the * +* GNU Lesser General Public License. This exception does not however * +* invalidate any other reasons why the executable file might be * +* covered by the GNU Lesser General Public License. * +* * +* OpenFlipper is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU LesserGeneral Public * +* License along with OpenFlipper. If not, * +* see . * +* * +\*===========================================================================*/ + +/*===========================================================================*\ +* * +* $Revision: 12438 $ * +* $LastChangedBy: moebius $ * +* $Date: 2011-09-22 17:16:17 +0200 (Thu, 22 Sep 2011) $ * +* * +\*===========================================================================*/ + +#ifndef TEXTBROWSERWIDGET_HH +#define TEXTBROWSERWIDGET_HH + +#include +#include + +#include + +class TextBrowserSideArea; + + +class TextBrowserWidget : public QPlainTextEdit +{ + Q_OBJECT + + private: + enum FoldType { + SHADER, + RENDEROBJECT + }; + + struct Fold { + Fold() : + start(-1), + end(-1), + folded(false), + type(SHADER) + {} + + Fold(int _start, int _end, FoldType _type) : + start(_start), + end(_end), + folded(false), + type(_type) + {} + + bool contains (int n) const { + return (start <= n) && (n <= end); + } + + // start positition in the document + int start; + // end positition in the document + int end; + bool folded; + FoldType type; + }; + + + public: + TextBrowserWidget(QWidget *parent = 0); + + void sideAreaPaintEvent(QPaintEvent *event); + int sideAreaWidth(); + + protected: + void resizeEvent(QResizeEvent *event); + virtual void mouseDoubleClickEvent(QMouseEvent* e); + + private slots: + void updateTextBrowserSideAreaWidth(); + void updateTextBrowserSideArea(const QRect &, int); + void foldAll(); + void unfoldAll(); + void fold(Fold& _fold); + void unfold(Fold& _fold); + void toggleFold(int _position); + void updateFolds(); + /** \brief get the _fold corresponding to the document _position + * @param _position position in the document + * @param _fold fold in folds_ at the position if found + * + * \return true if fold was found (otherwise false is returned) + */ + bool getFold(int _position, Fold& _fold); + + private: + TextBrowserSideArea* sideArea_; + static QString const startRenderObjectTag_; + static QString const startVertexShaderTag_; + static QString const endVertexShaderTag_; + static QString const startGeometryShaderTag_; + static QString const endGeometryShaderTag_; + static QString const startFragmentShaderTag_; + static QString const endFragmentShaderTag_; + + std::vector folds_; + /// maps positions in the document to indices in folds_ + std::map blockPosToFold_; +}; + + +class TextBrowserSideArea : public QWidget +{ + public: + TextBrowserSideArea(TextBrowserWidget* _textBrowser) : + QWidget(_textBrowser), + textBrowser_(_textBrowser) + {} + + QSize sizeHint() const { + return QSize(textBrowser_->sideAreaWidth(), 0); + } + + protected: + void paintEvent(QPaintEvent *event) { + textBrowser_->sideAreaPaintEvent(event); + } + + private: + TextBrowserWidget* textBrowser_; +}; + + +#endif // TEXTBROWSERWIDGET_HH diff --git a/widgets/rendererWidget/rendererObjectWidget.cc b/widgets/rendererWidget/rendererObjectWidget.cc index 7fab1f8408abf43be1a8dd8834fbdf70ba2f6bdc..a0aa833e1a1b741baaf532570cc2b938c66e4ea1 100644 --- a/widgets/rendererWidget/rendererObjectWidget.cc +++ b/widgets/rendererWidget/rendererObjectWidget.cc @@ -42,7 +42,7 @@ #include "rendererObjectWidget.hh" -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= 0x050000 #include #else #include @@ -57,7 +57,8 @@ RendererObjectWidget::RendererObjectWidget(QWidget *parent) : QDialog(parent), - highlighter_(0) + highlighter_(0), + textBrowser_(0) { setupUi(this); @@ -68,7 +69,10 @@ RendererObjectWidget::RendererObjectWidget(QWidget *parent) closeButton->setIcon( QIcon(iconPath + "window-close.png")); - highlighter_ = new RenderObjectHighlighter( textBrowser->document() ); + textBrowser_ = new TextBrowserWidget(this); + textBrowserLayout->addWidget(textBrowser_); + + highlighter_ = new RenderObjectHighlighter( textBrowser_->document() ); connect(showShadersBox,SIGNAL(clicked()),this,SLOT(update())); } @@ -88,22 +92,20 @@ void RendererObjectWidget::update() { RendererInfo* renderer = renderManager().active(PluginFunctions::activeExaminer()); - textBrowser->clear(); + textBrowser_->clear(); if ( renderer ) { - textBrowser->insertPlainText(tr("Current renderer: ") + renderer->name +"\n"); - textBrowser->insertPlainText(tr("Description: ") + renderer->description +"\n"); - textBrowser->insertPlainText(tr("Version: ") + renderer->version + "\n" ); - textBrowser->insertPlainText("\n" ); + textBrowser_->insertPlainText(tr("Current renderer: ") + renderer->name +"\n"); + textBrowser_->insertPlainText(tr("Description: ") + renderer->description +"\n"); + textBrowser_->insertPlainText(tr("Version: ") + renderer->version + "\n" ); + textBrowser_->insertPlainText("\n" ); //TODO: Flag for shader output activate/deactivate if ( renderManager().activeId(PluginFunctions::activeExaminer()) != 0 ) - textBrowser->insertPlainText(renderer->plugin->renderObjectsInfo(showShadersBox->isChecked())); + textBrowser_->insertPlainText(renderer->plugin->renderObjectsInfo(showShadersBox->isChecked())); } else { - textBrowser->setText("Unable to get renderer!"); + textBrowser_->insertPlainText("Unable to get renderer!"); } - - } diff --git a/widgets/rendererWidget/rendererObjectWidget.hh b/widgets/rendererWidget/rendererObjectWidget.hh index d10667957800dd1188401555320dd7a105ba40b5..eaab5749cee300d06fb75260a0fde3f4f55b395d 100644 --- a/widgets/rendererWidget/rendererObjectWidget.hh +++ b/widgets/rendererWidget/rendererObjectWidget.hh @@ -45,6 +45,7 @@ #include #include "renderObjectHighLighter.hh" +#include "TextBrowserWidget.hh" class RendererObjectWidget : public QDialog, public Ui::RendererObjectWidget { @@ -64,6 +65,6 @@ class RendererObjectWidget : public QDialog, public Ui::RendererObjectWidget private: RenderObjectHighlighter* highlighter_; - + TextBrowserWidget* textBrowser_; }; diff --git a/widgets/rendererWidget/rendererObjectWidget.ui b/widgets/rendererWidget/rendererObjectWidget.ui index 188c55aad807a9deb5283bec61ceecb41f19cd60..e620fbe2ab27495c37c3517b49987618581c58fb 100644 --- a/widgets/rendererWidget/rendererObjectWidget.ui +++ b/widgets/rendererWidget/rendererObjectWidget.ui @@ -7,7 +7,7 @@ 0 0 939 - 527 + 513 @@ -62,7 +62,7 @@ - +