Last significant change: 2002/07/26
The Midad sub framework allows one to display and interact with graphical representations of data objects. Of historical note, there is an obsolete previous version called MIDAD (all caps). This code is still in the repository, but should not be used.
This chapter is broken up into the following sections:
Section to be written.
This section describes the design of Midad. It is usefull for the new user to briefly skim through this, particularly the description of in section 20.3.2.
Midad generally follows the Model-View-Control (MVC) pattern (see Applications Programming in Smalltalk-80(TM): How to use Model-View-Controller (MVC) by Steve Burbeck, Ph.D. for the canonical paper), either explicitly or implicitly. The basic idea of MVC is to isolate the data (Model) from the things that displays it (Views) and the things that modifiy it (Controls).
These three concepts are formalized into actuall base classes of the same name:
The main objects a user is most likely to interact with or see on the screen are the following.
One can Draw() non-Scenery TObjects in the usual TPad/TCanvas way.
One draws Scenery by Add()ing it to the Scene. If new'ed with manage(), the Scenery will be memory managed (it is held in a SigC::Ptr<Scenery>).
A Scene attaches to a Scenery's "modified" signal in order to mark the Scene's Modified bit.
A Scene has an associated "Scene Type" available as either a string (eg, "U-Z", "U-Plane-Strip") which is stored in the TPad's title variable (second arg to constructor) or an enum (kUZ, kUPlaneStrip). This Scene Type can be queried by the Scenery in order to know what the Scene's "User Corrdinates" are (ie, "U-Z" means draw in meters in the U vs. Z projection, "UPlaneStrip" means draw in plane# on X and strip# on Y).
The Scenery base class provides the "modified" signal (so it is kind of a model from the consideration of a Scene). The inheriting class should call "modified.emit()" if it wants the Scene notified that it should be updated.
The Scenery base class overloads the ExecuteEvent() and DistancetoPrimitive() methods in order to provide various signals related to mouse movement and clicking and track which graphical TObject is under or closest to the pointer.
Scenery is a TObject holding collections of one or more graphical primitives (plain TObjects or TObject+SceneElement objects, see below). To implement the graphical object a Scenery subclass should call Scenery::ClearPrimitives() create and give new primitives to Scenery::AddPrimitive() in response to any change in the scenery.
Scenery has various virtual methods which provide hooks into the rest of the system (eg: GetInfo() to return a string for display in the status bar).
Scenery can get a pointer to its Scene via GetScene().
The Scene and Scenery classes sort of follow the View and Model patterns with Scenes being Views (or rather composite-Views) of multiple Scenery Models. However, the difference is that there is a 1:n relationship between Scene:Scenery. This causes problems with updating. When each Scenery changes its "modified" signal triggers the "dirty" bit in the Scene to be set (ie, TPad::Modified() is called). The modifications don't take effecut until TPad::Update() is called.
The trouble comes in when one has multiple Scenery objects changing and deciding how to call TPad::Update(). Naively and simply one could call Update after each Scenery is modified. However, this causes multiple redraws if multiple Scenery exists in the Scene. This is slow an unsightly.
To fix this, Update() needs to be called "out of band" of the Scene/Scenery connection after all Scenery has reported their modification to the Scene. One way to do this is to have each Controller trigger a "global_update" signal after all of its signals have been dispatched and to which all Scenes (and other classes in a similar predicament) can attach.
MIDAD make heavy use of SigC::Ptr<>s to provide flexible memory management. All Gui classes hold their children and Controls and Views hold their Models in SigC::Ptr<>s. Also Scenes hold their Scenery and Ranges are held in this manner.
This allows the object held in a Ptr to be deleted when the Ptr is deleted if the object was created on the heap with manage() and there are no other Ptrs referencing it. Ie:
SigC::Ptrobj; { SigC::Ptr obj1 = manage(new SomeObject()); SigC::Ptr obj2 = manage(new SomeObject()); obj = obj2 // obj1, obj2 lives } // obj1 is deleted, obj2 lives on.To be manageed in this way the object must inherit from SigC::Object. If an object is created on the heap with out manage or created on the stack then the deletion of the Ptr will not cause a deletion of the object.
A consequence of using this method of memory management is that it can be dangerous to hold a managed object in a plain pointer. Gui child widgets, Models, Scenery, and Ranges are so managed so should be always stored in Ptrs.
The Midad sub framework is accessed by loading in libMidad.so. The main external interface is the Mint object. However, for most people, once created the instance of Mint can be safely ignored as it attaches and talks to the main JobControl JobC object (see section 1). However, one can use it to control Midad from a ROOT macro file.
Here is how one would minimally configure Midad. First, a minimal JobControl set up:
JobC* setup_jobc() { gSystem->Load("libMidad.so"); JobC* jc = new JobC; jc->Path.Create("MinimalMidad", "DigitListModule::Get " "DigitListModule::Reco "); jc->Input.Set("Streams=DaqSnarl"); return jc; }
It is important to load in libMidad.so before proceeding. Next, a minimal Midad setup:
Mint* start_midad(JobC* jc) { Mint* mint = new Mint(*jc); // Tell Midad about digits Registry digits(false); digits.Set("CandName","canddigitlist"); digits.Set("CandType","CandDigitListHandle"); mint->MakeModel("digits","DigitList",&digits); // Create a "Multi" display mint->SpawnDisplay("my multi display","Multi"); // Add some digit "scenery" mint->AddScenery("my multi display","All","DigitList","digits"); return mint; }
At this point one can use jc->Run(1) or the buttons provided by the display to navigate the events. You should be able to see un-DeMuxed candidate digitizations.