当前位置: 首页 > article >正文

【学写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);
}
代码介绍
  1. 继承关系:
  • RS_Undoable 继承自 RS_Flags,因此可以使用 RS_Flags 中的标志位管理功能。
  1. 成员函数:
  • 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,表示对象已被撤销。

关键点解析
  1. 撤销状态管理:
  • 使用 RS2::FlagUndone 标志位来表示对象的撤销状态。

  • 当标志位被设置时,对象处于撤销状态(不可见);当标志位被清除时,对象处于正常状态(可见)。

  1. 通知机制:
  • 通过纯虚函数 undoStateChanged(bool undone),子类可以接收到撤销状态变化的通知。

  • 子类可以实现此函数以更新对象的可见性或执行其他操作。

  1. 运行时类型识别(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);
}
代码解析
  1. get_undo_state(&self):
  • 返回当前对象的撤销状态(true 表示已撤销,false 表示未撤销)。
  1. set_undo_state(&mut self, undone: bool):

设置对象的撤销状态为 undone。

  1. change_undo_state(&mut self):
  • 切换对象的撤销状态。

  • 调用 set_undo_state(!get_undo_state()) 切换状态。

  • 调用 undo_state_changed(get_undo_state()) 通知状态变化。

  1. undo_state_changed(&mut self, undone: bool):
  • 当撤销状态变化时调用。

  • 子类可以实现此方法以响应状态变化(例如更新对象的可见性)。


http://www.kler.cn/a/582426.html

相关文章:

  • 【Linux内核系列】:文件系统
  • 一文说清docker及docker compose的应用和部署
  • UI显示不出来问题(有的能显示出来一个方法,有的数据显示不出来另一个方法),多次尝试无果
  • CSPM-3级国标认证,项目管理如何成为组织变革的核心引擎?
  • 裂变营销策略在“开源链动2+1模式AI智能名片S2B2C商城小程序”中的应用探索
  • JavaScript性能优化实战:让你的Web应用飞起来
  • AI+API引爆数据分析:BI已成过去?
  • 【漫话机器学习系列】133.决定系数(R²:Coefficient of Determination)
  • 微电网管理 实现分布式能源的智能调度和管理
  • ROS——节点、工作空间、功能包
  • 【18】单片机编程核心技巧:变量赋值与高位填充机制
  • 每日一题——两两交换链表中的节点
  • 【实战ES】实战 Elasticsearch:快速上手与深度实践-8.1.1基于ES的语义搜索(BERT嵌入向量)
  • Spring Boot集成EasyExcel
  • 自学Java-Java高级技术(单元测试、反射、注解、动态代理)
  • wps word 正文部分段前段后间距调整无用
  • libpcap捕捉过滤wifi beacon包解析国标飞行器drone id报文
  • 【python-uiautomator2】手机上的ATX应用界面报错问题处理:无法提供服务,非am instrument启动
  • Percona XtraBackup8.0备份实例
  • 如何保证Redis与MySQL双写一致性?分布式场景下的终极解决方案