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

Truncate displayed ship names to prevent overflowing containers #2631

Merged
merged 4 commits into from
Jun 16, 2017
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
3 changes: 2 additions & 1 deletion source/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,10 +520,11 @@ void Engine::Step(bool isActive)
}
else
{
const Font &font = FontSet::Get(14);
if(target->GetSystem() == player.GetSystem() && target->Cloaking() < 1.)
targetUnit = target->Facing().Unit();
info.SetSprite("target sprite", target->GetSprite(), targetUnit, target->GetFrameIndex(step));
info.SetString("target name", target->Name());
info.SetString("target name", font.TruncateMiddle(target->Name(), 150));
info.SetString("target type", target->ModelName());
if(!target->GetGovernment())
info.SetString("target government", "No Government");
Expand Down
40 changes: 40 additions & 0 deletions source/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,46 @@ string Font::TruncateFront(const string &str, int width) const



string Font::TruncateMiddle(const string &str, int width) const
{
int prevChars = str.size();
int prevWidth = Width(str);
if(prevWidth <= width)
return str;

width -= Width("...");
// As a safety against infinite loops (even though they won't be possible if
// this implementation is correct), limit the number of loops to the number
// of characters in the string.
for(size_t i = 0; i < str.length(); ++i)
{
// Loop until the previous width we tried was too long and this one is
// too short, or vice versa. Each time, the next string length we try is
// interpolated from the previous width.
int nextChars = (prevChars * width) / prevWidth;
bool isSame = (nextChars == prevChars);
bool prevWorks = (prevWidth <= width);
nextChars += (prevWorks ? isSame : -isSame);

int leftChars = nextChars / 2;
int rightChars = nextChars - leftChars;
int nextWidth = Width(str.substr(0, leftChars) + str.substr(str.size() - rightChars));
bool nextWorks = (nextWidth <= width);
if(prevWorks != nextWorks && abs(nextChars - prevChars) == 1)
{
leftChars = min(prevChars,nextChars) / 2;
rightChars = min(prevChars, nextChars) - leftChars;
return str.substr(0, leftChars) + "..." + str.substr(str.size() - rightChars);
}

prevChars = nextChars;
prevWidth = nextWidth;
}
return str;
}



int Font::Height() const
{
return height;
Expand Down
1 change: 1 addition & 0 deletions source/Font.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Font {
int Width(const char *str, char after = ' ') const;
std::string Truncate(const std::string &str, int width) const;
std::string TruncateFront(const std::string &str, int width) const;
std::string TruncateMiddle(const std::string &str, int width) const;

int Height() const;

Expand Down
4 changes: 3 additions & 1 deletion source/HailPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.
#include "HailPanel.h"

#include "DrawList.h"
#include "Font.h"
#include "FontSet.h"
#include "Format.h"
#include "GameData.h"
Expand Down Expand Up @@ -43,8 +44,9 @@ HailPanel::HailPanel(PlayerInfo &player, const shared_ptr<Ship> &ship)
SetInterruptible(false);

const Government *gov = ship->GetGovernment();
const Font &font = FontSet::Get(14);
if(!ship->Name().empty())
header = gov->GetName() + " " + ship->Noun() + " \"" + ship->Name() + "\":";
header = font.Truncate(gov->GetName() + " " + ship->Noun() + " \"" + ship->Name(), 328) + "\":";
else
header = ship->ModelName() + " (" + gov->GetName() + "): ";
// Drones are always unpiloted, so they never respond to hails.
Expand Down
3 changes: 2 additions & 1 deletion source/PlayerInfoPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ void PlayerInfoPanel::DrawFleet(const Rectangle &bounds)
// Loop through all the player's ships.
int index = scroll;
auto sit = player.Ships().begin() + scroll;
const Font &font = FontSet::Get(14);
for( ; sit < player.Ships().end(); ++sit)
{
// Bail out if we've used out the whole drawing area.
Expand All @@ -472,7 +473,7 @@ void PlayerInfoPanel::DrawFleet(const Rectangle &bounds)
zones.emplace_back(table.GetCenterPoint(), table.GetRowSize(), index);

// Indent the ship name if it is a fighter or drone.
table.Draw(ship.CanBeCarried() ? " " + ship.Name() : ship.Name());
table.Draw(font.TruncateMiddle(ship.CanBeCarried() ? " " + ship.Name() : ship.Name(), 217));
table.Draw(ship.ModelName());

const System *system = ship.GetSystem();
Expand Down
32 changes: 18 additions & 14 deletions source/ShipInfoPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.

using namespace std;

namespace {
static const double WIDTH = 250.;
}


ShipInfoPanel::ShipInfoPanel(PlayerInfo &player, int index)
Expand Down Expand Up @@ -273,24 +276,25 @@ void ShipInfoPanel::UpdateInfo()
void ShipInfoPanel::DrawShipStats(const Rectangle &bounds)
{
// Check that the specified area is big enough.
if(bounds.Width() < 250.)
if(bounds.Width() < WIDTH)
return;

// Colors to draw with.
Color dim = *GameData::Colors().Get("medium");
Color bright = *GameData::Colors().Get("bright");
const Ship &ship = **shipIt;
const Font &font = FontSet::Get(14);

// Table attributes.
Table table;
table.AddColumn(0, Table::LEFT);
table.AddColumn(230, Table::RIGHT);
table.SetUnderline(0, 230);
table.AddColumn(WIDTH - 20, Table::RIGHT);
table.SetUnderline(0, WIDTH - 20);
table.DrawAt(bounds.TopLeft() + Point(10., 8.));

// Draw the ship information.
table.Draw("ship:", dim);
table.Draw(ship.Name(), bright);
table.Draw(font.TruncateMiddle(ship.Name(), WIDTH - 50), bright);

table.Draw("model:", dim);
table.Draw(ship.ModelName(), bright);
Expand All @@ -303,7 +307,7 @@ void ShipInfoPanel::DrawShipStats(const Rectangle &bounds)
void ShipInfoPanel::DrawOutfits(const Rectangle &bounds, Rectangle &cargoBounds)
{
// Check that the specified area is big enough.
if(bounds.Width() < 250.)
if(bounds.Width() < WIDTH)
return;

// Colors to draw with.
Expand All @@ -314,8 +318,8 @@ void ShipInfoPanel::DrawOutfits(const Rectangle &bounds, Rectangle &cargoBounds)
// Table attributes.
Table table;
table.AddColumn(0, Table::LEFT);
table.AddColumn(230, Table::RIGHT);
table.SetUnderline(0, 230);
table.AddColumn(WIDTH - 20, Table::RIGHT);
table.SetUnderline(0, WIDTH - 20);
Point start = bounds.TopLeft() + Point(10., 8.);
table.DrawAt(start);

Expand All @@ -330,8 +334,8 @@ void ShipInfoPanel::DrawOutfits(const Rectangle &bounds, Rectangle &cargoBounds)
// plus at least one outfit.
if(table.GetRowBounds().Bottom() + 40. > bounds.Bottom())
{
start += Point(250., 0.);
if(start.X() + 230. > bounds.Right())
start += Point(WIDTH, 0.);
if(start.X() + WIDTH - 20 > bounds.Right())
break;
table.DrawAt(start);
}
Expand All @@ -344,8 +348,8 @@ void ShipInfoPanel::DrawOutfits(const Rectangle &bounds, Rectangle &cargoBounds)
// Check if we've gone below the bottom of the bounds.
if(table.GetRowBounds().Bottom() > bounds.Bottom())
{
start += Point(250., 0.);
if(start.X() + 230. > bounds.Right())
start += Point(WIDTH, 0.);
if(start.X() + WIDTH - 20 > bounds.Right())
break;
table.DrawAt(start);
table.Draw(category, bright);
Expand Down Expand Up @@ -385,7 +389,7 @@ void ShipInfoPanel::DrawWeapons(const Rectangle &bounds)
const Sprite *sprite = ship.GetSprite();
double scale = 0.;
if(sprite)
scale = min(240. / sprite->Width(), 240. / sprite->Height());
scale = min((WIDTH - 10) / sprite->Width(), (WIDTH - 10) / sprite->Height());

// Figure out the left- and right-most hardpoints on the ship. If they are
// too far apart, the scale may need to be reduced.
Expand Down Expand Up @@ -497,8 +501,8 @@ void ShipInfoPanel::DrawCargo(const Rectangle &bounds)
const CargoHold &cargo = (player.Cargo().Used() ? player.Cargo() : ship.Cargo());
Table table;
table.AddColumn(0, Table::LEFT);
table.AddColumn(230, Table::RIGHT);
table.SetUnderline(-5, 235);
table.AddColumn(WIDTH - 20, Table::RIGHT);
table.SetUnderline(-5, WIDTH - 15);
table.DrawAt(bounds.TopLeft() + Point(10., 8.));

double endY = bounds.Bottom() - 30. * (cargo.Passengers() != 0);
Expand Down
9 changes: 6 additions & 3 deletions source/ShipyardPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,12 @@ bool ShipyardPanel::CanSell() const
void ShipyardPanel::Sell()
{
static const int MAX_LIST = 20;
static const int MAX_NAME_WIDTH = 250 - 30;

int count = playerShips.size();
int initialCount = count;
string message = "Sell ";
const Font &font = FontSet::Get(14);
if(count == 1)
message += playerShip->Name();
else if(count <= MAX_LIST)
Expand All @@ -255,16 +257,17 @@ void ShipyardPanel::Sell()
else
{
while(count-- > 1)
message += ",\n" + (*it++)->Name();
message += ",\n" + font.TruncateMiddle((*it++)->Name(), MAX_NAME_WIDTH);
message += ",\nand ";
}
message += (*it)->Name();
}
else
{
auto it = playerShips.begin();
for(int i = 0; i < MAX_LIST - 1; ++i)
message += (*it++)->Name() + ",\n";
message += (*it++)->Name() + ",\n";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional to not truncate the first ship's name?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was indeed intentional, because the first line doesn't start with the ship's name and thus has different wrapping behavior than all the other lines.

for(int i = 1; i < MAX_LIST - 1; ++i)
message += font.TruncateMiddle((*it++)->Name(), MAX_NAME_WIDTH) + ",\n";

message += "and " + Format::Number(count - (MAX_LIST - 1)) + " other ships";
}
Expand Down
2 changes: 1 addition & 1 deletion source/ShopPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,8 @@ void ShopPanel::DrawShip(const Ship &ship, const Point &center, bool isSelected)
float zoomSize = SHIP_SIZE - 60.f;

// Draw the ship name.
const string &name = ship.Name().empty() ? ship.ModelName() : ship.Name();
const Font &font = FontSet::Get(14);
const string &name = ship.Name().empty() ? ship.ModelName() : font.TruncateMiddle(ship.Name(), SIDE_WIDTH - 61);
Point offset(-.5f * font.Width(name), -.5f * SHIP_SIZE + 10.f);
font.Draw(name, center + offset, *GameData::Colors().Get("bright"));

Expand Down