JujuAdams / Scribble

Efficient, internationalized, multi-effects text renderer for GameMaker
https://www.jujuadams.com/Scribble/
MIT License
322 stars 47 forks source link

Add underline and strikethrough #184

Open OmegaX1000 opened 3 years ago

OmegaX1000 commented 3 years ago

I don't know if you can do this with normal game maker studio text functions let alone with scribble but this feels like a nice thing to have...

DragoniteSpam commented 3 years ago

[slant] can be used to emulate italics (but tends to be frowned on by typographers). Bold doesn't have an equivalent; I don't know what Juju's stance on adding one would be. With that said, you can set up a font with actual bold and italics attributes in GameMaker and change the font to it on the fly with [font_name].

Strikethrough and underline are unaccounted for since those are just lines being drawn and not actually font attributes. I imagine those cold be added.

OmegaX1000 commented 3 years ago

it would be easier if this was built into scribble, it eliminates a few extra steps...

DragoniteSpam commented 3 years ago

Actually, I was looking at an old version of the documentation: you can now combine font families together, and switch between them using formatting tags: https://github.com/JujuAdams/Scribble/wiki/Functions-(Font-Modification)

JujuAdams commented 3 years ago

As Dragonite kindly points out, swapping between bold and italic (and bold+italic) fonts is supported using the [b] and [i] and [bi] command tags. You need to set these up manually using scribble_font_set_style_family as Scribble does not procedurally associate fonts (it used to, but it was unreliable).

Adding underline and strikethrough is... something I'll think about. I'm not 100% sure if GM reveals enough information to handle these features, though I will check.

DragoniteSpam commented 3 years ago

I'm sure you can put together something that's "good enough" just based on the dimensions of each glyph and or the final positions of each vertex. No idea how much doing something simple like that would offend typographers though.

patchuby commented 2 months ago

I just implemented underline, I'm adding my (badly written) functions to get individual lines width and draw an underline in case it's useful as a jumping-off point. And it's only for horizontal, left to right languages (do vertical scripts have underline ?) The textargument supplied is the scribble element, underline_pos is the total length in pixel of the underline, across multiple lines.

function scribble_get_lines_width(text)
{
    var _line_count = text.get_line_count();
    var _glyph_count = text.get_glyph_count();
    var _previous_x = 99999;
    var _last_leftmost_glyph = -1;

    text[$ "__lines_width"] = array_create(_line_count);

    if(_line_count == 1) text.__lines_width[0] = text.get_bbox().width;
    else
    {
        var j = 0;
        for(var i = 0; i < _glyph_count; i++)
        {
            var _current_x = text.get_glyph_data(i).left;
            if(_current_x < _previous_x || i == _glyph_count - 1) 
            {
                if(_last_leftmost_glyph != -1)
                {
                    text.__lines_width[j] = text.get_glyph_data(i - 1).right - text.get_glyph_data(_last_leftmost_glyph).left;
                    j++;
                }
                _last_leftmost_glyph = i;
            }
            _previous_x = _current_x;
        }
    }

    text[$ "__total_width"] = 0;

    for(var i = 0; i < _line_count; i++) text.__total_width+= text.__lines_width[i];
}

function scribble_draw_underline(text,xx,yy,underline_pos,typist = undefined,color = c_black,alpha = 1,align = fa_left,thickness = 3)
{
    if(underline_pos < 1) exit;
    if(text[$ "__lines_width"] == undefined) show_debug_message("Error trying to draw underline before having called 'scribble_get_lines_width'");
    draw_set_color(color);
    draw_set_alpha(alpha)
    if(typist != undefined) var _underline_pos = min(typist.__revealed_total_width,underline_pos);
    else _underline_pos = underline_pos;
    var _current_left = 0;
    var _bbox = text.get_bbox();
    for(var i = 0; i < text.get_line_count(); i++)
    {
        if(_underline_pos < _current_left) break;
        if(_underline_pos >= _current_left +  text.__lines_width[i])  var line_progress = text.__lines_width[i];
        else line_progress = _underline_pos - _current_left;

        var dist = line_height/2 + (i * line_height);
        var x1 = xx + lengthdir_x(dist,-90);

        if(align == fa_center) x1 += (_bbox.width - text.__lines_width[i])/2;
        else if(align == fa_right) x1 += _bbox.width - text.__lines_width[i];

        var y1 = yy + lengthdir_y(dist,-90);
        draw_rectangle(x1,y1,x1 + line_progress,y1 + thickness,false);

        _current_left+= text.__lines_width[i];
    }
}