Bläddra i källkod

Add credits roll

kobewi 1 år sedan
förälder
incheckning
336bf5269d
4 ändrade filer med 351 tillägg och 5 borttagningar
  1. 245 0
      editor/credits_roll.cpp
  2. 68 0
      editor/credits_roll.h
  3. 33 4
      editor/editor_about.cpp
  4. 5 1
      editor/editor_about.h

+ 245 - 0
editor/credits_roll.cpp

@@ -0,0 +1,245 @@
+/**************************************************************************/
+/*  credits_roll.cpp                                                      */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#include "credits_roll.h"
+
+#include "core/authors.gen.h"
+#include "core/donors.gen.h"
+#include "core/input/input.h"
+#include "core/license.gen.h"
+#include "core/string/string_builder.h"
+#include "editor/editor_string_names.h"
+#include "editor/themes/editor_scale.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/color_rect.h"
+#include "scene/gui/label.h"
+#include "scene/gui/texture_rect.h"
+
+Label *CreditsRoll::_create_label(const String &p_with_text, LabelSize p_size) {
+	Label *label = memnew(Label);
+	label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+	label->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
+	label->set_text(p_with_text);
+
+	switch (p_size) {
+		case LabelSize::NORMAL: {
+			label->add_theme_font_size_override(SceneStringName(font_size), font_size_normal);
+		} break;
+
+		case LabelSize::HEADER: {
+			label->add_theme_font_size_override(SceneStringName(font_size), font_size_header);
+			label->add_theme_font_override(SceneStringName(font), bold_font);
+		} break;
+
+		case LabelSize::BIG_HEADER: {
+			label->add_theme_font_size_override(SceneStringName(font_size), font_size_big_header);
+			label->add_theme_font_override(SceneStringName(font), bold_font);
+		} break;
+	}
+	content->add_child(label);
+	return label;
+}
+
+void CreditsRoll::_create_nothing(int p_size) {
+	if (p_size == -1) {
+		p_size = 30 * EDSCALE;
+	}
+	Control *c = memnew(Control);
+	c->set_custom_minimum_size(Vector2(0, p_size));
+	content->add_child(c);
+}
+
+String CreditsRoll::_build_string(const char *const *p_from) const {
+	StringBuilder sb;
+
+	while (*p_from) {
+		sb.append(String::utf8(*p_from));
+		sb.append("\n");
+		p_from++;
+	}
+	return sb.as_string();
+}
+
+void CreditsRoll::_notification(int p_what) {
+	switch (p_what) {
+		case NOTIFICATION_VISIBILITY_CHANGED: {
+			if (!is_visible()) {
+				set_process_internal(false);
+				mouse_enabled = false;
+			}
+		} break;
+
+		case NOTIFICATION_TRANSLATION_CHANGED: {
+			if (project_manager) {
+				project_manager->set_text(TTR("Project Manager", "Job Title"));
+			}
+		} break;
+
+		case NOTIFICATION_WM_GO_BACK_REQUEST: {
+			hide();
+		} break;
+
+		case NOTIFICATION_INTERNAL_PROCESS: {
+			const Vector2 pos = content->get_position();
+			if (pos.y < -content->get_size().y - 30) {
+				hide();
+				break;
+			}
+
+			if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::RIGHT)) {
+				hide();
+				break;
+			}
+
+			bool lmb = Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT);
+			if (!mouse_enabled && !lmb) {
+				// Makes sure that the initial double click does not speed up text.
+				mouse_enabled = true;
+			}
+
+			if ((mouse_enabled && lmb) || Input::get_singleton()->is_action_pressed(SNAME("ui_accept"))) {
+				content->set_position(Vector2(pos.x, pos.y - 2000 * get_process_delta_time()));
+			} else {
+				content->set_position(Vector2(pos.x, pos.y - 100 * get_process_delta_time()));
+			}
+		} break;
+	}
+}
+
+void CreditsRoll::roll_credits() {
+	if (!project_manager) {
+		font_size_normal = get_theme_font_size("main_size", EditorStringName(EditorFonts)) * 2;
+		font_size_header = font_size_normal + 10 * EDSCALE;
+		font_size_big_header = font_size_header + 20 * EDSCALE;
+		bold_font = get_theme_font("bold", EditorStringName(EditorFonts));
+
+		{
+			const Ref<Texture2D> logo_texture = get_editor_theme_icon("Logo");
+
+			TextureRect *logo = memnew(TextureRect);
+			logo->set_custom_minimum_size(Vector2(0, logo_texture->get_height() * 3));
+			logo->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
+			logo->set_texture(logo_texture);
+			content->add_child(logo);
+		}
+
+		_create_label(TTRC("Credits"), LabelSize::BIG_HEADER);
+
+		_create_nothing();
+
+		_create_label(TTRC("Project Founders"), LabelSize::HEADER);
+		_create_label(_build_string(AUTHORS_FOUNDERS));
+
+		_create_nothing();
+
+		_create_label(TTRC("Lead Developer"), LabelSize::HEADER);
+		_create_label(_build_string(AUTHORS_LEAD_DEVELOPERS));
+
+		_create_nothing();
+
+		project_manager = _create_label(TTR("Project Manager", "Job Title"), LabelSize::HEADER);
+		_create_label(_build_string(AUTHORS_PROJECT_MANAGERS));
+
+		_create_nothing();
+
+		_create_label(TTRC("Developers"), LabelSize::HEADER);
+		_create_label(_build_string(AUTHORS_DEVELOPERS));
+
+		_create_nothing();
+
+		_create_label(TTRC("Patrons"), LabelSize::HEADER);
+		_create_label(_build_string(DONORS_PATRONS));
+
+		_create_nothing();
+
+		_create_label(TTRC("Platinum Sponsors"), LabelSize::HEADER);
+		_create_label(_build_string(DONORS_SPONSORS_PLATINUM));
+
+		_create_nothing();
+
+		_create_label(TTRC("Gold Sponsors"), LabelSize::HEADER);
+		_create_label(_build_string(DONORS_SPONSORS_GOLD));
+
+		_create_nothing();
+
+		_create_label(TTRC("Silver Sponsors"), LabelSize::HEADER);
+		_create_label(_build_string(DONORS_SPONSORS_SILVER));
+
+		_create_nothing();
+
+		_create_label(TTRC("Diamond Members"), LabelSize::HEADER);
+		_create_label(_build_string(DONORS_MEMBERS_DIAMOND));
+
+		_create_nothing();
+
+		_create_label(TTRC("Titanium Members"), LabelSize::HEADER);
+		_create_label(_build_string(DONORS_MEMBERS_TITANIUM));
+
+		_create_nothing();
+
+		_create_label(TTRC("Platinum Members"), LabelSize::HEADER);
+		_create_label(_build_string(DONORS_MEMBERS_PLATINUM));
+
+		_create_nothing();
+
+		_create_label(TTRC("Gold Members"), LabelSize::HEADER);
+		_create_label(_build_string(DONORS_MEMBERS_GOLD));
+
+		_create_nothing();
+		_create_label(String::utf8(GODOT_LICENSE_TEXT));
+
+		_create_nothing(400 * EDSCALE);
+		_create_label(TTRC("Thank you for choosing Godot Engine!"), LabelSize::BIG_HEADER);
+	}
+
+	Window *root = get_tree()->get_root();
+	content->set_position(Vector2(content->get_position().x, root->get_size().y + 30));
+
+	set_position(root->get_position());
+	set_size(root->get_size());
+
+	popup();
+	set_process_internal(true);
+}
+
+CreditsRoll::CreditsRoll() {
+	set_wrap_controls(false);
+
+	{
+		ColorRect *background = memnew(ColorRect);
+		background->set_color(Color(0, 0, 0, 1));
+		background->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+		add_child(background);
+	}
+
+	content = memnew(VBoxContainer);
+	content->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+	add_child(content);
+}

+ 68 - 0
editor/credits_roll.h

@@ -0,0 +1,68 @@
+/**************************************************************************/
+/*  credits_roll.h                                                        */
+/**************************************************************************/
+/*                         This file is part of:                          */
+/*                             GODOT ENGINE                               */
+/*                        https://godotengine.org                         */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
+/*                                                                        */
+/* Permission is hereby granted, free of charge, to any person obtaining  */
+/* a copy of this software and associated documentation files (the        */
+/* "Software"), to deal in the Software without restriction, including    */
+/* without limitation the rights to use, copy, modify, merge, publish,    */
+/* distribute, sublicense, and/or sell copies of the Software, and to     */
+/* permit persons to whom the Software is furnished to do so, subject to  */
+/* the following conditions:                                              */
+/*                                                                        */
+/* The above copyright notice and this permission notice shall be         */
+/* included in all copies or substantial portions of the Software.        */
+/*                                                                        */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
+/**************************************************************************/
+
+#pragma once
+
+#include "scene/gui/popup.h"
+
+class Label;
+class VBoxContainer;
+class Font;
+
+class CreditsRoll : public Popup {
+	GDCLASS(CreditsRoll, Popup);
+
+	enum class LabelSize {
+		NORMAL,
+		HEADER,
+		BIG_HEADER,
+	};
+
+	int font_size_normal = 0;
+	int font_size_header = 0;
+	int font_size_big_header = 0;
+	Ref<Font> bold_font;
+
+	bool mouse_enabled = false;
+	VBoxContainer *content = nullptr;
+	Label *project_manager = nullptr;
+
+	Label *_create_label(const String &p_with_text, LabelSize p_size = LabelSize::NORMAL);
+	void _create_nothing(int p_size = -1);
+	String _build_string(const char *const *p_from) const;
+
+protected:
+	void _notification(int p_what);
+
+public:
+	void roll_credits();
+
+	CreditsRoll();
+};

+ 33 - 4
editor/editor_about.cpp

@@ -33,6 +33,8 @@
 #include "core/authors.gen.h"
 #include "core/donors.gen.h"
 #include "core/license.gen.h"
+#include "editor/credits_roll.h"
+#include "editor/editor_node.h"
 #include "editor/editor_string_names.h"
 #include "editor/gui/editor_version_button.h"
 #include "editor/themes/editor_scale.h"
@@ -80,6 +82,19 @@ void EditorAbout::_license_tree_selected() {
 	_tpl_text->set_text(selected->get_metadata(0));
 }
 
+void EditorAbout::_project_manager_clicked() {
+	if (!EditorNode::get_singleton()) {
+		// Don't allow in Project Manager.
+		return;
+	}
+
+	if (!credits_roll) {
+		credits_roll = memnew(CreditsRoll);
+		add_child(credits_roll);
+	}
+	credits_roll->roll_credits();
+}
+
 void EditorAbout::_item_with_website_selected(int p_id, ItemList *p_il) {
 	const String website = p_il->get_item_metadata(p_id);
 	if (!website.is_empty()) {
@@ -91,7 +106,7 @@ void EditorAbout::_item_list_resized(ItemList *p_il) {
 	p_il->set_fixed_column_width(p_il->get_size().x / 3.0 - 16 * EDSCALE * 2.5); // Weird. Should be 3.0 and that's it?.
 }
 
-ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<String> &p_sections, const char *const *const p_src[], const int p_single_column_flags, const bool p_allow_website) {
+ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<String> &p_sections, const char *const *const p_src[], const int p_single_column_flags, const bool p_allow_website, const String &p_easter_egg_section) {
 	ScrollContainer *sc = memnew(ScrollContainer);
 	sc->set_name(p_name);
 	sc->set_v_size_flags(Control::SIZE_EXPAND);
@@ -107,9 +122,11 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St
 		bool single_column = p_single_column_flags & (1 << i);
 		const char *const *names_ptr = p_src[i];
 		if (*names_ptr) {
+			const String &section_name = *itr;
+
 			Label *lbl = memnew(Label);
 			lbl->set_theme_type_variation("HeaderSmall");
-			lbl->set_text(*itr);
+			lbl->set_text(section_name);
 			vbc->add_child(lbl);
 
 			ItemList *il = memnew(ItemList);
@@ -151,6 +168,17 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St
 					}
 				}
 			} else {
+				if (section_name == p_easter_egg_section) {
+					// Easter egg :D
+					il->set_focus_mode(Control::FOCUS_CLICK);
+					il->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+
+					il->connect("item_activated", callable_mp(this, &EditorAbout::_project_manager_clicked).unbind(1), CONNECT_DEFERRED);
+
+					il->add_theme_style_override("focus", empty_stylebox);
+					il->add_theme_style_override("selected", empty_stylebox);
+				}
+
 				while (*names_ptr) {
 					il->add_item(String::utf8(*names_ptr++), nullptr, false);
 				}
@@ -217,7 +245,8 @@ EditorAbout::EditorAbout() {
 	dev_sections.push_back(TTR("Project Founders"));
 	dev_sections.push_back(TTR("Lead Developer"));
 	// TRANSLATORS: This refers to a job title.
-	dev_sections.push_back(TTR("Project Manager", "Job Title"));
+	const String project_manager = TTR("Project Manager", "Job Title");
+	dev_sections.push_back(project_manager);
 	dev_sections.push_back(TTR("Developers"));
 	const char *const *dev_src[] = {
 		AUTHORS_FOUNDERS,
@@ -225,7 +254,7 @@ EditorAbout::EditorAbout() {
 		AUTHORS_PROJECT_MANAGERS,
 		AUTHORS_DEVELOPERS,
 	};
-	tc->add_child(_populate_list(TTR("Authors"), dev_sections, dev_src, 0b1)); // First section (Project Founders) is always one column.
+	tc->add_child(_populate_list(TTR("Authors"), dev_sections, dev_src, 0b1, false, project_manager)); // First section (Project Founders) is always one column.
 
 	// Donors.
 

+ 5 - 1
editor/editor_about.h

@@ -37,6 +37,8 @@
 #include "scene/gui/texture_rect.h"
 #include "scene/gui/tree.h"
 
+class CreditsRoll;
+
 /**
  * NOTE: Do not assume the EditorNode singleton to be available in this class' methods.
  * EditorAbout is also used from the project manager where EditorNode isn't initialized.
@@ -46,15 +48,17 @@ class EditorAbout : public AcceptDialog {
 
 private:
 	void _license_tree_selected();
+	void _project_manager_clicked();
 	void _item_with_website_selected(int p_id, ItemList *p_il);
 	void _item_list_resized(ItemList *p_il);
-	ScrollContainer *_populate_list(const String &p_name, const List<String> &p_sections, const char *const *const p_src[], int p_single_column_flags = 0, bool p_allow_website = false);
+	ScrollContainer *_populate_list(const String &p_name, const List<String> &p_sections, const char *const *const p_src[], int p_single_column_flags = 0, bool p_allow_website = false, const String &p_easter_egg_section = String());
 
 	Tree *_tpl_tree = nullptr;
 	RichTextLabel *license_text_label = nullptr;
 	RichTextLabel *_tpl_text = nullptr;
 	TextureRect *_logo = nullptr;
 	Vector<ItemList *> name_lists;
+	CreditsRoll *credits_roll = nullptr;
 
 protected:
 	void _notification(int p_what);