開発

[binllion] カーソルを表示する

データを編集する上で必要になるカーソルを表示するようにしてみます。

ratatuiの座標は左上が原点になっているのでそこを基点に計算することになります。

ただ移動するだけではなく、エディタとしてはカーソルの位置にある値を編集する必要があるので画面上にポジションとデータのインデックスをSyncさせる必要がります。

そこでCursorPosition構造体を新たに追加しました。

とりあえず目視でカーソルの原点を決めて、あとは各値の間にある空白も計算した横移動や一行に配置するデータ数に応じて縦移動もできるように計算しています。

これで、カーソルとデータの要素のインデックスをSyncするようにできていると思います。

pub(crate) struct Message {
    bin_data: BinData,
    cursor: CursorPosition,
}
Code language: CSS (css)

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;
        }
    }
}
Code language: PHP (php)

続いてキーイベントの処理部分です。

キーイベントと上記で定義したメソッドを紐づけしています。

カーソルの操作はとりあえずviの操作と一緒にしています。

        // 通常のキー入力処理
        match key_event.code {
            // 文字関連
            // カーソル左移動
            KeyCode::Char('h') => {
                cursor.move_to_left();
            }
            // カーソル右移動
            KeyCode::Char('l') => {
                cursor.move_to_right(len);
            }
.....Code language: PHP (php)

また新たにconstantsのモジュールを追加してここに複数箇所で使用する定数の定義を集めようと思います。

LINE_LENは一行に配置するデータ要素数です。

pub(crate) const LINE_LEN: usize = 16;
Code language: JavaScript (javascript)

GitHubにコードをアップロードしています。0.1.0バージョン

コードのコメントに書かれているfirst_stepなどをcargoコマンドに渡すと実行できます。

# Example
$ cargo run --example first_stepCode language: Bash (bash)
管理人

Recent Posts

期間限定!書籍無料キャンペーン2026

書籍発売1.5周年を記念して2…

2週間 ago

情報セキュリティマネジメント試験取得への道

スキルアップを図るべく情報セキ…

3か月 ago

ファイナンシャルプランナー3級試験取得への道

スキルアップを図るべくファイナ…

4か月 ago

[rust] New Type Patternを使ってみる

DDDの考えを取り入れることで…

6か月 ago

RustでDDDの要素を取り入れてみる

前回SOLID原則というものを…

7か月 ago