// SPDX-FileCopyrightText: 2021-2024 Leroy Hopson // SPDX-License-Identifier: MIT #pragma once #include #include #include #include #include #include #include #include #include #include #include #include namespace godot { class Terminal : public Control { GDCLASS(Terminal, Control) private: typedef std::map, uint32_t> KeyMap; enum FontType { NORMAL, BOLD, ITALICS, BOLD_ITALICS, }; static const char *COLOR_NAMES[18]; static const char *FONT_TYPES[4]; static const KeyMap KEY_MAP; public: enum AttrFlag { INVERSE = 1 << 0, BLINK = 1 << 1, CURSOR = 1 << 2, }; enum InverseMode { INVERSE_MODE_INVERT, INVERSE_MODE_SWAP, }; Terminal(); ~Terminal(); int get_cols() const; int get_rows() const; Vector2i get_cursor_pos() const; Vector2 get_cell_size() const; void set_max_scrollback(const int p_max_scrollback); int get_max_scrollback() const; void set_bell_muted(const bool p_bell_muted); bool get_bell_muted() const; void set_bell_cooldown(const double p_bell_cooldown); double get_bell_cooldown() const; void set_blink_on_time(const double p_blink_on_time); double get_blink_on_time() const; void set_blink_off_time(const double p_blink_off_time); double get_blink_off_time() const; void clear(); void select(const int p_from_line, const int p_from_column, const int p_to_line, const int p_to_column); String copy_all(); String copy_selection(); void set_copy_on_selection(const bool p_enable); bool get_copy_on_selection() const; void set_inverse_mode(const int mode); int get_inverse_mode() const; String write(const Variant data); void _gui_input(const Ref &event) override; protected: static void _bind_methods(); private: unsigned int max_scrollback; unsigned int cols; unsigned int rows; double blink_on_time; double blink_off_time; // If true, text in the terminal will be copied to the clipboard when selected. bool copy_on_selection; InverseMode inverse_mode; RenderingServer *rs; tsm_screen *screen; tsm_vte *vte; tsm_age_t framebuffer_age; PackedByteArray response; static void _write_cb(struct tsm_vte *vte, const char *u8, size_t len, void *data); // If muted, the "bell" signal will not be emitted when the bell "\u0007" character // is written to the terminal. bool bell_muted; // Amount of time in seconds that must pass before emitting a new "bell" signal. // This can be useful in cases where the bell character is being written too // frequently such as `while true; do echo -e "\a"; done`. double bell_cooldown; Timer* bell_timer; static void _bell_cb(struct tsm_vte *vte, void *data); static int _draw_cb(struct tsm_screen *con, uint64_t id, const uint32_t *ch, size_t len, unsigned int width, unsigned int posx, unsigned int posy, const struct tsm_screen_attr *attr, tsm_age_t age, void *data); PackedColorArray palette; std::map> fonts; int32_t font_size; double font_offset; Vector2 size; Vector2 cell_size; Vector2i cursor_position; Ref attr_image; Ref attr_texture; // StyleBox. Ref style_normal; Ref style_focus; RID style_canvas_item; // Background. Ref back_image; Ref back_texture; Ref back_shader; Ref back_material; RID back_canvas_item; // Foreground. RID char_shader, char_material, char_canvas_item, canvas, viewport, fore_canvas_item; Ref fore_shader; Ref fore_material; void _notification(const int what); void initialize_rendering(); void update_theme(); void update_sizes(bool force = false); void set_shader_parameters(const String &name = "", const Variant &value = nullptr); bool redraw_requested = false; void _on_frame_post_draw(); void draw_screen(); void refresh(); void cleanup_rendering(); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_value); void _get_property_list(List *p_list) const; bool _is_valid_color_name(const String &p_name); bool _is_valid_font_type(const String &p_name); Ref last_input_event_key; void initialize_input(); void _handle_key_input(Ref event); void _handle_mouse_wheel(Ref event); bool selecting = false; Vector2i selection_last_point; void _handle_selection(Ref event); typedef std::function ScreenCopyFunction; String _copy_screen(ScreenCopyFunction func); void set_default_theme_items(); }; } // namespace godot VARIANT_ENUM_CAST(Terminal::InverseMode);