Render text/highlight selected text on the canvas

Now we don't render the default ui::Entry edges, but we paint just a
border of the text bounds + the rendered text highlighting selected
text on the canvas itself.

With this change click mouse positions are translated with a scale
factor that changes depending on the app::Editor zoom.
This commit is contained in:
David Capello 2024-06-19 16:41:28 -03:00
parent a487bcec7d
commit 5591a59001
4 changed files with 118 additions and 24 deletions

View File

@ -35,6 +35,12 @@
#include "ui/message.h"
#include "ui/paint_event.h"
#ifdef LAF_SKIA
#include "app/util/shader_helpers.h"
#include "os/skia/skia_helpers.h"
#include "os/skia/skia_surface.h"
#endif
namespace app {
using namespace ui;
@ -82,7 +88,13 @@ public:
m_doc->generateMaskBoundaries();
}
ExtraCelRef extraCel() const { return m_extraCel; }
// Returns the extra cel with the text rendered (but without the
// selected text highlighted).
ExtraCelRef extraCel() {
renderExtraCelBase();
renderExtraCelText(false);
return m_extraCel;
}
private:
bool onProcessMessage(Message* msg) override {
@ -112,36 +124,48 @@ private:
}
void onPaint(PaintEvent& ev) override {
Entry::onPaint(ev);
Graphics* g = ev.graphics();
// Don't paint the base Entry borders
//Entry::onPaint(ev);
if (!hasText())
return;
// Paint border
{
ui::Paint paint;
paint.style(ui::Paint::Stroke);
set_checkered_paint_mode(paint, 0,
gfx::rgba(0, 0, 0, 255),
gfx::rgba(255, 255, 255, 255));
g->drawRect(clientBounds(), paint);
}
try {
text::TextBlobRef blob = textBlob();
if (!blob) {
if (!textBlob()) {
m_doc->setExtraCel(nullptr);
m_editor->invalidate();
return;
}
const auto textColor =
color_utils::color_for_image(
Preferences::instance().colorBar.fgColor(),
IMAGE_RGB);
// Render extra cel with text + selected text
renderExtraCelBase();
renderExtraCelText(true);
m_doc->setExtraCel(m_extraCel);
doc::ImageRef image = render_text_blob(blob, textColor);
if (image) {
renderExtraCelBase();
// Paint caret
if (isCaretVisible()) {
int scroll, caret;
getEntryThemeInfo(&scroll, &caret, nullptr, nullptr);
doc::blend_image(
m_extraCel->image(), image.get(),
gfx::Clip(image->bounds().size()),
m_doc->sprite()->palette(m_editor->frame()),
255, doc::BlendMode::NORMAL);
m_doc->setExtraCel(m_extraCel);
m_editor->invalidate();
gfx::RectF caretBounds = getCharBoxBounds(caret);
caretBounds *= gfx::SizeF(scale());
caretBounds.w = 1;
g->fillRect(gfx::rgba(0, 0, 0), caretBounds);
}
m_editor->invalidate();
}
catch (const std::exception& e) {
StatusBar::instance()->showTip(500, std::string(e.what()));
@ -159,6 +183,50 @@ private:
doc::BlendMode::SRC);
}
void renderExtraCelText(const bool withSelection) {
const auto textColor =
color_utils::color_for_image(
Preferences::instance().colorBar.fgColor(),
IMAGE_RGB);
text::TextBlobRef blob = textBlob();
if (!blob)
return;
doc::ImageRef image = render_text_blob(blob, textColor);
if (!image)
return;
// Invert selected range in the image
if (withSelection) {
Range range;
getEntryThemeInfo(nullptr, nullptr, nullptr, &range);
if (!range.isEmpty()) {
gfx::RectF selectedBounds =
getCharBoxBounds(range.from) |
getCharBoxBounds(range.to-1);
if (!selectedBounds.isEmpty()) {
#ifdef LAF_SKIA
sk_sp<SkSurface> skSurface = wrap_docimage_in_sksurface(image.get());
os::SurfaceRef surface = base::make_ref<os::SkiaSurface>(skSurface);
os::Paint paint;
paint.blendMode(os::BlendMode::Xor);
paint.color(textColor);
surface->drawRect(selectedBounds, paint);
#endif // LAF_SKIA
}
}
}
doc::blend_image(
m_extraCel->image(), image.get(),
gfx::Clip(image->bounds().size()),
m_doc->sprite()->palette(m_editor->frame()),
255, doc::BlendMode::NORMAL);
}
Editor* m_editor;
Doc* m_doc;
ExtraCelRef m_extraCel;
@ -178,7 +246,7 @@ WritingTextState::WritingTextState(Editor* editor,
App::instance()->contextBar()->FontChange.connect(
&WritingTextState::onFontChange, this);
m_entry->setBounds(calcEntryBounds());
onEditorResize(editor);
}
WritingTextState::~WritingTextState()
@ -232,8 +300,11 @@ bool WritingTextState::onKeyUp(Editor*, KeyMessage* msg)
return true;
}
void WritingTextState::onEditorResize(Editor*)
void WritingTextState::onEditorResize(Editor* editor)
{
const gfx::PointF scale(editor->projection().scaleX(),
editor->projection().scaleY());
m_entry->setScale(scale);
m_entry->setBounds(calcEntryBounds());
}

View File

@ -25,6 +25,7 @@
#ifdef LAF_SKIA
#include "app/util/shader_helpers.h"
#include "os/skia/skia_helpers.h"
#include "os/skia/skia_surface.h"
#endif

View File

@ -52,6 +52,7 @@ Entry::Entry(const int maxsize, const char* format, ...)
, m_recent_focused(false)
, m_lock_selection(false)
, m_translate_dead_keys(true)
, m_scale(1.0f, 1.0f)
{
enableFlags(CTRL_RIGHT_CLICK);
@ -235,6 +236,16 @@ gfx::Rect Entry::getEntryTextBounds() const
return onGetEntryTextBounds();
}
gfx::Rect Entry::getCharBoxBounds(const int charBoxIndex)
{
int i = 0;
int x = 0;
for (; i<charBoxIndex; ++i) {
x += m_boxes[i].width;
}
return gfx::Rect(x, 0, m_boxes[i].width, textHeight());
}
bool Entry::onProcessMessage(Message* msg)
{
switch (msg->type()) {
@ -551,9 +562,9 @@ gfx::Rect Entry::onGetEntryTextBounds() const
return bounds;
}
int Entry::getCaretFromMouse(MouseMessage* mousemsg)
int Entry::getCaretFromMouse(MouseMessage* mouseMsg)
{
int mouseX = mousemsg->position().x;
const int mouseX = mouseMsg->position().x;
if (mouseX < bounds().x+border().left()) {
// Scroll to the left
return std::max(0, m_scroll-1);
@ -569,7 +580,8 @@ int Entry::getCaretFromMouse(MouseMessage* mousemsg)
indexBox = j+1;
}
int x = bounds().x + border().left() + segmentWidth + m_boxes[indexBox].width / 2;
const int x = bounds().x + border().left()
+ (segmentWidth + m_boxes[indexBox].width / 2) * m_scale.x;
if (mouseX > bounds().x2() - border().right()) {
if (x >= bounds().x2() - border().right()) {

View File

@ -63,6 +63,9 @@ namespace ui {
void getEntryThemeInfo(int* scroll, int* caret, int* state, Range* range) const;
gfx::Rect getEntryTextBounds() const;
gfx::PointF scale() const { return m_scale; }
void setScale(const gfx::PointF& scale) { m_scale = scale; }
static gfx::Size sizeHintWithText(Entry* entry,
const std::string& text);
@ -70,6 +73,8 @@ namespace ui {
obs::signal<void()> Change;
protected:
gfx::Rect getCharBoxBounds(int charBoxIndex);
// Events
bool onProcessMessage(Message* msg) override;
void onSizeHint(SizeHintEvent& ev) override;
@ -137,6 +142,11 @@ namespace ui {
bool m_translate_dead_keys : 1;
Range m_selecting_words;
std::unique_ptr<std::string> m_suffix;
// Scale (1.0 by default) applied to each axis. Can be used in
// case you are going to display/paint the text scaled and want to
// convert the mouse position correctly.
gfx::PointF m_scale;
};
} // namespace ui