|
![]() |
|
Thread Tools | Search this Thread |
![]() |
#1 |
Enthusiast
![]() Posts: 25
Karma: 50
Join Date: Apr 2016
Device: calibre
|
Rules, templates, and functions for column coloring and composed icons
I want to visually format my library (the column grid) as follows:
1) Color all columns red if the book contains no ebook formats (although it might have other formats, such as LNK or MP3). 2) Fill a column with "composed icons" (a series of icons) to represent different statuses of the book: a) if I own a physical copy of the book (#own:"=p") b) if the book is part of a series c) if the book has a LNK format (a folder shortcut) There seem to be many different ways to accomplish the above. Following are some of the things I've tried. Some work, and I'm requesting help to fix the things that don't. Ideally I would like to use the most efficient method possible, to minimize any impact on calibre's performance. So, to the best of my knowedge, the methods I describe below are arranged in order of increasing efficiency (but please correct me if I'm wrong ![]() METHOD 1 - Basic rules - THIS WORKS 1) Color all columns red if the book contains no ebook formats: Preferences > Look and Feel > Column coloring: Set the color of <All Columns> to <red> if the <Formats> column <does not have> values <EPUB, MOBI, PDF> (Note: Since a book might have other formats such as LNK or MP3, I can't just use the rule: if the <Formats> column <is not set>.) 2) Fill a column with "composed icons": Preferences > Look and Feel > Column icons: Set the <composed icons w/no text> of <Icons> to <book.png> if the <Own> column <has> value <p> Set the <composed icons w/no text> of <Icons> to <series.png> if the <Series> column <is set> Set the <composed icons w/no text> of <Icons> to <folder.png> if the <Formats> column <has> value <LNK> METHOD 2 - Multiple advanced rules for column icons - THIS WORKS Preferences > Look and Feel > Column icons: Advanced Rule: Set <composed icons w/no text> for column <Icons>: program: contains(field('#own'), 'p', 'book.png', '') Advanced Rule: Set <composed icons w/no text> for column <Icons>: program: test(field('series'), 'series.png', '') Advanced Rule: Set <composed icons w/no text> for column <Icons>: program: contains(approximate_formats(), 'LNK', 'folder.png', '') METHOD 3 - Single advanced rule for column icons - PARTIALLY WORKS Advanced Rule: Set <composed icons w/no text> for column <Icons>: Code:
program: list_union( '', strcat( contains(field('#own'), 'p', 'book.png,', ''), test(field('series'), 'series.png', ''), contains(approximate_formats(), 'LNK', 'folder.png,', ''), ), ',') Note: I got the idea for the above rule from chaley's posts here and here. METHOD 4 - User-defined template functions As chaley has suggested (e.g. here), a custom template function would probably be the most efficient method, but I haven't been able to get very far. For example: 1) Color all columns red if the book contains no ebook formats: Preferences > Look and Feel > Template Functions: name: has_ebook arg count: 1 doc: has_ebook(val) -- evaluate whether 'val' (passed as 'approximate_formats()') has any of the given ebook formats, and return "true" or "false" program code: Code:
def evaluate(self, formatter, kwargs, mi, locals, val): contains(val, 'EPUB|MOBI|PDF', 'true', 'false') Column type: Column built from other columns Template (press F2 in grid to edit): Code:
program: f = approximate_formats(); has_ebook(f) EXCEPTION: global name 'contains' is not defined If you've made it this far, thanks for reading! It's been an interesting exploration, and I'd be very grateful for any feedback. ![]() calibre 2.63 [64bit] on Windows 10 Pro |
![]() |
![]() |
![]() |
#2 | ||
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,365
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
1) The template must return a colon-separated list, not a comma-separated list. 2) 'series.png' does not contain a separator. The following template, adapted from yours to use a column and icons I have available, works. Code:
program: list_union( '', strcat( contains(field('#enum'), 'two', 'add_book.png:', ''), test(field('series'), 'arrow-up.png:', ''), contains(approximate_formats(), 'epub', 'debug.png:', ''), ), ':') Quote:
Code:
def evaluate(self, formatter, kwargs, mi, locals): import re fmt_data = mi._proxy_metadata.db_approx_formats fmt_data = ','.join(v.upper() for v in fmt_data) return '' if re.search('EPUB|MOBI|PDF', fmt_data) is None else 'Yes' You would call it like this: Code:
program: has_ebook() |
||
![]() |
![]() |
Advert | |
|
![]() |
#3 | |||
Enthusiast
![]() Posts: 25
Karma: 50
Join Date: Apr 2016
Device: calibre
|
Quote:
![]() I modified it to display blank icons if a match is not found. This aligns the icons so that they are always displayed in the same position. Code:
program: list_union( '', strcat( contains(field('#own'), 'p', 'book.png:', 'blank.png:'), test(field('series'), 'series.png:', 'blank.png:'), contains(approximate_formats(), 'LNK', 'folder.png:', 'blank.png:'), ), ':') Quote:
![]() Quote:
I am now using the has_ebook() function you provided as follows: Preferences > Look and Feel > Column coloring: Advanced Rule for <All Columns>: Code:
program: test(has_ebook(), '', 'red') Even though I've dabbled in programming over the years, I don't know Python, and there's a lot in your function that I don't understand. Creating a function instead of a template for the composed icons may be beyond me. So thanks for helping me to get this far. ![]() Last edited by readin; 08-11-2016 at 11:30 AM. Reason: correction |
|||
![]() |
![]() |
![]() |
#4 | ||
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,365
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
You are welcome. It is fun to work with people who do their homework.
![]() Quote:
Code:
def evaluate(self, formatter, kwargs, mi, locals, color): import re fmt_data = mi._proxy_metadata.db_approx_formats fmt_data = ','.join(v.upper() for v in fmt_data) return '' if re.search('EPUB|MOBI|PDF', fmt_data) is None else color Given that it returns 'color' without change, you could use the same function for an icon simply by passing 'foo.png' instead of 'red'. Quote:
|
||
![]() |
![]() |
![]() |
#5 | |||
Enthusiast
![]() Posts: 25
Karma: 50
Join Date: Apr 2016
Device: calibre
|
Quote:
![]() Quote:
![]() ![]() Quote:
Code:
program: strcat( icon_if_set('series', 'series'), ':', icon_if_fmt('LNK', 'folder'), ) Code:
name: icon_if_set arg count: 2 doc: icon_if_set(field, icon) -- if 'field' value is set, returns icon filename ('icon' + '.png:'), else returns 'blank.png' program code: def evaluate(self, formatter, kwargs, mi, locals, field, icon): if mi.get(field): return icon + '.png' return 'blank.png' Code:
name: icon_if_fmt arg count: 2 doc: icon_if_fmt(format, icon) -- if format is found, returns icon filename ('icon' + '.png'), else returns 'blank.png' program code: def evaluate(self, formatter, kwargs, mi, locals, format, icon): import re fmt_data = mi._proxy_metadata.db_approx_formats fmt_data = ','.join(v.upper() for v in fmt_data) if re.search(format, fmt_data): return icon + '.png' return 'blank.png' Code:
name: icon_if_val arg count: 3 doc: icon_if_val(field, val, icon) -- if 'field' contains 'val', returns icon filename ('icon' + '.png'), else returns 'blank.png' program code: def evaluate(self, formatter, kwargs, mi, locals, field, val, icon): import re if re.search(val, mi.get(field)): return icon + '.png' return 'blank.png' EXCEPTION: expected string or buffer |
|||
![]() |
![]() |
Advert | |
|
![]() |
#6 |
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,365
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Thinking about this a bit more, I think that the best solution is
Code:
program: contains(approximate_formats(), 'EPUB|MOBI|PDF', 'red', '')
Code:
program: list_re(approximate_formats(), ',', '^(EPUB|MOBI|PDF)$', 'red'); Alternatively you could do the same thing as a custom template function, which will be faster because it isn't as general as list_re. Code:
def evaluate(self, formatter, kwargs, mi, locals, color): import re fmt_data = mi._proxy_metadata.db_approx_formats for f in fmt_data: if re.search('^(EPUB|MOBI|PDF)$', f): return color return '' |
![]() |
![]() |
![]() |
#7 | |
Grand Sorcerer
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() Posts: 12,365
Karma: 8012652
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
Code:
import re f = ','.join(mi.get(field)) if re.search(val, f): Code:
import re f = mi.get(field) if isinstance(f, list): f = ','.join(f) if re.search(val, f): ![]() |
|
![]() |
![]() |
![]() |
#8 |
Enthusiast
![]() Posts: 25
Karma: 50
Join Date: Apr 2016
Device: calibre
|
True, but you're very good at explaining!
![]() Here's what I have now: 1) An advanced rule for coloring books if they don't have an ebook format: Code:
program: contains(approximate_formats(), 'EPUB|MOBI|PDF', '', 'red') Code:
program: strcat( icon_if_val('#own', 'p', 'book'), ':', icon_if_set('series', 'series'), ':', icon_if_fmt('LNK', 'folder') ) Code:
name: icon_if_val arg count: 3 doc: icon_if_val(field, val, icon) -- if 'field' contains 'val', returns icon filename ('icon' + '.png'), else returns 'blank.png' program code: def evaluate(self, formatter, kwargs, mi, locals, field, val, icon): import re f = mi.get(field) # if 'field' is an array (like tags), convert it to a CSV list: if isinstance(f, list): f = ','.join(f) if re.search(val, f): return icon + '.png' return 'blank.png' Code:
name: icon_if_set arg count: 2 doc: icon_if_set(field, icon) -- if 'field' value is set, returns icon filename ('icon' + '.png:'), else returns 'blank.png' program code: def evaluate(self, formatter, kwargs, mi, locals, field, icon): if mi.get(field): return icon + '.png' return 'blank.png' Code:
name: icon_if_fmt arg count: 2 doc: icon_if_fmt(format, icon) -- if format is found, returns icon filename ('icon' + '.png'), else returns 'blank.png' program code: def evaluate(self, formatter, kwargs, mi, locals, format, icon): import re fmt_data = mi._proxy_metadata.db_approx_formats fmt_data = ','.join(v.upper() for v in fmt_data) if re.search(format, fmt_data): return icon + '.png' return 'blank.png' ![]() Everything seems to be working perfectly. Thanks so much for all your help! ![]() |
![]() |
![]() |
![]() |
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
Column coloring rules | BookJunkieLI | Library Management | 7 | 12-06-2014 05:18 PM |
question on column coloring | Jade Aislin | Library Management | 3 | 07-09-2012 09:54 AM |
column coloring | iomari | Calibre | 1 | 05-08-2012 07:43 AM |
How do YOU use column coloring? | gweminence | Calibre | 28 | 05-04-2012 01:16 AM |
Trouble with column coloring | redawgts | Calibre | 2 | 10-09-2011 03:13 AM |