Skip to content

Commit cdd78ab

Browse files
authored
Merge pull request #75845 from db48x/implement-uilist-second-column
format `uilist` menu entries with a table
2 parents 6412e91 + 20011ca commit cdd78ab

File tree

2 files changed

+82
-52
lines changed

2 files changed

+82
-52
lines changed

src/ui.cpp

Lines changed: 79 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,6 @@ void uilist_impl::on_resized()
6161

6262
void uilist_impl::draw_controls()
6363
{
64-
float hotkey_width =
65-
ImGui::CalcTextSize( "[X]" ).x + ImGui::GetStyle().ItemSpacing.x;
66-
6764
if( !parent.text.empty() ) {
6865
cataimgui::draw_colored_text( parent.text );
6966
ImGui::Separator();
@@ -81,47 +78,58 @@ void uilist_impl::draw_controls()
8178
ImGui::TableNextRow();
8279
ImGui::TableSetColumnIndex( 1 );
8380

81+
float entry_height = ImGui::GetTextLineHeightWithSpacing();
8482
if( ImGui::BeginChild( "scroll", parent.calculated_menu_size, false ) ) {
85-
// It would be natural to make the entries into buttons, or
86-
// combos, or other pre-built ui elements. For now I am mostly
87-
// going to copy the style of the original textual ui elements.
88-
for( size_t i = 0; i < parent.fentries.size(); i++ ) {
89-
auto entry = parent.entries[parent.fentries[i]];
90-
ImGui::PushID( i );
91-
ImGuiSelectableFlags_ flags = !entry.enabled ? ImGuiSelectableFlags_Disabled :
92-
ImGuiSelectableFlags_None;
93-
bool is_selected = static_cast<int>( i ) == parent.fselected;
94-
if( ImGui::Selectable( "", is_selected, flags | ImGuiSelectableFlags_AllowItemOverlap ) ||
95-
ImGui::IsItemHovered() ) {
96-
parent.fselected = i;
97-
parent.selected = parent.fentries[parent.fselected];
98-
}
99-
ImGui::SameLine( 0, 0 );
100-
if( is_selected ) {
101-
ImGui::SetItemDefaultFocus();
102-
ImGui::SetScrollHereY();
103-
}
83+
if( ImGui::BeginTable( "menu items", 3, ImGuiTableFlags_SizingFixedFit ) ) {
84+
ImGui::TableSetupColumn( "hotkey", ImGuiTableColumnFlags_WidthFixed,
85+
parent.calculated_hotkey_width );
86+
ImGui::TableSetupColumn( "primary", ImGuiTableColumnFlags_WidthFixed,
87+
parent.calculated_label_width );
88+
ImGui::TableSetupColumn( "secondary", ImGuiTableColumnFlags_WidthFixed,
89+
parent.calculated_secondary_width );
90+
91+
// It would be natural to make the entries into buttons, or
92+
// combos, or other pre-built ui elements. For now I am mostly
93+
// going to copy the style of the original textual ui elements.
94+
for( size_t i = 0; i < parent.fentries.size(); i++ ) {
95+
auto entry = parent.entries[parent.fentries[i]];
96+
ImGui::TableNextRow( ImGuiTableRowFlags_None, entry_height );
97+
ImGui::TableSetColumnIndex( 0 );
98+
99+
ImVec2 rowMin = ImGui::GetCursorScreenPos();
100+
ImVec2 rowMax = ImVec2( rowMin.x + parent.calculated_menu_size.x, rowMin.y + entry_height );
101+
bool is_hovered = ImGui::IsMouseHoveringRect( rowMin, rowMax, false );
102+
if( is_hovered ) {
103+
ImGui::TableSetBgColor( ImGuiTableBgTarget_RowBg1,
104+
ImColor( ImGui::GetStyle().Colors[ ImGuiCol_HeaderHovered ] ) );
105+
parent.fselected = i;
106+
}
107+
bool is_selected = static_cast<int>( i ) == parent.fselected;
108+
if( is_selected ) {
109+
ImGui::SetItemDefaultFocus();
110+
ImGui::SetScrollHereY();
111+
ImGui::TableSetBgColor( ImGuiTableBgTarget_RowBg1,
112+
ImColor( ImGui::GetStyle().Colors[ ImGuiCol_HeaderActive ] ) );
113+
}
104114

105-
if( entry.hotkey.has_value() ) {
106-
ImGui::Text( "%c", '[' );
107-
ImGui::SameLine( 0, 0 );
108-
nc_color color = is_selected ? parent.hilight_color : parent.hotkey_color;
109-
cataimgui::draw_colored_text( entry.hotkey.value().short_description(),
110-
color );
111-
ImGui::SameLine( 0, 0 );
112-
ImGui::Text( "%c", ']' );
113-
ImGui::SameLine();
114-
} else {
115-
ImGui::SetCursorPosX( hotkey_width );
115+
if( entry.hotkey.has_value() ) {
116+
nc_color color = is_selected ? parent.hilight_color : parent.hotkey_color;
117+
cataimgui::draw_colored_text( entry.hotkey.value().short_description(),
118+
color );
119+
}
120+
ImGui::TableSetColumnIndex( 1 );
121+
nc_color color = ( is_selected ?
122+
parent.hilight_color :
123+
( entry.enabled || entry.force_color ?
124+
entry.text_color :
125+
parent.disabled_color ) );
126+
cataimgui::draw_colored_text( entry.txt, color );
127+
ImGui::TableSetColumnIndex( 2 );
128+
if( !entry.ctxt.empty() ) {
129+
cataimgui::draw_colored_text( entry.ctxt, color );
130+
}
116131
}
117-
nc_color color = ( is_selected ?
118-
parent.hilight_color :
119-
( entry.enabled || entry.force_color ?
120-
entry.text_color :
121-
parent.disabled_color ) );
122-
cataimgui::draw_colored_text( entry.txt,
123-
color );
124-
ImGui::PopID();
132+
ImGui::EndTable();
125133
}
126134
}
127135
ImGui::EndChild();
@@ -357,6 +365,9 @@ void uilist::init()
357365
desired_bounds = std::nullopt;
358366
calculated_bounds = { -1.f, -1.f, -1.f, -1.f };
359367
calculated_menu_size = { 0.0, 0.0 };
368+
calculated_hotkey_width = 0.0;
369+
calculated_label_width = 0.0;
370+
calculated_secondary_width = 0.0;
360371
extra_space_left = 0.0;
361372
extra_space_right = 0.0;
362373
ret = UILIST_WAIT_INPUT;
@@ -556,6 +567,8 @@ static ImVec2 calc_size( const std::string_view line )
556567

557568
void uilist::calc_data()
558569
{
570+
ImGuiStyle s = ImGui::GetStyle();
571+
559572
std::vector<int> autoassign;
560573
for( size_t i = 0; i < entries.size(); i++ ) {
561574
if( entries[ i ].enabled ) {
@@ -594,13 +607,13 @@ void uilist::calc_data()
594607
bool has_titlebar = !title.empty();
595608
if( has_titlebar ) {
596609
title_size = calc_size( title );
597-
title_size.y += ImGui::GetStyle().FramePadding.y * 2.0;
610+
title_size.y += s.FramePadding.y * 2.0;
598611
}
599612

600613
ImVec2 text_size = {};
601614
if( !text.empty() ) {
602615
text_size = calc_size( text );
603-
text_size.y += ImGui::GetStyle().ItemSpacing.y * 2.0;
616+
text_size.y += s.ItemSpacing.y * 2.0;
604617
}
605618

606619
ImVec2 desc_size = {};
@@ -614,37 +627,51 @@ void uilist::calc_data()
614627
if( desc_size.y <= 0.0 ) {
615628
desc_enabled = false;
616629
}
617-
desc_size.y += ImGui::GetStyle().ItemSpacing.y * 2.0;
630+
desc_size.y += s.ItemSpacing.y * 2.0;
618631
}
619632
float additional_height = title_size.y + text_size.y + desc_size.y + 2.0 *
620-
( ImGui::GetStyle().FramePadding.y + ImGui::GetStyle().WindowBorderSize );
633+
( s.FramePadding.y + s.WindowBorderSize );
621634

622635
if( vmax * ImGui::GetTextLineHeightWithSpacing() + additional_height >
623636
ImGui::GetMainViewport()->Size.y ) {
624637
vmax = floorf( ( ImGui::GetMainViewport()->Size.y - additional_height ) /
625638
ImGui::GetTextLineHeightWithSpacing() );
626639
}
627640

628-
calculated_menu_size = { 0.0, 0.0 };
641+
float padding = 2.0f * s.CellPadding.x;
642+
calculated_hotkey_width = ImGui::CalcTextSize( "X" ).x;
643+
calculated_label_width = 0.0;
644+
calculated_secondary_width = 0.0;
629645
for( int fentry : fentries ) {
630-
calculated_menu_size.x = std::max( calculated_menu_size.x, calc_size( entries[fentry].txt ).x );
646+
calculated_label_width = std::max( calculated_label_width, calc_size( entries[fentry].txt ).x );
647+
calculated_secondary_width = std::max( calculated_secondary_width,
648+
calc_size( entries[fentry].ctxt ).x );
631649
}
632-
calculated_menu_size.x += ImGui::CalcTextSize( " [X] " ).x;
650+
calculated_menu_size = { 0.0, 0.0 };
651+
calculated_menu_size.x += calculated_hotkey_width + padding;
652+
calculated_menu_size.x += calculated_label_width + padding;
653+
calculated_menu_size.x += calculated_secondary_width + padding;
633654
calculated_menu_size.y = std::min( ImGui::GetMainViewport()->Size.y - additional_height,
634-
vmax * ImGui::GetTextLineHeightWithSpacing() ) + ( ImGui::GetStyle().FramePadding.y * 2.0 );
655+
vmax * ImGui::GetTextLineHeightWithSpacing() ) + ( s.FramePadding.y * 2.0 );
635656

636657
extra_space_left = 0.0;
637658
extra_space_right = 0.0;
638659
if( callback != nullptr ) {
639-
extra_space_left = callback->desired_extra_space_left( ) + ImGui::GetStyle().FramePadding.x;
640-
extra_space_right = callback->desired_extra_space_right( ) + ImGui::GetStyle().FramePadding.x;
660+
extra_space_left = callback->desired_extra_space_left( ) + s.FramePadding.x;
661+
extra_space_right = callback->desired_extra_space_right( ) + s.FramePadding.x;
641662
}
642663

643664
float longest_line_width = std::max( std::max( title_size.x, text_size.x ),
644665
std::max( calculated_menu_size.x, desc_size.x ) );
645666
calculated_bounds.w = extra_space_left + extra_space_right + longest_line_width
646-
+ 2 * ( ImGui::GetStyle().WindowPadding.x + ImGui::GetStyle().WindowBorderSize );
667+
+ 2 * ( s.WindowPadding.x + s.WindowBorderSize );
647668
calculated_bounds.h = calculated_menu_size.y + additional_height;
669+
670+
if( longest_line_width > calculated_menu_size.x ) {
671+
calculated_menu_size.x = longest_line_width;
672+
calculated_label_width = calculated_menu_size.x - calculated_hotkey_width - padding -
673+
calculated_secondary_width - padding - padding;
674+
}
648675
}
649676

650677
void uilist::setup()

src/ui.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,9 @@ class uilist // NOLINT(cata-xy)
460460
private:
461461
ImVec2 calculated_menu_size;
462462
cataimgui::bounds calculated_bounds;
463+
float calculated_hotkey_width;
464+
float calculated_label_width;
465+
float calculated_secondary_width;
463466
float extra_space_left;
464467
float extra_space_right;
465468
std::vector<int> fentries;

0 commit comments

Comments
 (0)