[System] WordWrap

Scripts

14 years
edited 8 years
http://en.wikipedia.org/wiki/Word_wrapping

This is not as featured/precise as text editor word wrapping, but it does the job pretty well.

The description is in the documentation.

Code (jass) Select
1
library WordWrap /* v2.1.0.0 
2
*********************************************************************
3
*
4
*  Simulates word wrapping for multiboards and texttags.
5
*  Word wrapping is where, if a text is too long, it will
6
*  cut to the next line rather than cutting off the text.
7
*
8
*  How it works:
9
*
10
*      - Specify a source string and a size margin. The margin
11
*        determines what the size of the line can be before it
12
*        splits the string into fragments. The value is more or
13
*        less arbritrary, so just experiment with values.
14
*      - Explodes the string by spaces into words.
15
*      - Checks the size of each word.
16
*      - Once the size margin is reached, it will cut the string.
17
*      - The first line is stored in the array under the index 0.
18
*      - Rinse and repeat until it fragments the entire string.
19
*      - You can retrieve the count to know the max index reached.
20
*
21
*********************************************************************
22
*
23
*   */uses/*
24
*   
25
*       */ StringSize /*  https://wc3modding.info/5014/snippet-stringsize/
26
*
27
*    This library does not require Ascii, but StringSize requires
28
*    the Ascii library:
29
*
30
*
31
*********************************************************************
32
*
33
*  function WordWrapString takes string source, real sizeMargin, boolean preserveColors returns nothing
34
*
35
*      - Breaks the string into several fragments.
36
*      - Size margin determines the size the string can reach
37
*        before it fragments the string and breaks to the next
38
*        line.
39
*      - Preserve colors is a boolean to check if a color
40
*        code is being broken during the word wrap. If you
41
*        are not using color codes (ex: |cffffcc00text|r)
42
*        then you should set this to false to save performance.
43
*
44
*  function GetWrappedStringFragment takes integer index returns string
45
*
46
*      - Retrieves the fragmented strings. The indices start at 0
47
*        and will go up to the "count" index - 1. (see below) The last
48
*        line will be:
49
*
50
*          GetWrappedStringFragment(GetWrappedStringCount() - 1)
51
*
52
*  function GetWrappedStringCount takes nothing returns integer
53
*
54
*      - Returns the total number of fragments. Indices start at 0,
55
*        and the final line will be this number minus 1. 
56
*
57
*********************************************************************
58
*
59
*  struct WordWrap
60
*
61
*      static method getLine takes integer index returns string
62
*
63
*      static method getCount takes nothing returns integer
64
*
65
*      static method create takes string source, real sizeMargin, boolean preserveColors returns thistype
66
*
67
*********************************************************************
68
*
69
*  Credits
70
*
71
*      - cleeezzz & tooltiperror for the idea.
72
*
73
*  Bugs
74
*
75
*      - If there is a single word that is longer than the
76
*        "sizeMargin" input, then this system will fail. 
77
*        It requires extra checks. I may update this later
78
*        to fix that problem, but for now this should be fine.
79
*        PM or message me if you have any problems.
80
*
81
*********************************************************************/
82
83
    struct WordWrap extends array 
84
        private static string array line
85
        private static integer count = 0
86
87
        static method getLine takes integer index returns string
88
            return line[index]
89
        endmethod
90
        
91
        static method getCount takes nothing returns integer
92
            return count
93
        endmethod
94
        
95
        private static method preserveColor takes nothing returns nothing
96
            local integer i = 0
97
            local integer k = 0
98
            local integer l = 0
99
            local string temp = ""
100
            local string hex = ""
101
            local boolean carryOn = false
102
            loop
103
                exitwhen i == count
104
                set carryOn = false
105
                set hex = ""
106
                set k = 0
107
                set l = StringLength(line[i])
108
                loop
109
                    exitwhen k == l 
110
                    set temp = SubString(line[i], k, k+1)
111
                    if temp == "|" then
112
                        set temp = SubString(line[i], k+1, k+2)
113
                        if temp == "c" then
114
                            set hex = SubString(line[i], k, k+10)
115
                            set carryOn = true
116
                        elseif temp == "r" then
117
                            set carryOn = false
118
                        endif
119
                    endif
120
                    set k = k + 1
121
                endloop
122
                set i = i + 1
123
                if carryOn then
124
                    set line[i] = hex + line[i] 
125
                endif
126
            endloop
127
        endmethod
128
        
129
        static method create takes string source, real size, boolean preserveColors returns thistype
130
            local integer l = StringLength(source)
131
            local integer i = 0
132
            local integer k = 0 
133
            local string s
134
            
135
            local string word
136
            local real result = 0
137
            local real ssize = 0
138
            
139
            loop
140
                exitwhen count == 0
141
                set count = count - 1
142
                set line[count] = ""
143
            endloop
144
            loop
145
                exitwhen i == l
146
                set s = SubString(source, i, i+1)
147
                if s == " " or i == (l-1) then
148
                    set word = SubString(source, k, i) + s
149
                    set ssize = MeasureString(word)
150
                    set result = result + ssize
151
                    if result <= size then
152
                        set line[count] = line[count] + word
153
                    else
154
                        set count = count + 1
155
                        set line[count] = word
156
                        set result = ssize
157
                    endif
158
                    set k = i + 1
159
                endif
160
                set i = i + 1
161
            endloop
162
            set count = count + 1
163
            if preserveColors then
164
                call ForForce(bj_FORCE_PLAYER[0], function thistype.preserveColor)
165
            endif
166
            return 0
167
        endmethod
168
    endstruct
169
170
    function WordWrapString takes string source, real sizeMargin, boolean preserveColors returns nothing
171
        call WordWrap.create(source, sizeMargin, preserveColors)
172
    endfunction
173
174
    function GetWrappedStringFragment takes integer i returns string
175
        return WordWrap.getLine(i)
176
    endfunction
177
178
    function GetWrappedStringCount takes nothing returns integer
179
        return WordWrap.getCount()
180
    endfunction
181
182
endlibrary
183


Here is more information and pictures. First, take a look at this sample code:
Code (jass) Select
1
scope Testing initializer Init
2
    
3
    private function esc takes nothing returns nothing
4
        local string text = "Hello, my name is Joe. I work in a button factory. One day, my boss said to me, \"Hiya Joe! Are you busy?\" "+/*
5
        */" I said, \"No\"."    //our original text
6
        local integer i = 0
7
        call WordWrapString(text, 450, true) //We will break it into lines, 450 maximum pixels per line
8
        loop
9
            exitwhen i == GetWrappedStringCount()    //loop through each line up to the max line count.
10
            call BJDebugMsg(GetWrappedStringFragment(i))  //This is how you read a line
11
            set i = i + 1
12
        endloop
13
    endfunction
14
    
15
    private function Init takes nothing returns nothing
16
        local trigger t = CreateTrigger()
17
        call TriggerRegisterPlayerEvent(t, Player(0), EVENT_PLAYER_END_CINEMATIC)
18
        call TriggerAddAction(t, function esc)
19
    endfunction
20
endscope


This is that sample above, with a width of 150:

This is that sample above, but with a width of 450:


For color preservation, it is basically an option to preserve color codes when skipping to the next line. If it is set to "false", then it will not preserve the colors, boosting performance, but ruining how it looks. If you have something like this:
|cff00FF00Hello World! It is a
beautiful day!|r

It should color the entire text. However, without color preservation, it will only color the top line. It should be fine to disable this if you are only color coding individual words, or if you aren't using color codes, but otherwise it should be enabled.

Here is an example with color preservation:


Without it, it would look like this:


Enjoy, all feedback is welcome.
14 years
This is great! Really need a good system for making text on my SRPG, thanks for this one purge! Gonna try it when I got home.
13 years
Thanks.

I might end up making a multiboard/text tag system for this. It seems a bit much to have a system for everything, but it is really frustrating to deal with. If I made something to auto-extend multiboards or w/e or to create new text tags for new lines, then that thing would no longer be a problem. :)

If only there was a way to get resolution. I'm still looking to see if there is any hope of retrieving that.
13 years
I think the best way is to ask the user to say which resolution he is using through a dialog box or whatever else.
And because we don't always know which one we are using you could chek for each resolution what is the lowest texttag size available, and then display all these sizes with the text equal to the resolution, then the user just have to choice the biggest one he can see, but meh maybe it's already too much for the average battle.net player :p
13 years
Updated with optimizations and fixed a bug that came with my 2.0 update.
13 years
Definitely a very nice piece of code, and it does the job pretty well. Approved of course!!