Skip to content

Commit 5d05429

Browse files
committed
Admonition: inherit from LabeledFlowable
1 parent 05491d8 commit 5d05429

File tree

10 files changed

+91
-56
lines changed

10 files changed

+91
-56
lines changed

CHANGES.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ New Features:
5353

5454
Changed:
5555

56+
* Admonition is a LabeledFlowable subclass now; this makes it possible to show
57+
an icon to the left/right of the admonition text. This change will however
58+
require adjustments to the admonition styles in custom stylesheets. Also,
59+
the admonition style definitions in the 'sphinx' stylesheet needs more work.
5660
* The default for BodyPageTemplate.chapter_title_height is now ``None``, which
5761
creates a DownExpaningContainer for the chapter title flowables instead of
5862
one with a fixed height.

src/rinoh/data/stylesheets/sphinx.rts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,12 +567,24 @@ font_slant=ITALIC
567567

568568
[admonition]
569569
inline_title=false
570+
label_min_width=0
571+
label_max_width=0
572+
label_spacing=0
573+
align_baselines=false
570574
space_above=9pt
571575
space_below=5pt
572576
padding_top=0
573577
padding_bottom=4pt
574578
border_top=$(thin_black_stroke)
575579
border_bottom=$(thin_black_stroke)
580+
width=fill
581+
582+
[admonition content]
583+
;inline_title=false
584+
space_above=0
585+
space_below=0
586+
padding_top=0
587+
padding_bottom=0
576588

577589
[admonition title]
578590
base=body

src/rinoh/flowable.py

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
from itertools import chain
2222
from token import NAME
2323

24-
from .attribute import Attribute, OptionSet, Bool, OverrideDefault
24+
from .attribute import (AcceptNoneAttributeType, Attribute, OptionSet, Bool,
25+
OverrideDefault)
2526
from .color import Color
2627
from .dimension import Dimension, PT, DimensionBase
2728
from .draw import ShapeStyle, Rectangle, Line, LineStyle, Stroke
@@ -513,6 +514,7 @@ def initial_state(self, container):
513514
flowables_iter = self.flowables(container)
514515
title_text = self.get_style('title', container)
515516
if title_text:
517+
from .paragraph import Paragraph
516518
title = Paragraph(title_text.copy(), style='title')
517519
flowables_iter = chain((title, ), flowables_iter)
518520
return GroupedFlowablesState(self, flowables_iter)
@@ -646,11 +648,35 @@ def empty(self):
646648
return not self.children
647649

648650

651+
class FlowablesList(AcceptNoneAttributeType):
652+
@classmethod
653+
def check_type(cls, value):
654+
if not (super().check_type(value) or isinstance(value, (list, tuple))):
655+
return False
656+
return value is None or all(isinstance(val, Flowable) for val in value)
657+
658+
@classmethod
659+
def parse_string(cls, string, source):
660+
from . import styleds, reference
661+
662+
locals = {}
663+
locals.update(reference.__dict__)
664+
locals.update(styleds.__dict__)
665+
flowables = eval(string, {'__builtins__':{}}, locals) # TODO: parse!
666+
return [StaticGroupedFlowables(flowables, source=source)]
667+
668+
@classmethod
669+
def doc_format(cls):
670+
return ('Python source code that represents a list of '
671+
':class:`.Flowable`\\ s')
672+
673+
649674
class LabelPosition(OptionSet):
650675
values = ('left', 'right')
651676

652677

653678
class LabeledFlowableStyle(FlowableStyle):
679+
label = Attribute(FlowablesList, None, 'Custom label to override the default')
654680
label_position = Attribute(LabelPosition, 'left', 'Where to place the label')
655681
label_min_width = Attribute(Dimension, 12*PT, 'Minimum label width')
656682
label_max_width = Attribute(Dimension, 80*PT, 'Maximum label width')
@@ -693,12 +719,19 @@ class LabeledFlowable(Flowable):
693719

694720
def __init__(self, label, flowable, id=None, style=None, parent=None):
695721
super().__init__(id=id, style=style, parent=parent)
696-
self.label = label
722+
self._label = label # parent is set in prepare()
697723
self.flowable = flowable
698-
label.parent = flowable.parent = self
724+
flowable.parent = self
699725

700726
def prepare(self, flowable_target):
701727
super().prepare(flowable_target)
728+
custom_label = self.get_style('label', flowable_target)
729+
if custom_label:
730+
self.label = StaticGroupedFlowables(copy(custom_label),
731+
style='label')
732+
else:
733+
self.label = self._label
734+
self.label.parent = self
702735
self.label.prepare(flowable_target)
703736
self.flowable.prepare(flowable_target)
704737

@@ -911,6 +944,3 @@ def __init__(self, page_break=Break.ANY):
911944

912945
def render(self, container, last_descender, state=None, **kwargs):
913946
return 0, 0, last_descender
914-
915-
916-
from .paragraph import Paragraph

src/rinoh/frontend/rst/nodes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,6 @@ def build_flowable(self):
260260

261261

262262
class Admonition(DocutilsGroupingNode):
263-
grouped_flowables_class = rt.Admonition
264-
265263
def children_flowables(self, skip_first=0):
266264
try:
267265
self.title
@@ -275,7 +273,9 @@ def build_flowable(self):
275273
custom_title = self.title.styled_text()
276274
except AttributeError:
277275
custom_title = None
278-
return super().build_flowable(type=admonition_type, title=custom_title)
276+
content = rt.AdmonitionFlowables(self.children_flowables())
277+
return rt.Admonition(rt.DummyFlowable(), content,
278+
type=admonition_type, title=custom_title)
279279

280280

281281
class Attention(Admonition):

src/rinoh/frontend/sphinx/nodes.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
from sphinx.ext.graphviz import render_dot
2121

2222
from ...annotation import HyperLink
23-
from ...flowable import LabeledFlowable, StaticGroupedFlowables
23+
from ...flowable import DummyFlowable, LabeledFlowable, StaticGroupedFlowables
2424
from ...glossary import GlossaryTerm
25-
from ...image import Image, Figure
25+
from ...image import Image
2626
from ...index import IndexTerm, IndexTarget, InlineIndexTarget
2727
from ...paragraph import Paragraph
2828
from ...reference import Reference
29-
from ...structure import DefinitionList, List
29+
from ...structure import Admonition, AdmonitionFlowables, DefinitionList, List
3030
from ...text import SingleStyledText, MixedStyledText
3131
from ...util import intersperse
3232
from ...warnings import warn
@@ -248,8 +248,9 @@ def pop_title(items):
248248
children = self.children_flowables()
249249
first_paragraph = children[0]
250250
custom_title = pop_title(first_paragraph.content)
251-
return self.grouped_flowables_class(children, title=custom_title,
252-
style=subtype)
251+
content = AdmonitionFlowables(children)
252+
return Admonition(DummyFlowable(), content, title=custom_title,
253+
style=subtype)
253254

254255

255256
# special nodes

src/rinoh/structure.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
from .attribute import Attribute, Bool, Integer, OverrideDefault
1414
from .draw import Line, LineStyle
1515
from .element import create_destination
16-
from .flowable import GroupedFlowables, StaticGroupedFlowables, WarnFlowable
16+
from .flowable import (GroupedFlowables, LabeledFlowableStyle,
17+
StaticGroupedFlowables, WarnFlowable)
1718
from .flowable import LabeledFlowable, GroupedLabeledFlowables
1819
from .flowable import Flowable, FlowableStyle, GroupedFlowablesStyle
1920
from .layout import PageBreakException
@@ -26,13 +27,14 @@
2627
from .strings import StringField
2728
from .util import NotImplementedAttribute, itemcount
2829

30+
2931
__all__ = ['Section', 'Heading', 'ListStyle', 'List', 'ListItem',
3032
'ListItemLabel', 'ListItemLabelStyle', 'DefinitionList',
3133
'Header', 'Footer',
3234
'TableOfContentsSection', 'TableOfContents', 'TableOfContentsStyle',
3335
'ListOfStyle', 'ListOfEntry', 'ListOfEntryStyle',
3436
'TableOfContentsEntry', 'Admonition', 'AdmonitionStyle',
35-
'AdmonitionTitleParagraph',
37+
'AdmonitionFlowables', 'AdmonitionTitleParagraph',
3638
'HorizontalRule', 'HorizontalRuleStyle', 'OutOfLineFlowables']
3739

3840

@@ -400,17 +402,17 @@ class ListOfEntry(ReferencingParagraph):
400402
style_class = ListOfEntryStyle
401403

402404

403-
class AdmonitionStyle(GroupedFlowablesStyle):
405+
class AdmonitionStyle(LabeledFlowableStyle):
404406
inline_title = Attribute(Bool, True, "Show the admonition's title inline "
405407
"with the body text, if possible")
406408

407409

408-
class Admonition(StaticGroupedFlowables):
410+
class Admonition(LabeledFlowable):
409411
style_class = AdmonitionStyle
410412

411-
def __init__(self, flowables, title=None, type=None,
413+
def __init__(self, label, flowable, title=None, type=None,
412414
id=None, style=None, parent=None):
413-
super().__init__(flowables, id=id, style=style, parent=parent)
415+
super().__init__(label, flowable, id=id, style=style, parent=parent)
414416
self.custom_title = title
415417
self.admonition_type = type
416418

@@ -421,13 +423,16 @@ def custom_title_text(self):
421423
def title(self, document):
422424
return self.custom_title or document.get_string(self.admonition_type)
423425

426+
427+
class AdmonitionFlowables(StaticGroupedFlowables):
428+
424429
def flowables(self, container):
425-
title = self.title(container.document)
430+
title = self.parent.title(container.document)
426431
with suppress(AttributeError):
427432
title = title.copy()
428433
flowables = super().flowables(container)
429434
first_flowable = next(flowables)
430-
inline_title = self.get_style('inline_title', container)
435+
inline_title = self.parent.get_style('inline_title', container)
431436
if inline_title and isinstance(first_flowable, Paragraph):
432437
title = MixedStyledText(title, style='inline title')
433438
kwargs = dict(id=first_flowable.id, style=first_flowable.style,

src/rinoh/styleds.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from .structure import List, ListItem, ListItemLabel, DefinitionList
3333
from .structure import Section, TableOfContentsSection, Heading
3434
from .structure import ListOfEntry
35-
from .structure import Admonition, AdmonitionTitleParagraph
35+
from .structure import Admonition, AdmonitionFlowables, AdmonitionTitleParagraph
3636
from .structure import TableOfContents, TableOfContentsEntry
3737
from .structure import OutOfLineFlowables
3838
from .table import TableWithCaption, Table, TableSection, TableHead, TableBody

src/rinoh/stylesheets/matcher.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,21 +296,28 @@
296296
matcher('option argument', MixedStyledText.like('option_arg'))
297297

298298
matcher('admonition', Admonition)
299-
matcher('admonition title', 'admonition' / Paragraph.like('title'))
300-
matcher('admonition title paragraph', 'admonition' / +AdmonitionTitleParagraph)
301-
matcher('admonition inline title', SelectorByName('admonition')
299+
matcher('admonition label', 'admonition' / Flowable.like('label'))
300+
matcher('admonition content', 'admonition' / AdmonitionFlowables)
301+
matcher('admonition title', 'admonition content' / Paragraph.like('title'))
302+
matcher('admonition title paragraph', 'admonition content' / +AdmonitionTitleParagraph)
303+
matcher('admonition paragraph', 'admonition content' / Paragraph)
304+
matcher('admonition inline title', SelectorByName('admonition content')
302305
/ ... / StyledText.like('inline title'))
303306

304307
for admonition_type in ('attention', 'caution', 'danger', 'error', 'hint',
305308
'important', 'note', 'tip', 'warning', 'seealso'):
306309
admonition_selector = Admonition.like(admonition_type=admonition_type)
307310
matcher(admonition_type + ' admonition', admonition_selector)
308-
selector = admonition_selector / Paragraph.like('title')
311+
matcher(admonition_type + ' admonition label', admonition_selector / Flowable.like('label'))
312+
admonition_content_selector = admonition_selector / AdmonitionFlowables
313+
matcher(admonition_type + ' admonition content', admonition_content_selector)
314+
selector = admonition_content_selector / Paragraph.like('title')
309315
matcher(admonition_type + ' admonition title', selector)
310316
matcher(admonition_type + ' admonition title paragraph',
311-
admonition_selector / +AdmonitionTitleParagraph)
317+
admonition_content_selector / +AdmonitionTitleParagraph)
318+
matcher(admonition_type + ' admonition paragraph', admonition_content_selector / Paragraph)
312319
matcher(admonition_type + ' admonition inline title',
313-
admonition_selector / ... / StyledText.like('inline title'))
320+
admonition_content_selector / ... / StyledText.like('inline title'))
314321

315322
# page header and footer
316323

src/rinoh/template.py

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from functools import partial
1414
from itertools import chain
1515

16-
from . import styleds, reference
1716
from .attribute import (Bool, Integer, Attribute, AttributesDictionary,
1817
RuleSet, RuleSetFile, WithAttributes, AttributeType,
1918
OptionSet, AcceptNoneAttributeType, OverrideDefault,
@@ -24,7 +23,7 @@
2423
PageNumberFormat)
2524
from .element import create_destination
2625
from .image import BackgroundImage, Image
27-
from .flowable import Flowable, StaticGroupedFlowables
26+
from .flowable import Flowable, FlowablesList, StaticGroupedFlowables
2827
from .language import Language, EN
2928
from .layout import (Container, DownExpandingContainer, UpExpandingContainer,
3029
FlowablesContainer, FootnoteContainer, ChainedContainer,
@@ -115,27 +114,6 @@ def new_chapter_page(self, document_part, page_number, chain):
115114
return self.page(document_part, page_number, chain)
116115

117116

118-
class FlowablesList(AcceptNoneAttributeType):
119-
@classmethod
120-
def check_type(cls, value):
121-
if not (super().check_type(value) or isinstance(value, (list, tuple))):
122-
return False
123-
return value is None or all(isinstance(val, Flowable) for val in value)
124-
125-
@classmethod
126-
def parse_string(cls, string, source):
127-
locals = {}
128-
locals.update(reference.__dict__)
129-
locals.update(styleds.__dict__)
130-
flowables = eval(string, {'__builtins__':{}}, locals) # TODO: parse!
131-
return [StaticGroupedFlowables(flowables, source=source)]
132-
133-
@classmethod
134-
def doc_format(cls):
135-
return ('Python source code that represents a list of '
136-
':class:`.Flowable`\\ s')
137-
138-
139117
class BodyPageTemplateBase(PageTemplateBase):
140118
header_footer_distance = Option(Dimension, 14*PT, 'Distance of the '
141119
'header and footer to the content area')

src/rinoh/text.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ def from_tokens(cls, tokens, source):
195195
items = []
196196
while tokens.next.type:
197197
if tokens.next.type == NAME:
198+
from .inline import InlineFlowable
198199
items.append(InlineFlowable.from_tokens(tokens, source))
199200
elif tokens.next.type == STRING:
200201
items.append(cls.text_from_tokens(tokens))
@@ -245,6 +246,7 @@ def validate(cls, value):
245246

246247
@classmethod
247248
def _substitute_variables(cls, text, style):
249+
from .reference import Field
248250
def substitute_controlchars_htmlentities(string, style=None):
249251
try:
250252
return ControlCharacter.all[string]()
@@ -714,7 +716,3 @@ def __init__(self, text_or_items, id=None, style=SUBSCRIPT_STYLE,
714716
class ErrorText(SingleStyledText):
715717
def __init__(self, text, style=ERROR_STYLE, parent=None, source=None):
716718
super().__init__(text, style=style, parent=parent, source=source)
717-
718-
719-
from .reference import Field
720-
from .inline import InlineFlowable

0 commit comments

Comments
 (0)