Siv3D でおしゃれなアプリランチャーを作ろう (49 行)

![0.gif](https://lh3.googleusercontent.com/-AbW28FCLqmw/Vl-5zadAYXI/AAAAAAAAEgg/MSJg7jaQrFA/s830-Ic42/0.gif)

1 台のパソコンで複数の作品を展示するときに、ショートカットをデスクトップに雑然と並べるだけではプレイヤーに不親切です。Siv3D March 2016 を使って、おしゃれなアプリランチャーを作りましょう。このアプリランチャーは、Siv3D 製以外のアプリや、Web ブラウザを使った作品の起動にも対応します。
 

#1. 外部アプリを起動しよう
`System::CreateProcess()` は、第 1 引数で指定した外部のプログラムを実行します。
## サンプル 1-1

```cpp
# include <Siv3D.hpp>

void Main()
{
	System::CreateProcess(L"C:/Windows/System32/notepad.exe");

	while (System::Update())
	{

	}
}
```

戻り値の `ProcessInfo` を通して、プロセスが実行中であるかを調べられます。
外部アプリケーションが実行されている間はランチャーを最小化するようにしましょう。
## サンプル 1-2

```cpp
# include <Siv3D.hpp>

void Main()
{
	Optional<ProcessInfo> process = System::CreateProcess(L"C:/Windows/System32/notepad.exe");

	while (System::Update())
	{
		if (process)
		{
			if (process->isRunning())
			{
				Window::Minimize();
			}
			else
			{
				Window::Restore();
				process = none;
			}
		}
	}
}
```

#2. Web ブラウザを起動しよう

`System::CreateProcess()` の第 2 引数には、外部のプログラムを起動する際のコマンドラインオプションを指定できます。Internet Explorer の場合は、`-new [URL]` で、指定した URL をオープンします。
## サンプル 2-1

```cpp
# include <Siv3D.hpp>

void Main()
{
	Optional<ProcessInfo> process = System::CreateProcess(L"C:/Program Files/Internet Explorer/iexplore.exe",
		L"-new http://play-siv3d.hateblo.jp/");

	while (System::Update())
	{
		if (process)
		{
			if (process->isRunning())
			{
				Window::Minimize();
			}
			else
			{
				Window::Restore();
				process = none;
			}
		}
	}
}
```

#3. 選択画面を作ろう
アプリの名前、アプリのパス、コマンドラインオプションを配列に用意しましょう。
## サンプル 3-1
![3-1.png](https://qiita-image-store.s3.amazonaws.com/0/30255/2e294031-6ffb-07cb-fec6-96b0d2f0d8e3.png)

```cpp
# include <Siv3D.hpp>

struct Application
{
	String name;
	FilePath path;
	String option;
};

void Main()
{
	Window::Resize(640, 310);
	Window::SetStyle(WindowStyle::NonFrame);
	const Font font(20, Typeface::Light);

	const Array<Application> applications =
	{
		{ L"メモ帳", L"C:/Windows/System32/notepad.exe", L"" },
		{ L"ペイント", L"C:/Windows/System32/mspaint.exe", L"" },
		{ L"電卓", L"C:/Windows/System32/calc.exe", L"" },
	};

	Optional<ProcessInfo> process;

	while (System::Update())
	{
		for (auto i : step(applications.size()))
		{
			const Rect rect(40, 40 + i * 80, 250, 60);

			rect.draw();

			font(applications[i].name).draw(rect.pos.movedBy(24, 8), Palette::Black);

			if (rect.leftClicked)
			{
				process = System::CreateProcess(applications[i].path, applications[i].option);
			}
		}

		if (process)
		{
			if (process->isRunning())
			{
				Window::Minimize();
			}
			else
			{
				Window::Restore();
				process = none;
			}
		}
	}
}
```

#4. アプリの説明とサムネイル画像を表示しよう
アプリの説明とサムネイル画像を加えます。
## サンプル 4-1
![4-1.png](https://qiita-image-store.s3.amazonaws.com/0/30255/9ded9616-e33e-38e0-05f1-691417ab3461.png)

```cpp
# include <Siv3D.hpp>

struct Application
{
	String name;
	FilePath path;
	String option;
	String description;
	Texture thumbnail;
};

void Main()
{
	Window::Resize(640, 310);
	Window::SetStyle(WindowStyle::NonFrame);
	const Font font(20, Typeface::Light), fontDesc(16);
	const Texture texture(Image(L"Example/Windmill.png").scale(270, 180));

	const Array<Application> applications =
	{
		{ L"メモ帳", L"C:/Windows/System32/notepad.exe", L"", L"メモを書けるよ", texture },
		{ L"ペイント", L"C:/Windows/System32/mspaint.exe", L"", L"絵を描けるよ", texture },
		{ L"電卓", L"C:/Windows/System32/calc.exe", L"", L"計算してくれるよ", texture },
	};

	Optional<ProcessInfo> process;
	size_t currentIndex = 0;

	while (System::Update())
	{
		for (auto i : step(applications.size()))
		{
			const Rect rect(40, 40 + i * 80, 250, 60);

			if (rect.mouseOver)
			{
				currentIndex = i;
			}

			rect.draw();

			font(applications[i].name).draw(rect.pos.movedBy(24, 8), Palette::Black);

			if (rect.leftClicked)
			{
				process = System::CreateProcess(applications[i].path, applications[i].option);
			}
		}

		applications[currentIndex].thumbnail.draw(330, 40);

		fontDesc(applications[currentIndex].description).drawCenter({ 465, 248 }, Palette::White);

		if (process)
		{
			if (process->isRunning())
			{
				Window::Minimize();
			}
			else
			{
				Window::Restore();
				process = none;
			}
		}
	}
}
```

#5. 完成
デザインをアレンジしましょう。今回は付箋や写真をイメージしました。
[参考: Play Siv3D! サンプル | 付箋](http://play-siv3d.hateblo.jp/entry/sample/postit)

## サンプル 5-1 (49 行)
![5-1.png](https://qiita-image-store.s3.amazonaws.com/0/30255/3c5f6257-f799-aacd-f86d-a4288797b91a.png)

```cpp
# include <Siv3D.hpp>

struct Application
{
	String name;
	FilePath path;
	String option;
	String description;
	Texture thumbnail;
};

void Main()
{
	Window::Resize(640, 310);
	Window::SetStyle(WindowStyle::NonFrame);
	Graphics::SetBackground(Color(240, 250, 230));
	const Font font(20, Typeface::Light), fontDesc(16);
	const Texture texture(Image(L"Example/Windmill.png").scale(270, 180));

	const Array<Application> applications =
	{
		{ L"メモ帳", L"C:/Windows/System32/notepad.exe", L"", L"メモを書けるよ", texture },
		{ L"ペイント", L"C:/Windows/System32/mspaint.exe", L"", L"絵を描けるよ", texture },
		{ L"電卓", L"C:/Windows/System32/calc.exe", L"", L"計算してくれるよ", texture },
	};

	Array<double> angleOffsets(applications.size());

	for (auto& angleOffset : angleOffsets)
	{
		angleOffset = Random(-1.5, 1.5);
	}

	Optional<ProcessInfo> process;
	size_t currentIndex = 0;

	while (System::Update())
	{
		for (auto i : step(applications.size()))
		{
			const Rect rect(40 + i % 2 * 20, 40 + i * 80, 250, 60);

			if (rect.mouseOver)
			{
				currentIndex = i;
			}

			const bool selected = (currentIndex == i);

			Graphics2D::SetTransform(Mat3x2::Rotate(Radians(selected ? 3 : 1), rect.pos));
			rect.drawShadow({ 1, 1 }, 12, -1, ColorF(0, 0.4));
			Graphics2D::SetTransform(Mat3x2::Identity());

			rect.draw(HSV(i * 40, 0.6, selected ? 1.0 : 0.95));
			font(applications[i].name).draw(rect.pos.movedBy(24, 8), Palette::Black);

			if (rect.leftClicked)
			{
				process = System::CreateProcess(applications[i].path, applications[i].option);
			}
		}

		const Vec2 pinPos(465, 50);

		Graphics2D::SetTransform(Mat3x2::Rotate(Radians(angleOffsets[currentIndex]), pinPos));
		Rect(330, 40, texture.size).drawShadow({ 2, 2 }, 12, 3, ColorF(0, 0.4));
		applications[currentIndex].thumbnail.draw(330, 40).drawFrame(10, 0).stretched(-10).drawFrame(1, 0, Palette::Gray);
		Graphics2D::SetTransform(Mat3x2::Identity());

		Circle(pinPos, 6).drawShadow({ 3, 3 }, 4, 1);
		Circle(pinPos, 6).draw(HSV(0, 0.7, 0.9)).stretched(-2).draw(HSV(0, 0.9, 0.9));
		fontDesc(applications[currentIndex].description).drawCenter({ pinPos.x, 248 }, Palette::Black);

		if (process)
		{
			if (process->isRunning())
			{
				Window::Minimize();
			}
			else
			{
				Window::Restore();
				process = none;
			}
		}
	}
}
```

このページの最初のムービーに出てくるサムネイルを使いたい場合は、以下の 3 つの画像をダウンロードしてください。

![0.png](https://qiita-image-store.s3.amazonaws.com/0/30255/4d121eea-b7a9-ef01-9cdd-c2e574d2be5c.png) ![1.png](https://qiita-image-store.s3.amazonaws.com/0/30255/ba9425ee-eb64-18b6-c124-35189f29e29b.png) ![2.png](https://qiita-image-store.s3.amazonaws.com/0/30255/e6a61ec2-d510-30a2-6cb0-89d8531154c9.png)

明日の記事は @Sigureya さんです。
よろしくお願いします。