Scribble icon indicating copy to clipboard operation
Scribble copied to clipboard

Implement Greg's Custom Line Wrapping

Open JujuAdams opened this issue 3 years ago • 3 comments

Greg Lobanov suggested an alternate line wrapping method. This is currently going to be v hard to implement with the current parser so will have to wait until the parser rewrite.

function text_add_linebreaks(str,width,scale){
//str is the original input string
//width is the max width we want to fit inside, or -1 for no max
//scale is the scaling on the text
//if a 4th argument is supplied, it's the maximum number of lines we can break into.
    var sw = string_width(str)*scale, //current string width
        sh = string_height(str)*scale, //current height
        slines = string_count("#",str), //how many lines are already present?
        lines = 1+slines, 
        maxlines = -1;
if argument_count>3{
    maxlines = argument[3];    
}
 
//determine a target number of lines by breaking it until it hypothetically fits inside the width, or if no width is set, then we just aim to make the width no more than 2x the height   
 while(((width!=-1 and (sw/lines)>width) or (width==-1 and (sw/lines)>(sh*(lines)*2))) and (maxlines<0 or lines<maxlines)){
        lines += 1;
    }

//from roughly even spots throughout the string, find spaces which we can replace with a newline.
    for(var l=1;l<lines-slines;l+=1){
        var t = str;

        var cc = round(string_length(t)*(l)/(lines-slines)),
            c = 0,
            i = 0;
        while((c+cc)>0 and (c+cc)<=string_length(t)){
            if string_char_at(t,cc+c)==" "{
                t = string_delete(t,cc+c,1);
                t = string_insert("#",t,cc+c);
                str = t;
                break;
            }else{
                if !is_even(i){
                    c = -c;
                }else{
                    c = abs(c)+1;
                }
                i += 1;
            }
        }

    }
    
    return str;
}

JujuAdams avatar Apr 19 '21 09:04 JujuAdams

I was able to recreate this using this short helper script. It uses scribble on a single long text line to work out the total width, then uses width that to work out an optimal new balanced width that can be input to a simple .wrap(). scribble does all the work. :)

function scribble_add_linebreaks(dialog_scribble,max_width,max_lines){
		var w = dialog_scribble.get_width(),
			h = dialog_scribble.get_height(),
			lines = 1;
			while(lines<max_lines and ((w/lines)>max_width or (w/lines)>(h*lines*12))){
				lines += 1;
			}
			dialog_scribble.wrap(w/(lines*.95));
}

gl326 avatar Aug 19 '23 19:08 gl326

Per CSS: https://www.w3.org/TR/css-text-4/#valdef-text-wrap-balance Demo for Chrome https://codepen.io/web-dot-dev/pen/KKxjpQm Adobe's older JS impl https://github.com/adobe/balance-tex

offalynne avatar Aug 22 '23 00:08 offalynne

To paraphrase an explanation of the web solution I saw elsewhere: Do an initial wrap pass at the specified width, multiply that width by 80% as a "virtual width", and then minimise the virtual width until it is as low as possible without adding a new line using similar binary search to what Scribble does already.

JujuAdams avatar Aug 22 '23 05:08 JujuAdams