diff --git a/Applications/Browser/InspectorWidget.cpp b/Applications/Browser/InspectorWidget.cpp index df724a2726a..2c0d3c0e902 100644 --- a/Applications/Browser/InspectorWidget.cpp +++ b/Applications/Browser/InspectorWidget.cpp @@ -42,7 +42,7 @@ void InspectorWidget::set_inspected_node(Web::Node* node) { m_document->set_inspected_node(node); if (node && node->is_element()) { - auto& element = Web::to(*node); + auto& element = downcast(*node); if (element.resolved_style()) { m_style_table_view->set_model(Web::StylePropertiesModel::create(*element.resolved_style())); m_computed_style_table_view->set_model(Web::StylePropertiesModel::create(*element.computed_style())); diff --git a/DevTools/HackStudio/EditorWrapper.h b/DevTools/HackStudio/EditorWrapper.h index 00c2143c3c6..cea322fab25 100644 --- a/DevTools/HackStudio/EditorWrapper.h +++ b/DevTools/HackStudio/EditorWrapper.h @@ -55,8 +55,6 @@ private: RefPtr m_editor; }; -template<> -inline bool Core::is(const Core::Object& object) -{ - return !strcmp(object.class_name(), "EditorWrapper"); -} +AK_BEGIN_TYPE_TRAITS(EditorWrapper) +static bool is_type(const Core::Object& object) { return !strcmp(object.class_name(), "EditorWrapper"); } +AK_END_TYPE_TRAITS() diff --git a/Libraries/LibCore/Object.h b/Libraries/LibCore/Object.h index 53852ef8207..99d9238925f 100644 --- a/Libraries/LibCore/Object.h +++ b/Libraries/LibCore/Object.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -147,8 +148,8 @@ protected: // NOTE: You may get child events for children that are not yet fully constructed! virtual void child_event(ChildEvent&); - virtual void did_begin_inspection() {} - virtual void did_end_inspection() {} + virtual void did_begin_inspection() { } + virtual void did_end_inspection() { } private: Object* m_parent { nullptr }; @@ -159,29 +160,15 @@ private: NonnullRefPtrVector m_children; }; -template -inline bool is(const Object&) { return false; } - -template -inline T& to(Object& object) -{ - ASSERT(is::Type>(object)); - return static_cast(object); -} - -template -inline const T& to(const Object& object) -{ - ASSERT(is::Type>(object)); - return static_cast(object); } +namespace Core { template inline void Object::for_each_child_of_type(Callback callback) { for_each_child([&](auto& child) { if (is(child)) - return callback(to(child)); + return callback(downcast(child)); return IterationDecision::Continue; }); } diff --git a/Libraries/LibGUI/AbstractButton.h b/Libraries/LibGUI/AbstractButton.h index 1fc701bf7d1..7e62e5a9f1c 100644 --- a/Libraries/LibGUI/AbstractButton.h +++ b/Libraries/LibGUI/AbstractButton.h @@ -91,10 +91,6 @@ private: } -template<> -inline bool Core::is(const Core::Object& object) -{ - if (!is(object)) - return false; - return to(object).is_abstract_button(); -} +AK_BEGIN_TYPE_TRAITS(GUI::AbstractButton) +static bool is_type(const Core::Object& object) { return is(object) && downcast(object).is_abstract_button(); } +AK_END_TYPE_TRAITS() diff --git a/Libraries/LibGUI/Action.cpp b/Libraries/LibGUI/Action.cpp index 8bb9ef7c884..8a4edb6d9d4 100644 --- a/Libraries/LibGUI/Action.cpp +++ b/Libraries/LibGUI/Action.cpp @@ -152,9 +152,9 @@ Action::Action(const StringView& text, const Shortcut& shortcut, RefPtr(*parent)) { + if (parent && is(*parent)) { m_scope = ShortcutScope::WidgetLocal; - } else if (parent && Core::is(*parent)) { + } else if (parent && is(*parent)) { m_scope = ShortcutScope::WindowLocal; } else { m_scope = ShortcutScope::ApplicationGlobal; diff --git a/Libraries/LibGUI/Action.h b/Libraries/LibGUI/Action.h index 6694ff31ddd..332e45647ef 100644 --- a/Libraries/LibGUI/Action.h +++ b/Libraries/LibGUI/Action.h @@ -42,23 +42,23 @@ namespace GUI { namespace CommonActions { - NonnullRefPtr make_open_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_save_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_undo_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_redo_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_cut_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_copy_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_paste_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_delete_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_move_to_front_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_move_to_back_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_fullscreen_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_quit_action(Function); - NonnullRefPtr make_go_back_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_go_forward_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_go_home_action(Function callback, Core::Object* parent = nullptr); - NonnullRefPtr make_reload_action(Function, Core::Object* parent = nullptr); - NonnullRefPtr make_select_all_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_open_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_save_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_undo_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_redo_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_cut_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_copy_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_paste_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_delete_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_move_to_front_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_move_to_back_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_fullscreen_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_quit_action(Function); +NonnullRefPtr make_go_back_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_go_forward_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_go_home_action(Function callback, Core::Object* parent = nullptr); +NonnullRefPtr make_reload_action(Function, Core::Object* parent = nullptr); +NonnullRefPtr make_select_all_action(Function, Core::Object* parent = nullptr); }; class Action final : public Core::Object { @@ -168,8 +168,6 @@ private: } -template<> -inline bool Core::is(const Core::Object& object) -{ - return object.is_action(); -} +AK_BEGIN_TYPE_TRAITS(GUI::Action) +static bool is_type(const Core::Object& object) { return object.is_action(); } +AK_END_TYPE_TRAITS() diff --git a/Libraries/LibGUI/RadioButton.cpp b/Libraries/LibGUI/RadioButton.cpp index d8c982145d9..d7fcc5f6952 100644 --- a/Libraries/LibGUI/RadioButton.cpp +++ b/Libraries/LibGUI/RadioButton.cpp @@ -74,7 +74,7 @@ void RadioButton::for_each_in_group(Callback callback) if (!parent()) return; parent()->for_each_child_of_type([&](auto& child) { - return callback(static_cast(child)); + return callback(downcast(child)); }); } diff --git a/Libraries/LibGUI/RadioButton.h b/Libraries/LibGUI/RadioButton.h index 18a492b5a0c..d4a0445da42 100644 --- a/Libraries/LibGUI/RadioButton.h +++ b/Libraries/LibGUI/RadioButton.h @@ -55,10 +55,6 @@ private: } -template<> -inline bool Core::is(const Core::Object& object) -{ - if (!is(object)) - return false; - return to(object).is_radio_button(); -} +AK_BEGIN_TYPE_TRAITS(GUI::RadioButton) +static bool is_type(const Core::Object& object) { return is(object) && downcast(object).is_radio_button(); } +AK_END_TYPE_TRAITS() diff --git a/Libraries/LibGUI/StackWidget.cpp b/Libraries/LibGUI/StackWidget.cpp index f72e26e1af8..eaaf05dfa11 100644 --- a/Libraries/LibGUI/StackWidget.cpp +++ b/Libraries/LibGUI/StackWidget.cpp @@ -63,9 +63,9 @@ void StackWidget::resize_event(ResizeEvent& event) void StackWidget::child_event(Core::ChildEvent& event) { - if (!event.child() || !Core::is(*event.child())) + if (!event.child() || !is(*event.child())) return Widget::child_event(event); - auto& child = Core::to(*event.child()); + auto& child = downcast(*event.child()); if (event.type() == Event::ChildAdded) { if (!m_active_widget) set_active_widget(&child); diff --git a/Libraries/LibGUI/TabWidget.cpp b/Libraries/LibGUI/TabWidget.cpp index 91d1468ba18..8426e087a43 100644 --- a/Libraries/LibGUI/TabWidget.cpp +++ b/Libraries/LibGUI/TabWidget.cpp @@ -102,9 +102,9 @@ Gfx::IntRect TabWidget::child_rect_for_size(const Gfx::IntSize& size) const void TabWidget::child_event(Core::ChildEvent& event) { - if (!event.child() || !Core::is(*event.child())) + if (!event.child() || !is(*event.child())) return Widget::child_event(event); - auto& child = Core::to(*event.child()); + auto& child = downcast(*event.child()); if (event.type() == Event::ChildAdded) { if (!m_active_widget) set_active_widget(&child); diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp index 5d1a1238875..8142d8b14ba 100644 --- a/Libraries/LibGUI/Widget.cpp +++ b/Libraries/LibGUI/Widget.cpp @@ -109,24 +109,24 @@ Widget::~Widget() void Widget::child_event(Core::ChildEvent& event) { if (event.type() == Event::ChildAdded) { - if (event.child() && Core::is(*event.child()) && layout()) { + if (event.child() && is(*event.child()) && layout()) { if (event.insertion_before_child() && event.insertion_before_child()->is_widget()) - layout()->insert_widget_before(Core::to(*event.child()), Core::to(*event.insertion_before_child())); + layout()->insert_widget_before(downcast(*event.child()), downcast(*event.insertion_before_child())); else - layout()->add_widget(Core::to(*event.child())); + layout()->add_widget(downcast(*event.child())); } - if (window() && event.child() && Core::is(*event.child())) - window()->did_add_widget({}, Core::to(*event.child())); + if (window() && event.child() && is(*event.child())) + window()->did_add_widget({}, downcast(*event.child())); } if (event.type() == Event::ChildRemoved) { if (layout()) { - if (event.child() && Core::is(*event.child())) - layout()->remove_widget(Core::to(*event.child())); + if (event.child() && is(*event.child())) + layout()->remove_widget(downcast(*event.child())); else invalidate_layout(); } - if (window() && event.child() && Core::is(*event.child())) - window()->did_remove_widget({}, Core::to(*event.child())); + if (window() && event.child() && is(*event.child())) + window()->did_remove_widget({}, downcast(*event.child())); update(); } return Core::Object::child_event(event); @@ -470,9 +470,9 @@ Gfx::IntRect Widget::screen_relative_rect() const Widget* Widget::child_at(const Gfx::IntPoint& point) const { for (int i = children().size() - 1; i >= 0; --i) { - if (!Core::is(children()[i])) + if (!is(children()[i])) continue; - auto& child = Core::to(children()[i]); + auto& child = downcast(children()[i]); if (!child.is_visible()) continue; if (child.content_rect().contains(point)) diff --git a/Libraries/LibGUI/Widget.h b/Libraries/LibGUI/Widget.h index 7b8966c5058..2a7937f60f1 100644 --- a/Libraries/LibGUI/Widget.h +++ b/Libraries/LibGUI/Widget.h @@ -40,12 +40,6 @@ extern WidgetClassRegistration registration_##class_name; \ WidgetClassRegistration registration_##class_name(#class_name, []() { return class_name::construct(); }); -template<> -inline bool Core::is(const Core::Object& object) -{ - return object.is_widget(); -} - namespace GUI { enum class SizePolicy { @@ -249,8 +243,8 @@ public: void for_each_child_widget(Callback callback) { for_each_child([&](auto& child) { - if (Core::is(child)) - return callback(Core::to(child)); + if (is(child)) + return callback(downcast(child)); return IterationDecision::Continue; }); } @@ -278,9 +272,9 @@ public: protected: Widget(); - virtual void custom_layout() {} - virtual void did_change_font() {} - virtual void did_layout() {} + virtual void custom_layout() { } + virtual void did_change_font() { } + virtual void did_layout() { } virtual void paint_event(PaintEvent&); virtual void resize_event(ResizeEvent&); virtual void show_event(ShowEvent&); @@ -347,14 +341,18 @@ private: inline Widget* Widget::parent_widget() { - if (parent() && Core::is(*parent())) - return &Core::to(*parent()); + if (parent() && is(*parent())) + return &downcast(*parent()); return nullptr; } inline const Widget* Widget::parent_widget() const { - if (parent() && Core::is(*parent())) - return &Core::to(*parent()); + if (parent() && is(*parent())) + return &downcast(*parent()); return nullptr; } } + +AK_BEGIN_TYPE_TRAITS(GUI::Widget) +static bool is_type(const Core::Object& object) { return object.is_widget(); } +AK_END_TYPE_TRAITS() diff --git a/Libraries/LibGUI/Window.h b/Libraries/LibGUI/Window.h index a13e51b6513..64542e6dbb4 100644 --- a/Libraries/LibGUI/Window.h +++ b/Libraries/LibGUI/Window.h @@ -266,8 +266,6 @@ private: } -template<> -inline bool Core::is(const Core::Object& object) -{ - return object.is_window(); -} +AK_BEGIN_TYPE_TRAITS(GUI::Window) +static bool is_type(const Core::Object& object) { return object.is_window(); } +AK_END_TYPE_TRAITS() diff --git a/Libraries/LibGUI/Window.h.orig b/Libraries/LibGUI/Window.h.orig new file mode 100644 index 00000000000..b6e8688978b --- /dev/null +++ b/Libraries/LibGUI/Window.h.orig @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace GUI { + +enum class StandardCursor { + None = 0, + Arrow, + IBeam, + ResizeHorizontal, + ResizeVertical, + ResizeDiagonalTLBR, + ResizeDiagonalBLTR, + ResizeColumn, + ResizeRow, + Hand, + Help, + Drag, + Move, + Wait, +}; + +class Window : public Core::Object { + C_OBJECT(Window) +public: + virtual ~Window() override; + + static Window* from_window_id(int); + + bool is_modal() const { return m_modal; } + void set_modal(bool); + + bool is_fullscreen() const { return m_fullscreen; } + void set_fullscreen(bool); + + bool is_maximized() const; + + bool is_frameless() const { return m_frameless; } + void set_frameless(bool frameless) { m_frameless = frameless; } + + bool is_resizable() const { return m_resizable; } + void set_resizable(bool resizable) { m_resizable = resizable; } + + bool is_minimizable() const { return m_minimizable; } + void set_minimizable(bool minimizable) { m_minimizable = minimizable; } + + void set_double_buffering_enabled(bool); + void set_has_alpha_channel(bool); + void set_opacity(float); + void set_window_type(WindowType); + + int window_id() const { return m_window_id; } + + String title() const; + void set_title(const StringView&); + + Color background_color() const { return m_background_color; } + void set_background_color(Color color) { m_background_color = color; } + + enum class CloseRequestDecision { + StayOpen, + Close, + }; + + Function on_close_request; + Function on_active_input_change; + Function on_activity_change; + + int x() const { return rect().x(); } + int y() const { return rect().y(); } + int width() const { return rect().width(); } + int height() const { return rect().height(); } + + Gfx::IntRect rect() const; + Gfx::IntSize size() const { return rect().size(); } + void set_rect(const Gfx::IntRect&); + void set_rect(int x, int y, int width, int height) { set_rect({ x, y, width, height }); } + + Gfx::IntPoint position() const { return rect().location(); } + + void move_to(int x, int y) { move_to({ x, y }); } + void move_to(const Gfx::IntPoint& point) { set_rect({ point, size() }); } + + void resize(int width, int height) { resize({ width, height }); } + void resize(const Gfx::IntSize& size) { set_rect({ position(), size }); } + + virtual void event(Core::Event&) override; + + bool is_visible() const; + bool is_active() const { return m_is_active; } + bool is_active_input() const { return m_is_active_input; } + + bool is_accessory() const { return m_accessory; } + void set_accessory(bool accessory) { m_accessory = accessory; } + + void show(); + void hide(); + virtual void close(); + void move_to_front(); + + void start_wm_resize(); + + Widget* main_widget() { return m_main_widget; } + const Widget* main_widget() const { return m_main_widget; } + void set_main_widget(Widget*); + + template + inline T& set_main_widget(Args&&... args) + { + auto widget = T::construct(forward(args)...); + set_main_widget(widget.ptr()); + return *widget; + } + + Widget* focused_widget() { return m_focused_widget; } + const Widget* focused_widget() const { return m_focused_widget; } + void set_focused_widget(Widget*); + + void update(); + void update(const Gfx::IntRect&); + + void set_global_cursor_tracking_widget(Widget*); + Widget* global_cursor_tracking_widget() { return m_global_cursor_tracking_widget.ptr(); } + const Widget* global_cursor_tracking_widget() const { return m_global_cursor_tracking_widget.ptr(); } + + void set_automatic_cursor_tracking_widget(Widget*); + Widget* automatic_cursor_tracking_widget() { return m_automatic_cursor_tracking_widget.ptr(); } + const Widget* automatic_cursor_tracking_widget() const { return m_automatic_cursor_tracking_widget.ptr(); } + + Widget* hovered_widget() { return m_hovered_widget.ptr(); } + const Widget* hovered_widget() const { return m_hovered_widget.ptr(); } + void set_hovered_widget(Widget*); + + Gfx::Bitmap* front_bitmap() { return m_front_bitmap.ptr(); } + Gfx::Bitmap* back_bitmap() { return m_back_bitmap.ptr(); } + + Gfx::IntSize size_increment() const { return m_size_increment; } + void set_size_increment(const Gfx::IntSize&); + Gfx::IntSize base_size() const { return m_base_size; } + void set_base_size(const Gfx::IntSize&); + + void set_override_cursor(StandardCursor); + void set_override_cursor(const Gfx::Bitmap&); + + void set_icon(const Gfx::Bitmap*); + void apply_icon(); + const Gfx::Bitmap* icon() const { return m_icon.ptr(); } + + Vector focusable_widgets() const; + + virtual void save_to(AK::JsonObject&) override; + + void schedule_relayout(); + + static void for_each_window(Badge, Function); + static void update_all_windows(Badge); + void notify_state_changed(Badge, bool minimized, bool occluded); + + virtual bool is_visible_for_timer_purposes() const override { return m_visible_for_timer_purposes; } + + Action* action_for_key_event(const KeyEvent&); + + void did_add_widget(Badge, Widget&); + void did_remove_widget(Badge, Widget&); + + Window* find_parent_window(); + + void set_progress(int); + +protected: + Window(Core::Object* parent = nullptr); + virtual void wm_event(WMEvent&); + +private: + virtual bool is_window() const override final { return true; } + + void handle_drop_event(DropEvent&); + void handle_mouse_event(MouseEvent&); + void handle_multi_paint_event(MultiPaintEvent&); + void handle_key_event(KeyEvent&); + void handle_resize_event(ResizeEvent&); + void handle_input_entered_or_left_event(Core::Event&); + void handle_became_active_or_inactive_event(Core::Event&); + void handle_close_request(); + void handle_theme_change_event(ThemeChangeEvent&); + void handle_drag_move_event(DragEvent&); + void handle_left_event(); + + void server_did_destroy(); + + RefPtr create_backing_bitmap(const Gfx::IntSize&); + RefPtr create_shared_bitmap(Gfx::BitmapFormat, const Gfx::IntSize&); + void set_current_backing_bitmap(Gfx::Bitmap&, bool flush_immediately = false); + void flip(const Vector& dirty_rects); + void force_update(); + + RefPtr m_front_bitmap; + RefPtr m_back_bitmap; + RefPtr m_icon; + RefPtr m_custom_cursor; + int m_window_id { 0 }; + float m_opacity_when_windowless { 1.0f }; + RefPtr m_main_widget; + WeakPtr m_focused_widget; + WeakPtr m_global_cursor_tracking_widget; + WeakPtr m_automatic_cursor_tracking_widget; + WeakPtr m_hovered_widget; + Gfx::IntRect m_rect_when_windowless; + String m_title_when_windowless; + Vector m_pending_paint_event_rects; + Gfx::IntSize m_size_increment; + Gfx::IntSize m_base_size; + Color m_background_color { Color::WarmGray }; + WindowType m_window_type { WindowType::Normal }; + StandardCursor m_override_cursor { StandardCursor::None }; + bool m_is_active { false }; + bool m_is_active_input { false }; + bool m_has_alpha_channel { false }; + bool m_double_buffering_enabled { true }; + bool m_modal { false }; + bool m_resizable { true }; + bool m_minimizable { true }; + bool m_fullscreen { false }; + bool m_frameless { false }; + bool m_layout_pending { false }; + bool m_visible_for_timer_purposes { true }; + bool m_visible { false }; + bool m_accessory { false }; +}; + +} + +template<> +inline bool Core::is(const Core::Object& object) +{ + return object.is_window(); +}