!7 // function: func(S) -> bool (true = handled) // guiComponent may be null srecord VoiceTarget(S moduleID, JComponent guiComponent, O function) {} cmodule VoiceTargets > DynObjectTable { start { dontPersist(); dm_onTopInput_q(voidfunc(S s) { for (VoiceTarget vt : getVoiceTargets()) { if (!dm_moduleExists(vt.moduleID)) continue with remove(vt); temp dm_enter(vt.moduleID); if (isTrue(callF(vt.function, s))) ret; } }); } // hold targets during reload O _getReloadData() { ret data; } void _setReloadData(L data) { main addAll(this.data, map(data, func(O o) -> VoiceTarget { shallowCloneToClass(VoiceTarget, o) })); } // API void addVoiceTarget(S moduleID, JComponent guiComponent, O function) enter { assertNotNull(+guiComponent); assertNempty(+moduleID); final VoiceTarget vt = new(moduleID, guiComponent, function); bindToComponent(guiComponent, r { add(vt) }, r { remove(vt) }); } L getVoiceTargets() enter { ret cloneList(data); } }