1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
#
# Copyright (c) 2008 - 2016 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.
"""
Various routines to display meaningful tooltips (text or graphical).
The show() function displays a tooltip showing part of a Document.
"""
from PyQt5.QtCore import QSize
from PyQt5.QtGui import (
QFont, QPainter, QPixmap, QTextCursor, QTextDocument)
from PyQt5.QtWidgets import QLabel
import metainfo
import tokeniter
import highlighter
import textformats
import gadgets.customtooltip
import tokeniter
import ly.lex.lilypond
def pixmap(cursor, num_lines=6, scale=0.8):
"""Return a QPixmap displaying the selected lines of the document.
If the cursor has no selection, num_lines are drawn.
By default the text is drawn 0.8 * the normal font size. You can change
that by supplying the scale parameter.
"""
block = cursor.document().findBlock(cursor.selectionStart())
c2 = QTextCursor(block)
if cursor.hasSelection():
c2.setPosition(cursor.selectionEnd(), QTextCursor.KeepAnchor)
c2.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor)
else:
c2.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor, num_lines)
data = textformats.formatData('editor')
doc = QTextDocument()
font = QFont(data.font)
font.setPointSizeF(font.pointSizeF() * scale)
doc.setDefaultFont(font)
doc.setPlainText(c2.selection().toPlainText())
if metainfo.info(cursor.document()).highlighting:
highlighter.highlight(doc, state=tokeniter.state(block))
size = doc.size().toSize() + QSize(8, -4)
pix = QPixmap(size)
pix.fill(data.baseColors['background'])
doc.drawContents(QPainter(pix))
return pix
def show(cursor, pos=None, num_lines=6):
"""Displays a tooltip showing part of the cursor's Document.
If the cursor has a selection, those blocks are displayed.
Otherwise, num_lines lines are displayed.
If pos is not given, the global mouse position is used.
"""
pix = pixmap(cursor, num_lines)
label = QLabel()
label.setPixmap(pix)
label.setStyleSheet("QLabel { border: 1px solid #777; }")
label.resize(pix.size())
widgets.customtooltip.show(label, pos)
def text(cursor):
"""Return basic tooltip text displaying filename, line and column information.
If the position is inside a music expression, the name of the variable the
expression is assigned to is also appended on a new line. If the time
position can be determined it is appended on a third line.
"""
filename = cursor.document().documentName()
line = cursor.blockNumber() + 1
column = cursor.position() - cursor.block().position()
text = "{0} ({1}:{2})".format(filename, line, column)
definition = get_definition(cursor)
if definition:
text += '\n' + definition
time_pos = time_position(cursor)
if time_pos:
text += '\n' + _("Position: {pos}").format(pos=time_pos)
return text
def get_definition(cursor):
"""Return the variable name the cursor's music expression is assigned to.
If the music is in a \\score instead, "\\score" is returned.
Returns None if no variable name can be found.
"""
block = cursor.block()
while block.isValid():
state = tokeniter.state(block)
if isinstance(state.parser(), ly.lex.lilypond.ParseGlobal):
for t in tokeniter.tokens(block)[:2]:
if type(t) is ly.lex.lilypond.Name:
return t[:]
elif isinstance(t, ly.lex.lilypond.Keyword) and t == '\\score':
return '\\score'
block = block.previous()
def time_position(cursor):
"""Returns the time position of the music the cursor points at.
Format the value as "5/1" etc.
"""
import documentinfo
pos = documentinfo.music(cursor.document()).time_position(cursor.position())
if pos is not None:
import ly.duration
return ly.duration.format_fraction(pos)
|