next up previous contents
Next: Monte Carlo Information Up: The MINOS Off-line Software Previous: Dispatcher   Contents

Subsections


Minos Event Display (sub) framework: Midad

Last significant change: 2002/07/26

Introduction

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:


Using and configuring Midad with out writing code.

Section to be written.


Midad Design

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.


Design Overview

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:

Models:
All Models have a modified signal which is triggered whenever their internal state is changed. Models may have other signals as well. Models export an interface to their data to be used by corresponding Controls.

Views:
Views subclass View<ModelType> and should implement Configure(ModelType&). This method is called in response to the Model's modified signal which is connected in View<>::ConnectModel(). The Model is held by the View base class in a SigC::Ptr<> (see memory management below).

Controls:
Controls, like Views, are templated on a Model type and hold their Model in a SigC::Ptr<>. However, instead of responding to a Model::modified signal, they modify the Model via whatever interface it exports.


Main graphical objects

The main objects a user is most likely to interact with or see on the screen are the following.

Displays:
Display is a base class providing a default compound widget which includes a menubar, a button bar a central box for sub classes to fill and a statusbar. Typically, Display sub classses will fill this central box with one or more Scenes and any accompanying widgets.

Scenes:
A Scene is a TPad which has Range objects to control its range and knows about Scenery and SceneElements (see below).

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).

Scenery:
Scenery is the TPad/ROOT side of a graphical View of a Model (the full class will likely inherit from both Scenery and some View, however this isn't a requirement - one could create non-View scenery).

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().

SceneElements:
A graphical "primitive" can inherit from just some TObject or both a TObject and a SceneElement in order to provide more features, such as custom context menus, triggering info placed in the status bar when the mouse pointer is over them, etc.


Update Policy for Scene and Scenery

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.


Memory Management

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.


Configuring Midad in a ROOT macro

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.

Minimal setup

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.

Detailed setup


next up previous contents
Next: Monte Carlo Information Up: The MINOS Off-line Software Previous: Dispatcher   Contents
Robert Hatcher 2009-02-16