Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a better way to wrap text containing color tags #76513

Merged
merged 3 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/cata_imgui.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
#include "cata_imgui.h"

#include <stack>
#include <type_traits>

#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui/imgui.h>
#include <imgui/imgui_internal.h>
#undef IMGUI_DEFINE_MATH_OPERATORS
#include <imgui/imgui_freetype.h>

#include "color.h"
#include "filesystem.h"
#include "input.h"
#include "output.h"
#include "system_locale.h"
Expand Down Expand Up @@ -1042,3 +1038,20 @@ void cataimgui::PushMonoFont()
ImGui::PushFont( ImGui::GetIO().Fonts->Fonts[1] );
#endif
}

bool cataimgui::BeginRightAlign( const char *str_id )
{
if( ImGui::BeginTable( str_id, 2, ImGuiTableFlags_SizingFixedFit, ImVec2( -1, 0 ) ) ) {
ImGui::TableSetupColumn( "a", ImGuiTableColumnFlags_WidthStretch );

ImGui::TableNextColumn();
ImGui::TableNextColumn();
return true;
}
return false;
}

void cataimgui::EndRightAlign()
{
ImGui::EndTable();
}
4 changes: 4 additions & 0 deletions src/cata_imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct input_event;
#include "sdl_wrappers.h"
#include "color_loader.h"
#endif
#include "text.h"

struct point;
struct ImVec2;
Expand Down Expand Up @@ -151,4 +152,7 @@ void load_colors();

void PushGuiFont();
void PushMonoFont();

bool BeginRightAlign( const char *str_id );
void EndRightAlign();
} // namespace cataimgui
1 change: 1 addition & 0 deletions src/item_pocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,7 @@ void item_pocket::contents_info( std::vector<iteminfo> &info, int pocket_number,
contains_weight() ) );
info.emplace_back( weight_to_info( cont_type_str, _( " of " ),
weight_capacity() ) );
info.back().bNewLine = true;
} else {
// With ammo_restriction, total capacity does not matter, but show current volume/weight
info.emplace_back( vol_to_info( cont_type_str, _( "Volume: " ),
Expand Down
67 changes: 38 additions & 29 deletions src/magic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2519,22 +2519,24 @@ class spellcasting_callback : public uilist_callback

void refresh( uilist *menu ) override {
ImGui::TableSetColumnIndex( 2 );
std::string ignore_string = casting_ignore ? _( "Ignore Distractions" ) :
_( "Popup Distractions" );
ImGui::TextColored( casting_ignore ? c_red : c_light_green, "%s %s", "[I]", ignore_string.c_str() );
const std::string assign_letter = _( "Assign Hotkey [=]" );
float w = ImGui::CalcTextSize( assign_letter.c_str() ).x;
float x = ImGui::GetContentRegionAvail().x - w;
ImGui::SameLine( x, 0 );
ImGui::TextColored( c_yellow, "%s", assign_letter.c_str() );
ImGui::NewLine();
if( ImGui::BeginChild( "spell info", { desired_extra_space_right( ), 0 }, false,
ImGuiWindowFlags_AlwaysAutoResize ) ) {
ImGui::SameLine( 0.0, -1.0 );
ImVec2 info_size = ImGui::GetContentRegionAvail();
info_size.y -= ImGui::GetTextLineHeightWithSpacing();
if( ImGui::BeginChild( "spell info", info_size, false,
ImGuiWindowFlags_AlwaysVerticalScrollbar ) ) {
if( menu->previewing >= 0 && static_cast<size_t>( menu->previewing ) < known_spells.size() ) {
display_spell_info( menu->previewing );
}
}
ImGui::EndChild();
std::string ignore_string = casting_ignore ? _( "Ignore Distractions" ) :
_( "Popup Distractions" );
ImGui::TextColored( casting_ignore ? c_red : c_light_green, "%s %s", "[I]", ignore_string.c_str() );
ImGui::SameLine();
if( cataimgui::BeginRightAlign( "hotkeys" ) ) {
ImGui::TextColored( c_yellow, "%s", _( "Assign Hotkey [=]" ) );
cataimgui::EndRightAlign();
}
}
};

Expand Down Expand Up @@ -2633,12 +2635,18 @@ void spellcasting_callback::display_spell_info( size_t index )
cataimgui::set_scroll( spell_info_scroll );
ImGui::TextColored( c_yellow, "%s", sp.spell_class() == trait_NONE ? _( "Classless" ) :
sp.spell_class()->name().c_str() );
// we remove 6 characteres from the width because there seems to be issues with wrapping in this menu (even with TextWrapped)
// TODO(thePotatomancer): investigate and fix the strange wrapping issues in this menu as well as oth er imgui menus
float spell_info_width = ImGui::GetContentRegionAvail().x - ( ImGui::CalcTextSize( " " ).x * 16 );
cataimgui::draw_colored_text( sp.description(), spell_info_width );
std::vector<std::string> lines = string_split( sp.description(), '\n' );
for( std::string &l : lines ) {
cataimgui::TextColoredParagraph( c_white, l );
ImGui::NewLine();
}
ImGui::NewLine();
cataimgui::draw_colored_text( sp.enumerate_spell_data( pc ), spell_info_width );

std::vector<std::string> lines2 = string_split( sp.enumerate_spell_data( pc ), '\n' );
for( std::string &l : lines2 ) {
cataimgui::TextColoredParagraph( c_white, l );
ImGui::NewLine();
}
ImGui::NewLine();

// Calculates temp_level_adjust from EoC, saves it to the spell for later use, and prepares to display the result
Expand All @@ -2651,7 +2659,7 @@ void spellcasting_callback::display_spell_info( size_t index )
}
const bool is_psi = sp.has_flag( spell_flag::PSIONIC );

double column_width = desired_extra_space_right( ) / 2.0;
double column_width = ImGui::GetContentRegionAvail().x / 2.0;
if( ImGui::BeginTable( "data", 2 ) ) {
ImGui::TableSetupColumn( "current level", ImGuiTableColumnFlags_WidthFixed, column_width );
ImGui::TableSetupColumn( "max level", ImGuiTableColumnFlags_WidthFixed, column_width );
Expand Down Expand Up @@ -2832,21 +2840,19 @@ void spellcasting_callback::display_spell_info( size_t index )
ImGui::Text( "%s: %s", _( "Duration" ), sp.duration_string( pc ).c_str() );
}

// TODO(db48x): rewrite to display via ImGui directly, so that wrapping can be done correctly
// TODO(thePotatomancer): once we do rewrite it make sure to pass wrapping info to draw_colored_text or skip it entirely
float width = ImGui::GetContentRegionAvail().x / ImGui::CalcTextSize( "X" ).x;
if( sp.has_components() ) {
ImGui::NewLine();
if( !sp.components().get_components().empty() ) {
for( const std::string &line : sp.components().get_folded_components_list(
width - 6, c_light_gray, pc.crafting_inventory( pc.pos(), 0, false ), return_true<item> ) ) {
cataimgui::draw_colored_text( line );
0, c_light_gray, pc.crafting_inventory( pc.pos(), 0, false ), return_true<item> ) ) {
cataimgui::TextColoredParagraph( c_white, line );
ImGui::NewLine();
}
}
if( !( sp.components().get_tools().empty() && sp.components().get_qualities().empty() ) ) {
for( const std::string &line : sp.components().get_folded_tools_list(
width - 6, c_light_gray, pc.crafting_inventory( pc.pos(), 0, false ) ) ) {
cataimgui::draw_colored_text( line );
0, c_light_gray, pc.crafting_inventory( pc.pos(), 0, false ) ) ) {
cataimgui::TextColoredParagraph( c_white, line );
ImGui::NewLine();
}
}
Expand Down Expand Up @@ -2943,7 +2949,7 @@ spell &known_magic::select_spell( Character &guy )
spell_menu.desired_bounds = {
-1.0,
-1.0,
std::max( 80, TERMX * 3 / 8 ) *ImGui::CalcTextSize( "X" ).x,
-1.0,
clamp( static_cast<int>( known_spells_sorted.size() ), 24, TERMY * 9 / 10 ) *ImGui::GetTextLineHeight(),
};

Expand Down Expand Up @@ -3066,6 +3072,7 @@ static std::string color_number( const float num )
return colorize( "0", c_white );
}
}

static void draw_spellbook_info( const spell_type &sp )
{
const spell fake_spell( sp.id );
Expand All @@ -3086,7 +3093,11 @@ static void draw_spellbook_info( const spell_type &sp )
ImGui::TextColored( c_yellow, "%s", spell_class.c_str() );

ImGui::NewLine();
cataimgui::draw_colored_text( sp.description.translated() );
std::vector<std::string> lines = string_split( sp.description.translated(), '\n' );
for( std::string &l : lines ) {
cataimgui::TextColoredParagraph( c_white, l );
ImGui::NewLine();
}
ImGui::NewLine();

cataimgui::draw_colored_text( string_format( "%s: %d", _( "Difficulty" ),
Expand Down Expand Up @@ -3174,10 +3185,8 @@ float spellbook_callback::desired_extra_space_right( )

void spellbook_callback::refresh( uilist *menu )
{
ImVec2 info_size = { desired_extra_space_right( ),
desired_extra_space_right( ) * 3.0f * 1.62f
};
ImGui::TableSetColumnIndex( 2 );
ImVec2 info_size = ImGui::GetContentRegionAvail();
if( ImGui::BeginChild( "spellbook info", info_size, false,
ImGuiWindowFlags_AlwaysAutoResize ) ) {
if( menu->selected >= 0 && static_cast<size_t>( menu->selected ) < spells.size() ) {
Expand Down
88 changes: 87 additions & 1 deletion src/main_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "auto_pickup.h"
#include "avatar.h"
#include "cata_imgui.h"
#include "cata_scope_helpers.h"
#include "cata_utility.h"
#include "catacharset.h"
Expand Down Expand Up @@ -52,7 +53,6 @@
#include "wcwidth.h"
#include "worldfactory.h"

#include "cata_imgui.h"
#include "imgui/imgui.h"

class demo_ui : public cataimgui::window
Expand All @@ -68,10 +68,18 @@ class demo_ui : public cataimgui::window
void on_resized() override {
init();
};

private:
std::shared_ptr<cataimgui::Paragraph> stuff;
};

demo_ui::demo_ui() : cataimgui::window( _( "ImGui Demo Screen" ) )
{
// char *text = "Some long text that will wrap around nicely. </color> <color_green><color_red>Some red text in the </color>middle.</color> Some long text that will <color_light_blue_yellow>wrap around nicely.";
db48x marked this conversation as resolved.
Show resolved Hide resolved
std::string text =
"Some long text that will wrap around nicely. <color_red>Some red text in the middle.</color> Some long text that will wrap around nicely.";
stuff = std::make_shared<cataimgui::Paragraph>();
stuff->append_colored_text( text, c_white );
}

cataimgui::bounds demo_ui::get_bounds()
Expand All @@ -81,7 +89,85 @@ cataimgui::bounds demo_ui::get_bounds()

void demo_ui::draw_controls()
{
#ifndef TUI
ImGui::ShowDemoWindow();
#endif

#ifdef TUI
ImGui::SetNextWindowPos( { 0, 0 }, ImGuiCond_Once );
ImGui::SetNextWindowSize( { 60, 40 }, ImGuiCond_Once );
#else
ImGui::SetNextWindowSize( { 620, 900 }, ImGuiCond_Once );
#endif
if( ImGui::Begin( "test" ) ) {
#ifdef TUI
static float wrap_width = 50.0f;
ImGui::SliderFloat( "Wrap width", &wrap_width, 1, 60, "%.0f" );
float marker_size = 0.0f;
#else
static float wrap_width = 200.0f;
ImGui::SliderFloat( "Wrap width", &wrap_width, -20, 600, "%.0f" );
float marker_size = ImGui::GetTextLineHeight();
#endif

#define WRAP_START() \
ImDrawList *draw_list = ImGui::GetWindowDrawList(); \
ImVec2 pos = ImGui::GetCursorScreenPos(); \
ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y); \
ImVec2 marker_max = \
ImVec2(pos.x + wrap_width + marker_size, pos.y + marker_size); \
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);

#define WRAP_END() \
draw_list->AddRectFilled(marker_min, marker_max, \
IM_COL32(255, 0, 255, 255)); \
ImGui::PopTextWrapPos();

// three sentences in a nicely–wrapped paragraph
if( ImGui::CollapsingHeader( "Plain wrapped text" ) ) {
WRAP_START();
ImGui::TextWrapped( "%s",
"Some long text that will wrap around nicely. Some red text in the middle. Some long text that will wrap around nicely." );
WRAP_END();
ImGui::NewLine();
}

if( ImGui::CollapsingHeader( "Styled Paragraph" ) ) {
WRAP_START();
cataimgui::TextStyled( stuff, wrap_width );
WRAP_END();
ImGui::NewLine();
}

if( ImGui::CollapsingHeader( "Unstyled Paragraph" ) ) {
WRAP_START();
cataimgui::TextUnstyled( stuff, wrap_width );
WRAP_END();
ImGui::NewLine();
}

if( ImGui::CollapsingHeader( "Styled Paragraph, no allocations" ) ) {
WRAP_START();
cataimgui::TextParagraph( c_white, "Some long text that will wrap around nicely.", wrap_width );
cataimgui::TextParagraph( c_red, " Some red text in the middle.", wrap_width );
cataimgui::TextParagraph( c_white, " Some long text that will wrap around nicely.", wrap_width );
ImGui::NewLine();
WRAP_END();
ImGui::NewLine();
}

if( ImGui::CollapsingHeader( "Naive attempt" ) ) {
WRAP_START();
// same three sentences, but the color breaks the wrapping
ImGui::TextUnformatted( "Some long text that will wrap around nicely." );
ImGui::SameLine();
ImGui::TextColored( c_red, "%s", "Some red text in the middle." );
ImGui::SameLine();
ImGui::TextUnformatted( "Some long text that will wrap around nicely." );
WRAP_END();
}
}
ImGui::End();
}

void demo_ui::init()
Expand Down
Loading
Loading