UI - Main screen
Main
の画面を編集ポップアップの背後にレンダリングする必要があるため、最初に描画してから、ポップアップに関する追加のロジックがあります。
私たちのレイアウト
Frame
を手に入れたので、実際にウィジェットを描画し始めることができます。レイアウトを作成することから始めます。
let chunks = Layout::default() .direction(Direction::Vertical) .constraints([ Constraint::Length(3), Constraint::Min(1), Constraint::Length(3), ]) .split(frame.area());
変数 chunks
には、スペースの左上隅とサイズを含む Rect
オブジェクトの長さ3配列が含まれています。ウィジェットを準備した後、後でこれらを使用します。
タイトル
タイトルは、どのアプリケーションにとっても重要な要素です。タイトルは、ユーザーが何ができるか、どこにいるかを理解する上で役立ちます。タイトルを作成するには、Paragraph
ウィジェット (テキストのみを表示するために使用される) を使用し、境界線を有効にした Block
を指定して、Paragraph
の周囲に境界線を表示することを指示します。Block
と Paragraph
の詳細については、ブロック レシピ と パラグラフ レシピ を参照してください。
let title_block = Block::default() .borders(Borders::ALL) .style(Style::default());
let title = Paragraph::new(Text::styled( "Create New Json", Style::default().fg(Color::Green), )) .block(title_block);
frame.render_widget(title, chunks[0]);
このコードでは、まず最初に、すべての境界線が有効で、デフォルトのスタイルが設定された Block
を作成します。次に、緑色のスタイルが設定された「Create New Json」というテキストを含む段落ウィジェットを作成します。段落の作成の詳細については、段落レシピ を、テキストのスタイル設定についてはテキストのスタイル設定レシピ を参照してください。最後に、Frame
で render_widget
を呼び出し、レンダリングするウィジェットと、ウィジェットを配置する場所とサイズを表す Rect
を指定します (すべてのウィジェットはこのように描画されます)。
既存のペアのリスト
また、ユーザーがすでに入力したキーと値のペアも表示できるようにしたいと考えています。
そのためには、別のウィジェットである List
を使用します。リストは名前の通り、各 ListItem
ごとに新しいテキスト行を作成し、状態を渡すことができるため、追加作業をほとんど行わずにリスト上の項目の選択を実装できます。選択は実装しません。ユーザーがすでに入力したものを表示できるようにするだけです。
let mut list_items = Vec::<ListItem>::new();
for key in app.pairs.keys() { list_items.push(ListItem::new(Line::from(Span::styled( format!("{: <25} : {}", key, app.pairs.get(key).unwrap()), Style::default().fg(Color::Yellow), )))); }
let list = List::new(list_items);
frame.render_widget(list, chunks[1]);
ライン、スパン、スタイルの詳細については、 Displaying Text recipes を参照してください
この関数の一部では、 ListItem
のベクトルを作成し、スタイルとフォーマットされたキー価値ペアを入力します。最後に、 List
ウィジェットを作成し、レンダリングします。
下のナビゲーションバー
アプリケーションを初めて使用するユーザーが、どのキーを押せるかについてのヒントを見るのに役立ちます。そのために、2 つのバーと別のレイアウトを実装します。これらの 2 つのバーには、1) 現在の画面 (Main
、Editing
、および Exiting
) と 2) 使用可能なキーバインドに関する情報が含まれます。
ここでは、Span
の Vec
を作成します。これは、後で Paragraph
によって 1 行に変換されます。(Span
は Line
とは異なります。Span
は、スタイルが適用された Text
のセクションを示し、改行で終了しません)
let current_navigation_text = vec![ // The first half of the text match app.current_screen { CurrentScreen::Main => Span::styled("Normal Mode", Style::default().fg(Color::Green)), CurrentScreen::Editing => { Span::styled("Editing Mode", Style::default().fg(Color::Yellow)) } CurrentScreen::Exiting => Span::styled("Exiting", Style::default().fg(Color::LightRed)), } .to_owned(), // A white divider bar to separate the two sections Span::styled(" | ", Style::default().fg(Color::White)), // The final section of the text, with hints on what the user is editing { if let Some(editing) = &app.currently_editing { match editing { CurrentlyEditing::Key => { Span::styled("Editing Json Key", Style::default().fg(Color::Green)) } CurrentlyEditing::Value => { Span::styled("Editing Json Value", Style::default().fg(Color::LightGreen)) } } } else { Span::styled("Not Editing Anything", Style::default().fg(Color::DarkGray)) } }, ];
let mode_footer = Paragraph::new(Line::from(current_navigation_text)) .block(Block::default().borders(Borders::ALL));
次に、利用可能なキーを備えたナビゲーションバーでヒントを作成します。これには、異なるスタイルのテキストのセクションがいくつかありません。したがって、コードが少なくなります。
let current_keys_hint = { match app.current_screen { CurrentScreen::Main => Span::styled( "(q) to quit / (e) to make new pair", Style::default().fg(Color::Red), ), CurrentScreen::Editing => Span::styled( "(ESC) to cancel/(Tab) to switch boxes/enter to complete", Style::default().fg(Color::Red), ), CurrentScreen::Exiting => Span::styled( "(q) to quit / (e) to make new pair", Style::default().fg(Color::Red), ), } };
let key_notes_footer = Paragraph::new(Line::from(current_keys_hint)).block(Block::default().borders(Borders::ALL));
最後に、最初のネストされたレイアウトを作成します。 Layout.split
関数には Rect
が必要であり、 Frame
ではなく、以前のレイアウトからチャンクの1つを新しいレイアウトのスペースとして渡すことができます。上記のグラフィックからほとんどのセクションを覚えている場合:
split
のパラメーターとして渡すことにより、このスペースに新しいレイアウトを作成します ( chunks[2]
) 。
let footer_chunks = Layout::default() .direction(Direction::Horizontal) .constraints([Constraint::Percentage(50), Constraint::Percentage(50)]) .split(chunks[2]);
このコードに相当する視覚的なものは次のとおりです。
そして今、私たちは適切なスペースでフッターの段落をレンダリングすることができます。
frame.render_widget(mode_footer, footer_chunks[0]); frame.render_widget(key_notes_footer, footer_chunks[1]);