examples: annotate examples
[nit.git] / lib / gamnit / bmfont.nit
index afdbf04..d052922 100644 (file)
@@ -283,7 +283,7 @@ end
 #     var pos: Point3d[Float] = ui_camera.top_left.offset(128.0, -128.0, 0.0)
 #     var ui_text = new TextSprites(font, pos)
 #
-#     redef fun on_create
+#     redef fun create_scene
 #     do
 #         super
 #
@@ -366,15 +366,28 @@ class BMFontAsset
                var dx = 0.0
                var dy = 0.0
                var text_width = 0.0
+               var line_sprites = new Array[Sprite]
+               var height = 0.0
+
+               # Has the current line height been added to `height`?
+               var line_height_counted = false
 
+               # TextSprite customization
                var max_width = text_sprites.max_width
                var max_height = text_sprites.max_height
                var scale = text_sprites.scale
 
+               # Font customization
                var line_height = desc.line_height * scale
                var partial_line_skip = line_height * partial_line_mod.to_f
-               var line_sprites = new Array[Sprite]
 
+               # Links data
+               text_sprites.links.clear
+               var in_link = false
+               var link_sprites = new Array[Sprite]
+               var link_name = ""
+
+               # Loop over all characters
                var prev_char = null
                var i = -1
                while i < text.length - 1 do
@@ -388,14 +401,21 @@ class BMFontAsset
                                dy -= line_height
                                if max_height != null and max_height < -dy + line_height then break
                                dx = 0.0
+                               if not line_height_counted then
+                                       # Force to account for empty lines
+                                       height += line_height
+                               end
+                               line_height_counted = false
                                prev_char = null
                                continue
                        else if c == pld then
                                dy -= partial_line_skip
+                               height += partial_line_skip
                                word_break = true
                                continue
                        else if c == plu then
                                dy += partial_line_skip
+                               height -= partial_line_skip # We could keep two heights and return the max
                                word_break = true
                                continue
                        else if c.is_whitespace then
@@ -406,8 +426,57 @@ class BMFontAsset
                                        else 16.0
                                dx += space_advance * scale
                                word_break = true
+                       else if c == '[' then
+                               # Open link?
+                               if i + 1 < text.length and text[i+1] == '[' then
+                                       # Escape if duplicated
+                                       i += 1
+                               else
+                                       in_link = true
+                                       continue
+                               end
+                       else if c == ']' then
+                               # Close link?
+                               if i + 1 < text.length and text[i+1] == ']' then
+                                       # Escape if duplicated
+                                       i += 1
+                               else
+                                       # If there's a () use it as link_name
+                                       var j = i + 1
+                                       if j < text.length and text[j] == '(' then
+                                               var new_name
+                                               new_name = ""
+                                               loop
+                                                       j += 1
+                                                       if j > text.length then
+                                                               # No closing ), abort
+                                                               new_name = null
+                                                               break
+                                                       end
+
+                                                       var l = text[j]
+                                                       if l == ')' then break
+                                                       new_name += l.to_s
+                                               end
+                                               if new_name != null then
+                                                       link_name = new_name
+                                                       i = j
+                                               end
+                                       end
+
+                                       # Register the link for the clients
+                                       text_sprites.links[link_name] = link_sprites
+
+                                       # Prepare next link
+                                       in_link = false
+                                       link_sprites = new Array[Sprite]
+                                       link_name = ""
+                                       continue
+                               end
                        end
 
+                       if in_link then link_name += c.to_s
+
                        # End of a word?
                        if word_break then
                                # If we care about line width, check for overflow
@@ -418,25 +487,28 @@ class BMFontAsset
                                        for wi in [i+1..text.length[ do
                                                var w = text[wi]
 
-                                               if w == '\n' or w == pld or w == plu or w.is_whitespace then break
+                                               if w == '\n' or w == pld or w == plu or w.is_whitespace or (in_link and w == ']') then break
+
+                                               if not desc.chars.keys.has(w) then
+                                                       var rc = replacement_char
+                                                       if rc == null then continue
+                                                       w = rc
+                                               end
+
                                                word_len += advance(prev_w, w) * scale
                                                prev_w = w
                                        end
 
                                        # Would the line be too long?
                                        if dx + word_len > max_width then
-                                               if text_sprites.wrap then
-                                                       # Wrap
-                                                       justify(line_sprites, text_sprites.align, dx)
-                                                       dy -= line_height
-                                                       if max_height != null and max_height < -dy + line_height then break
-                                                       dx = 0.0
-                                               else
-                                                       # Cut short
-                                                       justify(line_sprites, text_sprites.align, dx)
-                                                       dy -= line_height
-                                                       if max_height != null and max_height < -dy + line_height then break
-                                                       dx = 0.0
+                                               justify(line_sprites, text_sprites.align, dx)
+                                               dy -= line_height
+                                               if max_height != null and max_height < -dy + line_height then break
+                                               dx = 0.0
+                                               line_height_counted = false
+
+                                               if not text_sprites.wrap then
+                                                       # Cut short, skip everything until the next new line
                                                        while c != '\n' and i < text.length - 1 do
                                                                i += 1
                                                                c = text[i]
@@ -467,11 +539,18 @@ class BMFontAsset
                        s.scale = scale * char_info.scale
                        text_sprites.sprites.add s
                        line_sprites.add s
+                       if in_link then link_sprites.add s
 
                        dx += (advance + kerning) * scale
                        prev_char = c
 
                        text_width = text_width.max(dx)
+
+                       if not line_height_counted then
+                               # Increase `height` only once per line iff there's a caracter
+                               line_height_counted = true
+                               height += line_height
+                       end
                end
 
                justify(line_sprites, text_sprites.align, dx)
@@ -483,7 +562,7 @@ class BMFontAsset
                end
 
                text_sprites.width = text_width.max(dx)
-               text_sprites.height = dy + line_height
+               text_sprites.height = height
        end
 
        # Character replacing other characters missing from the font