Browse Source

Split up sheet_view.py. Cleanup a bunch of imports

looper
Ben Niemann 6 years ago
parent
commit
ebcdd6af32
  1. 379
      noisicaa/ui/base_track_item.py
  2. 329
      noisicaa/ui/beat_track_item.py
  3. 49
      noisicaa/ui/dock_widget.py
  4. 28
      noisicaa/ui/editor_app.py
  5. 6
      noisicaa/ui/editor_window.py
  6. 17
      noisicaa/ui/flowlayout.py
  7. 3
      noisicaa/ui/instrument_library.py
  8. 2
      noisicaa/ui/model.py
  9. 16
      noisicaa/ui/piano_test.py
  10. 3
      noisicaa/ui/pipeline_graph_monitor.py
  11. 1
      noisicaa/ui/pipeline_graph_view.py
  12. 1
      noisicaa/ui/project_view.py
  13. 12
      noisicaa/ui/project_view_test.py
  14. 88
      noisicaa/ui/render_sheet_dialog.py
  15. 1
      noisicaa/ui/render_sheet_dialog_test.py
  16. 805
      noisicaa/ui/score_track_item.py
  17. 1
      noisicaa/ui/settings.py
  18. 159
      noisicaa/ui/sheet_property_track_item.py
  19. 1653
      noisicaa/ui/sheet_view.py
  20. 14
      noisicaa/ui/sheet_view_test.py
  21. 4
      noisicaa/ui/svg_symbol_filetest.py
  22. 40
      noisicaa/ui/tool_dock.py
  23. 3
      noisicaa/ui/track_properties_dock.py
  24. 1
      noisicaa/ui/tracks_dock.py
  25. 3
      noisicaa/ui/tracks_dock_test.py
  26. 9
      noisicaa/ui/ui_process.py
  27. 15
      noisicaa/ui/uitest_utils.py

379
noisicaa/ui/base_track_item.py

@ -0,0 +1,379 @@
#!/usr/bin/python3
import logging
import enum
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from .misc import QGraphicsGroup
logger = logging.getLogger(__name__)
class Layer(enum.IntEnum):
BG = 0
MAIN = 1
DEBUG = 2
EDIT = 3
MOUSE = 4
EVENTS = 5
NUM_LAYERS = 6
class MeasureLayout(object):
def __init__(self):
self.size = QtCore.QSize()
self.baseline = 0
@property
def is_valid(self):
return self.width > 0 and self.height > 0
@property
def width(self):
return self.size.width()
@width.setter
def width(self, value):
self.size.setWidth(value)
@property
def height(self):
return self.size.height()
@height.setter
def height(self, value):
self.size.setHeight(value)
@property
def extend_above(self):
return self.baseline
@property
def extend_below(self):
return self.height - self.baseline
def __eq__(self, other):
assert isinstance(other, MeasureLayout)
return (self.size == other.size) and (self.baseline == other.baseline)
class MeasureItemImpl(QtWidgets.QGraphicsItem):
def __init__(self, sheet_view, track_item, measure_reference, **kwargs):
super().__init__(**kwargs)
self._sheet_view = sheet_view
self._track_item = track_item
self._measure_reference = measure_reference
if self._measure_reference is not None:
self._measure = measure_reference.measure
self._measure_listener = self._measure_reference.listeners.add(
'measure_id', self.measureChanged)
else:
self._measure = None
self._measure_listener = None
self._layout = None
self._layers = {}
self._layers[Layer.BG] = QGraphicsGroup()
self._background = QtWidgets.QGraphicsRectItem(self._layers[Layer.BG])
self._background.setPen(QtGui.QPen(Qt.NoPen))
self._background.setBrush(QtGui.QColor(240, 240, 255))
self._background.setVisible(False)
self._selected = False
@property
def measure(self):
return self._measure
@property
def measure_reference(self):
return self._measure_reference
@property
def track_item(self):
return self._track_item
def boundingRect(self):
return QtCore.QRectF(0, 0, self._layout.width, self._layout.height)
def paint(self, painter, option, widget=None):
pass
def close(self):
if self._measure_listener is not None:
self._measure_listener.remove()
def measureChanged(self, old_value, new_value):
self._measure = self._measure_reference.measure
self.recomputeLayout()
def recomputeLayout(self):
layout = self.computeLayout()
if layout != self._layout:
self._sheet_view.updateSheet()
else:
self.updateMeasure()
def computeLayout(self):
raise NotImplementedError
def setLayout(self, layout):
self._layout = layout
def updateMeasure(self):
pass
@property
def layers(self):
return sorted(self._layers.keys())
def getLayer(self, layer_id):
return self._layers.get(layer_id, None)
def width(self):
return self._layout.width
def buildContextMenu(self, menu):
insert_measure_action = QtWidgets.QAction(
"Insert measure", menu,
statusTip="Insert an empty measure at this point.",
triggered=self.onInsertMeasure)
menu.addAction(insert_measure_action)
remove_measure_action = QtWidgets.QAction(
"Remove measure", menu,
statusTip="Remove this measure.",
triggered=self.onRemoveMeasure)
menu.addAction(remove_measure_action)
def contextMenuEvent(self, event):
menu = QtWidgets.QMenu()
self._track_item.buildContextMenu(menu)
self.buildContextMenu(menu)
menu.exec_(event.screenPos())
event.accept()
def onInsertMeasure(self):
self.send_command_async(
self._sheet_view.sheet.id, 'InsertMeasure',
tracks=[self._measure.track.index],
pos=self._measure_reference.index)
def onRemoveMeasure(self):
self.send_command_async(
self._sheet_view.sheet.id, 'RemoveMeasure',
tracks=[self._measure.track.index],
pos=self._measure_reference.index)
def mousePressEvent(self, event):
if event.modifiers() == Qt.ControlModifier:
if self.selected():
self._sheet_view.removeFromSelection(self)
else:
self._sheet_view.clearSelection()
self._sheet_view.addToSelection(self)
event.accept()
return
return super().mousePressEvent(event)
def clearPlaybackPos(self):
pass
def setPlaybackPos(
self, sample_pos, num_samples, start_tick, end_tick, first):
pass
def setSelected(self, selected):
if selected != self._selected:
self._selected = selected
self._background.setVisible(self._selected)
self.updateMeasure()
def selected(self):
return self._selected
async def getCopy(self):
return {'class': type(self._measure).__name__,
'id': self._measure.id,
'data': await self.project_client.serialize(self._measure.id) }
class TrackItemImpl(object):
measure_item_cls = None
def __init__(self, sheet_view, track, **kwargs):
super().__init__(**kwargs)
self._sheet_view = sheet_view
self._track = track
self._instrument_selector = None
self._prev_note_highlight = None
self._prev_playback_measures = set()
self._measures = []
for mref in self._track.measure_list:
measure_item = self.measure_item_cls( # pylint: disable=not-callable
**self.context, sheet_view=self._sheet_view,
track_item=self, measure_reference=mref)
self._measures.append(measure_item)
self._ghost_measure_item = self.measure_item_cls( # pylint: disable=not-callable
**self.context, sheet_view=self._sheet_view,
track_item=self, measure_reference=None)
self._listeners = [
self._track.listeners.add('name', self.onNameChanged),
self._track.listeners.add(
'measure_list', self.onMeasureListChanged),
self._track.listeners.add('muted', self.onMutedChanged),
self._track.listeners.add('volume', self.onVolumeChanged),
self._track.listeners.add('visible', self.onVisibleChanged),
]
def close(self):
for listener in self._listeners:
listener.remove()
while len(self._measures) > 0:
measure = self._measures.pop(0)
if measure.selected():
self._sheet_view.removeFromSelection(
measure, update_object=False)
measure.close()
self._ghost_measure_item.close()
self._ghost_measure_item = None
@property
def track(self):
return self._track
@property
def measures(self):
return self._measures + [self._ghost_measure_item]
def removeMeasure(self, idx):
measure = self._measures[idx]
if measure.selected():
self._sheet_view.removeFromSelection(measure, update_object=False)
measure.close()
del self._measures[idx]
def onMeasureListChanged(self, action, *args):
if action == 'insert':
idx, measure_reference = args
measure_item = self.measure_item_cls( # pylint: disable=not-callable
**self.context, sheet_view=self._sheet_view,
track_item=self, measure_reference=measure_reference)
self._measures.insert(idx, measure_item)
self._sheet_view.updateSheet()
elif action == 'delete':
idx, measure_reference = args
self.removeMeasure(idx)
self._sheet_view.updateSheet()
else:
raise ValueError("Unknown action %r" % action)
def onNameChanged(self, old_name, new_name):
# TODO: only update the first measure.
self._sheet_view.updateSheet()
def onMutedChanged(self, old_value, new_value):
pass # TODO
def onVolumeChanged(self, old_value, new_value):
pass # TODO
def onVisibleChanged(self, old_value, new_value):
self._sheet_view.updateSheet()
def buildContextMenu(self, menu):
track_properties_action = QtWidgets.QAction(
"Edit track properties...", menu,
statusTip="Edit the properties of this track.",
triggered=self.onTrackProperties)
menu.addAction(track_properties_action)
remove_track_action = QtWidgets.QAction(
"Remove track", menu,
statusTip="Remove this track.",
triggered=self.onRemoveTrack)
menu.addAction(remove_track_action)
def onRemoveTrack(self):
self.send_command_async(
self._track.parent.id, 'RemoveTrack',
track=self._track.index)
def onTrackProperties(self):
dialog = QtWidgets.QDialog()
dialog.setWindowTitle("Track Properties")
name = QtWidgets.QLineEdit(dialog)
name.setText(self._track.name)
form_layout = QtWidgets.QFormLayout()
form_layout.addRow("Name", name)
close = QtWidgets.QPushButton("Close")
close.clicked.connect(dialog.close)
buttons = QtWidgets.QHBoxLayout()
buttons.addStretch(1)
buttons.addWidget(close)
layout = QtWidgets.QVBoxLayout()
layout.addLayout(form_layout)
layout.addLayout(buttons)
dialog.setLayout(layout)
ret = dialog.exec_()
self.send_command_async(
self._track.id, 'UpdateTrackProperties',
name=name.text())
def setPlaybackPos(
self, sample_pos, num_samples, start_measure_idx,
start_measure_tick, end_measure_idx, end_measure_tick):
playback_measures = set()
measure_idx = start_measure_idx
first = True
while True:
measure_item = self.measures[measure_idx]
if measure_idx == start_measure_idx:
start_tick = start_measure_tick
else:
start_tick = 0
if measure_idx == end_measure_idx:
end_tick = end_measure_tick
else:
end_tick = measure_item.measure.duration.ticks
measure_item.setPlaybackPos(
sample_pos, num_samples, start_tick, end_tick, first)
playback_measures.add(measure_idx)
if measure_idx == end_measure_idx:
break
measure_idx = (measure_idx + 1) % len(self._track.measure_list)
first = False
for measure_idx in self._prev_playback_measures - playback_measures:
self.measures[measure_idx].clearPlaybackPos()
self._prev_playback_measures = playback_measures
def onPasteMeasuresAsLink(self, data):
print(data)

329
noisicaa/ui/beat_track_item.py

@ -0,0 +1,329 @@
#!/usr/bin/python3
import logging
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from noisicaa import audioproc
from noisicaa import music
from .misc import QGraphicsGroup
from . import ui_base
from . import base_track_item
logger = logging.getLogger(__name__)
class BeatMeasureLayout(base_track_item.MeasureLayout):
pass
class BeatMeasureItemImpl(base_track_item.MeasureItemImpl):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._ghost_beat = None
self._layers[base_track_item.Layer.MAIN] = QGraphicsGroup()
self._layers[base_track_item.Layer.EVENTS] = QGraphicsGroup()
self._layers[base_track_item.Layer.EDIT] = QGraphicsGroup()
self.setAcceptHoverEvents(True)
self._measure_listeners = []
if self._measure is not None:
self.addMeasureListeners()
self.playback_pos = QtWidgets.QGraphicsLineItem(
self._layers[base_track_item.Layer.EVENTS])
self.playback_pos.setVisible(False)
self.playback_pos.setLine(0, 0, 0, 20)
pen = QtGui.QPen(Qt.black)
pen.setWidth(3)
self.playback_pos.setPen(pen)
def close(self):
super().close()
for listener in self._measure_listeners:
listener.remove()
self._measure_listeners.clear()
def addMeasureListeners(self):
self._measure_listeners.append(self._measure.listeners.add(
'beats-changed', lambda *args: self.recomputeLayout()))
self._measure_listeners.append(self._measure.listeners.add(
'beats', lambda *args: self.recomputeLayout()))
def measureChanged(self, old_value, new_value):
super().measureChanged(old_value, new_value)
for listener in self._measure_listeners:
listener.remove()
self._measure_listeners.clear()
self.addMeasureListeners()
def computeLayout(self):
width = 100
height_above = 30
height_below = 30
layout = BeatMeasureLayout()
layout.size = QtCore.QSize(width, height_above + height_below)
layout.baseline = height_above
return layout
def updateMeasure(self):
assert self._layout.width > 0 and self._layout.height > 0
self._background.setRect(0, 0, self._layout.width, self._layout.height)
layer = self._layers[base_track_item.Layer.MAIN]
self._sheet_view.clearLayer(layer)
is_first = (
self._measure_reference is not None
and self._measure_reference.index == 0)
if self._measure is not None:
black = Qt.black
else:
black = QtGui.QColor(200, 200, 200)
line = QtWidgets.QGraphicsLineItem(layer)
line.setLine(0, self._layout.baseline,
self._layout.width, self._layout.baseline)
line.setPen(black)
if self._measure is not None:
line = QtWidgets.QGraphicsLineItem(layer)
line.setLine(0, 0, 0, self._layout.height)
line.setPen(black)
if self._measure_reference.is_last:
line = QtWidgets.QGraphicsLineItem(layer)
line.setLine(
self._layout.width, 0,
self._layout.width, self._layout.height)
line.setPen(black)
for i in range(1, 8 * self._measure.time_signature.upper):
x = int(i * self._layout.width / (8 * self._measure.time_signature.upper))
if i % 8 == 0:
h = 10
elif i % 4 == 0:
h = 4
else:
h = 2
tick = QtWidgets.QGraphicsLineItem(layer)
tick.setLine(x, self._layout.baseline - h,
x, self._layout.baseline + h)
tick.setPen(black)
line = QtWidgets.QGraphicsLineItem(layer)
line.setLine(0, self._layout.baseline - 20,
0, self._layout.baseline)
line.setPen(black)
if is_first:
text = QtWidgets.QGraphicsSimpleTextItem(
layer)
text.setText("> %s" % self._measure.track.name)
text.setPos(0, 0)
for beat in self._measure.beats:
assert 0 <= beat.timepos < self._measure.duration
pos = int(
self._layout.width
* beat.timepos
/ self._measure.duration)
beat_vel = QtWidgets.QGraphicsRectItem(layer)
beat_vel.setRect(0, 0, 4, 22 * beat.velocity / 127)
beat_vel.setPen(QtGui.QPen(Qt.NoPen))
beat_vel.setBrush(QtGui.QColor(255, 200, 200))
beat_vel.setPos(pos + 2, self._layout.baseline + 8)
beat_path = QtGui.QPainterPath()
beat_path.moveTo(0, -12)
beat_path.lineTo(0, 12)
beat_path.lineTo(8, 0)
beat_path.closeSubpath()
beat_item = QtWidgets.QGraphicsPathItem(layer)
beat_item.setPath(beat_path)
beat_item.setPen(QtGui.QPen(Qt.NoPen))
beat_item.setBrush(black)
beat_item.setPos(pos, self._layout.baseline)
def setGhost(self):
if self._ghost_beat is not None:
return
self.removeGhost()
layer = self._layers[base_track_item.Layer.EDIT]
self._ghost_beat = QtWidgets.QGraphicsRectItem(layer)
self._ghost_beat.setRect(0, -30, 8, 50)
self._ghost_beat.setBrush(Qt.black)
self._ghost_beat.setPen(QtGui.QPen(Qt.NoPen))
self._ghost_beat.setOpacity(0.2)
def removeGhost(self):
if self._ghost_beat is not None:
self._ghost_beat.setParentItem(None)
if self._ghost_beat.scene() is not None:
self.scene().removeItem(self._ghost_beat)
self._ghost_beat = None
def hoverEnterEvent(self, event):
super().hoverEnterEvent(event)
self.grabMouse()
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
if not self.boundingRect().contains(event.pos()):
self._track_item.playNoteOff()
self._sheet_view.setInfoMessage('')
self.removeGhost()
self.ungrabMouse()
return
if self._measure is None:
return
self.setGhost()
ghost_timepos = music.Duration(
int(8 * self._measure.time_signature.upper
* event.pos().x() / self._layout.width),
8 * self._measure.time_signature.upper)
self._ghost_beat.setPos(
int(self._layout.width * ghost_timepos / self._measure.duration),
self._layout.baseline)
def mousePressEvent(self, event):
if (self._measure is None
and event.button() == Qt.LeftButton
and event.modifiers() == Qt.NoModifier):
self.send_command_async(
self._sheet_view.sheet.id,
'InsertMeasure', tracks=[], pos=-1)
event.accept()
return
if self._layout.width <= 0 or self._layout.height <= 0:
logger.warning("mousePressEvent without valid layout.")
return
if (event.button() == Qt.LeftButton
and event.modifiers() == Qt.NoModifier):
click_timepos = music.Duration(
int(8 * self._measure.time_signature.upper
* event.pos().x() / self._layout.width),
8 * self._measure.time_signature.upper)
for beat in self._measure.beats:
if beat.timepos == click_timepos:
self.send_command_async(
self._measure.id, 'RemoveBeat', beat_id=beat.id)
event.accept()
return
self.send_command_async(
self._measure.id, 'AddBeat', timepos=click_timepos)
self._track_item.playNoteOn(self._measure.track.pitch)
event.accept()
return
return super().mousePressEvent(event)
def wheelEvent(self, event):
if self._measure is not None:
if self._layout.width <= 0 or self._layout.height <= 0:
logger.warning("mousePressEvent without valid layout.")
return
if event.modifiers() in (Qt.NoModifier, Qt.ShiftModifier):
if event.modifiers() == Qt.ShiftModifier:
vel_delta = (1 if event.delta() > 0 else -1)
else:
vel_delta = (10 if event.delta() > 0 else -10)
click_timepos = music.Duration(
int(8 * self._measure.time_signature.upper
* event.pos().x() / self._layout.width),
8 * self._measure.time_signature.upper)
for beat in self._measure.beats:
if beat.timepos == click_timepos:
self.send_command_async(
beat.id, 'SetBeatVelocity',
velocity=max(0, min(127, beat.velocity + vel_delta)))
event.accept()
return
return super().wheelEvent(event)
def buildContextMenu(self, menu):
super().buildContextMenu(menu)
def clearPlaybackPos(self):
self.playback_pos.setVisible(False)
def setPlaybackPos(
self, sample_pos, num_samples, start_tick, end_tick, first):
if first:
assert 0 <= start_tick < self._measure.duration.ticks
assert self._layout.width > 0 and self._layout.height > 0
pos = (
self._layout.width
* start_tick
/ self._measure.duration.ticks)
self.playback_pos.setPos(pos, 0)
self.playback_pos.setVisible(True)
class BeatMeasureItem(ui_base.ProjectMixin, BeatMeasureItemImpl):
pass
class BeatTrackItemImpl(base_track_item.TrackItemImpl):
measure_item_cls = BeatMeasureItem
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._play_last_pitch = None
def playNoteOn(self, pitch):
self.playNoteOff()
self.call_async(
self._sheet_view.audioproc_client.add_event(
'sheet:%s/track:%s' % (
self._sheet_view.sheet.id,
self.track.id),
audioproc.NoteOnEvent(-1, pitch)))
self._play_last_pitch = pitch
def playNoteOff(self):
if self._play_last_pitch is not None:
self.call_async(
self._sheet_view.audioproc_client.add_event(
'sheet:%s/track:%s' % (
self._sheet_view.sheet.id,
self.track.id),
audioproc.NoteOffEvent(-1, self._play_last_pitch)))
self._play_last_pitch = None
class BeatTrackItem(ui_base.ProjectMixin, BeatTrackItemImpl):
pass

49
noisicaa/ui/dock_widget.py

@ -2,16 +2,17 @@
import logging
from PyQt5.QtCore import Qt, QSize, QMargins
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QDockWidget, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QToolButton, QLayout
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from . import ui_base
logger = logging.getLogger(__name__)
class DockWidget(ui_base.CommonMixin, QDockWidget):
class DockWidget(ui_base.CommonMixin, QtWidgets.QDockWidget):
def __init__(self, title, identifier,
allowed_areas=Qt.AllDockWidgetAreas,
initial_area=Qt.RightDockWidgetArea,
@ -33,37 +34,37 @@ class DockWidget(ui_base.CommonMixin, QDockWidget):
self.parent()._view_menu.addAction(self.toggleViewAction())
name = QLabel(self, textFormat=Qt.PlainText)
name = QtWidgets.QLabel(self, textFormat=Qt.PlainText)
name.setText(self.windowTitle())
#self.windowTitleChanged.connect(name.setText)
self.hide_button = QToolButton(
icon=QIcon.fromTheme('list-remove'),
self.hide_button = QtWidgets.QToolButton(
icon=QtGui.QIcon.fromTheme('list-remove'),
autoRaise=True,
focusPolicy=Qt.NoFocus)
self.hide_button.clicked.connect(self.toggleHide)
self.float_button = QToolButton(
icon=QIcon.fromTheme('view-fullscreen'),
self.float_button = QtWidgets.QToolButton(
icon=QtGui.QIcon.fromTheme('view-fullscreen'),
checkable=True,
autoRaise=True,
focusPolicy=Qt.NoFocus)
self.float_button.toggled.connect(self.setFloating)
self.close_button = QToolButton(
icon=QIcon.fromTheme('window-close'),
self.close_button = QtWidgets.QToolButton(
icon=QtGui.QIcon.fromTheme('window-close'),
autoRaise=True,
focusPolicy=Qt.NoFocus)
self.close_button.clicked.connect(lambda: self.setVisible(False))
layout = QHBoxLayout()
layout.setContentsMargins(QMargins(0, 0, 0, 0))
layout = QtWidgets.QHBoxLayout()
layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
layout.addWidget(self.hide_button)
layout.addWidget(name, 1)
layout.addWidget(self.float_button)
layout.addWidget(self.close_button)
self.titlebar = QWidget(self)
self.titlebar = QtWidgets.QWidget(self)
self.titlebar.setLayout(layout)
self.setTitleBarWidget(self.titlebar)
@ -73,14 +74,14 @@ class DockWidget(ui_base.CommonMixin, QDockWidget):
self.topLevelChanged.connect(self.onTopLevelChanged)
self.main_widget = None
self.filler = QWidget(self)
self.filler = QtWidgets.QWidget(self)
self.main_layout = QVBoxLayout()
self.main_layout.setContentsMargins(QMargins(0, 0, 0, 0))
self.main_layout.setSizeConstraint(QLayout.SetMinAndMaxSize)
self.main_layout = QtWidgets.QVBoxLayout()
self.main_layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
self.main_layout.setSizeConstraint(QtWidgets.QLayout.SetMinAndMaxSize)
self.main_layout.addWidget(self.filler)
top_widget = QWidget(self)
top_widget = QtWidgets.QWidget(self)
top_widget.setLayout(self.main_layout)
super().setWidget(top_widget)
@ -102,20 +103,20 @@ class DockWidget(ui_base.CommonMixin, QDockWidget):
if top_level:
if self.widget() is not None:
self.widget().show()
self.hide_button.setIcon(QIcon.fromTheme('list-remove'))
self.hide_button.setIcon(QtGui.QIcon.fromTheme('list-remove'))
def onFeaturesChanged(self, features):
self.float_button.setVisible(
features & QDockWidget.DockWidgetFloatable != 0)
features & QtWidgets.QDockWidget.DockWidgetFloatable != 0)
self.close_button.setVisible(
features & QDockWidget.DockWidgetClosable != 0)
features & QtWidgets.QDockWidget.DockWidgetClosable != 0)
def toggleHide(self):
if self.main_widget.isHidden():
self.filler.hide()
self.main_widget.show()
self.hide_button.setIcon(QIcon.fromTheme('list-remove'))
self.hide_button.setIcon(QtGui.QIcon.fromTheme('list-remove'))
else:
self.main_widget.hide()
self.filler.show()
self.hide_button.setIcon(QIcon.fromTheme('list-add'))
self.hide_button.setIcon(QtGui.QIcon.fromTheme('list-add'))

28
noisicaa/ui/editor_app.py

@ -5,19 +5,11 @@ import os
import sys
import traceback
from PyQt5.QtCore import QSettings, QByteArray
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import (
QAction,
QMessageBox,
QApplication,
QStyleFactory,
QFileDialog,
)
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from noisicaa import audioproc
from noisicaa import node_db
from noisicaa import music
from noisicaa import devices
from ..exceptions import RestartAppException, RestartAppCleanException
from ..constants import EXIT_EXCEPTION, EXIT_RESTART, EXIT_RESTART_CLEAN
@ -87,7 +79,7 @@ class NodeDBClient(node_db.NodeDBClientMixin, NodeDBClientImpl):
pass
class BaseEditorApp(QApplication):
class BaseEditorApp(QtWidgets.QApplication):
def __init__(self, process, runtime_settings, settings=None):
super().__init__(['noisicaä'])
@ -96,7 +88,7 @@ class BaseEditorApp(QApplication):
self.runtime_settings = runtime_settings
if settings is None:
settings = QSettings('odahoda.de', 'noisicaä')
settings = QtCore.QSettings('odahoda.de', 'noisicaä')
if runtime_settings.start_clean:
settings.clear()
self.settings = settings
@ -118,7 +110,7 @@ class BaseEditorApp(QApplication):
style_name = self.settings.value('appearance/qtStyle', '')
if style_name:
style = QStyleFactory.create(style_name)
style = QtWidgets.QStyleFactory.create(style_name)
self.setStyle(style)
await self.createNodeDB()
@ -131,7 +123,7 @@ class BaseEditorApp(QApplication):
self.midi_hub = self.createMidiHub()
self.midi_hub.start()
self.show_edit_areas_action = QAction(
self.show_edit_areas_action = QtWidgets.QAction(
"Show Edit Areas", self,
checkable=True,
triggered=self.onShowEditAreasChanged)
@ -184,7 +176,7 @@ class BaseEditorApp(QApplication):
def dumpSettings(self):
for key in self.settings.allKeys():
value = self.settings.value(key)
if isinstance(value, (bytes, QByteArray)):
if isinstance(value, (bytes, QtCore.QByteArray)):
value = '[%d bytes]' % len(value)
logger.info('%s: %s', key, value)
@ -342,12 +334,12 @@ class EditorApp(BaseEditorApp):
logger.error('%s: %s', title, msg)
try:
errorbox = QMessageBox()
errorbox = QtWidgets.QMessageBox()
errorbox.setWindowTitle("noisicaä crashed")
errorbox.setText(title)
errorbox.setInformativeText(msg)
errorbox.setIcon(QMessageBox.Critical)
errorbox.addButton("Exit", QMessageBox.AcceptRole)
errorbox.setIcon(QtWidgets.QMessageBox.Critical)
errorbox.addButton("Exit", QtWidgets.QMessageBox.AcceptRole)
errorbox.exec_()
except:
logger.error(

6
noisicaa/ui/editor_window.py

@ -7,22 +7,16 @@
import logging
import textwrap
import pprint
import os.path
import enum
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from noisicaa import music
from ..exceptions import RestartAppException, RestartAppCleanException
from .command_shell import CommandShell
from .settings import SettingsDialog
from .project_view import ProjectView
from .instrument_library import InstrumentLibraryDialog
from .flowlayout import FlowLayout
from ..constants import DATA_DIR
from .dock_widget import DockWidget
from .tool_dock import ToolsDockWidget
from .tracks_dock import TracksDockWidget

17
noisicaa/ui/flowlayout.py

@ -1,11 +1,11 @@
import functools
from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtWidgets import QLayout, QSizePolicy
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
from PyQt5 import QtWidgets
class FlowLayout(QLayout):
class FlowLayout(QtWidgets.QLayout):
def __init__(self, parent=None, margin=0, spacing=-1):
super().__init__(parent)
@ -47,7 +47,7 @@ class FlowLayout(QLayout):
@functools.lru_cache(10)
def heightForWidth(self, width):
height = self.doLayout(QRect(0, 0, width, 0), True)
height = self.doLayout(QtCore.QRect(0, 0, width, 0), True)
return height
def invalidate(self):
@ -62,13 +62,13 @@ class FlowLayout(QLayout):
return self.minimumSize()
def minimumSize(self):
size = QSize()
size = QtCore.QSize()
for item in self.itemList:
size = size.expandedTo(item.minimumSize())
margin, _, _, _ = self.getContentsMargins()
size += QSize(2 * margin, 2 * margin)
size += QtCore.QSize(2 * margin, 2 * margin)
return size
def doLayout(self, rect, testOnly):
@ -88,7 +88,8 @@ class FlowLayout(QLayout):
lineHeight = 0
if not testOnly:
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
item.setGeometry(
QtCore.QRect(QtCore.QPoint(x, y), item.sizeHint()))
x = nextX
lineHeight = max(lineHeight, item.sizeHint().height())

3
noisicaa/ui/instrument_library.py

@ -6,15 +6,12 @@
import asyncio
import logging
import os.path
from PyQt5.QtCore import Qt
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from .piano import PianoWidget
from ..constants import DATA_DIR
from . import ui_base
from ..instr import library

2
noisicaa/ui/model.py

@ -2,8 +2,6 @@
import logging
from noisicaa import core
from noisicaa import node_db
from noisicaa.music import model
from noisicaa.music import project_client

16
noisicaa/ui/piano_test.py

@ -1,19 +1,11 @@
#/usr/bin/python3
import unittest
from unittest import mock
from PyQt5.QtCore import Qt, QEvent
from PyQt5.QtGui import QFocusEvent, QKeyEvent
if __name__ == '__main__':
import pyximport
pyximport.install()
from noisicaa import devices
from noisicaa import music
from . import uitest_utils
from . import piano
# from noisicaa import devices
# from noisicaa import music
# from . import uitest_utils
# from . import piano
# class PianoTest(uitest_utils.UITest):

3
noisicaa/ui/pipeline_graph_monitor.py

@ -1,9 +1,7 @@
#!/usr/bin/python
import logging
import math
import random
import time
import toposort
@ -13,7 +11,6 @@ from PyQt5 import QtGui
from PyQt5 import QtWidgets
from noisicaa import audioproc
from noisicaa import core
from noisicaa.core import ipc
from . import ui_base

1
noisicaa/ui/pipeline_graph_view.py

@ -11,7 +11,6 @@ from PyQt5 import QtWidgets
from noisicaa import music
from noisicaa import node_db
from noisicaa.audioproc import node_types
from . import ui_base
from . import dock_widget
from . import mute_button

1
noisicaa/ui/project_view.py

@ -7,7 +7,6 @@ from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from noisicaa import music
from . import pipeline_graph_view
from . import sheet_view
from . import tool_dock

12
noisicaa/ui/project_view_test.py

@ -1,23 +1,21 @@
#!/usr/bin/python3
import unittest
from unittest import mock
from PyQt5 import QtGui
from . import uitest_utils
from . import tool_dock
from . import sheet_view
from . import project_view
from . import model
from . import sheet_property_track_item
class SheetPropertyMeasureItem(
uitest_utils.TestMixin, sheet_view.SheetPropertyMeasureItemImpl):
uitest_utils.TestMixin,
sheet_property_track_item.SheetPropertyMeasureItemImpl):
pass
class SheetPropertyTrackItem(
uitest_utils.TestMixin, sheet_view.SheetPropertyTrackItemImpl):
uitest_utils.TestMixin,
sheet_property_track_item.SheetPropertyTrackItemImpl):
measure_item_cls = SheetPropertyMeasureItem
class SheetView(uitest_utils.TestMixin, sheet_view.SheetViewImpl):

88
noisicaa/ui/render_sheet_dialog.py

@ -3,30 +3,15 @@
import logging
import os.path
import threading
import time
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtGui import QIcon, QFont, QPalette, QColor
from PyQt5.QtWidgets import (
QMessageBox,
QWidget,
QPushButton,
QHBoxLayout,
QVBoxLayout,
QFormLayout,
QLineEdit,
QDialog,
QToolButton,
QFileDialog,
QComboBox,
QProgressBar,
QLabel,
)
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
logger = logging.getLogger(__name__)
class RenderSheetDialog(QDialog):
class RenderSheetDialog(QtWidgets.QDialog):
def __init__(self, parent, app, sheet):
super().__init__(parent)
@ -39,57 +24,57 @@ class RenderSheetDialog(QDialog):
self.setWindowTitle("noisicaä - Render Sheet")
self.top_area = QWidget(self)
self.top_area = QtWidgets.QWidget(self)
self.select_output_directory = QToolButton(
self.select_output_directory = QtWidgets.QToolButton(
self.top_area,
icon=QIcon.fromTheme('document-open'),
icon=QtGui.QIcon.fromTheme('document-open'),
autoRaise=True)
self.select_output_directory.clicked.connect(self.onSelectOutputDirectory)
self.output_directory = QLineEdit(self.top_area, text="/tmp")
self.output_directory = QtWidgets.QLineEdit(self.top_area, text="/tmp")
self.file_name = QLineEdit(self.top_area, text="test.flac")
self.file_name = QtWidgets.QLineEdit(self.top_area, text="test.flac")
self.file_format = QComboBox(self.top_area)
self.file_format = QtWidgets.QComboBox(self.top_area)
self.file_format.addItem("FLAC", userData="flac")
#self.file_format.addItem("OGG", userData="ogg")
self.file_format.currentIndexChanged.connect(self.onFileFormatChanged)
self.progress = QProgressBar(
self.progress = QtWidgets.QProgressBar(
self.top_area, minimum=0, maximum=100, visible=False)
self.progress.setMinimumWidth(200)
self.status = QLabel(self, visible=False)
font = QFont(self.status.font())
font.setWeight(QFont.Bold)
self.status = QtWidgets.QLabel(self, visible=False)
font = QtGui.QFont(self.status.font())
font.setWeight(QtGui.QFont.Bold)
if font.pixelSize() != -1:
font.setPixelSize(14 * font.pixelSize() // 10)
else:
font.setPointSizeF(1.4 * font.pointSizeF())
self.status.setFont(font)
self.abort_button = QPushButton("Abort", visible=False)
self.abort_button = QtWidgets.QPushButton("Abort", visible=False)
self.abort_button.clicked.connect(self.onAbort)
self.close_button = QPushButton("Close")
self.close_button = QtWidgets.QPushButton("Close")
self.close_button.clicked.connect(self.close)
self.render_button = QPushButton("Render")
self.render_button = QtWidgets.QPushButton("Render")
self.render_button.clicked.connect(self.onRender)
output_directory_layout = QHBoxLayout(spacing=1)
output_directory_layout = QtWidgets.QHBoxLayout(spacing=1)
output_directory_layout.addWidget(self.output_directory, 1)
output_directory_layout.addWidget(self.select_output_directory)
top_layout = QFormLayout()
top_layout = QtWidgets.QFormLayout()
top_layout.addRow("Output Directory", output_directory_layout)
top_layout.addRow("Filename", self.file_name)
top_layout.addRow("Format", self.file_format)
self.top_area.setLayout(top_layout)
buttons = QHBoxLayout()
buttons = QtWidgets.QHBoxLayout()
buttons.addWidget(self.progress)
buttons.addWidget(self.status)
buttons.addWidget(self.abort_button)
@ -97,14 +82,14 @@ class RenderSheetDialog(QDialog):
buttons.addWidget(self.render_button)
buttons.addWidget(self.close_button)
layout = QVBoxLayout()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.top_area, 1)
layout.addLayout(buttons)
self.setLayout(layout)
def onSelectOutputDirectory(self):
path = QFileDialog.getExistingDirectory(
path = QtWidgets.QFileDialog.getExistingDirectory(
parent=self,
caption="Select output directory...",
directory=self.output_directory.text())
@ -146,26 +131,29 @@ class RenderSheetDialog(QDialog):
if self._renderer.status == Renderer.SUCCESS:
self.status.setText("Done.")
palette = QPalette(self.status.palette())
palette.setColor(QPalette.WindowText, QColor(60, 160, 60))
palette = QtGui.QPalette(self.status.palette())
palette.setColor(
QtGui.QPalette.WindowText, QtGui.QColor(60, 160, 60))
self.status.setPalette(palette)
elif self._renderer.status == Renderer.ABORTED:
self.status.setText("Aborted")
palette = QPalette(self.status.palette())
palette.setColor(QPalette.WindowText, QColor(255, 60, 60))
palette = QtGui.QPalette(self.status.palette())
palette.setColor(
QtGui.QPalette.WindowText, QtGui.QColor(255, 60, 60))
self.status.setPalette(palette)
elif self._renderer.status == Renderer.FAILED:
self.status.setText("Failed!")
palette = QPalette(self.status.palette())
palette.setColor(QPalette.WindowText, QColor(255, 60, 60))
palette = QtGui.QPalette(self.status.palette())
palette.setColor(
QtGui.QPalette.WindowText, QtGui.QColor(255, 60, 60))
self.status.setPalette(palette)
msg = QMessageBox(self)
msg = QtWidgets.QMessageBox(self)
msg.setWindowTitle("Renderer failed")
msg.setText("Rendering failed with an error:")
msg.setInformativeText(self._renderer.reason)
msg.setIcon(QMessageBox.Critical)
msg.addButton("Ok", QMessageBox.AcceptRole)
msg.setIcon(QtWidgets.QMessageBox.Critical)
msg.addButton("Ok", QtWidgets.QMessageBox.AcceptRole)
msg.exec_()
self._renderer = None
@ -182,9 +170,9 @@ class RenderSheetDialog(QDialog):
self._renderer.abort()
class Renderer(QObject):
progress = pyqtSignal(int)
done = pyqtSignal()
class Renderer(QtCore.QObject):
progress = QtCore.pyqtSignal(int)
done = QtCore.pyqtSignal()
ABORTED = 'aborted'
SUCCESS = 'success'

1
noisicaa/ui/render_sheet_dialog_test.py

@ -1,7 +1,6 @@
#/usr/bin/python3
import unittest
from unittest import mock
if __name__ == '__main__':
import pyximport

805
noisicaa/ui/score_track_item.py