diff options
| -rw-r--r-- | src/editor/editor.h | 29 | ||||
| -rw-r--r-- | src/editor/editor_gui_internal.h | 55 | ||||
| -rw-r--r-- | src/editor/editor_infobox.cpp | 238 | ||||
| -rw-r--r-- | src/editor/editor_layout.cpp | 283 | ||||
| -rw-r--r-- | src/editor/editor_menubar.cpp | 430 | ||||
| -rw-r--r-- | src/editor/editor_viewtype_segment.cpp | 119 | ||||
| -rw-r--r-- | src/editor/editor_window.cpp | 285 | ||||
| -rw-r--r-- | src/editor/gui.cpp | 1280 |
8 files changed, 1427 insertions, 1292 deletions
diff --git a/src/editor/editor.h b/src/editor/editor.h index b000816..6735d47 100644 --- a/src/editor/editor.h +++ b/src/editor/editor.h @@ -58,15 +58,15 @@ enum Editor2DViewType_t { EDITOR_2DVIEW_FRONT_ELEVATION = 2 }; -enum EditorToolbarHit_t { - EDITOR_TOOLBAR_HIT_NONE = -1, - EDITOR_TOOLBAR_HIT_FILE = 0, - EDITOR_TOOLBAR_HIT_EDIT = 1, - EDITOR_TOOLBAR_HIT_VIEW = 2, - EDITOR_TOOLBAR_HIT_TOOLS = 3, - EDITOR_TOOLBAR_HIT_SAVE = 4, - EDITOR_TOOLBAR_HIT_UNDO = 5, - EDITOR_TOOLBAR_HIT_REDO = 6 +enum EditorMenubarEntryType_t { + EDITOR_MENUBAR_ENTRY_FUNCTION = 0, + EDITOR_MENUBAR_ENTRY_SUBMENU = 1 +}; + +struct EDITOR_MENUBAR_ENTRY { + char text[64]{}; + U8 type{}; + LIST<EDITOR_MENUBAR_ENTRY> entries{}; }; struct GAME_EDITOR; @@ -195,6 +195,10 @@ extern void editor_new_map_cb( void* ); extern void editor_create_map_view( GAME_EDITOR* e ); extern void editor_update_properties_column( GAME_EDITOR* e ); +extern const char* editor_tool_name(); +extern void editor_set_view_mode( I32 mode ); +extern void editor_toolbar_set_open( struct GUI_EDITOR_TOOLBAR* bar, U8 file_open, U8 edit_open ); +extern U8 editor_toolbar_menu_open( const struct GUI_EDITOR_TOOLBAR* bar ); extern void editor_undo_clear( GAME_EDITOR* e ); extern void editor_undo_record_create_walls( GAME_EDITOR* e, I32 start_idx, I32 count ); extern void editor_undo_record_create_poly( GAME_EDITOR* e, I32 start_idx ); @@ -281,9 +285,10 @@ struct GUI_EDITOR_VIEWTYPE_SEGMENT : GUI_BASE { struct GUI_EDITOR_TOOLBAR : GUI_BASE { U8 held{}; - I32 held_item{-1}; - U8 file_open{}; - U8 edit_open{}; + I32 held_root{-1}; + I32 held_sub{-1}; + I32 open_root{-1}; + LIST<EDITOR_MENUBAR_ENTRY> entries{}; }; extern GUI_EDITORWINDOW* gui_editorwindow( I32 w, I32 h ); diff --git a/src/editor/editor_gui_internal.h b/src/editor/editor_gui_internal.h new file mode 100644 index 0000000..ff9b140 --- /dev/null +++ b/src/editor/editor_gui_internal.h @@ -0,0 +1,55 @@ +#pragma once + +#include "editor.h" +#include "../util.h" + +constexpr I32 EDITOR_LAYOUT_MARGIN = 10; +constexpr I32 EDITOR_LAYOUT_TITLE_OFFSET = 15; +constexpr I32 EDITOR_LAYOUT_MENU_Y = 1; +constexpr I32 EDITOR_LAYOUT_MENU_H = 22; +constexpr I32 EDITOR_LAYOUT_NAV_Y = EDITOR_LAYOUT_MENU_Y + EDITOR_LAYOUT_MENU_H + 4; +constexpr I32 EDITOR_LAYOUT_CONTENT_Y = EDITOR_LAYOUT_NAV_Y + 28; +constexpr I32 EDITOR_LAYOUT_COLUMN_GAP = 10; +constexpr I32 EDITOR_LAYOUT_VIEW_TOOL_GAP = 17; +constexpr I32 EDITOR_LAYOUT_TOOL_BTN_TOP_GAP = 3; +constexpr I32 EDITOR_LAYOUT_TOOL_PANEL_GAP = 5; +constexpr I32 EDITOR_LAYOUT_LEFT_BOX_GAP = 10; +constexpr I32 EDITOR_LAYOUT_STATUS_H = 22; +constexpr I32 EDITOR_LAYOUT_STATUS_GAP = 6; +constexpr I32 EDITOR_LAYOUT_TOOL_PANEL_W = 300; +constexpr I32 EDITOR_LAYOUT_TOOL_PANEL_H = 150; +constexpr I32 EDITOR_LAYOUT_PROPS_DEFAULT_W = 300; +constexpr I32 EDITOR_LAYOUT_PROPS_DEFAULT_H = 300; +constexpr I32 EDITOR_LAYOUT_VIEW_DEFAULT_H = 370; +constexpr I32 EDITOR_LAYOUT_PROPS_MIN_W = 200; +constexpr I32 EDITOR_LAYOUT_PROPS_MIN_H = 120; +constexpr I32 EDITOR_LAYOUT_ASSETS_MIN_H = 120; +constexpr I32 EDITOR_LAYOUT_VIEW_MIN_H = 140; +constexpr I32 EDITOR_LAYOUT_RIGHT_MIN_W = 260; + +constexpr I32 EDITOR_TOOLBAR_DROPDOWN_W = 120; + +extern U8 editor_menu_hover_mask_active; +extern I32 editor_menu_hover_real_x; +extern I32 editor_menu_hover_real_y; + +extern GUI_EDITOR_VIEWTYPE_SEGMENT* gui_editor_viewtype_segment( I32 x, I32 y, I32 w, I32 h, const char* name ); +extern GUI_EDITOR_TOOLBAR* gui_editor_toolbar( I32 x, I32 y, I32 w, I32 h, const char* name ); +extern GUI_EDITOR_INFOBOX* gui_editor_infobox( I32 x, I32 y, I32 w, I32 h, U8 type, const char* name ); + +extern void editor_apply_view_mode( GAME_EDITOR* e ); +extern void editor_toolbar_close_menu(); +extern void editor_create_header_controls( GAME_EDITOR* e ); +extern void editor_raise_header_toolbar( GAME_EDITOR* e ); + +extern void editor_set_bounds( GUI_BASE* node, I32 x, I32 y, I32 w, I32 h ); +extern void editor_resize_base_view( GUI_EDITORWINDOW* wnd ); +extern void editor_layout_start_menu( GAME_EDITOR* e ); +extern void editor_layout_map_view( GAME_EDITOR* e ); + +extern void editor_create_properties_column( GAME_EDITOR* e ); +extern void editor_create_auxiliary_panels( GAME_EDITOR* e ); +extern void editor_update_toolview( GAME_EDITOR* e ); +extern void editor_create_toolview_column( GAME_EDITOR* e ); +extern void editor_create_game_view_column( GAME_EDITOR* e ); +extern void settool( U8 t ); diff --git a/src/editor/editor_infobox.cpp b/src/editor/editor_infobox.cpp new file mode 100644 index 0000000..8e455d9 --- /dev/null +++ b/src/editor/editor_infobox.cpp @@ -0,0 +1,238 @@ +#include "editor_gui_internal.h" + +#include "../game.h" +#include "../render/gl_2d.h" + +constexpr I32 EDITOR_ASSETS_ROW_H = 28; +constexpr I32 EDITOR_ASSETS_THUMB = 20; +constexpr I32 EDITOR_ASSETS_INNER_PAD_X = 8; +constexpr I32 EDITOR_ASSETS_INNER_PAD_Y = 6; +constexpr I32 EDITOR_ASSETS_SCROLLBAR_W = 7; +constexpr I32 EDITOR_ASSETS_SCROLLBAR_GAP = 4; +constexpr I32 EDITOR_ASSETS_SCROLL_STEP = 20; + +struct EDITOR_ASSETS_LAYOUT { + I32 inner_x{}; + I32 inner_y{}; + I32 inner_w{}; + I32 list_h{}; + I32 row_x{}; + I32 row_w{}; + I32 count{}; + I32 content_h{}; + I32 max_scroll{}; + U8 show_scroll{}; + I32 track_x{}; + I32 track_y{}; + I32 track_h{}; +}; + +static EDITOR_ASSETS_LAYOUT editor_assets_layout( GUI_EDITOR_INFOBOX* box, I32 panel_x, I32 panel_y, I32 prop_count ) { + EDITOR_ASSETS_LAYOUT l{}; + l.inner_x = panel_x + EDITOR_ASSETS_INNER_PAD_X; + l.inner_y = panel_y + EDITOR_ASSETS_INNER_PAD_Y; + l.inner_w = max( 1, box->w - ( EDITOR_ASSETS_INNER_PAD_X * 2 ) ); + l.list_h = max( 1, box->h - ( EDITOR_ASSETS_INNER_PAD_Y * 2 ) ); + l.count = prop_count + 1; + l.content_h = l.count * EDITOR_ASSETS_ROW_H; + l.max_scroll = max( 0, l.content_h - l.list_h ); + l.show_scroll = l.content_h > l.list_h; + l.row_x = l.inner_x + 1; + l.row_w = l.inner_w - 2; + if( l.show_scroll ) + l.row_w -= EDITOR_ASSETS_SCROLLBAR_W + EDITOR_ASSETS_SCROLLBAR_GAP; + l.row_w = max( 1, l.row_w ); + l.track_x = l.inner_x + l.inner_w - EDITOR_ASSETS_SCROLLBAR_W - 1 - ( EDITOR_ASSETS_SCROLLBAR_GAP / 2 ); + l.track_y = l.inner_y; + l.track_h = l.list_h - 2; + return l; +} + +static void editor_assets_clamp_scroll( const EDITOR_ASSETS_LAYOUT& l ) { + editor->gui.assets_scroll = min( max( 0, editor->gui.assets_scroll ), l.max_scroll ); +} + +static void gui_editor_infobox_draw_assets( GUI_EDITOR_INFOBOX* box, I32 panel_x, I32 panel_y ) { + if( !editor->map ) + return; + + WORLD_MAP* map = editor->map; + EDITOR_ASSETS_LAYOUT l = editor_assets_layout( box, panel_x, panel_y, (I32)map->props.size ); + editor_assets_clamp_scroll( l ); + I32 yoff = -editor->gui.assets_scroll; + + for( I32 idx = 0; idx < l.count; ++idx ) { + I32 row_y = l.inner_y + idx * EDITOR_ASSETS_ROW_H + yoff; + if( row_y + EDITOR_ASSETS_ROW_H - 2 <= l.inner_y || row_y >= l.inner_y + l.list_h ) + continue; + + U8 map_entry = idx == 0; + SURF_PROPS* p = map_entry ? 0 : &map->props[idx - 1]; + U8 selected = 0; + if( editor->gui.props ) { + if( map_entry ) { + selected = editor->gui.props->seltype == EDITOR_SELECT_ORIGIN + && editor->gui.props->curselect == editor->map; + } else { + selected = editor->gui.props->seltype == EDITOR_SELECT_SURFPROPS + && editor->gui.props->curselect == p; + } + } + + CLR rowbg = idx % 2 ? ui_clr.bg : ui_clr.bg_alt; + if( selected ) + rowbg = CLR::blend( ui_clr.border, ui_clr.bg, 0.70f ); + + gui_draw_frect( l.row_x, row_y, l.row_w, EDITOR_ASSETS_ROW_H - 2, rowbg ); + + I32 tx = l.row_x + 3; + I32 ty = row_y + 3; + gui_draw_frect( tx, ty, EDITOR_ASSETS_THUMB, EDITOR_ASSETS_THUMB, ui_clr.border ); + if( map_entry ) { + gui_draw_frect( tx + 1, ty + 1, EDITOR_ASSETS_THUMB - 2, EDITOR_ASSETS_THUMB - 2, ui_clr.bg_alt ); + gui_draw_str( tx + EDITOR_ASSETS_THUMB / 2, ty + 4, ALIGN_C, FNT_JPN12, ui_clr.txt, "m" ); + } else if( p->tex ) { + gl_2d_textured_frect( _gui.gl2d_font, { (F32)(tx + 1), (F32)(ty + 1) }, { (F32)(EDITOR_ASSETS_THUMB - 2), (F32)(EDITOR_ASSETS_THUMB - 2) }, p->tex ); + } else { + gui_draw_frect( tx + 1, ty + 1, EDITOR_ASSETS_THUMB - 2, EDITOR_ASSETS_THUMB - 2, p->clr ); + } + + I32 text_x = tx + EDITOR_ASSETS_THUMB + 8; + CLR txt = ui_clr.txt; + if( map_entry ) { + gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[map] -> %s", map->name ); + } else if( p->tex ) { + gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[%d] -> %s", idx - 1, p->tex->name ); + } else { + gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[%d] -> %.2f, %.2f, %.2f", idx - 1, p->clr.r, p->clr.g, p->clr.b ); + } + } + + if( !l.show_scroll ) + return; + + gui_draw_frect( l.track_x, l.track_y, EDITOR_ASSETS_SCROLLBAR_W, l.track_h, ui_clr.bg_alt ); + gui_draw_rect( l.track_x, l.track_y, EDITOR_ASSETS_SCROLLBAR_W, l.track_h, ui_clr.border ); + + I32 thumb_h = max( 18, ( l.track_h * l.list_h ) / max( 1, l.content_h ) ); + thumb_h = min( thumb_h, l.track_h ); + I32 travel = max( 1, l.track_h - thumb_h ); + I32 thumb_y = l.track_y + ( travel * editor->gui.assets_scroll ) / max( 1, l.max_scroll ); + gui_draw_frect( l.track_x, thumb_y + 1, EDITOR_ASSETS_SCROLLBAR_W, max( 1, thumb_h - 1 ), ui_clr.txt ); +} + +static void gui_editor_infobox_draw_fn( void* ptr ) { + GUI_EDITOR_INFOBOX* box = (GUI_EDITOR_INFOBOX*)ptr; + I32 x = gui_relx( box ); + I32 y = gui_rely( box ); + I32 w = box->w; + I32 h = box->h; + + if( box->type == EDITOR_INFOBOX_STATUS ) { + CLR col = gui_is_fg_window( box ) ? ui_clr.border : ui_clr.border_inactive; + gui_draw_frect( x, y, w, h, col ); + gui_draw_frect( x + 1, y + 1, w - 2, h - 2, ui_clr.bg_sec ); + gui_draw_str( + x + 6, + y + 4, + ALIGN_L, + FNT_JPN12, + ui_clr.txt, + "selected tool: %s. click in viewport to create/edit.", + editor_tool_name() + ); + + if( editor->game && editor->game->gl ) { + GL_DATA* gl = editor->game->gl; + gui_draw_str( + x + w - 6, + y + 4, + ALIGN_R, + FNT_JPN12, + ui_clr.txt, + "fps: %.3f (%.5f ms) %dx%d", + gl->fps, + gl->frametime, + gl->canvas_size[0], + gl->canvas_size[1] + ); + } + return; + } + + gui_draw_str( x, y, ALIGN_L, FNT_JPN12, ui_clr.txt, "assets" ); + y += EDITOR_LAYOUT_TITLE_OFFSET; + + CLR col = gui_is_fg_window( box ) ? ui_clr.border : ui_clr.border_inactive; + gui_draw_frect( x, y, w, h, col ); + gui_draw_frect( x + 1, y + 1, w - 2, h - 2, ui_clr.bg_sec ); + + gui_draw_push_clip( x + 2, y + 2, w - 4, h - 4 ); + gui_editor_infobox_draw_assets( box, x, y ); + gui_draw_pop_clip(); +} + +static void gui_editor_infobox_input_fn( void* ptr ) { + GUI_EDITOR_INFOBOX* box = (GUI_EDITOR_INFOBOX*)ptr; + static U8 assets_click_held = 0; + if( box->type == EDITOR_INFOBOX_ASSETS ) { + I32 x = gui_relx( box ); + I32 y = gui_rely( box ) + EDITOR_LAYOUT_TITLE_OFFSET; + I32 w = box->w; + I32 h = box->h; + I32 prop_count = editor->map ? (I32)editor->map->props.size : 0; + EDITOR_ASSETS_LAYOUT l = editor_assets_layout( box, x, y, prop_count ); + editor_assets_clamp_scroll( l ); + I32 mx, my; + gui_cursor_pos( &mx, &my ); + U8 inbounds = mx >= x && mx <= x + w && my >= y && my <= y + h; + if( inbounds ) { + U8 scroll = gui_mbutton_down( GUI_MBTNSCROLL ); + if( scroll ) { + gui_capture_scroll(); + if( scroll == 1 ) editor->gui.assets_scroll -= EDITOR_ASSETS_SCROLL_STEP; + else if( scroll == (U8)-1 ) editor->gui.assets_scroll += EDITOR_ASSETS_SCROLL_STEP; + editor_assets_clamp_scroll( l ); + } + + U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); + if( m1 && !assets_click_held && editor->map ) { + if( mx >= l.row_x && mx < l.row_x + l.row_w ) { + I32 idx = ( my - l.inner_y + editor->gui.assets_scroll ) / EDITOR_ASSETS_ROW_H; + if( idx >= 0 && idx < l.count && editor->gui.props ) { + if( idx == 0 ) gui_editor_propview_select( editor->gui.props, editor->map, EDITOR_SELECT_ORIGIN ); + else gui_editor_propview_select( editor->gui.props, &editor->map->props[idx - 1], EDITOR_SELECT_SURFPROPS ); + } + } + } + assets_click_held = m1; + } + + if( !gui_mbutton_down( GUI_MBTNLEFT ) ) + assets_click_held = 0; + } + + gui_base_input_fn( box ); +} + +GUI_EDITOR_INFOBOX* gui_editor_infobox( I32 x, I32 y, I32 w, I32 h, U8 type, const char* name ) { + if( !gui_check_target() ) + return 0; + + GUI_EDITOR_INFOBOX* box = new GUI_EDITOR_INFOBOX; + box->x = x; + box->y = y; + box->w = w; + box->h = h; + box->xbound = w; + box->ybound = h + ( type == EDITOR_INFOBOX_STATUS ? 0 : EDITOR_LAYOUT_TITLE_OFFSET ); + box->draw_fn = gui_editor_infobox_draw_fn; + box->input_fn = gui_editor_infobox_input_fn; + box->type = type; + strcpy( box->name, name ); + + GUI_VIEW* parent = gui_get_view(); + box->parent = parent; + parent->children.push( box ); + return box; +} diff --git a/src/editor/editor_layout.cpp b/src/editor/editor_layout.cpp new file mode 100644 index 0000000..f98ef00 --- /dev/null +++ b/src/editor/editor_layout.cpp @@ -0,0 +1,283 @@ +#include "editor_gui_internal.h" + +static I32 editor_layout_props_w_max( GUI_EDITORWINDOW* wnd ) { + I32 max_w = wnd->w - ( EDITOR_LAYOUT_MARGIN * 2 ) - EDITOR_LAYOUT_COLUMN_GAP - EDITOR_LAYOUT_RIGHT_MIN_W; + return max( EDITOR_LAYOUT_PROPS_MIN_W, max_w ); +} + +static I32 editor_layout_content_bottom( GUI_EDITORWINDOW* wnd ) { + return wnd->h - EDITOR_LAYOUT_MARGIN - EDITOR_LAYOUT_STATUS_H - EDITOR_LAYOUT_STATUS_GAP; +} + +static I32 editor_layout_left_available_h( GUI_EDITORWINDOW* wnd ) { + return max( 1, editor_layout_content_bottom( wnd ) - EDITOR_LAYOUT_CONTENT_Y ); +} + +static I32 editor_layout_view_h_max( GUI_EDITORWINDOW* wnd ) { + I32 max_h = editor_layout_content_bottom( wnd ) + - EDITOR_LAYOUT_CONTENT_Y + - EDITOR_LAYOUT_VIEW_TOOL_GAP + - EDITOR_LAYOUT_TOOL_PANEL_H + - ( EDITOR_LAYOUT_TITLE_OFFSET * 2 ); + return max( EDITOR_LAYOUT_VIEW_MIN_H, max_h ); +} + +static void editor_layout_clamp_custom_sizes( GAME_EDITOR* e ) { + if( !e || !e->wnd ) + return; + + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + if( egui->props_w <= 0 ) egui->props_w = EDITOR_LAYOUT_PROPS_DEFAULT_W; + if( egui->props_h <= 0 ) egui->props_h = EDITOR_LAYOUT_PROPS_DEFAULT_H; + if( egui->view_h <= 0 ) egui->view_h = EDITOR_LAYOUT_VIEW_DEFAULT_H; + + egui->props_w = min( max( egui->props_w, EDITOR_LAYOUT_PROPS_MIN_W ), editor_layout_props_w_max( e->wnd ) ); + + I32 left_avail_h = editor_layout_left_available_h( e->wnd ); + I32 max_props_h = left_avail_h - EDITOR_LAYOUT_LEFT_BOX_GAP - EDITOR_LAYOUT_ASSETS_MIN_H - ( EDITOR_LAYOUT_TITLE_OFFSET * 2 ); + max_props_h = max( EDITOR_LAYOUT_PROPS_MIN_H, max_props_h ); + egui->props_h = min( max( egui->props_h, EDITOR_LAYOUT_PROPS_MIN_H ), max_props_h ); + + egui->view_h = editor_layout_view_h_max( e->wnd ); +} + +static EDITOR_LAYOUT editor_calc_layout( GAME_EDITOR* e ) { + GUI_EDITORWINDOW* wnd = e->wnd; + editor_layout_clamp_custom_sizes( e ); + + EDITOR_LAYOUT l{}; + l.left_x = EDITOR_LAYOUT_MARGIN; + l.left_w = e->gui.props_w; + l.right_x = l.left_x + l.left_w + EDITOR_LAYOUT_COLUMN_GAP; + l.right_w = max( 1, wnd->w - EDITOR_LAYOUT_MARGIN - l.right_x ); + l.tool_btn_x = l.right_x; + l.tool_btn_w = 45; + l.tool_panel_x = l.tool_btn_x + l.tool_btn_w + EDITOR_LAYOUT_TOOL_PANEL_GAP; + l.tool_panel_w = EDITOR_LAYOUT_TOOL_PANEL_W; + + l.top_y = EDITOR_LAYOUT_NAV_Y; + l.props_y = EDITOR_LAYOUT_CONTENT_Y; + l.view_y = EDITOR_LAYOUT_CONTENT_Y; + l.props_h = e->gui.props_h; + + I32 left_total_h = max( 1, editor_layout_content_bottom( wnd ) - l.props_y ); + I32 props_max_h = left_total_h - EDITOR_LAYOUT_LEFT_BOX_GAP - EDITOR_LAYOUT_ASSETS_MIN_H - ( EDITOR_LAYOUT_TITLE_OFFSET * 2 ); + props_max_h = max( EDITOR_LAYOUT_PROPS_MIN_H, props_max_h ); + l.props_h = min( max( l.props_h, EDITOR_LAYOUT_PROPS_MIN_H ), props_max_h ); + l.assets_y = l.props_y + EDITOR_LAYOUT_TITLE_OFFSET + l.props_h + EDITOR_LAYOUT_LEFT_BOX_GAP; + l.assets_h = max( EDITOR_LAYOUT_ASSETS_MIN_H, editor_layout_content_bottom( wnd ) - l.assets_y - EDITOR_LAYOUT_TITLE_OFFSET ); + + l.view_h = e->gui.view_h; + l.tool_y = l.view_y + EDITOR_LAYOUT_TITLE_OFFSET + l.view_h + EDITOR_LAYOUT_VIEW_TOOL_GAP; + l.tool_btn_y = l.tool_y + EDITOR_LAYOUT_TOOL_BTN_TOP_GAP; + + I32 bottom_content = editor_layout_content_bottom( wnd ); + l.tool_h = max( 1, bottom_content - l.tool_y - EDITOR_LAYOUT_TITLE_OFFSET ); + l.tool_panel_h = l.tool_h; + l.tool_btn_step = 23; + + I32 required_w = l.tool_btn_w + EDITOR_LAYOUT_TOOL_PANEL_GAP + l.tool_panel_w; + if( required_w > l.right_w ) { + I32 overflow = required_w - l.right_w; + I32 shrink_panel = min( overflow, max( 0, l.tool_panel_w - 180 ) ); + l.tool_panel_w -= shrink_panel; + } + l.tool_panel_x = l.tool_btn_x + l.tool_btn_w + EDITOR_LAYOUT_TOOL_PANEL_GAP; + + l.status_x = EDITOR_LAYOUT_MARGIN; + l.status_w = max( 1, wnd->w - EDITOR_LAYOUT_MARGIN * 2 ); + l.status_h = EDITOR_LAYOUT_STATUS_H; + l.status_y = wnd->h - EDITOR_LAYOUT_MARGIN - l.status_h; + return l; +} + +void editor_set_bounds( GUI_BASE* node, I32 x, I32 y, I32 w, I32 h ) { + if( !node ) + return; + + I32 x_extra = node->xbound - node->w; + I32 y_extra = node->ybound - node->h; + if( x_extra < 0 ) x_extra = 0; + if( y_extra < 0 ) y_extra = 0; + + node->x = x; + node->y = y; + node->w = max( 1, w ); + node->h = max( 1, h ); + node->xbound = node->w + x_extra; + node->ybound = node->h + y_extra; +} + +void editor_resize_base_view( GUI_EDITORWINDOW* wnd ) { + GUI_VIEW* base = (GUI_VIEW*)gui_find_node( wnd, "BASE_VIEW" ); + if( !base ) + return; + + editor_set_bounds( base, 1, 1, wnd->w - 2, wnd->h - 2 ); +} + +void editor_layout_start_menu( GAME_EDITOR* e ) { + GUI_EDITORWINDOW* wnd = e->wnd; + GUI_LIST* list = (GUI_LIST*)gui_find_node( wnd, "map list" ); + GUI_BUTTON* new_map = (GUI_BUTTON*)gui_find_node( wnd, "new map" ); + GUI_BUTTON* load_map = (GUI_BUTTON*)gui_find_node( wnd, "load map" ); + if( !list || !new_map || !load_map ) + return; + + const I32 min_margin = 10; + const I32 list_title_offset = 15; + const I32 button_gap = 10; + const I32 button_h = 25; + const I32 list_button_gap = 5; + I32 list_w = 200; + I32 list_h = 200; + I32 max_list_w = max( 80, wnd->w - min_margin * 2 ); + I32 start_y = EDITOR_LAYOUT_CONTENT_Y; + I32 max_list_h = max( 80, wnd->h - ( start_y + list_title_offset + list_button_gap + button_h + min_margin ) ); + if( list_w > max_list_w ) list_w = max_list_w; + if( list_h > max_list_h ) list_h = max_list_h; + + I32 x = ( wnd->w - list_w ) / 2; + I32 y = start_y; + I32 bottom = y + list_title_offset + list_h + list_button_gap + button_h; + if( bottom > wnd->h - min_margin ) + y = max( min_margin, wnd->h - min_margin - ( list_title_offset + list_h + list_button_gap + button_h ) ); + + editor_set_bounds( list, x, y, list_w, list_h ); + I32 bw = max( 50, ( list_w - button_gap ) / 2 ); + I32 by = y + list_title_offset + list_h + list_button_gap; + editor_set_bounds( new_map, x, by, bw, button_h ); + editor_set_bounds( load_map, x + bw + button_gap, by, bw, button_h ); +} + +static void editor_layout_tool_buttons( GUI_EDITORWINDOW* wnd, const EDITOR_LAYOUT& l ) { + const char* names[] = { "none", "select", "wall", "poly", "sprite", "ent" }; + I32 y = l.tool_btn_y; + for( U32 i = 0; i < sizeof( names ) / sizeof( names[0] ); ++i ) { + GUI_BUTTON* btn = (GUI_BUTTON*)gui_find_node( wnd, names[i] ); + editor_set_bounds( btn, l.tool_btn_x, y, l.tool_btn_w, 20 ); + y += l.tool_btn_step; + } +} + +static void editor_layout_header_controls( GAME_EDITOR* e, const EDITOR_LAYOUT& l ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + GUI_BASE* toolbar = egui->header_toolbar; + GUI_BUTTON* back = egui->header_back; + GUI_BUTTON* v2btn = egui->header_mode_2d; + GUI_BUTTON* v3btn = egui->header_mode_3d; + GUI_BUTTON* simbtn = egui->header_mode_sim; + GUI_LABEL* view_type_lbl = egui->header_viewtype_label; + GUI_BASE* view_type_seg = egui->header_viewtype; + + const I32 top_btn_h = 20; + const I32 nav_left_x = 10; + const I32 nav_btn_w = 92; + const I32 nav_gap = 8; + const I32 mode_btn_w = 92; + I32 mode_group_w = mode_btn_w * 3 + nav_gap * 2; + I32 mode_x = e->wnd->w - EDITOR_LAYOUT_MARGIN - mode_group_w; + I32 type_seg_x = l.right_x; + I32 type_lbl_w = 64; + I32 type_lbl_x = type_seg_x - type_lbl_w - 6; + I32 max_type_w = mode_x - type_seg_x - 8; + I32 type_seg_w = min( 174, max( 120, max_type_w ) ); + + editor_set_bounds( toolbar, 1, EDITOR_LAYOUT_MENU_Y, e->wnd->w - 3, EDITOR_LAYOUT_MENU_H ); + editor_set_bounds( back, nav_left_x, l.top_y, nav_btn_w, top_btn_h ); + + GUI_BUTTON* mode_btns[] = { v2btn, v3btn, simbtn }; + const char* mode_names[] = { "[ 2d view ]", "[ 3d view ]", "[ simulation ]" }; + for( I32 i = 0; i < 3; ++i ) { + I32 bx = mode_x + ( mode_btn_w + nav_gap ) * i; + editor_set_bounds( mode_btns[i], bx, l.top_y, mode_btn_w, top_btn_h ); + if( mode_btns[i] ) + snprintf( mode_btns[i]->name, GUI_NAME_LEN, "%s", mode_names[i] ); + } + + U8 show_viewtype = e->gui.view_mode == EDITOR_VIEWMODE_2D; + if( view_type_lbl ) { + view_type_lbl->x = type_lbl_x; + view_type_lbl->y = l.top_y + 4; + view_type_lbl->enabled = show_viewtype; + } + if( view_type_seg ) { + editor_set_bounds( view_type_seg, type_seg_x, l.top_y, type_seg_w, top_btn_h ); + view_type_seg->enabled = show_viewtype; + } +} + +static void editor_layout_left_column( GAME_EDITOR* e, const EDITOR_LAYOUT& l ) { + editor_set_bounds( e->gui.props, l.left_x, l.props_y, l.left_w, l.props_h ); + if( e->gui.props->itemview ) { + editor_set_bounds( e->gui.props->itemview, 0, EDITOR_LAYOUT_TITLE_OFFSET, e->gui.props->w, e->gui.props->h ); + } + + if( e->gui.assets ) + editor_set_bounds( e->gui.assets, l.left_x, l.assets_y, l.left_w, l.assets_h ); +} + +static void editor_layout_view_panels( GAME_EDITOR* e, const EDITOR_LAYOUT& l ) { + editor_set_bounds( e->gui.v2d, l.right_x, l.view_y, l.right_w, l.view_h ); + e->gui.v2d->ybound = e->gui.v2d->h + EDITOR_LAYOUT_TITLE_OFFSET; + editor_set_bounds( e->gui.v3d, l.right_x, l.view_y, l.right_w, l.view_h ); + e->gui.v3d->ybound = e->gui.v3d->h + EDITOR_LAYOUT_TITLE_OFFSET; +} + +static void editor_layout_tool_panel( GAME_EDITOR* e, const EDITOR_LAYOUT& l ) { + editor_layout_tool_buttons( e->wnd, l ); + editor_set_bounds( e->gui.tool, l.tool_panel_x, l.tool_y, l.tool_panel_w, l.tool_panel_h ); + if( e->gui.tool->itemview ) { + editor_set_bounds( e->gui.tool->itemview, 0, EDITOR_LAYOUT_TITLE_OFFSET, e->gui.tool->w, e->gui.tool->h ); + } +} + +static void editor_layout_2d_footer( GAME_EDITOR* e ) { + if( !e->gui.gridlabel ) + return; + + I32 gx = 150; + I32 gy = e->gui.v2d->h - 4; + e->gui.gridlabel->x = gx; + e->gui.gridlabel->y = gy + 1; + + GUI_BUTTON* plus = (GUI_BUTTON*)gui_find_node( e->gui.v2d, "+" ); + GUI_BUTTON* minus = (GUI_BUTTON*)gui_find_node( e->gui.v2d, "-" ); + GUI_CHECKBOX* propgrid = (GUI_CHECKBOX*)gui_find_node( e->gui.v2d, "properties grid" ); + GUI_CHECKBOX* wireframe = (GUI_CHECKBOX*)gui_find_node( e->gui.v2d, "wireframe" ); + editor_set_bounds( plus, gx + 70, gy, 18, 18 ); + editor_set_bounds( minus, gx + 93, gy, 18, 18 ); + editor_set_bounds( propgrid, gx + 120, gy, propgrid ? propgrid->w : 120, 18 ); + editor_set_bounds( wireframe, gx + 240, gy, wireframe ? wireframe->w : 80, 18 ); +} + +static void editor_layout_3d_footer( GAME_EDITOR* e ) { + GUI_BUTTON* compile = (GUI_BUTTON*)gui_find_node( e->gui.v3d, "compile bsp" ); + GUI_CHECKBOX* drawbsp = (GUI_CHECKBOX*)gui_find_node( e->gui.v3d, "draw bsp" ); + I32 gy3d = e->gui.v3d->h - 4; + editor_set_bounds( compile, 1, gy3d, 90, 18 ); + editor_set_bounds( drawbsp, 101, gy3d, drawbsp ? drawbsp->w : 80, 18 ); +} + +void editor_layout_map_view( GAME_EDITOR* e ) { + if( !e->gui.v2d || !e->gui.v3d || !e->gui.props || !e->gui.tool ) + return; + + EDITOR_LAYOUT l = editor_calc_layout( e ); + editor_raise_header_toolbar( e ); + + editor_layout_header_controls( e, l ); + editor_layout_left_column( e, l ); + editor_layout_view_panels( e, l ); + editor_layout_tool_panel( e, l ); + if( e->gui.status ) + editor_set_bounds( e->gui.status, l.status_x, l.status_y, l.status_w, l.status_h ); + + editor_apply_view_mode( e ); + editor_layout_2d_footer( e ); + editor_layout_3d_footer( e ); + + editor_update_properties_column( e ); + gui_editor_toolview_update( e->gui.tool ); + editor_notify_grid_change( e ); +} diff --git a/src/editor/editor_menubar.cpp b/src/editor/editor_menubar.cpp new file mode 100644 index 0000000..5491c05 --- /dev/null +++ b/src/editor/editor_menubar.cpp @@ -0,0 +1,430 @@ +#include "editor_gui_internal.h" + +U8 editor_menu_hover_mask_active = 0; +I32 editor_menu_hover_real_x = 0; +I32 editor_menu_hover_real_y = 0; + +static void editor_header_back_cb( void* ) { + editor_toolbar_close_menu(); + editor_close( editor ); +} + +static void editor_header_mode_2d_cb( void* ) { + editor_set_view_mode( EDITOR_VIEWMODE_2D ); +} + +static void editor_header_mode_3d_cb( void* ) { + editor_set_view_mode( EDITOR_VIEWMODE_3D ); +} + +static void editor_header_mode_sim_cb( void* ) { + editor_set_view_mode( EDITOR_VIEWMODE_SIM ); +} + +void editor_apply_view_mode( GAME_EDITOR* e ) { + if( !e || !e->gui.v2d || !e->gui.v3d ) + return; + + if( e->gui.view_mode == EDITOR_VIEWMODE_2D ) { + e->gui.v2d->enabled = 1; + e->gui.v3d->enabled = 0; + return; + } + + e->gui.v2d->enabled = 0; + e->gui.v3d->enabled = 1; +} + +U8 editor_toolbar_menu_open( const GUI_EDITOR_TOOLBAR* bar ) { + return bar && bar->open_root >= 0; +} + +static I32 editor_toolbar_find_root( GUI_EDITOR_TOOLBAR* bar, const char* text ) { + if( !bar || !text ) + return -1; + + for( I32 i = 0; i < (I32)bar->entries.size; ++i ) { + if( !strcmp( bar->entries[i].text, text ) ) + return i; + } + + return -1; +} + +void editor_toolbar_set_open( GUI_EDITOR_TOOLBAR* bar, U8 file_open, U8 edit_open ) { + if( !bar ) + return; + + bar->open_root = -1; + if( file_open ) + bar->open_root = editor_toolbar_find_root( bar, "file" ); + else if( edit_open ) + bar->open_root = editor_toolbar_find_root( bar, "edit" ); +} + +void editor_toolbar_close_menu() { + if( !editor ) + return; + + GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)editor->gui.header_toolbar; + editor_toolbar_set_open( bar, 0, 0 ); +} + +void editor_set_view_mode( I32 mode ) { + if( !editor ) + return; + + editor_toolbar_close_menu(); + editor->gui.view_mode = mode; + editor_apply_view_mode( editor ); + editor_layout_map_view( editor ); +} + +void editor_raise_header_toolbar( GAME_EDITOR* e ) { + if( !e || !e->map || !e->wnd || !e->gui.header_toolbar ) + return; + + GUI_BASE* bar = e->gui.header_toolbar; + GUI_BASE* parent = bar->parent; + if( !parent ) + return; + + I32 idx = parent->children.idx_of( bar ); + if( idx == -1 || idx == (I32)parent->children.size - 1 ) + return; + + parent->children.erase( idx ); + parent->children.push( bar ); +} + +static void editor_menubar_set_entry( EDITOR_MENUBAR_ENTRY* entry, const char* text, U8 type ) { + if( !entry ) + return; + + entry->entries.clear(); + snprintf( entry->text, sizeof( entry->text ), "%s", text ); + entry->type = type; +} + +static void editor_toolbar_init_entries( GUI_EDITOR_TOOLBAR* bar ) { + if( !bar ) + return; + + bar->entries.clear(); + bar->entries.resize( 4 ); + + editor_menubar_set_entry( &bar->entries[0], "file", EDITOR_MENUBAR_ENTRY_SUBMENU ); + bar->entries[0].entries.resize( 1 ); + editor_menubar_set_entry( &bar->entries[0].entries[0], "save", EDITOR_MENUBAR_ENTRY_FUNCTION ); + + editor_menubar_set_entry( &bar->entries[1], "edit", EDITOR_MENUBAR_ENTRY_SUBMENU ); + bar->entries[1].entries.resize( 2 ); + editor_menubar_set_entry( &bar->entries[1].entries[0], "undo", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_menubar_set_entry( &bar->entries[1].entries[1], "redo", EDITOR_MENUBAR_ENTRY_FUNCTION ); + + editor_menubar_set_entry( &bar->entries[2], "view", EDITOR_MENUBAR_ENTRY_SUBMENU ); + bar->entries[2].entries.resize( 3 ); + editor_menubar_set_entry( &bar->entries[2].entries[0], "2d view", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_menubar_set_entry( &bar->entries[2].entries[1], "3d view", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_menubar_set_entry( &bar->entries[2].entries[2], "simulation", EDITOR_MENUBAR_ENTRY_FUNCTION ); + + editor_menubar_set_entry( &bar->entries[3], "tools", EDITOR_MENUBAR_ENTRY_SUBMENU ); + bar->entries[3].entries.resize( 6 ); + editor_menubar_set_entry( &bar->entries[3].entries[0], "none", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_menubar_set_entry( &bar->entries[3].entries[1], "select", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_menubar_set_entry( &bar->entries[3].entries[2], "wall", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_menubar_set_entry( &bar->entries[3].entries[3], "poly", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_menubar_set_entry( &bar->entries[3].entries[4], "sprite", EDITOR_MENUBAR_ENTRY_FUNCTION ); + editor_menubar_set_entry( &bar->entries[3].entries[5], "ent", EDITOR_MENUBAR_ENTRY_FUNCTION ); +} + +static I32 editor_toolbar_root_width( EDITOR_MENUBAR_ENTRY* entry ) { + if( !entry ) + return 44; + + I32 text_w = 0; + gui_draw_get_str_bounds( &text_w, 0, FNT_JPN12, "%s", entry->text ); + return max( 44, text_w + 16 ); +} + +static I32 editor_toolbar_dropdown_width( EDITOR_MENUBAR_ENTRY* entry ) { + if( !entry || entry->type != EDITOR_MENUBAR_ENTRY_SUBMENU ) + return EDITOR_TOOLBAR_DROPDOWN_W; + + I32 width = EDITOR_TOOLBAR_DROPDOWN_W; + for( I32 i = 0; i < (I32)entry->entries.size; ++i ) { + I32 text_w = 0; + gui_draw_get_str_bounds( &text_w, 0, FNT_JPN12, "%s", entry->entries[i].text ); + width = max( width, text_w + 20 ); + } + + return width; +} + +static void editor_toolbar_root_rect( GUI_EDITOR_TOOLBAR* bar, I32 idx, I32* rx, I32* ry, I32* rw, I32* rh ) { + I32 x = gui_relx( bar ); + I32 y = gui_rely( bar ); + I32 cx = x + 8; + for( I32 i = 0; i < idx; ++i ) + cx += editor_toolbar_root_width( &bar->entries[i] ) + 4; + + I32 w = editor_toolbar_root_width( &bar->entries[idx] ); + *rx = cx; + *ry = y + 2; + *rw = w; + *rh = max( 1, bar->h - 4 ); +} + +static void editor_toolbar_sub_rect( GUI_EDITOR_TOOLBAR* bar, I32 root_idx, I32 row, I32* rx, I32* ry, I32* rw, I32* rh ) { + I32 root_x = 0, root_y = 0, root_w = 0, root_h = 0; + editor_toolbar_root_rect( bar, root_idx, &root_x, &root_y, &root_w, &root_h ); + I32 row_h = max( 18, root_h ); + + *rx = root_x; + *ry = gui_rely( bar ) + bar->h + row * row_h; + *rw = editor_toolbar_dropdown_width( &bar->entries[root_idx] ); + *rh = row_h; +} + +static U8 editor_toolbar_pt_in_rect( I32 mx, I32 my, I32 x, I32 y, I32 w, I32 h ) { + return mx >= x && mx < x + w && my >= y && my < y + h; +} + +struct EDITOR_MENUBAR_HIT { + I32 root{-1}; + I32 sub{-1}; +}; + +static EDITOR_MENUBAR_HIT editor_toolbar_hit_test( GUI_EDITOR_TOOLBAR* bar, I32 mx, I32 my ) { + EDITOR_MENUBAR_HIT hit{}; + for( I32 i = 0; i < (I32)bar->entries.size; ++i ) { + I32 x = 0, y = 0, w = 0, h = 0; + editor_toolbar_root_rect( bar, i, &x, &y, &w, &h ); + if( editor_toolbar_pt_in_rect( mx, my, x, y, w, h ) ) { + hit.root = i; + return hit; + } + } + + if( bar->open_root >= 0 && bar->open_root < (I32)bar->entries.size ) { + EDITOR_MENUBAR_ENTRY* root = &bar->entries[bar->open_root]; + if( root->type == EDITOR_MENUBAR_ENTRY_SUBMENU ) { + for( I32 i = 0; i < (I32)root->entries.size; ++i ) { + I32 x = 0, y = 0, w = 0, h = 0; + editor_toolbar_sub_rect( bar, bar->open_root, i, &x, &y, &w, &h ); + if( editor_toolbar_pt_in_rect( mx, my, x, y, w, h ) ) { + hit.root = bar->open_root; + hit.sub = i; + return hit; + } + } + } + } + + return hit; +} + +static U8 editor_toolbar_entry_enabled( const EDITOR_MENUBAR_ENTRY* root, const EDITOR_MENUBAR_ENTRY* entry ) { + if( !root || !entry ) + return 0; + + if( !strcmp( root->text, "edit" ) && !strcmp( entry->text, "undo" ) ) + return editor && editor->undo_actions.size > 0; + if( !strcmp( root->text, "edit" ) && !strcmp( entry->text, "redo" ) ) + return editor && editor->redo_actions.size > 0; + + return 1; +} + +static void editor_toolbar_invoke( const EDITOR_MENUBAR_ENTRY* root, const EDITOR_MENUBAR_ENTRY* entry ) { + if( !root || !entry || !editor ) + return; + if( !editor_toolbar_entry_enabled( root, entry ) ) + return; + + if( !strcmp( root->text, "file" ) && !strcmp( entry->text, "save" ) ) { + editor_save_map( editor ); + return; + } + if( !strcmp( root->text, "edit" ) && !strcmp( entry->text, "undo" ) ) { + editor_undo( editor ); + return; + } + if( !strcmp( root->text, "edit" ) && !strcmp( entry->text, "redo" ) ) { + editor_redo( editor ); + return; + } + if( !strcmp( root->text, "view" ) && !strcmp( entry->text, "2d view" ) ) { + editor_set_view_mode( EDITOR_VIEWMODE_2D ); + return; + } + if( !strcmp( root->text, "view" ) && !strcmp( entry->text, "3d view" ) ) { + editor_set_view_mode( EDITOR_VIEWMODE_3D ); + return; + } + if( !strcmp( root->text, "view" ) && !strcmp( entry->text, "simulation" ) ) { + editor_set_view_mode( EDITOR_VIEWMODE_SIM ); + return; + } + if( !strcmp( root->text, "tools" ) ) { + if( !strcmp( entry->text, "none" ) ) settool( EDITOR_TOOL_NONE ); + else if( !strcmp( entry->text, "select" ) ) settool( EDITOR_TOOL_SELECT ); + else if( !strcmp( entry->text, "wall" ) ) settool( EDITOR_TOOL_WALL ); + else if( !strcmp( entry->text, "poly" ) ) settool( EDITOR_TOOL_POLY ); + else if( !strcmp( entry->text, "sprite" ) ) settool( EDITOR_TOOL_SPRITE ); + else if( !strcmp( entry->text, "ent" ) ) settool( EDITOR_TOOL_ENT ); + } +} + +static void gui_editor_toolbar_draw_fn( void* ptr ) { + GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; + I32 x = gui_relx( bar ); + I32 y = gui_rely( bar ); + I32 mx = 0, my = 0; + if( editor_menu_hover_mask_active ) { + mx = editor_menu_hover_real_x; + my = editor_menu_hover_real_y; + } else { + gui_cursor_pos( &mx, &my ); + } + + U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); + EDITOR_MENUBAR_HIT hit = editor_toolbar_hit_test( bar, mx, my ); + CLR hover_fill = CLR::blend( ui_clr.border, ui_clr.bg, 0.70f ); + CLR active_fill = CLR::blend( ui_clr.bg_sec, ui_clr.border, 0.22f ); + + CLR border = gui_is_fg_window( bar ) ? ui_clr.border : ui_clr.border_inactive; + gui_draw_frect( x, y, bar->w, bar->h, ui_clr.bg_sec ); + + for( I32 i = 0; i < (I32)bar->entries.size; ++i ) { + I32 rx = 0, ry = 0, rw = 0, rh = 0; + editor_toolbar_root_rect( bar, i, &rx, &ry, &rw, &rh ); + U8 is_hover = hit.root == i && hit.sub == -1; + U8 is_active = bar->held && bar->held_root == i && bar->held_sub == -1 && m1; + U8 is_open = bar->open_root == i; + + CLR fill = ui_clr.bg_sec; + if( is_open || is_hover ) + fill = hover_fill; + if( is_active ) + fill = active_fill; + + if( is_open || is_active || is_hover ) + gui_draw_frect( rx, ry, rw, rh, fill ); + gui_draw_str( rx + 6, y + bar->h / 2 - 8, ALIGN_L, FNT_JPN12, ui_clr.txt, "%s", bar->entries[i].text ); + } + + if( bar->open_root < 0 || bar->open_root >= (I32)bar->entries.size ) + return; + + EDITOR_MENUBAR_ENTRY* root = &bar->entries[bar->open_root]; + if( root->type != EDITOR_MENUBAR_ENTRY_SUBMENU ) + return; + + if( !root->entries.size ) + return; + + I32 panel_x = 0, panel_y = 0, panel_w = 0, panel_h = 0; + editor_toolbar_sub_rect( bar, bar->open_root, 0, &panel_x, &panel_y, &panel_w, &panel_h ); + I32 row_h = panel_h; + gui_draw_frect( panel_x, panel_y, panel_w, row_h * root->entries.size, border ); + gui_draw_frect( panel_x + 1, panel_y + 1, max( 1, panel_w - 2 ), max( 1, row_h * (I32)root->entries.size - 2 ), ui_clr.bg_sec ); + + for( I32 i = 0; i < (I32)root->entries.size; ++i ) { + EDITOR_MENUBAR_ENTRY* entry = &root->entries[i]; + I32 rx = 0, ry = 0, rw = 0, rh = 0; + editor_toolbar_sub_rect( bar, bar->open_root, i, &rx, &ry, &rw, &rh ); + + U8 enabled = editor_toolbar_entry_enabled( root, entry ); + U8 is_hover = hit.root == bar->open_root && hit.sub == i; + U8 is_active = bar->held && bar->held_root == bar->open_root && bar->held_sub == i && m1; + + CLR fill = ui_clr.bg_sec; + if( enabled && is_active ) + fill = active_fill; + else if( is_hover ) + fill = hover_fill; + gui_draw_frect( rx + 1, ry + 1, max( 1, rw - 2 ), max( 1, rh - 2 ), fill ); + + CLR txt_clr = enabled ? ui_clr.txt : ui_clr.txt_inactive; + gui_draw_str( rx + 8, ry + rh / 2 - 8, ALIGN_L, FNT_JPN12, txt_clr, "%s", entry->text ); + } +} + +static void gui_editor_toolbar_input_fn( void* ptr ) { + GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; + I32 mx, my; + gui_cursor_pos( &mx, &my ); + U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); + EDITOR_MENUBAR_HIT hit = editor_toolbar_hit_test( bar, mx, my ); + + if( m1 ) { + if( !bar->held ) { + bar->held = 1; + bar->held_root = hit.root; + bar->held_sub = hit.sub; + if( hit.root == -1 && editor_toolbar_menu_open( bar ) ) + bar->open_root = -1; + } + return; + } + + if( bar->held && bar->held_root == hit.root && bar->held_sub == hit.sub ) { + if( hit.sub >= 0 ) { + EDITOR_MENUBAR_ENTRY* root = &bar->entries[hit.root]; + EDITOR_MENUBAR_ENTRY* sub = &root->entries[hit.sub]; + editor_toolbar_invoke( root, sub ); + bar->open_root = -1; + } else if( hit.root >= 0 ) { + EDITOR_MENUBAR_ENTRY* root = &bar->entries[hit.root]; + if( root->type == EDITOR_MENUBAR_ENTRY_SUBMENU ) { + if( bar->open_root == hit.root ) bar->open_root = -1; + else bar->open_root = hit.root; + } else { + editor_toolbar_invoke( root, root ); + bar->open_root = -1; + } + } + } + + bar->held = 0; + bar->held_root = -1; + bar->held_sub = -1; +} + +GUI_EDITOR_TOOLBAR* gui_editor_toolbar( I32 x, I32 y, I32 w, I32 h, const char* name ) { + if( !gui_check_target() ) + return 0; + + GUI_EDITOR_TOOLBAR* bar = new GUI_EDITOR_TOOLBAR; + bar->x = x; + bar->y = y; + bar->w = w; + bar->h = h; + bar->xbound = w; + bar->ybound = h + 120; + bar->draw_fn = gui_editor_toolbar_draw_fn; + bar->input_fn = gui_editor_toolbar_input_fn; + bar->held = 0; + bar->held_root = -1; + bar->held_sub = -1; + bar->open_root = -1; + strcpy( bar->name, name ); + editor_toolbar_init_entries( bar ); + + GUI_VIEW* parent = gui_get_view(); + bar->parent = parent; + parent->children.push( bar ); + return bar; +} + +void editor_create_header_controls( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + egui->header_toolbar = gui_editor_toolbar( 1, EDITOR_LAYOUT_MENU_Y, e->wnd->w - 3, EDITOR_LAYOUT_MENU_H, "editor toolbar" ); + egui->header_back = gui_button( 10, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ back ]", editor_header_back_cb ); + egui->header_viewtype_label = gui_label( 250, EDITOR_LAYOUT_NAV_Y + 4, "view type:" ); + egui->header_viewtype = gui_editor_viewtype_segment( 320, EDITOR_LAYOUT_NAV_Y, 186, 20, "viewtype segment" ); + egui->header_mode_2d = gui_button( 500, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ 2d view ]", editor_header_mode_2d_cb ); + egui->header_mode_3d = gui_button( 600, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ 3d view ]", editor_header_mode_3d_cb ); + egui->header_mode_sim = gui_button( 700, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ simulation ]", editor_header_mode_sim_cb ); +} diff --git a/src/editor/editor_viewtype_segment.cpp b/src/editor/editor_viewtype_segment.cpp new file mode 100644 index 0000000..7cd5c2d --- /dev/null +++ b/src/editor/editor_viewtype_segment.cpp @@ -0,0 +1,119 @@ +#include "editor_gui_internal.h" + +static void editor_header_viewtype_segment_widths( I32 w, I32* w0, I32* w1, I32* w2 ) { + I32 base = max( 1, w / 3 ); + I32 rem = max( 0, w - base * 3 ); + *w0 = base + ( rem > 0 ? 1 : 0 ); + *w1 = base + ( rem > 1 ? 1 : 0 ); + *w2 = max( 1, w - *w0 - *w1 ); +} + +static I32 editor_header_viewtype_segment_index( GUI_EDITOR_VIEWTYPE_SEGMENT* seg, I32 mx, I32 my ) { + I32 x = gui_relx( seg ); + I32 y = gui_rely( seg ); + if( mx < x || mx >= x + seg->w || my < y || my >= y + seg->h ) + return -1; + + I32 w0 = 0, w1 = 0, w2 = 0; + editor_header_viewtype_segment_widths( seg->w, &w0, &w1, &w2 ); + I32 rel = mx - x; + if( rel < w0 ) return 0; + if( rel < w0 + w1 ) return 1; + return 2; +} + +static void gui_editor_viewtype_segment_draw_fn( void* ptr ) { + GUI_EDITOR_VIEWTYPE_SEGMENT* seg = (GUI_EDITOR_VIEWTYPE_SEGMENT*)ptr; + I32 x = gui_relx( seg ); + I32 y = gui_rely( seg ); + I32 mx, my; + gui_cursor_pos( &mx, &my ); + I32 hover_seg = editor_header_viewtype_segment_index( seg, mx, my ); + I32 active_seg = editor->gui.view2d_type; + U8 down = gui_mbutton_down( GUI_MBTNLEFT ); + + CLR border = gui_is_fg_window( seg ) ? ui_clr.border : ui_clr.border_inactive; + I32 inner_x = x + 1; + I32 inner_y = y + 1; + I32 inner_w = max( 1, seg->w - 2 ); + I32 inner_h = max( 1, seg->h - 2 ); + gui_draw_frect( inner_x, inner_y, inner_w, inner_h, ui_clr.bg_sec ); + + I32 w0 = 0, w1 = 0, w2 = 0; + editor_header_viewtype_segment_widths( inner_w, &w0, &w1, &w2 ); + I32 segx[3] = { inner_x, inner_x + w0, inner_x + w0 + w1 }; + I32 segw[3] = { w0, w1, w2 }; + const char* txts[3] = { "x/y", "x/z", "y/z" }; + + for( I32 i = 0; i < 3; ++i ) { + U8 selected = i == active_seg; + U8 hover = hover_seg == i; + + CLR fill = ui_clr.bg_sec; + if( selected ) + fill = CLR::blend( ui_clr.bg_alt, ui_clr.border, 0.15f ); + else if( hover ) + fill = CLR::blend( ui_clr.bg_alt, ui_clr.bg_sec, 0.5f ); + + if( selected && down && hover ) + fill = CLR::blend( fill, ui_clr.bg_sec, 0.35f ); + + gui_draw_frect( segx[i], inner_y, max( 1, segw[i] ), inner_h, fill ); + + CLR txt = selected ? ui_clr.txt : CLR::blend( ui_clr.txt, ui_clr.bg_sec, 0.45f ); + gui_draw_str( segx[i] + segw[i] / 2, y + ( seg->h / 2 ) - 7, ALIGN_C, FNT_JPN12, txt, txts[i] ); + } + + I32 split1_x = inner_x + w0; + I32 split2_x = inner_x + w0 + w1; + gui_draw_line( split1_x, inner_y, split1_x, inner_y + inner_h - 1, border ); + gui_draw_line( split2_x, inner_y, split2_x, inner_y + inner_h - 1, border ); + gui_draw_rect( x, y, seg->w, seg->h, border ); +} + +static void gui_editor_viewtype_segment_input_fn( void* ptr ) { + GUI_EDITOR_VIEWTYPE_SEGMENT* seg = (GUI_EDITOR_VIEWTYPE_SEGMENT*)ptr; + I32 mx, my; + gui_cursor_pos( &mx, &my ); + U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); + I32 cur_seg = editor_header_viewtype_segment_index( seg, mx, my ); + + if( m1 ) { + if( !seg->held ) { + seg->held = 1; + seg->held_seg = cur_seg; + } + return; + } + + if( seg->held && seg->held_seg >= 0 && seg->held_seg == cur_seg ) { + editor->gui.view2d_type = seg->held_seg; + editor_layout_map_view( editor ); + } + + seg->held = 0; + seg->held_seg = -1; +} + +GUI_EDITOR_VIEWTYPE_SEGMENT* gui_editor_viewtype_segment( I32 x, I32 y, I32 w, I32 h, const char* name ) { + if( !gui_check_target() ) + return 0; + + GUI_EDITOR_VIEWTYPE_SEGMENT* seg = new GUI_EDITOR_VIEWTYPE_SEGMENT; + seg->x = x; + seg->y = y; + seg->w = w; + seg->h = h; + seg->xbound = w; + seg->ybound = h; + seg->draw_fn = gui_editor_viewtype_segment_draw_fn; + seg->input_fn = gui_editor_viewtype_segment_input_fn; + seg->held = 0; + seg->held_seg = -1; + strcpy( seg->name, name ); + + GUI_VIEW* parent = gui_get_view(); + seg->parent = parent; + parent->children.push( seg ); + return seg; +} diff --git a/src/editor/editor_window.cpp b/src/editor/editor_window.cpp new file mode 100644 index 0000000..51ca67d --- /dev/null +++ b/src/editor/editor_window.cpp @@ -0,0 +1,285 @@ +#include "editor_gui_internal.h" + +#include "../game.h" + +void gui_editorwindow_draw_fn( void* ptr ) { + GUI_EDITORWINDOW* wnd = (GUI_EDITORWINDOW*)ptr; + editor_raise_header_toolbar( editor ); + + GUI_BASE* toolbar = ( editor && editor->map ) ? editor->gui.header_toolbar : 0; + GUI_EDITOR_TOOLBAR* tbar = (GUI_EDITOR_TOOLBAR*)toolbar; + U8 menu_open = editor_toolbar_menu_open( tbar ); + + F32 saved_mx = input.mouse.pos.x; + F32 saved_my = input.mouse.pos.y; + if( menu_open ) { + editor_menu_hover_mask_active = 1; + editor_menu_hover_real_x = (I32)saved_mx; + editor_menu_hover_real_y = (I32)saved_my; + input.mouse.pos.x = -100000.f; + input.mouse.pos.y = -100000.f; + } else { + editor_menu_hover_mask_active = 0; + } + + CLR clr = gui_is_fg_window( wnd ) ? ui_clr.border : ui_clr.border_inactive; + gui_draw_frect( wnd->x, wnd->y, wnd->w, wnd->h, clr ); + gui_draw_frect( wnd->x + 1, wnd->y + 1, wnd->w - 2, wnd->h - 2, ui_clr.bg ); + + wnd->children.each( fn( GUI_BASE** ptr ) { + GUI_BASE* it = *ptr; + if( !it->enabled ) return; + if( it->draw_fn ) it->draw_fn( it ); + else dlog( "gui_editorwindow_draw_fn(): child %p has no draw_fn", it ); + } ); + + input.mouse.pos.x = saved_mx; + input.mouse.pos.y = saved_my; + editor_menu_hover_mask_active = 0; +} + +static void gui_editorwindow_input_fn( void* ptr ) { + GUI_EDITORWINDOW* wnd = (GUI_EDITORWINDOW*)ptr; + editor_raise_header_toolbar( editor ); + + GUI_BASE* toolbar = ( editor && editor->map ) ? editor->gui.header_toolbar : 0; + if( toolbar && toolbar->enabled && toolbar->input_fn ) + toolbar->input_fn( toolbar ); + + GUI_EDITOR_TOOLBAR* tbar = (GUI_EDITOR_TOOLBAR*)toolbar; + if( editor_toolbar_menu_open( tbar ) ) + return; + + wnd->children.each( fn( GUI_BASE** childptr ) { + GUI_BASE* child = *childptr; + if( !child || child == toolbar || !child->enabled || !child->input_fn ) + return; + child->input_fn( child ); + } ); +} + +GUI_EDITORWINDOW* gui_editorwindow_create( I32 w, I32 h ) { + GUI_EDITORWINDOW* wnd = new GUI_EDITORWINDOW; + wnd->x = 0; + wnd->y = 0; + wnd->xbound = wnd->w = w; + wnd->ybound = wnd->h = h; + wnd->locked = 1; + wnd->draw_fn = gui_editorwindow_draw_fn; + wnd->input_fn = gui_editorwindow_input_fn; + strcpy( wnd->name, "EDITORWINDOW" ); + + _gui.windows.push( wnd ); + gui_set_window( wnd ); + gui_set_view( 0 ); + gui_view( 1, 1, w - 2, h - 2 ); + return wnd; +} + +GUI_EDITORWINDOW* gui_editorwindow( I32 w, I32 h ) { + GUI_EDITORWINDOW* wnd = gui_editorwindow_create( w, h ); + GAME_EDITOR* e = editor; + LIST<GUI_LIST_ENTRY>* map_list = editor_get_map_list( e ); + gui_list( wnd->w / 2 - 100, EDITOR_LAYOUT_CONTENT_Y, 200, 200, "map list", map_list, &editor->gui.map_select ); + gui_button( wnd->w / 2 - 100, EDITOR_LAYOUT_CONTENT_Y + 220, 95, 25, "new map", editor_new_map_cb ); + gui_button( wnd->w / 2 + 5, EDITOR_LAYOUT_CONTENT_Y + 220, 95, 25, "load map", editor_load_map_cb ); + return wnd; +} + +void editor_update_properties_column( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + gui_editor_propview_update( egui->props ); +} + +void editor_create_properties_column( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + egui->props = gui_editor_propview( 10, EDITOR_LAYOUT_CONTENT_Y, 300, 460 ); + gui_editor_propview_select( egui->props, e->map, EDITOR_SELECT_ORIGIN ); +} + +void editor_create_auxiliary_panels( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + egui->assets = gui_editor_infobox( 10, EDITOR_LAYOUT_CONTENT_Y + 310, 300, 180, EDITOR_INFOBOX_ASSETS, "EDITOR_ASSETS_VIEW" ); + egui->status = gui_editor_infobox( 10, 568, 780, EDITOR_LAYOUT_STATUS_H, EDITOR_INFOBOX_STATUS, "EDITOR_STATUS_VIEW" ); +} + +void editor_update_toolview( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + gui_editor_toolview_update( egui->tool ); +} + +void settool( U8 t ) { + editor->tool.type = t; + if( editor->gui.v2d ) + editor->gui.v2d->poly_drag = 0; + if( editor->gui.tool ) + editor_update_toolview( editor ); +} + +const char* editor_tool_name() { + switch( editor->tool.type ) { + case EDITOR_TOOL_SELECT: return "select"; + case EDITOR_TOOL_WALL: return "wall"; + case EDITOR_TOOL_POLY: return "poly"; + case EDITOR_TOOL_SPRITE: return "sprite"; + case EDITOR_TOOL_ENT: return "ent"; + default: return "none"; + } +} + +static U8 EDITOR_TOOL_BUTTON_TYPES[] = { + EDITOR_TOOL_NONE, + EDITOR_TOOL_SELECT, + EDITOR_TOOL_WALL, + EDITOR_TOOL_POLY, + EDITOR_TOOL_SPRITE, + EDITOR_TOOL_ENT +}; + +static void settool_btn_cb( void* ptr ) { + GUI_BUTTON* btn = (GUI_BUTTON*)ptr; + if( !btn || !btn->extra ) + return; + + settool( *(U8*)btn->extra ); +} + +void editor_create_toolview_column( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + + I32 x = 320; + I32 y = EDITOR_LAYOUT_CONTENT_Y + EDITOR_LAYOUT_VIEW_DEFAULT_H + EDITOR_LAYOUT_VIEW_TOOL_GAP + EDITOR_LAYOUT_TOOL_BTN_TOP_GAP; + I32 off = 23; + const char* labels[] = { "none", "select", "wall", "poly", "sprite", "ent" }; + + for( U32 i = 0; i < sizeof( labels ) / sizeof( labels[0] ); ++i ) { + GUI_BUTTON* btn = gui_button( x, y, 45, 20, labels[i], settool_btn_cb ); + btn->extra = &EDITOR_TOOL_BUTTON_TYPES[i]; + y += off; + } + + egui->tool = gui_editor_toolview( 370, y - EDITOR_LAYOUT_TOOL_BTN_TOP_GAP, 300, 150 ); + gui_editor_toolview_update( egui->tool ); +} + +void editor_create_game_view_column( GAME_EDITOR* e ) { + GAME_EDITOR::EDITOR_GUI* egui = &e->gui; + I32 x = 320, y = EDITOR_LAYOUT_CONTENT_Y; + egui->v2d = gui_editor_2dview( x, y, 468, 370 ); + egui->v3d = gui_editor_3dview( x, y, 468, 370 ); + egui->v2d->enabled = 1; + egui->v3d->enabled = 0; +} + +void editor_create_map_view( GAME_EDITOR* e ) { + if( !e->map ) { + dlog( "editor_create_map_views() : no map loaded\n" ); + return; + } + + GUI_EDITORWINDOW* w = e->wnd; + w->children.each( fn( GUI_BASE** ptr ) { + gui_free( *ptr ); + } ); + w->children.clear(); + editor_clear_gui_state_refs( e ); + + e->gui.view2d_type = EDITOR_2DVIEW_TOP_DOWN; + e->gui.view_mode = EDITOR_VIEWMODE_2D; + + gui_set_window( w ); + gui_set_view( 0 ); + gui_view( 1, 1, w->w - 2, w->h - 2 ); + + editor_create_header_controls( e ); + editor_create_properties_column( e ); + editor_create_toolview_column( e ); + editor_create_game_view_column( e ); + editor_create_auxiliary_panels( e ); + editor_layout_map_view( e ); +} + +void editor_resize( GAME_EDITOR* e, I32 w, I32 h ) { + if( !e || !e->wnd ) + return; + + w = max( 1, w ); + h = max( 1, h ); + + GUI_EDITORWINDOW* wnd = e->wnd; + if( wnd->w == w && wnd->h == h ) + return; + + editor_set_bounds( wnd, 0, 0, w, h ); + editor_resize_base_view( wnd ); + + if( e->map ) editor_layout_map_view( e ); + else editor_layout_start_menu( e ); + + if( !e->gui.new_map_popup ) + return; + + GUI_WINDOW* popup = e->gui.new_map_popup; + if( popup->x > w - 5 ) popup->x = w - 5; + if( popup->x + popup->w < 5 ) popup->x = 5 - popup->w; + if( popup->y > h - 5 ) popup->y = h - 5; + if( popup->y + popup->h < 5 ) popup->y = 5 - popup->h; +} + +void close_new_map_popup( void* ) { + gui_push_callback( pfn( void* ) { + GUI_WINDOW* popup = editor->gui.new_map_popup; + if( !popup ) + return; + + gui_free( popup ); + editor->gui.new_map_popup = 0; + } ); +} + +void editor_new_map_cb( void* ptr ) { + if( editor->gui.new_map_popup ) + return; + + GUI_WINDOW* cwnd = gui_get_window(); + GUI_VIEW* view = gui_get_view(); + + I32 wx = 250; + I32 wy = 140; + I32 ww = 300; + I32 wh = 200; + + editor->gui.new_map_popup = gui_window( wx, wy, ww, wh ); + gui_title( "new map" ); + GUI_TEXTBOX* tb = gui_textbox( 10, 20, ww - 20, 20, "name", 32 ); + tb->active = 1; + + gui_button( ww - 50 - 70, wh - 20 - 10, 50, 20, "ok", pfn( void* ptr ) { + GUI_BUTTON* btn = (GUI_BUTTON*)ptr; + GUI_TEXTBOX* name = (GUI_TEXTBOX*)gui_find_node( btn->parent, "name" ); + if( !name ) + return; + + editor_new_map( editor, name->value ); + close_new_map_popup( 0 ); + } ); + + gui_button( ww - 50 - 10, wh - 20 - 10, 50, 20, "cancel", close_new_map_popup ); + gui_set_window( cwnd ); + gui_set_view( view ); +} + +void editor_load_map_cb( void* ptr ) { + GUI_LIST* list = (GUI_LIST*)gui_find_node( editor->wnd, "map list" ); + GUI_LIST_ENTRY* e = gui_list_get_selected( list ); + if( !e ) + return; + + char full_path[256]; + sprintf( full_path, "../assets/maps/%s", e->title ); + + if( editor->map ) + editor_close( editor ); + + editor_load_map( editor, full_path ); +} diff --git a/src/editor/gui.cpp b/src/editor/gui.cpp deleted file mode 100644 index 088421d..0000000 --- a/src/editor/gui.cpp +++ /dev/null @@ -1,1280 +0,0 @@ -#include "editor.h" -#include "../game/world/bsp.h" -#include "../game/assets.h" -#include "../game.h" -#include "../render/gl_2d.h" - -const I32 EDITOR_LAYOUT_MARGIN = 10; -const I32 EDITOR_LAYOUT_TITLE_OFFSET = 15; -const I32 EDITOR_LAYOUT_MENU_Y = 1; -const I32 EDITOR_LAYOUT_MENU_H = 22; -const I32 EDITOR_LAYOUT_NAV_Y = EDITOR_LAYOUT_MENU_Y + EDITOR_LAYOUT_MENU_H + 4; -const I32 EDITOR_LAYOUT_CONTENT_Y = EDITOR_LAYOUT_NAV_Y + 28; -const I32 EDITOR_LAYOUT_COLUMN_GAP = 10; -const I32 EDITOR_LAYOUT_VIEW_TOOL_GAP = 17; -const I32 EDITOR_LAYOUT_TOOL_BTN_TOP_GAP = 3; -const I32 EDITOR_LAYOUT_TOOL_PANEL_GAP = 5; -const I32 EDITOR_LAYOUT_LEFT_BOX_GAP = 10; -const I32 EDITOR_LAYOUT_STATUS_H = 22; -const I32 EDITOR_LAYOUT_STATUS_GAP = 6; -const I32 EDITOR_LAYOUT_TOOL_PANEL_W = 300; -const I32 EDITOR_LAYOUT_TOOL_PANEL_H = 150; -const I32 EDITOR_LAYOUT_PROPS_DEFAULT_W = 300; -const I32 EDITOR_LAYOUT_PROPS_DEFAULT_H = 300; -const I32 EDITOR_LAYOUT_VIEW_DEFAULT_H = 370; -const I32 EDITOR_LAYOUT_PROPS_MIN_W = 200; -const I32 EDITOR_LAYOUT_PROPS_MIN_H = 120; -const I32 EDITOR_LAYOUT_ASSETS_MIN_H = 120; -const I32 EDITOR_LAYOUT_VIEW_MIN_H = 140; -const I32 EDITOR_LAYOUT_RIGHT_MIN_W = 260; - -static void editor_layout_map_view( GAME_EDITOR* e ); -static U8 editor_menu_hover_mask_active = 0; -static I32 editor_menu_hover_real_x = 0; -static I32 editor_menu_hover_real_y = 0; - -static void editor_toolbar_set_open( GUI_EDITOR_TOOLBAR* bar, U8 file_open, U8 edit_open ); - -static void editor_toolbar_close_menu() { - GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)editor->gui.header_toolbar; - editor_toolbar_set_open( bar, 0, 0 ); -} - -static void editor_apply_view_mode( GAME_EDITOR* e ) { - if( !e || !e->gui.v2d || !e->gui.v3d ) - return; - - U8 mode = e->gui.view_mode; - if( mode == EDITOR_VIEWMODE_2D ) { - e->gui.v2d->enabled = 1; - e->gui.v3d->enabled = 0; - return; - } - - e->gui.v2d->enabled = 0; - e->gui.v3d->enabled = 1; -} - -static void editor_header_back_cb( void* ) { - editor_toolbar_close_menu(); - editor_close( editor ); -} - -static void editor_set_view_mode( I32 mode ) { - editor_toolbar_close_menu(); - editor->gui.view_mode = mode; - editor_apply_view_mode( editor ); - editor_layout_map_view( editor ); -} - -static void editor_header_mode_2d_cb( void* ) { - editor_set_view_mode( EDITOR_VIEWMODE_2D ); -} - -static void editor_header_mode_3d_cb( void* ) { - editor_set_view_mode( EDITOR_VIEWMODE_3D ); -} - -static void editor_header_mode_sim_cb( void* ) { - editor_set_view_mode( EDITOR_VIEWMODE_SIM ); -} - -static void editor_header_viewtype_segment_widths( I32 w, I32* w0, I32* w1, I32* w2 ) { - I32 base = max( 1, w / 3 ); - I32 rem = max( 0, w - base * 3 ); - *w0 = base + ( rem > 0 ? 1 : 0 ); - *w1 = base + ( rem > 1 ? 1 : 0 ); - *w2 = max( 1, w - *w0 - *w1 ); -} - -static I32 editor_header_viewtype_segment_index( GUI_EDITOR_VIEWTYPE_SEGMENT* seg, I32 mx, I32 my ) { - I32 x = gui_relx( seg ); - I32 y = gui_rely( seg ); - if( mx < x || mx >= x + seg->w || my < y || my >= y + seg->h ) - return -1; - - I32 w0 = 0, w1 = 0, w2 = 0; - editor_header_viewtype_segment_widths( seg->w, &w0, &w1, &w2 ); - I32 rel = mx - x; - if( rel < w0 ) return 0; - if( rel < w0 + w1 ) return 1; - return 2; -} - -static void gui_editor_viewtype_segment_draw_fn( void* ptr ) { - GUI_EDITOR_VIEWTYPE_SEGMENT* seg = (GUI_EDITOR_VIEWTYPE_SEGMENT*)ptr; - I32 x = gui_relx( seg ); - I32 y = gui_rely( seg ); - I32 mx, my; - gui_cursor_pos( &mx, &my ); - I32 hover_seg = editor_header_viewtype_segment_index( seg, mx, my ); - I32 active_seg = editor->gui.view2d_type; - U8 down = gui_mbutton_down( GUI_MBTNLEFT ); - - CLR border = gui_is_fg_window( seg ) ? ui_clr.border : ui_clr.border_inactive; - I32 inner_x = x + 1; - I32 inner_y = y + 1; - I32 inner_w = max( 1, seg->w - 2 ); - I32 inner_h = max( 1, seg->h - 2 ); - gui_draw_frect( inner_x, inner_y, inner_w, inner_h, ui_clr.bg_sec ); - - I32 w0 = 0, w1 = 0, w2 = 0; - editor_header_viewtype_segment_widths( inner_w, &w0, &w1, &w2 ); - I32 segx[3] = { inner_x, inner_x + w0, inner_x + w0 + w1 }; - I32 segw[3] = { w0, w1, w2 }; - const char* txts[3] = { "x/y", "x/z", "y/z" }; - - for( I32 i = 0; i < 3; ++i ) { - U8 selected = i == active_seg; - U8 hover = hover_seg == i; - - CLR fill = ui_clr.bg_sec; - if( selected ) - fill = CLR::blend( ui_clr.bg_alt, ui_clr.border, 0.15f ); - else if( hover ) - fill = CLR::blend( ui_clr.bg_alt, ui_clr.bg_sec, 0.5f ); - - if( selected && down && hover ) - fill = CLR::blend( fill, ui_clr.bg_sec, 0.35f ); - - gui_draw_frect( segx[i], inner_y, max( 1, segw[i] ), inner_h, fill ); - - CLR txt = selected ? ui_clr.txt : CLR::blend( ui_clr.txt, ui_clr.bg_sec, 0.45f ); - gui_draw_str( segx[i] + segw[i] / 2, y + ( seg->h / 2 ) - 7, ALIGN_C, FNT_JPN12, txt, txts[i] ); - } - - I32 split1_x = inner_x + w0; - I32 split2_x = inner_x + w0 + w1; - gui_draw_line( split1_x, inner_y, split1_x, inner_y + inner_h - 1, border ); - gui_draw_line( split2_x, inner_y, split2_x, inner_y + inner_h - 1, border ); - gui_draw_rect( x, y, seg->w, seg->h, border ); -} - -static void gui_editor_viewtype_segment_input_fn( void* ptr ) { - GUI_EDITOR_VIEWTYPE_SEGMENT* seg = (GUI_EDITOR_VIEWTYPE_SEGMENT*)ptr; - I32 mx, my; - gui_cursor_pos( &mx, &my ); - U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); - I32 cur_seg = editor_header_viewtype_segment_index( seg, mx, my ); - - if( m1 ) { - if( !seg->held ) { - seg->held = 1; - seg->held_seg = cur_seg; - } - return; - } - - if( seg->held && seg->held_seg >= 0 && seg->held_seg == cur_seg ) { - editor->gui.view2d_type = seg->held_seg; - editor_layout_map_view( editor ); - } - - seg->held = 0; - seg->held_seg = -1; -} - -static GUI_EDITOR_VIEWTYPE_SEGMENT* gui_editor_viewtype_segment( I32 x, I32 y, I32 w, I32 h, const char* name ) { - if( !gui_check_target() ) - return 0; - - GUI_EDITOR_VIEWTYPE_SEGMENT* seg = new GUI_EDITOR_VIEWTYPE_SEGMENT; - seg->x = x; - seg->y = y; - seg->w = w; - seg->h = h; - seg->xbound = w; - seg->ybound = h; - seg->draw_fn = gui_editor_viewtype_segment_draw_fn; - seg->input_fn = gui_editor_viewtype_segment_input_fn; - seg->held = 0; - seg->held_seg = -1; - strcpy( seg->name, name ); - - GUI_VIEW* parent = gui_get_view(); - seg->parent = parent; - parent->children.push( seg ); - return seg; -} - -const I32 EDITOR_TOOLBAR_DROPDOWN_W = 74; - -static U8 editor_toolbar_pt_in_rect( I32 mx, I32 my, I32 x, I32 y, I32 w, I32 h ) { - return mx >= x && mx < x + w && my >= y && my < y + h; -} - -static void editor_toolbar_set_open( GUI_EDITOR_TOOLBAR* bar, U8 file_open, U8 edit_open ) { - if( !bar ) - return; - - bar->file_open = file_open; - bar->edit_open = edit_open; -} - -static void editor_toolbar_item_rect( GUI_EDITOR_TOOLBAR* bar, I32 idx, I32* rx, I32* ry, I32* rw, I32* rh ) { - static const I32 widths[4] = { 44, 44, 44, 52 }; - I32 x = gui_relx( bar ); - I32 y = gui_rely( bar ); - I32 cx = x + 8; - for( I32 i = 0; i < idx; ++i ) - cx += widths[i] + 4; - - *rx = cx; - *ry = y + 2; - *rw = widths[idx]; - *rh = max( 1, bar->h - 4 ); -} - -static void editor_toolbar_dropdown_row_rect( GUI_EDITOR_TOOLBAR* bar, I32 anchor_idx, I32 row, I32* rx, I32* ry, I32* rw, I32* rh ) { - I32 x = 0, y = 0, w = 0, h = 0; - editor_toolbar_item_rect( bar, anchor_idx, &x, &y, &w, &h ); - *rx = x; - *rh = max( 18, h ); - *ry = gui_rely( bar ) + bar->h + row * *rh; - *rw = EDITOR_TOOLBAR_DROPDOWN_W; -} - -static I32 editor_toolbar_hit_test( GUI_EDITOR_TOOLBAR* bar, I32 mx, I32 my ) { - for( I32 i = 0; i < 4; ++i ) { - I32 x = 0, y = 0, w = 0, h = 0; - editor_toolbar_item_rect( bar, i, &x, &y, &w, &h ); - if( editor_toolbar_pt_in_rect( mx, my, x, y, w, h ) ) - return i; - } - - if( bar->file_open ) { - I32 x = 0, y = 0, w = 0, h = 0; - editor_toolbar_dropdown_row_rect( bar, EDITOR_TOOLBAR_HIT_FILE, 0, &x, &y, &w, &h ); - if( editor_toolbar_pt_in_rect( mx, my, x, y, w, h ) ) - return EDITOR_TOOLBAR_HIT_SAVE; - } - - if( bar->edit_open ) { - for( I32 i = 0; i < 2; ++i ) { - I32 x = 0, y = 0, w = 0, h = 0; - editor_toolbar_dropdown_row_rect( bar, EDITOR_TOOLBAR_HIT_EDIT, i, &x, &y, &w, &h ); - if( editor_toolbar_pt_in_rect( mx, my, x, y, w, h ) ) - return i == 0 ? EDITOR_TOOLBAR_HIT_UNDO : EDITOR_TOOLBAR_HIT_REDO; - } - } - - return EDITOR_TOOLBAR_HIT_NONE; -} - -static void gui_editor_toolbar_draw_fn( void* ptr ) { - GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; - I32 x = gui_relx( bar ); - I32 y = gui_rely( bar ); - I32 mx, my; - if( editor_menu_hover_mask_active ) { - mx = editor_menu_hover_real_x; - my = editor_menu_hover_real_y; - } else { - gui_cursor_pos( &mx, &my ); - } - U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); - I32 hover = editor_toolbar_hit_test( bar, mx, my ); - CLR hover_fill = CLR::blend( ui_clr.border, ui_clr.bg, 0.70f ); - CLR active_fill = CLR::blend( ui_clr.bg_sec, ui_clr.border, 0.22f ); - - CLR border = gui_is_fg_window( bar ) ? ui_clr.border : ui_clr.border_inactive; - gui_draw_frect( x, y, bar->w, bar->h, ui_clr.bg_sec ); - - static const char* labels[4] = { "file", "edit", "view", "tools" }; - for( I32 i = 0; i < 4; ++i ) { - I32 rx = 0, ry = 0, rw = 0, rh = 0; - editor_toolbar_item_rect( bar, i, &rx, &ry, &rw, &rh ); - U8 is_hover = hover == i; - U8 is_active = bar->held && bar->held_item == i && m1; - U8 is_open = ( bar->file_open && i == EDITOR_TOOLBAR_HIT_FILE ) - || ( bar->edit_open && i == EDITOR_TOOLBAR_HIT_EDIT ); - - CLR fill = ui_clr.bg_sec; - if( is_open ) - fill = hover_fill; - else if( is_active ) - fill = active_fill; - else if( is_hover ) - fill = hover_fill; - - if( is_open || is_active || is_hover ) - gui_draw_frect( rx, ry, rw, rh, fill ); - gui_draw_str( rx + 6, y + bar->h / 2 - 8, ALIGN_L, FNT_JPN12, ui_clr.txt, labels[i] ); - } - - if( bar->file_open ) { - I32 rx = 0, ry = 0, rw = 0, rh = 0; - editor_toolbar_dropdown_row_rect( bar, EDITOR_TOOLBAR_HIT_FILE, 0, &rx, &ry, &rw, &rh ); - U8 is_hover = hover == EDITOR_TOOLBAR_HIT_SAVE; - U8 is_active = bar->held && bar->held_item == EDITOR_TOOLBAR_HIT_SAVE && m1; - - gui_draw_frect( rx, ry, rw, rh, border ); - CLR fill = ui_clr.bg_sec; - if( is_active ) - fill = active_fill; - else if( is_hover ) - fill = hover_fill; - - gui_draw_frect( rx + 1, ry + 1, max( 1, rw - 2 ), max( 1, rh - 2 ), fill ); - gui_draw_str( rx + 8, ry + rh / 2 - 8, ALIGN_L, FNT_JPN12, ui_clr.txt, "save" ); - } - - if( bar->edit_open ) { - const U8 enabled[2] = { editor->undo_actions.size > 0, editor->redo_actions.size > 0 }; - const char* labels[2] = { "undo", "redo" }; - const I32 hit_id[2] = { EDITOR_TOOLBAR_HIT_UNDO, EDITOR_TOOLBAR_HIT_REDO }; - - I32 panel_x = 0, panel_y = 0, panel_w = 0, panel_h = 0; - editor_toolbar_dropdown_row_rect( bar, EDITOR_TOOLBAR_HIT_EDIT, 0, &panel_x, &panel_y, &panel_w, &panel_h ); - I32 row_h = panel_h; - gui_draw_frect( panel_x, panel_y, panel_w, row_h * 2, border ); - gui_draw_frect( panel_x + 1, panel_y + 1, max( 1, panel_w - 2 ), max( 1, row_h * 2 - 2 ), ui_clr.bg_sec ); - - for( I32 i = 0; i < 2; ++i ) { - I32 rx = 0, ry = 0, rw = 0, rh = 0; - editor_toolbar_dropdown_row_rect( bar, EDITOR_TOOLBAR_HIT_EDIT, i, &rx, &ry, &rw, &rh ); - U8 is_hover = hover == hit_id[i]; - U8 is_active = bar->held && bar->held_item == hit_id[i] && m1; - - CLR fill = ui_clr.bg_sec; - if( enabled[i] && is_active ) - fill = active_fill; - else if( is_hover ) - fill = hover_fill; - gui_draw_frect( rx + 1, ry + 1, max( 1, rw - 2 ), max( 1, rh - 2 ), fill ); - - CLR txt_clr = enabled[i] ? ui_clr.txt : ui_clr.txt_inactive; - gui_draw_str( rx + 8, ry + rh / 2 - 8, ALIGN_L, FNT_JPN12, txt_clr, labels[i] ); - } - } -} - -static void gui_editor_toolbar_input_fn( void* ptr ) { - GUI_EDITOR_TOOLBAR* bar = (GUI_EDITOR_TOOLBAR*)ptr; - I32 mx, my; - gui_cursor_pos( &mx, &my ); - U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); - I32 hit = editor_toolbar_hit_test( bar, mx, my ); - - if( m1 ) { - if( !bar->held ) { - bar->held = 1; - bar->held_item = hit; - if( hit == EDITOR_TOOLBAR_HIT_NONE && ( bar->file_open || bar->edit_open ) ) - editor_toolbar_set_open( bar, 0, 0 ); - } - return; - } - - if( bar->held && bar->held_item == hit ) { - switch( hit ) { - case EDITOR_TOOLBAR_HIT_FILE: - editor_toolbar_set_open( bar, !bar->file_open, 0 ); - break; - case EDITOR_TOOLBAR_HIT_EDIT: - editor_toolbar_set_open( bar, 0, !bar->edit_open ); - break; - case EDITOR_TOOLBAR_HIT_SAVE: - editor_toolbar_set_open( bar, 0, 0 ); - editor_save_map( editor ); - break; - case EDITOR_TOOLBAR_HIT_UNDO: - editor_toolbar_set_open( bar, 0, 0 ); - editor_undo( editor ); - break; - case EDITOR_TOOLBAR_HIT_REDO: - editor_toolbar_set_open( bar, 0, 0 ); - editor_redo( editor ); - break; - case EDITOR_TOOLBAR_HIT_VIEW: - case EDITOR_TOOLBAR_HIT_TOOLS: - editor_toolbar_set_open( bar, 0, 0 ); - break; - default: - break; - } - } - - bar->held = 0; - bar->held_item = EDITOR_TOOLBAR_HIT_NONE; -} - -static GUI_EDITOR_TOOLBAR* gui_editor_toolbar( I32 x, I32 y, I32 w, I32 h, const char* name ) { - if( !gui_check_target() ) - return 0; - - GUI_EDITOR_TOOLBAR* bar = new GUI_EDITOR_TOOLBAR; - bar->x = x; - bar->y = y; - bar->w = w; - bar->h = h; - bar->xbound = w; - bar->ybound = h + 52; - bar->draw_fn = gui_editor_toolbar_draw_fn; - bar->input_fn = gui_editor_toolbar_input_fn; - bar->held = 0; - bar->held_item = EDITOR_TOOLBAR_HIT_NONE; - bar->file_open = 0; - bar->edit_open = 0; - strcpy( bar->name, name ); - - GUI_VIEW* parent = gui_get_view(); - bar->parent = parent; - parent->children.push( bar ); - return bar; -} - -static void editor_raise_header_toolbar( GAME_EDITOR* e ) { - if( !e || !e->map || !e->wnd || !e->gui.header_toolbar ) - return; - - GUI_BASE* bar = e->gui.header_toolbar; - GUI_BASE* parent = bar->parent; - if( !parent ) - return; - - I32 idx = parent->children.idx_of( bar ); - if( idx == -1 || idx == (I32)parent->children.size - 1 ) - return; - - parent->children.erase( idx ); - parent->children.push( bar ); -} - -static void editor_set_bounds( GUI_BASE* node, I32 x, I32 y, I32 w, I32 h ) { - if( !node ) - return; - - I32 x_extra = node->xbound - node->w; - I32 y_extra = node->ybound - node->h; - if( x_extra < 0 ) x_extra = 0; - if( y_extra < 0 ) y_extra = 0; - - node->x = x; - node->y = y; - node->w = max( 1, w ); - node->h = max( 1, h ); - node->xbound = node->w + x_extra; - node->ybound = node->h + y_extra; -} - -static void editor_create_header_controls( GAME_EDITOR* e ) { - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - - egui->header_toolbar = gui_editor_toolbar( 1, EDITOR_LAYOUT_MENU_Y, e->wnd->w - 3, EDITOR_LAYOUT_MENU_H, "editor toolbar" ); - - egui->header_back = gui_button( 10, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ back ]", editor_header_back_cb ); - - egui->header_viewtype_label = gui_label( 250, EDITOR_LAYOUT_NAV_Y + 4, "view type:" ); - egui->header_viewtype = gui_editor_viewtype_segment( 320, EDITOR_LAYOUT_NAV_Y, 186, 20, "viewtype segment" ); - - egui->header_mode_2d = gui_button( 500, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ 2d view ]", editor_header_mode_2d_cb ); - egui->header_mode_3d = gui_button( 600, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ 3d view ]", editor_header_mode_3d_cb ); - egui->header_mode_sim = gui_button( 700, EDITOR_LAYOUT_NAV_Y, 92, 20, "[ simulation ]", editor_header_mode_sim_cb ); -} - -static I32 editor_layout_props_w_max( GUI_EDITORWINDOW* wnd ) { - I32 max_w = wnd->w - ( EDITOR_LAYOUT_MARGIN * 2 ) - EDITOR_LAYOUT_COLUMN_GAP - EDITOR_LAYOUT_RIGHT_MIN_W; - return max( EDITOR_LAYOUT_PROPS_MIN_W, max_w ); -} - -static I32 editor_layout_content_bottom( GUI_EDITORWINDOW* wnd ) { - return wnd->h - EDITOR_LAYOUT_MARGIN - EDITOR_LAYOUT_STATUS_H - EDITOR_LAYOUT_STATUS_GAP; -} - -static I32 editor_layout_left_available_h( GUI_EDITORWINDOW* wnd ) { - return max( 1, editor_layout_content_bottom( wnd ) - EDITOR_LAYOUT_CONTENT_Y ); -} - -static I32 editor_layout_view_h_max( GUI_EDITORWINDOW* wnd ) { - I32 max_h = editor_layout_content_bottom( wnd ) - - EDITOR_LAYOUT_CONTENT_Y - - EDITOR_LAYOUT_VIEW_TOOL_GAP - - EDITOR_LAYOUT_TOOL_PANEL_H - - ( EDITOR_LAYOUT_TITLE_OFFSET * 2 ); - return max( EDITOR_LAYOUT_VIEW_MIN_H, max_h ); -} - -static void editor_layout_clamp_custom_sizes( GAME_EDITOR* e ) { - if( !e || !e->wnd ) - return; - - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - if( egui->props_w <= 0 ) - egui->props_w = EDITOR_LAYOUT_PROPS_DEFAULT_W; - if( egui->props_h <= 0 ) - egui->props_h = EDITOR_LAYOUT_PROPS_DEFAULT_H; - if( egui->view_h <= 0 ) - egui->view_h = EDITOR_LAYOUT_VIEW_DEFAULT_H; - - egui->props_w = min( max( egui->props_w, EDITOR_LAYOUT_PROPS_MIN_W ), editor_layout_props_w_max( e->wnd ) ); - I32 left_avail_h = editor_layout_left_available_h( e->wnd ); - I32 max_props_h = left_avail_h - - EDITOR_LAYOUT_LEFT_BOX_GAP - - EDITOR_LAYOUT_ASSETS_MIN_H - - ( EDITOR_LAYOUT_TITLE_OFFSET * 2 ); - max_props_h = max( EDITOR_LAYOUT_PROPS_MIN_H, max_props_h ); - egui->props_h = min( max( egui->props_h, EDITOR_LAYOUT_PROPS_MIN_H ), max_props_h ); - - I32 view_max = editor_layout_view_h_max( e->wnd ); - egui->view_h = view_max; -} - -static const char* editor_tool_name() { - switch( editor->tool.type ) { - case EDITOR_TOOL_SELECT: return "select"; - case EDITOR_TOOL_WALL: return "wall"; - case EDITOR_TOOL_POLY: return "poly"; - case EDITOR_TOOL_SPRITE: return "sprite"; - case EDITOR_TOOL_ENT: return "ent"; - default: return "none"; - } -} - -const I32 EDITOR_ASSETS_ROW_H = 28; -const I32 EDITOR_ASSETS_THUMB = 20; -const I32 EDITOR_ASSETS_INNER_PAD_X = 8; -const I32 EDITOR_ASSETS_INNER_PAD_Y = 6; -const I32 EDITOR_ASSETS_SCROLLBAR_W = 7; -const I32 EDITOR_ASSETS_SCROLLBAR_GAP = 4; -const I32 EDITOR_ASSETS_SCROLL_STEP = 20; - -struct EDITOR_ASSETS_LAYOUT { - I32 inner_x{}; - I32 inner_y{}; - I32 inner_w{}; - I32 list_h{}; - I32 row_x{}; - I32 row_w{}; - I32 count{}; - I32 content_h{}; - I32 max_scroll{}; - U8 show_scroll{}; - I32 track_x{}; - I32 track_y{}; - I32 track_h{}; -}; - -static EDITOR_ASSETS_LAYOUT editor_assets_layout( GUI_EDITOR_INFOBOX* box, I32 panel_x, I32 panel_y, I32 prop_count ) { - EDITOR_ASSETS_LAYOUT l{}; - l.inner_x = panel_x + EDITOR_ASSETS_INNER_PAD_X; - l.inner_y = panel_y + EDITOR_ASSETS_INNER_PAD_Y; - l.inner_w = max( 1, box->w - ( EDITOR_ASSETS_INNER_PAD_X * 2 ) ); - l.list_h = max( 1, box->h - ( EDITOR_ASSETS_INNER_PAD_Y * 2 ) ); - l.count = prop_count + 1; - l.content_h = l.count * EDITOR_ASSETS_ROW_H; - l.max_scroll = max( 0, l.content_h - l.list_h ); - l.show_scroll = l.content_h > l.list_h; - l.row_x = l.inner_x + 1; - l.row_w = l.inner_w - 2; - if( l.show_scroll ) - l.row_w -= EDITOR_ASSETS_SCROLLBAR_W + EDITOR_ASSETS_SCROLLBAR_GAP; - l.row_w = max( 1, l.row_w ); - l.track_x = l.inner_x + l.inner_w - EDITOR_ASSETS_SCROLLBAR_W - 1 - ( EDITOR_ASSETS_SCROLLBAR_GAP / 2 ); - l.track_y = l.inner_y; - l.track_h = l.list_h - 2; - return l; -} - -static void editor_assets_clamp_scroll( const EDITOR_ASSETS_LAYOUT& l ) { - editor->gui.assets_scroll = min( max( 0, editor->gui.assets_scroll ), l.max_scroll ); -} - -static void gui_editor_infobox_draw_assets( GUI_EDITOR_INFOBOX* box, I32 panel_x, I32 panel_y ) { - if( !editor->map ) - return; - - WORLD_MAP* map = editor->map; - EDITOR_ASSETS_LAYOUT l = editor_assets_layout( box, panel_x, panel_y, (I32)map->props.size ); - editor_assets_clamp_scroll( l ); - I32 yoff = -editor->gui.assets_scroll; - - for( I32 idx = 0; idx < l.count; ++idx ) { - I32 row_y = l.inner_y + idx * EDITOR_ASSETS_ROW_H + yoff; - if( row_y + EDITOR_ASSETS_ROW_H - 2 <= l.inner_y || row_y >= l.inner_y + l.list_h ) - continue; - - U8 map_entry = idx == 0; - SURF_PROPS* p = map_entry ? 0 : &map->props[idx - 1]; - U8 selected = 0; - if( editor->gui.props ) { - if( map_entry ) { - selected = editor->gui.props->seltype == EDITOR_SELECT_ORIGIN - && editor->gui.props->curselect == editor->map; - } else { - selected = editor->gui.props->seltype == EDITOR_SELECT_SURFPROPS - && editor->gui.props->curselect == p; - } - } - - CLR rowbg = idx % 2 ? ui_clr.bg : ui_clr.bg_alt; - if( selected ) - rowbg = CLR::blend( ui_clr.border, ui_clr.bg, 0.70f ); - - gui_draw_frect( l.row_x, row_y, l.row_w, EDITOR_ASSETS_ROW_H - 2, rowbg ); - - I32 tx = l.row_x + 3; - I32 ty = row_y + 3; - gui_draw_frect( tx, ty, EDITOR_ASSETS_THUMB, EDITOR_ASSETS_THUMB, ui_clr.border ); - if( map_entry ) { - gui_draw_frect( tx + 1, ty + 1, EDITOR_ASSETS_THUMB - 2, EDITOR_ASSETS_THUMB - 2, ui_clr.bg_alt ); - gui_draw_str( tx + EDITOR_ASSETS_THUMB / 2, ty + 4, ALIGN_C, FNT_JPN12, ui_clr.txt, "m" ); - } else if( p->tex ) { - gl_2d_textured_frect( _gui.gl2d_font, { (F32)(tx + 1), (F32)(ty + 1) }, { (F32)(EDITOR_ASSETS_THUMB - 2), (F32)(EDITOR_ASSETS_THUMB - 2) }, p->tex ); - } else { - gui_draw_frect( tx + 1, ty + 1, EDITOR_ASSETS_THUMB - 2, EDITOR_ASSETS_THUMB - 2, p->clr ); - } - - I32 text_x = tx + EDITOR_ASSETS_THUMB + 8; - CLR txt = ui_clr.txt; - if( map_entry ) { - gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[map] -> %s", map->name ); - } else if( p->tex ) { - gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[%d] -> %s", idx - 1, p->tex->name ); - } else { - gui_draw_str( text_x, row_y + 7, ALIGN_L, FNT_JPN12, txt, "[%d] -> %.2f, %.2f, %.2f", idx - 1, p->clr.r, p->clr.g, p->clr.b ); - } - - } - - if( l.show_scroll ) { - gui_draw_frect( l.track_x, l.track_y, EDITOR_ASSETS_SCROLLBAR_W, l.track_h, ui_clr.bg_alt ); - gui_draw_rect( l.track_x, l.track_y, EDITOR_ASSETS_SCROLLBAR_W, l.track_h, ui_clr.border ); - - I32 thumb_h = max( 18, ( l.track_h * l.list_h ) / max( 1, l.content_h ) ); - thumb_h = min( thumb_h, l.track_h ); - I32 travel = max( 1, l.track_h - thumb_h ); - I32 thumb_y = l.track_y + ( travel * editor->gui.assets_scroll ) / max( 1, l.max_scroll ); - gui_draw_frect( l.track_x, thumb_y + 1, EDITOR_ASSETS_SCROLLBAR_W, max( 1, thumb_h - 1 ), ui_clr.txt ); - } -} - -static void gui_editor_infobox_draw_fn( void* ptr ) { - GUI_EDITOR_INFOBOX* box = (GUI_EDITOR_INFOBOX*)ptr; - - I32 x = gui_relx( box ); - I32 y = gui_rely( box ); - I32 w = box->w; - I32 h = box->h; - - if( box->type == EDITOR_INFOBOX_STATUS ) { - CLR col = gui_is_fg_window( box )? ui_clr.border : ui_clr.border_inactive; - gui_draw_frect( x, y, w, h, col ); - gui_draw_frect( x + 1, y + 1, w - 2, h - 2, ui_clr.bg_sec ); - gui_draw_str( - x + 6, - y + 4, - ALIGN_L, - FNT_JPN12, - ui_clr.txt, - "selected tool: %s. click in viewport to create/edit.", - editor_tool_name() - ); - - if( editor->game && editor->game->gl ) { - GL_DATA* gl = editor->game->gl; - gui_draw_str( - x + w - 6, - y + 4, - ALIGN_R, - FNT_JPN12, - ui_clr.txt, - "fps: %.3f (%.5f ms) %dx%d", - gl->fps, - gl->frametime, - gl->canvas_size[0], - gl->canvas_size[1] - ); - } - return; - } - - gui_draw_str( x, y, ALIGN_L, FNT_JPN12, ui_clr.txt, "assets" ); - y += EDITOR_LAYOUT_TITLE_OFFSET; - - CLR col = gui_is_fg_window( box )? ui_clr.border : ui_clr.border_inactive; - gui_draw_frect( x, y, w, h, col ); - gui_draw_frect( x + 1, y + 1, w - 2, h - 2, ui_clr.bg_sec ); - - gui_draw_push_clip( x + 2, y + 2, w - 4, h - 4 ); - gui_editor_infobox_draw_assets( box, x, y ); - gui_draw_pop_clip(); -} - -static void gui_editor_infobox_input_fn( void* ptr ) { - GUI_EDITOR_INFOBOX* box = (GUI_EDITOR_INFOBOX*)ptr; - static U8 assets_click_held = 0; - if( box->type == EDITOR_INFOBOX_ASSETS ) { - I32 x = gui_relx( box ); - I32 y = gui_rely( box ) + EDITOR_LAYOUT_TITLE_OFFSET; - I32 w = box->w; - I32 h = box->h; - I32 prop_count = editor->map ? (I32)editor->map->props.size : 0; - EDITOR_ASSETS_LAYOUT l = editor_assets_layout( box, x, y, prop_count ); - editor_assets_clamp_scroll( l ); - I32 mx, my; - gui_cursor_pos( &mx, &my ); - U8 inbounds = mx >= x && mx <= x + w && my >= y && my <= y + h; - if( inbounds ) { - U8 scroll = gui_mbutton_down( GUI_MBTNSCROLL ); - if( scroll ) { - gui_capture_scroll(); - if( scroll == 1 ) - editor->gui.assets_scroll -= EDITOR_ASSETS_SCROLL_STEP; - else if( scroll == (U8)-1 ) - editor->gui.assets_scroll += EDITOR_ASSETS_SCROLL_STEP; - - editor_assets_clamp_scroll( l ); - } - - U8 m1 = gui_mbutton_down( GUI_MBTNLEFT ); - if( m1 && !assets_click_held && editor->map ) { - if( mx >= l.row_x && mx < l.row_x + l.row_w ) { - I32 idx = ( my - l.inner_y + editor->gui.assets_scroll ) / EDITOR_ASSETS_ROW_H; - if( idx >= 0 && idx < l.count && editor->gui.props ) { - if( idx == 0 ) - gui_editor_propview_select( editor->gui.props, editor->map, EDITOR_SELECT_ORIGIN ); - else - gui_editor_propview_select( editor->gui.props, &editor->map->props[idx - 1], EDITOR_SELECT_SURFPROPS ); - } - } - } - assets_click_held = m1; - } - if( !gui_mbutton_down( GUI_MBTNLEFT ) ) - assets_click_held = 0; - } - - gui_base_input_fn( box ); -} - -static GUI_EDITOR_INFOBOX* gui_editor_infobox( I32 x, I32 y, I32 w, I32 h, U8 type, const char* name ) { - if( !gui_check_target() ) - return 0; - - GUI_EDITOR_INFOBOX* box = new GUI_EDITOR_INFOBOX; - box->x = x; - box->y = y; - box->w = w; - box->h = h; - box->xbound = w; - box->ybound = h + ( type == EDITOR_INFOBOX_STATUS ? 0 : EDITOR_LAYOUT_TITLE_OFFSET ); - box->draw_fn = gui_editor_infobox_draw_fn; - box->input_fn = gui_editor_infobox_input_fn; - box->type = type; - strcpy( box->name, name ); - - GUI_VIEW* parent = gui_get_view(); - box->parent = parent; - parent->children.push( box ); - return box; -} - -static EDITOR_LAYOUT editor_calc_layout( GAME_EDITOR* e ) { - GUI_EDITORWINDOW* wnd = e->wnd; - editor_layout_clamp_custom_sizes( e ); - - EDITOR_LAYOUT l{}; - l.left_x = EDITOR_LAYOUT_MARGIN; - l.left_w = e->gui.props_w; - l.right_x = l.left_x + l.left_w + EDITOR_LAYOUT_COLUMN_GAP; - l.right_w = max( 1, wnd->w - EDITOR_LAYOUT_MARGIN - l.right_x ); - l.tool_btn_x = l.right_x; - l.tool_btn_w = 45; - l.tool_panel_x = l.tool_btn_x + l.tool_btn_w + EDITOR_LAYOUT_TOOL_PANEL_GAP; - l.tool_panel_w = EDITOR_LAYOUT_TOOL_PANEL_W; - - l.top_y = EDITOR_LAYOUT_NAV_Y; - l.props_y = EDITOR_LAYOUT_CONTENT_Y; - l.view_y = EDITOR_LAYOUT_CONTENT_Y; - l.props_h = e->gui.props_h; - I32 left_total_h = max( 1, editor_layout_content_bottom( wnd ) - l.props_y ); - I32 props_max_h = left_total_h - - EDITOR_LAYOUT_LEFT_BOX_GAP - - EDITOR_LAYOUT_ASSETS_MIN_H - - ( EDITOR_LAYOUT_TITLE_OFFSET * 2 ); - props_max_h = max( EDITOR_LAYOUT_PROPS_MIN_H, props_max_h ); - l.props_h = min( max( l.props_h, EDITOR_LAYOUT_PROPS_MIN_H ), props_max_h ); - l.assets_y = l.props_y + EDITOR_LAYOUT_TITLE_OFFSET + l.props_h + EDITOR_LAYOUT_LEFT_BOX_GAP; - l.assets_h = max( EDITOR_LAYOUT_ASSETS_MIN_H, editor_layout_content_bottom( wnd ) - l.assets_y - EDITOR_LAYOUT_TITLE_OFFSET ); - - l.view_h = e->gui.view_h; - l.tool_y = l.view_y + EDITOR_LAYOUT_TITLE_OFFSET + l.view_h + EDITOR_LAYOUT_VIEW_TOOL_GAP; - l.tool_btn_y = l.tool_y + EDITOR_LAYOUT_TOOL_BTN_TOP_GAP; - - I32 bottom_content = editor_layout_content_bottom( wnd ); - l.tool_h = max( 1, bottom_content - l.tool_y - EDITOR_LAYOUT_TITLE_OFFSET ); - l.tool_panel_h = l.tool_h; - l.tool_btn_step = 23; - - l.tool_panel_w = EDITOR_LAYOUT_TOOL_PANEL_W; - I32 required_w = l.tool_btn_w + EDITOR_LAYOUT_TOOL_PANEL_GAP + l.tool_panel_w; - if( required_w > l.right_w ) { - I32 overflow = required_w - l.right_w; - I32 shrink_panel = min( overflow, max( 0, l.tool_panel_w - 180 ) ); - l.tool_panel_w -= shrink_panel; - } - - l.tool_panel_x = l.tool_btn_x + l.tool_btn_w + EDITOR_LAYOUT_TOOL_PANEL_GAP; - - l.status_x = EDITOR_LAYOUT_MARGIN; - l.status_w = max( 1, wnd->w - EDITOR_LAYOUT_MARGIN * 2 ); - l.status_h = EDITOR_LAYOUT_STATUS_H; - l.status_y = wnd->h - EDITOR_LAYOUT_MARGIN - l.status_h; - - return l; -} - -static void editor_resize_base_view( GUI_EDITORWINDOW* wnd ) { - GUI_VIEW* base = (GUI_VIEW*)gui_find_node( wnd, "BASE_VIEW" ); - if( !base ) - return; - - editor_set_bounds( base, 1, 1, wnd->w - 2, wnd->h - 2 ); -} - -static void editor_layout_start_menu( GAME_EDITOR* e ) { - GUI_EDITORWINDOW* wnd = e->wnd; - GUI_LIST* list = (GUI_LIST*)gui_find_node( wnd, "map list" ); - GUI_BUTTON* new_map = (GUI_BUTTON*)gui_find_node( wnd, "new map" ); - GUI_BUTTON* load_map = (GUI_BUTTON*)gui_find_node( wnd, "load map" ); - if( !list || !new_map || !load_map ) - return; - - const I32 min_margin = 10; - const I32 list_title_offset = 15; - const I32 button_gap = 10; - const I32 button_h = 25; - const I32 list_button_gap = 5; - I32 list_w = 200; - I32 list_h = 200; - I32 max_list_w = max( 80, wnd->w - min_margin * 2 ); - I32 start_y = EDITOR_LAYOUT_CONTENT_Y; - I32 max_list_h = max( 80, wnd->h - ( start_y + list_title_offset + list_button_gap + button_h + min_margin ) ); - if( list_w > max_list_w ) list_w = max_list_w; - if( list_h > max_list_h ) list_h = max_list_h; - - I32 x = ( wnd->w - list_w ) / 2; - I32 y = start_y; - I32 bottom = y + list_title_offset + list_h + list_button_gap + button_h; - if( bottom > wnd->h - min_margin ) { - y = max( min_margin, wnd->h - min_margin - ( list_title_offset + list_h + list_button_gap + button_h ) ); - } - - editor_set_bounds( list, x, y, list_w, list_h ); - I32 bw = max( 50, ( list_w - button_gap ) / 2 ); - I32 by = y + list_title_offset + list_h + list_button_gap; - editor_set_bounds( new_map, x, by, bw, button_h ); - editor_set_bounds( load_map, x + bw + button_gap, by, bw, button_h ); -} - -static void editor_layout_tool_buttons( GUI_EDITORWINDOW* wnd, const EDITOR_LAYOUT& l ) { - const char* names[] = { "none", "select", "wall", "poly", "sprite", "ent" }; - I32 y = l.tool_btn_y; - for( U32 i = 0; i < sizeof( names ) / sizeof( names[0] ); ++i ) { - GUI_BUTTON* btn = (GUI_BUTTON*)gui_find_node( wnd, names[i] ); - editor_set_bounds( btn, l.tool_btn_x, y, l.tool_btn_w, 20 ); - y += l.tool_btn_step; - } -} - -static void editor_layout_map_view( GAME_EDITOR* e ) { - if( !e->gui.v2d || !e->gui.v3d || !e->gui.props || !e->gui.tool ) - return; - - EDITOR_LAYOUT l = editor_calc_layout( e ); - editor_raise_header_toolbar( e ); - - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - GUI_BASE* toolbar = egui->header_toolbar; - GUI_BUTTON* back = egui->header_back; - GUI_BUTTON* v2btn = egui->header_mode_2d; - GUI_BUTTON* v3btn = egui->header_mode_3d; - GUI_BUTTON* simbtn = egui->header_mode_sim; - GUI_LABEL* view_type_lbl = egui->header_viewtype_label; - GUI_BASE* view_type_seg = egui->header_viewtype; - - const I32 menu_btn_y = EDITOR_LAYOUT_MENU_Y; - const I32 top_btn_y = l.top_y; - const I32 top_btn_h = 20; - const I32 nav_left_x = 10; - const I32 nav_btn_w = 92; - const I32 nav_gap = 8; - const I32 mode_btn_w = 92; - I32 mode_group_w = mode_btn_w * 3 + nav_gap * 2; - I32 mode_x = e->wnd->w - EDITOR_LAYOUT_MARGIN - mode_group_w; - I32 type_seg_x = l.right_x; - I32 type_lbl_w = 64; - I32 type_lbl_x = type_seg_x - type_lbl_w - 6; - I32 max_type_w = mode_x - type_seg_x - 8; - I32 type_seg_w = min( 174, max( 120, max_type_w ) ); - - editor_set_bounds( toolbar, 1, menu_btn_y, e->wnd->w - 3, EDITOR_LAYOUT_MENU_H ); - - editor_set_bounds( back, nav_left_x, top_btn_y, nav_btn_w, top_btn_h ); - - GUI_BUTTON* mode_btns[] = { v2btn, v3btn, simbtn }; - const char* mode_names[] = { "[ 2d view ]", "[ 3d view ]", "[ simulation ]" }; - for( I32 i = 0; i < 3; ++i ) { - I32 bx = mode_x + ( mode_btn_w + nav_gap ) * i; - editor_set_bounds( mode_btns[i], bx, top_btn_y, mode_btn_w, top_btn_h ); - if( mode_btns[i] ) - snprintf( mode_btns[i]->name, GUI_NAME_LEN, "%s", mode_names[i] ); - } - - U8 show_viewtype = e->gui.view_mode == EDITOR_VIEWMODE_2D; - if( view_type_lbl ) { - view_type_lbl->x = type_lbl_x; - view_type_lbl->y = top_btn_y + 4; - view_type_lbl->enabled = show_viewtype; - } - if( view_type_seg ) { - editor_set_bounds( view_type_seg, type_seg_x, top_btn_y, type_seg_w, top_btn_h ); - view_type_seg->enabled = show_viewtype; - } - - editor_set_bounds( e->gui.props, l.left_x, l.props_y, l.left_w, l.props_h ); - if( e->gui.props->itemview ) { - editor_set_bounds( - e->gui.props->itemview, - 0, - EDITOR_LAYOUT_TITLE_OFFSET, - e->gui.props->w, - e->gui.props->h - ); - } - if( e->gui.assets ) { - editor_set_bounds( e->gui.assets, l.left_x, l.assets_y, l.left_w, l.assets_h ); - } - - editor_set_bounds( e->gui.v2d, l.right_x, l.view_y, l.right_w, l.view_h ); - e->gui.v2d->ybound = e->gui.v2d->h + EDITOR_LAYOUT_TITLE_OFFSET; - editor_set_bounds( e->gui.v3d, l.right_x, l.view_y, l.right_w, l.view_h ); - e->gui.v3d->ybound = e->gui.v3d->h + EDITOR_LAYOUT_TITLE_OFFSET; - - editor_layout_tool_buttons( e->wnd, l ); - - editor_set_bounds( e->gui.tool, l.tool_panel_x, l.tool_y, l.tool_panel_w, l.tool_panel_h ); - if( e->gui.tool->itemview ) { - editor_set_bounds( - e->gui.tool->itemview, - 0, - EDITOR_LAYOUT_TITLE_OFFSET, - e->gui.tool->w, - e->gui.tool->h - ); - } - if( e->gui.status ) { - editor_set_bounds( e->gui.status, l.status_x, l.status_y, l.status_w, l.status_h ); - } - - editor_apply_view_mode( e ); - - if( e->gui.gridlabel ) { - I32 gx = 150; - I32 gy = e->gui.v2d->h - 4; - e->gui.gridlabel->x = gx; - e->gui.gridlabel->y = gy + 1; - - GUI_BUTTON* plus = (GUI_BUTTON*)gui_find_node( e->gui.v2d, "+" ); - GUI_BUTTON* minus = (GUI_BUTTON*)gui_find_node( e->gui.v2d, "-" ); - GUI_CHECKBOX* propgrid = (GUI_CHECKBOX*)gui_find_node( e->gui.v2d, "properties grid" ); - GUI_CHECKBOX* wireframe = (GUI_CHECKBOX*)gui_find_node( e->gui.v2d, "wireframe" ); - editor_set_bounds( plus, gx + 70, gy, 18, 18 ); - editor_set_bounds( minus, gx + 93, gy, 18, 18 ); - editor_set_bounds( propgrid, gx + 120, gy, propgrid ? propgrid->w : 120, 18 ); - editor_set_bounds( wireframe, gx + 240, gy, wireframe ? wireframe->w : 80, 18 ); - } - - GUI_BUTTON* compile = (GUI_BUTTON*)gui_find_node( e->gui.v3d, "compile bsp" ); - GUI_CHECKBOX* drawbsp = (GUI_CHECKBOX*)gui_find_node( e->gui.v3d, "draw bsp" ); - I32 gy3d = e->gui.v3d->h - 4; - editor_set_bounds( compile, 1, gy3d, 90, 18 ); - editor_set_bounds( drawbsp, 101, gy3d, drawbsp ? drawbsp->w : 80, 18 ); - - editor_update_properties_column( e ); - gui_editor_toolview_update( e->gui.tool ); - editor_notify_grid_change( e ); -} - -void gui_editorwindow_draw_fn( void* ptr ) { - GUI_EDITORWINDOW* wnd = (GUI_EDITORWINDOW*)ptr; - editor_raise_header_toolbar( editor ); - GUI_BASE* toolbar = ( editor && editor->map ) ? editor->gui.header_toolbar : 0; - GUI_EDITOR_TOOLBAR* tbar = (GUI_EDITOR_TOOLBAR*)toolbar; - U8 menu_open = tbar && ( tbar->file_open || tbar->edit_open ); - F32 saved_mx = input.mouse.pos.x; - F32 saved_my = input.mouse.pos.y; - if( menu_open ) { - editor_menu_hover_mask_active = 1; - editor_menu_hover_real_x = (I32)saved_mx; - editor_menu_hover_real_y = (I32)saved_my; - input.mouse.pos.x = -100000.f; - input.mouse.pos.y = -100000.f; - } else { - editor_menu_hover_mask_active = 0; - } - - CLR clr = gui_is_fg_window( wnd )? ui_clr.border : ui_clr.border_inactive; - gui_draw_frect( wnd->x, wnd->y, wnd->w, wnd->h, clr ); - gui_draw_frect( wnd->x + 1, wnd->y + 1, wnd->w - 2, wnd->h - 2, ui_clr.bg ); - - wnd->children.each( fn( GUI_BASE** ptr ) { - GUI_BASE* it = *ptr; - if( !it->enabled ) return; - - if( it->draw_fn ) it->draw_fn( it ); - else dlog( "gui_editorwindow_draw_fn(): child %p has no draw_fn", it ); - } ); - - input.mouse.pos.x = saved_mx; - input.mouse.pos.y = saved_my; - editor_menu_hover_mask_active = 0; -} - -static void gui_editorwindow_input_fn( void* ptr ) { - GUI_EDITORWINDOW* wnd = (GUI_EDITORWINDOW*)ptr; - editor_raise_header_toolbar( editor ); - - GUI_BASE* toolbar = ( editor && editor->map ) ? editor->gui.header_toolbar : 0; - if( toolbar && toolbar->enabled && toolbar->input_fn ) - toolbar->input_fn( toolbar ); - - GUI_EDITOR_TOOLBAR* tbar = (GUI_EDITOR_TOOLBAR*)toolbar; - U8 menu_open = tbar && ( tbar->file_open || tbar->edit_open ); - if( menu_open ) - return; - - wnd->children.each( fn( GUI_BASE** childptr ) { - GUI_BASE* child = *childptr; - if( !child || child == toolbar || !child->enabled || !child->input_fn ) - return; - - child->input_fn( child ); - } ); -} - -GUI_EDITORWINDOW* gui_editorwindow_create( I32 w, I32 h ) { - GUI_EDITORWINDOW* wnd = new GUI_EDITORWINDOW; - wnd->x = 0; - wnd->y = 0; - wnd->xbound = wnd->w = w; - wnd->ybound = wnd->h = h; - wnd->locked = 1; - wnd->draw_fn = gui_editorwindow_draw_fn; - wnd->input_fn = gui_editorwindow_input_fn; - strcpy( wnd->name, "EDITORWINDOW" ); - - _gui.windows.push( wnd ); - gui_set_window( wnd ); - - gui_set_view( 0 ); - gui_view( 1, 1, w - 2, h - 2 ); - return wnd; -} - -GUI_EDITORWINDOW* gui_editorwindow( I32 w, I32 h ) { - GUI_EDITORWINDOW* wnd = gui_editorwindow_create( w, h ); - - GAME_EDITOR* e = editor; - LIST<GUI_LIST_ENTRY>* map_list = editor_get_map_list( e ); - - gui_list( wnd->w / 2 - 100, EDITOR_LAYOUT_CONTENT_Y, 200, 200, "map list", map_list, &editor->gui.map_select ); - gui_button( wnd->w / 2 - 100, EDITOR_LAYOUT_CONTENT_Y + 220, 95, 25, "new map", editor_new_map_cb ); - gui_button( wnd->w / 2 + 5, EDITOR_LAYOUT_CONTENT_Y + 220, 95, 25, "load map", editor_load_map_cb ); - return wnd; -} - - -void editor_update_properties_column( GAME_EDITOR* e ) { - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - gui_editor_propview_update( egui->props ); -} - -void editor_create_properties_column( GAME_EDITOR* e ) { - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - egui->props = gui_editor_propview( 10, EDITOR_LAYOUT_CONTENT_Y, 300, 460 ); - gui_editor_propview_select( egui->props, e->map, EDITOR_SELECT_ORIGIN ); -} - -void editor_create_auxiliary_panels( GAME_EDITOR* e ) { - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - egui->assets = gui_editor_infobox( 10, EDITOR_LAYOUT_CONTENT_Y + 310, 300, 180, EDITOR_INFOBOX_ASSETS, "EDITOR_ASSETS_VIEW" ); - egui->status = gui_editor_infobox( 10, 568, 780, EDITOR_LAYOUT_STATUS_H, EDITOR_INFOBOX_STATUS, "EDITOR_STATUS_VIEW" ); -} - -void editor_update_toolview( GAME_EDITOR* e ) { - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - gui_editor_toolview_update( egui->tool ); -} - -void settool( U8 t ) { - editor->tool.type = t; - - if( editor->gui.v2d ) { - editor->gui.v2d->poly_drag = 0; - } - - if( editor->gui.tool ) { - editor_update_toolview( editor ); - } -} - -static U8 EDITOR_TOOL_BUTTON_TYPES[] = { - EDITOR_TOOL_NONE, - EDITOR_TOOL_SELECT, - EDITOR_TOOL_WALL, - EDITOR_TOOL_POLY, - EDITOR_TOOL_SPRITE, - EDITOR_TOOL_ENT -}; - -static void settool_btn_cb( void* ptr ) { - GUI_BUTTON* btn = (GUI_BUTTON*)ptr; - if( !btn || !btn->extra ) - return; - - settool( *(U8*)btn->extra ); -} - -void editor_create_toolview_column( GAME_EDITOR* e ) { - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - - I32 x = 320; - I32 y = EDITOR_LAYOUT_CONTENT_Y + EDITOR_LAYOUT_VIEW_DEFAULT_H + EDITOR_LAYOUT_VIEW_TOOL_GAP + EDITOR_LAYOUT_TOOL_BTN_TOP_GAP; - I32 off = 23; - const char* labels[] = { "none", "select", "wall", "poly", "sprite", "ent" }; - - for( U32 i = 0; i < sizeof( labels ) / sizeof( labels[0] ); ++i ) { - GUI_BUTTON* btn = gui_button( x, y, 45, 20, labels[i], settool_btn_cb ); - btn->extra = &EDITOR_TOOL_BUTTON_TYPES[i]; - y += off; - } - - egui->tool = gui_editor_toolview( 370, y - EDITOR_LAYOUT_TOOL_BTN_TOP_GAP, 300, 150 ); - gui_editor_toolview_update( egui->tool ); -} - -void editor_create_game_view_column( GAME_EDITOR* e ) { - GAME_EDITOR::EDITOR_GUI* egui = &e->gui; - I32 x = 320, y = EDITOR_LAYOUT_CONTENT_Y; - egui->v2d = gui_editor_2dview( x, y, 468, 370 ); - egui->v3d = gui_editor_3dview( x, y, 468, 370 ); - egui->v2d->enabled = 1; - egui->v3d->enabled = 0; -} - -void editor_create_map_view( GAME_EDITOR* e ) { - if( !e->map ) { - dlog( "editor_create_map_views() : no map loaded\n" ); - return; - } - - GUI_EDITORWINDOW* w = e->wnd; - w->children.each( fn( GUI_BASE** ptr ) { - gui_free( *ptr ); - } ); - w->children.clear(); - editor_clear_gui_state_refs( e ); - e->gui.view2d_type = EDITOR_2DVIEW_TOP_DOWN; - e->gui.view_mode = EDITOR_VIEWMODE_2D; - - gui_set_window( w ); - gui_set_view( 0 ); - - gui_view( 1, 1, w->w - 2, w->h - 2 ); - - editor_create_header_controls( e ); - editor_create_properties_column( e ); - editor_create_toolview_column( e ); - editor_create_game_view_column( e ); - editor_create_auxiliary_panels( e ); - editor_layout_map_view( e ); -} - -void editor_resize( GAME_EDITOR* e, I32 w, I32 h ) { - if( !e || !e->wnd ) - return; - - w = max( 1, w ); - h = max( 1, h ); - - GUI_EDITORWINDOW* wnd = e->wnd; - if( wnd->w == w && wnd->h == h ) - return; - - editor_set_bounds( wnd, 0, 0, w, h ); - editor_resize_base_view( wnd ); - - if( e->map ) - editor_layout_map_view( e ); - else - editor_layout_start_menu( e ); - - if( e->gui.new_map_popup ) { - GUI_WINDOW* popup = e->gui.new_map_popup; - if( popup->x > w - 5 ) popup->x = w - 5; - if( popup->x + popup->w < 5 ) popup->x = 5 - popup->w; - if( popup->y > h - 5 ) popup->y = h - 5; - if( popup->y + popup->h < 5 ) popup->y = 5 - popup->h; - } -} - -void close_new_map_popup( void* ) { - gui_push_callback( pfn( void* ) { - GUI_WINDOW* popup = editor->gui.new_map_popup; - if( !popup ) - return; - - gui_free( popup ); - editor->gui.new_map_popup = 0; - } ); -} - -void editor_new_map_cb( void* ptr ) { - if( editor->gui.new_map_popup ) return; - - GUI_WINDOW* cwnd = gui_get_window(); - GUI_VIEW* view = gui_get_view(); - - I32 wx = 250; - I32 wy = 140; - I32 ww = 300; - I32 wh = 200; - - editor->gui.new_map_popup = gui_window( wx, wy, ww, wh ); - gui_title( "new map" ); - GUI_TEXTBOX* tb = gui_textbox( 10, 20, ww - 20, 20, "name", 32 ); - tb->active = 1; - - gui_button( ww - 50 - 70, wh - 20 - 10, 50, 20, "ok", pfn( void* ptr ) { - GUI_BUTTON* btn = (GUI_BUTTON*)ptr; - GUI_TEXTBOX* name = (GUI_TEXTBOX*)gui_find_node( btn->parent, "name" ); - if( !name ) - return; - - editor_new_map( editor, name->value ); - close_new_map_popup( 0 ); - } ); - - gui_button( ww - 50 - 10, wh - 20 - 10, 50, 20, "cancel", close_new_map_popup ); - - gui_set_window( cwnd ); - gui_set_view( view ); -} - -void editor_load_map_cb( void* ptr ) { - GUI_LIST* list = (GUI_LIST*)gui_find_node( editor->wnd, "map list" ); - - GUI_LIST_ENTRY* e = gui_list_get_selected( list ); - if( !e ) - return; - - char full_path[256]; - sprintf( full_path, "../assets/maps/%s", e->title ); - - if( editor->map ) - editor_close( editor ); - - editor_load_map( editor, full_path ); -} |
