JavaScript (Electron) を使ってアプリの見栄えを整える

# Electronを使って見栄えを整えてみる

ElectronはJavaScriptでデスクトップアプリケーションが作れるツールです。
前回「[30分で出来る、JavaScript (Electron) でデスクトップアプリを作って配布するまで](http://qiita.com/nyanchu/items/15d514d9b9f87e5c0a29)」では簡単なアプリを作って配布するところまでやりました。
あとはいつも通りの JS + HTML + CSS でガリガリ書いていけばいいのですが、まずは見た目から入ろうということで、もう少しアプリっぽい見栄えにしてみましょう。

ちなみに、Macではいろいろ動作を確認しましたが、Windowsは知りません。
大体同じように動くはずですが、もしダメだったらWindows版の記述を教えて頂けると助かります。

# 基本設定は browser-window APIで

browser-windowはアプリのウィンドウを表示するためのAPIです。
例えば、以下は単なるindex.htmlを表示するだけの記述です。

```js
var browserWindow = require('browser-window');
// 画面表示
var mainWindow = new BrowserWindow({ width: 800, height: 600});
mainWindow.loadUrl('file://' + __dirname + '/index.html');
```

BrowserWindowの引数にwidth, heightを渡しているのでなんとなくわかると思いますが、こいつにいろいろ設定を足してあげることで基本的なウィンドウのカスタマイズが出来ます。
以下、設定の一部を紹介します。その他の細かい設定は[ドキュメント](http://electron.atom.io/docs/v0.29.0/api/browser-window/)をご覧ください。

* `x`, `y` (Integer) ･･･
 ウィンドウを表示させる位置を左と上からの絶対値で指定します。
* `center` (Boolean) ･･･
 ウィンドウの表示位置を真ん中に指定します。
* `width`, `height` (Integer) ･･･
 ウィンドウの幅、高さを指定します。`min-width` や `max-width` なども指定できます。
* `resizable` (Boolean) ･･･
 ウィンドウがリザイズ可能かどうかの指定です。
* `show` (Boolean) ･･･
 ウィンドウを表示するかどうかのオプションです。バックグラウンドで静かに動いているようなアプリを作る場合に使うのでしょう。
* `transparent` (Boolean) ･･･
 ウィンドウの背景を透明にするかどうかの設定です。
* `frame` (Boolean) ･･･
 ウィンドウの枠を表示するかどうかの設定です。

さて、これ以降は実践的なチュートリアルをやってみます。

# フレームを非表示、背景を透明にしてみる

ウィンドウのフレームを非表示にしたり、背景を透明にすることが出来ます。
デフォルトのままよりもクールな見栄えが作れそうですね。
試しにやってみましょう。

通常時はこちら。

![スクリーンショット 2015-07-19 14.02.35.png](https://qiita-image-store.s3.amazonaws.com/0/27159/4701f764-1e74-3c44-9571-6ad405d0740f.png)

browser-window に以下の設定を足してみます。

```js
mainWindow = new BrowserWindow({
  'width': 500,
  'height': 600,
  'transparent': true,
  'frame': false
});
```

![スクリーンショット 2015-07-19 14.03.27.png](https://qiita-image-store.s3.amazonaws.com/0/27159/d0db61e9-f1e5-a0c0-549e-6a2187d6e14c.png)


最高にクールになりましたね。
デスクトップがよく見えます。
ドラッグも出来ないし、ウィンドウを閉じることすら出来ません。

いや、これはさすがに不便すぎる･･･これをやるならアプリの移動や終了イベントを自前実装した上で使ったほうが良さそうです。
逆に、上手く使えばクールなアプリが作れそうです。
ドラッグに関しては、index.htmlで以下の設定をすることで、ページの中身をクリックしてウィンドウを移動させることは出来るようになります。

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Sample</title>
  <style>
    body {
      -webkit-app-region: drag; /* ドラッグ可能に */
      -webkit-user-select: none; /* ドラッグはテキスト選択と競合するので禁止 */
    }   
  </style>
</head>
<body>
  <p>Hello World</p>
</body>
</html>
```

# メニューバーにアイコンをつける

メニューバーとは、Macなら上にあるバー、Windowsなら下にあるバーのことです。
ここに専用のアイコンを表示することが出来ます。

### アイコンを表示する

アイコンを表示するにはTrayというAPIを使います。適当に用意したアイコンのパスを渡してみましょう。

```js
var Tray = require('tray');
var appIcon = new Tray(__dirname + '/images/icon.png');
```

すると、メニューバーの1番左に出ました。目立つように青色にしてみましたが、黒のほうがクールかもしれません。
ちなみにアイコンは24px*24pxが良いです。
大きくても一応表示されますが、凄いことになります。

![スクリーンショット 2015-07-20 20.04.39.png](https://qiita-image-store.s3.amazonaws.com/0/27159/3955fd56-4d7e-0fd0-e2cb-982eadd1777e.png)

### コンテキストメニューを追加する

これだけだとさすがに面白くないので、このアイコンをちょっとカスタマイズしてみましょう。
クリックした時にメニューが表示されるようにします。
メニューを表示するにはMenu APIを使います。

```js
var Tray = require('tray');
var Menu = require('menu');

// メニューアイコン設定
var appIcon = new Tray(__dirname + '/images/icon.png');
// コンテキストメニュー追加
var contextMenu = Menu.buildFromTemplate([
  {label: '選択メニュー1', type: 'radio'},
  {label: '選択メニュー2', type: 'radio'},
  {type: 'separator'},
  {label: 'サブメニュー', submenu: [
    {label: 'サブメニュー1'},
    {label: 'サブメニュー2'}
    ]},
  {label: '終了', accelerator: 'Command+Q', click: function() { app.quit(); }}
]);
appIcon.setContextMenu(contextMenu);
// アイコンにマウスオーバーした時の説明
appIcon.setToolTip('This is sample.');
```

Menuの形式はコードを見れば大体わかると思うので、細かい説明は割愛します。もっと詳しく知りたい方は[ドキュメント](https://github.com/atom/electron/blob/master/docs/api/menu.md)をご覧ください。
さて、上記のコードを実行してみると、以下のようになります。

![スクリーンショット-2015-07-20-20.51.30.png](https://qiita-image-store.s3.amazonaws.com/0/27159/bc44fef7-0e38-3bc0-4136-cb8123ec9906.png)

### アイコンをクリックした時だけ表示するアプリにする

コンテキストメニューをつけない場合に限り、アイコンのクリックイベントが取れます。
普段は非表示のアプリにしておいて、クリックされたら表示、なんてアプリも作れますね。
簡単に書くと以下のような感じ。

```js
var BrowserWindow = require('browser-window');
var Tray = require('tray');

// メニューアイコン設定
var appIcon = new Tray(__dirname + '/images/icon.png');
// ウィンドウはデフォルト非表示
appIcon.window = new BrowserWindow({width:500, height: 500, show: false});
// ドックも非表示
app.dock.hide();
appIcon.window.loadUrl('file://' + __dirname + '/index.html');
// クリックされたら表示・非表示切り替え
appIcon.on('clicked', function clicked (e, bounds) {
  if (appIcon.window.isVisible()) {
    appIcon.window.hide();
  } else {
    appIcon.window.show();
  }
});
```

バックグラウンドで動作するようなアプリを作るのに使えそうです。

# アプリケーションメニューをつける

上記ではアイコンをクリックした時のコンテキストメニューをつけました。
次はアプリケーションメニューもつけてみましょう。こちらも先ほどと同じくMenu APIを使うので、書き方は大体同じです。
細かい説明は割愛します。

```js
// アプリケーションメニュー設定
var menu = Menu.buildFromTemplate([
  {
    label: 'Sample',
    submenu: [
      {label: 'About'},
      {label: 'Quit'}
    ]
  },
  {
    label: 'File',
    submenu: [
      {label: 'New File'},
      {label: 'Paste'}
    ]
  },
  {
    label: 'Edit',
    submenu: [
      {label: 'Copy', accelerator: 'Command+C', selector: 'copy'},
      {label: 'Paste', accelerator: 'Command+V', selector: 'paste'}
    ]
  }
]);
Menu.setApplicationMenu(menu);
```

アプリケーションメニューが出ました。

![スクリーンショット 2015-07-20 21.36.56.png](https://qiita-image-store.s3.amazonaws.com/0/27159/f25277c2-ba4d-6acf-0950-f7c67f6ee126.png)

アプリケーションメニューはsubmenuまで指定しないと無視されます。
また、画像を見ればわかるかと思いますが配列の最初の設定がアプリ名をクリックしたときのメニューになります。
QuickStart時では「Electron」になってしまいますが、ちゃんとパッケージングした後は自分の指定した名前になるのでご安心を。

# アプリのアイコンを変える

さて、恐らく皆さんが一番カスタマイズしたいのがこれでしょう。
アプリ自体のアイコンの変更です。デフォルトではElectronになっています。
これを変更するのは、実はとても簡単です。
「[30分で出来る、JavaScript (Electron) でデスクトップアプリを作って配布するまで](http://qiita.com/nyanchu/items/15d514d9b9f87e5c0a29)」で紹介した electron-packager が上手いことやってくれます。
パッケージングする際に以下のオプションを指定するだけです。

```bash
$ electron-packager . sample --platform=darwin--arch=x64 --version=0.30.0 --icon=images/icon.icns
```

すると、ちゃんとアイコンが変わりました。右から2つ目のやつです。

![スクリーンショット 2015-07-20 22.50.53.png](https://qiita-image-store.s3.amazonaws.com/0/27159/693fed6d-641d-02f9-b9d1-334198c81dcf.png)

ただ、Windows版アプリだとそのままでは上手くいかないようです。
詳しくは[ドキュメント](https://www.npmjs.com/package/electron-packager)をご覧ください。

ちなみに、icnsファイルの生成方法は「[Macアプリの.icnsを作るときのメモ](http://qiita.com/Jacminik/items/a4c8fe20a4cba62f428b)」が参考になりました。
ただ、上記の方法だと面倒くさすぎて僕は Img2icons アプリを使いました。

# まとめ

だいぶアプリっぽい見栄えになったのではないでしょうか？
まだ透過などの凝った見栄えを作るのは難しそうですが、普通のアプリで出来る大体のことはElectronで可能です。
ここまで来たらあとは中身をゴリゴリ書いていけば良さそうですね。