Allow custom nicknames/profession names to use format specifiers

Also prevent selecting/applying operations to uneditable units
develop
lethosor 2015-01-09 15:05:49 -05:00
parent 21e96ba369
commit b5797daa8a
1 changed files with 152 additions and 40 deletions

@ -32,6 +32,7 @@
#include "uicommon.h"
using std::stringstream;
using std::set;
using std::vector;
using std::string;
@ -287,6 +288,13 @@ enum altsort_mode {
ALTSORT_MAX
};
string itos (int n)
{
stringstream ss;
ss << n;
return ss.str();
}
bool descending;
df::job_skill sort_skill;
df::unit_labor sort_labor;
@ -391,43 +399,130 @@ bool sortBySelected (const UnitInfo *d1, const UnitInfo *d2)
template<typename T>
class StringFormatter {
public:
typedef std::tuple<string, string, string(*)(T)> T_opt;
typedef string(*T_callback)(T);
typedef std::tuple<string, string, T_callback> T_opt;
typedef vector<T_opt> T_optlist;
static bool compare_opts(const T_opt &first, const T_opt &second)
{
// Sort by option length, decreasing
return std::get<0>(first).size() > std::get<0>(second).size();
}
StringFormatter() {}
void add_option(string spec, string help, string (*callback)(T))
{
format_options.push_back(std::make_tuple(spec, help, callback));
opt_list.push_back(std::make_tuple(spec, help, callback));
std::sort(opt_list.begin(), opt_list.end(), StringFormatter<T>::compare_opts);
}
T_optlist *get_options() { return &opt_list; }
void clear_options()
{
opt_list.clear();
}
string grab_opt (string s, size_t start)
{
for (auto it = opt_list.begin(); it != opt_list.end(); ++it)
{
string opt = std::get<0>(*it);
if (opt == s.substr(start, opt.size()))
return opt;
}
return "";
}
T_callback get_callback (string s)
{
for (auto it = opt_list.begin(); it != opt_list.end(); ++it)
{
if (std::get<0>(*it) == s)
return std::get<2>(*it);
}
return NULL;
}
T_optlist *get_options() { return &format_options; }
void clear_options() { format_options.clear(); }
string format (T obj, string fmt)
{
return fmt;
string dest = "";
bool in_opt = false;
size_t i = 0;
while (i < fmt.size())
{
if (in_opt)
{
if (fmt[i] == '%')
{
// escape: %% -> %
in_opt = false;
dest.push_back('%');
i++;
}
else
{
string opt = grab_opt(fmt, i);
if (opt.size())
{
T_callback func = get_callback(opt);
if (func != NULL)
dest += func(obj);
i += opt.size();
}
else
{
// Unrecognized format option; replace with original text
dest.push_back('%');
in_opt = false;
}
}
}
else
{
if (fmt[i] == '%')
in_opt = true;
else
dest.push_back(fmt[i]);
i++;
}
}
return dest;
}
protected:
T_optlist format_options;
T_optlist opt_list;
};
namespace unit_ops {
std::string get_real_name(df::unit *u)
{ return Translation::TranslateName(&u->name); }
std::string get_nickname(df::unit *u)
{ return Translation::TranslateName(Units::getVisibleName(u)); }
std::string get_real_name_eng(df::unit *u)
{ return Translation::TranslateName(&u->name, true); }
std::string get_nickname_eng(df::unit *u)
{ return Translation::TranslateName(Units::getVisibleName(u), true); }
void set_nickname(df::unit *u, std::string nick)
{ Units::setNickname(u, nick); }
void set_profname(df::unit *u, std::string prof)
{ u->custom_profession = prof; }
string get_real_name(UnitInfo *u)
{ return Translation::TranslateName(&u->unit->name, false); }
string get_nickname(UnitInfo *u)
{ return Translation::TranslateName(Units::getVisibleName(u->unit), false); }
string get_real_name_eng(UnitInfo *u)
{ return Translation::TranslateName(&u->unit->name, true); }
string get_nickname_eng(UnitInfo *u)
{ return Translation::TranslateName(Units::getVisibleName(u->unit), true); }
string get_profname(UnitInfo *u)
{ return Units::getProfessionName(u->unit); }
string get_real_profname(UnitInfo *u)
{
string tmp = u->unit->custom_profession;
u->unit->custom_profession = "";
string ret = get_profname(u);
u->unit->custom_profession = tmp;
return ret;
}
void set_nickname(UnitInfo *u, std::string nick)
{
Units::setNickname(u->unit, nick);
u->name = get_nickname(u);
u->transname = get_nickname_eng(u);
}
void set_profname(UnitInfo *u, std::string prof)
{
u->unit->custom_profession = prof;
u->profession = get_profname(u);
}
}
class viewscreen_unitbatchopst : public dfhack_viewscreen {
public:
enum page { MENU, NICKNAME, PROFNAME };
viewscreen_unitbatchopst(vector<UnitInfo*> *units)
:cur_page(MENU), entry(""), units(units)
:cur_page(MENU), entry(""), units(units), selection_empty(false)
{
menu_options.multiselect = false;
menu_options.auto_select = true;
@ -440,8 +535,16 @@ public:
menu_options.filterDisplay();
formatter.add_option("n", "Displayed name (or nickname)", unit_ops::get_nickname);
formatter.add_option("N", "Real name", unit_ops::get_real_name);
formatter.add_option("en", "Displayed name (or nickname), English", unit_ops::get_nickname_eng);
formatter.add_option("eN", "Real name, English", unit_ops::get_real_name_eng);
formatter.add_option("en", "Displayed name (or nickname), in English", unit_ops::get_nickname_eng);
formatter.add_option("eN", "Real name, in English", unit_ops::get_real_name_eng);
formatter.add_option("p", "Displayed profession", unit_ops::get_profname);
formatter.add_option("P", "Real profession", unit_ops::get_real_profname);
selection_empty = true;
for (auto it = units->begin(); it != units->end(); ++it)
{
if ((*it)->selected)
selection_empty = false;
}
}
std::string getFocusString() { return "unitlabors/batch"; }
void select_page (page p)
@ -450,16 +553,12 @@ public:
entry = "";
cur_page = p;
}
string format_string(df::unit* u, string format)
{
return format;
}
void apply(void (*func)(df::unit*, string), string arg, StringFormatter<df::unit*> *arg_formatter)
void apply(void (*func)(UnitInfo*, string), string arg, StringFormatter<UnitInfo*> *arg_formatter)
{
for (auto it = units->begin(); it != units->end(); ++it)
{
df::unit* u = (*it)->unit;
if (!u) continue;
UnitInfo* u = (*it);
if (!u || !u->unit || !u->selected || !u->allowEdit) continue;
string cur_arg = arg_formatter->format(u, arg);
func(u, cur_arg);
}
@ -473,6 +572,8 @@ public:
Screen::dismiss(this);
return;
}
if (selection_empty)
return;
if (menu_options.feed(events))
{
// Allow left mouse button to trigger menu options
@ -510,27 +611,35 @@ public:
{
dfhack_viewscreen::render();
Screen::clear();
int x = 2, y = 2;
if (cur_page == MENU)
{
Screen::drawBorder(" Dwarf Manipulator - Batch Operations ");
if (selection_empty)
{
OutputString(COLOR_LIGHTRED, x, y, "No dwarves selected!");
return;
}
menu_options.display(true);
}
else if (cur_page == NICKNAME || cur_page == PROFNAME)
{
std::string name_type = (cur_page == page::NICKNAME) ? "Nickname" : "Profession name";
int x = 2, y = 2;
OutputString(COLOR_GREY, x, y, "Custom " + name_type + ":");
x = 2; y = 4;
x = 2; y += 2;
OutputString(COLOR_WHITE, x, y, entry);
OutputString(COLOR_LIGHTGREEN, x, y, "_");
x = 2; y = 6;
StringFormatter<df::unit*>::T_optlist *format_options = formatter.get_options();
x = 2; y += 2;
OutputString(COLOR_DARKGREY, x, y, "(Leave blank to use original name)");
x = 2; y += 2;
OutputString(COLOR_WHITE, x, y, "Format options:");
StringFormatter<UnitInfo*>::T_optlist *format_options = formatter.get_options();
for (auto it = format_options->begin(); it != format_options->end(); ++it)
{
x = 2; y++;
auto opt = *it;
OutputString(COLOR_LIGHTCYAN, x, y, "%" + string(std::get<0>(opt)));
OutputString(COLOR_WHITE, x, y, ": " + string(std::get<1>(opt)));
x = 2; y++;
}
}
}
@ -539,7 +648,8 @@ protected:
page cur_page;
string entry;
vector<UnitInfo*> *units;
StringFormatter<df::unit*> formatter;
StringFormatter<UnitInfo*> formatter;
bool selection_empty;
private:
void resize(int32_t x, int32_t y)
{
@ -1193,12 +1303,13 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
i++)
{
if (i == last_selection) continue;
if (!units[i]->allowEdit) continue;
units[i]->selected = units[last_selection]->selected;
}
}
}
if (events->count(interface_key::CUSTOM_X))
if (events->count(interface_key::CUSTOM_X) && cur->allowEdit)
{
cur->selected = !cur->selected;
last_selection = input_row;
@ -1207,6 +1318,7 @@ void viewscreen_unitlaborsst::feed(set<df::interface_key> *events)
if (events->count(interface_key::CUSTOM_A) || events->count(interface_key::CUSTOM_SHIFT_A))
{
for (size_t i = 0; i < units.size(); i++)
if (units[i]->allowEdit)
units[i]->selected = (bool)events->count(interface_key::CUSTOM_A);
}
@ -1309,10 +1421,10 @@ void viewscreen_unitlaborsst::render()
fg = 10; // 2:1
Screen::paintString(Screen::Pen(' ', fg, bg), col_offsets[DISP_COLUMN_STRESS], 4 + row, stress);
if (cur->selected)
Screen::paintTile(Screen::Pen('\373', 10, 0), col_offsets[DISP_COLUMN_SELECTED], 4 + row);
else
Screen::paintTile(Screen::Pen('-', 8, 0), col_offsets[DISP_COLUMN_SELECTED], 4 + row);
Screen::paintTile(
(cur->selected) ? Screen::Pen('\373', COLOR_LIGHTGREEN, 0) :
((cur->allowEdit) ? Screen::Pen('-', COLOR_DARKGREY, 0) : Screen::Pen('-', COLOR_RED, 0)),
col_offsets[DISP_COLUMN_SELECTED], 4 + row);
fg = 15;
if (row_offset == sel_row)