You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Merge pull request #90092 from KoBeWi/casually_adding_credits_roll_to_a_GAME_engine
Add credits roll
This commit is contained in:
245
editor/credits_roll.cpp
Normal file
245
editor/credits_roll.cpp
Normal file
@@ -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
editor/credits_roll.h
Normal file
68
editor/credits_roll.h
Normal file
@@ -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,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,10 +122,12 @@ 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 §ion_name = *itr;
|
||||
|
||||
Label *lbl = memnew(Label);
|
||||
lbl->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
|
||||
lbl->set_theme_type_variation("HeaderSmall");
|
||||
lbl->set_text(*itr);
|
||||
lbl->set_text(section_name);
|
||||
vbc->add_child(lbl);
|
||||
|
||||
ItemList *il = memnew(ItemList);
|
||||
@@ -152,6 +169,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);
|
||||
}
|
||||
@@ -219,7 +247,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,
|
||||
@@ -227,7 +256,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.
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user