The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
achievements_dialog.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 - 2025
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13*/
14
15#define GETTEXT_DOMAIN "wesnoth-lib"
16
18
21#include "gettext.hpp"
23#include "gui/widgets/grid.hpp"
24#include "gui/widgets/label.hpp"
27#include "log.hpp"
30
31static lg::log_domain log_config("config");
32#define ERR_CONFIG LOG_STREAM(err, log_config)
33
35{
36
38
40 : modal_dialog(window_id())
41 , last_selected_(prefs::get().selected_achievement_group())
42 , achievements_box_(nullptr)
43 , content_names_(nullptr)
44{
45}
46
48{
49 std::vector<config> content_list;
50 content_names_ = &find_widget<menu_button>("selected_achievements_list");
51 connect_signal_notify_modified(*content_names_, std::bind(&achievements_dialog::set_achievements_row, this));
52
53 achievements_box_ = find_widget<listbox>("achievements_list", false, true);
54 int selected = 0;
55
56 for(const auto& list : game_config_manager::get()->get_achievements()) {
57 // only display the achievements for the first dropdown option on first showing the dialog
58 if(list.content_for_ == last_selected_ || last_selected_ == "") {
59 selected = content_list.size();
60 }
61
62 // populate all possibilities into the dropdown
63 content_list.emplace_back("label", list.display_name_);
64 }
65
66 if(content_list.size() > 0) {
67 content_names_->set_values(content_list);
68 content_names_->set_selected(selected, false);
70 }
71}
72
74{
75 prefs::get().set_selected_achievement_group(last_selected_);
76}
77
79{
83 int achieved_count = 0;
84
85 for(const auto& ach : list.achievements_) {
86 if(ach.achieved_) {
87 achieved_count++;
88 } else if(ach.hidden_ && !ach.achieved_) {
89 continue;
90 }
91
92 const bool in_progress = ach.max_progress_ != 0 && ach.current_progress_ != -1;
93 const auto in_progress_name = !in_progress
94 ? ach.name_
95 : t_string(VGETTEXT("$title ($count/$total)", {{
96 {"title", ach.name_},
97 {"count", std::to_string(ach.current_progress_)},
98 {"total", std::to_string(ach.max_progress_)}
99 }}));
100
102 { "icon", {
103 { "label", ach.achieved_
104 ? ach.icon_completed_
105 : ach.icon_
106 }
107 }},
108 { "name", {
109 { "label", ach.achieved_
110 ? ach.name_completed_
111 : in_progress_name
112 }
113 }},
114 { "description", {
115 { "label", ach.achieved_
116 ? t_string(markup::span_color("green", ach.description_completed_))
117 : ach.description_
118 }
119 }}
120 });
121
122 auto& achievement_progress = newrow.find_widget<progress_bar>("achievement_progress");
123 if(in_progress) {
124 achievement_progress.set_percentage((ach.current_progress_ / double(ach.max_progress_)) * 100);
125 } else {
126 achievement_progress.set_visible(gui2::widget::visibility::invisible);
127 }
128
129 auto& name = newrow.find_widget<styled_widget>("name");
130 name.get_canvas(0).set_variable("achieved", wfl::variant(ach.achieved_));
131
132 set_sub_achievements(newrow, ach);
133 }
134
135 auto& achieved_label = find_widget<label>("achievement_count");
136 achieved_label.set_label(VGETTEXT("Completed $count/$total", {
137 {"count", std::to_string(achieved_count)} ,
138 {"total", std::to_string(list.achievements_.size())}
139 }));
140}
141
143{
144 // There's a fixed limit of 28 sub achievements, that's a documented part of the
145 // WML API, chosen due to the GUI layout (see the commit message of ad3f1c95b0).
146 // The WML adds them all, and this method either sets the image or sets them
147 // invisible, depending on how many sub achievements there actually are.
148
149 // The C++ doesn't hardcode the limit, it just looks for widgets whose ids are
150 // consectively numbered and then uses data from the corresponding element of
151 // the ach.sub_achievements_ vector.
152 int i = 0;
153
154 for(const sub_achievement& sub_ach : ach.sub_achievements_)
155 {
156 auto img = newrow.find_widget<drawing>("sub_icon" + std::to_string(i), false, false);
157 if(img) {
158 img->set_label(sub_ach.achieved_ ? sub_ach.icon_completed_ : sub_ach.icon_);
159 img->set_tooltip(sub_ach.description_);
160 } else {
161 // Exceeded the number of [drawing] tags in the GUI WML.
162 ERR_CONFIG << "Too many sub achievements for ‘" << ach.id_ << "’, ‘"
163 << sub_ach.id_ << "’ will not be displayed";
164 }
165 i++;
166 }
167
168 // Hide any [drawing] that doesn't have a corresponding sub_achievement tag
169 while(auto img = newrow.find_widget<drawing>("sub_icon" + std::to_string(i), false, false))
170 {
171 img->set_visible(visibility::invisible);
172 i++;
173 }
174}
175
176} // namespace gui2::dialogs
#define ERR_CONFIG
static lg::log_domain log_config("config")
static game_config_manager * get()
std::vector< achievement_group > & get_achievements()
void set_variable(const std::string &key, wfl::variant &&value)
Definition canvas.hpp:165
virtual void post_show() override
Actions to be taken after the window has been shown.
virtual void pre_show() override
Actions to be taken before showing the window.
void set_sub_achievements(grid &newrow, const achievement &ach)
Abstract base class for all modal dialogs.
Base container class.
Definition grid.hpp:32
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition listbox.cpp:92
void clear()
Removes all the rows in the listbox, clearing it.
Definition listbox.cpp:147
void set_selected(unsigned selected, bool fire_event=true)
void set_values(const std::vector<::config > &values, unsigned selected=0)
virtual unsigned get_value() const override
Inherited from selectable_item.
void set_percentage(unsigned percentage)
canvas & get_canvas(const unsigned index)
T * find_widget(const std::string_view id, const bool must_be_active, const bool must_exist)
Gets a widget with the wanted id.
Definition widget.hpp:747
@ invisible
The user set the widget invisible, that means:
static prefs & get()
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
This file contains the window object, this object is a top level container which has the event manage...
Standard logging facilities (interface).
#define REGISTER_DIALOG(window_id)
Wrapper for REGISTER_DIALOG2.
std::map< std::string, widget_item > widget_data
Definition widget.hpp:36
std::string span_color(const color_t &color, Args &&... data)
Applies Pango markup to the input specifying its display color.
Definition markup.hpp:110
A set of achievements tied to a particular content.
std::string content_for_
The internal ID used for this content.
std::vector< achievement > achievements_
The achievements associated to this content.
Represents a single achievement and its data.
std::string id_
The ID of the achievement.
std::vector< sub_achievement > sub_achievements_
The list of distinct sub-achievements for this achievement.
Represents a distinct sub-achievement within another achievement.
#define i