1/**************************************************************************/
2/* editor_log.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef EDITOR_LOG_H
32#define EDITOR_LOG_H
33
34#include "core/os/thread.h"
35#include "scene/gui/box_container.h"
36#include "scene/gui/button.h"
37#include "scene/gui/label.h"
38#include "scene/gui/line_edit.h"
39#include "scene/gui/panel_container.h"
40#include "scene/gui/rich_text_label.h"
41#include "scene/gui/texture_button.h"
42#include "scene/gui/texture_rect.h"
43
44class UndoRedo;
45
46class EditorLog : public HBoxContainer {
47 GDCLASS(EditorLog, HBoxContainer);
48
49public:
50 enum MessageType {
51 MSG_TYPE_STD,
52 MSG_TYPE_ERROR,
53 MSG_TYPE_STD_RICH,
54 MSG_TYPE_WARNING,
55 MSG_TYPE_EDITOR,
56 };
57
58private:
59 struct LogMessage {
60 String text;
61 MessageType type;
62 int count = 1;
63 bool clear = true;
64
65 LogMessage() {}
66
67 LogMessage(const String p_text, MessageType p_type, bool p_clear) :
68 text(p_text),
69 type(p_type),
70 clear(p_clear) {
71 }
72 };
73
74 struct {
75 Color error_color;
76 Ref<Texture2D> error_icon;
77
78 Color warning_color;
79 Ref<Texture2D> warning_icon;
80
81 Color message_color;
82 } theme_cache;
83
84 // Encapsulates all data and functionality regarding filters.
85 struct LogFilter {
86 private:
87 // Force usage of set method since it has functionality built-in.
88 int message_count = 0;
89 bool active = true;
90
91 public:
92 MessageType type;
93 Button *toggle_button = nullptr;
94
95 void initialize_button(const String &p_tooltip, Callable p_toggled_callback) {
96 toggle_button = memnew(Button);
97 toggle_button->set_toggle_mode(true);
98 toggle_button->set_pressed(true);
99 toggle_button->set_text(itos(message_count));
100 toggle_button->set_tooltip_text(TTR(p_tooltip));
101 // Don't tint the icon even when in "pressed" state.
102 toggle_button->add_theme_color_override("icon_color_pressed", Color(1, 1, 1, 1));
103 toggle_button->set_focus_mode(FOCUS_NONE);
104 // When toggled call the callback and pass the MessageType this button is for.
105 toggle_button->connect("toggled", p_toggled_callback.bind(type));
106 }
107
108 int get_message_count() {
109 return message_count;
110 }
111
112 void set_message_count(int p_count) {
113 message_count = p_count;
114 toggle_button->set_text(itos(message_count));
115 }
116
117 bool is_active() {
118 return active;
119 }
120
121 void set_active(bool p_active) {
122 toggle_button->set_pressed(p_active);
123 active = p_active;
124 }
125
126 LogFilter(MessageType p_type) :
127 type(p_type) {
128 }
129 };
130
131 Vector<LogMessage> messages;
132 // Maps MessageTypes to LogFilters for convenient access and storage (don't need 1 member per filter).
133 HashMap<MessageType, LogFilter *> type_filter_map;
134
135 RichTextLabel *log = nullptr;
136
137 Button *clear_button = nullptr;
138 Button *copy_button = nullptr;
139
140 Button *collapse_button = nullptr;
141 bool collapse = false;
142
143 Button *show_search_button = nullptr;
144 LineEdit *search_box = nullptr;
145
146 // Reference to the "Output" button on the toolbar so we can update it's icon when
147 // Warnings or Errors are encounetered.
148 Button *tool_button = nullptr;
149
150 bool is_loading_state = false; // Used to disable saving requests while loading (some signals from buttons will try trigger a save, which happens during loading).
151 Timer *save_state_timer = nullptr;
152
153 static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type);
154
155 ErrorHandlerList eh;
156
157 Thread::ID current;
158
159 //void _dragged(const Point2& p_ofs);
160 void _clear_request();
161 void _copy_request();
162 static void _undo_redo_cbk(void *p_self, const String &p_name);
163
164 void _rebuild_log();
165 void _add_log_line(LogMessage &p_message, bool p_replace_previous = false);
166
167 void _set_filter_active(bool p_active, MessageType p_message_type);
168 void _set_search_visible(bool p_visible);
169 void _search_changed(const String &p_text);
170
171 void _process_message(const String &p_msg, MessageType p_type, bool p_clear);
172 void _reset_message_counts();
173
174 void _set_collapse(bool p_collapse);
175
176 void _start_state_save_timer();
177 void _save_state();
178 void _load_state();
179
180 void _update_theme();
181
182protected:
183 void _notification(int p_what);
184
185public:
186 void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD);
187 void set_tool_button(Button *p_tool_button);
188 void register_undo_redo(UndoRedo *p_undo_redo);
189 void deinit();
190
191 void clear();
192
193 EditorLog();
194 ~EditorLog();
195};
196
197VARIANT_ENUM_CAST(EditorLog::MessageType);
198
199#endif // EDITOR_LOG_H
200