---
# System prepended metadata

title: HW5 使用命令物件 (Command Object) 撤銷
tags: [使用者介面程式設計]

---

# HW5 使用命令物件 (Command Object) 撤銷


請訪問[此連結](https://classroom.github.com/a/JJ3jryix)以取得 HW5 起始程式碼，並遵照 `readme.md` 執行檔案，若有遇到任何問題請聯繫助教。

請在 **<font color="#f00">2023 年 05 月 10 日下午 23:59 (UTC+8)</font>** 之前將此文件連同程式碼提交至所開設的 repo。我們將以截止時間前最後一次提交的內容作為批改項目。


## 作業概述

在此作業中，請使用使用線性取消模型 (linear undo model) 將撤銷功能添加到作業三的圖形編輯器中，該模型使用命令物件模式 (Command Object pattern) 實現。我們在 React 中創建了一個編輯器的參考實作，**您需要使用它**。

請注意，此版本刪除了 Canvas 圖層和全部刪除按鈕（並且不包括線條繪製），因為我們認為這些對學習撤銷沒有幫助。

與之前的作業一樣，你**可以**使用某些函式庫，包含React,  [Create-React-App](https://create-react-app.dev/docs/getting-started/), [ReactRouter](https://reactrouter.com/en/6.9.0), [ReactStrap](https://www.npmjs.com/package/reactstrap), [React Context API](https://legacy.reactjs.org/docs/context.html)（這是一個較新的 API，正在成為跨組件傳遞資料的流行方式）。我們在按鈕上使用的圖標來自 [react-icons](https://react-icons.github.io/react-icons/)，如果你預計實作右方額外命令物件列表的加分作業，那麼 [react-scroll-to-bottom](https://www.npmjs.com/package/react-scroll-to-bottom) 可在此派上用場。

然而，你**不可以**使用函式庫實作命令對像模式，如果想使用非上面提及之函式庫，請寄信詢問助教。

此作業的使用者界面與作業三基本相同，差異在於新增了撤消和重做按鈕，並刪除了 Canvas 圖層、全部刪除功能與線條繪製。


## 可用資源

Michael Liu 和 Clara Cook (HCII 課程助教) 已實作作業三內容，請點選[此連結](https://classroom.github.com/a/JJ3jryix)以取得該內容的起始程式碼。**請注意：你必須修改起始程式碼的基本實作，而不僅僅是新增文件，具體來說，請在創建、修改和刪除物件的所有位置編輯程式碼，以便使用命令物件來執行這些操作，並使物件可被撤銷。**

我們已針對實現命令物件的方法創建一組JavaScript 規範文件，以及有關更改填充顏色的命令物件，但尚不能真正作用的草稿，請應該使用這些來構建命令物件和線性撤消。

起始程式碼包含以下文件：

* `hw5-undo-using-command-objects-YOURID/` - 此資料夾包含所有使用 React 實作圖形編輯器的相關文件，你必須基於這些程式碼，並新增撤銷處理功能。此資料夾還包含：
    * `CommandObject.js` 和 ``ChangeFillColorCommandObject.js`` - 這些文件位於子目錄 hw5-undo-using-command-objects-YOURID/src/shared/commandObjects/，提供與實作命令物件相關的結構和範例。

此外，請瀏覽以下圖片和影片，以了解具體規範：

* [HW5-example.mp4](https://www.cs.cmu.edu/~bam/uicourse/05631fall2022/HW5/HW5-example.mp4) - 一段說明作業五應有的模樣與事件的影片
* [HW5-base.png](https://www.cs.cmu.edu/~bam/uicourse/05631fall2022/HW5/HW5-base.png) - 從基本版本開始的界面示意圖
* [HW5-command-list.png](https://www.cs.cmu.edu/~bam/uicourse/05631fall2022/HW5/HW5-command-list.png) - 執行幾項操作，並撤銷三個命令後的界面示意圖



## 詳細要求


請實作以下要求，並參考前段所附之影片與圖片，以獲得滿分。如果作業敘述上有些模糊，或是你的實作可能會偏離定義行為，請以信件或 NTU COOL 詢問助教。

* 所有的操作都可以如同尋常程式一般是**可撤銷**的，類似於 PowerPoint 撤銷的運作機制。詳細資訊請參考上章節中的影片。當撤銷執行後，需恢復繪圖並選取受影響物件。
* 使用者必須能**連續執行多個撤銷操作**，直到回到初始狀態（線性撤銷模型）。
* 在撤銷執行後，使用者可使用**重做按鍵**來取消撤銷行為，並讓繪圖回復到撤銷發生前的狀態。可執行的重做次數應和撤銷次數相同。
* 如果使用者在執行一個以上的撤銷操作後，**執行並非撤銷或重做的其他操**作，那麼**之前撤銷的操作將不可被重做**(這是線性撤銷模型的標準方式)，且新操作應被儲存在撤銷堆疊 (stack)中。
* 請針對每一個操作（創建、刪除、移動物件、更改填充顏色、更改線條顏色、更改線條寬度），**定義從 `CommandObject` 擴展 (extend) 的類別 (Class)**
* 當撤銷跟重做按鈕不可被使用時，他們應該是灰色的
    * 當沒有任何先前操作時，撤銷按鈕應該變灰
    * 當沒有任何已撤銷操作可重做時，重做按鈕應該變灰
* 可撤銷的操作包含：
    * **創建（圖形繪製）**：
        * 撤銷後會使該物件消失，且**不選取**任何物件。（注意：此部分與 PowerPoint 撤銷後會選取先前物件的實作不同)
        * 重做創建操作後，在任何情形中都將**自動選取**重新建立的物件。
    * **更改填充顏色或邊框顏色**：
        * 執行撤銷後將使顏色恢復到更改前狀態。
        * 如果使用者在選取物件後多次更改顏色，這些動作都應該可單獨被撤銷。
        * 受撤銷動作影響的物件應被選取，且操作面板上的顏色區塊應呈現當前值。
    * **更改邊框寬度**：
        * 即使在拖曳操作面板上的邊框寬度滑塊 (slider) 時經過多個數值，在執行重做時僅需回復到拖曳滑塊前。舉例來說，如果拖曳滑塊前所選取物件邊框寬度為 3px，那麼按下滑鼠不放，並從 3px 拖曳到 10px 再回到 2px 後放開滑鼠，由於最終僅執行了將邊框由 3px 調整為 2px 的操作，因此點擊撤銷按鈕將使選取物件邊框變回 3px。
        * 如果使用者連續兩次更改邊框寬度，那麼這兩次修改將可被單獨撤銷。
        *  受撤銷操作影響的物件應被選取，且操作面板上的邊框寬度區塊應呈現當前值。
    * **移動**：
        * 撤銷移動將使物件回復到先前的位置。如果更改邊框寬度一樣，只有按下滑鼠前與放開滑鼠後的物件位置，可被撤銷或重做按鈕影響。
        * 受撤銷操作影響的物件應被選取。
    * **刪除**：
        * 撤銷刪除將使物件重新出現並呈現被選取狀態，而重做將使物件再次消失並使圖層上沒有任何東西被選取。
        * 注意：使用者可以在撤銷刪除 (A) 後手動選擇其他物件 (B) ，然後執行重做刪除。在這種情況下，重作刪除時仍需刪除原始物件 (A) 
* 注意：**單擊以選取其他物件是不可撤銷的行為**。也就是說，不可以為「選取物件」與「選取背景已取消所有選取」分配命令物件，也不可加入撤銷堆疊。
* 如果選取的物件因撤銷或重做而改變，則**操作面板的顏色、邊框寬度、邊框顏色...等值，應與改變後的選取物件符合**。
* 同樣的，**在更改繪圖模式（箭頭、矩形或圓形）後，或者在沒有選取任何物件時，更改當前顏色或邊框寬度，也同樣是不可撤銷的**，因此不可加入撤銷堆疊。然而，如果選取物件因為其他撤銷／重做行為發生變化，那麼操作面板狀態也會受影響。
* 由於**中止操作行為**（使用 ESC 停止當前操作）不改變任何狀態，因此**不應影響撤銷堆疊**。
* **在執行撤銷或重做後，請始終更改為選取模式**。舉例來說，如果使用者在選取模式下選取物件、改變顏色、將模式改為矩形模式，最後執行撤銷，在這種情形中，模式應該改回選取模式，以便選取顏色更改操作被撤銷的物件。即便撤銷創建或重做刪除時不需要選取任何物件，仍建議在任何情形中，皆在撤銷/重做後改為選取模式。

## 加分項目
* **對所有與線條相關的操作提供撤銷/重做功能（最多在此作業中+5分）**
    * 我們不小心遺漏作業 3 中的線條繪製與編輯，由於本作業不需要，因此請註釋掉線條相關程式碼，或者也可以新增對線條繪製、刪除和編輯的撤銷/重做功能，以獲得高達 5 分的額外分數。

* **撤銷、重作鍵盤快捷鍵實現 （每個+1，最多在本作業中+2分）**
    * 將 ctrl+z (或 command+z)作為撤銷快捷鍵
    * 將 ctrl+y (或 command+shift+z)作為重做快捷鍵
    
* **增加命令列表區塊（最多在此作業中+5分）**
    * 在繪圖區右側添加命令列表區塊，如同 [HW5-command-list.png](https://www.cs.cmu.edu/~bam/uicourse/05631fall2022/HW5/HW5-command-list.png) 和 [HW5-example.mp4](https://www.cs.cmu.edu/~bam/uicourse/05631fall2022/HW5/HW5-example.mp4)所顯示
    * 若想獲取完整加分，請令該區塊顯示：
        * 當前操作
        * 應該刪除「由於撤消之後進行新操作，而不可被重做」的操作
        * 將未完成（撤銷且可被重做）的操作顯示為灰色
* **為所有編輯操作添加重複操作 （最多在此作業中+15分）**
    * 重做按鈕上的文字與 icon 應適時改變為重複
    * 若當前有選取物件，則可將更改顏色與邊框寬度的操作，針對該物件進行重複套用。若無當前選取物件，則重複操作則不能被使用。
    * 在執行重複時，必須重複創建命令物件
    * 重複刪除應該刪除當前選取的物件
    * 不能對移動操作進行重複
    * 重複操作應出現在撤銷堆疊中，以便使用正常方式撤銷。如果你實作了繪圖區右側的命令列表區塊，則其應該有個合理的名字，例如 "repeat of change line border color to #ea3323"
    * 重複按鈕在不能使用時應該是灰色的。例如：移動操作。
* **添加四個輕推 (nudge) 移動操作 （每個方向 +2 分，最多在此作業中 +8 分）** 
    * 在點擊鍵盤上、下、左、右鍵時，將所選物件朝該方向移動幾個像素。且其是可被撤銷的。
    * 如同 PowerPoint 的實作一般，要取得所有加分，**請將多個同方向的輕推操作合併成一個可撤銷操作**。
* **使用直接逆模型 (direct inverse model) 添加對選擇性撤消和選擇性重複的支持（最多在此作業中 +15 分）**

    * 這個加分項目**需要你先實現上述的命令列表區塊加分項和重複加分項**，然後還要支持：
        * 通過點擊命令列表區塊中的命令來選擇它
        * 在左側操作面板部分新增「選擇性撤銷(selective undo)」與「選擇性重複(selective repeat)」按鈕，且僅在可進行這些操作時啟用，否則應標為灰色。
        * 點擊上述按鈕，會使右側命令列表中選取的命令選擇性的撤銷或重複，並將該操作放入撤銷歷史紀錄（因此他應出現在命令列表的末尾），且操作的名稱應該是合理的，例如 "selective repeat of change line border color to #ea3323"


## 評分標準

由於此作業包含多個部分，因此以下為不同功能所占分數，總分為 100 分（不包含加分）。

* 5 分：README 
* 95 分：網頁實作
    * 20 分：整體實作與良好的程式碼風格 (coding style)
    * 75 分：撤銷/重做行為正確
        * 25 分：實作線性撤銷模型
            * 正確從撤銷堆疊 (stack) 中新增或刪除項目（6 分）
            * 執行一個以上的撤銷後，執行並非撤銷或重做的其他操作，那麼之前撤銷的操作不可被重做 （6 分）
            * 可以連續執行多個撤銷 （3 分）
            * 相應的使撤銷和重做按鈕變灰 （2 分）
            * 單擊以選取其他物件是不可撤銷的行為 （2 分）
            * 如選取的物件因撤銷或重做而改變，則操作面板的顏色、邊框寬度、邊框顏色… 等值，應符合改變後選取物件 （2 分）
            * 中止操作行為不改變任何狀態，因此不應影響撤銷堆疊 （2 分）
            * 在執行撤銷或重做後，請始終更改為選取模式 （2 分）
        * 50 分：5 項可撤銷的操作實作（每項 10 分）
            * 創建、更改填充顏色或邊框顏色、更改邊框寬度、移動、刪除


    


## 繳交規範與截止期限

請訪問[此連結](https://classroom.github.com/a/JJ3jryix)以取得 HW5 起始程式碼，並遵照 `readme.md` 執行檔案，若有遇到任何問題請聯繫助教。


除了程式碼之外，請同時在 Repo 中新增 `README` 文件。該文件可以是純文字、markdown（建議）、Microsoft Word 或 pdf 格式。其中應包含：

* 姓名
* 你所實作的網站如何被測試
* 你所實作的加分作業項目，以及如何觸發它
* 認為此作業最難實作的部分與原因
* 其他與軟體設計相關之感興趣內容


請在 **<font color="#f00">2023 年 05 月 10 日下午 23:59 (UTC+8)</font>** 之前將此文件連同程式碼提交至所開設的 repo。我們將以截止時間前最後一次提交的內容作為批改項目。


###### tags: `使用者介面程式設計`