Skip to content

Commit

Permalink
Let terminal GUI remember its previous size (depending on a new pref) (
Browse files Browse the repository at this point in the history
…#68)

* removing extraneous spaces; adding a few comments

* comments

* qt deprecations: replacing desktop with primaryScreen and screenGeometry with size

* comments

* removing commented code about logo

* remove the subtractions, because this is all captured by availableGeometry anyway

* implementing new pref TERMINAL_WINSIZE_BEHAVIOR
  • Loading branch information
cxrodgers authored Feb 9, 2021
1 parent 066d763 commit eda5404
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 128 deletions.
210 changes: 83 additions & 127 deletions autopilot/core/terminal.py
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

Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -192,9 +195,6 @@ def __init__(self):
#self.heartbeat(once=True)
self.logger.info('Terminal Initialized')




def initUI(self):
"""
Initializes graphical elements of Terminal.
Expand All @@ -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
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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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:
# The moderate size
self.move(primary_display.left(), primary_display.top())
self.resize(1000, 400)


## 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')

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -721,7 +699,6 @@ def subject_protocols(self):

return subjects_protocols


def reassign_protocols(self):
"""
Batch reassign protocols and steps.
Expand Down Expand Up @@ -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')
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -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_())


10 changes: 9 additions & 1 deletion autopilot/prefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,15 @@ class Scopes(Enum):
"default": str(_basedir / "pilot_db.json"),
"scope": Scopes.TERMINAL
},
'TERMINAL_WINSIZE_BEHAVIOR': {
'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?",
Expand Down Expand Up @@ -345,7 +354,6 @@ class Scopes(Enum):
'depends': 'AUDIOSERVER',
"scope": Scopes.AUDIO
},

})
"""
Ordered Dictionary containing default values for prefs.
Expand Down

0 comments on commit eda5404

Please sign in to comment.