Skip to content

Commit

Permalink
Merge pull request #423 from PeterBjuhr/svg-edit
Browse files Browse the repository at this point in the history
Svg edit - multiple improvements, and start of transferring edits to the source
  • Loading branch information
wbsoft committed Apr 21, 2014
2 parents e88b8be + 85b8cf0 commit 084c578
Show file tree
Hide file tree
Showing 11 changed files with 1,006 additions and 167 deletions.
51 changes: 51 additions & 0 deletions frescobaldi_app/objecteditor/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2008 - 2014 by Wilbert Berendsen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# See http://www.gnu.org/licenses/ for more information.

"""
An Object Editor
"""

# Note: This is only a very first stub

from __future__ import unicode_literals

import sys

from PyQt4.QtCore import Qt
from PyQt4.QtGui import QKeySequence

import panel

class ObjectEditor(panel.Panel):
def __init__(self, mainwindow):
super(ObjectEditor, self).__init__(mainwindow)
self.hide()
self.toggleViewAction().setShortcut(QKeySequence("Meta+Alt+E"))
mainwindow.addDockWidget(Qt.LeftDockWidgetArea, self)

def translateUI(self):
self.setWindowTitle(_("Object Editor"))
self.toggleViewAction().setText(_("O&bject Editor"))

def createWidget(self):
from . import widget
w = widget.Widget(self)
return w


98 changes: 98 additions & 0 deletions frescobaldi_app/objecteditor/defineoffset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2008 - 2014 by Wilbert Berendsen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# See http://www.gnu.org/licenses/ for more information.

"""
Finds out which type of LilyPond object the offset will be applied to
using ly.music, stores this data and creates and inserts an override command.
"""

from __future__ import unicode_literals

from PyQt4 import QtGui

import documentinfo
import lydocument
import reformat


class DefineOffset():

def __init__(self, doc):
self.doc = doc
self.docinfo = documentinfo.music(doc)
self.node = None
self.lilyObject = None
self.lilyContext = ""
self.pos = 0

def getCurrentLilyObject(self, cursor):
""" Use cursor from textedit link to get type of object being edited."""
lycursor = lydocument.cursor(cursor)
self.pos = lycursor.start
node = self.docinfo.node(self.pos)
self.node = node
child = self.docinfo.iter_music(node)
for c in child:
name = c.__class__.__name__ #get instance name
return self.item2object(name)
name = node.__class__.__name__
return self.item2object(name)

def item2object(self, item):
""" Translate item type into name of
LilyPond object.
"""
item2objectDict = {
"String": { "GrobType": "TextScript" },
"Markup": { "GrobType": "TextScript" },
"Tempo": { "GrobType": "MetronomeMark",
"Context" : "Score" },
"Articulation": { "GrobType": "Script" }
}
try:
obj = item2objectDict[item]
except KeyError:
obj = { "GrobType": "still testing!" }
self.lilyObject = obj["GrobType"]
if "Context" in obj:
self.lilyContext = obj["Context"]
return obj["GrobType"]

def insertOverride(self, x, y):
""" Insert the override command. """
doc = lydocument.Document(self.doc)
block = doc.block(self.pos)
p = block.position()
cursor = QtGui.QTextCursor(self.doc)
cursor.setPosition(p)
cursor.beginEditBlock()
cursor.insertText(self.createOffsetOverride(x, y))
cursor.insertBlock()
cursor.endEditBlock()
reformat.reformat(cursor)

def createOffsetOverride(self, x, y):
""" Create the override command.
Can this be created as a node?
"""
objToOverride = self.lilyContext
if len(objToOverride) > 0:
objToOverride += "."
objToOverride += self.lilyObject
return "\once \override " + objToOverride + ".extra-offset = #'(" + str(x) + " . " + str(y) + ")"
179 changes: 179 additions & 0 deletions frescobaldi_app/objecteditor/widget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2008 - 2014 by Wilbert Berendsen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# See http://www.gnu.org/licenses/ for more information.

"""
An Object Editor widget.
"""

from __future__ import unicode_literals

import sys

from PyQt4 import QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *

import app
import objecteditor

from . import defineoffset


class Widget(QWidget):

# I think we will work with individual editor objects for different types of objects.
# Each one will be shown/hidden on demand, i.e. when an element is activated
# through the SVG view, the music view or the cursor in the source.
# Each editor object handles its own connections to signals.
# (PS: The object editor will also work with the source code directly,
# i.e. independently of graphical SVG editing.)

def __init__(self, tool):
super(Widget, self).__init__(tool)
self.mainwindow = tool.mainwindow()
self.define = None

import panelmanager
self.svgview = panelmanager.manager(tool.mainwindow()).svgview.widget().view

layout = QVBoxLayout(spacing=1)
self.setLayout(layout)

self.elemLabel = QLabel()

self.XOffsetBox = QDoubleSpinBox()
self.XOffsetBox.setRange(-99,99)
self.XOffsetBox.setSingleStep(0.1)
self.XOffsetLabel = l = QLabel()
l.setBuddy(self.XOffsetBox)

self.YOffsetBox = QDoubleSpinBox()
self.YOffsetBox.setRange(-99,99)
self.YOffsetBox.setSingleStep(0.1)
self.YOffsetLabel = l = QLabel()
l.setBuddy(self.YOffsetBox)

self.insertButton = QPushButton("insert offset in source", self)
self.insertButton.clicked.connect(self.callInsert)

layout.addWidget(self.elemLabel)
layout.addWidget(self.XOffsetBox)
layout.addWidget(self.XOffsetLabel)
layout.addWidget(self.YOffsetBox)
layout.addWidget(self.YOffsetLabel)
layout.addWidget(self.insertButton)

layout.addStretch(1)

app.translateUI(self)
self.loadSettings()

self.connectSlots()

def connectSlots(self):
# On creation we connect to all available signals
self.connectToSvgView()

def connectToSvgView(self):
"""Register with signals emitted by the
SVG viewer for processing graphical editing.
"""
self.svgview.objectStartDragging.connect(self.startDragging)
self.svgview.objectDragging.connect(self.Dragging)
self.svgview.objectDragged.connect(self.Dragged)
self.svgview.cursor.connect(self.setObjectFromCursor)

def disconnectFromSvgView(self):
"""Do not process graphical edits when the
Object Editor isn't visible."""
self.svgview.objectStartDragging.disconnect()
self.svgview.objectDragging.disconnect()
self.svgview.objectDragged.disconnect()
self.svgview.cursor.disconnect()

def translateUI(self):
self.XOffsetLabel.setText(_("X Offset"))
self.XOffsetBox.setToolTip(_("Display the X Offset"))
self.YOffsetLabel.setText(_("Y Offset"))
self.YOffsetBox.setToolTip(_("Display the Y Offset"))
self.insertButton.setEnabled(False)

def hideEvent(self, event):
"""Disconnect from all graphical editing signals
when the panel isn't visible
"""
self.disconnectFromSvgView()
event.accept()

def showEvent(self, event):
"""Connect to the graphical editing signals
when the panel becomes visible
"""
self.connectToSvgView()
event.accept()

def callInsert(self):
""" Insert the override command in the source."""
if self.define:
self.define.insertOverride(self.XOffsetBox.value(), self.YOffsetBox.value())

@QtCore.pyqtSlot(float, float)
def setOffset(self, x, y):
"""Display the updated offset."""
self.XOffsetBox.setValue(x)
self.YOffsetBox.setValue(y)

@QtCore.pyqtSlot(float, float)
def startDragging(self, x, y):
"""Set the value of the offset externally."""
# temporary debug output
#print "Start dragging with offset", x, y
self.setOffset(x, y)

@QtCore.pyqtSlot(float, float)
def Dragging(self, x, y):
"""Set the value of the offset externally."""
# temporary debug output
# print "Dragging with offset", x, y
self.setOffset(x, y)

@QtCore.pyqtSlot(float, float)
def Dragged(self, x, y):
"""Set the value of the offset externally."""
# temporary debug output
#print "Dragged to", x, y
self.setOffset(x, y)

@QtCore.pyqtSlot(QTextCursor)
def setObjectFromCursor(self, cursor):
"""Set selected element."""
self.define = defineoffset.DefineOffset(self.mainwindow.currentDocument())
self.elemLabel.setText(self.define.getCurrentLilyObject(cursor))
self.insertButton.setEnabled(True)

def loadSettings(self):
"""Called on construction. Load settings and set checkboxes state."""
s = QSettings()
s.beginGroup('object_editor')

def saveSettings(self):
"""Called on close. Save settings and checkboxes state."""
s = QSettings()
s.beginGroup('object_editor')

3 changes: 3 additions & 0 deletions frescobaldi_app/panelmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ def __init__(self, mainwindow):
self.loadPanel("doclist.DocumentList")
self.loadPanel("outline.OutlinePanel")
self.loadPanel("layoutcontrol.LayoutControlOptions")
# The Object editor is highly experimental and should be
# commented out for stable releases.
self.loadPanel("objecteditor.ObjectEditor")

self.createActions()

Expand Down
Loading

0 comments on commit 084c578

Please sign in to comment.