Custom gadgets in a frame 
Author Message
 Custom gadgets in a frame

Has anybody run into this problem?

define class <my-list-control> (<list-control>) end class;

define frame <my-frame> (<simple-frame>)
  pane my-list-control (frame)
    make (<my-list-control>);

  layout (frame)
    horizontally()
      frame.my-list-control;
    end;
end frame;

begin
  start-frame (make (<my-frame>));
end;

This yields a runtime error:

<my-frame> is not an instance of <sheet>

Anybody know why this is?  This *severely* limits the extensibility of
DUIM.

-- Dustin Voss



Sun, 06 Oct 2002 03:00:00 GMT  
 Custom gadgets in a frame
Hi Dustin,


Quote:
>Has anybody run into this problem?

>define class <my-list-control> (<list-control>) end class;

>define frame <my-frame> (<simple-frame>)
>  pane my-list-control (frame)
>    make (<my-list-control>);

>  layout (frame)
>    horizontally()
>      frame.my-list-control;
>    end;
>end frame;

>begin
>  start-frame (make (<my-frame>));
>end;

>This yields a runtime error:

><my-frame> is not an instance of <sheet>

>Anybody know why this is?  This *severely* limits the extensibility of
>DUIM.

>-- Dustin Voss

This should be in a DUIM FAQ, it is a counterintuitive part of the
DUIM design. Basically, the gadget classes are all abstract, so you
are subclassing a class that isn't a complete implementation. So
typically you would only subclass a gadget to build a completely
new implementation.

There are two ways in which you can effectively subclass gadgets
as you were expecting:

1. Use the module win32-duim, and subclass <win32-list-box>.

  This subclasses the concrete Win32 representation of <list-box>,
  but obviously limits your code to only working on Windows.

2. Use 'define pane' to wrap the list box.

  Something like this (untested):

    define pane <my-list-box> (<list-box>)
      pane inner-list-box (pane)
        make(<list-box>, ...);
      layout (pane)
        vertically ()
          pane.inner-list-box
        end;
    end pane <my-list-box>;

  I think this has been discussed before, so you might be able to
  find more detail in the archives.

I typically find that subclassing a gadget is something you don't
need to do, in languages such as Java you have to do it in order
to add new methods, but in Dylan you can add methods without having
a new class. The whole Functional Developer IDE is written in DUIM,
and we didn't find a need to subclass gadgets.

If you'd like to tell me what you're trying to do, I'd be happy to
offer some advice on how I might solve such a problem.

I hope this helps,

Andy

---
Andy Armstrong

Send FREE April Fool's Greetings to your friends!
http://www.whowhere.lycos.com/redirects/American_Greetings.rdct



Sun, 06 Oct 2002 03:00:00 GMT  
 Custom gadgets in a frame


Quote:

>1. Use the module win32-duim, and subclass <win32-list-box>.

>  This subclasses the concrete Win32 representation of <list-box>,
>  but obviously limits your code to only working on Windows.

Unfortunately the various <win32-*> gadget classes aren't exported from win32-
duim and the methods on them are sealed. It would be nice if they were exported
and/or open - for those times when you want to subclass a windows control (I'm
talking about Win32 subclassing of window controls, not OO subclassing) and use
it from DUIM with the same basic implementation as a standard windows control
but only the window creation routines overridden. This doesn't happen a lot in
practice though.

Quote:

>2. Use 'define pane' to wrap the list box.

This is the approach I've used for this type of thing - from your
recommendation to me on comp.lang.dylan a while ago:

http://www.deja.com/article/466988275

I've found in practice that it works fine.

Chris.
--
http://www.double.co.nz/dylan



Mon, 07 Oct 2002 03:00:00 GMT  
 Custom gadgets in a frame

Quote:



>>1. Use the module win32-duim, and subclass <win32-list-box>.

>>  This subclasses the concrete Win32 representation of <list-box>,
>>  but obviously limits your code to only working on Windows.

>Unfortunately the various <win32-*> gadget classes aren't exported from
win32-
>duim and the methods on them are sealed. It would be nice if they were
exported
>and/or open - for those times when you want to subclass a windows control
(I'm
>talking about Win32 subclassing of window controls, not OO subclassing) and
use
>it from DUIM with the same basic implementation as a standard windows
control
>but only the window creation routines overridden. This doesn't happen a lot
in
>practice though.

Andy Armstrong and I had planned to make all the win32-duim gadgets
be open and abstract, with a sealed instantiable class for each open
abstract class.  Then we would export the abstract classes, and people
could extend the Win32 gadgets.  Do people think this is important?
It's not hard, but it does displace potentially more important work.


Mon, 07 Oct 2002 03:00:00 GMT  
 Custom gadgets in a frame

Quote:

> Andy Armstrong and I had planned to make all the win32-duim gadgets
> be open and abstract, with a sealed instantiable class for each open
> abstract class.  Then we would export the abstract classes, and people
> could extend the Win32 gadgets.  Do people think this is important?
> It's not hard, but it does displace potentially more important work.

This is one of the points in my pile of feedback that I've not had time
to get back to FO. I needed to extend the concrete platform-specific
gadgets for new behavior and could not. I didn't think of using the
wrapper approach, so I don't know if that would have worked well. (Seems
like it would?)


Mon, 07 Oct 2002 03:00:00 GMT  
 Custom gadgets in a frame

Quote:

> Hi Dustin,


> >Has anybody run into this problem?

[Cannot subclass a DUIM gadget]

Quote:
> >Anybody know why this is?  This *severely* limits the extensibility
of
> >DUIM.

> >-- Dustin Voss

> This should be in a DUIM FAQ, it is a counterintuitive part of the
> DUIM design. Basically, the gadget classes are all abstract, so you
> are subclassing a class that isn't a complete implementation. So
> typically you would only subclass a gadget to build a completely
> new implementation.

> There are two ways in which you can effectively subclass gadgets
> as you were expecting:

> 1. Use the module win32-duim, and subclass <win32-list-box>.

>   This subclasses the concrete Win32 representation of <list-box>,
>   but obviously limits your code to only working on Windows.

Well, since the only implementation of DUIM is on Windows, this isn't a
problem...

- Show quoted text -

Quote:
> 2. Use 'define pane' to wrap the list box.

>   Something like this (untested):

>     define pane <my-list-box> (<list-box>)
>       pane inner-list-box (pane)
>         make(<list-box>, ...);
>       layout (pane)
>         vertically ()
>           pane.inner-list-box
>         end;
>     end pane <my-list-box>;

>   I think this has been discussed before, so you might be able to
>   find more detail in the archives.

> I typically find that subclassing a gadget is something you don't
> need to do, in languages such as Java you have to do it in order
> to add new methods, but in Dylan you can add methods without having
> a new class. The whole Functional Developer IDE is written in DUIM,
> and we didn't find a need to subclass gadgets.

> If you'd like to tell me what you're trying to do, I'd be happy to
> offer some advice on how I might solve such a problem.

Sure...I'm sub-classing the control to support drag & drop operations.
This is as fine a time as any to reveal the (limited) extent of my
genius.

My original plan was to handle drag & drop like I would in a C app.  In
the handler for some event (<button-press-event> or <pointer-drag-
event>), I write an event loop which takes over from the standard
loop.  I track the mouse pointer and pass other events off to the
standard event dispatcher.  I could not do that in Dylan, because there
are no functions to fetch and enqueue an OS event.

I briefly considered using a separate thread running the with-pointer-
grabbed macro, and ended up doing that, but only after my other attempt
failed.  I had tried to write a handle-event method on <sheet> and
<button-release-event> to learn when the drag & drop operation was
completed, but alas, there was already such a method and I couldn't
override it.

So I ended up with the threaded version.  When the user starts a drag
in a drag & drop-capable control (i.e. any control that inherits from
the <drag&droppable> class [a Java naming convention I like]), the
control's <pointer-drag-event> handler starts a 'monitor' thread.  The
thread runs a with-pointer-grabbed macro and, in the middle of the
macro, waits on a <synchronization> object that indicates the drag &
drop is complete.

Meanwhile, back in the main thread, all pointer events are getting
trapped and routed to <drag&droppable> event handlers, courtesy of the
still-in-dynamic-scope with-pointer-grabbed macro.  The <pointer-drag-
event> handler notifies drag & drop-capable controls that something is
being dragged over them.  A <button-release-event> handler is keeping
an eye out for the end of the drag & drop.  Since ALL pointer events,
even those over other sheets, are being trapped, this handler can
monitor what's going on over foreign sheets.  When the drag & drop
ends, the handler notifies the appropriate controls.

Notifications, in true DUIM fashion, are via callbacks.  I've provided
some additional slots to specify the callbacks in the layout code just
like other gadgets do.

Now, I say this in past tense, but I haven't been able to test it
because of the subclassing problem.  I need to subclass for three
reasons:

1) I don't want to rewrite DUIM.  I must use the existing event and
sheet architecture, but I must extend the behavior for drag & drop-
capable controls.  That means I must subclass controls and write
methods on the new classes.

2) I want drag & drop controls to be as seamless as possible, hence the
new callback slots and corresponding init keywords.

3) Finally, this subclassing must be done via mixin so the programmers
(meaning me) can use drag & drop without a god-awful amount of work.

So there it is.  Source code follows.  Comments?

-- Dustin Voss

/****************************
 *  Mixin class (exported)  *
 ****************************/

define class <drag&droppable> (<object>)

  // Source callbacks
  slot drag-begin-callback    :: <function>, init-value: #f, init-
keyword: #"drag-begin-callback";
  slot drag-complete-callback :: <function>, init-value: #f, init-
keyword: #"drag-complete-callback";
  slot drag-cancel-callback   :: <function>, init-value: #f, init-
keyword: #"drag-cancel-callback";

  // Target callbacks
  slot drag-over-callback     :: <function>, init-value: #f, init-
keyword: #"drag-over-callback";
  slot drag-target-callback   :: <function>, init-value: #f, init-
keyword: #"drag-target-callback";

end class <drag&droppable>;

/******************************
 *  Internal state variables  *
 ******************************/

define variable *drag-object* = make (<object-table>);  // keyed by
pointer

define variable *drag-monitor-thread* = make (limited (<object-table>,
of: <thread>));  // keyed by pointer
define variable *drag-monitor-sync* = make (limited (<object-table>,
of: <synchronization>));
  // keyed by thread, not by pointer

/*****************************************************
 *  object-being-dragged setter/getter on <pointer>  *
 *****************************************************/

define method object-being-dragged (pointer :: <pointer>) => (object ::
<object>);
  element (*drag-object*, pointer, default: #f);
end method;

define method object-being-dragged-setter (object :: false-or
(<object>), pointer :: <pointer>)
  if (object)
    *drag-object*[pointer] := object;
  else
    remove-key! (*drag-object*, pointer);
  end if
end method;

/********************
 *  Event handlers  *
 ********************

As the mouse moves, the sheets' handlers monitor the mouse button to
make sure it is still
pressed.  They call drag-over on the drag&drop sheets under the mouse.
The non-drag&drop
sheets are ignored.  When the mouse button is released, the handler
calls the drag-drop
callback on the target sheet and the drag-complete callback on the
source sheet.  If the
target sheet isn't a drag&drop sheet, the drag-cancel callback is
called on the source sheet.

How does this divvy up drag&drop control?

- Source sheets need the drag-source, -complete, and -cancel callbacks.
- Destination sheets need the drag-over and -target callbacks. */

// This is called when starting or continuing a drag

define method handle-event (source :: <drag&droppable>, event ::
<pointer-drag-event>) => ()
  let pointer = event.event-pointer;

  if (element (*drag-monitor-thread*, pointer, default: #f))
    // This drag is being monitored...continuing to drag
    if (instance? (pointer.pointer-sheet, <drag&droppable>))
      drag-over-callback (pointer.pointer-sheet);
    end if

  else
    // Not being monitored, so this is a new drag!  Start the monitor
    let sync-for-thread = make (<synchronization>, name: "Release me to
kill drag-monitor");
    let drag-monitor-method = method () => ()
                                // Grab the pointer until the sync
becomes available
                                with-pointer-grabbed (source)
                                  wait-for (sync-for-thread);
                                end;
                              end method;

    wait-for (sync-for-thread);  // Make the sync unavailable (I assume
it is created available)
    let monitor-thread = make (<thread>, function: drag-monitor-method);

    // The drag is now official.  Store for later reference
    *drag-monitor-thread*[pointer] := monitor-thread;
    *drag-monitor-sync*[monitor-thread] := sync-for-thread;

    // Notify the source that the drag has started
    drag-begin-callback (source);
  end if;

  next-method();
end method;

// This handler determines when the drag is finished, and cleans up

define method handle-event (source :: <drag&droppable>, event ::
<button-release-event>) => ()
  let pointer = event.event-pointer;
  let monitor-thread = element (*drag-monitor-thread*, pointer,
default: #f);

  if (monitor-thread)
    // A drag operation is in progress...but it's done now

    // Dismantle the thread stuff
    release (*drag-monitor-sync*[monitor-thread]); // This should end
the pointer-grab thread
    join-thread (monitor-thread);
    remove-key! (*drag-monitor-thread*, pointer);
    remove-key! (*drag-monitor-sync*, monitor-thread);

    // Call the call-backs
    let destination = pointer.pointer-sheet;
    if (instance? (destination, <drag&droppable>))
      // Drop was completed successfully.
      drag-target-callback (destination);
      drag-complete-callback (source);
    else
      // Couldn't complete drop.
      drag-cancel-callback (source);
    end if;
  end if;

  next-method();
end method;

--


(Welcome to account Madness!)

Sent via Deja.com http://www.deja.com/
Before you buy.



Mon, 07 Oct 2002 03:00:00 GMT  
 
 [ 6 post ] 

 Relevant Pages 

1. Delete problem in custom transaction frame CL5.5

2. Custom Tcl_Obj, call frame

3. Question on full-custom ASIC and semi-custom ASIC

4. links in html-frame affecting vrml-frame

5. Java in frame can't get instance of Java EAI + VRML in another frame

6. Movietexture Frame by Frame control

7. Q:wpy - multiple frames within main frame

8. resources for vtcl - hide frames and display new frames

9. How do I pack things in a frame in a toplevel frame

10. Removing widgets from frames, why frames don't resize to 0x0

11. come changes to the deuce editor gadget

12. Deuce gadgets and streams

 

 
Powered by phpBB® Forum Software