前回はFluent.Ribbonのソースコードのビルド方法の投稿でした。なぜ、ビルド方法なのかというと、Fluent.Ribbonのプルリクエストを作成しようとしていたからです。
Fluent.Ribbonのビルドの目的
Fluent.Ribbonのプルリクエストを作成するためには、まずは、手元でソースコードをビルドして、動作を確認できる必要があります。Visual Studioのソリューションだったので、ソリューションをVisual Studioで開けば、すぐにビルド、実行できると思いこんでいました。
ところが、テストアプリ(Fluent.Ribbon.Showcase)をビルド・実行するだけでは、テストアプリをビルドすることができませんでした。
いろいろ試して、ビルドできるようになったので、他の人も同じ状況になることがあるかなと思い、記録として残すために投稿しました。
ビルドができるようになったので、コードを変更して動作確認をすることができ、プルリクエストを作成する準備ができました。
Fluent.Ribbonのプルリクエストの目的
プルリクエストを作成しようと思ったきっかけは、リボンUIのシンプル モードを利用したくなったことです。
リボンUIを容易に実現するために利用できるライブラリーとしてFluent.Ribbonがあります。Fluent.Ribbonライブラリーは、モジュールはnugetで公開されており、また、ソースコードはGitHubで公開されています。
しかし、このFluent.Ribbonライブラリーでは、シンプル モードのリボンUIがサポートされていませんでした。シンプル モードのリボンUIのサポートについて、2019年にissue #695 ([Feature] Simplified Ribbon #695)として登録されています。
Splitwirezさんにより、初期的なコードが作成され、プルリクエスト#707 ([WIP] Feature: Simplified Ribbon #707)として登録されていました。ところが、そのプルリクエストは、最終的には完成しませんでした。
そこで、完成度を上げたプルリクエストを作成しようと思った次第です。
リボンUI
リボンUIは、マイクロソフト オフィスのアプリなどに利用されているユーザーインターフェース(UI)です。2007年初頭にOffice 2007 (Office 12) で採用が始まったUIです。そのリボンUIで少し前から、サイズが小さいリボンUI (シンプル リボン)も使われるようになりました。
マイクロソフト ワードのリボンUIで、今までのリボンUIと小さいサイズのリボンUIを比較したいと思います。なお、サンプル画像は英語版のUIとなりますが、日本語版のUIも同様です。
クラシック リボン
まずは、2007年当初からある通常のリボンUI(クラッシック リボン)です。
このように、上部にタブ(File, Home, Insert, Layout, ….)があり、現在選択しているタブ(Home)のコマンドなどがその下に表示されています。タブの高さは文字にして1行分の高さです。その下のコマンドエリアは、文字にして4行分相当の高さがあります。
シンプル リボン
次に、シンプルモードのリボンUI(シンプル リボン)です。
シンプル リボンは、上部のタブの領域は、クラッシック リボンと変わりません。変わるのは、下部のコマンドエリアです。高さは文字にして1.5行程度です。また、各コマンドのテキストやコマンドグループのテキストは、表示されていません。アイコンが主体のUIとなります。
これにより、コンテンツエリア(マイクロソフト ワードの場合は、ドキュメント表示部分)が広くなります。
クラシック リボンとシンプル リボンの切り替え
クラシック リボンとシンプル リボンの切り替えは、リボンUIの一番右にあるメニューボタンで行います。
メニューを開くと、「クラシック リボン (Classic Ribbon)」と「シンプル リボン (Simplified ribbon)」の項目があるので、それをクリックすることにより切り替えます。
リボンの幅を小さくしたとき
リボンUIでは、リボンの幅を小さくしたとき、使用頻度の低いコマンドから順番に小さく表示されるようになります。各コマンドの表示を小さくしても表示しきれない場合は、折りたたまれたボタンになります。ただし、折りたたまれ方が「クラシック リボン」と「シンプル リボン」では異なります。
クラシック リボン
クラシック リボンでは、リボングループごとに、折りたたまれたボタンになります。
上の絵で、赤枠の中のリボンボタンはすべて、折りたたまれたボタンになっています。下三角のボタンをクリックすると、折りたたまれたボタン群が表示されます。また、折りたたまれたボタンは、リボングループ(縦棒のセパレータで区切られた範囲)ごとに一つ用意されます。
シンプル リボン
シンプル リボンでは、クラシック リボンと同様にリボングループごとに折りたたまれたボタンになります。しかし、さらに幅を小さくすると、折りたたまれボタンの一部がリボンUIの一番右に現れるオーバーフローボタン(「・・・」ボタン)に格納されます。
オーバーフローボタンをクリックすると、折りたたまれたボタン群が表示されます。オーバーフローボタンの中は、リボングループごとにヘッダー(上記の例ではParagraph)が追加され、メニュー形式で表示されます。
シンプル リボンの挙動を観察していると、リボンの幅に関係なく、シンプル リボンにした瞬間に、オーバーフローボタンに移動するコマンドもありました。
シンプル リボンのプルリクエストを作成
シンプル リボンの実装の現状
このような挙動のシンプル ボタンを利用したくなりました。しかし、現時点のFluent.Ribbonには、シンプル リボンの機能はありません。2019年にSplitwirezさんによって作成された、初期段階のアイデアコード(PR: [WIP] Feature: Simplified Ribbon #707)があるのみです。
シンプルモードのリボンUIのサポートに関するissue #695 ([Feature] Simplified Ribbon #695)に記載があるように、Splitwirezさんは別のプロジェクトに興味が移っており、完成版のコードを作成するつもりなはいと明言しています。
また、Fluent.Ribbonのオナーであるbatzenさんも 「シンプルモードのリボンUIのサポートに関するissue #695」を、2年間放置しており、続きの実装をするつもりはないようです。
シンプル リボンのPRを作成
シンプル リボンの機能を追加したく、GitHubにあるFluent.Ribbonのレポジトリーを私のGitHubのレポジトリーにフォーク(Fork)しました。そして、feature-simplified-ribbonブランチとして、実装を開始しました。もともと、SplitwirezさんのPRのfeature-simplified-ribbonブランチの派生として始めましたが、最終的には、Splitwirezさんのコードはほとんど残っていません。
というのも、SplitwirezさんのPRは、初期の試験的なコードであり、
- ボタンコントロールにしか対応していないこと
リボンで使用できるコントロールは、トグルボタン、コンボボックス、スプリットボタン、スピナー、エディットボックス、ラジオボタン、チェックボックスなど多数あります。 - 動的なモード遷移(クラシック リボン←シンプル リボン)が考慮されていないこと
- ウィンドウ幅のリサイズに対するコントロールの再配置が考慮されていないこと
- オーバーフローボタンが考慮されていないこと
など、設計が不十分であったためです。
最終的には、オーバーフローボタンを除き、シンプル リボンの機能を実装しました。
オーバーフローボタンを実装しなかったのは、シンプルリボンの機能が早期に利用できることを優先したためです。実装する過程で、オーバーフローボタンについては、後から実装を追加する形でも、先行実装したシンプルリボンの基本機能に矛盾しない形で実現可能であると判断しました。
シンプル リボン機能の利用
通常の利用であれば、シンプル リボンを使用するためには、
- 各コントロールのMediumIconプロパティにアイコンを設定
- Ribbon@IsSimplifiedプロパティでモード遷移を制御
で利用できます。高度なカスタマイズして利用したい場合は、追加のプロパティを利用して制御できます。
シンプル リボンの機能の仕様
最終的に以下の仕様で、実装しました。
標準的な使い方用
- リボンタブ内で利用できる各コントロールにMediumIconプロパティ(*@MediumIcon)を追加
シンプル リボンでは、24×24相当のアイコンが利用されます。すでに存在していたIconプロパティ、LargeIconプロパティは、それぞれ16×16相当、32×32相当のアイコン用です。シンプル リボンで利用するアイコンのサイズは、その中間のサイズとなるためMediumIconプロパティとしました。 - Ribbonコントロールに読み書き可能なIsSimplifiedプロパティ(Ribbon@IsSimplified)を追加
アプリは、XAML、もしくは、コードで、このプロパティにTrueをセットすることにより、シンプル リボンに遷移できます。このプロパティをアプリ起動中は任意のタイミングで状態遷移できます。
高度なカスタマイズ用
- リボンタブ内で利用できる各コントロールにSimplifiedSizeDefinitionプロパティ(*@SimplifiedSizeDefinition)を追加
クラシック リボン モードとシンプル リボン モードでは、別のレイアウトなので、ウィンドウ幅のリサイズにともなう各コントロールのリサイズ条件は異なると考えました。したがって、既存のSizeDefinitionプロパティはクラシック リボン モード用としました。シンプル リボン モード用として、SimplifiedSizeDefinitionプロパティを追加しました。ただし、デフォルト値は、両方とも”Large,Middle,Small”です。 - RibbonGroupBoxにStateDefinition/SimplifiedStateDefinitionプロパティを追加
ウィンドウ幅のリサイズに伴うリボングループ内のレイアウト方法を制御するためのプロパティです。クラシックモードでは、StateDefinitionが利用され、デフォルト値は”Large,Middle,Small,Collapsed”です。シンプル リボンモードではSimplifiedStateDefinitionが利用され、デフォルト値は”Large,Middle,Collapsed”です。
ウィンドウ幅のリサイズに伴うリボングループのリサイズは、RibbonTabItem@ReduceOrderで制御します。このReduceOrderで制御する対象のRibbonGroupBoxのStateが上記のプロパティで制限できます。このプロパティを追加した理由は、シンプル リボン モードでは、デフォルト動作としてSmall Stateを使いたくなかったためです。 - リボンタブ内で利用できる各コントロールに読み出し専用のIsSimplifiedプロパティ(*@IsSimplified)を追加
リボン内で利用できる各コントロール(RibbonGroupBox/Button/ComboBox/TextBox/Spinnerなど)のスタイルやテンプレートをカスタマイズしたいときに、このプロパティをStyleTriggerやTemplate Triggerとして利用することにより、モードに合わせたカスタマイズができます。Fluent.Ribbonのデフォルトのスタイルやテンプレートもこのプロパティをトリガーとして実装しています。
RibbonGroupBoxのStateとコントロールのレイアウトの関係
Fluent.Ribbonでは、RibbonTabItem@ReduceOderを設定することにより、ウィンドウ幅のリサイズに伴って、リボングループ内のコントロールのサイズが自動調整されます。
各コントロールは、基本的に以下の方針でシンプル リボン モードのときのスタイルが実装されています。
- Large: アイコン(24×24)とヘッダーテキスト
- Middle: アイコン(24×24)
- Small: アイコン(16×16)
もちろん、TextBoxなどのように、編集エリアが必須のコントロールの場合は、Middleであっても、編集エリアは存在します。
シンプル リボン機能のプルリクエストのマージ状況
今回、シンプル リボン機能を実装するうえで、既存の実装にもいくつかバグを見つけたり、機能を追加したりしています。そのため、私が作成したプルリクエストは一つではなく、6個作成しました。一つがシンプルリボンの機能を実現するもので、残り5つが既存のFluent.Ribbonのバグフィックスと機能拡張です。
現時点(2021年5月15日)で、6個のうち4個がFluent.Ribbonにマージされました。シンプルリボンの機能のプルリクエストはいつ頃にマージしてくれるでしょうか。待ち遠しいです。
以上、今回は、Fluent.Ribbonにシンプルリボンの機能を追加するために作成したプルリクエストに関する内容の投稿でした。
“Fluent.Ribbonにシンプル リボンの機能を追加” への1件の返信