From 221df9f0fe86980a7d64735393c7eabd3280dd58 Mon Sep 17 00:00:00 2001 From: skyjake Date: Sun, 14 Apr 2013 13:25:21 +0300 Subject: [PATCH] Refactor|Client: Allowing Widgets to use the bindings system In the future the bindings system and widgets will be refactored into a more integrated whole, but for now we just want Widgets to be able to specify actions via event bindings. --- doomsday/client/include/ui/b_command.h | 2 +- doomsday/client/include/ui/b_context.h | 22 +++++++++++- doomsday/client/include/ui/widgetactions.h | 22 ++++++------ doomsday/client/src/ui/b_command.cpp | 2 +- doomsday/client/src/ui/b_context.cpp | 41 +++++++++++++++------- doomsday/client/src/ui/widgetactions.cpp | 27 ++++++++++---- 6 files changed, 82 insertions(+), 34 deletions(-) diff --git a/doomsday/client/include/ui/b_command.h b/doomsday/client/include/ui/b_command.h index 923fbac158..a37eb54926 100644 --- a/doomsday/client/include/ui/b_command.h +++ b/doomsday/client/include/ui/b_command.h @@ -64,6 +64,6 @@ void B_EventBindingToString(const evbinding_t* eb, ddstring_t* str); * * @return Action to be triggered, or @c NULL. Caller gets ownership. */ -de::Action *B_FindCommandBindingAction(evbinding_t *eb, ddevent_t const *event, struct bcontext_s *eventClass); +de::Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, struct bcontext_s *eventClass); #endif // __DOOMSDAY_BIND_COMMAND_H__ diff --git a/doomsday/client/include/ui/b_context.h b/doomsday/client/include/ui/b_context.h index 0081edb3ca..f8db355d0b 100644 --- a/doomsday/client/include/ui/b_context.h +++ b/doomsday/client/include/ui/b_context.h @@ -76,7 +76,27 @@ void B_DestroyControlBinding(controlbinding_t* conBin); void B_InitControlBindingList(controlbinding_t* listRoot); void B_DestroyControlBindingList(controlbinding_t* listRoot); boolean B_DeleteBinding(bcontext_t* bc, int bid); -de::Action *B_ActionForEvent(ddevent_t const *event); + +/** + * Finds the action bound to a given event, iterating through all enabled + * binding contexts. + * + * @param event Event to match against. + * + * @return Action instance (caller gets ownership), or @c NULL if not found. + */ +de::Action *B_ActionForEvent(ddevent_t const *event); + +/** + * Finds the action bound to a given event. + * + * @param bc Binding context to look in. + * @param event Event to match against. + * + * @return Action instance (caller gets ownership), or @c NULL if not found. + */ +de::Action *BindContext_ActionForEvent(bcontext_t *bc, ddevent_t const *event); + boolean B_FindMatchingBinding(bcontext_t* bc, evbinding_t* match1, dbinding_t* match2, evbinding_t** evResult, dbinding_t** dResult); void B_PrintContexts(void); diff --git a/doomsday/client/include/ui/widgetactions.h b/doomsday/client/include/ui/widgetactions.h index ab11e25086..4d95278978 100644 --- a/doomsday/client/include/ui/widgetactions.h +++ b/doomsday/client/include/ui/widgetactions.h @@ -32,7 +32,9 @@ * @todo "WidgetActions" is a work-in-progress name. * * @todo There should be one of these in every widget that has actions bound. - * When that's done, the old binding contexts become obsolete. + * When that's done, many of the old binding contexts become obsolete. There + * should still be support for several alternative contexts within one widget, + * for instance depending on the mode of the widget (e.g., automap pan). * * @todo What to do about control bindings? */ @@ -41,23 +43,19 @@ class WidgetActions public: WidgetActions(); - /** - * Returns an action that the user has bound to the provided event. - * - * @param event Event instance. - * - * @return Action bound to the event. Caller gets ownership of the Action. - */ - de::Action *actionForEvent(de::Event const &event); - /** * If an action has been defined for the event, trigger it. * - * @param event Event instance. + * This is meant to be used as a way for Widgets to take advantage of the + * traditional bindings system for user-customizable actions. + * + * @param event Event instance. + * @param context Name of the binding context. If empty, all contexts + * all checked. * * @return @c true if even was triggered, @c false otherwise. */ - bool tryEvent(de::Event const &event); + bool tryEvent(de::Event const &event, de::String const &context = ""); bool tryEvent(ddevent_t const *ev); diff --git a/doomsday/client/src/ui/b_command.cpp b/doomsday/client/src/ui/b_command.cpp index 997c5af87f..b6ae88e21b 100644 --- a/doomsday/client/src/ui/b_command.cpp +++ b/doomsday/client/src/ui/b_command.cpp @@ -358,7 +358,7 @@ static void B_SubstituteInCommand(char const *command, ddevent_t const *event, } } -de::Action *B_FindCommandBindingAction(evbinding_t *eb, ddevent_t const *event, struct bcontext_s *eventClass) +de::Action *EventBinding_ActionForEvent(evbinding_t *eb, ddevent_t const *event, struct bcontext_s *eventClass) { int i; inputdev_t* dev = 0; diff --git a/doomsday/client/src/ui/b_context.cpp b/doomsday/client/src/ui/b_context.cpp index ac6b7dc04f..19b518731b 100644 --- a/doomsday/client/src/ui/b_context.cpp +++ b/doomsday/client/src/ui/b_context.cpp @@ -365,9 +365,7 @@ void B_SetContextFallback(const char* name, int (*responderFunc)(event_t*)) bcontext_t* B_ContextByName(const char* name) { - int i; - - for(i = 0; i < bindContextCount; ++i) + for(int i = 0; i < bindContextCount; ++i) { if(!strcasecmp(name, bindContexts[i]->name)) return bindContexts[i]; @@ -535,6 +533,23 @@ boolean B_DeleteBinding(bcontext_t* bc, int bid) return false; } +de::Action *BindContext_ActionForEvent(bcontext_t *bc, ddevent_t const *event) +{ + if(!(bc->flags & BCF_ACTIVE)) + return 0; + + // See if the command bindings will have it. + for(evbinding_t *eb = bc->commandBinds.next; eb != &bc->commandBinds; eb = eb->next) + { + de::Action *act = 0; + if((act = EventBinding_ActionForEvent(eb, event, bc)) != 0) + { + return act; + } + } + return 0; +} + de::Action *B_ActionForEvent(ddevent_t const *event) { event_t ev; @@ -543,23 +558,25 @@ de::Action *B_ActionForEvent(ddevent_t const *event) for(int i = 0; i < bindContextCount; ++i) { bcontext_t *bc = bindContexts[i]; - de::Action *act = 0; - if(!(bc->flags & BCF_ACTIVE)) continue; - // See if the command bindings will have it. - for(evbinding_t *eb = bc->commandBinds.next; eb != &bc->commandBinds; eb = eb->next) + de::Action *act = BindContext_ActionForEvent(bc, event); + if(act) { - if((act = B_FindCommandBindingAction(eb, event, bc)) != 0) - { - return act; - } + return act; } - // Try the fallbacks. + /** + * @todo Conceptually the fallback responders don't belong: instead of + * "responding" (immediately performing a reaction), we should be + * returning an Action instance. -jk + */ + + // Try the fallback responders. if(bc->ddFallbackResponder && bc->ddFallbackResponder(event)) return 0; // fallback responder executed something + if(bc->fallbackResponder && bc->fallbackResponder(&ev)) return 0; // fallback responder executed something } diff --git a/doomsday/client/src/ui/widgetactions.cpp b/doomsday/client/src/ui/widgetactions.cpp index f4ec39b781..11855d5232 100644 --- a/doomsday/client/src/ui/widgetactions.cpp +++ b/doomsday/client/src/ui/widgetactions.cpp @@ -38,16 +38,29 @@ DENG2_PIMPL(WidgetActions) WidgetActions::WidgetActions() : d(new Instance(this)) {} -Action *WidgetActions::actionForEvent(Event const &event) -{ - return 0; -} - -bool WidgetActions::tryEvent(Event const &event) +bool WidgetActions::tryEvent(Event const &event, String const &context) { ddevent_t ddev; DD_ConvertEvent(event, &ddev); - return tryEvent(&ddev); + if(context.isEmpty()) + { + // Check all enabled contexts. + return tryEvent(&ddev); + } + + // Check a specific binding context for an action. + bcontext_t *bc = B_ContextByName(context.toLatin1()); + if(bc) + { + std::auto_ptr act(BindContext_ActionForEvent(bc, &ddev)); + if(act.get()) + { + act->trigger(); + return true; + } + } + + return false; } bool WidgetActions::tryEvent(ddevent_t const *ev)