mIRC Home    About    Download    Register    News    Help

Print Thread
#267197 18/04/20 06:25 PM
Joined: Jan 2004
Posts: 2,127
maroon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Jan 2004
Posts: 2,127
I was expecting that using $width to create the 4th parm for $wrap works, but it doesn't. In this case, it's chopping the string unless setting %adjust to at least 2 or greater. And, word=1 is supposed to wrap at whole words, but in this case (not not for all strings) it's still chopping in the middle of a word.

//var -s %string test string , %font Tahoma , %fontsize 12 , %adjust 0, %width $width(%string ,%font,%fontsize) | echo -a word=0 $wrap( %string , %font , %fontsize , $calc(%width + %adjust) , 00 , 1 ) | echo -a word=1 $wrap( %string , %font , %fontsize , $calc(%width + %adjust) , 01 , 1 )

maroon #267213 23/04/20 10:54 AM
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
Thanks for your bug report. That sounds about right. All $wrap() guarantees is that it will wrap strings before the pixel width, not that it will match the pixel width returned by $width() exactly. It also does not guarantee that it will chop at whole words, ie. it will not chop at a space near the beginning of a string to leave a whole word. It will look from around the middle of the string and onwards for spaces to chop at.

Khaled #267214 23/04/20 11:40 AM
Joined: Jul 2006
Posts: 4,145
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,145
Hum, I disagree with how you say $wrap should work, $wrap has been working correctly before.

All $wrap guarantees is that it will wrap BEFORE the width is reached, or at maximum at that width, this is pretty much how it is useful, if it were to wrap after that width, it wouldn't be useful to pass a max width.
And the help file agrees with that:
Quote
Returns Nth line in text wrapped to the specified width in pixels.


And if the word parameter is passed (or by default, according to the help file), it should wrap all the same, but at word.

The total width of a line returned by $wrap can never exceed the width value passed to it.

To elaborate a bit on the report, it makes sense that if "text" takes 100 pixels in width to be drawn in a certain font & size, it will never wrap on a width of 100 pixels, but $wrap reports a wrap, that's not correct.

Another example, if it takes 100 pixels in width to draw "this is a string" in a specific font & size, and you pass 90 in width to $wrap, with word = 0 it should wrap around "in" in "this is a string", with word = 1 (or by default) it would wrap at "a".

If this is considered not a bug, I would like to see a switch which does the above, I'll make test to see if 6.35 had $wrap correct.


Last edited by Wims; 23/04/20 03:42 PM.

#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Khaled #267215 23/04/20 03:41 PM
Joined: Jan 2004
Posts: 2,127
maroon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Jan 2004
Posts: 2,127
But /help says that it wraps to the specified width, not "close to" the width. To most people reading that, "to" means "at" not "before".

I agree that it should chop in the middle of a word if the 'word' is longer than the specified width, but in my example, even when the specified width matches the actual width, or is 1 pixel wider, it's still chopping instead of including the remainder of the word which does fit within the specified width. In my prior example, when %adjust is 0 or 1, the string is less than or equal to the specified width, so there's no need for wrapping or chopping.

And it's chopping apparently because, while there is a space in the string, it's not late enough in the string for $wrap to notice it. So, ignoring the first half of the string explains to me why this next example also gets chopped, even though there's plenty of spaces.

//var -s %string a b c d e f g h i j k l m abcdefghijklmnopqrstuvwxyz , %font Tahoma , %fontsize 12 , %adjust 0, %width $width(%string ,%font,%fontsize) | echo -a word=0 $wrap( %string , %font , %fontsize , $calc(%width + %adjust) , 00 , 1 ) | echo -a word=1 $wrap( %string , %font , %fontsize , $calc(%width + %adjust) , 01 , 1 )

Wims #267216 23/04/20 04:12 PM
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
Quote
All $wrap guarantees is that it will wrap BEFORE the width is reached, or at maximum at that width

Right, my previous post was unclear. That is what it was designed for, to wrap before, and as close to, the specified width, otherwise it wouldn't have much use. I have updated my post.

Quote
And if the word parameter is passed (or by default, according to the help file), it should wrap all the same, but at word.

It will only wrap at a word if a space is located from around half and onwards through the string. This has always been the case.

$wrap() will not match $width() exactly, so the best you can expect is that $wrap() will wrap text before the width.

maroon #267217 23/04/20 04:19 PM
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
Quote
But /help says that it wraps to the specified width, not "close to" the width. To most people reading that, "to" means "at" not "before".

Well, it cannot wrap to the width exactly. To do that, it would have to chop letters in half. It is wrapping as close as it can to before the width specified.

If you are asking it to wrap on whole words, it will also try that, but only if there is a space delimiting the words from around half way onwards through the string.

Quote
but in my example, even when the specified width matches the actual width, or is 1 pixel wider,

That is because you are expacting $wrap() to measure in exactly the same way as $width(). I mentioned in my previous post that this will not be the case. The best you can hope for is that it will wrap as close as it can before the specified width.

Khaled #267219 24/04/20 01:43 AM
Joined: Jul 2006
Posts: 4,145
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,145
Quote
That is what it was designed for, to wrap before, and as close to, the specified width, otherwise it wouldn't have much use. I have updated my post.

Ok.
Let me also clarify: I meant that it should use the maximum width available.

I wrote a custom $wrap2 identifier which does the job I/we are talking about:


Code
alias wrap2 {
  ;$1 = text $2 = font $3 = size, $4 = width, $5 = B $6 = C $7 = D $8 = N $9 = word $10 = optional C
  if ($1 == $null) || ($2 == $null) || ($3 == $null) || ($4 == $null) || ($8 == $null) { echo -s * $wrap2 insufficient params | return }
  if ($4 == 0) {
    if ($8 == 0) return 0
    return 
  }
  elseif ($width($1,$2,$3,$5,$6,$7) <= $4) {
    if ($8 == 0) return 1
    return $1
  }
  ;else echo -s $v1
  ;if no word
  if (!$9) {
    ;if N = 0 return total number of lines
    if ($8 == 0) return $ceil($calc($width($1,$2,$3,$5,$6,$7) / $4))
    else {
      var %index 1,%n 0,%seek,%len
      ;otherwise, we get each line and return it if N correspond
      while ($mid($1,%index,1) != $null) {
        %seek = 1
        %len = $calc($len($1) - %index + 1)
        while (%seek <= %len) && ($width($mid($1,%index,%seek),$2,$3,$5,$6,$7) <= $4) {
          inc %seek        
        }
        dec %seek
        inc %n
        if (%n == $8) returnex $mid($1,%index,%seek)
        %index = %index + %seek
      }
    }
    ;last line because seek > len
    returnex $mid($1,%index)
  }
  else {

    var %n 0,%seek 1,%rp $iif($chr($10) isin \[]-,\ $+ $v1,$v1),%p /([^\x20 $+ %rp $+ ]+)([\x20 $+ %rp $+ ]+|$)/
    var %index 1
    while ($regex(wrap2,$mid($1,%seek),%p)) {
      var -p %wt %r $+ $regml(wrap2,1)
      if ($width(%wt,$2,$3,$5,$6,$7) > $4) {
        inc %n
        if (!%r) {
          if ($8 == 0) return 0
          return 
        }
        if (%n == $8) {
          returnex $mid(%wt,1,- $+ $calc($len($regml(wrap2,1) $+ $regml(wrap2,2)) + 1))
        }
        unset %r
        var %no 1
      }
      if (!%no) {
        var -p %r %r $+ $regml(wrap2,1) $+ $regml(wrap2,2)
        inc %seek $len($regml(wrap2,1) $+ $regml(wrap2,2))
      }
      unset %no
    }
    inc %n
  }
  if ($8 == 0) return %n
  returnex %wt
}


And I wrote a code demonstrating the neat differences (which is, in fact, very small and hard to see in practice)

Code
alias testingwrap {
  window -pdfoBC +slt @tw -1 -1 400 1000
  testingwrap_refresh
}

alias testingwrap_refresh {
  drawrect -frn @tw 16777215 0 0 0 $window(@tw).dw $window(@tw).dh
  var %1 This is a line wrapped with stuff ok very long line
  var %font segoe ui symbol,%size 15
  var %x 0,%y 0 ,%w $window(@tw).dw
  var %a 1,%wrap1 $wrap(%1,%font,%size,%w,0,0)
  while (%a <= %wrap1) {
    drawtext -rn @tw 0 $qt(%font) %size %x %y $wrap(%1,%font,%size,%w,0,%a)
    inc %a
    inc %y 20
  }

  var %a 1,%wrap1 $wrap2(%1,%font,%size,%w,0,0,0,0,0)
  var %y = 200
  while (%a <= %wrap1) {
    drawtext -rn @tw 0 $qt(%font) %size %x %y $wrap2(%1,%font,%size,%w,0,0,0,%a,0)
    inc %a
    inc %y 20
  }
  var %a 1,%wrap1 $wrap(%1,%font,%size,%w,1,0)
  var %y = 400
  while (%a <= %wrap1) {
    drawtext -rn @tw 0 $qt(%font) %size %x %y $wrap(%1,%font,%size,%w,1,%a)
    inc %a
    inc %y 20
  }

  var %a 1,%wrap1 $wrap2(%1,%font,%size,%w,0,0,0,0,1)
  var %y = 600
  while (%a <= %wrap1) {
    drawtext -rn @tw 0 $qt(%font) %size %x %y $wrap2(%1,%font,%size,%w,0,0,0,%a,1)
    inc %a
    inc %y 20
  }
  drawdot @Tw
  .timertw -ho 1 30 testingwrap_refresh
}
on *:close:@tw:.timertw off
First line = mIRC's $wrap with word = 0.
Second line = $wrap2 with word = 0
Third line = mIRC's $wrap with word = 1
Fourth line = $wrap2 with word = 1

As i said the difference is not very big at where it wraps.
However $wrap actually breaks on the rule of word boundary (when word = 1) when the width is too small to fit a word, in this case it will show the maximum possible width of the word and then wrap, which allows to see the text even with small widths.

My custom alias is not doing that, instead it will report that the total number of line is 0, because you won't be able to draw the word entirely. Note that this version of the alias still make it possible to access the early part of a wrapped line as long as they fit, even though the next chunk might not fit and would return $null, but N = 0 always return 0 when any of the chunk/word can't fit, it could be changed.

Also $wrap has some bugs without the word parameter, this bug was reported years ago: $wrap(Hello World,Tahoma,11,1,0,1) is H but should be $null because you cannot draw H with one pixel.
If at least $wrap(Hello World,Tahoma,11,1,0,2) were 'e', it would make sense but there i think it should return $null.



Another topic is that we cannot currently draw consecutives spaces with /drawtext, and to overcome this issue, we must change spaces to something else, maybe a switch for /drawtext to draw from a binvar could be added?
My alias allows for a $10 parameter to be a ascii/code point value to be used as a character for boundary instead of the space ascii 32.
Unicode space characters exist, but we would need a way to pass that to $wrap.

If not for the old bug, I don't think $wrap is that buggy with word parameter = 0, it's not pixel perfect but good enough for practice, it may still be great to see $wrap fixed/extended to be pixel perfect.

I'll make more test with word = 1 but it would be great to be able to draw consecutives space with drawtext to see this in action.

Note: $wrap does need to be extended to support the new parameter of $width


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Wims #267221 24/04/20 08:24 AM
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
Quote
However $wrap actually breaks on the rule of word boundary (when word = 1) when the width is too small to fit a word, in this case it will show the maximum possible width of the word and then wrap, which allows to see the text even with small widths.

That is indeed what it was designed to do.

Quote
Also $wrap has some bugs without the word parameter, this bug was reported years ago: $wrap(Hello World,Tahoma,11,1,0,1) is H but should be $null because you cannot draw H with one pixel.

Again, this is intended.

$wrap() was implemented a long time ago to behave in the way it does. There are no plans to change its behaviour now.

I think the issue here is that you want a $wrap() that works in different way for a particular use.

If you want a new identifier that works in a different way, please post this as a feature suggestion.

Khaled #267222 24/04/20 08:40 AM
Joined: Jul 2006
Posts: 4,145
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,145
I don't really want a new identifier, just describing observation, I believe asking for a new parameter for $wrap to go with $width's new parameter belong to this thread though, but I'll post in feature suggestion.


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Wims #267224 24/04/20 12:15 PM
Joined: Dec 2002
Posts: 5,411
Hoopy frood
Offline
Hoopy frood
Joined: Dec 2002
Posts: 5,411
Okay. Looking at $wrap(), it might be possible to extend the [word] parameter to support a set of switches, ie. if it is 0 or 1, it will continue to work as it does now. However, it if is a set of switches, eg. 'w' for word wrap, 'a' for an alternative mode that behaves the way you are suggesting, and so on, that could work.


Link Copied to Clipboard