LCOV - code coverage report
Current view: top level - lib/src - text.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 45 66 68.2 %
Date: 2021-08-10 15:50:53 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:ui';
       2             : 
       3             : import 'package:flutter/material.dart' as material;
       4             : 
       5             : import 'anchor.dart';
       6             : import 'components/cache/memory_cache.dart';
       7             : import 'components/text_component.dart';
       8             : import 'extensions/size.dart';
       9             : import 'extensions/vector2.dart';
      10             : 
      11             : /// [TextRenderer] is the abstract API that Flame uses for rendering text in its features
      12             : /// this class can be extended to provide an implementation of text rendering in the engine.
      13             : ///
      14             : /// See [TextPaint] for the default implementation offered by Flame
      15             : abstract class TextRenderer<T extends BaseTextConfig> {
      16             :   /// A registry containing default providers for every [TextRenderer] subclass;
      17             :   /// used by [createDefault] to create default parameter values.
      18             :   ///
      19             :   /// If you add a new [TextRenderer] child, you can register it by adding it,
      20             :   /// alongisde a provider lambda, to this map.
      21           3 :   static Map<Type, TextRenderer Function()> defaultCreatorsRegistry = {
      22           2 :     TextRenderer: () => TextPaint(),
      23           2 :     TextPaint: () => TextPaint(),
      24             :   };
      25             : 
      26             :   final T config;
      27             : 
      28           1 :   TextRenderer({required this.config});
      29             : 
      30             :   /// Renders a given [text] in a given position [position] using the provided [canvas] and [anchor].
      31             :   ///
      32             :   /// Renders it in the given position, considering the [anchor] specified.
      33             :   /// For example, if [Anchor.center] is specified, it's going to be drawn centered around [position].
      34             :   ///
      35             :   /// Example usage (Using TextPaint implementation):
      36             :   ///
      37             :   ///     const TextPaint config = TextPaint(fontSize: 48.0, fontFamily: 'Awesome Font');
      38             :   ///     config.render(canvas, Vector2(size.x - 10, size.y - 10, anchor: Anchor.bottomRight);
      39             :   void render(
      40             :     Canvas canvas,
      41             :     String text,
      42             :     Vector2 position, {
      43             :     Anchor anchor = Anchor.topLeft,
      44             :   });
      45             : 
      46             :   /// Given a [text] String, returns the width of that [text].
      47             :   double measureTextWidth(String text);
      48             : 
      49             :   /// Given a [text] String, returns the height of that [text].
      50             :   double measureTextHeight(String text);
      51             : 
      52             :   /// Given a [text] String, returns a Vector2 with the size of that [text] has.
      53           1 :   Vector2 measureText(String text) {
      54           1 :     return Vector2(
      55           1 :       measureTextWidth(text),
      56           1 :       measureTextHeight(text),
      57             :     );
      58             :   }
      59             : 
      60             :   /// Creates a new instance of this painter but transforming the [config]
      61             :   /// object via the provided lambda.
      62             :   TextRenderer<T> copyWith(T Function(T) transform);
      63             : 
      64             :   /// Given a generic type [T], creates a default renderer of that type.
      65           1 :   static T createDefault<T extends TextRenderer>() {
      66           2 :     final creator = defaultCreatorsRegistry[T];
      67             :     if (creator != null) {
      68           1 :       return creator() as T;
      69             :     } else {
      70           0 :       throw 'Unkown implementation of TextRenderer: $T. Please register it under [defaultCreatorsRegistry].';
      71             :     }
      72             :   }
      73             : }
      74             : 
      75             : /// A Text Config contains all typographical information required to render texts; i.e., font size, text direction, etc.
      76             : abstract class BaseTextConfig {
      77             :   /// The font size to be used, in points.
      78             :   final double fontSize;
      79             : 
      80             :   /// The direction to render this text (left to right or right to left).
      81             :   ///
      82             :   /// Normally, leave this as is for most languages.
      83             :   /// For proper fonts of languages like Hebrew or Arabic, replace this with [TextDirection.rtl].
      84             :   final TextDirection textDirection;
      85             : 
      86             :   /// The height of line, as a multiple of font size.
      87             :   final double? lineHeight;
      88             : 
      89          42 :   const BaseTextConfig({
      90             :     this.fontSize = 24.0,
      91             :     this.textDirection = TextDirection.ltr,
      92             :     this.lineHeight,
      93             :   });
      94             : }
      95             : 
      96             : /// An extension of the BaseTextConfig which includes more configs supported by
      97             : /// TextPaint
      98             : class TextPaintConfig extends BaseTextConfig {
      99             :   /// The font color to be used.
     100             :   ///
     101             :   /// Dart's [Color] class is just a plain wrapper on top of ARGB color (0xAARRGGBB).
     102             :   /// For example,
     103             :   ///
     104             :   ///     const TextPaint config = TextPaint(color: const Color(0xFF00FF00)); // green
     105             :   ///
     106             :   /// You can also use your Palette class to access colors used in your game.
     107             :   final Color color;
     108             : 
     109             :   /// The font family to be used. You can use available by default fonts for your platform (like Arial), or you can add custom fonts.
     110             :   ///
     111             :   /// To add custom fonts, add the following code to your pubspec.yaml file:
     112             :   ///
     113             :   ///     flutter:
     114             :   ///       fonts:
     115             :   ///         - family: 5x5
     116             :   ///           fonts:
     117             :   ///             - asset: assets/fonts/5x5_pixel.ttf
     118             :   ///
     119             :   /// In this example we are adding a font family that's being named '5x5' provided in the specified ttf file.
     120             :   /// You must provide the full path of the ttf file (from root); you should put it into your assets folder, and preferably inside a fonts folder.
     121             :   /// You don't need to add this together with the other assets on the flutter/assets bit.
     122             :   /// The name you choose for the font family can be any name (it's not inside the TTF file and the filename doesn't need to match).
     123             :   final String fontFamily;
     124             : 
     125             :   /// Creates a constant [TextPaint] with sensible defaults.
     126             :   ///
     127             :   /// Every parameter can be specified.
     128          43 :   const TextPaintConfig({
     129             :     this.color = const Color(0xFF000000),
     130             :     this.fontFamily = 'Arial',
     131             :     double fontSize = 24.0,
     132             :     TextDirection textDirection = TextDirection.ltr,
     133             :     double? lineHeight,
     134           1 :   }) : super(
     135             :           fontSize: fontSize,
     136             :           textDirection: textDirection,
     137             :           lineHeight: lineHeight,
     138             :         );
     139             : 
     140             :   /// Creates a new [TextPaintConfig] changing only the [fontSize].
     141             :   ///
     142             :   /// This does not change the original (as it's immutable).
     143           1 :   TextPaintConfig withFontSize(double fontSize) {
     144           1 :     return TextPaintConfig(
     145             :       fontSize: fontSize,
     146           1 :       color: color,
     147           1 :       fontFamily: fontFamily,
     148           1 :       textDirection: textDirection,
     149             :     );
     150             :   }
     151             : 
     152             :   /// Creates a new [TextPaintConfig] changing only the [color].
     153             :   ///
     154             :   /// This does not change the original (as it's immutable).
     155           0 :   TextPaintConfig withColor(Color color) {
     156           0 :     return TextPaintConfig(
     157           0 :       fontSize: fontSize,
     158             :       color: color,
     159           0 :       fontFamily: fontFamily,
     160           0 :       textDirection: textDirection,
     161             :     );
     162             :   }
     163             : 
     164             :   /// Creates a new [TextPaintConfig] changing only the [fontFamily].
     165             :   ///
     166             :   /// This does not change the original (as it's immutable).
     167           1 :   TextPaintConfig withFontFamily(String fontFamily) {
     168           1 :     return TextPaintConfig(
     169           1 :       fontSize: fontSize,
     170           1 :       color: color,
     171             :       fontFamily: fontFamily,
     172           1 :       textDirection: textDirection,
     173             :     );
     174             :   }
     175             : 
     176             :   /// Creates a new [TextPaintConfig] changing only the [textAlign].
     177             :   ///
     178             :   /// This does not change the original (as it's immutable).
     179           0 :   TextPaintConfig withTextAlign(TextAlign textAlign) {
     180           0 :     return TextPaintConfig(
     181           0 :       fontSize: fontSize,
     182           0 :       color: color,
     183           0 :       fontFamily: fontFamily,
     184           0 :       textDirection: textDirection,
     185             :     );
     186             :   }
     187             : 
     188             :   /// Creates a new [TextPaintConfig] changing only the [textDirection].
     189             :   ///
     190             :   /// This does not change the original (as it's immutable).
     191           0 :   TextPaintConfig withTextDirection(TextDirection textDirection) {
     192           0 :     return TextPaintConfig(
     193           0 :       fontSize: fontSize,
     194           0 :       color: color,
     195           0 :       fontFamily: fontFamily,
     196             :       textDirection: textDirection,
     197             :     );
     198             :   }
     199             : }
     200             : 
     201             : /// A Text Config contains all typographical information required to render texts; i.e., font size and color, family, etc.
     202             : ///
     203             : /// It does not hold information regarding the position of the text to be render neither the text itself (the string).
     204             : /// To hold all those information, use the Text component.
     205             : ///
     206             : /// It is used by [TextComponent].
     207             : class TextPaint extends TextRenderer<TextPaintConfig> {
     208             :   final MemoryCache<String, material.TextPainter> _textPainterCache =
     209             :       MemoryCache();
     210             : 
     211           1 :   TextPaint({
     212             :     TextPaintConfig config = const TextPaintConfig(),
     213           1 :   }) : super(config: config);
     214             : 
     215           0 :   @override
     216             :   void render(
     217             :     Canvas canvas,
     218             :     String text,
     219             :     Vector2 p, {
     220             :     Anchor anchor = Anchor.topLeft,
     221             :   }) {
     222           0 :     final tp = toTextPainter(text);
     223           0 :     final translatedPosition = anchor.translate(p, tp.size.toVector2());
     224           0 :     tp.paint(canvas, translatedPosition.toOffset());
     225             :   }
     226             : 
     227           1 :   @override
     228             :   double measureTextWidth(String text) {
     229           2 :     return toTextPainter(text).width;
     230             :   }
     231             : 
     232           1 :   @override
     233             :   double measureTextHeight(String text) {
     234           2 :     return toTextPainter(text).height;
     235             :   }
     236             : 
     237             :   /// Returns a [material.TextPainter] that allows for text rendering and size measuring.
     238             :   ///
     239             :   /// A [material.TextPainter] has three important properties: paint, width and height (or size).
     240             :   ///
     241             :   /// Example usage:
     242             :   ///
     243             :   ///     const TextPaint config = TextPaint(fontSize: 48.0, fontFamily: 'Awesome Font');
     244             :   ///     final tp = config.toTextPainter('Score: $score');
     245             :   ///     tp.paint(c, Offset(size.width - p.width - 10, size.height - p.height - 10));
     246             :   ///
     247             :   /// However, you probably want to use the [render] method which already renders for you considering the anchor.
     248             :   /// That way, you don't need to perform the math for yourself.
     249           1 :   material.TextPainter toTextPainter(String text) {
     250           2 :     if (!_textPainterCache.containsKey(text)) {
     251           1 :       final style = material.TextStyle(
     252           2 :         color: config.color,
     253           2 :         fontSize: config.fontSize,
     254           2 :         fontFamily: config.fontFamily,
     255           2 :         height: config.lineHeight,
     256             :       );
     257           1 :       final span = material.TextSpan(
     258             :         style: style,
     259             :         text: text,
     260             :       );
     261           1 :       final tp = material.TextPainter(
     262             :         text: span,
     263           2 :         textDirection: config.textDirection,
     264             :       );
     265           1 :       tp.layout();
     266             : 
     267           2 :       _textPainterCache.setValue(text, tp);
     268             :     }
     269           2 :     return _textPainterCache.getValue(text)!;
     270             :   }
     271             : 
     272           1 :   @override
     273             :   TextPaint copyWith(
     274             :     TextPaintConfig Function(TextPaintConfig) transform,
     275             :   ) {
     276           3 :     return TextPaint(config: transform(config));
     277             :   }
     278             : }

Generated by: LCOV version 1.15