Project Alice
Loading...
Searching...
No Matches
gui_technology_window.hpp
Go to the documentation of this file.
1#pragma once
2
5#include "triggers.hpp"
6
7namespace ui {
8
9void invention_description(sys::state& state, text::layout_base& contents, dcon::invention_id inv_id, int32_t indent) noexcept;
10void technology_description(sys::state& state, text::layout_base& contents, dcon::technology_id tech_id) noexcept;
11
13public:
15 bool is_active(sys::state& state) noexcept final;
16 void button_action(sys::state& state) noexcept final;
17
20 }
21
22 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
23 state.world.for_each_technology([&](dcon::technology_id id) {
24 auto fat_id = dcon::fatten(state.world, id);
25 if(state.culture_definitions.tech_folders[fat_id.get_folder_index()].category != category)
26 return;
27 bool discovered = state.world.nation_get_active_technologies(state.local_player_nation, id);
28 bool can_research = command::can_start_research(state, state.local_player_nation, id);
29 bool is_current = state.world.nation_get_current_research(state.local_player_nation) == id;
30 auto color = discovered
32 : (is_current
34 : (can_research
37 auto name = fat_id.get_name();
38 auto box = text::open_layout_box(contents, 0);
40 text::close_layout_box(contents, box);
41 });
42 switch(category) {
44 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::army_tech_research_bonus, true);
45 break;
47 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::commerce_tech_research_bonus, true);
48 break;
50 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::culture_tech_research_bonus, true);
51 break;
53 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::industry_tech_research_bonus, true);
54 break;
56 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::navy_tech_research_bonus, true);
57 break;
59 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::military_theory_tech_research_bonus, true);
60 break;
62 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::population_tech_research_bonus, true);
63 break;
65 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::diplomacy_tech_research_bonus, true);
66 break;
68 active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::flavor_tech_research_bonus, true);
69 break;
71 break;
72 }
73 }
74};
75
77public:
79 void on_update(sys::state& state) noexcept override {
80 auto discovered = 0;
81 auto total = 0;
82 state.world.for_each_technology([&](dcon::technology_id id) {
83 auto fat_id = dcon::fatten(state.world, id);
84 if(state.culture_definitions.tech_folders[fat_id.get_folder_index()].category == category) {
85 discovered += state.world.nation_get_active_technologies(state.local_player_nation, id) ? 1 : 0;
86 ++total;
87 }
88 });
89 progress = bool(total) && bool(discovered) ? float(discovered) / float(total) : 0.f;
90 }
91};
92
94 std::string get_text(sys::state& state) noexcept {
95 auto discovered = 0;
96 auto total = 0;
97 state.world.for_each_technology([&](dcon::technology_id id) {
98 auto fat_id = dcon::fatten(state.world, id);
99 if(state.culture_definitions.tech_folders[fat_id.get_folder_index()].category == category) {
100 discovered += state.world.nation_get_active_technologies(state.local_player_nation, id) ? 1 : 0;
101 ++total;
102 }
103 });
104 return text::produce_simple_string(state, std::to_string(discovered) + "/" + std::to_string(total));
105 }
106
107public:
109 void on_update(sys::state& state) noexcept override {
110 set_text(state, get_text(state));
111 }
112};
113
115 image_element_base* folder_icon = nullptr;
116 simple_text_element_base* folder_name = nullptr;
117 technology_folder_tab_sub_button* folder_button = nullptr;
118 technology_tab_progress* folder_progress = nullptr;
119 technology_num_discovered_text* folder_num_discovered = nullptr;
120
121public:
124 folder_button->category = category = new_category;
125
126 folder_icon->frame = static_cast<int32_t>(category);
128
129 folder_num_discovered->category = folder_progress->category = category;
130 folder_progress->on_update(state);
131 folder_num_discovered->on_update(state);
132 }
133
134 std::unique_ptr<element_base> make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override {
135 if(name == "folder_button") {
136 auto ptr = make_element_by_type<technology_folder_tab_sub_button>(state, id);
137 folder_button = ptr.get();
138 return ptr;
139 } else if(name == "folder_icon") {
140 auto ptr = make_element_by_type<image_element_base>(state, id);
141 folder_icon = ptr.get();
142 return ptr;
143 } else if(name == "folder_category") {
144 auto ptr = make_element_by_type<simple_text_element_base>(state, id);
145 folder_name = ptr.get();
146 return ptr;
147 } else if(name == "folder_progress") {
148 auto ptr = make_element_by_type<technology_tab_progress>(state, id);
149 folder_progress = ptr.get();
150 return ptr;
151 } else if(name == "folder_number_discovered") {
152 auto ptr = make_element_by_type<technology_num_discovered_text>(state, id);
153 folder_num_discovered = ptr.get();
154 return ptr;
155 } else {
156 return nullptr;
157 }
158 }
159};
160
162 std::string get_text(sys::state& state) noexcept {
163 auto tech_id = nations::current_research(state, state.local_player_nation);
164 if(tech_id) {
165 auto tech = dcon::fatten(state.world, tech_id);
166 auto const& folder = state.culture_definitions.tech_folders[tech.get_folder_index()];
167 std::string str{};
168 str += text::produce_simple_string(state, folder.name);
169 str += ", ";
171 return str;
172 } else {
173 return "";
174 }
175 }
176
177public:
178 void on_update(sys::state& state) noexcept override {
179 set_text(state, get_text(state));
180 }
181};
182
184 dcon::technology_id tech_id;
185};
187public:
188 void button_action(sys::state& state) noexcept override {
189 auto content = retrieve<dcon::technology_id>(state, parent);
190 if(state.ui_state.technology_subwindow) {
191 Cyto::Any sl_payload = technology_select_tech{content};
192 state.ui_state.technology_subwindow->impl_set(state, sl_payload);
193 }
194 }
195
196 void button_right_action(sys::state& state) noexcept override {
197 auto content = retrieve<dcon::technology_id>(state, parent);
198 auto it = std::find(state.ui_state.tech_queue.begin(), state.ui_state.tech_queue.end(), content);
199 if(it != state.ui_state.tech_queue.end()) {
200 state.ui_state.tech_queue.erase(it);
201 state.game_state_updated.store(true, std::memory_order::release);
202 }
203 }
204
205 void button_shift_action(sys::state& state) noexcept override {
206 auto content = retrieve<dcon::technology_id>(state, parent);
207 if(!content)
208 return;
209
210 auto it = std::find(state.ui_state.tech_queue.begin(), state.ui_state.tech_queue.end(), content);
211 if(it == state.ui_state.tech_queue.end()) {
212 if(content != state.world.nation_get_current_research(state.local_player_nation) && !state.world.nation_get_active_technologies(state.local_player_nation, content)) { // don't add already researched or researching
213 state.ui_state.tech_queue.push_back(content);
215 }
216 } else {
217 state.ui_state.tech_queue.erase(it);
218 state.ui_state.tech_queue.push_back(content);
220 }
221 }
222
225 }
226
227 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
228 auto content = retrieve<dcon::technology_id>(state, parent);
229 auto fat_id = dcon::fatten(state.world, content);
230 if(auto name = fat_id.get_name(); state.key_is_localized(name)) {
231 auto box = text::open_layout_box(contents, 0);
233 text::close_layout_box(contents, box);
234 }
235 if(auto desc = fat_id.get_desc(); state.key_is_localized(desc)) {
236 auto box = text::open_layout_box(contents, 0);
237 text::add_to_layout_box(state, contents, box, desc);
238 text::close_layout_box(contents, box);
239 }
240 technology_description(state, contents, content);
241 {
242 auto box = text::open_layout_box(contents, 0);
243 text::localised_format_box(state, contents, box, "tech_queue_explain");
244 text::close_layout_box(contents, box);
245 }
246 }
247};
248
250public:
251 void on_update(sys::state& state) noexcept override {
252 auto content = retrieve<dcon::technology_id>(state, parent);
253 auto fat_id = dcon::fatten(state.world, content);
254
255 auto it = std::find(state.ui_state.tech_queue.begin(), state.ui_state.tech_queue.end(), content);
256 if(it == state.ui_state.tech_queue.end()) {
257 // not queued
259 } else {
260 // queued
261 simple_text_element_base::set_text(state, "(" + std::to_string(std::distance(state.ui_state.tech_queue.begin(), it) + 1) + ") " + text::get_name_as_string(state, fat_id));
262 }
263 }
264};
265
267 technology_item_button* tech_button = nullptr;
268 culture::tech_category category;
269
270public:
271 dcon::technology_id tech_id{};
272
273 std::unique_ptr<element_base> make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override {
274 if(name == "start_research") {
275 auto ptr = make_element_by_type<technology_item_button>(state, id);
276 tech_button = ptr.get();
277 return ptr;
278 } else if(name == "tech_name") {
279 return make_element_by_type<technology_name_text>(state, id);
280 } else {
281 return nullptr;
282 }
283 }
284
285 void on_update(sys::state& state) noexcept override {
286 if(!tech_id)
287 return;
288
289 if(state.world.nation_get_active_technologies(state.local_player_nation, tech_id)) {
290 // Fully researched.
291 tech_button->frame = 1;
292 } else if(nations::current_research(state, state.local_player_nation) == tech_id) {
293 // Research in progress.
294 tech_button->frame = 0;
295 } else if(command::can_start_research(state, state.local_player_nation, tech_id)) {
296 // Can be researched.
297 tech_button->frame = 2;
298 } else {
299 // Can not be researched yet.
300 tech_button->frame = 3;
301 }
302 }
303
304 message_result get(sys::state& state, Cyto::Any& payload) noexcept override {
305 if(payload.holds_type<dcon::technology_id>()) {
306 payload.emplace<dcon::technology_id>(tech_id);
308 }
310 }
311 message_result set(sys::state& state, Cyto::Any& payload) noexcept override;
312};
313
315public:
316 void on_update(sys::state& state) noexcept override {
317 auto content = retrieve<dcon::invention_id>(state, parent);
318 frame = int32_t(state.world.invention_get_technology_type(content));
319 }
320
323 }
324
325 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
326 auto content = retrieve<dcon::invention_id>(state, parent);
327 auto category = static_cast<culture::tech_category>(state.world.invention_get_technology_type(content));
328 auto box = text::open_layout_box(contents, 0);
330 text::close_layout_box(contents, box);
331 }
332};
333
335public:
336 void on_update(sys::state& state) noexcept override {
337 auto content = retrieve<dcon::invention_id>(state, parent);
339 }
340
343 }
344
345 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
346 auto content = retrieve<dcon::invention_id>(state, parent);
347
348 if(auto name = state.world.invention_get_name(content); name) {
349 auto box = text::open_layout_box(contents, 0);
351 text::close_layout_box(contents, box);
352 }
353 if(auto desc = state.world.invention_get_name(content); desc) {
354 auto box = text::open_layout_box(contents, 0);
355 text::add_to_layout_box(state, contents, box, desc);
356 text::close_layout_box(contents, box);
357 }
359 invention_description(state, contents, content, 0);
361 }
362};
363
365public:
366 void on_update(sys::state& state) noexcept override {
367 if(auto content = retrieve<dcon::invention_id>(state, parent); content) {
368 auto mod_k = state.world.invention_get_chance(content);
369 auto chances = trigger::evaluate_additive_modifier(state, mod_k, trigger::to_generic(state.local_player_nation),
370 trigger::to_generic(state.local_player_nation), 0);
371 set_text(state, text::format_percentage(chances / 100.f, 0));
372 }
373 }
374
377 }
378
379 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
380 if(auto content = retrieve<dcon::invention_id>(state, parent); content) {
381 text::add_line(state, contents, "alice_invention_chance");
382 auto mod_k = state.world.invention_get_chance(content);
383 additive_value_modifier_description(state, contents, mod_k, trigger::to_generic(state.local_player_nation), trigger::to_generic(state.local_player_nation), 0);
384 }
385 }
386};
387
388class technology_possible_invention : public listbox_row_element_base<dcon::invention_id> {
389public:
390 std::unique_ptr<element_base> make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override {
391 if(name == "folder_icon") {
392 return make_element_by_type<invention_image>(state, id);
393 } else if(name == "invention_name") {
394 return make_element_by_type<invention_name_text>(state, id);
395 } else if(name == "invention_percent") {
396 return make_element_by_type<invention_chance_percent_text>(state, id);
397 } else {
398 return nullptr;
399 }
400 }
401};
402
405};
406
407class technology_possible_invention_listbox : public listbox_element_base<technology_possible_invention, dcon::invention_id> {
408protected:
409 std::string_view get_row_element_name() override {
410 return "invention_window";
411 }
412
413public:
414 void on_update(sys::state& state) noexcept override {
415 row_contents.clear();
416 state.world.for_each_invention([&](dcon::invention_id id) {
417 auto lim_trigger_k = state.world.invention_get_limit(id);
418 if(!state.world.nation_get_active_inventions(state.local_player_nation, id) && trigger::evaluate(state, lim_trigger_k, trigger::to_generic(state.local_player_nation),
419 trigger::to_generic(state.local_player_nation), -1))
420 row_contents.push_back(id);
421 });
422
423 auto sort_order = retrieve< invention_sort_type>(state, parent);
424 switch(sort_order) {
426 std::sort(row_contents.begin(), row_contents.end(), [&](dcon::invention_id a, dcon::invention_id b) {
427 auto a_name = text::produce_simple_string(state, dcon::fatten(state.world, a).get_name());
428 auto b_name = text::produce_simple_string(state, dcon::fatten(state.world, b).get_name());
429 return a_name < b_name;
430 });
431 break;
433 std::sort(row_contents.begin(), row_contents.end(), [&](dcon::invention_id a, dcon::invention_id b) {
434 return state.world.invention_get_technology_type(a) < state.world.invention_get_technology_type(b);
435 });
436 break;
438 std::sort(row_contents.begin(), row_contents.end(), [&](dcon::invention_id a, dcon::invention_id b) {
439 auto mod_a = state.world.invention_get_chance(a);
440 auto chances_a = trigger::evaluate_additive_modifier(state, mod_a, trigger::to_generic(state.local_player_nation),
441 trigger::to_generic(state.local_player_nation), 0);
442 auto mod_b = state.world.invention_get_chance(b);
443 auto chances_b = trigger::evaluate_additive_modifier(state, mod_b, trigger::to_generic(state.local_player_nation),
444 trigger::to_generic(state.local_player_nation), 0);
445
446 return chances_a > chances_b;
447 });
448 break;
449 }
450 update(state);
451 }
452};
453
455public:
456 void on_update(sys::state& state) noexcept override {
457 auto content = retrieve<dcon::invention_id>(state, parent);
458 frame = 0; // inactive
459 if(content && state.world.nation_get_active_inventions(state.local_player_nation, content)) {
460 frame = 1; // This invention's been discovered
461 } else {
462 auto tech_id = retrieve<dcon::technology_id>(state, parent);
463 if(tech_id && state.world.nation_get_active_technologies(state.local_player_nation, tech_id))
464 frame = 2; // Active technology but not invention
465 }
466 }
467
470 }
471
472 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
473 auto inv = retrieve<dcon::invention_id>(state, parent);
474 auto tech_id = retrieve<dcon::technology_id>(state, parent);
475 if(inv && state.world.nation_get_active_inventions(state.local_player_nation, inv)) {
476 text::add_line(state, contents, "invention_bulb_3");
477 } else if(tech_id && state.world.nation_get_active_technologies(state.local_player_nation, tech_id)) {
478 text::add_line(state, contents, "invention_bulb_2");
479 } else {
480 text::add_line(state, contents, "invention_bulb_1");
481 }
482 }
483};
484class technology_selected_invention : public listbox_row_element_base<dcon::invention_id> {
485public:
486 std::unique_ptr<element_base> make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override {
487 if(name == "invention_icon") {
488 return make_element_by_type<technology_selected_invention_image>(state, id);
489 } else if(name == "i_invention_name") {
490 return make_element_by_type<invention_name_text>(state, id);
491 } else {
492 return nullptr;
493 }
494 }
495};
496class technology_selected_inventions_listbox : public listbox_element_base<technology_selected_invention, dcon::invention_id> {
497protected:
498 std::string_view get_row_element_name() override {
499 return "invention_icon_window";
500 }
501
502public:
503 void on_update(sys::state& state) noexcept override {
504 auto content = retrieve<dcon::technology_id>(state, parent);
505 row_contents.clear();
506 state.world.for_each_invention([&](dcon::invention_id id) {
507 auto lim_trigger_k = state.world.invention_get_limit(id);
508 bool activable_by_this_tech = false;
509 trigger::recurse_over_triggers(state.trigger_data.data() + state.trigger_data_indices[lim_trigger_k.index() + 1],
510 [&](uint16_t* tval) {
511 if((tval[0] & trigger::code_mask) == trigger::technology && trigger::payload(tval[1]).tech_id == content)
512 activable_by_this_tech = true;
513 });
514 if(activable_by_this_tech)
515 row_contents.push_back(id);
516 });
517 update(state);
518 }
519};
520
522public:
523 void on_update(sys::state& state) noexcept override {
524 if(parent) {
525 Cyto::Any payload = dcon::technology_id{};
526 parent->impl_get(state, payload);
527 auto content = any_cast<dcon::technology_id>(payload);
528
529 base_data.data.image.gfx_object = state.world.technology_get_image(content);
530 }
531 }
532};
533
535public:
536 void on_update(sys::state& state) noexcept override {
537 if(parent) {
538 Cyto::Any payload = dcon::technology_id{};
539 parent->impl_get(state, payload);
540 auto content = any_cast<dcon::technology_id>(payload);
541
542 set_text(state, std::to_string(state.world.technology_get_year(content)));
543 }
544 }
545};
546
548public:
549 void on_update(sys::state& state) noexcept override {
550 auto t = retrieve<dcon::technology_id>(state, parent);
551 if(t) {
552 set_text(state, std::to_string(int64_t(
553 culture::effective_technology_cost(state, state.ui_date.to_ymd(state.start_date).year, state.local_player_nation, t)
554 )));
555 } else {
556 set_text(state, "");
557 }
558 }
559
562 }
563
564 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
565 auto tech_id = retrieve<dcon::technology_id>(state, parent);
566 if(!tech_id)
567 return;
568
569 auto base_cost = state.world.technology_get_cost(tech_id);
570 auto availability_year = state.world.technology_get_year(tech_id);
571 auto folder = state.world.technology_get_folder_index(tech_id);
572 auto category = state.culture_definitions.tech_folders[folder].category;
573
574 {
575 auto box = text::open_layout_box(contents);
576 text::localised_format_box(state, contents, box, "base_value");
577 text::add_space_to_layout_box(state, contents, box);
578 text::add_to_layout_box(state, contents, box, int64_t(base_cost));
579 text::close_layout_box(contents, box);
580 }
581
582 switch(category) {
584 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::army_tech_research_bonus, true);
585 break;
587 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::navy_tech_research_bonus, true);
588 break;
590 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::commerce_tech_research_bonus, true);
591 break;
593 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::culture_tech_research_bonus, true);
594 break;
596 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::industry_tech_research_bonus, true);
597 break;
598 //non vanilla
600 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::military_theory_tech_research_bonus, true);
601 break;
603 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::population_tech_research_bonus, true);
604 break;
606 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::diplomacy_tech_research_bonus, true);
607 break;
609 ui::active_modifiers_description(state, contents, state.local_player_nation, 0, sys::national_mod_offsets::flavor_tech_research_bonus, true);
610 break;
611 default:
612 break;
613 }
614
615 auto ol_mod = state.world.nation_get_active_technologies( state.world.overlord_get_ruler(state.world.nation_get_overlord_as_subject(state.local_player_nation)), tech_id) ? state.defines.tech_factor_vassal : 1.0f;
616
617 if(ol_mod != 1.0f) {
618 text::add_line(state, contents, "tech_ol_tt", text::variable_type::x, text::fp_percentage{ ol_mod });
619 }
620
621 auto year_mod = (1.0f - std::max(0.0f, float(state.ui_date.to_ymd(state.start_date).year - availability_year) / state.defines.tech_year_span));
622 if(year_mod != 1.0f) {
623 text::add_line(state, contents, "tech_year_tt", text::variable_type::x, text::fp_percentage{ year_mod });
624 }
625 }
626};
627
629public:
630 void on_create(sys::state& state) noexcept override {
631 base_data.size.y *= 2; // Nudge fix for technology descriptions
632 base_data.size.y -= 24;
633 base_data.size.x -= 10;
635 }
636 void on_update(sys::state& state) noexcept override {
637 auto content = retrieve<dcon::technology_id>(state, parent);
639 text::layout_parameters{0, 0, int16_t(base_data.size.x), int16_t(base_data.size.y),
640 base_data.data.text.font_handle, 0, text::alignment::left,
641 text::is_black_from_font_id(base_data.data.text.font_handle) ? text::text_color::black : text::text_color::white, false});
642 technology_description(state, layout, content);
644 }
645};
646
648public:
649 void on_update(sys::state& state) noexcept override {
650 auto content = retrieve<dcon::technology_id>(state, parent);
651 disabled = !command::can_start_research(state, state.local_player_nation, content);
652 }
653
654 void button_action(sys::state& state) noexcept override {
655 auto content = retrieve<dcon::technology_id>(state, parent);
656 command::start_research(state, state.local_player_nation, content);
657 }
658};
659
661public:
662 std::unique_ptr<element_base> make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override {
663 if(name == "picture") {
664 return make_element_by_type<technology_image>(state, id);
665 } else if(name == "title") {
666 return make_element_by_type<generic_name_text<dcon::technology_id>>(state, id);
667 } else if(name == "effect") {
668 return make_element_by_type<technology_selected_effect_text>(state, id);
669 } else if(name == "diff_icon") {
670 return make_element_by_type<image_element_base>(state, id);
671 } else if(name == "diff_label") {
672 return make_element_by_type<simple_body_text>(state, id);
673 } else if(name == "diff") {
674 return make_element_by_type<technology_research_points_text>(state, id);
675 } else if(name == "year_label") {
676 return make_element_by_type<simple_body_text>(state, id);
677 } else if(name == "year") {
678 return make_element_by_type<technology_year_text>(state, id);
679 } else if(name == "start") {
680 return make_element_by_type<technology_start_research>(state, id);
681 } else if(name == "inventions") {
682 return make_element_by_type<technology_selected_inventions_listbox>(state, id);
683 } else {
684 return nullptr;
685 }
686 }
687};
688
690 simple_text_element_base* group_name = nullptr;
691
692public:
694
695 std::unique_ptr<element_base> make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override {
696 if(name == "group_name") {
697 auto ptr = make_element_by_type<simple_text_element_base>(state, id);
698 group_name = ptr.get();
699 return ptr;
700 } else {
701 return nullptr;
702 }
703 }
704
705 message_result set(sys::state& state, Cyto::Any& payload) noexcept override {
706 if(payload.holds_type<culture::folder_info>()) {
707 auto folder = any_cast<culture::folder_info>(payload);
708 group_name->set_text(state, text::produce_simple_string(state, folder.name));
710 } else if(payload.holds_type<culture::tech_category>()) {
711 auto enum_val = any_cast<culture::tech_category>(payload);
712 set_visible(state, category == enum_val);
714 }
716 }
717};
718
720public:
723 }
724
725 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
726 auto box = text::open_layout_box(contents, 0);
727 text::add_to_layout_box(state, contents, box, text::produce_simple_string(state, "technologyview_sort_by_type_tooltip"),
729 text::close_layout_box(contents, box);
730 }
731
732 void button_action(sys::state& state) noexcept override {
734 }
735};
736
738public:
741 }
742
743 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
744 auto box = text::open_layout_box(contents, 0);
745 text::add_to_layout_box(state, contents, box, text::produce_simple_string(state, "technologyview_sort_by_name_tooltip"),
747 text::close_layout_box(contents, box);
748 }
749
750 void button_action(sys::state& state) noexcept override {
752 }
753};
754
756public:
759 }
760
761 void update_tooltip(sys::state& state, int32_t x, int32_t y, text::columnar_layout& contents) noexcept override {
762 auto box = text::open_layout_box(contents, 0);
763 text::add_to_layout_box(state, contents, box, text::produce_simple_string(state, "technologyview_sort_by_percent_tooltip"),
765 text::close_layout_box(contents, box);
766 }
767
768 void button_action(sys::state& state) noexcept override {
770 }
771};
772
773class technology_window : public generic_tabbed_window<culture::tech_category> {
774 technology_selected_tech_window* selected_tech_win = nullptr;
775 dcon::technology_id tech_id{};
777public:
778 void on_create(sys::state& state) noexcept override {
780
781 xy_pair folder_offset = state.ui_defs.gui[state.ui_state.defs_by_name.find(state.lookup_key("folder_offset"))->second.definition].position;
782 for(auto curr_folder = culture::tech_category::army; curr_folder != culture::tech_category(5);
783 curr_folder = static_cast<culture::tech_category>(static_cast<uint8_t>(curr_folder) + 1)) {
784 auto ptr = make_element_by_type<technology_folder_tab_button>(state,
785 state.ui_state.defs_by_name.find(state.lookup_key("folder_window"))->second.definition);
786 ptr->set_category(state, curr_folder);
787 ptr->base_data.position = folder_offset;
788 folder_offset.x += ptr->base_data.size.x;
789 add_child_to_front(std::move(ptr));
790 }
791
792 // Collect folders by category; the order in which we add technology groups and stuff
793 // will be determined by this:
794 // Order of category
795 // **** Order of folders within category
796 // ******** Order of appearance of technologies that have said folder?
797 std::vector<std::vector<size_t>> folders_by_category(static_cast<size_t>(5));
798 for(size_t i = 0; i < state.culture_definitions.tech_folders.size(); i++) {
799 auto const& folder = state.culture_definitions.tech_folders[i];
800 folders_by_category[static_cast<size_t>(folder.category)].push_back(i);
801 }
802 // Now obtain the x-offsets of each folder (remember only one category of folders
803 // is ever shown at a time)
804 std::vector<size_t> folder_x_offset(state.culture_definitions.tech_folders.size(), 0);
805 for(auto const& folder_category : folders_by_category) {
806 size_t y_offset = 0;
807 for(auto const folder_index : folder_category)
808 folder_x_offset[folder_index] = y_offset++;
809 }
810 // Technologies per folder (used for positioning!!!)
811 std::vector<size_t> items_per_folder(state.culture_definitions.tech_folders.size(), 0);
812
813 xy_pair base_group_offset =
814 state.ui_defs.gui[state.ui_state.defs_by_name.find(state.lookup_key("tech_group_offset"))->second.definition].position;
815 xy_pair base_tech_offset = state.ui_defs.gui[state.ui_state.defs_by_name.find(state.lookup_key("tech_offset"))->second.definition].position;
816
818 cat = static_cast<culture::tech_category>(static_cast<uint8_t>(cat) + 1)) {
819 // Add tech group names
820 int16_t group_count = 0;
821 for(auto const& folder : state.culture_definitions.tech_folders) {
822 if(folder.category != cat)
823 continue;
824
825 auto ptr = make_element_by_type<technology_tech_group_window>(state,
826 state.ui_state.defs_by_name.find(state.lookup_key("tech_group"))->second.definition);
827
828 ptr->category = cat;
829 Cyto::Any payload = culture::folder_info(folder);
830 ptr->impl_set(state, payload);
831
832 ptr->base_data.position.x = static_cast<int16_t>(base_group_offset.x + (group_count * ptr->base_data.size.x));
833 ptr->base_data.position.y = base_group_offset.y;
834 ++group_count;
835 add_child_to_front(std::move(ptr));
836 }
837
838 // Add technologies
839 state.world.for_each_technology([&](dcon::technology_id tid) {
840 auto tech = dcon::fatten(state.world, tid);
841 size_t folder_id = static_cast<size_t>(tech.get_folder_index());
842 const auto& folder = state.culture_definitions.tech_folders[folder_id];
843 if(folder.category != cat)
844 return;
845
846 auto ptr = make_element_by_type<technology_item_window>(state,
847 state.ui_state.defs_by_name.find(state.lookup_key("tech_window"))->second.definition);
848
849 Cyto::Any payload = tid;
850 ptr->impl_set(state, payload);
851
852 ptr->base_data.position.x =
853 static_cast<int16_t>(base_group_offset.x + (folder_x_offset[folder_id] * ptr->base_data.size.x));
854 // 16px spacing between tech items, 109+16 base offset
855 ptr->base_data.position.y =
856 static_cast<int16_t>(base_group_offset.y + base_tech_offset.y +
857 (static_cast<int16_t>(items_per_folder[folder_id]) * ptr->base_data.size.y));
858 items_per_folder[folder_id]++;
859 add_child_to_front(std::move(ptr));
860 });
861 }
862
863 // Properly setup technology displays...
864 Cyto::Any payload = active_tab;
865 impl_set(state, payload);
866
867 set_visible(state, false);
868 }
869
870 std::unique_ptr<element_base> make_child(sys::state& state, std::string_view name, dcon::gui_def_id id) noexcept override {
871 if(name == "main_bg") {
872 return make_element_by_type<image_element_base>(state, id);
873 } else if(name == "bg_tech") {
874 return make_element_by_type<opaque_element_base>(state, id);
875 } else if(name == "close_button") {
876 return make_element_by_type<generic_close_button>(state, id);
877 } else if(name == "administration") {
878 return make_element_by_type<simple_body_text>(state, id);
879 } else if(name == "current_research") {
880 return make_element_by_type<simple_body_text>(state, id);
881 } else if(name == "administration_type") {
882 return make_element_by_type<national_tech_school>(state, id);
883 } else if(name == "research_progress") {
884 return make_element_by_type<nation_technology_research_progress>(state, id);
885 } else if(name == "research_progress_name") {
886 return make_element_by_type<nation_current_research_text>(state, id);
887 } else if(name == "research_progress_category") {
888 return make_element_by_type<technology_research_progress_category_text>(state, id);
889 } else if(name == "selected_tech_window") {
890 auto ptr = make_element_by_type<technology_selected_tech_window>(state, id);
891 selected_tech_win = ptr.get();
892 return ptr;
893 } else if(name == "sort_by_type") {
894 auto ptr = make_element_by_type<technology_sort_by_type_button>(state, id);
895 ptr->base_data.position.y -= 1; // Nudge
896 return ptr;
897 } else if(name == "sort_by_name") {
898 return make_element_by_type<technology_sort_by_name_button>(state, id);
899 } else if(name == "sort_by_percent") {
900 auto ptr = make_element_by_type<technology_sort_by_percent_button>(state, id);
901 ptr->base_data.position.y -= 1; // Nudge
902 return ptr;
903 } else if(name == "inventions") {
904 return make_element_by_type<technology_possible_invention_listbox>(state, id);
905 } else {
906 return nullptr;
907 }
908 }
909
910 message_result set(sys::state& state, Cyto::Any& payload) noexcept override {
911 if(payload.holds_type<culture::tech_category>()) {
912 active_tab = any_cast<culture::tech_category>(payload);
913 for(auto& c : children)
914 c->impl_set(state, payload);
916 } else if(payload.holds_type<technology_select_tech>()) {
917 tech_id = any_cast<technology_select_tech>(payload).tech_id;
918 selected_tech_win->impl_on_update(state);
920 }
922 }
923
924 message_result get(sys::state& state, Cyto::Any& payload) noexcept override {
925 if(payload.holds_type<dcon::technology_id>()) {
926 payload.emplace<dcon::technology_id>(tech_id);
928 } else if(payload.holds_type<dcon::nation_id>()) {
929 payload.emplace<dcon::nation_id>(state.local_player_nation);
931 } else if(payload.holds_type<element_selection_wrapper<invention_sort_type>>()) {
932 invention_sort = any_cast<element_selection_wrapper<invention_sort_type>>(payload).data;
935 } else if(payload.holds_type<invention_sort_type>()) {
936 payload = invention_sort;
938 }
940 }
941};
942
943} // namespace ui
dcon::text_key get_name() noexcept
message_result impl_set(sys::state &state, Cyto::Any &payload) noexcept final
void add_child_to_front(std::unique_ptr< element_base > child) noexcept final
std::vector< std::unique_ptr< element_base > > children
void impl_on_update(sys::state &state) noexcept override
virtual message_result impl_set(sys::state &state, Cyto::Any &payload) noexcept
element_base * parent
virtual message_result get(sys::state &state, Cyto::Any &payload) noexcept
virtual void impl_on_update(sys::state &state) noexcept
message_result impl_get(sys::state &state, Cyto::Any &payload) noexcept
virtual void on_create(sys::state &state) noexcept
element_data base_data
void set_visible(sys::state &state, bool vis)
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
void on_update(sys::state &state) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void on_update(sys::state &state) noexcept override
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
void on_update(sys::state &state) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void calibrate_scrollbar(sys::state &state) noexcept
void on_create(sys::state &state) noexcept override
multiline_text_element_base * delegate
void set_text(sys::state &state, std::string const &new_text)
void set_category(sys::state &state, culture::tech_category new_category)
std::unique_ptr< element_base > make_child(sys::state &state, std::string_view name, dcon::gui_def_id id) noexcept override
void button_action(sys::state &state) noexcept final
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
bool is_active(sys::state &state) noexcept final
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void on_update(sys::state &state) noexcept override
void button_shift_action(sys::state &state) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
void button_action(sys::state &state) noexcept override
void button_right_action(sys::state &state) noexcept override
void on_update(sys::state &state) noexcept override
std::unique_ptr< element_base > make_child(sys::state &state, std::string_view name, dcon::gui_def_id id) noexcept override
message_result set(sys::state &state, Cyto::Any &payload) noexcept override
message_result get(sys::state &state, Cyto::Any &payload) noexcept override
void on_update(sys::state &state) noexcept override
void on_update(sys::state &state) noexcept override
void on_update(sys::state &state) noexcept override
std::unique_ptr< element_base > make_child(sys::state &state, std::string_view name, dcon::gui_def_id id) noexcept override
void on_update(sys::state &state) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
void on_update(sys::state &state) noexcept override
void on_update(sys::state &state) noexcept override
void on_create(sys::state &state) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
void on_update(sys::state &state) noexcept override
std::unique_ptr< element_base > make_child(sys::state &state, std::string_view name, dcon::gui_def_id id) noexcept override
void on_update(sys::state &state) noexcept override
std::unique_ptr< element_base > make_child(sys::state &state, std::string_view name, dcon::gui_def_id id) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void button_action(sys::state &state) noexcept override
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void button_action(sys::state &state) noexcept override
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
void update_tooltip(sys::state &state, int32_t x, int32_t y, text::columnar_layout &contents) noexcept override
void button_action(sys::state &state) noexcept override
tooltip_behavior has_tooltip(sys::state &state) noexcept override
void button_action(sys::state &state) noexcept override
void on_update(sys::state &state) noexcept override
void on_update(sys::state &state) noexcept override
message_result set(sys::state &state, Cyto::Any &payload) noexcept override
std::unique_ptr< element_base > make_child(sys::state &state, std::string_view name, dcon::gui_def_id id) noexcept override
void on_create(sys::state &state) noexcept override
std::unique_ptr< element_base > make_child(sys::state &state, std::string_view name, dcon::gui_def_id id) noexcept override
message_result get(sys::state &state, Cyto::Any &payload) noexcept override
message_result set(sys::state &state, Cyto::Any &payload) noexcept override
void on_update(sys::state &state) noexcept override
bool can_start_research(sys::state &state, dcon::nation_id source, dcon::technology_id tech)
Definition: commands.cpp:183
float effective_technology_cost(sys::state &state, uint32_t current_year, dcon::nation_id target_nation, dcon::technology_id tech_id)
Definition: culture.cpp:904
std::string get_tech_category_name(tech_category t)
Definition: culture.cpp:12
tech_category
Definition: culture.hpp:106
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
dcon::technology_id current_research(sys::state const &state, dcon::nation_id n)
Definition: nations.cpp:606
void add_to_layout_box(sys::state &state, layout_base &dest, layout_box &box, embedded_flag ico)
Definition: text.cpp:1165
std::string get_name_as_string(sys::state &state, T t)
Definition: text.hpp:954
layout_box open_layout_box(layout_base &dest, int32_t indent)
Definition: text.cpp:1799
void localised_format_box(sys::state &state, layout_base &dest, layout_box &box, std::string_view key, text::substitution_map const &sub)
Definition: text.cpp:1880
endless_layout create_endless_layout(sys::state &state, layout &dest, layout_parameters const &params)
Definition: text.cpp:1100
void add_line(sys::state &state, layout_base &dest, dcon::text_key txt, int32_t indent)
Definition: text.cpp:1899
void add_line_break_to_layout(sys::state &state, columnar_layout &dest)
Definition: text.cpp:1152
std::string produce_simple_string(sys::state const &state, dcon::text_key id)
Definition: text.cpp:617
std::string format_percentage(float num, size_t digits)
Definition: text.cpp:977
void add_space_to_layout_box(sys::state &state, layout_base &dest, layout_box &box)
Definition: text.cpp:1788
void close_layout_box(columnar_layout &dest, layout_box &box)
Definition: text.cpp:1807
int32_t to_generic(dcon::province_id v)
Definition: triggers.hpp:12
bool evaluate(sys::state &state, dcon::trigger_key key, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5865
float evaluate_additive_modifier(sys::state &state, dcon::value_modifier_key modifier, int32_t primary, int32_t this_slot, int32_t from_slot)
Definition: triggers.cpp:5796
uint16_t * recurse_over_triggers(uint16_t *source, T const &f)
void additive_value_modifier_description(sys::state &state, text::layout_base &layout, dcon::value_modifier_key modifier, int32_t primary, int32_t this_slot, int32_t from_slot)
tooltip_behavior
void send(sys::state &state, element_base *parent, T value)
void technology_description(sys::state &state, text::layout_base &contents, dcon::technology_id tech_id) noexcept
message_result
void invention_description(sys::state &state, text::layout_base &contents, dcon::invention_id inv_id, int32_t indent) noexcept
void active_modifiers_description(sys::state &state, text::layout_base &layout, dcon::nation_id n, int32_t identation, dcon::national_modifier_value nmid, bool header)
uchar uint8_t
union ui::element_data::internal_data data
dcon::gfx_object_id gfx_object
element_base * technology_subwindow
ankerl::unordered_dense::map< dcon::text_key, element_target, hash_text_key > defs_by_name
std::vector< dcon::technology_id > tech_queue