[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: string-width error?

In article <199502081156.AA05284@xs1.xs4all.nl>, psto@xs4all.nl (Peter
Stone) wrote:

> Thanks for advice for everybody. The width problem was endeed caused
> by string exceeding the build-in Mac OS limit, which was undocumented 
> in the MCL manual.
> Natural-size works fine when the text to be sized contains newlines at 
> the end of each row. But the string I'm sizing is "a very long string 
> without newlines". Its width must be calculated in chunks. Here is the 
> unlimited length version of string-width.

[function to determine width of string in a given font deleted]

> Text item can now be sized to match a given horisontal width, here 400. 
> Note that 370 approximates the shorter lines due wrapping when the text
> is to be shown with wilma mixin. 

I thought this was what you were looking for.  The approximation you
mention above means that your solution may give you an incorrect result
(either too big or too small--or am i wrong about this?).  Just for kicks
I've included my uglier way of doing this which I originally wrote so i
could vertically center some text in a dialog item. The function
"text-max-vert" will give you the exact height needed to display a given
string in a static text dialog item (and should work for other text
display items that word wrap in the same way that text-edit does).  It
also accounts for differences resulting from justification. This could
also be modified to work on text with multiple styles.  

On the other hand, it sure aint portable....but it does use prog1 :-)

If anybody really wants this I could post an example
static-text-dialog-item that adjusts its height automatically to its text
& width.

;; Given some text, a width, a font, a justification and a
;; word wrap setting, return the number of vertical pixels 
;; needed to display the text.
;; This requires a bit of explanation.  Basically a
;; dummy TERec is being created with the desired width and filled
;; with the correct text in the desired font.  Then TEGetHeight
;; is called.  
;; There are some silly details.  The TERec needs to be created
;; at a given size.  The width is known but the height is, of course,
;; not.  The height of the dummy TERec luckily doesn't matter to
;; TEGetHeight, so i just make a square rectangle.  The other detail
;; is that TEGetHeight needs start and end line numbers.  The start is
;; 1, of course, and the length of the string is used for the endline
;; on the grounds that this is the max number of lines it could occupy.

(defun text-max-vert (str width font &key  (just :left) (auto-wrap? t))
  (rlet ((r :Rect :topLeft 0 :botRight (make-point width width)))
    (let ((te_h (#_TEStylNew r r))
          (str-len (length str)))
      (with-cstrs ((cstr str))
        (#_TESetText cstr str-len te_h))
      (#_TESetJust (just-constant just) te_h)
      (hset te_h :TERec.crOnly (if auto-wrap? 0 -1))
      (set-font te_h font)
        (#_TEGetHeight str-len 1 te_h)
        (#_TEDispose te_h)))))

(defun set-font (te_h font-spec)
  (multiple-value-bind (ff ms) (font-codes font-spec)
    ;; why do i feel like i'm programming in C?
    (rlet ((ts :TextStyle
               :tsFont        (#_HiWord ff)
               :tsFace        (ash (#_LoWord ff) -8)
               :tsSize        (#_LoWord ms)))
      (#_TESetStyle #$doAll ts t te_h)
      (#_TECalText te_h))))

(defun just-constant (just)
  ;; Convert a mcl justification keyword to the corresponding
  ;; toolbox constant
  (ecase just
    (:default #$teFlushDefault)
    (:center  #$teCenter)
    (:right   #$teFlushRight)
    (:left    #$teFlushLeft)))

Michael Korcuska
Institute for the Learning Sciences
Northwestern University