Skip to content
408 changes: 408 additions & 0 deletions docs/dev_doc/UndoRedoStackDesign.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ void ReorderNormalCoherentlyAlgo::runImpl(FieldHandle inputField, FieldHandle& o
for (j = 0; j < noOfV; j++)
{
k=(j+1)%noOfV;
edges.insert(std::make_pair(elem[i][j], elem[i][k]));
edges.emplace(elem[i][j], elem[i][k]);
}
outputVMesh->add_elem(nodesFromFace);

Expand Down
28 changes: 14 additions & 14 deletions src/Graphics/Glyphs/GlyphConstructor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,157 +60,157 @@
return const_cast<GlyphData&>(getDataConst(prim));
}

void GlyphConstructor::buildObject(GeometryObjectSpire& geom, const std::string& uniqueNodeID,
const bool isTransparent, const double transparencyValue, const ColorScheme& colorScheme,
RenderState state, const BBox& bbox, const bool isClippable,
const Core::Datatypes::ColorMapHandle colorMap)
{
for (auto prim : {SpireIBO::PRIMITIVE::POINTS, SpireIBO::PRIMITIVE::LINES, SpireIBO::PRIMITIVE::TRIANGLES})
{
const auto& data = getDataConst(prim);
if (data.numVBOElements_ == 0) continue;
bool useColor = colorScheme == ColorScheme::COLOR_IN_SITU || colorScheme == ColorScheme::COLOR_MAP;
bool useNormals = data.normals_.size() == data.points_.size();
int numAttributes = 3;

RenderType renderType = RenderType::RENDER_VBO_IBO;
ColorRGB dft = state.defaultColor;

std::string shader = (useNormals ? "Shaders/Phong" : "Shaders/Flat");
std::vector<SpireVBO::AttributeData> attribs;
std::vector<SpireSubPass::Uniform> uniforms;

attribs.push_back(SpireVBO::AttributeData("aPos", 3 * sizeof(float)));
uniforms.push_back(SpireSubPass::Uniform("uUseClippingPlanes", isClippable));
uniforms.push_back(SpireSubPass::Uniform("uUseFog", true));
attribs.emplace_back("aPos", 3 * sizeof(float));
uniforms.emplace_back("uUseClippingPlanes", isClippable);
uniforms.emplace_back("uUseFog", true);

if (useNormals)
{
numAttributes += 3;
attribs.push_back(SpireVBO::AttributeData("aNormal", 3 * sizeof(float)));
uniforms.push_back(SpireSubPass::Uniform("uAmbientColor", glm::vec4(0.1f, 0.1f, 0.1f, 1.0f)));
uniforms.push_back(SpireSubPass::Uniform("uSpecularColor", glm::vec4(0.1f, 0.1f, 0.1f, 0.1f)));
uniforms.push_back(SpireSubPass::Uniform("uSpecularPower", 32.0f));
attribs.emplace_back("aNormal", 3 * sizeof(float));
uniforms.emplace_back("uAmbientColor", glm::vec4(0.1f, 0.1f, 0.1f, 1.0f));
uniforms.emplace_back("uSpecularColor", glm::vec4(0.1f, 0.1f, 0.1f, 0.1f));
uniforms.emplace_back("uSpecularPower", 32.0f);
}

SpireText text;
SpireTexture2D texture;
if (useColor)
{
if(colorMap)
{
numAttributes += 2;
shader += "_ColorMap";
attribs.push_back(SpireVBO::AttributeData("aTexCoords", 2 * sizeof(float)));
attribs.emplace_back("aTexCoords", 2 * sizeof(float));

const static int colorMapResolution = 256;
for(int i = 0; i < colorMapResolution; ++i)
{
ColorRGB color = colorMap->valueToColor(static_cast<float>(i)/colorMapResolution * 2.0f - 1.0f);
texture.bitmap.push_back(color.r()*255.99f);
texture.bitmap.push_back(color.g()*255.99f);
texture.bitmap.push_back(color.b()*255.99f);
texture.bitmap.push_back(color.a()*255.99f);
}

texture.name = "ColorMap";
texture.height = 1;
texture.width = colorMapResolution;
}
else
{
numAttributes += 4;
shader += "_Color";
attribs.push_back(SpireVBO::AttributeData("aColor", 4 * sizeof(float)));
attribs.emplace_back("aColor", 4 * sizeof(float));
}
}
else
{
uniforms.push_back(SpireSubPass::Uniform("uDiffuseColor",
glm::vec4(dft.r(), dft.g(), dft.b(), static_cast<float>(transparencyValue))));
uniforms.emplace_back("uDiffuseColor",
glm::vec4(dft.r(), dft.g(), dft.b(), static_cast<float>(transparencyValue)));
}

if (isTransparent) uniforms.push_back(SpireSubPass::Uniform("uTransparency", static_cast<float>(transparencyValue)));
if (isTransparent) uniforms.emplace_back("uTransparency", static_cast<float>(transparencyValue));

size_t pointsLeft = data.points_.size();
size_t startOfPass = 0;
int passNumber = 0;
while(pointsLeft > 0)
{
std::string passID = uniqueNodeID + "_" + std::to_string(int(prim)) + "_" + std::to_string(passNumber++);
std::string vboName = passID + "VBO";
std::string iboName = passID + "IBO";
std::string passName = passID + "Pass";

const static size_t maxPointsPerPass = 3 << 24; //must be a number divisible by 2, 3 and, 4
uint32_t pointsInThisPass = std::min(pointsLeft, maxPointsPerPass);
size_t endOfPass = startOfPass + pointsInThisPass;
pointsLeft -= pointsInThisPass;

size_t vboSize = static_cast<size_t>(pointsInThisPass) * numAttributes * sizeof(float);
size_t iboSize = static_cast<size_t>(pointsInThisPass) * sizeof(uint32_t);
std::shared_ptr<spire::VarBuffer> iboBufferSPtr(new spire::VarBuffer(iboSize));
std::shared_ptr<spire::VarBuffer> vboBufferSPtr(new spire::VarBuffer(vboSize));
auto iboBufferSPtr = std::make_shared<spire::VarBuffer>(iboSize);
auto vboBufferSPtr = std::make_shared<spire::VarBuffer>(vboSize);
auto iboBuffer = iboBufferSPtr.get();
auto vboBuffer = vboBufferSPtr.get();

for (auto a : data.indices_) if(a >= startOfPass && a < endOfPass)
iboBuffer->write(static_cast<uint32_t>(a - startOfPass));

BBox newBBox;
for (size_t i = startOfPass; i < endOfPass; ++i)
{
auto point = data.points_.at(i);
newBBox.extend(Point(point.x(), point.y(), point.z()));
vboBuffer->write(static_cast<float>(point.x()));
vboBuffer->write(static_cast<float>(point.y()));
vboBuffer->write(static_cast<float>(point.z()));

if (useNormals)
{
auto normal = data.normals_.at(i);
vboBuffer->write(static_cast<float>(normal.x()));
vboBuffer->write(static_cast<float>(normal.y()));
vboBuffer->write(static_cast<float>(normal.z()));
}

if (useColor)
{
auto color = data.colors_.at(i);
if(!colorMap)
{
vboBuffer->write(static_cast<float>(color.r()));
vboBuffer->write(static_cast<float>(color.g()));
vboBuffer->write(static_cast<float>(color.b()));
vboBuffer->write(static_cast<float>(color.a()));
}
else
{
vboBuffer->write(static_cast<float>(color.r()));
vboBuffer->write(static_cast<float>(color.r()));
}
}
}
if(!bbox.valid()) newBBox.reset();

startOfPass = endOfPass;

SpireVBO geomVBO(vboName, attribs, vboBufferSPtr, data.numVBOElements_, newBBox, true);
SpireIBO geomIBO(iboName, prim, sizeof(uint32_t), iboBufferSPtr);

state.set(RenderState::ActionFlags::IS_ON, true);
state.set(RenderState::ActionFlags::HAS_DATA, true);
SpireSubPass pass(passName, vboName, iboName, shader, colorScheme, state, renderType, geomVBO, geomIBO, text, texture);

for (const auto& uniform : uniforms) pass.addUniform(uniform);

geom.vbos().push_back(geomVBO);
geom.ibos().push_back(geomIBO);
geom.passes().push_back(pass);
}
}
}

Check notice on line 213 in src/Graphics/Glyphs/GlyphConstructor.cc

View check run for this annotation

codefactor.io / CodeFactor

src/Graphics/Glyphs/GlyphConstructor.cc#L63-L213

Complex Method
uint32_t GlyphConstructor::setOffset(SpireIBO::PRIMITIVE prim)
{
auto& data = getData(prim);
Expand Down
18 changes: 18 additions & 0 deletions src/Interface/Application/ModuleWidget.cc
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,22 @@ void ModuleWidget::subnetButtonClicked()

void ModuleWidget::setLogButtonColor(const QColor& color)
{
const auto incoming = static_cast<int>(
(color == Qt::red) ? LogColorPriority::Error :
(color == Qt::yellow) ? LogColorPriority::Warning :
LogColorPriority::Remark);

// Only update if the incoming message has strictly higher priority than
// whatever is already shown (fixes #103: remark after error stays red).
int expected = currentLogPriority_.load();
while (incoming > expected)
{
if (currentLogPriority_.compare_exchange_weak(expected, incoming))
break;
}
if (incoming <= expected)
return;

if (color == Qt::red)
{
errored_ = true;
Expand All @@ -531,6 +547,7 @@ void ModuleWidget::setLogButtonColor(const QColor& color)

void ModuleWidget::resetLogButtonColor()
{
currentLogPriority_ = static_cast<int>(LogColorPriority::None);
fullWidgetDisplay_->setStatusColor("");
}

Expand Down Expand Up @@ -1092,6 +1109,7 @@ bool ModuleWidget::executeWithSignals()
{
Q_EMIT signalExecuteButtonIconChangeToStop();
errored_ = false;
currentLogPriority_ = static_cast<int>(LogColorPriority::None);
//colorLocked_ = true; //TODO
timer_.reset(new SimpleScopedTimer);
theModule_->executeWithSignals();
Expand Down
2 changes: 2 additions & 0 deletions src/Interface/Application/ModuleWidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,8 @@ private Q_SLOTS:
bool deletedFromGui_, colorLocked_;
bool executedOnce_, skipExecuteDueToFatalError_, disabled_, programmablePortEnabled_{false};
std::atomic<bool> errored_;
enum class LogColorPriority { None = 0, Remark = 1, Warning = 2, Error = 3 };
std::atomic<int> currentLogPriority_ { static_cast<int>(LogColorPriority::None) };
int previousPageIndex_ {0};
QDialog* replaceWithDialog_{ nullptr };

Expand Down
58 changes: 42 additions & 16 deletions src/Interface/Application/NoteEditor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@

using namespace SCIRun::Gui;

// Applies a character format to all text in the document without
// destroying existing formatting (unlike the setPlainText(toPlainText()) hack).
static void applyFormatToAll(QTextEdit* edit, const QTextCharFormat& format)
{
QTextCursor cursor = edit->textCursor();
cursor.select(QTextCursor::Document);
cursor.mergeCharFormat(format);
edit->setTextCursor(cursor);
}

NoteEditor::NoteEditor(const QString& moduleName, bool positionAdjustable, QWidget* parent) : QDialog(parent), moduleName_(moduleName)
{
setupUi(this);
Expand Down Expand Up @@ -74,13 +84,13 @@ void NoteEditor::changeFontSize(const QString& text)
size = defaultNoteFontSize_;
else
size = text.toDouble();
textEdit_->setFontPointSize(size);
textEdit_->setPlainText(textEdit_->toPlainText());
QTextCharFormat fmt;
fmt.setFontPointSize(size);
applyFormatToAll(textEdit_, fmt);
}

void NoteEditor::changeTextAlignment(const QString& text)
{
//TODO: only changes one line at a time...may just chuck this option
Qt::Alignment alignment;
if (text == "Left")
alignment = Qt::AlignLeft;
Expand All @@ -90,8 +100,12 @@ void NoteEditor::changeTextAlignment(const QString& text)
alignment = Qt::AlignRight;
else // text == "Justify")
alignment = Qt::AlignJustify;
textEdit_->setAlignment(alignment);
textEdit_->setPlainText(textEdit_->toPlainText());
QTextCursor cursor = textEdit_->textCursor();
cursor.select(QTextCursor::Document);
QTextBlockFormat blockFmt;
blockFmt.setAlignment(alignment);
cursor.mergeBlockFormat(blockFmt);
textEdit_->setTextCursor(cursor);
}

void NoteEditor::changeTextColor()
Expand All @@ -105,15 +119,23 @@ void NoteEditor::setNoteHtml(const QString& text)
{
textEdit_->blockSignals(true);
textEdit_->setHtml(text);
// Sync color tracking state from the loaded HTML so that Reset Color and
// Cancel work correctly against the actual loaded color, not Qt::white.
QTextCursor cursor = textEdit_->textCursor();
cursor.movePosition(QTextCursor::Start);
const auto loadedColor = cursor.charFormat().foreground().color();
if (loadedColor.isValid())
currentColor_ = previousColor_ = loadedColor;
textEdit_->blockSignals(false);
}

void NoteEditor::setNoteFontSize(int size)
{
textEdit_->blockSignals(true);
fontSizeComboBox_->blockSignals(true);
textEdit_->setFontPointSize(size);
textEdit_->setPlainText(textEdit_->toPlainText());
QTextCharFormat fmt;
fmt.setFontPointSize(size);
applyFormatToAll(textEdit_, fmt);
int index = fontSizeComboBox_->findText(QString::number(size));
if (index != -1)
fontSizeComboBox_->setCurrentIndex(index);
Expand All @@ -129,9 +151,9 @@ void NoteEditor::setDefaultNoteFontSize(int size)
if (fontSizeComboBox_->currentText() == "Default")
{
textEdit_->blockSignals(true);

textEdit_->setFontPointSize(size);
textEdit_->setPlainText(textEdit_->toPlainText());
QTextCharFormat fmt;
fmt.setFontPointSize(size);
applyFormatToAll(textEdit_, fmt);
currentNote_.html_ = textEdit_->toHtml();
if (callCount_ > 1)
updateNote();
Expand All @@ -144,9 +166,9 @@ void NoteEditor::setNoteColor(const QColor& color)
{
if (color.isValid())
{
previousColor_ = textEdit_->textColor();
textEdit_->setTextColor(color);
textEdit_->setPlainText(textEdit_->toPlainText());
QTextCharFormat fmt;
fmt.setForeground(QBrush(color));
applyFormatToAll(textEdit_, fmt);
updateNote();
}
else
Expand All @@ -162,10 +184,12 @@ void NoteEditor::resetText()

void NoteEditor::resetTextColor()
{
auto oldColor = textEdit_->textColor();
textEdit_->setTextColor(previousColor_);
textEdit_->setPlainText(textEdit_->toPlainText());
const auto oldColor = currentColor_;
QTextCharFormat fmt;
fmt.setForeground(QBrush(previousColor_));
applyFormatToAll(textEdit_, fmt);
previousColor_ = currentColor_ = oldColor;
updateNote();
}

void NoteEditor::ok()
Expand All @@ -177,6 +201,7 @@ void NoteEditor::cancel()
{
textEdit_->setHtml(noteHtmlBackup_);
fontSizeComboBox_->setCurrentIndex(fontSizeBackup_);
currentColor_ = previousColor_ = colorBackup_;
hide();
}

Expand All @@ -191,5 +216,6 @@ void NoteEditor::showEvent(QShowEvent* event)
{
noteHtmlBackup_ = textEdit_->toHtml();
fontSizeBackup_ = fontSizeComboBox_->currentIndex();
colorBackup_ = currentColor_;
QDialog::showEvent(event);
}
2 changes: 1 addition & 1 deletion src/Interface/Application/NoteEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ private Q_SLOTS:
Note currentNote_;
QString noteHtmlBackup_;
int fontSizeBackup_, positionBackup_;
QColor previousColor_, currentColor_;
QColor previousColor_, currentColor_, colorBackup_;
NotePosition position_;
int defaultNoteFontSize_{ 20 };
int callCount_{ 0 };
Expand Down
45 changes: 2 additions & 43 deletions src/Interface/Application/SCIRunMainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -359,33 +359,8 @@
<property name="whatsThis">
<string>Enter a filter string here. The module list below will display only those modules whose name matches the filter (either by exact string or wildcard).</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearFilterButton_">
<property name="minimumSize">
<size>
<width>58</width>
<height>35</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>58</width>
<height>35</height>
</size>
</property>
<property name="toolTip">
<string>Clear filter text</string>
</property>
<property name="whatsThis">
<string>Click this button to clear the filter text and see all available modules.</string>
</property>
<property name="text">
<string>Clear</string>
</property>
<property name="flat">
<bool>false</bool>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
Expand Down Expand Up @@ -1361,21 +1336,5 @@
</widget>
<resources/>
<connections>
<connection>
<sender>clearFilterButton_</sender>
<signal>clicked()</signal>
<receiver>moduleFilterLineEdit_</receiver>
<slot>clear()</slot>
<hints>
<hint type="sourcelabel">
<x>243</x>
<y>64</y>
</hint>
<hint type="destinationlabel">
<x>141</x>
<y>63</y>
</hint>
</hints>
</connection>
</connections>
</ui>
2 changes: 2 additions & 0 deletions src/Interface/Modules/Base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ SET(Interface_Modules_Base_HEADERS_M
CustomWidgets/QtHistogramWidget.h
CustomWidgets/QtHistogramGraph.h
CustomWidgets/CodeEditorWidgets.h
CustomWidgets/FileNameLineEdit.h
CustomWidgets/CTK/ctkColorPickerButton.h
CustomWidgets/CTK/ctkDoubleSpinBox.h
CustomWidgets/CTK/ctkDoubleSpinBox_p.h
Expand All @@ -78,6 +79,7 @@ SET(Interface_Modules_Base_SOURCES
CustomWidgets/QtHistogramWidget.cc
CustomWidgets/QtHistogramGraph.cc
CustomWidgets/CodeEditorWidgets.cc
CustomWidgets/FileNameLineEdit.cc
CustomWidgets/CTK/ctkColorPickerButton.cpp
CustomWidgets/CTK/ctkDoubleSpinBox.cpp
CustomWidgets/CTK/ctkPopupWidget.cpp
Expand Down
56 changes: 56 additions & 0 deletions src/Interface/Modules/Base/CustomWidgets/FileNameLineEdit.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
For more information, please see: http://software.sci.utah.edu

The MIT License

Copyright (c) 2020 Scientific Computing and Imaging Institute,
University of Utah.

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#include <Interface/Modules/Base/CustomWidgets/FileNameLineEdit.h>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
#include <QUrl>

FileNameLineEdit::FileNameLineEdit(QWidget* parent)
: QLineEdit(parent)
{
setAcceptDrops(true);
}

void FileNameLineEdit::dragEnterEvent(QDragEnterEvent* event)
{
if (event->mimeData()->hasUrls())
event->acceptProposedAction();
else
QLineEdit::dragEnterEvent(event);
}

void FileNameLineEdit::dropEvent(QDropEvent* event)
{
const auto urls = event->mimeData()->urls();
if (!urls.isEmpty())
{
setText(urls.first().toLocalFile());
Q_EMIT editingFinished();
}
}
Loading
Loading