kopia lustrzana https://github.com/corrscope/corrscope
Merge pull request #219 from nyanpasu64/remove-ui-xml
Replace XML .ui files with stack-based Python codepull/357/head
commit
6c3bd82f58
|
|
@ -3,6 +3,7 @@ import os
|
|||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
|
||||
from PyInstaller.building.api import PYZ, EXE, COLLECT
|
||||
from PyInstaller.building.build_main import Analysis
|
||||
|
|
@ -19,10 +20,12 @@ def keep(dir, wildcard):
|
|||
return [(include, dir) for include in includes]
|
||||
|
||||
|
||||
datas = keep("corrscope/gui", "*.ui")
|
||||
InFile = str
|
||||
OutFolder = str
|
||||
datas: List[Tuple[InFile, OutFolder]] = []
|
||||
|
||||
version = v.pyinstaller_write_version()
|
||||
datas.append((v.version_txt, "."))
|
||||
datas += [(str(v.version_txt), ".")]
|
||||
|
||||
app_name = "corrscope"
|
||||
app_name_version = f"{app_name}-{version}"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ from typing import Optional, List, Any, Tuple, Callable, Union, Dict, Sequence
|
|||
import PyQt5.QtCore as qc
|
||||
import PyQt5.QtWidgets as qw
|
||||
import attr
|
||||
from PyQt5 import uic
|
||||
from PyQt5.QtCore import QModelIndex, Qt
|
||||
from PyQt5.QtCore import QVariant
|
||||
from PyQt5.QtGui import QKeySequence, QFont, QCloseEvent
|
||||
|
|
@ -21,7 +20,7 @@ from corrscope import cli
|
|||
from corrscope.channel import ChannelConfig
|
||||
from corrscope.config import CorrError, copy_config, yaml
|
||||
from corrscope.corrscope import CorrScope, Config, Arguments, default_config
|
||||
from corrscope.gui.data_bind import (
|
||||
from corrscope.gui.model_bind import (
|
||||
PresentationModel,
|
||||
map_gui,
|
||||
behead,
|
||||
|
|
@ -34,6 +33,7 @@ from corrscope.gui.history_file_dlg import (
|
|||
get_open_file_list,
|
||||
get_save_file_path,
|
||||
)
|
||||
from corrscope.gui.view_mainwindow import MainWindow as Ui_MainWindow
|
||||
from corrscope.gui.util import color2hex, Locked, find_ranges, TracebackDialog
|
||||
from corrscope.layout import Orientation, StereoOrientation
|
||||
from corrscope.outputs import IOutputConfig, FFplayOutputConfig, FFmpegOutputConfig
|
||||
|
|
@ -74,7 +74,7 @@ def gui_main(cfg_or_path: Union[Config, Path]):
|
|||
sys.exit(app.exec_())
|
||||
|
||||
|
||||
class MainWindow(qw.QMainWindow):
|
||||
class MainWindow(qw.QMainWindow, Ui_MainWindow):
|
||||
"""
|
||||
Main window.
|
||||
|
||||
|
|
@ -94,7 +94,7 @@ class MainWindow(qw.QMainWindow):
|
|||
self.pref = gp.load_prefs()
|
||||
|
||||
# Load UI.
|
||||
uic.loadUi(res("mainwindow.ui"), self) # sets windowTitle
|
||||
self.setupUi(self) # sets windowTitle
|
||||
|
||||
# Bind UI buttons, etc. Functions block main thread, avoiding race conditions.
|
||||
self.master_audio_browse.clicked.connect(self.on_master_audio_browse)
|
||||
|
|
@ -151,7 +151,7 @@ class MainWindow(qw.QMainWindow):
|
|||
self._update_unsaved_title()
|
||||
|
||||
# GUI layout widgets
|
||||
tabWidget: qw.QTabWidget
|
||||
left_tabs: qw.QTabWidget
|
||||
|
||||
# Config models
|
||||
model: Optional["ConfigModel"] = None
|
||||
|
|
@ -232,7 +232,7 @@ class MainWindow(qw.QMainWindow):
|
|||
self._cfg_path = cfg_path
|
||||
self._any_unsaved = False
|
||||
self.load_title()
|
||||
self.tabWidget.setCurrentIndex(0)
|
||||
self.left_tabs.setCurrentIndex(0)
|
||||
|
||||
if self.model is None:
|
||||
self.model = ConfigModel(cfg)
|
||||
|
|
|
|||
|
|
@ -1,795 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1160</width>
|
||||
<height>0</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabGeneral">
|
||||
<attribute name="title">
|
||||
<string>&General</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="optionGlobal">
|
||||
<property name="title">
|
||||
<string>Global</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="fpsL">
|
||||
<property name="text">
|
||||
<string>FPS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="BoundSpinBox" name="fps">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="trigger_msL">
|
||||
<property name="text">
|
||||
<string>Trigger Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="BoundSpinBox" name="trigger_ms">
|
||||
<property name="minimum">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="render_msL">
|
||||
<property name="text">
|
||||
<string>Render Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="BoundSpinBox" name="render_ms">
|
||||
<property name="minimum">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="amplificationL">
|
||||
<property name="text">
|
||||
<string>Amplification</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="BoundDoubleSpinBox" name="amplification">
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="begin_timeL">
|
||||
<property name="text">
|
||||
<string>Begin Time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="BoundDoubleSpinBox" name="begin_time">
|
||||
<property name="maximum">
|
||||
<double>9999.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="optionAppear">
|
||||
<property name="title">
|
||||
<string>Appearance</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="render_resolutionL">
|
||||
<property name="text">
|
||||
<string>Resolution</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="BoundLineEdit" name="render_resolution">
|
||||
<property name="text">
|
||||
<string>vs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="render__bg_colorL">
|
||||
<property name="text">
|
||||
<string>Background</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="BoundColorWidget" name="render__bg_color" native="true"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="render__init_line_colorL">
|
||||
<property name="text">
|
||||
<string>Line Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="BoundColorWidget" name="render__init_line_color" native="true"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="render__line_widthL">
|
||||
<property name="text">
|
||||
<string>Line Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="BoundDoubleSpinBox" name="render__line_width">
|
||||
<property name="minimum">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="render__grid_colorL">
|
||||
<property name="text">
|
||||
<string>Grid Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="OptionalColorWidget" name="render__grid_color" native="true"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="render__midline_colorL">
|
||||
<property name="text">
|
||||
<string>Midline Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="OptionalColorWidget" name="render__midline_color" native="true"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="BoundCheckBox" name="render__v_midline">
|
||||
<property name="text">
|
||||
<string>Vertical</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="BoundCheckBox" name="render__h_midline">
|
||||
<property name="text">
|
||||
<string>Horizontal Midline</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="optionLayout">
|
||||
<property name="title">
|
||||
<string>Layout</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="layout__orientationL">
|
||||
<property name="text">
|
||||
<string>Orientation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="BoundComboBox" name="layout__orientation"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="layout__ncolsL">
|
||||
<property name="text">
|
||||
<string>Columns</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="layoutDims">
|
||||
<item>
|
||||
<widget class="BoundSpinBox" name="layout__ncols">
|
||||
<property name="specialValueText">
|
||||
<string notr="true"> </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="layout__nrowsL">
|
||||
<property name="text">
|
||||
<string>Rows</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="BoundSpinBox" name="layout__nrows">
|
||||
<property name="specialValueText">
|
||||
<string notr="true"> </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabStereo">
|
||||
<attribute name="title">
|
||||
<string>&Stereo</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="optionStereo">
|
||||
<property name="title">
|
||||
<string>Stereo Enable</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_8">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="trigger_stereoL">
|
||||
<property name="text">
|
||||
<string>Trigger Stereo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="BoundComboBox" name="trigger_stereo"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="render_stereoL">
|
||||
<property name="text">
|
||||
<string>Render Stereo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="BoundComboBox" name="render_stereo"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="dockStereo_2">
|
||||
<property name="title">
|
||||
<string>Stereo Appearance</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_7">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="layout__stereo_orientationL">
|
||||
<property name="text">
|
||||
<string>Stereo Orientation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="BoundComboBox" name="layout__stereo_orientation"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="render__stereo_grid_opacityL">
|
||||
<property name="text">
|
||||
<string>Grid Opacity</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="BoundDoubleSpinBox" name="render__stereo_grid_opacity">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.250000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabPerf">
|
||||
<attribute name="title">
|
||||
<string>&Performance</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="perfAll">
|
||||
<property name="title">
|
||||
<string>Preview and Render</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="trigger_subsamplingL">
|
||||
<property name="text">
|
||||
<string>Trigger Subsampling</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="BoundSpinBox" name="trigger_subsampling">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="render_subsamplingL">
|
||||
<property name="text">
|
||||
<string>Render Subsampling</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="BoundSpinBox" name="render_subsampling">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="perfPreview">
|
||||
<property name="title">
|
||||
<string>Preview Only</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="render_subfpsL">
|
||||
<property name="text">
|
||||
<string>Render FPS Divisor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="BoundSpinBox" name="render_subfps">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="render__res_divisorL">
|
||||
<property name="text">
|
||||
<string>Resolution Divisor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="BoundDoubleSpinBox" name="render__res_divisor">
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="audioColumn">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="audioGroup">
|
||||
<property name="title">
|
||||
<string>Master Audio</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="BoundLineEdit" name="master_audio">
|
||||
<property name="text">
|
||||
<string>/</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="master_audio_browse">
|
||||
<property name="text">
|
||||
<string>&Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="optionAudio">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Trigger</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="trigger__edge_strengthL">
|
||||
<property name="text">
|
||||
<string>Edge Strength</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="trigger__responsivenessL">
|
||||
<property name="text">
|
||||
<string>Responsiveness</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="trigger__buffer_falloffL">
|
||||
<property name="text">
|
||||
<string>Buffer Falloff</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="BoundDoubleSpinBox" name="trigger__edge_strength">
|
||||
<property name="minimum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="BoundDoubleSpinBox" name="trigger__responsiveness">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="BoundDoubleSpinBox" name="trigger__buffer_falloff">
|
||||
<property name="singleStep">
|
||||
<double>0.500000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" rowspan="2">
|
||||
<widget class="BoundCheckBox" name="trigger__pitch_tracking">
|
||||
<property name="text">
|
||||
<string>Pitch Tracking</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="trigger__edge_directionL">
|
||||
<property name="text">
|
||||
<string>Edge Direction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="BoundComboBox" name="trigger__edge_direction"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="channelsGroup">
|
||||
<property name="title">
|
||||
<string>Oscilloscope Channels</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="channelBar">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ShortcutButton" name="channelAdd">
|
||||
<property name="text">
|
||||
<string>&Add...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ShortcutButton" name="channelDelete">
|
||||
<property name="text">
|
||||
<string>&Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ShortcutButton" name="channelUp">
|
||||
<property name="text">
|
||||
<string>Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ShortcutButton" name="channelDown">
|
||||
<property name="text">
|
||||
<string>Down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ChannelTableView" name="channel_view"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>&File</string>
|
||||
</property>
|
||||
<addaction name="actionNew"/>
|
||||
<addaction name="actionOpen"/>
|
||||
<addaction name="actionSave"/>
|
||||
<addaction name="actionSaveAs"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPreview"/>
|
||||
<addaction name="actionRender"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>&Tools</string>
|
||||
</property>
|
||||
<addaction name="action_separate_render_dir"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuTools"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionNew"/>
|
||||
<addaction name="actionOpen"/>
|
||||
<addaction name="actionSave"/>
|
||||
<addaction name="actionSaveAs"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPreview"/>
|
||||
<addaction name="actionRender"/>
|
||||
</widget>
|
||||
<action name="actionOpen">
|
||||
<property name="text">
|
||||
<string>&Open</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave">
|
||||
<property name="text">
|
||||
<string>&Save</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew">
|
||||
<property name="text">
|
||||
<string>&New</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+N</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSaveAs">
|
||||
<property name="text">
|
||||
<string>Save &As</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExit">
|
||||
<property name="text">
|
||||
<string>E&xit</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPreview">
|
||||
<property name="text">
|
||||
<string>&Preview</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+P</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRender">
|
||||
<property name="text">
|
||||
<string>&Render to Video</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+R</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_separate_render_dir">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Separate Render Folder</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>BoundLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>corrscope/gui/data_bind.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BoundSpinBox</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>corrscope/gui/data_bind.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BoundDoubleSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header>corrscope/gui/data_bind.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BoundComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>corrscope/gui/data_bind.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BoundCheckBox</class>
|
||||
<extends>QCheckBox</extends>
|
||||
<header>corrscope/gui/data_bind.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ShortcutButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>corrscope/gui/__init__.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ChannelTableView</class>
|
||||
<extends>QTableView</extends>
|
||||
<header>corrscope/gui/__init__.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>BoundColorWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>corrscope/gui/data_bind.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>OptionalColorWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>corrscope/gui/data_bind.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -71,6 +71,9 @@ class PresentationModel(qc.QObject):
|
|||
updater()
|
||||
|
||||
|
||||
SKIP_BINDING = "skip"
|
||||
|
||||
|
||||
def map_gui(view: "MainWindow", model: PresentationModel) -> None:
|
||||
"""
|
||||
Binding:
|
||||
|
|
@ -90,7 +93,8 @@ def map_gui(view: "MainWindow", model: PresentationModel) -> None:
|
|||
# Exclude nameless ColorText inside BoundColorWidget wrapper,
|
||||
# since bind_widget(path="") will crash.
|
||||
# BoundColorWidget.bind_widget() handles binding children.
|
||||
if path:
|
||||
if path != SKIP_BINDING:
|
||||
assert path != ""
|
||||
widget.bind_widget(model, path)
|
||||
|
||||
|
||||
|
|
@ -366,6 +370,7 @@ class _ColorText(BoundLineEdit):
|
|||
|
||||
def __init__(self, parent: QWidget, optional: bool):
|
||||
super().__init__(parent)
|
||||
self.setObjectName(SKIP_BINDING)
|
||||
self.optional = optional
|
||||
|
||||
hex_color = qc.pyqtSignal(str)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
SOURCES += view_mainwindow.py
|
||||
TRANSLATIONS += corrscope_xa.ts
|
||||
|
|
@ -0,0 +1,402 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from corrscope.gui.view_stack import (
|
||||
LayoutStack,
|
||||
set_layout,
|
||||
central_widget,
|
||||
append_widget,
|
||||
add_row,
|
||||
add_tab,
|
||||
set_attr_objectName,
|
||||
append_stretch,
|
||||
add_grid_col,
|
||||
Both,
|
||||
set_menu_bar,
|
||||
append_menu,
|
||||
add_toolbar,
|
||||
)
|
||||
|
||||
NBSP = "\xa0"
|
||||
|
||||
|
||||
def fixed_size_policy():
|
||||
return QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||||
|
||||
|
||||
# noinspection PyAttributeOutsideInit
|
||||
class MainWindow(QWidget):
|
||||
@staticmethod
|
||||
def tr(*args, **kwargs) -> str:
|
||||
"""Only at runtime, not at pylupdate5 time."""
|
||||
# noinspection PyCallByClass,PyTypeChecker
|
||||
return QCoreApplication.translate("MainWindow", *args, **kwargs)
|
||||
|
||||
def setupUi(self, MainWindow: QMainWindow):
|
||||
MainWindow.resize(1160, 0)
|
||||
|
||||
s = LayoutStack(MainWindow)
|
||||
|
||||
# Window contents
|
||||
with central_widget(s, QWidget) as self.centralWidget:
|
||||
horizontalLayout = set_layout(s, QHBoxLayout)
|
||||
|
||||
# Left-hand config tabs
|
||||
with append_widget(s, QTabWidget) as self.left_tabs:
|
||||
self.tabGeneral = self.add_general_tab(s)
|
||||
self.tabStereo = self.add_stereo_tab(s)
|
||||
self.tabPerf = self.add_performance_tab(s)
|
||||
|
||||
# Right-hand channel list
|
||||
with append_widget(s, QVBoxLayout) as self.audioColumn:
|
||||
|
||||
# Top bar (master audio, trigger)
|
||||
self.add_top_bar(s)
|
||||
|
||||
# Channel list (group box)
|
||||
self.channelsGroup = self.add_channels_list(s)
|
||||
|
||||
# Right-hand channel list expands to fill space.
|
||||
horizontalLayout.setStretch(1, 1)
|
||||
|
||||
self.add_actions(s, MainWindow)
|
||||
|
||||
# Creates references to labels
|
||||
set_attr_objectName(self, s)
|
||||
|
||||
# Initializes labels by reference
|
||||
self.retranslateUi(MainWindow)
|
||||
self.left_tabs.setCurrentIndex(0)
|
||||
|
||||
# Depends on objectName
|
||||
QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def add_general_tab(self, s: LayoutStack) -> QWidget:
|
||||
tr = self.tr
|
||||
with self._add_tab(s, tr("&General")) as tab:
|
||||
set_layout(s, QVBoxLayout)
|
||||
|
||||
# Global group
|
||||
with append_widget(s, QGroupBox) as self.optionGlobal:
|
||||
set_layout(s, QFormLayout)
|
||||
|
||||
with add_row(s, BoundSpinBox) as self.fps:
|
||||
self.fps.setMinimum(1)
|
||||
self.fps.setMaximum(999)
|
||||
self.fps.setSingleStep(10)
|
||||
|
||||
with add_row(s, BoundSpinBox) as self.trigger_ms:
|
||||
self.trigger_ms.setMinimum(5)
|
||||
self.trigger_ms.setSingleStep(5)
|
||||
|
||||
with add_row(s, BoundSpinBox) as self.render_ms:
|
||||
self.render_ms.setMinimum(5)
|
||||
self.render_ms.setSingleStep(5)
|
||||
|
||||
with add_row(s, BoundDoubleSpinBox) as self.amplification:
|
||||
self.amplification.setSingleStep(0.1)
|
||||
|
||||
with add_row(s, BoundDoubleSpinBox) as self.begin_time:
|
||||
self.begin_time.setMaximum(9999.0)
|
||||
|
||||
with append_widget(s, QGroupBox) as self.optionAppearance:
|
||||
set_layout(s, QFormLayout)
|
||||
|
||||
with add_row(s, BoundLineEdit) as self.render_resolution:
|
||||
pass
|
||||
|
||||
with add_row(s, BoundColorWidget) as self.render__bg_color:
|
||||
pass
|
||||
|
||||
with add_row(s, BoundColorWidget) as self.render__init_line_color:
|
||||
pass
|
||||
|
||||
with add_row(s, BoundDoubleSpinBox) as self.render__line_width:
|
||||
self.render__line_width.setMinimum(0.5)
|
||||
self.render__line_width.setSingleStep(0.5)
|
||||
|
||||
with add_row(s, OptionalColorWidget) as self.render__grid_color:
|
||||
pass
|
||||
|
||||
with add_row(s, OptionalColorWidget) as self.render__midline_color:
|
||||
pass
|
||||
|
||||
with add_row(s, BoundCheckBox, BoundCheckBox) as (
|
||||
self.render__v_midline,
|
||||
self.render__h_midline,
|
||||
):
|
||||
pass
|
||||
|
||||
with append_widget(s, QGroupBox) as self.optionLayout:
|
||||
set_layout(s, QFormLayout)
|
||||
|
||||
with add_row(s, BoundComboBox) as self.layout__orientation:
|
||||
pass
|
||||
|
||||
with add_row(s, QLabel, QHBoxLayout) as (
|
||||
self.layout__ncolsL,
|
||||
self.layoutDims,
|
||||
):
|
||||
with append_widget(s, BoundSpinBox) as self.layout__ncols:
|
||||
self.layout__ncols.setSpecialValueText(NBSP)
|
||||
|
||||
with append_widget(s, QLabel) as self.layout__nrowsL:
|
||||
pass
|
||||
|
||||
with append_widget(s, BoundSpinBox) as self.layout__nrows:
|
||||
self.layout__nrows.setSpecialValueText(NBSP)
|
||||
|
||||
append_stretch(s)
|
||||
|
||||
return tab
|
||||
|
||||
def add_stereo_tab(self, s: LayoutStack) -> QWidget:
|
||||
tr = self.tr
|
||||
with self._add_tab(s, tr("&Stereo")) as tab:
|
||||
set_layout(s, QVBoxLayout)
|
||||
|
||||
with append_widget(s, QGroupBox) as self.optionStereo:
|
||||
set_layout(s, QFormLayout)
|
||||
with add_row(s, BoundComboBox) as self.trigger_stereo:
|
||||
pass
|
||||
|
||||
with add_row(s, BoundComboBox) as self.render_stereo:
|
||||
pass
|
||||
|
||||
with append_widget(s, QGroupBox) as self.dockStereo_2:
|
||||
set_layout(s, QFormLayout)
|
||||
|
||||
with add_row(s, BoundComboBox) as self.layout__stereo_orientation:
|
||||
pass
|
||||
|
||||
with add_row(s, BoundDoubleSpinBox) as (
|
||||
self.render__stereo_grid_opacity
|
||||
):
|
||||
self.render__stereo_grid_opacity.setMaximum(1.0)
|
||||
self.render__stereo_grid_opacity.setSingleStep(0.25)
|
||||
|
||||
append_stretch(s)
|
||||
|
||||
return tab
|
||||
|
||||
def add_performance_tab(self, s: LayoutStack) -> QWidget:
|
||||
tr = self.tr
|
||||
with self._add_tab(s, tr("&Performance")) as tab:
|
||||
set_layout(s, QVBoxLayout)
|
||||
|
||||
with append_widget(s, QGroupBox) as self.perfAll:
|
||||
set_layout(s, QFormLayout)
|
||||
|
||||
with add_row(s, BoundSpinBox) as self.trigger_subsampling:
|
||||
self.trigger_subsampling.setMinimum(1)
|
||||
|
||||
with add_row(s, BoundSpinBox) as self.render_subsampling:
|
||||
self.render_subsampling.setMinimum(1)
|
||||
|
||||
with append_widget(s, QGroupBox) as self.perfPreview:
|
||||
set_layout(s, QFormLayout)
|
||||
|
||||
with add_row(s, BoundSpinBox) as self.render_subfps:
|
||||
self.render_subfps.setMinimum(1)
|
||||
|
||||
with add_row(s, BoundDoubleSpinBox) as self.render__res_divisor:
|
||||
self.render__res_divisor.setMinimum(1.0)
|
||||
self.render__res_divisor.setSingleStep(0.5)
|
||||
|
||||
append_stretch(s)
|
||||
|
||||
return tab
|
||||
|
||||
@staticmethod
|
||||
def _add_tab(s: LayoutStack, label: str = ""):
|
||||
return add_tab(s, QWidget, label)
|
||||
|
||||
def add_top_bar(self, s):
|
||||
with append_widget(s, QHBoxLayout):
|
||||
# Master audio
|
||||
with append_widget(s, QGroupBox) as self.masterAudioGroup:
|
||||
set_layout(s, QHBoxLayout)
|
||||
with append_widget(s, BoundLineEdit) as self.master_audio:
|
||||
pass
|
||||
with append_widget(s, QPushButton) as self.master_audio_browse:
|
||||
pass
|
||||
|
||||
# Trigger config
|
||||
with append_widget(s, QGroupBox) as self.optionAudio:
|
||||
# Prevent expansion (does nothing even if removed :| )
|
||||
self.optionAudio.setSizePolicy(fixed_size_policy())
|
||||
|
||||
set_layout(s, QGridLayout)
|
||||
|
||||
with add_grid_col(s, BoundComboBox) as (self.trigger__edge_direction):
|
||||
pass
|
||||
|
||||
with add_grid_col(s, BoundDoubleSpinBox) as (
|
||||
self.trigger__edge_strength
|
||||
):
|
||||
self.trigger__edge_strength.setMinimum(0.0)
|
||||
|
||||
with add_grid_col(s, BoundDoubleSpinBox) as (
|
||||
self.trigger__responsiveness
|
||||
):
|
||||
self.trigger__responsiveness.setMaximum(1.0)
|
||||
self.trigger__responsiveness.setSingleStep(0.1)
|
||||
|
||||
with add_grid_col(s, BoundDoubleSpinBox) as (
|
||||
self.trigger__buffer_falloff
|
||||
):
|
||||
self.trigger__buffer_falloff.setSingleStep(0.5)
|
||||
|
||||
with add_grid_col(s, BoundCheckBox, Both) as (
|
||||
self.trigger__pitch_tracking
|
||||
):
|
||||
assert isinstance(self.trigger__pitch_tracking, QWidget)
|
||||
|
||||
def add_channels_list(self, s):
|
||||
with append_widget(s, QGroupBox) as group:
|
||||
set_layout(s, QVBoxLayout)
|
||||
|
||||
# Button toolbar
|
||||
with append_widget(s, QHBoxLayout) as self.channelBar:
|
||||
append_stretch(s)
|
||||
|
||||
with append_widget(s, ShortcutButton) as self.channelAdd:
|
||||
pass
|
||||
with append_widget(s, ShortcutButton) as self.channelDelete:
|
||||
pass
|
||||
with append_widget(s, ShortcutButton) as self.channelUp:
|
||||
pass
|
||||
with append_widget(s, ShortcutButton) as self.channelDown:
|
||||
pass
|
||||
|
||||
# Spreadsheet grid
|
||||
with append_widget(s, ChannelTableView) as self.channel_view:
|
||||
pass
|
||||
|
||||
return group
|
||||
|
||||
def add_actions(self, s: LayoutStack, MainWindow):
|
||||
# Setup actions
|
||||
self.actionOpen = QAction(MainWindow)
|
||||
self.actionSave = QAction(MainWindow)
|
||||
self.actionNew = QAction(MainWindow)
|
||||
self.actionSaveAs = QAction(MainWindow)
|
||||
self.actionExit = QAction(MainWindow)
|
||||
self.actionPreview = QAction(MainWindow)
|
||||
self.actionRender = QAction(MainWindow)
|
||||
self.action_separate_render_dir = QAction(MainWindow)
|
||||
self.action_separate_render_dir.setCheckable(True)
|
||||
|
||||
# Setup menu_bar
|
||||
assert s.widget is MainWindow
|
||||
with set_menu_bar(s) as self.menuBar:
|
||||
with append_menu(s) as self.menuFile:
|
||||
self.menuFile.addAction(self.actionNew)
|
||||
self.menuFile.addAction(self.actionOpen)
|
||||
self.menuFile.addAction(self.actionSave)
|
||||
self.menuFile.addAction(self.actionSaveAs)
|
||||
self.menuFile.addSeparator()
|
||||
self.menuFile.addAction(self.actionPreview)
|
||||
self.menuFile.addAction(self.actionRender)
|
||||
self.menuFile.addSeparator()
|
||||
self.menuFile.addAction(self.actionExit)
|
||||
|
||||
with append_menu(s) as self.menuTools:
|
||||
self.menuTools.addAction(self.action_separate_render_dir)
|
||||
|
||||
# Setup toolbar
|
||||
with add_toolbar(s, Qt.TopToolBarArea) as self.toolBar:
|
||||
self.toolBar.addAction(self.actionNew)
|
||||
self.toolBar.addAction(self.actionOpen)
|
||||
self.toolBar.addAction(self.actionSave)
|
||||
self.toolBar.addAction(self.actionSaveAs)
|
||||
self.toolBar.addSeparator()
|
||||
self.toolBar.addAction(self.actionPreview)
|
||||
self.toolBar.addAction(self.actionRender)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def retranslateUi(self, MainWindow):
|
||||
tr = self.tr
|
||||
|
||||
MainWindow.setWindowTitle(tr("MainWindow"))
|
||||
|
||||
self.optionGlobal.setTitle(tr("Global"))
|
||||
self.fpsL.setText(tr("FPS"))
|
||||
self.trigger_msL.setText(tr("Trigger Width"))
|
||||
self.render_msL.setText(tr("Render Width"))
|
||||
self.amplificationL.setText(tr("Amplification"))
|
||||
self.begin_timeL.setText(tr("Begin Time"))
|
||||
self.optionAppearance.setTitle(tr("Appearance"))
|
||||
self.render_resolutionL.setText(tr("Resolution"))
|
||||
self.render_resolution.setText(tr("vs"))
|
||||
self.render__bg_colorL.setText(tr("Background"))
|
||||
self.render__init_line_colorL.setText(tr("Line Color"))
|
||||
self.render__line_widthL.setText(tr("Line Width"))
|
||||
self.render__grid_colorL.setText(tr("Grid Color"))
|
||||
self.render__midline_colorL.setText(tr("Midline Color"))
|
||||
self.render__v_midline.setText(tr("Vertical"))
|
||||
self.render__h_midline.setText(tr("Horizontal Midline"))
|
||||
self.optionLayout.setTitle(tr("Layout"))
|
||||
self.layout__orientationL.setText(tr("Orientation"))
|
||||
self.layout__ncolsL.setText(tr("Columns"))
|
||||
self.layout__nrowsL.setText(tr("Rows"))
|
||||
self.optionStereo.setTitle(tr("Stereo Enable"))
|
||||
self.trigger_stereoL.setText(tr("Trigger Stereo"))
|
||||
self.render_stereoL.setText(tr("Render Stereo"))
|
||||
self.dockStereo_2.setTitle(tr("Stereo Appearance"))
|
||||
self.layout__stereo_orientationL.setText(tr("Stereo Orientation"))
|
||||
self.render__stereo_grid_opacityL.setText(tr("Grid Opacity"))
|
||||
|
||||
self.perfAll.setTitle(tr("Preview and Render"))
|
||||
self.trigger_subsamplingL.setText(tr("Trigger Subsampling"))
|
||||
self.render_subsamplingL.setText(tr("Render Subsampling"))
|
||||
self.perfPreview.setTitle(tr("Preview Only"))
|
||||
self.render_subfpsL.setText(tr("Render FPS Divisor"))
|
||||
self.render__res_divisorL.setText(tr("Resolution Divisor"))
|
||||
self.masterAudioGroup.setTitle(tr("Master Audio"))
|
||||
self.master_audio.setText(tr("/"))
|
||||
self.master_audio_browse.setText(tr("&Browse..."))
|
||||
self.optionAudio.setTitle(tr("Trigger"))
|
||||
self.trigger__edge_strengthL.setText(tr("Edge Strength"))
|
||||
self.trigger__responsivenessL.setText(tr("Responsiveness"))
|
||||
self.trigger__buffer_falloffL.setText(tr("Buffer Falloff"))
|
||||
self.trigger__pitch_tracking.setText(tr("Pitch Tracking"))
|
||||
self.trigger__edge_directionL.setText(tr("Edge Direction"))
|
||||
|
||||
self.channelsGroup.setTitle(tr("Oscilloscope Channels"))
|
||||
self.channelAdd.setText(tr("&Add..."))
|
||||
self.channelDelete.setText(tr("&Delete"))
|
||||
self.channelUp.setText(tr("Up"))
|
||||
self.channelDown.setText(tr("Down"))
|
||||
self.menuFile.setTitle(tr("&File"))
|
||||
self.menuTools.setTitle(tr("&Tools"))
|
||||
self.toolBar.setWindowTitle(tr("toolBar"))
|
||||
self.actionOpen.setText(tr("&Open"))
|
||||
self.actionOpen.setShortcut(tr("Ctrl+O"))
|
||||
self.actionSave.setText(tr("&Save"))
|
||||
self.actionSave.setShortcut(tr("Ctrl+S"))
|
||||
self.actionNew.setText(tr("&New"))
|
||||
self.actionNew.setShortcut(tr("Ctrl+N"))
|
||||
self.actionSaveAs.setText(tr("Save &As"))
|
||||
self.actionSaveAs.setShortcut(tr("Ctrl+Shift+S"))
|
||||
self.actionExit.setText(tr("E&xit"))
|
||||
self.actionExit.setShortcut(tr("Ctrl+Q"))
|
||||
self.actionPreview.setText(tr("&Preview"))
|
||||
self.actionPreview.setShortcut(tr("Ctrl+P"))
|
||||
self.actionRender.setText(tr("&Render to Video"))
|
||||
self.actionRender.setShortcut(tr("Ctrl+R"))
|
||||
self.action_separate_render_dir.setText(tr("&Separate Render Folder"))
|
||||
|
||||
|
||||
from corrscope.gui.__init__ import ChannelTableView, ShortcutButton
|
||||
from corrscope.gui.model_bind import (
|
||||
BoundCheckBox,
|
||||
BoundColorWidget,
|
||||
BoundComboBox,
|
||||
BoundDoubleSpinBox,
|
||||
BoundLineEdit,
|
||||
BoundSpinBox,
|
||||
OptionalColorWidget,
|
||||
)
|
||||
|
|
@ -0,0 +1,280 @@
|
|||
from contextlib import contextmanager
|
||||
from typing import *
|
||||
|
||||
import attr
|
||||
from PyQt5.QtCore import QObject, Qt
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from corrscope.util import obj_name
|
||||
|
||||
T = TypeVar("T")
|
||||
ctx = Iterator
|
||||
SomeQW = TypeVar("SomeQW", bound=QWidget)
|
||||
WidgetOrLayout = TypeVar("WidgetOrLayout", bound=Union[QWidget, QLayout])
|
||||
|
||||
|
||||
def new_widget_or_layout(
|
||||
item_type: Type[WidgetOrLayout], parent: QWidget
|
||||
) -> WidgetOrLayout:
|
||||
"""Creates a widget or layout, for insertion into an existing layout.
|
||||
Do NOT use for filling a widget with a layout!"""
|
||||
if issubclass(item_type, QWidget):
|
||||
right = item_type(parent)
|
||||
else:
|
||||
right = item_type(None)
|
||||
return right
|
||||
|
||||
|
||||
@attr.dataclass
|
||||
class StackFrame:
|
||||
widget: Optional[QWidget]
|
||||
layout: Optional[QLayout] = None
|
||||
|
||||
def with_layout(self, layout: Optional[QLayout]):
|
||||
return attr.evolve(self, layout=layout)
|
||||
|
||||
|
||||
class LayoutStack:
|
||||
def __init__(self, root: Optional[QWidget]):
|
||||
self._items = [StackFrame(root)]
|
||||
self.widget_to_label: Dict[QWidget, QLabel] = {}
|
||||
|
||||
@contextmanager
|
||||
def push(self, item: T) -> ctx[T]:
|
||||
if isinstance(item, StackFrame):
|
||||
frame = item
|
||||
elif isinstance(item, QWidget):
|
||||
frame = StackFrame(item)
|
||||
elif isinstance(item, QLayout):
|
||||
frame = self.peek().with_layout(item)
|
||||
else:
|
||||
raise TypeError(obj_name(item))
|
||||
|
||||
self._items.append(frame)
|
||||
|
||||
try:
|
||||
yield item
|
||||
finally:
|
||||
self._items.pop()
|
||||
|
||||
def peek(self) -> StackFrame:
|
||||
return self._items[-1]
|
||||
|
||||
@property
|
||||
def widget(self):
|
||||
return self.peek().widget
|
||||
|
||||
@property
|
||||
def layout(self):
|
||||
return self.peek().layout
|
||||
|
||||
|
||||
def set_layout(stack: LayoutStack, layout_type: Type[QLayout]) -> QLayout:
|
||||
layout = layout_type(stack.peek().widget)
|
||||
stack.peek().layout = layout
|
||||
return layout
|
||||
|
||||
|
||||
def assert_peek(stack: LayoutStack, cls):
|
||||
assert isinstance(stack.widget, cls)
|
||||
|
||||
|
||||
def central_widget(stack: LayoutStack, widget_type: Type[SomeQW] = QWidget):
|
||||
assert_peek(stack, QMainWindow)
|
||||
# do NOT orphan=True
|
||||
return _add_widget(stack, widget_type, exit_action="setCentralWidget")
|
||||
|
||||
|
||||
def orphan_widget(stack: LayoutStack, widget_type: Type[SomeQW] = QWidget):
|
||||
return _add_widget(stack, widget_type, orphan=True)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def append_widget(
|
||||
stack: LayoutStack, item_type: Type[WidgetOrLayout]
|
||||
) -> ctx[WidgetOrLayout]:
|
||||
with _add_widget(stack, item_type) as item:
|
||||
yield item
|
||||
add_widget_or_layout(stack.layout, item)
|
||||
|
||||
|
||||
# noinspection PyArgumentList
|
||||
def add_widget_or_layout(layout: QLayout, item: WidgetOrLayout, *args, **kwargs):
|
||||
if isinstance(item, QWidget):
|
||||
layout.addWidget(item, *args, **kwargs)
|
||||
elif isinstance(item, QLayout):
|
||||
# QLayout and some subclasses (like QFormLayout) omit this method,
|
||||
# and will crash at runtime.
|
||||
layout.addLayout(item, *args, **kwargs)
|
||||
else:
|
||||
raise TypeError(item)
|
||||
|
||||
|
||||
# Main window toolbars/menus
|
||||
|
||||
|
||||
def set_menu_bar(stack: LayoutStack):
|
||||
assert_peek(stack, QMainWindow)
|
||||
return _add_widget(stack, QMenuBar, exit_action="setMenuBar")
|
||||
|
||||
|
||||
# won't bother adding type hints that pycharm is too dumb to understand
|
||||
def append_menu(stack: LayoutStack):
|
||||
assert_peek(stack, QMenuBar)
|
||||
return _add_widget(stack, QMenu, exit_action="addMenu")
|
||||
|
||||
|
||||
def add_toolbar(stack: LayoutStack, area=Qt.TopToolBarArea):
|
||||
assert_peek(stack, QMainWindow)
|
||||
|
||||
def _add_toolbar(parent: QMainWindow, toolbar):
|
||||
parent.addToolBar(area, toolbar)
|
||||
|
||||
return _add_widget(stack, QToolBar, exit_action=_add_toolbar)
|
||||
|
||||
|
||||
# Implementation
|
||||
|
||||
|
||||
@contextmanager
|
||||
def _add_widget(
|
||||
stack: LayoutStack,
|
||||
item_type: Type[WidgetOrLayout],
|
||||
orphan=False,
|
||||
exit_action: Union[Callable[[Any, Any], Any], str] = "",
|
||||
) -> ctx[WidgetOrLayout]:
|
||||
"""
|
||||
- Constructs item_type using parent.
|
||||
- Yields item_type.
|
||||
"""
|
||||
|
||||
if not orphan:
|
||||
parent = stack.widget
|
||||
else:
|
||||
parent = None
|
||||
|
||||
with stack.push(new_widget_or_layout(item_type, parent)) as item:
|
||||
yield item
|
||||
|
||||
real_parent = stack.widget
|
||||
if callable(exit_action):
|
||||
exit_action(real_parent, item)
|
||||
elif exit_action:
|
||||
getattr(real_parent, exit_action)(item)
|
||||
|
||||
|
||||
def append_stretch(stack: LayoutStack):
|
||||
cast(QBoxLayout, stack.layout).addStretch()
|
||||
|
||||
|
||||
Left = TypeVar("Left", bound=QWidget)
|
||||
Right = TypeVar("Right", bound=Union[QWidget, QLayout]) # same as WidgetOrLayout
|
||||
|
||||
|
||||
Both = object()
|
||||
|
||||
|
||||
def widget_pair_inserter(append_widgets: Callable):
|
||||
@contextmanager
|
||||
def add_row_col(stack: LayoutStack, arg1, arg2=None):
|
||||
left_type: Type[Left]
|
||||
right_type: Type[Right]
|
||||
if arg2 is None:
|
||||
left_type, right_type = QLabel, arg1
|
||||
auto_left_label = True
|
||||
else:
|
||||
left_type, right_type = arg1, arg2
|
||||
auto_left_label = False
|
||||
|
||||
parent = stack.widget
|
||||
left = new_widget_or_layout(left_type, parent) # TODO support str
|
||||
|
||||
if right_type is Both:
|
||||
right = Both
|
||||
push = left
|
||||
else:
|
||||
right = new_widget_or_layout(right_type, parent)
|
||||
push = right
|
||||
|
||||
with stack.push(push):
|
||||
if right is Both:
|
||||
yield left
|
||||
elif auto_left_label:
|
||||
yield right
|
||||
else:
|
||||
yield left, right
|
||||
|
||||
append_widgets(stack.layout, left, right)
|
||||
if auto_left_label:
|
||||
assert isinstance(left, QLabel)
|
||||
stack.widget_to_label[right] = left
|
||||
|
||||
return add_row_col
|
||||
|
||||
|
||||
def _add_row(layout: QFormLayout, left, right):
|
||||
assert isinstance(layout, QFormLayout), layout
|
||||
if right is Both:
|
||||
raise TypeError("Cannot add_row(QFormLayout, span=Both)")
|
||||
return layout.addRow(left, right)
|
||||
|
||||
|
||||
add_row = widget_pair_inserter(_add_row)
|
||||
|
||||
|
||||
def _add_grid_col(layout: QGridLayout, up, down):
|
||||
assert isinstance(layout, QGridLayout), layout
|
||||
col = layout.columnCount()
|
||||
|
||||
"""
|
||||
void QGridLayout::addWidget(
|
||||
QWidget *widget,
|
||||
int fromRow, int fromColumn, [int rowSpan, int columnSpan],
|
||||
Qt::Alignment alignment = Qt::Alignment()
|
||||
)
|
||||
"""
|
||||
if down is Both:
|
||||
shape = lambda: [0, col, -1, 1]
|
||||
add_widget_or_layout(layout, up, *shape())
|
||||
else:
|
||||
shape = lambda row: [row, col]
|
||||
add_widget_or_layout(layout, up, *shape(0))
|
||||
add_widget_or_layout(layout, down, *shape(1))
|
||||
|
||||
|
||||
add_grid_col = widget_pair_inserter(_add_grid_col)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def add_tab(stack, widget_type: Type[SomeQW] = QWidget, label: str = "") -> ctx[SomeQW]:
|
||||
"""
|
||||
- Constructs widget using parent.
|
||||
- Yields widget.
|
||||
"""
|
||||
tabs: QTabWidget = stack.widget
|
||||
assert isinstance(tabs, QTabWidget), tabs
|
||||
|
||||
with orphan_widget(stack, widget_type) as w:
|
||||
yield w
|
||||
tabs.addTab(w, label)
|
||||
|
||||
|
||||
# After building a tree...
|
||||
def set_attr_objectName(ui, stack: LayoutStack):
|
||||
"""
|
||||
- Set objectName of all objects referenced by ui.
|
||||
- For all object $name added by add_row() or add_grid_col(),
|
||||
if $label was generated but not yielded
|
||||
setattr(ui.$name + "L" = $label)
|
||||
"""
|
||||
widget_to_label = stack.widget_to_label
|
||||
|
||||
for name, obj in dict(ui.__dict__).items():
|
||||
if not isinstance(obj, QObject):
|
||||
continue
|
||||
obj.setObjectName(name)
|
||||
if obj in widget_to_label:
|
||||
label = widget_to_label[obj]
|
||||
label_name = name + "L"
|
||||
label.setObjectName(label_name)
|
||||
ui.__dict__[label_name] = label
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import pytest
|
||||
|
||||
from corrscope.gui.data_bind import rgetattr, rsetattr, rhasattr, flatten_attr
|
||||
from corrscope.gui.model_bind import rgetattr, rsetattr, rhasattr, flatten_attr
|
||||
|
||||
|
||||
class Person(object):
|
||||
Ładowanie…
Reference in New Issue