CinderでGUIを作るなら、Pretzel GUIがいいかも


# ビルトインのGUI機能、cinder::params

cinder付属のsample ParamsBasicを見ると、cinder::paramsでGUIを作っている。
同僚の[李くん](http://solid-jellyfish.com/)いわく、anttweakbarのラッパーらしい。
スライダーを作っただけなのに、キーボード入力、+/-ボタン、なぞのグルグルUIがついてくるのは、なかなか素晴らしい。なぞのグルグルUIとか、役立つのかわからんけど。
![なぞのグルグル](http://i.gyazo.com/60a4c0bd0ee4e35c52b047d3fa229db7.png)

個人的にcinder::paramsがいいなぁと思ったのは、GUIの操作をしたときのコールバックをupdateFnに登録できるところ。
ここにラムダ式をセットしたりすると、おしゃれなコードを書いてる気分になっていい。
最近実用した例としては、OpenCVの関数で入力パラメータが奇数であることが条件だったので、その場合に

```c++
int sliderValue;
int oddNumberParameter;

params->addParam("window size", &sliderValue).updateFn([this](){ oddNumberParameter = 2*sliderValue+1;});

```

こんなかんじで書いてみた。

だが、こいつには一個だけ不満があって、xmlにsave/loadする機能がない。。
自前で書けばいいじゃんというツッコミもあるけど、１回別のBlockを探してみることにしました。

# Pretzel GUI

再び同僚の李くんに相談したところ、Pretzel GUIというのがまあまあいいよ、とのこと。
[PretzelGUI](https://github.com/cwhitney/PretzelGui)

こちらにはばっちりとxmlへのsave/loadメソッドがついている。
![](http://i.gyazo.com/5c0829620a107d626758ffa9db538088.png)

残念ながら、cinder::paramsのupdateFnみたいな機能はないみたいだ。
あと、windowをリサイズしたときとか、GUIパネルをドラッグして移動したあとに、スライダーとマウスの当たり判定にバグが出たことがあった（スライダーのちょっと上にマウスを乗せたときに、反応する）

だが、それ以外は満足。


コード全文

```C++:GuiExample.cpp
#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"

#include "cinder/params/Params.h"
#include "pretzel/PretzelGui.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class GuiExampleApp : public AppNative {
  public:
	void setup();
	void draw();
    
    cinder::params::InterfaceGlRef params;
    Pretzel::PretzelGui* pretzel;
    
    int a;
};

void GuiExampleApp::setup()
{
    params = cinder::params::InterfaceGl::create(getWindow(), "cinder::params", Vec2i(320, 240));
    params->addParam("Slider", &a).updateFn([this]() { console() << "コールバック関数" << std::endl; });
    
    pretzel = new Pretzel::PretzelGui("Pretzel GUI");
    pretzel->setPos(Vec2i(320, 0));
    pretzel->addSlider("Slider", &a, 0, 100);
    pretzel->addSaveLoad();
    pretzel->loadSettings();
}

void GuiExampleApp::draw()
{
	// clear out the window with black
	gl::clear( Color( 0, 0, 0 ) );
    params->draw();
    pretzel->draw();
}
```


### 余談その１ Macで、プロジェクトにあとからPretzel GUIを加えるときに注意

本筋とは関係ないが、XcodeであとからPretzel GUIを追加すると、PretzelGlobal.cppでコンパイルエラーがでる。
エラーメッセージ＆該当箇所をみるとすぐわかるが、NSCursorまわりで、Objective-Cのコードが書いてある。
なので、PretzelGlobal.cppをObjective-C++のコードとしてコンパイルするように設定してやればよい。
Xcodeで右側のペインを出して、Typeを指定。
![](http://i.gyazo.com/08c5b36173e8708a2b53f61ab88f1b5a.png)

tinderboxで新規にプロジェクトを作るときに、Pretzelを追加している場合は、気にしなくてOK。
どうゆう仕組みになってるのかなぁと思ったら、Pretzelのcinderblock.xmlに以下の記述があった。

	<platform os="macosx">
		<source compileAs="mm">src/pretzel/PretzelGlobal.cpp</source>
	</platform>

compileAsっていうAttributeがあって、指定できるようになっているんですね。
やはり、しっかり設計されているなーという印象のCinder。

### 余談その２ oF/CinderのGUI

話が長くなりそうなのでここは雑に書きます。
GUIのoFのアドオン/CinderのBlockって結構たくさんあるが、それぞれ設計が違って、おもしろい（もしくは、めんどい）。

* [ofxSimpleGuiToo](https://github.com/memo/ofxSimpleGuiToo), PretzelGui, cinder::params はclass Tの参照またはポインタをGUIの部品にセットして、GUIを動かすと直接値も変化する系
* [ofxUI](https://github.com/rezaali/ofxUI)はコールバックをセットして、GUIに変化があったときの処理を書いていく系
* oFの0.8以降で入ったofxGuiはofxSlider_<T>がTの値へ直接代入できるように、代入演算子がオーバーロードされているという、また違った作り

個人的には、cinder::paramsの、値は直接変わるし、簡単にコールバックも設定できる、という作りが一番好きです。