naev 0.12.5
dev_sysedit.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#include "physfs.h"
12
13#include "naev.h"
15
16#include <libgen.h>
17
18#include "dev_sysedit.h"
19
20#include "array.h"
21#include "conf.h"
22#include "dev_spob.h"
23#include "dev_system.h"
24#include "dev_uniedit.h"
25#include "dialogue.h"
26#include "economy.h"
27#include "ndata.h"
28#include "nstring.h"
29#include "opengl.h"
30#include "opengl_render.h"
31#include "safelanes.h"
32#include "space.h"
33#include "toolkit.h"
34
35#define BUTTON_WIDTH 100
36#define BUTTON_HEIGHT 30
37
38#define SYSEDIT_EDIT_WIDTH 500
39#define SYSEDIT_EDIT_HEIGHT 400
40
41#define SYSEDIT_DRAG_THRESHOLD 300
42#define SYSEDIT_MOVE_THRESHOLD 10
43
44#define SYSEDIT_ZOOM_STEP 1.2
45#define SYSEDIT_ZOOM_MAX 1
46#define SYSEDIT_ZOOM_MIN -23
47
48/*
49 * Selection types.
50 */
51enum {
57};
58
62typedef struct Select_s {
63 int type;
64 union {
65 int spob;
66 int jump;
67 int asteroid;
68 int astexclude;
69 } u;
70} Select_t;
71static Select_t *sysedit_select = NULL;
72static int sysedit_nselect = 0;
73static int sysedit_mselect = 0;
75static int sysedit_tadd = 0;
76static char **sysedit_tagslist = NULL;
77
78/*
79 * System editor stuff.
80 */
81static StarSystem *sysedit_sys = NULL;
82static unsigned int sysedit_wid = 0;
83static unsigned int sysedit_widEdit = 0;
84static int sysedit_grid = 1;
85static double sysedit_xpos = 0.;
86static double sysedit_ypos = 0.;
87static double sysedit_zoom = 1.;
88static int sysedit_moved = 0;
89static unsigned int sysedit_dragTime = 0;
90static int sysedit_drag = 0;
91static int sysedit_dragSel = 0;
92static double sysedit_mx = 0.;
93static double sysedit_my = 0.;
94
95/* Stored checkbox values. */
96static int jp_hidden = 0;
97static int jp_exit = 0;
98
99/*
100 * System editor Prototypes.
101 */
102/* Custom system editor widget. */
103static void sysedit_buttonZoom( unsigned int wid, const char *str );
104static void sysedit_render( double bx, double by, double w, double h,
105 void *data );
106static void sysedit_renderAsteroidsField( double bx, double by,
107 const AsteroidAnchor *ast,
108 int selected );
109static void sysedit_renderAsteroidExclusion( double bx, double by,
110 const AsteroidExclusion *aexcl,
111 int selected );
112static void sysedit_renderBG( double bx, double bw, double w, double h,
113 double x, double y );
114static void sysedit_renderSprite( const glTexture *gfx, double bx, double by,
115 double x, double y, int sx, int sy,
116 const glColour *c, int selected,
117 const char *caption );
118static void sysedit_focusLose( unsigned int wid, const char *wgtname );
119static int sysedit_mouseTrySelect( const Select_t *sel, double x, double y,
120 double t, double mx, double my,
121 SDL_Keymod mod, void ( *func )( void ) );
122static int sysedit_mouse( unsigned int wid, const SDL_Event *event, double mx,
123 double my, double w, double h, double xr, double yr,
124 void *data );
125/* Button functions. */
126static void sysedit_close( unsigned int wid, const char *wgt );
127static void sysedit_btnNewSpob( unsigned int wid_unused, const char *unused );
128static void sysedit_btnNewAsteroids( unsigned int wid_unused,
129 const char *unused );
130static UniAttribute_t *sysedit_asteroidsAttr( const AsteroidAnchor *ast );
131static void sysedit_btnRename( unsigned int wid_unused, const char *unused );
132static void sysedit_btnRemove( unsigned int wid_unused, const char *unused );
133static void sysedit_btnReset( unsigned int wid_unused, const char *unused );
134static void sysedit_btnScale( unsigned int wid_unused, const char *unused );
135static void sysedit_btnGrid( unsigned int wid_unused, const char *unused );
136static void sysedit_btnEdit( unsigned int wid_unused, const char *unused );
137/* Spob editing. */
138static void sysedit_editPnt( void );
139static void sysedit_editPntClose( unsigned int wid, const char *unused );
140static void sysedit_spobDesc( unsigned int wid, const char *unused );
141static void sysedit_spobDescReturn( unsigned int wid, const char *unused );
142static void sysedit_spobDescClose( unsigned int wid, const char *unused );
143static void sysedit_genServicesList( unsigned int wid );
144static void sysedit_btnTechEdit( unsigned int wid, const char *unused );
145static void sysedit_genTechList( unsigned int wid );
146static void sysedit_btnAddTech( unsigned int wid, const char *unused );
147static void sysedit_btnRmTech( unsigned int wid, const char *unused );
148static void sysedit_btnTagsEdit( unsigned int wid, const char *unused );
149static void sysedit_genTagsList( unsigned int wid );
150static void sysedit_btnAddTag( unsigned int wid, const char *unused );
151static void sysedit_btnRmTag( unsigned int wid, const char *unused );
152static void sysedit_btnNewTag( unsigned int wid, const char *unused );
153static void sysedit_btnTagsClose( unsigned int wid, const char *unused );
154static void sysedit_btnAddService( unsigned int wid, const char *unused );
155static void sysedit_btnRmService( unsigned int wid, const char *unused );
156static void sysedit_spobGFX( unsigned int wid_unused, const char *wgt );
157static void sysedit_btnGFXClose( unsigned int wid, const char *wgt );
158static void sysedit_btnGFXApply( unsigned int wid, const char *wgt );
159static void sysedit_btnFaction( unsigned int wid_unused, const char *unused );
160static void sysedit_btnFactionSet( unsigned int wid, const char *unused );
161/* Jump editing */
162static void sysedit_editJump( void );
163static void sysedit_editJumpClose( unsigned int wid, const char *unused );
164/* Asteroid editing. */
165static void sysedit_editAsteroids( void );
166static void sysedit_editAsteroidsClose( unsigned int wid, const char *unused );
167static void sysedit_genAsteroidsList( unsigned int wid );
168static void sysedit_btnAsteroidsDelete( unsigned int wid, const char *unused );
169static void sysedit_btnRmAsteroid( unsigned int wid, const char *unused );
170static void sysedit_btnAddAsteroid( unsigned int wid, const char *unused );
171/* Exclusion zone editing. */
172static void sysedit_editExclusion( void );
173static void sysedit_editExclusionClose( unsigned int wid, const char *unused );
174static void sysedit_btnExclusionDelete( unsigned int wid, const char *unused );
175/* Keybindings handling. */
176static int sysedit_keys( unsigned int wid, SDL_Keycode key, SDL_Keymod mod,
177 int isrepeat );
178/* Selection. */
179static int sysedit_selectCmp( const Select_t *a, const Select_t *b );
180static int sysedit_isSelected( const Select_t *s );
181static void sysedit_checkButtons( void );
182static void sysedit_deselect( void );
183static void sysedit_selectAdd( const Select_t *sel );
184static void sysedit_selectRm( const Select_t *sel );
185/* Diffs. */
186static void sysedit_diffCreateSpobStr( const Spob *spb, UniHunkType_t type,
187 char *str );
188static void sysedit_diffCreateSpobInt( const Spob *spb, UniHunkType_t type,
189 int data );
190static void sysedit_diffCreateSpobFloat( const Spob *spb, UniHunkType_t type,
191 double fdata );
192
196void sysedit_open( StarSystem *sys )
197{
198 unsigned int wid;
199 char buf[128];
200 int i;
201 const glColour cBG = { 0., 0., 0., 0.95 };
202
203 /* Reconstructs the jumps - just in case. */
205
206 /* Reset some variables. */
207 sysedit_sys = sys;
208 sysedit_drag = 0;
210 sysedit_xpos = 0.;
211 sysedit_ypos = 0.;
212
213 /* Load graphics. */
215
216 /* Create the window. */
217 snprintf( buf, sizeof( buf ), _( "%s - Star System Editor" ), sys->name );
218 wid = window_create( "wdwSysEdit", buf, -1, -1, -1, -1 );
219 window_setDynamic( wid, 1 );
221 window_setBorder( wid, 0 );
222 sysedit_wid = wid;
223
225
226 /* Actual viewport, at the bottom. */
227 window_addCust( wid, 0, 0, SCREEN_W, SCREEN_H, "cstSysEdit", 1,
229 NULL );
230
231 /* Overlay background. */
232 window_addRect( wid, SCREEN_W - 130, 0, 130, SCREEN_H, "rctRCol", &cBG, 0 );
233 window_addRect( wid, 0, 0, SCREEN_W, 60, "rctBBar", &cBG, 0 );
234
235 /* Close button. */
236 window_addButtonKey( wid, -15, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
237 _( "Exit" ), sysedit_close, SDLK_x );
238 i = 1;
239
240 /* Scale. */
241 window_addButton( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * i, BUTTON_WIDTH,
242 BUTTON_HEIGHT, "btnScale", _( "Scale" ),
244 i += 1;
245
246 /* Reset. */
247 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * i, BUTTON_WIDTH,
248 BUTTON_HEIGHT, "btnReset", _( "Reset Jumps" ),
249 sysedit_btnReset, SDLK_r );
250 i += 1;
251
252 /* Editing. */
253 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * i, BUTTON_WIDTH,
254 BUTTON_HEIGHT, "btnEdit", _( "Edit" ), sysedit_btnEdit,
255 SDLK_e );
256 i += 1;
257
258 /* Remove. */
259 window_addButton( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * i, BUTTON_WIDTH,
260 BUTTON_HEIGHT, "btnRemove", _( "Remove" ),
262 i += 1;
263
264 /* New spob. */
265 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * i, BUTTON_WIDTH,
266 BUTTON_HEIGHT, "btnNewSpob", _( "New Spob" ),
267 sysedit_btnNewSpob, SDLK_n );
268 i += 1;
269
270 /* New asteroids. */
271 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * i, BUTTON_WIDTH,
272 BUTTON_HEIGHT, "btnNewAsteroids", _( "New Asteroids" ),
273 sysedit_btnNewAsteroids, SDLK_a );
274 i += 1;
275
276 /* Toggle Grid. */
277 window_addButtonKey( wid, -15, 20 + ( BUTTON_HEIGHT + 20 ) * i, BUTTON_WIDTH,
278 BUTTON_HEIGHT, "btnGrid", _( "Grid" ), sysedit_btnGrid,
279 SDLK_g );
280
281 /* Options button. */
282 window_addButton( wid, -15 - BUTTON_WIDTH - 20, 20, BUTTON_HEIGHT,
283 BUTTON_HEIGHT, "btnOptions", NULL, uniedit_options );
284 window_buttonCustomRender( wid, "btnOptions",
285 window_buttonCustomRenderGear );
286
287 /* Zoom buttons */
288 window_addButton( wid, 20, 20, 30, 30, "btnZoomIn", p_( "zoomin", "+" ),
290 window_addButton( wid, 60, 20, 30, 30, "btnZoomOut", p_( "zoomout", "-" ),
292
293 /* Selected text. */
294 snprintf( buf, sizeof( buf ), _( "Radius: %.0f" ), sys->radius );
295 window_addText( wid, 100, 10, SCREEN_W / 2 - 140, 30, 0, "txtSelected",
296 &gl_smallFont, NULL, buf );
297
298 /* Deselect everything. */
300}
301
305static int sysedit_keys( unsigned int wid, SDL_Keycode key, SDL_Keymod mod,
306 int isrepeat )
307{
308 (void)wid;
309 (void)mod;
310 (void)isrepeat;
311
312 switch ( key ) {
313
314 default:
315 return 0;
316 }
317}
318
322static void sysedit_close( unsigned int wid, const char *wgt )
323{
324 /* Unload graphics. */
326
327 /* Remove selection. */
329
330 /* Set the dominant faction. */
332
333 /* Update asteroid info. */
335
336 /* Save the system */
337 if ( conf.devautosave ) {
339 uniedit_saveError();
340 }
341
342 /* Reconstruct universe presences. */
345
346 /* Close the window. */
347 window_close( wid, wgt );
348
349 /* Update the universe editor's sidebar text. */
351
352 /* Unset. */
353 sysedit_wid = 0;
354}
355
359static void sysedit_editPntClose( unsigned int wid, const char *unused )
360{
361 (void)unused;
362 const char *inp;
363 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
364 int data;
365 double fdata;
366
367 fdata = atof( window_getInput( sysedit_widEdit, "inpPop" ) );
368 if ( fabs( fdata - p->population ) > 0. ) {
369 if ( uniedit_diffMode )
370 sysedit_diffCreateSpobFloat( p, HUNK_TYPE_SPOB_POPULATION, fdata );
371 else
372 p->population = fdata;
373 }
374
375 inp = window_getInput( sysedit_widEdit, "inpClass" );
376 if ( strcmp( p->class, inp ) != 0 ) {
377 if ( uniedit_diffMode ) {
378 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_CLASS, strdup( inp ) );
379 } else {
380 free( p->class );
381 if ( inp[0] == '\0' )
382 p->class = NULL;
383 else
384 p->class = strdup( inp );
385 }
386 }
387
388 inp = window_getInput( sysedit_widEdit, "inpLua" );
389 if ( ( inp != p->lua_file ) ||
390 ( ( p->lua_file != NULL ) && ( inp != NULL ) &&
391 strcmp( p->lua_file, inp ) != 0 ) ) {
392 if ( uniedit_diffMode ) {
393 if ( ( inp == NULL ) || ( strlen( inp ) == 0 ) )
394 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_LUA, NULL );
395 else
396 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_LUA, strdup( inp ) );
397 } else {
398 free( p->lua_file );
399 if ( ( inp == NULL ) || ( strlen( inp ) == 0 ) )
400 p->lua_file = NULL;
401 else
402 p->lua_file = strdup( inp );
403 }
404 }
405
406 fdata = atof( window_getInput( sysedit_widEdit, "inpPresenceBase" ) );
407 if ( fabs( p->presence.base - fdata ) > 1e-5 ) {
408 if ( uniedit_diffMode )
409 sysedit_diffCreateSpobFloat( p, HUNK_TYPE_SPOB_PRESENCE_BASE, fdata );
410 else
411 p->presence.base = fdata;
412 }
413 fdata = atof( window_getInput( sysedit_widEdit, "inpPresenceBonus" ) );
414 if ( fabs( p->presence.bonus - fdata ) > 1e-5 ) {
415 if ( uniedit_diffMode )
416 sysedit_diffCreateSpobFloat( p, HUNK_TYPE_SPOB_PRESENCE_BONUS, fdata );
417 else
418 p->presence.bonus = fdata;
419 }
420 data = atoi( window_getInput( sysedit_widEdit, "inpPresenceRange" ) );
421 if ( data != p->presence.range ) {
422 if ( uniedit_diffMode )
423 sysedit_diffCreateSpobInt( p, HUNK_TYPE_SPOB_PRESENCE_RANGE, data );
424 else
425 p->presence.range = data;
426 }
427 fdata = atof( window_getInput( sysedit_widEdit, "inpHide" ) );
428 if ( fabs( p->hide - fdata ) > 1e-5 ) {
429 if ( uniedit_diffMode )
430 sysedit_diffCreateSpobFloat( p, HUNK_TYPE_SPOB_HIDE, fdata );
431 else
432 p->hide = fdata;
433 }
434
435 for ( int i = 0; i < array_size( sysedit_tagslist ); i++ )
436 free( sysedit_tagslist[i] );
438 sysedit_tagslist = NULL;
439
440 /* Have to recompute presences if stuff changed. */
442
443 if ( !uniedit_diffMode ) {
444 if ( conf.devautosave ) {
445 if ( dpl_saveSpob( p ) )
446 uniedit_saveError();
447 }
448
449 /* Clean up presences. */
452 }
453
454 window_close( wid, unused );
455}
456
460static void sysedit_btnNewSpob( unsigned int wid_unused, const char *unused )
461{
462 (void)wid_unused;
463 (void)unused;
464 Spob *p, *b;
465 char *name;
466 int good;
467
468 if ( uniedit_diffMode ) {
469 /* TODO let select the spob from a list. */
471 ( "Adding new spobs is not supported in diff mode!" ) );
472 return;
473 }
474
475 /* Get new name. */
476 name = dialogue_inputRaw( _( "New Spob Creation" ), 1, 32,
477 _( "What do you want to name the new spob?" ) );
478 if ( name == NULL )
479 return;
480
481 /* Check for collision. */
482 if ( spob_exists( name ) ) {
483 dialogue_alert( _( "Space object by the name of #r'%s'#0 already exists "
484 "in the #r'%s'#0 system" ),
485 name, spob_getSystemName( name ) );
486 free( name );
487 sysedit_btnNewSpob( 0, NULL );
488 return;
489 }
490
491 /* Create the new spob. */
492 p = spob_new();
493 p->name = name;
494
495 /* Set filename. */
496 char *cleanname = uniedit_nameFilter( p->name );
497 SDL_asprintf( &p->filename, "%s.xml", cleanname );
498 free( cleanname );
499
500 /* Base spob data off another. */
501 good = 0;
502 while ( !good ) {
503 b = spob_get( space_getRndSpob( 0, 0, NULL ) );
504 good = !( ( b->class == NULL ) || ( b->gfx_spacePath == NULL ) ||
505 ( b->gfx_spaceName == NULL ) || ( b->gfx_exterior == NULL ) ||
506 ( b->gfx_exteriorPath == NULL ) );
507 }
508 p->class = strdup( b->class );
509 p->gfx_spacePath = strdup( b->gfx_spacePath );
510 p->gfx_spaceName = strdup( b->gfx_spaceName );
511 p->gfx_exterior = strdup( b->gfx_exterior );
512 p->gfx_exteriorPath = strdup( b->gfx_exteriorPath );
513 p->pos.x = sysedit_xpos / sysedit_zoom;
514 p->pos.y = sysedit_ypos / sysedit_zoom;
515 p->hide = HIDE_DEFAULT_SPOB;
516 p->radius = b->radius;
517
518 /* Add new spob. */
520
521 /* Run galaxy modifications. */
524
525 if ( conf.devautosave ) {
526 int ret = dsys_saveSystem( sysedit_sys );
527 ret |= dpl_saveSpob( p );
528 if ( ret )
529 uniedit_saveError();
530 }
531
532 /* Reload graphics. */
534}
535
539static void sysedit_btnNewAsteroids( unsigned int wid_unused,
540 const char *unused )
541{
542 (void)wid_unused;
543 (void)unused;
544 const char *title, *caption;
545 char *ret;
546 const char *opts[] = {
547 _( "Asteroid Field" ),
548 _( "Exclusion Zone" ),
549 _( "Cancel" ),
550 };
551
552 /* See if we want to make a field or exclusion zone. */
553 title = _( "Add asteroid field or exclusion zone?" );
554 caption = _( "Do you wish to add an asteroid field or an asteroid exclusion "
555 "zone that will remove all asteroids that will appear in it?" );
556 dialogue_makeChoice( title, caption, 3 );
557 dialogue_addChoice( title, caption, opts[0] );
558 dialogue_addChoice( title, caption, opts[1] );
559 dialogue_addChoice( title, caption, opts[2] );
560 ret = dialogue_runChoice();
561 if ( ret == NULL )
562 ret = strdup( opts[0] );
563
564 if ( strcmp( ret, opts[0] ) == 0 ) {
565 free( ret );
566 AsteroidAnchor *ast = &array_grow( &sysedit_sys->asteroids );
567
568 if ( uniedit_diffMode ) {
569 char *label = dialogue_inputRaw(
570 _( "New Asteroid Field Creation" ), 1, 32,
571 _( "What do you want to label the new asteroid field? This is used "
572 "when referencing the asteroid field and is not displayed to "
573 "the "
574 "player." ) );
575 if ( label == NULL )
576 return;
577 for ( int i = 0; i < array_size( sysedit_sys->asteroids ); i++ ) {
578 if ( sysedit_sys->asteroids[i].label &&
579 ( strcmp( sysedit_sys->asteroids[i].label, label ) == 0 ) ) {
580 dialogue_alert( _( "Asteroid field with label '%s' already "
581 "exists in system '%s'!" ),
582 label, sysedit_sys->name );
583 return;
584 }
585 }
586
587 /* Create the new unidiff hunk. */
588 uniedit_diffCreateSysStr( sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_ADD,
589 label );
590 return;
591 }
592
593 asteroid_initAnchor( ast );
597 } else if ( strcmp( ret, opts[1] ) == 0 ) {
598 free( ret );
599 AsteroidExclusion *exc = &array_grow( &sysedit_sys->astexclude );
600 if ( uniedit_diffMode ) {
601 /* TODO. */
602 return;
603 }
604
605 memset( exc, 0, sizeof( AsteroidExclusion ) );
606 exc->radius = 1000.;
609 } else {
610 free( ret );
611 return;
612 }
613
614 if ( conf.devautosave ) {
616 uniedit_saveError();
617 }
618}
619
620static UniAttribute_t *sysedit_asteroidsAttr( const AsteroidAnchor *ast )
621{
622 UniAttribute_t attr;
624 attr.name = strdup( "label" );
625 attr.value = strdup( ast->label );
626 array_push_back( &attr_list, attr );
627 return attr_list;
628}
629
630static void sysedit_btnRename( unsigned int wid_unused, const char *unused )
631{
632 (void)wid_unused;
633 (void)unused;
634 for ( int i = 0; i < sysedit_nselect; i++ ) {
635 Select_t *sel = &sysedit_select[i];
636 const char *prompt;
637
638 if ( sel->type != SELECT_SPOB )
639 continue;
640
641 char *name, *oldName, *newName, *filtered;
642 Spob *p = sysedit_sys[i].spobs[sel->u.spob];
643
644 /* Get new name. */
645 if ( uniedit_diffMode )
646 prompt =
647 _( "What do you want to rename the spob #r%s#0?\n\n#rNote:#0 this "
648 "will only change the display name of the space object." );
649 else
650 prompt =
651 _( "What do you want to rename the spob #r%s#0?\n\n#rNote:#0 this "
652 "will rename and copy the space object data file." );
653 name = dialogue_input( _( "Rename Spob" ), 1, 32, prompt, p->name );
654 if ( name == NULL )
655 continue;
656
657 if ( uniedit_diffMode ) {
658 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_DISPLAYNAME,
659 name ); /* Name is already allocated. */
660 } else {
661 /* Check for collision. */
662 if ( spob_exists( name ) ) {
663 dialogue_alert( _( "Space object by the name of #r'%s'#0 already "
664 "exists in the #r'%s'#0 system" ),
665 name, spob_getSystemName( name ) );
666 free( name );
667 i--;
668 continue;
669 }
670
671 /* Rename. */
672 filtered = strdup( p->filename );
673 SDL_asprintf( &oldName, "%s/spob/%s", conf.dev_data_dir,
674 basename( filtered ) );
675 free( filtered );
676
677 filtered = uniedit_nameFilter( name );
678 SDL_asprintf( &newName, "%s/spob/%s.xml", conf.dev_data_dir,
679 filtered );
680 free( filtered );
681
682 if ( rename( oldName, newName ) )
683 WARN( _( "Failed to rename '%s' to '%s'!" ), oldName, newName );
684
685 /* Clean up. */
686 free( oldName );
687 free( p->filename );
688
689 /* Replace name in stack. */
690 spob_rename( p, name );
691 p->filename = newName;
692
694 dpl_saveSpob( p );
695 }
696
697 /* Rename input if called from edit window. */
699 window_modifyText( sysedit_widEdit, "txtName", p->name );
700 }
701}
702
706static void sysedit_btnRemove( unsigned int wid_unused, const char *unused )
707{
708 (void)wid_unused;
709 (void)unused;
710 char *file;
711
712 if ( uniedit_diffMode ) {
713 if ( dialogue_YesNo(
714 _( "Remove selected objects (excluding jumps)?" ),
715 _( "Objects will be removed through the current diff." ) ) ) {
716 for ( int i = 0; i < sysedit_nselect; i++ ) {
717 Select_t *sel = &sysedit_select[i];
718 if ( sel->type == SELECT_SPOB ) {
719 const Spob *sp = sysedit_sys->spobs[sel->u.spob];
720 uniedit_diffCreateSysStr( sysedit_sys, HUNK_TYPE_SPOB_REMOVE,
721 strdup( sp->name ) );
722 } else if ( sel->type == SELECT_ASTEROID ) {
723 AsteroidAnchor *ast = &sysedit_sys->asteroids[sel->u.asteroid];
724 if ( ( ast->label == NULL ) ||
725 ( strcmp( ast->label, "" ) == 0 ) ) {
726 dialogue_alertRaw( _( "Modifying asteroid fields in diff "
727 "mode is only supported when "
728 "they "
729 "have labels. Please set a label via "
730 "the property editor." ) );
731 return;
732 }
733 uniedit_diffCreateSysStr(
734 sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_REMOVE, ast->label );
735 } /* TODO remove asteroid exclusions. */
736 /*else if ( sel->type == SELECT_ASTEXCLUDE ) {
737 AsteroidExclusion *exc =
738 &sysedit_sys->astexclude[sel->u.astexclude];
739 array_erase( &sysedit_sys->astexclude, exc, exc + 1 );
740 }*/
741 }
742 }
743 } else {
744 if ( dialogue_YesNo( _( "Remove selected objects (excluding jumps)?" ),
745 _( "This can not be undone." ) ) ) {
746 for ( int i = 0; i < sysedit_nselect; i++ ) {
747 const Select_t *sel = &sysedit_select[i];
748 if ( sel->type == SELECT_SPOB ) {
749 const Spob *sp = sysedit_sys->spobs[sel->u.spob];
750 char *filtered = uniedit_nameFilter( sp->name );
751 SDL_asprintf( &file, "%s/spob/%s.xml", conf.dev_data_dir,
752 filtered );
753 remove( file );
754
755 free( filtered );
756 free( file );
757
759 } else if ( sel->type == SELECT_ASTEROID ) {
760 AsteroidAnchor *ast = &sysedit_sys->asteroids[sel->u.asteroid];
761 asteroid_freeAnchor( ast );
762 array_erase( &sysedit_sys->asteroids, ast, ast + 1 );
763 } else if ( sel->type == SELECT_ASTEXCLUDE ) {
764 AsteroidExclusion *exc =
765 &sysedit_sys->astexclude[sel->u.astexclude];
766
767 array_erase( &sysedit_sys->astexclude, exc, exc + 1 );
768 }
769 }
770
771 /* Run galaxy modifications. */
774 }
775 }
776}
777
781static void sysedit_btnReset( unsigned int wid_unused, const char *unused )
782{
783 (void)wid_unused;
784 (void)unused;
785
786 if ( uniedit_diffMode ) {
788 _( "Reseting systems is not supported in diff mode!" ) );
789 return;
790 }
791
792 for ( int i = 0; i < sysedit_nselect; i++ ) {
793 Select_t *sel = &sysedit_select[i];
794 if ( sel->type == SELECT_JUMPPOINT )
795 sysedit_sys[i].jumps[sel->u.jump].flags |= JP_AUTOPOS;
796 }
797
798 /* Must reconstruct jumps. */
800}
801
805static void sysedit_btnScale( unsigned int wid_unused, const char *unused )
806{
807 (void)wid_unused;
808 (void)unused;
809 char *str;
810 double s;
811 StarSystem *sys;
812
813 if ( uniedit_diffMode ) {
815 _( "Scaling systems is not supported in diff mode!" ) );
816 return;
817 }
818
819 /* Prompt scale amount. */
820 str = dialogue_inputRaw(
821 _( "Scale Star System" ), 1, 32,
822 _( "By how much do you want to scale the star system?" ) );
823 if ( str == NULL )
824 return;
825
826 sys = sysedit_sys; /* Comfort. */
827 s = atof( str );
828 free( str );
829
830 /* In case screwed up. */
831 if ( ( s < 0.1 ) || ( s > 10. ) ) {
832 int i = dialogue_YesNo( _( "Scale Star System" ),
833 _( "Are you sure you want to scale the star "
834 "system by %.2f (from %.2f to %.2f)?" ),
835 s, sys->radius, sys->radius * s );
836 if ( i == 0 )
837 return;
838 }
839
840 sysedit_sysScale( sys, s );
841}
842
846void sysedit_sysScale( StarSystem *sys, double factor )
847{
848 char buf[STRMAX];
849
850 /* Ignore trivial scaling. */
851 if ( fabs( factor - 1.0 ) < 1e-5 )
852 return;
853
854 /* Scale radius. */
855 sys->radius *= factor;
856 snprintf( buf, sizeof( buf ), _( "Radius: %.0f" ), sys->radius );
857 if ( sysedit_wid > 0 )
858 window_modifyText( sysedit_wid, "txtSelected", buf );
859
860 /* Scale spobs. */
861 for ( int i = 0; i < array_size( sys->spobs ); i++ ) {
862 Spob *p = sys->spobs[i];
863 vec2_cset( &p->pos, p->pos.x * factor, p->pos.y * factor );
864 }
865
866 /* Scale jumps. */
867 for ( int i = 0; i < array_size( sys->jumps ); i++ ) {
868 JumpPoint *jp = &sys->jumps[i];
869 vec2_cset( &jp->pos, jp->pos.x * factor, jp->pos.y * factor );
870 }
871
872 /* Scale asteroids. */
873 for ( int i = 0; i < array_size( sys->asteroids ); i++ ) {
874 AsteroidAnchor *ast = &sys->asteroids[i];
875 vec2_cset( &ast->pos, ast->pos.x * factor, ast->pos.y * factor );
876 ast->radius *= factor;
877 }
878 for ( int i = 0; i < array_size( sys->astexclude ); i++ ) {
879 AsteroidExclusion *exc = &sys->astexclude[i];
880 vec2_cset( &exc->pos, exc->pos.x * factor, exc->pos.y * factor );
881 exc->radius *= factor;
882 }
883
884 /* Must reconstruct jumps. */
886}
887
891static void sysedit_btnGrid( unsigned int wid_unused, const char *unused )
892{
893 (void)wid_unused;
894 (void)unused;
895
897}
898
902static void sysedit_render( double bx, double by, double w, double h,
903 void *data )
904{
905 (void)data;
906 StarSystem *sys;
907 double x, y, z;
908
909 /* Comfort++. */
910 sys = sysedit_sys;
911 z = sysedit_zoom;
912
913 /* Coordinate translation. */
914 x = bx - sysedit_xpos + w / 2;
915 y = by - sysedit_ypos + h / 2;
916
917 /* First render background with lines. */
918 sysedit_renderBG( bx, by, w, h, x, y );
919
920 /* Render spobs. */
921 for ( int i = 0; i < array_size( sys->spobs ); i++ ) {
922 Spob *p = sys->spobs[i];
923 const Select_t sel = {
924 .type = SELECT_SPOB,
925 .u.spob = i,
926 };
927 int selected = sysedit_isSelected( &sel );
928 /* TODO handle non-sprite rendering. */
929 if ( p->gfx_space != NULL )
930 sysedit_renderSprite( p->gfx_space, x, y, p->pos.x, p->pos.y, 0, 0,
931 NULL, selected, p->name );
932 }
933
934 /* Render jump points. */
935 for ( int i = 0; i < array_size( sys->jumps ); i++ ) {
936 const glColour *c;
937 JumpPoint *jp = &sys->jumps[i];
938 const Select_t sel = {
939 .type = SELECT_JUMPPOINT,
940 .u.jump = i,
941 };
942 int selected = sysedit_isSelected( &sel );
943
944 /* Choose colour. */
945 c = ( jp->flags & JP_AUTOPOS ) ? &cGreen : NULL;
946
947 /* Render. */
948 sysedit_renderSprite( jumppoint_gfx, x, y, jp->pos.x, jp->pos.y, jp->sx,
949 jp->sy, c, selected, jp->target->name );
950 }
951
952 /* Render asteroids */
953 for ( int i = 0; i < array_size( sys->asteroids ); i++ ) {
954 const AsteroidAnchor *ast = &sys->asteroids[i];
955 const Select_t sel = {
956 .type = SELECT_ASTEROID,
957 .u.asteroid = i,
958 };
959 int selected = sysedit_isSelected( &sel );
960 sysedit_renderAsteroidsField( x, y, ast, selected );
961 }
962
963 /* Render asteroid exclusions */
964 for ( int i = 0; i < array_size( sys->astexclude ); i++ ) {
965 const AsteroidExclusion *aexcl = &sys->astexclude[i];
966 const Select_t sel = {
967 .type = SELECT_ASTEXCLUDE,
968 .u.astexclude = i,
969 };
970 int selected = sysedit_isSelected( &sel );
971 sysedit_renderAsteroidExclusion( x, y, aexcl, selected );
972 }
973
974 /* Render safe lanes. */
975 SafeLane *safelanes = safelanes_get( -1, 0, sys );
976 for ( int i = 0; i < array_size( safelanes ); i++ ) {
977 vec2 *posns[2];
978 Spob *pnt;
979 JumpPoint *njp;
980 glColour col;
981 const SafeLane *sf = &safelanes[i];
982
983 for ( int j = 0; j < 2; j++ ) {
984 switch ( sf->point_type[j] ) {
985 case SAFELANE_LOC_SPOB:
986 pnt = spob_getIndex( sf->point_id[j] );
987 posns[j] = &pnt->pos;
988 break;
989 case SAFELANE_LOC_DEST_SYS:
990 njp = jump_getTarget( system_getIndex( sf->point_id[j] ), sys );
991 posns[j] = &njp->pos;
992 break;
993 default:
994 WARN( _( "Invalid vertex type." ) );
995 continue;
996 }
997 }
998
999 col = *faction_colour( sf->faction );
1000 col.a = 0.3;
1001
1002 /* Get positions and stuff. */
1003 double x1, y1, x2, y2, ry, rx, r, rw, rh;
1004 x1 = x + posns[0]->x * z;
1005 y1 = y + posns[0]->y * z;
1006 x2 = x + posns[1]->x * z;
1007 y2 = y + posns[1]->y * z;
1008 rx = x2 - x1;
1009 ry = y2 - y1;
1010 r = atan2( ry, rx );
1011 rw = MOD( rx, ry ) / 2.;
1012 rh = 9.;
1013
1014 /* Render. */
1015 glUseProgram( shaders.safelane.program );
1016 gl_renderShader( ( x1 + x2 ) / 2., ( y1 + y2 ) / 2., rw, rh, r,
1017 &shaders.safelane, &col, 1 );
1018 }
1019 array_free( safelanes );
1020
1021 /* Render cursor position. */
1022 gl_print( &gl_defFontMono, bx + 5., by + 65., &cWhite, "% 9.2f x % 9.2f",
1023 ( bx + sysedit_mx - x ) / z, ( by + sysedit_my - y ) / z );
1024}
1025
1030static void sysedit_renderAsteroidsField( double bx, double by,
1031 const AsteroidAnchor *ast,
1032 int selected )
1033{
1034 double tx, ty, z;
1035
1036 /* Inits. */
1037 z = sysedit_zoom;
1038
1039 /* Translate asteroid field center's coords. */
1040 tx = bx + ast->pos.x * z;
1041 ty = by + ast->pos.y * z;
1042
1043 if ( selected ) {
1044 const glColour csel = COL_ALPHA( cFontBlue, 0.5 );
1045 gl_renderCircle( tx, ty, ast->radius * sysedit_zoom, &csel, 1 );
1046 }
1047
1048 gl_renderCircle( tx, ty, ast->radius * sysedit_zoom, &cOrange, 0 );
1049 gl_printMidRaw( &gl_smallFont, 200, tx - 100, ty - gl_smallFont.h / 2.,
1050 ( selected ) ? &cRed : NULL, -1., _( "Asteroid Field" ) );
1051}
1052
1057static void sysedit_renderAsteroidExclusion( double bx, double by,
1058 const AsteroidExclusion *aexcl,
1059 int selected )
1060{
1061 double tx, ty, z, r, rr;
1062 const glColour *col;
1063
1064 /* Inits. */
1065 z = sysedit_zoom;
1066
1067 /* Translate asteroid field center's coords. */
1068 tx = bx + aexcl->pos.x * z;
1069 ty = by + aexcl->pos.y * z;
1070 r = aexcl->radius * sysedit_zoom;
1071 rr = r * sin( M_PI / 4. );
1072
1073 if ( selected ) {
1074 const glColour csel = COL_ALPHA( cFontBlue, 0.5 );
1075 gl_renderCircle( tx, ty, r, &csel, 1 );
1076 }
1077
1078 col = ( selected ) ? &cWhite : &cRed;
1079
1080 gl_renderCircle( tx, ty, r, col, 0 );
1081 gl_renderCross( tx, ty, r, col );
1082 gl_renderRectEmpty( tx - rr, ty - rr, rr * 2, rr * 2, col );
1083}
1084
1088static void sysedit_renderBG( double bx, double by, double w, double h,
1089 double x, double y )
1090{
1091 /* Comfort. */
1092 const double z = sysedit_zoom;
1093 const double s = 1000.;
1094
1095 /* Vars */
1096 double startx, starty, spacing;
1097 int nx, ny;
1098
1099 /* Render blackness. */
1100 gl_renderRect( bx, by, w, h, &cBlack );
1101
1102 /* Must have grid activated. */
1103 if ( !sysedit_grid )
1104 return;
1105
1106 /* Draw lines that go through 0,0 */
1107 gl_renderRect( x - 1., by, 3., h, &cLightBlue );
1108 gl_renderRect( bx, y - 1., w, 3., &cLightBlue );
1109
1110 /* Render lines. */
1111 spacing = s * z;
1112 startx = bx + fmod( x - bx, spacing );
1113 starty = by + fmod( y - by, spacing );
1114
1115 nx = lround( w / spacing );
1116 ny = lround( h / spacing );
1117
1118 /* Vertical. */
1119 for ( int i = 0; i < nx; i++ ) {
1120 double d = startx + ( i * spacing );
1121 gl_renderLine( d, by, d, by + h, &cBlue );
1122 }
1123 /* Horizontal. */
1124 for ( int i = 0; i < ny; i++ ) {
1125 double d = starty + ( i * spacing );
1126 gl_renderLine( bx, d, bx + w, d, &cBlue );
1127 }
1128
1129 gl_renderCircle( x, y, sysedit_sys->radius * z, &cLightBlue, 0 );
1130}
1131
1135static void sysedit_renderSprite( const glTexture *gfx, double bx, double by,
1136 double x, double y, int sx, int sy,
1137 const glColour *c, int selected,
1138 const char *caption )
1139{
1140 double tx, ty, z;
1141
1142 /* Comfort. */
1143 z = sysedit_zoom;
1144
1145 /* Selection graphic. */
1146 if ( selected ) {
1147 const glColour csel = COL_ALPHA( cFontBlue, 0.5 );
1148 gl_renderCircle( bx + x * z, by + y * z, gfx->sw * z * 1.1, &csel, 1 );
1149 }
1150
1151 /* Translate coords. */
1152 tx = bx + ( x - gfx->sw / 2. ) * z;
1153 ty = by + ( y - gfx->sh / 2. ) * z;
1154 /* Blit the spob. */
1155 gl_renderScaleSprite( gfx, tx, ty, sx, sy, gfx->sw * z, gfx->sh * z, c );
1156
1157 /* Display caption. */
1158 if ( caption != NULL ) {
1159 const glColour *col;
1160 if ( selected )
1161 col = &cRed;
1162 else
1163 col = c;
1164 gl_printMidRaw( &gl_smallFont, gfx->sw * z + 100, tx - 50,
1165 ty - gl_smallFont.h - 5, col, -1., caption );
1166 }
1167}
1168
1172static void sysedit_focusLose( unsigned int wid, const char *wgtname )
1173{
1174 (void)wid;
1175 (void)wgtname;
1177}
1178
1179static int sysedit_mouseTrySelect( const Select_t *sel, double x, double y,
1180 double t, double mx, double my,
1181 SDL_Keymod mod, void ( *func )( void ) )
1182{
1183 x *= sysedit_zoom;
1184 y *= sysedit_zoom;
1185
1186 if ( ( pow2( mx - x ) + pow2( my - y ) ) > t )
1187 return 0;
1188
1189 /* Check if already selected. */
1190 for ( int j = 0; j < sysedit_nselect; j++ ) {
1191 if ( !sysedit_selectCmp( sel, &sysedit_select[j] ) )
1192 continue;
1193
1194 sysedit_dragSel = 1;
1195 sysedit_tsel = *sel;
1196
1197 /* Check modifier. */
1198 if ( mod & ( KMOD_LCTRL | KMOD_RCTRL ) )
1199 sysedit_tadd = 0;
1200 else {
1201 /* Detect double click to open spob editor. */
1202 if ( ( SDL_GetTicks() - sysedit_dragTime <
1203 SYSEDIT_DRAG_THRESHOLD * 2 ) &&
1205 if ( func != NULL )
1206 func();
1207 sysedit_dragSel = 0;
1208 return 1;
1209 }
1210 sysedit_tadd = -1;
1211 }
1212 sysedit_dragTime = SDL_GetTicks();
1213 sysedit_moved = 0;
1214 return 1;
1215 }
1216
1217 /* Add the system if not selected. */
1218 if ( mod & ( KMOD_LCTRL | KMOD_RCTRL ) )
1219 sysedit_selectAdd( sel );
1220 else {
1222 sysedit_selectAdd( sel );
1223 }
1225
1226 /* Start dragging anyway. */
1227 sysedit_dragSel = 1;
1228 sysedit_dragTime = SDL_GetTicks();
1229 sysedit_moved = 0;
1230 return 1;
1231}
1232
1236static int sysedit_mouse( unsigned int wid, const SDL_Event *event, double mx,
1237 double my, double w, double h, double xr, double yr,
1238 void *data )
1239{
1240 (void)data;
1241 StarSystem *sys = sysedit_sys;
1242 SDL_Keymod mod = SDL_GetModState();
1243
1244 switch ( event->type ) {
1245
1246 case SDL_MOUSEWHEEL:
1247 /* Must be in bounds. */
1248 if ( ( mx < 0. ) || ( mx > w ) || ( my < 0. ) || ( my > h ) )
1249 return 0;
1250
1251 if ( event->wheel.y > 0 )
1252 sysedit_buttonZoom( 0, "btnZoomIn" );
1253 else if ( event->wheel.y < 0 )
1254 sysedit_buttonZoom( 0, "btnZoomOut" );
1255
1256 return 1;
1257
1258 case SDL_MOUSEBUTTONDOWN:
1259 /* Must be in bounds. */
1260 if ( ( mx < 0. ) || ( mx > w ) || ( my < 0. ) || ( my > h ) )
1261 return 0;
1262 window_setFocus( wid, "cstSysEdit" );
1263
1264 /* selecting star system */
1265 mx -= w / 2 - sysedit_xpos;
1266 my -= h / 2 - sysedit_ypos;
1267
1268 /* Check spobs. */
1269 for ( int i = 0; i < array_size( sys->spobs ); i++ ) {
1270 Spob *p = sys->spobs[i];
1271 const Select_t sel = {
1272 .type = SELECT_SPOB,
1273 .u.spob = i,
1274 };
1275
1276 /* Threshold. */
1277 double t = pow2( p->radius ); /* Radius^2 */
1278 t *= pow2( 2. * sysedit_zoom );
1279
1280 /* Try to select. */
1281 if ( sysedit_mouseTrySelect( &sel, p->pos.x, p->pos.y, t, mx, my, mod,
1282 sysedit_editPnt ) )
1283 return 1;
1284 }
1285
1286 /* Check jump points. */
1287 for ( int i = 0; i < array_size( sys->jumps ); i++ ) {
1288 JumpPoint *jp = &sys->jumps[i];
1289 const Select_t sel = {
1290 .type = SELECT_JUMPPOINT,
1291 .u.jump = i,
1292 };
1293
1294 /* Threshold. */
1295 double t = jumppoint_gfx->sw * jumppoint_gfx->sh / 4.; /* Radius^2 */
1296 t *= pow2( 2. * sysedit_zoom );
1297
1298 /* Try to select. */
1299 if ( sysedit_mouseTrySelect( &sel, jp->pos.x, jp->pos.y, t, mx, my,
1300 mod, sysedit_editJump ) )
1301 return 1;
1302 }
1303
1304 /* Check asteroids exclusions. */
1305 for ( int i = 0; i < array_size( sys->astexclude ); i++ ) {
1306 AsteroidExclusion *exc = &sys->astexclude[i];
1307 const Select_t sel = {
1308 .type = SELECT_ASTEXCLUDE,
1309 .u.astexclude = i,
1310 };
1311 double t = pow2( exc->radius * sysedit_zoom );
1312
1313 /* Try to select. */
1314 if ( sysedit_mouseTrySelect( &sel, exc->pos.x, exc->pos.y, t, mx, my,
1315 mod, sysedit_editExclusion ) )
1316 return 1;
1317 }
1318
1319 /* Check asteroids. */
1320 for ( int i = 0; i < array_size( sys->asteroids ); i++ ) {
1321 AsteroidAnchor *ast = &sys->asteroids[i];
1322 const Select_t sel = {
1323 .type = SELECT_ASTEROID,
1324 .u.asteroid = i,
1325 };
1326 double t = pow2( ast->radius * sysedit_zoom );
1327
1328 /* Try to select. */
1329 if ( sysedit_mouseTrySelect( &sel, ast->pos.x, ast->pos.y, t, mx, my,
1330 mod, sysedit_editAsteroids ) )
1331 return 1;
1332 }
1333
1334 /* Start dragging. */
1335 if ( !( mod & ( KMOD_LCTRL | KMOD_RCTRL ) ) ) {
1336 sysedit_drag = 1;
1337 sysedit_dragTime = SDL_GetTicks();
1338 sysedit_moved = 0;
1340 }
1341 return 1;
1342
1343 case SDL_MOUSEBUTTONUP:
1344 if ( sysedit_drag ) {
1345 if ( ( SDL_GetTicks() - sysedit_dragTime < SYSEDIT_DRAG_THRESHOLD ) &&
1347 if ( sysedit_tsel.type == SELECT_NONE )
1349 else
1351 }
1352 sysedit_drag = 0;
1353
1354 if ( conf.devautosave ) {
1355 int ret = dsys_saveSystem( sysedit_sys );
1356 for ( int i = 0; i < sysedit_nselect; i++ )
1357 if ( sysedit_select[i].type == SELECT_SPOB )
1358 ret |= dpl_saveSpob( sys->spobs[sysedit_select[i].u.spob] );
1359 if ( ret )
1360 uniedit_saveError();
1361 }
1362 }
1363 if ( sysedit_dragSel ) {
1364 if ( ( SDL_GetTicks() - sysedit_dragTime < SYSEDIT_DRAG_THRESHOLD ) &&
1366 ( sysedit_tsel.type != SELECT_NONE ) ) {
1367 if ( sysedit_tadd == 0 )
1369 else {
1372 }
1373 }
1374 sysedit_dragSel = 0;
1375
1376 /* Save all spobs in our selection - their positions might have
1377 * changed. */
1378 if ( conf.devautosave ) {
1379 int ret = dsys_saveSystem( sysedit_sys );
1380 for ( int i = 0; i < sysedit_nselect; i++ )
1381 if ( sysedit_select[i].type == SELECT_SPOB )
1382 ret |= dpl_saveSpob( sys->spobs[sysedit_select[i].u.spob] );
1383 if ( ret )
1384 uniedit_saveError();
1385 }
1386 }
1387 break;
1388
1389 case SDL_MOUSEMOTION:
1390 /* Update mouse positions. */
1391 sysedit_mx = mx;
1392 sysedit_my = my;
1393
1394 /* Handle dragging. */
1395 if ( sysedit_drag ) {
1396 /* axis is inverted */
1397 sysedit_xpos -= xr;
1398 sysedit_ypos += yr;
1399
1400 /* Update mouse movement. */
1401 sysedit_moved += ABS( xr ) + ABS( yr );
1402 }
1403 /* Dragging selection around. */
1404 else if ( sysedit_dragSel && ( sysedit_nselect > 0 ) ) {
1406 ( SDL_GetTicks() - sysedit_dragTime > SYSEDIT_DRAG_THRESHOLD ) ) {
1407 double xmove = xr / sysedit_zoom;
1408 double ymove = -yr / sysedit_zoom;
1409 for ( int i = 0; i < sysedit_nselect; i++ ) {
1410 Spob *p;
1411 JumpPoint *jp;
1412 AsteroidAnchor *ast;
1413 AsteroidExclusion *exc;
1414 Select_t *sel = &sysedit_select[i];
1415
1416 switch ( sel->type ) {
1417 case SELECT_SPOB:
1418 p = sys->spobs[sel->u.spob];
1419 if ( uniedit_diffMode ) {
1420 sysedit_diffCreateSpobFloat( p, HUNK_TYPE_SPOB_POS_X,
1421 p->pos.x + xmove );
1422 sysedit_diffCreateSpobFloat( p, HUNK_TYPE_SPOB_POS_Y,
1423 p->pos.y + ymove );
1424 } else {
1425 p->pos.x += xmove;
1426 p->pos.y += ymove;
1427 }
1428 break;
1429
1430 case SELECT_JUMPPOINT:
1431 jp = &sys->jumps[sel->u.jump];
1432 if ( uniedit_diffMode ) {
1433 /* TODO diff. */
1434 dialogue_alertRaw( _( "Editing jump points is not yet "
1435 "supported in diff mode." ) );
1436 } else {
1437 jp->flags &= ~( JP_AUTOPOS );
1438 jp->pos.x += xmove;
1439 jp->pos.y += ymove;
1440 }
1441 break;
1442
1443 case SELECT_ASTEROID:
1444 ast = &sys->asteroids[sel->u.asteroid];
1445 if ( uniedit_diffMode ) {
1446 if ( ( ast->label == NULL ) ||
1447 ( strcmp( ast->label, "" ) == 0 ) ) {
1449 _( "Modifying asteroid fields in diff mode is only "
1450 "supported when "
1451 "they "
1452 "have labels. Please set a label via the "
1453 "property editor." ) );
1454 } else {
1455 uniedit_diffCreateSysFloatAttr(
1456 sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_POS_X,
1457 ast->pos.x + xmove, sysedit_asteroidsAttr( ast ) );
1458 uniedit_diffCreateSysFloatAttr(
1459 sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_POS_Y,
1460 ast->pos.y + ymove, sysedit_asteroidsAttr( ast ) );
1461 }
1462 } else {
1463 ast->pos.x += xmove;
1464 ast->pos.y += ymove;
1465 }
1466 break;
1467
1468 case SELECT_ASTEXCLUDE:
1469 exc = &sys->astexclude[sel->u.astexclude];
1470 if ( uniedit_diffMode ) {
1471 /* TODO diff. */
1472 } else {
1473 exc->pos.x += xmove;
1474 exc->pos.y += ymove;
1475 }
1476 break;
1477 }
1478 }
1479 }
1480
1481 /* Update mouse movement. */
1482 sysedit_moved += ABS( xr ) + ABS( yr );
1483 }
1484 break;
1485 }
1486
1487 return 0;
1488}
1489
1496static void sysedit_buttonZoom( unsigned int wid, const char *str )
1497{
1498 (void)wid;
1499
1500 /* Transform coords to normal. */
1503
1504 /* Apply zoom. */
1505 if ( strcmp( str, "btnZoomIn" ) == 0 ) {
1507 sysedit_zoom =
1509 } else if ( strcmp( str, "btnZoomOut" ) == 0 ) {
1511 sysedit_zoom =
1513 }
1514
1515 /* Transform coords back. */
1518}
1519
1523static void sysedit_deselect( void )
1524{
1525 if ( sysedit_nselect > 0 )
1526 free( sysedit_select );
1527 sysedit_select = NULL;
1528 sysedit_nselect = 0;
1529 sysedit_mselect = 0;
1530
1531 /* Button check. */
1533}
1534
1538static void sysedit_checkButtons( void )
1539{
1540 int sel_spob, sel_jump, sel_asteroid, sel_exclusion;
1541
1542 /* See if a spob or jump is selected. */
1543 sel_spob = 0;
1544 sel_jump = 0;
1545 sel_asteroid = 0;
1546 sel_exclusion = 0;
1547 for ( int i = 0; i < sysedit_nselect; i++ ) {
1548 const Select_t *sel = &sysedit_select[i];
1549 switch ( sel->type ) {
1550 case SELECT_SPOB:
1551 sel_spob++;
1552 break;
1553 case SELECT_JUMPPOINT:
1554 sel_spob++;
1555 break;
1556 case SELECT_ASTEROID:
1557 sel_asteroid++;
1558 break;
1559 case SELECT_ASTEXCLUDE:
1560 sel_exclusion++;
1561 break;
1562 }
1563 }
1564
1565 /* Spob dependent. */
1566 if ( sel_spob || sel_asteroid || sel_exclusion )
1567 window_enableButton( sysedit_wid, "btnRemove" );
1568 else
1569 window_disableButton( sysedit_wid, "btnRemove" );
1570
1571 /* Jump dependent. */
1572 if ( sel_jump )
1573 window_enableButton( sysedit_wid, "btnReset" );
1574 else
1575 window_disableButton( sysedit_wid, "btnReset" );
1576
1577 /* Editor - just one spob. */
1578 if ( sysedit_nselect == 1 )
1579 window_enableButton( sysedit_wid, "btnEdit" );
1580 else
1581 window_disableButton( sysedit_wid, "btnEdit" );
1582}
1583
1587static void sysedit_selectAdd( const Select_t *sel )
1588{
1589 /* Allocate if needed. */
1590 if ( sysedit_mselect < sysedit_nselect + 1 ) {
1591 if ( sysedit_mselect == 0 )
1592 sysedit_mselect = 1;
1593 sysedit_mselect *= 2;
1595 realloc( sysedit_select, sizeof( Select_t ) * sysedit_mselect );
1596 }
1597
1598 /* Add system. */
1601
1602 /* Button check. */
1604}
1605
1609static void sysedit_selectRm( const Select_t *sel )
1610{
1611 for ( int i = 0; i < sysedit_nselect; i++ ) {
1612 if ( sysedit_selectCmp( &sysedit_select[i], sel ) ) {
1614 memmove( &sysedit_select[i], &sysedit_select[i + 1],
1615 sizeof( Select_t ) * ( sysedit_nselect - i ) );
1616 /* Button check. */
1618 return;
1619 }
1620 }
1621 WARN( _( "Trying to deselect item that is not in selection!" ) );
1622}
1623
1629static int sysedit_selectCmp( const Select_t *a, const Select_t *b )
1630{
1631 return ( memcmp( a, b, sizeof( Select_t ) ) == 0 );
1632}
1633
1637static int sysedit_isSelected( const Select_t *sel )
1638{
1639 for ( int i = 0; i < sysedit_nselect; i++ )
1640 if ( sysedit_selectCmp( sel, &sysedit_select[i] ) )
1641 return 1;
1642 return 0;
1643}
1644
1648static void sysedit_editPnt( void )
1649{
1650 unsigned int wid;
1651 int x, y, w, l, bw;
1652 char buf[STRMAX_SHORT], title[128];
1653 const char *s;
1654 Spob *p;
1655
1656 p = sysedit_sys->spobs[sysedit_select[0].u.spob];
1657
1658 /* Create the window. */
1659 snprintf( title, sizeof( title ), _( "Space Object Property Editor - %s" ),
1660 p->name );
1661 wid = window_create( "wdwSysEditPnt", title, -1, -1, SYSEDIT_EDIT_WIDTH,
1663 sysedit_widEdit = wid;
1664
1666
1667 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
1668
1669 /* Rename button. */
1670 y = -40;
1671 snprintf( buf, sizeof( buf ), "%s ", _( "Name:" ) );
1672 w = gl_printWidthRaw( NULL, buf );
1673 window_addText( wid, 20, y, 180, 15, 0, "txtNameLabel", &gl_smallFont, NULL,
1674 buf );
1675 snprintf( buf, sizeof( buf ), "%s", p->name );
1676 window_addText( wid, 20 + w, y, 180, 15, 0, "txtName", &gl_smallFont, NULL,
1677 buf );
1678 window_addButton( wid, -20, y - gl_defFont.h / 2. + BUTTON_HEIGHT / 2., bw,
1679 BUTTON_HEIGHT, "btnRename", _( "Rename" ),
1680 sysedit_btnRename );
1681 window_addButton(
1682 wid, -20 - 15 - bw, y - gl_defFont.h / 2. + BUTTON_HEIGHT / 2., bw,
1683 BUTTON_HEIGHT, "btnFaction", _( "Faction" ), sysedit_btnFaction );
1684
1685 y -= gl_defFont.h + 5;
1686
1687 snprintf( buf, sizeof( buf ), "%s ", _( "Faction:" ) );
1688 w = gl_printWidthRaw( NULL, buf );
1689 window_addText( wid, 20, y, 180, 15, 0, "txtFactionLabel", &gl_smallFont,
1690 NULL, buf );
1691 snprintf( buf, sizeof( buf ), "%s",
1692 p->presence.faction >= 0 ? faction_name( p->presence.faction )
1693 : _( "None" ) );
1694 window_addText( wid, 20 + w, y, 180, 15, 0, "txtFaction", &gl_smallFont,
1695 NULL, buf );
1696 y -= gl_defFont.h + 5;
1697
1698 /* Input widgets and labels. */
1699 x = 20;
1700 s = _( "Population" );
1701 l = gl_printWidthRaw( NULL, s );
1702 window_addText( wid, x, y, l, 20, 1, "txtPop", NULL, NULL, s );
1703 window_addInput( wid, x += l + 5, y, 80, 20, "inpPop", 12, 1, NULL );
1704 window_setInputFilter( wid, "inpPop", INPUT_FILTER_NUMBER );
1705 x += 80 + 10;
1706
1707 s = _( "Class" );
1708 l = gl_printWidthRaw( NULL, s );
1709 window_addText( wid, x, y, l, 20, 1, "txtClass", NULL, NULL, s );
1710 window_addInput( wid, x += l + 5, y, 30, 20, "inpClass", 16, 1, NULL );
1711 x += 30 + 10;
1712
1713 s = _( "Lua" );
1714 l = gl_printWidthRaw( NULL, s );
1715 window_addText( wid, x, y, l, 20, 1, "txtLua", NULL, NULL, s );
1716 window_addInput( wid, x += l + 5, y, 180, 20, "inpLua", 50, 1, NULL );
1717 y -= gl_defFont.h + 15;
1718
1719 /* Second row. */
1720 x = 20;
1721 s = _( "Base Presence" );
1722 l = gl_printWidthRaw( NULL, s );
1723 window_addText( wid, x, y, l, 20, 1, "txtPresenceBase", NULL, NULL, s );
1724 window_addInput( wid, x += l + 5, y, 50, 20, "inpPresenceBase", 5, 1, NULL );
1725 window_setInputFilter( wid, "inpPresenceBase", INPUT_FILTER_NUMBER );
1726 x += 50 + 10;
1727
1728 s = _( "Bonus Presence" );
1729 l = gl_printWidthRaw( NULL, s );
1730 window_addText( wid, x, y, l, 20, 1, "txtPresenceBonus", NULL, NULL, s );
1731 window_addInput( wid, x += l + 5, y, 50, 20, "inpPresenceBonus", 5, 1,
1732 NULL );
1733 window_setInputFilter( wid, "inpPresenceBonus", INPUT_FILTER_NUMBER );
1734 x += 50 + 10;
1735
1736 s = p_( "sysedit", "Range" );
1737 l = gl_printWidthRaw( NULL, s );
1738 window_addText( wid, x, y, l, 20, 1, "txtPresenceRange", NULL, NULL, s );
1739 window_addInput( wid, x += l + 5, y, 30, 20, "inpPresenceRange", 1, 1,
1740 NULL );
1741 window_setInputFilter( wid, "inpPresenceRange", INPUT_FILTER_NUMBER );
1742 // x += 30 + 10;
1743
1744 x = 250;
1745 y -= gl_defFont.h + 15;
1746 s = _( "hide" );
1747 l = gl_printWidthRaw( NULL, s );
1748 window_addText( wid, x, y, l, 20, 1, "txtHide", NULL, NULL, s );
1749 window_addInput( wid, x += l + 5, y, 50, 20, "inpHide", 4, 1, NULL );
1750 window_setInputFilter( wid, "inpHide", INPUT_FILTER_NUMBER );
1751 // x += 50 + 10;
1752
1753 /* Tags. */
1754 x = 250;
1755 y -= gl_defFont.h + 20;
1756 l = scnprintf( buf, sizeof( buf ), "#n%s#0", _( "Tags:" ) );
1757 for ( int i = 0; i < array_size( p->tags ); i++ )
1758 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s %s",
1759 ( ( i > 0 ) ? "," : "" ), p->tags[i] );
1760 window_addText( wid, x, y, 240, 100, 0, "txtTags", NULL, NULL, buf );
1761
1762 /* Bottom buttons. */
1763 window_addButton( wid, -20 - bw * 3 - 15 * 3, 35 + BUTTON_HEIGHT, bw,
1764 BUTTON_HEIGHT, "btnRmService", _( "Rm Service" ),
1766 window_addButton( wid, -20 - bw * 2 - 15 * 2, 35 + BUTTON_HEIGHT, bw,
1767 BUTTON_HEIGHT, "btnAddService", _( "Add Service" ),
1769 window_addButton( wid, -20 - bw - 15, 35 + BUTTON_HEIGHT, bw, BUTTON_HEIGHT,
1770 "btnEditTech", _( "Edit Tech" ), sysedit_btnTechEdit );
1771 window_addButton( wid, -20, 35 + BUTTON_HEIGHT, bw, BUTTON_HEIGHT,
1772 "btnEditTags", _( "Edit Tags" ), sysedit_btnTagsEdit );
1773 window_addButton( wid, -20 - bw * 3 - 15 * 3, 20, bw, BUTTON_HEIGHT,
1774 "btnDesc", _( "Description" ), sysedit_spobDesc );
1775 window_addButton( wid, -20 - bw * 2 - 15 * 2, 20, bw, BUTTON_HEIGHT,
1776 "btnLandGFX", _( "Land GFX" ), sysedit_spobGFX );
1777 window_addButton( wid, -20 - bw - 15, 20, bw, BUTTON_HEIGHT, "btnSpaceGFX",
1778 _( "Space GFX" ), sysedit_spobGFX );
1779 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
1781
1782 /* Load current values. */
1783 snprintf( buf, sizeof( buf ), "%lf", p->population );
1784 window_setInput( wid, "inpPop", buf );
1785 snprintf( buf, sizeof( buf ), "%s", p->class );
1786 window_setInput( wid, "inpClass", buf );
1787 window_setInput( wid, "inpLua", p->lua_file );
1788 snprintf( buf, sizeof( buf ), "%g", p->presence.base );
1789 window_setInput( wid, "inpPresenceBase", buf );
1790 snprintf( buf, sizeof( buf ), "%g", p->presence.bonus );
1791 window_setInput( wid, "inpPresenceBonus", buf );
1792 snprintf( buf, sizeof( buf ), "%d", p->presence.range );
1793 window_setInput( wid, "inpPresenceRange", buf );
1794 snprintf( buf, sizeof( buf ), "%g", p->hide );
1795 window_setInput( wid, "inpHide", buf );
1796
1797 /* Generate the list. */
1799}
1800
1804static void jp_type_check_hidden_update( unsigned int wid, const char *str )
1805{
1806 (void)str;
1807 if ( jp_hidden == 0 ) {
1808 jp_hidden = 1;
1809 jp_exit = 0;
1810 } else
1811 jp_hidden = 0;
1812 window_checkboxSet( wid, "chkHidden", jp_hidden );
1813 window_checkboxSet( wid, "chkExit", jp_exit );
1814}
1815
1819static void jp_type_check_exit_update( unsigned int wid, const char *str )
1820{
1821 (void)str;
1822 if ( jp_exit == 0 ) {
1823 jp_exit = 1;
1824 jp_hidden = 0;
1825 } else
1826 jp_exit = 0;
1827 window_checkboxSet( wid, "chkHidden", jp_hidden );
1828 window_checkboxSet( wid, "chkExit", jp_exit );
1829}
1830
1834static void jp_type_check_nolanes_update( unsigned int wid, const char *str )
1835{
1836 int s = window_checkboxState( wid, str );
1837 JumpPoint *j = &sysedit_sys->jumps[sysedit_select[0].u.jump];
1838 if ( s )
1839 jp_setFlag( j, JP_NOLANES );
1840 else
1841 jp_rmFlag( j, JP_NOLANES );
1842}
1843
1847static void sysedit_editJump( void )
1848{
1849 unsigned int wid;
1850 int x, y, w, l, bw;
1851 char buf[STRMAX_SHORT];
1852 const char *s;
1853 JumpPoint *j = &sysedit_sys->jumps[sysedit_select[0].u.jump];
1854
1855 /* Create the window. */
1856 wid = window_create( "wdwJumpPointEditor", _( "Jump Point Editor" ), -1, -1,
1858 sysedit_widEdit = wid;
1859
1860 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
1861
1862 /* Target lable. */
1863 y = -40;
1864 snprintf( buf, sizeof( buf ), _( "Target: " ) );
1865 w = gl_printWidthRaw( NULL, buf );
1866 window_addText( wid, 20, y, 180, 15, 0, "txtTargetLabel", &gl_smallFont,
1867 NULL, buf );
1868 snprintf( buf, sizeof( buf ), "%s", j->target->name );
1869 window_addText( wid, 20 + w, y, 180, 15, 0, "txtName", &gl_smallFont, NULL,
1870 buf );
1871
1872 y -= gl_defFont.h + 10;
1873
1874 /* Input widgets and labels. */
1875 x = 20;
1876
1877 /* Initial checkbox state */
1878 jp_hidden = 0;
1879 jp_exit = 0;
1880 if ( jp_isFlag( j, JP_HIDDEN ) )
1881 jp_hidden = 1;
1882 else if ( jp_isFlag( j, JP_EXITONLY ) )
1883 jp_exit = 1;
1884 /* Create check boxes. */
1885 window_addCheckbox( wid, x, y, 100, 20, "chkHidden", _( "Hidden" ),
1887 y -= 20;
1888 window_addCheckbox( wid, x, y, 100, 20, "chkExit", _( "Exit only" ),
1890 y -= 20;
1891 window_addCheckbox( wid, x, y, 100, 20, "chkNolanes", _( "No lanes" ),
1893 jp_isFlag( j, JP_NOLANES ) );
1894 y -= 30;
1895
1896 s = _( "Hide" ); /* TODO: if inpType == 0 disable hide box */
1897 l = gl_printWidthRaw( NULL, s );
1898 window_addText( wid, x, y, l, 20, 1, "txtHide", NULL, NULL, s );
1899 window_addInput( wid, x + l + 8, y, 50, 20, "inpHide", 4, 1, NULL );
1900 window_setInputFilter( wid, "inpHide", INPUT_FILTER_NUMBER );
1901 // x += 50 + 10;
1902
1903 /* Bottom buttons. */
1904 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
1906
1907 /* Load current values. */
1908 snprintf( buf, sizeof( buf ), "%g", j->hide );
1909 window_setInput( wid, "inpHide", buf );
1910}
1911
1915static void sysedit_editJumpClose( unsigned int wid, const char *unused )
1916{
1917 (void)unused;
1918 JumpPoint *j = &sysedit_sys->jumps[sysedit_select[0].u.jump];
1919
1920 if ( uniedit_diffMode ) {
1921 /* TODO implement. */
1923 _( "Editing jump points is not yet supported in diff mode." ) );
1924 window_close( wid, unused );
1925 return;
1926 }
1927
1928 /* TODO add diff support. */
1929 if ( jp_hidden == 1 ) {
1930 jp_setFlag( j, JP_HIDDEN );
1931 jp_rmFlag( j, JP_EXITONLY );
1932 } else if ( jp_exit == 1 ) {
1933 jp_setFlag( j, JP_EXITONLY );
1934 jp_rmFlag( j, JP_HIDDEN );
1935 } else {
1936 jp_rmFlag( j, JP_HIDDEN );
1937 jp_rmFlag( j, JP_EXITONLY );
1938 }
1939 j->hide = atof( window_getInput( sysedit_widEdit, "inpHide" ) );
1940
1941 window_close( wid, unused );
1942}
1943
1947static void sysedit_editAsteroids( void )
1948{
1949 unsigned int wid;
1950 int x, y, l, bw;
1951 char buf[STRMAX_SHORT];
1952 const char *s;
1953 const AsteroidAnchor *ast =
1954 &sysedit_sys->asteroids[sysedit_select[0].u.asteroid];
1955
1956 /* Create the window. */
1957 wid = window_create( "wdwAsteroidsEditor", _( "Asteroid Field Editor" ), -1,
1959 sysedit_widEdit = wid;
1960 window_setCancel( wid, sysedit_editAsteroidsClose );
1961
1962 /* Input widgets and labels. */
1963 x = 20;
1964
1965 /* Add some inputs. */
1966 y = -40;
1967 s = _( "Label: " );
1968 l = gl_printWidthRaw( NULL, s );
1969 window_addText( wid, x, y, l, 20, 1, "txtLabel", NULL, NULL, s );
1970 if ( uniedit_diffMode )
1971 window_addText( wid, x + l + 8, y, 80, 20, 1, "txtInpLabel", NULL, NULL,
1972 ast->label );
1973 else
1974 window_addInput( wid, x + l + 8, y, 80, 20, "inpLabel", 10, 1, NULL );
1975 x += l + 20 + 80 + 8;
1976 s = _( "Density: " );
1977 l = gl_printWidthRaw( NULL, s );
1978 if ( x + l > SYSEDIT_EDIT_WIDTH - 20 ) {
1979 x = 20;
1980 y -= 30;
1981 }
1982 window_addText( wid, x, y, l, 20, 1, "txtDensity", NULL, NULL, s );
1983 window_addInput( wid, x + l + 8, y, 80, 20, "inpDensity", 10, 1, NULL );
1984 window_setInputFilter( wid, "inpDensity", INPUT_FILTER_NUMBER );
1985 x += l + 20 + 80 + 8;
1986 s = _( "Radius: " );
1987 l = gl_printWidthRaw( NULL, s );
1988 if ( x + l > SYSEDIT_EDIT_WIDTH - 20 ) {
1989 x = 20;
1990 y -= 30;
1991 }
1992 window_addText( wid, x, y, l, 20, 1, "txtInput", NULL, NULL, s );
1993 window_addInput( wid, x + l + 8, y, 80, 20, "inpRadius", 10, 1, NULL );
1994 window_setInputFilter( wid, "inpRadius", INPUT_FILTER_NUMBER );
1995 x += l + 20 + 80 + 8;
1996 s = _( "Max Speed: " );
1997 l = gl_printWidthRaw( NULL, s );
1998 if ( x + l > SYSEDIT_EDIT_WIDTH - 20 ) {
1999 x = 20;
2000 y -= 30;
2001 }
2002 window_addText( wid, x, y, l, 20, 1, "txtMaxspeed", NULL, NULL, s );
2003 window_addInput( wid, x + l + 8, y, 80, 20, "inpMaxspeed", 10, 1, NULL );
2004 window_setInputFilter( wid, "inpMaxspeed", INPUT_FILTER_NUMBER );
2005 x += l + 20 + 80 + 8;
2006 s = _( "Accel: " );
2007 l = gl_printWidthRaw( NULL, s );
2008 if ( x + l > SYSEDIT_EDIT_WIDTH - 20 ) {
2009 x = 20;
2010 y -= 30;
2011 }
2012 window_addText( wid, x, y, l, 20, 1, "txtAccel", NULL, NULL, s );
2013 window_addInput( wid, x + l + 8, y, 80, 20, "inpAccel", 10, 1, NULL );
2014 window_setInputFilter( wid, "inpAccel", INPUT_FILTER_NUMBER );
2015 y -= 40;
2016
2017 /* Button width. */
2018 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 2.;
2019
2020 /* List Captions. */
2021 window_addText( wid, 20, y, bw, gl_smallFont.h, 1, "txtAsteroidsHave", NULL,
2022 NULL, _( "Asteroids" ) );
2023 window_addText( wid, 20 + bw + 15, y, bw, gl_smallFont.h, 1,
2024 "txtAsteroidsAvailable", NULL, NULL, _( "Available" ) );
2025
2026 /* Button width. */
2027 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
2028
2029 /* Bottom buttons. */
2030 window_addButton( wid, 20, 20, bw, BUTTON_HEIGHT, "btnRmAsteroid",
2031 _( "Rm Asteroid" ), sysedit_btnRmAsteroid );
2032 window_addButton( wid, 20 + bw + 15, 20, bw, BUTTON_HEIGHT, "btnAddAsteroid",
2033 _( "Add Asteroid" ), sysedit_btnAddAsteroid );
2034 window_addButton( wid, 20 + 2 * ( bw + 15 ), 20, bw, BUTTON_HEIGHT,
2035 "btnDelete", _( "Delete" ), sysedit_btnAsteroidsDelete );
2036 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
2037 sysedit_editAsteroidsClose );
2038
2039 /* List to choose the different asteroids that appear. Has to be created
2040 * after buttons. */
2041 sysedit_genAsteroidsList( wid );
2042
2043 /* Load current values. */
2044 if ( !uniedit_diffMode && ( ast->label != NULL ) )
2045 window_setInput( wid, "inpLabel", ast->label );
2046 snprintf( buf, sizeof( buf ), "%g", ast->density );
2047 window_setInput( wid, "inpDensity", buf );
2048 snprintf( buf, sizeof( buf ), "%g", ast->radius );
2049 window_setInput( wid, "inpRadius", buf );
2050 snprintf( buf, sizeof( buf ), "%g", ast->maxspeed );
2051 window_setInput( wid, "inpMaxspeed", buf );
2052 snprintf( buf, sizeof( buf ), "%g", ast->accel );
2053 window_setInput( wid, "inpAccel", buf );
2054}
2055
2056static void sysedit_genAsteroidsList( unsigned int wid )
2057{
2058 int hpos, apos, nhave, navail;
2059 int x, y, w, h;
2060 const AsteroidAnchor *ast =
2061 &sysedit_sys->asteroids[sysedit_select[0].u.asteroid];
2062 const AsteroidTypeGroup *astgroups;
2063 char **have, **available;
2064 int wx, wy, ww, wh;
2065
2066 window_posWidget( wid, "txtAsteroidsHave", &wx, &wy );
2067 window_dimWidget( wid, "txtAsteroidsHave", &ww, &wh );
2068
2069 hpos = apos = -1;
2070 if ( widget_exists( wid, "lstAsteroidsHave" ) &&
2071 widget_exists( wid, "lstAsteroidsAvailable" ) ) {
2072 hpos = toolkit_getListPos( wid, "lstAsteroidsHave" );
2073 apos = toolkit_getListPos( wid, "lstAsteroidsAvailable" );
2074 window_destroyWidget( wid, "lstAsteroidsHave" );
2075 window_destroyWidget( wid, "lstAsteroidsAvailable" );
2076 }
2077
2078 /* Set up positions. */
2079 w = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 2.;
2080 h = 200;
2081 x = 20;
2082 y = wy + wh - 15 - h;
2083
2084 /* Find and add used asteroids. */
2085 nhave = array_size( ast->groups );
2086 if ( nhave > 0 ) {
2087 have = malloc( sizeof( char * ) * nhave );
2088 for ( int i = 0; i < nhave; i++ )
2089 have[i] = strdup( ast->groups[i]->name );
2090 window_enableButton( wid, "btnRmAsteroid" );
2091 } else {
2092 have = NULL;
2093 window_disableButton( wid, "btnRmAsteroid" );
2094 }
2095 window_addList( wid, x, y, w, h, "lstAsteroidsHave", have, nhave, 0, NULL,
2096 sysedit_btnRmAsteroid );
2097 x += w + 15;
2098
2099 /* Load all asteroid types. */
2100 astgroups = astgroup_getAll();
2101 navail = array_size( astgroups );
2102 if ( navail > 0 ) {
2103 available = malloc( sizeof( char * ) * navail );
2104 for ( int i = 0; i < navail; i++ )
2105 available[i] = strdup( astgroups[i].name );
2106 qsort( available, navail, sizeof( char * ), strsort );
2107 window_enableButton( wid, "btnAddAsteroid" );
2108 } else {
2109 available = NULL;
2110 window_disableButton( wid, "btnAddAsteroid" );
2111 }
2112 window_addList( wid, x, y, w, h, "lstAsteroidsAvailable", available, navail,
2113 0, NULL, sysedit_btnAddAsteroid );
2114
2115 /* Restore positions. */
2116 if ( hpos != -1 && apos != -1 ) {
2117 toolkit_setListPos( wid, "lstAsteroidsHave", hpos );
2118 toolkit_setListPos( wid, "lstAsteroidsAvailable", apos );
2119 }
2120}
2121
2122static void sysedit_btnRmAsteroid( unsigned int wid, const char *unused )
2123{
2124 (void)unused;
2125 int pos = toolkit_getListPos( wid, "lstAsteroidsHave" );
2126 AsteroidAnchor *ast;
2127 if ( pos < 0 )
2128 return;
2129 if ( array_size( sysedit_sys->asteroids ) <= 0 )
2130 return;
2131 ast = &sysedit_sys->asteroids[sysedit_select[0].u.asteroid];
2132
2133 if ( uniedit_diffMode ) {
2134 if ( ( ast->label == NULL ) || ( strcmp( ast->label, "" ) == 0 ) ) {
2136 _( "Modifying asteroid fields in diff mode is only supported when "
2137 "they "
2138 "have labels. Please set a label via the property editor." ) );
2139 return;
2140 }
2141 uniedit_diffCreateSysStrAttr(
2142 sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_REMOVE_TYPE,
2143 ast->groups[pos]->name, sysedit_asteroidsAttr( ast ) );
2144 } else {
2145 if ( array_size( ast->groups ) > 0 )
2146 array_erase( &ast->groups, &ast->groups[pos], &ast->groups[pos + 1] );
2147 }
2148
2149 sysedit_genAsteroidsList( wid );
2150}
2151
2152static void sysedit_btnAddAsteroid( unsigned int wid, const char *unused )
2153{
2154 (void)unused;
2155 const char *selected = toolkit_getList( wid, "lstAsteroidsAvailable" );
2156 AsteroidAnchor *ast = &sysedit_sys->asteroids[sysedit_select[0].u.asteroid];
2157 AsteroidTypeGroup *grp = astgroup_getName( selected );
2158 /* Failed to add. */
2159 if ( grp == NULL )
2160 return;
2161 if ( uniedit_diffMode ) {
2162 if ( ( ast->label == NULL ) || ( strcmp( ast->label, "" ) == 0 ) ) {
2164 _( "Modifying asteroid fields in diff mode is only supported when "
2165 "they "
2166 "have labels. Please set a label via the property editor." ) );
2167 return;
2168 }
2169 uniedit_diffCreateSysStrAttr( sysedit_sys,
2170 HUNK_TYPE_SSYS_ASTEROIDS_ADD_TYPE,
2171 grp->name, sysedit_asteroidsAttr( ast ) );
2172 } else {
2173 array_push_back( &ast->groups, grp );
2174 }
2175
2176 sysedit_genAsteroidsList( wid );
2177}
2178
2179static void sysedit_btnAsteroidsDelete( unsigned int wid, const char *unused )
2180{
2181 int i = dialogue_YesNo(
2182 _( "Remove Asteroid Field" ),
2183 _( "Are you sure you want to remove this asteroid field?" ) );
2184 if ( i == 0 )
2185 return;
2186
2187 AsteroidAnchor *ast = &sysedit_sys->asteroids[sysedit_select[0].u.asteroid];
2188
2189 if ( uniedit_diffMode ) {
2190 if ( ( ast->label == NULL ) || ( strcmp( ast->label, "" ) == 0 ) ) {
2192 _( "Modifying asteroid fields in diff mode is only supported when "
2193 "they "
2194 "have labels. Please set a label via the property editor." ) );
2195 return;
2196 }
2197 uniedit_diffCreateSysStr( sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_REMOVE,
2198 ast->label );
2199 window_close( wid, unused );
2200 return;
2201 }
2202
2203 asteroid_freeAnchor( ast );
2204 array_erase( &sysedit_sys->asteroids, ast, ast + 1 );
2205
2206 if ( conf.devautosave ) {
2208 uniedit_saveError();
2209 }
2210
2211 window_close( wid, unused );
2212}
2213
2214static void sysedit_editAsteroidsClose( unsigned int wid, const char *unused )
2215{
2216 AsteroidAnchor *ast = &sysedit_sys->asteroids[sysedit_select[0].u.asteroid];
2217
2218 if ( uniedit_diffMode ) {
2219 double density, radius, maxspeed, accel;
2220 if ( ( ast->label == NULL ) || ( strcmp( ast->label, "" ) == 0 ) ) {
2222 _( "Editing asteroids in diff mode is only supported when they "
2223 "have labels. Please set a label via the property editor." ) );
2224 window_close( wid, unused );
2225 }
2226 density = atof( window_getInput( sysedit_widEdit, "inpDensity" ) );
2227 if ( ast->density - density > DOUBLE_TOL )
2228 uniedit_diffCreateSysFloatAttr(
2229 sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_DENSITY, density,
2230 sysedit_asteroidsAttr( ast ) );
2231 radius = atof( window_getInput( sysedit_widEdit, "inpRadius" ) );
2232 if ( ast->radius - radius > DOUBLE_TOL )
2233 uniedit_diffCreateSysFloatAttr(
2234 sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_RADIUS, density,
2235 sysedit_asteroidsAttr( ast ) );
2236 maxspeed = atof( window_getInput( sysedit_widEdit, "inpMaxspeed" ) );
2237 if ( ast->maxspeed - maxspeed > DOUBLE_TOL )
2238 uniedit_diffCreateSysFloatAttr(
2239 sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_MAXSPEED, density,
2240 sysedit_asteroidsAttr( ast ) );
2241 accel = atof( window_getInput( sysedit_widEdit, "inpAccel" ) );
2242 if ( ast->accel - accel > DOUBLE_TOL )
2243 uniedit_diffCreateSysFloatAttr(
2244 sysedit_sys, HUNK_TYPE_SSYS_ASTEROIDS_ACCEL, density,
2245 sysedit_asteroidsAttr( ast ) );
2246 return;
2247 }
2248 const char *label = window_getInput( sysedit_widEdit, "inpLabel" );
2249 free( ast->label );
2250 ast->label = NULL;
2251 if ( ( label != NULL ) && ( strcmp( label, "" ) != 0 ) ) {
2252 int found = 0;
2253 for ( int i = 0; i < array_size( sysedit_sys->asteroids ); i++ ) {
2254 if ( sysedit_sys->asteroids[i].label &&
2255 ( strcmp( sysedit_sys->asteroids[i].label, label ) == 0 ) ) {
2256 dialogue_alert( _( "Asteroid field with label '%s' already "
2257 "exists in system '%s'!" ),
2258 label, sysedit_sys->name );
2259 found = 1;
2260 break;
2261 }
2262 }
2263 if ( !found )
2264 ast->label = strdup( label );
2265 }
2266 ast->density = atof( window_getInput( sysedit_widEdit, "inpDensity" ) );
2267 ast->radius = atof( window_getInput( sysedit_widEdit, "inpRadius" ) );
2268 ast->maxspeed = atof( window_getInput( sysedit_widEdit, "inpMaxspeed" ) );
2269 ast->accel = atof( window_getInput( sysedit_widEdit, "inpAccel" ) );
2270
2271 /* Need to update some internals based on new values. */
2273
2274 if ( conf.devautosave ) {
2276 uniedit_saveError();
2277 }
2278
2279 window_close( wid, unused );
2280}
2281
2282static void sysedit_editExclusion( void )
2283{
2284 unsigned int wid;
2285 int x, y, l, bw;
2286 char buf[STRMAX_SHORT];
2287 const char *s;
2288 const AsteroidExclusion *exc =
2289 &sysedit_sys->astexclude[sysedit_select[0].u.astexclude];
2290
2291 /* Create the window. */
2292 wid = window_create( "wdwExclusionEditor",
2293 _( "Asteroid Exclusion Zone Editor" ), -1, -1,
2295 sysedit_widEdit = wid;
2296 window_setCancel( wid, sysedit_editExclusionClose );
2297
2298 /* Add some inputs. */
2299 x = 20;
2300 y = -40;
2301 s = _( "Label: " );
2302 l = gl_printWidthRaw( NULL, s );
2303 window_addText( wid, x, y, l, 20, 1, "txtLabel", NULL, NULL, s );
2304 if ( uniedit_diffMode )
2305 window_addText( wid, x + l + 8, y, 80, 20, 1, "txtInpLabel", NULL, NULL,
2306 exc->label );
2307 else
2308 window_addInput( wid, x + l + 8, y, 80, 20, "inpLabel", 10, 1, NULL );
2309 x += l + 20 + 80 + 8;
2310 s = _( "Radius: " );
2311 l = gl_printWidthRaw( NULL, s );
2312 window_addText( wid, x, y, l, 20, 1, "txtInput", NULL, NULL, s );
2313 window_addInput( wid, x + l + 8, y, 80, 20, "inpRadius", 10, 1, NULL );
2314 window_setInputFilter( wid, "inpRadius", INPUT_FILTER_NUMBER );
2315
2316 /* Bottom buttons. */
2317 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
2318 window_addButton( wid, -20 - 15 - bw, 20, bw, BUTTON_HEIGHT, "btnDelete",
2319 _( "Delete" ), sysedit_btnExclusionDelete );
2320 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
2321 sysedit_editExclusionClose );
2322
2323 /* Load current values. */
2324 if ( !uniedit_diffMode && ( exc->label != NULL ) )
2325 window_setInput( wid, "inpLabel", exc->label );
2326 snprintf( buf, sizeof( buf ), "%g", exc->radius );
2327 window_setInput( wid, "inpRadius", buf );
2328}
2329
2330static void sysedit_btnExclusionDelete( unsigned int wid, const char *unused )
2331{
2332 int i = dialogue_YesNo(
2333 _( "Remove Asteroid Exclusion Zone" ),
2334 _( "Are you sure you want to remove this asteroid exclusion zone?" ) );
2335 if ( i == 0 )
2336 return;
2337
2338 AsteroidExclusion *exc =
2339 &sysedit_sys->astexclude[sysedit_select[0].u.astexclude];
2340
2341 array_erase( &sysedit_sys->astexclude, exc, exc + 1 );
2342
2343 if ( conf.devautosave ) {
2345 uniedit_saveError();
2346 }
2347
2348 window_close( wid, unused );
2349}
2350
2351static void sysedit_editExclusionClose( unsigned int wid, const char *unused )
2352{
2353 AsteroidExclusion *exc =
2354 &sysedit_sys->astexclude[sysedit_select[0].u.astexclude];
2355
2356 const char *label = window_getInput( sysedit_widEdit, "inpLabel" );
2357 free( exc->label );
2358 exc->label = NULL;
2359 if ( ( label != NULL ) && ( strcmp( label, "" ) != 0 ) ) {
2360 int found = 0;
2361 for ( int i = 0; i < array_size( sysedit_sys->astexclude ); i++ ) {
2362 if ( sysedit_sys->astexclude[i].label &&
2363 ( strcmp( sysedit_sys->astexclude[i].label, label ) == 0 ) ) {
2364 dialogue_alert( _( "Asteroid exclusion with label '%s' already "
2365 "exists in system '%s'!" ),
2366 label, sysedit_sys->name );
2367 found = 1;
2368 break;
2369 }
2370 }
2371 if ( !found )
2372 exc->label = strdup( label );
2373 }
2374 exc->radius = atof( window_getInput( sysedit_widEdit, "inpRadius" ) );
2375
2376 if ( conf.devautosave ) {
2378 uniedit_saveError();
2379 }
2380
2381 window_close( wid, unused );
2382}
2383
2388static void sysedit_spobDesc( unsigned int wid, const char *unused )
2389{
2390 (void)unused;
2391 int x, y, h, w, bw;
2392 Spob *p;
2393 const char *desc, *bardesc;
2394 char title[128];
2395
2396 p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2397
2398 /* Create the window. */
2399 snprintf( title, sizeof( title ), _( "Space Object Information - %s" ),
2400 p->name );
2401 wid = window_create( "wdwSpobDesc", title, -1, -1, SYSEDIT_EDIT_WIDTH,
2404
2405 x = 20;
2406 y = -40;
2407 w = SYSEDIT_EDIT_WIDTH - 40;
2408 h = ( SYSEDIT_EDIT_HEIGHT - gl_defFont.h * 2 - 30 - 60 - BUTTON_HEIGHT -
2409 10 ) /
2410 2.;
2411 desc = p->description ? p->description : _( "None" );
2412 bardesc = p->bar_description ? p->bar_description : _( "None" );
2413 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
2414
2415 window_addButton( wid, -20 - bw * 3 - 15 * 3, 20, bw, BUTTON_HEIGHT,
2416 "btnProperties", _( "Properties" ),
2418
2419 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
2421
2422 /* Description label and text. */
2423 window_addText( wid, x, y, w, gl_defFont.h, 0, "txtDescriptionLabel",
2424 &gl_defFont, NULL, _( "Landing Description" ) );
2425 y -= gl_defFont.h + 10;
2426 window_addInput( wid, x, y, w, h, "txtDescription", 1024, 0, NULL );
2427 window_setInputFilter( wid, "txtDescription", "[]{}~<>@#$^|_" );
2428 y -= h + 10;
2429 /* Load current values. */
2430 window_setInput( wid, "txtDescription", desc );
2431
2432 /* Bar description label and text. */
2433 window_addText( wid, x, y, w, gl_defFont.h, 0, "txtBarDescriptionLabel",
2434 &gl_defFont, NULL, _( "Bar Description" ) );
2435 y -= gl_defFont.h + 10;
2436 window_addInput( wid, x, y, w, h, "txtBarDescription", 1024, 0, NULL );
2437 window_setInputFilter( wid, "txtBarDescription", "[]{}~<>@#$^|_" );
2438 /* Load current values. */
2439 window_setInput( wid, "txtBarDescription", bardesc );
2440}
2441
2446static void sysedit_spobDescReturn( unsigned int wid, const char *unused )
2447{
2448 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2449 const char *mydesc = window_getInput( wid, "txtDescription" );
2450 const char *mybardesc = window_getInput( wid, "txtBarDescription" );
2451
2452 if ( ( mydesc != NULL ) && ( ( p->description == NULL ) ||
2453 ( strcmp( mydesc, p->description ) != 0 ) ) ) {
2454 if ( uniedit_diffMode ) {
2455 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_DESCRIPTION,
2456 strdup( mydesc ) );
2457 } else {
2458 free( p->description );
2459 p->description = strdup( mydesc );
2460 }
2461 }
2462 if ( ( mybardesc != NULL ) &&
2463 ( ( p->bar_description == NULL ) ||
2464 ( strcmp( mybardesc, p->bar_description ) != 0 ) ) ) {
2465 if ( uniedit_diffMode ) {
2466 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_BAR,
2467 strdup( mybardesc ) );
2468 } else {
2469 free( p->bar_description );
2470 p->bar_description = strdup( mybardesc );
2471 }
2472 }
2473
2474 window_close( wid, unused );
2475}
2476
2480static void sysedit_spobDescClose( unsigned int wid, const char *unused )
2481{
2482 sysedit_spobDescReturn( wid, unused );
2484}
2485
2489static void sysedit_genServicesList( unsigned int wid )
2490{
2491 int j, n, nservices;
2492 Spob *p;
2493 char **have, **lack;
2494 int x, y, w, h, hpos, lpos;
2495
2496 hpos = lpos = -1;
2497
2498 /* Destroy if exists. */
2499 if ( widget_exists( wid, "lstServicesHave" ) &&
2500 widget_exists( wid, "lstServicesLacked" ) ) {
2501 hpos = toolkit_getListPos( wid, "lstServicesHave" );
2502 lpos = toolkit_getListPos( wid, "lstServicesLacked" );
2503 window_destroyWidget( wid, "lstServicesHave" );
2504 window_destroyWidget( wid, "lstServicesLacked" );
2505 }
2506
2507 p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2508 x = 20;
2509 y = 20 + BUTTON_HEIGHT * 2 + 30;
2510 w = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
2511 h = SYSEDIT_EDIT_HEIGHT - y - 130;
2512
2513 /* Get all missing services. */
2514 n = nservices = 0;
2515 for ( int i = 1; i < SPOB_SERVICES_MAX; i <<= 1 ) {
2516 if ( !spob_hasService( p, i ) && ( i != SPOB_SERVICE_INHABITED ) )
2517 n++;
2518 nservices++; /* Cheaply track all service types. */
2519 }
2520
2521 /* Get all the services the spob has. */
2522 j = 0;
2523 have = malloc( sizeof( char * ) * MAX( nservices - n, 1 ) );
2524 if ( nservices == n )
2525 have[j++] = strdup( _( "None" ) );
2526 else
2527 for ( int i = 1; i < SPOB_SERVICES_MAX; i <<= 1 )
2528 if ( spob_hasService( p, i ) && ( i != SPOB_SERVICE_INHABITED ) )
2529 have[j++] = strdup( spob_getServiceName( i ) );
2530
2531 /* Add list. */
2532 window_addList( wid, x, y, w, h, "lstServicesHave", have, j, 0, NULL,
2534 x += w + 15;
2535
2536 /* Add list of services the spob lacks. */
2537 j = 0;
2538 lack = malloc( sizeof( char * ) * MAX( 1, n ) );
2539 if ( !n )
2540 lack[j++] = strdup( _( "None" ) );
2541 else
2542 for ( int i = 1; i < SPOB_SERVICES_MAX; i <<= 1 )
2543 if ( !spob_hasService( p, i ) && ( i != SPOB_SERVICE_INHABITED ) )
2544 lack[j++] = strdup( spob_getServiceName( i ) );
2545
2546 /* Add list. */
2547 window_addList( wid, x, y, w, h, "lstServicesLacked", lack, j, 0, NULL,
2549
2550 /* Restore positions. */
2551 if ( hpos != -1 && lpos != -1 ) {
2552 toolkit_setListPos( wid, "lstServicesHave", hpos );
2553 toolkit_setListPos( wid, "lstServicesLacked", lpos );
2554 }
2555}
2556
2560static void sysedit_btnAddService( unsigned int wid, const char *unused )
2561{
2562 (void)unused;
2563 const char *selected = toolkit_getList( wid, "lstServicesLacked" );
2564 if ( ( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ) )
2565 return;
2566 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2567
2568 /* Enable the service. All services imply landability. */
2569 if ( uniedit_diffMode ) {
2570 if ( !spob_hasService( p, SPOB_SERVICE_LAND ) )
2571 sysedit_diffCreateSpobStr(
2572 p, HUNK_TYPE_SPOB_SERVICE_ADD,
2573 strdup( spob_getServiceName( SPOB_SERVICE_LAND ) ) );
2574 if ( !spob_hasService( p, SPOB_SERVICE_INHABITED ) )
2575 sysedit_diffCreateSpobStr(
2576 p, HUNK_TYPE_SPOB_SERVICE_ADD,
2577 strdup( spob_getServiceName( SPOB_SERVICE_INHABITED ) ) );
2578 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_SERVICE_ADD,
2579 strdup( selected ) );
2580 } else {
2581 p->services |= spob_getService( selected ) | SPOB_SERVICE_INHABITED |
2582 SPOB_SERVICE_LAND;
2583 }
2584
2585 /* Regenerate the list. */
2587}
2588
2592static void sysedit_btnRmService( unsigned int wid, const char *unused )
2593{
2594 (void)unused;
2595 const char *selected = toolkit_getList( wid, "lstServicesHave" );
2596 if ( ( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ) )
2597 return;
2598 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2599
2600 /* Flip the bit. Safe enough, as it's always 1 to start with. */
2601 if ( uniedit_diffMode ) {
2602 if ( strcmp( selected, "Land" ) == 0 ) {
2603 /* Remove them all. */
2604 for ( int i = 1; i < SPOB_SERVICES_MAX; i <<= 1 ) {
2605 if ( !spob_hasService( p, i ) )
2606 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_SERVICE_ADD,
2607 strdup( spob_getServiceName( i ) ) );
2608 }
2609 } else
2610 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_SERVICE_REMOVE,
2611 strdup( selected ) );
2612 } else {
2613 /* If landability was removed, the rest must go, too. */
2614 if ( strcmp( selected, "Land" ) == 0 )
2615 p->services = 0;
2616 else
2617 p->services ^= spob_getService( selected );
2618 }
2619
2621}
2622
2626static void sysedit_btnTechEdit( unsigned int wid, const char *unused )
2627{
2628 (void)unused;
2629 int y, w, bw;
2630
2631 /* Create the window. */
2632 wid = window_create( "wdwSpobTechEditor", _( "Space Object Tech Editor" ),
2635
2636 w = ( SYSEDIT_EDIT_WIDTH - 40 - 15 ) / 2.;
2637 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
2638
2639 /* Close button. */
2640 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
2641 window_close );
2642 y = 20 + BUTTON_HEIGHT + 15;
2643
2644 /* Remove button. */
2645 window_addButton( wid, -20 - ( w + 15 ), y, w, BUTTON_HEIGHT, "btnRm",
2646 _( "Rm Tech" ), sysedit_btnRmTech );
2647
2648 /* Add button. */
2649 window_addButton( wid, -20, y, w, BUTTON_HEIGHT, "btnAdd", _( "Add Tech" ),
2651
2652 sysedit_genTechList( wid );
2653}
2654
2658static void sysedit_genTechList( unsigned int wid )
2659{
2660 Spob *p;
2661 char **have, **lack;
2662 int j, n, x, y, w, h, hpos, lpos;
2663
2664 hpos = lpos = -1;
2665
2666 /* Destroy if exists. */
2667 if ( widget_exists( wid, "lstTechsHave" ) &&
2668 widget_exists( wid, "lstTechsLacked" ) ) {
2669 hpos = toolkit_getListPos( wid, "lstTechsHave" );
2670 lpos = toolkit_getListPos( wid, "lstTechsLacked" );
2671 window_destroyWidget( wid, "lstTechsHave" );
2672 window_destroyWidget( wid, "lstTechsLacked" );
2673 }
2674
2675 p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2676 w = ( SYSEDIT_EDIT_WIDTH - 40 - 15 ) / 2.;
2677 x = -20 - w - 15;
2678 y = 20 + BUTTON_HEIGHT * 2 + 30;
2679 h = SYSEDIT_EDIT_HEIGHT - y - 30;
2680
2681 /* Get all the techs the spob has. */
2682 n = 0;
2683 if ( p->tech != NULL )
2684 have = tech_getItemNames( p->tech, &n );
2685 else {
2686 have = malloc( sizeof( char *) );
2687 have[n++] = strdup( _( "None" ) );
2688 }
2689
2690 /* Add list. */
2691 window_addList( wid, x, y, w, h, "lstTechsHave", have, n, 0, NULL,
2693 x += w + 15;
2694
2695 /* Omit the techs that the spob already has from the list. */
2696 n = 0;
2697 if ( p->tech != NULL ) {
2698 char **tmp = tech_getAllItemNames( &j );
2699 for ( int i = 0; i < j; i++ )
2700 if ( !tech_hasItem( p->tech, tmp[i] ) )
2701 n++;
2702
2703 if ( !n ) {
2704 lack = malloc( sizeof( char *) );
2705 lack[n++] = strdup( _( "None" ) );
2706 } else {
2707 lack = malloc( sizeof( char * ) * j );
2708 n = 0;
2709 for ( int i = 0; i < j; i++ )
2710 if ( !tech_hasItem( p->tech, tmp[i] ) )
2711 lack[n++] = strdup( tmp[i] );
2712 }
2713
2714 /* Clean up. */
2715 for ( int i = 0; i < j; i++ )
2716 free( tmp[i] );
2717
2718 free( tmp );
2719 } else
2720 lack = tech_getAllItemNames( &n );
2721
2722 /* Add list. */
2723 window_addList( wid, x, y, w, h, "lstTechsLacked", lack, n, 0, NULL,
2725
2726 /* Restore positions. */
2727 if ( hpos != -1 && lpos != -1 ) {
2728 toolkit_setListPos( wid, "lstTechsHave", hpos );
2729 toolkit_setListPos( wid, "lstTechsLacked", lpos );
2730 }
2731}
2732
2736static void sysedit_btnAddTech( unsigned int wid, const char *unused )
2737{
2738 (void)unused;
2739 const char *selected = toolkit_getList( wid, "lstTechsLacked" );
2740 if ( ( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ) )
2741 return;
2742 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2743
2744 if ( uniedit_diffMode ) {
2745 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_TECH_ADD,
2746 strdup( selected ) );
2747 } else {
2748 if ( p->tech == NULL )
2749 p->tech = tech_groupCreate();
2750 tech_addItemTech( p->tech, selected );
2751 }
2752
2753 /* Regenerate the list. */
2754 sysedit_genTechList( wid );
2755}
2756
2760static void sysedit_btnRmTech( unsigned int wid, const char *unused )
2761{
2762 (void)unused;
2763 const char *selected = toolkit_getList( wid, "lstTechsHave" );
2764 if ( ( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ) )
2765 return;
2766 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2767
2768 if ( uniedit_diffMode ) {
2769 if ( tech_hasItem( p->tech, selected ) )
2770 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_TECH_REMOVE,
2771 strdup( selected ) );
2772 } else {
2773 int n;
2774 if ( tech_hasItem( p->tech, selected ) )
2775 tech_rmItemTech( p->tech, selected );
2776 n = tech_getItemCount( p->tech );
2777 if ( !n )
2778 p->tech = NULL;
2779 }
2780
2781 /* Regenerate the list. */
2782 sysedit_genTechList( wid );
2783}
2784
2788static void sysedit_btnTagsEdit( unsigned int wid, const char *unused )
2789{
2790 (void)unused;
2791 int y, w, bw;
2792
2793 /* Create the window. */
2794 wid = window_create( "wdwSpobTagsEditor", _( "Space Object Tags Editor" ),
2796 window_setCancel( wid, sysedit_btnTagsClose );
2797
2798 w = ( SYSEDIT_EDIT_WIDTH - 40 - 15 ) / 2.;
2799 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
2800
2801 /* Close button. */
2802 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
2803 sysedit_btnTagsClose );
2804 y = 20 + BUTTON_HEIGHT + 15;
2805
2806 /* Remove button. */
2807 window_addButton( wid, -20 - ( w + 15 ), y, w, BUTTON_HEIGHT, "btnRm",
2808 _( "Rm Tag" ), sysedit_btnRmTag );
2809
2810 /* Add button. */
2811 window_addButton( wid, -20, y, w, BUTTON_HEIGHT, "btnAdd", _( "Add Tag" ),
2813
2814 /* New tag. */
2815 window_addButton( wid, -20 - ( w + 15 ), 20, w, BUTTON_HEIGHT, "btnNew",
2816 _( "New Tag" ), sysedit_btnNewTag );
2817
2818 /* Generate list of tags. */
2819 if ( sysedit_tagslist == NULL ) {
2820 Spob *spob_all = spob_getAll();
2821 sysedit_tagslist = array_create( char * );
2822 for ( int i = 0; i < array_size( spob_all ); i++ ) {
2823 Spob *s = &spob_all[i];
2824 for ( int j = 0; j < array_size( s->tags ); j++ ) {
2825 const char *t = s->tags[j];
2826 int found = 0;
2827 for ( int k = 0; k < array_size( sysedit_tagslist ); k++ )
2828 if ( strcmp( sysedit_tagslist[k], t ) == 0 ) {
2829 found = 1;
2830 break;
2831 }
2832 if ( !found )
2833 array_push_back( &sysedit_tagslist, strdup( t ) );
2834 }
2835 }
2836 qsort( sysedit_tagslist, array_size( sysedit_tagslist ), sizeof( char * ),
2837 strsort );
2838 }
2839
2840 sysedit_genTagsList( wid );
2841}
2842
2843/*
2844 * Tags are closed so update tags.
2845 */
2846static void sysedit_btnTagsClose( unsigned int wid, const char *unused )
2847{
2848 char buf[STRMAX_SHORT];
2849 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2850 int l = scnprintf( buf, sizeof( buf ), "#n%s#0", _( "Tags:" ) );
2851 for ( int i = 0; i < array_size( p->tags ); i++ )
2852 l += scnprintf( &buf[l], sizeof( buf ) - l, "%s %s",
2853 ( ( i > 0 ) ? "," : "" ), p->tags[i] );
2854 window_modifyText( sysedit_widEdit, "txtTags", buf );
2855
2856 window_close( wid, unused );
2857}
2858
2862static void sysedit_genTagsList( unsigned int wid )
2863{
2864 Spob *p;
2865 char **have, **lack;
2866 int n, x, y, w, h, hpos, lpos, empty;
2867
2868 hpos = lpos = -1;
2869
2870 /* Destroy if exists. */
2871 if ( widget_exists( wid, "lstTagsHave" ) &&
2872 widget_exists( wid, "lstTagsLacked" ) ) {
2873 hpos = toolkit_getListPos( wid, "lstTagsHave" );
2874 lpos = toolkit_getListPos( wid, "lstTagsLacked" );
2875 window_destroyWidget( wid, "lstTagsHave" );
2876 window_destroyWidget( wid, "lstTagsLacked" );
2877 }
2878
2879 p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2880 w = ( SYSEDIT_EDIT_WIDTH - 40 - 15 ) / 2.;
2881 x = -20 - w - 15;
2882 y = 20 + BUTTON_HEIGHT * 2 + 30;
2883 h = SYSEDIT_EDIT_HEIGHT - y - 30;
2884
2885 /* Get all the techs the spob has. */
2886 n = array_size( p->tags );
2887 if ( n > 0 ) {
2888 have = malloc( n * sizeof( char * ) );
2889 for ( int i = 0; i < n; i++ )
2890 have[i] = strdup( p->tags[i] );
2891 empty = 0;
2892 } else {
2893 have = malloc( sizeof( char *) );
2894 have[n++] = strdup( _( "None" ) );
2895 empty = 1;
2896 }
2897
2898 /* Add list. */
2899 window_addList( wid, x, y, w, h, "lstTagsHave", have, n, 0, NULL,
2901 x += w + 15;
2902
2903 /* Omit the techs that the spob already has from the list. */
2904 n = 0;
2905 lack = malloc( array_size( sysedit_tagslist ) * sizeof( char * ) );
2906 for ( int i = 0; i < array_size( sysedit_tagslist ); i++ ) {
2907 const char *t = sysedit_tagslist[i];
2908 if ( empty )
2909 lack[n++] = strdup( t );
2910 else {
2911 int found = 0;
2912 for ( int j = 0; j < array_size( p->tags ); j++ )
2913 if ( strcmp( p->tags[j], t ) == 0 ) {
2914 found = 1;
2915 break;
2916 }
2917 if ( !found )
2918 lack[n++] = strdup( t );
2919 }
2920 }
2921
2922 /* Add list. */
2923 window_addList( wid, x, y, w, h, "lstTagsLacked", lack, n, 0, NULL,
2925
2926 /* Restore positions. */
2927 if ( hpos != -1 && lpos != -1 ) {
2928 toolkit_setListPos( wid, "lstTagsHave", hpos );
2929 toolkit_setListPos( wid, "lstTagsLacked", lpos );
2930 }
2931}
2932
2936static void sysedit_btnAddTag( unsigned int wid, const char *unused )
2937{
2938 (void)unused;
2939 const char *selected = toolkit_getList( wid, "lstTagsLacked" );
2940 if ( ( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ) )
2941 return;
2942 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2943
2944 if ( uniedit_diffMode ) {
2945 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_TAG_ADD,
2946 strdup( selected ) );
2947 } else {
2948 if ( p->tags == NULL )
2949 p->tags = array_create( char * );
2950 array_push_back( &p->tags, strdup( selected ) );
2951 }
2952
2953 /* Regenerate the list. */
2954 sysedit_genTagsList( wid );
2955}
2956
2960static void sysedit_btnRmTag( unsigned int wid, const char *unused )
2961{
2962 (void)unused;
2963 const char *selected;
2964
2965 selected = toolkit_getList( wid, "lstTagsHave" );
2966 if ( ( selected == NULL ) || ( strcmp( selected, _( "None" ) ) == 0 ) )
2967 return;
2968
2969 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
2970
2971 if ( uniedit_diffMode ) {
2972 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_TAG_REMOVE,
2973 strdup( selected ) );
2974 } else {
2975 int i;
2976 for ( i = 0; i < array_size( p->tags ); i++ )
2977 if ( strcmp( selected, p->tags[i] ) == 0 )
2978 break;
2979 if ( i >= array_size( p->tags ) )
2980 return;
2981 free( p->tags[i] );
2982 array_erase( &p->tags, &p->tags[i], &p->tags[i + 1] );
2983 }
2984
2985 /* Regenerate the list. */
2986 sysedit_genTagsList( wid );
2987}
2988
2992static void sysedit_btnNewTag( unsigned int wid, const char *unused )
2993{
2994 (void)unused;
2995 char *tag =
2996 dialogue_input( _( "Add New Spob Tag" ), 1, 128,
2997 _( "Please write the new tag to add to the spob." ) );
2998 if ( tag == NULL )
2999 return;
3000
3001 Spob *s = sysedit_sys->spobs[sysedit_select[0].u.spob];
3002 if ( uniedit_diffMode ) {
3003 sysedit_diffCreateSpobStr( s, HUNK_TYPE_SPOB_TAG_ADD, tag );
3004 } else {
3005 if ( s->tags == NULL )
3006 s->tags = array_create( char * );
3007 array_push_back( &s->tags, tag ); /* gets freed later */
3008
3009 /* Also add to list of all tags. */
3010 array_push_back( &sysedit_tagslist, strdup( tag ) );
3011 }
3012
3013 /* Regenerate the list. */
3014 sysedit_genTagsList( wid );
3015}
3016
3020static void sysedit_btnFaction( unsigned int wid_unused, const char *unused )
3021{
3022 (void)wid_unused;
3023 (void)unused;
3024 unsigned int wid;
3025 int pos, j, y, h, bw, *factions;
3026 char **str;
3027 Spob *p;
3028
3029 p = sysedit_sys->spobs[sysedit_select[0].u.spob];
3030
3031 /* Create the window. */
3032 wid = window_create( "wdwModifyFaction", _( "Modify Faction" ), -1, -1,
3035
3036 /* Generate factions list. */
3037 factions = faction_getAll();
3038 str = malloc( sizeof( char *) * ( array_size( factions ) + 1 ) );
3039 str[0] = strdup( _( "None" ) );
3040 j = 1;
3041 for ( int i = 0; i < array_size( factions ); i++ )
3042 str[j++] = strdup( faction_name(
3043 factions[i] ) ); /* Not translating so we can use faction_get */
3044 qsort( &str[1], j - 1, sizeof( char * ), strsort );
3045
3046 /* Get current faction. */
3047 if ( p->presence.faction >= 0 ) {
3048 const char *s = faction_name( p->presence.faction );
3049 pos = 0;
3050 for ( int i = 0; i < j; i++ )
3051 if ( strcmp( s, str[i] ) == 0 )
3052 pos = i;
3053 } else
3054 pos = -1;
3055
3056 bw = ( SYSEDIT_EDIT_WIDTH - 40 - 15 * 3 ) / 4.;
3057 y = 20 + BUTTON_HEIGHT + 15;
3058 h = SYSEDIT_EDIT_HEIGHT - y - 30;
3059 window_addList( wid, 20, -40, SYSEDIT_EDIT_WIDTH - 40, h, "lstFactions", str,
3060 j, pos, NULL, sysedit_btnFactionSet );
3061
3062 /* Close button. */
3063 window_addButton( wid, -20, 20, bw, BUTTON_HEIGHT, "btnClose", _( "Close" ),
3064 window_close );
3065
3066 /* Add button. */
3067 window_addButton( wid, -20 - ( bw + 15 ), 20, bw, BUTTON_HEIGHT, "btnAdd",
3068 _( "Set" ), sysedit_btnFactionSet );
3069
3070 array_free( factions );
3071}
3072
3076static void sysedit_btnFactionSet( unsigned int wid, const char *unused )
3077{
3078 (void)unused;
3079 const char *selected = toolkit_getList( wid, "lstFactions" );
3080 if ( selected == NULL )
3081 return;
3082 Spob *p = sysedit_sys->spobs[sysedit_select[0].u.spob];
3083
3084 if ( uniedit_diffMode ) {
3085 sysedit_diffCreateSpobStr( p, HUNK_TYPE_SPOB_FACTION,
3086 strdup( selected ) );
3087 } else {
3088 /* "None" case. */
3089 if ( toolkit_getListPos( wid, "lstFactions" ) == 0 ) {
3090 p->presence.faction = -1;
3091 } else {
3092 /* Set the faction. */
3093 p->presence.faction = faction_get( selected );
3094 }
3095 }
3096
3097 /* Update the editor window. */
3098 window_modifyText( sysedit_widEdit, "txtFaction",
3099 p->presence.faction >= 0
3100 ? faction_name( p->presence.faction )
3101 : _( "None" ) );
3102
3103 window_close( wid, unused );
3104}
3105
3109static void sysedit_btnEdit( unsigned int wid_unused, const char *unused )
3110{
3111 (void)wid_unused;
3112 (void)unused;
3113 const Select_t *sel = &sysedit_select[0];
3114 if ( sel->type == SELECT_SPOB )
3116 else if ( sel->type == SELECT_JUMPPOINT )
3118 else if ( sel->type == SELECT_ASTEROID )
3120 else if ( sel->type == SELECT_ASTEXCLUDE )
3121 sysedit_editExclusion();
3122}
3123
3127static void sysedit_spobGFX( unsigned int wid_unused, const char *wgt )
3128{
3129 (void)wid_unused;
3130 unsigned int wid;
3131 size_t nfiles, j;
3132 char *path, buf[STRMAX_SHORT];
3133 char **files;
3134 glTexture *t;
3135 ImageArrayCell *cells;
3136 int w, h, land;
3137 Spob *p;
3138 glColour c;
3139
3140 land = ( strcmp( wgt, "btnLandGFX" ) == 0 );
3141
3142 p = sysedit_sys->spobs[sysedit_select[0].u.spob];
3143 /* Create the window. */
3144 snprintf( buf, sizeof( buf ), _( "%s - Space Object Properties" ), p->name );
3145 wid = window_create( "wdwSpobGFX", buf, -1, -1, -1, -1 );
3146 window_dimWindow( wid, &w, &h );
3147
3150
3151 /* Close button. */
3152 window_addButton( wid, -20, 20, BUTTON_WIDTH, BUTTON_HEIGHT, "btnClose",
3153 _( "Close" ), sysedit_btnGFXClose );
3154
3155 /* Apply button. */
3156 window_addButton( wid, -20, 20 + ( 20 + BUTTON_HEIGHT ), BUTTON_WIDTH,
3157 BUTTON_HEIGHT, land ? "btnApplyLand" : "btnApplySpace",
3158 _( "Apply" ), sysedit_btnGFXApply );
3159
3160 /* Find images first. */
3161 path = land ? SPOB_GFX_EXTERIOR_PATH : SPOB_GFX_SPACE_PATH;
3162 files = PHYSFS_enumerateFiles( path );
3163 for ( nfiles = 0; files[nfiles]; nfiles++ ) {
3164 }
3165 cells = calloc( nfiles, sizeof( ImageArrayCell ) );
3166
3167 j = 0;
3168 for ( size_t i = 0; i < nfiles; i++ ) {
3169 PHYSFS_Stat path_stat;
3170 const char *filepath;
3171 snprintf( buf, sizeof( buf ), "%s/%s", path, files[i] );
3172 /* Ignore directories. */
3173 if ( !PHYSFS_stat( buf, &path_stat ) ) {
3174 WARN( _( "Unable to check file type for '%s'!" ), buf );
3175 continue;
3176 }
3177 if ( path_stat.filetype != PHYSFS_FILETYPE_REGULAR )
3178 continue;
3179
3180 t = gl_newImage( buf, OPENGL_TEX_MIPMAPS );
3181 if ( t == NULL )
3182 continue;
3183 cells[j].image = t;
3184 cells[j].caption = strdup( files[i] );
3185 filepath = ( land ? p->gfx_exteriorPath : p->gfx_spacePath );
3186 c = ( ( filepath == NULL ) || strcmp( files[i], filepath ) != 0 )
3187 ? cBlack
3188 : cOrange;
3189 memcpy( &cells[j].bg, &c, sizeof( glColour ) );
3190 j++;
3191 }
3192 PHYSFS_freeList( files );
3193
3194 /* Add image array. */
3195 window_addImageArray( wid, 20, 20, w - 60 - BUTTON_WIDTH, h - 60, "iarGFX",
3196 128, 128, cells, j, NULL, NULL, NULL );
3197 toolkit_setImageArray( wid, "iarGFX", path );
3198}
3199
3203static void sysedit_btnGFXClose( unsigned int wid, const char *wgt )
3204{
3205 window_close( wid, wgt );
3206}
3207
3211static void sysedit_btnGFXApply( unsigned int wid, const char *wgt )
3212{
3213 Spob *p;
3214 const char *str;
3215 char *path, buf[PATH_MAX];
3216 int land;
3217
3218 land = ( strcmp( wgt, "btnApplyLand" ) == 0 );
3219 p = sysedit_sys->spobs[sysedit_select[0].u.spob];
3220
3221 /* Get output. */
3222 str = toolkit_getImageArray( wid, "iarGFX" );
3223 if ( str == NULL )
3224 return;
3225
3226 /* New path. */
3227 path = land ? SPOB_GFX_EXTERIOR_PATH : SPOB_GFX_SPACE_PATH;
3228 snprintf( buf, sizeof( buf ), "%s/%s", path, str );
3229
3230 if ( land ) {
3231 free( p->gfx_exteriorPath );
3232 free( p->gfx_exterior );
3233 snprintf( buf, sizeof( buf ), SPOB_GFX_EXTERIOR_PATH "%s", str );
3234 p->gfx_exteriorPath = strdup( str );
3235 p->gfx_exterior = strdup( buf );
3236 } else { /* Free old texture, load new. */
3237 free( p->gfx_spaceName );
3238 free( p->gfx_spacePath );
3239 p->gfx_spaceName = strdup( buf );
3240 p->gfx_spacePath = strdup( str );
3241 gl_freeTexture( p->gfx_space );
3242 p->gfx_space = NULL;
3243 p->radius = -1.; /* Reset radius. */
3244 spob_gfxLoad( p );
3245 }
3246
3247 /* For now we close. */
3248 sysedit_btnGFXClose( wid, wgt );
3249}
3250
3251static void sysedit_diffCreateSpobStr( const Spob *spb, UniHunkType_t type,
3252 char *str )
3253{
3254 UniHunk_t hunk;
3255 memset( &hunk, 0, sizeof( hunk ) );
3256 hunk.target.type = HUNK_TARGET_SPOB;
3257 hunk.target.u.name = strdup( spb->name );
3258 hunk.type = type;
3259 hunk.dtype = HUNK_DATA_STRING;
3260 hunk.u.name = str;
3261 uniedit_diffAdd( &hunk );
3262}
3263static void sysedit_diffCreateSpobInt( const Spob *spb, UniHunkType_t type,
3264 int data )
3265{
3266 UniHunk_t hunk;
3267 memset( &hunk, 0, sizeof( hunk ) );
3268 hunk.target.type = HUNK_TARGET_SPOB;
3269 hunk.target.u.name = strdup( spb->name );
3270 hunk.type = type;
3271 hunk.dtype = HUNK_DATA_INT;
3272 hunk.u.data = data;
3273 uniedit_diffAdd( &hunk );
3274}
3275static void sysedit_diffCreateSpobFloat( const Spob *spb, UniHunkType_t type,
3276 double fdata )
3277{
3278 UniHunk_t hunk;
3279 memset( &hunk, 0, sizeof( hunk ) );
3280 hunk.target.type = HUNK_TARGET_SPOB;
3281 hunk.target.u.name = strdup( spb->name );
3282 hunk.type = type;
3283 hunk.dtype = HUNK_DATA_FLOAT;
3284 hunk.u.fdata = fdata;
3285 uniedit_diffAdd( &hunk );
3286}
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_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:122
#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
void asteroids_computeInternals(AsteroidAnchor *a)
Updates internal alues of an asteroid field.
Definition asteroid.c:508
void asteroid_freeAnchor(AsteroidAnchor *ast)
Frees an asteroid anchor.
Definition asteroid.c:1036
const AsteroidTypeGroup * astgroup_getAll(void)
Gets all the asteroid type groups.
Definition asteroid.c:1159
AsteroidTypeGroup * astgroup_getName(const char *name)
Gets an asteroid type group by name.
Definition asteroid.c:1170
void asteroid_initAnchor(AsteroidAnchor *ast)
Initializes an asteroid anchor.
Definition asteroid.c:1019
#define BUTTON_HEIGHT
Definition board.c:28
#define BUTTON_WIDTH
Definition board.c:27
int dpl_saveSpob(const Spob *p)
Saves a spob.
Definition dev_spob.c:28
@ SELECT_ASTEROID
Definition dev_sysedit.c:55
@ SELECT_ASTEXCLUDE
Definition dev_sysedit.c:56
@ SELECT_JUMPPOINT
Definition dev_sysedit.c:54
@ SELECT_NONE
Definition dev_sysedit.c:52
@ SELECT_SPOB
Definition dev_sysedit.c:53
static Select_t sysedit_tsel
Definition dev_sysedit.c:74
static void jp_type_check_nolanes_update(unsigned int wid, const char *str)
Updates the jump point checkboxes.
#define SYSEDIT_ZOOM_STEP
Definition dev_sysedit.c:44
static void sysedit_btnGFXApply(unsigned int wid, const char *wgt)
Apply new graphics.
static void sysedit_selectRm(const Select_t *sel)
Removes a system from the selection.
static double sysedit_xpos
Definition dev_sysedit.c:85
static int sysedit_nselect
Definition dev_sysedit.c:72
static int jp_hidden
Definition dev_sysedit.c:96
static int sysedit_grid
Definition dev_sysedit.c:84
static unsigned int sysedit_wid
Definition dev_sysedit.c:82
static void jp_type_check_exit_update(unsigned int wid, const char *str)
Updates the jump point checkboxes.
static void sysedit_close(unsigned int wid, const char *wgt)
Closes the system editor widget.
static void sysedit_editPntClose(unsigned int wid, const char *unused)
Closes the spob editor, saving the changes made.
static int sysedit_drag
Definition dev_sysedit.c:90
static void sysedit_buttonZoom(unsigned int wid, const char *str)
Handles the button zoom clicks.
static int sysedit_tadd
Definition dev_sysedit.c:75
static void sysedit_selectAdd(const Select_t *sel)
Adds a system to the selection.
static void sysedit_focusLose(unsigned int wid, const char *wgtname)
Called when it's de-focused.
static void sysedit_btnGrid(unsigned int wid_unused, const char *unused)
Toggles the grid.
static void sysedit_btnNewSpob(unsigned int wid_unused, const char *unused)
Enters the editor in new spob mode.
static int sysedit_selectCmp(const Select_t *a, const Select_t *b)
Compares two selections to see if they are the same.
#define SYSEDIT_EDIT_WIDTH
Definition dev_sysedit.c:38
static void sysedit_btnReset(unsigned int wid_unused, const char *unused)
Resets jump points.
static int sysedit_keys(unsigned int wid, SDL_Keycode key, SDL_Keymod mod, int isrepeat)
Handles keybindings.
static void sysedit_render(double bx, double by, double w, double h, void *data)
System editor custom widget rendering.
static double sysedit_ypos
Definition dev_sysedit.c:86
static int sysedit_isSelected(const Select_t *s)
Check to see if something is selected.
static void sysedit_renderAsteroidsField(double bx, double by, const AsteroidAnchor *ast, int selected)
Draws an asteroid field on the map.
static void sysedit_btnRmTag(unsigned int wid, const char *unused)
Removes a tech from a spob.
static unsigned int sysedit_widEdit
Definition dev_sysedit.c:83
static void sysedit_genTagsList(unsigned int wid)
Generates the spob tech list.
static int jp_exit
Definition dev_sysedit.c:97
static void sysedit_btnAddService(unsigned int wid, const char *unused)
Adds a service to a spob.
static void sysedit_genTechList(unsigned int wid)
Generates the spob tech list.
static void sysedit_btnGFXClose(unsigned int wid, const char *wgt)
Closes the spob graphic editor.
static void sysedit_deselect(void)
Deselects everything.
static void sysedit_checkButtons(void)
Checks to see which buttons should be active and the likes.
static void sysedit_btnRmTech(unsigned int wid, const char *unused)
Removes a tech from a spob.
static double sysedit_zoom
Definition dev_sysedit.c:87
static void sysedit_btnFaction(unsigned int wid_unused, const char *unused)
Edits a spob's faction.
static void sysedit_spobGFX(unsigned int wid_unused, const char *wgt)
Opens the spob landing or space graphic editor.
static void sysedit_editAsteroids(void)
Opens the asteroid editor.
static char ** sysedit_tagslist
Definition dev_sysedit.c:76
static void sysedit_renderSprite(const glTexture *gfx, double bx, double by, double x, double y, int sx, int sy, const glColour *c, int selected, const char *caption)
Renders a sprite for the custom widget.
static StarSystem * sysedit_sys
Definition dev_sysedit.c:81
#define SYSEDIT_DRAG_THRESHOLD
Definition dev_sysedit.c:41
static void sysedit_btnEdit(unsigned int wid_unused, const char *unused)
Opens the system property editor.
#define SYSEDIT_ZOOM_MIN
Definition dev_sysedit.c:46
static void sysedit_btnNewTag(unsigned int wid, const char *unused)
Adds a tech to a spob.
#define SYSEDIT_MOVE_THRESHOLD
Definition dev_sysedit.c:42
static void sysedit_renderAsteroidExclusion(double bx, double by, const AsteroidExclusion *aexcl, int selected)
Draws an asteroid exclusion zone on the map.
static void sysedit_spobDescClose(unsigned int wid, const char *unused)
Closes both the spob description window and the properties window.
static void sysedit_btnFactionSet(unsigned int wid, const char *unused)
Actually modifies the faction.
static unsigned int sysedit_dragTime
Definition dev_sysedit.c:89
#define SYSEDIT_EDIT_HEIGHT
Definition dev_sysedit.c:39
static void sysedit_spobDesc(unsigned int wid, const char *unused)
Displays the spob landing description and bar description in a separate window.
static void sysedit_editJumpClose(unsigned int wid, const char *unused)
Closes the jump editor, saving the changes made.
static void sysedit_btnScale(unsigned int wid_unused, const char *unused)
Interface for scaling a system from the system view.
static int sysedit_mselect
Definition dev_sysedit.c:73
static void sysedit_genServicesList(unsigned int wid)
Generates the spob services list.
static double sysedit_my
Definition dev_sysedit.c:93
static void sysedit_btnRemove(unsigned int wid_unused, const char *unused)
Removes spobs.
void sysedit_open(StarSystem *sys)
Opens the system editor interface.
static void sysedit_btnRmService(unsigned int wid, const char *unused)
Removes a service from a spob.
static void sysedit_renderBG(double bx, double bw, double w, double h, double x, double y)
Renders the custom widget background.
static void sysedit_btnAddTag(unsigned int wid, const char *unused)
Adds a tech to a spob.
static void sysedit_btnTagsEdit(unsigned int wid, const char *unused)
Edits a spob's tags.
static void sysedit_editPnt(void)
Edits a spob.
static int sysedit_moved
Definition dev_sysedit.c:88
static void sysedit_spobDescReturn(unsigned int wid, const char *unused)
Closes the spob description window and returns to the properties window.
static void sysedit_btnAddTech(unsigned int wid, const char *unused)
Adds a tech to a spob.
void sysedit_sysScale(StarSystem *sys, double factor)
Scales a system.
static int sysedit_mouse(unsigned int wid, const SDL_Event *event, double mx, double my, double w, double h, double xr, double yr, void *data)
System editor custom widget mouse handling.
static void jp_type_check_hidden_update(unsigned int wid, const char *str)
Updates the jump point checkboxes.
static double sysedit_mx
Definition dev_sysedit.c:92
static void sysedit_btnTechEdit(unsigned int wid, const char *unused)
Edits a spob's tech.
static int sysedit_dragSel
Definition dev_sysedit.c:91
static void sysedit_btnNewAsteroids(unsigned int wid_unused, const char *unused)
Enters the editor in new spob mode.
#define SYSEDIT_ZOOM_MAX
Definition dev_sysedit.c:45
static void sysedit_editJump(void)
Edits a jump.
static Select_t * sysedit_select
Definition dev_sysedit.c:71
int dsys_saveSystem(StarSystem *sys)
Saves a star system.
Definition dev_system.c:82
void uniedit_selectText(void)
Sets the selected system text.
char * dialogue_runChoice(void)
Run the dialog and return the clicked string.
Definition dialogue.c:817
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
void dialogue_addChoice(const char *caption, const char *msg, const char *opt)
Add a choice to the dialog.
Definition dialogue.c:796
void dialogue_alertRaw(const char *msg)
Displays an alert popup with only an ok button and a message.
Definition dialogue.c:149
void dialogue_makeChoice(const char *caption, const char *msg, int opts)
Create the choice dialog. Need to add choices with below method.
Definition dialogue.c:773
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 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
int gl_printMidRaw(const glFont *ft_font, int width, double x, double y, const glColour *c, double outlineR, const char *text)
Displays text centered in position and width.
Definition font.c:821
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
void land(Spob *p, int load)
Opens up all the land dialogue stuff.
Definition land.c:1413
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 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
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_renderLine(double x1, double y1, double x2, double y2, const glColour *c)
Draws a line.
void gl_renderScaleSprite(const glTexture *sprite, double bx, double by, int sx, int sy, double bw, double bh, const glColour *c)
Blits a scaled sprite, position is in absolute screen coordinates.
void gl_renderRectEmpty(double x, double y, double w, double h, const glColour *c)
Renders a rectangle.
void gl_renderCross(double x, double y, double r, const glColour *c)
Renders a cross at a given position.
void gl_renderCircle(double cx, double cy, double r, const glColour *c, int filled)
Draws a circle.
glTexture * gl_newImage(const char *path, const unsigned int flags)
Loads an image as a texture.
Definition opengl_tex.c:587
void gl_freeTexture(glTexture *texture)
Frees a texture.
Definition opengl_tex.c:835
static const double c[]
Definition rng.c:256
static const double d[]
Definition rng.c:263
void safelanes_recalculate(void)
Update the safe lane locations in response to the universe changing (e.g., diff applied).
Definition safelanes.c:296
SafeLane * safelanes_get(int faction, int standing, const StarSystem *system)
Gets a set of safelanes for a faction and system.
Definition safelanes.c:233
void space_reconstructPresences(void)
Reset the presence of all systems.
Definition space.c:4620
int spob_exists(const char *spobname)
Check to see if a spob exists.
Definition space.c:1185
void systems_reconstructJumps(void)
Reconstructs the jumps.
Definition space.c:2990
Spob * spob_getAll(void)
Gets an array (array.h) of all spobs.
Definition space.c:1166
int spob_rename(Spob *p, char *newname)
Renames a spob.
Definition space.c:455
int spob_getService(const char *name)
Converts name to spob service flag.
Definition space.c:197
void system_setFaction(StarSystem *sys)
Sets the system faction based on the spobs it has.
Definition space.c:3377
Spob * spob_get(const char *spobname)
Gets a spob based on its name.
Definition space.c:1107
const char * space_getRndSpob(int landable, unsigned int services, int(*filter)(Spob *p))
Gets the name of a random spob.
Definition space.c:666
StarSystem * system_getIndex(int id)
Get the system by its index.
Definition space.c:1038
JumpPoint * jump_getTarget(const StarSystem *target, const StarSystem *sys)
Less safe version of jump_get that works with pointers.
Definition space.c:1303
void system_updateAsteroids(StarSystem *sys)
Updates some internal calculations about asteroids in a system.
Definition space.c:347
int system_addSpob(StarSystem *sys, const char *spobname)
Adds a spob to a star system.
Definition space.c:2668
void spob_gfxLoad(Spob *spob)
Loads a spob's graphics (and radius).
Definition space.c:2206
Spob * spob_getIndex(int ind)
Gets spob by index.
Definition space.c:1140
const char * spob_getSystemName(const char *spobname)
Get the name of a system from a spobname.
Definition space.c:1082
const char * spob_getServiceName(int service)
Gets the (English) name for a service code.
Definition space.c:169
Spob * spob_new(void)
Creates a new spob.
Definition space.c:1804
glTexture * jumppoint_gfx
Definition space.c:111
void space_gfxLoad(StarSystem *sys)
Loads all the graphics for a star system.
Definition space.c:2266
int system_rmSpob(StarSystem *sys, const char *spobname)
Removes a spob from a star system.
Definition space.c:2709
Represents an asteroid field anchor.
Definition asteroid.h:111
double radius
Definition asteroid.h:118
double density
Definition asteroid.h:115
double maxspeed
Definition asteroid.h:123
Asteroid * asteroids
Definition asteroid.h:116
AsteroidTypeGroup ** groups
Definition asteroid.h:120
Represents an asteroid exclusion zone.
Definition asteroid.h:136
Represents a group of asteroids.
Definition asteroid.h:78
Describes a safe lane, patrolled by a faction, within a system.
Definition safelanes.h:29
int point_id[2]
Definition safelanes.h:32
int faction
Definition safelanes.h:30
SafeLaneLocType point_type[2]
Definition safelanes.h:31
Selection generic for stuff in a system.
Definition dev_sysedit.c:62
union Select_t::@341261112304346203054132216237006377314237372055 u
Represents a Space Object (SPOB), including and not limited to planets, stations, wormholes,...
Definition space.h:102
char ** tags
Definition space.h:155
char * name
Definition space.h:105
vec2 pos
Definition space.h:109
union UniHunkTarget_t::@042061014075140046260132141131357236050307054376 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::@305371200110240060025050140203231327261371246122 u
UniHunkType_t type
Definition unidiff.h:164
UniHunkTarget_t target
Definition unidiff.h:163
Abstraction for rendering sprite sheets.
Definition opengl_tex.h:43
double sw
Definition opengl_tex.h:53
double sh
Definition opengl_tex.h:54
Represents a 2d vector.
Definition vec2.h:45
double y
Definition vec2.h:47
double x
Definition vec2.h:46
int tech_rmItemTech(tech_group_t *tech, const char *value)
Removes an item from a tech.
Definition tech.c:506
tech_group_t * tech_groupCreate(void)
Creates a tech group.
Definition tech.c:196
int tech_getItemCount(const tech_group_t *tech)
Gets the number of techs within a given group.
Definition tech.c:785
int tech_hasItem(const tech_group_t *tech, const char *item)
Checks whether a given tech group has the specified item.
Definition tech.c:680
int tech_addItemTech(tech_group_t *tech, const char *value)
Adds an item to a tech.
Definition tech.c:480
char ** tech_getItemNames(const tech_group_t *tech, int *n)
Gets the names of all techs within a given group.
Definition tech.c:797
char ** tech_getAllItemNames(int *n)
Gets the names of all techs.
Definition tech.c:817
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_dimWidget(unsigned int wid, const char *name, int *w, int *h)
Gets the dimensions of a widget.
Definition toolkit.c:415
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_setAccept(unsigned int wid, void(*accept)(unsigned int, const char *))
Sets the default accept function of the window.
Definition toolkit.c:846
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
int window_existsID(unsigned int wid)
Checks to see if a window with a certain ID exists.
Definition toolkit.c:608
void window_posWidget(unsigned int wid, const char *name, int *x, int *y)
Gets a widget's position.
Definition toolkit.c:441
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