-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cxrodgers dev terminal winsize #70
Changes from 7 commits
add65ec
91b470d
5672cd2
cee13c8
f6d1a0f
261c788
164bc91
904976d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,15 @@ | ||
"""Methods for running the Terminal GUI""" | ||
|
||
import argparse | ||
import json | ||
import sys | ||
import os | ||
|
||
import datetime | ||
import logging | ||
import threading | ||
from collections import OrderedDict as odict | ||
import numpy as np | ||
|
||
from PySide2 import QtCore, QtGui, QtSvg, QtWidgets | ||
|
||
from autopilot import prefs | ||
from autopilot.core import styles | ||
|
||
|
@@ -35,16 +34,14 @@ | |
# init prefs for module access | ||
prefs.init(prefs_file) | ||
|
||
|
||
|
||
from autopilot.core.subject import Subject | ||
from autopilot.core.plots import Plot_Widget | ||
from autopilot.core.networking import Terminal_Station, Net_Node | ||
from autopilot.core.utils import InvokeEvent, Invoker, get_invoker | ||
from autopilot.core.gui import Control_Panel, Protocol_Wizard, Weights, Reassign, Calibrate_Water, Bandwidth_Test | ||
from autopilot.core.loggers import init_logger | ||
|
||
|
||
# Try to import viz, but continue if that doesn't work | ||
IMPORTED_VIZ = False | ||
VIZ_ERROR = None | ||
try: | ||
|
@@ -123,6 +120,12 @@ def __init__(self): | |
# store instance | ||
globals()['_TERMINAL'] = self | ||
|
||
# Load settings | ||
# These are stored in ~/.config/Autopilot/Terminal.conf | ||
# Currently, the only setting is "geometry", but loading here | ||
# in case we start to use other ones in the future | ||
self.settings = QtCore.QSettings("Autopilot", "Terminal") | ||
|
||
# networking | ||
self.node = None | ||
self.networking = None | ||
|
@@ -192,9 +195,6 @@ def __init__(self): | |
#self.heartbeat(once=True) | ||
self.logger.info('Terminal Initialized') | ||
|
||
|
||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ty for cleaning up my mess ;) |
||
def initUI(self): | ||
""" | ||
Initializes graphical elements of Terminal. | ||
|
@@ -205,40 +205,42 @@ def initUI(self): | |
* :class:`.gui.Control_Panel` | ||
* :class:`.plots.Plot_Widget` | ||
""" | ||
|
||
|
||
# set central widget | ||
# Set central widget | ||
self.widget = QtWidgets.QWidget() | ||
self.setCentralWidget(self.widget) | ||
|
||
|
||
|
||
# Start GUI | ||
# Set the layout | ||
self.layout = QtWidgets.QGridLayout() | ||
self.layout.setSpacing(0) | ||
self.layout.setContentsMargins(0,0,0,0) | ||
self.widget.setLayout(self.layout) | ||
|
||
# Set title | ||
self.setWindowTitle('Terminal') | ||
#self.menuBar().setFixedHeight(40) | ||
|
||
# Main panel layout | ||
#self.panel_layout.setContentsMargins(0,0,0,0) | ||
|
||
# Init toolbar | ||
# File menu | ||
# make menu take up 1/10 of the screen | ||
winsize = app.desktop().availableGeometry() | ||
|
||
# This is the pixel resolution of the entire screen | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. appreciate this update and commenting!!!! |
||
screensize = app.primaryScreen().size() | ||
|
||
# This is the available geometry of the primary screen, excluding | ||
# window manager reserved areas such as task bars and system menus. | ||
primary_display = app.primaryScreen().availableGeometry() | ||
|
||
|
||
## Initalize the menuBar | ||
# Linux: Set the menuBar to a fixed height | ||
# Darwin: Don't worry about menuBar | ||
if sys.platform == 'darwin': | ||
bar_height = 0 | ||
else: | ||
bar_height = (winsize.height()/30)+5 | ||
bar_height = (primary_display.height()/30)+5 | ||
self.menuBar().setFixedHeight(bar_height) | ||
|
||
|
||
# Create a File menu | ||
self.file_menu = self.menuBar().addMenu("&File") | ||
self.file_menu.setObjectName("file") | ||
|
||
# Add "New Pilot" and "New Protocol" actions to File menu | ||
new_pilot_act = QtWidgets.QAction("New &Pilot", self, triggered=self.new_pilot) | ||
new_prot_act = QtWidgets.QAction("New Pro&tocol", self, triggered=self.new_protocol) | ||
#batch_create_subjects = QtWidgets.QAction("Batch &Create subjects", self, triggered=self.batch_subjects) | ||
|
@@ -247,8 +249,10 @@ def initUI(self): | |
self.file_menu.addAction(new_prot_act) | ||
#self.file_menu.addAction(batch_create_subjects) | ||
|
||
# Tools menu | ||
# Create a Tools menu | ||
self.tool_menu = self.menuBar().addMenu("&Tools") | ||
|
||
# Add actions to Tools menu | ||
subject_weights_act = QtWidgets.QAction("View Subject &Weights", self, triggered=self.subject_weights) | ||
update_protocol_act = QtWidgets.QAction("Update Protocols", self, triggered=self.update_protocols) | ||
reassign_act = QtWidgets.QAction("Batch Reassign Protocols", self, triggered=self.reassign_protocols) | ||
|
@@ -258,12 +262,12 @@ def initUI(self): | |
self.tool_menu.addAction(reassign_act) | ||
self.tool_menu.addAction(calibrate_act) | ||
|
||
# Plots menu | ||
# Create a Plots menu and add Psychometric Curve action | ||
self.plots_menu = self.menuBar().addMenu("&Plots") | ||
psychometric = QtGui.QAction("Psychometric Curve", self, triggered=self.plot_psychometric) | ||
self.plots_menu.addAction(psychometric) | ||
|
||
# Tests menu | ||
# Create a Tests menu and add a Test Bandwidth action | ||
self.tests_menu = self.menuBar().addMenu("Test&s") | ||
bandwidth_test_act = QtWidgets.QAction("Test Bandwidth", self, triggered=self.test_bandwidth) | ||
self.tests_menu.addAction(bandwidth_test_act) | ||
|
@@ -279,89 +283,69 @@ def initUI(self): | |
self.data_panel = Plot_Widget() | ||
self.data_panel.init_plots(self.pilots.keys()) | ||
|
||
|
||
|
||
# Logo goes up top | ||
# https://stackoverflow.com/questions/25671275/pyside-how-to-set-an-svg-icon-in-qtreewidgets-item-and-change-the-size-of-the | ||
|
||
# | ||
# pixmap_path = os.path.join(os.path.dirname(prefs.get('AUTOPILOT_ROOT')), 'graphics', 'autopilot_logo_small.svg') | ||
# #svg_renderer = QtSvg.QSvgRenderer(pixmap_path) | ||
# #image = QtWidgets.QImage() | ||
# #self.logo = QtSvg.QSvgWidget() | ||
# | ||
# | ||
# # set size, preserving aspect ratio | ||
# logo_height = round(44.0*((bar_height-5)/44.0)) | ||
# logo_width = round(139*((bar_height-5)/44.0)) | ||
# | ||
# svg_renderer = QtSvg.QSvgRenderer(pixmap_path) | ||
# image = QtGui.QImage(logo_width, logo_height, QtGui.QImage.Format_ARGB32) | ||
# # Set the ARGB to 0 to prevent rendering artifacts | ||
# image.fill(0x00000000) | ||
# svg_renderer.render(QtGui.QPainter(image)) | ||
# pixmap = QtGui.QPixmap.fromImage(image) | ||
# self.logo = QtWidgets.QLabel() | ||
# self.logo.setPixmap(pixmap) | ||
|
||
# Set logo to corner widget | ||
if sys.platform != 'darwin': | ||
self.menuBar().setCornerWidget(self.logo, QtCore.Qt.TopRightCorner) | ||
self.menuBar().adjustSize() | ||
|
||
#self.logo.load(pixmap_path) | ||
# Combine all in main layout | ||
# Add Control Panel and Data Panel to main layout | ||
#self.layout.addWidget(self.logo, 0,0,1,2) | ||
self.layout.addWidget(self.control_panel, 0,0,1,1) | ||
self.layout.addWidget(self.data_panel, 0,1,1,1) | ||
self.layout.setColumnStretch(0, 1) | ||
self.layout.setColumnStretch(1, 3) | ||
|
||
# Set size of window to be fullscreen without maximization | ||
# Until a better solution is found, if not set large enough, the pilot tabs will | ||
# expand into infinity. See the Expandable_Tabs class | ||
#pdb.set_trace() | ||
screensize = app.desktop().screenGeometry() | ||
winsize = app.desktop().availableGeometry() | ||
|
||
# want to subtract bounding title box, our title bar, and logo height. | ||
# our y offset will be the size of the bounding title box | ||
|
||
# Then our tilebar | ||
# multiply by three to get the inner (file, etc.) bar, the top bar (min, maximize, etc) | ||
# and then the very top system tray bar in ubuntu | ||
#titleBarHeight = self.style().pixelMetric(QtWidgets.QStyle.PM_TitleBarHeight, | ||
# QtWidgets.QStyleOptionTitleBar(), self) * 3 | ||
title_bar_height = screensize.height()-winsize.height() | ||
|
||
#titleBarHeight = bar_height*2 | ||
# finally our logo | ||
logo_height = bar_height | ||
|
||
|
||
|
||
winheight = winsize.height() - title_bar_height - logo_height # also subtract logo height | ||
winsize.setHeight(winheight) | ||
self.max_height = winheight | ||
self.setGeometry(winsize) | ||
self.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) | ||
|
||
# Set heights on control panel and data panel | ||
|
||
|
||
# move to primary display and show maximized | ||
primary_display = app.desktop().availableGeometry(0) | ||
self.move(primary_display.left(), primary_display.top()) | ||
# self.resize(primary_display.width(), primary_display.height()) | ||
# | ||
self.control_panel.setMaximumHeight(winheight) | ||
self.data_panel.setMaximumHeight(winheight) | ||
|
||
## Set window size | ||
# The window size behavior depends on TERMINAL_WINSIZE_BEHAVIOR pref | ||
# If 'remember': restore to the geometry from the last close | ||
# If 'maximum': restore to fill the entire screen | ||
# If 'moderate': restore to a reasonable size of (1000, 400) pixels | ||
terminal_winsize_behavior = prefs.get('TERMINAL_WINSIZE_BEHAVIOR') | ||
|
||
# Set geometry according to pref | ||
if terminal_winsize_behavior == 'maximum': | ||
# Set geometry to available geometry | ||
self.setGeometry(primary_display) | ||
|
||
# Set SizePolicy to maximum | ||
self.setSizePolicy( | ||
QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) | ||
|
||
# Move to top left corner of primary display | ||
self.move(primary_display.left(), primary_display.top()) | ||
|
||
# Also set the maximum height of each panel | ||
self.control_panel.setMaximumHeight(primary_display.height()) | ||
self.data_panel.setMaximumHeight(primary_display.height()) | ||
|
||
elif terminal_winsize_behavior == 'remember': | ||
# Attempt to restore previous geometry | ||
if self.settings.value("geometry") is None: | ||
# It was never saved, for instance, this is the first time | ||
# this app has been run | ||
# So default to the moderate size | ||
self.move(primary_display.left(), primary_display.top()) | ||
self.resize(1000, 400) | ||
else: | ||
# It was saved, so restore the last geometry | ||
self.restoreGeometry(self.settings.value("geometry")) | ||
|
||
else: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor style thing, make explicit and then fallback, will do. otherwise this looks good |
||
# The moderate size | ||
self.move(primary_display.left(), primary_display.top()) | ||
self.resize(1000, 400) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i take it these are empirical? that's fine, we mebs want to have some option for like "half screen," and i think i'll add the ability to set position explicitly too There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, (1000, 400) is my favorite autopilot window size. I suppose we could call that "empirical". For the typical new user use-case, where they open it up and have either 0 or 1 Pis connected, something like this makes a bit more sense than full-screen (IMHO) |
||
|
||
|
||
## Finalize some aesthetics | ||
# set stylesheet for main window | ||
self.setStyleSheet(styles.TERMINAL) | ||
|
||
# set fonts to antialias | ||
self.setFont(self.font().setStyleStrategy(QtGui.QFont.PreferAntialias)) | ||
|
||
|
||
## Show, and log that initialization is complete | ||
self.show() | ||
logging.info('UI Initialized') | ||
|
||
|
@@ -399,7 +383,6 @@ def heartbeat(self, once=False): | |
self.heartbeat_timer.daemon = True | ||
self.heartbeat_timer.start() | ||
|
||
|
||
def toggle_start(self, starting, pilot, subject=None): | ||
"""Start or Stop running the currently selected subject's task. Sends a | ||
message containing the task information to the concerned pilot. | ||
|
@@ -529,11 +512,6 @@ def l_state(self, value): | |
#self.control_panel.panels[value['pilot']].button.set_state(value['state']) | ||
self.pilots[value['pilot']]['state'] = value['state'] | ||
|
||
|
||
|
||
|
||
|
||
|
||
def l_handshake(self, value): | ||
""" | ||
Pilot is sending its IP and state on startup. | ||
|
@@ -721,7 +699,6 @@ def subject_protocols(self): | |
|
||
return subjects_protocols | ||
|
||
|
||
def reassign_protocols(self): | ||
""" | ||
Batch reassign protocols and steps. | ||
|
@@ -830,8 +807,6 @@ def plot_psychometric(self): | |
if psychometric_dialog.result() != 1: | ||
return | ||
|
||
|
||
|
||
chart = viz.plot_psychometric(psychometric_dialog.plot_params) | ||
|
||
text, ok = QtGui.QInputDialog.getText(self, 'save plot?', 'what to call this thing') | ||
|
@@ -841,27 +816,9 @@ def plot_psychometric(self): | |
|
||
#chart.serve() | ||
|
||
|
||
|
||
|
||
|
||
#viz.plot_psychometric(self.subjects_protocols) | ||
#result = psychometric_dialog.exec_() | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
def closeEvent(self, event): | ||
""" | ||
When Closing the Terminal Window, close any running subject objects, | ||
|
@@ -871,6 +828,9 @@ def closeEvent(self, event): | |
to explicitly kill it. | ||
|
||
""" | ||
# Save the window geometry, to be optionally restored next time | ||
self.settings.setValue("geometry", self.saveGeometry()) | ||
|
||
# TODO: Check if any subjects are currently running, pop dialog asking if we want to stop | ||
|
||
# Close all subjects files | ||
|
@@ -884,15 +844,11 @@ def closeEvent(self, event): | |
|
||
event.accept() | ||
|
||
# Create the QApplication and run it | ||
# Prefs were already loaded at the very top | ||
if __name__ == "__main__": | ||
|
||
#with open(prefs_file) as prefs_file_open: | ||
# prefs = json.load(prefs_file_open) | ||
|
||
app = QtWidgets.QApplication(sys.argv) | ||
#app.setGraphicsSystem("opengl") | ||
app.setStyle('GTK+') # Keeps some GTK errors at bay | ||
ex = Terminal() | ||
sys.exit(app.exec_()) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -282,6 +282,15 @@ class Scopes(Enum): | |
"default": str(_basedir / "pilot_db.json"), | ||
"scope": Scopes.TERMINAL | ||
}, | ||
'TERMINAL_WINSIZE_BEHAVIOR': { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should be a multi-select box i think. |
||
'type': 'str', | ||
'text': ( | ||
'How the Terminal window is sized: ' | ||
'"maximum", "moderate", or "remember"' | ||
), | ||
'default': 'moderate', | ||
"scope": Scopes.TERMINAL | ||
}, | ||
'LINEAGE': { | ||
'type': 'choice', | ||
"text": "Are we a parent or a child?", | ||
|
@@ -345,7 +354,6 @@ class Scopes(Enum): | |
'depends': 'AUDIOSERVER', | ||
"scope": Scopes.AUDIO | ||
}, | ||
|
||
}) | ||
""" | ||
Ordered Dictionary containing default values for prefs. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this. let's move it to be in the autopilot directory so it's all in one place? looks like
QSettings
supports being constructed with a filename, i'll add a pref for thatThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will add description to docstring too