Enable sorting campaign list in chronological or lexicographical order

This commit is contained in:
Celtic Minstrel 2017-08-12 23:18:06 -04:00
parent 1fe8ed3a13
commit 25a0d099a9
29 changed files with 509 additions and 18 deletions

View file

@ -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.

View file

@ -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"

View file

@ -22,6 +22,8 @@
name= _ "Delfadors 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

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -32,6 +32,8 @@
id=LOW
define=CAMPAIGN_LOW
rank=125
start_year="20 YW"
end_year="93 YW"
type=hybrid

View file

@ -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)"

View file

@ -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

View file

@ -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"

View file

@ -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")}

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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" />

View file

@ -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">

View file

@ -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

View file

@ -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

View file

@ -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();
}

View file

@ -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

View file

@ -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();

View file

@ -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

View 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()

View 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);
}

View 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);