@@ -25,52 +25,69 @@ void render_titlebar(HDC hdc) {
2525 int th = DPI (TITLEBAR_H );
2626 fill_rect (hdc , 0 , 0 , g_editor .client_w , th , CLR_BG_DARK );
2727
28- SelectObject (hdc , g_editor .font_title );
2928 SetBkMode (hdc , TRANSPARENT );
3029
31- static const wchar_t * fab_icons [MENU_COUNT ] = {
32- L"\x2630" , L"\x270E" , L"\x2315" , L"\x2699" ,
33- };
30+ /* Tabs (starting from left edge) */
31+ int tx = DPI (6 );
32+ int right_limit = g_editor .client_w - DPI (46 ) * 3 - DPI (8 );
33+ SelectObject (hdc , g_editor .font_ui_small );
3434
35- int fab_size = DPI (28 );
36- int fab_pad = DPI (6 );
37- int fab_start_x = DPI (8 );
38- int fab_y = (th - fab_size ) / 2 ;
35+ for (int i = 0 ; i < g_editor .tab_count ; i ++ ) {
36+ Document * doc = g_editor .tabs [i ];
37+ wchar_t label [128 ];
38+ swprintf (label , 128 , L"%ls%ls" , doc -> title , doc -> modified ? L" \x2022" : L"" );
39+ int tw = (int )wcslen (label ) * DPI (8 ) + DPI (TAB_PAD ) * 2 ;
40+ if (tw < DPI (TAB_MIN_W )) tw = DPI (TAB_MIN_W );
41+ if (tw > DPI (TAB_MAX_W )) tw = DPI (TAB_MAX_W );
3942
40- SelectObject (hdc , g_editor .font_ui_small );
41- for (int i = 0 ; i < MENU_COUNT ; i ++ ) {
42- int fx = fab_start_x + i * (fab_size + fab_pad );
43-
44- COLORREF fab_bg ;
45- if (g_editor .menu_open == i ) {
46- fab_bg = CLR_ACCENT ;
47- } else if (g_editor .fab_hover == i ) {
48- fab_bg = g_theme .is_dark ? RGB (50 , 50 , 62 ) : RGB (220 , 220 , 225 );
43+ if (tx + tw > right_limit ) break ;
44+
45+ if (i == g_editor .active_tab ) {
46+ fill_rounded_rect (hdc , tx , DPI (5 ), tw , th - DPI (5 ), DPI (10 ), CLR_TAB_ACTIVE );
47+ fill_rounded_rect (hdc , tx + DPI (12 ), th - DPI (3 ), tw - DPI (24 ), DPI (2 ), DPI (1 ), CLR_ACCENT );
48+ draw_text (hdc , tx + DPI (TAB_PAD ), (th - DPI (12 )) / 2 , label , (int )wcslen (label ), CLR_TEXT );
4949 } else {
50- fab_bg = g_theme . is_dark ? RGB ( 38 , 38 , 46 ) : RGB ( 235 , 235 , 238 );
50+ draw_text ( hdc , tx + DPI ( TAB_PAD ), ( th - DPI ( 12 )) / 2 , label , ( int ) wcslen ( label ), CLR_OVERLAY0 );
5151 }
52- fill_rounded_rect (hdc , fx , fab_y , fab_size , fab_size , fab_size / 2 , fab_bg );
5352
54- COLORREF icon_clr = (g_editor .menu_open == i ) ?
55- (g_theme .is_dark ? RGB (255 , 255 , 255 ) : RGB (255 , 255 , 255 )) : CLR_SUBTEXT ;
56- SetTextColor (hdc , icon_clr );
57- RECT fr = { fx , fab_y , fx + fab_size , fab_y + fab_size };
58- DrawTextW (hdc , fab_icons [i ], 1 , & fr , DT_CENTER | DT_VCENTER | DT_SINGLELINE );
53+ /* Tab close (×) button — use main font for larger size */
54+ SelectObject (hdc , g_editor .font_ui );
55+ draw_text (hdc , tx + tw - DPI (22 ), (th - DPI (16 )) / 2 , L"\x00D7" , 1 , CLR_OVERLAY0 );
56+ SelectObject (hdc , g_editor .font_ui_small );
5957
60- g_editor . menu_bar_widths [ i ] = fab_size + fab_pad ;
58+ tx += tw + DPI ( 4 ) ;
6159 }
6260
63- int fab_total_w = MENU_COUNT * (fab_size + fab_pad );
64- int title_x = fab_start_x + fab_total_w + DPI (12 );
61+ /* New tab (+) button — use main font for larger size */
62+ if (tx + DPI (30 ) <= right_limit ) {
63+ SelectObject (hdc , g_editor .font_ui );
64+ draw_text (hdc , tx + DPI (6 ), (th - DPI (16 )) / 2 , L"+" , 1 , CLR_OVERLAY0 );
65+ SelectObject (hdc , g_editor .font_ui_small );
66+ }
6567
66- SelectObject (hdc , g_editor .font_title );
67- Document * doc = current_doc ();
68- if (doc ) {
69- wchar_t title [256 ];
70- swprintf (title , 256 , L"%ls%ls" , doc -> title , doc -> modified ? L" \x2022" : L"" );
71- draw_text (hdc , title_x , (th - DPI (16 )) / 2 , title , (int )wcslen (title ), CLR_SUBTEXT );
68+ /* Dropdown trigger button (▾) — after (+) button */
69+ int btn_size = DPI (22 );
70+ int btn_x = tx + DPI (32 );
71+ int btn_y = (th - btn_size ) / 2 ;
72+ g_editor .dropdown_btn_x = btn_x ;
73+
74+ COLORREF btn_bg ;
75+ if (g_editor .menu_open >= 0 ) {
76+ btn_bg = CLR_ACCENT ;
77+ } else if (g_editor .dropdown_hover ) {
78+ btn_bg = g_theme .is_dark ? RGB (50 , 50 , 62 ) : RGB (220 , 220 , 225 );
79+ } else {
80+ btn_bg = g_theme .is_dark ? RGB (38 , 38 , 46 ) : RGB (235 , 235 , 238 );
7281 }
82+ fill_rounded_rect (hdc , btn_x , btn_y , btn_size , btn_size , DPI (4 ), btn_bg );
7383
84+ SelectObject (hdc , g_editor .font_ui_small );
85+ COLORREF icon_clr = (g_editor .menu_open >= 0 ) ? RGB (255 , 255 , 255 ) : CLR_SUBTEXT ;
86+ RECT br = { btn_x , btn_y , btn_x + btn_size , btn_y + btn_size };
87+ SetTextColor (hdc , icon_clr );
88+ DrawTextW (hdc , L"\x25BE" , 1 , & br , DT_CENTER | DT_VCENTER | DT_SINGLELINE );
89+
90+ /* Window control buttons */
7491 int bw = DPI (46 ), bh = th ;
7592 int x = g_editor .client_w - bw * 3 ;
7693
@@ -98,38 +115,8 @@ void render_titlebar(HDC hdc) {
98115}
99116
100117void render_tabbar (HDC hdc ) {
101- int y = DPI (TITLEBAR_H + MENUBAR_H );
102- int tbh = DPI (TABBAR_H );
103- fill_rect (hdc , 0 , y , g_editor .client_w , tbh , CLR_BG_DARK );
104-
105- SelectObject (hdc , g_editor .font_ui_small );
106- SetBkMode (hdc , TRANSPARENT );
107-
108- int x = DPI (8 );
109- for (int i = 0 ; i < g_editor .tab_count ; i ++ ) {
110- Document * doc = g_editor .tabs [i ];
111- wchar_t label [128 ];
112- swprintf (label , 128 , L"%ls%ls" , doc -> title , doc -> modified ? L" \x2022" : L"" );
113- int tw = (int )wcslen (label ) * DPI (8 ) + DPI (TAB_PAD ) * 2 ;
114- if (tw < DPI (TAB_MIN_W )) tw = DPI (TAB_MIN_W );
115- if (tw > DPI (TAB_MAX_W )) tw = DPI (TAB_MAX_W );
116-
117- if (i == g_editor .active_tab ) {
118- fill_rounded_rect (hdc , x , y + DPI (5 ), tw , tbh - DPI (5 ), DPI (10 ), CLR_TAB_ACTIVE );
119- fill_rounded_rect (hdc , x + DPI (12 ), y + tbh - DPI (3 ), tw - DPI (24 ), DPI (2 ), DPI (1 ), CLR_ACCENT );
120- draw_text (hdc , x + DPI (TAB_PAD ), y + (tbh - DPI (12 )) / 2 , label , (int )wcslen (label ), CLR_TEXT );
121- } else {
122- draw_text (hdc , x + DPI (TAB_PAD ), y + (tbh - DPI (12 )) / 2 , label , (int )wcslen (label ), CLR_OVERLAY0 );
123- }
124-
125- draw_text (hdc , x + tw - DPI (20 ), y + (tbh - DPI (12 )) / 2 , L"\x00D7" , 1 , CLR_OVERLAY0 );
126-
127- x += tw + DPI (4 );
128- }
129-
130- draw_text (hdc , x + DPI (8 ), y + (tbh - DPI (12 )) / 2 , L"+" , 1 , CLR_OVERLAY0 );
131-
132- fill_rect (hdc , 0 , y + tbh - 1 , g_editor .client_w , 1 , CLR_SURFACE0 );
118+ /* Tabs are now rendered inline in the titlebar */
119+ (void )hdc ;
133120}
134121
135122void render_statusbar (HDC hdc ) {
@@ -952,31 +939,35 @@ void render_menubar(HDC hdc) {
952939}
953940
954941void render_menu_dropdown (HDC hdc ) {
955- if (g_editor .menu_open < 0 || g_editor . menu_open >= MENU_COUNT ) return ;
942+ if (g_editor .menu_open < 0 ) return ;
956943
957- const MenuDef * menu = & g_menus [g_editor .menu_open ];
958944 int item_h = DPI (26 );
959945 int sep_h = DPI (9 );
946+ int header_h = DPI (24 );
960947 int dropdown_w = DPI (260 );
961948 int pad_x = DPI (12 );
962949
963- int fab_size = DPI (28 );
964- int fab_pad = DPI (6 );
965- int fab_start_x = DPI (8 );
966-
967- int dropdown_x = fab_start_x + g_editor .menu_open * (fab_size + fab_pad );
950+ int dropdown_x = g_editor .dropdown_btn_x ;
968951 int dropdown_y = DPI (TITLEBAR_H );
969952
953+ /* Calculate total height across all menus */
970954 int total_h = DPI (4 );
971- for (int i = 0 ; i < menu -> item_count ; i ++ ) {
972- total_h += (menu -> items [i ].id == MENU_ID_SEP ) ? sep_h : item_h ;
955+ for (int m = 0 ; m < MENU_COUNT ; m ++ ) {
956+ if (m > 0 ) total_h += sep_h ; /* separator between categories */
957+ total_h += header_h ; /* category header */
958+ for (int i = 0 ; i < g_menus [m ].item_count ; i ++ ) {
959+ total_h += (g_menus [m ].items [i ].id == MENU_ID_SEP ) ? sep_h : item_h ;
960+ }
973961 }
974962 total_h += DPI (4 );
975963
964+ /* Shadow */
976965 fill_rounded_rect (hdc , dropdown_x + DPI (2 ), dropdown_y + DPI (2 ),
977966 dropdown_w , total_h , DPI (8 ), RGB (0 , 0 , 0 ));
967+ /* Background */
978968 fill_rounded_rect (hdc , dropdown_x , dropdown_y , dropdown_w , total_h , DPI (8 ),
979969 g_theme .is_dark ? RGB (34 , 34 , 42 ) : RGB (248 , 248 , 248 ));
970+ /* Border */
980971 HPEN pen = CreatePen (PS_SOLID , 1 , CLR_SURFACE1 );
981972 HBRUSH hollow = (HBRUSH )GetStockObject (HOLLOW_BRUSH );
982973 HPEN old_pen = (HPEN )SelectObject (hdc , pen );
@@ -991,40 +982,60 @@ void render_menu_dropdown(HDC hdc) {
991982 SetBkMode (hdc , TRANSPARENT );
992983
993984 int cy = dropdown_y + DPI (4 );
994- for (int i = 0 ; i < menu -> item_count ; i ++ ) {
995- const MenuItem * item = & menu -> items [i ];
985+ int flat_idx = 0 ;
996986
997- if (item -> id == MENU_ID_SEP ) {
987+ for (int m = 0 ; m < MENU_COUNT ; m ++ ) {
988+ const MenuDef * menu = & g_menus [m ];
989+
990+ /* Category separator (between groups, not before the first) */
991+ if (m > 0 ) {
998992 int line_y = cy + sep_h / 2 ;
999993 fill_rect (hdc , dropdown_x + pad_x , line_y , dropdown_w - pad_x * 2 , 1 , CLR_SURFACE0 );
1000994 cy += sep_h ;
1001- continue ;
1002995 }
1003996
1004- if (g_editor .menu_hover_item == i ) {
1005- fill_rounded_rect (hdc , dropdown_x + DPI (4 ), cy , dropdown_w - DPI (8 ), item_h ,
1006- DPI (4 ), CLR_ACCENT );
1007- SetTextColor (hdc , g_theme .is_dark ? RGB (255 , 255 , 255 ) : RGB (255 , 255 , 255 ));
1008- }
997+ /* Category header */
998+ SelectObject (hdc , g_editor .font_title );
999+ draw_text (hdc , dropdown_x + pad_x , cy + (header_h - DPI (12 )) / 2 ,
1000+ menu -> label , (int )wcslen (menu -> label ), CLR_OVERLAY0 );
1001+ SelectObject (hdc , g_editor .font_ui_small );
1002+ cy += header_h ;
1003+
1004+ /* Menu items */
1005+ for (int i = 0 ; i < menu -> item_count ; i ++ ) {
1006+ const MenuItem * item = & menu -> items [i ];
1007+
1008+ if (item -> id == MENU_ID_SEP ) {
1009+ int line_y = cy + sep_h / 2 ;
1010+ fill_rect (hdc , dropdown_x + pad_x , line_y , dropdown_w - pad_x * 2 , 1 , CLR_SURFACE0 );
1011+ cy += sep_h ;
1012+ continue ;
1013+ }
10091014
1010- COLORREF label_clr = (g_editor .menu_hover_item == i )
1011- ? (g_theme .is_dark ? RGB (255 , 255 , 255 ) : RGB (255 , 255 , 255 ))
1012- : CLR_TEXT ;
1013- draw_text (hdc , dropdown_x + pad_x , cy + (item_h - DPI (12 )) / 2 ,
1014- item -> label , (int )wcslen (item -> label ), label_clr );
1015-
1016- if (item -> shortcut ) {
1017- SIZE ssz ;
1018- GetTextExtentPoint32W (hdc , item -> shortcut , (int )wcslen (item -> shortcut ), & ssz );
1019- COLORREF sc_clr = (g_editor .menu_hover_item == i )
1020- ? (g_theme .is_dark ? RGB (205 , 210 , 230 ) : RGB (220 , 230 , 255 ))
1021- : CLR_OVERLAY0 ;
1022- draw_text (hdc , dropdown_x + dropdown_w - pad_x - ssz .cx ,
1023- cy + (item_h - DPI (12 )) / 2 ,
1024- item -> shortcut , (int )wcslen (item -> shortcut ), sc_clr );
1025- }
1015+ if (g_editor .menu_hover_item == flat_idx ) {
1016+ fill_rounded_rect (hdc , dropdown_x + DPI (4 ), cy , dropdown_w - DPI (8 ), item_h ,
1017+ DPI (4 ), CLR_ACCENT );
1018+ }
10261019
1027- cy += item_h ;
1020+ COLORREF label_clr = (g_editor .menu_hover_item == flat_idx )
1021+ ? RGB (255 , 255 , 255 ) : CLR_TEXT ;
1022+ draw_text (hdc , dropdown_x + pad_x , cy + (item_h - DPI (12 )) / 2 ,
1023+ item -> label , (int )wcslen (item -> label ), label_clr );
1024+
1025+ if (item -> shortcut ) {
1026+ SIZE ssz ;
1027+ GetTextExtentPoint32W (hdc , item -> shortcut , (int )wcslen (item -> shortcut ), & ssz );
1028+ COLORREF sc_clr = (g_editor .menu_hover_item == flat_idx )
1029+ ? (g_theme .is_dark ? RGB (205 , 210 , 230 ) : RGB (220 , 230 , 255 ))
1030+ : CLR_OVERLAY0 ;
1031+ draw_text (hdc , dropdown_x + dropdown_w - pad_x - ssz .cx ,
1032+ cy + (item_h - DPI (12 )) / 2 ,
1033+ item -> shortcut , (int )wcslen (item -> shortcut ), sc_clr );
1034+ }
1035+
1036+ flat_idx ++ ;
1037+ cy += item_h ;
1038+ }
10281039 }
10291040}
10301041
0 commit comments