Merge branch 'master' of git://free-cad.git.sourceforge.net/gitroot/free-cad/free-cad
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#include "PyTools.h"
|
||||
#include "Exception.h"
|
||||
#include "PyObjectBase.h"
|
||||
#include <CXX/Extensions.hxx>
|
||||
|
||||
|
||||
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<PythonStdOutput>
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -166,6 +166,9 @@ QStringList BitmapFactoryInst::findIconFiles() const
|
||||
files << it->absoluteFilePath();
|
||||
}
|
||||
|
||||
#if QT_VERSION >= 0x040500
|
||||
files.removeDuplicates();
|
||||
#endif
|
||||
return files;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<const char*> &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 */
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
# include <float.h>
|
||||
# include <algorithm>
|
||||
# include <Inventor/SoPickedPoint.h>
|
||||
# include <Inventor/SoPrimitiveVertex.h>
|
||||
# include <Inventor/actions/SoCallbackAction.h>
|
||||
# include <Inventor/actions/SoGetBoundingBoxAction.h>
|
||||
# include <Inventor/actions/SoGetPrimitiveCountAction.h>
|
||||
@@ -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();
|
||||
|
||||
@@ -63,6 +63,7 @@ protected:
|
||||
const SoPrimitiveVertex * v2,
|
||||
const SoPrimitiveVertex * v3,
|
||||
SoPickedPoint * pp);
|
||||
virtual void generatePrimitives(SoAction * action);
|
||||
|
||||
private:
|
||||
enum Binding {
|
||||
|
||||
@@ -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; i<cnt; i++)
|
||||
t[i] = trans;
|
||||
pcShapeMaterial->transparency.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;
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 6.4 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 6.5 KiB |
Reference in New Issue
Block a user