diff --git a/imgsrc/calibreSymbols.spd b/imgsrc/calibreSymbols.spd new file mode 100644 index 0000000000..da751f442a --- /dev/null +++ b/imgsrc/calibreSymbols.spd @@ -0,0 +1,152 @@ +SplineFontDB: 3.0 +FontName: calibreSymbols +FullName: calibre Symbols +FamilyName: calibre Symbols +Weight: Medium +Copyright: Created by Kovid Goyal with FontForge 2.0 (http://fontforge.sf.net) +UComments: "2012-2-27: Created." +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -100 +UnderlineWidth: 50 +Ascent: 800 +Descent: 200 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +NeedsXUIDChange: 1 +XUID: [1021 913 325894820 11538708] +FSType: 0 +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1330331997 +ModificationTime: 1330337167 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 90 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +MarkAttachClasses: 1 +DEI: 91125 +Encoding: UnicodeFull +UnicodeInterp: none +NameList: Adobe Glyph List +DisplaySize: -24 +AntiAlias: 1 +FitToEm: 1 +WidthSeparation: 150 +WinInfo: 0 75 22 +BeginPrivate: 0 +EndPrivate +BeginChars: 1114112 3 + +StartChar: uni2605 +Encoding: 9733 9733 0 +Width: 933 +VWidth: 0 +Flags: W +LayerCount: 2 +Fore +SplineSet +544.1 344.853 m 1 + 723.713 360.062 l 2 + 774.129 364.181 799.969 366.241 801.229 366.241 c 0 + 816.984 366.241 824.862 359.429 824.862 345.803 c 0 + 824.862 340.416 823.287 336.218 820.136 333.207 c 0 + 816.984 330.197 792.878 314.274 747.817 285.438 c 2 + 596.566 188 l 1 + 693.461 -56.3096 l 2 + 694.722 -58.8447 695.353 -62.6465 695.353 -67.7168 c 0 + 695.353 -72.4697 693.619 -76.5898 690.152 -80.0742 c 0 + 686.687 -83.5605 682.905 -85.3027 678.81 -85.3027 c 0 + 675.028 -85.3027 671.089 -83.9561 666.991 -81.2637 c 0 + 662.896 -78.5693 640.681 -59.7949 600.348 -24.9385 c 2 + 466.11 91.9873 l 1 + 333.765 -23.0381 l 2 + 292.172 -59.1621 269.405 -78.5693 265.467 -81.2637 c 0 + 261.527 -83.9561 257.667 -85.3027 253.887 -85.3027 c 0 + 249.475 -85.3027 245.457 -83.4814 241.833 -79.8369 c 0 + 238.209 -76.1934 236.397 -72.1523 236.397 -67.7168 c 0 + 236.397 -64.8652 245.379 -40.7832 263.34 4.53027 c 2 + 335.184 188 l 1 + 181.096 287.34 l 2 + 137.61 315.225 114.372 330.593 111.379 333.445 c 0 + 108.385 336.297 106.888 340.416 106.888 345.803 c 0 + 106.888 359.745 114.924 366.717 130.994 366.717 c 0 + 132.255 366.717 154.312 364.815 197.167 361.013 c 2 + 387.648 344.853 l 1 + 430.661 528.798 l 2 + 441.69 576.646 448.544 602.945 451.222 607.699 c 0 + 453.9 612.452 458.863 614.828 466.11 614.828 c 0 + 473.674 614.828 478.716 612.215 481.236 606.986 c 0 + 483.757 601.758 491.005 573.317 502.979 521.667 c 2 + 544.1 344.853 l 1 +EndSplineSet +Validated: 524289 +EndChar + +StartChar: zero +Encoding: 48 48 1 +Width: 1303 +VWidth: 2048 +Flags: W +HStem: -43.3789 76.7998<582.097 721.09> 623.341 76.7998<582.097 721.091> +VStem: 403.82 97.4395<148.044 508.66> 802.221 96.959<148.044 508.659> +LayerCount: 2 +Fore +SplineSet +651.5 623.341 m 0 + 601.58 623.341 564.061 598.78 538.939 549.66 c 0 + 513.82 500.541 501.26 426.7 501.26 328.141 c 0 + 501.26 229.9 513.82 156.221 538.939 107.101 c 0 + 564.061 57.9805 601.58 33.4209 651.5 33.4209 c 0 + 701.74 33.4209 739.42 57.9805 764.54 107.101 c 0 + 789.66 156.221 802.221 229.9 802.221 328.141 c 0 + 802.221 426.7 789.66 500.541 764.54 549.66 c 0 + 739.42 598.78 701.74 623.341 651.5 623.341 c 0 +651.5 700.141 m 0 + 731.82 700.141 793.18 668.38 835.58 604.859 c 0 + 877.979 541.341 899.18 449.101 899.18 328.141 c 0 + 899.18 207.5 877.979 115.421 835.58 51.9004 c 0 + 793.18 -11.6201 731.819 -43.3789 651.5 -43.3789 c 0 + 571.18 -43.3789 509.82 -11.6201 467.42 51.9004 c 0 + 425.021 115.421 403.82 207.5 403.82 328.141 c 0 + 403.82 449.101 425.021 541.341 467.42 604.859 c 0 + 509.82 668.38 571.18 700.141 651.5 700.141 c 0 +EndSplineSet +Validated: 524289 +EndChar + +StartChar: period +Encoding: 46 46 2 +Width: 516 +VWidth: 2048 +Flags: W +HStem: 53.4004 166.199<203.263 309.297> +VStem: 174.6 163.801<82.9501 190.955> +LayerCount: 2 +Fore +SplineSet +338.4 142.8 m 0 + 338.4 119.2 330.5 98.4004 314.7 80.4004 c 0 + 298.9 62.4004 277 53.4004 249 53.4004 c 0 + 225.4 53.4004 207.1 61.2002 194.1 76.7998 c 0 + 181.1 92.4004 174.6 111 174.6 132.6 c 0 + 174.6 155.8 182.6 176.1 198.6 193.5 c 0 + 214.6 210.9 236.8 219.6 265.2 219.6 c 0 + 288.8 219.6 306.9 212.2 319.5 197.4 c 0 + 332.1 182.6 338.4 164.4 338.4 142.8 c 0 +EndSplineSet +Validated: 524289 +EndChar +EndChars +EndSplineFont diff --git a/resources/fonts/calibreSymbols.otf b/resources/fonts/calibreSymbols.otf new file mode 100644 index 0000000000..6406e2b2a8 Binary files /dev/null and b/resources/fonts/calibreSymbols.otf differ diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 445a0dbc03..c27c004ba2 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -806,6 +806,23 @@ def is_gui_thread(): global gui_thread return gui_thread is QThread.currentThread() +_rating_font = None +def rating_font(): + global _rating_font + if _rating_font is None: + from PyQt4.Qt import QFontDatabase + _rating_font = 'Arial Unicode MS' if iswindows else 'sans-serif' + fontid = QFontDatabase.addApplicationFont( + #P('fonts/liberation/LiberationSerif-Regular.ttf') + P('fonts/calibreSymbols.otf') + ) + if fontid > -1: + try: + _rating_font = unicode(list( + QFontDatabase.applicationFontFamilies(fontid))[0]) + except: + pass + return _rating_font def find_forms(srcdir): base = os.path.join(srcdir, 'calibre', 'gui2') diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index 628f846aea..08df7007a2 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -20,7 +20,7 @@ from calibre.ebooks.metadata.sources.identify import urls_from_identifiers from calibre.constants import filesystem_encoding from calibre.library.comments import comments_to_html from calibre.gui2 import (config, open_local_file, open_url, pixmap_to_data, - gprefs) + gprefs, rating_font) from calibre.utils.icu import sort_key from calibre.utils.formatter import EvalFormatter from calibre.utils.date import is_date_undefined @@ -116,6 +116,14 @@ def render_data(mi, use_roman_numbers=True, all_fields=False): val = force_unicode(val) ans.append((field, u'%s'%comments_to_html(val))) + elif metadata['datatype'] == 'rating': + val = getattr(mi, field) + if val: + val = val/2.0 + ans.append((field, + u'%s%s'%( + name, rating_font(), u'\u2605'*int(val)))) elif metadata['datatype'] == 'composite' and \ metadata['display'].get('contains_html', False): val = getattr(mi, field) diff --git a/src/calibre/gui2/cover_flow.py b/src/calibre/gui2/cover_flow.py index 4ba6c198f2..dd4763782a 100644 --- a/src/calibre/gui2/cover_flow.py +++ b/src/calibre/gui2/cover_flow.py @@ -10,10 +10,11 @@ Module to implement the Cover Flow feature import sys, os, time from PyQt4.Qt import (QImage, QSizePolicy, QTimer, QDialog, Qt, QSize, QAction, - QStackedLayout, QLabel, QByteArray, pyqtSignal, QKeySequence) + QStackedLayout, QLabel, QByteArray, pyqtSignal, QKeySequence, QFont) from calibre import plugins -from calibre.gui2 import config, available_height, available_width, gprefs +from calibre.gui2 import (config, available_height, available_width, gprefs, + rating_font) pictureflow, pictureflowerror = plugins['pictureflow'] @@ -102,6 +103,8 @@ if pictureflow is not None: type=Qt.QueuedConnection) self.context_menu = None self.setContextMenuPolicy(Qt.DefaultContextMenu) + if hasattr(self, 'setSubtitleFont'): + self.setSubtitleFont(QFont(rating_font())) def set_context_menu(self, cm): self.context_menu = cm diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index c9736719b5..13a64f154e 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -5,16 +5,12 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from math import cos, sin, pi -from PyQt4.Qt import (QColor, Qt, QModelIndex, QSize, QApplication, - QPainterPath, QLinearGradient, QBrush, - QPen, QStyle, QPainter, QStyleOptionViewItemV4, - QIcon, QDoubleSpinBox, QVariant, QSpinBox, - QStyledItemDelegate, QComboBox, QTextDocument, - QAbstractTextDocumentLayout) +from PyQt4.Qt import (Qt, QApplication, QStyle, QIcon, QDoubleSpinBox, + QVariant, QSpinBox, QStyledItemDelegate, QComboBox, QTextDocument, + QAbstractTextDocumentLayout, QFont) -from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog +from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog, rating_font from calibre.gui2.widgets import EnLineEdit from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox from calibre.utils.date import now, format_date, qt_to_dt @@ -27,81 +23,35 @@ from calibre.gui2.languages import LanguagesEdit class RatingDelegate(QStyledItemDelegate): # {{{ - COLOR = QColor("blue") - SIZE = 16 - def __init__(self, parent): - QStyledItemDelegate.__init__(self, parent) - self._parent = parent - self.dummy = QModelIndex() - self.star_path = QPainterPath() - self.star_path.moveTo(90, 50) - for i in range(1, 5): - self.star_path.lineTo(50 + 40 * cos(0.8 * i * pi), \ - 50 + 40 * sin(0.8 * i * pi)) - self.star_path.closeSubpath() - self.star_path.setFillRule(Qt.WindingFill) - self.gradient = QLinearGradient(0, 0, 0, 100) - self.factor = self.SIZE/100. - - def sizeHint(self, option, index): - #num = index.model().data(index, Qt.DisplayRole).toInt()[0] - return QSize(5*(self.SIZE), self.SIZE+4) - - def paint(self, painter, option, index): - style = self._parent.style() - option = QStyleOptionViewItemV4(option) - self.initStyleOption(option, index) - option.text = u'' - num = index.model().data(index, Qt.DisplayRole).toInt()[0] - def draw_star(): - painter.save() - painter.scale(self.factor, self.factor) - painter.translate(50.0, 50.0) - painter.rotate(-20) - painter.translate(-50.0, -50.0) - painter.drawPath(self.star_path) - painter.restore() - - painter.save() - if hasattr(QStyle, 'CE_ItemViewItem'): - style.drawControl(QStyle.CE_ItemViewItem, option, - painter, self._parent) - elif option.state & QStyle.State_Selected: - painter.fillRect(option.rect, option.palette.highlight()) - else: - painter.fillRect(option.rect, option.backgroundBrush) - - try: - painter.setRenderHint(QPainter.Antialiasing) - painter.setClipRect(option.rect) - y = option.rect.center().y()-self.SIZE/2. - x = option.rect.left() - color = index.data(Qt.ForegroundRole) - if color.isNull() or not color.isValid(): - color = self.COLOR - else: - color = QColor(color) - painter.setPen(QPen(color, 1, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) - self.gradient.setColorAt(0.0, color) - self.gradient.setColorAt(1.0, color) - painter.setBrush(QBrush(self.gradient)) - painter.translate(x, y) - i = 0 - while i < num: - draw_star() - painter.translate(self.SIZE, 0) - i += 1 - except: - import traceback - traceback.print_exc() - painter.restore() + def __init__(self, *args, **kwargs): + QStyledItemDelegate.__init__(self, *args, **kwargs) + self.rf = QFont(rating_font()) + self.em = Qt.ElideMiddle def createEditor(self, parent, option, index): sb = QStyledItemDelegate.createEditor(self, parent, option, index) sb.setMinimum(0) sb.setMaximum(5) + sb.setSuffix(' ' + _('stars')) return sb + + def displayText(self, value, locale): + r = value.toInt()[0] + if r < 0 or r > 5: + r = 0 + return u'\u2605'*r + + def sizeHint(self, option, index): + option.font = self.rf + option.textElideMode = self.em + return QStyledItemDelegate.sizeHint(self, option, index) + + def paint(self, painter, option, index): + option.font = self.rf + option.textElideMode = self.em + return QStyledItemDelegate.paint(self, painter, option, index) + # }}} class DateDelegate(QStyledItemDelegate): # {{{ diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 044c01c39e..0b3c048a2e 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -588,8 +588,8 @@ class BooksModel(QAbstractTableModel): # {{{ def rating_type(r, idx=-1): r = self.db.data[r][idx] - r = r/2 if r else 0 - return QVariant(r) + r = r/2.0 if r else 0 + return QVariant(int(r)) def datetime_type(r, idx=-1): val = self.db.data[r][idx] diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 48049b765f..b622009a69 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -200,10 +200,10 @@ class BooksView(QTableView): # {{{ ac = a if self._model.sorted_on[1] else d ac.setCheckable(True) ac.setChecked(True) - if col not in ('ondevice', 'rating', 'inlibrary') and \ + if col not in ('ondevice', 'inlibrary') and \ (not self.model().is_custom_column(col) or \ self.model().custom_columns[col]['datatype'] not in ('bool', - 'rating')): + )): m = self.column_header_context_menu.addMenu( _('Change text alignment for %s') % name) al = self._model.alignment_map.get(col, 'left') diff --git a/src/calibre/gui2/metadata/single_download.py b/src/calibre/gui2/metadata/single_download.py index 091c10462b..6149c3be8a 100644 --- a/src/calibre/gui2/metadata/single_download.py +++ b/src/calibre/gui2/metadata/single_download.py @@ -27,7 +27,7 @@ from calibre.utils.logging import GUILog as Log from calibre.ebooks.metadata.sources.identify import (identify, urls_from_identifiers) from calibre.ebooks.metadata.book.base import Metadata -from calibre.gui2 import error_dialog, NONE +from calibre.gui2 import error_dialog, NONE, rating_font from calibre.utils.date import (utcnow, fromordinal, format_date, UNDEFINED_DATE, as_utc) from calibre.library.comments import comments_to_html @@ -254,6 +254,7 @@ class ResultsView(QTableView): # {{{ return ret def show_details(self, index): + f = rating_font() book = self.model().data(index, Qt.UserRole) parts = [ '
', @@ -265,7 +266,8 @@ class ResultsView(QTableView): # {{{ if series[1]: parts.append('
%s: %s
'%series) if not book.is_null('rating'): - parts.append('
%s
'%('\u2605'*int(book.rating))) + style = 'style=\'font-family:"%s"\''%f + parts.append('
%s
'%(style, '\u2605'*int(book.rating))) parts.append('
') if book.identifiers: urls = urls_from_identifiers(book.identifiers) diff --git a/src/calibre/gui2/pictureflow/pictureflow.cpp b/src/calibre/gui2/pictureflow/pictureflow.cpp index 4e9d8a402d..876c8cc65e 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.cpp +++ b/src/calibre/gui2/pictureflow/pictureflow.cpp @@ -364,6 +364,8 @@ public: QTime previousPosTimestamp; int pixelDistanceMoved; int pixelsToMovePerSlide; + QFont subtitleFont; + void setImages(FlowImages *images); void dataChanged(); @@ -422,6 +424,7 @@ PictureFlowPrivate::PictureFlowPrivate(PictureFlow* w, int queueLength_) step = 0; target = 0; fade = 256; + subtitleFont = QFont(); triggerTimer.setSingleShot(true); triggerTimer.setInterval(0); @@ -674,9 +677,13 @@ void PictureFlowPrivate::render_text(QPainter *painter, int index) { caption = slideImages->caption(index); subtitle = slideImages->subtitle(index); buffer_width = buffer.width(); buffer_height = buffer.height(); + subtitleFont.setPixelSize(fontSize); brect = painter->boundingRect(QRect(0, 0, buffer_width, fontSize), TEXT_FLAGS, caption); + painter->save(); + painter->setFont(subtitleFont); brect2 = painter->boundingRect(QRect(0, 0, buffer_width, fontSize), TEXT_FLAGS, subtitle); + painter->restore(); // So that if there is no subtitle, the caption is not flush with the bottom if (brect2.height() < fontSize) brect2.setHeight(fontSize); @@ -691,7 +698,11 @@ void PictureFlowPrivate::render_text(QPainter *painter, int index) { painter->drawText(brect, TEXT_FLAGS, caption); brect2.moveTop(buffer_height - brect2.height()); + + painter->save(); + painter->setFont(subtitleFont); painter->drawText(brect2, TEXT_FLAGS, slideImages->subtitle(index)); + painter->restore(); } // Render the slides. Updates only the offscreen buffer. @@ -1168,6 +1179,17 @@ void PictureFlow::setSlideSize(QSize size) d->setSlideSize(size); } +void PictureFlow::setSubtitleFont(QFont font) +{ + d->subtitleFont = font; +} + +QFont PictureFlow::subtitleFont() const +{ + return d->subtitleFont; +} + + QImage PictureFlow::slide(int index) const { return d->slide(index); diff --git a/src/calibre/gui2/pictureflow/pictureflow.h b/src/calibre/gui2/pictureflow/pictureflow.h index f2c2c947e6..c5a9c76190 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.h +++ b/src/calibre/gui2/pictureflow/pictureflow.h @@ -92,6 +92,7 @@ Q_OBJECT Q_PROPERTY(int currentSlide READ currentSlide WRITE setCurrentSlide) Q_PROPERTY(QSize slideSize READ slideSize WRITE setSlideSize) + Q_PROPERTY(QFont subtitleFont READ subtitleFont WRITE setSubtitleFont) public: /*! @@ -120,6 +121,17 @@ public: */ void setSlideSize(QSize size); + /*! + Returns the font used to render subtitles + */ + QFont subtitleFont() const; + + /*! + Sets the font used to render subtitles + */ + void setSubtitleFont(QFont font); + + /*! Clears any caches held to free up memory */ diff --git a/src/calibre/gui2/pictureflow/pictureflow.sip b/src/calibre/gui2/pictureflow/pictureflow.sip index 84d2498ea9..21c6209df5 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.sip +++ b/src/calibre/gui2/pictureflow/pictureflow.sip @@ -41,6 +41,10 @@ public : void setSlideSize(QSize size); + QFont subtitleFont() const; + + void setSubtitleFont(QFont font); + void clearCaches(); virtual QImage slide(int index) const; diff --git a/src/calibre/library/field_metadata.py b/src/calibre/library/field_metadata.py index de95eabd40..5b81f4a6a6 100644 --- a/src/calibre/library/field_metadata.py +++ b/src/calibre/library/field_metadata.py @@ -173,7 +173,7 @@ class FieldMetadata(dict): 'datatype':'rating', 'is_multiple':{}, 'kind':'field', - 'name':_('Ratings'), + 'name':_('Rating'), 'search_terms':['rating'], 'is_custom':False, 'is_category':True,