Response table hacking

Back Up Next

I'm working with an application which allows user dynamically
define all menu items. Basically system works by reading the menu
configuration file and registering each menu command with an
associated macro language program. Registering menu item returns
dynamic id for the command and that's where the problems start.
OWL requires separate response table entry for each command id
and if I allow, for example, 500 menu items, response table
grows quite big:

const int COMMAND_BASE = 10000;

DEFINE_RESPONSE_TABLE1(MyFrame, TDecoratedFrame)
    EV_COMMAND_AND_ID(COMMAND_BASE + 0, OnCommand),
    EV_COMMAND_AND_ID(COMMAND_BASE + 1, OnCommand),
    EV_COMMAND_AND_ID(COMMAND_BASE + 2, OnCommand),
...imagine 496 lines here...
    EV_COMMAND_AND_ID(COMMAND_BASE + 499, OnCommand),
END_RESPONSE_TABLE;

All other application frameworks I'm familiar with (WX, QT, MFC)
allow command id ranges in their connections between menu items
and handler functions. For example, MFC:

BEGIN_MESSAGE_MAP(MyFrame, CFrameWnd)
    ON_COMMAND_RANGE(COMMAND_BASE, COMMAND_BASE + 499, OnCommand)
END_MESSAGE_MAP()

Now, let's see if we can create something similar in OWL. From
the eventhan.h we can see that id/function matching is done by
virtual Find function with a comparision operator as a parameter:

#define DEFINE_RESPONSE_TABLE1(cls, base)\
      bool cls::Find(TEventInfo& eventInfo, TEqualOperator equal)\
        { eventInfo.Object = (GENERIC*)this;\
           return SearchEntries((TGenericTableEntry __RTFAR*)__entries,
           eventInfo, equal) ||\
           base::Find(eventInfo, equal);}\
       DEFINE_RESPONSE_TABLE_ENTRIES(cls)

So, we can create our own comparison function which checks if
the given id is between defined range. Next problem is to store
that range somewhere. The response table entry stores the command
id to Id variable which seems to be unsigned integer. In 32 bit
environment this is big enough to store two 16 bit identifiers:
lower limit and upper limit. With this information we can write
new response table definitions and a comparison function:

bool range_check(TGenericTableEntry __RTFAR& entry, TEventHandler::TEventInfo& info)
{
  return (entry.Msg == info.Msg && info.Id >= LoUint16(entry.Id) && info.Id <= HiUint16(entry.Id));
}

#define DEFINE_RESPONSE_TABLE_RANGE1(cls, base)\
     bool cls::Find(TEventInfo& eventInfo, TEqualOperator equal)\
        { eventInfo.Object = (GENERIC*)this;\
           return SearchEntries((TGenericTableEntry __RTFAR*)__entries, eventInfo, equal) ||\
           SearchEntries((TGenericTableEntry __RTFAR*)__entries, eventInfo, range_check) ||\
           base::Find(eventInfo, equal) ||\
           base::Find(eventInfo, range_check);}\
           DEFINE_RESPONSE_TABLE_ENTRIES(cls)

#define EV_COMMAND_RANGE_AND_ID(from, to, method)\
   {0, MkUint32(from, to), (TAnyDispatcher)::v_WPARAM_Dispatch,\
   (TMyPMF)v_U_Sig(&TMyClass::method)}

System packs the lower limit to lower 16 bits of Id and the
upper limit to higher 16 bits by using the MkUint32() function.
Find function checks first if the id is equal to entry's id and
then if it is between the lower and upper range. If entry is not
found, the same procedure is repeated to base class. This works,
because if we use 16 bit identifiers, single id definition cannot
never match with range definition which has nonzero high 16 bits.
Now we can write the original 500 line response table like this:

DEFINE_RESPONSE_TABLE_RANGE1(MyFrame, TDecoratedFrame)
    EV_COMMAND_RANGE_AND_ID(COMMAND_BASE, COMMAND_BASE + 499, OnCommand),
END_RESPONSE_TABLE;

Neat thing with this is that it can be done without touching the
OWL sources just by defining the new comparision function and
response table definitions in the application sources. Drawback
is, of course, that it cannot be used in 16 bit programs and we
are limited to 16 bit command identifiers. However, neither of
these does not seem to really big problem.

I'm not sure if this hack should ever be added to OWL sources,
but I'm sending it here anyway, because someone might find it
useful. Definitions for classes with multiple inheritance is
left as an exercise...

Mikko

Mikko Syrjä Kielotie 14 B phone: +358 9 2532 4411
3D-system Oy FIN-01300 Vantaa fax: +358 9 2532 4433
Finland email: mikko@3d-system.fi

Revised: March 17, 2000.


Copyright © 1998-2001 Yura Bidus. All rights reserved.