home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
yacl-012.zip
/
ui
/
winevt.cxx
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-04
|
20KB
|
672 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.
*
*/
// MS/Windows-specific stuff
#if defined(__GNUC__)
#pragma implementation
#endif
#include "ui/cntroler.h"
#include "ui/menu.h"
#include "ui/btngroup.h"
#include <ctl3d.h>
static struct {
UINT message;
UI_EventType yaclEvent;
} TransTable [] = {
WM_SETFOCUS, Event_GetFocus,
WM_KILLFOCUS, Event_LoseFocus,
WM_LBUTTONDOWN, Event_LButtonPress,
WM_LBUTTONUP, Event_LButtonRelease,
WM_LBUTTONDBLCLK, Event_LButtonDblClk,
WM_MBUTTONDOWN, Event_MButtonPress,
WM_MBUTTONUP, Event_MButtonRelease,
WM_MBUTTONDBLCLK, Event_MButtonDblClk,
WM_RBUTTONDOWN, Event_RButtonPress,
WM_RBUTTONUP, Event_RButtonRelease,
WM_RBUTTONDBLCLK, Event_RButtonDblClk,
WM_CHAR, Event_KeyTyped,
WM_MOUSEMOVE, Event_MouseMove,
WM_CLOSE, Event_CloseDown,
WM_INITMENU, Event_GetFocus,
WM_INITMENUPOPUP, Event_GetFocus,
WM_MENUSELECT, Event_GetFocus,
WM_MOVE, Event_Reconfigure,
WM_SIZE, Event_Reconfigure,
WM_PAINT, Event_Paint,
WM_COMMAND, Event_Select,
// BM_SETCHECK, Event_Select,
WM_VSCROLL, Event_None, // Set by special handling
WM_HSCROLL, Event_None, // Set by special handling
0, Event_Other
};
long FAR PASCAL _export YACLWindowProc (HWND, unsigned, WORD, LONG);
long FAR PASCAL _export YACLDialogProc (HWND, unsigned, WORD, LONG);
bool UI_Controller::_DoOneEvent (NativeEventStruct& msg, UI_Event& e)
{
// Process a single native event, return its translation in e. Return
// TRUE if everything is ok, FALSE if the termination filter said YES.
bool dsp = FALSE;
dsp = TranslateNativeEvent (msg, e);
// Now here's a major HACK to handle tabs:
bool disp = (msg.message != WM_CHAR || msg.wParam != '\011');
if (!disp && e._origin) {
disp = (e._origin->_style & ES_MULTILINE) ||
(CL_String (e._origin->WindowClass()).InLowerCase() != "edit");
// A tab sent to a single-line edit control would cause a beep, so
// we don't dispatch it.
}
// Windows requires cursor setting on every mouse move, otherwise
// it reverts to the window class cursor! (see the documentation
// for the SetCursor call) Setting of cursor on every move
// can only be avoided if we use a NULL for the window class
// cursor; but if we do that, we'll not able to set our mouse
// cursor when the mouse moves out of the client area and back in,
// because we have no way of knowing when the mouse has moved out
// of the client area. There's also the problem that cursor shape
// changes on click.
if (msg.message == WM_SETCURSOR || msg.message == WM_MOUSEMOVE) {
if (_inWaitState)
SetCurrentCursor (_defaultCursor);
else {
POINT p;
GetCursorPos (&p);
HWND hWnd = WindowFromPoint (p);
UI_VisualObject* dest = (*this)[hWnd];
if (dest)
SetCurrentCursor (dest->Cursor());
}
}
if (disp && msg.message != WM_SETCURSOR)
DispatchMessage (&msg);
if (e._origin && dsp && _viewTree
&& _visualObjMap.IncludesKey (e._origin->_handle)) {
// ^^^^^^^^^^^^^^^^^^^^^^^
// These tests are is needed because it is possible that the
// DispatchMessage call above generated events that destroyed the
// tree or e._origin or both.
if ( !_eventFilter || _eventFilter->Execute (e, 0) ) {
if (e._origin->WindowClass() != _YACLWindowClassName)
DispatchNativeEvent (e);
// We don't dispatch events from a VisualObject whose class is
// YACLWindowClassName, because those are done by the
// WindowProc.
}
if (_termination && _termination->Execute (e, 0))
return FALSE;
}
DispatchSoftEvents();
return TRUE;
}
bool UI_Controller::ProcessNativeEvents ()
{
NativeEventStruct msg;
while (_root && GetMessage (&msg, NULL, 0, 0) ) {
TranslateMessage (&msg);
UI_Event e (Event_None, NULL);
if (!_DoOneEvent (msg, e))
return FALSE;
}
return TRUE;
}
void UI_Controller::FlushEventQueue ()
{
NativeEventStruct msg;
while (_root && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE));
}
void UI_Controller::DispatchPendingEvents ()
{
DispatchSoftEvents ();
NativeEventStruct msg;
UI_Event e (Event_None, NULL);
while (_root && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)
&& _DoOneEvent (msg, e));
}
bool UI_Controller::DispatchNativeEvent ( UI_Event& e )
{
if (!_root)
return TRUE;
bool ret_val = TRUE;
switch (e.Type ()) {
case Event_MouseMove:
if ( _current != e.Destination () ) {
// The mouse entered a different visual obj
if ( _current ) {
UI_Event leave (Event_ViewLeave, _current);
DispatchEvent (&leave);
}
_current = e.Destination ();
UI_Event enter (Event_ViewEnter, e.Destination ());
ret_val = DispatchEvent (&enter);
}
ret_val = DispatchEvent (&e);
break;
default:
ret_val = DispatchEvent (&e);
break;
}
return ret_val;
}
// We need a MenuEntry class to maintain the _menuMap object. This is a map
// of <menu item id, parent handle> pairs to menu item objects. This is the
// only way we can decode the destination of a menu event.
class MenuEntry: public CL_Object {
public:
MenuEntry (UI_ViewID id, UI_ViewHandle handle)
: _id (id), _handle (handle) {};
~MenuEntry () {};
short Compare (const CL_Object& o) const;
const char* ClassName () const {return "MenuEntry";};
private:
UI_ViewID _id;
UI_ViewHandle _handle;
};
short MenuEntry::Compare (const CL_Object& o) const
{
const MenuEntry& entry = (const MenuEntry&) o;
if (_handle == entry._handle)
return _id == entry._id ? 0 : (_id < entry._id ? -1 : 1);
return _handle < entry._handle ? -1 : 1;
}
bool UI_Controller::MenuItemCreated (UI_MenuItem* item)
// Called from the MenuItem::_PrivateInitialize
{
MenuEntry* entry = new MenuEntry
(item->_id, item->Container().Parent()->ViewHandle());
return _menuMap.Add (entry, (long) item);
}
bool UI_Controller::MenuItemDestroyed (UI_MenuItem* item)
// Called from the MenuItem destructor
{
MenuEntry entry (item->_id, item->Container().Parent()->ViewHandle());
CL_PtrIntAssoc a = _menuMap.Remove (&entry);
return a.value != 0;
}
bool UI_Controller::TranslateNativeEvent (NativeEventStruct& msg, UI_Event& e)
{
e._nativeEvent = new NativeEventStruct;
*(NativeEventStruct*)(e._nativeEvent) = msg;
e.curPos = UI_Rectangle (LOWORD (msg.lParam), HIWORD (msg.lParam), 0, 0);
e._metaKey = (msg.lParam & (1L << 29)) ? TRUE : FALSE;
e._shiftKey = (GetKeyState (VK_SHIFT) & 0x8000) ? TRUE : FALSE;
e._ctrlKey = (GetKeyState (VK_CONTROL) & 0x8000) ? TRUE : FALSE;
UI_VisualObject* view = NULL;
for (short i = 0; TransTable [i].message != 0; i++) {
if (TransTable [i].message == msg.message)
break;
}
e._type = TransTable[i].yaclEvent;
UI_ViewHandle window_key;
if (msg.message == WM_INITMENU || msg.message == WM_INITMENUPOPUP) {
window_key = (long) msg.wParam;
e.param = msg.wParam;
}
else if (msg.message == WM_VSCROLL || msg.message == WM_HSCROLL) {
window_key = HIWORD (msg.lParam);
e.param = LOWORD (msg.lParam);
switch (msg.wParam) {
case SB_BOTTOM:
e._type = Event_ScrollToEnd;
break;
case SB_ENDSCROLL:
e._type = Event_FinishScroll;
break;
case SB_LINEDOWN:
e._type = Event_ScrollForwardLine;
break;
case SB_PAGEDOWN:
e._type = Event_ScrollForwardPage;
break;
case SB_LINEUP:
e._type = Event_ScrollBackwardLine;
break;
case SB_PAGEUP:
e._type = Event_ScrollBackwardPage;
break;
case SB_THUMBPOSITION:
e._type = Event_ScrollToPosition;
break;
case SB_THUMBTRACK:
e._type = Event_Scroll;
break;
}
}
else
window_key = (long) msg.hwnd;
view = (UI_VisualObject *) _visualObjMap [window_key];
e._origin = e._dest = view;
switch (msg.message) {
case WM_MOVE: {
long w = 0, h = 0;
if (view) {
w = view->_shape.Width();
h = view->_shape.Height();
}
e.curPos = UI_Rectangle (LOWORD (msg.lParam), HIWORD
(msg.lParam), w, h);
break;
}
case WM_SIZE: {
long x = 0, y = 0;
if (view) {
x = view->_shape.Left();
y = view->_shape.Top();
}
e.curPos = UI_Rectangle (x, y, LOWORD (msg.lParam), HIWORD
(msg.lParam));
switch (msg.wParam) {
case SIZE_MINIMIZED:
e._type = Event_Iconify;
break;
case SIZE_MAXIMIZED:
e._type = Event_FullScreen;
break;
case SIZE_RESTORED:
e._type = (view && view->IsIconified()) ? Event_Deiconify
: Event_Reconfigure;
break;
default:
e._type = Event_Reconfigure;
break;
}
break;
}
case WM_CHAR:
e.key = msg.wParam;
break;
default:
break;
}
// Now process the menu messages
if (msg.message == WM_MENUSELECT) {
MenuEntry entry (msg.wParam, msg.hwnd);
UI_MenuItem* itm = (UI_MenuItem*) _menuMap[&entry];
if (LOWORD (msg.lParam) == 0xffff && HIWORD (msg.lParam) == 0) {
// Menu closed
e._type = Event_LoseFocus;
e._origin = e._dest = itm;
_focus = NULL;
}
else {
if (_focus) {
UI_Event loseFocus (Event_LoseFocus, _focus, _focus);
DispatchEvent (&loseFocus);
}
e._type = Event_GetFocus;
e._origin = e._dest = _focus = itm;
e.param = msg.wParam;
}
}
else if (msg.message == WM_COMMAND) {
if (LOWORD (msg.lParam) == 0) {
// Message from a menu: Event_Select
MenuEntry entry (msg.wParam, msg.hwnd);
UI_MenuItem* itm = (UI_MenuItem*) _menuMap[&entry];
e._origin = e._dest = itm;
e.param = msg.wParam; // Set the menu id
}
else {
// Message from a control
e._origin = e._dest = (UI_VisualObject*)
_visualObjMap [LOWORD (msg.lParam)];
switch (HIWORD (msg.lParam)) {
case LBN_SELCHANGE:
// case CBN_SELCHANGE:
// windows.h defines CBN_SELCHANGE == LBN_SELCHANGE!!
case BN_CLICKED:
e._type = Event_Select;
break;
default:
e._type = Event_Other;
break;
}
}
}
return e._dest != NULL;
}
void UI_Controller::_MakeWindowsInterface (const UI_Event& e)
{
// We don't create the interface for the child of a composite if the
// composite was built from a resource under MS/Windows
bool b = TRUE;
UI_VisualObject* origin = e.Origin();
UI_VisualObject* parent = origin->_parent;
bool res = parent && parent->CreatedViaResource ();
if (!parent || !res)
b = origin->MakeVisualElement ();
if (b && origin->ViewHandle ()) {
Register (origin);
if (!res)
ShowWindow (origin->ViewHandle (),
origin->_visible ? SW_SHOW : SW_HIDE
);
}
origin->_PrivateInitialize ();
origin->Initialize ();
}
long UI_Controller::WindowProc ( HWND hWnd, unsigned message,
WORD wParam, LONG lParam)
{
UI_Event e (Event_None, NULL);
NativeEventStruct msg;
msg.hwnd = hWnd;
msg.message = message;
msg.lParam = lParam;
msg.wParam = wParam;
TranslateNativeEvent (msg, e);
UI_VisualObject* v = e.Origin ();
long retVal = 0;
switch (message) {
case WM_SETTEXT:
case WM_NCPAINT:
case WM_NCACTIVATE:
if (!v || !v->Has3DLook())
retVal = DefWindowProc (hWnd, message, wParam, lParam);
else {
SetWindowLong (hWnd, DWL_MSGRESULT,
Ctl3dDlgFramePaint (hWnd, message, wParam, lParam));
retVal = TRUE;
}
break;
case WM_CTLCOLOR: {
if (!v || !v->Has3DLook())
retVal = DefWindowProc (hWnd, message, wParam, lParam);
else {
HBRUSH hbr = Ctl3dCtlColorEx (message, wParam, lParam);
if (hbr)
retVal = hbr;
else
retVal =_buttonFaceBrush;
}
break;
}
case WM_COMMAND:
retVal = DefWindowProc (hWnd, message, wParam, lParam);
if (HIWORD(lParam) == 0) {
// Menu item was selected; now make it lose focus:
UI_Event event (Event_LoseFocus, e._origin, e._origin);
DispatchEvent (&event);
}
break;
case WM_PAINT: {
// Clear out any invalid area:
PAINTSTRUCT ps;
HDC hdc = BeginPaint (hWnd, &ps);
HBRUSH hbr = v && v->Has3DLook() ? _buttonFaceBrush
: GetStockObject (WHITE_BRUSH);
FillRect (hdc, &ps.rcPaint, hbr);
EndPaint (hWnd, &ps);
retVal = 0;
break;
}
case WM_ERASEBKGND:
// When a previously obscured window is unobscured, Windows sends a
// WM_PAINT, a WM_NCPAINT and a WM_ERASEBKGND, *in that order*. So
// if we call DefWindowProc in response to the WM_ERASEBKGND, the
// previously painted area is erased! So we don't call
// DefWindowProc, but instead:
retVal = 1; // Pretend we processed the message
break;
case WM_CLOSE:
retVal = 0;
break;
default:
retVal = DefWindowProc (hWnd, message, wParam, lParam);
break;
}
if (!_eventFilter || _eventFilter->Execute (e, 0) )
DispatchNativeEvent (e);
return retVal;
}
long UI_Controller::DialogProc (HWND hWnd, unsigned message,
WORD wParam, LONG lParam)
{
UI_Event e (Event_None, NULL);
NativeEventStruct msg;
msg.hwnd = hWnd;
msg.message = message;
msg.lParam = lParam;
msg.wParam = wParam;
TranslateNativeEvent (msg, e);
if ( !_eventFilter || _eventFilter->Execute (e, 0) ) {
DispatchNativeEvent (e);
}
if (message == WM_COMMAND && HIWORD(lParam) == 0) {
// Menu item was selected; now make it lose focus:
UI_Event event (Event_LoseFocus, e._origin, e._origin);
DispatchEvent (&event);
}
switch (message) {
case WM_SETTEXT:
case WM_NCPAINT:
case WM_NCACTIVATE:
SetWindowLong (hWnd, DWL_MSGRESULT,
Ctl3dDlgFramePaint (hWnd, message, wParam, lParam));
return TRUE;
case WM_CTLCOLOR: {
HBRUSH hbr = Ctl3dCtlColorEx (message, wParam, lParam);
if (hbr)
return hbr;
return _buttonFaceBrush;
}
case WM_COMMAND:
if (HIWORD(lParam) == 0) {
// Menu item was selected; now make it lose focus:
UI_Event event (Event_LoseFocus, e._origin, e._origin);
DispatchEvent (&event);
}
break;
}
return 0;
}
long UI_Controller::BtnGroupProc (HWND hWnd, unsigned msg,
WORD wParam, LONG lP)
{
int low = GetProp (hWnd, BTNGROUP_PROPERTY1);
int hi = GetProp (hWnd, BTNGROUP_PROPERTY2);
UI_ButtonGroup* group = (UI_ButtonGroup*) _visualObjMap[hWnd];
if (low == 0 || hi == 0 || !group)
return DefWindowProc (hWnd, msg, wParam, lP);
FARPROC realProc = (FARPROC) MAKELONG (low, hi);
long retVal = 0L;
switch (msg) {
case WM_ERASEBKGND: {
RECT rect;
GetClientRect (hWnd, &rect);
HBRUSH brush = CreateSolidBrush
(GetSysColor (group->Has3DLook() ? COLOR_BTNFACE :
COLOR_WINDOW));
FillRect ((HDC) wParam, &rect, brush);
DeleteObject (brush);
// Now just call the real proc, pretending that no painting was
// done, and let it do its thing:
break;
}
case WM_CTLCOLOR: {
if (group && group->Has3DLook()) {
HBRUSH hbr = Ctl3dCtlColorEx (msg, wParam, lP);
if (hbr)
retVal = hbr;
}
else
retVal = CallWindowProc (realProc, hWnd, msg, wParam, lP);
break;
}
default:
retVal = CallWindowProc (realProc, hWnd, msg, wParam, lP);
break;
}
MSG mesg;
mesg.hwnd = hWnd;
mesg.message = msg;
mesg.lParam = lP;
mesg.wParam = wParam;
UI_Event e (Event_None, NULL);
TranslateNativeEvent (mesg, e);
DispatchNativeEvent (e);
return retVal;
}
// MS Windows window manager messages caught here
long FAR PASCAL _export YACLWindowProc (HWND hwnd, unsigned msg, WORD
wParam, LONG lp)
{
return _TheApplication->Controller().WindowProc (hwnd, msg, wParam, lp);
}
long FAR PASCAL _export YACLDialogProc (HWND h, unsigned m, WORD w, LONG l)
// (HWND, unsigned, WORD, LONG)
{
return _TheApplication->Controller().DialogProc (h, m, w, l);
}
long FAR PASCAL _export YACLBtnGroupProc (HWND h, unsigned m,
WORD w, LONG l)
{
return _TheApplication->Controller().BtnGroupProc (h, m, w, l);
}
void initApplicationMS(HANDLE hInst)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wc.lpfnWndProc = (WNDPROC) YACLWindowProc;
wc.cbClsExtra = NULL;
wc.cbWndExtra = NULL;
wc.hInstance = hInst;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = _YACLWindowClassName;
if ( !RegisterClass (&wc) )
CL_Error::Warning ("UI_Controller: RegisterClass '%s' failed!",
wc.lpszClassName);
}