naev 0.10.4
nlua_tk.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include <lauxlib.h>
11#include <stdlib.h>
12
13#include "naev.h"
16#include "nlua_tk.h"
17
18#include "array.h"
19#include "dialogue.h"
20#include "input.h"
21#include "land.h"
22#include "land_outfits.h"
23#include "log.h"
24#include "nlua_colour.h"
25#include "nlua_gfx.h"
26#include "nlua_outfit.h"
27#include "nluadef.h"
28#include "toolkit.h"
29
30/* Stuff for the custom toolkit. */
31#define TK_CUSTOMDONE "__customDone"
32typedef struct custom_functions_s {
33 lua_State *L;
34 int done;
35 /* Function references. */
36 int update;
37 int draw;
38 int keyboard;
39 int mouse;
40 int resize;
41 int textinput;
43static int cust_update( double dt, void* data );
44static void cust_render( double x, double y, double w, double h, void* data );
45static int cust_event( unsigned int wid, SDL_Event *event, void* data );
46static int cust_key( SDL_Keycode key, SDL_Keymod mod, int pressed, custom_functions_t *cf );
47static int cust_text( const char *str, custom_functions_t *cf );
48static int cust_mouse( int type, int button, double x, double y, custom_functions_t *cf );
49static int cust_event_window( SDL_WindowEventID event, Sint32 w, Sint32 h, custom_functions_t *cf );
50
51/* Toolkit methods. */
52static int tkL_isOpen( lua_State *L );
53static int tkL_query( lua_State *L );
54static int tkL_msg( lua_State *L );
55static int tkL_yesno( lua_State *L );
56static int tkL_input( lua_State *L );
57static int tkL_choice( lua_State *L );
58static int tkL_list( lua_State *L );
59static int tkL_merchantOutfit( lua_State *L );
60static int tkL_custom( lua_State *L );
61static int tkL_customRename( lua_State *L );
62static int tkL_customFullscreen( lua_State *L );
63static int tkL_customResize( lua_State *L );
64static int tkL_customSize( lua_State *L );
65static int tkL_customDone( lua_State *L );
66static const luaL_Reg tkL_methods[] = {
67 { "isOpen", tkL_isOpen },
68 { "query", tkL_query },
69 { "msg", tkL_msg },
70 { "yesno", tkL_yesno },
71 { "input", tkL_input },
72 { "choice", tkL_choice },
73 { "list", tkL_list },
74 { "merchantOutfit", tkL_merchantOutfit },
75 { "custom", tkL_custom },
76 { "customRename", tkL_customRename },
77 { "customFullscreen", tkL_customFullscreen },
78 { "customResize", tkL_customResize },
79 { "customSize", tkL_customSize },
80 { "customDone", tkL_customDone },
81 {0,0}
82};
90int nlua_loadTk( nlua_env env )
91{
92 nlua_register(env, "tk", tkL_methods, 0);
93 nlua_loadCol(env);
94 nlua_loadGFX(env);
95 return 0;
96}
97
123static int tkL_isOpen( lua_State *L )
124{
125 lua_pushboolean(L,toolkit_isOpen());
126 return 1;
127}
128
140static int tkL_query( lua_State *L )
141{
142 const char *wdwname, *wgtname;
143 unsigned int wid;
144 int bx, by, x, y, w, h;
145 wdwname = luaL_checkstring( L, 1 );
146 wgtname = luaL_optstring( L, 2, NULL );
147 wid = window_get( wdwname );
148 if (wid == 0)
149 return 0;
150 window_posWindow( wid, &bx, &by );
151 if (wgtname == NULL) {
152 x = bx;
153 y = by;
154 window_dimWindow( wid, &w, &h );
155 }
156 else {
157 window_posWidget( wid, wgtname, &x, &y );
158 window_dimWidget( wid, wgtname, &w, &h );
159 x += bx;
160 y += by;
161 }
162 lua_pushinteger( L, x );
163 lua_pushinteger( L, y );
164 lua_pushinteger( L, w );
165 lua_pushinteger( L, h );
166 return 4;
167}
168
182static int tkL_msg( lua_State *L )
183{
184 const char *title, *str, *img;
185 int width, height;
186
187 // Get fixed arguments : title, string to display and image filename
188 title = luaL_checkstring(L,1);
189 str = luaL_checkstring(L,2);
190
191 if (lua_gettop(L) > 2) {
192 img = luaL_checkstring(L,3);
193
194 // Get optional arguments : width and height
195 width = (lua_gettop(L) < 4) ? -1 : luaL_checkinteger(L,4);
196 height = (lua_gettop(L) < 5) ? -1 : luaL_checkinteger(L,5);
197
198 dialogue_msgImgRaw( title, str, img, width, height );
199 return 0;
200 }
201 dialogue_msgRaw( title, str );
202 return 0;
203}
214static int tkL_yesno( lua_State *L )
215{
216 int ret;
217 const char *title, *str;
218
219 title = luaL_checkstring(L,1);
220 str = luaL_checkstring(L,2);
221
222 ret = dialogue_YesNoRaw( title, str );
223 lua_pushboolean(L,ret);
224 return 1;
225}
238static int tkL_input( lua_State *L )
239{
240 const char *title, *str;
241 char *ret;
242 int min, max;
243
244 title = luaL_checkstring(L,1);
245 min = luaL_checkint(L,2);
246 max = luaL_checkint(L,3);
247 str = luaL_checkstring(L,4);
248
249 ret = dialogue_inputRaw( title, min, max, str );
250 if (ret != NULL) {
251 lua_pushstring(L, ret);
252 free(ret);
253 }
254 else
255 lua_pushnil(L);
256 return 1;
257}
258
271static int tkL_choice( lua_State *L )
272{
273 int ret, opts;
274 const char *title, *str;
275 char *result;
276
277 /* Handle parameters. */
278 opts = lua_gettop(L) - 2;
279 title = luaL_checkstring(L,1);
280 str = luaL_checkstring(L,2);
281
282 /* Do an initial scan for invalid arguments. */
283 for (int i=0; i<opts; i++)
284 luaL_checkstring(L, i+3);
285
286 /* Create dialogue. */
287 dialogue_makeChoice( title, str, opts );
288 for (int i=0; i<opts; i++)
289 dialogue_addChoice( title, str, luaL_checkstring(L,i+3) );
290 result = dialogue_runChoice();
291 if (result == NULL) /* Something went wrong, return nil. */
292 return 0;
293
294 /* Handle results. */
295 ret = -1;
296 for (int i=0; i<opts && ret==-1; i++) {
297 if (strcmp(result, luaL_checkstring(L,i+3)) == 0)
298 ret = i+1; /* Lua uses 1 as first index. */
299 }
300
301 /* Push parameters. */
302 lua_pushnumber(L,ret);
303 lua_pushstring(L,result);
304
305 /* Clean up. */
306 free(result);
307
308 return 2;
309}
310
323static int tkL_list( lua_State *L )
324{
325 int ret, opts;
326 const char *title, *str;
327 char **choices;
328 NLUA_MIN_ARGS(3);
329
330 /* Handle parameters. */
331 opts = lua_gettop(L) - 2;
332 title = luaL_checkstring(L,1);
333 str = luaL_checkstring(L,2);
334
335 /* Do an initial scan for invalid arguments. */
336 for (int i=0; i<opts; i++)
337 luaL_checkstring(L, i+3);
338
339 /* Will be freed by the toolkit. */
340 choices = malloc( sizeof(char*) * opts );
341 for (int i=0; i<opts; i++)
342 choices[i] = strdup( luaL_checkstring(L, i+3) );
343
344 ret = dialogue_listRaw( title, choices, opts, str );
345
346 /* Cancel returns -1, do nothing. */
347 if (ret == -1)
348 return 0;
349
350 /* Push index and choice string. */
351 lua_pushnumber(L, ret+1);
352 lua_pushstring(L, choices[ret]);
353
354 return 2;
355}
356
367static int tkL_merchantOutfit( lua_State *L )
368{
369 const Outfit **outfits;
370 unsigned int wid;
371 const char *name;
372 int w, h;
373
374 name = luaL_checkstring(L,1);
375
376 if (!lua_istable(L,2))
377 NLUA_INVALID_PARAMETER(L);
378
379 outfits = array_create_size( const Outfit*, lua_objlen(L,2) );
380 /* Iterate over table. */
381 lua_pushnil(L);
382 while (lua_next(L, -2) != 0) {
383 array_push_back( &outfits, luaL_validoutfit(L, -1) );
384 lua_pop(L,1);
385 }
386
387 /* Create window. */
388 if (SCREEN_W < LAND_WIDTH || SCREEN_H < LAND_HEIGHT) {
389 w = -1; /* Fullscreen. */
390 h = -1;
391 }
392 else {
393 w = LAND_WIDTH + 0.5 * (SCREEN_W - LAND_WIDTH);
394 h = LAND_HEIGHT + 0.5 * (SCREEN_H - LAND_HEIGHT);
395 }
396 wid = window_create( "wdwMerchantOutfit", name, -1, -1, w, h );
397 outfits_open( wid, outfits );
398
399 return 0;
400}
401
416static int tkL_custom( lua_State *L )
417{
418 int w = luaL_checkinteger(L, 2);
419 int h = luaL_checkinteger(L, 3);
420 const char *caption = luaL_checkstring(L, 1);
421 custom_functions_t *cf = calloc( 1, sizeof(custom_functions_t) );
422
423 /* Set up custom function pointers. */
424 cf->L = L;
425#define GETFUNC( address, pos ) \
426do { \
427 lua_pushvalue( L, (pos) ); \
428 luaL_checktype(L, -1, LUA_TFUNCTION); \
429 (address) = luaL_ref(L, LUA_REGISTRYINDEX); \
430} while (0)
431 GETFUNC( cf->update, 4 );
432 GETFUNC( cf->draw, 5 );
433 GETFUNC( cf->keyboard, 6 );
434 GETFUNC( cf->mouse, 7 );
435 GETFUNC( cf->resize, 8 );
436 GETFUNC( cf->textinput, 9 );
437#undef GETFUNC
438
439 /* Set done condition. */
440 lua_pushboolean(L, 0);
441 lua_setglobal(L, TK_CUSTOMDONE );
442
443 /* Create the dialogue. */
444 dialogue_custom( caption, w, h, cust_update, cust_render, cust_event, cf, 1 );
445
446 /* Clean up. */
447 cf->done = 1;
448 luaL_unref(L, LUA_REGISTRYINDEX, cf->update);
449 luaL_unref(L, LUA_REGISTRYINDEX, cf->draw);
450 luaL_unref(L, LUA_REGISTRYINDEX, cf->keyboard);
451 luaL_unref(L, LUA_REGISTRYINDEX, cf->mouse);
452 luaL_unref(L, LUA_REGISTRYINDEX, cf->resize);
453 luaL_unref(L, LUA_REGISTRYINDEX, cf->textinput);
454
455 return 0;
456}
457
464static int tkL_customRename( lua_State *L )
465{
466 const char *s = luaL_checkstring(L,1);
467 unsigned int wid = window_get( "dlgMsg" );
468 if (wid == 0)
469 NLUA_ERROR(L, _("custom dialogue not open"));
470 window_setDisplayname( wid, s );
471 return 0;
472}
473
480static int tkL_customFullscreen( lua_State *L )
481{
482 int enable = lua_toboolean(L,1);
483 unsigned int wid = window_get( "dlgMsg" );
484 if (wid == 0)
485 NLUA_ERROR(L, _("custom dialogue not open"));
487 return 0;
488}
489
497static int tkL_customResize( lua_State *L )
498{
499 int w, h;
500 unsigned int wid = window_get( "dlgMsg" );
501 if (wid == 0)
502 NLUA_ERROR(L, _("custom dialogue not open"));
503 w = luaL_checkinteger(L,1);
504 h = luaL_checkinteger(L,2);
505 dialogue_customResize( w, h );
506 return 0;
507}
508
516static int tkL_customSize( lua_State *L )
517{
518 int w, h;
519 unsigned int wid = window_get( "dlgMsg" );
520 if (wid == 0)
521 NLUA_ERROR(L, _("custom dialogue not open"));
522 window_dimWindow( wid, &w, &h );
523 lua_pushinteger(L,w);
524 lua_pushinteger(L,h);
525 return 2;
526}
527
532static int tkL_customDone( lua_State *L )
533{
534 unsigned int wid = window_get( "dlgMsg" );
535 if (wid == 0)
536 NLUA_ERROR(L, _("custom dialogue not open"));
537 lua_pushboolean(L, 1);
538 lua_setglobal(L, TK_CUSTOMDONE );
539 return 0;
540}
541
542static int cust_pcall( lua_State *L, int nargs, int nresults )
543{
544 int errf, ret;
545
546#if DEBUGGING
547 errf = lua_gettop(L) - nargs;
548 lua_pushcfunction(L, nlua_errTrace);
549 lua_insert(L, errf);
550#else /* DEBUGGING */
551 errf = 0;
552#endif /* DEBUGGING */
553
554 ret = lua_pcall( L, nargs, nresults, errf );
555
556#if DEBUGGING
557 lua_remove(L, errf);
558#endif /* DEBUGGING */
559
560 return ret;
561}
562static int cust_update( double dt, void* data )
563{
564 int ret;
566 if (cf->done)
567 return 1; /* Mark done. */
568 lua_State *L = cf->L;
569 lua_rawgeti(L, LUA_REGISTRYINDEX, cf->update);
570 lua_pushnumber(L, dt);
571 if (cust_pcall( L, 1, 0 )) {
572 cf->done = 1;
573 WARN(_("Custom dialogue internal error: %s"), lua_tostring(L,-1));
574 lua_pop(L,1);
575 return 1;
576 }
577 /* Check if done. */
578 lua_getglobal(L, TK_CUSTOMDONE );
579 ret = lua_toboolean(L, -1);
580 lua_pop(L, 1);
581 return ret;
582}
583static void cust_render( double x, double y, double w, double h, void* data )
584{
586 if (cf->done)
587 return;
588 lua_State *L = cf->L;
589 lua_rawgeti(L, LUA_REGISTRYINDEX, cf->draw);
590 lua_pushnumber(L, x);
591 lua_pushnumber(L, y);
592 lua_pushnumber(L, w);
593 lua_pushnumber(L, h);
594 if (cust_pcall( L, 4, 0 )) {
595 cf->done = 1;
596 WARN(_("Custom dialogue internal error: %s"), lua_tostring(L,-1));
597 lua_pop(L,1);
598 }
599}
600static int cust_event( unsigned int wid, SDL_Event *event, void* data )
601{
602 (void) wid;
603 double x, y;
605 if (cf->done)
606 return 0;
607
608 /* Handle all the events. */
609 switch (event->type) {
610 case SDL_MOUSEBUTTONDOWN:
611 x = gl_screen.x;
612 y = gl_screen.y;
613 return cust_mouse( 1, event->button.button, event->button.x+x, event->button.y+y, cf );
614 case SDL_MOUSEBUTTONUP:
615 x = gl_screen.x;
616 y = gl_screen.y;
617 return cust_mouse( 2, event->button.button, event->button.x+x, event->button.y+y, cf );
618 case SDL_MOUSEMOTION:
619 x = gl_screen.x;
620 y = gl_screen.y;
621 return cust_mouse( 3, -1, event->button.x+x, event->button.y+y, cf );
622 case SDL_MOUSEWHEEL:
623 return cust_mouse( 4, -1, event->wheel.x, event->wheel.y, cf );
624
625 case SDL_KEYDOWN:
626 return cust_key( event->key.keysym.sym, event->key.keysym.mod, 1, cf );
627 case SDL_KEYUP:
628 return cust_key( event->key.keysym.sym, event->key.keysym.mod, 0, cf );
629
630 case SDL_TEXTINPUT:
631 return cust_text( event->text.text, cf );
632
633 case SDL_WINDOWEVENT:
634 return cust_event_window( event->window.event, event->window.data1, event->window.data2, cf );
635
636 default:
637 return 0;
638 }
639
640 return 0;
641}
642static int cust_key( SDL_Keycode key, SDL_Keymod mod, int pressed, custom_functions_t *cf )
643{
644 int b;
645 lua_State *L = cf->L;
646 lua_rawgeti(L, LUA_REGISTRYINDEX, cf->keyboard);
647 lua_pushboolean(L, pressed );
648 lua_pushstring(L, SDL_GetKeyName(key));
649 lua_pushstring(L, input_modToText(mod));
650 if (cust_pcall( L, 3, 1 )) {
651 cf->done = 1;
652 WARN(_("Custom dialogue internal error: %s"), lua_tostring(L,-1));
653 lua_pop(L,1);
654 return 0;
655 }
656 b = lua_toboolean(L, -1);
657 lua_pop(L,1);
658 return b;
659}
660static int cust_text( const char *str, custom_functions_t *cf )
661{
662 int b;
663 lua_State *L = cf->L;
664 lua_rawgeti(L, LUA_REGISTRYINDEX, cf->textinput);
665 lua_pushstring(L, str);
666 if (cust_pcall( L, 1, 1 )) {
667 cf->done = 1;
668 WARN(_("Custom dialogue internal error: %s"), lua_tostring(L,-1));
669 lua_pop(L,1);
670 return 0;
671 }
672 b = lua_toboolean(L, -1);
673 lua_pop(L,1);
674 return b;
675}
676static int cust_mouse( int type, int button, double x, double y, custom_functions_t *cf )
677{
678 int b, nargs = 3;
679 lua_State *L = cf->L;
680 lua_rawgeti(L, LUA_REGISTRYINDEX, cf->mouse);
681 lua_pushnumber(L, x);
682 lua_pushnumber(L, y);
683 lua_pushnumber(L, type);
684 if (type < 3) {
685 switch (button) {
686 case SDL_BUTTON_LEFT: button=1; break;
687 case SDL_BUTTON_RIGHT: button=2; break;
688 default: button=3; break;
689 }
690 lua_pushnumber(L, button);
691 nargs++;
692 }
693 if (cust_pcall( L, nargs, 1 )) {
694 cf->done = 1;
695 WARN(_("Custom dialogue internal error: %s"), lua_tostring(L,-1));
696 lua_pop(L,1);
697 return 0;
698 }
699 b = lua_toboolean(L, -1);
700 lua_pop(L,1);
701 return b;
702}
703static int cust_event_window( SDL_WindowEventID event, Sint32 w, Sint32 h, custom_functions_t *cf )
704{
705 int b;
706 lua_State *L = cf->L;
707
708 if (event == SDL_WINDOWEVENT_RESIZED)
709 return 1;
710
711 lua_rawgeti(L, LUA_REGISTRYINDEX, cf->resize);
712 lua_pushinteger(L, w );
713 lua_pushinteger(L, h );
714 if (cust_pcall( L, 2, 1 )) {
715 cf->done = 1;
716 WARN(_("Custom dialogue internal error: %s"), lua_tostring(L,-1));
717 lua_pop(L,1);
718 return 0;
719 }
720 b = lua_toboolean(L, -1);
721 lua_pop(L,1);
722 return b;
723}
Provides macros to work with dynamic arrays.
#define array_create_size(basic_type, capacity)
Creates a new dynamic array of ‘basic_type’ with an initial capacity.
Definition: array.h:102
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition: array.h:129
char * dialogue_runChoice(void)
Run the dialog and return the clicked string.
Definition: dialogue.c:792
char * dialogue_inputRaw(const char *title, int min, int max, const char *msg)
Creates a dialogue that allows the player to write a message.
Definition: dialogue.c:465
int dialogue_listRaw(const char *title, char **items, int nitems, const char *msg)
Creates a list dialogue with OK and Cancel button.
Definition: dialogue.c:600
int dialogue_YesNoRaw(const char *caption, const char *msg)
Runs a dialogue with both yes and no options.
Definition: dialogue.c:366
void dialogue_custom(const char *caption, int width, int height, int(*update)(double dt, void *data), void(*render)(double x, double y, double w, double h, void *data), int(*event)(unsigned int wid, SDL_Event *event, void *data), void *data, int autofree)
Opens a custom dialogue window.
Definition: dialogue.c:863
void dialogue_addChoice(const char *caption, const char *msg, const char *opt)
Add a choice to the dialog.
Definition: dialogue.c:770
int dialogue_customResize(int width, int height)
Resizes a custom dialogue.
Definition: dialogue.c:964
void dialogue_msgImgRaw(const char *caption, const char *msg, const char *img, int width, int height)
Opens a dialogue window with an ok button, a fixed message and an image.
Definition: dialogue.c:290
void dialogue_makeChoice(const char *caption, const char *msg, int opts)
Create the choice dialog. Need to add choices with below method.
Definition: dialogue.c:748
void dialogue_msgRaw(const char *caption, const char *msg)
Opens a dialogue window with an ok button and a fixed message.
Definition: dialogue.c:261
int dialogue_customFullscreen(int enable)
Converts a custom dialogue to fullscreen.
Definition: dialogue.c:927
const char * input_modToText(SDL_Keymod mod)
Gets the human readable version of mod.
Definition: input.c:521
void outfits_open(unsigned int wid, const Outfit **outfits)
Opens the outfit exchange center window.
Definition: land_outfits.c:117
Header file with generic functions and naev-specifics.
int nlua_errTrace(lua_State *L)
Gets a trace from Lua.
Definition: nlua.c:792
int nlua_loadCol(nlua_env env)
Loads the colour library.
Definition: nlua_colour.c:52
int nlua_loadGFX(nlua_env env)
Loads the graphics library.
Definition: nlua_gfx.c:97
const Outfit * luaL_validoutfit(lua_State *L, int ind)
Makes sure the outfit is valid or raises a Lua error.
Definition: nlua_outfit.c:135
static int tkL_customSize(lua_State *L)
Gets the size of a custom widget.
Definition: nlua_tk.c:516
static int tkL_customRename(lua_State *L)
Renames the custom widget window.
Definition: nlua_tk.c:464
static int tkL_isOpen(lua_State *L)
Bindings for interacting with the Toolkit.
Definition: nlua_tk.c:123
static const luaL_Reg tkL_methods[]
Definition: nlua_tk.c:66
static int tkL_msg(lua_State *L)
Creates a window with an ok button, and optionally an image.
Definition: nlua_tk.c:182
int nlua_loadTk(nlua_env env)
Loads the Toolkit Lua library.
Definition: nlua_tk.c:90
static int tkL_input(lua_State *L)
Creates a window that allows player to write text input.
Definition: nlua_tk.c:238
static int tkL_choice(lua_State *L)
Creates a window with a number of selectable options.
Definition: nlua_tk.c:271
static int tkL_query(lua_State *L)
Gets the position and dimensions of either a window or a widget.
Definition: nlua_tk.c:140
static int tkL_yesno(lua_State *L)
Displays a window with Yes and No buttons.
Definition: nlua_tk.c:214
static int tkL_customFullscreen(lua_State *L)
Sets the custom widget fullscreen.
Definition: nlua_tk.c:480
static int tkL_list(lua_State *L)
Creates a window with an embedded list of choices.
Definition: nlua_tk.c:323
static int tkL_customDone(lua_State *L)
Ends the execution of a custom widget.
Definition: nlua_tk.c:532
static int tkL_customResize(lua_State *L)
Sets the custom widget fullscreen.
Definition: nlua_tk.c:497
static int tkL_merchantOutfit(lua_State *L)
Opens an outfit merchant window.
Definition: nlua_tk.c:367
static int tkL_custom(lua_State *L)
Creates a custom widget window.
Definition: nlua_tk.c:416
glInfo gl_screen
Definition: opengl.c:51
static const double b[]
Definition: rng.c:256
A ship outfit, depends radically on the type.
Definition: outfit.h:304
lua_State * L
Definition: nlua_tk.c:33
int y
Definition: opengl.h:38
int x
Definition: opengl.h:37
unsigned int window_create(const char *name, const char *displayname, const int x, const int y, const int w, const int h)
Creates a window.
Definition: toolkit.c:696
void window_dimWidget(unsigned int wid, const char *name, int *w, int *h)
Gets the dimensions of a widget.
Definition: toolkit.c:416
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition: toolkit.c:371
int toolkit_isOpen(void)
Checks to see if the toolkit is open.
Definition: toolkit.c:95
void window_posWidget(unsigned int wid, const char *name, int *x, int *y)
Gets a widget's position.
Definition: toolkit.c:442
unsigned int window_get(const char *wdwname)
Gets the ID of a window.
Definition: toolkit.c:671
void window_posWindow(unsigned int wid, int *x, int *y)
Gets the dimensions of a window.
Definition: toolkit.c:393
int window_setDisplayname(unsigned int wid, const char *displayname)
Sets the displayname of a window.
Definition: toolkit.c:631