diff --git a/src/Base/Interpreter.cpp b/src/Base/Interpreter.cpp index a1ddd5a7a..427e439dc 100644 --- a/src/Base/Interpreter.cpp +++ b/src/Base/Interpreter.cpp @@ -38,6 +38,7 @@ #include "PyTools.h" #include "Exception.h" #include "PyObjectBase.h" +#include char format2[1024]; //Warning! Can't go over 512 characters!!! @@ -89,6 +90,36 @@ SystemExitException::SystemExitException(const SystemExitException &inst) // --------------------------------------------------------- +// Fixes #0000831: python print causes File descriptor error on windows +class PythonStdOutput : public Py::PythonExtension +{ +public: + static void init_type(void) + { + behaviors().name("PythonStdOutput"); + behaviors().doc("Python standard output"); + add_varargs_method("write",&PythonStdOutput::write,"write()"); + add_varargs_method("flush",&PythonStdOutput::flush,"flush()"); + } + + PythonStdOutput() + { + } + ~PythonStdOutput() + { + } + + Py::Object write(const Py::Tuple&) + { + return Py::None(); + } + Py::Object flush(const Py::Tuple&) + { + return Py::None(); + } +}; + +// --------------------------------------------------------- InterpreterSingleton::InterpreterSingleton() { @@ -311,6 +342,10 @@ const char* InterpreterSingleton::init(int argc,char *argv[]) PyEval_InitThreads(); Py_Initialize(); PySys_SetArgv(argc, argv); + PythonStdOutput::init_type(); + PythonStdOutput* out = new PythonStdOutput(); + PySys_SetObject("stdout", out); + PySys_SetObject("stderr", out); this->_global = PyEval_SaveThread(); } diff --git a/src/Gui/BitmapFactory.cpp b/src/Gui/BitmapFactory.cpp index 9b781a4d0..4b5adccb9 100644 --- a/src/Gui/BitmapFactory.cpp +++ b/src/Gui/BitmapFactory.cpp @@ -166,6 +166,9 @@ QStringList BitmapFactoryInst::findIconFiles() const files << it->absoluteFilePath(); } +#if QT_VERSION >= 0x040500 + files.removeDuplicates(); +#endif return files; } diff --git a/src/Gui/DlgActionsImp.cpp b/src/Gui/DlgActionsImp.cpp index 6c392426b..664277bcb 100644 --- a/src/Gui/DlgActionsImp.cpp +++ b/src/Gui/DlgActionsImp.cpp @@ -384,7 +384,8 @@ IconDialog::IconDialog(QWidget* parent) QStringList names = BitmapFactory().findIconFiles(); for (QStringList::Iterator it = names.begin(); it != names.end(); ++it) { item = new QListWidgetItem(ui->listWidget); - item->setIcon(QIcon(*it)); + //item->setIcon(QIcon(*it)); + item->setIcon(QIcon(BitmapFactory().pixmap((const char*)it->toUtf8()))); item->setText(QFileInfo(*it).baseName()); item->setToolTip(*it); } diff --git a/src/Gui/PythonConsole.cpp b/src/Gui/PythonConsole.cpp index f82b27063..3f8eb7d48 100644 --- a/src/Gui/PythonConsole.cpp +++ b/src/Gui/PythonConsole.cpp @@ -59,29 +59,29 @@ using namespace Gui; namespace Gui { -static const QChar promptEnd( QLatin1Char(' ') ); //< char for detecting prompt end - -inline int promptLength( const QString &lineStr ) - { return lineStr.indexOf( promptEnd ) + 1; } - -inline QString stripPromptFrom( const QString &lineStr ) - { return lineStr.mid( promptLength(lineStr) ); } - -/** - * cursorBeyond checks if cursor is at a valid position to accept keyEvents. - * @param cursor - cursor to check - * @param limit - cursor that marks the begin of the input region - * @param shift - offset for shifting the limit for non-selection cursors [default: 0] - * @return true if a keyEvent is ok at cursor's position, false otherwise - */ -inline bool cursorBeyond( const QTextCursor &cursor, const QTextCursor &limit, int shift = 0 ) -{ - int pos = limit.position(); - if (cursor.hasSelection()) - return (cursor.selectionStart() >= pos && cursor.selectionEnd() >= pos); - else - return cursor.position() >= (pos + shift); -} +static const QChar promptEnd( QLatin1Char(' ') ); //< char for detecting prompt end + +inline int promptLength( const QString &lineStr ) + { return lineStr.indexOf( promptEnd ) + 1; } + +inline QString stripPromptFrom( const QString &lineStr ) + { return lineStr.mid( promptLength(lineStr) ); } + +/** + * cursorBeyond checks if cursor is at a valid position to accept keyEvents. + * @param cursor - cursor to check + * @param limit - cursor that marks the begin of the input region + * @param shift - offset for shifting the limit for non-selection cursors [default: 0] + * @return true if a keyEvent is ok at cursor's position, false otherwise + */ +inline bool cursorBeyond( const QTextCursor &cursor, const QTextCursor &limit, int shift = 0 ) +{ + int pos = limit.position(); + if (cursor.hasSelection()) + return (cursor.selectionStart() >= pos && cursor.selectionEnd() >= pos); + else + return cursor.position() >= (pos + shift); +} struct PythonConsoleP { @@ -363,7 +363,7 @@ void InteractiveInterpreter::clearBuffer() * Constructs a PythonConsole which is a child of 'parent'. */ PythonConsole::PythonConsole(QWidget *parent) - : TextEdit(parent), WindowParameter( "Editor" ), _sourceDrain(NULL) + : TextEdit(parent), WindowParameter( "Editor" ), _sourceDrain(NULL) { d = new PythonConsoleP(); d->interactive = false; @@ -464,10 +464,10 @@ void PythonConsole::OnChange( Base::Subject &rCaller,const char* sR void PythonConsole::keyPressEvent(QKeyEvent * e) { bool restartHistory = true; - QTextCursor cursor = this->textCursor(); - QTextCursor inputLineBegin = this->inputBegin(); + QTextCursor cursor = this->textCursor(); + QTextCursor inputLineBegin = this->inputBegin(); - if (!cursorBeyond( cursor, inputLineBegin )) + if (!cursorBeyond( cursor, inputLineBegin )) { /** * The cursor is placed not on the input line (or within the prompt string) @@ -482,7 +482,7 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) case Qt::Key_Return: case Qt::Key_Enter: case Qt::Key_Escape: - case Qt::Key_Backspace: + case Qt::Key_Backspace: this->moveCursor( QTextCursor::End ); break; @@ -511,20 +511,20 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) * - show call tips on period */ QTextBlock inputBlock = inputLineBegin.block(); //< get the last paragraph's text - QString inputLine = inputBlock.text(); - QString inputStrg = stripPromptFrom( inputLine ); + QString inputLine = inputBlock.text(); + QString inputStrg = stripPromptFrom( inputLine ); switch (e->key()) { case Qt::Key_Escape: { - // disable current input string - i.e. put it to history but don't execute it. - if (!inputStrg.isEmpty()) + // disable current input string - i.e. put it to history but don't execute it. + if (!inputStrg.isEmpty()) { - d->history.append( QLatin1String("# ") + inputStrg ); //< put commented string to history ... - inputLineBegin.insertText( QString::fromAscii("# ") ); //< and comment it on console + d->history.append( QLatin1String("# ") + inputStrg ); //< put commented string to history ... + inputLineBegin.insertText( QString::fromAscii("# ") ); //< and comment it on console setTextCursor( inputLineBegin ); - printPrompt(d->interpreter->hasPendingInput() //< print adequate prompt + printPrompt(d->interpreter->hasPendingInput() //< print adequate prompt ? PythonConsole::Incomplete : PythonConsole::Complete); } @@ -533,8 +533,8 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) case Qt::Key_Return: case Qt::Key_Enter: { - d->history.append( inputStrg ); //< put statement to history - runSource( inputStrg ); //< commit input string + d->history.append( inputStrg ); //< put statement to history + runSource( inputStrg ); //< commit input string } break; case Qt::Key_Period: @@ -542,14 +542,14 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) // analyse context and show available call tips int contextLength = cursor.position() - inputLineBegin.position(); TextEdit::keyPressEvent(e); - d->callTipsList->showTips( inputStrg.left( contextLength ) ); + d->callTipsList->showTips( inputStrg.left( contextLength ) ); } break; case Qt::Key_Home: { QTextCursor::MoveMode mode = (e->modifiers() & Qt::ShiftModifier)? QTextCursor::KeepAnchor /* else */ : QTextCursor::MoveAnchor; - cursor.setPosition( inputLineBegin.position(), mode ); + cursor.setPosition( inputLineBegin.position(), mode ); setTextCursor( cursor ); ensureCursorVisible(); } break; @@ -557,7 +557,7 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) case Qt::Key_Up: { // if possible, move back in history - if (d->history.prev( inputStrg )) + if (d->history.prev( inputStrg )) { overrideCursor( d->history.value() ); } restartHistory = false; } break; @@ -585,7 +585,7 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) case Qt::Key_Backspace: { - if (cursorBeyond( cursor, inputLineBegin, +1 )) + if (cursorBeyond( cursor, inputLineBegin, +1 )) { TextEdit::keyPressEvent(e); } } break; @@ -598,9 +598,9 @@ void PythonConsole::keyPressEvent(QKeyEvent * e) // the event and afterwards update the list widget if (d->callTipsList->isVisible()) { d->callTipsList->validateCursor(); } - - // disable history restart if input line changed - restartHistory &= (inputLine != inputBlock.text()); + + // disable history restart if input line changed + restartHistory &= (inputLine != inputBlock.text()); } // any cursor move resets the history to its latest item. if (restartHistory) @@ -647,40 +647,40 @@ void PythonConsole::printPrompt(PythonConsole::Prompt mode) d->error = QString::null; } - if (mode != PythonConsole::Special) - { - // Append the prompt string - QTextCursor cursor = textCursor(); - cursor.beginEditBlock(); - cursor.movePosition(QTextCursor::End); - QTextBlock block = cursor.block(); - - // Python's print command appends a trailing '\n' to the system output. - // In this case, however, we should not add a new text block. We force - // the current block to be normal text (user state = 0) to be highlighted - // correctly and append the '>>> ' or '... ' to this block. - if (block.length() > 1) - cursor.insertBlock(cursor.blockFormat(), cursor.charFormat()); - else - block.setUserState(0); - - switch (mode) - { - case PythonConsole::Incomplete: - cursor.insertText(QString::fromAscii("... ")); - break; - case PythonConsole::Complete: - cursor.insertText(QString::fromAscii(">>> ")); - break; - default: - break; - } - cursor.endEditBlock(); + // Append the prompt string + QTextCursor cursor = textCursor(); - // move cursor to the end - cursor.movePosition(QTextCursor::End); - setTextCursor(cursor); - } + if (mode != PythonConsole::Special) + { + cursor.beginEditBlock(); + cursor.movePosition(QTextCursor::End); + QTextBlock block = cursor.block(); + + // Python's print command appends a trailing '\n' to the system output. + // In this case, however, we should not add a new text block. We force + // the current block to be normal text (user state = 0) to be highlighted + // correctly and append the '>>> ' or '... ' to this block. + if (block.length() > 1) + cursor.insertBlock(cursor.blockFormat(), cursor.charFormat()); + else + block.setUserState(0); + + switch (mode) + { + case PythonConsole::Incomplete: + cursor.insertText(QString::fromAscii("... ")); + break; + case PythonConsole::Complete: + cursor.insertText(QString::fromAscii(">>> ")); + break; + default: + break; + } + cursor.endEditBlock(); + } + // move cursor to the end + cursor.movePosition(QTextCursor::End); + setTextCursor(cursor); } /** @@ -710,17 +710,17 @@ void PythonConsole::appendOutput(const QString& output, int state) */ void PythonConsole::runSource(const QString& line) { - /** - * Check if there's a "source drain", which want's to consume the source in another way then just executing it. - * If so, put the source to the drain and emit a signal to notify the consumer, whoever this may be. - */ - if (this->_sourceDrain) - { - *this->_sourceDrain = line; - Q_EMIT pendingSource(); - return; - } - + /** + * Check if there's a "source drain", which want's to consume the source in another way then just executing it. + * If so, put the source to the drain and emit a signal to notify the consumer, whoever this may be. + */ + if (this->_sourceDrain) + { + *this->_sourceDrain = line; + Q_EMIT pendingSource(); + return; + } + bool incomplete = false; Base::PyGILStateLocker lock; PyObject* default_stdout = PySys_GetObject("stdout"); @@ -730,11 +730,11 @@ void PythonConsole::runSource(const QString& line) d->interactive = true; try { - d->history.markScratch(); //< mark current history position ... + d->history.markScratch(); //< mark current history position ... // launch the command now incomplete = d->interpreter->push(line.toUtf8()); - if (!incomplete) - { d->history.doScratch(); } //< ... and scratch history entries that might have been added by executing the line. + if (!incomplete) + { d->history.doScratch(); } //< ... and scratch history entries that might have been added by executing the line. setFocus(); // if focus was lost } catch (const Base::SystemExitException&) { @@ -845,21 +845,21 @@ void PythonConsole::changeEvent(QEvent *e) TextEdit::changeEvent(e); } -void PythonConsole::mouseReleaseEvent( QMouseEvent *e ) -{ - TextEdit::mouseReleaseEvent( e ); - if (e->button() == Qt::LeftButton) - { - QTextCursor cursor = this->textCursor(); - if (cursor.hasSelection() == false - && cursor < this->inputBegin()) - { - cursor.movePosition( QTextCursor::End ); - this->setTextCursor( cursor ); - } - } -} - +void PythonConsole::mouseReleaseEvent( QMouseEvent *e ) +{ + TextEdit::mouseReleaseEvent( e ); + if (e->button() == Qt::LeftButton) + { + QTextCursor cursor = this->textCursor(); + if (cursor.hasSelection() == false + && cursor < this->inputBegin()) + { + cursor.movePosition( QTextCursor::End ); + this->setTextCursor( cursor ); + } + } +} + /** * Drops the event \a e and writes the right Python command. */ @@ -958,17 +958,17 @@ void PythonConsole::insertFromMimeData (const QMimeData * source) } } -QTextCursor PythonConsole::inputBegin( void ) const -{ - // construct cursor at begin of input line ... - QTextCursor inputLineBegin( this->textCursor() ); - inputLineBegin.movePosition( QTextCursor::End ); - inputLineBegin.movePosition( QTextCursor::StartOfLine ); - // ... and move cursor right beyond the prompt. - inputLineBegin.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptLength( inputLineBegin.block().text() ) ); - return inputLineBegin; -} - +QTextCursor PythonConsole::inputBegin( void ) const +{ + // construct cursor at begin of input line ... + QTextCursor inputLineBegin( this->textCursor() ); + inputLineBegin.movePosition( QTextCursor::End ); + inputLineBegin.movePosition( QTextCursor::StartOfLine ); + // ... and move cursor right beyond the prompt. + inputLineBegin.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, promptLength( inputLineBegin.block().text() ) ); + return inputLineBegin; +} + QMimeData * PythonConsole::createMimeDataFromSelection () const { QMimeData* mime = new QMimeData(); @@ -990,7 +990,7 @@ QMimeData * PythonConsole::createMimeDataFromSelection () const int pos = b.position(); if ( pos >= s && pos <= e ) { if (b.userState() > -1 && b.userState() < pythonSyntax->maximumUserState()) { - lines << stripPromptFrom( b.text() ); + lines << stripPromptFrom( b.text() ); } } } @@ -1059,7 +1059,7 @@ void PythonConsole::runSourceFromMimeData(const QString& source) QString select = cursor.selectedText(); cursor.removeSelectedText(); last = last + select; - line = stripPromptFrom( cursor.block().text() ); + line = stripPromptFrom( cursor.block().text() ); } // put statement to the history @@ -1111,10 +1111,10 @@ void PythonConsole::runSourceFromMimeData(const QString& source) void PythonConsole::overrideCursor(const QString& txt) { // Go to the last line and the fourth position, right after the prompt - QTextCursor cursor = this->inputBegin(); - int blockLength = this->textCursor().block().text().length(); - - cursor.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, blockLength ); //<< select text to override + QTextCursor cursor = this->inputBegin(); + int blockLength = this->textCursor().block().text().length(); + + cursor.movePosition( QTextCursor::Right, QTextCursor::KeepAnchor, blockLength ); //<< select text to override cursor.removeSelectedText(); cursor.insertText(txt); // move cursor to the end @@ -1126,7 +1126,7 @@ void PythonConsole::contextMenuEvent ( QContextMenuEvent * e ) { QMenu menu(this); QAction *a; - bool mayPasteHere = cursorBeyond( this->textCursor(), this->inputBegin() ); + bool mayPasteHere = cursorBeyond( this->textCursor(), this->inputBegin() ); a = menu.addAction(tr("&Copy"), this, SLOT(copy()), Qt::CTRL+Qt::Key_C); a->setEnabled(textCursor().hasSelection()); @@ -1144,7 +1144,7 @@ void PythonConsole::contextMenuEvent ( QContextMenuEvent * e ) a = menu.addAction(tr("&Paste"), this, SLOT(paste()), Qt::CTRL+Qt::Key_V); const QMimeData *md = QApplication::clipboard()->mimeData(); - a->setEnabled( mayPasteHere && md && canInsertFromMimeData(md)); + a->setEnabled( mayPasteHere && md && canInsertFromMimeData(md)); a = menu.addAction(tr("Select All"), this, SLOT(selectAll()), Qt::CTRL+Qt::Key_A); a->setEnabled(!document()->isEmpty()); @@ -1226,20 +1226,22 @@ void PythonConsole::onCopyCommand() d->type = PythonConsoleP::Normal; } -QString PythonConsole::readline( void ) -{ - QEventLoop loop; - QString inputBuffer; - - printPrompt( PythonConsole::Special ); - this->_sourceDrain = &inputBuffer; //< enable source drain ... - // ... and wait until we get notified about pendingSource - QObject::connect( this, SIGNAL(pendingSource()), &loop, SLOT(quit()) ); - loop.exec(); - this->_sourceDrain = NULL; //< disable source drain - return inputBuffer.append(QChar::fromAscii('\n')); //< pass a newline here, since the readline-caller may need it! -} - +QString PythonConsole::readline( void ) +{ + QEventLoop loop; + QString inputBuffer; + + printPrompt( PythonConsole::Special ); + this->_sourceDrain = &inputBuffer; //< enable source drain ... + // ... and wait until we get notified about pendingSource + QObject::connect( this, SIGNAL(pendingSource()), &loop, SLOT(quit()) ); + // application is about to quit + if (loop.exec() != 0) + { PyErr_SetInterrupt(); } //< send SIGINT to python + this->_sourceDrain = NULL; //< disable source drain + return inputBuffer.append(QChar::fromAscii('\n')); //< pass a newline here, since the readline-caller may need it! +} + // --------------------------------------------------------------------- PythonConsoleHighlighter::PythonConsoleHighlighter(QObject* parent) @@ -1290,7 +1292,7 @@ void PythonConsoleHighlighter::colorChanged(const QString& type, const QColor& c // --------------------------------------------------------------------- ConsoleHistory::ConsoleHistory() -: _scratchBegin(0) +: _scratchBegin(0) { _it = _history.end(); } @@ -1391,28 +1393,28 @@ void ConsoleHistory::restart( void ) _it = _history.end(); } -/** - * markScratch stores the current end index of the history list. - * Note: with simply remembering a start index, it does not work to nest scratch regions. - * However, just replace the index keeping by a stack - in case this is be a concern. - */ -void ConsoleHistory::markScratch( void ) -{ - _scratchBegin = _history.length(); -} - -/** - * doScratch removes the tail of the history list, starting from the index marked lately. - */ -void ConsoleHistory::doScratch( void ) -{ - if (_scratchBegin < _history.length()) - { - _history.erase( _history.begin() + _scratchBegin, _history.end() ); - this->restart(); - } -} - +/** + * markScratch stores the current end index of the history list. + * Note: with simply remembering a start index, it does not work to nest scratch regions. + * However, just replace the index keeping by a stack - in case this is be a concern. + */ +void ConsoleHistory::markScratch( void ) +{ + _scratchBegin = _history.length(); +} + +/** + * doScratch removes the tail of the history list, starting from the index marked lately. + */ +void ConsoleHistory::doScratch( void ) +{ + if (_scratchBegin < _history.length()) + { + _history.erase( _history.begin() + _scratchBegin, _history.end() ); + this->restart(); + } +} + // ----------------------------------------------------- /* TRANSLATOR Gui::PythonInputField */ diff --git a/src/Mod/Part/Gui/SoBrepShape.cpp b/src/Mod/Part/Gui/SoBrepShape.cpp index 0f8dacbab..39658d073 100644 --- a/src/Mod/Part/Gui/SoBrepShape.cpp +++ b/src/Mod/Part/Gui/SoBrepShape.cpp @@ -35,6 +35,7 @@ # include # include # include +# include # include # include # include @@ -154,6 +155,9 @@ void SoBrepFaceSet::GLRender(SoGLRenderAction *action) renderSelection(action); if (this->highlightIndex.getValue() >= 0) renderHighlight(action); + // When setting transparency shouldGLRender() handles the rendering and returns false. + // Therefore generatePrimitives() needs to be re-implemented to handle the materials + // correctly. if (!this->shouldGLRender(action)) return; @@ -210,6 +214,276 @@ void SoBrepFaceSet::GLRenderBelowPath(SoGLRenderAction * action) inherited::GLRenderBelowPath(action); } + // this macro actually makes the code below more readable :-) +#define DO_VERTEX(idx) \ + if (mbind == PER_VERTEX) { \ + pointDetail.setMaterialIndex(matnr); \ + vertex.setMaterialIndex(matnr++); \ + } \ + else if (mbind == PER_VERTEX_INDEXED) { \ + pointDetail.setMaterialIndex(*mindices); \ + vertex.setMaterialIndex(*mindices++); \ + } \ + if (nbind == PER_VERTEX) { \ + pointDetail.setNormalIndex(normnr); \ + currnormal = &normals[normnr++]; \ + vertex.setNormal(*currnormal); \ + } \ + else if (nbind == PER_VERTEX_INDEXED) { \ + pointDetail.setNormalIndex(*nindices); \ + currnormal = &normals[*nindices++]; \ + vertex.setNormal(*currnormal); \ + } \ + if (tb.isFunction()) { \ + vertex.setTextureCoords(tb.get(coords->get3(idx), *currnormal)); \ + if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++); \ + } \ + else if (tbind != NONE) { \ + pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx); \ + vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++)); \ + } \ + vertex.setPoint(coords->get3(idx)); \ + pointDetail.setCoordinateIndex(idx); \ + this->shapeVertex(&vertex); + +void SoBrepFaceSet::generatePrimitives(SoAction * action) +{ + //TODO +#if 0 + inherited::generatePrimitives(action); +#else + //This is highly experimental!!! + + if (this->coordIndex.getNum() < 3) return; + + SoState * state = action->getState(); + + if (this->vertexProperty.getValue()) { + state->push(); + this->vertexProperty.getValue()->doAction(action); + } + + Binding mbind = this->findMaterialBinding(state); + Binding nbind = this->findNormalBinding(state); + + const SoCoordinateElement * coords; + const SbVec3f * normals; + const int32_t * cindices; + int numindices; + const int32_t * nindices; + const int32_t * tindices; + const int32_t * mindices; + SbBool doTextures; + SbBool sendNormals; + SbBool normalCacheUsed; + + sendNormals = TRUE; // always generate normals + + this->getVertexData(state, coords, normals, cindices, + nindices, tindices, mindices, numindices, + sendNormals, normalCacheUsed); + + SoTextureCoordinateBundle tb(action, FALSE, FALSE); + doTextures = tb.needCoordinates(); + + if (!sendNormals) nbind = OVERALL; + else if (normalCacheUsed && nbind == PER_VERTEX) { + nbind = PER_VERTEX_INDEXED; + } + else if (normalCacheUsed && nbind == PER_FACE_INDEXED) { + nbind = PER_FACE; + } + + if (this->getNodeType() == SoNode::VRML1) { + // For VRML1, PER_VERTEX means per vertex in shape, not PER_VERTEX + // on the state. + if (mbind == PER_VERTEX) { + mbind = PER_VERTEX_INDEXED; + mindices = cindices; + } + if (nbind == PER_VERTEX) { + nbind = PER_VERTEX_INDEXED; + nindices = cindices; + } + } + + Binding tbind = NONE; + if (doTextures) { + if (tb.isFunction() && !tb.needIndices()) { + tbind = NONE; + tindices = NULL; + } + // FIXME: just call inherited::areTexCoordsIndexed() instead of + // the if-check? 20020110 mortene. + else if (SoTextureCoordinateBindingElement::get(state) == + SoTextureCoordinateBindingElement::PER_VERTEX) { + tbind = PER_VERTEX; + tindices = NULL; + } + else { + tbind = PER_VERTEX_INDEXED; + if (tindices == NULL) tindices = cindices; + } + } + + if (nbind == PER_VERTEX_INDEXED && nindices == NULL) { + nindices = cindices; + } + if (mbind == PER_VERTEX_INDEXED && mindices == NULL) { + mindices = cindices; + } + + int texidx = 0; + TriangleShape mode = POLYGON; + TriangleShape newmode; + const int32_t *viptr = cindices; + const int32_t *viendptr = viptr + numindices; + const int32_t *piptr = this->partIndex.getValues(0); + int num_partindices = this->partIndex.getNum(); + const int32_t *piendptr = piptr + num_partindices; + int32_t v1, v2, v3, v4, v5 = 0, pi; // v5 init unnecessary, but kills a compiler warning. + + SoPrimitiveVertex vertex; + SoPointDetail pointDetail; + SoFaceDetail faceDetail; + + vertex.setDetail(&pointDetail); + + SbVec3f dummynormal(0,0,1); + const SbVec3f *currnormal = &dummynormal; + if (normals) currnormal = normals; + vertex.setNormal(*currnormal); + + int matnr = 0; + int normnr = 0; + int trinr = 0; + pi = piptr < piendptr ? *piptr++ : -1; + while (pi == 0) { + // It may happen that a part has no triangles + pi = piptr < piendptr ? *piptr++ : -1; + if (mbind == PER_PART) + matnr++; + else if (mbind == PER_PART_INDEXED) + mindices++; + } + + while (viptr + 2 < viendptr) { + v1 = *viptr++; + v2 = *viptr++; + v3 = *viptr++; + if (v1 < 0 || v2 < 0 || v3 < 0) { + break; + } + v4 = viptr < viendptr ? *viptr++ : -1; + if (v4 < 0) newmode = TRIANGLES; + else { + v5 = viptr < viendptr ? *viptr++ : -1; + if (v5 < 0) newmode = QUADS; + else newmode = POLYGON; + } + if (newmode != mode) { + if (mode != POLYGON) this->endShape(); + mode = newmode; + this->beginShape(action, mode, &faceDetail); + } + else if (mode == POLYGON) this->beginShape(action, POLYGON, &faceDetail); + + // vertex 1 can't use DO_VERTEX + if (mbind == PER_PART) { + if (trinr == 0) { + pointDetail.setMaterialIndex(matnr); + vertex.setMaterialIndex(matnr++); + } + } + else if (mbind == PER_PART_INDEXED) { + if (trinr == 0) { + pointDetail.setMaterialIndex(*mindices); + vertex.setMaterialIndex(*mindices++); + } + } + else if (mbind == PER_VERTEX || mbind == PER_FACE) { + pointDetail.setMaterialIndex(matnr); + vertex.setMaterialIndex(matnr++); + } + else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) { + pointDetail.setMaterialIndex(*mindices); + vertex.setMaterialIndex(*mindices++); + } + if (nbind == PER_VERTEX || nbind == PER_FACE) { + pointDetail.setNormalIndex(normnr); + currnormal = &normals[normnr++]; + vertex.setNormal(*currnormal); + } + else if (nbind == PER_FACE_INDEXED || nbind == PER_VERTEX_INDEXED) { + pointDetail.setNormalIndex(*nindices); + currnormal = &normals[*nindices++]; + vertex.setNormal(*currnormal); + } + + if (tb.isFunction()) { + vertex.setTextureCoords(tb.get(coords->get3(v1), *currnormal)); + if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++); + } + else if (tbind != NONE) { + pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx); + vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++)); + } + pointDetail.setCoordinateIndex(v1); + vertex.setPoint(coords->get3(v1)); + this->shapeVertex(&vertex); + + DO_VERTEX(v2); + DO_VERTEX(v3); + + if (mode != TRIANGLES) { + DO_VERTEX(v4); + if (mode == POLYGON) { + DO_VERTEX(v5); + v1 = viptr < viendptr ? *viptr++ : -1; + while (v1 >= 0) { + DO_VERTEX(v1); + v1 = viptr < viendptr ? *viptr++ : -1; + } + this->endShape(); + } + } + faceDetail.incFaceIndex(); + if (mbind == PER_VERTEX_INDEXED) { + mindices++; + } + if (nbind == PER_VERTEX_INDEXED) { + nindices++; + } + if (tindices) tindices++; + + trinr++; + if (pi == trinr) { + pi = piptr < piendptr ? *piptr++ : -1; + while (pi == 0) { + // It may happen that a part has no triangles + pi = piptr < piendptr ? *piptr++ : -1; + if (mbind == PER_PART) + matnr++; + else if (mbind == PER_PART_INDEXED) + mindices++; + } + trinr = 0; + } + } + if (mode != POLYGON) this->endShape(); + + if (normalCacheUsed) { + this->readUnlockNormalCache(); + } + + if (this->vertexProperty.getValue()) { + state->pop(); + } +#endif +} + +#undef DO_VERTEX + void SoBrepFaceSet::renderHighlight(SoGLRenderAction *action) { SoState * state = action->getState(); diff --git a/src/Mod/Part/Gui/SoBrepShape.h b/src/Mod/Part/Gui/SoBrepShape.h index 273bb370c..4be3b7e8e 100644 --- a/src/Mod/Part/Gui/SoBrepShape.h +++ b/src/Mod/Part/Gui/SoBrepShape.h @@ -63,6 +63,7 @@ protected: const SoPrimitiveVertex * v2, const SoPrimitiveVertex * v3, SoPickedPoint * pp); + virtual void generatePrimitives(SoAction * action); private: enum Binding { diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index b066476eb..b9ae984c2 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -281,6 +281,29 @@ void ViewProviderPartExt::onChanged(const App::Property* prop) ViewProviderGeometryObject::onChanged(prop); DiffuseColor.setValue(ShapeColor.getValue()); } + else if (prop == &Transparency) { + const App::Material& Mat = ShapeMaterial.getValue(); + long value = (long)(100*Mat.transparency); + if (value != Transparency.getValue()) { + float trans = Transparency.getValue()/100.0f; + if (pcShapeBind->value.getValue() == SoMaterialBinding::PER_PART) { + int cnt = pcShapeMaterial->diffuseColor.getNum(); + pcShapeMaterial->transparency.setNum(cnt); + float *t = pcShapeMaterial->transparency.startEditing(); + for (int i=0; itransparency.finishEditing(); + } + else { + pcShapeMaterial->transparency = trans; + } + + App::PropertyContainer* parent = ShapeMaterial.getContainer(); + ShapeMaterial.setContainer(0); + ShapeMaterial.setTransparency(trans); + ShapeMaterial.setContainer(parent); + } + } else if (prop == &Lighting) { if (Lighting.getValue() == 0) pShapeHints->vertexOrdering = SoShapeHints::UNKNOWN_ORDERING; diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Chamfer.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Chamfer.svg index 305c7fea0..1019cd0fe 100644 --- a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Chamfer.svg +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Chamfer.svg @@ -15,82 +15,11 @@ id="svg3364" sodipodi:version="0.32" inkscape:version="0.48.3.1 r9886" - sodipodi:docname="Part_Chamfer.svg" + sodipodi:docname="PartDesign_Chamfer.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.1"> - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + image/svg+xml + @@ -147,40 +171,27 @@ id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer"> - - - - + id="g3780" + transform="matrix(0.82780005,0,0,0.83717425,-0.2499405,9.0601524)"> + sodipodi:nodetypes="cccccccc" /> + + transform="matrix(1.2080212,0,0,1.1944945,0.30193342,-10.822302)" + sodipodi:nodetypes="ccccc" /> diff --git a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Fillet.svg b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Fillet.svg index 21cebca06..4a63ca37f 100644 --- a/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Fillet.svg +++ b/src/Mod/PartDesign/Gui/Resources/icons/PartDesign_Fillet.svg @@ -14,12 +14,23 @@ height="64px" id="svg3364" sodipodi:version="0.32" - inkscape:version="0.48.2 r9819" - sodipodi:docname="Part_Fillet_mod.svg" + inkscape:version="0.48.3.1 r9886" + sodipodi:docname="PartDesign_Fillet.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.1"> + + + + + style="stop-color:#f82b39;stop-opacity:1;" /> + style="stop-color:#520001;stop-opacity:1;" /> @@ -71,39 +82,6 @@ inkscape:vp_z="116.36364 : 23.818182 : 1" inkscape:persp3d-origin="32 : 21.333333 : 1" id="perspective3372" /> - - - + + inkscape:window-maximized="0" /> @@ -183,40 +171,25 @@ inkscape:label="Layer 1" inkscape:groupmode="layer"> + id="g3780" + transform="matrix(0.82780005,0,0,0.83717425,-0.2499405,9.0601524)"> + - - - -