by Mikko Syrjä
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 comparison 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);
}
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 comparison function and response table definitions in the application sources.
I'm not sure if this hack should ever be added to OWLNext sources, but someone might find it useful. Definitions for classes with multiple inheritance is left as an exercise.
Wiki: Knowledge_Base
Wiki: Response_tables_without_macros
The idea for a response table ranges looks nice, maybe we should include it in the OWLNext sources. --[[User:Jogybl|Jogybl]] 20:15, 23 March 2010 (UTC)