mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 06:47:35 +00:00
LibVT: Create VT::Range and use it to replace selection start / end
Based on GUI::TextRange, This is both a bit more expressive and will eventually be used for searching within the terminal
This commit is contained in:
parent
6efdabfc6f
commit
6446135681
3 changed files with 120 additions and 36 deletions
87
Libraries/LibVT/Range.h
Normal file
87
Libraries/LibVT/Range.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2020, the SerenityOS developers.
|
||||
* 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 <LibVT/Position.h>
|
||||
|
||||
namespace VT {
|
||||
|
||||
class Range {
|
||||
public:
|
||||
Range() { }
|
||||
Range(const VT::Position& start, const VT::Position& end)
|
||||
: m_start(start)
|
||||
, m_end(end)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_valid() const { return m_start.is_valid() && m_end.is_valid(); }
|
||||
void clear()
|
||||
{
|
||||
m_start = {};
|
||||
m_end = {};
|
||||
}
|
||||
|
||||
VT::Position& start() { return m_start; }
|
||||
VT::Position& end() { return m_end; }
|
||||
const VT::Position& start() const { return m_start; }
|
||||
const VT::Position& end() const { return m_end; }
|
||||
|
||||
Range normalized() const { return Range(normalized_start(), normalized_end()); }
|
||||
|
||||
void set_start(const VT::Position& position) { m_start = position; }
|
||||
void set_end(const VT::Position& position) { m_end = position; }
|
||||
|
||||
void set(const VT::Position& start, const VT::Position& end)
|
||||
{
|
||||
m_start = start;
|
||||
m_end = end;
|
||||
}
|
||||
|
||||
bool operator==(const Range& other) const
|
||||
{
|
||||
return m_start == other.m_start && m_end == other.m_end;
|
||||
}
|
||||
|
||||
bool contains(const VT::Position& position) const
|
||||
{
|
||||
if (!(position.row() > m_start.row() || (position.row() == m_start.row() && position.column() >= m_start.column())))
|
||||
return false;
|
||||
if (!(position.row() < m_end.row() || (position.row() == m_end.row() && position.column() <= m_end.column())))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
VT::Position normalized_start() const { return m_start < m_end ? m_start : m_end; }
|
||||
VT::Position normalized_end() const { return m_start < m_end ? m_end : m_start; }
|
||||
|
||||
VT::Position m_start;
|
||||
VT::Position m_end;
|
||||
};
|
||||
|
||||
};
|
|
@ -255,11 +255,11 @@ void TerminalWidget::keydown_event(GUI::KeyEvent& event)
|
|||
|
||||
// Clear the selection if we type in/behind it.
|
||||
auto future_cursor_column = (event.key() == KeyCode::Key_Backspace) ? m_terminal.cursor_column() - 1 : m_terminal.cursor_column();
|
||||
auto min_selection_row = min(m_selection_start.row(), m_selection_end.row());
|
||||
auto max_selection_row = max(m_selection_start.row(), m_selection_end.row());
|
||||
auto min_selection_row = min(m_selection.start().row(), m_selection.end().row());
|
||||
auto max_selection_row = max(m_selection.start().row(), m_selection.end().row());
|
||||
|
||||
if (future_cursor_column <= last_selection_column_on_row(m_terminal.cursor_row()) && m_terminal.cursor_row() >= min_selection_row && m_terminal.cursor_row() <= max_selection_row) {
|
||||
m_selection_end = {};
|
||||
m_selection.set_end({});
|
||||
update_copy_action();
|
||||
update();
|
||||
}
|
||||
|
@ -491,23 +491,16 @@ void TerminalWidget::set_opacity(u8 new_opacity)
|
|||
force_repaint();
|
||||
}
|
||||
|
||||
VT::Position TerminalWidget::normalized_selection_start() const
|
||||
{
|
||||
if (m_selection_start < m_selection_end)
|
||||
return m_selection_start;
|
||||
return m_selection_end;
|
||||
}
|
||||
|
||||
VT::Position TerminalWidget::normalized_selection_end() const
|
||||
{
|
||||
if (m_selection_start < m_selection_end)
|
||||
return m_selection_end;
|
||||
return m_selection_start;
|
||||
}
|
||||
|
||||
bool TerminalWidget::has_selection() const
|
||||
{
|
||||
return m_selection_start.is_valid() && m_selection_end.is_valid();
|
||||
return m_selection.is_valid();
|
||||
}
|
||||
|
||||
void TerminalWidget::set_selection(const VT::Range& selection)
|
||||
{
|
||||
m_selection = selection;
|
||||
update_copy_action();
|
||||
update();
|
||||
}
|
||||
|
||||
bool TerminalWidget::selection_contains(const VT::Position& position) const
|
||||
|
@ -516,6 +509,8 @@ bool TerminalWidget::selection_contains(const VT::Position& position) const
|
|||
return false;
|
||||
|
||||
if (m_rectangle_selection) {
|
||||
auto m_selection_start = m_selection.start();
|
||||
auto m_selection_end = m_selection.end();
|
||||
auto min_selection_column = min(m_selection_start.column(), m_selection_end.column());
|
||||
auto max_selection_column = max(m_selection_start.column(), m_selection_end.column());
|
||||
auto min_selection_row = min(m_selection_start.row(), m_selection_end.row());
|
||||
|
@ -524,7 +519,8 @@ bool TerminalWidget::selection_contains(const VT::Position& position) const
|
|||
return position.column() >= min_selection_column && position.column() <= max_selection_column && position.row() >= min_selection_row && position.row() <= max_selection_row;
|
||||
}
|
||||
|
||||
return position >= normalized_selection_start() && position <= normalized_selection_end();
|
||||
auto normalized_selection = m_selection.normalized();
|
||||
return position >= normalized_selection.start() && position <= normalized_selection.end();
|
||||
}
|
||||
|
||||
VT::Position TerminalWidget::buffer_position_at(const Gfx::IntPoint& position) const
|
||||
|
@ -564,8 +560,7 @@ void TerminalWidget::doubleclick_event(GUI::MouseEvent& event)
|
|||
end_column = column;
|
||||
}
|
||||
|
||||
m_selection_start = { position.row(), start_column };
|
||||
m_selection_end = { position.row(), end_column };
|
||||
m_selection.set({ position.row(), start_column }, { position.row(), end_column });
|
||||
update_copy_action();
|
||||
}
|
||||
GUI::Frame::doubleclick_event(event);
|
||||
|
@ -631,11 +626,9 @@ void TerminalWidget::mousedown_event(GUI::MouseEvent& event)
|
|||
int end_column = m_terminal.columns() - 1;
|
||||
|
||||
auto position = buffer_position_at(event.position());
|
||||
m_selection_start = { position.row(), start_column };
|
||||
m_selection_end = { position.row(), end_column };
|
||||
m_selection.set({ position.row(), start_column }, { position.row(), end_column });
|
||||
} else {
|
||||
m_selection_start = buffer_position_at(event.position());
|
||||
m_selection_end = {};
|
||||
m_selection.set(buffer_position_at(event.position()), {});
|
||||
}
|
||||
if (m_alt_key_held)
|
||||
m_rectangle_selection = true;
|
||||
|
@ -700,9 +693,9 @@ void TerminalWidget::mousemove_event(GUI::MouseEvent& event)
|
|||
else
|
||||
m_auto_scroll_direction = AutoScrollDirection::None;
|
||||
|
||||
auto old_selection_end = m_selection_end;
|
||||
m_selection_end = position;
|
||||
if (old_selection_end != m_selection_end) {
|
||||
VT::Position old_selection_end = m_selection.end();
|
||||
m_selection.set_end(position);
|
||||
if (old_selection_end != m_selection.end()) {
|
||||
update_copy_action();
|
||||
update();
|
||||
}
|
||||
|
@ -744,8 +737,10 @@ void TerminalWidget::set_scroll_length(int length)
|
|||
String TerminalWidget::selected_text() const
|
||||
{
|
||||
StringBuilder builder;
|
||||
auto start = normalized_selection_start();
|
||||
auto end = normalized_selection_end();
|
||||
|
||||
auto normalized_selection = m_selection.normalized();
|
||||
auto start = normalized_selection.start();
|
||||
auto end = normalized_selection.end();
|
||||
|
||||
for (int row = start.row(); row <= end.row(); ++row) {
|
||||
int first_column = first_selection_column_on_row(row);
|
||||
|
@ -774,12 +769,14 @@ String TerminalWidget::selected_text() const
|
|||
|
||||
int TerminalWidget::first_selection_column_on_row(int row) const
|
||||
{
|
||||
return row == normalized_selection_start().row() || m_rectangle_selection ? normalized_selection_start().column() : 0;
|
||||
auto normalized_selection_start = m_selection.normalized().start();
|
||||
return row == normalized_selection_start.row() || m_rectangle_selection ? normalized_selection_start.column() : 0;
|
||||
}
|
||||
|
||||
int TerminalWidget::last_selection_column_on_row(int row) const
|
||||
{
|
||||
return row == normalized_selection_end().row() || m_rectangle_selection ? normalized_selection_end().column() : m_terminal.columns() - 1;
|
||||
auto normalized_selection_end = m_selection.normalized().end();
|
||||
return row == normalized_selection_end.row() || m_rectangle_selection ? normalized_selection_end.column() : m_terminal.columns() - 1;
|
||||
}
|
||||
|
||||
void TerminalWidget::terminal_history_changed()
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <LibGUI/Frame.h>
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
#include <LibVT/Range.h>
|
||||
#include <LibVT/Terminal.h>
|
||||
|
||||
class TerminalWidget final : public GUI::Frame
|
||||
|
@ -76,9 +77,9 @@ public:
|
|||
bool has_selection() const;
|
||||
bool selection_contains(const VT::Position&) const;
|
||||
String selected_text() const;
|
||||
VT::Range normalized_selection() const { return m_selection.normalized(); }
|
||||
void set_selection(const VT::Range& selection);
|
||||
VT::Position buffer_position_at(const Gfx::IntPoint&) const;
|
||||
VT::Position normalized_selection_start() const;
|
||||
VT::Position normalized_selection_end() const;
|
||||
|
||||
void scroll_to_bottom();
|
||||
|
||||
|
@ -146,8 +147,7 @@ private:
|
|||
|
||||
VT::Terminal m_terminal;
|
||||
|
||||
VT::Position m_selection_start;
|
||||
VT::Position m_selection_end;
|
||||
VT::Range m_selection;
|
||||
|
||||
String m_hovered_href;
|
||||
String m_hovered_href_id;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue