

#ifndef _controller_h_
#define _controller_h_





/*
 *
 *          Copyright (C) 1995, M. A. Sridhar
 *  
 *
 *     This software is Copyright M. A. Sridhar, 1995. You are free
 *     to copy, modify or distribute this software  as you see fit,
 *     and to use  it  for  any  purpose, provided   this copyright
 *     notice and the following   disclaimer are included  with all
 *     copies.
 *
 *                        DISCLAIMER
 *
 *     The author makes no warranties, either expressed or implied,
 *     with respect  to  this  software, its  quality, performance,
 *     merchantability, or fitness for any particular purpose. This
 *     software is distributed  AS IS.  The  user of this  software
 *     assumes all risks  as to its quality  and performance. In no
 *     event shall the author be liable for any direct, indirect or
 *     consequential damages, even if the  author has been  advised
 *     as to the possibility of such damages.
 *
 */



/*
  Authors:   M. A. Sridhar
             N. Bhowmik
*/

// The Controller   class encapsulates the object  creation, disposal, event
// capturing and dispatching   details of a  YACL application.  In any  YACL
// application, there    can   be  only   one    instance  of   this class.
// This instance owns and manages the event queue (which contains only soft
// events), the view tree (containing the parent-child relationship among
// the VisualObjects)
// and the stack of VisualObjects currently responding to events.  The
// Controller fields and dispatches all
// hard events from the windowing system as well as soft
// events generated  by other YACL objects.
//
// As documented elsewhere, YACL does
// not allow  static  VisualObjects, nor does  it allow explicit  deletion
// of VisualObjects. Destroying a VisualObject is done via the
// Application's {\tt Destroy} method. The Controller ensures that the
// object and its  children are  then destroyed. 
// 
// In addition to  event and object management,  the controller also  provides
// methods for handling the mouse and keyboard.



#if defined(__GNUC__)
#pragma interface
#endif


#include "base/tree.h"
#include "base/objset.h"

#include "ui/visualob.h"
#include "ui/rectangl.h"
#include "ui/event.h"
#include "ui/applic.h"
#include "ui/cursor.h"
#include "ui/timer.h"

#if defined(__X_MOTIF__)
#include "base/objset.h"
#endif

class YACL_UI UI_MenuItem;
class YACL_UI UI_MDIMainWindow;

class YACL_UI UI_Controller: public CL_Object {

public:

    UI_Controller (UI_Application* appl);
    // Construct the Controller instance for Application {\tt appl}. This
    // constructor need never be invoked from application code, because the
    // only Controller  instance is constructed by the Application object.

    ~UI_Controller ();
    // Destructor: called when the application is finished.
    

    //
    // -------------Mouse Control----------------------------
    //
    
    void GiveMouseTo (UI_VisualObject* aView);
    // Mouse capture: Direct all mouse events to {\tt aView} irrespective of
    // cursor position. This mouse capture is ended by the {\tt
    // ReleaseMouse} method.

    void ReleaseMouse ();
    // Stop directing all mouse events to a particular view. This ends the
    // capture state begun by the {\tt GiveMouseTo} method.

    //
    //--------------KeyBoard Control-------------------
    //
    
    void GiveFocusTo (UI_VisualObject* v);
    // Direct all keyboard events to v.

    // ----------------------- Cursor display -----------------------

    void BeginWait ();
    // Begin a ``wait state'' by displaying the platform-specific wait
    // cursor. Until {\tt EndWait} is called, the mouse cursor will not change.

    void EndWait ();
    // End the wait state begun by {\tt BeginWait}.

    //
    //----------------Modal Input--------------------------
    //

     
    void Beep ();
    // Provide a short beep.
    
    // ----------------- Event methods -------------------

    void EventLoop (CL_AbstractBinding* termination = NULL,
                    CL_AbstractBinding* eventFilter = NULL);
    // This is a generalized event loop that does the following: retrieve an
    // event, invoke {\tt eventFilter} on that event, and dispatch the event if
    // {\tt eventFilter} returns TRUE. Then invoke {\tt termination} with
    // the event as parameter, and stop the loop if it returns TRUE. The two
    // filters are remembered in instance variables; this makes it possible
    // to have nested event loops, which are necessary in situations  such
    // as modal dialogs.
    //
    // The default value of both parameters is NULL; a NULL {\tt termination}
    // binding is assumed to always return FALSE, while a NULL {\tt
    // eventFilter} binding is assumed to always return TRUE.
    //
    // This method is merely a wrapper; the actual loop is in the {\tt
    // ProcessNativeEvents} method.
    
    void Run ();
    // The {\tt Run} method is simply a convenient way of running the
    // {\tt EventLoop} until the app gets a Quit event. 

    void DispatchPendingEvents ();
    // Dispatch all pending hard events. This method must be called
    // periodically when in long processing loops when a progress dialog
    // needs to be maintained.

    void AddEvent (UI_Event* e);
    // Add event {\tt e} to the event queue. The added event will be
    // dispatched after all currently pending hard events are dispatched.
    //
    // The Controller becomes the owner of the added Event object, and
    // destroys it after dispatching it.

    UI_Event* CurrentEvent () const {return _currentEvent;}
    // Return the event currently being processed. Return NULL if no such
    // event.

    short EventsPending (UI_EventType t, UI_VisualObject* v);
    // Return the number of events of type {\tt t} pending for any of
    // the children of {\tt v}.
    
    // ----------------------- View methods ----------------------
    
    UI_CompositeVObject* Root () {return _root;};
    // Return the root of the view tree, i.e., the main window of the
    // application.

    CL_ObjectSequence ChildrenOf  (UI_VisualObject* o);
    // Return the children of the given VisualObject as an
    // ObjectSequence. Each cell in this sequence can be cast down to {\tt
    // UI_VisualObject*}. 
    
    CL_IntegerTree* ViewTree () {return &_viewTree;};
    // Return a pointer to the view tree.

    UI_VisualObject* operator[] (UI_ViewHandle h); 
    // Return the visual object with view handle {\tt h}.

    UI_VisualObject* VObjUnderMouse() const {return _current;};
    // Return the visual object over which the mouse is currently
    // positioned.
    
    void MakeTopWindow (UI_CompositeVObject* root);
    // Make {\tt root} the main window of the application. Must be called
    // once and no more, at the beginning of the application.

    bool Destroy (UI_VisualObject* aView);
    // [YACL Internal use only] Destroy {\tt view} and all its descendants
    // in the view tree. This  method must not be called from application
    // code; the correct way to shut down and destroy a VisualObject is via the
    // Application class' {\tt Destroy} method.

    const CL_ObjectSequence& CurrentEventStack () const
        {return _currentEventStack;};
    // Return the set of VisualObjects on which event actions are currently
    // in progress.

    UI_VisualObject* Focus () {return _focus;};
    // Return the VisualObject that currently has input focus.
    
    
#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__)
    short Initialize (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdln,
                      short nCmdShow);
    // [MS/Windows-specific method] For YACL internal use only.
    
#elif defined(__OS2__)
    short Initialize ();
    // [OS/2-specific method] For YACL internal use only.

#elif defined(__X_MOTIF__) || defined(__X_YACL__)
    short Initialize (int& argc, char *argv[]);
    // [X-windows-specific method] For YACL internal use only.

#if defined(__X_MOTIF__)
    struct _WidgetRec* RootShell() { return _rootshell; };
    // [X-Motif-specific method, for YACL internal use only] Return the
    // shell widget for the application.

#endif
    void ChangeCursor (Window w, const UI_Cursor&);
    // [X-windows-specific method, for YACL internal use only]
    
    Display* AppDisplay () {return _display;};
    // [X-windows-specific method, for YACL internal use only] Return the
    // {\tt Display} for the application.

#endif

    const char* ClassName () const { return "UI_Controller";};

protected:

    // ------- General event methods --------------


    bool ProcessSoftEvent (UI_Event* e);
    // Process the MakeInterface and Quit events.

    bool ProcessNativeEvents ();
    // Run a loop that retrieves and processes hard events from the window
    // system. Each retrieved event is passed to the current event filter
    // (set up by the most recent invocation of the {\tt EventLoop} method),
    // and is dispatched only if the latter allows it by returning TRUE.
    // Each event is also passed to the current termination filter; if the
    // latter returns TRUE, {\tt ProcessNativeEvents} returns to its caller.
    //
    // The return value of this method is FALSE if the current termination
    // filter disallowed dispatching, and TRUE otherwise. The only case in
    // which this method returns a TRUE value is when the application
    // terminates. 

    void DispatchSoftEvents ();
    // Dispatch all the soft events in the event queue and clear it out.
    // This method is called after each hard event is processed.
    
    UI_Event* RemoveEvent ();
    // Remove an event from the queue and return it.


    //
    // Instance variables:
    //
 
    UI_CompositeVObject* _root; 
    CL_IntegerTree       _viewTree; // Maintains all views in their proper
                                    // hierarchical order

    CL_ObjectSequence    _eventQueue;  // Queue of events
    UI_VisualObject*     _current;  // Object that is currently under the
                                    // mouse (not necessarily has focus)
    
    CL_IntPtrMap         _visualObjMap;
    UI_VisualObject*     _focus; // The object currently in focus


#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__)
    HANDLE hInst;    
    HANDLE hPrevInst;
#elif defined(__X_MOTIF__)
    struct _WidgetRec*   _rootshell;
    ulong                _grabWindow;
    CL_IntPtrMap         _shellMap;     // Map of shell widgets to
                                        // CompositeVObjects
    Display*             _display;
    CL_ObjectSet         _uninitedObjs;
    
#elif defined(__X_YACL__)
    Display*             _display;
    CL_ObjectSequence    _timerQueue;
    long                 _nextTimerId;
#endif

private:
    void _InitController ();
    // [Internal use only]

    void FlushEventQueue ();
    // Eat all the pending events that the platform has sent.
    
    bool RootDestroyed ();
    // Are we finished? 

    UI_Event* TranslateNativeEvent (NativeEventStruct& msg);
    // Translate the native event into a YACL event. Return the translated
    // event. It is the responsibility of the caller of this method to
    // destroy the returned event. Note that this method *must* return a
    // non-NULL event -- other parts of YACL code rely on this.
    //
    // This method is called by {\tt ProcessNativeEvents} and by the
    // WindowProc functions under OS/2 and Windows.

    bool DispatchNativeEvent (UI_Event& e);
    // Dispatch the event. This method returns the return value of the
    // handler that executed the event. The handler's return value
    // determines whether the event is sent up the view tree; if the value
    // is FALSE, the event is not sent up.
    //
    // This method is called (indirectly) by {\tt ProcessNativeEvents}.

#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__)
    bool _DoOneEvent (NativeEventStruct&);
    // [MS-Windows-specific, internal use only]
    
    void _MakeWindowsInterface (const UI_Event& e);
    // [MS-Windows-specific, internal use only] Create  the visual element
    // for {\tt e}'s destination. The parameter is a MakeInterface event.
    
    friend long FAR PASCAL YACLWindowProc (HWND ,unsigned, UINT, LONG);
    // [MS-Windows-specific, internal use only]
    
    friend long FAR PASCAL YACLSimpleVObjProc (HWND ,unsigned, UINT, LONG);
    // [MS-Windows-specific, internal use only]
    
    friend long FAR PASCAL YACLDialogProc (HWND ,unsigned, UINT, LONG);
    // [MS-Windows-specific, internal use only]

    friend long FAR PASCAL YACL_UI YACLBtnGroupProc (HWND hwnd,
                           unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only] Needed because YACL
    // subclasses button groups.
    
    friend long FAR PASCAL YACL_UI YACLBtnProc (HWND hwnd,
                         unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only] Needed because YACL
    // subclasses buttons.
    
    friend long FAR PASCAL YACL_UI YACLEditProc (HWND hwnd,
                         unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only] Needed because YACL
    // subclasses edit controls.
    
    friend long FAR PASCAL YACL_UI YACLMDIFrameProc (HWND hwnd,
                         unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only] Needed because YACL
    // subclasses edit controls.
    
    friend long FAR PASCAL YACL_UI YACLMDIChildProc (HWND hwnd,
                         unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only] Needed because YACL
    // subclasses edit controls.
    
    long MDIFrameProc (HWND hwnd, unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only]
    
    long MDIChildProc (HWND hwnd, unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only]
    
    long WindowProc (HWND, unsigned, UINT, LONG);
    // [MS-Windows-specific, internal use only]
    
    long DialogProc (HWND, unsigned, UINT, LONG);
    // [MS-Windows-specific, internal use only]

    long BtnGroupProc (HWND hwnd, unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only] Needed because YACL
    // subclasses button groups.
    
    long BtnProc (HWND hwnd, unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only] Needed because YACL
    // subclasses buttons.
    
    long EditProc (HWND hwnd, unsigned msg, UINT wParam, LONG lp);
    // [MS-Windows-specific, internal use only] Needed because YACL
    // subclasses edit controls.
    

    CL_PtrIntMap         _menuMap;
    bool                 _mainWindowIsMDI;
#if defined(__MS_WIN32__)
    HANDLE               _buttonFaceBrush;
#else
    ulong                _buttonFaceBrush;
#endif

#elif defined(__OS2__)
    HAB   _hab;
    HMQ   _hmq;
    HWND  _deIconifyPending; // Set to the handle of the window that was
                             // de-iconified. Used to delay the dispatch
                             // of the de-iconify event until after painting
    
    void _AbortPMApp (const char* errMsg);
    // [OS/2-specific, YACL internal use only]
    // Abort the application after emitting the given error message. Called
    // only in exceptional circumstances, e.g., when window creation fails.

    bool _DoOneEvent (NativeEventStruct&);
    // [OS/2-specific, internal use only]
    
    void _MakeOS2Interface (const UI_Event& e);
    // [OS/2-specific, internal use only]
    
    friend MRESULT EXPENTRY YACLWindowProc (HWND hWnd, ULONG msg, MPARAM p1,
                                            MPARAM p2);
    // [OS/2-specific, internal use only]
    
    friend MRESULT EXPENTRY YACLBmpBtnProc (HWND hWnd, ULONG msg, MPARAM p1,
                                            MPARAM p2);
    // [OS/2-specific, internal use only]
    
#elif defined(__X_MOTIF__) || defined(__X_YACL__)
    bool _DoOneEvent (NativeEventStruct&);
    // [X-windows-specific, internal use only]

    void _MakeXInterface (const UI_Event& e);
    // [X-windows-specific, internal use only]

    bool _ChildToBeCreated (UI_VisualObject*);
    // [X-windows-specific, internal use only]

    bool _WaitForNextEvent ();
    // [X-windows-specific, internal use only] Wait for the next event
    // (either an X event or a timer expiration). Return TRUE if it's a
    // timer expiration and FALSE if it's an X event.

    void _DispatchTimerEvents ();
    // [X-windows-specific, internal use only]

    UI_OneShotTimer*     _doubleClickTimer;
#endif

    UI_Cursor            _defaultCursor;
    bool                 _inWaitState;
    CL_AbstractBinding*  _eventFilter;
    CL_AbstractBinding*  _termination;
    UI_Event*            _currentEvent;
    CL_ObjectSequence    _currentEventStack; // Stack of targets of
                                             // currently active events


public:
    bool DispatchEvent (UI_Event* e);
    // [Internal use only] Dispatch {\tt e} up the view tree, beginning at
    // {\tt e}'s destination.


    void Register (UI_VisualObject* view);
    // [Internal use only]
    // Add {\tt view} to the view tree  as child of {\tt view->Parent()}. If
    // {\tt view}'s parent is NULL, this method assumes that the root is
    // being created, and that the parameter is a CompositeVObject.

    bool SetCurrentCursor (UI_Cursor&);
    // [Internal use only] Set the current cursor being shown. Return
    // TRUE if a cursor was set,  FALSE otherwise.
    
#if defined(__MS_WINDOWS__) || defined(__MS_WIN32__)
    bool MenuItemCreated   (UI_MenuItem* item);
    // [MS-Windows-specific, for internal use only]

    bool MenuItemDestroyed (UI_MenuItem* item);
    // [MS-Windows-specific, for internal use only]

    void SubclassControl (UI_ViewHandle handle, FARPROC proc);
    // [MS-Windows-specific, for internal use only]

    void MDIClientCreated   (UI_MDIMainWindow*);
    // [MS-Windows-specific, for internal use only]

    static void SetVObjPtr (HWND handle, UI_VisualObject* v);
    // [MS-Windows-specific, for internal use only]

    static UI_VisualObject* VObjPtr (HWND handle);
    // [MS-Windows-specific, for internal use only]

    
#if defined(__MS_WIN32__)
    HANDLE ButtonFaceBrush () const {return _buttonFaceBrush;};
    // [MS-Win32-specific, for internal use only]
    
#else
    long ButtonFaceBrush () const {return _buttonFaceBrush;};
    // [MS-Windows-specific, for internal use only]

#endif

#elif defined(__OS2__)
    HAB AnchorBlockHandle () const {return _hab;};
    // [OS/2-specific, for internal use only] Return the anchor block handle
    // for the application.
    
    HMQ MessageQueueHandle() const {return _hmq;};
    // [OS/2-specific, for internal use only] Return the message queue
    // handle for the application.
    
#elif defined(__X_MOTIF__)
    static void XEventHandler (struct _WidgetRec* w, void *, XEvent* xevent,
                               char *);
    // [X-Motif-specific; internal use only]

    void RealizeWidget (struct _WidgetRec* w);
    // [X-Motif-specific; internal use only]
    
    ulong RegisterTimeOut (long msec, void (*function) (void*, ulong*),
                           void* client_data);
    // [X-Motif-specific; internal use only]

    void UnregisterTimeOut (UI_Timer*);
    // [X-Motif-specific; internal use only]

    void _InitializeUninitedObjs ();
    // [X/Motif-specific, internal use only] Initializes th objects yet to
    // be initialized. This is to do the RealizeWidget stuff.

#elif defined(__X_YACL__)
    static void XEventHandler (struct _WidgetRec* w, void *, XEvent* xevent,
                               char *);
    // [X-windows-specific; internal use only]

    ulong RegisterTimeOut (long msec, UI_Timer* client_data);
    // [X-windows-specific; internal use only]

    void UnregisterTimeOut (UI_Timer*);
    // [X-windows-specific; internal use only]
    
#endif

#if defined(__X_MOTIF__) || defined(__X_YACL__)
    enum ErrorHandlerEnum {
        XErrors_Ignore,
        XErrors_Warning,
        XErrors_Fatal
    };
    static void SetErrorHandling (ErrorHandlerEnum e);
    // [X-windows-specific; internal use only]
    
#endif
};



#endif

