【学写LibreCAD】 4.1 RS_Undoable文件
RS_Undoable 类为 LibreCAD 中的对象提供了撤销和重做功能的核心支持。通过标志位管理和通知机制,子类可以轻松实现撤销状态的管理和响应。这种设计模式在需要支持撤销操作的应用程序中非常常见,例如图形编辑器、CAD 软件等。详细代码如下:
头文件 rs_undoable.h
#ifndef RS_UNDOABLE_H
#define RS_UNDOABLE_H
#include "rs.h"
#include "rs_flags.h"
/**
* Base class for something that can be added and deleted and every
* addition and deletion can be undone.
*
* @see RS_Undo
* @author Andrew Mustun
*/
class RS_Undoable : public RS_Flags {
public:
/**
* Runtime type identification for undoables.
* Note that this is voluntarily. The default implementation
* returns RS2::UndoableUnknown.
*/
virtual RS2::UndoableType undoRtti() const {
return RS2::UndoableUnknown;
}
void changeUndoState();
void setUndoState(bool undone);
bool isUndone() const;
/**
* Can be overwritten by the implementing class to be notified
* when the undo state changes (the undoable becomes visible / invisible).
*/
virtual void undoStateChanged(bool undone) = 0;
};
#endif
源文件 rs_undoable.cpp
#include "rs_undoable.h"
#include "rs_undocycle.h"
/**
* The undoable thing gets activated if it was undone and
* deactivated otherwise.
*/
void RS_Undoable::changeUndoState() {
toggleFlag(RS2::FlagUndone);
undoStateChanged(isUndone());
}
/**
* Undoes or redoes an undoable.
*/
void RS_Undoable::setUndoState(bool undone) {
if (undone) {
setFlag(RS2::FlagUndone);
} else {
delFlag(RS2::FlagUndone);
}
undoStateChanged(isUndone());
}
/**
* Is this entity in the Undo memory and not active?
*/
bool RS_Undoable::isUndone() const {
return getFlag(RS2::FlagUndone);
}
代码介绍
- 继承关系:
- RS_Undoable 继承自 RS_Flags,因此可以使用 RS_Flags 中的标志位管理功能。
- 成员函数:
-
undoRtti():
- 用于运行时类型识别(RTTI)。
- 函数仅标记了Entity类对象,用于rs_document类的removeUndoable函数与rs_undocycle类的std::ostream& operator <<函数。
-
rust实现中,该函数放Entity类处理。
-
changeUndoState():
- 切换撤销状态(即从撤销到重做,或从重做到撤销)。
- 调用 toggleFlag(RS2::FlagUndone) 切换标志位。
- 调用 undoStateChanged(isUndone()) 通知子类状态变化。
-
setUndoState(bool undone):
-
设置撤销状态。
-
如果 undone 为 true,则设置 RS2::FlagUndone 标志位;否则清除该标志位。
-
调用 undoStateChanged(isUndone()) 通知状态变化。
-
-
isUndone() const:
-
检查当前对象是否处于撤销状态。
-
返回 true 表示对象已被撤销(不可见),返回 false 表示对象处于正常状态(可见)。
-
-
undoStateChanged(bool undone):
-
纯虚函数,子类必须实现。
-
当撤销状态发生变化时调用,通知子类对象的状态变化(例如对象的可见性变化)。
-
-
isUndone():
-
返回 RS2::FlagUndone 标志位的当前状态。
-
如果标志位被设置,则返回 true,表示对象已被撤销。
关键点解析
- 撤销状态管理:
-
使用 RS2::FlagUndone 标志位来表示对象的撤销状态。
-
当标志位被设置时,对象处于撤销状态(不可见);当标志位被清除时,对象处于正常状态(可见)。
- 通知机制:
-
通过纯虚函数 undoStateChanged(bool undone),子类可以接收到撤销状态变化的通知。
-
子类可以实现此函数以更新对象的可见性或执行其他操作。
- 运行时类型识别(RTTI):
- undoRtti() 函数提供了运行时类型识别的功能,子类可以重写此函数以返回具体的类型。
rust实现
我们可以通过 trait 来实现类似的功能。考虑undoRtti()函数使用数量有限,不实现该功能; isUndone()函数需要通过get_undo_state(&self)函数间接实现;撤销状态在具体结构中实现。相关代码如下:
// src/engine/undoable.rs
pub trait Undoable {
/// 获得撤销状态
fn get_undo_state(&self) -> bool;
/// 设置撤销状态
fn set_undo_state(&mut self, undone: bool);
/// 切换撤销状态
fn change_undo_state(&mut self){
set_undo_state(!get_undo_state());
undo_state_changed(get_undo_state());
}
/// 当撤销状态变化时调用
fn undo_state_changed(&mut self, undone: bool);
}
代码解析
- get_undo_state(&self):
- 返回当前对象的撤销状态(true 表示已撤销,false 表示未撤销)。
- set_undo_state(&mut self, undone: bool):
设置对象的撤销状态为 undone。
- change_undo_state(&mut self):
-
切换对象的撤销状态。
-
调用 set_undo_state(!get_undo_state()) 切换状态。
-
调用 undo_state_changed(get_undo_state()) 通知状态变化。
- undo_state_changed(&mut self, undone: bool):
-
当撤销状态变化时调用。
-
子类可以实现此方法以响应状态变化(例如更新对象的可见性)。