lua_lv.c 11.3 KB
Newer Older
1
2
3
4
5
6
7
8
/***
 LiveView functions
 
 @author Magic Lantern Team
 @copyright 2014
 @license GPL
 @module lv
 */
9
10
11
12
13
14

#include <dryos.h>
#include <string.h>
#include <shoot.h>
#include <property.h>
#include <zebra.h>
David Milligan's avatar
David Milligan committed
15
#include <lvinfo.h>
16
#include <powersave.h>
17
18
19

#include "lua_common.h"

David Milligan's avatar
David Milligan committed
20
21
22
23
24
25
26
27
28
29

struct lvinfo_item_entry
{
    struct lvinfo_item item;
    lua_State * L;
    int custom_drawing;
    int function_ref;
    int self_ref;
};

30
31
32
static int luaCB_lv_index(lua_State * L)
{
    LUA_PARAM_STRING_OPTIONAL(key, 2, "");
33
    /// Whether or not LV is enabled (may be running or paused).
David Milligan's avatar
David Milligan committed
34
    // @tfield bool enabled
35
36
37
38
39
40
41
42
43
44
    if(!strcmp(key, "enabled")) lua_pushboolean(L, lv || LV_PAUSED);
    /// Whether or not LV is paused (shutter open, but sensor inactive; useful for powersaving).
    // @tfield bool paused
    else if(!strcmp(key, "paused")) lua_pushboolean(L, LV_PAUSED);
    /// Whether or not LV is running (that is, enabled and not paused).
    // @tfield bool running
    else if(!strcmp(key, "running")) lua_pushboolean(L, lv);
    /// Get/set LiveView zoom factor (1, 5, 10).
    // @tfield bool zoom
    else if(!strcmp(key, "zoom")) lua_pushinteger(L, lv_dispsize);
45
46
47
48
49
50
51
52
    /// Get the status of LiveView overlays (false = disabled, 1 = Canon, 2 = ML)
    // @tfield int overlays
    else if(!strcmp(key, "overlays"))
    {
        if (zebra_should_run()) lua_pushinteger(L, 2);
        else if (lv && lv_disp_mode) lua_pushinteger(L, 1);
        else lua_pushboolean(L, 0);
    }
53
54
55
56
57
58
59
60
    /// Get the name of current LiveView video mode.
    ///
    /// Examples: MV-1080, MV-720, MVC-1080, REC-1080, ZOOM-X5, PH-LV, PH-QR, PLAY-PH, PLAY-MV...
    //@tfield string vidmode
    else if(!strcmp(key, "vidmode"))
    {
        lua_pushstring(L, get_video_mode_name(0));
    }
61
62
63
64
65
66
67
68
69
70
71
72
73
    else lua_rawget(L, 1);
    return 1;
}

static int luaCB_lv_newindex(lua_State * L)
{
    LUA_PARAM_STRING_OPTIONAL(key, 2, "");
    if(!strcmp(key, "enabled"))
    {
        LUA_PARAM_BOOL(value, 3);
        if(value && !lv && !LV_PAUSED) force_liveview();
        else if(lv) close_liveview();
    }
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
    else if(!strcmp(key, "zoom"))
    {
        LUA_PARAM_INT(value, 3);

        if (!lv)
        {
            return luaL_error(L, "LiveView must be enabled");
        }

        set_lv_zoom(value);

        if (lv_dispsize != value)
        {
            return luaL_error(L, "Could not set LiveView zoom");
        }
    }
90
91
92
93
94
95
96
    else
    {
        lua_rawset(L, 1);
    }
    return 0;
}

97
98
99
100
/***
 Enter LiveView.
 @function start
 */
101
102
103
104
105
106
static int luaCB_lv_start(lua_State * L)
{
    force_liveview();
    return 0;
}

107
108
109
110
/***
 Pause LiveView (but leave shutter open).
 @function pause
 */
111
112
113
114
115
116
static int luaCB_lv_pause(lua_State * L)
{
    PauseLiveView();
    return 0;
}

117
118
119
120
/***
 Resume LiveView.
 @function resume
 */
121
122
123
124
125
126
static int luaCB_lv_resume(lua_State * L)
{
    ResumeLiveView();
    return 0;
}

127
128
129
130
/***
 Exit LiveView.
 @function stop
 */
131
132
133
134
135
136
static int luaCB_lv_stop(lua_State * L)
{
    close_liveview();
    return 0;
}

137
/***
alex@thinkpad's avatar
alex@thinkpad committed
138
 Wait for N frames in LiveView.
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
 @tparam int num_frames
 @function wait
 */
static int luaCB_lv_wait(lua_State * L)
{
    LUA_PARAM_INT(num_frames, 1);

    int ok = wait_lv_frames(num_frames);

    if (!ok)
    {
        return luaL_error(L,
            lv ? "lv.wait failed (timeout?)"
               : "lv.wait failed (LV stopped)"
        );
    }
    return 0;
}

David Milligan's avatar
David Milligan committed
158
159
160
161
162
163
164
165
166
167
168
static LVINFO_UPDATE_FUNC(lua_lvinfo_update)
{
    struct lvinfo_item_entry * entry = (struct lvinfo_item_entry *)item;
    if(!entry) return;
    if(entry->custom_drawing && !can_draw)
    {
        item->custom_drawing = 1;
        return;
    }
    lua_State * L = entry->L;
    struct semaphore * sem = NULL;
169
    if (lua_take_semaphore(L, 50, &sem) == 0)
David Milligan's avatar
David Milligan committed
170
    {
171
        ASSERT(sem);
David Milligan's avatar
David Milligan committed
172
173
174
175
176
177
178
        if(entry->function_ref != LUA_NOREF)
        {
            if(lua_rawgeti(L, LUA_REGISTRYINDEX, entry->function_ref) == LUA_TFUNCTION)
            {
                lua_rawgeti(L, LUA_REGISTRYINDEX, entry->self_ref);
                if(docall(L, 1, 1))
                {
179
                    fprintf(stderr, "[%s] script error:\n %s\n", lua_get_script_filename(L), lua_tostring(L, -1));
180
                    lua_save_last_error(L);
David Milligan's avatar
David Milligan committed
181
182
183
184
185
186
187
188
                }
            }
            lua_pop(L,1);
        }
        give_semaphore(sem);
    }
    else
    {
189
        printf("[%s] semaphore timeout: lv.info.update (%dms)\n", lua_get_script_filename(L), 50);
David Milligan's avatar
David Milligan committed
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
    }
}

static int luaCB_lvinfo_index(lua_State * L);
static int luaCB_lvinfo_newindex(lua_State * L);

/***
 Create a new LV info item
 @tparam table definition A table with the inital values for properties of the item
 @treturn lvinfo
 @function info
 */
static int luaCB_lv_info(lua_State * L)
{
    struct lvinfo_item_entry * entry = lua_newuserdata(L, sizeof(struct lvinfo_item_entry));
    if(!entry) return luaL_error(L, "malloc error");
206
207
208
209
    
    //script created a lvinfo so it can't be unloaded
    lua_set_cant_unload(L, 1, LUA_LVINFO_UNLOAD_MASK);
    
David Milligan's avatar
David Milligan committed
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
    struct lvinfo_item * item = &(entry->item);
    memset(entry, 0, sizeof(struct lvinfo_item_entry));
    lua_pushvalue(L, -1);
    entry->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
    entry->L = L;
    lua_newtable(L);
    lua_pushcfunction(L, luaCB_lvinfo_index);
    lua_setfield(L, -2, "__index");
    lua_pushcfunction(L, luaCB_lvinfo_newindex);
    lua_setfield(L, -2, "__newindex");
    lua_setmetatable(L, -2);
    
    lua_pushvalue(L, 1);
    
    item->name = LUA_FIELD_STRING("name", "unknown");
    item->value = LUA_FIELD_STRING("value", "unknown");
    item->priority = LUA_FIELD_INT("priority", 0);
    item->preferred_position = LUA_FIELD_INT("preferred_position", 0);
228
    item->which_bar = LUA_FIELD_INT("which_bar", LV_WHEREVER_IT_FITS);
David Milligan's avatar
David Milligan committed
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
    entry->custom_drawing = LUA_FIELD_BOOL("custom_drawing", 0);
    
    if(lua_getfield(L, -1, "update") == LUA_TFUNCTION)
    {
        entry->function_ref = luaL_ref(L, LUA_REGISTRYINDEX);
        item->update = lua_lvinfo_update;
    }
    else
    {
        entry->function_ref = LUA_NOREF;
        item->update = NULL;
        lua_pop(L,1);
    }
    
    lvinfo_add_item(item);
    lua_pop(L, 1);
    
    return 1;
}

/***
alex@thinkpad's avatar
alex@thinkpad committed
250
 Represents an info item that is displayed in the ML info bars in LiveView.
David Milligan's avatar
David Milligan committed
251
252
253
254
255
256
257
258
259
260
261
262
 @type lvinfo
 */

static int luaCB_lvinfo_index(lua_State * L)
{
    if(!lua_isuserdata(L, 1)) return luaL_argerror(L, 1, NULL);
    struct lvinfo_item_entry * entry = lua_touserdata(L, 1);
    if(!entry) return luaL_argerror(L, 1, "internal error: userdata was NULL");
    struct lvinfo_item * item = &(entry->item);
    
    LUA_PARAM_STRING_OPTIONAL(key, 2, "");
    
alex@thinkpad's avatar
alex@thinkpad committed
263
    /// Function called before displaying; can override strings, dimensions and so on.
David Milligan's avatar
David Milligan committed
264
265
    // @function update
    if(!strcmp(key, "update")) lua_rawgeti(L, LUA_REGISTRYINDEX, entry->function_ref);
alex@thinkpad's avatar
alex@thinkpad committed
266
    /// Get/Set the item name (for menu).
David Milligan's avatar
David Milligan committed
267
268
    // @tfield string name
    else if(!strcmp(key, "name")) lua_pushstring(L, item->name);
alex@thinkpad's avatar
alex@thinkpad committed
269
    /// Get/Set the item value.
David Milligan's avatar
David Milligan committed
270
271
    // @tfield string value
    else if(!strcmp(key, "value")) lua_pushstring(L, item->value);
alex@thinkpad's avatar
alex@thinkpad committed
272
    /// Get/Set the item background color.
David Milligan's avatar
David Milligan committed
273
274
    // @tfield int background see @{constants.COLOR}
    else if(!strcmp(key, "background")) lua_pushinteger(L, item->color_bg);
alex@thinkpad's avatar
alex@thinkpad committed
275
    /// Get/Set the item foreground color.
David Milligan's avatar
David Milligan committed
276
277
    // @tfield int foreground see @{constants.COLOR}
    else if(!strcmp(key, "foreground")) lua_pushinteger(L, item->color_fg);
alex@thinkpad's avatar
alex@thinkpad committed
278
    /// Get/Set whether the item uses custom drawing.
David Milligan's avatar
David Milligan committed
279
280
    // @tfield bool custom_drawing
    else if(!strcmp(key, "custom_drawing")) lua_pushboolean(L, entry->custom_drawing);
alex@thinkpad's avatar
alex@thinkpad committed
281
282
    /// Get the item font assigned by the backend.
    // @tfield int font readonly see @{constants.FONT}
David Milligan's avatar
David Milligan committed
283
    else if(!strcmp(key, "font")) lua_pushinteger(L, item->fontspec);
alex@thinkpad's avatar
alex@thinkpad committed
284
    /// Get/Set the item height.
David Milligan's avatar
David Milligan committed
285
286
    // @tfield int height
    else if(!strcmp(key, "height")) lua_pushinteger(L, item->height);
alex@thinkpad's avatar
alex@thinkpad committed
287
288
    /// Get/Set the item's preferred horizontal position (signed integer, look up other `struct lvinfo_item` items in ML source code).
    // @tfield[opt=0] int preferred_position
David Milligan's avatar
David Milligan committed
289
    else if(!strcmp(key, "preferred_position")) lua_pushinteger(L, item->preferred_position);
alex@thinkpad's avatar
alex@thinkpad committed
290
291
    /// Get/Set the item priority: if there's not enough space, the items with low priority will disappear.
    // @tfield[opt=0] int priority
David Milligan's avatar
David Milligan committed
292
    else if(!strcmp(key, "priority")) lua_pushinteger(L, item->priority);
alex@thinkpad's avatar
alex@thinkpad committed
293
294
295
    /// Get/Set the which bar the item appears on (see enum lvinfo_bar in lvinfo.h).
    ///
    /// TODO: constants.
296
    // @tfield[opt=anywhere] int bar
David Milligan's avatar
David Milligan committed
297
    else if(!strcmp(key, "bar")) lua_pushinteger(L, item->which_bar);
alex@thinkpad's avatar
alex@thinkpad committed
298
299
300
    /// Get/Set the item width; default: measured from value and fontspec.
    ///
    /// 0 = do not display this item at all.
David Milligan's avatar
David Milligan committed
301
302
    // @tfield int width
    else if(!strcmp(key, "width")) lua_pushinteger(L, item->width);
alex@thinkpad's avatar
alex@thinkpad committed
303
304
    /// Get the item x position.
    // @tfield int x readonly
David Milligan's avatar
David Milligan committed
305
    else if(!strcmp(key, "x")) lua_pushinteger(L, item->x);
alex@thinkpad's avatar
alex@thinkpad committed
306
307
    /// Get the item y position.
    // @tfield int y readonly
David Milligan's avatar
David Milligan committed
308
309
310
311
312
    else if(!strcmp(key, "y")) lua_pushinteger(L, item->y);
    else lua_rawget(L, 1);
    return 1;
}

313
314
315
316
317
318
static void set_string(char ** entry, const char * value)
{
    if(*entry) free(*entry);
    *entry = copy_string(value);
}

David Milligan's avatar
David Milligan committed
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
static int luaCB_lvinfo_newindex(lua_State * L)
{
    if(!lua_isuserdata(L, 1)) return luaL_argerror(L, 1, NULL);
    struct lvinfo_item_entry * entry = lua_touserdata(L, 1);
    if(!entry) return luaL_argerror(L, 1, "internal error: userdata was NULL");
    struct lvinfo_item * item = &(entry->item);
    
    LUA_PARAM_STRING_OPTIONAL(key, 2, "");
    
    if(!strcmp(key, "update"))
    {
        if(entry->function_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, entry->function_ref);
        if(!lua_isfunction(L, 3))
        {
            entry->function_ref = LUA_NOREF;
            item->update = NULL;
        }
        else
        {
            entry->function_ref = luaL_ref(L, LUA_REGISTRYINDEX);
            item->update = lua_lvinfo_update;
        }
    }
    else if(!strcmp(key, "name"))
    {
        LUA_PARAM_STRING(value, 3);
345
        set_string(&(item->name),value);
David Milligan's avatar
David Milligan committed
346
347
348
349
    }
    else if(!strcmp(key, "value"))
    {
        LUA_PARAM_STRING(value, 3);
350
        set_string(&(item->value),value);
David Milligan's avatar
David Milligan committed
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
    }
    else if(!strcmp(key, "background"))
    {
        LUA_PARAM_INT(value, 3);
        item->color_bg = value;
    }
    else if(!strcmp(key, "foreground"))
    {
        LUA_PARAM_INT(value, 3);
        item->color_fg = value;
    }
    else if(!strcmp(key, "custom_drawing"))
    {
        LUA_PARAM_BOOL(value, 3);
        entry->custom_drawing = value;
    }
    else if(!strcmp(key, "height"))
    {
        LUA_PARAM_INT(value, 3);
        item->height = value;
    }
    else if(!strcmp(key, "preferred_position"))
    {
        LUA_PARAM_INT(value, 3);
        item->preferred_position = value;
    }
    else if(!strcmp(key, "priority"))
    {
        LUA_PARAM_INT(value, 3);
        item->priority = value;
    }
    else if(!strcmp(key, "bar"))
    {
        LUA_PARAM_INT(value, 3);
        item->which_bar = value;
    }
    else
    {
        lua_rawset(L, 1);
    }
    return 0;
}

394
395
396
static const char * lua_lv_fields[] =
{
    "enabled",
397
398
399
    "paused",
    "running",
    "zoom",
400
    "overlays",
401
402
403
    NULL
};

404
405
406
407
408
409
static const luaL_Reg lvlib[] =
{
    { "start", luaCB_lv_start },
    { "pause", luaCB_lv_pause },
    { "resume", luaCB_lv_resume },
    { "stop", luaCB_lv_stop },
410
    { "wait", luaCB_lv_wait },
David Milligan's avatar
David Milligan committed
411
    { "info", luaCB_lv_info },
412
413
414
    { NULL, NULL }
};

415
LUA_LIB(lv)