Line data Source code
1 : // Copyright 2014 The Flutter Authors.
2 : // Copyright 2020 Suragch.
3 : // All rights reserved.
4 : // Use of this source code is governed by a BSD-style license that can be
5 : // found in the LICENSE file.
6 :
7 : import 'package:flutter/foundation.dart';
8 : import 'package:flutter/widgets.dart';
9 :
10 : import 'mongol_rich_text.dart';
11 : import '../base/mongol_text_painter.dart';
12 : import '../base/mongol_text_align.dart';
13 :
14 : /// A run of vertical text with a single style.
15 : ///
16 : /// The [MongolText] widget displays a string of vertical text with single
17 : /// style. The string might break across multiple lines or might all be
18 : /// displayed on the same line depending on the layout constraints.
19 : ///
20 : /// The [style] argument is optional. When omitted, the text will use the style
21 : /// from the closest enclosing [DefaultTextStyle]. If the given style's
22 : /// [TextStyle.inherit] property is true (the default), the given style will
23 : /// be merged with the closest enclosing [DefaultTextStyle]. This merging
24 : /// behavior is useful, for example, to make the text bold while using the
25 : /// default font family and size.
26 : ///
27 : /// {@tool snippet}
28 : ///
29 : /// This example shows how to display text using the [MongolText] widget with the
30 : /// [overflow] set to [TextOverflow.ellipsis].
31 : ///
32 : /// If the text is shorter than the available space, it is displayed in full
33 : /// without an ellipsis.
34 : ///
35 : /// If the text overflows, the Text widget displays an ellipsis to trim the
36 : /// overflowing text.
37 : ///
38 : /// ```dart
39 : /// Text(
40 : /// 'Hello, $_name! How are you?',
41 : /// textAlign: MongolTextAlign.center,
42 : /// overflow: TextOverflow.ellipsis,
43 : /// style: TextStyle(fontWeight: FontWeight.bold),
44 : /// )
45 : /// ```
46 : /// {@end-tool}
47 : ///
48 : /// Using the [MongolText.rich] constructor, the [MongolText] widget can
49 : /// display a paragraph with differently styled [TextSpan]s. The sample
50 : /// that follows displays "Hello beautiful world" with different styles
51 : /// for each word.
52 : ///
53 : /// ```dart
54 : /// const MongolText.rich(
55 : /// TextSpan(
56 : /// text: 'Hello', // default text style
57 : /// children: <TextSpan>[
58 : /// TextSpan(text: ' beautiful ', style: TextStyle(fontStyle: FontStyle.italic)),
59 : /// TextSpan(text: 'world', style: TextStyle(fontWeight: FontWeight.bold)),
60 : /// ],
61 : /// ),
62 : /// )
63 : /// ```
64 : ///
65 : /// See also:
66 : ///
67 : /// * [MongolRichText], which gives you more control over the text styles.
68 : /// * [DefaultTextStyle], which sets default styles for [MongolText] widgets.
69 : class MongolText extends StatelessWidget {
70 : /// Creates a text widget for vertical Mongolian layout.
71 : ///
72 : /// If the [style] argument is null, the text will use the style from the
73 : /// closest enclosing [DefaultTextStyle].
74 : ///
75 : /// The [overflow] property's behavior is affected by the [softWrap] argument.
76 : /// If the [softWrap] is true or null, the glyph causing overflow, and those
77 : /// that follow, will not be rendered. Otherwise, it will be shown with the
78 : /// given overflow option.
79 10 : const MongolText(
80 : this.data, {
81 : Key? key,
82 : this.style,
83 : this.textAlign,
84 : this.softWrap,
85 : this.overflow,
86 : this.textScaleFactor,
87 : this.maxLines,
88 : this.semanticsLabel,
89 : }) : assert(
90 0 : data != null,
91 : 'A non-null String must be provided to a MongolText widget.',
92 : ),
93 : textSpan = null,
94 3 : super(key: key);
95 :
96 : /// Creates a vertical Mongolian text widget with a [TextSpan].
97 : ///
98 : /// The [textSpan] parameter must not be null.
99 : ///
100 : /// See [MongolRichText] which provides a lower-level way to draw text.
101 1 : const MongolText.rich(
102 : this.textSpan, {
103 : Key? key,
104 : this.style,
105 : this.textAlign,
106 : this.softWrap,
107 : this.overflow,
108 : this.textScaleFactor,
109 : this.maxLines,
110 : this.semanticsLabel,
111 : }) : assert(
112 0 : textSpan != null,
113 : 'A non-null TextSpan must be provided to a Text.rich widget.',
114 : ),
115 : data = null,
116 0 : super(key: key);
117 :
118 : /// This is the text that the MongolText widget will display.
119 : final String? data;
120 :
121 : /// The text to display as a [TextSpan].
122 : ///
123 : /// This will be null if [data] is provided instead.
124 : final TextSpan? textSpan;
125 :
126 : /// This is the style to use for the whole text string. If null a default
127 : /// style will be used.
128 : final TextStyle? style;
129 :
130 : /// How the text should be aligned vertically.
131 : final MongolTextAlign? textAlign;
132 :
133 : /// Whether the text should break at soft line breaks.
134 : ///
135 : /// If false, the glyphs in the text will be positioned as if there were
136 : /// unlimited vertical space.
137 : final bool? softWrap;
138 :
139 : /// How visual overflow should be handled.
140 : ///
141 : /// Defaults to retrieving the value from the nearest [DefaultTextStyle] ancestor.
142 : final TextOverflow? overflow;
143 :
144 : /// Font pixels per logical pixel
145 : final double? textScaleFactor;
146 :
147 : /// An optional maximum number of lines for the text to span, wrapping if
148 : /// necessary. If the text exceeds the given number of lines, it will be
149 : /// truncated according to [overflow].
150 : ///
151 : /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
152 : /// edge of the box.
153 : ///
154 : /// If this is null, but there is an ambient [DefaultTextStyle] that specifies
155 : /// an explicit number for its [DefaultTextStyle.maxLines], then the
156 : /// [DefaultTextStyle] value will take precedence. You can use a
157 : /// [MongolRichText] widget directly to entirely override the
158 : /// [DefaultTextStyle].
159 : final int? maxLines;
160 :
161 : /// An alternative semantics label for this text.
162 : ///
163 : /// If present, the semantics of this widget will contain this value instead
164 : /// of the actual text. This will overwrite any of the semantics labels applied
165 : /// directly to the [TextSpan]s.
166 : ///
167 : /// This is useful for replacing abbreviations or shorthands with the full
168 : /// text value:
169 : ///
170 : /// ```dart
171 : /// MongolText(r'$$', semanticsLabel: 'Double dollars')
172 : /// ```
173 : final String? semanticsLabel;
174 :
175 8 : @override
176 : Widget build(BuildContext context) {
177 8 : final defaultTextStyle = DefaultTextStyle.of(context);
178 8 : var effectiveTextStyle = style;
179 14 : if (style == null || style!.inherit) {
180 16 : effectiveTextStyle = defaultTextStyle.style.merge(effectiveTextStyle);
181 : }
182 8 : if (MediaQuery.boldTextOverride(context)) {
183 : effectiveTextStyle = effectiveTextStyle!
184 0 : .merge(const TextStyle(fontWeight: FontWeight.bold));
185 : }
186 16 : final defaultTextAlign = mapHorizontalToMongolTextAlign(defaultTextStyle.textAlign);
187 8 : Widget result = MongolRichText(
188 8 : textAlign: textAlign ?? defaultTextAlign ?? MongolTextAlign.top,
189 16 : softWrap: softWrap ?? defaultTextStyle.softWrap,
190 16 : overflow: overflow ?? defaultTextStyle.overflow,
191 16 : textScaleFactor: textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
192 16 : maxLines: maxLines ?? defaultTextStyle.maxLines,
193 8 : text: TextSpan(
194 : style: effectiveTextStyle,
195 8 : text: data,
196 10 : children: textSpan != null ? <TextSpan>[textSpan!] : null,
197 : ),
198 : );
199 8 : if (semanticsLabel != null) {
200 0 : result = Semantics(
201 : textDirection: TextDirection.ltr,
202 0 : label: semanticsLabel,
203 0 : child: ExcludeSemantics(
204 : child: result,
205 : ),
206 : );
207 : }
208 : return result;
209 : }
210 :
211 0 : @override
212 : void debugFillProperties(DiagnosticPropertiesBuilder properties) {
213 0 : super.debugFillProperties(properties);
214 0 : properties.add(StringProperty('data', data, showName: false));
215 0 : if (textSpan != null) {
216 0 : properties.add(textSpan!.toDiagnosticsNode(
217 : name: 'textSpan', style: DiagnosticsTreeStyle.transition));
218 : }
219 0 : style?.debugFillProperties(properties);
220 0 : properties.add(EnumProperty<MongolTextAlign>('textAlign', textAlign, defaultValue: null));
221 0 : properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box height', ifFalse: 'no wrapping except at line break characters', showName: true));
222 0 : properties.add(EnumProperty<TextOverflow>('overflow', overflow, defaultValue: null));
223 0 : properties.add(
224 0 : DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: 1.0));
225 0 : properties.add(IntProperty('maxLines', maxLines, defaultValue: null));
226 0 : if (semanticsLabel != null) {
227 0 : properties.add(StringProperty('semanticsLabel', semanticsLabel));
228 : }
229 : }
230 : }
|