Skip to content

Commit 8c5c82f

Browse files
committed
cleanup cursor render function too
1 parent 599b73e commit 8c5c82f

1 file changed

Lines changed: 115 additions & 55 deletions

File tree

library/SDLConsole_impl.cpp

Lines changed: 115 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,6 +1605,68 @@ class Widget : public SignalEmitter {
16051605
Widget& operator=(const Widget&) = delete;
16061606
};
16071607

1608+
class Cursor {
1609+
private:
1610+
// 1x1 texture stretched to font's single character dimensions
1611+
SDL_Texture* texture_;
1612+
SDL_Renderer* renderer_;
1613+
size_t position_ { 0 };
1614+
SDL_Rect rect_ {};
1615+
public:
1616+
Cursor(SDL_Renderer* renderer) : renderer_(renderer)
1617+
{
1618+
texture_ = sdl_tsd.CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, 1, 1);
1619+
if (texture_ == nullptr) {
1620+
throw(std::runtime_error(sdl_console::SDL_GetError()));
1621+
}
1622+
1623+
// FFFFFF = rgb white, 7F = 50% transparant
1624+
Uint32 pixel = 0xFFFFFF7F;
1625+
if (sdl_console::SDL_UpdateTexture(texture_, NULL, &pixel, sizeof(Uint32)) != 0) {
1626+
throw(std::runtime_error(sdl_console::SDL_GetError()));
1627+
}
1628+
// For transparancy
1629+
sdl_console::SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
1630+
}
1631+
1632+
size_t position() const
1633+
{
1634+
return position_;
1635+
}
1636+
1637+
void reset_position()
1638+
{
1639+
position_ = 0;
1640+
}
1641+
1642+
void set_rect(const SDL_Rect& r)
1643+
{
1644+
rect_ = r;
1645+
}
1646+
1647+
void render() const
1648+
{
1649+
render_texture(renderer_, texture_, rect_);
1650+
}
1651+
1652+
Cursor& operator=(size_t position) {
1653+
position_ = position;
1654+
return *this;
1655+
}
1656+
1657+
Cursor& operator++() { ++position_; return *this; }
1658+
Cursor& operator--() { if (position_ > 0) { --position_; } return *this; }
1659+
1660+
Cursor& operator+=(std::size_t n) { position_ += n; return *this; }
1661+
Cursor& operator-=(std::size_t n) { position_ = (n > position_) ? 0 : position_ - n; return *this; }
1662+
1663+
Cursor(const Cursor&) = delete;
1664+
Cursor& operator=(const Cursor&) = delete;
1665+
Cursor(Cursor&&) = delete;
1666+
Cursor& operator=(Cursor&&) = delete;
1667+
1668+
};
1669+
16081670
class Prompt : public Widget {
16091671
public:
16101672
// Holds wrapped lines from input
@@ -1614,9 +1676,7 @@ class Prompt : public Widget {
16141676
// The input portion of the prompt.
16151677
std::u32string* input;
16161678
std::u32string saved_input;
1617-
size_t cursor { 0 }; // position of cursor within an entry
1618-
// 1x1 texture stretched to font's single character dimensions
1619-
SDL_Texture* cursor_texture;
1679+
Cursor cursor;
16201680
/*
16211681
* For input history.
16221682
* use deque to hold a stable reference.
@@ -1625,14 +1685,12 @@ class Prompt : public Widget {
16251685
int history_index;
16261686

16271687
Prompt(Widget* parent)
1628-
: Widget(parent)
1688+
: Widget(parent), cursor(renderer())
16291689
{
16301690
input = &history.emplace_back(U"");
16311691

16321692
set_prompt_text(props().get(property::PROMPT_TEXT).value_or(U"> "));
16331693

1634-
create_cursor_texture();
1635-
16361694
connect_global<SDL_KeyboardEvent>(SDL_KEYDOWN, [this](SDL_KeyboardEvent& e) {
16371695
on_SDL_KEYDOWN(e);
16381696
});
@@ -1647,22 +1705,6 @@ class Prompt : public Widget {
16471705
//sdl_tsd.DestroyTexture(cursor_texture);
16481706
}
16491707

1650-
// NOTE: Only called by constructor.
1651-
void create_cursor_texture()
1652-
{
1653-
cursor_texture = sdl_tsd.CreateTexture(renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, 1, 1);
1654-
if (cursor_texture == nullptr)
1655-
throw(std::runtime_error(sdl_console::SDL_GetError()));
1656-
1657-
// FFFFFF = rgb white, 7F = 50% transparant
1658-
Uint32 pixel = 0xFFFFFF7F;
1659-
if (sdl_console::SDL_UpdateTexture(cursor_texture, NULL, &pixel, sizeof(Uint32)) != 0) {
1660-
throw(std::runtime_error(sdl_console::SDL_GetError()));
1661-
}
1662-
// For transparancy
1663-
sdl_console::SDL_SetTextureBlendMode(cursor_texture, SDL_BLENDMODE_BLEND);
1664-
}
1665-
16661708
/* OutputPane does this */
16671709
void render() override
16681710
{
@@ -1671,8 +1713,9 @@ class Prompt : public Widget {
16711713
void put_input_from_clipboard()
16721714
{
16731715
auto* str = sdl_console::SDL_GetClipboardText();
1674-
if (*str != '\0')
1716+
if (*str != '\0') {
16751717
put_input_at_cursor(text::from_utf8(str));
1718+
}
16761719
// Always free, even when empty.
16771720
sdl_console::SDL_free(str);
16781721
}
@@ -1715,13 +1758,13 @@ class Prompt : public Widget {
17151758

17161759
case SDLK_b:
17171760
if (sdl_console::SDL_GetModState() & KMOD_CTRL) {
1718-
cursor = text::find_prev_word(*input, cursor);
1761+
cursor = text::find_prev_word(*input, cursor.position());
17191762
}
17201763
break;
17211764

17221765
case SDLK_f:
17231766
if (sdl_console::SDL_GetModState() & KMOD_CTRL) {
1724-
cursor = text::find_next_word(*input, cursor);
1767+
cursor = text::find_next_word(*input, cursor.position());
17251768
}
17261769
break;
17271770
case SDLK_c:
@@ -1742,19 +1785,20 @@ class Prompt : public Widget {
17421785
std::swap(history, saved_history);
17431786
input = &history.emplace_back(U"");
17441787
history_index = history.size() - 1;
1745-
reset_cursor();
1788+
cursor.reset_position();
17461789
}
17471790

17481791
void new_command_input()
17491792
{
17501793
emit(InternalEventType::new_command_input, input);
17511794

17521795
// If empty, log an empty line? But don't add it to history.
1753-
if (input->empty()) return;
1796+
if (input->empty()) { return; }
17541797

17551798
input = &history.emplace_back(U"");
17561799
history_index = history.size() - 1;
1757-
reset_cursor();
1800+
//reset_cursor();
1801+
cursor.reset_position();
17581802
wrap_text();
17591803
}
17601804

@@ -1763,7 +1807,7 @@ class Prompt : public Widget {
17631807
saved_input = *input;
17641808
emit(InternalEventType::new_input, input);
17651809
input->clear();
1766-
reset_cursor();
1810+
cursor.reset_position();
17671811
wrap_text();
17681812
}
17691813

@@ -1774,11 +1818,6 @@ class Prompt : public Widget {
17741818
wrap_text();
17751819
}
17761820

1777-
void reset_cursor()
1778-
{
1779-
cursor = 0;
1780-
}
1781-
17821821
void set_prompt_text(const std::u32string& value)
17831822
{
17841823
prompt_text = value;
@@ -1793,7 +1832,7 @@ class Prompt : public Widget {
17931832
*/
17941833
void set_input_from_history(const ScrollAction sa)
17951834
{
1796-
if (history.empty()) return;
1835+
if (history.empty()) { return; }
17971836

17981837
if (sa == ScrollAction::up && history_index > 0) {
17991838
history_index--;
@@ -1810,6 +1849,7 @@ class Prompt : public Widget {
18101849

18111850
void put_input_at_cursor(const std::u32string& str)
18121851
{
1852+
#if 0
18131853
/* if cursor is at end of line, it's a simple concatenation */
18141854
if (cursor == input->length()) {
18151855
*input += str;
@@ -1818,6 +1858,16 @@ class Prompt : public Widget {
18181858
input->insert(cursor, str);
18191859
}
18201860
cursor += str.length();
1861+
#endif
1862+
/* if cursor is at end of line, it's a simple concatenation */
1863+
if (cursor.position() == input->length()) {
1864+
*input += str;
1865+
} else {
1866+
/* else insert text into line at cursor's index */
1867+
input->insert(cursor.position(), str);
1868+
}
1869+
cursor += str.length();
1870+
18211871
wrap_text();
18221872
}
18231873

@@ -1830,30 +1880,31 @@ class Prompt : public Widget {
18301880

18311881
void erase_input()
18321882
{
1833-
if (cursor == 0 || input->empty())
1883+
if (cursor.position() == 0 || input->empty()) {
18341884
return;
1885+
}
18351886

1836-
if (input->length() == cursor) {
1887+
if (input->length() == cursor.position()) {
18371888
input->pop_back();
18381889
} else {
18391890
/* else shift the text from cursor left by one character */
1840-
input->erase(cursor-1, 1);
1891+
input->erase(cursor.position()-1, 1);
18411892
}
1842-
cursor -= 1;
1893+
--cursor;
18431894
wrap_text();
18441895
}
18451896

18461897
void move_cursor_left()
18471898
{
1848-
if (cursor > 0) {
1849-
cursor--;
1899+
if (cursor.position() > 0) {
1900+
--cursor;
18501901
}
18511902
}
18521903

18531904
void move_cursor_right()
18541905
{
1855-
if (cursor < input->length()) {
1856-
cursor++;
1906+
if (cursor.position() < input->length()) {
1907+
++cursor;
18571908
}
18581909
}
18591910

@@ -1867,51 +1918,61 @@ class Prompt : public Widget {
18671918
{
18681919
entry.text = prompt_text + *input;
18691920
entry.wrap_text(font->char_width, frame.w);
1921+
update_cursor_geometry_for_render();
18701922
}
18711923

1872-
// TODO: The cursor x,y position should be updated
1873-
// elsewhere, such as when the cursor position changes.
1874-
// instead of within its rendering function.
1875-
void render_cursor(int scroll_offset)
1924+
void update_cursor_geometry_for_render()
18761925
{
1877-
if (entry.fragments().empty())
1926+
if (entry.fragments().empty()) {
18781927
return;
1928+
}
18791929

18801930
// cursor's starting position
1881-
auto cursor_pos = cursor + prompt_text.length();
1931+
auto cursor_pos = cursor.position() + prompt_text.length();
18821932
TextEntry::Fragment *line;
18831933

18841934
// cursor is at the end
18851935
if (cursor_pos == entry.text.length()) {
1936+
#if 0
18861937
if (scroll_offset > 0) {
18871938
// cursor is not visible.
18881939
return;
18891940
}
1941+
#endif
18901942
line = &entry.fragments().back();
1891-
// else find the line containing the cursor
1943+
// else find the line containing the cursor
18921944
} else {
18931945
auto line_opt = entry.fragment_from_offset(cursor_pos);
1894-
if (!line_opt.has_value())
1946+
if (!line_opt.has_value()) {
18951947
return; // should not happen
1948+
}
18961949

18971950
line = &line_opt.value().get();
1951+
1952+
#if 0
18981953
// the very bottom of the prompt is the last entry
18991954
// entry_offset = entry.size-1 at bottom
19001955
int r = (entry.size - 1) - line->entry_offset;
1956+
19011957
// scroll_offset starts at 0.
19021958
if (scroll_offset > r) {
19031959
// cursor is not visible.
19041960
return;
19051961
}
1962+
#endif
19061963
}
19071964

19081965
auto lh = font->line_height_with_spacing();
19091966
auto cw = font->char_width;
19101967
auto cx = (cursor_pos - line->start_offset) * cw;
19111968
auto cy = line->coord.y;
19121969

1913-
SDL_Rect rect{ (int)cx, cy, cw, lh };
1914-
render_texture(renderer(), cursor_texture, rect);
1970+
cursor.set_rect({ (int)cx, cy, cw, lh });
1971+
}
1972+
1973+
void render_cursor(int scroll_offset)
1974+
{
1975+
cursor.render();
19151976
}
19161977

19171978
Prompt(const Prompt&) = delete;
@@ -2785,7 +2846,6 @@ class OutputPane : public Widget {
27852846
}
27862847
}
27872848

2788-
// FIXME: Position and rows to render calculations should be done elsewhere.
27892849
std::vector<VisibleRow> get_visible_entry_rows(TextEntry& entry, int& ypos, int& row_counter, int max_row)
27902850
{
27912851
std::vector<VisibleRow> vrows;
@@ -2819,7 +2879,7 @@ class OutputPane : public Widget {
28192879
}
28202880

28212881
for (const auto& row : visible_rows_cache.rows) {
2822-
font->set_color(row.color);
2882+
auto sc = font->set_color(row.color);
28232883
font->render(row.text, row.coord.x, row.coord.y);
28242884
}
28252885
}

0 commit comments

Comments
 (0)