steve@Pkg.Mcc.COM (Steve Madere) (06/06/91)
Here at MCC one of our programmers created a new kind of dialog that does not allow any other interactors to receive events while it is "popped up". We call this a Modal Dialog. What we had to do was to take over the run operation during display of the MD and refuse to pass on any events occurring outside the bounds of the local scene to their targets. Modal Dialogs seem to be a standard part of a GUI so I wonder how is it that all of you other people out there accomplish this task? Ours looks rather kludgey since it requires finding out what the boundary of the dialog box is and then checking every event to see if it occurred within this box. on an unrelated note..... Does IV 3.0 work with g++ yet? (I know it's an old and tired question but I REALLY want to use IBuild and my only c++ compiler is g++). Thanks. Steve Madere steve@pkg.mcc.com
david@UUNET.UU.NET (06/06/91)
I hacked this together a while ago. Basically we do the same thing. You take over the event loop and continue reading events, passing on events that occur within the dialog box, until some state has changed. I use a ButtonState, but obviously other answers exist. Of course this is unique to the application, I can't grab events from other apps. I guess what I would have really liked is a way to inform the world that such and such an interactor wants to grab focus and have the world take care of it. If you get any interesting responses to this would you mind passing them on to me? david David Rivas david@lolita.ntlp.com Northfield Trading L. P. (303) 985-3366
neil@AKBAR.TELEOS.COM (06/06/91)
IV2.6 ===== Here at MCC one of our programmers created a new kind of dialog that does not allow any other interactors to receive events while it is "popped up". We call this a Modal Dialog. What we had to do was to take over the run operation during display of the MD and refuse to pass on any events occurring outside the bounds of the local scene to their targets. I had the same problem. In fact, with the non modal dialogs, it was easy to invoke the same dialog box twice, leaving internal variables in a bad state. I came up with the same solution as you: checking the bounding box of the Dialog and only passing on events inside. However, there is a fatal flaw with that approach as well. If the window manager buries the dialog window (e.g. if you click on the boundary of an overlapping window initially behind the dialog), the dialog box will be partly or completely obscured, potentially by another window of the same application. Now an event read in the Dialog::Run for this other window may be within the Dialog bounding box, but not destined for a subwindow of the Dialog. Same problem occurrs, and it is not as unlikely as it sounds! My solution - actually check the target interactor for having the dialog as an ancestor: /* * Loop reading events. */ int v; do { Read(e); // Only handle events for interactors whose ancestors include this. for(Interactor *i = e.target; i; i = i->Parent()) { if(i == this) { e.target->Handle(e); break; } } state->GetValue(v); } while(v == 0); Neil/. Neil@teleos.com
vlis@lurch.stanford.edu (John Vlissides) (06/08/91)
> Here at MCC one of our programmers created > a new kind of dialog that does not allow any > other interactors to receive events while it > is "popped up". We call this a Modal Dialog. > > What we had to do was to take over the run > operation during display of the MD and refuse > to pass on any events occurring outside the > bounds of the local scene to their targets. > > I had the same problem. In fact, with the non modal dialogs, it was > easy to invoke the same dialog box twice, leaving internal variables > in a bad state. I came up with the same solution as you: checking the > bounding box of the Dialog and only passing on events inside. > > However, there is a fatal flaw with that approach as well. If the > window manager buries the dialog window (e.g. if you click on the boundary > of an overlapping window initially behind the dialog), the dialog box > will be partly or completely obscured, potentially by another window of the > same application. Now an event read in the Dialog::Run for this other window > may be within the Dialog bounding box, but not destined for a subwindow > of the Dialog. Same problem occurrs, and it is not as unlikely as it sounds! > > My solution - actually check the target interactor for having the dialog > as an ancestor: The BasicDialog class in Unidraw (3.0) addresses this problem in a similar manner by defining Forward and IsAChild members: void BasicDialog::Forward (Event& e) { if (IsAChild(e.target)) { e.target->Handle(e); } else { Handle(e); } } boolean BasicDialog::IsAChild (Interactor* i) { Scene* parent = i->Parent(); while (parent != nil) { if (parent == this) { return true; } parent = parent->Parent(); } return false; } Subclasses use Forward instead of Handle to forward events only to interactors inside the dialog. AcknowledgeDialog, for example, simply posts a message that the user can dismiss: class AcknowledgeDialog : public BasicDialog { public: AcknowledgeDialog(const char* title, const char* subtitle = ""); virtual void Acknowledge(); private: Interactor* Interior(); }; AcknowledgeDialog::AcknowledgeDialog ( const char* title, const char* subtitle ) : BasicDialog(new ButtonState, title, subtitle) { Insert(Interior()); input = new Sensor(noEvents); input->Catch(KeyEvent); } void AcknowledgeDialog::Acknowledge () { Event e; int v = 0; state->SetValue(v); do { Read(e); if (e.eventType == KeyEvent) { state->SetValue(e.keystring[0]); } else { Forward(e); } state->GetValue(v); } while (v == 0); } Interactor* AcknowledgeDialog::Interior () { const int space = round(.5*cm); return new MarginFrame( new VBox( new HBox(_title, new HGlue), new HBox(_subtitle, new HGlue), new VGlue(space), new HBox( new HGlue, new PushButton(" OK ", state, 1), new HGlue ) ), space, space/2, 0 ); } -- John Vlissides Computer Systems Lab Stanford University vlis@interviews.stanford.edu