mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-05 18:40:37 +00:00
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:
parent
0bf9353a02
commit
ae1d9ca9b1
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user