LuminoEngine / Lumino

Lumino is a framework for building real-time graphics applications.
https://luminoengine.github.io
MIT License
207 stars 14 forks source link

UIEventHandler の登録 API を整理する #142

Open lriki opened 4 years ago

lriki commented 4 years ago

[2021/1/6] やっぱり現状維持にしてみる

Builder パターンの導入を始めたので、そっちで対応してみる。C++ から使うときはほとんどこのケースで足りる。

auto button = UIButton::Builder()
    .onClicked(handler)
    .build();

新しめの UI フレームワークは Builder パターンないしそれに近い、副作用の少ない方法で UI要素を構築するケースが多い。これで十分な感じ。

connectXX は主に Binding を作るとき、「これはイベントハンドラの登録関数です」を強調するのに使うことにしてみる。

イベント名は過去形?

ネイティブに近いフレームワークは過去形が多い傾向。 ただ過去形に統一しすぎると MouseDowned とかなじみ無い名前になる。

タイミングを区別するなら WPF の "Preview" Prefix のようなものを付ける、でいいかも。

Proposal

connectOnXXXX 及び onXXXX のインターフェイスを変更する。 例えば UIButton の Clicked イベントであれば、

Ref<EventConnection> connectOnClicked(Ref<UIEventHandler> handler);
virtual void onClicked(UIEventArgs* e) override;

UIButton* onClicked(Ref<UIEventHandler> handler, Ref<EventConnection>* outConnection = nullptr);
virtual void onClickedEvent(UIEventArgs* e) override;

ただし、on~ は他のモジュールでも使用している仮想関数実装の命名規則でもあるため、上記そのまま適用は難しいかもしれない。

候補としては、

Motivation

現在、ユーザープログラムから、イベントをハンドリングする方法は次の2通り。

ユーザープログラムから見ると、このうち A は非常によく使い、B はあまり使わない。 (A はコントロールを利用するための API であるが、B はコントロールをカスタマイズするための API)

そのため以下のような不満が出てきた。

Note

on~ を採用しているものはそれなりにある。ただ、signal ではなく普通のプロパティとして単一のハンドラをセットするケースが多い印象。

C# の Event や、signal-slot の仕組みで作られているものは on~ ではないことが多いみたい。

WPF

Material-UI

onClick の呼び出し元は handleClick. ただ仮想関数という考え方ではない。

一番根っこは div の onClick にローカル定義した関数をセットしているだけ。 \<div ... onClick={handleClick} ...>

JavaScript

Flutter

Unity(UIElements)

これらはすべて C# の event として実装されている。

仮想関数は次のような命名になっている。

UE4

イベントと仮想関数の命名規則に区別はない。

Kivy

イベントと仮想関数の命名規則に区別はない。

Qt

Android

UIKit

GTK

Rust azul

let button = Button::with_label("+1").dom().with_id("button")
      .with_callback(On::MouseUp, Callback(update_counter));

Rust gtk

button.connect_clicked(move |_| { ... });

Rust iced

Button::new(&mut self.reset_button, Text::new("reset"))
    .on_press(Message::Reset),

OrbTk iced

self.on_mouse_up(move |p| { ... });

Note

現時点で Event<> な変数は次の通り。

canUndoChanged;
canRedoChanged;

m_onCollisionEnter;
m_onCollisionLeave;
m_onCollisionStay;
m_onUIEvent;
m_onChecked;
m_onUnchecked;

m_onActivated;
m_onDeactivated;

m_onSubmit;
DragStarted;
DragDelta;
DragCompleted;
DragCanceled;

m_onItemSubmitted;
m_onGenerateTreeItem;

m_onCanExecuteChanged;
m_onCanExecuteEvent;
m_onExecuteEvent;

m_onClosed;
m_onImGuiLayer;

m_onClick;
m_onItemClick;
m_onSelectionChanged;
m_onSelectedTabChanged;

m_onRender

onGenerateTreeItem, onRender あたりは他の名前にし辛いかも。

onUIEvent は動詞でもないケースなので、Ruby とかだと普通の変数と区別ができなくなる。 スクリプト系だとこのあたりの視認性が悪くなるのはマイナス。