source: branches/reyalp-flt/core/modules/module_menu.c @ 1489

Revision 1489, 9.2 KB checked in by tsv, 17 months ago (diff)

Flat branch update.

Added User-friendly module interface.

  • Modules are cleanly integrated into common menu. New module is called on start. It recursively scan module directory and make hierarchical menu for it.
  • Some modules made more standalone (could be used with no values)
  • Remove unneeded options/items

It is possible to organize modules on-build but this will cause problem unaccesibility on old cameras (like scripts/4pack/*)

Line 
1/*
2 *   Module: "Modules Menu"
3 *              Recursively scan argument[0] directory and make submenu binded to argument[1] menuitem
4 *
5 *   TODO: store results to text cache file .CACHE to avoid module load later (detect by size/timestamp)
6 *
7 *   (c)2011 Sergey Taranenko aka tsvstar
8 */
9
10
11#include "stdlib.h"
12#include "keyboard.h"
13#include "platform.h"
14#include "core.h"
15#include "lang.h"
16#include "gui.h"
17#include "../gui_draw.h"
18#include "../gui_lang.h"
19#include "../gui_menu.h"
20#include "../module_exportlist.h"
21
22#include "../module_load.h"
23
24//-------------------------------------------------------------------
25static char buf[250];
26
27int strlen_basepath;
28
29// module info
30char modulename[32];
31struct ModuleInfo minfo;
32
33//-------------------------------------------------------------------
34
35void free_modules_submenu( CMenu* menu )
36{
37        const CMenuItem* cur;
38
39        for ( cur=menu->menu; cur->type; cur++ ) {
40                if ( cur->type == MENUITEM_SUBMENU ) {
41                        free_modules_submenu( (CMenu*) cur->value );
42                        free( (void*)cur->text );                       
43                } else if ( cur->type == MENUITEM_PROC ) {
44                        free( (void*)cur->arg );
45                }
46        }
47
48        free(menu);
49}
50
51
52//-------------------------------------------------------------------
53
54// Small hack: reuse fileselector nothumb.c
55//     Sort first are dirs - then modules
56// Return: -1= v1<v2(keep) , 1= v1>v2
57//------------------------------------------
58extern int fselect_sort_nothumb(const void* v1, const void* v2);
59int fselect_sort(const void* v1, const void* v2) {
60
61        const CMenuItem *i1=v1, *i2=v2;
62
63        if (i1->type == MENUITEM_SUBMENU ) {
64                if (i2->type != MENUITEM_SUBMENU )
65                        return -1;
66        return strcmp( lang_str(i1->text), lang_str(i2->text) );
67        } else {
68                if (i2->type == MENUITEM_SUBMENU )
69                        return 1;
70        return strcmp( lang_str(i1->text), lang_str(i2->text) );
71        }
72}
73
74//-------------------------------------------------------------------
75static int parse_module( char* content, int size )
76{
77        struct flat_hdr* flat = (struct flat_hdr*)content;
78
79        memset( &minfo, 0, sizeof(minfo) );
80        modulename[0]=0;
81        //strncpy ( modulename, "no name", sizeof(modulename) );
82
83        if ( size < sizeof (struct flat_hdr) )
84                return 0;
85        char b[5];
86        memcpy(b,flat->magic,4);
87        b[4]=0;
88
89        if ( strncmp( flat->magic, FLAT_MAGIC_NUMBER, sizeof(flat->magic) ) )
90                return 0;
91
92        if ( flat->rev != FLAT_VERSION )
93                return 0;
94
95        if ( flat->_module_info > (size - sizeof(struct ModuleInfo)) )
96                return 0;
97
98        memcpy( &minfo, content+flat->_module_info, sizeof(struct ModuleInfo) );
99
100        if ( minfo.magicnum != MODULEINFO_V1_MAGICNUM ||
101                 minfo.sizeof_struct!=sizeof(struct ModuleInfo) )
102                return 0;
103
104        if ( minfo.moduleName < 0 )
105          { strncpy( modulename, lang_str(-minfo.moduleName), sizeof(modulename)); }
106        else if ( minfo.moduleName >= flat->entry )
107          { strncpy( modulename, (content+minfo.moduleName), sizeof(modulename)); }
108
109        return 1;
110}
111
112
113// Load info from module "fn" to minfo
114// Return: 0-fail, 1-ok
115static int load_module_info(char* fn)
116{
117        return load_from_file(fn, parse_module);
118}
119
120
121//---------------------------------------------------------
122CMenu* scan_directory(const char* dir) {
123
124    DIR           *d;
125    struct dirent *de;
126    static struct stat   st;
127
128        char curdir[100];
129        strcpy( curdir, dir);
130
131    int iter, count, len;
132        CMenu* mmenu = 0;
133        CMenuItem* mitems = 0;
134        CMenuItem* curitem;
135
136        // Two iterations:
137        //              first for draft count possible elements. then allocate
138        //              second exact check and filling each elements
139        for ( iter=1; iter<=2; iter++ )
140        {
141            d = opendir(curdir);
142        if (!d) return 0;
143
144                count = 0;
145            for( de = readdir(d); de; de = readdir(d) ) {
146
147            if (de->d_name[0] == 0xE5 /* deleted entry */ )
148                                continue;
149
150            if (de->d_name[0] == '.' && de->d_name[1]==0)
151                                continue;
152
153            if (de->d_name[0] == '.' && de->d_name[1]=='.' && de->d_name[2] == 0 )
154                                continue;
155
156                sprintf(buf, "%s/%s", curdir, de->d_name);
157                if (stat(buf, &st)!=0)
158                                continue;
159                       
160                        if ( st.st_attrib != DOS_ATTR_DIRECTORY &&
161                                 st.st_size <= (sizeof(struct flat_hdr)+sizeof(struct ModuleInfo)) )
162                                continue;
163
164                        if ( iter==2 ) {
165
166                                curitem=mitems+count;
167
168                                if ( st.st_attrib == DOS_ATTR_DIRECTORY ) {
169                                        void* submenu = 0;
170                                        submenu = scan_directory( buf );
171
172                                        if ( submenu==0 )
173                                                continue;
174
175                                        curitem->text = (int)malloc( strlen(de->d_name)+1 );
176                                        if ( curitem->text==0 ) continue;
177                                        curitem->type = MENUITEM_SUBMENU;
178                                        curitem->value = submenu;
179                                        strcpy( (char*)curitem->text, de->d_name);
180                                } else {
181
182                                        char *ext = strchr(de->d_name,'.');
183                            if ( !ext || (ext[1]|0x20)!='f' || (ext[2]|0x20)!='l' || (ext[3]|0x20)!='t' )
184                                                continue;
185
186                                        if ( !load_module_info(buf) )
187                                                continue;
188
189                                        if (minfo.flags & MODULEINFO_FLAG_SYSTEM )
190                                                continue;
191
192                                        len = ( minfo.moduleName < 0 ) ? 0 : strlen(modulename);
193
194                                        curitem->arg = (int)malloc( len+1 + strlen(buf)-strlen_basepath );
195                                        if ( curitem->arg==0 ) continue;
196
197                                        curitem->type = MENUITEM_PROC;
198                                        curitem->value = (void*)gui_menu_run_fltmodule;
199                                        strcpy( (void*)curitem->arg, buf+strlen_basepath+1 );
200
201                                        if ( minfo.moduleName < 0 )
202                                                curitem->text= -minfo.moduleName;
203                                        else {
204                                                curitem->text = curitem->arg + strlen((char*)curitem->arg)+1;
205                                                strcpy( (char*)curitem->text, modulename );
206                                        }
207                                }
208
209                                curitem->symbol=0x5c;
210                        }
211
212                        count++;
213                }
214
215                closedir(d);
216
217                // Iteration#1 final: allocate menuitems
218                if (iter==1) {
219
220                        if ( count==0 ) { closedir(d); return 0;}
221
222                        len = sizeof(CMenu) + sizeof(CMenuItem)*(count+2);
223                        mmenu=malloc( len );
224                        if ( mmenu==0 ) return 0;
225                        mitems = (CMenuItem*) ((char*)mmenu + sizeof(CMenu) );
226                        memset( mmenu, 0, len );
227                }
228        }
229
230        // Iteration#2 final
231
232        if ( count == 0 ) {
233                free( mmenu );
234                return 0;
235        }
236
237        // .. fill Cmenu
238        mmenu->symbol = 0x29;
239        mmenu->on_change = 0;
240        mmenu->menu = mitems;
241        if ( strlen(curdir)==strlen_basepath )
242                strcpy( buf, "Modules");
243        else
244                sprintf( buf, "Modules %s", curdir+strlen_basepath+1);
245
246        mmenu->title = (int)malloc( strlen(buf)+1 );
247        if ( mmenu->title==0 )
248        {
249                free( mmenu );
250                return 0;
251        }
252
253        strcpy( (void*)mmenu->title, buf );
254
255
256        // sort item
257    qsort(mitems, count, sizeof(CMenuItem), fselect_sort_nothumb);
258
259
260        // Add "Back" item
261        curitem=mitems+count;
262        curitem->text = LANG_MENU_BACK;
263        curitem->symbol=0x51;
264    curitem->type = MENUITEM_UP;
265
266        return mmenu;
267}
268
269
270
271// =========  MODULE INIT =================
272int module_idx=-1;
273
274/***************** BEGIN OF AUXILARY PART *********************
275  ATTENTION: DO NOT REMOVE OR CHANGE SIGNATURES IN THIS SECTION
276 **************************************************************/
277
278void* MODULE_EXPORT_LIST[] = {
279        /* 0 */ (void*)EXPORTLIST_MAGIC_NUMBER,
280        /* 1 */ (void*)0
281                };
282
283
284//---------------------------------------------------------
285// PURPOSE:   Bind module symbols with chdk.
286//              Required function
287// PARAMETERS: pointer to chdk list of export
288// RETURN VALUE: 1 error, 0 ok
289//---------------------------------------------------------
290int _module_loader( void** chdk_export_list )
291{
292        if ( (unsigned int)chdk_export_list[0] != EXPORTLIST_MAGIC_NUMBER )
293        return 1;
294
295        // If "gui_menu_run_fltmodule" is 0, then menu system is changed
296        if ( chdk_export_list[MODULESYM_GUI_MENU_RUN_FLTMODULE] == 0)
297                return 1;
298
299        return 0;
300}
301
302
303
304//---------------------------------------------------------
305// PURPOSE: Finalize module operations (close allocs, etc)
306// RETURN VALUE: 0-ok, 1-fail
307//---------------------------------------------------------
308int _module_unloader()
309{
310    return 0;
311}
312
313
314//---------------------------------------------------------
315// PURPOSE: Default action
316// NOTE: Please comment this function if no default action and this library module
317//---------------------------------------------------------
318int _module_run(int moduleidx, int argn, int* arguments)
319{
320        module_idx=moduleidx;
321
322    if ( argn!=2 ) {
323                module_async_unload(moduleidx);         // fail to init - "unload me"
324                return 1;
325        }
326
327        CMenu* menu;
328        CMenuItem* item = (void*) arguments[1];
329        switch ( item->type )
330        {
331                case MENUITEM_SUBMENU:
332                        free_modules_submenu( (CMenu*) item->value );
333                case MENUITEM_PROC:
334                case MENUITEM_TEXT:
335                        item->type = MENUITEM_TEXT;
336                        break;
337                default:
338                        // should never be other types
339                        module_async_unload(moduleidx);
340                        return 1;
341        }
342
343        strlen_basepath = strlen( (char*) arguments[0] );
344        menu = scan_directory( (char*) arguments[0] );
345        if ( menu!=0 ) {
346                item->type = MENUITEM_SUBMENU;
347                item->value = (int*)menu;
348        }
349
350        module_async_unload(moduleidx);         // processing finished - "unload me"
351        return 0;
352}
353
354
355/******************** Module Information structure ******************/
356
357struct ModuleInfo _module_info = {      MODULEINFO_V1_MAGICNUM,
358                                                                        sizeof(struct ModuleInfo),
359
360                                                                        ANY_CHDK_BRANCH, 0,                     // Requirements of CHDK version
361                                                                        ANY_PLATFORM_ALLOWED,           // Specify platform dependency
362                                                                        MODULEINFO_FLAG_SYSTEM,         // flag
363                                                                        (int32_t)"Module Menu",         // Module name
364                                                                        1, 0,                                           // Module version
365                                                                        (int32_t)"Scan directory for modules and create submenu hierarchy"
366                                                                 };
367
368/*************** END OF AUXILARY PART *******************/
Note: See TracBrowser for help on using the repository browser.