Enable sorting campaign list in chronological or lexicographical order
This commit is contained in:
parent
1fe8ed3a13
commit
25a0d099a9
29 changed files with 509 additions and 18 deletions
|
@ -11,6 +11,8 @@
|
|||
name= _ "An Orcish Incursion"
|
||||
abbrev= _ "AOI"
|
||||
rank=10
|
||||
start_year="8 YW"
|
||||
end_year="9 YW"
|
||||
first_scenario=01_Defend_the_Forest
|
||||
define="CAMPAIGN_AN_ORCISH_INCURSION"
|
||||
description=_ "Defend the forests of the elves against the first orcs to reach the Great Continent, learning valuable tactics as you do so.
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
[campaign]
|
||||
id=Dead_Water
|
||||
rank=170
|
||||
start_year="626 YW"
|
||||
end_year="627 YW"
|
||||
icon="units/undead/soulless-swimmer.png~RC(magenta>blue)"
|
||||
name= _ "Dead Water"
|
||||
abbrev= _ "DW"
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
name= _ "Delfador’s Memoirs"
|
||||
abbrev=_ "DM"
|
||||
rank=160
|
||||
start_year="468 YW"
|
||||
end_year="470 YW"
|
||||
icon="units/human-magi/elder-mage.png~RC(magenta>red)"
|
||||
image="data/campaigns/Delfadors_Memoirs/images/campaign_image.png"
|
||||
first_scenario=01_Overture
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
[campaign]
|
||||
id=Descent_into_Darkness
|
||||
rank=150
|
||||
start_year="389 YW"
|
||||
end_year="390 YW"
|
||||
icon="data/campaigns/Descent_Into_Darkness/images/units/dark-mage.png~RC(magenta>red)"
|
||||
image="data/campaigns/Descent_Into_Darkness/images/campaign_image.png"
|
||||
name= _ "Descent into Darkness"
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
[campaign]
|
||||
id=Eastern_Invasion
|
||||
rank=130
|
||||
start_year="625 YW"
|
||||
end_year="627 YW"
|
||||
icon="units/human-loyalists/general.png~RC(magenta>red)"
|
||||
name= _ "Eastern Invasion"
|
||||
abbrev= _ "EI"
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
image="data/campaigns/Heir_To_The_Throne/images/campaign_image.png"
|
||||
abbrev= _ "HttT"
|
||||
rank=20
|
||||
start_year="517 YW"
|
||||
end_year="518 YW"
|
||||
define=CAMPAIGN_HEIR_TO_THE_THRONE
|
||||
first_scenario=01_The_Elves_Besieged
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
id=LOW
|
||||
define=CAMPAIGN_LOW
|
||||
rank=125
|
||||
start_year="20 YW"
|
||||
end_year="93 YW"
|
||||
|
||||
type=hybrid
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
name= _ "Liberty"
|
||||
abbrev= _ "Liberty"
|
||||
rank=110
|
||||
year="501 YW"
|
||||
first_scenario=01_The_Raid
|
||||
define=CAMPAIGN_LIBERTY
|
||||
icon="units/human-outlaws/fugitive.png~RC(magenta>red)"
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
name= _ "Northern Rebirth"
|
||||
abbrev= _ "NR"
|
||||
rank=240
|
||||
start_year="534 YW"
|
||||
end_year="535 YW"
|
||||
first_scenario=01_Breaking_the_Chains
|
||||
define=CAMPAIGN_NORTHERN_REBIRTH
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
name= _ "The Sceptre of Fire"
|
||||
abbrev= _ "SoF"
|
||||
rank=215
|
||||
start_year="25 YW"
|
||||
end_year="40 YW"
|
||||
define="CAMPAIGN_SCEPTRE_FIRE"
|
||||
extra_defines=ENABLE_DWARVISH_RUNESMITH
|
||||
first_scenario="1_A_Bargain_is_Struck"
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
name= _ "Secrets of the Ancients"
|
||||
abbrev= _ "SotA"
|
||||
rank=180
|
||||
start_year="22 YW"
|
||||
end_year="23 YW"
|
||||
first_scenario=01_Slipping_Away
|
||||
extra_defines=ENABLE_ANCIENT_LICH,ENABLE_DEATH_KNIGHT
|
||||
{CAMPAIGN_DIFFICULTY EASY "units/undead-skeletal/skeleton/skeleton-idle-2.png~RC(magenta>red)"( _ "Unpleasant") ( _ "Normal")}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
name= _ "Son of the Black-Eye"
|
||||
abbrev= _ "SotBE"
|
||||
rank=220
|
||||
start_year="842 YW"
|
||||
end_year="858 YW"
|
||||
first_scenario=01_End_of_Peace
|
||||
define=CAMPAIGN_SON_OF_THE_BLACK_EYE
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
image="data/campaigns/The_Hammer_of_Thursagan/images/campaign_image.png"
|
||||
abbrev= _ "THoT"
|
||||
rank=140
|
||||
start_year="550 YW"
|
||||
end_year="551 YW"
|
||||
define=CAMPAIGN_THE_HAMMER_OF_THURSAGAN
|
||||
first_scenario=01_At_the_East_Gate
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
[campaign]
|
||||
id=The_Rise_of_Wesnoth
|
||||
rank=230
|
||||
start_year="2 BW"
|
||||
end_year="1 YW"
|
||||
name= _ "The Rise of Wesnoth"
|
||||
icon="data/campaigns/The_Rise_Of_Wesnoth/images/units/noble-lord.png"
|
||||
image="data/campaigns/The_Rise_Of_Wesnoth/images/campaign_image.png"
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
define=CAMPAIGN_THE_SOUTH_GUARD
|
||||
rank=15
|
||||
start_year="607 YW"
|
||||
end_year="608 YW"
|
||||
|
||||
icon="data/campaigns/The_South_Guard/images/deoran/horseman-commander-defend.png"
|
||||
image="data/campaigns/The_South_Guard/images/campaign_image.png"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
[campaign]
|
||||
id=Two_Brothers
|
||||
rank=5
|
||||
year="363 YW"
|
||||
icon="units/human-loyalists/knight/knight.png~RC(magenta>red)~CROP(13,11,72,72)"
|
||||
image="data/campaigns/Two_Brothers/images/campaign_image.png"
|
||||
name= _ "A Tale of Two Brothers"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
image="data/campaigns/Under_the_Burning_Suns/images/campaign_image.png"
|
||||
abbrev= _ "UtBS"
|
||||
rank=250
|
||||
year="300 AF"
|
||||
define=CAMPAIGN_UNDER_THE_BURNING_SUNS
|
||||
first_scenario=01_The_Morning_After
|
||||
|
||||
|
|
|
@ -195,6 +195,61 @@
|
|||
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
[column]
|
||||
grow_factor = 0
|
||||
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_grow = true
|
||||
|
||||
[grid]
|
||||
[row]
|
||||
[column]
|
||||
grow_factor = 0
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_grow = true
|
||||
|
||||
[label]
|
||||
label = _"Sort by:"
|
||||
[/label]
|
||||
[/column]
|
||||
[column]
|
||||
grow_factor = 1
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_grow = true
|
||||
|
||||
[toggle_button]
|
||||
definition = "listbox_header"
|
||||
id = "sort_name"
|
||||
label = _"Name"
|
||||
tooltip = _"Sort by full campaign name in alphabetical order"
|
||||
[/toggle_button]
|
||||
[/column]
|
||||
[column]
|
||||
grow_factor = 1
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_grow = true
|
||||
|
||||
[toggle_button]
|
||||
definition = "listbox_header"
|
||||
id = "sort_time"
|
||||
label = _"Dates"
|
||||
tooltip = _"Sort in approximate chronological order of story events"
|
||||
[/toggle_button]
|
||||
[/column]
|
||||
[/row]
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[row]
|
||||
grow_factor = 1
|
||||
|
||||
|
|
|
@ -3006,6 +3006,14 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Tests\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Tests\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\tests\test_irdya_date.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">true</ExcludedFromBuild>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Tests\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Tests\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Tests\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Tests\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\tests\test_lexical_cast.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Tests\</ObjectFileName>
|
||||
|
@ -3284,6 +3292,12 @@
|
|||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)utils\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)utils\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\utils\irdya_datetime.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)utils\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)utils\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)utils\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)utils\</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\utils\make_enum.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)utils\</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)utils\</ObjectFileName>
|
||||
|
@ -4004,6 +4018,7 @@
|
|||
<ClInclude Include="..\..\src\utils\functional.hpp" />
|
||||
<ClInclude Include="..\..\src\utils\general.hpp" />
|
||||
<ClInclude Include="..\..\src\utils\io.hpp" />
|
||||
<ClInclude Include="..\..\src\utils\irdya_datetime.hpp" />
|
||||
<ClInclude Include="..\..\src\utils\iterable_pair.hpp" />
|
||||
<ClInclude Include="..\..\src\utils\make_enum.hpp" />
|
||||
<ClInclude Include="..\..\src\utils\markov_generator.hpp" />
|
||||
|
|
|
@ -1541,6 +1541,12 @@
|
|||
<ClCompile Include="..\..\src\preferences\lobby.cpp">
|
||||
<Filter>Preferences</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\utils\irdya_datetime.cpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\tests\test_irdya_date.cpp">
|
||||
<Filter>Tests</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\src\addon\client.hpp">
|
||||
|
@ -2988,6 +2994,9 @@
|
|||
<ClInclude Include="..\..\src\preferences\lobby.hpp">
|
||||
<Filter>Preferences</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\utils\irdya_datetime.hpp">
|
||||
<Filter>utils</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\tests\test_sdl_utils.hpp">
|
||||
|
|
|
@ -13,6 +13,7 @@ tests/test_formula_ai.cpp
|
|||
tests/test_formula_core.cpp
|
||||
tests/test_formula_function.cpp
|
||||
tests/test_image_modifications.cpp
|
||||
tests/test_irdya_date.cpp
|
||||
tests/test_lexical_cast.cpp
|
||||
tests/test_make_enum.cpp
|
||||
tests/test_map_location.cpp
|
||||
|
|
|
@ -387,6 +387,7 @@ units/types.cpp
|
|||
units/udisplay.cpp
|
||||
units/unit.cpp
|
||||
utils/context_free_grammar_generator.cpp
|
||||
utils/irdya_datetime.hpp
|
||||
utils/markov_generator.cpp
|
||||
utils/name_generator_factory.cpp
|
||||
variable.cpp
|
||||
|
|
|
@ -185,6 +185,16 @@ campaign::campaign(const config& data)
|
|||
, min_players_(2)
|
||||
, max_players_(2)
|
||||
{
|
||||
if(data.has_attribute("start_year")) {
|
||||
dates_.first = irdya_date::read_date(data["start_year"]);
|
||||
if(data.has_attribute("end_year")) {
|
||||
dates_.second = irdya_date::read_date(data["end_year"]);
|
||||
} else {
|
||||
dates_.second = dates_.first;
|
||||
}
|
||||
} else if(data.has_attribute("year")) {
|
||||
dates_.first = dates_.second = irdya_date::read_date(data["year"]);
|
||||
}
|
||||
set_metadata();
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "generators/map_generator.hpp"
|
||||
#include "mp_game_settings.hpp"
|
||||
#include "utils/make_enum.hpp"
|
||||
#include "utils/irdya_datetime.hpp"
|
||||
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
|
@ -253,6 +254,11 @@ public:
|
|||
return min_players_ <= player_count && max_players_ >= player_count;
|
||||
}
|
||||
|
||||
std::pair<irdya_date, irdya_date> dates() const
|
||||
{
|
||||
return dates_;
|
||||
}
|
||||
|
||||
private:
|
||||
campaign(const campaign&) = delete;
|
||||
void operator=(const campaign&) = delete;
|
||||
|
@ -262,6 +268,7 @@ private:
|
|||
std::string image_label_;
|
||||
int min_players_;
|
||||
int max_players_;
|
||||
std::pair<irdya_date, irdya_date> dates_;
|
||||
};
|
||||
|
||||
class create_engine
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "serialization/string_utils.hpp"
|
||||
|
||||
#include "utils/functional.hpp"
|
||||
#include "utils/irdya_datetime.hpp"
|
||||
#include "video.hpp"
|
||||
|
||||
namespace gui2
|
||||
|
@ -95,7 +96,11 @@ void campaign_selection::campaign_selected(window& window)
|
|||
|
||||
assert(tree.selected_item());
|
||||
if(tree.selected_item()->id() != "") {
|
||||
const unsigned choice = lexical_cast<unsigned>(tree.selected_item()->id());
|
||||
auto iter = std::find(page_ids_.begin(), page_ids_.end(), tree.selected_item()->id());
|
||||
const int choice = iter - page_ids_.begin();
|
||||
if(iter == page_ids_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
multi_page& pages = find_widget<multi_page>(&window, "campaign_details", false);
|
||||
pages.select_page(choice);
|
||||
|
@ -104,6 +109,78 @@ void campaign_selection::campaign_selected(window& window)
|
|||
|
||||
}
|
||||
|
||||
void campaign_selection::sort_campaigns(window& window, campaign_selection::CAMPAIGN_ORDER order, bool ascending)
|
||||
{
|
||||
using level_ptr = ng::create_engine::level_ptr;
|
||||
auto levels = engine_.get_levels_by_type_unfiltered(ng::level::TYPE::SP_CAMPAIGN);
|
||||
switch(order) {
|
||||
case RANK: // Already sorted by rank
|
||||
if(!ascending) {
|
||||
// This'll actually never happen, but who knows if that'll ever change...
|
||||
std::reverse(levels.begin(), levels.end());
|
||||
}
|
||||
break;
|
||||
case DATE:
|
||||
std::sort(levels.begin(), levels.end(), [ascending](const level_ptr& a, const level_ptr& b) {
|
||||
auto cpn_a = std::dynamic_pointer_cast<ng::campaign>(a), cpn_b = std::dynamic_pointer_cast<ng::campaign>(b);
|
||||
if(cpn_b == nullptr) return cpn_a != nullptr;
|
||||
if(cpn_a == nullptr) return false;
|
||||
return ascending ? cpn_a->dates().first < cpn_b->dates().first : cpn_a->dates().first > cpn_b->dates().first;
|
||||
});
|
||||
break;
|
||||
case NAME:
|
||||
std::sort(levels.begin(), levels.end(), [ascending](const level_ptr& a, const level_ptr& b) {
|
||||
int cmp = translation::icompare(a->name(), b->name());
|
||||
return ascending ? cmp < 0 : cmp > 0;
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
tree_view& tree = find_widget<tree_view>(&window, "campaign_tree", false);
|
||||
// Remember which campaign was selected...
|
||||
std::string was_selected = tree.selected_item()->id();
|
||||
tree.clear();
|
||||
for(const auto& level : levels) {
|
||||
add_campaign_to_tree(window, level->data());
|
||||
}
|
||||
|
||||
if(!was_selected.empty()) {
|
||||
tree_view_node& node = find_widget<tree_view_node>(&window, was_selected, false);
|
||||
node.select_node();
|
||||
}
|
||||
}
|
||||
|
||||
void campaign_selection::toggle_sorting_selection(window& window, CAMPAIGN_ORDER order) {
|
||||
static bool force = false;
|
||||
if(force) {
|
||||
return;
|
||||
}
|
||||
if(current_sorting_ == order) {
|
||||
if(currently_sorted_asc_) {
|
||||
currently_sorted_asc_ = false;
|
||||
} else {
|
||||
currently_sorted_asc_ = true;
|
||||
current_sorting_ = RANK;
|
||||
}
|
||||
} else if(current_sorting_ == RANK) {
|
||||
currently_sorted_asc_ = true;
|
||||
current_sorting_ = order;
|
||||
} else {
|
||||
currently_sorted_asc_ = true;
|
||||
current_sorting_ = order;
|
||||
force = true;
|
||||
if(order == NAME) {
|
||||
toggle_button& sort_time = find_widget<toggle_button>(&window, "sort_time", false);
|
||||
sort_time.set_value(0);
|
||||
} else if(order == DATE) {
|
||||
toggle_button& sort_name = find_widget<toggle_button>(&window, "sort_name", false);
|
||||
sort_name.set_value(0);
|
||||
}
|
||||
force = false;
|
||||
}
|
||||
sort_campaigns(window, current_sorting_, currently_sorted_asc_);
|
||||
}
|
||||
|
||||
void campaign_selection::pre_show(window& window)
|
||||
{
|
||||
/***** Setup campaign tree. *****/
|
||||
|
@ -112,33 +189,25 @@ void campaign_selection::pre_show(window& window)
|
|||
tree.set_selection_change_callback(
|
||||
std::bind(&campaign_selection::campaign_selected, this, std::ref(window)));
|
||||
|
||||
toggle_button& sort_name = find_widget<toggle_button>(&window, "sort_name", false);
|
||||
toggle_button& sort_time = find_widget<toggle_button>(&window, "sort_time", false);
|
||||
sort_name.set_callback_state_change(std::bind(&campaign_selection::toggle_sorting_selection, this, std::ref(window), NAME));
|
||||
sort_time.set_callback_state_change(std::bind(&campaign_selection::toggle_sorting_selection, this, std::ref(window), DATE));
|
||||
|
||||
window.keyboard_capture(&tree);
|
||||
|
||||
/***** Setup campaign details. *****/
|
||||
multi_page& pages = find_widget<multi_page>(&window, "campaign_details", false);
|
||||
|
||||
unsigned id = 0;
|
||||
for(const auto & level : engine_.get_levels_by_type_unfiltered(ng::level::TYPE::SP_CAMPAIGN)) {
|
||||
const config& campaign = level->data();
|
||||
|
||||
/*** Add tree item ***/
|
||||
std::map<std::string, string_map> data;
|
||||
string_map item;
|
||||
|
||||
item["label"] = campaign["icon"];
|
||||
data.emplace("icon", item);
|
||||
|
||||
item["label"] = campaign["name"];
|
||||
data.emplace("name", item);
|
||||
|
||||
item["label"] = campaign["completed"].to_bool() ? "misc/laurel.png" : "misc/blank-hex.png";
|
||||
data.emplace("victory", item);
|
||||
|
||||
tree.add_node("campaign", data).set_id(std::to_string(id++));
|
||||
add_campaign_to_tree(window, campaign);
|
||||
|
||||
/*** Add detail item ***/
|
||||
item.clear();
|
||||
data.clear();
|
||||
std::map<std::string, string_map> data;
|
||||
string_map item;
|
||||
|
||||
item["label"] = campaign["description"];
|
||||
item["use_markup"] = "true";
|
||||
|
@ -153,6 +222,7 @@ void campaign_selection::pre_show(window& window)
|
|||
data.emplace("image", item);
|
||||
|
||||
pages.add_page(data);
|
||||
page_ids_.push_back(campaign["id"]);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -184,6 +254,24 @@ void campaign_selection::pre_show(window& window)
|
|||
campaign_selected(window);
|
||||
}
|
||||
|
||||
void campaign_selection::add_campaign_to_tree(window& window, const config& campaign)
|
||||
{
|
||||
tree_view& tree = find_widget<tree_view>(&window, "campaign_tree", false);
|
||||
std::map<std::string, string_map> data;
|
||||
string_map item;
|
||||
|
||||
item["label"] = campaign["icon"];
|
||||
data.emplace("icon", item);
|
||||
|
||||
item["label"] = campaign["name"];
|
||||
data.emplace("name", item);
|
||||
|
||||
item["label"] = campaign["completed"].to_bool() ? "misc/laurel.png" : "misc/blank-hex.png";
|
||||
data.emplace("victory", item);
|
||||
|
||||
tree.add_node("campaign", data).set_id(campaign["id"]);
|
||||
}
|
||||
|
||||
void campaign_selection::post_show(window& window)
|
||||
{
|
||||
tree_view& tree = find_widget<tree_view>(&window, "campaign_tree", false);
|
||||
|
@ -194,7 +282,10 @@ void campaign_selection::post_show(window& window)
|
|||
|
||||
assert(tree.selected_item());
|
||||
if(tree.selected_item()->id() != "") {
|
||||
choice_ = lexical_cast<unsigned>(tree.selected_item()->id());
|
||||
auto iter = std::find(page_ids_.begin(), page_ids_.end(), tree.selected_item()->id());
|
||||
if(iter != page_ids_.end()) {
|
||||
choice_ = iter - page_ids_.begin();
|
||||
}
|
||||
}
|
||||
|
||||
deterministic_ = find_widget<toggle_button>(&window, "checkbox_deterministic", false).get_value_bool();
|
||||
|
|
|
@ -33,6 +33,7 @@ public:
|
|||
, choice_(-1)
|
||||
, deterministic_(false)
|
||||
, mod_states_()
|
||||
, current_sorting_(RANK)
|
||||
{
|
||||
set_restore(true);
|
||||
}
|
||||
|
@ -62,6 +63,15 @@ private:
|
|||
/** Inherited from modal_dialog. */
|
||||
virtual void post_show(window& window) override;
|
||||
|
||||
enum CAMPAIGN_ORDER {RANK, DATE, NAME} current_sorting_;
|
||||
bool currently_sorted_asc_ = true;
|
||||
|
||||
void sort_campaigns(window& window, CAMPAIGN_ORDER order, bool ascending);
|
||||
|
||||
void add_campaign_to_tree(window& window, const config& campaign);
|
||||
|
||||
void toggle_sorting_selection(window& window, CAMPAIGN_ORDER order);
|
||||
|
||||
void mod_toggled(window& window);
|
||||
|
||||
ng::create_engine& engine_;
|
||||
|
@ -73,6 +83,8 @@ private:
|
|||
bool deterministic_;
|
||||
|
||||
boost::dynamic_bitset<> mod_states_;
|
||||
|
||||
std::vector<std::string> page_ids_;
|
||||
};
|
||||
|
||||
} // namespace dialogs
|
||||
|
|
91
src/tests/test_irdya_date.cpp
Normal file
91
src/tests/test_irdya_date.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright (C) 2003 - 2017 by the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#define GETTEXT_DOMAIN "wesnoth-test"
|
||||
|
||||
#include "utils/irdya_datetime.hpp"
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(test_irdya_datetime)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_irdya_date_parse) {
|
||||
irdya_date BW_423 = irdya_date::read_date(" 423 BW ");
|
||||
irdya_date YW_123 = irdya_date::read_date(" 123 YW ");
|
||||
irdya_date BF_109 = irdya_date::read_date(" 109 BF ");
|
||||
irdya_date AF_928 = irdya_date::read_date(" 928 AF ");
|
||||
|
||||
BOOST_CHECK_EQUAL(BW_423.get_epoch(), irdya_date::EPOCH::BEFORE_WESNOTH);
|
||||
BOOST_CHECK_EQUAL(BW_423.get_year(), 423);
|
||||
BOOST_CHECK_EQUAL(YW_123.get_epoch(), irdya_date::EPOCH::WESNOTH);
|
||||
BOOST_CHECK_EQUAL(YW_123.get_year(), 123);
|
||||
BOOST_CHECK_EQUAL(BF_109.get_epoch(), irdya_date::EPOCH::BEFORE_FALL);
|
||||
BOOST_CHECK_EQUAL(BF_109.get_year(), 109);
|
||||
BOOST_CHECK_EQUAL(AF_928.get_epoch(), irdya_date::EPOCH::AFTER_FALL);
|
||||
BOOST_CHECK_EQUAL(AF_928.get_year(), 928);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_irdya_date_equal) {
|
||||
irdya_date first(EPOCH::WESNOTH, 12);
|
||||
irdya_date second(EPOCH::WESNOTH, 12);
|
||||
BOOST_CHECK_EQUAL(first, second);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_irdya_date_ordering) {
|
||||
irdya_date BW_34(EPOCH::BEFORE_WESNOTH, 34), BW_12(EPOCH::BEFORE_WESNOTH, 12), YW_40(EPOCH::WESNOTH, 40), YW_52(EPOCH::WESNOTH, 52);
|
||||
irdya_date BF_29(EPOCH::BEFORE_FALL, 29), BF_42(EPOCH::BEFORE_FALL, 42), AF_12(EPOCH::AFTER_FALL, 12), AF_102(EPOCH::AFTER_FALL, 102), Y0;
|
||||
|
||||
BOOST_CHECK(BW_34 < BW_12);
|
||||
BOOST_CHECK(BW_34 < YW_40);
|
||||
BOOST_CHECK(BW_34 < YW_52);
|
||||
BOOST_CHECK(BW_34 < BF_42);
|
||||
BOOST_CHECK(BW_34 < BF_29);
|
||||
BOOST_CHECK(BW_34 < AF_12);
|
||||
BOOST_CHECK(BW_34 < AF_102);
|
||||
BOOST_CHECK(BW_34 < Y0);
|
||||
|
||||
BOOST_CHECK(BW_12 < YW_40);
|
||||
BOOST_CHECK(BW_12 < YW_52);
|
||||
BOOST_CHECK(BW_12 < BF_42);
|
||||
BOOST_CHECK(BW_12 < BW_29);
|
||||
BOOST_CHECK(BW_12 < AF_12);
|
||||
BOOST_CHECK(BW_12 < AF_102);
|
||||
BOOST_CHECK(BW_12 < Y0);
|
||||
|
||||
BOOST_CHECK(YW_40 < YW_52);
|
||||
BOOST_CHECK(YW_40 < BF_42);
|
||||
BOOST_CHECK(Y@_40 < BF_29);
|
||||
BOOST_CHECK(YW_40 < AF_12);
|
||||
BOOST_CHECK(YW_40 < AF_102);
|
||||
BOOST_CHECK(YW_40 < Y0);
|
||||
|
||||
BOOST_CHECK(YW_52 < BF_42);
|
||||
BOOST_CHECK(YW_52 < BF_29);
|
||||
BOOST_CHECK(YW_52 < AF_12);
|
||||
BOOST_CHECK(YW_52 < AF_102);
|
||||
BOOST_CHECK(YW_52 < Y0);
|
||||
|
||||
BOOST_CHECK(BF_42 < BF_29);
|
||||
BOOST_CHECK(BF_42 < AF_12);
|
||||
BOOST_CHECK(BF_42 < AF_102);
|
||||
BOOST_CHECK(BF_42 < Y0);
|
||||
|
||||
BOOST_CHECK(BF_29 < AF_12);
|
||||
BOOST_CHECK(BF_29 < AF_102);
|
||||
BOOST_CHECK(BF_29 < Y0);
|
||||
|
||||
BOOST_CHECK(AF_12 < AF_102);
|
||||
BOOST_CHECK(AF_12 < Y0);
|
||||
BOOST_CHECK(AF_102 < Y0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
116
src/utils/irdya_datetime.cpp
Normal file
116
src/utils/irdya_datetime.cpp
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
Copyright (C) 2003 - 2017 by the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "utils/irdya_datetime.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include <exception>
|
||||
|
||||
irdya_date irdya_date::read_date(const std::string& date)
|
||||
{
|
||||
irdya_date date_result;
|
||||
// Currently only supports a year and an epoch.
|
||||
size_t year_start = date.find_first_not_of(' ');
|
||||
if(year_start == std::string::npos) {
|
||||
//throw std::invalid_argument("Irdya date is missing year");
|
||||
date_result.year = 0;
|
||||
return date_result;
|
||||
}
|
||||
size_t year_end = date.find_first_of(' ', year_start);
|
||||
if(year_end == std::string::npos) {
|
||||
year_end = date.size();
|
||||
}
|
||||
date_result.year = std::stoi(date.substr(year_start, year_end - year_start));
|
||||
size_t epoch_start = date.find_first_not_of(' ', year_end);
|
||||
if(epoch_start == std::string::npos) {
|
||||
date_result.epoch = EPOCH::WESNOTH;
|
||||
} else {
|
||||
size_t epoch_end = date.find_first_of(' ', epoch_start);
|
||||
date_result.epoch = EPOCH::string_to_enum(date.substr(epoch_start, epoch_end - epoch_start), EPOCH::WESNOTH);
|
||||
}
|
||||
return date_result;
|
||||
}
|
||||
|
||||
std::string irdya_date::to_string() const
|
||||
{
|
||||
std::string result = std::to_string(year) + " ";
|
||||
switch(epoch.v) {
|
||||
case EPOCH::BEFORE_WESNOTH:
|
||||
// TRANSLATORS: "Before Wesnoth" - epoch suffix for years prior to the founding of Wesnoth
|
||||
result += _("BW");
|
||||
break;
|
||||
case EPOCH::WESNOTH:
|
||||
// TRANSLATORS: "Year of Wesnoth" - epoch suffix for years after the founding of Wesnoth
|
||||
result += _("YW");
|
||||
break;
|
||||
case EPOCH::BEFORE_FALL:
|
||||
// TRANSLATORS: "Before the Fall" - epoch suffix for years prior to the fall of Wesnoth
|
||||
result += _("BF");
|
||||
break;
|
||||
case EPOCH::AFTER_FALL:
|
||||
// TRANSLATORS: "After the Fall" - epoch suffix for years after the fall of Wesonth
|
||||
result += _("AF");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator<(const irdya_date& a, const irdya_date& b)
|
||||
{
|
||||
if(!b.is_valid()) {
|
||||
return a.is_valid();
|
||||
}
|
||||
if(!a.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
if(a.get_epoch().v < b.get_epoch().v) {
|
||||
return true;
|
||||
}
|
||||
if(a.get_epoch().v > b.get_epoch().v) {
|
||||
return false;
|
||||
}
|
||||
using EPOCH = irdya_date::EPOCH;
|
||||
// The BW and BF epochs count backward, much like BCE
|
||||
if((a.get_epoch() == EPOCH::BEFORE_WESNOTH || a.get_epoch() == EPOCH::BEFORE_FALL) && a.get_year() > b.get_year()) {
|
||||
return true;
|
||||
}
|
||||
if(a.get_year() < b.get_year()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator>(const irdya_date& a, const irdya_date& b)
|
||||
{
|
||||
return b < a;
|
||||
}
|
||||
|
||||
bool operator<=(const irdya_date& a, const irdya_date& b)
|
||||
{
|
||||
return !(a > b);
|
||||
}
|
||||
|
||||
bool operator>=(const irdya_date& a, const irdya_date& b)
|
||||
{
|
||||
return !(a < b);
|
||||
}
|
||||
|
||||
bool operator==(const irdya_date& a, const irdya_date& b)
|
||||
{
|
||||
return a.get_year() == b.get_year() && a.get_epoch() == b.get_epoch();
|
||||
}
|
||||
|
||||
bool operator!=(const irdya_date& a, const irdya_date& b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
52
src/utils/irdya_datetime.hpp
Normal file
52
src/utils/irdya_datetime.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2003 - 2017 by the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils/make_enum.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class irdya_date {
|
||||
public:
|
||||
MAKE_ENUM(EPOCH,
|
||||
(BEFORE_WESNOTH, "BW")
|
||||
(WESNOTH, "YW")
|
||||
(BEFORE_FALL, "BF")
|
||||
(AFTER_FALL, "AF")
|
||||
);
|
||||
private:
|
||||
EPOCH epoch;
|
||||
unsigned int year = 0, month, day;
|
||||
// TODO: Decide how many months and days there are!
|
||||
public:
|
||||
static irdya_date read_date(const std::string& date);
|
||||
irdya_date() = default;
|
||||
irdya_date(EPOCH epoch, unsigned year) : epoch(epoch), year(year) {}
|
||||
|
||||
EPOCH get_epoch() const {return epoch;}
|
||||
unsigned int get_year() const {return year;}
|
||||
bool is_valid() const {
|
||||
// There is no year 0, so use that to represent an "invalid" date
|
||||
return year != 0;
|
||||
}
|
||||
// Outputs a locale-dependent string describing the year
|
||||
std::string to_string() const;
|
||||
};
|
||||
|
||||
bool operator<(const irdya_date& a, const irdya_date& b);
|
||||
bool operator<=(const irdya_date& a, const irdya_date& b);
|
||||
bool operator>(const irdya_date& a, const irdya_date& b);
|
||||
bool operator>=(const irdya_date& a, const irdya_date& b);
|
||||
bool operator==(const irdya_date& a, const irdya_date& b);
|
||||
bool operator!=(const irdya_date& a, const irdya_date& b);
|
Loading…
Add table
Reference in a new issue