Makro Python-Assistentenfenster
| Beschreibung |
|---|
| Dieses Makro bietet einen Arbeitsbereich zum Ausschneiden/Kopieren/Einfügen von Python-Code. Es ist segmentiert, sodass verschiedene Abschnitte ausgewählt werden können, und bleibt zwischen FreeCAD-Sitzungen bestehen. Versionsmakro : 1.0 Datum der letzten Änderung : 2015-01-21 FreeCAD version : Alle Herunterladen : Werkzeugleisten-Symbol Autor: Piffpoof |
| Autor |
| Piffpoof |
| Herunterladen |
| Werkzeugleisten-Symbol |
| Links |
| Makros Rezepte Wie man Makros installiert Symbolleisten anpassen |
| Macro-Version |
| 1.0 |
| Datum der letzten Änderung |
| 2015-01-21 |
| FreeCAD-Version(s) |
| Alle |
| Standardverknüpfung |
| None |
| Siehe auch |
| None |
Einer der leistungsstarken Aspekte von Python ist die Python-Konsole, die sowohl als Ausgabegerät als auch als dynamischer Interpreter für Quellcode dient. Das Python-Assistentenfenster (im Folgenden als „PAF” bezeichnet) bietet zusätzliche Funktionen für die Python-Konsole.
Temporary code for external macro link. Do not use this code. This code is used exclusively by Addon Manager. Link for optional manual installation: Macro
# This code is copied instead of the original macro code
# to guide the user to the online download page.
# Use it if the code of the macro is larger than 64 KB and cannot be included in the wiki
# or if the RAW code URL is somewhere else in the wiki.
from PySide import QtGui, QtCore
diag = QtGui.QMessageBox(QtGui.QMessageBox.Information,
"Information",
"This macro must be downloaded from this link\n"
"\n"
"http://pastebin.com/raw/2m0u94Z1" + "\n"
"\n"
"Quit this window to access the download page")
diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
import webbrowser
webbrowser.open("http://pastebin.com/raw/2m0u94Z1")
Beschreibung
Als moderne Entwicklungsumgebung hat Python gegenüber älteren Sprachen und deren Entwicklungsumgebungen viele Vorteile. Ein großer Vorteil ist die Python-Konsole, in der Code interaktiv eingegeben und die Ergebnisse empfangen werden können. (REPL). Diese Ergebnisse können dann kopiert und entweder zum Erstellen von Python-Quellcode (in einem Quellcode-Editor) verwendet oder in geänderter Form wieder in die Python-Konsole eingefügt werden, um weitere Ausgaben zu erhalten. Dies ist eine sehr leistungsfähige Methode zur Entwicklung von Code.
So leistungsstark die Python-Konsole auch sein mag, sie weist zwei offensichtliche Mängel auf:
- Die Konsole hat eine begrenzte Größe, sodass die Ergebnisse der Arbeit von vor 20 Minuten möglicherweise weit vom Bildschirm entfernt sind. Sie sind zwar nicht verloren gegangen, aber es ist umständlich, sie wiederzufinden.
- Die Konsole wird jedes Mal gelöscht, wenn man die FreeCAD-Sitzung beendet. Wenn man FreeCAD das nächste Mal startet, ist die Konsole leer (abgesehen von der Python-Startmeldung)
Das PAW bietet Folgendes:
- Sie bleibt zwischen den FreeCAD-Sitzungen bestehen, es "verschwindet" nichts aus ihr, es sei denn, der Benutzer entfernt es.
- Sie verfügt über ein Kontextmenü, das Folgendes ermöglicht:
- die Standard-Bearbeitungsoperanden: Kopieren & Einfügen & Alles auswählen
- Kopieren einer Auswahl in die Python-Konsole
- Kopieren des gesamten Inhalts der PAW in die Python-Konsole
- Anhängen des Inhalts der Python-Konsole an die PAW
- Einfügen von Textmarkierungen, die die Verwaltung des Textes erleichtern
- Auswahl zwischen zwei aufeinanderfolgenden Markierungen
- Entfernen des Präfixes ">>> ", das die Python-Konsole zur Kennzeichnung der Ausgabe verwendet
- Reduzieren mehrerer Leerzeilen auf einzelne Leerzeilen
- Personalisieren der Arbeitsumgebung durch Verwalten der PAW (sowie des FreeCAD-Hauptfensters) über eine schiebereglerbasierte GUI
Installation
Der gesamte Code für pythonAssistantWindow.FCMacro befindet sich in einem Makro. Die Installation besteht also darin, den Code in das entsprechende Makroverzeichnis zu kopieren und pythonAssistantWindow über das Makro-Menü, die Python-Konsole oder eine Symbolleisten-Schaltfläche (die bevorzugte Methode) aufzurufen.
- Siehe How to install macros/de über Informationen zur Installation dieses Makro-Codes
- Siehe Customize Toolbars/de über Informationen zur Installation als Schaltfläche in einer Symbolleiste
Hinweis: Eine globale Variable innerhalb von FreeCAD wird verwendet, um den persistenten Speicher zu koordinieren.
Hinweis: Eine Textdatei im Verzeichnis „UserAppData” wird verwendet, um den Textinhalt des PAF zwischen FreeCAD-Sitzungen zu speichern.
Anwendung
Das PAF lässt sich am besten als Schaltfläche in einer Symbolleiste verwenden. Es kann über das Makro-Menü oder durch Einfügen des Codes in die Python-Konsole ausgeführt werden, aber die beiden letztgenannten Optionen beeinträchtigen die Benutzerfreundlichkeit erheblich.
Wenn FreeCAD gestartet wird, gibt es keine Anzeichen für das PAW, außer einer Schaltfläche in der Symbolleiste. Durch Klicken auf die Schaltfläche wird Folgendes ausgelöst:
- Das PAW wird in der unteren rechten Ecke geöffnet.
- Die Standardeinstellungen sehen vor, dass etwa 1/3 der Bildschirmbreite für das PAW reserviert ist, während der Rest vom FreeCAD-Hauptfenster genutzt wird. Die Höhe des PAW beträgt etwa 1/3 der Fensterhöhe.
- Der Inhalt des PAW bei seiner letzten Ausführung wird im Fenster angezeigt – es sollte kein Unterschied zur letzten Verwendung bestehen.
- Wenn das PAW zuvor noch nicht ausgeführt wurde, ist der Inhalt leer.
- Wenn das PAW bereits geöffnet, aber durch andere Fenster verdeckt ist, wird es nach oben verschoben, sodass es sichtbar wird.
- Durch Schließen des PAW wird der Inhalt in eine Datei geschrieben und das Fenster geschlossen – es erscheint kein Dialogfeld, in dem man gefragt wird, ob man speichern möchte oder nicht.
- Es erscheint jedoch ein Dialogfeld, in dem man gefragt wird, ob man speichern möchte, wenn FreeCAD mit ungespeicherten Änderungen im PAW beendet wird (Menü -> FreeCAD beenden).
Die meisten Funktionen für PAW werden über das Kontextmenü bereitgestellt. Die Optionen sind:
- Kopieren
– bietet die Standardfunktion "Kopieren" - Auswahl in die Konsole kopieren
– die aktuelle Auswahl wird an das Ende der Python-Konsole kopiert - Inhalt in die Konsole kopieren
– der gesamte Inhalt von PAW wird an das Ende der Python-Konsole kopiert - Einfügen
– bietet die Standardfunktion „Einfügen“ - Inhalt der Python-Konsole an PAW anhängen
– die Kopien der Python-Konsole werden an das Ende der PAW angehängt – man beachte, dass der Inhalt der Python-Konsole eine Mischung aus Python-Code, Ausgaben von Python-Code, Fehlermeldungstexten und Ausgaben aus beliebigen Teilen von FreeCAD sein kann - Zwischen Markierungen wählen
– Markierungen werden verwendet, um den Text der PAW in Abschnitte zu unterteilen. Sobald der Inhalt in Abschnitte unterteilt ist, kann ein Abschnitt einzeln ausgewählt und bearbeitet werden (z. B. Kopieren, In die Python-Konsole kopieren, Löschen). Der Zweck von Markierungen besteht darin, separate und unabhängige Sequenzen von Python-Anweisungen in der PAW zu ermöglichen, die dann einzeln verwaltet und bearbeitet werden können. - Alle auswählen
– bietet die Standardfunktion "Alle auswählen". - Clearbr
– bietet die Standardfunktion "Löschen", mit der der gesamte Text im PAW gelöscht wird - Markierung einfügen
– fügt eine Textmarkierung an der aktuellen Cursorposition ein - ">>> " entfernen
– nachdem die Python-Konsolenausgabe in den PAW kopiert wurde, werden alle Zeilen, die von ausgeführten Python-Befehlen ausgegeben wurden, mit ">>> " vorangestellt. Diese Option entfernt diese Präfixe, sodass die Ausgabe als kontextfreie Daten verwendet werden kann. - Mehrere Leerzeilen auf einzelne Leerzeilen reduzieren
– komprimiert den Text, indem mehrere Leerzeilen entfernt werden. - GUI-Einstellungen ändern
– öffnet ein modales Fenster mit drei Steuerelementen:
- Ein Schieberegler zum Einstellen des Prozentsatzes der Bildschirmbreite, der für das PAW reserviert ist (man beachte, dass es eine bestimmte Breite gibt, unter die das FreeCAD-Hauptfenster nicht gehen kann).
- Ein Schieberegler zum Einstellen des Prozentsatzes der Bildschirmhöhe, der für das PAW reserviert ist.
- Ein Paar Optionsfelder, um anzugeben, ob das PAW oben oder unten auf der linken Seite des Bildschirms platziert werden soll.
- Als Datei speichern
– Der Inhalt des PAW-Fensters wird in eine vom Benutzer ausgewählte Datei geschrieben – Der Inhalt des PAW wird nicht verändert - Fenster schließen
– Das PAW-Fenster wird geschlossen und der Inhalt in die permanente Speicherdatei geschrieben
Hinweis: Es erscheint kein Dialogfeld, in dem man zum Speichern aufgefordert wird, dies geschieht automatisch
Benutzeroberfläche
Die Benutzeroberfläche ist ein einfaches Textbearbeitungsfenster mit einer Schaltfläche zum Starten von PAF und einem Kontextmenü mit Optionen für die Bearbeitung des Textes im Textbearbeitungsfenster. Die Optionen werden im Abschnitt Verwendung beschrieben.
Beispiele
Ein erstes Beispiel
Im Januar benötigt Ihr Kollege Hilfe beim Python-Code, um eine Datei zu aktualisieren. Sie schreiben und debuggen den Code auf Ihrem Computer und senden ihm den Quellcode. Sie haben drei verschiedene Möglichkeiten gefunden, um die Aufgabe zu lösen, und sind sich nicht sicher, welche davon die beste ist. Sie kopieren alle drei fertigen Versionen auf den PAF und trennen sie durch Markierungen.
Zu Beginn des Monats Mai arbeiten Sie fröhlich mit FreeCAD an Ihrem Flaschenprojekt. Es gibt einige Probleme, den genauen Python-Code zu finden, um das Gewünschte zu generieren, also modellieren Sie dies grafisch und der entsprechende Python-Code wird in der Python-Konsole generiert. Mit PAF kopieren Sie den Inhalt der Python-Konsole in PAF. Sie formen ihn, indem Sie ihn zurückverschieben und ausführen, die Ergebnisse kopieren, sie in PAF modifizieren und zurückkopieren, bis Sie zufrieden sind.
Am nächsten Montag kommt Ihr Chef zu Ihnen und sagt, dass im Werk dringend ein CAD-Operator benötigt wird, da es Probleme mit der Faltsequenz für den neuen Verpackungsstrom gibt. Sie fliegen noch am selben Tag dorthin und bleiben zwei Wochen lang vor Ort. Sie erledigen Ihren Auftrag und kehren dann an Ihren normalen Arbeitsplatz zurück.
Als Sie zurückkommen, ist offensichtlich, dass andere Ihren Bereich als Mittagspausenraum genutzt haben, sodass Sie ein wenig aufräumen müssen. Wenn Sie FreeCAD starten und auf die Schaltfläche PAF in der Symbolleiste klicken, finden Sie Ihre Arbeit von gestern vor, als wäre sie erst gestern entstanden. Sie erkennen, dass die Lösung für Ihr Flaschendesign in dem Dateicode liegt, den Sie im Januar geschrieben haben, zusammen mit dem, was Sie zwei Wochen zuvor hinterlassen haben. Schnell können Sie die Code-Segmente auswählen und in die Python-Konsole kopieren, um sie auszuführen und zu optimieren.
Sobald der Code stabil ist, können man ihn entweder als Python-Datei oder als FreeCAD-Makrodatei speichern.
Ein weiteres Beispiel
Sie versuchen herauszufinden, was mit den Rotationswerten verschiedener Objekte in einer Baugruppe nicht stimmt. Von den 27 Objekten können Sie kein Muster erkennen, welche Objekte betroffen sind. Also schreiben Sie ein paar Zeilen Python-Code, um die fehlerhaften Objekte zu isolieren, und fügen diesen Code in die PAF ein. Dann schreiben Sie ein paar Zeilen Python-Code, um die Label- und Rotationswerte zu erhalten, und fügen diesen Code ebenfalls in die PAF ein. Kopieren Sie den Code, um alle Objekte aufzulisten, die Sie sehen möchten, und wiederholen Sie dies für jedes Objekt – alles im PAF. Die Python-Konsole enthält alle diese Ergebnisse (einschließlich Tippfehlern und Fehlermeldungen), aber sie ist längst aus dem sichtbaren Bereich des Fensters herausgescrollt. Jetzt haben Sie also einen übersichtlichen Satz von Python-Zeilen, den Sie aus dem PAF kopieren, in die Python-Konsole einfügen und schon haben Sie die genaue Liste der Objekte, die debuggt werden müssen – zusammen mit ihren spezifischen Werten. Bei Bedarf können Sie die Ergebnisse aus der Python-Konsole dann wieder in den PAF einfügen – setzen Sie ihnen das Python-Kommentarzeichen („#“) vor, wenn Sie sie im Python-Code speichern und ausführbar halten möchten. Schließlich können Sie diese Zusammenstellung aus dem PAF in einer Datei speichern, damit sie sicher auf der Festplatte liegt. So sind Sie bereit für das nächste Mal, wenn Sie die Logik im Code übernehmen oder anpassen müssen.
Optionen
Die einzige Option für das PAW ist die Möglichkeit, seine anfängliche Anzeigegröße und -form entsprechend der Größe und Form des FreeCAD-Hauptfensters zu ändern. Es gibt drei Konstanten im Python-Code, die die anfängliche Größe und Platzierung des PAW festlegen.
Anmerkungen
Dieser Code enthält einen sehr einfachen Konzeptnachweis für einen persistenten Speicher. Er kann für alle nützlich sein, die eine solche Kapazität benötigen.
Verweise
keine (bisher)
Skript
Macro_Python_Assistant_Window.FCMacro
#
#
# Python Assistant Window
# v 0.1 initial release
#
#
#***********************************************************************************
#
# provide a text editing window with functions to aid in coding Python within FreeCAD
#
############ To Do ############
# - contextual window doesn't fire if cursor is on last position in file
# - executing "from PySide import QtGui, QtCore" on console seems to close window
# - is it possible to copy code to console and then select and execute it?
##############################
#***********************************************************************************
# The next three variables define the width and height and vertical positioning
# of the Python Assistant Window
# 'pawWidthPercent' specifies the percentage of the screen width to be assigned to the Python Assistant Window
# 'pawHeightPercent' specifies the percentage of the screen height to be assigned to the Python Assistant Window
# 'pawAtBottomFlag' specifies if the Python Assistant Window is at the top or the bottom
# The Python Assistant Window is automatically placed at the left,
# so pawWidthPercent = 26, pawHeightPercent = 41, pawAtBottomFlag = False will cause the
# following:
# 1) the main FreeCAD window will be placed in the upper left corner of the screen,
# it's height will be 100% of the screen height,
# it's width will be 74% (=100%-26%) of the screen
# 2) the Python Assistant Window will be placed in the left side of the screen,
# it's height will be 41% of the screen height,
# it's width will be 26% of the screen
# it will be at the top (leaving empty space below it)
# The empty space (either above or below the Python Assistant Window),
# is left for the text editor (for editing the Macros) to be placed in.
#
pawWidthPercentInitial = 37.5 # percent of the screen width
pawHeightPercentInitial = 32.0 # percent of the screen height
pawAtBottomFlagInitial = True
#***********************************************************************************
# import statements
import sys, operator, os
from os.path import expanduser
from PySide import QtGui, QtCore
# UI Class definitions
class PythonAssistantWindow(QtGui.QMainWindow):
""""""
def __init__(self, pythonTextToEdit):
self.textIn = pythonTextToEdit
super(PythonAssistantWindow, self).__init__()
self.initUI(pythonTextToEdit)
def initUI(self, pythonTextToEdit):
"""Constructor"""
# set default return value and pointer to subsequent child window
self.result = userCancelled
self.childWindow = None
self.alertWindow = None
# set window dimensions for Python Advisor Window from the constants at the top of Macro file
self.pawWinWidth = pawWidthPercentInitial/100.0 * availableWidth
self.pawWinHeight = pawHeightPercentInitial/100.0 * availableHeight
self.left = screenWidth - self.pawWinWidth
if pawAtBottomFlagInitial:
self.top = screenHeight - self.pawWinHeight
else:
self.top = 0
self.editorHeight = self.pawWinHeight
# set dimensions for main FreeCAD window
self.mainWinWidth = availableWidth - (self.pawWinWidth+interWindowGap)
self.mainWinHeight = availableHeight
# define main window
FreeCADGui.getMainWindow().setGeometry(0, 0, self.mainWinWidth, self.mainWinHeight)
# now set up this window
self.setGeometry(self.left, self.top, self.pawWinWidth, self.pawWinHeight)
self.setWindowTitle("Python Assistant Window")
#
centralWidget = QtGui.QWidget(self)
layout = QtGui.QGridLayout()
centralWidget.setLayout(layout)
# set up text editing widget
self.text_editor = QtGui.QPlainTextEdit(self)
self.text_editor.move(0,0)
self.text_editor.resize(self.pawWinWidth,self.editorHeight)
self.text_editor.appendPlainText(self.textIn)
self.text_editor.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
self.text_editor.textChanged.connect(self.onTextChanged)
# set up a monospace font for the text editor to match the Python console
font = QtGui.QFont()
font.setFamily("Courier")
font.setStyleHint(QtGui.QFont.Monospace)
font.setFixedPitch(True)
font.setPointSize(12)
self.text_editor.setFont(font)
#self.text_editor.cursorPositionChanged.connect(self.onCursorPosition)
self.cursor = self.text_editor.textCursor()
# populate layout
layout.addWidget(self.text_editor,0,0)
self.setCentralWidget(centralWidget)
# set contextual menu options for text editing widget
# menu dividers
mnuDivider1 = QtGui.QAction(self)
mnuDivider1.setText(menuDividerText)
mnuDivider1.triggered.connect(self.onMenuDivider)
mnuDivider2 = QtGui.QAction(self)
mnuDivider2.setText(menuDividerText)
mnuDivider2.triggered.connect(self.onMenuDivider)
mnuDivider3 = QtGui.QAction(self)
mnuDivider3.setText(menuDividerText)
mnuDivider3.triggered.connect(self.onMenuDivider)
mnuDivider4 = QtGui.QAction(self)
mnuDivider4.setText(menuDividerText)
mnuDivider4.triggered.connect(self.onMenuDivider)
# clear text
mnuClear = QtGui.QAction(self)
mnuClear.setText("Clear")
mnuClear.triggered.connect(self.onClear)
# paste copy/paste buffer
mnuPaste = QtGui.QAction(self)
mnuPaste.setText("Paste")
mnuPaste.triggered.connect(self.onPaste)
# paste contents of console
mnuAppendFromConsole = QtGui.QAction(self)
mnuAppendFromConsole.setText("Append contents of console")
mnuAppendFromConsole.triggered.connect(self.onAppendFromConsole)
# select between markers
mnuSelectMarkers = QtGui.QAction(self)
mnuSelectMarkers.setText("Select between markers")
mnuSelectMarkers.triggered.connect(self.onSelectMarkers)
# select all
mnuSelectAll = QtGui.QAction(self)
mnuSelectAll.setText("Select all")
mnuSelectAll.triggered.connect(self.onSelectAll)
# insert marker
mnuInsertMarker = QtGui.QAction(self)
mnuInsertMarker.setText("Insert marker")
mnuInsertMarker.triggered.connect(self.onInsertMarker)
# remove console generated ">>> " character strings
mnuStripPrefix = QtGui.QAction(self)
mnuStripPrefix.setText("Remove '>>> '")
mnuStripPrefix.triggered.connect(self.onStripPrefix)
# remove blank lines
mnuReduceBlankLines = QtGui.QAction(self)
mnuReduceBlankLines.setText("Delete multiple blank lines")
mnuReduceBlankLines.triggered.connect(self.onReduceBlankLines)
# copy selection
mnuCopy = QtGui.QAction(self)
mnuCopy.setText("Copy")
mnuCopy.triggered.connect(self.onCopy)
# copy selection to console
mnuCopySelectionToConsole = QtGui.QAction(self)
mnuCopySelectionToConsole.setText("Copy selection to console")
mnuCopySelectionToConsole.triggered.connect(self.onCopySelectionToConsole)
# copy to console
mnuCopyToConsole = QtGui.QAction(self)
mnuCopyToConsole.setText("Copy contents to console")
mnuCopyToConsole.triggered.connect(self.onCopyToConsole)
# save as file
mnuSaveAsFile = QtGui.QAction(self)
mnuSaveAsFile.setText("Save contents to file")
mnuSaveAsFile.triggered.connect(self.onSaveAsFile)
# close window
mnuCloseWindow = QtGui.QAction(self)
mnuCloseWindow.setText("Close window")
mnuCloseWindow.triggered.connect(self.onCloseWindow)
# alter GUI settings
mnuSettings = QtGui.QAction(self)
mnuSettings.setText("=Alter GUI settings=")
mnuSettings.triggered.connect(self.onSettings)
# define menu and add options
self.text_editor.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
self.text_editor.addAction(mnuCopy)
self.text_editor.addAction(mnuCopySelectionToConsole)
self.text_editor.addAction(mnuCopyToConsole)
self.text_editor.addAction(mnuDivider1)
self.text_editor.addAction(mnuPaste)
self.text_editor.addAction(mnuAppendFromConsole)
self.text_editor.addAction(mnuSelectMarkers)
self.text_editor.addAction(mnuSelectAll)
self.text_editor.addAction(mnuClear)
self.text_editor.addAction(mnuDivider2)
self.text_editor.addAction(mnuInsertMarker)
self.text_editor.addAction(mnuStripPrefix)
self.text_editor.addAction(mnuReduceBlankLines)
self.text_editor.addAction(mnuDivider3)
self.text_editor.addAction(mnuSaveAsFile)
self.text_editor.addAction(mnuSettings)
self.text_editor.addAction(mnuCloseWindow)
#
self.show()
#----------------------------------------------------------------------
def onMenuDivider(self):
# just a divider in the menu so we don't do anything
pass
def onClear(self):
# clear editing field
self.text_editor.clear()
def onPaste(self):
# paste contents of system copy/paste buffer into QPlainTextEdit field
self.text_editor.paste()
def onAppendFromConsole(self):
# copy text from "Python console"
mainWindow = FreeCADGui.getMainWindow()
pcDW = mainWindow.findChild(QtGui.QDockWidget, "Python console")
pcPTE = pcDW.findChild(QtGui.QPlainTextEdit, "Python console")
consoleStr = pcPTE.document().toPlainText()
self.text_editor.appendPlainText(copyFromConsoleText)
self.text_editor.appendPlainText("")
self.text_editor.appendPlainText(consoleStr)
def onCopy(self):
# copy selected text to system copy/paste buffer
self.text_editor.copy()
def onCopySelectionToConsole(self):
# copy selected text to "Python console"
mainWindow = FreeCADGui.getMainWindow()
pcDW = mainWindow.findChild(QtGui.QDockWidget, "Python console")
pcPTE = pcDW.findChild(QtGui.QPlainTextEdit, "Python console")
#
cursor = self.text_editor.textCursor()
cursorText = self.text_editor.toPlainText()
textToCopy = cursorText[cursor.selectionStart():cursor.selectionEnd()]
if len(textToCopy)>0:
pcPTE.appendPlainText(textToCopy)
def onCopyToConsole(self):
# copy text to "Python console"
mainWindow = FreeCADGui.getMainWindow()
pcDW = mainWindow.findChild(QtGui.QDockWidget, "Python console")
pcPTE = pcDW.findChild(QtGui.QPlainTextEdit, "Python console")
pcPTE.appendPlainText(copyToConsoleText)
pcPTE.appendPlainText()
def onInsertMarker(self):
# insert marker
self.text_editor.insertPlainText(markerText)
def onStripPrefix(self):
# strip out ">>> " from text edit window
self.text_editor.selectAll()
if len(self.text_editor.toPlainText())>0:
self.text_editor.selectAll()
tmp = self.text_editor.toPlainText()
self.text_editor.clear()
self.text_editor.appendPlainText(tmp.replace(">>> ",""))
def onReduceBlankLines(self):
# reduce multiple blank lines to single blank lines
contents = self.text_editor.toPlainText()
self.text_editor.clear()
self.text_editor.appendPlainText(os.linesep.join([s for s in contents.splitlines() if s]))
def onSelectMarkers(self):
cursor = self.text_editor.textCursor()
cursorText = self.text_editor.toPlainText()
bNum = cursor.blockNumber(); cNum = cursor.columnNumber()
pos = cursor.position(); cursorTextLength = len(cursorText)
occurrences = [i for i in range(len(cursorText)) if cursorText.startswith(markerText, i)]
if len(occurrences)==0:
self.alertWindow = QtGui.QMessageBox()
self.alertWindow.setText("There are no markers...")
self.alertWindow.show()
elif len(occurrences)==1:
hdrStart = occurrences[0]
hdrEnd = hdrStart + markerTextLength
if pos<hdrStart:
selectStart = 0; selectEnd = hdrStart
self.cursor.setPosition(selectStart)
self.cursor.setPosition(selectEnd, QtGui.QTextCursor.KeepAnchor)
self.text_editor.setTextCursor(self.cursor)
if pos>hdrEnd:
selectStart = hdrEnd; selectEnd = cursorTextLength
self.cursor.setPosition(selectStart)
self.cursor.setPosition(selectEnd, QtGui.QTextCursor.KeepAnchor)
self.text_editor.setTextCursor(self.cursor)
else:
startOccurrences = list(); endOccurrences = list(occurrences)
for i in range(len(occurrences)):
startOccurrences.append(occurrences[i] + markerTextLength + 1)
startOccurrences.insert( 0, 0)
endOccurrences.insert( len(occurrences), cursorTextLength)
for i in range(len(occurrences)+1):
if startOccurrences[i]<pos<endOccurrences[i]:
if i==0:
selectStart = startOccurrences[i]
else:
selectStart = startOccurrences[i]-1
selectEnd = endOccurrences[i]
self.cursor.setPosition(selectStart)
self.cursor.setPosition(selectEnd, QtGui.QTextCursor.KeepAnchor)
self.text_editor.setTextCursor(self.cursor)
break
def onSelectAll(self):
self.text_editor.selectAll()
def onCloseWindow(self):
self.close()
def onSettings(self):
# get new width (as %), height (as %), vertical flag
self.childWindow = GetGuiConfigParams(self)
pass
def onTextChanged(self):
FreeCAD.PythonAssistantWindowStatus[1] = True
def onCursorPosition(self):
#print ("Line: {} | Column: {}".format(
# self.text_editor.textCursor().blockNumber(),
# self.text_editor.textCursor().columnNumber()))
#print self.text_editor.textCursor().position()+self.text_editor.textCursor().columnNumber()
pass
def onSaveAsFile(self):
filePath = QtGui.QFileDialog.getSaveFileName(parent=None,caption="Save contents as",dir=expanduser("~"),filter="*.txt")
file = open(filePath[0],"w")
file.write(self.text_editor.toPlainText())
file.close()
def closeEvent(self,event):
# write out contents for next session
file = open(persistenceFile,"w")
file.write(self.text_editor.toPlainText())
file.close()
# clear global flag
del FreeCAD.PythonAssistantWindowStatus
self.close()
class GetGuiConfigParams(QtGui.QMainWindow):
""""""
def __init__(self, parentWindow):
self.parentWindow = parentWindow
super(GetGuiConfigParams, self).__init__()
self.initUI(parentWindow)
def initUI(self, parentWindow):
"""Constructor"""
self.result = userCancelled
# grab geometry from our parent so we can tell if user has changed values
self.initialParentWindowX = self.parentWindow.geometry().x()
self.initialParentWindowY = self.parentWindow.geometry().y()
self.initialParentWindowH = self.parentWindow.geometry().height()
self.initialParentWindowW = self.parentWindow.geometry().width()
self.initialHeightSliderSetting = self.initialParentWindowH/float(availableHeight)*100
self.initialWidthSliderSetting = self.initialParentWindowW/float(availableWidth-interWindowGap)*100
# set some fixed GUI attributes
width = 450
height = 40
buttonWidth = 80
sliderWidth = 100
self.setWindowTitle("GUI Configuration")
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
self.resize(width, height)
self.widthSlider = self.initialWidthSliderSetting
self.heightSlider = self.initialHeightSliderSetting
#
centralWidget = QtGui.QWidget(self)
layout = QtGui.QGridLayout()
centralWidget.setLayout(layout)
verticalLine = QtGui.QFrame()
# sliders
widthSlider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
widthSlider.setFocusPolicy(QtCore.Qt.NoFocus)
widthSlider.valueChanged[int].connect(self.widthSliderChangeValue)
widthSlider.setFixedWidth(sliderWidth)
widthSlider.setValue(self.initialWidthSliderSetting)
heightSlider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
heightSlider.setFocusPolicy(QtCore.Qt.NoFocus)
heightSlider.valueChanged[int].connect(self.heightSliderChangeValue)
heightSlider.setFixedWidth(sliderWidth)
heightSlider.setValue(self.initialHeightSliderSetting)
# labels
pawWidthLbl = QtGui.QLabel("Python Assistant Window width", self)
pawHeightLbl = QtGui.QLabel("Python Assistant Window height", self)
# radio buttons - window top or bottom
self.rb1 = QtGui.QRadioButton("Window at Top",self)
self.rb1.clicked.connect(self.onRb1)
self.rb2 = QtGui.QRadioButton("Window at Bottom",self)
self.rb2.toggle() # set default value
self.rb2.clicked.connect(self.onRb2)
if self.parentWindow.geometry().y()==0:
self.rb1.toggle()
# cancel button
cancelButton = QtGui.QPushButton('Cancel', self)
cancelButton.clicked.connect(self.onCancel)
cancelButton.setFixedWidth(buttonWidth)
# OK button
okButton = QtGui.QPushButton('OK', self)
okButton.clicked.connect(self.onOk)
okButton.setFixedWidth(buttonWidth)
#
verticalLine.setFrameStyle(QtGui.QFrame.VLine)
verticalLine.setSizePolicy(QtGui.QSizePolicy.Minimum,QtGui.QSizePolicy.Expanding)
#
pawWidthLbl.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
pawHeightLbl.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
self.rb1.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
self.rb2.setSizePolicy(QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
# populate layout
layout.addWidget(widthSlider,0,0)
layout.addWidget(pawWidthLbl,0,1)
layout.addWidget(heightSlider,2,0)
layout.addWidget(pawHeightLbl,2,1)
layout.addWidget(verticalLine,0,2,3,1)
layout.addWidget(self.rb1,0,3)
layout.addWidget(self.rb2,2,3)
layout.addWidget(cancelButton,3,1,QtCore.Qt.AlignRight)
layout.addWidget(okButton,3,3)
#
self.setCentralWidget(centralWidget)
#
self.show()
def widthSliderChangeValue(self, value):
self.widthSliderValue = value
def heightSliderChangeValue(self, value):
self.heightSliderValue = value
def onRb1(self):
pass
def onRb2(self):
pass
def onCancel(self):
self.result = userCancelled
self.close()
def onOk(self):
self.result = "OK"
# the two slider values are the width and height of the Python Assistant Window
# resize main FreeCAD window
freeCadMainWidth = ((1-(self.widthSliderValue/100.0)) * availableWidth)-(3*interWindowGap)
FreeCADGui.getMainWindow().setGeometry(0, 0, freeCadMainWidth, availableHeight)
# resize the PAW window
newPawWidth = availableWidth-freeCadMainWidth
newPawHeight = (self.heightSliderValue/100.0) * availableHeight
if self.rb1.isChecked():
newPawTop = 0
else:
newPawTop = availableHeight - newPawHeight
self.parentWindow.setGeometry(freeCadMainWidth+interWindowGap, newPawTop, newPawWidth-interWindowGap, newPawHeight)
self.close()
#----------------------------------------------------------------------
# Class definitions
# Function definitions
def onFreeCADShutdown():
# this will be invoked when FreeCAD is told to shut down
#QtGui.QMessageBox.information(None,"","FreeCAD shutting down")
if FreeCAD.PythonAssistantWindowStatus[1]:
reply = QtGui.QMessageBox.question(None, "",
"The Python Assistant Window has changes, do you want to save them?",
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes:
# write out contents for next session
file = open(persistenceFile,"w")
file.write(FreeCAD.PythonAssistantWindowStatus[0].text_editor.toPlainText())
file.close()
del FreeCAD.PythonAssistantWindowStatus
# Constant definitions
userCancelled = "Cancelled"
markerText = "#=========== marker ===========\n"
markerTextLength = len(markerText)
copyFromConsoleText = "#=========== copy from console ==========="
copyToConsoleText = "#============ copy to console ============"
menuDividerText = "--------"
interWindowGap = 3 # space between 2 windows for appearance sake
persistenceFile = App.ConfigGet("UserAppData")+"PythonAssistantWindow.txt"
# code ***********************************************************************************
# put down user data saving routine for when FreeCAD exits
mw=Gui.getMainWindow()
mw.mainWindowClosed.connect(onFreeCADShutdown)
# get screen dimensions
screenWidth = QtGui.QDesktopWidget().screenGeometry().width()
screenHeight = QtGui.QDesktopWidget().screenGeometry().height()
# get dimensions for available space on screen
availableWidth = QtGui.QDesktopWidget().availableGeometry().width()
availableHeight = QtGui.QDesktopWidget().availableGeometry().height()
if not hasattr(FreeCAD,"PythonAssistantWindowStatus"):
previousContents = ""
if os.path.isfile(persistenceFile):
# read contents of last session
file = open(persistenceFile,"r")
previousContents = file.read()
file.close()
# open window with contents from last session
form = PythonAssistantWindow(previousContents)
# save pointer to window so it can be located again and Raised when it becomes obscured
FreeCAD.PythonAssistantWindowStatus = [None, False]
FreeCAD.PythonAssistantWindowStatus[0] = form
else:
# window is open so Raise it so it is visible
FreeCAD.PythonAssistantWindowStatus[0].raise_()
pass
#
#OS: Mac OS X
#Word size: 64-bit
#Version: 0.14.3703 (Git)
#Branch: releases/FreeCAD-0-14
#Hash: c6edd47334a3e6f209e493773093db2b9b4f0e40
#Python version: 2.7.5
#Qt version: 4.8.6
#Coin version: 3.1.3
#SoQt version: 1.5.0
#OCC version: 6.7.0
#
#thus ends the macro...
