Author Topic: PCL: how to attach to a view for a dynamic process  (Read 8222 times)

Offline Nocturnal

  • PixInsight Jedi Council Member
  • *******
  • Posts: 2727
    • http://www.carpephoton.com

Hi,

I'm working on a dynamic process module. I'm using the dynamiccrop module as an example. I'm making some progress with other areas of the module but my event handlers for view mouse events aren't getting called. Somehow I'm not attaching my module to the view when it's clicked on. Where does this happen?

Here are some code snippets:

Code: [Select]
bool ProfileInterface::WantsReadoutNotifications() const
{
   return true;
}

InterfaceFeatures ProfileInterface::Features() const
{
   return InterfaceFeature::DefaultDynamic;
}

bool ProfileInterface::IsDynamicInterface() const
{
   return true;
}


and

Code: [Select]
   //
   // Dynamic Interface bits
   virtual bool WantsReadoutNotifications() const;
   void DynamicPaint( const View& v, Graphics& g, const DRect& ur ) const;
   void DynamicMousePress( View& v, const DPoint& p, int button, unsigned buttons, unsigned modifiers );
   void DynamicMouseRelease( View& v, const DPoint& p, int button, unsigned buttons, unsigned modifiers );


and

Code: [Select]
IsoString ProfileInterface::Id() const
{
   return "DynamicProfile";
}
bool ProfileInterface::WantsReadoutNotifications() const
{
   return true;
}

InterfaceFeatures ProfileInterface::Features() const
{
   return InterfaceFeature::DefaultDynamic;
}

bool ProfileInterface::IsDynamicInterface() const
{
   return true;
}

void ProfileInterface::ExitDynamicMode()
{
   //
   // Forget current target view.
   //
   if ( view != 0 )
      delete view, view = 0;

   //
   // Reset the instance. This ensures default GUI control values.
   //
   instance.Assign( ProfileInstance( TheProfileProcess ) );

   //
   // Update GUI
   //
   //InitControls();
   UpdateControls();
}


It seems I'm missing the part where the framework tells my code that a view has been selected so I can grab it. I've put break points in the event handlers and they don't get called.

Thanks!
Best,

    Sander
---
Edge HD 1100
QHY-8 for imaging, IMG0H mono for guiding, video cameras for occulations
ASI224, QHY5L-IIc
HyperStar3
WO-M110ED+FR-III/TRF-2008
Takahashi EM-400
PIxInsight, DeepSkyStacker, PHD, Nebulosity

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: PCL: how to attach to a view for a dynamic process
« Reply #1 on: 2009 May 05 01:43:29 »
Hi Sander,

Code: [Select]
bool ProcessingInterface::IsDynamicInterface() const
Is just a declaration of intentions. It's necessary for an interface to work dynamically, but it isn't sufficient. Along with returning true from IsDynamicInterface(), you need to reimplement:

Code: [Select]
bool Launch( const MetaProcess& P, const ProcessImplementation* p, bool& dynamic, unsigned& flags )
The Launch member function gets called when the user invokes your interface, for example by double-clicking a process icon, or from the Process Explorer. To start a dynamic session, a possible implementation could be (code excerpted from DynamicCropInterface.cpp):

Code: [Select]
bool DynamicCropInterface::Launch( const MetaProcess& P, const ProcessImplementation*, bool& dynamic, unsigned& /*flags*/ )
{
   // ### Deferred initialization
   if ( GUI == 0 )
   {
      GUI = new GUIData( *this );
      SetWindowTitle( "DynamicCrop" );
      InitControls();
      UpdateControls();
   }

   dynamic = true;
   return &P == TheDynamicCropProcess;
}

Note that we are assigning true to dynamic. In this way the core application knows that the interface wants to start a new dynamic session. After this function, the whole set of dynamic event handlers are available and will be called automatically by the core application when the corresponding events occur.

The "###" comment above is there because the "normal" way a processing interface initializes is by reimplementing the ProcessingInterface::Initialize() virtual member function, which is called briefly after module installation. Deferred initialization is a technique that postpones initialization of all GUI resources until the first call to Launch(). This technique saves a lot of time and memory and is currently used by all standard interfaces; it is of course the recommended way to initialize newly created interfaces (eventually, Initialize() will be obsoleted).

Quote
It seems I'm missing the part where the framework tells my code that a view has been selected so I can grab it.

Actually, that doesn't happen. Your interface must select one or more views explicitly through calls to:

Code: [Select]
void View::AddToDynamicTargets();
A dynamic target is a view that is being controlled by a dynamic interface. In some way your interface owns all dynamic targets during a dynamic session, and the core ensures that no dynamic target can be closed or modified. Following a strict object-oriented methodology, even your dynamic interface is not allowed to modify one of its dynamic targets (it must explicitly remove it from the dynamic targets set with View::RemoveFromDynamicTargets() before attempting to change it).

Your interface is free to use the most appropriate method to select one or more dynamic targets. However, you must do it in an event handler. The usual way is to wait until the first call to DynamicMousePress(). This is what DynamicCrop, CloneStamp, DBE, etc. do. By "first call" we mean the first call after the Launch() invocation that assigns true to the dynamic reference argument, as shown above.

Now the bad news :) I guess what you're trying to do doesn't require a dynamic interface at all  ;D

Are you trying to write a tool that does "something" whenever the user clicks on a view? I ask this because you're reimplementing WantsReadoutNotifications(). In fact, using the readout notification system is the recommended way to implement relatively simple tools that don't require the fully-fledged interactive functionality provided by dynamic interfaces. Note that relatively simple here refers just to interactivity; your interface can do extremely sophisticated things using only readout notifications.

To be a client of the readout notification system, your interface must reimplement the following virtual member functions of ProcessingInterface:

Code: [Select]
virtual bool WantsReadoutNotifications() const
{
   return true; // to receive readout notifications.
}

virtual void BeginReadout( const View& v )
{
   // This is called when the user clicks on a view.
}

virtual void UpdateReadout( const View& v, const DPoint& p, double R, double G, double B, double A )
{
   // Called when a new pixel readout is available.
   // *** Edited: Of course, the R,G,B,A pixel sample values are in the [0,1] range, irrespective of v's
   // data type. Sure you already guessed this, but just wanted to point out this important fact.
}

virtual void EndReadout( const View& v )
{
   // Called when the user releases the mouse after a readout operation.
}

By reimplementing just these four member functions, your interface can do almost everything 8)

Does this help you? (hope so ::) )
« Last Edit: 2009 May 05 01:50:42 by Juan Conejero »
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline Nocturnal

  • PixInsight Jedi Council Member
  • *******
  • Posts: 2727
    • http://www.carpephoton.com
Re: PCL: how to attach to a view for a dynamic process
« Reply #2 on: 2009 May 05 05:32:47 »
Hi Juan,

thanks for this extensive help, as always. I'm pretty sure I need to write a dynamic process as I want the user to be able to draw a line in a view of which I will then draw the profile. So just a readout won't be enough. A different module that shows a local 3D profile ala the script already written in a different thread could be handy but that's not my intent right now.

I'll give your suggestions a try.
Best,

    Sander
---
Edge HD 1100
QHY-8 for imaging, IMG0H mono for guiding, video cameras for occulations
ASI224, QHY5L-IIc
HyperStar3
WO-M110ED+FR-III/TRF-2008
Takahashi EM-400
PIxInsight, DeepSkyStacker, PHD, Nebulosity

Offline Nocturnal

  • PixInsight Jedi Council Member
  • *******
  • Posts: 2727
    • http://www.carpephoton.com
Re: PCL: how to attach to a view for a dynamic process
« Reply #3 on: 2009 May 05 06:39:44 »
Ok, I was *almost* there. I had the Launch routine but didn't do this  dynamic = true; Now I'm capturing mouse events. I understand now that I capture *every* mouse event to every view so I myself must choose the view like you indicated. Alright, work to do :)
Best,

    Sander
---
Edge HD 1100
QHY-8 for imaging, IMG0H mono for guiding, video cameras for occulations
ASI224, QHY5L-IIc
HyperStar3
WO-M110ED+FR-III/TRF-2008
Takahashi EM-400
PIxInsight, DeepSkyStacker, PHD, Nebulosity

Offline Nocturnal

  • PixInsight Jedi Council Member
  • *******
  • Posts: 2727
    • http://www.carpephoton.com
Re: PCL: how to attach to a view for a dynamic process
« Reply #4 on: 2009 May 05 07:04:25 »
Alright, I'm getting the start and end points of my drag operation but now void ProfileInterface::DynamicPaint( const View& v, Graphics& g, const DRect& ur ) const isn't getting called even when I obscure the active view. What magic am I missing? I have attached the ProfileInterface source. Don't laugh, it's a mess.
Best,

    Sander
---
Edge HD 1100
QHY-8 for imaging, IMG0H mono for guiding, video cameras for occulations
ASI224, QHY5L-IIc
HyperStar3
WO-M110ED+FR-III/TRF-2008
Takahashi EM-400
PIxInsight, DeepSkyStacker, PHD, Nebulosity

Offline Juan Conejero

  • PTeam Member
  • PixInsight Jedi Grand Master
  • ********
  • Posts: 7111
    • http://pixinsight.com/
Re: PCL: how to attach to a view for a dynamic process
« Reply #5 on: 2009 May 05 07:24:18 »
Ah, I see, you're writing a line profiling tool. Great!  >:D

You must reimplement this member function:

Code: [Select]
virtual bool RequiresDynamicUpdate( const View& v, const DRect& r ) const
and return true if you need to update the r rectangle (in image coordinates) or if your drawing intersects r. The easiest way to ensure that your DynamicPaint() will be called always is:

Code: [Select]
virtual bool RequiresDynamicUpdate( const View& v, const DRect& r ) const
{
   return true;
}

which is simple and effective while you are debugging your drawing routines.

Of course, for production code, unless your painting routine is very very simple, you must return true only if you actually need to redraw over the passed rectangle and view.
Juan Conejero
PixInsight Development Team
http://pixinsight.com/

Offline David Serrano

  • PTeam Member
  • PixInsight Guru
  • ****
  • Posts: 503
Re: PCL: how to attach to a view for a dynamic process
« Reply #6 on: 2009 May 05 10:01:34 »
I want the user to be able to draw a line in a view of which I will then draw the profile.

In the beginning I also thought about a simple 2D profiling tool, based on horizontal or vertical lines. But then I dared to write the 3D one, and it seems it worked out pretty well ;).
--
 David Serrano

Offline Nocturnal

  • PixInsight Jedi Council Member
  • *******
  • Posts: 2727
    • http://www.carpephoton.com
Re: PCL: how to attach to a view for a dynamic process
« Reply #7 on: 2009 May 05 12:39:47 »
Well I have to start somewhere  8)

OK, I'm getting closer. I'm trapping the start and end of my line and drawing them (incorrectly right now, translation error I'll fix) on the image. The problem is that I need to zoom the view to make the line appear. While dragging the line doesn't appear either. So somehow I'm preventing the view from redrawing after the bitmap with the line is xor'd onto the view. What's still missing?

Thanks.
Best,

    Sander
---
Edge HD 1100
QHY-8 for imaging, IMG0H mono for guiding, video cameras for occulations
ASI224, QHY5L-IIc
HyperStar3
WO-M110ED+FR-III/TRF-2008
Takahashi EM-400
PIxInsight, DeepSkyStacker, PHD, Nebulosity