11#include "ui/world_inspector.h"
22
33#include <stdio.h>
4+ #include <stdbool.h>
45#include <world.h>
56#include <ui/theme.h>
6- #include " game/model.h"
7- #include " game/camera.h"
7+ #include < game/model.h>
8+ #include < game/camera.h>
89#include <widget/widget.h>
910#include <widget/text_widget.h>
1011#include <widget/button_widget.h>
1112#include <misc/wchar_funcs.h>
12- #include <stdbool .h>
13+ #include <type_database .h>
1314#include <io/log.h>
1415
16+ #define BUTTON_HIDDEN_X_POS 10.0f
17+ #define CREATE_NEW_OBJ_TEXT "Create new object"
18+
1519enum te_world_item_type {
1620 TE_WIT_MODEL ,
1721 TE_WIT_CAMERA ,
@@ -37,6 +41,9 @@ struct te_world_inspector {
3741 te_button_widget * button_3dobj ;
3842 te_button_widget * button_2dobj ;
3943
44+ // Text of the button to create new game objects.
45+ te_text_widget * button_text_create_new_obj ;
46+
4047 // Valid while spawned, buttons that fill all available space (moved outside of the viewport if should not be visible).
4148 // Number of items in this array is @ref item_buttons_count.
4249 te_button_widget * * item_buttons ;
@@ -58,6 +65,8 @@ struct te_world_inspector {
5865
5966 // `true` if should display world's "3D objects", `false` if "2D objects".
6067 bool is_3dobj_mode_selected ;
68+
69+ bool is_creating_new_game_obj ;
6170};
6271
6372te_world_inspector *
@@ -66,12 +75,17 @@ world_inspector_create(void) {
6675
6776 inspector -> left_panel = NULL ;
6877 inspector -> item_list = NULL ;
78+ inspector -> button_2dobj = NULL ;
79+ inspector -> button_3dobj = NULL ;
6980 inspector -> game_world = NULL ;
81+ inspector -> button_text_create_new_obj = NULL ;
82+ inspector -> page_text = NULL ;
7083 inspector -> item_buttons = NULL ;
7184 inspector -> item_buttons_count = 0 ;
7285 inspector -> item_list_count = 0 ;
7386 inspector -> current_page = 0 ;
7487 inspector -> is_3dobj_mode_selected = true;
88+ inspector -> is_creating_new_game_obj = false;
7589
7690 return inspector ;
7791}
@@ -272,6 +286,7 @@ refresh_item_names(te_world_inspector* inspector) {
272286 widget_set_relative_size (widget , size );
273287 }
274288
289+ // Get button text.
275290 unsigned int child_count ;
276291 te_widget * * child_widgets =
277292 widget_get_child_widgets_tmp (button_widget_get_widget (button ), & child_count );
@@ -321,7 +336,7 @@ refresh_item_names(te_world_inspector* inspector) {
321336
322337 vec2 pos ;
323338 widget_get_relative_position (widget , pos );
324- pos [0 ] = 10.0f ;
339+ pos [0 ] = BUTTON_HIDDEN_X_POS ;
325340
326341 widget_set_relative_position (
327342 button_widget_get_widget (inspector -> item_buttons [button_idx ]), pos );
@@ -401,6 +416,126 @@ on_button_2dobj_clicked(te_button_widget* button) {
401416 button_widget_set_color (inspector -> button_3dobj , color );
402417}
403418
419+ static void
420+ on_button_create_new_object_clicked (te_button_widget * button ) {
421+ te_world_inspector * inspector = widget_get_custom_ptr (button_widget_get_widget (button ));
422+
423+ inspector -> is_creating_new_game_obj = !inspector -> is_creating_new_game_obj ;
424+
425+ if (inspector -> is_creating_new_game_obj ) {
426+ // Turn this button into a "cancel" button.
427+ unsigned int text_len ;
428+ wchar_t * wtext = wchar_from_char ("Cancel object creation" , & text_len );
429+ text_widget_set_text_own (inspector -> button_text_create_new_obj , wtext , text_len );
430+ } else {
431+ unsigned int text_len ;
432+ wchar_t * wtext = wchar_from_char (CREATE_NEW_OBJ_TEXT , & text_len );
433+ text_widget_set_text_own (inspector -> button_text_create_new_obj , wtext , text_len );
434+
435+ refresh_item_names (inspector );
436+ return ;
437+ }
438+
439+ // First hide all world item buttons.
440+ for (unsigned int button_idx = 0 ; button_idx < inspector -> item_buttons_count ;
441+ button_idx ++ ) {
442+ te_widget * widget = button_widget_get_widget (inspector -> item_buttons [button_idx ]);
443+
444+ vec2 pos ;
445+ widget_get_relative_position (widget , pos );
446+ pos [0 ] = BUTTON_HIDDEN_X_POS ;
447+
448+ widget_set_relative_position (
449+ button_widget_get_widget (inspector -> item_buttons [button_idx ]), pos );
450+ }
451+
452+ unsigned int type_count ;
453+ const char * * types = type_database_get_all_type_ids (& type_count );
454+
455+ // Now unhide buttons with possible options.
456+ const float hpadding = theme_get_horizontal_padding () / theme_get_left_panel_width ();
457+ for (unsigned int type_idx = 0 ;
458+ type_idx < type_count && type_idx < inspector -> item_buttons_count ; type_idx ++ ) {
459+ te_button_widget * button = inspector -> item_buttons [type_idx ];
460+ {
461+ // Show button.
462+ te_widget * widget = button_widget_get_widget (button );
463+
464+ vec2 pos ;
465+ widget_get_relative_position (widget , pos );
466+ pos [0 ] = hpadding ;
467+
468+ widget_set_relative_position (widget , pos );
469+ }
470+
471+ // Get button text.
472+ unsigned int child_count ;
473+ te_widget * * child_widgets =
474+ widget_get_child_widgets_tmp (button_widget_get_widget (button ), & child_count );
475+ te_text_widget * button_text = NULL ;
476+ for (unsigned int i = 0 ; i < child_count ; i ++ ) {
477+ if (!widget_is_serialization_allowed (child_widgets [i ])) {
478+ // Internal widget (rect) of the button.
479+ continue ;
480+ }
481+ button_text = widget_get_owner (child_widgets [i ]);
482+ break ;
483+ }
484+
485+ // Set text.
486+ unsigned int text_len ;
487+ wchar_t * wtext = wchar_from_char (types [type_idx ], & text_len );
488+ text_widget_set_text_own (button_text , wtext , text_len );
489+ }
490+
491+ free (types );
492+ }
493+
494+ static void
495+ on_button_list_item_clicked (te_button_widget * button ) {
496+ te_world_inspector * inspector = widget_get_custom_ptr (button_widget_get_widget (button ));
497+
498+ if (inspector -> is_creating_new_game_obj ) {
499+ // Button name stores type ID from type database.
500+
501+ // Get button text.
502+ unsigned int child_count ;
503+ te_widget * * child_widgets =
504+ widget_get_child_widgets_tmp (button_widget_get_widget (button ), & child_count );
505+ te_text_widget * button_text = NULL ;
506+ for (unsigned int i = 0 ; i < child_count ; i ++ ) {
507+ if (!widget_is_serialization_allowed (child_widgets [i ])) {
508+ // Internal widget (rect) of the button.
509+ continue ;
510+ }
511+ button_text = widget_get_owner (child_widgets [i ]);
512+ break ;
513+ }
514+
515+ unsigned int text_len ;
516+ wchar_t * wtext = text_widget_get_text (button_text , & text_len );
517+ char * type_id = wchar_to_char (wtext , & text_len );
518+
519+ const te_type_info * info = type_database_get_type_info (type_id );
520+ if (info == NULL ) {
521+ log_error_fmt ("expected to get a valid type info for type ID \"%s\"" , type_id );
522+ abort ();
523+ }
524+ free (type_id );
525+
526+ void * new_game_obj = info -> create ();
527+ info -> spawn (inspector -> game_world , new_game_obj );
528+
529+ inspector -> is_creating_new_game_obj = false;
530+ wtext = wchar_from_char (CREATE_NEW_OBJ_TEXT , & text_len );
531+ text_widget_set_text_own (inspector -> button_text_create_new_obj , wtext , text_len );
532+
533+ rebuild_item_list (inspector );
534+ refresh_item_names (inspector );
535+ return ;
536+ }
537+ }
538+
404539void
405540world_inspector_add (te_world_inspector * inspector , te_widget * left_panel ) {
406541 if (inspector -> left_panel != NULL ) {
@@ -440,7 +575,7 @@ world_inspector_add(te_world_inspector* inspector, te_widget* left_panel) {
440575 wchar_t * title_text = wchar_from_char ("World inspector:" , & title_len );
441576 text_widget_set_text_own (title , title_text , title_len );
442577 }
443- y_pos += vspacing ;
578+ y_pos += vspacing / 2.0f ;
444579
445580 // World object type buttons: 3D objects or 2D objects.
446581 {
@@ -537,6 +672,48 @@ world_inspector_add(te_world_inspector* inspector, te_widget* left_panel) {
537672 text = wchar_from_char ("2D objects" , & text_len );
538673 text_widget_set_text_own (text_2dobj , text , text_len );
539674 }
675+ y_pos += theme_get_button_height () + vspacing / 2.0f ;
676+
677+ // Button to create new game objects.
678+ {
679+ te_button_widget * button = button_widget_create ();
680+ {
681+ te_widget * widget = button_widget_get_widget (button );
682+ widget_set_custom_ptr (widget , inspector );
683+ widget_set_parent (widget , left_panel );
684+ widget_set_relative_position (widget , (vec2 ){hpadding , y_pos });
685+ widget_set_relative_size (widget , (vec2 ){total_width , theme_get_button_height ()});
686+ }
687+
688+ vec4 color ;
689+ theme_get_button_color (color );
690+ button_widget_set_color (button , color );
691+
692+ theme_get_button_color_hovered (color );
693+ button_widget_set_color_hovered (button , color );
694+
695+ theme_get_button_color_pressed (color );
696+ button_widget_set_color_pressed (button , color );
697+
698+ button_widget_set_on_clicked (button , on_button_create_new_object_clicked );
699+
700+ // Button text.
701+ te_text_widget * text_widget = text_widget_create ();
702+ inspector -> button_text_create_new_obj = text_widget ;
703+ {
704+ te_widget * widget = text_widget_get_widget (text_widget );
705+ widget_set_parent (widget , button_widget_get_widget (button ));
706+ widget_set_relative_position (
707+ widget , (vec2 ){hpadding_in_button , vpadding_in_button });
708+ widget_set_relative_size (
709+ widget , (vec2 ){1.0f - hpadding_in_button , 1.0f - vpadding_in_button });
710+ }
711+ text_widget_set_text_height (text_widget , theme_get_text_height ());
712+
713+ unsigned int text_len ;
714+ wchar_t * text = wchar_from_char (CREATE_NEW_OBJ_TEXT , & text_len );
715+ text_widget_set_text_own (text_widget , text , text_len );
716+ }
540717 y_pos += theme_get_button_height ();
541718
542719 const float world_item_list_y_pos = y_pos ;
@@ -558,7 +735,7 @@ world_inspector_add(te_world_inspector* inspector, te_widget* left_panel) {
558735 <= world_item_list_y_pos + list_and_nav_menu_height );
559736 }
560737
561- const float list_button_width = total_width ;
738+ // Create buttons.
562739 inspector -> item_buttons = malloc (sizeof (te_button_widget * ) * button_count );
563740 inspector -> item_buttons_count = button_count ;
564741 for (unsigned int i = 0 ; i < button_count ; i ++ ) {
@@ -568,9 +745,11 @@ world_inspector_add(te_world_inspector* inspector, te_widget* left_panel) {
568745 {
569746 te_widget * widget = button_widget_get_widget (button );
570747 widget_set_parent (widget , left_panel );
748+ widget_set_custom_value (widget , i );
749+ widget_set_custom_ptr (widget , inspector );
571750 widget_set_relative_position (widget , (vec2 ){hpadding , y_pos });
572751 widget_set_relative_size (
573- widget , (vec2 ){list_button_width , theme_get_button_height ()});
752+ widget , (vec2 ){total_width , theme_get_button_height ()});
574753 }
575754
576755 vec4 color ;
@@ -583,6 +762,8 @@ world_inspector_add(te_world_inspector* inspector, te_widget* left_panel) {
583762 theme_get_button_color_pressed (color );
584763 button_widget_set_color_pressed (button , color );
585764
765+ button_widget_set_on_clicked (button , on_button_list_item_clicked );
766+
586767 // Button text.
587768 te_text_widget * text = text_widget_create ();
588769 {
0 commit comments