/*!
@~chinese
@file dabstractdialog.h
@ingroup dtkwidget
@class Dtk::Widget::DAbstractDialog
@brief 可以使用 DAbstractDialog 类创建符合 DDE 风格的对话框窗口.
@details 对话框是一个用于供用户进行短暂周期的任务交互的顶层窗体。 DDialogs 对话框可以是模态的或非模态的。 对话框可以提供一个 return "返回值", 并且对话框可以拥有 default "默认按钮"。
@note 请注意 DAbstractDialog (以及其他继承自 QDialog 的对话框)对构造时传入的 parent 父组件的行为和其他 Qt 组件或 DTK 组件不同。一个对话框总是一个顶层控件(top-level widget),但如果它有一个父组件 则对话框的默认位置将会位于其父组件的正中央,并共用其父控件的任务栏入口。
@section 模态与非模态相关介绍
@subsection modal 模态对话框
    一个 {模态} (modal)对话框可以阻止对模态对话框之外的原可见窗体的操作,如请求用户输入文件名的对话框或是对应用程序本身进行设置的对话框就常是模态对话框。
    模态对话框可以是`Qt::ApplicationModal` "应用模态" 的（默认）,也可以是 `Qt::WindowModal` "窗体模态" 的。
    当应用模态对话框出现后,用户必须完成与对话框的交互并关闭对话框才能继续与应用的其他窗体进行交互。<br>
    窗体模态对话框则仅仅阻止用户与这个对话框的父窗体进行交互而不影响这个父窗体之外的其他窗体。<br>
    显示模态对话框的常见做法是调用`exec()` 。当对话框被用户关闭时,`exec()` 会提供一个有用的return "返回值" 。
    通常,需要关闭一个对话框并使其返回期望的值时,我们可以把默认按钮,如 `OK` 确认按钮连接到 `accept()` 槽,并把  `Cancel` 取消按钮连接到`reject()` 槽。当然,也可以调用 `done()` 槽并传递 `Accepted` 或是 `Rejected `达到相同目的。<br>
    另一个可行方案是调用`setModal(true)`或 `setWindowModality()`, 然后调用 `show()`。而区别于`exec()`的是, `show()` 将立即交回控制权给调用者。
    对于类似显示进度条的应用场景,如需限定用户只能与对话框交互(比如,允许取消一个执行时间过长的操作),此时 setModal(true) 就很有用处。<br>
@subsection modeless 非模态对话框
    一个 {非模态}(modeless)对话框表示其对话框本身的操作和该应用的其他窗口互相独立互不影响。
    例如文字处理程序中的“查找文字”功能通常是非模态的,以便用户同时操作对话框和应用程序窗口
    非模态对话框通过调用 show() 使其显示, 其会将控制权立即返回给调用者<br>
    如果在隐藏对话框后调用 `QWidget::show()` `show()` ,对话框将显示在其原本所在的位置。若要记住用户调整对话框位置后的位置,
    需要在`QWidget::closeEvent()` `closeEvent()`中保存窗体位置并在显示对话框前移动对话框到所保存的位置。
@subsection default 默认按钮
    对话框的 **默认** 按钮是指当用户直接按下回车(Enter / Return)键时所会被按下的按钮。用以表明用户接受了对话框的某些操作并想要关闭对话框。对于 QDialog 可以使用`QPushButton::setDefault()`, `QPushButton::isDefault()`和 `QPushButton::autoDefault()`
    来设置或调整一个对话框的默认按钮。
@subsection escapekey 退出(Escape)键
    如果用户在对话框出现后按下了 Esc 键, 将会触发 `QDialog::reject()`并导致窗体被关闭。 QCloseEvent "关闭事件"
    不可以是`QEvent::ignore()`"忽略事件" .
@subsection return 返回值 (模态对话框)
    模态对话框通常伴随返回值一同使用。例如用来标识判断用户是按下了  OK 确认按钮 还是 Cancel 取消按钮。
    对话框可以通过调用`accept()`或 `reject()` 槽来关闭, `exec()` 则会根据实际情况返回 `Accepted` 或 `Rejected` 。
    如果对话框没有被销毁,也可以通过`result()`得到对话框的返回值。

    若要修改对话框的关闭行为,你可以重新实现`accept()`, `reject()` 或 `done()` 。而`QWidget::closeEvent()``closeEvent()`仅当你需要记住对话框位置或是重载标准的关闭行为时才应使用
@sa DDialog, QDialog

@enum Dtk::Widget::DAbstractDialog::DisplayPosition
@brief 对话框显示位置
@var Dtk::Widget::DAbstractDialog::DisplayPosition Dtk::Widget::DAbstractDialog::Center
@brief 在屏幕中央显示此对话框
@var Dtk::Widget::DAbstractDialog::DisplayPosition Dtk::Widget::DAbstractDialog::TopRight
@brief 在屏幕的右上方显示此对话框

@fn Dtk::Widget::DAbstractDialog::DAbstractDialog(QWidget *parent = nullptr)
@brief 构造一个DAbstractDialog实例
@param[in] parent 父对象

@fn Dtk::Widget::DAbstractDialog::DAbstractDialog(bool blurIfPossible, QWidget *parent = nullptr)
@brief 构造一个 DAbstractDialog 实例
@sa DAbstractDialog(QWidget *parent = nullptr)
@param[in] parent 父对象
@param[in] blurIfPossible 决定要不要开启窗口背景模糊

@property DisplayPosition Dtk::Widget::DAbstractDialog::displayPosition()
@brief 获取对话框显示位置
@return 返回坐标

@fn void Dtk::Widget::DAbstractDialog::setDisplayPosition(DisplayPosition displayPosition)
@brief 设置对话框显示位置
@sa DAbstractDialog::displayPosition()

@fn void Dtk::Widget::DAbstractDialog::move(const QPoint &pos)
@brief 将窗口移动到指定坐标

@fn void Dtk::Widget::DAbstractDialog::move(int x, int y)
@brief 将窗口移动到指定坐标
@sa DAbstractDialog::move(const QPoint &pos)

@fn void Dtk::Widget::DAbstractDialog::setGeometry(const QRect &rect)
@brief 构造一个矩形

@fn void Dtk::Widget::DAbstractDialog::moveToCenter()
@brief 将对话框移动至屏幕中央或其父控件的中央

@fn void Dtk::Widget::DAbstractDialog::moveToTopRight()
@brief 将对话框移动至屏幕右上角或其父控件的右上角

@fn void Dtk::Widget::DAbstractDialog::moveToTopRightByRect(const QRect &rect)
@brief 移动对话框到给定`rect`区域的右上角。`rect`是移动所需要参照的`QRect`位置。

@fn void Dtk::Widget::DAbstractDialog::setDisplayPosition(DAbstractDialog::DisplayPosition displayPosition)
@brief 设置对话框的显示位置 displayPosition 要显示到的位置

@fn void Dtk::Widget::DAbstractDialog::moveToCenterByRect(const QRect &rect)
@brief 移动对话框到给定`rect`区域的中央。`rect`是移动对话框要参照的`QRect`区域

@fn void Dtk::Widget::DAbstractDialog::mousePressEvent(QMouseEvent *event)
@brief 对话框的鼠标点击事件
@sa QMouseEvent

@fn void Dtk::Widget::DAbstractDialog::mouseReleaseEvent(QMouseEvent *event)
@brief 对话框的鼠标释放事件
@sa QMouseEvent

@fn void Dtk::Widget::DAbstractDialog::mouseMoveEvent(QMouseEvent *event)
@brief 对话框的鼠标移动事件
@sa QMouseEvent

@fn void Dtk::Widget::DAbstractDialog::resizeEvent(QResizeEvent *event)
@brief 窗口大小改变事件
@sa QResizeEvent
@warning  不要在resizeEvent中改变窗口geometry,可能会导致以下问题.在双屏开启不同缩放比时:<br>
    屏幕A缩放为1,屏幕B缩放为2。窗口初始在屏幕B上,此时大小为 100x100,则其缩放
    后的真实大小为200x200,由于窗口管理器会对未设置过位置的窗口自动布局,接下来
    窗口可能会因为位置改变而被移动到屏幕A上,则此对话框的大小将变化为 200x200,
    触发了resize事件,紧接着又会尝试将窗口位置更新到鼠标所在屏幕的中心,如果鼠标
    所在屏幕为B,则在移动窗口位置时又会根据B的缩放比重新设置窗口大小,窗口将变为：
    400x400,将形成一个循环。。。

@fn void Dtk::Widget::DAbstractDialog::showEvent(QShowEvent *event)
@brief 窗口显示事件,如果收到过鼠标移动事件不再使用自动布局
@sa QShowEvent

@fn void Dtk::Widget::DAbstractDialog::sizeChanged(QSize size)
@brief 窗口大小发生改变

*/
