Slintでモーダルダイアログを実現する

# はじめに

これは[Slint Advent Calender 2024](https://qiita.com/advent-calendar/2024/slint) 11日目の記事です。

昨日は[@hermit4](https://qiita.com/hermit4)さんの[Slint言語入門(3)　構文についての続き](https://qiita.com/hermit4/items/53f71549087a7d51ed15)でした。知らなかった機能がたくさん! 覚えておいて必要な時に使えるようになっておきたいですね。

さて私事ですが、2024年は[Slint](https://slint.dev/)を知り、RustでGUIアプリケーションを作ることの可能性を感じることができました。

実際にSlintを少し触ってみましたが、ウィンドウシステムレベルのDialogは今のところモードレス表示しかできないらしく、ユーザーに操作を促す機能としては使い所が難しいかなと感じていました。

おそらく対策としてはメインウィンドウ内に表示するタイプのモーダルダイアログを実現する必要があるのだろうなとは思いつつ、まだ試すことができないままでした。

アドベントカレンダーの季節が来たということで、この機会にとそれを実験してみたというのがこの記事です。

# 実装

さっそくですが、[SlintPad](https://slintpad.com/)を使って以下のように実装してみました。

```rust
import { VerticalBox, Button, StandardButton } from "std-widgets.slint";
export component TestModalDialog {
    property<bool> dialog-visible;

    VerticalBox {
        alignment: center;
        Text {
            text: "Test modal dialog";
            font-size: 24px;
            horizontal-alignment: center;
        }
        HorizontalLayout { 
            alignment: center;
            Button {
                text: "Show modal dialog";
                clicked => {
                    dialog-visible = true;
                }
            }
        }
    }

    if dialog-visible: Rectangle {
        width: 100%;
        height:  100%;
        background: #0000007f;
        TouchArea {
        }
        Rectangle {
            width: 250px;
            height: 200px;
            background: #EFEFEFFF;
            border-radius: 20px;
            drop-shadow-blur: 10px;
            drop-shadow-color: #0000007F;
            Dialog {
                width: 100%;
                height: 100%;
                VerticalBox {
                    Text {
                        text: "Hello, World!";
                        font-size: 24px;
                        horizontal-alignment: center;
                    }
                    Text {
                        text: "This is a modal dialog greeting!";
                    }
                }
                StandardButton {
                    kind: close;
                    clicked => {
                        dialog-visible = false;
                    }
                }
            }
        }
    }
}

```

右側のPreviewでShow modal dialogボタンを押すと、以下のように表示が変わります。

![ModelDialog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100666/fe927857-23dd-3e7e-56ae-40a5224ad539.png)

なんかこれでよさそうな気がしますね! それはそうとしょっぱなからコードを貼り付けてしまったので、以下で解説を行います。

# 解説

`dialog-visible`というプロパティを作成し、ダイアログが表示中かどうかを保持します。これはShow modal dialogボタンを押すとtrueになります。

Slint言語にはconditional elementという機能があり、`if dialog-visible: Rectangle {...`と記述することで`dialog-visible`がtrueの時だけこのRectangleを生成することができます。これによりダイアログを表示します。

最初に作るRectangleはダイアログの下を薄暗くするためのもので、`width`と`height`は100%、色は黒い半透明にします。

TouchAreaはダイアログの下にあるものからイベントを奪うために必要で、これがないと押せてはいけないはずのボタンなどが押せてしまいます。

次のRectangleでダイアログの形を作ります。角を丸めたり、影を付けたりしてそれっぽくしてあげました。

その内側にDialogの本体を作ります。なんかそれっぽくテキストを表示したりします。

最後にStandardButtonで閉じるボタンを作ります。クリックされたら`dialog-visible`をfalseにしてダイアログを非表示とします。

# おわりに

以前調査したときには不満に思っていたダイアログの機能不足ですが、この方法で実現してあげれば問題なさそうです。昨今のユーザーはウェブアプリなどでこのタイプのモーダルダイアログに馴染んでいるでしょうし、ウィンドウシステムレベルのダイアログに固執する必要もきっとないのでしょう。

というわけでSlintに関する自分の中の懸案は解消したので、来年はもう少し本格的に使っていく機会があればなと思っています。

お読みいただきありがとうございました。明日は[@task_jp](https://qiita.com/task_jp)さんです。お楽しみに!