naev 0.12.6
dev_uniedit.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "SDL_events.h"
11
12#include "naev.h"
14
15#include <ctype.h>
16#include <libgen.h>
17#include <unistd.h>
18
19#include "dev_uniedit.h"
20
21#include "array.h"
22#include "conf.h"
23#include "dev_diff.h"
24#include "dev_spob.h"
25#include "dev_sysedit.h"
26#include "dev_system.h"
27#include "dialogue.h"
28#include "economy.h"
29#include "map.h"
30#include "map_find.h"
31#include "ndata.h"
32#include "nfile.h"
33#include "nstring.h"
34#include "opengl.h"
35#include "pause.h"
36#include "safelanes.h"
37#include "space.h"
38#include "tk/toolkit_priv.h"
39#include "toolkit.h"
40#include "unidiff.h"
41#include "utf8.h"
42
43#define BUTTON_WIDTH 100
44#define BUTTON_HEIGHT 30
45
46#define UNIEDIT_EDIT_WIDTH 400
47#define UNIEDIT_EDIT_HEIGHT 450
48
49#define UNIEDIT_FIND_WIDTH 400
50#define UNIEDIT_FIND_HEIGHT 500
51
52#define UNIEDIT_DRAG_THRESHOLD 300
53#define UNIEDIT_MOVE_THRESHOLD 10
54#define UNIEDIT_CLICK_THRESHOLD 20.
55#define UNIEDIT_DOUBLECLICK_THRESHOLD 300
56
57#define UNIEDIT_ZOOM_STEP 1.2
58#define UNIEDIT_ZOOM_MAX 5.
59#define UNIEDIT_ZOOM_MIN -5.
60
61/*
62 * The editor modes.
63 */
71
72typedef enum UniEditViewMode_ {
73 UNIEDIT_VIEW_DEFAULT,
74 UNIEDIT_VIEW_VIRTUALSPOBS,
75 UNIEDIT_VIEW_RADIUS,
76 UNIEDIT_VIEW_NOLANES,
77 UNIEDIT_VIEW_BACKGROUND,
78 UNIEDIT_VIEW_ASTEROIDS,
79 UNIEDIT_VIEW_INTERFERENCE,
80 UNIEDIT_VIEW_TECH,
81 UNIEDIT_VIEW_PRESENCE_SUM,
82 UNIEDIT_VIEW_PRESENCE,
83} UniEditViewMode;
84
85extern StarSystem *systems_stack;
86
87int uniedit_diffMode = 0;
88int uniedit_diffSaved = 0;
89static UniHunk_t *uniedit_diff = NULL;
91static UniEditViewMode uniedit_viewmode =
92 UNIEDIT_VIEW_DEFAULT;
93static int uniedit_view_faction = -1;
94static unsigned int uniedit_wid = 0;
95static unsigned int uniedit_widEdit = 0;
96static unsigned int uniedit_widFind = 0;
97static double uniedit_xpos = 0.;
98static double uniedit_ypos = 0.;
99static double uniedit_zoom = 1.;
100static int uniedit_moved = 0;
101static unsigned int uniedit_lastClick = 0;
102static int uniedit_drag = 0;
103static int uniedit_dragSys = 0;
104static int uniedit_dragSel = 0;
105static double uniedit_dragSelX =
106 0;
107static double uniedit_dragSelY =
108 0;
109static double uniedit_rotate = 0.;
110static double uniedit_rotate_cx = 0.;
111static double uniedit_rotate_cy = 0.;
112static StarSystem **uniedit_sys = NULL;
113static StarSystem *uniedit_tsys = NULL;
114static int uniedit_tadd = 0;
115static double uniedit_mx = 0.;
116static double uniedit_my = 0.;
117static double uniedit_dt = 0.;
118static char **uniedit_tagslist = NULL;
119
120static map_find_t *found_cur = NULL;
121static int found_ncur = 0;
122
123/*
124 * Universe editor Prototypes.
125 */
126/* Selection. */
127static void uniedit_deselect( void );
128static void uniedit_selectAdd( StarSystem *sys );
129static void uniedit_selectRm( StarSystem *sys );
130/* System and spob search. */
131static void uniedit_findSys( void );
132static void uniedit_findSysClose( unsigned int wid, const char *name );
133static void uniedit_findSearch( unsigned int wid, const char *str );
134static void uniedit_findShowResults( unsigned int wid, map_find_t *found,
135 int n );
136static void uniedit_centerSystem( unsigned int wid, const char *unused );
137static int uniedit_sortCompare( const void *p1, const void *p2 );
138/* Options. */;
139static void uniedit_options_setpath( unsigned int wid, const char *unused );
140static void uniedit_options_close( unsigned int wid, const char *unused );
141/* System editing. */
142static void uniedit_editSys( void );
143static void uniedit_editSysClose( unsigned int wid, const char *name );
144static void uniedit_editGenList( unsigned int wid );
145static void uniedit_btnEditRename( unsigned int wid, const char *unused );
146static void uniedit_btnEditRmSpob( unsigned int wid, const char *unused );
147static void uniedit_btnEditAddSpob( unsigned int wid, const char *unused );
148static void uniedit_btnEditAddSpobAdd( unsigned int wid, const char *unused );
149static void uniedit_btnViewModeSet( unsigned int wid, const char *unused );
150static void uniedit_chkNolanes( unsigned int wid, const char *wgtname );
151/* System renaming. */
152static int uniedit_checkName( const char *name );
153static void uniedit_renameSys( void );
154/* New system. */
155static void uniedit_newSys( double x, double y );
156/* Jump handling. */
157static void uniedit_toggleJump( StarSystem *sys );
158/* Tags. */
159static void uniedit_btnEditTags( unsigned int wid, const char *unused );
160static void uniedit_genTagsList( unsigned int wid );
161static void uniedit_btnAddTag( unsigned int wid, const char *unused );
162static void uniedit_btnRmTag( unsigned int wid, const char *unused );
163static void uniedit_btnNewTag( unsigned int wid, const char *unused );
164static void uniedit_btnTagsClose( unsigned int wid, const char *unused );
165/* Custom system editor widget. */
166static void uniedit_buttonZoom( unsigned int wid, const char *str );
167static void uniedit_render( double bx, double by, double w, double h,
168 void *data );
169static void uniedit_renderOverlay( double bx, double by, double bw, double bh,
170 void *data );
171static void uniedit_focusLose( unsigned int wid, const char *wgtname );
172static int uniedit_mouse( unsigned int wid, const SDL_Event *event, double mx,
173 double my, double w, double h, double rx, double ry,
174 void *data );
175static void uniedit_renderFactionDisks( double x, double y, double r );
176static void uniedit_renderVirtualSpobs( double x, double y, double r );
177/* Button functions. */
178static void uniedit_close( unsigned int wid, const char *wgt );
179static void uniedit_save( unsigned int wid_unused, const char *unused );
180static void uniedit_btnView( unsigned int wid_unused, const char *unused );
181static void uniedit_btnJump( unsigned int wid_unused, const char *unused );
182static void uniedit_btnEdit( unsigned int wid_unused, const char *unused );
183static void uniedit_btnNew( unsigned int wid_unused, const char *unused );
184static void uniedit_btnOpen( unsigned int wid_unused, const char *unused );
185static void uniedit_btnFind( unsigned int wid_unused, const char *unused );
186/* Keybindings handling. */
187static int uniedit_keys( unsigned int wid, SDL_Keycode key, SDL_Keymod mod,
188 int isrepeat );
189/* Diffs. */
190static void uniedit_diffEditor( unsigned int wid_unused, const char *unused );
191static void uniedit_diff_toggle( unsigned int wid, const char *wgt );
192static void uniedit_diff_load( unsigned int wid, const char *wgt );
193static void uniedit_diff_remove( unsigned int wid, const char *wgt );
194static void uniedit_diff_close( unsigned int wid, const char *unused );
195static void uniedit_diffSsysPos( StarSystem *s, double x, double y );
196static void uniedit_diffClear( void );
197/* Misc. */
198static void uniedit_saveTest( void );
199
203void uniedit_open( unsigned int wid_unused, const char *unused )
204{
205 (void)wid_unused;
206 (void)unused;
207 unsigned int wid;
208 int buttonPos = 0;
209 const glColour cBG = { 0., 0., 0., 0.95 };
210
211 /* Pause. */
212 pause_game();
213
214 /* Must have no diffs applied. */
215 diff_clear();
216 uniedit_diff = array_create( UniHunk_t );
217 uniedit_diffSaved = 1; /* Start OK with empty diffs. */
218
219 /* Reset some variables. */
221 uniedit_viewmode = UNIEDIT_VIEW_DEFAULT;
223 uniedit_drag = 0;
224 uniedit_dragSys = 0;
225 uniedit_dragSel = 0;
226 uniedit_tsys = NULL;
227 uniedit_tadd = 0;
228 uniedit_zoom = 1.;
229 uniedit_xpos = 0.;
230 uniedit_ypos = 0.;
231 uniedit_dt = 0.;
232
233 /* Create the window. */
234 wid = window_create( "wdwUniverseEditor", _( "Universe Editor" ), -1, -1, -1,
235 -1 );
236 window_setDynamic( wid, 1 );
238 window_setBorder( wid, 0 );
239 uniedit_wid = wid;
240
241 /* Actual viewport, below everything. */
242 window_addCust( wid, 0, 0, SCREEN_W, SCREEN_H, "cstSysEdit", 1,
244 NULL );
245 window_custSetOverlay( wid, "cstSysEdit", uniedit_renderOverlay );
246
247 /* Overlay background. */
248 window_addRect( wid, SCREEN_W - 130, 0, 130, SCREEN_H, "rctRCol", &cBG, 0 );
249 window_addRect( wid, 0, 0, SCREEN_W, 60, "rctBBar", &cBG, 0 );
250
251 /* Close button. */
252 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
253 BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose", _( "Exit" ),
254 uniedit_close, SDLK_x );
255 buttonPos++;
256
257 /* Save button. */
258 window_addButton( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
259 BUTTON_WIDTH, BUTTON_HEIGHT, "btnSave",
260 uniedit_diffMode ? _( "Save Diff" ) : _( "Save All" ),
261 uniedit_save );
262 buttonPos++;
263
264 /* Diff button. */
265 window_addButton( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
266 BUTTON_WIDTH, BUTTON_HEIGHT, "btnDiff", _( "Diffs" ),
267 uniedit_diffEditor );
268 buttonPos++;
269
270 /* View button. */
271 window_addButton( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
272 BUTTON_WIDTH, BUTTON_HEIGHT, "btnView", _( "View Mode" ),
274 buttonPos++;
275
276 /* Jump toggle. */
277 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
278 BUTTON_WIDTH, BUTTON_HEIGHT, "btnJump", _( "Jump" ),
279 uniedit_btnJump, SDLK_j );
280 buttonPos++;
281
282 /* Edit system. */
283 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
284 BUTTON_WIDTH, BUTTON_HEIGHT, "btnEdit", _( "Edit" ),
285 uniedit_btnEdit, SDLK_e );
286 buttonPos++;
287
288 /* New system. */
289 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
290 BUTTON_WIDTH, BUTTON_HEIGHT, "btnNew", _( "New Sys" ),
291 uniedit_btnNew, SDLK_n );
292 buttonPos++;
293
294 /* Open a system. */
295 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
296 BUTTON_WIDTH, BUTTON_HEIGHT, "btnOpen", _( "Open" ),
297 uniedit_btnOpen, SDLK_o );
298 buttonPos++;
299
300 /* Find a system or spob. */
301 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * buttonPos,
302 BUTTON_WIDTH, BUTTON_HEIGHT, "btnFind", _( "Find" ),
303 uniedit_btnFind, SDLK_f );
304 // buttonPos++;
305
306 /* Options button. */
307 window_addButton( wid, -15 - BUTTON_WIDTH - 20, 20, BUTTON_HEIGHT,
308 BUTTON_HEIGHT, "btnOptions", NULL, uniedit_options );
309 window_buttonCustomRender( wid, "btnOptions",
310 window_buttonCustomRenderGear );
311
312 /* Zoom buttons */
313 window_addButton( wid, 20, 20, 30, 30, "btnZoomIn", p_( "zoomin", "+" ),
315 window_addButton( wid, 60, 20, 30, 30, "btnZoomOut", p_( "zoomout", "-" ),
317
318 /* Nebula. */
319 window_addText( wid, -10, -20, 110, 200, 0, "txtNebula", &gl_smallFont, NULL,
320 _( "N/A" ) );
321
322 /* Presence. */
323 window_addText( wid, -10, -80 - gl_smallFont.h - 5, 110, 200, 0,
324 "txtPresence", &gl_smallFont, NULL, _( "N/A" ) );
325
326 /* Selected text. */
327 window_addText( wid, 100, 10, SCREEN_W / 2 - 140, 30, 0, "txtSelected",
328 &gl_smallFont, NULL, NULL );
329
330 /* Deselect everything. */
332
333 /* Do a test. */
334 uniedit_saveTest();
335}
336
337static void uniedit_saveDirectoryChoose( void *data,
338 const char *const *filelist,
339 int filter )
340{
341 (void)data;
342 (void)filter;
343 if (filelist == NULL) {
344 WARN( _( "Error calling %s: %s" ), "SDL_ShowOpenFolderDialog",
345 SDL_GetError() );
346 return;
347 } else if (filelist[0] == NULL) {
348 /* Cancelled by user. */
349 return;
350 }
351
352 free( conf.dev_data_dir );
353 conf.dev_data_dir = strdup( filelist[0] );
354 uniedit_saveTest();
355}
356void uniedit_saveError( void )
357{
358 const char *datadir =
359 ( conf.dev_data_dir == NULL ) ? "[NULL]" : conf.dev_data_dir;
360 if (!dialogue_YesNo( _( "Unable to Save Data!" ),
361 _( "There has been an error saving data from the "
362 "editor! Please check "
363 "the error logs or open the console for more "
364 "information. You likely "
365 "have the wrong path set."
366 "\n\n"
367 "The current data directory is '#b%s#0'"
368 "\n"
369 "Do you wish to choose a new directory?" ),
370 datadir ))
371 return;
372 SDL_ShowOpenFolderDialog( uniedit_saveDirectoryChoose, NULL,
373 gl_screen.window, conf.dev_data_dir, 0 );
374}
375
376static int uniedit_saveTestDirectory( const char *path )
377{
378 char buf[PATH_MAX];
379 if (nfile_dirExists( path ))
380 return 0;
381 if (!nfile_dirMakeExist( path ))
382 return -1;
383 snprintf( buf, sizeof( buf ), "%s/.naevtestpath", path );
384 if (!nfile_touch( path ))
385 return -1;
386 if (!remove( buf ))
387 return -1;
388 if (!rmdir( path ))
389 return -1;
390 return 0;
391}
392
393static void uniedit_saveTest( void )
394{
395 char buf[PATH_MAX];
396 if (conf.dev_data_dir == NULL) {
398 _( "Invalid Save Directory" ),
399 _( "Data directory is not set. Do you wish to choose a directory "
400 "to save files with the editor to? You will be unable to save "
401 "until it is set."
402 "\n\n"
403 "Do you wish to choose a new directory?" ) ))
404 return;
405 SDL_ShowOpenFolderDialog( uniedit_saveDirectoryChoose, NULL,
406 gl_screen.window, conf.dev_data_dir, 0 );
407 return;
408 }
409
410 snprintf( buf, sizeof( buf ), "%s/ssys/", conf.dev_data_dir );
411 if (uniedit_saveTestDirectory( buf ))
412 goto failed;
413 snprintf( buf, sizeof( buf ), "%s/spob/", conf.dev_data_dir );
414 if (uniedit_saveTestDirectory( buf ))
415 goto failed;
416
417 return;
418failed:
419 if (!dialogue_YesNo( _( "Invalid Save Directory" ),
420 _( "The writing directory for the editor does not "
421 "seem to exist. Maybe the path is wrong?\n"
422 "\n"
423 "The current data directory is '#b%s#0'"
424 "\n"
425 "Do you wish to choose a new directory?" ),
426 conf.dev_data_dir ))
427 return;
428 SDL_ShowOpenFolderDialog( uniedit_saveDirectoryChoose, NULL,
429 gl_screen.window, conf.dev_data_dir, 0 );
430}
431
435static int uniedit_keys( unsigned int wid, SDL_Keycode key, SDL_Keymod mod,
436 int isrepeat )
437{
438 (void)wid;
439 (void)isrepeat;
440 int n;
441
442 switch (key) {
443 /* Mode changes. */
444 case SDLK_ESCAPE:
446 return 1;
447
448 case SDLK_a:
449 if (mod & ( KMOD_LCTRL | KMOD_RCTRL )) {
451 for (int i = 0; i < array_size( systems_stack ); i++)
453 return 1;
454 }
455 return 0;
456
457 case SDLK_r:
458 n = array_size( uniedit_sys );
459 if (n > 1) {
461 uniedit_rotate = 0.; /* Initialize rotation. */
463 for (int i = 0; i < n; i++) {
464 uniedit_rotate_cx += uniedit_sys[i]->pos.x;
465 uniedit_rotate_cy += uniedit_sys[i]->pos.y;
466 }
467 uniedit_rotate_cx /= (double)n;
468 uniedit_rotate_cy /= (double)n;
469 }
470 return 1;
471
472 default:
473 return 0;
474 }
475}
476
480static void uniedit_close( unsigned int wid, const char *wgt )
481{
482 if (uniedit_diffMode && !uniedit_diffSaved) {
484 _( "#rUnsaved Progress" ),
485 _( "You have #runsaved changes#0 to the universe diff. Are you "
486 "sure you wish to close the editor and #rlose all your "
487 "changes#0?" ) ))
488 return;
489 }
490
491 uniedit_diffClear();
492
493 /* Frees some memory. */
495
496 /* Reconstruct jumps. */
498
499 /* Unpause. */
500 unpause_game();
501
502 /* Close the window. */
503 window_close( wid, wgt );
504}
505
506static void uniedit_save_callback( void *userdata, const char *const *filelist,
507 int filter )
508{
509 (void)userdata;
510 (void)filter;
511
512 if (filelist == NULL) {
513 WARN( _( "Error calling %s: %s" ), "SDL_ShowSaveFileDialog",
514 SDL_GetError() );
515 return;
516 } else if (filelist[0] == NULL) {
517 /* Cancelled by user. */
518 return;
519 }
520
521 /* Actually save it. */
522 ddiff_save( uniedit_diff, filelist[0] );
523 uniedit_diffSaved = 1;
524}
525/*
526 * @brief Saves the systems.
527 */
528static void uniedit_save( unsigned int wid_unused, const char *unused )
529{
530 (void)wid_unused;
531 (void)unused;
532
533 if (uniedit_diffMode) {
534 const SDL_DialogFileFilter filter[] = {
535 { .name = _( "Diff XML file" ), .pattern = "xml" },
536 { NULL, NULL },
537 };
538 char buf[PATH_MAX];
539 snprintf( buf, sizeof( buf ), "%s/unidiff/newunidiff.xml",
540 conf.dev_data_dir );
541 SDL_ShowSaveFileDialog( uniedit_save_callback, NULL, gl_screen.window,
542 filter, buf );
543 } else {
544 int ret = 0;
545 ret |= dsys_saveAll();
546 ret |= dpl_saveAll();
547 if (ret)
548 uniedit_saveError();
549 }
550}
551
552/*
553 * @brief Toggles autosave.
554 */
555void uniedit_options( unsigned int wid_unused, const char *unused )
556{
557 (void)wid_unused;
558 (void)unused;
559 const int w = 300;
560 const int h = 300;
561 int y;
562 char buf[STRMAX_SHORT];
563 unsigned int wid =
564 window_create( "wdwEditorOptions", _( "Editor Options" ), -1, -1, w, h );
565 window_onClose( wid, uniedit_options_close );
566
567 /* Close button. */
568 window_addButton( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
569 _( "Close" ), window_close );
570
571 y = -40;
572 snprintf( buf, sizeof( buf ), "#nData Path:#0 %s", conf.dev_data_dir );
573 window_addText( wid, 20, y, w - 40, 20, 0, "txtDataPath", NULL, NULL, buf );
574 y -= 20;
575 window_addButton( wid, 20, y, BUTTON_WIDTH, BUTTON_HEIGHT, "btnSetPath",
576 _( "Set Path" ), uniedit_options_setpath );
577
578 /* Autosave toggle. */
579 y -= 40;
580 window_addCheckbox( wid, 20, y, w - 40, 20, "chkEditAutoSave",
581 _( "Automatically save changes" ), NULL,
582 conf.devautosave );
583}
584
585static void uniedit_options_setpath_callback( void *userdata,
586 const char *const *filelist,
587 int filter )
588{
589 (void)filter;
590 unsigned int wid = *(unsigned int *)userdata;
591 char buf[STRMAX_SHORT];
592
593 if (filelist == NULL) {
594 WARN( _( "Error calling %s: %s" ), "SDL_ShowOpenFolderDialog",
595 SDL_GetError() );
596 return;
597 } else if (filelist[0] == NULL) {
598 /* Cancelled by user. */
599 return;
600 }
601
602 /* Update. */
603 free( conf.dev_data_dir );
604 conf.dev_data_dir = strdup( filelist[0] );
605
606 snprintf( buf, sizeof( buf ), "#nData Path:#0 %s", conf.dev_data_dir );
607 window_modifyText( wid, "txtDataPath", buf );
608}
609static void uniedit_options_setpath( unsigned int wid, const char *unused )
610{
611 (void)unused;
612 SDL_ShowOpenFolderDialog( uniedit_options_setpath_callback, &wid,
613 gl_screen.window, conf.dev_data_dir, 0 );
614}
615
616static void uniedit_options_close( unsigned int wid, const char *unused )
617{
618 (void)unused;
619 conf.devautosave = window_checkboxState( wid, "chkEditAutoSave" );
620}
621
622static int factionGenerates( int f, int tocheck, double *w )
623{
624 const FactionGenerator *fg = faction_generators( f );
625 for (int i = 0; i < array_size( fg ); i++) {
626 if (fg[i].id == tocheck) {
627 if (w != NULL)
628 *w = fg[i].weight;
629 return 1;
630 }
631 }
632 return 0;
633}
634
638static void uniedit_btnView( unsigned int wid_unused, const char *unused )
639{
640 (void)wid_unused;
641 (void)unused;
642 unsigned int wid;
643 int n, h, k;
644 Spob *spobs;
645 char **str;
646 int *factions;
647
648 /* Find usable factions. */
649 factions = faction_getAll();
650 spobs = spob_getAll();
651 for (int i = 0; i < array_size( factions ); i++) {
652 int f = factions[i];
653 int hasfact = 0;
654 for (int j = 0; j < array_size( spobs ); j++) {
655 Spob *p = &spobs[j];
656 if (( p->presence.faction != f ) &&
657 !factionGenerates( p->presence.faction, f, NULL ))
658 continue;
659 if (p->presence.base == 0. && p->presence.bonus == 0.)
660 continue;
661 hasfact = 1;
662 break;
663 }
664 if (!hasfact)
665 factions[i] = -1;
666 }
667
668 /* Create the window. */
669 wid = window_create( "wdwUniEditView", _( "Select a View Mode" ), -1, -1,
672
673 /* Add virtual spob list. */
674 n = 9; /* Number of special cases. */
675 str = malloc( sizeof( char * ) * ( array_size( factions ) + n ) );
676 str[0] = strdup( _( "Default" ) );
677 str[1] = strdup( _( "Virtual Spobs" ) );
678 str[2] = strdup( _( "System Radius" ) );
679 str[3] = strdup( _( "No Lanes" ) );
680 str[4] = strdup( _( "Background" ) );
681 str[5] = strdup( _( "Asteroids" ) );
682 str[6] = strdup( _( "Interference" ) );
683 str[7] = strdup( _( "Tech" ) );
684 str[8] = strdup( _( "Sum of Presences" ) );
685 k = n;
686 for (int i = 0; i < array_size( factions ); i++) {
687 int f = factions[i];
688 if (f >= 0)
689 str[k++] = strdup(
690 faction_name( f ) ); /* Not translating so we can use faction_get */
691 }
692 qsort( &str[n], k - n, sizeof( char * ), strsort );
693 h = UNIEDIT_EDIT_HEIGHT - 60 - ( BUTTON_HEIGHT + 20 );
694 window_addList( wid, 20, -40, UNIEDIT_EDIT_WIDTH - 40, h, "lstViewModes",
695 str, k, 0, NULL, uniedit_btnViewModeSet );
696
697 /* Close button. */
698 window_addButton( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
699 _( "Close" ), window_close );
700
701 /* Add button. */
702 window_addButton( wid, -20 - ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
703 BUTTON_HEIGHT, "btnSet", _( "Set" ),
705
706 /* Clean up. */
707 array_free( factions );
708}
709
713static void uniedit_btnJump( unsigned int wid_unused, const char *unused )
714{
715 (void)wid_unused;
716 (void)unused;
717
719}
720
724static void uniedit_btnNew( unsigned int wid_unused, const char *unused )
725{
726 (void)wid_unused;
727 (void)unused;
728
730}
731
735static void uniedit_btnOpen( unsigned int wid_unused, const char *unused )
736{
737 (void)wid_unused;
738 (void)unused;
739
740 if (array_size( uniedit_sys ) != 1)
741 return;
742
744}
745
749static void uniedit_btnFind( unsigned int wid_unused, const char *unused )
750{
751 (void)wid_unused;
752 (void)unused;
753
755}
756
760static void uniedit_btnEdit( unsigned int wid_unused, const char *unused )
761{
762 (void)wid_unused;
763 (void)unused;
764
766}
767
768static void uniedit_renderFactionDisks( double x, double y, double r )
769{
770 const glColour *col;
771 glColour c;
772
774 c.r = col->r;
775 c.g = col->g;
776 c.b = col->b;
777 c.a = 0.5;
778
779 for (int i = 0; i < array_size( systems_stack ); i++) {
780 double tx, ty, sr, presence;
781 StarSystem *sys = system_getIndex( i );
782
783 tx = x + sys->pos.x * uniedit_zoom;
784 ty = y + sys->pos.y * uniedit_zoom;
785
786 presence = system_getPresence( sys, uniedit_view_faction );
787
788 /* draws the disk representing the faction */
789 sr = 0.5 * M_PI * sqrt( presence ) * uniedit_zoom;
790
791 // glUseProgram(shaders.factiondisk.program);
792 // glUniform1f(shaders.factiondisk.paramf, r / sr );
793 // gl_renderShader( tx, ty, sr, sr, 0., &shaders.factiondisk, &c, 1 );
794 (void)r;
795 gl_renderCircle( tx, ty, sr, &c, 1 );
796 }
797}
798
799static void uniedit_renderVirtualSpobs( double x, double y, double r )
800{
801 const glColour c = { .r = 1., .g = 1., .b = 1., .a = 0.3 };
802
803 for (int i = 0; i < array_size( systems_stack ); i++) {
804 double tx, ty, sr;
805 StarSystem *sys = system_getIndex( i );
806
807 tx = x + sys->pos.x * uniedit_zoom;
808 ty = y + sys->pos.y * uniedit_zoom;
809
810 /* draws the disk representing the faction */
811 sr = 5. * M_PI * sqrt( (double)array_size( sys->spobs_virtual ) ) *
813
814 (void)r;
815 gl_renderCircle( tx, ty, sr, &c, 1 );
816 }
817}
818
819static void uniedit_renderRadius( double x, double y, double r )
820{
821 const glColour c = { .r = 1., .g = 1., .b = 1., .a = 0.3 };
822
823 for (int i = 0; i < array_size( systems_stack ); i++) {
824 double tx, ty, sr;
825 StarSystem *sys = system_getIndex( i );
826
827 tx = x + sys->pos.x * uniedit_zoom;
828 ty = y + sys->pos.y * uniedit_zoom;
829
830 /* draws the disk representing the faction */
831 sr = 5. * M_PI * sqrt( sys->radius / 10e3 ) * uniedit_zoom;
832
833 (void)r;
834 gl_renderCircle( tx, ty, sr, &c, 1 );
835 }
836}
837
838static void uniedit_renderNolanes( double x, double y, double r )
839{
840 const glColour c = { .r = 1., .g = 1., .b = 1., .a = 0.3 };
841
842 for (int i = 0; i < array_size( systems_stack ); i++) {
843 double tx, ty, sr;
844 StarSystem *sys = system_getIndex( i );
845
846 if (!sys_isFlag( sys, SYSTEM_NOLANES ))
847 continue;
848
849 tx = x + sys->pos.x * uniedit_zoom;
850 ty = y + sys->pos.y * uniedit_zoom;
851
852 /* draws the disk representing the faction */
853 sr = 5. * M_PI * uniedit_zoom;
854
855 (void)r;
856 gl_renderCircle( tx, ty, sr, &c, 1 );
857 }
858}
859
860static void uniedit_renderBackground( double x, double y, double r )
861{
862 const glColour c = { .r = 1., .g = 1., .b = 1., .a = 0.3 };
863
864 for (int i = 0; i < array_size( systems_stack ); i++) {
865 double tx, ty, sr;
866 StarSystem *sys = system_getIndex( i );
867
868 if (sys->background == NULL)
869 continue;
870
871 tx = x + sys->pos.x * uniedit_zoom;
872 ty = y + sys->pos.y * uniedit_zoom;
873
874 /* draws the disk representing the faction */
875 sr = 7. * M_PI * uniedit_zoom;
876
877 (void)r;
878 gl_renderCircle( tx, ty, sr, &c, 1 );
879 }
880}
881
882static void uniedit_renderAsteroids( double x, double y, double r )
883{
884 const glColour c = { .r = 1., .g = 1., .b = 1., .a = 0.3 };
885
886 for (int i = 0; i < array_size( systems_stack ); i++) {
887 double tx, ty, sr;
888 StarSystem *sys = system_getIndex( i );
889 double density = sys->asteroid_density;
890
891 if (density <= 0.)
892 continue;
893
894 tx = x + sys->pos.x * uniedit_zoom;
895 ty = y + sys->pos.y * uniedit_zoom;
896
897 /* Draw disk. */
898 sr = 0.3 * M_PI * sqrt( density ) * uniedit_zoom;
899 (void)r;
900 gl_renderCircle( tx, ty, sr, &c, 1 );
901 }
902}
903
904static void uniedit_renderInterference( double x, double y, double r )
905{
906 const glColour c = { .r = 1., .g = 1., .b = 1., .a = 0.3 };
907
908 for (int i = 0; i < array_size( systems_stack ); i++) {
909 double tx, ty, sr;
910 StarSystem *sys = system_getIndex( i );
911
912 tx = x + sys->pos.x * uniedit_zoom;
913 ty = y + sys->pos.y * uniedit_zoom;
914
915 /* draws the disk representing the faction */
916 sr = 5. * M_PI * sqrt( sys->interference / 20. ) * uniedit_zoom;
917
918 (void)r;
919 gl_renderCircle( tx, ty, sr, &c, 1 );
920 }
921}
922
923static void uniedit_renderTech( double x, double y, double r )
924{
925 const glColour c = { .r = 1., .g = 1., .b = 1., .a = 0.3 };
926
927 for (int i = 0; i < array_size( systems_stack ); i++) {
928 double tx, ty, sr;
929 StarSystem *sys = system_getIndex( i );
930 int hastech = 0;
931
932 for (int j = 0; j < array_size( sys->spobs ); j++) {
933 if (sys->spobs[j]->tech != NULL) {
934 hastech = 1;
935 break;
936 }
937 }
938 if (!hastech)
939 continue;
940
941 tx = x + sys->pos.x * uniedit_zoom;
942 ty = y + sys->pos.y * uniedit_zoom;
943
944 /* Draw disk. */
945 sr = 7. * M_PI * uniedit_zoom;
946 (void)r;
947 gl_renderCircle( tx, ty, sr, &c, 1 );
948 }
949}
950
951static void uniedit_renderPresenceSum( double x, double y, double r )
952{
953 const glColour c = { .r = 1., .g = 1., .b = 1., .a = 0.3 };
954
955 for (int i = 0; i < array_size( systems_stack ); i++) {
956 double tx, ty, sr;
957 StarSystem *sys = system_getIndex( i );
958
959 double total = 0.;
960 for (int j = 0; j < array_size( sys->presence ); j++)
961 total += MAX( 0., sys->presence[j].value );
962
963 tx = x + sys->pos.x * uniedit_zoom;
964 ty = y + sys->pos.y * uniedit_zoom;
965
966 /* draws the disk representing the faction */
967 sr = 0.2 * M_PI * sqrt( total ) * uniedit_zoom;
968
969 (void)r;
970 gl_renderCircle( tx, ty, sr, &c, 1 );
971 }
972}
973
974/* @brief Renders important map stuff.
975 */
976void uniedit_renderMap( double bx, double by, double w, double h, double x,
977 double y, double zoom, double r )
978{
979 /* Background */
980 gl_renderRect( bx, by, w, h, &cBlack );
981
982 /* Render faction disks. */
983 switch (uniedit_viewmode) {
984 case UNIEDIT_VIEW_DEFAULT:
985 map_renderDecorators( x, y, zoom, 1, 1. );
986 map_renderFactionDisks( x, y, zoom, r, 1, 1. );
987 map_renderSystemEnvironment( x, y, zoom, 1, 1. );
988 break;
989
990 case UNIEDIT_VIEW_VIRTUALSPOBS:
991 uniedit_renderVirtualSpobs( x, y, r );
992 break;
993
994 case UNIEDIT_VIEW_RADIUS:
995 uniedit_renderRadius( x, y, r );
996 break;
997
998 case UNIEDIT_VIEW_NOLANES:
999 uniedit_renderNolanes( x, y, r );
1000 break;
1001
1002 case UNIEDIT_VIEW_BACKGROUND:
1003 uniedit_renderBackground( x, y, r );
1004 break;
1005
1006 case UNIEDIT_VIEW_ASTEROIDS:
1007 uniedit_renderAsteroids( x, y, r );
1008 break;
1009
1010 case UNIEDIT_VIEW_INTERFERENCE:
1011 uniedit_renderInterference( x, y, r );
1012 break;
1013
1014 case UNIEDIT_VIEW_TECH:
1015 uniedit_renderTech( x, y, r );
1016 break;
1017
1018 case UNIEDIT_VIEW_PRESENCE_SUM:
1019 uniedit_renderPresenceSum( x, y, r );
1020 break;
1021
1022 case UNIEDIT_VIEW_PRESENCE:
1023 if (uniedit_view_faction >= 0)
1024 uniedit_renderFactionDisks( x, y, r );
1025 break;
1026 }
1027
1028 /* Render jump paths. */
1029 map_renderJumps( x, y, zoom, r, 1 );
1030
1031 /* Render systems. */
1032 map_renderSystems( bx, by, x, y, zoom, w, h, r, MAPMODE_EDITOR );
1033
1034 /* Render system names. */
1035 map_renderNames( bx, by, x, y, zoom, w, h, 1, 1. );
1036
1037 glClear( GL_DEPTH_BUFFER_BIT );
1038}
1039
1043static void uniedit_render( double bx, double by, double w, double h,
1044 void *data )
1045{
1046 (void)data;
1047 double x, y, r;
1048
1050
1051 /* Parameters. */
1052 map_renderParams( bx, by, uniedit_xpos, uniedit_ypos, w, h, uniedit_zoom, &x,
1053 &y, &r );
1054
1055 /* Render map stuff. */
1056 uniedit_renderMap( bx, by, w, h, x, y, uniedit_zoom, r );
1057
1058 /* Render the selected system selections. */
1059 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1060 StarSystem *sys = uniedit_sys[i];
1061 glUseProgram( shaders.selectspob.program );
1062 glUniform1f( shaders.selectspob.dt, uniedit_dt );
1063 gl_renderShader( x + sys->pos.x * uniedit_zoom,
1064 y + sys->pos.y * uniedit_zoom, 1.5 * r, 1.5 * r, 0.,
1065 &shaders.selectspob, &cWhite, 1 );
1066 }
1067}
1068
1069static char getValCol( double val )
1070{
1071 if (val > 0.)
1072 return 'g';
1073 else if (val < 0.)
1074 return 'r';
1075 return '0';
1076}
1077static int getPresenceVal( int f, const SpobPresence *ap, double *base,
1078 double *bonus )
1079{
1080 int gf = 0;
1081 double w;
1082 if (( ap->faction != f ) && !( gf = factionGenerates( ap->faction, f, &w ) ))
1083 return 0;
1084 if (gf == 0) {
1085 *base = ap->base;
1086 *bonus = ap->bonus;
1087 } else {
1088 *base = ap->base * w;
1089 *bonus = ap->bonus * w;
1090 }
1091 return 1;
1092}
1093
1097static void uniedit_renderOverlay( double bx, double by, double bw, double bh,
1098 void *data )
1099{
1100 double x, y, mx, my, sx, sy;
1101 double value, base, bonus;
1102 char buf[STRMAX] = { '\0' };
1103 StarSystem *sys, *cur, *mousesys;
1104 SystemPresence *sp;
1105 (void)data;
1106
1107 x = bx + uniedit_mx;
1108 y = by + uniedit_my;
1109
1110 /* Correct coordinates. */
1111 mx = uniedit_mx - bw / 2. + uniedit_xpos;
1112 my = uniedit_my - bh / 2. + uniedit_ypos;
1113 mx /= uniedit_zoom;
1114 my /= uniedit_zoom;
1115
1116 /* Display location. */
1117 gl_print( &gl_defFontMono, bx + 5, by + 65, &cWhite, "% 7.2f x % 7.2f", mx,
1118 my );
1119
1120 /* Select drag stuff. */
1121 if (uniedit_dragSel) {
1122 double l, r, b, t, rx, ry;
1123 const glColour col = { .r = 0.2, .g = 0.2, .b = 0.8, .a = 0.5 };
1124
1125 l = MIN( uniedit_dragSelX, mx );
1126 r = MAX( uniedit_dragSelX, mx );
1127 b = MIN( uniedit_dragSelY, my );
1128 t = MAX( uniedit_dragSelY, my );
1129
1130 /* Project back to screen space. */
1131 rx = ( l * uniedit_zoom ) + bw / 2. - uniedit_xpos;
1132 ry = ( b * uniedit_zoom ) + bh / 2. - uniedit_ypos;
1133
1134 gl_renderRect( rx, ry, ( r - l ) * uniedit_zoom, ( t - b ) * uniedit_zoom,
1135 &col );
1136 }
1137
1138 /* Don't cover up stuff if possible. */
1139 if (( x > SCREEN_W - 130 ) || ( y < 60 ))
1140 return;
1141
1143 toolkit_drawAltText( x, y, _( "Click to add a new system" ) );
1144 return;
1145 } else if (uniedit_mode == UNIEDIT_JUMP) {
1146 toolkit_drawAltText( x, y, _( "Click to toggle jump route" ) );
1147 return;
1148 } else if (uniedit_viewmode == UNIEDIT_VIEW_DEFAULT)
1149 return;
1150
1151 /* Find mouse over system. */
1152 mousesys = NULL;
1153 for (int i = 0; i < array_size( systems_stack ); i++) {
1154 sys = system_getIndex( i );
1155 sx = sys->pos.x;
1156 sy = sys->pos.y;
1157 if (( pow2( sx - mx ) + pow2( sy - my ) ) >
1159 continue;
1160 mousesys = sys;
1161 break;
1162 }
1163 if (mousesys == NULL)
1164 return;
1165 sys = mousesys;
1166 sx = sys->pos.x;
1167 sy = sys->pos.y;
1168
1169 /* Handle virtual spob viewer. */
1170 if (uniedit_viewmode == UNIEDIT_VIEW_VIRTUALSPOBS) {
1171 int l;
1172
1173 if (array_size( sys->spobs_virtual ) == 0)
1174 return;
1175
1176 /* Count spobs. */
1177 l = 0;
1178 for (int j = 0; j < array_size( sys->spobs_virtual ); j++) {
1179 const VirtualSpob *va = sys->spobs_virtual[j];
1180 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s%s",
1181 ( l > 0 ) ? "\n" : "", va->name );
1182 }
1183
1184 toolkit_drawAltText( x, y, buf );
1185 return;
1186 }
1187
1188 /* Handle radius view. */
1189 else if (uniedit_viewmode == UNIEDIT_VIEW_RADIUS) {
1190 scnprintf( &buf[0], sizeof( buf ), _( "System Radius: %s" ),
1191 num2strU( sys->radius, 0 ) );
1192 toolkit_drawAltText( x, y, buf );
1193 return;
1194 }
1195
1196 /* Handle background. */
1197 else if (uniedit_viewmode == UNIEDIT_VIEW_BACKGROUND) {
1198 if (sys->background != NULL) {
1199 scnprintf( &buf[0], sizeof( buf ), _( "Background: %s" ),
1200 sys->background );
1201 toolkit_drawAltText( x, y, buf );
1202 }
1203 return;
1204 }
1205
1206 /* Handle asteroids. */
1207 else if (uniedit_viewmode == UNIEDIT_VIEW_ASTEROIDS) {
1208 if (array_size( sys->asteroids ) > 0) {
1209 int l = 0;
1210 l = scnprintf( &buf[l], sizeof( buf ) - l, _( "Density: %g" ),
1211 sys->asteroid_density );
1212 for (int i = 0; i < array_size( sys->asteroids ); i++) {
1213 AsteroidAnchor *ast = &sys->asteroids[i];
1214 for (int j = 0; j < array_size( ast->groups ); j++)
1215 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s%s",
1216 ( l > 0 ) ? "\n" : "", ast->groups[j]->name );
1217 }
1218 toolkit_drawAltText( x, y, buf );
1219 }
1220 return;
1221 }
1222
1223 /* Handle interference. */
1224 else if (uniedit_viewmode == UNIEDIT_VIEW_INTERFERENCE) {
1225 if (sys->interference > 0.) {
1226 scnprintf( &buf[0], sizeof( buf ), _( "Interference: %.0f%%" ),
1227 sys->interference );
1228 toolkit_drawAltText( x, y, buf );
1229 }
1230 return;
1231 }
1232
1233 /* Handle tech radius. */
1234 else if (uniedit_viewmode == UNIEDIT_VIEW_TECH) {
1235 char *techlist[256];
1236 int ntechs = 0;
1237 const int len = sizeof( techlist ) / sizeof( char * );
1238 int l;
1239
1240 if (array_size( sys->spobs ) == 0)
1241 return;
1242
1243 /* Count spobs. */
1244 l = 0;
1245 for (int j = 0; j < array_size( sys->spobs ); j++) {
1246 const Spob *spob = sys->spobs[j];
1247 int n;
1248 char **techs;
1249 if (spob->tech == NULL)
1250 continue;
1251 techs = tech_getItemNames( spob->tech, &n );
1252 for (int k = 0; ( k < n ) && ( ntechs < len - 1 ); k++)
1253 techlist[ntechs++] = techs[k];
1254 free( techs );
1255 }
1256 qsort( techlist, ntechs, sizeof( char * ), strsort );
1257 for (int k = 0; k < ntechs; k++) {
1258 if (( k > 0 ) && ( strcmp( techlist[k - 1], techlist[k] ) == 0 ))
1259 continue;
1260 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s%s",
1261 ( l > 0 ) ? "\n" : "", techlist[k] );
1262 }
1263 for (int k = 0; k < ntechs; k++)
1264 free( techlist[k] );
1265
1266 toolkit_drawAltText( x, y, buf );
1267 return;
1268 }
1269
1270 /* Handle presence sum. */
1271 else if (uniedit_viewmode == UNIEDIT_VIEW_PRESENCE_SUM) {
1272 int l;
1273
1274 if (array_size( sys->presence ) == 0)
1275 return;
1276
1277 value = 0.;
1278 for (int j = 0; j < array_size( sys->presence ); j++)
1279 value += MAX( sys->presence[j].value, 0. );
1280
1281 /* Count spobs. */
1282 l = scnprintf( buf, sizeof( buf ), _( "Total: %.0f" ), value );
1283 for (int j = 0; j < array_size( sys->presence ); j++) {
1284 sp = &sys->presence[j];
1285 if (sp->value <= 0.)
1286 continue;
1287 l += scnprintf( &buf[l], sizeof( buf ) - l, "\n%s: %.0f = %.0f + %.0f",
1288 faction_name( sp->faction ), sp->value, sp->base,
1289 sp->bonus );
1290 }
1291 toolkit_drawAltText( x, y, buf );
1292 return;
1293 }
1294
1295 /* Handle presence mode. */
1296 else if (uniedit_viewmode == UNIEDIT_VIEW_PRESENCE) {
1297 int l;
1298 int f = uniedit_view_faction;
1299 if (f < 0)
1300 return;
1301
1302 /* Total presence. */
1303 value = system_getPresenceFull( sys, f, &base, &bonus );
1304 l = scnprintf(
1305 buf, sizeof( buf ), "#%c%.0f#0 = #%c%.0f#0 + #%c%.0f#0 [%s - %s]",
1306 getValCol( value ), value, getValCol( base ), base, getValCol( bonus ),
1307 bonus, system_name( sys ), faction_name( f ) );
1308
1309 /* Local presence sources. */
1310 for (int j = 0; j < array_size( sys->spobs ); j++) {
1311 Spob *spob = sys->spobs[j];
1312 if (!getPresenceVal( f, &spob->presence, &base, &bonus ))
1313 continue;
1314 l += scnprintf( &buf[l], sizeof( buf ) - l,
1315 "\n#%c%.0f#0 (#%c%+.0f#0) [%s]", getValCol( base ),
1316 base, getValCol( bonus ), bonus, spob_name( spob ) );
1317 }
1318 for (int j = 0; j < array_size( sys->spobs_virtual ); j++) {
1319 const VirtualSpob *va = sys->spobs_virtual[j];
1320 for (int p = 0; p < array_size( va->presences ); p++) {
1321 if (!getPresenceVal( f, &va->presences[p], &base, &bonus ))
1322 continue;
1323 l += scnprintf( &buf[l], sizeof( buf ) - l,
1324 "\n#%c%.0f#0 (#%c%+.0f#0) [%s]", getValCol( base ),
1325 base, getValCol( bonus ), bonus, _( va->name ) );
1326 }
1327 }
1328
1329 /* Find neighbours if possible. */
1330 for (int k = 0; k < array_size( sys->jumps ); k++) {
1331 cur = sys->jumps[k].target;
1332 for (int j = 0; j < array_size( cur->spobs ); j++) {
1333 Spob *spob = cur->spobs[j];
1334 if (!getPresenceVal( f, &spob->presence, &base, &bonus ))
1335 continue;
1336 l += scnprintf( &buf[l], sizeof( buf ) - l,
1337 "\n#%c%.0f#0 (#%c%+.0f#0) [%s (%s)]",
1338 getValCol( base ), base * 0.5, getValCol( bonus ),
1339 bonus * 0.5, spob_name( spob ), _( cur->name ) );
1340 }
1341 for (int j = 0; j < array_size( cur->spobs_virtual ); j++) {
1342 const VirtualSpob *va = cur->spobs_virtual[j];
1343 for (int p = 0; p < array_size( va->presences ); p++) {
1344 if (!getPresenceVal( f, &va->presences[p], &base, &bonus ))
1345 continue;
1346 l +=
1347 scnprintf( &buf[l], sizeof( buf ) - l,
1348 "\n#%c%.0f#0 (#%c%+.0f#0) [%s (%s)]",
1349 getValCol( base ), base * 0.5, getValCol( bonus ),
1350 bonus * 0.5, _( va->name ), _( cur->name ) );
1351 }
1352 }
1353 }
1354
1355 toolkit_drawAltText( x, y, buf );
1356 return;
1357 }
1358}
1359
1363static void uniedit_focusLose( unsigned int wid, const char *wgtname )
1364{
1365 (void)wid;
1366 (void)wgtname;
1368}
1369
1373static int uniedit_mouse( unsigned int wid, const SDL_Event *event, double mx,
1374 double my, double w, double h, double rx, double ry,
1375 void *data )
1376{
1377 (void)data;
1378 unsigned int lastClick;
1379 StarSystem *clickedsys;
1380 int inselection;
1381 SDL_Keymod mod;
1382
1383 /* Handle modifiers. */
1384 mod = SDL_GetModState();
1385
1386 switch (event->type) {
1387
1388 case SDL_MOUSEWHEEL:
1389 /* Must be in bounds. */
1390 if (( mx < 0. ) || ( mx > w - 130. ) || ( my < 60. ) || ( my > h ))
1391 return 0;
1392
1393 if (event->wheel.y > 0)
1394 uniedit_buttonZoom( 0, "btnZoomIn" );
1395 else if (event->wheel.y < 0)
1396 uniedit_buttonZoom( 0, "btnZoomOut" );
1397
1398 return 1;
1399
1400 case SDL_MOUSEBUTTONDOWN:
1401 /* Must be in bounds. */
1402 if (( mx < 0. ) || ( mx > w - 130. ) || ( my < 60. ) || ( my > h ))
1403 return 0;
1404 window_setFocus( wid, "cstSysEdit" );
1405 lastClick = uniedit_lastClick;
1406 uniedit_lastClick = SDL_GetTicks();
1407
1408 /* Selecting star system */
1409 mx -= w / 2. - uniedit_xpos;
1410 my -= h / 2. - uniedit_ypos;
1411 mx /= uniedit_zoom;
1412 my /= uniedit_zoom;
1413
1414 /* Finish rotation. */
1417 return 1;
1418 }
1419
1420 /* Create new system if applicable. */
1422 uniedit_newSys( mx, my );
1424 return 1;
1425 }
1426
1427 /* Find clicked system. */
1428 clickedsys = NULL;
1429 for (int i = 0; i < array_size( systems_stack ); i++) {
1430 StarSystem *sys = system_getIndex( i );
1431 if (( pow2( mx - sys->pos.x ) + pow2( my - sys->pos.y ) ) >
1433 continue;
1434 clickedsys = sys;
1435 break;
1436 }
1437
1438 /* Set jump if applicable. */
1439 if (clickedsys != NULL && uniedit_mode == UNIEDIT_JUMP) {
1440 uniedit_toggleJump( clickedsys );
1442 return 1;
1443 }
1444
1445 /* See if it is selected. */
1446 inselection = 0;
1447 if (clickedsys != NULL) {
1448 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1449 if (uniedit_sys[i] != clickedsys)
1450 continue;
1451 inselection = 1;
1452 break;
1453 }
1454 }
1455
1456 /* Handle double click. */
1457 if (clickedsys != NULL && inselection && array_size( uniedit_sys ) == 1) {
1458 if (( SDL_GetTicks() - lastClick < UNIEDIT_DOUBLECLICK_THRESHOLD ) &&
1461 uniedit_drag = 0;
1462 uniedit_dragSys = 0;
1463 uniedit_dragSel = 0;
1464 return 1;
1465 }
1466 }
1467
1468 /* Clicked on selected system. */
1469 if (( clickedsys != NULL ) && inselection) {
1470 uniedit_dragSys = 1;
1471 uniedit_tsys = clickedsys;
1472 /* Check modifier. */
1473 if (mod & ( KMOD_LCTRL | KMOD_RCTRL ))
1474 uniedit_tadd = 0;
1475 else
1476 uniedit_tadd = -1;
1477 uniedit_moved = 0;
1478 return 1;
1479 }
1480
1481 /* Clicked on non-selected system. */
1482 if (clickedsys != NULL) {
1483 /* Add the system if not selected. */
1484 if (!( mod & ( KMOD_LCTRL | KMOD_RCTRL ) ))
1486 uniedit_selectAdd( clickedsys );
1487 uniedit_tsys = NULL;
1488 return 1;
1489 }
1490
1491 /* Start dragging. */
1492 uniedit_moved = 0;
1493 uniedit_tsys = NULL;
1494 if (mod & ( KMOD_LCTRL | KMOD_RCTRL | KMOD_LSHIFT | KMOD_RSHIFT )) {
1495 if (mod & ( KMOD_LSHIFT | KMOD_RSHIFT ))
1497 uniedit_dragSel = 1;
1498 uniedit_dragSelX = mx;
1499 uniedit_dragSelY = my;
1500 return 1;
1501 } else {
1502 uniedit_drag = 1;
1503 return 1;
1504 }
1505 break;
1506
1507 case SDL_MOUSEBUTTONUP:
1508 if (uniedit_drag) {
1509 if (( SDL_GetTicks() - uniedit_lastClick < UNIEDIT_DRAG_THRESHOLD ) &&
1511 if (uniedit_tsys == NULL)
1513 else
1515 }
1516 uniedit_drag = 0;
1517 }
1518 if (uniedit_dragSys) {
1519 if (( SDL_GetTicks() - uniedit_lastClick < UNIEDIT_DRAG_THRESHOLD ) &&
1521 ( uniedit_tsys != NULL )) {
1522 if (uniedit_tadd == 0)
1524 else {
1527 }
1528 }
1529 uniedit_dragSys = 0;
1530 if (conf.devautosave) {
1531 int ret = 0;
1532 for (int i = 0; i < array_size( uniedit_sys ); i++)
1533 ret |= dsys_saveSystem( uniedit_sys[i] );
1534 if (ret)
1535 uniedit_saveError();
1536 }
1537 }
1538 if (uniedit_dragSel) {
1539 double l, r, b, t;
1540
1541 /* Selecting star system */
1542 mx -= w / 2. - uniedit_xpos;
1543 my -= h / 2. - uniedit_ypos;
1544 mx /= uniedit_zoom;
1545 my /= uniedit_zoom;
1546
1547 /* Get bounds. */
1548 l = MIN( uniedit_dragSelX, mx );
1549 r = MAX( uniedit_dragSelX, mx );
1550 b = MIN( uniedit_dragSelY, my );
1551 t = MAX( uniedit_dragSelY, my );
1552
1553 for (int i = 0; i < array_size( systems_stack ); i++) {
1554 StarSystem *sys = &systems_stack[i];
1555 double x = sys->pos.x;
1556 double y = sys->pos.y;
1557 if (( x >= l ) && ( x <= r ) && ( y >= b ) && ( y <= t ))
1558 uniedit_selectAdd( sys );
1559 }
1560
1561 uniedit_dragSel = 0;
1562 }
1563 break;
1564
1565 case SDL_MOUSEMOTION:
1566 /* Update mouse positions. */
1567 uniedit_mx = mx;
1568 uniedit_my = my;
1569
1570 /* Handle rotation. */
1572 double a1, a2, amod;
1573 double cx = mx - w / 2. + uniedit_xpos;
1574 double cy = my - h / 2. + uniedit_ypos;
1575 cx /= uniedit_zoom;
1576 cy /= uniedit_zoom;
1577 cx -= uniedit_rotate_cx;
1578 cy -= uniedit_rotate_cy;
1579 a1 = atan2( cy, cx );
1580 cx -= rx / uniedit_zoom;
1581 cy += ry / uniedit_zoom;
1582 a2 = atan2( cy, cx );
1583 amod = a1 - a2;
1584 uniedit_rotate += amod;
1585 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1586 StarSystem *s = uniedit_sys[i];
1587 double sx = s->pos.x - uniedit_rotate_cx;
1588 double sy = s->pos.y - uniedit_rotate_cy;
1589 double a = atan2( sy, sx );
1590 double m = hypot( sx, sy );
1591 uniedit_diffSsysPos( s, uniedit_rotate_cx + m * cos( a + amod ),
1592 uniedit_rotate_cy + m * sin( a + amod ) );
1593 }
1594 }
1595
1596 /* Handle dragging. */
1597 if (uniedit_drag) {
1598 /* axis is inverted */
1599 uniedit_xpos -= rx;
1600 uniedit_ypos += ry;
1601
1602 /* Update mouse movement. */
1603 uniedit_moved += ABS( rx ) + ABS( ry );
1604 } else if (uniedit_dragSys && ( array_size( uniedit_sys ) > 0 )) {
1606 ( SDL_GetTicks() - uniedit_lastClick > UNIEDIT_DRAG_THRESHOLD )) {
1607 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1608 StarSystem *s = uniedit_sys[i];
1609 uniedit_diffSsysPos( s, s->pos.x + rx / uniedit_zoom,
1610 s->pos.y - ry / uniedit_zoom );
1611 }
1612 }
1613
1614 /* Update mouse movement. */
1615 uniedit_moved += ABS( rx ) + ABS( ry );
1616 }
1617 break;
1618 }
1619
1620 return 0;
1621}
1622
1628static int uniedit_checkName( const char *name )
1629{
1630 /* Avoid name collisions. */
1631 for (int i = 0; i < array_size( systems_stack ); i++) {
1632 if (strcmp( name, system_getIndex( i )->name ) == 0) {
1633 dialogue_alert( _( "The Star System '%s' already exists!" ), name );
1634 return 1;
1635 }
1636 }
1637 return 0;
1638}
1639
1640char *uniedit_nameFilter( const char *name )
1641{
1642 size_t len = strlen( name ) + 1;
1643 char *out = malloc( len );
1644 strncpy( out, name, len );
1645 out[len - 1] = '\0';
1646 size_t i = 0;
1647 size_t j = 0;
1648 uint32_t c;
1649 while (( c = u8_nextchar( name, &i ) )) {
1650 if (isascii( c )) {
1651 if (( c == ' ' ) || ( c == '/' ) || ( c == '\\' ) || ( c == ':' ) ||
1652 ( c == '.' )) {
1653 size_t o = u8_offset( name, j );
1654 out[o] = '_';
1655 } else if (isupper( c )) {
1656 size_t o = u8_offset( name, j );
1657 out[o] = tolower( c );
1658 }
1659 }
1660 j++;
1661 }
1662 return out;
1663}
1664
1668static void uniedit_renameSys( void )
1669{
1670 int cancelall_prompt = 0;
1671 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1672 char *name, *oldName, *newName;
1673 const char *prompt;
1674 StarSystem *sys = uniedit_sys[i];
1675
1676 /* Get name. */
1677 if (uniedit_diffMode)
1678 prompt = _( "What do you want to rename #r%s#0?\n\n#rNote:#0 this "
1679 "will only change the display name of the system." );
1680 else
1681 prompt = _( "What do you want to rename #r%s#0?\n\n#rNote:#0 this "
1682 "will rename and copy the system data file." );
1683 name = dialogue_input( _( "Rename Star System" ), 1, 32, prompt,
1684 system_name( sys ) );
1685
1686 /* Keep current name. */
1687 if (name == NULL) {
1688 if (!cancelall_prompt && ( i < array_size( uniedit_sys ) )) {
1689 if (dialogue_YesNoRaw( _( "Cancel batch renaming?" ),
1690 _( "Do you want to cancel renaming all "
1691 "selected star systems?" ) ))
1692 break;
1693 cancelall_prompt = 1;
1694 }
1695 continue;
1696 }
1697
1698 if (uniedit_diffMode) {
1699 uniedit_diffCreateSysStr( sys, HUNK_TYPE_SSYS_DISPLAYNAME,
1700 name ); /* Name is already allocated. */
1701 } else {
1702 char *filtered;
1703
1704 /* Try again. */
1705 if (uniedit_checkName( name )) {
1706 free( name );
1707 i--;
1708 continue;
1709 }
1710
1711 /* Change the name. */
1712 filtered = strdup( sys->filename );
1713 SDL_asprintf( &oldName, "%s/ssys/%s", conf.dev_data_dir,
1714 basename( filtered ) );
1715 free( filtered );
1716
1717 filtered = uniedit_nameFilter( name );
1718 SDL_asprintf( &newName, "%s/ssys/%s.xml", conf.dev_data_dir,
1719 filtered );
1720 free( filtered );
1721
1722 if (rename( oldName, newName ))
1723 WARN( _( "Failed to rename '%s' to '%s'!" ), oldName, newName );
1724
1725 free( oldName );
1726 free( sys->filename );
1727 free( sys->name );
1728
1729 sys->filename = newName;
1730 sys->name = name;
1731 dsys_saveSystem( sys );
1732
1733 /* TODO probably have to reupdate stack?? */
1734
1735 /* Re-save adjacent systems. */
1736 for (int j = 0; j < array_size( sys->jumps ); j++)
1737 dsys_saveSystem( sys->jumps[j].target );
1738 }
1739 }
1740
1741 /* Update text if necessary. */
1743}
1744
1748static void uniedit_newSys( double x, double y )
1749{
1750 char *name;
1751 StarSystem *sys;
1752
1753 if (uniedit_diffMode) {
1755 ( "Adding new systems is not supported in diff mode!" ) );
1756 return;
1757 }
1758
1759 /* Get name. */
1760 name = dialogue_inputRaw( _( "New Star System Creation" ), 1, 32,
1761 _( "What do you want to name the new system?" ) );
1762
1763 /* Abort. */
1764 if (name == NULL) {
1765 dialogue_alertRaw( _( "Star System creation aborted!" ) );
1766 return;
1767 }
1768
1769 /* Make sure there is no collision. */
1770 if (uniedit_checkName( name )) {
1771 free( name );
1772 uniedit_newSys( x, y );
1773 return;
1774 }
1775
1776 /* Create the system. */
1777 sys = system_new();
1778 sys->name = name;
1779 sys->pos.x = x;
1780 sys->pos.y = y;
1781 sys->spacedust = DUST_DENSITY_DEFAULT;
1782 sys->radius = RADIUS_DEFAULT;
1783
1784 /* Set filename. */
1785 char *cleanname = uniedit_nameFilter( sys->name );
1786 SDL_asprintf( &sys->filename, "%s.xml", cleanname );
1787 free( cleanname );
1788
1789 /* Select new system. */
1791 uniedit_selectAdd( sys );
1792
1793 if (conf.devautosave) {
1794 if (dsys_saveSystem( sys ))
1795 uniedit_saveError();
1796 }
1797}
1798
1802static void uniedit_toggleJump( StarSystem *sys )
1803{
1804 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1805 int rm = 0;
1806 StarSystem *isys = uniedit_sys[i];
1807 for (int j = 0; j < array_size( isys->jumps ); j++) {
1808 StarSystem *target = isys->jumps[j].target;
1809 /* Target already exists, remove. */
1810 if (target == sys) {
1811 rm = 1;
1812
1813 if (uniedit_diffMode) {
1814 uniedit_diffCreateSysStr( isys, HUNK_TYPE_JUMP_REMOVE,
1815 strdup( sys->name ) );
1816 } else {
1817 system_rmJump( isys, sys );
1818 system_rmJump( sys, isys );
1819 }
1820
1821 break;
1822 }
1823 }
1824 /* Target doesn't exist, add. */
1825 if (!rm) {
1826 if (uniedit_diffMode) {
1827 uniedit_diffCreateSysStr( isys, HUNK_TYPE_JUMP_ADD,
1828 strdup( sys->name ) );
1829 } else {
1830 system_addJump( isys, sys );
1831 system_addJump( sys, isys );
1832 }
1833 }
1834 }
1835
1836 if (!uniedit_diffMode) {
1837 /* Reconstruct jumps just in case. */
1839 /* Reconstruct universe presences. */
1842
1843 if (conf.devautosave) {
1844 int ret = dsys_saveSystem( sys );
1845 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1846 StarSystem *isys = uniedit_sys[i];
1847 ret |= dsys_saveSystem( isys );
1848 }
1849 if (ret)
1850 uniedit_saveError();
1851 }
1852 }
1853
1854 /* Update sidebar text. */
1856}
1857
1861static void uniedit_deselect( void )
1862{
1864 uniedit_sys = NULL;
1865
1866 /* Change window stuff. */
1867 window_disableButton( uniedit_wid, "btnJump" );
1868 window_disableButton( uniedit_wid, "btnEdit" );
1869 window_disableButton( uniedit_wid, "btnOpen" );
1870 window_modifyText( uniedit_wid, "txtSelected", _( "#nNo selection" ) );
1871 window_modifyText( uniedit_wid, "txtNebula", _( "N/A" ) );
1872 window_modifyText( uniedit_wid, "txtPresence", _( "N/A" ) );
1873}
1874
1878static void uniedit_selectAdd( StarSystem *sys )
1879{
1880 if (uniedit_sys == NULL)
1881 uniedit_sys = array_create( StarSystem * );
1882
1884
1885 /* Set text again. */
1887
1888 /* Enable buttons again. */
1889 window_enableButton( uniedit_wid, "btnJump" );
1890 window_enableButton( uniedit_wid, "btnEdit" );
1891 if (array_size( uniedit_sys ) == 1)
1892 window_enableButton( uniedit_wid, "btnOpen" );
1893 else
1894 window_disableButton( uniedit_wid, "btnOpen" );
1895}
1896
1900static void uniedit_selectRm( StarSystem *sys )
1901{
1902 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1903 if (uniedit_sys[i] == sys) {
1906 if (array_size( uniedit_sys ) == 1)
1907 window_enableButton( uniedit_wid, "btnOpen" );
1908 else
1909 window_disableButton( uniedit_wid, "btnOpen" );
1910 return;
1911 }
1912 }
1913 WARN( _( "Trying to remove system '%s' from selection when not selected." ),
1914 sys->name );
1915}
1916
1921{
1922 int l;
1923 char buf[STRMAX];
1924
1925 l = 0;
1926 for (int i = 0; i < array_size( uniedit_sys ); i++) {
1927 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s%s", uniedit_sys[i]->name,
1928 ( i == array_size( uniedit_sys ) - 1 ) ? "" : ", " );
1929 }
1930
1931 if (l == 0)
1933 else {
1934 window_modifyText( uniedit_wid, "txtSelected", buf );
1935
1936 /* Presence text. */
1937 if (array_size( uniedit_sys ) == 1) {
1938 StarSystem *sys = uniedit_sys[0];
1939
1940 buf[0] = '\0';
1941 l = 0;
1942 if (sys->nebu_density > 0.)
1943 l += scnprintf( &buf[l], sizeof( buf ) - l,
1944 _( "%.0f Density\n%.1f Volatility\n%.0f Hue" ),
1945 sys->nebu_density, sys->nebu_volatility,
1946 sys->nebu_hue * 360. );
1947 if (sys->interference > 0.)
1948 /*l +=*/scnprintf( &buf[l], sizeof( buf ) - l,
1949 _( "%s%.1f Interference" ),
1950 ( l > 0 ) ? "\n" : "", sys->interference );
1951
1952 window_modifyText( uniedit_wid, "txtNebula", buf );
1953
1954 /* Update presence stuff. */
1955 map_updateFactionPresence( uniedit_wid, "txtPresence", sys, 1 );
1956 } else {
1957 window_modifyText( uniedit_wid, "txtNebula",
1958 _( "Multiple selected" ) );
1959 window_modifyText( uniedit_wid, "txtPresence",
1960 _( "Multiple selected" ) );
1961 }
1962 }
1963
1964 window_moveWidget( uniedit_wid, "txtPresence", -10,
1965 -40 - window_getTextHeight( uniedit_wid, "txtNebula" ) );
1966}
1967
1974static void uniedit_buttonZoom( unsigned int wid, const char *str )
1975{
1976 (void)wid;
1977 /* Transform coords to normal. */
1980
1981 /* Apply zoom. */
1982 if (strcmp( str, "btnZoomIn" ) == 0) {
1984 uniedit_zoom =
1986 } else if (strcmp( str, "btnZoomOut" ) == 0) {
1988 uniedit_zoom =
1990 }
1991
1992 /* Transform coords back. */
1995}
1996
2000static void uniedit_findSys( void )
2001{
2002 unsigned int wid;
2003 int x, y;
2004
2005 x = 40;
2006
2007 /* Create the window. */
2008 wid = window_create( "wdwFindSystemsandSpobs", _( "Find Systems and Spobs" ),
2010 uniedit_widFind = wid;
2011
2012 x = 20;
2013
2014 /* Close button. */
2015 window_addButton( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
2016 _( "Close" ), uniedit_findSysClose );
2017
2018 /* Find input widget. */
2019 y = -45;
2020 window_addInput( wid, x, y, UNIEDIT_FIND_WIDTH - 40, 20, "inpFind", 32, 1,
2021 NULL );
2022 window_setInputCallback( wid, "inpFind", uniedit_findSearch );
2023
2024 /* Close when escape is pressed. */
2026
2027 /* Generate the list. */
2028 uniedit_findSearch( wid, NULL );
2029
2030 /* Focus the input widget. */
2031 window_setFocus( wid, "inpFind" );
2032}
2033
2037static void uniedit_findSearch( unsigned int wid, const char *str )
2038{
2039 (void)str;
2040 int n, nspobs, nsystems;
2041 const char *name;
2042 char **spobs, **systems;
2043 map_find_t *found;
2044
2045 name = window_getInput( wid, "inpFind" );
2046
2047 /* Search for names. */
2048 spobs = spob_searchFuzzyCase( name, &nspobs );
2049 systems = system_searchFuzzyCase( name, &nsystems );
2050
2051 free( found_cur );
2052 found_cur = NULL;
2053
2054 /* Construct found table. */
2055 found = malloc( sizeof( map_find_t ) * ( nspobs + nsystems ) );
2056 n = 0;
2057
2058 /* Add spobs to the found table. */
2059 for (int i = 0; i < nspobs; i++) {
2060 /* Spob must be real. */
2061 Spob *spob = spob_get( spobs[i] );
2062 if (spob == NULL)
2063 continue;
2064
2065 const char *sysname = spob_getSystemName( spobs[i] );
2066 if (sysname == NULL)
2067 continue;
2068
2069 StarSystem *sys = system_get( sysname );
2070 if (sys == NULL)
2071 continue;
2072
2073 /* Set some values. */
2074 found[n].spob = spob;
2075 found[n].sys = sys;
2076
2077 /* Set fancy name. */
2078 snprintf( found[n].display, sizeof( found[n].display ),
2079 _( "%s (%s system)" ), spobs[i], system_name( sys ) );
2080 n++;
2081 }
2082 free( spobs );
2083
2084 /* Add systems to the found table. */
2085 for (int i = 0; i < nsystems; i++) {
2086 StarSystem *sys = system_get( systems[i] );
2087
2088 /* Set some values. */
2089 found[n].spob = NULL;
2090 found[n].sys = sys;
2091
2092 strncpy( found[n].display, sys->name, sizeof( found[n].display ) - 1 );
2093 n++;
2094 }
2095 free( systems );
2096
2097 /* Globals. */
2098 found_cur = found;
2099 found_ncur = n;
2100
2101 /* Display results. */
2102 uniedit_findShowResults( wid, found, n );
2103}
2104
2108static void uniedit_findShowResults( unsigned int wid, map_find_t *found,
2109 int n )
2110{
2111 int y, h;
2112 char **str;
2113
2114 /* Destroy if exists. */
2115 if (widget_exists( wid, "lstResults" ))
2116 window_destroyWidget( wid, "lstResults" );
2117
2118 y = -45 - BUTTON_HEIGHT - 20;
2119
2120 if (n == 0) {
2121 str = malloc( sizeof( char * ) );
2122 str[0] = strdup( _( "None" ) );
2123 n = 1;
2124 } else {
2125 qsort( found, n, sizeof( map_find_t ), uniedit_sortCompare );
2126
2127 str = malloc( sizeof( char * ) * n );
2128 for (int i = 0; i < n; i++)
2129 str[i] = strdup( found[i].display );
2130 }
2131
2132 /* Add list. */
2133 h = UNIEDIT_FIND_HEIGHT + y - BUTTON_HEIGHT - 30;
2134 window_addList( wid, 20, y, UNIEDIT_FIND_WIDTH - 40, h, "lstResults", str, n,
2135 0, uniedit_centerSystem, NULL );
2136}
2137
2141static void uniedit_findSysClose( unsigned int wid, const char *name )
2142{
2143 /* Clean up if necessary. */
2144 free( found_cur );
2145 found_cur = NULL;
2146
2147 /* Close the window. */
2148 window_close( wid, name );
2149}
2150
2154static void uniedit_centerSystem( unsigned int wid, const char *unused )
2155{
2156 (void)unused;
2157 StarSystem *sys;
2158 int pos;
2159
2160 /* Make sure it's valid. */
2161 if (found_ncur == 0 || found_cur == NULL)
2162 return;
2163
2164 pos = toolkit_getListPos( wid, "lstResults" );
2165 sys = found_cur[pos].sys;
2166
2167 if (sys == NULL)
2168 return;
2169
2170 /* Center. */
2171 uniedit_xpos = sys->pos.x * uniedit_zoom;
2172 uniedit_ypos = sys->pos.y * uniedit_zoom;
2173}
2174
2178static int uniedit_sortCompare( const void *p1, const void *p2 )
2179{
2180 /* Convert pointer. */
2181 const map_find_t *f1 = (map_find_t *)p1;
2182 const map_find_t *f2 = (map_find_t *)p2;
2183 /* Sort by name, nothing more. */
2184 return strcasecmp( f1->sys->name, f2->sys->name );
2185}
2186
2190static void uniedit_editSys( void )
2191{
2192 unsigned int wid;
2193 int x, y, l;
2194 char buf[STRMAX_SHORT];
2195 const char *s;
2196 StarSystem *sys;
2197
2198 /* Must have a system. */
2199 if (array_size( uniedit_sys ) == 0)
2200 return;
2201 sys = uniedit_sys[0];
2202
2203 /* Create the window. */
2204 wid = window_create( "wdwStarSystemPropertyEditor",
2205 _( "Star System Property Editor" ), -1, -1,
2207 uniedit_widEdit = wid;
2209
2210 x = 20;
2211
2212 /* Close button. */
2213 window_addButton( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
2214 _( "Close" ), uniedit_editSysClose );
2215
2216 /* Rename button. */
2217 y = -45;
2218 snprintf( buf, sizeof( buf ), "%s #n%s", _( "Name:" ),
2219 ( array_size( uniedit_sys ) > 1 ) ? _( "#rvarious" )
2220 : uniedit_sys[0]->name );
2221 window_addText( wid, x, y, 180, 15, 0, "txtName", &gl_smallFont, NULL, buf );
2222 window_addButton( wid, 200, y + 3, BUTTON_WIDTH, 21, "btnRename",
2223 _( "Rename" ), uniedit_btnEditRename );
2224
2225 /* New row. */
2226 y -= gl_defFont.h + 15;
2227
2228 /* Add general stats */
2229 s = _( "Radius" );
2230 l = gl_printWidthRaw( NULL, s );
2231 window_addText( wid, x, y, l, 20, 1, "txtRadius", NULL, NULL, s );
2232 window_addInput( wid, x += l + 7, y, 80, 20, "inpRadius", 10, 1, NULL );
2233 window_setInputFilter( wid, "inpRadius", INPUT_FILTER_NUMBER );
2234 x += 80 + 12;
2235 s = _( "(Scales spob positions)" );
2236 l = gl_printWidthRaw( NULL, s );
2237 window_addText( wid, x, y, l, 20, 1, "txtRadiusComment", NULL, NULL, s );
2238
2239 /* New row. */
2240 x = 20;
2241 y -= gl_defFont.h + 15;
2242
2243 s = _( "Dust" );
2244 l = gl_printWidthRaw( NULL, s );
2245 window_addText( wid, x, y, l, 20, 1, "txtDust", NULL, NULL, s );
2246 window_addInput( wid, x += l + 7, y, 50, 20, "inpDust", 4, 1, NULL );
2247 window_setInputFilter( wid, "inpDust", INPUT_FILTER_NUMBER );
2248 x += 50 + 12;
2249
2250 s = _( "Interference" );
2251 l = gl_printWidthRaw( NULL, s );
2252 window_addText( wid, x, y, l, 20, 1, "txtInterference", NULL, NULL, s );
2253 window_addInput( wid, x += l + 7, y, 55, 20, "inpInterference", 5, 1, NULL );
2254 window_setInputFilter( wid, "inpInterference", INPUT_FILTER_NUMBER );
2255
2256 /* New row. */
2257 x = 20;
2258 y -= gl_defFont.h + 15;
2259
2260 s = _( "Nebula" );
2261 l = gl_printWidthRaw( NULL, s );
2262 window_addText( wid, x, y, l, 20, 1, "txtNebula", NULL, NULL, s );
2263 window_addInput( wid, x += l + 7, y, 50, 20, "inpNebula", 4, 1, NULL );
2264 window_setInputFilter( wid, "inpNebula", INPUT_FILTER_NUMBER );
2265 x += 50 + 12;
2266
2267 s = _( "Volatility" );
2268 l = gl_printWidthRaw( NULL, s );
2269 window_addText( wid, x, y, l, 20, 1, "txtVolatility", NULL, NULL, s );
2270 window_addInput( wid, x += l + 7, y, 50, 20, "inpVolatility", 4, 1, NULL );
2271 window_setInputFilter( wid, "inpVolatility", INPUT_FILTER_NUMBER );
2272 x += 50 + 12;
2273
2274 s = _( "Hue" );
2275 l = gl_printWidthRaw( NULL, s );
2276 window_addText( wid, x, y, l, 20, 1, "txtHue", NULL, NULL, s );
2277 window_addInput( wid, x += l + 7, y, 50, 20, "inpHue", 4, 1, NULL );
2278 window_setInputFilter( wid, "inpHue", INPUT_FILTER_NUMBER );
2279 x += 50 + 12;
2280
2281 /* Next row. */
2282 // x = 20;
2283 y -= gl_defFont.h + 15;
2284
2285 s = _( "No lanes" );
2286 window_addCheckbox( wid, x, y, 100, gl_defFont.h, "chkNolanes", s,
2287 uniedit_chkNolanes, sys_isFlag( sys, SYSTEM_NOLANES ) );
2288
2289 /* Tags. */
2290 x = 20;
2291 y -= gl_defFont.h + 15;
2292 l = scnprintf( buf, sizeof( buf ), "#n%s#0", _( "Tags: " ) );
2293 for (int i = 0; i < array_size( sys->tags ); i++)
2294 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s%s",
2295 ( i == 0 ) ? "" : ", ", sys->tags[i] );
2296 window_addText( wid, x, y, UNIEDIT_EDIT_WIDTH - 40, 20, 0, "txtTags", NULL,
2297 NULL, buf );
2298
2299 /* Load values */
2300 snprintf( buf, sizeof( buf ), "%g", sys->radius );
2301 window_setInput( wid, "inpRadius", buf );
2302 snprintf( buf, sizeof( buf ), "%d", sys->spacedust );
2303 window_setInput( wid, "inpDust", buf );
2304 snprintf( buf, sizeof( buf ), "%g", sys->interference );
2305 window_setInput( wid, "inpInterference", buf );
2306 snprintf( buf, sizeof( buf ), "%g", sys->nebu_density );
2307 window_setInput( wid, "inpNebula", buf );
2308 snprintf( buf, sizeof( buf ), "%g", sys->nebu_volatility );
2309 window_setInput( wid, "inpVolatility", buf );
2310 snprintf( buf, sizeof( buf ), "%g", sys->nebu_hue * 360. );
2311 window_setInput( wid, "inpHue", buf );
2312
2313 /* Generate the list. */
2314 uniedit_editGenList( wid );
2315}
2316
2320static void uniedit_editGenList( unsigned int wid )
2321{
2322 int j, n;
2323 StarSystem *sys;
2324 char **str;
2325 int y, h, has_spobs;
2326
2327 /* Destroy if exists. */
2328 if (widget_exists( wid, "lstSpobs" ))
2329 window_destroyWidget( wid, "lstSpobs" );
2330
2331 y = -180;
2332
2333 /* Check to see if it actually has virtual spobs. */
2334 sys = uniedit_sys[0];
2335 n = array_size( sys->spobs_virtual );
2336 has_spobs = !!n;
2337
2338 /* Generate list. */
2339 j = 0;
2340 str = malloc( sizeof( char * ) * ( n + 1 ) );
2341 if (has_spobs) {
2342 /* Virtual spob button. */
2343 for (int i = 0; i < n; i++) {
2344 const VirtualSpob *va = sys->spobs_virtual[i];
2345 str[j++] = strdup( va->name );
2346 }
2347 } else
2348 str[j++] = strdup( _( "None" ) );
2349
2350 /* Add list. */
2351 h = UNIEDIT_EDIT_HEIGHT + y - 20 - 2 * ( BUTTON_HEIGHT + 20 );
2352 window_addList( wid, 20, y, UNIEDIT_EDIT_WIDTH - 40, h, "lstSpobs", str, j,
2353 0, NULL, NULL );
2354 y -= h + 20;
2355
2356 /* Add buttons if needed. */
2357 if (!widget_exists( wid, "btnRmSpob" ))
2358 window_addButton( wid, -20, y + 3, BUTTON_WIDTH, BUTTON_HEIGHT,
2359 "btnRmSpob", _( "Remove" ), uniedit_btnEditRmSpob );
2360 if (!widget_exists( wid, "btnAddSpob" ))
2361 window_addButton( wid, -20 - ( 20 + BUTTON_WIDTH ), y + 3, BUTTON_WIDTH,
2362 BUTTON_HEIGHT, "btnAddSpob", _( "Add" ),
2364
2365 if (!widget_exists( wid, "btnEditTags" ))
2366 window_addButton( wid, -20 - ( 20 + BUTTON_WIDTH ) * 2, y + 3,
2367 BUTTON_WIDTH, BUTTON_HEIGHT, "btnEditTags",
2368 _( "Edit Tags" ), uniedit_btnEditTags );
2369}
2370
2374static void uniedit_editSysClose( unsigned int wid, const char *name )
2375{
2376 StarSystem *sys;
2377 double scale;
2378 int data;
2379 double fdata;
2380
2381 /* We already know the system exists because we checked when opening the
2382 * dialog. */
2383 sys = uniedit_sys[0];
2384
2385 /* Changes in radius need to scale the system spob positions. */
2386 scale = atof( window_getInput( wid, "inpRadius" ) ) / sys->radius;
2387 if (fabs( scale - 1. ) > 1e-5) {
2388 if (uniedit_diffMode)
2390 _( "Changing system radius not supported in diff mode!" ) );
2391 else
2392 sysedit_sysScale( sys, scale );
2393 }
2394
2395 data = atoi( window_getInput( wid, "inpDust" ) );
2396 if (data != sys->spacedust) {
2397 if (uniedit_diffMode)
2398 uniedit_diffCreateSysInt( sys, HUNK_TYPE_SSYS_DUST, data );
2399 else
2400 sys->spacedust = data;
2401 }
2402 fdata = atof( window_getInput( wid, "inpInterference" ) );
2403 if (fabs( sys->interference - fdata ) > 1e-5) {
2404 if (uniedit_diffMode)
2405 uniedit_diffCreateSysFloat( sys, HUNK_TYPE_SSYS_INTERFERENCE, fdata );
2406 else
2407 sys->interference = fdata;
2408 }
2409 fdata = atof( window_getInput( wid, "inpNebula" ) );
2410 if (fabs( sys->nebu_density - fdata ) > 1e-5) {
2411 if (uniedit_diffMode)
2412 uniedit_diffCreateSysFloat( sys, HUNK_TYPE_SSYS_NEBU_DENSITY, fdata );
2413 else
2414 sys->nebu_density = fdata;
2415 }
2416 fdata = atof( window_getInput( wid, "inpVolatility" ) );
2417 if (fabs( sys->nebu_volatility - fdata ) > 1e-5) {
2418 if (uniedit_diffMode)
2419 uniedit_diffCreateSysFloat( sys, HUNK_TYPE_SSYS_NEBU_VOLATILITY,
2420 fdata );
2421 else
2422 sys->nebu_volatility = fdata;
2423 }
2424 fdata = atof( window_getInput( wid, "inpHue" ) ) / 360.;
2425 if (fabs( sys->nebu_hue - fdata ) > 1e-5) {
2426 if (uniedit_diffMode)
2427 uniedit_diffCreateSysFloat( sys, HUNK_TYPE_SSYS_NEBU_HUE, fdata );
2428 else
2429 sys->nebu_hue = fdata;
2430 }
2431
2432 /* Reset trails if necessary. */
2433 Pilot *const *plt_stack = pilot_getAll();
2434 for (int i = 0; i < array_size( plt_stack ); i++)
2435 pilot_clearTrails( plt_stack[i] );
2436
2437 /* Only update when not doing diffs. */
2438 if (!uniedit_diffMode) {
2439 /* Reconstruct universe presences. */
2442 }
2443
2444 /* Text might need changing. */
2446
2447 if (conf.devautosave) {
2448 if (dsys_saveSystem( uniedit_sys[0] ))
2449 uniedit_saveError();
2450 }
2451
2452 /* Close the window. */
2453 window_close( wid, name );
2454}
2455
2459static void uniedit_btnEditRmSpob( unsigned int wid, const char *unused )
2460{
2461 (void)unused;
2462 /* Get selection. */
2463 const char *selected = toolkit_getList( wid, "lstSpobs" );
2464
2465 /* Make sure it's valid. */
2466 if (( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ))
2467 return;
2468
2469 if (uniedit_diffMode) {
2470 uniedit_diffCreateSysStr( uniedit_sys[0], HUNK_TYPE_VSPOB_REMOVE,
2471 strdup( selected ) );
2472 } else {
2473 /* Remove the spob. */
2474 int ret = system_rmVirtualSpob( uniedit_sys[0], selected );
2475 if (ret != 0) {
2476 dialogue_alert( _( "Failed to remove virtual spob '%s'!" ), selected );
2477 return;
2478 }
2479
2480 /* Run galaxy modifications. */
2483 }
2484
2485 uniedit_editGenList( wid );
2486}
2487
2491static void uniedit_btnEditAddSpob( unsigned int parent, const char *unused )
2492{
2493 (void)parent;
2494 (void)unused;
2495 unsigned int wid;
2496 const VirtualSpob *va;
2497 char **str;
2498 int h;
2499
2500 /* Get all spobs. */
2501 va = virtualspob_getAll();
2502 if (array_size( va ) == 0) {
2503 dialogue_alert( _( "No virtual spobs to add! Please add virtual spobs to "
2504 "the '%s' directory first." ),
2505 VIRTUALSPOB_DATA_PATH );
2506 return;
2507 }
2508
2509 /* Create the window. */
2510 wid = window_create( "wdwAddaVirtualSpob", _( "Add a Virtual Spob" ), -1, -1,
2513
2514 /* Add virtual spob list. */
2515 str = malloc( sizeof( char * ) * array_size( va ) );
2516 for (int i = 0; i < array_size( va ); i++)
2517 str[i] = strdup( va[i].name );
2518 h = UNIEDIT_EDIT_HEIGHT - 60 - ( BUTTON_HEIGHT + 20 );
2519 window_addList( wid, 20, -40, UNIEDIT_EDIT_WIDTH - 40, h, "lstSpobs", str,
2520 array_size( va ), 0, NULL, NULL );
2521
2522 /* Close button. */
2523 window_addButton( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
2524 _( "Close" ), window_close );
2525
2526 /* Add button. */
2527 window_addButton( wid, -20 - ( BUTTON_WIDTH + 20 ), 20, BUTTON_WIDTH,
2528 BUTTON_HEIGHT, "btnAdd", _( "Add" ),
2530}
2531
2535static void uniedit_btnEditAddSpobAdd( unsigned int wid, const char *unused )
2536{
2537 const char *selected;
2538
2539 /* Get selection. */
2540 selected = toolkit_getList( wid, "lstSpobs" );
2541 if (selected == NULL)
2542 return;
2543
2544 if (uniedit_diffMode) {
2545 uniedit_diffCreateSysStr( uniedit_sys[0], HUNK_TYPE_VSPOB_ADD,
2546 strdup( selected ) );
2547 } else {
2548 /* Add virtual presence. */
2549 int ret = system_addVirtualSpob( uniedit_sys[0], selected );
2550 if (ret != 0) {
2551 dialogue_alert( _( "Failed to add virtual spob '%s'!" ), selected );
2552 return;
2553 }
2554
2555 /* Run galaxy modifications. */
2558
2559 if (conf.devautosave) {
2560 if (dsys_saveSystem( uniedit_sys[0] ))
2561 uniedit_saveError();
2562 }
2563 }
2564
2565 /* Regenerate the list. */
2567
2568 /* Close the window. */
2569 window_close( wid, unused );
2570}
2571
2575static void uniedit_btnEditTags( unsigned int wid, const char *unused )
2576{
2577 (void)unused;
2578 int y, w, bw;
2579
2580 /* Create the window. */
2581 wid = window_create( "wdwSystemTagsEditor", _( "System Tags Editor" ), -1,
2583 window_setCancel( wid, uniedit_btnTagsClose );
2584
2585 w = ( UNIEDIT_EDIT_WIDTH - 40 - 15 ) / 2.;
2586 bw = ( UNIEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
2587
2588 /* Close button. */
2589 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
2590 uniedit_btnTagsClose );
2591 y = 20 + BUTTON_HEIGHT + 15;
2592
2593 /* Remove button. */
2594 window_addButton( wid, -20 - ( w + 15 ), y, w, BUTTON_HEIGHT, "btnRm",
2595 _( "Rm Tag" ), uniedit_btnRmTag );
2596
2597 /* Add button. */
2598 window_addButton( wid, -20, y, w, BUTTON_HEIGHT, "btnAdd", _( "Add Tag" ),
2600
2601 /* New tag. */
2602 window_addButton( wid, -20 - ( w + 15 ), 20, w, BUTTON_HEIGHT, "btnNew",
2603 _( "New Tag" ), uniedit_btnNewTag );
2604
2605 /* Generate list of tags. */
2606 if (uniedit_tagslist == NULL) {
2607 StarSystem *systems_all = system_getAll();
2608 uniedit_tagslist = array_create( char * );
2609 for (int i = 0; i < array_size( systems_all ); i++) {
2610 StarSystem *s = &systems_all[i];
2611 for (int j = 0; j < array_size( s->tags ); j++) {
2612 const char *t = s->tags[j];
2613 int found = 0;
2614 for (int k = 0; k < array_size( uniedit_tagslist ); k++)
2615 if (strcmp( uniedit_tagslist[k], t ) == 0) {
2616 found = 1;
2617 break;
2618 }
2619 if (!found)
2620 array_push_back( &uniedit_tagslist, strdup( t ) );
2621 }
2622 }
2623 qsort( uniedit_tagslist, array_size( uniedit_tagslist ), sizeof( char * ),
2624 strsort );
2625 }
2626
2627 uniedit_genTagsList( wid );
2628}
2629
2630/*
2631 * Tags are closed so update tags.
2632 */
2633static void uniedit_btnTagsClose( unsigned int wid, const char *unused )
2634{
2635 char buf[STRMAX_SHORT];
2636 StarSystem *s = uniedit_sys[0];
2637 int l = scnprintf( buf, sizeof( buf ), "#n%s#0", _( "Tags: " ) );
2638 for (int i = 0; i < array_size( s->tags ); i++)
2639 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s%s",
2640 ( ( i > 0 ) ? ", " : "" ), s->tags[i] );
2641 window_modifyText( uniedit_widEdit, "txtTags", buf );
2642
2643 window_close( wid, unused );
2644}
2645
2649static void uniedit_genTagsList( unsigned int wid )
2650{
2651 StarSystem *s;
2652 char **have, **lack;
2653 int n, x, y, w, h, hpos, lpos, empty;
2654
2655 hpos = lpos = -1;
2656
2657 /* Destroy if exists. */
2658 if (widget_exists( wid, "lstTagsHave" ) &&
2659 widget_exists( wid, "lstTagsLacked" )) {
2660 hpos = toolkit_getListPos( wid, "lstTagsHave" );
2661 lpos = toolkit_getListPos( wid, "lstTagsLacked" );
2662 window_destroyWidget( wid, "lstTagsHave" );
2663 window_destroyWidget( wid, "lstTagsLacked" );
2664 }
2665
2666 s = uniedit_sys[0];
2667 w = ( UNIEDIT_EDIT_WIDTH - 40 - 15 ) / 2.;
2668 x = -20 - w - 15;
2669 y = 20 + BUTTON_HEIGHT * 2 + 30;
2670 h = UNIEDIT_EDIT_HEIGHT - y - 30;
2671
2672 /* Get all the techs the spob has. */
2673 n = array_size( s->tags );
2674 if (n > 0) {
2675 have = malloc( n * sizeof( char * ) );
2676 for (int i = 0; i < n; i++)
2677 have[i] = strdup( s->tags[i] );
2678 empty = 0;
2679 } else {
2680 have = malloc( sizeof( char * ) );
2681 have[n++] = strdup( _( "None" ) );
2682 empty = 1;
2683 }
2684
2685 /* Add list. */
2686 window_addList( wid, x, y, w, h, "lstTagsHave", have, n, 0, NULL,
2688 x += w + 15;
2689
2690 /* Omit the techs that the spob already has from the list. */
2691 n = 0;
2692 lack = malloc( array_size( uniedit_tagslist ) * sizeof( char * ) );
2693 for (int i = 0; i < array_size( uniedit_tagslist ); i++) {
2694 const char *t = uniedit_tagslist[i];
2695 if (empty)
2696 lack[n++] = strdup( t );
2697 else {
2698 int found = 0;
2699 for (int j = 0; j < array_size( s->tags ); j++)
2700 if (strcmp( s->tags[j], t ) == 0) {
2701 found = 1;
2702 break;
2703 }
2704 if (!found)
2705 lack[n++] = strdup( t );
2706 }
2707 }
2708
2709 /* Add list. */
2710 window_addList( wid, x, y, w, h, "lstTagsLacked", lack, n, 0, NULL,
2712
2713 /* Restore positions. */
2714 if (hpos != -1 && lpos != -1) {
2715 toolkit_setListPos( wid, "lstTagsHave", hpos );
2716 toolkit_setListPos( wid, "lstTagsLacked", lpos );
2717 }
2718}
2719
2723static void uniedit_btnAddTag( unsigned int wid, const char *unused )
2724{
2725 (void)unused;
2726 const char *selected = toolkit_getList( wid, "lstTagsLacked" );
2727 if (( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ))
2728 return;
2729
2730 if (uniedit_diffMode) {
2731 uniedit_diffCreateSysStr( uniedit_sys[0], HUNK_TYPE_SSYS_TAG_ADD,
2732 strdup( selected ) );
2733 } else {
2734 StarSystem *s = uniedit_sys[0];
2735 if (s->tags == NULL)
2736 s->tags = array_create( char * );
2737 array_push_back( &s->tags, strdup( selected ) );
2738 }
2739
2740 /* Regenerate the list. */
2741 uniedit_genTagsList( wid );
2742}
2743
2747static void uniedit_btnRmTag( unsigned int wid, const char *unused )
2748{
2749 (void)unused;
2750 const char *selected = toolkit_getList( wid, "lstTagsHave" );
2751 if (( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ))
2752 return;
2753
2754 if (uniedit_diffMode) {
2755 uniedit_diffCreateSysStr( uniedit_sys[0], HUNK_TYPE_SSYS_TAG_REMOVE,
2756 strdup( selected ) );
2757 } else {
2758 int i;
2759 StarSystem *s = uniedit_sys[0];
2760 for (i = 0; i < array_size( s->tags ); i++)
2761 if (strcmp( selected, s->tags[i] ) == 0)
2762 break;
2763 if (i >= array_size( s->tags ))
2764 return;
2765 free( s->tags[i] );
2766 array_erase( &s->tags, &s->tags[i], &s->tags[i + 1] );
2767 }
2768
2769 /* Regenerate the list. */
2770 uniedit_genTagsList( wid );
2771}
2772
2776static void uniedit_btnNewTag( unsigned int wid, const char *unused )
2777{
2778 (void)unused;
2779 char *tag =
2780 dialogue_input( _( "Add New System Tag" ), 1, 128,
2781 _( "Please write the new tag to add to the system." ) );
2782 if (tag == NULL)
2783 return;
2784
2785 if (uniedit_diffMode) {
2786 uniedit_diffCreateSysStr( uniedit_sys[0], HUNK_TYPE_SSYS_TAG_ADD,
2787 strdup( tag ) );
2788 } else {
2789 StarSystem *s = uniedit_sys[0];
2790 if (s->tags == NULL)
2791 s->tags = array_create( char * );
2792 array_push_back( &s->tags, tag ); /* tag gets freed later. */
2793 }
2794
2795 /* Also add to list of all tags. */
2796 array_push_back( &uniedit_tagslist, strdup( tag ) );
2797
2798 /* Regenerate the list. */
2799 uniedit_genTagsList( wid );
2800}
2801
2805static void uniedit_btnEditRename( unsigned int wid, const char *unused )
2806{
2807 (void)unused;
2808 char buf[STRMAX_SHORT];
2809
2810 /* Rename systems. */
2812
2813 /* Update text. */
2814 snprintf( buf, sizeof( buf ), "%s #n%s", _( "Name:" ),
2815 ( array_size( uniedit_sys ) > 1 ) ? _( "#rvarious" )
2816 : uniedit_sys[0]->name );
2817 window_modifyText( wid, "txtName", buf );
2818}
2819
2823static void uniedit_btnViewModeSet( unsigned int wid, const char *unused )
2824{
2825 const char *selected;
2826 int pos;
2827
2828 /* Check default. */
2829 pos = toolkit_getListPos( wid, "lstViewModes" );
2831 if (pos == 0) {
2832 uniedit_viewmode = UNIEDIT_VIEW_DEFAULT;
2833 window_close( wid, unused );
2834 return;
2835 } else if (pos == 1) {
2836 uniedit_viewmode = UNIEDIT_VIEW_VIRTUALSPOBS;
2837 window_close( wid, unused );
2838 return;
2839 } else if (pos == 2) {
2840 uniedit_viewmode = UNIEDIT_VIEW_RADIUS;
2841 window_close( wid, unused );
2842 return;
2843 } else if (pos == 3) {
2844 uniedit_viewmode = UNIEDIT_VIEW_NOLANES;
2845 window_close( wid, unused );
2846 return;
2847 } else if (pos == 4) {
2848 uniedit_viewmode = UNIEDIT_VIEW_BACKGROUND;
2849 window_close( wid, unused );
2850 return;
2851 } else if (pos == 5) {
2852 uniedit_viewmode = UNIEDIT_VIEW_ASTEROIDS;
2853 window_close( wid, unused );
2854 return;
2855 } else if (pos == 6) {
2856 uniedit_viewmode = UNIEDIT_VIEW_INTERFERENCE;
2857 window_close( wid, unused );
2858 return;
2859 } else if (pos == 7) {
2860 uniedit_viewmode = UNIEDIT_VIEW_TECH;
2861 window_close( wid, unused );
2862 return;
2863 } else if (pos == 8) {
2864 uniedit_viewmode = UNIEDIT_VIEW_PRESENCE_SUM;
2865 window_close( wid, unused );
2866 return;
2867 }
2868
2869 /* Get selection. */
2870 selected = toolkit_getList( wid, "lstViewModes" );
2871 if (selected == NULL)
2872 return;
2873
2874 uniedit_viewmode = UNIEDIT_VIEW_PRESENCE;
2875 uniedit_view_faction = faction_get( selected );
2876
2877 /* Close the window. */
2878 window_close( wid, unused );
2879}
2880
2881static void uniedit_chkNolanes( unsigned int wid, const char *wgtname )
2882{
2883 int s = window_checkboxState( wid, wgtname );
2884 StarSystem *sys = uniedit_sys[0];
2885 if (uniedit_diffMode) {
2886 if (s)
2887 uniedit_diffCreateSysNone( sys, HUNK_TYPE_SSYS_NOLANES_ADD );
2888 else
2889 uniedit_diffCreateSysNone( sys, HUNK_TYPE_SSYS_NOLANES_REMOVE );
2890 } else {
2891 if (s)
2892 sys_setFlag( sys, SYSTEM_NOLANES );
2893 else
2894 sys_rmFlag( sys, SYSTEM_NOLANES );
2895 }
2896}
2897
2898static void uniedit_diffClear( void )
2899{
2900 diff_start();
2901 for (int i = 0; i < array_size( uniedit_diff ); i++) {
2902 UniHunk_t *h = &uniedit_diff[i];
2903 diff_revertHunk( h );
2904 diff_cleanupHunk( h );
2905 }
2906 diff_end();
2907
2908 array_free( uniedit_diff );
2909 uniedit_diff = NULL;
2910}
2911
2912static int uniedit_diff_cmp( const void *p1, const void *p2 )
2913{
2914 const UniHunk_t *h1 = p1;
2915 const UniHunk_t *h2 = p2;
2916 int ret = h1->target.type - h2->target.type;
2917 if (ret)
2918 return ret;
2919 /* Should be same type. */
2920 ret = strcmp( h1->target.u.name, h2->target.u.name );
2921 if (ret)
2922 return ret;
2923 return h1->type -
2924 h2->type; /* Should not overlap with same target and type. */
2925}
2926
2927void uniedit_diffCreateSysNone( const StarSystem *sys, UniHunkType_t type )
2928{
2929 UniHunk_t hunk;
2930 memset( &hunk, 0, sizeof( hunk ) );
2931 hunk.target.type = HUNK_TARGET_SYSTEM;
2932 hunk.target.u.name = strdup( sys->name );
2933 hunk.type = type;
2934 hunk.dtype = HUNK_DATA_NONE;
2935 uniedit_diffAdd( &hunk );
2936}
2937
2938void uniedit_diffCreateSysStr( const StarSystem *sys, UniHunkType_t type,
2939 char *str )
2940{
2941 uniedit_diffCreateSysStrAttr( sys, type, str, NULL );
2942}
2943void uniedit_diffCreateSysStrAttr( const StarSystem *sys, UniHunkType_t type,
2944 char *str, UniAttribute_t *attr )
2945{
2946 UniHunk_t hunk;
2947 memset( &hunk, 0, sizeof( hunk ) );
2948 hunk.target.type = HUNK_TARGET_SYSTEM;
2949 hunk.target.u.name = strdup( sys->name );
2950 hunk.type = type;
2951 hunk.dtype = HUNK_DATA_STRING;
2952 hunk.u.name = str;
2953 hunk.attr = attr;
2954 uniedit_diffAdd( &hunk );
2955}
2956
2957void uniedit_diffCreateSysInt( const StarSystem *sys, UniHunkType_t type,
2958 int data )
2959{
2960 uniedit_diffCreateSysIntAttr( sys, type, data, NULL );
2961}
2962void uniedit_diffCreateSysIntAttr( const StarSystem *sys, UniHunkType_t type,
2963 int data, UniAttribute_t *attr )
2964{
2965 UniHunk_t hunk;
2966 memset( &hunk, 0, sizeof( hunk ) );
2967 hunk.target.type = HUNK_TARGET_SYSTEM;
2968 hunk.target.u.name = strdup( sys->name );
2969 hunk.type = type;
2970 hunk.dtype = HUNK_DATA_INT;
2971 hunk.u.data = data;
2972 hunk.attr = attr;
2973 uniedit_diffAdd( &hunk );
2974}
2975
2976void uniedit_diffCreateSysFloat( const StarSystem *sys, UniHunkType_t type,
2977 double fdata )
2978{
2979 uniedit_diffCreateSysFloatAttr( sys, type, fdata, NULL );
2980}
2981void uniedit_diffCreateSysFloatAttr( const StarSystem *sys, UniHunkType_t type,
2982 double fdata, UniAttribute_t *attr )
2983{
2984 UniHunk_t hunk;
2985 memset( &hunk, 0, sizeof( hunk ) );
2986 hunk.target.type = HUNK_TARGET_SYSTEM;
2987 hunk.target.u.name = strdup( sys->name );
2988 hunk.type = type;
2989 hunk.dtype = HUNK_DATA_FLOAT;
2990 hunk.u.fdata = fdata;
2991 hunk.attr = attr;
2992 uniedit_diffAdd( &hunk );
2993}
2994
2995void uniedit_diffAdd( UniHunk_t *hunk )
2996{
2997 uniedit_diffSaved = 0; /* Unsaved progress. */
2998 diff_start();
2999
3000 /* Replace if already same type exists. */
3001 for (int i = 0; i < array_size( uniedit_diff ); i++) {
3002 UniHunk_t *hi = &uniedit_diff[i];
3003 if (hi->target.type != hunk->target.type)
3004 continue;
3005 if (strcmp( hi->target.u.name, hunk->target.u.name ) != 0)
3006 continue;
3007 if (hi->type != hunk->type)
3008 continue;
3009 if (array_size( hi->attr ) != array_size( hunk->attr ))
3010 continue;
3011 if (( hi->attr != NULL ) && ( hunk->attr != NULL )) {
3012 for (int j = 0; j < array_size( hi->attr ); j++) {
3013 int found = 0;
3014 for (int k = 0; k < array_size( hunk->attr ); k++) {
3015 if (( strcmp( hi->attr[j].name, hunk->attr[k].name ) == 0 ) ||
3016 ( strcmp( hi->attr[j].name, hunk->attr[k].name ) == 0 )) {
3017 found = 1;
3018 break;
3019 }
3020 }
3021 if (!found)
3022 continue;
3023 }
3024 }
3025
3026 /* Have to revert the old one and then patch. */
3027 diff_revertHunk( hi );
3028 diff_cleanupHunk( hi );
3029 if (diff_patchHunk( hunk ))
3030 WARN( _( "uniedit: failed to patch '%s'" ),
3031 diff_hunkName( hunk->type ) );
3032 diff_end();
3033 memcpy( hi, hunk, sizeof( UniHunk_t ) );
3034 return;
3035 }
3036
3037 /* Patch the hunk. */
3038 if (diff_patchHunk( hunk ))
3039 WARN( _( "uniedit: failed to patch '%s'" ), diff_hunkName( hunk->type ) );
3040 diff_end();
3041
3042 array_push_back( &uniedit_diff, *hunk );
3043
3044 /* Sort, order shouldn't matter, but it will help save in a coherent way. */
3045 qsort( uniedit_diff, array_size( uniedit_diff ), sizeof( UniHunk_t ),
3046 uniedit_diff_cmp );
3047}
3048
3049static void uniedit_diffSsysPos( StarSystem *s, double x, double y )
3050{
3051 UniHunk_t hunk;
3052
3053 if (!uniedit_diffMode) {
3054 s->pos.x = x;
3055 s->pos.y = y;
3056 return;
3057 }
3058
3059 hunk.target.type = HUNK_TARGET_SYSTEM;
3060 hunk.target.u.name = strdup( s->name );
3061 hunk.type = HUNK_TYPE_SSYS_POS_X;
3062 hunk.dtype = HUNK_DATA_FLOAT;
3063 hunk.u.fdata = x;
3064 uniedit_diffAdd( &hunk );
3065
3066 hunk.target.u.name = strdup( s->name );
3067 hunk.type = HUNK_TYPE_SSYS_POS_Y;
3068 hunk.u.fdata = y;
3069 uniedit_diffAdd( &hunk );
3070}
3071
3072static void uniedit_diff_regenList( unsigned int wid )
3073{
3074 char **items;
3075 int w, h;
3076 int p = 0;
3077
3078 window_dimWindow( wid, &w, &h );
3079 if (widget_exists( wid, "lstDiffs" )) {
3080 p = toolkit_getListPos( wid, "lstDiffs" );
3081 window_destroyWidget( wid, "lstDiffs" );
3082 }
3083
3084 items = malloc( sizeof( char * ) * array_size( uniedit_diff ) );
3085 for (int i = 0; i < array_size( uniedit_diff ); i++) {
3086 const UniHunk_t *hi = &uniedit_diff[i];
3087 SDL_asprintf( &items[i], "%s: %s", hi->target.u.name,
3088 diff_hunkName( hi->type ) );
3089 }
3090 int y = -30 - 30 - 20;
3091 window_addList( wid, 20, y, w - 40, h + y - BUTTON_HEIGHT - 40, "lstDiffs",
3092 items, array_size( uniedit_diff ), p, NULL, NULL );
3093}
3094
3095static void uniedit_diffEditor( unsigned int wid_unused, const char *unused )
3096{
3097 (void)wid_unused;
3098 (void)unused;
3099 const int w = 600;
3100 const int h = 400;
3101 int y;
3102 unsigned int wid =
3103 window_create( "wdwEditorDiffs", _( "Diff Options" ), -1, -1, w, h );
3104 window_onClose( wid, uniedit_diff_close );
3105
3106 /* Close button. */
3107 window_addButton( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
3108 _( "Close" ), window_close );
3109
3110 /* Autosave toggle. */
3111 y = -30;
3112 window_addCheckbox(
3113 wid, 20, y, w - 40, 20, "chkDiffMode",
3114 _( "Diff Mode (creates a diff instead of direct modification)" ),
3115 uniedit_diff_toggle, uniedit_diffMode );
3116 y -= 30;
3117
3118 /* List current changes. */
3119 window_addText( wid, 20, y, w - 40, 20, 0, "txtSDiff", NULL, NULL,
3120 _( "#nCurrent Diff Contents:" ) );
3121 /* y -= 20; */
3122 uniedit_diff_regenList( wid );
3123
3124 /* More buttons. */
3125 window_addButton( wid, -20 - ( BUTTON_WIDTH + 20 ) * 1, 20, BUTTON_WIDTH,
3126 BUTTON_HEIGHT, "btnLoad", _( "Load" ), uniedit_diff_load );
3127 window_addButton( wid, -20 - ( BUTTON_WIDTH + 20 ) * 2, 20, BUTTON_WIDTH,
3128 BUTTON_HEIGHT, "btnRemove", _( "Remove" ),
3129 uniedit_diff_remove );
3130}
3131
3132static void uniedit_diff_toggle( unsigned int wid, const char *wgt )
3133{
3134 if (uniedit_diffMode && !uniedit_diffSaved) {
3135 if (!dialogue_YesNoRaw(
3136 _( "#rUnsaved Progress" ),
3137 _( "You have #runsaved changes#0 to the universe diff. Are you "
3138 "sure you wish to disable diff mode and #rlose all your "
3139 "changes#0?" ) )) {
3140 window_checkboxSet( wid, wgt, 1 );
3141 return;
3142 }
3143 }
3144 uniedit_diffMode = window_checkboxState( wid, wgt );
3145 if (!uniedit_diffMode) {
3146 uniedit_diffClear();
3147 diff_clear();
3148 /* Regen list. */
3149 uniedit_diff_regenList( wid );
3150 }
3151}
3152
3153static void uniedit_diff_load_callback( void *userdata,
3154 const char *const *filelist,
3155 int filter )
3156{
3157 (void)filter;
3158 unsigned int wid = *(unsigned int *)userdata;
3159 UniDiffData_t data;
3160
3161 if (filelist == NULL) {
3162 WARN( _( "Error calling %s: %s" ), "SDL_ShowOpenFileDialog",
3163 SDL_GetError() );
3164 return;
3165 } else if (filelist[0] == NULL) {
3166 /* Cancelled by user. */
3167 return;
3168 }
3169
3170 /* TODO with SDL3 this can be called from another thread, so we have to make
3171 * this more robust... */
3172 uniedit_diffClear();
3173 diff_parse( &data, strdup( filelist[0] ) );
3174 uniedit_diff = data.hunks;
3175 data.hunks = NULL;
3176 diff_freeData( &data );
3177
3178 /* We're now in diff mode! */
3179 uniedit_diffMode = 1;
3180 window_checkboxSet( wid, "chkDiffMode", 1 );
3181
3182 /* Apply the patches. */
3183 diff_start();
3184 for (int i = 0; i < array_size( uniedit_diff ); i++) {
3185 UniHunk_t *hunk = &uniedit_diff[i];
3186 diff_patchHunk( hunk );
3187 }
3188 diff_end();
3189
3190 /* Regen list .*/
3191 uniedit_diff_regenList( wid );
3192}
3193
3194static void uniedit_diff_load( unsigned int wid, const char *wgt )
3195{
3196 (void)wgt;
3197 const SDL_DialogFileFilter filter[] = {
3198 { .name = _( "Diff XML file" ), .pattern = "xml" },
3199 { NULL, NULL },
3200 };
3201 /* Open dialogue to load the diff. */
3202 SDL_ShowOpenFileDialog( uniedit_diff_load_callback, &wid, gl_screen.window,
3203 filter, conf.dev_data_dir, 0 );
3204}
3205
3206static void uniedit_diff_remove( unsigned int wid, const char *unused )
3207{
3208 (void)unused;
3209 int p = toolkit_getListPos( wid, "lstDiffs" );
3210
3211 /* Undo hunk. */
3212 diff_start();
3213 diff_revertHunk( &uniedit_diff[p] );
3214 diff_end();
3215
3216 /* Free memory. */
3217 diff_cleanupHunk( &uniedit_diff[p] );
3218 array_erase( &uniedit_diff, &uniedit_diff[p], &uniedit_diff[p + 1] );
3219
3220 /* Regen list. */
3221 uniedit_diff_regenList( wid );
3222}
3223
3224static void uniedit_diff_close( unsigned int wid, const char *unused )
3225{
3226 (void)unused;
3227 uniedit_diffMode = window_checkboxState( wid, "chkDiffMode" );
3228 window_buttonCaption( uniedit_wid, "btnSave",
3229 uniedit_diffMode ? _( "Save Diff" )
3230 : _( "Save All" ) );
3231}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:170
#define array_erase(ptr_array, first, last)
Erases elements in interval [first, last).
Definition array.h:148
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:179
#define array_push_back(ptr_array, element)
Adds a new element at the end of the array.
Definition array.h:134
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
#define BUTTON_HEIGHT
Definition board.c:28
#define BUTTON_WIDTH
Definition board.c:27
StarSystem * systems_stack
Definition space.c:94
int dpl_saveAll(void)
Saves all the star spobs.
Definition dev_spob.c:188
void sysedit_open(StarSystem *sys)
Opens the system editor interface.
void sysedit_sysScale(StarSystem *sys, double factor)
Scales a system.
int dsys_saveSystem(StarSystem *sys)
Saves a star system.
Definition dev_system.c:82
int dsys_saveAll(void)
Saves all the star systems.
Definition dev_system.c:305
static UniEditMode uniedit_mode
Definition dev_uniedit.c:90
static void uniedit_btnOpen(unsigned int wid_unused, const char *unused)
Opens up a system.
static double uniedit_my
static void uniedit_btnEditRename(unsigned int wid, const char *unused)
Renames the systems in the system editor.
static double uniedit_rotate
static double uniedit_dt
static int uniedit_checkName(const char *name)
Checks to see if a system name is already in use.
static void uniedit_renderOverlay(double bx, double by, double bw, double bh, void *data)
Renders the overlay.
static double uniedit_xpos
Definition dev_uniedit.c:97
void uniedit_open(unsigned int wid_unused, const char *unused)
Opens the system editor interface.
static int uniedit_tadd
static void uniedit_close(unsigned int wid, const char *wgt)
Closes the system editor widget.
#define UNIEDIT_CLICK_THRESHOLD
Definition dev_uniedit.c:54
static double uniedit_dragSelX
static unsigned int uniedit_widFind
Definition dev_uniedit.c:96
#define UNIEDIT_DOUBLECLICK_THRESHOLD
Definition dev_uniedit.c:55
static map_find_t * found_cur
static void uniedit_btnEditAddSpobAdd(unsigned int wid, const char *unused)
Actually adds the virtual spob.
static void uniedit_btnNewTag(unsigned int wid, const char *unused)
Adds a tech to a system.
static void uniedit_deselect(void)
Deselects selected targets.
static void uniedit_btnAddTag(unsigned int wid, const char *unused)
Adds a tech to a spob.
static void uniedit_editSys(void)
Edits an individual system or group of systems.
#define UNIEDIT_FIND_WIDTH
Definition dev_uniedit.c:49
static void uniedit_newSys(double x, double y)
Creates a new system.
static double uniedit_ypos
Definition dev_uniedit.c:98
static int uniedit_drag
static void uniedit_btnNew(unsigned int wid_unused, const char *unused)
Enters the editor in new system mode.
static char ** uniedit_tagslist
#define UNIEDIT_ZOOM_STEP
Definition dev_uniedit.c:57
static StarSystem ** uniedit_sys
#define UNIEDIT_EDIT_HEIGHT
Definition dev_uniedit.c:47
static void uniedit_toggleJump(StarSystem *sys)
Toggles the jump point for the selected systems.
static void uniedit_editGenList(unsigned int wid)
Generates the virtual spob list.
static int uniedit_moved
static int uniedit_keys(unsigned int wid, SDL_Keycode key, SDL_Keymod mod, int isrepeat)
Handles keybindings.
static unsigned int uniedit_widEdit
Definition dev_uniedit.c:95
static void uniedit_buttonZoom(unsigned int wid, const char *str)
Handles the button zoom clicks.
static void uniedit_renameSys(void)
Renames all the currently selected systems.
static void uniedit_findSys(void)
Finds systems and spobs.
static void uniedit_btnFind(unsigned int wid_unused, const char *unused)
Opens the system property editor.
static int uniedit_dragSys
#define UNIEDIT_FIND_HEIGHT
Definition dev_uniedit.c:50
static void uniedit_findShowResults(unsigned int wid, map_find_t *found, int n)
Generates the virtual spob list.
static double uniedit_zoom
Definition dev_uniedit.c:99
static unsigned int uniedit_lastClick
static double uniedit_dragSelY
static int uniedit_dragSel
static double uniedit_rotate_cx
static void uniedit_btnJump(unsigned int wid_unused, const char *unused)
Enters the editor in new jump mode.
static void uniedit_btnEdit(unsigned int wid_unused, const char *unused)
Opens the system property editor.
#define UNIEDIT_DRAG_THRESHOLD
Definition dev_uniedit.c:52
static void uniedit_editSysClose(unsigned int wid, const char *name)
Closes the system property editor, saving the changes made.
static int uniedit_sortCompare(const void *p1, const void *p2)
qsort compare function for map finds.
static int uniedit_mouse(unsigned int wid, const SDL_Event *event, double mx, double my, double w, double h, double rx, double ry, void *data)
System editor custom widget mouse handling.
static void uniedit_btnEditAddSpob(unsigned int wid, const char *unused)
Adds a new virtual spob.
static double uniedit_rotate_cy
static void uniedit_btnViewModeSet(unsigned int wid, const char *unused)
Actually adds the virtual spob.
static int found_ncur
UniEditMode
Definition dev_uniedit.c:64
@ UNIEDIT_ROTATE
Definition dev_uniedit.c:68
@ UNIEDIT_NEWSYS
Definition dev_uniedit.c:67
@ UNIEDIT_DEFAULT
Definition dev_uniedit.c:65
@ UNIEDIT_JUMP
Definition dev_uniedit.c:66
static void uniedit_btnView(unsigned int wid_unused, const char *unused)
Allows selecting the view.
static double uniedit_mx
static void uniedit_selectAdd(StarSystem *sys)
Adds a system to the selection.
#define UNIEDIT_ZOOM_MAX
Definition dev_uniedit.c:58
#define UNIEDIT_ZOOM_MIN
Definition dev_uniedit.c:59
static void uniedit_centerSystem(unsigned int wid, const char *unused)
Centers the selected system.
static void uniedit_findSysClose(unsigned int wid, const char *name)
Closes the search dialogue.
static UniEditViewMode uniedit_viewmode
Definition dev_uniedit.c:91
static unsigned int uniedit_wid
Definition dev_uniedit.c:94
static void uniedit_findSearch(unsigned int wid, const char *str)
Searches for spobs and systems.
#define UNIEDIT_EDIT_WIDTH
Definition dev_uniedit.c:46
static int uniedit_view_faction
Definition dev_uniedit.c:93
#define UNIEDIT_MOVE_THRESHOLD
Definition dev_uniedit.c:53
void uniedit_selectText(void)
Sets the selected system text.
static void uniedit_btnRmTag(unsigned int wid, const char *unused)
Removes a tech from a spob.
static void uniedit_selectRm(StarSystem *sys)
Removes a system from the selection.
static void uniedit_focusLose(unsigned int wid, const char *wgtname)
Called when it's de-focused.
static void uniedit_btnEditRmSpob(unsigned int wid, const char *unused)
Removes a selected spob.
static void uniedit_btnEditTags(unsigned int wid, const char *unused)
Edits a spob's tags.
static void uniedit_render(double bx, double by, double w, double h, void *data)
System editor custom widget rendering.
static StarSystem * uniedit_tsys
static void uniedit_genTagsList(unsigned int wid)
Generates the spob tech list.
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:470
void dialogue_alert(const char *fmt,...)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:130
char * dialogue_input(const char *title, int min, int max, const char *fmt,...)
Creates a dialogue that allows the player to write a message.
Definition dialogue.c:441
int dialogue_YesNoRaw(const char *caption, const char *msg)
Runs a dialogue with both yes and no options.
Definition dialogue.c:373
void dialogue_alertRaw(const char *msg)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:149
int dialogue_YesNo(const char *caption, const char *fmt,...)
Runs a dialogue with both yes and no options.
Definition dialogue.c:352
int economy_execQueued(void)
Calls economy_refresh if an economy update is queued.
Definition economy.c:473
const char * faction_name(int f)
Gets a factions "real" (internal) name.
Definition faction.c:331
const FactionGenerator * faction_generators(int f)
Gets the faction's generators.
Definition faction.c:2366
const glColour * faction_colour(int f)
Gets the colour of the faction.
Definition faction.c:494
int * faction_getAll(void)
Returns all faction IDs in an array (array.h).
Definition faction.c:220
int faction_get(const char *name)
Gets a faction ID by name.
Definition faction.c:209
glFont gl_smallFont
Definition font.c:159
int gl_printWidthRaw(const glFont *ft_font, const char *text)
Gets the width that it would take to print some text.
Definition font.c:984
glFont gl_defFont
Definition font.c:158
void gl_print(const glFont *ft_font, const double x, const double y, const glColour *c, const char *fmt,...)
Prints text on screen like printf.
Definition font.c:725
glFont gl_defFontMono
Definition font.c:160
double naev_getrealdt(void)
Gets the last delta-tick.
Definition naev.c:1230
Header file with generic functions and naev-specifics.
#define MIN(x, y)
Definition naev.h:39
#define ABS(x)
Definition naev.h:32
#define pow2(x)
Definition naev.h:53
#define MAX(x, y)
Definition naev.h:37
#define PATH_MAX
Definition naev.h:57
int nfile_dirMakeExist(const char *path)
Creates a directory if it doesn't exist.
Definition nfile.c:277
int nfile_touch(const char *path)
Tries to create the file if it doesn't exist.
Definition nfile.c:533
int nfile_dirExists(const char *path)
Checks to see if a directory exists.
Definition nfile.c:309
int strsort(const void *p1, const void *p2)
Sort function for sorting strings with qsort().
Definition nstring.c:83
int scnprintf(char *text, size_t maxlen, const char *fmt,...)
Like snprintf(), but returns the number of characters ACTUALLY "printed" into the buffer....
Definition nstring.c:102
const char * num2strU(double n, int decimals)
Unsafe version of num2str that uses an internal buffer. Every call overwrites the return value.
Definition nstring.c:163
glInfo gl_screen
Definition opengl.c:47
void gl_renderShader(double x, double y, double w, double h, double r, const SimpleShader *shd, const glColour *c, int center)
Renders a simple shader.
void gl_renderRect(double x, double y, double w, double h, const glColour *c)
Renders a rectangle.
void gl_renderCircle(double cx, double cy, double r, const glColour *c, int filled)
Draws a circle.
void pause_game(void)
Pauses the game.
Definition pause.c:25
void unpause_game(void)
Unpauses the game.
Definition pause.c:43
Pilot *const * pilot_getAll(void)
Gets the pilot stack.
Definition pilot.c:93
void pilot_clearTrails(Pilot *p)
Resets the trails for a pilot.
Definition pilot.c:3722
static const double c[]
Definition rng.c:256
void safelanes_recalculate(void)
Update the safe lane locations in response to the universe changing (e.g., diff applied).
Definition safelanes.c:296
void space_reconstructPresences(void)
Reset the presence of all systems.
Definition space.c:4620
void systems_reconstructJumps(void)
Reconstructs the jumps.
Definition space.c:2990
int system_addJump(StarSystem *sys, StarSystem *target)
Adds a jump point between two star systems.
Definition space.c:2829
double system_getPresenceFull(const StarSystem *sys, int faction, double *base, double *bonus)
Get the presence of a faction in a system.
Definition space.c:4566
Spob * spob_getAll(void)
Gets an array (array.h) of all spobs.
Definition space.c:1166
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1107
int system_addVirtualSpob(StarSystem *sys, const char *spobname)
Adds a virtual spob to a system.
Definition space.c:2765
StarSystem * system_getIndex(int id)
Get the system by its index.
Definition space.c:1038
StarSystem * system_new(void)
Creates a new star system.
Definition space.c:2908
StarSystem * system_getAll(void)
Gets an array (array.h) of all star systems.
Definition space.c:925
char ** spob_searchFuzzyCase(const char *spobname, int *n)
Does a fuzzy case matching. Searches spob_name() but returns internal names.
Definition space.c:1211
char ** system_searchFuzzyCase(const char *sysname, int *n)
Does a fuzzy case matching. Searches translated names but returns internal names.
Definition space.c:948
StarSystem * system_get(const char *sysname)
Get the system from its name.
Definition space.c:1007
double system_getPresence(const StarSystem *sys, int faction)
Get the presence of a faction in a system.
Definition space.c:4537
int system_rmVirtualSpob(StarSystem *sys, const char *spobname)
Removes a virtual spob from a system.
Definition space.c:2789
VirtualSpob * virtualspob_getAll(void)
Gets all the virtual spobs.
Definition space.c:1243
const char * spob_getSystemName(const char *spobname)
Get the name of a system from a spobname.
Definition space.c:1082
const char * spob_name(const Spob *p)
Gets the translated name of a spob.
Definition space.c:1834
int system_rmJump(StarSystem *sys, StarSystem *target)
Removes a jump point from a star system.
Definition space.c:2868
Represents an asteroid field anchor.
Definition asteroid.h:111
Asteroid * asteroids
Definition asteroid.h:116
AsteroidTypeGroup ** groups
Definition asteroid.h:120
double weight
Definition faction.h:19
The representation of an in-game pilot.
Definition pilot.h:263
Represents the presence of a spob.
Definition space.h:78
double bonus
Definition space.h:81
double base
Definition space.h:80
int faction
Definition space.h:79
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:102
tech_group_t * tech
Definition space.h:137
SpobPresence presence
Definition space.h:121
Represents presence in a system.
Definition space.h:228
double value
Definition space.h:232
double base
Definition space.h:230
double bonus
Definition space.h:231
Universe diff filepath list.
Definition unidiff.h:183
union UniHunkTarget_t::@075106202173013221375222217331323374140174001165 u
UniHunkTargetType_t type
Definition unidiff.h:27
char * name
Definition unidiff.h:29
Represents a single hunk in the diff.
Definition unidiff.h:162
UniHunkDataType_t dtype
Definition unidiff.h:165
union UniHunk_t::@375235000240300110336260027115076046055102130370 u
UniHunkType_t type
Definition unidiff.h:164
UniAttribute_t * attr
Definition unidiff.h:177
UniHunkTarget_t target
Definition unidiff.h:163
Basically modifies system parameters without creating any real objects.
Definition space.h:91
SpobPresence * presences
Definition space.h:93
char * name
Definition space.h:92
Represents a found target.
Definition map_find.h:12
StarSystem * sys
Definition map_find.h:14
char display[STRMAX_SHORT]
Definition map_find.h:15
Spob * spob
Definition map_find.h:13
char ** tech_getItemNames(const tech_group_t *tech, int *n)
Gets the names of all techs within a given group.
Definition tech.c:797
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:688
void window_setDynamic(unsigned int wid, int dynamic)
Sets a window as dynamic, so that it is drawn every frame completely.
Definition toolkit.c:643
void window_setFocus(unsigned int wid, const char *wgtname)
Sets the focused widget in a window.
Definition toolkit.c:2488
void window_dimWindow(unsigned int wid, int *w, int *h)
Gets the dimensions of a window.
Definition toolkit.c:370
void window_setCancel(unsigned int wid, void(*cancel)(unsigned int, const char *))
Sets the default cancel function of the window.
Definition toolkit.c:868
void toolkit_drawAltText(int bx, int by, const char *alt)
Draws an alt text.
Definition toolkit.c:1460
void window_onClose(unsigned int wid, void(*fptr)(unsigned int, const char *))
Sets the default close function of the window.
Definition toolkit.c:824
void window_moveWidget(unsigned int wid, const char *name, int x, int y)
Moves a widget.
Definition toolkit.c:463
void window_destroyWidget(unsigned int wid, const char *wgtname)
Destroys a widget in a window.
Definition toolkit.c:1167
void window_handleKeys(unsigned int wid, int(*keyhandler)(unsigned int, SDL_Keycode, SDL_Keymod, int))
Sets the key handler for the window.
Definition toolkit.c:961
void window_setBorder(unsigned int wid, int enable)
Sets or removes the border of a window.
Definition toolkit.c:942
int widget_exists(unsigned int wid, const char *wgtname)
Checks to see if a widget exists.
Definition toolkit.c:1144
void window_close(unsigned int wid, const char *str)
Helper function to automatically close the window calling it.
Definition toolkit.c:1028
void diff_end(void)
Cleans up after applying a set of diffs.
Definition unidiff.c:796
void diff_clear(void)
Removes all active diffs. (Call before economy_destroy().)
Definition unidiff.c:1858
int diff_revertHunk(const UniHunk_t *hunk)
Reverts a hunk.
Definition unidiff.c:1101
void diff_cleanupHunk(UniHunk_t *hunk)
Cleans up a hunk.
Definition unidiff.c:1940
int diff_patchHunk(UniHunk_t *hunk)
Applies a hunk.
Definition unidiff.c:1114
void diff_start(void)
Starts applying a set of diffs.
Definition unidiff.c:788
const char * diff_hunkName(UniHunkType_t t)
Gets the human readable name of a hunk.
Definition unidiff.c:1922