提案 #1581
未完了Color Model
説明
mikutter上で色を表現するデータオブジェクトを標準提供する。
やりたいこと¶
現在、色情報を利用する場面は以下のとおりだが、色の表現方法が異なる:名前 | 形式 | 値の範囲 |
---|---|---|
UserConfig | RGB | 0..0xffff |
Cairo::Color::RGB | RGBA | 0..1 (Float) |
Gtk::Color | RGB | 0..0xffff |
Gdk::RGBA | RGBA | 0..1 (Float) |
CSS | RGB | 0..0xff |
現状だと、色をどこで利用するかによって適切に変換しなければならない。
異なるクラスなのは仕方ないにしても、UserConfigからCairoに変換するために、各要素を0xffffで割るみたいな処理を毎回実装しなければならない。
レンダリングを行う層以外ではそういった詳細には立ち入りたくないし、現にGtk3移行のときに変換処理がバグっていたことがあった。
mikutterプラグインの共通の色の表現があると、こういった問題を解決できる。
インターフェイス¶
RGBAの要素のみを要求する。
精度は、各要素を8bitで返すインターフェイスと、0-1のFloatやRationalで返すインターフェイスが考えられる。
アルファブレンド値自体は、無いと困るケースがあるので、このデータオブジェクトで表現に対応する。
ディスプレイは1677万色の表現能力しか持っておらず、24bit (0-255)で十分表現できる。したがって、現在採用しているほとんどの表現形式が過剰である。
また、これは人間の識別精度を十分超えているらしく、mikutterのユーザは今のところ地球人のみであると考えているので、これ以上の精度は不要である。
以上のことから、各8bitでも十分である。
一方で、0-1で表現すると、計算が楽で、何をやっているのかわかりやすいというメリットがある。
uint16_t conv(uint8_t c) {
return c * 0x101;
}
uint16_t conv(float c) {
return c * 0xffff;
}
ん〜どうしよっかな〜
永続化について¶
UserConfigは古いバージョンとの互換性のために現在の形式を維持しなければならない。
表現¶
各データクラスは、異なる方法でデータを保持するが、同じインターフェイスを持っている。
TrueColor (32bit color)
Color.new(255, 0, 0) # red
Color.new(255, 0, 0, 0) # red
Color.parse('#FF0000') # red
ContinuouslyColor
ContinuouslyColor.new(1.0, 0, 0) # red
ContinuouslyColor.new(1.0, 0, 0, 0) # red
同じインターフェイスを実装しColor Modelの要件を満たす独自の実装をプラグインが行うことによって、mikutterの色の表現方法を拡張できるように注意する。
操作¶
spellを使った場合、結果は必ずPromiseを受け取ることになる。色の操作はリアルタイム性が求められることが多く、spellは不適切である。
よくありそうな操作についてはColor Pluginで用意する。
UserConfigの読み込み、書き出し¶
RGBAの各要素は同じ方法で取得できるため、UserConfigに書き出せるはず。
現実的には、今の所UserConfigはあらゆるModelを永続化するような機能はもっていないため、別のところに変換ルーチンを実装しなければならない。
c = Plugin::Color.new(255, 255, 255)
UserConfig[:color] = c # 理想
UserConfig[:color] = Color.export_to_user_config(c) # 現実
一方、読み込みはColor Modelだったらどんなものに復元しても良いため、もう少し直接的になりそう。
c = UserConfig[:color] # 理想
Plugin::UserConfigColor.new(:color) # こういうのがあってもよい?
印字、変換¶
例えばHTML形式で印字したいなど。すべてのColor Modelに実装を要求すると印字形式が拡張できないが、インターフェイスが統一されているのでどうとでもなる。
def html_color(color)
'#%02f%02f%02f'.format(color.r, color.g, color.b)
end
Cairo::Colorに変換するといった処理は、gtk3プラグインなどが各々提供する。
Plugin::Gtk3.cairo_color(c)
比較¶
==で比較する場合、RGBA各要素を0-255で表現した値が等しければ等しいとする。
Color Modelインターフェイスの精度以上で比較する意味がないからである。
同様に、eql?とhashもすべてのColorModelが同じ計算式で値を算出しなければならない。
大小比較は、多分ソートすることがないので別にいいや
標準色¶
c = Plugin::Color::RED
16色とか256色とか用意する。
備考¶
red-colros gem は採用しない。
目的に対してできることが多すぎるため。
あと、色に対する複雑な演算をしたいわけじゃないので、その程度の理由で直接依存を増やしたくない。
Diva::Modelのatomic typeとして追加することも考えたが、wellknownではあるけどatomicではないかな
関連するチケット