From: Arthur Lemmens
Subject: Subject: Defining CAPI layouts in Lispworks
Date: 
Message-ID: <37F1369D.7387990B@simplex.nl>
Two months ago, Marco Antoniotti posted a question about Harlequin's
CAPI to comp.lang.lisp. Marco was:

> [...] designing my own layout which needs (don't
> ask me why - it's my business) to know the "best" size for the
> children *before* actually doing the display.

I've been doing some CAPI hacking last week, and I think I've finally found 
a decent way to do this. I've sent some code to the Lispworks mailing list 
(···@lisp.de) that shows how you can define your own layout. If anybody else 
is interested, just let me know and I'll be happy to mail you the code.

Arthur Lemmens

From: Marco Antoniotti
Subject: Re: Subject: Defining CAPI layouts in Lispworks
Date: 
Message-ID: <lwpuz288v4.fsf@copernico.parades.rm.cnr.it>
Arthur Lemmens <·······@simplex.nl> writes:

> Two months ago, Marco Antoniotti posted a question about Harlequin's
> CAPI to comp.lang.lisp. Marco was:
> 
> > [...] designing my own layout which needs (don't
> > ask me why - it's my business) to know the "best" size for the
> > children *before* actually doing the display.
> 
> I've been doing some CAPI hacking last week, and I think I've finally found 
> a decent way to do this. I've sent some code to the Lispworks mailing list 
> (···@lisp.de) that shows how you can define your own layout. If anybody else 
> is interested, just let me know and I'll be happy to mail you the code.
> 

I am obviously interested.

I have had a long discussion with Harlequin people.  The discussion
was very helpful and polite, but I still think that CAPI has a serious
lack in the layout protocol.  I.e. there is *no* way to know the
actual dimensions of many objects before you did a DISPLAY (i.e. an
actual "mapping" in X parlance) of the top level widget (another X
term).

Cheers

-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa
From: Arthur Lemmens
Subject: Re: Subject: Defining CAPI layouts in Lispworks
Date: 
Message-ID: <37F21393.EE6C9432@simplex.nl>
I wrote:
> I've sent some code to the Lispworks mailing list (···@lisp.de) that shows 
> how you can define your own layout. If anybody else is interested, just 
> let me know.

Macro Antoniotti writes: 
> I am obviously interested.

I sent you a mail Tuesday night but it seems to have bounced. 
I've resent it today.

> there is *no* way to know the actual dimensions of many objects before 
> you did a DISPLAY (i.e. an actual "mapping" in X parlance) of the top 
> level widget

After you call CAPI:DISPLAY, lots of things happen before anything gets
*actually displayed* on the screen. As part of the layout protocol,
the generic functions CALCULATE-CONSTRAINTS and CALCULATE-LAYOUT get
called. By subclassing LAYOUT and defining your own methods for 
CALCULATE-CONSTRAINS and CALCULATE-LAYOUT, you can find out the 
constraints (minimum/maximum width/height) of all child elements.
Based upon those constraints, you can *decide* what dimensions you 
want the child elements to have by setting their x,y,width,height
geometry slots. In my book, setting the actual dimensions is at least
as good as knowing them.

> I still think that CAPI has a serious lack in the layout protocol. 

I think you're mistaken. Please take a look at my code. When you've done
that, I'd be interested to know if you still think there's something 
missing in CAPI'S layout protocol.

Arthur Lemmens
From: Marco Antoniotti
Subject: Re: Subject: Defining CAPI layouts in Lispworks
Date: 
Message-ID: <lwln9p91jf.fsf@copernico.parades.rm.cnr.it>
Arthur Lemmens <·······@simplex.nl> writes:

> I wrote:
> > I've sent some code to the Lispworks mailing list (···@lisp.de) that shows 
> > how you can define your own layout. If anybody else is interested, just 
> > let me know.
> 
> Macro Antoniotti writes: 
> > I am obviously interested.
> 
> I sent you a mail Tuesday night but it seems to have bounced. 
> I've resent it today.
> 
> > there is *no* way to know the actual dimensions of many objects before 
> > you did a DISPLAY (i.e. an actual "mapping" in X parlance) of the top 
> > level widget
> 
> After you call CAPI:DISPLAY,

This is the crux!  I *do not* want to call CAPI:DISPLAY.  I want to
compute the dimensions of elements *without* calling CAPI:DISPLAY (or
CPAI:CONTAIN).

> lots of things happen before anything gets
> *actually displayed* on the screen.

I understand this.  I would like something that could do this "lot of
things" and *stop*.  Note that by CAPI:HIDE-INTERFACE you can achieve
all you need *after* you have CAPI:DISPLAYed a widget hierarchy.  But
you must have the first display done.  Not pretty.

> As part of the layout protocol,
> the generic functions CALCULATE-CONSTRAINTS and CALCULATE-LAYOUT get
> called. By subclassing LAYOUT and defining your own methods for 
> CALCULATE-CONSTRAINS and CALCULATE-LAYOUT, you can find out the 
> constraints (minimum/maximum width/height) of all child elements.
> Based upon those constraints, you can *decide* what dimensions you 
> want the child elements to have by setting their x,y,width,height
> geometry slots. In my book, setting the actual dimensions is at least
> as good as knowing them.

No it is not. Think of the following (admittetdly contrived) example.
You have some text to display in a dialog.  You want to display a
short message or a message in a scrolled subwindow depending on "how
much" text you have.  The easy way to do this is (1) compute how much
real estate you would occupy and then (2) decide what widget is best
for the display.  You cannot so this in CAPI.  CAPI forces you (in the
best case) to add *both* widgets in turn during
CAPI:CALCULATE-CONSTRAINTS and CAPI:CALCULATE-LAYOUT and then to
discard one of them.

We can go around this as long as you want.  You have no way to avoid
an unwanted DISPLAY in CAPI.

> > I still think that CAPI has a serious lack in the layout protocol. 
> 
> I think you're mistaken.

I would be very happy to be.  But I believe that CAPI is missing a
CAPI:REALIZE primitive (or a CAPI:MANAGE primitive) as it it is
present in Xt.  (Or at least a DISPLAY with an extra VISIBLE parameter).

> Please take a look at my code. When you've done
> that, I'd be interested to know if you still think there's something 
> missing in CAPI'S layout protocol.

Sure, pass me the code.  Seriously, I will be pleased to be
proven wrong.

Cheers

-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa
From: Arthur Lemmens
Subject: Re: Subject: Defining CAPI layouts in Lispworks
Date: 
Message-ID: <37F26F00.49A97206@simplex.nl>
Marco Antoniotti wrote:

> Think of the following (admittetdly contrived) example.
> You have some text to display in a dialog.  You want to display a
> short message or a message in a scrolled subwindow depending on "how
> much" text you have.  The easy way to do this is (1) compute how much
> real estate you would occupy and then (2) decide what widget is best
> for the display.  You cannot do this in CAPI. 

I think the code below does exactly what you're asking for.

> CAPI forces you (in the best case) to add *both* widgets in turn during
> CAPI:CALCULATE-CONSTRAINTS and CAPI:CALCULATE-LAYOUT and then to
> discard one of them.

So what? Only one of them will be visible. The other one will never
appear on the screen.

> We can go around this as long as you want.  You have no way to avoid
> an unwanted DISPLAY in CAPI.

Just because you have to call DISPLAY before you can start computing
widget dimensions doesn't mean that all widgets will be *actually*
displayed on the screen. Please look at the code below. If you insist,
insert a BREAK and a few format-statements in the CALCULATE-LAYOUT method 
to convince yourself that all dimensions have been computed before 
anything is displayed on the screen.

> Sure, pass me the code. 

I've tried mailing you twice. Both times the mail bounced.
Anyway, the code below should tell the whole story.

 --
Arthur Lemmens
 --

(capi:define-layout message ()
  ((text :initarg :text
         :initform ""
         :accessor message-text)
   (short :accessor message-short)
   (long :accessor message-long)))

(defmethod initialize-instance :after ((message message) &key text)
  ;; Create two child elements for the text.
  (let ((short (make-instance 'capi:title-pane
                              :text text
                              :font (gp:gf nil "times" :bold :roman 20)))
        (long (make-instance 'capi:display-pane
                             :text text
                             :vertical-scroll t)))
    (setf (message-short message) short
          (message-long message) long
          (capi:layout-description message) (list short long))))

  
(defmethod capi:interpret-description ((layout message) description interface)
  ;; Should return a list with a geometry object (whatever that is)
  ;; for each child. Here, we just pass the buck to PARSE-LAYOUT-DESCRIPTOR.
  (loop for child in description
        collect (capi:parse-layout-descriptor child interface layout)))

(defmethod capi:calculate-constraints ((layout message))
  ;; Keep it simple: just use arbitrary min-width/height.
  (capi:with-geometry layout
    (setq capi:%min-width% 150
          capi:%min-height% 150)))

(defmethod capi:calculate-layout ((layout message) x y width height)
  ;; If the text fits on one line, we use the title-pane (and hide
  ;; the display-pane by giving it zero width/height).
  ;; Otherwise, we do it the other way round.
  (flet ((hide (pane) (capi:with-geometry pane
                        (setq capi:%x% 0
                              capi:%y% 0
                              capi:%width% 0
                              capi:%height% 0))))
    (let ((text-width (capi:get-constraints (message-short layout))))
      (cond ((> text-width width)
             ;; Hide short, show long
             (hide (message-short layout))
             (capi:with-geometry (message-long layout)
               (setq capi:%x% 0
                     capi:%y% 0
                     capi:%width% (- width 20)
                     capi:%height% (- height 10))))
            (t
             ;; Show short, hide long
             (hide (message-long layout))
             (capi:with-geometry (message-short layout)
               (setq capi:%x% 0
                     capi:%y% 0
                     capi:%width% capi:%min-width%
                     capi:%height% capi:%min-height%)))))))
             
             
(defun test (text)
  ;; Try (TEST "Hello") and you get a title-pane.
  ;; Try (TEST "Hello, this is a message from your captain.") and
  ;; you get a display-pane with a vertical scrollbar.
  (capi:contain (make-instance 'message :text text)))