mirror of
https://github.com/kovidgoyal/calibre.git
synced 2026-03-12 12:51:07 -04:00
705 lines
30 KiB
Plaintext
705 lines
30 KiB
Plaintext
# vim:fileencoding=utf-8
|
|
# License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
|
|
from __python__ import bound_methods, hash_literals
|
|
|
|
from elementmaker import E
|
|
from gettext import gettext as _
|
|
|
|
from dom import add_extra_css, build_rule, clear, ensure_id
|
|
from utils import safe_set_inner_html
|
|
from widgets import create_button
|
|
|
|
CLASS_NAME = 'conversion-option-group'
|
|
indent = '↳\xa0'
|
|
|
|
add_extra_css(def():
|
|
style = ''
|
|
sel = '.' + CLASS_NAME + ' '
|
|
style += build_rule(sel + 'input[type="checkbox"]', margin_left='0')
|
|
style += build_rule(sel + '[data-option-name]', margin_bottom='1ex', display='block', padding_bottom='0.5ex')
|
|
style += build_rule(sel + '.simple-group > label', display='table-row')
|
|
style += build_rule(sel + '.simple-group > label > *', display='table-cell', padding_bottom='1ex', padding_right='1rem')
|
|
style += build_rule(sel + 'label.vertical', display='block')
|
|
style += build_rule(sel + 'label.vertical > *', display='block', padding_bottom='1ex', padding_right='1rem')
|
|
style += build_rule(sel + '[data-profile]', margin_left='2em', text_indent='-2em', font_size='smaller', margin_bottom='1ex')
|
|
style += build_rule(sel + '.subset-choice label', display='block', margin_bottom='1ex')
|
|
return style
|
|
)
|
|
|
|
|
|
# globals {{{
|
|
container_id = None
|
|
get_option_value = get_option_default_value = is_option_disabled = get_option_help = profiles = ui_data = None
|
|
entry_points = {}
|
|
registry = {}
|
|
listeners = {}
|
|
|
|
|
|
def ep(func):
|
|
entry_points[func.name] = func
|
|
return func
|
|
|
|
|
|
def add_listener(name, callback):
|
|
if not listeners[name]:
|
|
listeners[name] = v'[]'
|
|
listeners[name].push(callback)
|
|
|
|
|
|
def on_change(name):
|
|
if listeners[name]:
|
|
for callback in listeners[name]:
|
|
callback(name)
|
|
|
|
|
|
def sanitize_accelerator(text):
|
|
return text.replace('&', '')
|
|
# }}}
|
|
|
|
def subset_choice(name, choices, tooltip=None): # {{{
|
|
if get_option_default_value(name) is undefined:
|
|
raise KeyError(f'{name} is not a known option')
|
|
ans = E.div(data_option_name=name, class_='subset-choice')
|
|
if tooltip is not None:
|
|
ans.setAttribute('title', tooltip or get_option_help(name))
|
|
names = Object.keys(choices)
|
|
for cname in names:
|
|
ans.appendChild(E.label(E.input(type='checkbox', name=cname), '\xa0' + choices[cname]))
|
|
ops = {
|
|
'get': def (container):
|
|
ans = v'[]'
|
|
for w in container.querySelectorAll('input'):
|
|
if w.checked:
|
|
ans.push(w.name)
|
|
return ','.join(ans)
|
|
,
|
|
'set': def (container, val):
|
|
q = {x.strip():True for x in (val or '').split(',')}
|
|
for w in container.querySelectorAll('input'):
|
|
w.checked = bool(q[w.name])
|
|
,
|
|
'set_disabled': def (container, val):
|
|
pass
|
|
}
|
|
registry[name] = ops
|
|
ops.set(ans, get_option_value(name))
|
|
return ans
|
|
# }}}
|
|
|
|
def create_simple_widget(name, text, tooltip, input_widget_, getter, setter, suffix): # {{{
|
|
if get_option_default_value(name) is undefined:
|
|
raise KeyError(f'{name} is not a known option')
|
|
if not text.endswith(':'):
|
|
text = text + ':'
|
|
label = E.label(E.span(sanitize_accelerator(text)), E.span(input_widget_))
|
|
if suffix:
|
|
label.lastChild.appendChild(document.createTextNode('\xa0' + suffix))
|
|
label.dataset.optionName = name
|
|
label.setAttribute('title', tooltip or get_option_help(name))
|
|
|
|
def straight_input_widget(container):
|
|
return container.lastChild.firstChild
|
|
|
|
input_widget = straight_input_widget
|
|
|
|
ops = {
|
|
'get': def (container):
|
|
return getter(input_widget(container))
|
|
,
|
|
'set': def (container, val):
|
|
setter(input_widget(container), val)
|
|
,
|
|
'set_disabled': def (container, val):
|
|
if val:
|
|
container.classList.add('disabled')
|
|
input_widget(container).setAttribute('disabled', 'disabled')
|
|
else:
|
|
container.classList.remove('disabled')
|
|
input_widget(container).removeAttribute('disabled')
|
|
}
|
|
registry[name] = ops
|
|
ops.set(label, get_option_value(name))
|
|
if is_option_disabled(name):
|
|
ops.set_disabled(label, True)
|
|
input_widget(label).addEventListener('change', on_change.bind(None, name))
|
|
if listeners[name]:
|
|
window.setTimeout(on_change.bind(None, name), 0)
|
|
return label
|
|
# }}}
|
|
|
|
def checkbox(name, text, tooltip): # {{{
|
|
return create_simple_widget(name, text, tooltip, E.input(type='checkbox'),
|
|
def getter(w): # noqa: unused-local
|
|
return bool(w.checked)
|
|
,
|
|
def setter(w, val): # noqa: unused-local
|
|
w.checked = bool(val)
|
|
,
|
|
)
|
|
# }}}
|
|
|
|
def lineedit(name, text, width=25, tooltip=None, suffix=None): # {{{
|
|
return create_simple_widget(name, text, tooltip, E.input(type='text', size=str(width)),
|
|
def getter(w): # noqa: unused-local
|
|
ans = w.value
|
|
if ans and ans.strip():
|
|
return ans.strip()
|
|
,
|
|
def setter(w, val): # noqa: unused-local
|
|
w.value = val or ''
|
|
, suffix=suffix
|
|
)
|
|
# }}}
|
|
|
|
def float_spin(name, text, tooltip=None, step=0.1, min=0, max=100, unit=None): # {{{
|
|
f = E.input(type='number', step=str(step), min=str(min), max=str(max), required=True)
|
|
defval = get_option_default_value(name)
|
|
return create_simple_widget(name, text, tooltip, f,
|
|
def getter(w): # noqa: unused-local
|
|
try:
|
|
return float(w.value)
|
|
except:
|
|
return defval
|
|
,
|
|
def setter(w, val): # noqa: unused-local
|
|
w.value = str(float(val))
|
|
,
|
|
suffix=unit
|
|
)
|
|
# }}}
|
|
|
|
def int_spin(name, text, tooltip=None, step=1, min=0, max=100, unit=None): # {{{
|
|
f = E.input(type='number', step=str(step), min=str(min), max=str(max), required=True)
|
|
defval = get_option_default_value(name)
|
|
return create_simple_widget(name, text, tooltip, f,
|
|
def getter(w): # noqa: unused-local
|
|
try:
|
|
return int(w.value)
|
|
except:
|
|
return defval
|
|
,
|
|
def setter(w, val): # noqa: unused-local
|
|
w.value = str(int(val))
|
|
,
|
|
suffix=unit
|
|
)
|
|
# }}}
|
|
|
|
def choices(name, text, choices, tooltip): # {{{
|
|
f = E.select()
|
|
if Array.isArray(choices):
|
|
for key in choices:
|
|
f.appendChild(E.option(key, value=key))
|
|
else:
|
|
for key in choices:
|
|
f.appendChild(E.option(choices[key], value=key))
|
|
|
|
return create_simple_widget(name, text, tooltip, f,
|
|
def getter(w): # noqa: unused-local
|
|
return w.value
|
|
,
|
|
def setter(w, val): # noqa: unused-local
|
|
w.value = val
|
|
)
|
|
# }}}
|
|
|
|
def textarea(name, text, tooltip): # {{{
|
|
ans = create_simple_widget(name, text, tooltip, E.textarea(rows='30', cols='70'),
|
|
def getter(w): # noqa: unused-local
|
|
ans = w.value
|
|
if ans and ans.strip():
|
|
return ans.strip()
|
|
,
|
|
def setter(w, val): # noqa: unused-local
|
|
w.value = val or ''
|
|
)
|
|
ans.classList.add('vertical')
|
|
return ans
|
|
# }}}
|
|
|
|
def container_for_option(name):
|
|
return document.getElementById(container_id).querySelector(f'[data-option-name="{name}"]')
|
|
|
|
|
|
def get(name):
|
|
return registry[name].get(container_for_option(name))
|
|
|
|
|
|
def set(name, val):
|
|
registry[name].set(container_for_option(name), val)
|
|
|
|
|
|
def set_disabled(name, val):
|
|
registry[name].set_disabled(container_for_option(name), val)
|
|
|
|
|
|
# Look & feel {{{
|
|
@ep
|
|
def look_and_feel(container):
|
|
def subhead(text):
|
|
container.appendChild(E.div(
|
|
style='border-bottom: solid 1px currentColor; margin-bottom: 1ex; max-width: 35em', E.b(sanitize_accelerator(text))))
|
|
|
|
subhead(_('&Fonts'))
|
|
add_listener('disable_font_rescaling', def (name):
|
|
disabled = get('disable_font_rescaling')
|
|
for dname in 'font_size_mapping', 'base_font_size':
|
|
set_disabled(dname, disabled)
|
|
)
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('disable_font_rescaling', _('&Disable font size rescaling')))
|
|
g.appendChild(float_spin('base_font_size', _('Base font si&ze:'), max=50, unit='pt'))
|
|
g.appendChild(lineedit('font_size_mapping', _('Font size &key:')))
|
|
g.appendChild(float_spin('minimum_line_height', _('Minim&um line height:'), max=900, unit='%'))
|
|
g.appendChild(float_spin('line_height', _('Line hei&ght:'), unit='%'))
|
|
g.appendChild(lineedit('embed_font_family', _('Embed font fami&ly:')))
|
|
g.appendChild(checkbox('embed_all_fonts', _('&Embed all fonts in document')))
|
|
g.appendChild(checkbox('subset_embedded_fonts', _('&Subset all embedded fonts')))
|
|
g.appendChild(checkbox('keep_ligatures', _('Keep &ligatures')))
|
|
|
|
subhead(_('Te&xt'))
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(lineedit('input_encoding', _('I&nput character encoding:')))
|
|
g.appendChild(choices('change_justification', _('Text &justification:'),
|
|
{'original': _('Original'), 'left': _('Left align'), 'justify': _('Justify text')}
|
|
))
|
|
g.appendChild(checkbox('smarten_punctuation', _('Smarten &punctuation')))
|
|
g.appendChild(checkbox('unsmarten_punctuation', _('&UnSmarten punctuation')))
|
|
g.appendChild(checkbox('asciiize', _('&Transliterate unicode characters to ASCII')))
|
|
|
|
subhead(_('Lay&out'))
|
|
add_listener('remove_paragraph_spacing', def (name):
|
|
disabled = get('remove_paragraph_spacing')
|
|
set_disabled('remove_paragraph_spacing_indent_size', not disabled)
|
|
)
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('remove_paragraph_spacing', _('Remove &spacing between paragraphs')))
|
|
g.appendChild(float_spin('remove_paragraph_spacing_indent_size', indent + _('I&ndent size:'), min=-0.1, unit='em'))
|
|
g.appendChild(checkbox('insert_blank_line', _('Insert &blank line between paragraphs')))
|
|
g.appendChild(float_spin('insert_blank_line_size', indent + _('&Line size:'), unit='em'))
|
|
g.appendChild(checkbox('linearize_tables', _('&Linearize tables')))
|
|
|
|
subhead(_('St&yling'))
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(lineedit('filter_css', _('Filter Style Information'), 40))
|
|
container.appendChild(textarea('extra_css', 'E&xtra CSS'))
|
|
# }}}
|
|
|
|
# Heuristics {{{
|
|
@ep
|
|
def heuristics(container):
|
|
settings = v'[]'
|
|
def add(func, name, text, **kw):
|
|
g.appendChild(func(name, text, **kw))
|
|
settings.push(name)
|
|
|
|
add_listener('enable_heuristics', def (name):
|
|
disabled = not get('enable_heuristics')
|
|
for dname in settings:
|
|
set_disabled(dname, disabled)
|
|
)
|
|
blurb = _(
|
|
'<b>Heuristic processing</b> means that calibre will scan your book for common patterns and fix them.'
|
|
' As the name implies, this involves guesswork, which means that it could end up worsening the result'
|
|
' of a conversion, if calibre guesses wrong. Therefore, it is disabled by default. Often, if a conversion'
|
|
' does not turn out as you expect, turning on heuristics can improve matters. Read more about the various'
|
|
' heuristic processing options in the <a href="%s">User Manual</a>.''').replace(
|
|
'%s', 'https://manual.calibre-ebook.com/conversion.html#heuristic-processing')
|
|
container.appendChild(E.div(style='margin-bottom: 1ex'))
|
|
safe_set_inner_html(container.lastChild, blurb)
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('enable_heuristics', _('Enable &heuristic processing')))
|
|
add(checkbox, 'unwrap_lines', _('Unwrap lines'))
|
|
add(float_spin, 'html_unwrap_factor', indent + _('Line &un-wrap factor:'), max=1, step=0.05)
|
|
|
|
add(checkbox, 'markup_chapter_headings', _('Detect and markup unformatted chapter headings and sub headings'))
|
|
add(checkbox, 'renumber_headings', _('Renumber sequences of <h1> or <h2> tags to prevent splitting'))
|
|
add(checkbox, 'delete_blank_paragraphs', _('Delete blank lines between paragraphs'))
|
|
add(checkbox, 'format_scene_breaks', _('Ensure scene breaks are consistently formatted'))
|
|
add(lineedit, 'replace_scene_breaks', _('Rep&lace soft scene breaks:'))
|
|
add(checkbox, 'dehyphenate', _('Remove unnecessary hyphens'))
|
|
add(checkbox, 'italicize_common_cases', _('Italicize common words and patterns'))
|
|
add(checkbox, 'fix_indents', _('Replace entity indents with CSS indents'))
|
|
# }}}
|
|
|
|
# Page setup {{{
|
|
@ep
|
|
def page_setup(container):
|
|
def show_profile_desc(name):
|
|
profile = get(name)
|
|
data = profiles.input if name is 'input_profile' else profiles.output
|
|
profile = data[profile]
|
|
container_for_option(name).parentNode.querySelector('[data-profile="{}"'.format(
|
|
'input' if name is 'input_profile' else 'output')).textContent = indent + profile.description
|
|
|
|
add_listener('input_profile', show_profile_desc)
|
|
add_listener('output_profile', show_profile_desc)
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(float_spin('margin_left', _('Left page margin'), unit='pt', step=0.1, min=-1, max=200))
|
|
g.appendChild(float_spin('margin_top', _('Top page margin'), unit='pt', step=0.1, min=-1, max=200))
|
|
g.appendChild(float_spin('margin_right', _('Right page margin'), unit='pt', step=0.1, min=-1, max=200))
|
|
g.appendChild(float_spin('margin_bottom', _('Bottom page margin'), unit='pt', step=0.1, min=-1, max=200))
|
|
g.appendChild(choices('input_profile', _('&Input profile:'), {name: profiles.input[name].name for name in profiles.input}))
|
|
g.appendChild(E.div(data_profile='input'))
|
|
g.appendChild(choices('output_profile', _('&Output profile:'), {name: profiles.output[name].name for name in profiles.output}))
|
|
g.appendChild(E.div(data_profile='output'))
|
|
# }}}
|
|
|
|
# Structure detection {{{
|
|
@ep
|
|
def structure_detection(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(lineedit('chapter', _('Detect chapters at'), 50))
|
|
g.appendChild(choices('chapter_mark', _('Chap&ter mark:'), ['pagebreak', 'rule', 'both', 'none']))
|
|
g.appendChild(checkbox('remove_first_image', _('Remove first &image')))
|
|
g.appendChild(checkbox('remove_fake_margins', _('Remove &fake margins')))
|
|
g.appendChild(checkbox('insert_metadata', _('Insert metadata at start of book')))
|
|
g.appendChild(lineedit('page_breaks_before', _('Insert page breaks before'), 50))
|
|
g.appendChild(lineedit('start_reading_at', _('Start reading at'), 50))
|
|
# }}}
|
|
|
|
# ToC {{{
|
|
@ep
|
|
def toc(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('use_auto_toc', _('&Force use of auto-generated Table of Contents')))
|
|
g.appendChild(checkbox('no_chapters_in_toc', _('Do not add &detected chapters to the Table of Contents')))
|
|
g.appendChild(checkbox('duplicate_links_in_toc', _('Allow &duplicate links when creating the Table of Contents')))
|
|
g.appendChild(int_spin('max_toc_links', _('Number of &links to add to Table of Contents:')))
|
|
g.appendChild(int_spin('toc_threshold', _('Chapter &threshold:')))
|
|
g.appendChild(lineedit('toc_filter', _('TOC &filter:')))
|
|
g.appendChild(lineedit('level1_toc', _('Level &1 TOC (XPath expression):')))
|
|
g.appendChild(lineedit('level2_toc', _('Level &2 TOC (XPath expression):')))
|
|
g.appendChild(lineedit('level3_toc', _('Level &3 TOC (XPath expression):')))
|
|
# }}}
|
|
|
|
# Search & replace {{{
|
|
@ep
|
|
def search_and_replace(container):
|
|
|
|
def add(val):
|
|
c = container_for_option('search_replace')
|
|
c.appendChild(E.div(
|
|
class_='simple-group sr-instance',
|
|
style='border-bottom: solid 1px currentColor; margin-bottom: 1ex',
|
|
E.label(
|
|
E.span(_('Search:')), E.input(type='text', name='search')
|
|
),
|
|
E.label(
|
|
E.span(_('Replace:')), E.input(type='text', name='replace')
|
|
),
|
|
))
|
|
if val and val[0]:
|
|
c.lastChild.querySelector('input[name="search"]').value = val[0]
|
|
c.lastChild.querySelector('input[name="replace"]').value = val[1]
|
|
return c.lastChild
|
|
|
|
container.appendChild(E.div(data_option_name='search_replace'))
|
|
|
|
ops = {
|
|
'get': def get(container): # noqa: unused-local
|
|
ans = v'[]'
|
|
for div in container.querySelectorAll('.sr-instance'):
|
|
search, replace = div.querySelectorAll('input')
|
|
if search.value:
|
|
r = replace.value or '' # noqa: unused-local
|
|
ans.push(v'[search.value, r]')
|
|
return JSON.stringify(ans)
|
|
,
|
|
'set': def set(container, encval): # noqa: unused-local
|
|
try:
|
|
vals = JSON.parse(encval)
|
|
except:
|
|
vals = v'[]'
|
|
vals = vals or v'[]'
|
|
clear(container)
|
|
for val in vals:
|
|
add(val)
|
|
add()
|
|
,
|
|
'set_disabled': def set_disabled(container, disabled): # noqa: unused-local
|
|
pass
|
|
}
|
|
registry['search_replace'] = ops
|
|
ops.set(container.lastChild, get_option_value('search_replace'))
|
|
|
|
container.appendChild(E.div(
|
|
create_button(_('Add'), 'plus', action=def(): add();)
|
|
))
|
|
# }}}
|
|
|
|
# Comic Input {{{
|
|
@ep
|
|
def comic_input(container):
|
|
settings = v'[]'
|
|
def add(func, name, text, **kw):
|
|
g.appendChild(func(name, text, **kw))
|
|
settings.push(name)
|
|
|
|
add_listener('no_process', def (name):
|
|
disabled = get('no_process')
|
|
for dname in settings:
|
|
set_disabled(dname, disabled)
|
|
)
|
|
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('no_process', _('&Disable comic processing')))
|
|
add(checkbox, 'dont_grayscale', _('Disable conversion of images to &black and white'))
|
|
add(checkbox, 'dont_add_comic_pages_to_toc', _('Don\'t add links to &pages to the Table of Contents for CBC files'))
|
|
add(int_spin, 'colors', _('&Number of colors:'), max=256, step=8)
|
|
add(lineedit, 'comic_image_size', _('Override image si&ze:'))
|
|
add(checkbox, 'dont_normalize', _('Disable &normalize'))
|
|
add(checkbox, 'keep_aspect_ratio', _('Keep &aspect ratio'))
|
|
add(checkbox, 'dont_sharpen', _('Disable &Sharpening'))
|
|
add(checkbox, 'disable_trim', _('Disable &Trimming'))
|
|
add(checkbox, 'wide', _('&Wide'))
|
|
add(checkbox, 'landscape', _('&Landscape'))
|
|
add(checkbox, 'right2left', _('&Right to left'))
|
|
add(checkbox, 'no_sort', _('Don\'t so&rt'))
|
|
add(checkbox, 'despeckle', _('De&speckle'))
|
|
g.appendChild(choices('output_format', _('O&utput format:'), v"['png', 'jpg']"))
|
|
settings.push('output_format')
|
|
|
|
# }}}
|
|
|
|
# FB2 Input {{{
|
|
@ep
|
|
def fb2_input(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('no_inline_fb2_toc', _('Do not insert a Table of Contents at the beginning of the book')))
|
|
# }}}
|
|
|
|
# PDF Input {{{
|
|
@ep
|
|
def pdf_input(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(float_spin('unwrap_factor', _('Line &un-wrapping factor:'), max=1, step=0.01))
|
|
g.appendChild(checkbox('no_images', _('No &images')))
|
|
# }}}
|
|
|
|
# RTF Input {{{
|
|
@ep
|
|
def rtf_input(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('ignore_wmf', _('Ignore &WMF images in the RTF file')))
|
|
# }}}
|
|
|
|
# DOCX Input {{{
|
|
@ep
|
|
def docx_input(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('docx_no_cover', _('Do not try to autodetect a &cover from images in the document')))
|
|
g.appendChild(checkbox('docx_no_pagebreaks_between_notes', _('Do not add a page after every &endnote')))
|
|
g.appendChild(checkbox('docx_inline_subsup', _('Render &superscripts and subscripts so that they do not affect the line height')))
|
|
# }}}
|
|
|
|
# TXT Input {{{
|
|
@ep
|
|
def txt_input(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(choices('paragraph_type', _('Para&graph style:'), ui_data.paragraph_types))
|
|
g.appendChild(choices('formatting_type', _('Forma&tting style:'), ui_data.formatting_types))
|
|
g.appendChild(checkbox('preserve_spaces', _('Preserve &spaces')))
|
|
g.appendChild(checkbox('txt_in_remove_indents', _('Remove &indents at the beginning of lines')))
|
|
|
|
container.appendChild(E.div(
|
|
style='margin-top: 1ex',
|
|
_('Allowed Markdown extensions:'),
|
|
E.div(
|
|
style='margin-left: 1em; margin-top: 1ex',
|
|
subset_choice('markdown_extensions', ui_data.md_extensions)
|
|
)
|
|
))
|
|
# }}}
|
|
|
|
# EPUB Output {{{
|
|
@ep
|
|
def epub_output(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('dont_split_on_page_breaks', _('Do not &split on page breaks')))
|
|
g.appendChild(checkbox('no_default_epub_cover', _('No default &cover')))
|
|
g.appendChild(checkbox('epub_flatten', _('&Flatten EPUB file structure')))
|
|
g.appendChild(checkbox('no_svg_cover', _('No &SVG cover')))
|
|
g.appendChild(checkbox('preserve_cover_aspect_ratio', _('Preserve cover &aspect ratio')))
|
|
g.appendChild(checkbox('epub_inline_toc', _('Insert inline &Table of Contents')))
|
|
g.appendChild(checkbox('epub_toc_at_end', _('Put inserted Table of Contents at the &end of the book')))
|
|
g.appendChild(lineedit('toc_title', _('&Title for inserted ToC:')))
|
|
g.appendChild(int_spin('flow_size', _('Split files &larger than:'), unit='KB', max=1000000, step=20))
|
|
g.appendChild(choices('epub_version', _('EP&UB version:'), ui_data.versions))
|
|
# }}}
|
|
|
|
# DOCX Output {{{
|
|
@ep
|
|
def docx_output(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(choices('docx_page_size', _('Paper si&ze:'), ui_data.page_sizes))
|
|
g.appendChild(lineedit('docx_custom_page_size', _('&Custom size:')))
|
|
g.appendChild(float_spin('docx_page_margin_left', _('Page &left margin'), unit='pt', min=-100, max=500))
|
|
g.appendChild(float_spin('docx_page_margin_top', _('Page &top margin'), unit='pt', min=-100, max=500))
|
|
g.appendChild(float_spin('docx_page_margin_right', _('Page &right margin'), unit='pt', min=-100, max=500))
|
|
g.appendChild(float_spin('docx_page_margin_bottom', _('Page &bottom margin'), unit='pt', min=-100, max=500))
|
|
g.appendChild(checkbox('docx_no_toc', _('Do not insert the &Table of Contents as a page at the start of the document')))
|
|
g.appendChild(checkbox('docx_no_cover', _('Do not insert &cover as image at start of document')))
|
|
g.appendChild(checkbox('preserve_cover_aspect_ratio', _('Preserve the aspect ratio of the image inserted as cover')))
|
|
# }}}
|
|
|
|
# FB2 Output {{{
|
|
@ep
|
|
def fb2_output(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(choices('sectionize', _('Sec&tionize:'), ui_data.sectionize))
|
|
g.appendChild(choices('fb2_genre', _('&Genre:'), ui_data.genres))
|
|
# }}}
|
|
|
|
# LRF Output {{{
|
|
@ep
|
|
def lrf_output(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('autorotation', _('Enable &auto-rotation of wide images')))
|
|
g.appendChild(float_spin('wordspace', _('&Wordspace:'), min=1, max=20, unit='pt'))
|
|
g.appendChild(float_spin('minimum_indent', _('Minim&um para. indent:'), unit='pt'))
|
|
g.appendChild(checkbox('render_tables_as_images', _('Render &tables as images')))
|
|
g.appendChild(float_spin(
|
|
'text_size_multiplier_for_rendered_tables', indent + _('Text size multiplier for text in rendered tables:'), step=0.01))
|
|
g.appendChild(checkbox('header', _('Add &header')))
|
|
g.appendChild(float_spin('header_separation', indent + _('Header &separation:'), unit='pt'))
|
|
g.appendChild(lineedit('header_format', indent + _('Header &format:')))
|
|
g.appendChild(lineedit('serif_family', _('Serif fon&t family:')))
|
|
g.appendChild(lineedit('sans_family', _('Sans-serif font fami&ly:')))
|
|
g.appendChild(lineedit('mono_family', _('&Monospace font family:')))
|
|
# }}}
|
|
|
|
# MOBI Output {{{
|
|
@ep
|
|
def mobi_output(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('no_inline_toc', _('Do not add &Table of Contents to book')))
|
|
g.appendChild(lineedit('toc_title', indent + _('&Title for Table of Contents:')))
|
|
g.appendChild(checkbox('mobi_toc_at_start', _('Put generated Table of Contents at &start of book instead of end')))
|
|
g.appendChild(checkbox('mobi_ignore_margins', _('Ignore &margins')))
|
|
g.appendChild(checkbox('prefer_author_sort', _('Use author &sort for author')))
|
|
g.appendChild(checkbox('mobi_keep_original_images', _('Do not convert all images to &JPEG (may result in images not working in older viewers)')))
|
|
g.appendChild(checkbox('dont_compress', _('Disable &compression of the file contents')))
|
|
g.appendChild(choices('mobi_file_type', _('MOBI fi&le type:'), ui_data.file_types))
|
|
g.appendChild(lineedit('personal_doc', _('Personal Doc tag:')))
|
|
g.appendChild(checkbox('share_not_sync', _('Enable &sharing of book content via Facebook, etc. WARNING: Disables last read syncing')))
|
|
# }}}
|
|
|
|
# AZW3 Output {{{
|
|
@ep
|
|
def azw3_output(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('no_inline_toc', _('Do not add &Table of Contents to book')))
|
|
g.appendChild(lineedit('toc_title', indent + _('&Title for Table of Contents:')))
|
|
g.appendChild(checkbox('mobi_toc_at_start', _('Put generated Table of Contents at &start of book instead of end')))
|
|
g.appendChild(checkbox('prefer_author_sort', _('Use author &sort for author')))
|
|
g.appendChild(checkbox('dont_compress', _('Disable &compression of the file contents')))
|
|
g.appendChild(checkbox('share_not_sync', _('Enable &sharing of book content via Facebook, etc. WARNING: Disables last read syncing')))
|
|
# }}}
|
|
|
|
# PDB Output {{{
|
|
@ep
|
|
def pdb_output(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(choices('format', _('Forma&t:'), ui_data.formats))
|
|
g.appendChild(lineedit('pdb_output_encoding', _('O&utput encoding:')))
|
|
g.appendChild(checkbox('inline_toc', _('&Inline TOC')))
|
|
# }}}
|
|
|
|
# PDF Output {{{
|
|
@ep
|
|
def pdf_output(container):
|
|
add_listener('use_profile_size', def (name):
|
|
disabled = get('use_profile_size')
|
|
for dname in 'paper_size', 'custom_size', 'unit':
|
|
set_disabled(dname, disabled)
|
|
)
|
|
add_listener('pdf_use_document_margins', def (name):
|
|
disabled = get('pdf_use_document_margins')
|
|
for dname in 'left', 'top', 'right', 'bottom':
|
|
set_disabled(f'pdf_page_margin_{dname}', disabled)
|
|
)
|
|
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(checkbox('use_profile_size', _('&Use the paper size set in output profile')))
|
|
g.appendChild(choices('paper_size', indent + _('&Paper size:'), ui_data.paper_sizes))
|
|
g.appendChild(lineedit('custom_size', indent + _('&Custom size:')))
|
|
g.appendChild(choices('unit', indent + _('Custom size unit:'), ui_data.units))
|
|
g.appendChild(checkbox('preserve_cover_aspect_ratio', _('Preserve &aspect ratio of cover')))
|
|
g.appendChild(checkbox('pdf_page_numbers', _('Add page &numbers to the bottom of every page')))
|
|
g.appendChild(checkbox('pdf_hyphenate', _('&Break long words at the end of lines')))
|
|
g.appendChild(checkbox('pdf_add_toc', _('Add a printable &Table of Contents at the end')))
|
|
g.appendChild(lineedit('toc_title', indent + _('&Title for ToC:')))
|
|
g.appendChild(lineedit('pdf_serif_family', _('Serif famil&y:')))
|
|
g.appendChild(lineedit('pdf_sans_family', _('Sans fami&ly:')))
|
|
g.appendChild(lineedit('pdf_mono_family', _('&Monospace family:')))
|
|
g.appendChild(choices('pdf_standard_font', _('S&tandard font:'), ui_data.font_types))
|
|
g.appendChild(int_spin('pdf_default_font_size', _('Default font si&ze:'), unit='px'))
|
|
g.appendChild(int_spin('pdf_mono_font_size', _('Default font si&ze:'), unit='px'))
|
|
g.appendChild(checkbox('pdf_use_document_margins', _('Use page margins from the &document being converted')))
|
|
g.appendChild(float_spin('pdf_page_margin_left', indent + _('Left page margin'), unit='pt', min=-100, max=500))
|
|
g.appendChild(float_spin('pdf_page_margin_top', indent + _('Top page margin'), unit='pt', min=-100, max=500))
|
|
g.appendChild(float_spin('pdf_page_margin_right', indent + _('Right page margin'), unit='pt', min=-100, max=500))
|
|
g.appendChild(float_spin('pdf_page_margin_bottom', indent + _('Bottom page margin'), unit='pt', min=-100, max=500))
|
|
g.appendChild(lineedit('pdf_header_template', _('&Header template:')))
|
|
g.appendChild(lineedit('pdf_footer_template', _('&Footer template:')))
|
|
# }}}
|
|
|
|
# PMLZ Output {{{
|
|
@ep
|
|
def pml_output(container):
|
|
g = E.div(class_='simple-group')
|
|
container.appendChild(g)
|
|
g.appendChild(lineedit('pml_output_encoding', _('O&utput encoding:')))
|
|
g.appendChild(checkbox('inline_toc', _('&Inline TOC')))
|
|
g.appendChild(checkbox('full_image_depth', _('Do not &reduce image size and depth')))
|
|
# }}}
|
|
|
|
def restore_defaults():
|
|
for setting in registry:
|
|
set(setting, get_option_default_value(setting))
|
|
|
|
|
|
def create_option_group(group_name, ui_data_, profiles_, container, get_option_value_, get_option_default_value_, is_option_disabled_, get_option_help_, on_close):
|
|
nonlocal get_option_value, get_option_default_value, is_option_disabled, container_id, registry, listeners, get_option_help, profiles, ui_data
|
|
get_option_value, get_option_default_value, is_option_disabled, get_option_help = get_option_value_, get_option_default_value_, is_option_disabled_, get_option_help_
|
|
profiles, ui_data = profiles_, ui_data_
|
|
registry = {}
|
|
listeners = {}
|
|
container_id = ensure_id(container)
|
|
container.classList.add(CLASS_NAME)
|
|
entry_points[group_name](container)
|
|
container.appendChild(E.div(
|
|
style='margin-top: 2ex; padding-top: 2ex; border-top: solid 1px currentColor',
|
|
create_button(_('Done'), action=on_close),
|
|
'\xa0\xa0',
|
|
create_button(_('Restore defaults'), action=restore_defaults),
|
|
))
|
|
|
|
|
|
def commit_changes(set_option_value):
|
|
for name in registry:
|
|
set_option_value(name, get(name))
|