← Back to team overview

widelands-dev team mailing list archive

Re: [Merge] lp:~widelands-dev/widelands/economy-target-profiles into lp:widelands

 

You can now get rid of the second_phase variable entirely. Just check for !anything_selected at the end of the loop, then you can also get rid of

		if (anything_selected) {
			return;
		}


Confirmed that the layouting is fixed. The ware statistics doesn't fit yet at 800x600 resolution, can you give it 1 less row for that?

Also added 1 comment.

Diff comments:

> 
> === modified file 'src/wui/economy_options_window.cc'
> --- src/wui/economy_options_window.cc	2019-02-23 11:00:49 +0000
> +++ src/wui/economy_options_window.cc	2019-05-16 17:28:26 +0000
> @@ -186,35 +281,402 @@
>  			const Widelands::Economy::TargetQuantity& tq = is_wares ?
>  			                                                  economy->ware_target_quantity(index) :
>  			                                                  economy->worker_target_quantity(index);
> -			// Don't allow negative new amount.
> -			if (amount >= 0 || -amount <= static_cast<int>(tq.permanent)) {
> -				if (is_wares) {
> -					game.send_player_command(*new Widelands::CmdSetWareTargetQuantity(
> -					   game.get_gametime(), player_->player_number(), serial_, index,
> -					   tq.permanent + amount));
> +			// Don't allow negative new amount
> +			const int old_amount = static_cast<int>(tq.permanent);
> +			const int new_amount = std::max(0, old_amount + delta);
> +			if (new_amount == old_amount) {
> +				continue;
> +			}
> +			if (is_wares) {
> +				game.send_player_command(*new Widelands::CmdSetWareTargetQuantity(
> +				   game.get_gametime(), player_->player_number(), serial_, index, new_amount));
> +			} else {
> +				game.send_player_command(*new Widelands::CmdSetWorkerTargetQuantity(
> +				   game.get_gametime(), player_->player_number(), serial_, index, new_amount));
> +			}
> +		}
> +	}
> +}
> +
> +void EconomyOptionsWindow::EconomyOptionsPanel::reset_target() {
> +	Widelands::Game& game = dynamic_cast<Widelands::Game&>(player_->egbase());
> +	const bool is_wares = type_ == Widelands::wwWARE;
> +	const auto& items = is_wares ? player_->tribe().wares() : player_->tribe().workers();
> +	const PredefinedTargets settings = economy_options_window_->get_selected_target();
> +
> +	bool anything_selected = false;
> +	bool second_phase = false;
> +
> +run_second_phase:
> +	for (const Widelands::DescriptionIndex& index : items) {
> +		if (display_.ware_selected(index) || (second_phase && !display_.is_ware_hidden(index))) {
> +			anything_selected = true;
> +			if (is_wares) {
> +				game.send_player_command(*new Widelands::CmdSetWareTargetQuantity(
> +						game.get_gametime(), player_->player_number(), serial_, index, settings.wares.at(index)));
> +			} else {
> +				game.send_player_command(*new Widelands::CmdSetWorkerTargetQuantity(
> +						game.get_gametime(), player_->player_number(), serial_, index, settings.workers.at(index)));
> +			}
> +		}
> +	}
> +
> +	if (!second_phase && !anything_selected) {
> +		// Nothing was selected, now go through the loop again and change everything
> +		second_phase = true;
> +		goto run_second_phase;
> +	}
> +}
> +
> +constexpr unsigned kThinkInterval = 200;
> +
> +void EconomyOptionsWindow::think() {
> +	const uint32_t time = player_->egbase().get_gametime();
> +	if (time - time_last_thought_ < kThinkInterval || !player_->get_economy(serial_)) {
> +		// If our economy has been deleted, die() was already called, no need to do anything
> +		return;
> +	}
> +	time_last_thought_ = time;
> +	update_profiles();
> +}
> +
> +std::string EconomyOptionsWindow::applicable_target() {
> +	const Widelands::Economy* eco = player_->get_economy(serial_);
> +	for (const auto& pair : predefined_targets_) {
> +		bool matches = true;
> +		if (tabpanel_.active() == 0) {
> +			for (const Widelands::DescriptionIndex& index : player_->tribe().wares()) {
> +				const auto it = pair.second.wares.find(index);
> +				if (it != pair.second.wares.end() && eco->ware_target_quantity(index).permanent != it->second) {
> +					matches = false;
> +					break;
> +				}
> +			}
> +		} else {
> +			for (const Widelands::DescriptionIndex& index : player_->tribe().workers()) {
> +				const auto it = pair.second.workers.find(index);
> +				if (it != pair.second.workers.end() && eco->worker_target_quantity(index).permanent != it->second) {
> +					matches = false;
> +					break;
> +				}
> +			}
> +		}
> +		if (matches) {
> +			return pair.first;
> +		}
> +	}
> +	return "";
> +}
> +
> +void EconomyOptionsWindow::update_profiles() {
> +	const std::string current_profile = applicable_target();
> +
> +	for (const auto& pair : predefined_targets_) {
> +		if (last_added_to_dropdown_.count(pair.first) == 0) {
> +			return update_profiles_needed(current_profile);
> +		}
> +	}
> +	for (const auto& string : last_added_to_dropdown_) {
> +		if (!string.empty() && predefined_targets_.find(string) == predefined_targets_.end()) {
> +			return update_profiles_needed(current_profile);
> +		}
> +	}
> +	if (last_added_to_dropdown_.count("") == (current_profile.empty() ? 0 : 1)) {
> +		return update_profiles_needed(current_profile);
> +	}
> +
> +	update_profiles_select(current_profile);
> +}
> +
> +void EconomyOptionsWindow::update_profiles_needed(const std::string& current_profile) {
> +	dropdown_.clear();
> +	last_added_to_dropdown_.clear();
> +	for (const auto& pair : predefined_targets_) {
> +		dropdown_.add(_(pair.first), pair.first);
> +		last_added_to_dropdown_.insert(pair.first);
> +	}
> +	if (current_profile.empty()) {
> +		// Nothing selected
> +		dropdown_.add("", "");

The worst thing that will happen is that the player will get 2 entries labelled –, because the real value for this will still be "".

In other words, if you have

dropdown_.add(_("foo"), "bar");

and the user selects it, the select function will give you "bar", NOT _("foo").

We have to check the documentation of the dropdown carefully here, because both parameters happen to be strings in this case.

> +		last_added_to_dropdown_.insert("");
> +	}
> +	update_profiles_select(current_profile);
> +}
> +
> +void EconomyOptionsWindow::update_profiles_select(const std::string& current_profile) {
> +	if (dropdown_.is_expanded()) {
> +		return;
> +	}
> +	const std::string select = current_profile.empty() ? "" : _(current_profile);
> +	if (!dropdown_.has_selection() || dropdown_.get_selected() != select) {
> +		dropdown_.select(select);
> +	}
> +	assert(dropdown_.has_selection());
> +}
> +
> +void EconomyOptionsWindow::SaveProfileWindow::update_save_enabled() {
> +	const std::string& text = profile_name_.text();
> +	if (text.empty() || text == kDefaultEconomyProfile) {
> +		save_.set_enabled(false);
> +		save_.set_tooltip(text.empty() ? _("The profile name cannot be empty") :
> +				_("The default profile cannot be overwritten"));
> +	} else {
> +		save_.set_enabled(true);
> +		save_.set_tooltip(_("Save the profile under this name"));
> +	}
> +}
> +
> +void EconomyOptionsWindow::SaveProfileWindow::table_selection_changed() {
> +	if (!table_.has_selection()) {
> +		delete_.set_enabled(false);
> +		delete_.set_tooltip("");
> +		return;
> +	}
> +	const std::string& sel = table_[table_.selection_index()];
> +	if (economy_options_->get_predefined_targets().at(sel).undeletable) {
> +		delete_.set_tooltip(_("The predefined profiles cannot be deleted"));
> +		delete_.set_enabled(false);
> +	} else {
> +		delete_.set_tooltip(_("Delete the selected profiles"));
> +		delete_.set_enabled(true);
> +	}
> +	profile_name_.set_text(sel);
> +	update_save_enabled();
> +}
> +
> +void EconomyOptionsWindow::SaveProfileWindow::update_table() {
> +	table_.clear();
> +	for (const auto& pair : economy_options_->get_predefined_targets()) {
> +		table_.add(pair.first).set_string(0, _(pair.first));
> +	}
> +	layout();
> +}
> +
> +void EconomyOptionsWindow::SaveProfileWindow::save() {
> +	const std::string name = profile_name_.text();
> +	assert(!name.empty());
> +	assert(name != kDefaultEconomyProfile);
> +	for (const auto& pair : economy_options_->get_predefined_targets()) {
> +		if (pair.first == name) {
> +			UI::WLMessageBox m(this, _("Overwrite?"),
> +					_("A profile with this name already exists.\nDo you wish to replace it?"),
> +					UI::WLMessageBox::MBoxType::kOkCancel);
> +			if (m.run<UI::Panel::Returncodes>() != UI::Panel::Returncodes::kOk) {
> +				return;
> +			}
> +			break;
> +		}
> +	}
> +	economy_options_->do_create_target(name);
> +	die();
> +}
> +
> +void EconomyOptionsWindow::SaveProfileWindow::delete_selected() {
> +	assert(table_.has_selection());
> +
> +	auto& map = economy_options_->get_predefined_targets();
> +	const std::string& name = table_[table_.selection_index()];
> +
> +	assert(name != kDefaultEconomyProfile);
> +	assert(!map.at(name).undeletable);
> +	auto it = map.find(name);
> +	assert(it != map.end());
> +	map.erase(it);
> +
> +	economy_options_->save_targets();
> +	economy_options_->update_profiles();
> +	update_table();
> +}
> +
> +void EconomyOptionsWindow::SaveProfileWindow::unset_parent() {
> +	economy_options_ = nullptr;
> +	die();
> +}
> +
> +void EconomyOptionsWindow::SaveProfileWindow::think() {
> +	if (!economy_options_) {
> +		die();
> +	}
> +	UI::Window::think();
> +}
> +
> +EconomyOptionsWindow::SaveProfileWindow::SaveProfileWindow(UI::Panel* parent, EconomyOptionsWindow* eco)
> +   : UI::Window(parent, "save_economy_options_profile", 0, 0, 0, 0, _("Save Profile")),
> +     economy_options_(eco),
> +     main_box_(this, 0, 0, UI::Box::Vertical),
> +     table_box_(&main_box_, 0, 0, UI::Box::Vertical),
> +     table_(&table_box_, 0, 0, 460, 120, UI::PanelStyle::kWui),
> +     buttons_box_(&main_box_, 0, 0, UI::Box::Horizontal),
> +     profile_name_(&buttons_box_, 0, 0, 240, 0, 0, UI::PanelStyle::kWui),
> +     save_(&buttons_box_, "save", 0, 0, 80, 34, UI::ButtonStyle::kWuiPrimary, _("Save")),
> +     cancel_(&buttons_box_, "cancel", 0, 0, 80, 34, UI::ButtonStyle::kWuiSecondary, _("Cancel")),
> +     delete_(&buttons_box_, "delete", 0, 0, 80, 34, UI::ButtonStyle::kWuiSecondary, _("Delete")) {
> +	table_.add_column(200, _("Existing Profiles"));
> +	update_table();
> +
> +	table_.selected.connect([this](uint32_t) { table_selection_changed(); });
> +	profile_name_.changed.connect([this] { update_save_enabled(); });
> +	profile_name_.ok.connect([this] { save(); });
> +	profile_name_.cancel.connect([this] { die(); });
> +	save_.sigclicked.connect([this] { save(); });
> +	cancel_.sigclicked.connect([this] { die(); });
> +	delete_.sigclicked.connect([this] { delete_selected(); });
> +
> +	table_box_.add(&table_, UI::Box::Resizing::kFullSize);
> +	buttons_box_.add(&profile_name_, UI::Box::Resizing::kFullSize);
> +	buttons_box_.add(&save_);
> +	buttons_box_.add(&cancel_);
> +	buttons_box_.add(&delete_);
> +	main_box_.add(&table_box_, UI::Box::Resizing::kFullSize);
> +	main_box_.add(&buttons_box_, UI::Box::Resizing::kFullSize);
> +	set_center_panel(&main_box_);
> +
> +	table_selection_changed();
> +	update_save_enabled();
> +}
> +
> +EconomyOptionsWindow::SaveProfileWindow::~SaveProfileWindow() {
> +	if (economy_options_) {
> +		economy_options_->close_save_profile_window();
> +	}
> +}
> +
> +void EconomyOptionsWindow::create_target() {
> +	if (save_profile_dialog_) {
> +		// Already open
> +		return;
> +	}
> +	save_profile_dialog_ = new SaveProfileWindow(get_parent(), this);
> +}
> +
> +void EconomyOptionsWindow::close_save_profile_window() {
> +	assert(save_profile_dialog_);
> +	save_profile_dialog_ = nullptr;
> +}
> +
> +void EconomyOptionsWindow::do_create_target(const std::string& name) {
> +	assert(!name.empty());
> +	assert(name != kDefaultEconomyProfile);
> +	const Widelands::Tribes& tribes = player_->egbase().tribes();
> +	const Widelands::TribeDescr& tribe = player_->tribe();
> +	Widelands::Economy* economy = player_->get_economy(serial_);
> +	PredefinedTargets t;
> +	for (Widelands::DescriptionIndex di : tribe.wares()) {
> +		if (tribes.get_ware_descr(di)->has_demand_check(tribe.name())) {
> +			t.wares[di] = economy->ware_target_quantity(di).permanent;
> +		}
> +	}
> +	for (Widelands::DescriptionIndex di : tribe.workers()) {
> +		if (tribes.get_worker_descr(di)->has_demand_check()) {
> +			t.workers[di] = economy->worker_target_quantity(di).permanent;
> +		}
> +	}
> +	predefined_targets_[name] = t;
> +
> +	save_targets();
> +	update_profiles();
> +}
> +
> +void EconomyOptionsWindow::save_targets() {
> +	const Widelands::Tribes& tribes = player_->egbase().tribes();
> +	Profile profile;
> +
> +	std::map<std::string, uint32_t> serials;
> +	for (const auto& pair : predefined_targets_) {
> +		if (pair.first != kDefaultEconomyProfile) {
> +			serials.emplace(pair.first, serials.size());
> +		}
> +	}
> +	Section& global_section = profile.create_section(kDefaultEconomyProfile.c_str());
> +	for (const auto& pair : serials) {
> +		global_section.set_string(std::to_string(pair.second).c_str(), pair.first);
> +	}
> +
> +	for (const auto& pair : predefined_targets_) {
> +		if (pair.first == kDefaultEconomyProfile) {
> +			continue;
> +		}
> +		Section& section = profile.create_section(std::to_string(serials.at(pair.first)).c_str());
> +		for (const auto& setting : pair.second.wares) {
> +			section.set_natural(tribes.get_ware_descr(setting.first)->name().c_str(), setting.second);
> +		}
> +		for (const auto& setting : pair.second.workers) {
> +			section.set_natural(tribes.get_worker_descr(setting.first)->name().c_str(), setting.second);
> +		}
> +	}
> +
> +	Section& section = profile.create_section("undeletable");
> +	for (const auto& pair : predefined_targets_) {
> +		if (pair.first != kDefaultEconomyProfile) {
> +			section.set_bool(std::to_string(serials.at(pair.first)).c_str(), pair.second.undeletable);
> +		}
> +	}
> +
> +	g_fs->ensure_directory_exists(kEconomyProfilesDir);
> +	std::string complete_filename = kEconomyProfilesDir + g_fs->file_separator() + player_->tribe().name();
> +	profile.write(complete_filename.c_str(), false);
> +
> +	// Inform the windows of other economies of new and deleted profiles
> +	Notifications::publish(NoteEconomyProfile(serial_));
> +}
> +
> +void EconomyOptionsWindow::read_targets() {
> +	predefined_targets_.clear();
> +	const Widelands::Tribes& tribes = player_->egbase().tribes();
> +	const Widelands::TribeDescr& tribe = player_->tribe();
> +
> +	{
> +		PredefinedTargets t;
> +		t.undeletable = true;
> +		for (Widelands::DescriptionIndex di : tribe.wares()) {
> +			const Widelands::WareDescr* descr = tribes.get_ware_descr(di);
> +			if (descr->has_demand_check(tribe.name())) {
> +				t.wares.emplace(di, descr->default_target_quantity(tribe.name()));
> +			}
> +		}
> +		for (Widelands::DescriptionIndex di : tribe.workers()) {
> +			const Widelands::WorkerDescr* descr = tribes.get_worker_descr(di);
> +			if (descr->has_demand_check()) {
> +				t.workers.emplace(di, descr->default_target_quantity());
> +			}
> +		}
> +		predefined_targets_.emplace(kDefaultEconomyProfile, t);
> +	}
> +
> +	std::string complete_filename = kEconomyProfilesDir + g_fs->file_separator() + player_->tribe().name();
> +	Profile profile;
> +	profile.read(complete_filename.c_str());
> +
> +	Section* global_section = profile.get_section(kDefaultEconomyProfile);
> +	if (global_section) {
> +		std::map<std::string, std::string> serials;
> +		while (Section::Value* v = global_section->get_next_val()) {
> +			serials.emplace(std::string(v->get_name()), v->get_string());
> +		}
> +
> +		for (const auto& pair : serials) {
> +			Section* section = profile.get_section(pair.first);
> +			PredefinedTargets t;
> +			while (Section::Value* v = section->get_next_val()) {
> +				const std::string name = std::string(v->get_name());
> +				Widelands::DescriptionIndex di = tribes.ware_index(name);
> +				if (di == Widelands::INVALID_INDEX) {
> +					di = tribes.worker_index(name);
> +					assert(di != Widelands::INVALID_INDEX);
> +					t.workers.emplace(di, v->get_natural());
>  				} else {
> -					game.send_player_command(*new Widelands::CmdSetWorkerTargetQuantity(
> -					   game.get_gametime(), player_->player_number(), serial_, index,
> -					   tq.permanent + amount));
> +					t.wares.emplace(di, v->get_natural());
>  				}
>  			}
> +			predefined_targets_.emplace(pair.second, t);
>  		}
> -	}
> -}
>  
> -void EconomyOptionsWindow::EconomyOptionsPanel::reset_target() {
> -	Widelands::Game& game = dynamic_cast<Widelands::Game&>(player_->egbase());
> -	const bool is_wares = type_ == Widelands::wwWARE;
> -	const auto& items = is_wares ? player_->tribe().wares() : player_->tribe().workers();
> -	for (const Widelands::DescriptionIndex& index : items) {
> -		if (display_.ware_selected(index)) {
> -			if (is_wares) {
> -				game.send_player_command(*new Widelands::CmdResetWareTargetQuantity(
> -				   game.get_gametime(), player_->player_number(), serial_, index));
> -			} else {
> -				game.send_player_command(*new Widelands::CmdResetWorkerTargetQuantity(
> -				   game.get_gametime(), player_->player_number(), serial_, index));
> +		if (Section* section = profile.get_section("undeletable")) {
> +			while (Section::Value* v = section->get_next_val()) {
> +				predefined_targets_.at(serials.at(std::string(v->get_name()))).undeletable = v->get_bool();
>  			}
>  		}
>  	}
> +
> +	update_profiles();
>  }


-- 
https://code.launchpad.net/~widelands-dev/widelands/economy-target-profiles/+merge/366987
Your team Widelands Developers is subscribed to branch lp:~widelands-dev/widelands/economy-target-profiles.


References