Add:Core:Adding support for "saved" commands
authortinloaf <tinloaf@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Sat, 4 Apr 2009 18:40:53 +0000 (18:40 +0000)
committertinloaf <tinloaf@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Sat, 4 Apr 2009 18:40:53 +0000 (18:40 +0000)
git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk/navit@2184 ffa7fe5e-494d-0410-b361-a75ebd5db220

navit/command.c
navit/command.h
navit/osd.c
navit/osd.h

index 68e64d3..2fd6382 100644 (file)
@@ -44,8 +44,28 @@ struct context {
        struct result res;
 };
 
+struct command_saved_cb {
+       struct callback *cb;
+       struct attr attr;
+};
+
+struct command_saved {
+       struct context ctx;
+       struct result res;
+       char *command;                          // The command string itself
+       struct event_idle *idle_ev;             // Event to update this command
+       struct callback *idle_cb;
+       struct callback *register_cb;                   // Callback to register all the callbacks
+       struct event_idle *register_ev;         // Idle event to register all the callbacks
+       struct attr navit;
+       int num_cbs;
+       struct command_saved_cb *cbs;           // List of callbacks for this saved command
+       struct callback *cb; // Callback that should be called when we re-evaluate
+       int error;
+};
+
 enum error {
-       no_error=0,missing_closing_brace, missing_colon, wrong_type, illegal_number_format, illegal_character, missing_closing_bracket, invalid_type
+       no_error=0,missing_closing_brace, missing_colon, wrong_type, illegal_number_format, illegal_character, missing_closing_bracket, invalid_type, not_ready
 };
 
 static void eval_comma(struct context *ctx, struct result *res);
@@ -56,6 +76,56 @@ result_free(struct result *res)
 {
 }
 
+static int command_register_callbacks(struct command_saved *cs);
+
+static int
+get_next_object(struct context *ctx, struct result *res) {
+       char *op, *tmp;
+       op=ctx->expr;
+       res->varlen=0;
+       res->var=NULL;
+       res->attrnlen=0;
+       res->attrn=NULL;
+       
+       while (*op) {
+               if (op[0] == '"') {
+                       while (*op && (op[0] != '"')) {
+                               op++;
+                       }
+               }
+
+               if (op[0] >= 'a' && op[0] <= 'z') {
+                       res->attr.type=attr_none;
+                       res->var=op;
+                       while ((op[0] >= 'a' && op[0] <= 'z') || op[0] == '_') {
+                               res->varlen++;
+                               op++;
+                       }
+
+                       // If there is a bracket following, this is a function
+                       tmp = op;
+                       while (*tmp && g_ascii_isspace(*tmp)) {
+                               tmp++;
+                       }
+                       if (tmp[0] == '(') {
+                               continue;
+                       }
+
+                       ctx->expr=op;
+
+                       if (op[0] == '.') {
+                               return 2;                               // 2 means "more object names following"
+                       } else {
+                               return 1;                               // 1 means "no more object names following"
+                       }
+               }
+               
+               op++;
+       }
+
+       return 0;
+}
+
 static char *
 get_op(struct context *ctx, int test, ...)
 {
@@ -165,7 +235,7 @@ resolve_object(struct context *ctx, struct result *res)
 }
 
 static void
-resolve(struct context *ctx, struct result *res, struct attr *parent)
+resolve(struct context *ctx, struct result *res, struct attr *parent) //FIXME What is that parent for?
 {
        resolve_object(ctx, res);
        if (res->attr.type >= attr_type_object_begin && res->attr.type <= attr_type_object_end) {
@@ -443,13 +513,34 @@ eval_equality(struct context *ctx, struct result *res)
        eval_additive(ctx, res);
        if (ctx->error) return;
        for (;;) {
-               if (!(op=get_op(ctx,0,"==","!=",NULL))) return;
+               if (!(op=get_op(ctx,0,"==","!=","<=",">=","<",">",NULL))) return;
                eval_additive(ctx, &tmp);
                if (ctx->error) return;
-               if (op[0]  == '=') 
+
+               switch (op[0]) {
+               case '=':
                        set_int(ctx, res, (get_int(ctx, res) == get_int(ctx, &tmp)));
-               else
+                       break;
+               case '!':
                        set_int(ctx, res, (get_int(ctx, res) != get_int(ctx, &tmp)));
+                       break;
+               case '<':
+                       if (op[1] == '=') {
+                               set_int(ctx, res, (get_int(ctx, res) <= get_int(ctx, &tmp)));
+                       } else {
+                               set_int(ctx, res, (get_int(ctx, res) < get_int(ctx, &tmp)));
+                       }
+                       break;
+               case '>':
+                       if (op[1] == '=') {
+                               set_int(ctx, res, (get_int(ctx, res) >= get_int(ctx, &tmp)));
+                       } else {
+                               set_int(ctx, res, (get_int(ctx, res) > get_int(ctx, &tmp)));
+                       }
+                       break;
+               default:
+                       break;
+               }
                result_free(&tmp);
        }
 }
@@ -583,7 +674,7 @@ eval_comma(struct context *ctx, struct result *res)
 {
        struct result tmp;
 
-       eval_assignment(ctx, res);
+       eval_assignment(ctx, res);
        if (ctx->error) return;
        for (;;) {
                if (!get_op(ctx,0,",",NULL)) return;
@@ -750,3 +841,184 @@ command_add_table(struct callback_list *cbl, struct command_table *table, int co
        callback_list_add(cbl, cb);
 }
 
+void
+command_saved_set_cb (struct command_saved *cs, struct callback *cb)
+{
+       cs->cb = cb;
+}
+
+int
+command_saved_get_int (struct command_saved *cs)
+{
+       return get_int(&cs->ctx, &cs->res);
+}
+
+int 
+command_saved_error (struct command_saved *cs)
+{
+       return cs->error;
+}
+
+static void
+command_saved_evaluate_idle (struct command_saved *cs) 
+{
+       // Only run once at a time
+       if (cs->idle_ev) {
+               event_remove_idle(cs->idle_ev);
+               cs->idle_ev = NULL;
+       }
+
+       command_evaluate_to(&cs->navit, cs->command, &cs->ctx, &cs->res);
+
+       if (!cs->ctx.error) {
+               cs->error = 0;
+
+               if (cs->cb) {
+                       callback_call_1(cs->cb, cs);
+               }
+       } else {
+               cs->error = cs->ctx.error;
+       }
+}
+
+static void
+command_saved_evaluate(struct command_saved *cs)
+{      
+       if (cs->idle_ev) {
+               // We're already scheduled for reevaluation
+               return;
+       }
+
+       if (!cs->idle_cb) {
+               cs->idle_cb = callback_new_1(callback_cast(command_saved_evaluate_idle), cs);
+       }
+
+       cs->idle_ev = event_add_idle(100, cs->idle_cb);
+}
+
+static void
+command_saved_callbacks_changed(struct command_saved *cs)
+{
+       // For now, we delete each and every callback and then re-create them
+       int i;
+       struct object_func *func;
+       struct attr attr;
+
+       if (cs->register_ev) {
+               event_remove_idle(cs->register_ev);
+               cs->register_ev = NULL;
+       }
+
+       attr.type = attr_callback;
+
+       for (i = 0; i < cs->num_cbs; i++) {
+               func = object_func_lookup(cs->cbs[i].attr.type);
+               
+               if (!func->remove_attr) {
+                       dbg(0, "Could not remove command-evaluation callback because remove_attr is missing for type %i!\n", cs->cbs[i].attr.type);
+                       continue;
+               }
+
+               attr.u.callback = cs->cbs[i].cb;
+
+               func->remove_attr(cs->cbs[i].attr.u.data, &attr);
+               callback_destroy(cs->cbs[i].cb);
+       }
+
+       g_free(cs->cbs);
+       cs->cbs = NULL;
+       cs->num_cbs = 0;
+
+       // Now, re-create all the callbacks
+       command_register_callbacks(cs);
+}
+
+static int
+command_register_callbacks(struct command_saved *cs)
+{
+       struct attr prev,cb_attr,attr;
+       int status;
+       struct object_func *func;
+       struct callback *cb;
+       
+       attr = cs->navit;
+       cs->ctx.expr = cs->command;
+       cs->ctx.attr = &attr;
+       prev = cs->navit;       
+
+       while ((status = get_next_object(&cs->ctx, &cs->res)) != 0) {
+               resolve(&cs->ctx, &cs->res, NULL);
+
+               if (cs->ctx.error || (cs->res.attr.type == attr_none)) {
+                       // We could not resolve an object, perhaps because it has not been created
+                       return 0;
+               }
+
+               if (prev.type != attr_none) {
+                       func = object_func_lookup(prev.type);
+
+                       if (func->add_attr) {
+                               if (status == 2) { // This is not the final attribute name
+                                       cb = callback_new_attr_1(callback_cast(command_saved_callbacks_changed), cs->res.attr.type, (void*)cs);
+                                       attr = cs->res.attr;
+                               } else if (status == 1) { // This is the final attribute name
+                                       cb = callback_new_attr_1(callback_cast(command_saved_evaluate), cs->res.attr.type, (void*)cs);
+                                       cs->ctx.attr = &cs->navit;
+                               } else {
+                                       dbg(0, "Error: Strange status returned from get_next_object()\n");
+                               }
+
+                               cs->num_cbs++;
+                               cs->cbs = g_realloc(cs->cbs, (sizeof(struct command_saved_cb) * cs->num_cbs));
+                               cs->cbs[cs->num_cbs-1].cb = cb;
+                               cs->cbs[cs->num_cbs-1].attr = prev;
+                                       
+                               cb_attr.u.callback = cb;
+                               cb_attr.type = attr_callback;
+
+                               func->add_attr(prev.u.data, &cb_attr);
+
+                       } else {
+                               dbg(0, "Could not add callback because add_attr is missing for type %i}n", prev.type);
+                       }
+               }
+
+               if (status == 2) {
+                       prev = cs->res.attr;
+               } else {
+                       prev = cs->navit;
+               }
+       }
+
+       command_saved_evaluate_idle(cs);
+
+       return 1;
+}
+
+struct command_saved
+*command_saved_new(char *command, struct navit *navit, struct callback *cb)
+{
+       struct command_saved *ret;
+
+       ret = g_new0(struct command_saved, 1);
+       ret->command = g_strdup(command);
+       ret->navit.u.navit = navit;
+       ret->navit.type = attr_navit;
+       ret->cb = cb;
+       ret->error = not_ready;
+
+       if (!command_register_callbacks(ret)) {
+               // We try this as an idle call again
+               ret->register_cb = callback_new_1(callback_cast(command_saved_callbacks_changed), ret);
+               ret->register_ev = event_add_idle(300, ret->register_cb);
+       }               
+
+       return ret;
+}
+
+void 
+command_saved_destroy(struct command_saved *cs)
+{
+       g_free(cs->command);
+       g_free(cs);
+}
index 7dea058..0b3ba74 100644 (file)
@@ -4,6 +4,8 @@ struct command_table {
        int (*func)(void *data, char *cmd, struct attr **in, struct attr ***out);
 };
 
+struct command_saved;
+
 #define command_cast(x) (int (*)(void *, char *, struct attr **, struct attr ***))(x)
 
 void command_evaluate_to_void(struct attr *attr, char *expr, int **error);
@@ -11,4 +13,8 @@ char *command_evaluate_to_string(struct attr *attr, char *expr, int **error);
 int command_evaluate_to_int(struct attr *attr, char *expr, int **error);
 void command_evaluate(struct attr *attr, char *expr);
 void command_add_table(struct callback_list *cbl, struct command_table *table, int count, void *data);
-
+struct command_saved *command_saved_new(char *command, struct navit *navit, struct callback *cb);
+void command_saved_destroy(struct command_saved *cs);
+int command_saved_get_int(struct command_saved *cs);
+int command_saved_error(struct command_saved *cs);
+void command_saved_set_cb(struct command_saved *cs, struct callback *cb);
index 4df2126..5e87fbb 100644 (file)
@@ -116,6 +116,16 @@ osd_std_calculate_sizes(struct osd_item *item, struct osd_priv *priv, int w, int
        }
 }
 
+static void
+osd_std_reconfigure(struct osd_item *item, struct command_saved *cs)
+{
+       if (!command_saved_error(cs)) {
+               graphics_overlay_disable(item->gr, !command_saved_get_int(cs));
+       } else {
+               dbg(0, "Error in saved command: %i\n", command_saved_error(cs));
+       }
+}
+
 void
 osd_set_std_attr(struct attr **attrs, struct osd_item *item, int flags)
 {
@@ -148,8 +158,9 @@ osd_set_std_attr(struct attr **attrs, struct osd_item *item, int flags)
                item->osd_configuration = attr->u.num;
 
        attr=attr_search(attrs, NULL, attr_enable_expression);
-       if (attr)
-               item->enable_expression = g_strdup(attr->u.str);
+       if (attr) {
+               item->enable_cs = command_saved_new(attr->u.str, item->navit, NULL);
+       }
 
        attr = attr_search(attrs, NULL, attr_w);
        if (attr) {
@@ -214,16 +225,15 @@ osd_std_config(struct osd_item *item, struct navit *navit)
 {
        struct attr attr;
        dbg(1,"enter\n");
-       if (item->enable_expression) {
-               int error,configured;
-               attr.type=attr_navit;
-               attr.u.navit=navit;
-               configured=command_evaluate_to_int(&navit, item->enable_expression, &error);
-               if (error) {
-                       dbg(0,"evaluating %s resulted in error %d\n", item->enable_expression, error);
-                       configured=0;
+       if (item->enable_cs) {
+               item->reconfig_cb = callback_new_1(callback_cast(osd_std_reconfigure), item);
+               command_saved_set_cb(item->enable_cs, item->reconfig_cb);
+
+               if (!command_saved_error(item->enable_cs)) {
+                       item->configured = !! command_saved_get_int(item->enable_cs);
+               } else {
+                       dbg(0, "Error in saved command: %i.\n", command_saved_error(item->enable_cs));
                }
-               item->configured = !!configured;
        } else {
                if (!navit_get_attr(navit, attr_osd_configuration, &attr, NULL))
                        attr.u.num=-1;
index 21c2789..84e81e2 100644 (file)
@@ -42,9 +42,10 @@ struct osd_item {
        struct graphics_font *font;
        struct callback *cb;
        struct callback *resize_cb;
+       struct callback *reconfig_cb;
        int pressed;
        char *command;
-       char *enable_expression;
+       struct command_saved *enable_cs;
 };
 
 /* prototypes */