Hey list!

I've been trying to isolate the keyboard navigation as much as i could since you guys said it should be compiled optionally. 

While a lot of stuff could be moved to it's own file (g_kbdnav.c) there are also a lot of code that need to be in the middle of pd's core functions.

For example, here is the modified canvas_obj() function on the g_text.c to not cinlude the code related to keyboard navigation:

https://gist.github.com/HenriAugusto/e417c8f269ad10df2dc3359b907ea588

It's not as pretty as it could be but it's readable (if your editor has code folding you can just hide the relevant lines to see what the code looks like, for example).

Is there a better way to do this?

Cheers,
Henri.
____________________________

Just in case, those are examples of some other modified core functions:

in g_text.c

glist_drawiofor(...) - draws a rectangle around the selected in/outlet
canvas_howputnew(...) - position a new object exactly below/above to selected in/outlet

in g_canvas.c

canvas_drawlines(...) - draws lines in different colors while navigating through connections
canvas_map(...) - draws each object's index if the user has asked so (useful for the goto functionality)



De: Christof Ressi <christof.ressi@gmx.at>
Enviado: terça-feira, 16 de julho de 2019 14:32
Para: Henri Augusto Bisognini <msndohenri@hotmail.com>
Cc: pd-dev@lists.iem.at <pd-dev@lists.iem.at>
Assunto: Aw: Re: [PD-dev] First complete keyboard navigation prototype
 
Hi,
 
> But it appears that actually the size of the struct is deduced while compiling. So if you write an external it is going to think the canvas struct is the same size as it was in the pd header files that were used during compilation.
 
exactly.
 
> When using the pointer to implementation idiom, wouldn't the pointer itself change the size of the struct?
 
yes, it will
 
> You've said something about that not being a problem when you add it as the last member of the struct but i don't understand why and how that would work.
 
usually, externals shouldn't care about the *size* the t_editor struct (at least I can't think of any use case), so you can get away with adding new fields at the end (although it's certainly not recommended). Note that those headers aren't really public anyway!
 
However, appending fields conditionally can lead to problems:
 
struct Foo {
    int a;
#ifdef FOO_EX
    int c;
#endif
};
 
Now let's say we need to add another member:
 
struct Foo {
    int a;
#ifdef FOO_EX
    int c;
#endif
    in b;
};
 
If the host compiles with FOO_EX defined and the client doesn't, the latter will assume a wrong offset for 'b'.
 
The solution is to add a field for private data *once*. The advantage is that a) we can hide the private data and b) we can extend it without worrying about compatibility:
 
struct Foo {
   int a;
   PrivateFoo *p;
};
 
We can still add public members if needed:
 
struct Foo {
    int a;
    void *private;
    int b;
};
 
'private' points to a private data structure that is not be visible to clients. There you can conditionally enable members without problems:
 
struct PrivateFoo {
#ifdef USE_BAR
    struct MyFeature feature;
#endif
};
 
MyFeature could be in a seperate source file together with your methods and it only gets compiled when needed.
 
Again, have a look at the "t_canvas_private" struct and the "gl_privatedata" member of "_glist" (aka "t_canvas") and do the same for "_editor", e.g.:
 
in g_canvas.h:
 
typedef struct _editor {
    ...
    void *e_privatedata;
} t_editor;
 
in g_editor.c:
 
#ifdef HAVE_KEYBOARDNAV
#include "g_keyboardnav.h"
#endif
 
typedef struct _editor_private {
#ifdef HAVE_KEYBOARDNAV
    t_keyboardnav keyboardnav;
#endif
} t_editor_private;
 
the "t_keyboardnav" struct is defined in "g_keyboardnav.h" and its methods implemented in "g_keyboardnav.c". Both only get compiled when needed.
 
Hope this makes sense.
 
Christof