Compose for Desktopのウィジェットを思いつくだけ実装してみる

# Compose for Desktopとは
Android Jetpack ComposeをデスクトップOS向けに移植したライブラリ。
公式は[Compose for Desktop UI Framework \| JetBrains: Developer Tools for Professionals and Teams](https://www.jetbrains.com/lp/compose/)
AWTとSwingなどとの相互互換性を持ち、Skiaのグラフィックライブラリを使ってクロスプラットフォームを実現している。
実行ファイルにはJRE(JDKかな？)が同梱されるため、ファイルサイズは大きくなるが単体で実行可能。

## この記事は？
とりあえず思いつく限りのコンポーネントを表示して、そのコードを示す。
殆どはAndroid JetPack Composeと同じ。一部使えないinfixとかあるけど。

## 今回のコード全体
[compose\-desktop\-sample/all\_widgets at main · iwahara/compose\-desktop\-sample](https://github.com/iwahara/compose-desktop-sample/tree/main/all_widgets)

## 試したバージョン
kotlin: 1.4.20
compose for desktop : 0.2.0-build131

## ベースウィンドウ
![スクリーンショット 2020-11-28 1.20.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/28a57b02-2496-3031-c79e-d7dd1ff84053.png)

各ボタンをクリックすると、それぞれのコンポーネントを使ったウィンドウが新規表示される。


## Text
文字列を表示するコンポーネント。

![スクリーンショット 2020-11-28 1.26.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/cda6fd57-d35f-b1aa-9300-01111a30596b.png)

```kotlin

@Composable
fun TextSample() {
    val windowState = remember { mutableStateOf(false) }

    Button(onClick = {
        windowState.value = true
    }) {
        Text("Textのサンプル")
    }
    if (windowState.value) {
        Window(title = "Textのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100), centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {
            Column {
                Text("テキスト")
                Divider() //区切り線
                Text(AnnotatedString(
                        text = "複数のスタイルを割り当てる",
                        spanStyles = listOf(
                                AnnotatedString.Range(SpanStyle(fontStyle = FontStyle.Italic), 0, 5)
                        ),
                        paragraphStyles = listOf(
                                AnnotatedString.Range(ParagraphStyle(textAlign = TextAlign.Center), 0, 6),
                        )
                ))
            }
        }
    }
}
```

## Card
カード型のコンポーネント。
![スクリーンショット 2020-11-28 1.32.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/1e81ff55-4b93-8864-f552-48f2c49fa4b4.png)

```kotlin

@Composable
fun CardSample() {
    val windowState = remember { mutableStateOf(false) }

    Button(onClick = {
        windowState.value = true
    }) {
        Text("Cardのサンプル")
    }
    if (windowState.value) {
        Window(title = "Cardのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100), centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {
            Column {
                Card(Modifier.fillMaxWidth().padding(8.dp), elevation = 8.dp) {
                    Text("カードだよ")
                }
            }
        }

    }
}
```

## TextField
文字入力するためのコンポーネント。
![TextField.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/cf9ab8a7-bc44-7e0e-5a84-2685ebbb9886.gif)

```kotlin

@Composable
fun TextFieldSample() {
    val windowState = remember { mutableStateOf(false) }
    val textField = remember { mutableStateOf("") }
    Button(onClick = {
        windowState.value = true
    }) {
        Text("TextFieldのサンプル")
    }
    if (windowState.value) {
        Window(title = "TextFieldのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100),
                centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {

            Column {
                TextField(value = textField.value, onValueChange = {
                    textField.value = it
                }, label = {
                    Text("ラベル")
                }, placeholder = {
                    Text("プレースホルダー")
                })
                Text(textField.value)
            }
        }
    }

}
```

## CheckBox
チェックボックスのコンポーネント。
![スクリーンショット 2020-11-29 21.16.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/7b404ded-201a-577d-9d1d-bd2d2190c5b1.png)
![スクリーンショット 2020-11-29 21.16.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/a3a56552-ba56-244a-4d3a-385860fbe3ef.png)

```kotlin

@Composable
fun CheckBoxSample() {
    val windowState = remember { mutableStateOf(false) }
    val checked = remember { mutableStateOf(true) }
    Button(onClick = {
        windowState.value = true
    }) {
        Text("CheckBoxのサンプル")
    }
    if (windowState.value) {
        Window(title = "CheckBoxのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100), centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {
            Column {
                Checkbox(checked = checked.value,
                        onCheckedChange = {
                            checked.value = it
                        })
                Text(if (checked.value) "チェック済み！" else "チェックなし！")
            }
        }

    }
}
```


## RadioButton
ラジオボタンのコンポーネント
![スクリーンショット 2020-11-30 21.05.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/f484aafd-9a9f-738c-acb1-981875c82762.png)

![スクリーンショット 2020-11-30 21.05.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/b6e4468e-668f-fb1b-4cd1-13dc390e6903.png)

```kotlin

@Composable
fun RadioButtonSample() {
    val windowState = remember { mutableStateOf(false) }
    val selected = remember { mutableStateOf(true) }
    Button(onClick = {
        windowState.value = true
    }) {
        Text("RadioButtonのサンプル")
    }
    if (windowState.value) {
        Window(title = "RadioButtonのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100), centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {
            Column {

                RadioButton(selected = selected.value, onClick = {
                    selected.value = !selected.value
                })
                Text(if (selected.value) "選択済み！" else "選択なし！")
            }
        }

    }
}
```

## Switch
スイッチのコンポーネント
![スクリーンショット 2020-11-30 21.08.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/4ac6d89d-04d1-7eac-fcc9-377eedab53a6.png)

![スクリーンショット 2020-11-30 21.08.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/3c33bc84-9737-c740-24d2-7bcc6a616467.png)

```kotlin

@Composable
fun SwitchSample() {
    val windowState = remember { mutableStateOf(false) }
    val switchChecked = remember { mutableStateOf(false) }
    Button(onClick = {
        windowState.value = true
    }) {
        Text("Switchのサンプル")
    }
    if (windowState.value) {
        Window(title = "Switchのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100), centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {
            Column {
                Switch(checked = switchChecked.value, onCheckedChange = {
                    switchChecked.value = it
                })
                Text(if (switchChecked.value) "チェック済み！" else "チェックなし！")
            }
        }

    }

}
```

## Slider
スライダーのコンポーネント
![slider.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/c69e0ec6-ae84-67d7-41e5-ec94c5f7ba8c.gif)

```kotlin

@Composable
fun SliderSample() {
    val windowState = remember { mutableStateOf(false) }
    val sliderVal = remember { mutableStateOf(0.5f) }
    Button(onClick = {
        windowState.value = true
    }) {
        Text("Sliderのサンプル")
    }
    if (windowState.value) {
        Window(title = "Sliderのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100), centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {
            Column {
                Slider(value = sliderVal.value, onValueChange = {
                    sliderVal.value = it
                }, modifier = Modifier.weight(1f))
                Text("Slider ${sliderVal.value}", modifier = Modifier.weight(1f))
            }
        }

    }
}
```


## Progress
円形やバー型の進捗表示のためのコンポーネント
![progress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/a9c1e2fd-96cd-c38b-39e4-5f88338eb595.gif)

```kotlin

@Composable
fun ProgressSample() {
    val windowState = remember { mutableStateOf(false) }
    val progress = remember { mutableStateOf(0f) }

    Button(onClick = {
        windowState.value = true
    }) {
        Text("Progressのサンプル")
    }
    if (windowState.value) {
        Window(title = "Progressのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100), centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {
            Column {
                Text("progress ${progress.value}")
                Slider(value = progress.value, onValueChange = {
                    progress.value = it
                })
                LinearProgressIndicator(progress = progress.value)
                CircularProgressIndicator(progress = progress.value)
            }
        }

    }
}
```

## DropDownMenu
選択可能なリストのコンポーネント。
![dropdownlist.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/a8c007c9-0118-8ec9-ea2d-987b37cac912.gif)

```kotlin

@Composable
fun DropdownDemo() {

    val windowState = remember { mutableStateOf(false) }

    val items = listOf("A", "B", "C", "D", "E", "F")
    val showMenu = remember { mutableStateOf(false) }
    val selectedIndex = remember { mutableStateOf(0) }
    Button(onClick = {
        windowState.value = true
    }) {
        Text("DropdownMenuのサンプル")
    }
    if (windowState.value) {
        Window(title = "DropdownMenuのサンプル", size = IntSize(600, 600), location = IntOffset(100, 100), centered = false,
                onDismissRequest = {
                    windowState.value = false
                }) {
            Column {
                DropdownMenu(
                        toggle = {
                            Text(items[selectedIndex.value], modifier = Modifier.fillMaxWidth().clickable(onClick = { showMenu.value = true }))
                        },
                        expanded = showMenu.value,
                        onDismissRequest = { showMenu.value = false },
                ) {
                    items.forEachIndexed { index, s ->
                        DropdownMenuItem(
                                onClick = {
                                    selectedIndex.value = index
                                    showMenu.value = false
                                }
                        ) {
                            Text(text = s)
                        }
                    }
                }
            }
        }

    }
}
```

## SnackBar
通知のコンポーネント
![snackbar.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14421/75124687-f535-89dd-5110-281121ac86a2.gif)

```kotlin

@ExperimentalMaterialApi
@Composable
fun SnackBarSample(scaffoldState: ScaffoldState) {
    val snackBarVisibleState = remember { mutableStateOf(false) }
    val scope = rememberCoroutineScope()
    Button(onClick = { snackBarVisibleState.value = true }) {
        if (snackBarVisibleState.value) {
            Text("Snackbarが表示されてます")
        } else {
            Text("Snackbarを表示")
        }
    }
    if (snackBarVisibleState.value) {
        scope.launch {
            when (scaffoldState.snackbarHostState.showSnackbar("スナックバーやでー", "ボタンだよ")) {
                SnackbarResult.ActionPerformed -> snackBarVisibleState.value = false
                SnackbarResult.Dismissed -> snackBarVisibleState.value = false
            }
        }
    }
}
```

# 参考URL
[Overview \- Jetpack Compose Playground](https://foso.github.io/Jetpack-Compose-Playground/)