はじめに
連載「小型LCD向けGUI設計」で題材にしているサンプルコードを、単体でビルド・実行できる公開リポジトリにまとめました。
4行キャラクタLCDを想定した、最小構成のGUIライブラリです。C言語で「Widget+クラス関数表(vtable風)」の継承を、mallocを使わず静的確保だけで組み立てています。実機がなくても、PCのターミナルに20文字×4行のモックLCDを描画して動きを確かめられます。
記事の説明用に新規へ書き起こしたもので、特定製品のソースコードではありません。手を動かしながら設計を追える教材として置いています。
どんなもの?
+--------------------+
|Device Settings |
|>Rate:115k [Apply] |
| Lvl:5 Port:P1 |
| |
+--------------------+
これは ./demo の実出力です。行頭の記号は、GuiIcon(カーソル・編集中・操作不可)をモックLCDが文字へ落としたもの。実機ではLCDコントローラの外字番号になります。上下左右キーでフォーカスが動き、Comboで候補を選び、Spinで数値を編集し、Enterでボタンを実行する――という一連の操作を、そのままターミナルで再現します。
すぐ試す
依存はC11標準ライブラリだけ。クローンして2コマンドです。
git clone https://github.com/okakousuke/lcd-widget-gui
cd lcd-widget-gui
make run
make を使わないなら、記事と同じコマンドで直接ビルドできます。
cc -std=c11 -Wall -Wextra -Wpedantic -o demo gui.c demo.c
./demo
gcc (Ubuntu) 13.3.0 で警告0件、./demo は全シナリオの assert が成功(終了コード0)。GitHub Actions でも同じビルドと実行、さらに nm -u で malloc 系を引き込んでいないことまで自動チェックしています。
設計のさわり
詳しくは連載本編に譲りますが、芯だけ紹介します。
-
継承は「先頭メンバへ親型を実体で埋め込む」。
GuiButtonの先頭はGuiItem、その先頭はGuiVisual…と続くので、派生型のポインタをそのまま親型へキャストできます。崩れると事故るので、offset 0を_Static_assertでコンパイル時に固定(オブジェクト側8+クラス側8の計16本)。 -
クラス関数表は
const。各Widgetが持つのは「クラス関数表を指すklassポインタ1本」だけ。関数ポインタを全インスタンスへ配らないので、イベント関連のRAMは1ポインタぶんで済みます。 -
境界を分ける。描画は
GuiDisplayPort、装置制御はDeviceControlPortに寄せ、UIコードはレジスタや通信を知りません。だから表示がLCD→別デバイスへ変わっても、装置側がASIC→FPGAへ変わっても、直す場所が片側に閉じます。 - 編集は Change / Submit / Cancel。プレビュー中は確定値を触らず、Submitで確定、Cancelで編集開始前へ戻す(ハードウェア状態も含めて)。
GuiWidget GuiWidgetClass
├ GuiPage ├ GuiPageClass
└ GuiVisual └ GuiVisualClass
├ GuiLabel ├ GuiLabelClass
└ GuiItem └ GuiItemClass
├ GuiButton ├ GuiButtonClass
└ GuiNamedItem └ GuiNamedItemClass
├ GuiCombo ├ GuiComboClass
└ GuiSpin └ GuiSpinClass
ライセンス
MIT License です。改変・再配布は自由なので、自分のLCDやキー配置に合わせて削ったり足したりする土台に使ってください。
連載本編
設計判断の背景や、実機で苦労したところは本編で扱っています。
- 4行LCDでもUI設計は必要だった ― 物理ボタンと専用ハードウェアをつなぐ
- C言語でWidgetと継承風設計を作る ― 4行LCD向けGUIの内部構造
- mallocなしでイベント駆動GUIを組み立てる
- 物理ボタンから4行LCDのUIを設計する
- UIイベントと専用ハードウェアを分離する
- リアルタイムではない装置を、リアルタイムに感じさせる
おわりに
「4行しかないLCD」でも、ちゃんと設計すると画面追加が楽になります。まずは make run で動かして、gui.h の型階層と demo.c の組み立て方を眺めてみてください。気づいた点やバグは Issue / PR で歓迎です。