SwiftでWindows向けアプリを作る。ーグリーディングカードをつくってみた。ー

Windows向けのSwiftツールチェーンがダウンロード可能になったことによりツールチェーンを使って様々な方法でアプリを作成することができると思います。

方法に関しては過去に下記のような記事を投稿していますのであわせてみていただければと思います。

| [WindowsアプリをSwiftで作成する。](https://zenn.dev/kok_i/articles/7ab2ce7793d523)<BR>Windows向けのSwiftツールチェーンがダウンロード可能になったことによりツールチェーンを使って様々な方法でアプリを... | ![b6e3341685c71e6815d32ac1355297de29c65cbaf8a3d81c9ef2b0d07347.png](https://assets.st-note.com/production/uploads/ext/b6e3341685c71e6815d32ac1355297de29c65cbaf8a3d81c9ef2b0d07347.png)|
|:--|:-:|

今回は上記記事で参考にしているリポジトリを利用して「グリーディングカード」をアプリとして作成してみようと思います。

# グリーディングカード
> A greeting card is a piece of card stock, usually with an illustration or photo, made of high quality paper featuring an expression of friendship or other sentiment. Although greeting cards are usually given on special occasions such as birthdays, Christmas or other holidays, such as Halloween, they are also sent to convey thanks or express other feelings (such as condolences or best wishes to get well from illness).
> In Western countries and increasingly in other societies, many people traditionally mail seasonally themed cards to their friends and relatives in December. Many service businesses also send cards to their customers in this season, usually with a universally acceptable non-religious message such as "happy holidays" or "season's greetings.

Greeting card From Wikipedia, the free encyclopedia
https://en.wikipedia.org/wiki/Greeting_card

以下訳。
グリーティングカードとは、上質な紙で作られた、イラストや写真入りのカードで、友情などの気持ちを表現したものです。グリーティングカードは通常、誕生日やクリスマス、ハロウィンなどの特別な日に贈られますが、感謝の気持ちやその他の感情（お悔やみ、快気祝いなど）を伝えるために送られることもあります。

欧米諸国や最近では他の社会でも、12月に季節をテーマにしたカードを友人や親類に送る習慣がある人が多い。多くのサービス業でも、この季節になると、"happy holidays" や "season's greetings" などの宗教色のないメッセージを添えたカードを顧客に送ります。

とのことで今の季節に作成するといわゆるクリスマスカードということになります。

今回は下記のようなドット絵をプログラムで描画していこうと思います。
![スクリーンショット 2022-12-18 003320.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519522/f38641fb-210e-ce86-a540-a39a4943351f.png)

ドット絵は下記のサイトの絵を利用させていただいています。
https://dotown.maeda-design-room.net/

# 環境
OS: Windows 11 Version 22H2
Tool Chain: Swift 5.7
Editor: Visual Studio Code（以下VSCode）

# 作成
さっそく作成していきます。大体の方法は冒頭に載せました「WindowsアプリをSwiftで作成する。」という記事を参照していただければと思うのですが[記事内で利用させていただいているリポジトリ](https://github.com/compnerd/swift-win32)では仕様上2022/12/08現在ではViewに背景色を設定できません。そのため背景色を設定できるように一工夫してからドット絵を作成できるプログラムを書いていきます。

## 背景色を設定できるようにする
\swift-win32\Sources\SwiftWin32配下のColor.swiftとView.swiftで下記の変更を加えます。
注意点として、Viewに背景色を設定できるようにするという点で急な場しのぎの対応となっています。そのため根本的な解決ではないことをご了承ください。

アプローチとして、Viewの初期化時にWindowClassの背景色が確定してしまうViewの仕様だったのでその部分を一時的にコメントアウトし、Viewの初期化関数呼び出しのタイミングで背景色を設定してWindowClassを生成しそのWindowClassでViewを初期化するようにしました。

Color.swiftでinternalとして定義されているCOLORREF型で初期化できるメソッドを利用したいのでpublicに変更します。
```diff_swift:Color.swift
- internal init(color: COLORREF) {
+ public init(color: COLORREF) {
```

View.swiftでWindowClassの生成コードをコメントアウトします。
```diff_swift:View.swift
-    private static let `class`: WindowClass =
-        WindowClass(hInst: GetModuleHandleW(nil), name: "Swift.View",
-                    style: UInt32(CS_HREDRAW | CS_VREDRAW),
-                    hbrBackground: GetSysColorBrush(COLOR_3DFACE),
-                    hCursor: LoadCursorW(nil, IDC_ARROW))
+   // private static let `class`: WindowClass =
+   //     WindowClass(hInst: GetModuleHandleW(nil), name: "Swift.View",
+   //                 style: UInt32(CS_HREDRAW | CS_VREDRAW),
+   //                 hbrBackground: GetSysColorBrush(COLOR_3DFACE),
+   //                 hCursor: LoadCursorW(nil, IDC_ARROW))
```

View.swiftで初期化時にWindowClassを生成できるようにします。
whiteでOSの背景色を指定できるようにした理由としてはclearだとblackと値が同じで自分の使いたい色的に困ったのでwhiteをつぶしています。
こちらは使いたい色に応じて変更していただければと思います。
```diff_swift:View.swift
-   public convenience init(frame: Rect) {
-     self.init(frame: frame, class: View.class, style: View.style)
+   public convenience init(frame: Rect, backgroundColor: Color = Color.blue, name: String = "Swift.View") {
+     if backgroundColor == Color.white {
+       let `class` = WindowClass(hInst: GetModuleHandleW(nil), name: name,
+                   style: UInt32(CS_HREDRAW | CS_VREDRAW),
+                   hbrBackground: GetSysColorBrush(COLOR_3DFACE),
+                   hCursor: LoadCursorW(nil, IDC_ARROW))
+       self.init(frame: frame, class: `class`, style: View.style)
+     } else {
+       let `class` = WindowClass(hInst: GetModuleHandleW(nil), name: name,
+                   style: UInt32(CS_HREDRAW | CS_VREDRAW),
+                   hbrBackground: CreateSolidBrush(backgroundColor.COLORREF),
+                   hCursor: LoadCursorW(nil, IDC_ARROW))
+       self.init(frame: frame, class: `class`, style: View.style)
+     }
  }
```

これでColor型で色を指定してその色を背景色として生成できるViewの準備が整いました。

## ドット絵生成
Viewの生成で必要なのは座標とサイズ・背景色・固有の名称なので、それを指定できるようにしてドット絵のレイアウトとしてはColor型の2次元配列で指定することによってドット絵になるようにしています。
```swift:PixelBoardDemo.swift
private func createPixel(
    name: String,
    pixelWidth: Int,
    pixelHeight: Int,
    colors: [[Color]], 
    boxWidth: Double, 
    boxHeight: Double, 
    leftMargin: Double, 
    topMargin: Double
  ) -> [View] {
    var views: [View] = []
    for y in 0 ... pixelHeight - 1 {
      for x in 0 ... pixelWidth - 1 {
        views.append(
          View(
            frame: Rect(
              x: Double(x) * boxWidth + leftMargin, 
              y: Double(y) * boxHeight + topMargin,
              width: boxWidth, height: boxHeight
              ),
            backgroundColor: colors[y][x], 
            name: "Swift.Pixel\(name)(\(x),\(y))"
          )
        )
      }
    }
    return views
  }
```

# SwiftでWindows向けアプリを作る。ーグリーディングカードをつくってみた。ー
慣れ親しんだSwiftを使ってWindows向けアプリを作成してみました。GUIに関してはまだまだ開拓の余地があるようですが自分の調べた限りですとWin32というライブラリに関してはCやC++での記述が非常に参考になるので基本的にはSwiftに落とし込んでいくだけという印象を感じました。しかしSwiftぽく書くにはであったりアーキテクチャの再考やiOS・macOSアプリの作成と同じようにできないか？といった部分を非常に考えられているのがswift-win32というリポジトリの大きな特徴とも思いました。
これからも調査を続けていけたらと思います。

お読みいただきありがとうございました。