home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
yacl-012.zip
/
ui
/
cntroler.cxx
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-04
|
18KB
|
700 lines
/*
*
* Copyright (C) 1994, M. A. Sridhar
*
*
* This software is Copyright M. A. Sridhar, 1994. 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.
*
*/
#if defined(__GNUC__)
#pragma implementation
#endif
// ----------------------- Header file includes -----------------------
#include "base/treewalk.h"
#include "ui/cntroler.h"
#include "ui/applic.h"
#include "ui/menu.h"
#include "ui/composit.h"
#include "ui/event.h"
#include "ui/btngroup.h"
#if defined(__OS2__)
#include <stdlib.h>
#define INCL_PM
#include <os2.h>
#endif
#if defined (__X_MOTIF__)
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <X11/Shell.h>
#include <iostream.h> // DEBUG
#endif
#if defined(__GNUC__)
template class CL_Binding<UI_Controller>;
#endif
// ----------------------- Typedefs ---------------------------------
typedef CL_Binding<UI_Controller> ControllerBind;
typedef bool (UI_Controller::*ControllerMethod) (CL_Object&, long);
#if defined(__MS_WINDOWS__)
typedef long FAR PASCAL _export (*WinProc) (HWND, unsigned, WORD, LONG);
#endif
// ----------------------- Global and static variables -------------
char _YACLWindowClassName[] = "YACLWindow";
#if defined(__X_MOTIF__)
XtAppContext _YACLXAppContext;
#endif
// ----------------------- Function prototypes ----------------------
#if defined(__MS_WINDOWS__)
void initApplicationMS (HANDLE);
#elif defined(__OS2__)
MRESULT EXPENTRY YACLWindowProc (HWND, ULONG, MPARAM, MPARAM);
#elif defined(__X_MOTIF__)
// static void beep ( Widget, XEvent*, String*, unsigned int * );
// static XtActionsRec actionsTable [] =
// {
// {"beep", &beep}
// };
//
// static char defaultTranslations[] =
// "Ctrl<Key>J: beep() \n\
// Ctrl<Key>O: beep() \n\
// Ctrl<Key>M: beep() \n\
// <Key> RETURN: beep()";
// #define FONTHEIGHT(f) ((f)->max_bounds.ascent + \
// (f)->max_bounds.descent)
// static char _defaultTranslations[] =
// "<Btn1Down>(2+): lButtonDouble() \n\
// <Btn1Down>(2+): mButtonDouble() \n\
// <Btn1Down>(2+): rButtonDouble()";
//
// static XtActionsRec actionsTable [] =
// {
// {"lButtonDouble", UI_Controller::LButtonDouble}
// , {"mButtonDouble", UI_Controller::MButtonDouble}
// , {"rButtonDouble", UI_Controller::RButtonDouble}
// };
#endif
//
//----------------------Constructor-----------------------
//
UI_Controller::UI_Controller (UI_Application* appl)
{
UI_VisualObject::_Application = appl;
_InitController();
}
void UI_Controller::_InitController ()
{
widgetCount = 0;
_current = NULL;
UI_VisualObject::_Controller = this;
_viewTree = NULL;
_root = NULL;
_eventQueue = new CL_ObjectSequence;
_inWaitState = FALSE;
_focus = NULL;
_eventFilter = NULL;
_termination = NULL;
#if defined(__MS_WINDOWS__)
_buttonFaceBrush = CreateSolidBrush (GetSysColor (COLOR_BTNFACE));
#elif defined(__X_MOTIF_)
#endif
}
UI_Controller::~UI_Controller ( )
{
if ( _root != NULL )
Destroy ( _root );
_eventQueue->MakeEmpty ( );
if ( _viewTree )
delete _viewTree;
if ( _eventQueue )
delete _eventQueue;
#if defined(__OS2__)
WinDestroyMsgQueue (_hmq);
WinTerminate (_hab);
#elif defined(__MS_WINDOWS__)
DeleteObject ((HBRUSH) _buttonFaceBrush);
UnregisterClass ( _YACLWindowClassName, hInst );
_menuMap.DestroyContents ();
#endif
}
//
//-----------------Controller service methods----------------------------
//
//
//--------Mouse control methods
//
void UI_Controller::GiveMouseTo (const UI_VisualObject& view)
{
#if defined(__MS_WINDOWS__)
SetCapture (view._handle);
#elif defined (__OS2__)
WinSetCapture (HWND_DESKTOP, view._handle);
#elif defined(__X_MOTIF__)
// _grabWindow = XtWindow (view.ViewHandle());
// XGrabButton (AppDisplay(), AnyButton, AnyModifier, _grabWindow,
// True, 0xfffffff,
// GrabModeAsync, GrabModeAsync, _grabWindow, None);
#endif
}
void UI_Controller::ReleaseMouse()
{
#if defined(__MS_WINDOWS__)
ReleaseCapture();
#elif defined(__OS2__)
WinSetCapture (HWND_DESKTOP, NULL);
#elif defined(__X_MOTIF__)
// XUngrabButton (AppDisplay(), AnyButton, AnyModifier, _grabWindow);
#endif
}
void UI_Controller::GiveFocusTo (const UI_VisualObject& aView)
{
UI_ViewHandle h = aView.ViewHandle ();
#if defined(__MS_WINDOWS__)
if (h && h != GetFocus()) {
SetFocus (h);
}
#elif defined(__OS2__)
if (h && h != WinQueryFocus (HWND_DESKTOP))
WinSetFocus (HWND_DESKTOP, h);
#elif defined(__X_MOTIF__)
if (h)
XtSetKeyboardFocus (h, None);
#endif
}
UI_VisualObject* UI_Controller::operator [] (UI_ViewHandle h)
{
return (UI_VisualObject *) _visualObjMap [(long) h];
}
//
//---------------------Initialize-----------------------------
//
#if defined(__MS_WINDOWS__)
short UI_Controller::Initialize
(HANDLE hInstance, HANDLE hPrevInstance, LPSTR, short)
{
hInst = hInstance;
hPrevInst = hPrevInstance;
if ( !hPrevInstance )
initApplicationMS (hInstance);
return 1;
}
#elif defined(__X_MOTIF__)
short UI_Controller::Initialize ( int& argc, char *argv[] )
{
_shell = XtVaAppInitialize (&_YACLXAppContext, _TheApplication->AppClass(),
NULL, 0, &argc, argv, NULL,
NULL
);
Arg args [1];
short argn = 0;
XtSetArg (args [argn], XmNdeleteResponse, XmDO_NOTHING); argn++;
XtSetValues (_shell, args, argn);
// Do not destroy the shell widget in response to user
// requests; the library will take care of it.
// XtAppAddActions (_YACLXAppContext, actionsTable, XtNumber
// (actionsTable));
}
Display *UI_Controller::AppDisplay()
{
return XtDisplay (_shell);
}
#elif defined(__OS2__)
void UI_Controller::_AbortPMApp (const char* msg)
{
PERRINFO pErrInfoBlk;
PSZ pszOffSet;
void stdprint(void);
PSZ pszErrMsg;
DosBeep (100, 10);
DosBeep (440, 110);
if ((pErrInfoBlk = WinGetErrorInfo (_hab)) != NULL) {
pszOffSet = ((PSZ) pErrInfoBlk) + pErrInfoBlk->offaoffszMsg;
pszErrMsg = ((PSZ )pErrInfoBlk) + *((PSHORT)pszOffSet);
CL_String sMsg = CL_String("YACL: ") + msg + CL_String (" failed:\n")
+ pszErrMsg;
WinMessageBox
(HWND_DESKTOP, HWND_DESKTOP, sMsg.AsPtr(), "YACL FATAL", 0,
MB_MOVEABLE | MB_CUACRITICAL | MB_CANCEL );
WinFreeErrorInfo (pErrInfoBlk);
}
}
short UI_Controller::Initialize ()
{
if ((_hab = WinInitialize (0)) == NULLHANDLE)
_AbortPMApp ("WinInitialize");
if ((_hmq = WinCreateMsgQueue (_hab, 0)) == NULLHANDLE) {
_AbortPMApp ("WinCreateMsgQueue");
WinTerminate (_hab);
return FALSE;
}
if (!WinRegisterClass (_hab, _YACLWindowClassName, YACLWindowProc,
CS_SYNCPAINT | CS_MOVENOTIFY | CS_SIZEREDRAW, 0)) {
_AbortPMApp ("WinRegisterClass");
WinDestroyMsgQueue (_hmq);
WinTerminate (_hab);
return FALSE;
}
return TRUE;
}
#endif
void UI_Controller::MakeTopWindow (UI_CompositeVObject* rt)
{
if (_root && rt != _root)
CL_Error::Fatal ("Attempt to create two top windows.");
_root = rt;
if ( (_root->Title ()).Length () == 0 ){
CL_String title (_YACLWindowClassName);
_root->Title ()= title;
}
#if defined (__X_MOTIF__)
UI_VisualObject::_shell = _shell;
#endif
}
//
// -----------------------Controller methods-------------------
//
CL_ObjectSequence UI_Controller::ChildrenOf (const UI_VObjCollection& o)
{
CL_IntegerTreeNode* node = _viewTree->Node ((long) o.ViewHandle());
CL_ObjectSequence seq (node ? node->ChildCount() : 0);
if (!node)
return seq;
const CL_ObjectSequence& children = node->Children();
for (short i = 0; i < node->ChildCount(); i++)
seq[i] = (CL_Object*) ((CL_IntegerTreeNode*) children[i])->Content();
return seq;
}
void UI_Controller::Register (UI_VisualObject* view)
{
UI_VObjCollection* parent = view->_parent;
// _root is set when the main VisualObj is constructed. But Register is
// called only after its visual element has been created. So:
if ( _root && (view != _root)) {
UI_ViewHandle h = parent ? parent->ViewHandle()
: _root->ViewHandle();
CL_IntegerTreeNode* v = _viewTree->AddChild
((long) view->ViewHandle (), (long) h);
if (!v) // Should not happen
return;
v->Content () = (long) view;
}
else {
// We're creating the root of the view tree
_root = (UI_CompositeVObject *) view;
_viewTree = new CL_IntegerTree ((long) view->ViewHandle ());
_viewTree->Root()->Content() = (long)_root;
if ( (_root->Title ()).Length () == 0 ) {
CL_String title (_YACLWindowClassName);
_root->Title () = title;
}
}
// Now add visual object and window pair to the map
if (!_visualObjMap.Add ((long) view->ViewHandle (), view))
CL_Error::Warning ("Controller::Register: Duplicate handle %x "
"id %d class name '%s'", view->ViewHandle(),
view->ViewID(), view->ClassName());
}
// The following two functions are meant only for debugging support. This
// code might be useful in debugging, and therefore has not been deleted.
// static void PrintTree (const CL_IntegerTree& tree, CL_IntegerTreeNode* node,
// short depth = 0)
// {
// if (!node)
// return;
// CL_String s (' ', depth*4);
// UI_VisualObject* v = (UI_VisualObject*) node->Content();
// CL_Error::Warning ("%sHandle %ld Id %ld ptr %lx", s.AsPtr(),
// v->ViewHandle(), v->ViewID(), v);
// short n = node->ChildCount();
// if (n <= 0)
// return;
// CL_Error::Warning ("%s{", s.AsPtr());
// for (short i = 0; i < n; i++)
// PrintTree (tree, node->Child(i), depth+1);
// CL_Error::Warning ("%s}", s.AsPtr());
// }
//
//
// static void PrintMap (CL_IntPtrMap& map)
// {
// CL_Error::Warning ("---------");
// CL_IntPtrMapIterator itr (map);
// while (itr.More()) {
// CL_IntPtrAssoc a = itr.Next();
// UI_VisualObject* v = (UI_VisualObject*) a.value;
// CL_Error::Warning ("%ld %lx %ld", a.key, a.value, v->ViewID());
// }
// CL_Error::Warning ("---------\n");
// }
bool UI_Controller::Destroy (UI_VisualObject* view)
{
if ( view == NULL )
return FALSE;
if ( !(_visualObjMap.IncludesKey ((long) view->ViewHandle ())) )
return FALSE;
UI_ViewHandle vh = view->ViewHandle ();
// PrintTree (*_viewTree, _viewTree->Root()); // DEBUG
// We first go through the subtree and remove all the visual objects in
// the subtree from the visualObjMap. We then destroy the removed
// objects. This ensures that if the window system sends events to the
// objects while they're being destroyed, these events are not
// dispatched because the view handles will not be in the map.
CL_ObjectSequence toDestroy;
CL_IntegerTreePostWalker walker (_viewTree->Node ((long) vh));
while (walker.More()) {
UI_VisualObject* v = (UI_VisualObject *) walker.Next()->Content ();
if (v == _current)
_current = NULL;
if (v == _focus)
_focus = NULL;
if (v) {
if (v->ViewHandle())
_visualObjMap.Remove ((long) v->ViewHandle ());
toDestroy.Add (v);
}
}
if (view == _root) {
delete _viewTree;
_eventQueue->MakeEmpty ();
_viewTree = NULL;
_root = NULL;
}
else {
_viewTree->DestroySubtree ((long) vh);
// PrintTree (*_viewTree, _viewTree->Root()); // DEBUG
}
short n = toDestroy.Size();
for (short i = 0; i < n; i++) {
UI_VisualObject* v = (UI_VisualObject *) toDestroy[i];
v->Finalize ();
if ( v->_created )
v->DestroyVisualElement ();
delete v;
}
// PrintMap (_visualObjMap); // DEBUG
view = NULL;
return TRUE;
}
long UI_Controller::GetNextWidgetCount()
{
return ++widgetCount;
}
bool UI_Controller::DispatchEvent (UI_Event* e)
{
if (!_viewTree)
return TRUE; // No event dispatching -- the app is finished
if (_inWaitState)
return TRUE; // Do nothing if in wait state
UI_VisualObject* obj = e->Destination ();
if (e->_type == Event_GetFocus)
_focus = obj;
else if (e->_type == Event_LoseFocus)
_focus = NULL;
bool b = TRUE;
if (obj) {
b = obj->_PrivateHandleEvent (e);
if (b)
return TRUE;
UI_VObjCollection* vObj = obj->Parent();
while (vObj) {
e->_dest = vObj;
b = vObj->_PrivateHandleChildEvent (*e);
if (b) break;
vObj = vObj->Parent ();
}
}
return b;
}
bool UI_Controller::ProcessSoftEvent ( UI_Event* e )
{
bool done = FALSE;
switch (e->Type ()) {
case Event_Quit:
done = (e->Origin() == e->Destination() &&
e->Origin() == _root );
Destroy (e->Destination ());
break;
case Event_MakeInterface: {
UI_VisualObject* origin = e->Origin ();
if (!origin)
break;
#if defined(__MS_WINDOWS__)
_MakeWindowsInterface (*e);
#elif defined(__X_MOTIF__)
_MakeXInterface (*e);
#elif defined(__OS2__)
_MakeOS2Interface (*e);
#endif
break;
} // End of case Event_MakeInterface
default:
DispatchEvent (e);
break;
}
return done;
}
void UI_Controller::DispatchSoftEvents ()
{
UI_Event* e = NULL;
while ( _eventQueue->Size () > 0 ) {
e = (UI_Event*) _eventQueue->ExtractLeftmost ();
if ( !_eventFilter || _eventFilter->Execute (*e, 0) ) {
ProcessSoftEvent (e);
}
if ( _termination && _termination->Execute (*e, 0) ) {
delete e;
break;
}
delete e;
}
}
void UI_Controller::EventLoop (CL_AbstractBinding* termination,
CL_AbstractBinding* filter
)
{
// Save the filters.
CL_AbstractBinding* oldEventFilter = _eventFilter;
CL_AbstractBinding* oldTermFilter = _termination;
_eventFilter = filter;
_termination = termination;
// Run the loop
if ( _root )
ProcessNativeEvents ();
// Restore the filters
_eventFilter = oldEventFilter;
_termination = oldTermFilter;
}
bool UI_Controller::RootDestroyed ( CL_Object&, long )
{
return _root == NULL;
}
void UI_Controller::Run ()
{
if (!_root) {
CL_Error::Warning ("UI_Controller::Run: no root window");
return;
}
// Start by cleaning up the soft events
DispatchSoftEvents ();
ControllerBind bind ( this, &UI_Controller::RootDestroyed );
EventLoop ( &bind, NULL );
}
bool UI_Controller::SetCurrentCursor (UI_Cursor& c)
{
#if defined (__MS_WINDOWS__)
HCURSOR h = c.Handle();
if (h) {
SetCursor (h);
return TRUE;
}
return FALSE;
#elif defined(__OS2__)
if (c != UICursor_Default)
WinSetPointer (HWND_DESKTOP,
_inWaitState ? WinQuerySysPointer
(HWND_DESKTOP, SPTR_WAIT, FALSE)
: c.Handle());
return TRUE;
#elif defined (__X_MOTIF__)
XSetWindowAttributes attrs;
Display* dpy = XtDisplay (_shell);
attrs.cursor = (c == UICursor_Default) ? None : c.Handle();
XChangeWindowAttributes(dpy, XtWindow(_shell), CWCursor, &attrs);
XFlush(dpy);
return TRUE;
#endif
}
void UI_Controller::BeginWait ()
{
_inWaitState = TRUE;
_defaultCursor = UICursor_Wait;
DispatchPendingEvents ();
SetCurrentCursor (_defaultCursor);
}
void UI_Controller::EndWait ()
{
_inWaitState = FALSE;
_defaultCursor = UICursor_Arrow;
SetCurrentCursor (_defaultCursor);
FlushEventQueue ();
}
void UI_Controller::AddEvent(UI_Event* anEvent)
{
_eventQueue->Add ( anEvent );
}
UI_Event* UI_Controller::RemoveEvent ()
{
UI_Event *e;
if ( _eventQueue->Size () > 0 ){
e = ( UI_Event* ) _eventQueue->ExtractLeftmost ();
return e;
}
return NULL;
}
void UI_Controller::Beep ()
{
#if defined (__MS_WINDOWS__)
MessageBeep (MB_ICONQUESTION);
#elif defined (__X_MOTIF__)
XBell (XtDisplay (_current->_xwidget), 100);
#endif
}