diff --git a/manual/faq.rst b/manual/faq.rst index b6c88acbb4..51485a29a5 100644 --- a/manual/faq.rst +++ b/manual/faq.rst @@ -682,8 +682,11 @@ There are three possible things I know of, that can cause this: * The Logitech SetPoint Settings application causes random crashes in |app| when it is open. Close it before starting |app|. + * Constant Guard Protection by Xfinity causes crashes in |app|. You have to + manually allow |app| in it or uninstall Constant Guard Protection. + If none of the above apply to you, then there is some other program on your -computer that is interfering with |app|. First reboot your computer is safe +computer that is interfering with |app|. First reboot your computer in safe mode, to have as few running programs as possible, and see if the crashes still happen. If they do not, then you know it is some program causing the problem. The most likely such culprit is a program that modifies other programs' @@ -794,7 +797,7 @@ Why doesn't |app| have an automatic update? For many reasons: * *There is no need to update every week*. If you are happy with how |app| works turn off the update notification and be on your merry way. Check back to see if you want to update once a year or so. - * Pre downloading the updates for all users in the background would mean require about 80TB of bandwidth *every week*. That costs thousands of dollars a month. And |app| is currently growing at 300,000 new users every month. + * Pre downloading the updates for all users in the background would require about 80TB of bandwidth *every week*. That costs thousands of dollars a month. And |app| is currently growing at 300,000 new users every month. * If I implement a dialog that downloads the update and launches it, instead of going to the website as it does now, that would save the most ardent |app| updater, *at most five clicks a week*. There are far higher priority things to do in |app| development. * If you really, really hate downloading |app| every week but still want to be up to the latest, I encourage you to run from source, which makes updating trivial. Instructions are :ref:`available here `. diff --git a/recipes/hbr.recipe b/recipes/hbr.recipe index b80b0bace7..702795109b 100644 --- a/recipes/hbr.recipe +++ b/recipes/hbr.recipe @@ -11,11 +11,11 @@ class HBR(BasicNewsRecipe): timefmt = ' [%B %Y]' language = 'en' no_stylesheets = True - recipe_disabled = ('hbr.org has started requiring the use of javascript' - ' to log into their website. This is unsupported in calibre, so' - ' this recipe has been disabled. If you would like to see ' - ' HBR supported in calibre, contact hbr.org and ask them' - ' to provide a javascript free login method.') + # recipe_disabled = ('hbr.org has started requiring the use of javascript' + # ' to log into their website. This is unsupported in calibre, so' + # ' this recipe has been disabled. If you would like to see ' + # ' HBR supported in calibre, contact hbr.org and ask them' + # ' to provide a javascript free login method.') LOGIN_URL = 'https://hbr.org/login?request_url=/' LOGOUT_URL = 'https://hbr.org/logout?request_url=/' @@ -38,46 +38,37 @@ class HBR(BasicNewsRecipe): #articleAuthors{font-family:Georgia,"Times New Roman",Times,serif; font-style:italic; color:#000000;font-size:x-small;} #summaryText{font-family:Georgia,"Times New Roman",Times,serif; font-weight:bold; font-size:x-small;} ''' + use_javascript_to_login = True - def get_browser(self): - br = BasicNewsRecipe.get_browser(self) - self.logout_url = None - - #''' - br.open(self.LOGIN_URL) - br.select_form(name='signin-form') - br['signin-form:username'] = self.username - br['signin-form:password'] = self.password - raw = br.submit().read() - if '>Sign out<' not in raw: - raise Exception('Failed to login, are you sure your username and password are correct?') + def javascript_login(self, br, username, password): + from calibre.web.jsbrowser.browser import Timeout try: - link = br.find_link(text='Sign out') - if link: - self.logout_url = link.absolute_url - except: - self.logout_url = self.LOGOUT_URL - #''' - return br - - def cleanup(self): - if self.logout_url is not None: - self.browser.open(self.logout_url) + br.visit('https://hbr.org/login?request_url=/', timeout=20) + except Timeout: + pass + br.click('#accordion div[tabindex="0"]', wait_for_load=False) + f = br.select_form('#signin-form') + f['signin-form:username'] = username + f['signin-form:password'] = password + br.submit(wait_for_load=False) + br.run_for_a_time(30) def map_url(self, url): if url.endswith('/ar/1'): return url[:-1]+'pr' - def hbr_get_toc(self): - #return self.index_to_soup(open('/t/hbr.html').read()) + # return self.index_to_soup(open('/t/toc.html').read()) today = date.today() future = today + timedelta(days=30) for x in [x.strftime('%y%m') for x in (future, today)]: url = self.INDEX + x soup = self.index_to_soup(url) - if not soup.find(text='Issue Not Found'): + if (not soup.find(text='Issue Not Found') and not soup.find( + text="We're Sorry. There was an error processing your request") + and 'Exception: java.io.FileNotFoundException' not in + unicode(soup)): return soup raise Exception('Could not find current issue') @@ -85,8 +76,9 @@ class HBR(BasicNewsRecipe): feeds = [] current_section = None articles = [] - for x in soup.find(id='archiveToc').findAll(['h3', 'h4']): - if x.name == 'h3': + for x in soup.find(id='issueFeaturesContent').findAll(['li', 'h4']): + if x.name == 'h4': + if x.get('class', None) == 'basic':continue if current_section is not None and articles: feeds.append((current_section, articles)) current_section = self.tag_to_string(x).capitalize() @@ -102,7 +94,7 @@ class HBR(BasicNewsRecipe): if url.startswith('/'): url = 'http://hbr.org' + url url = self.map_url(url) - p = x.parent.find('p') + p = x.find('p', attrs={'class':'author'}) desc = '' if p is not None: desc = self.tag_to_string(p) @@ -114,10 +106,9 @@ class HBR(BasicNewsRecipe): 'date':''}) return feeds - def parse_index(self): soup = self.hbr_get_toc() - #open('/t/hbr.html', 'wb').write(unicode(soup).encode('utf-8')) + # open('/t/hbr.html', 'wb').write(unicode(soup).encode('utf-8')) feeds = self.hbr_parse_toc(soup) return feeds diff --git a/resources/compiled_coffeescript.zip b/resources/compiled_coffeescript.zip index 8186cccaa6..8948c66f69 100644 Binary files a/resources/compiled_coffeescript.zip and b/resources/compiled_coffeescript.zip differ diff --git a/src/calibre/db/categories.py b/src/calibre/db/categories.py index 900f245b36..8d07714c3e 100644 --- a/src/calibre/db/categories.py +++ b/src/calibre/db/categories.py @@ -66,6 +66,7 @@ def find_categories(field_metadata): def create_tag_class(category, fm, icon_map): cat = fm[category] + dt = cat['datatype'] icon = None label = fm.key_to_label(category) if icon_map: @@ -76,13 +77,13 @@ def create_tag_class(category, fm, icon_map): icon = icon_map['custom:'] icon_map[category] = icon is_editable = category not in {'news', 'rating', 'languages', 'formats', - 'identifiers'} + 'identifiers'} and dt != 'composite' if (tweaks['categories_use_field_for_author_name'] == 'author_sort' and (category == 'authors' or (cat['display'].get('is_names', False) and cat['is_custom'] and cat['is_multiple'] and - cat['datatype'] == 'text'))): + dt == 'text'))): use_sort_as_name = True else: use_sort_as_name = False diff --git a/src/calibre/ebooks/conversion/plugins/pdf_output.py b/src/calibre/ebooks/conversion/plugins/pdf_output.py index b9d016de2d..c473931aef 100644 --- a/src/calibre/ebooks/conversion/plugins/pdf_output.py +++ b/src/calibre/ebooks/conversion/plugins/pdf_output.py @@ -99,6 +99,18 @@ class PDFOutput(OutputFormatPlugin): recommended_value=False, help=_( 'Generate an uncompressed PDF, useful for debugging, ' 'only works with the new PDF engine.')), + OptionRecommendation(name='pdf_page_numbers', recommended_value=False, + help=_('Add page numbers to the bottom of every page in the generated PDF file. If you ' + 'specify a footer template, it will take precedence ' + 'over this option.')), + OptionRecommendation(name='pdf_footer_template', recommended_value=None, + help=_('An HTML template used to generate footers on every page.' + ' The string _PAGENUM_ will be replaced by the current page' + ' number.')), + OptionRecommendation(name='pdf_header_template', recommended_value=None, + help=_('An HTML template used to generate headers on every page.' + ' The string _PAGENUM_ will be replaced by the current page' + ' number.')), ]) def convert(self, oeb_book, output_path, input_plugin, opts, log): diff --git a/src/calibre/ebooks/oeb/display/paged.coffee b/src/calibre/ebooks/oeb/display/paged.coffee index aea51b5b23..aae9aeddd2 100644 --- a/src/calibre/ebooks/oeb/display/paged.coffee +++ b/src/calibre/ebooks/oeb/display/paged.coffee @@ -29,6 +29,10 @@ class PagedDisplay this.current_page_height = null this.document_margins = null this.use_document_margins = false + this.footer_template = null + this.header_template = null + this.header = null + this.footer = null read_document_margins: () -> # Read page margins from the document. First checks for an @page rule. @@ -102,6 +106,7 @@ class PagedDisplay # than max_col_width sm += Math.ceil( (col_width - this.max_col_width) / 2*n ) col_width = Math.max(100, ((ww - adjust)/n) - 2*sm) + this.col_width = col_width this.page_width = col_width + 2*sm this.screen_width = this.page_width * this.cols_per_screen this.current_page_height = window.innerHeight - this.margin_top - this.margin_bottom @@ -171,6 +176,30 @@ class PagedDisplay # log('Time to layout:', new Date().getTime() - start_time) return sm + create_header_footer: () -> + if this.header_template != null + this.header = document.createElement('div') + this.header.setAttribute('style', "overflow:hidden; display:block; position:absolute; left:#{ this.side_margin }px; top: 0px; height: #{ this.margin_top }px; width: #{ this.col_width }px; margin: 0; padding: 0") + document.body.appendChild(this.header) + if this.footer_template != null + this.footer = document.createElement('div') + this.footer.setAttribute('style', "overflow:hidden; display:block; position:absolute; left:#{ this.side_margin }px; top: #{ window.innerHeight - this.margin_bottom }px; height: #{ this.margin_bottom }px; width: #{ this.col_width }px; margin: 0; padding: 0") + document.body.appendChild(this.footer) + this.update_header_footer(1) + + position_header_footer: () -> + [left, top] = calibre_utils.viewport_to_document(0, 0, document.body.ownerDocument) + if this.header != null + this.header.style.setProperty('left', left+'px') + if this.footer != null + this.footer.style.setProperty('left', left+'px') + + update_header_footer: (pagenum) -> + if this.header != null + this.header.innerHTML = this.header_template.replace(/_PAGENUM_/g, pagenum+"") + if this.footer != null + this.footer.innerHTML = this.footer_template.replace(/_PAGENUM_/g, pagenum+"") + fit_images: () -> # Ensure no images are wider than the available width in a column. Note # that this method use getBoundingClientRect() which means it will diff --git a/src/calibre/ebooks/pdf/render/from_html.py b/src/calibre/ebooks/pdf/render/from_html.py index 6beedc5dd4..2cdc804a9e 100644 --- a/src/calibre/ebooks/pdf/render/from_html.py +++ b/src/calibre/ebooks/pdf/render/from_html.py @@ -161,6 +161,17 @@ class PDFWriter(QObject): debug=self.log.debug, compress=not opts.uncompressed_pdf, mark_links=opts.pdf_mark_links) + self.footer = opts.pdf_footer_template + if self.footer is None and opts.pdf_page_numbers: + self.footer = '

_PAGENUM_

' + self.header = opts.pdf_header_template + min_margin = 36 + if self.footer and opts.margin_bottom < min_margin: + self.log.warn('Bottom margin is too small for footer, increasing it.') + opts.margin_bottom = min_margin + if self.header and opts.margin_top < min_margin: + self.log.warn('Top margin is too small for header, increasing it.') + opts.margin_top = min_margin self.page.setViewportSize(QSize(self.doc.width(), self.doc.height())) self.render_queue = items @@ -264,6 +275,15 @@ class PDFWriter(QObject): py_bridge.value = book_indexing.all_links_and_anchors(); '''%(self.margin_top, 0, self.margin_bottom)) + if self.header: + self.bridge_value = self.header + evaljs('paged_display.header_template = py_bridge.value') + if self.footer: + self.bridge_value = self.footer + evaljs('paged_display.footer_template = py_bridge.value') + if self.header or self.footer: + evaljs('paged_display.create_header_footer();') + amap = self.bridge_value if not isinstance(amap, dict): amap = {'links':[], 'anchors':{}} # Some javascript error occurred @@ -272,6 +292,8 @@ class PDFWriter(QObject): mf = self.view.page().mainFrame() while True: self.doc.init_page() + if self.header or self.footer: + evaljs('paged_display.update_header_footer(%d)'%self.current_page_num) self.painter.save() mf.render(self.painter) self.painter.restore() @@ -279,7 +301,7 @@ class PDFWriter(QObject): self.doc.end_page() if not nsl[1] or nsl[0] <= 0: break - evaljs('window.scrollTo(%d, 0)'%nsl[0]) + evaljs('window.scrollTo(%d, 0); paged_display.position_header_footer();'%nsl[0]) if self.doc.errors_occurred: break diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index d7a2669b0b..301b5f7ea4 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -22,91 +22,94 @@ from calibre.utils.date import UNDEFINED_DATE # Setup gprefs {{{ gprefs = JSONConfig('gui') +defs = gprefs.defaults if isosx: - gprefs.defaults['action-layout-menubar'] = ( + defs['action-layout-menubar'] = ( 'Add Books', 'Edit Metadata', 'Convert Books', 'Choose Library', 'Save To Disk', 'Preferences', 'Help', ) - gprefs.defaults['action-layout-menubar-device'] = ( + defs['action-layout-menubar-device'] = ( 'Add Books', 'Edit Metadata', 'Convert Books', 'Location Manager', 'Send To Device', 'Save To Disk', 'Preferences', 'Help', ) - gprefs.defaults['action-layout-toolbar'] = ( + defs['action-layout-toolbar'] = ( 'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', None, 'Choose Library', 'Donate', None, 'Fetch News', 'Store', 'Save To Disk', 'Connect Share', None, 'Remove Books', ) - gprefs.defaults['action-layout-toolbar-device'] = ( + defs['action-layout-toolbar-device'] = ( 'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', 'Send To Device', None, None, 'Location Manager', None, None, 'Fetch News', 'Store', 'Save To Disk', 'Connect Share', None, 'Remove Books', ) else: - gprefs.defaults['action-layout-menubar'] = () - gprefs.defaults['action-layout-menubar-device'] = () - gprefs.defaults['action-layout-toolbar'] = ( + defs['action-layout-menubar'] = () + defs['action-layout-menubar-device'] = () + defs['action-layout-toolbar'] = ( 'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', None, 'Store', 'Donate', 'Fetch News', 'Help', None, 'Remove Books', 'Choose Library', 'Save To Disk', 'Connect Share', 'Preferences', ) - gprefs.defaults['action-layout-toolbar-device'] = ( + defs['action-layout-toolbar-device'] = ( 'Add Books', 'Edit Metadata', None, 'Convert Books', 'View', 'Send To Device', None, None, 'Location Manager', None, None, 'Fetch News', 'Save To Disk', 'Store', 'Connect Share', None, 'Remove Books', None, 'Help', 'Preferences', ) -gprefs.defaults['action-layout-toolbar-child'] = () +defs['action-layout-toolbar-child'] = () -gprefs.defaults['action-layout-context-menu'] = ( +defs['action-layout-context-menu'] = ( 'Edit Metadata', 'Send To Device', 'Save To Disk', 'Connect Share', 'Copy To Library', None, 'Convert Books', 'View', 'Open Folder', 'Show Book Details', 'Similar Books', 'Tweak ePub', None, 'Remove Books', ) -gprefs.defaults['action-layout-context-menu-device'] = ( +defs['action-layout-context-menu-device'] = ( 'View', 'Save To Disk', None, 'Remove Books', None, 'Add To Library', 'Edit Collections', ) -gprefs.defaults['action-layout-context-menu-cover-browser'] = ( +defs['action-layout-context-menu-cover-browser'] = ( 'Edit Metadata', 'Send To Device', 'Save To Disk', 'Connect Share', 'Copy To Library', None, 'Convert Books', 'View', 'Open Folder', 'Show Book Details', 'Similar Books', 'Tweak ePub', None, 'Remove Books', ) -gprefs.defaults['show_splash_screen'] = True -gprefs.defaults['toolbar_icon_size'] = 'medium' -gprefs.defaults['automerge'] = 'ignore' -gprefs.defaults['toolbar_text'] = 'always' -gprefs.defaults['font'] = None -gprefs.defaults['tags_browser_partition_method'] = 'first letter' -gprefs.defaults['tags_browser_collapse_at'] = 100 -gprefs.defaults['tag_browser_dont_collapse'] = [] -gprefs.defaults['edit_metadata_single_layout'] = 'default' -gprefs.defaults['default_author_link'] = 'http://en.wikipedia.org/w/index.php?search={author}' -gprefs.defaults['preserve_date_on_ctl'] = True -gprefs.defaults['manual_add_auto_convert'] = False -gprefs.defaults['cb_fullscreen'] = False -gprefs.defaults['worker_max_time'] = 0 -gprefs.defaults['show_files_after_save'] = True -gprefs.defaults['auto_add_path'] = None -gprefs.defaults['auto_add_check_for_duplicates'] = False -gprefs.defaults['blocked_auto_formats'] = [] -gprefs.defaults['auto_add_auto_convert'] = True -gprefs.defaults['ui_style'] = 'calibre' if iswindows or isosx else 'system' -gprefs.defaults['tag_browser_old_look'] = False -gprefs.defaults['book_list_tooltips'] = True -gprefs.defaults['bd_show_cover'] = True -gprefs.defaults['bd_overlay_cover_size'] = False -gprefs.defaults['tags_browser_category_icons'] = {} +defs['show_splash_screen'] = True +defs['toolbar_icon_size'] = 'medium' +defs['automerge'] = 'ignore' +defs['toolbar_text'] = 'always' +defs['font'] = None +defs['tags_browser_partition_method'] = 'first letter' +defs['tags_browser_collapse_at'] = 100 +defs['tag_browser_dont_collapse'] = [] +defs['edit_metadata_single_layout'] = 'default' +defs['default_author_link'] = 'http://en.wikipedia.org/w/index.php?search={author}' +defs['preserve_date_on_ctl'] = True +defs['manual_add_auto_convert'] = False +defs['cb_fullscreen'] = False +defs['worker_max_time'] = 0 +defs['show_files_after_save'] = True +defs['auto_add_path'] = None +defs['auto_add_check_for_duplicates'] = False +defs['blocked_auto_formats'] = [] +defs['auto_add_auto_convert'] = True +defs['ui_style'] = 'calibre' if iswindows or isosx else 'system' +defs['tag_browser_old_look'] = False +defs['book_list_tooltips'] = True +defs['bd_show_cover'] = True +defs['bd_overlay_cover_size'] = False +defs['tags_browser_category_icons'] = {} +defs['cover_browser_reflections'] = True +del defs # }}} NONE = QVariant() #: Null value to return from the data function of item models diff --git a/src/calibre/gui2/convert/pdf_output.py b/src/calibre/gui2/convert/pdf_output.py index e0674d066c..98334d1709 100644 --- a/src/calibre/gui2/convert/pdf_output.py +++ b/src/calibre/gui2/convert/pdf_output.py @@ -22,7 +22,7 @@ class PluginWidget(Widget, Ui_Form): 'override_profile_size', 'paper_size', 'custom_size', 'preserve_cover_aspect_ratio', 'pdf_serif_family', 'unit', 'pdf_sans_family', 'pdf_mono_family', 'pdf_standard_font', - 'pdf_default_font_size', 'pdf_mono_font_size']) + 'pdf_default_font_size', 'pdf_mono_font_size', 'pdf_page_numbers']) self.db, self.book_id = db, book_id for x in get_option('paper_size').option.choices: diff --git a/src/calibre/gui2/convert/pdf_output.ui b/src/calibre/gui2/convert/pdf_output.ui index 5e3c4c9137..a4d184d6bc 100644 --- a/src/calibre/gui2/convert/pdf_output.ui +++ b/src/calibre/gui2/convert/pdf_output.ui @@ -84,7 +84,7 @@ - + Se&rif family: @@ -94,10 +94,10 @@ - + - + &Sans family: @@ -107,10 +107,10 @@ - + - + &Monospace family: @@ -120,10 +120,10 @@ - + - + S&tandard font: @@ -133,10 +133,10 @@ - + - + Default font si&ze: @@ -146,14 +146,14 @@ - + px - + Monospace &font size: @@ -163,14 +163,14 @@ - + px - + Qt::Vertical @@ -183,6 +183,13 @@ + + + + Add page &numbers to the bottom of every page + + + diff --git a/src/calibre/gui2/cover_flow.py b/src/calibre/gui2/cover_flow.py index b7cebee2c0..8a7beb811c 100644 --- a/src/calibre/gui2/cover_flow.py +++ b/src/calibre/gui2/cover_flow.py @@ -106,6 +106,8 @@ if pictureflow is not None: self.setContextMenuPolicy(Qt.DefaultContextMenu) if hasattr(self, 'setSubtitleFont'): self.setSubtitleFont(QFont(rating_font())) + if not gprefs['cover_browser_reflections']: + self.setShowReflections(False) def set_context_menu(self, cm): self.context_menu = cm diff --git a/src/calibre/gui2/pictureflow/pictureflow.cpp b/src/calibre/gui2/pictureflow/pictureflow.cpp index 88fff1fd2c..e26309f4cf 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.cpp +++ b/src/calibre/gui2/pictureflow/pictureflow.cpp @@ -340,6 +340,9 @@ public: int currentSlide() const; void setCurrentSlide(int index); + bool showReflections() const; + void setShowReflections(bool show); + int getTarget() const; void showPrevious(); @@ -378,6 +381,7 @@ private: int slideHeight; int fontSize; int queueLength; + bool doReflections; int centerIndex; SlideInfo centerSlide; @@ -416,6 +420,7 @@ PictureFlowPrivate::PictureFlowPrivate(PictureFlow* w, int queueLength_) slideWidth = 200; slideHeight = 200; fontSize = 10; + doReflections = true; centerIndex = 0; queueLength = queueLength_; @@ -494,6 +499,15 @@ void PictureFlowPrivate::setCurrentSlide(int index) widget->emitcurrentChanged(centerIndex); } +bool PictureFlowPrivate::showReflections() const { + return doReflections; +} + +void PictureFlowPrivate::setShowReflections(bool show) { + doReflections = show; + triggerRender(); +} + void PictureFlowPrivate::showPrevious() { if(step >= 0) @@ -584,7 +598,7 @@ void PictureFlowPrivate::resetSlides() } } -static QImage prepareSurface(QImage img, int w, int h) +static QImage prepareSurface(QImage img, int w, int h, bool doReflections) { img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); @@ -602,19 +616,21 @@ static QImage prepareSurface(QImage img, int w, int h) for(int y = 0; y < h; y++) result.setPixel(y, x, img.pixel(x, y)); - // create the reflection - int ht = hs - h; - for(int x = 0; x < w; x++) - for(int y = 0; y < ht; y++) - { - QRgb color = img.pixel(x, img.height()-y-1); - //QRgb565 color = img.scanLine(img.height()-y-1) + x*sizeof(QRgb565); //img.pixel(x, img.height()-y-1); - int a = qAlpha(color); - int r = qRed(color) * a / 256 * (ht - y) / ht * 3/5; - int g = qGreen(color) * a / 256 * (ht - y) / ht * 3/5; - int b = qBlue(color) * a / 256 * (ht - y) / ht * 3/5; - result.setPixel(h+y, x, qRgb(r, g, b)); - } + if (doReflections) { + // create the reflection + int ht = hs - h; + for(int x = 0; x < w; x++) + for(int y = 0; y < ht; y++) + { + QRgb color = img.pixel(x, img.height()-y-1); + //QRgb565 color = img.scanLine(img.height()-y-1) + x*sizeof(QRgb565); //img.pixel(x, img.height()-y-1); + int a = qAlpha(color); + int r = qRed(color) * a / 256 * (ht - y) / ht * 3/5; + int g = qGreen(color) * a / 256 * (ht - y) / ht * 3/5; + int b = qBlue(color) * a / 256 * (ht - y) / ht * 3/5; + result.setPixel(h+y, x, qRgb(r, g, b)); + } + } return result; } @@ -652,12 +668,12 @@ QImage* PictureFlowPrivate::surface(int slideIndex) painter.setBrush(QBrush()); painter.drawRect(2, 2, slideWidth-3, slideHeight-3); painter.end(); - blankSurface = prepareSurface(blankSurface, slideWidth, slideHeight); + blankSurface = prepareSurface(blankSurface, slideWidth, slideHeight, doReflections); } return &blankSurface; } - surfaceCache.insert(slideIndex, new QImage(prepareSurface(img, slideWidth, slideHeight))); + surfaceCache.insert(slideIndex, new QImage(prepareSurface(img, slideWidth, slideHeight, doReflections))); return surfaceCache[slideIndex]; } @@ -1196,6 +1212,13 @@ QImage PictureFlow::slide(int index) const return d->slide(index); } +bool PictureFlow::showReflections() const { + return d->showReflections(); +} + +void PictureFlow::setShowReflections(bool show) { + d->setShowReflections(show); +} void PictureFlow::setImages(FlowImages *images) { diff --git a/src/calibre/gui2/pictureflow/pictureflow.h b/src/calibre/gui2/pictureflow/pictureflow.h index c5a9c76190..bc427e8580 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.h +++ b/src/calibre/gui2/pictureflow/pictureflow.h @@ -121,6 +121,12 @@ public: */ void setSlideSize(QSize size); + /*! + Turn the reflections on/off. + */ + void setShowReflections(bool show); + bool showReflections() const; + /*! Returns the font used to render subtitles */ diff --git a/src/calibre/gui2/pictureflow/pictureflow.sip b/src/calibre/gui2/pictureflow/pictureflow.sip index 21c6209df5..0fab379147 100644 --- a/src/calibre/gui2/pictureflow/pictureflow.sip +++ b/src/calibre/gui2/pictureflow/pictureflow.sip @@ -51,6 +51,10 @@ public : int currentSlide() const; + bool showReflections() const; + + void setShowReflections(bool show); + public slots: void setCurrentSlide(int index); diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py index b3423e5a8c..54b5e3a625 100644 --- a/src/calibre/gui2/preferences/look_feel.py +++ b/src/calibre/gui2/preferences/look_feel.py @@ -110,6 +110,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('bd_overlay_cover_size', gprefs) r('cover_flow_queue_length', config, restart_required=True) + r('cover_browser_reflections', gprefs) def get_esc_lang(l): if l == 'en': @@ -289,6 +290,8 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): self.update_font_display() gui.tags_view.reread_collapse_parameters() gui.library_view.refresh_book_details() + if gui.cover_flow is not None: + gui.cover_flow.setShowReflections(gprefs['cover_browser_reflections']) if __name__ == '__main__': from calibre.gui2 import Application diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui index fe6d9ecb62..5074eaf4e6 100644 --- a/src/calibre/gui2/preferences/look_feel.ui +++ b/src/calibre/gui2/preferences/look_feel.ui @@ -496,10 +496,7 @@ a few top-level elements. - - - - + Qt::Vertical @@ -512,14 +509,17 @@ a few top-level elements. - + + + + When showing cover browser in separate window, show it &fullscreen - + margin-left: 1.5em @@ -532,6 +532,13 @@ a few top-level elements. + + + + Show &reflections in the cover browser + + +