データを編集する上で必要になるカーソルを表示するようにしてみます。
ratatuiの座標は左上が原点になっているのでそこを基点に計算することになります。
ただ移動するだけではなく、エディタとしてはカーソルの位置にある値を編集する必要があるので画面上にポジションとデータのインデックスをSyncさせる必要がります。
そこでCursorPosition構造体を新たに追加しました。
とりあえず目視でカーソルの原点を決めて、あとは各値の間にある空白も計算した横移動や一行に配置するデータ数に応じて縦移動もできるように計算しています。
これで、カーソルとデータの要素のインデックスをSyncするようにできていると思います。
pub(crate) struct Message {
bin_data: BinData,
cursor: CursorPosition,
}
ORIGIN_XとORIGIN_Yはカーソルの原点です。STEPで横移動の距離単位を3としました。
saturating_add()やsaturating_sub()は型の数値範囲を超えないように足し算、引き算するメソッドです。
この場合だとusizeの0~18446744073709551615の間の値になります。このメソッドを使うと負の値にならず、この範囲の上限を超えないようになります。
これでインデックスがマイナスを指して範囲外のエラーを引き起こす事を防いでいます。
// カーソル位置管理
pub(crate) struct CursorPosition {
index: usize,
position: Position,
}
impl CursorPosition {
const STEP: usize = 3;
const ORIGIN_X: u16 = 10;
const ORIGIN_Y: u16 = 2;
pub(crate) fn new() -> Self {
let index = 0;
let position = Position {
x: Self::ORIGIN_X,
y: Self::ORIGIN_Y,
};
Self { index, position }
}
pub(crate) fn position(&self) -> &Position {
&self.position
}
pub(crate) fn move_to_right(&mut self, len: usize) {
self.index = self.index.saturating_add(1);
if self.index > len {
self.index = len;
}
}
pub(crate) fn move_to_left(&mut self) {
self.index = self.index.saturating_sub(1);
}
pub(crate) fn move_to_up(&mut self) {
self.index = self.index.saturating_sub(constants::LINE_LEN);
}
pub(crate) fn move_to_down(&mut self, len: usize) {
self.index = self.index.saturating_add(constants::LINE_LEN);
if self.index > len {
self.index = len;
}
}
// カーソル位置計算
pub(crate) fn calc_position(&mut self) {
self.position.x = Self::ORIGIN_X + (Self::STEP * (self.index % constants::LINE_LEN)) as u16;
self.position.y = Self::ORIGIN_Y + (self.index / constants::LINE_LEN) as u16;
}
// カーソル上限計算
pub(crate) fn adjust_y(&mut self, border: u16) {
if self.position.y > border {
self.position.y = border;
}
}
}
続いてキーイベントの処理部分です。
キーイベントと上記で定義したメソッドを紐づけしています。
カーソルの操作はとりあえずviの操作と一緒にしています。
// 通常のキー入力処理
match key_event.code {
// 文字関連
// カーソル左移動
KeyCode::Char('h') => {
cursor.move_to_left();
}
// カーソル右移動
KeyCode::Char('l') => {
cursor.move_to_right(len);
}
.....
また新たにconstantsのモジュールを追加してここに複数箇所で使用する定数の定義を集めようと思います。
LINE_LENは一行に配置するデータ要素数です。
pub(crate) const LINE_LEN: usize = 16;
TOC
- 準備
- ターミナル入出力を試す
- ターミナル系crateを利用する
- 編集データと表示処理
- 画面制御
- その他
GitHubにコードをアップロードしています。
コードのコメントに書かれているfirst_stepなどをcargoコマンドに渡すと実行できます。
# Example
$ cargo run --examples first_step