Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!cis.ohio-state.edu!ucbvax!agate!stanford.edu!leland.Stanford.EDU!portia!vlis From: vlis@lurch.stanford.edu (John Vlissides) Newsgroups: comp.windows.interviews Subject: Re: MOdal Dialogs/ G++ Message-ID: Date: 7 Jun 91 17:50:37 GMT References: <1991Jun5.141228@Pkg.Mcc.COM> <9106061529.AA29233@shelby.Stanford.EDU> Sender: news@leland.Stanford.EDU (Mr News) Organization: stanford university Lines: 107 In-Reply-To: neil@AKBAR.TELEOS.COM's message of Thu, 6 Jun 1991 15:29:18 GMT > 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