前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Unity Development Memo - 开发备忘录

Unity Development Memo - 开发备忘录

作者头像
CoderZ
发布2023-08-21 19:25:41
1900
发布2023-08-21 19:25:41
举报

简介

Development Memo工具目前包含Notes开发笔记和Todos开发任务待办两部分,这里以待办Tab页为例简单介绍工具的使用:

TODO待办

  • Sort排序方式:
    • Name ↓:按照待办项标题顺序排列;
    • Name ↑:按照待办项标题倒叙排列;
    • Created Time ↓:按照待办项创建时间顺序排列;
    • Created Time ↑:按照待办项创建时间倒叙排列。
  • Search检索: 列表会根据待办项标题是否包含检索框中输入的内容进行过滤,代码示意:
代码语言:javascript
复制
if (!string.IsNullOrEmpty(searchContent) && !todo.title.ToLower().Contains(searchContent.ToLower())) continue;
  • State状态:
    • :待办项已完成;
    • :待办项未完成且已逾期。

是否逾期判断:待办项未完成且当前日期已经超过预计完成日期。(既不是✓也不是!表示正常状态,代表待办项未完成但尚未逾期)。 待办项完成后在当前状态下拉框中将其标记为已完成。

  • • 添加、删除
    • Create New:增加新的待办项;
    • Delete:删除当前选中的待办项。

工具源码已上传至SKFramework框架Package Manager中:

SKFramework PackageManager

实现

待办

代码语言:javascript
复制
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;

using UnityEngine;
using UnityEditor;

namespace SK.Framework
{
    public class TodosTab : IDevelopmentMemoTab
    {
        private readonly DevelopmentMemo window;
        //数据文件路径
        private readonly string dataPath;
        //数据类
        [SerializeField] private TodosTabData data;
        //笔记列表的宽度
        private float listRectWidth = 280f;
        //左右分割线区域
        private Rect splitterRect;
        //是否正在拖拽分割线
        private bool isDragging;
        //列表滚动值
        private Vector2 listScroll;
        //待办详情滚动值
        private Vector2 detailScroll;
        //当前选中的待办项
        private TodoItem currentTodo;
        //标题的最大长度
        private const int titleLengthLimit = 20;
        //检索内容
        private string searchContent;

        public TodosTab(DevelopmentMemo window)
        {
            this.window = window;
            //拼接数据文件路径
            dataPath = Path.GetFullPath(".").Replace("\\", "/") + "/Library/DevelopmentMemo_Todos.dat";
            //判断文件是否存在
            if (File.Exists(dataPath))
            {
                using (FileStream fs = File.Open(dataPath, FileMode.Open))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    //反序列化
                    var deserialize = bf.Deserialize(fs);
                    if (deserialize != null)
                        data = deserialize as TodosTabData;
                    //反序列化失败 数据为空
                    if (data == null)
                    {
                        //删除无效数据文件 并初始化一个新的数据类
                        File.Delete(dataPath);
                        data = new TodosTabData();
                    }
                    else
                    {
                        //默认按照创建时间排序
                        data.todos = data.todos.OrderBy(m => m.createdTime).ToList();
                    }
                }
            }
            else data = new TodosTabData();

        }

        public void OnGUI()
        {
            OnTopGUI();
            OnBodyGUI();
        }
        private void OnTopGUI()
        {
            GUILayout.BeginHorizontal();
            //排序按钮
            GUI.enabled = data != null && data.todos.Count > 0;
            if (GUILayout.Button("Sort", EditorStyles.toolbarDropDown, GUILayout.Width(50f)))
            {
                GenericMenu gm = new GenericMenu();
                gm.AddItem(new GUIContent("Name ↓"), false, () => data.todos = data.todos.OrderBy(m => m.title).ToList());
                gm.AddItem(new GUIContent("Name ↑"), false, () => data.todos = data.todos.OrderByDescending(m => m.title).ToList());
                gm.AddItem(new GUIContent("Created Time ↓"), false, () => data.todos = data.todos.OrderBy(m => m.createdTime).ToList());
                gm.AddItem(new GUIContent("Created Time ↑"), false, () => data.todos = data.todos.OrderByDescending(m => m.createdTime).ToList());
                gm.ShowAsContext();
            }
            GUI.enabled = true;
            //检索输入框
            searchContent = GUILayout.TextField(searchContent, EditorStyles.toolbarSearchField);
            //当点击鼠标且鼠标位置不在输入框中时 取消控件的聚焦
            //if (Event.current.type == EventType.MouseDown && !GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition))
            //{
            //    GUI.FocusControl(null);
            //    window.Repaint();
            //}
            GUILayout.EndHorizontal();
        }

        private void OnBodyGUI()
        {
            GUILayout.BeginHorizontal();
            {
                //左侧列表
                GUILayout.BeginVertical(GUILayout.Width(listRectWidth));
                OnLeftGUI();
                GUILayout.EndVertical();

                //分割线
                GUILayout.BeginVertical(GUILayout.ExpandHeight(true), GUILayout.MaxWidth(5f));
                GUILayout.Box(string.Empty, "EyeDropperVerticalLine", GUILayout.ExpandHeight(true));
                GUILayout.EndVertical();
                splitterRect = GUILayoutUtility.GetLastRect();

                //右侧详情
                GUILayout.BeginVertical(GUILayout.ExpandWidth(true));
                OnRightGUI();
                GUILayout.EndVertical();
            }
            GUILayout.EndHorizontal();

            if (Event.current != null)
            {
                //光标
                EditorGUIUtility.AddCursorRect(splitterRect, MouseCursor.ResizeHorizontal);
                switch (Event.current.rawType)
                {
                    //开始拖拽分割线
                    case EventType.MouseDown:
                        isDragging = splitterRect.Contains(Event.current.mousePosition);
                        break;
                    case EventType.MouseDrag:
                        if (isDragging)
                        {
                            listRectWidth += Event.current.delta.x;
                            //限制其最大最小值
                            listRectWidth = Mathf.Clamp(listRectWidth, window.position.width * .3f, window.position.width * .8f);
                            window.Repaint();
                        }
                        break;
                    //结束拖拽分割线
                    case EventType.MouseUp:
                        if (isDragging)
                            isDragging = false;
                        break;
                }
            }
        }

        private void OnLeftGUI()
        {
            //滚动视图
            listScroll = EditorGUILayout.BeginScrollView(listScroll);
            {
                //遍历笔记列表
                for (int i = 0; i < data.todos.Count; i++)
                {
                    var todo = data.todos[i];
                    //如果检索输入框不为空 判断是否符合检索内容
                    if (!string.IsNullOrEmpty(searchContent) && !todo.title.ToLower().Contains(searchContent.ToLower())) continue;
                    GUILayout.BeginHorizontal(currentTodo == todo ? "MeTransitionSelectHead" : "ProjectBrowserHeaderBgTop");
                    GUILayout.Label(todo.title);
                    GUILayout.FlexibleSpace();
                    if (todo.isCompleted) GUILayout.Label("✓");
                    else if (todo.isOverdue) GUILayout.Label("!");
                    GUILayout.EndHorizontal();
                    //鼠标点击选中当前项
                    if (Event.current.type == EventType.MouseDown && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition))
                    {
                        if (currentTodo != todo)
                        {
                            GUI.FocusControl(null);
                            currentTodo = todo;
                            window.Repaint();
                        }
                    }
                }
            }
            EditorGUILayout.EndScrollView();

            GUILayout.FlexibleSpace();

            //创建新的笔记
            if (GUILayout.Button("Create New", EditorStyles.miniButton))
            {
                var note = new TodoItem()
                {
                    title = "New Todo",
                    createdTime = DateTime.Now.ToString(),
                };
                //添加到数据列表
                data.todos.Add(note);
            }
            GUILayout.Space(2.5f);
        }

        private void OnRightGUI()
        {
            if (currentTodo == null) return;

            detailScroll = EditorGUILayout.BeginScrollView(detailScroll);
            //标题
            GUILayout.Label("标题:", EditorStyles.boldLabel);
            GUILayout.BeginHorizontal(EditorStyles.helpBox);
            string newTitle = EditorGUILayout.TextField(currentTodo.title, EditorStyles.label);
            if (newTitle != currentTodo.title)
            {
                //长度限制
                if (newTitle.Length > 0 && newTitle.Length <= titleLengthLimit)
                    currentTodo.title = newTitle;
            }
            GUILayout.FlexibleSpace();
            GUILayout.Label(string.Format("{0}/{1}", currentTodo.title.Length, titleLengthLimit), EditorStyles.miniBoldLabel);
            GUILayout.EndHorizontal();

            //日期
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            GUILayout.Label(currentTodo.createdTime, EditorStyles.miniBoldLabel);
            GUILayout.EndHorizontal();

            //创建人
            GUILayout.Label("创建人:", EditorStyles.boldLabel);
            GUILayout.BeginHorizontal(EditorStyles.helpBox);
            currentTodo.creator = EditorGUILayout.TextField(currentTodo.creator, EditorStyles.label);
            GUILayout.EndHorizontal();
            GUILayout.Space(20f);

            //描述
            GUILayout.Label("待办描述:", EditorStyles.boldLabel);
            currentTodo.description = EditorGUILayout.TextArea(currentTodo.description,
                GUILayout.MaxWidth(window.position.width - listRectWidth - 15f), GUILayout.MinHeight(100f));
            GUILayout.Space(20f);

            //当前状态
            GUILayout.Label("当前状态:", EditorStyles.boldLabel);
            if (GUILayout.Button(currentTodo.isCompleted ? "已完成" : "未完成", "DropDownButton"))
            {
                GenericMenu gm = new GenericMenu();
                gm.AddItem(new GUIContent("未完成"), !currentTodo.isCompleted, () => { currentTodo.isCompleted = false; currentTodo.OverdueCal(); });
                gm.AddItem(new GUIContent("已完成"), currentTodo.isCompleted, () => { currentTodo.isCompleted = true; currentTodo.OverdueCal(); });
                gm.ShowAsContext();
            }
            GUILayout.Space(20f);

            //未完成
            if (!currentTodo.isCompleted)
            {
                EditorGUI.BeginChangeCheck();
                //预计完成日期
                GUILayout.Label("预计完成日期:", EditorStyles.boldLabel);
                GUILayout.BeginHorizontal();
                //年
                if (GUILayout.Button("<", GUILayout.Width(18f)))
                   currentTodo.estimatedCompletedTime = currentTodo.estimatedCompletedTime.AddYears(-1);
                GUILayout.Label(currentTodo.estimatedCompletedTime.Year.ToString(), GUILayout.Width(35f));
                if (GUILayout.Button(">", GUILayout.Width(18f)))
                    currentTodo.estimatedCompletedTime = currentTodo.estimatedCompletedTime.AddYears(1);
                GUILayout.Label("年", GUILayout.Width(20f));
                GUILayout.EndHorizontal();
                //月
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("<", GUILayout.Width(18f)))
                    currentTodo.estimatedCompletedTime = currentTodo.estimatedCompletedTime.AddMonths(-1);
                GUILayout.Label(currentTodo.estimatedCompletedTime.Month.ToString(), GUILayout.Width(35f));
                if (GUILayout.Button(">", GUILayout.Width(18f)))
                    currentTodo.estimatedCompletedTime = currentTodo.estimatedCompletedTime.AddMonths(1);
                GUILayout.Label("月", GUILayout.Width(20f));
                GUILayout.EndHorizontal();
                //日
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("<", GUILayout.Width(18f)))
                    currentTodo.estimatedCompletedTime = currentTodo.estimatedCompletedTime.AddDays(-1);
                GUILayout.Label(currentTodo.estimatedCompletedTime.Day.ToString(), GUILayout.Width(35f));
                if (GUILayout.Button(">", GUILayout.Width(18f)))
                    currentTodo.estimatedCompletedTime = currentTodo.estimatedCompletedTime.AddDays(1);
                GUILayout.Label("日", GUILayout.Width(20f));
                GUILayout.EndHorizontal();
                if (EditorGUI.EndChangeCheck())
                    currentTodo.OverdueCal();
            }

            //删除
            EditorGUILayout.Space();
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("Delete"))
            {
                if (EditorUtility.DisplayDialog("Notice", "Whether to delete the todo item ?", "Confirm", "Cancle"))
                {
                    data.todos.Remove(currentTodo);
                    currentTodo = null;
                    window.Repaint();
                }
            }
            GUILayout.EndHorizontal();
            EditorGUILayout.EndScrollView();
        }

        public void OnDisable()
        {
            try
            {
                //写入数据文件进行保存
                using (FileStream fs = File.Create(dataPath))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    //序列化
                    bf.Serialize(fs, data);
                }
            }
            catch (Exception ex)
            {
                Debug.LogError(ex);
            }
        }
    }
}

笔记

代码语言:javascript
复制
using System;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;

using UnityEngine;
using UnityEditor;

namespace SK.Framework
{
    /// <summary>
    /// 开发笔记Tab页
    /// </summary>
    public class NotesTab : IDevelopmentMemoTab
    {
        private readonly DevelopmentMemo window;
        //数据文件路径
        private readonly string dataPath;
        //数据类
        [SerializeField] private NotesTabData data;
        //笔记列表的宽度
        private float listRectWidth = 280f;
        //左右分割线区域
        private Rect splitterRect;
        //是否正在拖拽分割线
        private bool isDragging;
        //列表滚动值
        private Vector2 listScroll;
        //笔记详情滚动值
        private Vector2 detailScroll;
        //当前选中的笔记
        private NoteItem currentNote;
        //标题的最大长度
        private const int titleLengthLimit = 20;
        //检索内容
        private string searchContent;

        public NotesTab(DevelopmentMemo window)
        {
            this.window = window;
            //拼接数据文件路径
            dataPath = Path.GetFullPath(".").Replace("\\", "/") + "/Library/DevelopmentMemo_Notes.dat";
            //判断文件是否存在
            if (File.Exists(dataPath))
            {
                using (FileStream fs = File.Open(dataPath, FileMode.Open))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    //反序列化
                    var deserialize = bf.Deserialize(fs);
                    if (deserialize != null)
                        data = deserialize as NotesTabData;
                    //反序列化失败 数据为空
                    if (data == null)
                    {
                        //删除无效数据文件 并初始化一个新的数据类
                        File.Delete(dataPath);
                        data = new NotesTabData();
                    }
                    else
                    {
                        //默认按照创建时间排序
                        data.notes = data.notes.OrderBy(m => m.createdTime).ToList();
                    }
                }
            }
            else data = new NotesTabData();
        }

        public void OnGUI()
        {
            OnTopGUI();
            OnBodyGUI();
        }

        private void OnTopGUI()
        {
            GUILayout.BeginHorizontal();
            //排序按钮
            GUI.enabled = data != null && data.notes.Count > 0;
            if (GUILayout.Button("Sort", EditorStyles.toolbarDropDown, GUILayout.Width(50f)))
            {
                GenericMenu gm = new GenericMenu();
                gm.AddItem(new GUIContent("Name ↓"), false, () => data.notes = data.notes.OrderBy(m => m.title).ToList());
                gm.AddItem(new GUIContent("Name ↑"), false, () => data.notes = data.notes.OrderByDescending(m => m.title).ToList());
                gm.AddItem(new GUIContent("Created Time ↓"), false, () => data.notes = data.notes.OrderBy(m => m.createdTime).ToList());
                gm.AddItem(new GUIContent("Created Time ↑"), false, () => data.notes = data.notes.OrderByDescending(m => m.createdTime).ToList());
                gm.ShowAsContext();
            }
            GUI.enabled = true;
            //检索输入框
            searchContent = GUILayout.TextField(searchContent, EditorStyles.toolbarSearchField);
            //当点击鼠标且鼠标位置不在输入框中时 取消控件的聚焦
            //if (Event.current.type == EventType.MouseDown && !GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition))
            //{
            //    GUI.FocusControl(null);
            //    window.Repaint();
            //}
            GUILayout.EndHorizontal();
        }

        private void OnBodyGUI()
        {
            GUILayout.BeginHorizontal();
            {
                //左侧列表
                GUILayout.BeginVertical(GUILayout.Width(listRectWidth));
                OnLeftGUI();
                GUILayout.EndVertical();

                //分割线
                GUILayout.BeginVertical(GUILayout.ExpandHeight(true), GUILayout.MaxWidth(5f));
                GUILayout.Box(string.Empty, "EyeDropperVerticalLine", GUILayout.ExpandHeight(true));
                GUILayout.EndVertical();
                splitterRect = GUILayoutUtility.GetLastRect();

                //右侧详情
                GUILayout.BeginVertical(GUILayout.ExpandWidth(true));
                OnRightGUI();
                GUILayout.EndVertical();
            }
            GUILayout.EndHorizontal();

            if (Event.current != null)
            {
                //光标
                EditorGUIUtility.AddCursorRect(splitterRect, MouseCursor.ResizeHorizontal);
                switch (Event.current.rawType)
                {
                    //开始拖拽分割线
                    case EventType.MouseDown:
                        isDragging = splitterRect.Contains(Event.current.mousePosition);
                        break;
                    case EventType.MouseDrag:
                        if (isDragging)
                        {
                            listRectWidth += Event.current.delta.x;
                            //限制其最大最小值
                            listRectWidth = Mathf.Clamp(listRectWidth, window.position.width * .3f, window.position.width * .8f);
                            window.Repaint();
                        }
                        break;
                    //结束拖拽分割线
                    case EventType.MouseUp:
                        if (isDragging)
                            isDragging = false;
                        break;
                }
            }
        }

        private void OnLeftGUI()
        {
            //滚动视图
            listScroll = EditorGUILayout.BeginScrollView(listScroll);
            {
                //遍历笔记列表
                for (int i = 0; i < data.notes.Count; i++)
                {
                    var note = data.notes[i];
                    //如果检索输入框不为空 判断是否符合检索内容
                    if (!string.IsNullOrEmpty(searchContent) && !note.title.ToLower().Contains(searchContent.ToLower())) continue;

                    GUILayout.BeginHorizontal(currentNote == note ? "MeTransitionSelectHead" : "ProjectBrowserHeaderBgTop");
                    GUILayout.Label(note.title);
                    GUILayout.EndHorizontal();
                    //鼠标点击选中当前项
                    if (Event.current.type == EventType.MouseDown && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition))
                    {
                        if (currentNote != note)
                        {
                            GUI.FocusControl(null);
                            currentNote = note;
                            window.Repaint();
                        }
                    }
                }
            }
            EditorGUILayout.EndScrollView();

            GUILayout.FlexibleSpace();

            //创建新的笔记
            if (GUILayout.Button("Create New", EditorStyles.miniButton))
            {
                var note = new NoteItem()
                {
                    title = "New Note",
                    createdTime = DateTime.Now.ToString(),
                };
                //添加到数据列表
                data.notes.Add(note);
            }
            GUILayout.Space(2.5f);
        }

        private void OnRightGUI() 
        {
            if (currentNote == null) return;

            detailScroll = EditorGUILayout.BeginScrollView(detailScroll);
            //标题
            GUILayout.Label("标题:", EditorStyles.boldLabel);
            GUILayout.BeginHorizontal(EditorStyles.helpBox);
            string newTitle = EditorGUILayout.TextField(currentNote.title, EditorStyles.label);
            if (newTitle != currentNote.title)
            {
                //长度限制
                if (newTitle.Length > 0 && newTitle.Length <= titleLengthLimit)
                    currentNote.title = newTitle;
            }
            GUILayout.FlexibleSpace();
            GUILayout.Label(string.Format("{0}/{1}", currentNote.title.Length, titleLengthLimit), EditorStyles.miniBoldLabel);
            GUILayout.EndHorizontal();

            //日期
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            GUILayout.Label(currentNote.createdTime, EditorStyles.miniBoldLabel);
            GUILayout.EndHorizontal();

            //作者
            GUILayout.Label("作者:", EditorStyles.boldLabel);
            GUILayout.BeginHorizontal(EditorStyles.helpBox);
            currentNote.author = EditorGUILayout.TextField(currentNote.author, EditorStyles.label);
            GUILayout.EndHorizontal();
            GUILayout.Space(20f);


            //内容
            GUILayout.Label("内容:", EditorStyles.boldLabel);
            currentNote.content = EditorGUILayout.TextArea(currentNote.content, 
                GUILayout.MaxWidth(window.position.width - listRectWidth - 15f), GUILayout.MinHeight(200f));

            //删除
            EditorGUILayout.Space();
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("Delete"))
            {
                if (EditorUtility.DisplayDialog("Notice", "Whether to delete the note ?", "Confirm", "Cancle"))
                {
                    data.notes.Remove(currentNote);
                    currentNote = null;
                    window.Repaint();
                }
            }
            GUILayout.EndHorizontal();
            EditorGUILayout.EndScrollView();
        }

        public void OnDisable()
        {
            try
            {
                //写入数据文件进行保存
                using (FileStream fs = File.Create(dataPath))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    //序列化
                    bf.Serialize(fs, data);
                }
            }
            catch (Exception ex)
            {
                Debug.LogError(ex);
            }
        }
    }
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 当代野生程序猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
  • 实现
    • 待办
      • 笔记
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档