mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Edit book: Add a tool to insert arbitrary unicode characters, such as special spaces or punctuation or characters from non-English languages into the text
This commit is contained in:
parent
c06d44d598
commit
0012f5cc4b
201
imgsrc/character-set.svg
Normal file
201
imgsrc/character-set.svg
Normal file
@ -0,0 +1,201 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
|
||||
|
||||
<svg
|
||||
xmlns:ns="http://ns.adobe.com/SaveForWeb/1.0/"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.0"
|
||||
id="Livello_1"
|
||||
width="128"
|
||||
height="128"
|
||||
viewBox="0 0 124.176 66.475"
|
||||
overflow="visible"
|
||||
enable-background="new 0 0 124.176 66.475"
|
||||
xml:space="preserve"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="character-set.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
sodipodi:modified="true"
|
||||
inkscape:export-filename="/home/kovid/work/calibre/resources/images/character-set.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"><defs
|
||||
id="defs29"><linearGradient
|
||||
id="linearGradient3291"
|
||||
inkscape:collect="always"><stop
|
||||
id="stop3293"
|
||||
offset="0"
|
||||
style="stop-color:#000000;stop-opacity:1;" /><stop
|
||||
id="stop3295"
|
||||
offset="1"
|
||||
style="stop-color:#000000;stop-opacity:0;" /></linearGradient><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3291"
|
||||
id="radialGradient3336"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
|
||||
cx="63.912209"
|
||||
cy="115.70919"
|
||||
fx="63.912209"
|
||||
fy="115.7093"
|
||||
r="63.912209" /><linearGradient
|
||||
y2="0.00048828119"
|
||||
x2="22.481001"
|
||||
y1="65.662102"
|
||||
x1="22.481001"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="XMLID_4_"><stop
|
||||
id="stop8"
|
||||
style="stop-color:#2E3436"
|
||||
offset="0" /><stop
|
||||
id="stop10"
|
||||
style="stop-color:#000000"
|
||||
offset="1" /></linearGradient><linearGradient
|
||||
y2="15.8804"
|
||||
x2="64.6689"
|
||||
y1="65.662102"
|
||||
x1="64.6689"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="XMLID_5_"
|
||||
gradientTransform="matrix(1,0,0,1.0133482,0,1.6235306)"><stop
|
||||
id="stop15"
|
||||
style="stop-color:#2E3436"
|
||||
offset="0" /><stop
|
||||
id="stop17"
|
||||
style="stop-color:#000000"
|
||||
offset="1" /></linearGradient><linearGradient
|
||||
y2="4.2846999"
|
||||
x2="104.2773"
|
||||
y1="66.474602"
|
||||
x1="104.2773"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="XMLID_6_"
|
||||
gradientTransform="translate(0,1.687)"><stop
|
||||
id="stop22"
|
||||
style="stop-color:#2E3436"
|
||||
offset="0" /><stop
|
||||
id="stop24"
|
||||
style="stop-color:#000000"
|
||||
offset="1" /></linearGradient><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_4_"
|
||||
id="linearGradient2218"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1.0127815,0,68.971157)"
|
||||
x1="38.609329"
|
||||
y1="0.79894531"
|
||||
x2="38.366798"
|
||||
y2="50.62952" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#XMLID_6_"
|
||||
id="linearGradient2253"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.9813158,0,2.9290339)"
|
||||
x1="104.2773"
|
||||
y1="66.474602"
|
||||
x2="104.39857"
|
||||
y2="15.9262" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3291"
|
||||
id="radialGradient4261"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
|
||||
cx="63.912209"
|
||||
cy="115.70919"
|
||||
fx="63.912209"
|
||||
fy="115.7093"
|
||||
r="63.912209" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3291"
|
||||
id="radialGradient4265"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
|
||||
cx="63.912209"
|
||||
cy="115.70919"
|
||||
fx="63.912209"
|
||||
fy="115.7093"
|
||||
r="63.912209" /><radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3291"
|
||||
id="radialGradient4268"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,0.197802,0,92.82166)"
|
||||
cx="63.912209"
|
||||
cy="115.70919"
|
||||
fx="63.912209"
|
||||
fy="115.7093"
|
||||
r="63.912209" /></defs><sodipodi:namedview
|
||||
inkscape:window-height="1058"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base"
|
||||
width="128px"
|
||||
height="128px"
|
||||
borderlayer="false"
|
||||
inkscape:showpageshadow="false"
|
||||
showgrid="true"
|
||||
inkscape:zoom="3.8359375"
|
||||
inkscape:cx="64"
|
||||
inkscape:cy="64"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="22"
|
||||
inkscape:current-layer="Livello_1"
|
||||
inkscape:window-maximized="0"><inkscape:grid
|
||||
id="GridFromPre046Settings"
|
||||
type="xygrid"
|
||||
originx="0px"
|
||||
originy="0px"
|
||||
spacingx="4px"
|
||||
spacingy="4px"
|
||||
color="#3f3fff"
|
||||
empcolor="#3f3fff"
|
||||
opacity="0.15"
|
||||
empopacity="0.38"
|
||||
empspacing="0" /></sodipodi:namedview><metadata
|
||||
id="metadata3"><ns:sfw><ns:slices /><ns:sliceSourceBounds
|
||||
x="1.912"
|
||||
y="30.763"
|
||||
height="66.475"
|
||||
width="124.176"
|
||||
bottomLeftOrigin="true" /></ns:sfw><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><path
|
||||
style="fill:url(#linearGradient2218)"
|
||||
d="M 16.401176,17.7155 L 0,68.162 L 9.6406172,68.162 L 14.036496,53.853984 L 30.316406,53.853984 L 34.9245,68.162 L 44.95923,68.162 L 28.315523,17.7155 L 16.401176,17.7155 z M 21.949078,25.053731 L 22.10066,25.053731 C 22.86066,27.971554 23.690555,31.413123 24.677555,34.479827 L 28.709637,46.914905 L 15.582633,46.914905 L 19.523766,34.479827 C 20.434765,31.48807 21.190078,27.971554 21.949078,25.053731 z "
|
||||
id="path2200" /><path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="M 23.1875 28 C 17.786134 28 14.719782 31.645231 14.71875 36.15625 C 14.71875 40.496737 17.942815 44 23.1875 44 C 28.354875 44 31.624999 40.519503 31.625 36.09375 C 31.625 31.583884 28.651366 28 23.25 28 L 23.1875 28 z M 23.0625 32 L 23.15625 32 C 25.677144 32 27.15625 33.919307 27.15625 36 C 27.15625 38.23883 25.677144 40 23.15625 40 C 20.721219 40 19.15625 38.075555 19.15625 36.15625 C 19.15625 33.996488 20.540461 32 23.0625 32 z "
|
||||
transform="matrix(0.970125,0,0,0.970125,0,-28.8505)"
|
||||
id="path2228" /><path
|
||||
style="fill:url(#XMLID_5_)"
|
||||
id="path19"
|
||||
d="M 52.479,68.162 L 52.479,49.375538 L 46.479,53.567759 L 46.479,46.980996 L 52.479,42.788774 L 52.479,17.7155 L 61.821,17.7155 L 61.821,36.57695 L 71.694,29.841225 L 71.694,36.501962 L 61.821,43.237688 L 61.821,60.452447 L 82.859,60.452447 L 82.859,68.160987 L 52.479,68.160987 L 52.479,68.162 z " /><path
|
||||
style="fill:url(#linearGradient2253)"
|
||||
d="M 123.72,65.914787 C 121.518,67.002085 116.658,68.162 110.505,68.162 C 94.252,68.162 84.379,58.3773 84.379,43.519198 C 84.379,27.428564 96.075,17.7155 111.72,17.7155 C 117.872,17.7155 122.278,18.948033 124.176,19.890096 L 122.125,26.992859 C 119.694,25.978179 116.354,25.108733 112.1,25.108733 C 101.696,25.108733 94.176,31.342051 94.176,43.083494 C 94.176,53.811238 100.783,60.69615 112.025,60.69615 C 115.822,60.69615 119.771,59.970957 122.202,58.883659 L 123.72,65.914787 z "
|
||||
id="path2222" /><path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="M 105.08728,13.835 L 97.0125,2.1935 L 104.22438,2.1935 L 108.69271,8.6506979 L 108.8496,8.6506979 L 113.16104,2.1935 L 120.2955,2.1935 L 112.37761,13.835 L 105.08728,13.835 z "
|
||||
id="path26" /><path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.38139535;fill:url(#radialGradient4268);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:4;stroke-opacity:1"
|
||||
id="path1563"
|
||||
sodipodi:cx="63.912209"
|
||||
sodipodi:cy="115.70919"
|
||||
sodipodi:rx="63.912209"
|
||||
sodipodi:ry="12.641975"
|
||||
d="M 127.82442 115.70919 A 63.912209 12.641975 0 1 1 0,115.70919 A 63.912209 12.641975 0 1 1 127.82442 115.70919 z"
|
||||
transform="matrix(0.971458,0,0,0.3981189,-2.6300491e-5,44.226475)" /></svg>
|
After Width: | Height: | Size: 8.5 KiB |
BIN
resources/images/character-set.png
Normal file
BIN
resources/images/character-set.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.7 KiB |
@ -1068,6 +1068,9 @@ class Boss(QObject):
|
||||
if not editors:
|
||||
self.gui.preview.clear()
|
||||
|
||||
def insert_character(self):
|
||||
self.gui.insert_char.show()
|
||||
|
||||
# Shutdown {{{
|
||||
def quit(self):
|
||||
if not self.confirm_quit():
|
||||
|
@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
import unicodedata, re
|
||||
import unicodedata, re, weakref
|
||||
from bisect import bisect
|
||||
from functools import partial
|
||||
|
||||
@ -548,6 +548,7 @@ class CharDelegate(QStyledItemDelegate):
|
||||
class CharView(QListView):
|
||||
|
||||
show_name = pyqtSignal(object)
|
||||
char_selected = pyqtSignal(object)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
self.last_mouse_idx = -1
|
||||
@ -564,6 +565,16 @@ class CharView(QListView):
|
||||
self.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.customContextMenuRequested.connect(self.context_menu)
|
||||
self.showing_favorites = False
|
||||
pi = plugins['progress_indicator'][0]
|
||||
if hasattr(pi, 'set_no_activate_on_click'):
|
||||
pi.set_no_activate_on_click(self)
|
||||
self.activated.connect(self.item_activated)
|
||||
self.clicked.connect(self.item_activated)
|
||||
|
||||
def item_activated(self, index):
|
||||
char_code, ok = self.model().data(index, Qt.UserRole).toInt()
|
||||
if ok:
|
||||
self.char_selected.emit(chr(char_code))
|
||||
|
||||
def set_allow_drag_and_drop(self, enabled):
|
||||
if not enabled:
|
||||
@ -640,6 +651,8 @@ class CharSelect(Dialog):
|
||||
def __init__(self, parent=None):
|
||||
self.initialized = False
|
||||
Dialog.__init__(self, _('Insert character'), 'charmap_dialog', parent)
|
||||
self.setWindowIcon(QIcon(I('character-set.png')))
|
||||
self.focus_widget = None
|
||||
|
||||
def setup_ui(self):
|
||||
self.l = l = QGridLayout(self)
|
||||
@ -650,6 +663,7 @@ class CharSelect(Dialog):
|
||||
b.setCheckable(True)
|
||||
b.setChecked(False)
|
||||
b.setVisible(False)
|
||||
b.setDefault(True)
|
||||
|
||||
self.splitter = s = QSplitter(self)
|
||||
s.setChildrenCollapsible(False)
|
||||
@ -660,6 +674,7 @@ class CharSelect(Dialog):
|
||||
self.rearrange_button.toggled[bool].connect(self.set_allow_drag_and_drop)
|
||||
self.category_view.category_selected.connect(self.show_chars)
|
||||
self.char_view.show_name.connect(self.show_char_info)
|
||||
self.char_view.char_selected.connect(self.char_selected)
|
||||
s.addWidget(self.category_view), s.addWidget(self.char_view)
|
||||
|
||||
self.char_info = la = QLabel('\xa0')
|
||||
@ -701,10 +716,29 @@ class CharSelect(Dialog):
|
||||
self.char_info.clear()
|
||||
|
||||
def show(self):
|
||||
try:
|
||||
self.focus_widget = weakref.ref(QApplication.focusWidget())
|
||||
except TypeError:
|
||||
self.focus_widget = None
|
||||
self.initialize()
|
||||
Dialog.show(self)
|
||||
self.raise_()
|
||||
|
||||
def char_selected(self, c):
|
||||
if QApplication.keyboardModifiers() & Qt.CTRL:
|
||||
self.hide()
|
||||
if self.focus_widget is None or self.focus_widget() is None:
|
||||
QApplication.clipboard().setText(c)
|
||||
return
|
||||
w = self.focus_widget()
|
||||
if hasattr(w, 'textCursor'):
|
||||
cr = w.textCursor()
|
||||
cr.insertText(c)
|
||||
w.setTextCursor(cr)
|
||||
elif hasattr(w, 'insert'):
|
||||
w.insert(c)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication([])
|
||||
w = CharSelect()
|
||||
|
@ -29,6 +29,7 @@ from calibre.gui2.tweak_book.preview import Preview
|
||||
from calibre.gui2.tweak_book.search import SearchPanel
|
||||
from calibre.gui2.tweak_book.check import Check
|
||||
from calibre.gui2.tweak_book.toc import TOCViewer
|
||||
from calibre.gui2.tweak_book.char_select import CharSelect
|
||||
from calibre.gui2.tweak_book.editor.widget import register_text_editor_actions
|
||||
from calibre.gui2.tweak_book.editor.insert_resource import InsertImage
|
||||
|
||||
@ -217,6 +218,7 @@ class Main(MainWindow):
|
||||
self.check_book = Check(self)
|
||||
self.toc_view = TOCViewer(self)
|
||||
self.image_browser = InsertImage(self, for_browsing=True)
|
||||
self.insert_char = CharSelect(self)
|
||||
|
||||
self.create_actions()
|
||||
self.create_toolbars()
|
||||
@ -321,6 +323,8 @@ class Main(MainWindow):
|
||||
_('Beautify current file'))
|
||||
self.action_pretty_all = reg('format-justify-fill.png', _('&Beautify all files'), partial(self.boss.pretty_print, False), 'pretty-all', (),
|
||||
_('Beautify all files'))
|
||||
self.action_insert_char = reg('character-set.png', _('&Insert special character'), self.boss.insert_character, 'insert-character', (),
|
||||
_('Insert special character'))
|
||||
|
||||
# Polish actions
|
||||
group = _('Polish Book')
|
||||
@ -423,6 +427,7 @@ class Main(MainWindow):
|
||||
e.addAction(self.action_editor_cut)
|
||||
e.addAction(self.action_editor_copy)
|
||||
e.addAction(self.action_editor_paste)
|
||||
e.addAction(self.action_insert_char)
|
||||
e.addSeparator()
|
||||
e.addAction(self.action_preferences)
|
||||
|
||||
@ -505,6 +510,7 @@ class Main(MainWindow):
|
||||
b.setToolTip(_('Donate to support calibre development'))
|
||||
QTimer.singleShot(10, b.start_animation)
|
||||
self.global_bar.addWidget(w)
|
||||
self.global_bar.addAction(self.action_insert_char)
|
||||
a(self.action_help)
|
||||
|
||||
a = create(_('Polish book tool bar'), 'polish').addAction
|
||||
|
Loading…
x
Reference in New Issue
Block a user