[comp.windows.interviews] components of World

taylorp@sunstar.crd.ge.com (Patrick D. Taylor) (05/09/91)

I have a few questions about Scene and World in InterViews 2.6.

I want to get a list of components which have been inserted into the world.
According to the man page for Interactor, the GetComponents() member
function should return a list of the interactor's components if the
interactor is a Scene.  Scene does not implement GetComponents(), nor does
World, which is a Scene.  So World::GetComponents() is actually
Interactor::GetComponents(), which does nothing.  How do I get the
components of the World scene?

Also, the man page for Scene specifies that "when a scene is deleted, it
should delete all its component interactors.  The World scene does not do
this.  Why not?

What I want to be able to do is insert an arbitrary number of interactors
into a world.  Each interactor has a quit button which removes it from the
world.  When all of the interactors have been removed, the program should
terminate.  Thus, my main event loop would be something like:

	do {
	  Read(event);
	  event.target->Handle(event);
	  n = number of components left in world;
	} while (n > 0);

Any suggestions?

---
Pat Taylor	(taylorp@crd.ge.com)

linton@marktwain.rad.sgi.com (Mark Linton) (05/09/91)

In article <19378@crdgw1.crd.ge.com>, taylorp@sunstar.crd.ge.com (Patrick D. Taylor) writes:
|> I have a few questions about Scene and World in InterViews 2.6.
|> 
|> I want to get a list of components which have been inserted into the world.
|> According to the man page for Interactor, the GetComponents() member
|> function should return a list of the interactor's components if the
|> interactor is a Scene.  Scene does not implement GetComponents(), nor does
|> World, which is a Scene.  So World::GetComponents() is actually
|> Interactor::GetComponents(), which does nothing.  How do I get the
|> components of the World scene?
|> 
|> Also, the man page for Scene specifies that "when a scene is deleted, it
|> should delete all its component interactors.  The World scene does not do
|> this.  Why not?

You have clearly stated why World should not be a scene subclass,
which is the change we made in 3.0.  World is really just an interface
to the display/root window.

|> What I want to be able to do is insert an arbitrary number of interactors
|> into a world.  Each interactor has a quit button which removes it from the
|> world.  When all of the interactors have been removed, the program should
|> terminate.  Thus, my main event loop would be something like:
|> 
|> 	do {
|> 	  Read(event);
|> 	  event.target->Handle(event);
|> 	  n = number of components left in world;
|> 	} while (n > 0);
|> 
|> Any suggestions?

One approach is to have a list of all the components; the other has a count.
When you insert into the world, add to the list/count; subtract when you remove.
It is common to have an "application" object that manages this state.

brucec@phoebus.labs.tek.com (Bruce Cohen) (05/16/91)

In article <1991May9.161230.23058@fido.wpd.sgi.com> linton@marktwain.rad.sgi.com (Mark Linton) writes:
> 
> In article <19378@crdgw1.crd.ge.com>, taylorp@sunstar.crd.ge.com (Patrick D. Taylor) writes:
> |> I want to get a list of components which have been inserted into the world.
> |> According to the man page for Interactor, the GetComponents() member
> |> function should return a list of the interactor's components if the
> |> interactor is a Scene.  Scene does not implement GetComponents(), nor does
> |> World, which is a Scene.  So World::GetComponents() is actually
> |> Interactor::GetComponents(), which does nothing.  How do I get the
> |> components of the World scene?

> One approach is to have a list of all the components; the other has a count.
> When you insert into the world, add to the list/count; subtract when you remove.

I did this about three years ago under InterViews 2.4 for an application
which had to manage multiple windows, by subclassing World.  Here's the
code, pruned for readibility  (I added some other functionality to
handle some channel events as well).  Ignore the classname; it's from an
application which never saw the light of day, and the division of the
company has since been terminated with extreme prejudice.

Anyone who REALLY wants the gory details of the linked list
implementation and all the other stuff that I've elided here can have it
by email, but you really don't want it, trust me.

class OnRampWorld : public World
{
 public:
	OnRampWorld(const char*, int& argc, char* argv[]);
	virtual void Run();
    virtual void GetComponents(Interactor**, int, Interactor**&, int&);
	virtual void RequestTermination(Interactor* = nil);
    virtual void Delete();

 protected:
	int numChildren;

    virtual void DoInsert(Interactor*, boolean, Coord& x, Coord& y);
	virtual void DoRemove(Interactor*);

 private:
	LinkList* children;
};

extern OnRampWorld* WORLD;

OnRampWorld::OnRampWorld(const char* name, int& argc, char* argv[]) :
							(name, worldProperties, worldOptions, argc, argv)
{
	SetClassName("OnRamp");
	numChildren = 0;
	children = new LinkList;  // implementation of LinkList left as an exercise
}

void OnRampWorld::Delete()
{
	delete children;
}

void OnRampWorld::Run()
{
	Event e;

	// if there are no children left in this world, quit.
	do
	{
		Read(e);
		e.target->Handle(e);
	}
	while (e.target != nil && numChildren > 0);
}

// This is equivalent to a request to remove the interactor passed as an
// argument.  If the argument is a valid interactor and removing
// it will leave no more children of the world, the
// interactor is silently removed and the world terminates.  Otherwise the
// user is queried first; if the response is "proceed", all children are
// removed and the world terminates; otherwise nothing happens and the
// interactor argument is left alone.
void OnRampWorld::RequestTermination(Interactor* victim)
{
	Interactor* children[16];
	Interactor** childList;
	int childCount;
	// if the parameter is for the last child, then do it silently
	if (victim != nil && numChildren == 1)
	{
		// delete the child; Run will make everyone go away
		GetComponents(children,
					  sizeof(children)/ sizeof(children[0]),
					  childList, childCount);
		if (children[0] == victim)
		{
			Remove(victim);
		}
	}
	else
	{
		Event event;

        // Confirmer is one of a set of standard popup interaction
        // classes.  In particular, Confirmer displays the message
        // passed to it and has two buttons: "Proceed" and "Cancel".
        // Proceed causes the confirmer to return true, and Cancel
        // causes it to return false.
		Confirmer *confirmer = new Confirmer("Do you really want to quit \
the OnRamp programming environment?");
		WORLD->Poll(event);
		if (confirmer->Popup(event, true))
		{
			// kill off the world
			GetComponents(children,
						  sizeof(children)/ sizeof(children[0]),
						  childList, childCount);
			for (int i = 0; i < childCount; i++)
			{
				Remove(childList[i]);
			}
			if (childList != children)
			{
				delete childList;
			}
		}
	}
}

void OnRampWorld::DoInsert(Interactor* i, boolean m, Coord& x, Coord& y)
{
	children->Append(i);
	numChildren++;
}

void OnRampWorld::DoRemove(Interactor* i)
{
	if (i != nil)
	{
	 	World::DoRemove(i);
		numChildren--;
		children->Remove(i);
	}
}

void OnRampWorld::GetComponents(Interactor** c, int nc, Interactor**& a,
								 int& n)
{
	n = numChildren;
	if (n > nc)
	{
		a = new Interactor*[n];
	}
	else
	{
		a = c;
	}
	LinkListIterator iter(children);
	for (int i = 0; !iter.AtEnd(); i++)
	{
		a[i] = (Interactor*)(iter.Next());
	}
}
--
------------------------------------------------------------------------
Speaker-to-managers, aka
Bruce Cohen, Computer Research Lab        email: brucec@rl.labs.tek.com
Tektronix Laboratories, Tektronix, Inc.                phone: (503)627-5241
M/S 50-662, P.O. Box 500, Beaverton, OR  97077