diff --git a/CHANGELOG.md b/CHANGELOG.md
index 00e3a33b..617a38d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,13 @@ CHANGELOG for FlatCAM beta
=================================================
+23.04.2020
+
+- fixed the Tcl Command Help to work as expected; made the text of the commands to be colored in Red color and bold
+- added a 'Close' menu entry in the Tcl Shell context menu that will close (hide) the Tcl Shell Dock widget
+- on launching the Tcl Shell the Edit line will take focus immediately
+- in App.on_mouse_move_over_plot() method no longer will be done a setFocus() on every move, only when it is needed
+
22.04.2020
- added a new feature, project auto-saving controlled from Edit -> Preferences -> General -> APP. Preferences -> Enable Auto Save checkbox
diff --git a/FlatCAMApp.py b/FlatCAMApp.py
index 2b6e0cee..d366afa8 100644
--- a/FlatCAMApp.py
+++ b/FlatCAMApp.py
@@ -2105,7 +2105,7 @@ class App(QtCore.QObject):
self.ui.menuview_toggle_axis.triggered.connect(self.on_toggle_axis)
self.ui.menuview_toggle_workspace.triggered.connect(self.on_workspace_toggle)
- self.ui.menutoolshell.triggered.connect(self.on_toggle_shell)
+ self.ui.menutoolshell.triggered.connect(self.toggle_shell)
self.ui.menuhelp_about.triggered.connect(self.on_about)
self.ui.menuhelp_manual.triggered.connect(lambda: webbrowser.open(self.manual_url))
@@ -3326,7 +3326,7 @@ class App(QtCore.QObject):
# re-add the TCL Shell action to the Tools menu and reconnect it to ist slot function
self.ui.menutoolshell = self.ui.menutool.addAction(QtGui.QIcon(self.resource_location + '/shell16.png'),
'&Command Line\tS')
- self.ui.menutoolshell.triggered.connect(self.on_toggle_shell)
+ self.ui.menutoolshell.triggered.connect(self.toggle_shell)
# third install all of them
try:
@@ -3377,7 +3377,7 @@ class App(QtCore.QObject):
self.ui.jmp_btn.triggered.connect(self.on_jump_to)
self.ui.locate_btn.triggered.connect(lambda: self.on_locate(obj=self.collection.get_active()))
- self.ui.shell_btn.triggered.connect(self.on_toggle_shell)
+ self.ui.shell_btn.triggered.connect(self.toggle_shell)
self.ui.new_script_btn.triggered.connect(self.on_filenewscript)
self.ui.open_script_btn.triggered.connect(self.on_fileopenscript)
self.ui.run_script_btn.triggered.connect(self.on_filerunscript)
@@ -5173,7 +5173,7 @@ class App(QtCore.QObject):
# When the main event loop is not started yet in which case the qApp.quit() will do nothing
# we use the following command
# sys.exit(0)
- os._exit(0) # fix to work with Python 3.8
+ os._exit(0) # fix to work with Python 3.8
def kill_app(self):
# QtCore.QCoreApplication.quit()
@@ -5274,34 +5274,6 @@ class App(QtCore.QObject):
with open(config_file, 'w') as f:
f.writelines(data)
- def on_toggle_shell(self):
- """
- Toggle shell: if is visible close it, if it is closed then open it
- :return: None
- """
-
- self.report_usage("on_toggle_shell()")
-
- if self.ui.shell_dock.isVisible():
- self.ui.shell_dock.hide()
- else:
- self.ui.shell_dock.show()
-
- def on_toggle_shell_from_settings(self, state):
- """
- Toggle shell: if is visible close it, if it is closed then open it
- :return: None
- """
-
- self.report_usage("on_toggle_shell_from_settings()")
-
- if state is True:
- if not self.ui.shell_dock.isVisible():
- self.ui.shell_dock.show()
- else:
- if self.ui.shell_dock.isVisible():
- self.ui.shell_dock.hide()
-
def on_register_files(self, obj_type=None):
"""
Called whenever there is a need to register file extensions with FlatCAM.
@@ -8601,8 +8573,11 @@ class App(QtCore.QObject):
pan_button = 2
self.event_is_dragging = self.plotcanvas.is_dragging
- # So it can receive key presses
- self.plotcanvas.native.setFocus()
+ # So it can receive key presses but not when the Tcl Shell is active
+ if not self.ui.shell_dock.isVisible():
+ if not self.plotcanvas.native.hasFocus():
+ self.plotcanvas.native.setFocus()
+
self.pos_jump = event_pos
self.ui.popMenu.mouse_is_panning = False
@@ -12813,6 +12788,49 @@ class App(QtCore.QObject):
"""
pass
+ def toggle_shell(self):
+ """
+ Toggle shell: if is visible close it, if it is closed then open it
+ :return: None
+ """
+
+ self.report_usage("toggle_shell()")
+
+ if self.ui.shell_dock.isVisible():
+ self.ui.shell_dock.hide()
+ self.plotcanvas.native.setFocus()
+ else:
+ self.ui.shell_dock.show()
+
+ # I want to take the focus and give it to the Tcl Shell when the Tcl Shell is run
+ # self.shell._edit.setFocus()
+ QtCore.QTimer.singleShot(0, lambda: self.ui.shell_dock.widget()._edit.setFocus())
+
+ # HACK - simulate a mouse click - alternative
+ # no_km = QtCore.Qt.KeyboardModifier(QtCore.Qt.NoModifier) # no KB modifier
+ # pos = QtCore.QPoint((self.shell._edit.width() - 40), (self.shell._edit.height() - 2))
+ # e = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, pos, QtCore.Qt.LeftButton, QtCore.Qt.LeftButton,
+ # no_km)
+ # QtWidgets.qApp.sendEvent(self.shell._edit, e)
+ # f = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonRelease, pos, QtCore.Qt.LeftButton, QtCore.Qt.LeftButton,
+ # no_km)
+ # QtWidgets.qApp.sendEvent(self.shell._edit, f)
+
+ def on_toggle_shell_from_settings(self, state):
+ """
+ Toggle shell: if is visible close it, if it is closed then open it
+ :return: None
+ """
+
+ self.report_usage("on_toggle_shell_from_settings()")
+
+ if state is True:
+ if not self.ui.shell_dock.isVisible():
+ self.ui.shell_dock.show()
+ else:
+ if self.ui.shell_dock.isVisible():
+ self.ui.shell_dock.hide()
+
def shell_message(self, msg, show=False, error=False, warning=False, success=False, selected=False):
"""
Shows a message on the FlatCAM Shell
diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py
index ded1d7c2..6f1fe86e 100644
--- a/flatcamGUI/FlatCAMGUI.py
+++ b/flatcamGUI/FlatCAMGUI.py
@@ -3247,7 +3247,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Shell toggle
if key == QtCore.Qt.Key_S:
- self.app.on_toggle_shell()
+ self.app.toggle_shell()
# Add a Tool from shortcut
if key == QtCore.Qt.Key_T:
diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py
index 94fa88e2..0b243456 100644
--- a/flatcamGUI/GUIElements.py
+++ b/flatcamGUI/GUIElements.py
@@ -2560,10 +2560,11 @@ class DialogBoxRadio(QtWidgets.QDialog):
class _BrowserTextEdit(QTextEdit):
- def __init__(self, version):
+ def __init__(self, version, app=None):
QTextEdit.__init__(self)
self.menu = None
self.version = version
+ self.app = app
def contextMenuEvent(self, event):
self.menu = self.createStandardContextMenu(event.pos())
@@ -2571,6 +2572,12 @@ class _BrowserTextEdit(QTextEdit):
clear_action.setShortcut(QKeySequence(Qt.Key_Delete)) # it's not working, the shortcut
self.menu.addAction(clear_action)
clear_action.triggered.connect(self.clear)
+
+ if self.app:
+ close_action = QAction("Close", self)
+ self.menu.addAction(close_action)
+ close_action.triggered.connect(lambda: self.app.ui.shell_dock.hide())
+
self.menu.exec_(event.globalPos())
def clear(self):
diff --git a/flatcamTools/ToolShell.py b/flatcamTools/ToolShell.py
index 78f328d5..0f8a5f0f 100644
--- a/flatcamTools/ToolShell.py
+++ b/flatcamTools/ToolShell.py
@@ -33,10 +33,10 @@ class TermWidget(QWidget):
User pressed Enter. Client class should decide, if command must be executed or user may continue edit it
"""
- def __init__(self, version, *args):
+ def __init__(self, version, app, *args):
QWidget.__init__(self, *args)
- self._browser = _BrowserTextEdit(version=version)
+ self._browser = _BrowserTextEdit(version=version, app=app)
self._browser.setStyleSheet("font: 9pt \"Courier\";")
self._browser.setReadOnly(True)
self._browser.document().setDefaultStyleSheet(
@@ -92,10 +92,14 @@ class TermWidget(QWidget):
"""
Convert text to HTML for inserting it to browser
"""
- assert style in ('in', 'out', 'err', 'warning', 'success', 'selected')
+ assert style in ('in', 'out', 'err', 'warning', 'success', 'selected', 'raw')
- text = html.escape(text)
- text = text.replace('\n', '
')
+ if style != 'raw':
+ text = html.escape(text)
+ text = text.replace('\n', '
')
+ else:
+ text = text.replace('\n', '
')
+ text = text.replace('\t', ' ')
if style == 'in':
text = '%s' % text
@@ -107,6 +111,8 @@ class TermWidget(QWidget):
text = '%s' % text
elif style == 'selected':
text = ''
+ elif style == 'raw':
+ text = text
else:
text = '%s' % text # without span
is ignored!!!
@@ -177,23 +183,29 @@ class TermWidget(QWidget):
"""
self._append_to_browser('out', text)
+ def append_raw(self, text):
+ """
+ Append text to output widget as it is
+ """
+ self._append_to_browser('raw', text)
+
def append_success(self, text):
- """Appent text to output widget
+ """Append text to output widget
"""
self._append_to_browser('success', text)
def append_selected(self, text):
- """Appent text to output widget
+ """Append text to output widget
"""
self._append_to_browser('selected', text)
def append_warning(self, text):
- """Appent text to output widget
+ """Append text to output widget
"""
self._append_to_browser('warning', text)
def append_error(self, text):
- """Appent error text to output widget. Text is drawn with red background
+ """Append error text to output widget. Text is drawn with red background
"""
self._append_to_browser('err', text)
@@ -235,7 +247,7 @@ class FCShell(TermWidget):
:param version: FlatCAM version string
:param args: Parameters passed to the TermWidget parent class
"""
- TermWidget.__init__(self, version, *args)
+ TermWidget.__init__(self, version, *args, app=sysShell)
self._sysShell = sysShell
def is_command_complete(self, text):
diff --git a/tclCommands/TclCommandHelp.py b/tclCommands/TclCommandHelp.py
index a1af436e..d40ac267 100644
--- a/tclCommands/TclCommandHelp.py
+++ b/tclCommands/TclCommandHelp.py
@@ -22,10 +22,10 @@ if '_' not in builtins.__dict__:
class TclCommandHelp(TclCommand):
"""
- Tcl shell command to get the value of a system variable
+ Tcl shell command to show Help
example:
- get_sys excellon_zeros
+ help add_circle
"""
# List of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
@@ -58,21 +58,21 @@ class TclCommandHelp(TclCommand):
def execute(self, args, unnamed_args):
"""
- :param args:
+ :param args: Without any argument will display the list of commands. Can have as a argument
+ a tcl command name to display the help for that command.
:param unnamed_args:
:return:
"""
- print(self.app.tcl_commands_storage)
if 'name' in args:
name = args['name']
if name not in self.app.tcl_commands_storage:
return "Unknown command: %s" % name
- print(self.app.tcl_commands_storage[name]["help"])
+ self.app.shell.append_output(self.app.tcl_commands_storage[name]["help"])
else:
- if args is None:
- cmd_enum = _("Available commands:\n")
+ if not args:
+ cmd_enum = '%s\n' % _("Available commands:")
displayed_text = []
try:
@@ -85,14 +85,12 @@ class TclCommandHelp(TclCommand):
max_tabs = math.ceil(max_len / 8)
for cmd_name in sorted(self.app.tcl_commands_storage):
- cmd_description = self.app.tcl_commands_storage[cmd_name]['description']
+ cmd_description = "%s" % self.app.tcl_commands_storage[cmd_name]['description']
curr_len = len(cmd_name)
tabs = '\t'
- cmd_name_colored = ""
- cmd_name_colored += str(cmd_name)
- cmd_name_colored += ""
+ cmd_name_colored = "%s" % str(cmd_name)
# make sure to add the right number of tabs (1 tab = 8 spaces) so all the commands
# descriptions are aligned
@@ -102,7 +100,7 @@ class TclCommandHelp(TclCommand):
nr_tabs = 0
for x in range(max_tabs):
- if curr_len <= (x * 8):
+ if curr_len < (x * 8):
nr_tabs += 1
# nr_tabs = 2 if curr_len <= 8 else 1
@@ -111,9 +109,9 @@ class TclCommandHelp(TclCommand):
displayed_text.append(cmd_line_txt)
except Exception as err:
self.app.log.debug("App.setup_shell.shelp() when run as 'help' --> %s" % str(err))
- displayed_text = [' %s' % cmd for cmd in sorted(self.app.tcl_commands_storage)]
+ displayed_text = ['> %s\n' % cmd for cmd in sorted(self.app.tcl_commands_storage)]
- cmd_enum += '\n'.join(displayed_text)
- cmd_enum += '\n\n%s\n%s' % (_("Type help for usage."), _("Example: help open_gerber"))
+ cmd_enum += '
'.join(displayed_text)
+ cmd_enum += '
%s
%s' % (_("Type help for usage."), _("Example: help open_gerber"))
- print(cmd_enum)
\ No newline at end of file
+ self.app.shell.append_raw(cmd_enum)
diff --git a/tclCommands/__init__.py b/tclCommands/__init__.py
index 9a5b22cf..b4a8d324 100644
--- a/tclCommands/__init__.py
+++ b/tclCommands/__init__.py
@@ -1,7 +1,6 @@
import pkgutil
import sys
-# Todo: I think these imports are not needed.
# allowed command modules (please append them alphabetically ordered)
import tclCommands.TclCommandAddCircle
import tclCommands.TclCommandAddPolygon
@@ -27,6 +26,7 @@ import tclCommands.TclCommandGeoCutout
import tclCommands.TclCommandGeoUnion
import tclCommands.TclCommandGetNames
import tclCommands.TclCommandGetSys
+import tclCommands.TclCommandHelp
import tclCommands.TclCommandImportSvg
import tclCommands.TclCommandInteriors
import tclCommands.TclCommandIsolate
@@ -93,7 +93,6 @@ def register_all_commands(app, commands):
tcl_modules = {k: v for k, v in list(sys.modules.items()) if k.startswith('tclCommands.TclCommand')}
for key, mod in list(tcl_modules.items()):
- print(key)
if key != 'tclCommands.TclCommand':
class_name = key.split('.')[1]
class_type = getattr(mod, class_name)