検索機能付きポップアップウィンドウ(Editor拡張)
以前作成したポップアップウィンドウ(ポップアップウィンドウの作成)に検索機能を追加しました。
Script
ポップアップウィンドウ
作成したScriptは以下の通りです。
public class PopUpInfo
{
public static PopUpInfo instance = null;
private int id;
private int m_selected;
public PopUpInfo(int control_id)
{
id = control_id;
}
public static int GetSelectedValue(int control_id, int selected)
{
if (instance == null)
{
return selected;
}
if (instance.id == control_id)
{
selected = instance.m_selected;
}
return selected;
}
public void SetSelectedValue(int selected)
{
m_selected = selected;
}
}
public class EditorPopUpSearchWindow : PopupWindowContent
{
public static bool on_close = false;
private string[] m_button_names;
private bool[] m_hidden_flags;
private int m_selected;
private Rect m_rect_window;
private PopUpInfo m_instance;
private EditorWindow m_editorWindow;
private GUIStyle m_style_label, m_style_search;
private Texture2D tex_background;
private Color m_color_backgraound = new Color(0.2f, 0.2f, 0.2f, 1.0f);
private bool set_color = false;
private string search_term;
private Vector2 scroll_pos = Vector2.zero;
//背景色変更なし
public EditorPopUpSearchWindow(Rect rect_window, int selected, string[] button_names, GUIStyle style_popup_label, GUIStyle style_search_window, PopUpInfo instance, EditorWindow editorWindow)
{
m_button_names = button_names;
m_selected = selected;
m_rect_window = rect_window;
m_instance = instance;
m_style_label = style_popup_label;
m_style_search = style_search_window;
set_color = false;
m_editorWindow = editorWindow;
m_hidden_flags = new bool[m_button_names.Length];
for(int i = 0; i < m_hidden_flags.Length; i++) { m_hidden_flags[i] = false; }
}
//背景色変更あり
public EditorPopUpSearchWindow(Rect rect_window, int selected, string[] button_names, GUIStyle style_popup_label, GUIStyle style_search_window, Color color_background, PopUpInfo instance, EditorWindow editorWindow)
{
m_button_names = button_names;
m_selected = selected;
m_rect_window = rect_window;
m_instance = instance;
m_style_label = style_popup_label;
m_style_search = style_search_window;
m_color_backgraound = color_background;
set_color = true;
m_editorWindow = editorWindow;
m_hidden_flags = new bool[m_button_names.Length];
for (int i = 0; i < m_hidden_flags.Length; i++) { m_hidden_flags[i] = false; }
}
//背景色を変更する
public static int Create(Vector2 window_size, string label, int selected, string[] button_names, GUIStyle style_label, GUIStyle style_button, GUIStyle style_popup, GUIStyle style_search_window, Color color_background, PopUpPosition popup_position, EditorWindow editorWindow)
{
selected = EditorPopUpSearchWindow.PopUp(window_size, label, selected, button_names, style_label, style_button, style_popup, style_search_window, color_background, popup_position, editorWindow);
return selected;
}
//背景色を変更しない
public static int Create(Vector2 window_size, string label, int selected, string[] button_names, GUIStyle style_label, GUIStyle style_button, GUIStyle style_popup, GUIStyle style_search_window, PopUpPosition popup_position, EditorWindow editorWindow)
{
selected = EditorPopUpSearchWindow.PopUp(window_size, label, selected, button_names, style_label, style_button, style_popup, style_search_window, Color.clear, popup_position, editorWindow);
return selected;
}
static int PopUp(Vector2 window_size, string label, int selected, string[] button_names, GUIStyle style_label, GUIStyle style_button, GUIStyle style_popup, GUIStyle style_search_window, Color color_background, PopUpPosition popup_position, EditorWindow editorWindow)
{
int control_id = GUIUtility.GetControlID(FocusType.Passive);
selected = PopUpInfo.GetSelectedValue(control_id, selected);
Rect rect_control = GUILayoutUtility.GetRect(GUIContent.none, style_button);
int margin = 3;
int button_width = 85;
int label_width = (int)rect_control.width - button_width - margin;
Rect rect_label = new Rect(rect_control) { width = label_width };
Rect rect_button = new Rect(rect_control) { x = rect_control.x + label_width + margin, width = button_width };
Event event_current = Event.current;
Vector2 mouse_pos = event_current.mousePosition;
int label_id = GUIUtility.GetControlID(FocusType.Keyboard);
int button_id = GUIUtility.GetControlID(FocusType.Passive);
bool focus_button = false;
bool on_button = false;
bool on_click = false;
if (event_current.button == 0)
{
switch (event_current.type)
{
case EventType.MouseDown:
if (rect_label.Contains(mouse_pos))
{
GUIUtility.keyboardControl = label_id;
event_current.Use();
}
else if (rect_button.Contains(mouse_pos))
{
GUIUtility.keyboardControl = button_id;
on_click = true;
event_current.Use();
}
break;
}
}
//popupが閉じたとき
if (EditorPopUpSearchWindow.on_close)
{
GUIUtility.keyboardControl = label_id;
EditorPopUpSearchWindow.on_close = false;
}
if (GUIUtility.keyboardControl == label_id) focus_button = true;
if (GUIUtility.keyboardControl == button_id) on_button = true;
if (Event.current.type == EventType.Repaint)
{
style_label.Draw(rect_label, new GUIContent(label), false, false, false, focus_button || on_button);
style_button.Draw(rect_button, new GUIContent(button_names[selected]), false, false, on_button, focus_button);
}
//ボタンがクリックされた時の処理
if (on_click)
{
GUIStyle style_radio = new GUIStyle(EditorStyles.radioButton);
int size = button_names.Length;
int window_width = (int)window_size.x;
int window_height;
int search_field_height = (int)style_search_window.fixedHeight;
if (search_field_height <= 0) search_field_height = 18;
search_field_height += style_search_window.margin.top + style_search_window.margin.bottom;
int radio_button_height = (int)style_radio.fixedHeight;
if (radio_button_height <= 0) radio_button_height = 19;
radio_button_height *= size;
radio_button_height += style_radio.margin.top + style_radio.margin.bottom * size;
int bottom_margin = 2; //各要素の高さやmarginから計算した高さをwindowの高さとするとScrollBarが表示される。少し大きくすることで回避。
window_height = search_field_height + radio_button_height + bottom_margin;
if (window_height > window_size.y) window_height = (int)window_size.y; //要素の高さより指定されたwindowの高さが大きい場合は、windowの高さを要素の高さに合わせる
int window_x;
int window_y = (int)rect_button.y + (int)rect_button.height - window_height;
switch (popup_position)
{
case PopUpPosition.Left:
window_x = (int)rect_button.x;
break;
case PopUpPosition.Center:
window_x = (int)rect_button.x - (window_width - button_width) / 2;
break;
case PopUpPosition.Right:
window_x = (int)rect_button.x - (window_width - button_width);
break;
default:
window_x = (int)rect_button.x;
break;
}
PopUpInfo.instance = new PopUpInfo(control_id);
PopUpInfo.instance.SetSelectedValue(selected);
Rect rect_window = new Rect(window_x, window_y, window_width, window_height);
if (color_background != Color.clear)
{
var popup_content = new EditorPopUpSearchWindow(rect_window, selected, button_names, style_popup, style_search_window, color_background, PopUpInfo.instance, editorWindow);
PopupWindow.Show(rect_window, popup_content);
}
else
{
var popup_content = new EditorPopUpSearchWindow(rect_window, selected, button_names, style_popup, style_search_window, PopUpInfo.instance, editorWindow);
PopupWindow.Show(rect_window, popup_content);
}
}
return selected;
}
public override Vector2 GetWindowSize()
{
return new Vector2(m_rect_window.width, m_rect_window.height);
}
public override void OnOpen()
{
if (set_color)
{
tex_background = new Texture2D(1, 1, TextureFormat.RGB24, false);
tex_background.SetPixel(0, 0, m_color_backgraound);
tex_background.Apply();
}
}
public override void OnGUI(Rect rect)
{
if (set_color) GUI.DrawTexture(new Rect(0, 0, m_rect_window.width, m_rect_window.height), tex_background, ScaleMode.StretchToFill);
int name_length = m_button_names.Length;
if (name_length == 0) return;
EditorGUI.BeginChangeCheck();
search_term = EditorGUILayout.TextField(search_term, m_style_search);
if (EditorGUI.EndChangeCheck())
{
if(search_term != "")
{
for (int i = 0; i < name_length; i++)
{
m_hidden_flags[i] = true;
//大文字小文字の区別をなくす
string lower_name = m_button_names[i].ToLower();
int n = lower_name.IndexOf(search_term.ToLower());
//先頭から一致
//if (n == 0)
//{
// m_hidden_flags[i] = false;
//}
//どこかしら一致
if (n != -1)
{
m_hidden_flags[i] = false;
}
}
}
else
{
for (int i = 0; i < name_length; i++) { m_hidden_flags[i] = false; }
}
}
GUIStyle style_radio = new GUIStyle(EditorStyles.radioButton);
scroll_pos = EditorGUILayout.BeginScrollView(scroll_pos);
int selected = CustomEditorGUI.RadioButton(m_button_names, m_selected, m_hidden_flags, m_style_label, style_radio);
EditorGUILayout.EndScrollView();
if (m_selected != selected)
{
m_editorWindow.Repaint();
m_selected = selected;
}
if (m_instance != null)
{
PopUpInfo.instance.SetSelectedValue(m_selected);
}
}
public override void OnClose()
{
on_close = true;
PopUpInfo.instance = null;
m_editorWindow.Repaint();
}
}
検索を行うためのキーワードを入力するためのTextFieldを追加しています。EditorGUI.BeginChangeCheck()により、TextFieldの内容が変更された時のみ検索が実行されるようにしています。
EditorGUI.BeginChangeCheck();
search_term = EditorGUILayout.TextField(search_term, m_style_search);
始めにEditorGUI.EndChangeCheck()により、TextFiledの内容が変更された時に実行されるようにしています。
if (EditorGUI.EndChangeCheck())
{
・・・
}
次に、search_term != “”によりTextFieldに文字が入力されたか否かを判別します。文字列が入力されていない場合はm_hidden_flagsを全てfalseにすることで、ラジオボタンを全て表示するようにしています。
if(search_term != "")
{
・・・
}
else
{
for (int i = 0; i < name_length; i++) { m_hidden_flags[i] = false; }
}
文字が入力された場合の処理です。各ラジオボタンのラベル(m_button_names)と検索用キーワード(search_term)をそれぞれ、string.ToLower()により全て小文字にしています。これにより、大文字と小文字を区別することなく検索を行うことができます。
string lower_name = m_button_names[i].ToLower();
int n = lower_name.IndexOf(search_term.ToLower());
string.IndexOf()により、キーワードがラジオボタンのラベルに一致するか否かを判定します。string.IndexOf()は一致する部分がなければ-1を、一致する部分があればその位置を返します。よって、n != -1の場合にm_hidden_flags[i] = falseとし、ラジオボタンを表示するようにすれば、キーワードと一致したラジオボタンのみを表示できます。また、n == 0とすれば、キーワードがラベルの先頭から一致した場合のみ表示するようにできます。
//先頭から一致
//if (n == 0)
//{
// m_hidden_flags[i] = false;
//}
//どこかしら一致
if (n != -1)
{
m_hidden_flags[i] = false;
}
ラジオボタン
以前作成したラジオボタンへ表示、非表示の機能を追加したラジオボタンのScriptです。
public class CustomEditorGUI
{
public static int RadioButton(string[] labels, int selected, bool[] hidden_flags, GUIStyle style_label, GUIStyle style_radio)
{
Event event_current = Event.current;
Vector2 mouse_pos = event_current.mousePosition;
int length = labels.Length;
int margin = 3;
int button_size = style_radio.normal.background.width;
for (int i = 0; i < length; i++)
{
if (hidden_flags[i] == true) continue;
int control_id = GUIUtility.GetControlID(FocusType.Keyboard);
Rect rect_control = GUILayoutUtility.GetRect(GUIContent.none, style_radio);
Rect rect_button = new Rect(rect_control) { width = button_size };
Rect rect_label = new Rect(rect_control) { x = rect_button.width + margin, width = rect_control.width - rect_button.width - margin };
EditorGUI.PrefixLabel(rect_label, control_id, new GUIContent(labels[i]), style_label);
//radio button
bool is_on = false;
if (event_current.type == EventType.Repaint)
{
if (i == selected)
{
is_on = true;
}
style_radio.Draw(rect_button, GUIContent.none, control_id, is_on);
}
if (event_current.type == EventType.MouseDown)
{
if (rect_control.Contains(mouse_pos))
{
selected = i;
GUIUtility.keyboardControl = control_id;
HandleUtility.Repaint();
}
}
}
return selected;
}
}
表示するか非表示にするかをhidden_flagsによって受け取ります。そして、非表示とすることを指定されていた場合(true)、continueによりfor文の処理を飛ばすことで非表示にしています。
if (hidden_flags[i] == true) continue;
実行結果
以上のScriptを実行した結果は以下の通りです。キーワードによりラジオボタンの表示、非表示ができていることが分かります。
-
前の記事
MaterialのShaderプロパティーを表示 その2(Editor拡張) 2020.10.22
-
次の記事
ObjectFieldの作成(Editor拡張) 2020.11.23

コメントを書く