mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 23:18:10 +00:00
LibWeb: Add a blinking text cursor :^)
Each Web::Frame now has a cursor that sits at a DOM::Position. It will blink and look like a nice regular text cursor. It doesn't really do anything yet, but it will eventually.
This commit is contained in:
parent
e496a74bb3
commit
2c679d0c8b
5 changed files with 66 additions and 0 deletions
|
@ -32,6 +32,7 @@
|
||||||
#include <LibWeb/DOM/Document.h>
|
#include <LibWeb/DOM/Document.h>
|
||||||
#include <LibWeb/Layout/LayoutBlock.h>
|
#include <LibWeb/Layout/LayoutBlock.h>
|
||||||
#include <LibWeb/Layout/LayoutText.h>
|
#include <LibWeb/Layout/LayoutText.h>
|
||||||
|
#include <LibWeb/Page/Frame.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
namespace Web {
|
namespace Web {
|
||||||
|
@ -101,6 +102,28 @@ void LayoutText::paint_fragment(PaintContext& context, const LineBoxFragment& fr
|
||||||
painter.add_clip_rect(enclosing_int_rect(selection_rect));
|
painter.add_clip_rect(enclosing_int_rect(selection_rect));
|
||||||
painter.draw_text(enclosing_int_rect(fragment.absolute_rect()), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::TopLeft, context.palette().selection_text());
|
painter.draw_text(enclosing_int_rect(fragment.absolute_rect()), text.substring_view(fragment.start(), fragment.length()), Gfx::TextAlignment::TopLeft, context.palette().selection_text());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paint_cursor_if_needed(context, fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutText::paint_cursor_if_needed(PaintContext& context, const LineBoxFragment& fragment) const
|
||||||
|
{
|
||||||
|
if (!frame().cursor_blink_state())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (frame().cursor_position().node() != &node())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!(frame().cursor_position().offset() >= (unsigned)fragment.start() && frame().cursor_position().offset() < (unsigned)(fragment.start() + fragment.length())))
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto fragment_rect = fragment.absolute_rect();
|
||||||
|
|
||||||
|
float cursor_x = fragment_rect.x() + specified_style().font().width(fragment.text().substring_view(0, frame().cursor_position().offset() - fragment.start()));
|
||||||
|
float cursor_top = fragment_rect.top();
|
||||||
|
float cursor_height = fragment_rect.height();
|
||||||
|
Gfx::IntRect cursor_rect(cursor_x, cursor_top, 1, cursor_height);
|
||||||
|
context.painter().draw_rect(cursor_rect, context.palette().text_cursor());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void split_into_lines_by_rules(LayoutBlock& container, LayoutMode, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks);
|
void split_into_lines_by_rules(LayoutBlock& container, LayoutMode, bool do_collapse, bool do_wrap_lines, bool do_wrap_breaks);
|
||||||
|
void paint_cursor_if_needed(PaintContext&, const LineBoxFragment&) const;
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_chunk(Callback, LayoutMode, bool do_wrap_lines, bool do_wrap_breaks) const;
|
void for_each_chunk(Callback, LayoutMode, bool do_wrap_lines, bool do_wrap_breaks) const;
|
||||||
|
|
|
@ -150,6 +150,7 @@ bool EventHandler::handle_mousedown(const Gfx::IntPoint& position, unsigned butt
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (button == GUI::MouseButton::Left) {
|
if (button == GUI::MouseButton::Left) {
|
||||||
|
m_frame.set_cursor_position(DOM::Position(*node, result.index_in_node));
|
||||||
layout_root()->selection().set({ result.layout_node, result.index_in_node }, {});
|
layout_root()->selection().set({ result.layout_node, result.index_in_node }, {});
|
||||||
dump_selection("MouseDown");
|
dump_selection("MouseDown");
|
||||||
m_in_mouse_selection = true;
|
m_in_mouse_selection = true;
|
||||||
|
|
|
@ -40,6 +40,7 @@ Frame::Frame(DOM::Element& host_element, Frame& main_frame)
|
||||||
, m_event_handler({}, *this)
|
, m_event_handler({}, *this)
|
||||||
, m_host_element(host_element.make_weak_ptr())
|
, m_host_element(host_element.make_weak_ptr())
|
||||||
{
|
{
|
||||||
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame::Frame(Page& page)
|
Frame::Frame(Page& page)
|
||||||
|
@ -48,12 +49,23 @@ Frame::Frame(Page& page)
|
||||||
, m_loader(*this)
|
, m_loader(*this)
|
||||||
, m_event_handler({}, *this)
|
, m_event_handler({}, *this)
|
||||||
{
|
{
|
||||||
|
setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame::~Frame()
|
Frame::~Frame()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Frame::setup()
|
||||||
|
{
|
||||||
|
m_cursor_blink_timer = Core::Timer::construct(500, [this] {
|
||||||
|
if (m_cursor_position.node() && m_cursor_position.node()->layout_node()) {
|
||||||
|
m_cursor_blink_state = !m_cursor_blink_state;
|
||||||
|
m_cursor_position.node()->layout_node()->set_needs_display();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void Frame::set_document(DOM::Document* document)
|
void Frame::set_document(DOM::Document* document)
|
||||||
{
|
{
|
||||||
if (m_document == document)
|
if (m_document == document)
|
||||||
|
@ -168,4 +180,20 @@ Gfx::IntPoint Frame::to_main_frame_position(const Gfx::IntPoint& a_position)
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Frame::set_cursor_position(const DOM::Position & position)
|
||||||
|
{
|
||||||
|
if (m_cursor_position == position)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_cursor_position.node() && m_cursor_position.node()->layout_node())
|
||||||
|
m_cursor_position.node()->layout_node()->set_needs_display();
|
||||||
|
|
||||||
|
m_cursor_position = position;
|
||||||
|
|
||||||
|
if (m_cursor_position.node() && m_cursor_position.node()->layout_node())
|
||||||
|
m_cursor_position.node()->layout_node()->set_needs_display();
|
||||||
|
|
||||||
|
dbg() << "Cursor position: " << m_cursor_position;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,11 @@
|
||||||
#include <AK/Noncopyable.h>
|
#include <AK/Noncopyable.h>
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
#include <AK/WeakPtr.h>
|
#include <AK/WeakPtr.h>
|
||||||
|
#include <LibCore/Timer.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibGfx/Size.h>
|
#include <LibGfx/Size.h>
|
||||||
|
#include <LibWeb/DOM/Position.h>
|
||||||
#include <LibWeb/Loader/FrameLoader.h>
|
#include <LibWeb/Loader/FrameLoader.h>
|
||||||
#include <LibWeb/Page/EventHandler.h>
|
#include <LibWeb/Page/EventHandler.h>
|
||||||
#include <LibWeb/TreeNode.h>
|
#include <LibWeb/TreeNode.h>
|
||||||
|
@ -83,10 +85,17 @@ public:
|
||||||
Gfx::IntPoint to_main_frame_position(const Gfx::IntPoint&);
|
Gfx::IntPoint to_main_frame_position(const Gfx::IntPoint&);
|
||||||
Gfx::IntRect to_main_frame_rect(const Gfx::IntRect&);
|
Gfx::IntRect to_main_frame_rect(const Gfx::IntRect&);
|
||||||
|
|
||||||
|
const DOM::Position& cursor_position() const { return m_cursor_position; }
|
||||||
|
void set_cursor_position(const DOM::Position&);
|
||||||
|
|
||||||
|
bool cursor_blink_state() const { return m_cursor_blink_state; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Frame(DOM::Element& host_element, Frame& main_frame);
|
explicit Frame(DOM::Element& host_element, Frame& main_frame);
|
||||||
explicit Frame(Page&);
|
explicit Frame(Page&);
|
||||||
|
|
||||||
|
void setup();
|
||||||
|
|
||||||
Page& m_page;
|
Page& m_page;
|
||||||
Frame& m_main_frame;
|
Frame& m_main_frame;
|
||||||
|
|
||||||
|
@ -97,6 +106,10 @@ private:
|
||||||
RefPtr<DOM::Document> m_document;
|
RefPtr<DOM::Document> m_document;
|
||||||
Gfx::IntSize m_size;
|
Gfx::IntSize m_size;
|
||||||
Gfx::IntRect m_viewport_rect;
|
Gfx::IntRect m_viewport_rect;
|
||||||
|
|
||||||
|
DOM::Position m_cursor_position;
|
||||||
|
RefPtr<Core::Timer> m_cursor_blink_timer;
|
||||||
|
bool m_cursor_blink_state { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue