diff --git a/Qt/bridge/Qt_Event_Adapter.h b/Qt/bridge/Qt_Event_Adapter.h index 5243bde..f059a41 100644 --- a/Qt/bridge/Qt_Event_Adapter.h +++ b/Qt/bridge/Qt_Event_Adapter.h @@ -1,26 +1,21 @@ #pragma once -#include "Core2/event/Event.h" +#include "render_2D/event/Event.h" #include #include #include #include #include - namespace renderive { - struct Qt_Event_Adapter { static Pointer_Event to_pointer_event(const QMouseEvent* qt_event, Event_Type type); static Wheel_Event to_wheel_event(const QWheelEvent* qt_event); static Key_Event to_key_event(const QKeyEvent* qt_event, Event_Type type); static Resize_Event to_resize_event(const QResizeEvent* qt_event); - static PointF to_pointf(const QPointF& p); static Size to_size(const QSize& s); - static Mouse_Button to_mouse_button(Qt::MouseButton button); static std::uint8_t to_mouse_buttons(Qt::MouseButtons buttons); static Keyboard_Modifier to_keyboard_modifiers(Qt::KeyboardModifiers modifiers); static Key to_key(int qt_key); }; - } // namespace renderive diff --git a/Qt/bridge/Qt_Image_Adapter.h b/Qt/bridge/Qt_Image_Adapter.h index e5fc7d3..6dd3499 100644 --- a/Qt/bridge/Qt_Image_Adapter.h +++ b/Qt/bridge/Qt_Image_Adapter.h @@ -1,11 +1,8 @@ #pragma once -#include "Core2/base/Types.h" +#include "render_2D/base/Types.h" #include - namespace renderive { - struct Qt_Image_Adapter { static QImage to_qimage(const Image_View& view); }; - } // namespace renderive diff --git a/Qt/bridge/Qt_Presentation_Sink.h b/Qt/bridge/Qt_Presentation_Sink.h index c19722a..0c7037c 100644 --- a/Qt/bridge/Qt_Presentation_Sink.h +++ b/Qt/bridge/Qt_Presentation_Sink.h @@ -1,22 +1,16 @@ #pragma once -#include "Core2/plot/Plot_Core.h" +#include "render_2D/plot/Plot_Core.h" #include #include - class QWidget; - namespace renderive { - class Qt_Presentation_Sink final : public Presentation_Sink { public: explicit Qt_Presentation_Sink(QWidget* widget); ~Qt_Presentation_Sink() override; - void request_present(Rect dirty_rect) override; - private: struct Private; std::unique_ptr d; }; - } // namespace renderive diff --git a/Qt/plot/Plot.h b/Qt/plot/Plot.h index 664b7b2..32e3ec3 100644 --- a/Qt/plot/Plot.h +++ b/Qt/plot/Plot.h @@ -1,21 +1,15 @@ #pragma once - -#include "Core2/export.h" - +#include "render_2D/export.h" #include #include #include #include #include - #include - namespace renderive { - struct Abs_Plot_Private; class Latency_Eager_Plot; class Explicit_Plot; - class LIB_DECL Abs_Plot : public QWidget { Q_OBJECT public: @@ -28,16 +22,13 @@ public: void set_background_color(const QColor& color); void remove_renderable(const std::shared_ptr& renderable); ~Abs_Plot() override; - protected: explicit Abs_Plot(Abs_Plot_Private* private_data); void start_render_timer(); void stop_render_timer(); void update_render_interval(); - bool event(QEvent* event) final; void paintEvent(QPaintEvent* event) final; Abs_Plot_Private* d{}; }; - } // namespace renderive diff --git a/Widget/Qt/File_Gather_Widget.cpp b/Widget/Qt/File_Gather_Widget.cpp deleted file mode 100644 index 98db535..0000000 --- a/Widget/Qt/File_Gather_Widget.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include "File_Gather_Widget.h" -#include -namespace Flex_Qt { -void File_Gather_Widget::append(const std::uint8_t* data, size_t size) { - if (!init) { - Message::show( - Message::error, - "缓冲区还未初始化", - this, - 3000, - Message::Top_Right); - return; - } - file_gather.append(data, size); - value->set_text(QString::fromStdString(file_gather.append_value.to_json().to_json_string())); - speed->set_text(QString::fromStdString(file_gather.append_speed.to_json().to_json_string())); -} -File_Gather_Widget::Config::Config() { - buffer_size = 100000; - log_path = ""; -} -Psc::JSON File_Gather_Widget::Config::to_json() { - return VAR_JSON_2(buffer_size, log_path); -} -void File_Gather_Widget::Config::from_json(Psc::JSON* that_json) { - Get_J(buffer_size) - Get_J(log_path) -} -// 缓存文件目录 和 文件缓冲区大小 -File_Gather_Widget::File_Gather_Widget(std::string_view id) : Base_Cache(id) { - auto layout = new QVBoxLayout(this); - value = new Text_Shower(); - speed = new Text_Shower(); - value->set_title("值"); - speed->set_title("速度"); - path_select = new File_Tool("采集文件"); - size_select = new Byte_Select(); - size_select->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); - size_select->set_number_value(0); - size_select->set_title("缓冲区大小"); - confirm_button = new QPushButton("确定"); - layout->addWidget(path_select); - layout->addWidget(size_select); - layout->addWidget(value); - layout->addWidget(speed); - layout->addWidget(confirm_button); - layout->addStretch(); - QObject::connect(confirm_button, &QPushButton::clicked, [this]() { - if (init) { - Message::show( - Message::warning, - "已经初始化完成过", - this, - 3000, - Message::Top_Right); - return; - } - QString qpath = path_select->path(); - if (qpath.isEmpty()) { - Message::show( - Message::error, - "路径不能为空", - this, - 3000, - Message::Top_Right); - return; - } - std::filesystem::path path = qpath.toStdString(); - try { - // 如果是文件路径 - std::filesystem::path parent = path.parent_path(); - if (!parent.empty() && !std::filesystem::exists(parent)) { - if (!std::filesystem::create_directories(parent)) { - Message::show( - Message::error, - "目录创建失败", - this, - 3000, - Message::Top_Right); - return; - } - } - // 如果文件不存在就创建 - if (!std::filesystem::exists(path)) { - std::ofstream ofs(path.string(), std::ios::binary); - if (!ofs) { - Message::show( - Message::error, - "文件创建失败", - this, - 3000, - Message::Top_Right); - return; - } - } - } - catch (const std::exception& e) { - Message::show( - Message::error, - QString("路径错误: ") + e.what(), - this, - 3000, - Message::Top_Right); - return; - } - init = false; - file_gather.init(path.string(), size_select->value()); - init = true; - Message::show( - Message::success, - "初始化成功", - this, - 2000, - Message::Top_Right); - // 保存初始化成功的配置文件 - save(); - }); - auto json_file = get_config_path(); - Config config; - if (!std::filesystem::exists(json_file)) { - save(config); - } - auto tt = Psc::try_parse_json_file(json_file).and_then([&config](Psc::JSON&& json) -> Psc::expected { - config.from_json(&json); - return {}; - }); - if (!tt) { - Message::show( - Message::success, - "配置文件加载错误! " + QString::fromStdString(json_file), - this, - 2000, - Message::Top_Right); - } - size_select->set_number_value(config.buffer_size); - path_select->set_path(QString::fromStdString(config.log_path)); -} -void File_Gather_Widget::save() { - Config config; - config.buffer_size = size_select->value(); - config.log_path = path_select->path().toStdString(); - save(config); -} -void File_Gather_Widget::save(Config& config) { - auto json_file = get_config_path(); - std::ofstream ofs(json_file, std::ios::out | std::ios::trunc); - ofs << config.to_json().to_json_string(); - ofs.close(); -} -void File_Gather_Widget::contextMenuEvent(QContextMenuEvent* event) { - QWidget::contextMenuEvent(event); -} -} diff --git a/Widget/Qt/File_Gather_Widget.h b/Widget/Qt/File_Gather_Widget.h deleted file mode 100644 index 5a3c22d..0000000 --- a/Widget/Qt/File_Gather_Widget.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#include -#include -#include -#include "File_Tool.h" -#include "Message.h" -#include "Text_Shower.h" -#include "Value_Select.h" -#include "Psc_Cpp_Core/Base/File_Helper.h" -namespace Flex_Qt { -// 这个是用来采集文件使用的控件 -class File_Gather_Widget : public QWidget, public Base_Cache { -public: - void append(const std::uint8_t* data, size_t size); - struct Config { - std::size_t buffer_size; - std::string log_path; - Config(); - Psc::JSON to_json(); - void from_json(Psc::JSON* that_json); - }; - // 初始化参数 - Byte_Select* size_select; - File_Tool* path_select; - QPushButton* confirm_button{}; - Text_Shower* value; - Text_Shower* speed; - void save(); - void save(Config& config); - File_Gather_Widget(std::string_view id); // 一个名称用于标识 他会在可执行文件所在目录存储一些路径信息 - Psc::File_Gather file_gather; -protected: - void contextMenuEvent(QContextMenuEvent* event) override; -}; -class Test_File_Gather_Widget : public QWidget { -public: - File_Gather_Widget* file_gather_widget; - Test_File_Gather_Widget() { - auto layout = new QVBoxLayout(this); - file_gather_widget = new File_Gather_Widget("Test_File_Gather_Widget"); - layout->addWidget(file_gather_widget); - auto content = new QLineEdit("测试输入内容123"); - auto confirm = new QPushButton("确定"); - layout->addWidget(content); - layout->addWidget(confirm); - QObject::connect(confirm, &QPushButton::clicked, [this, content]() { - auto str = "123"; - auto text = content->text().toStdString(); - file_gather_widget->append((uint8_t*)text.data(), text.size()); - }); - } -}; -} diff --git a/Widget/Qt/File_Player_Widget.cpp b/Widget/Qt/File_Player_Widget.cpp deleted file mode 100644 index 858e7e4..0000000 --- a/Widget/Qt/File_Player_Widget.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "File_Player_Widget.h" -#include -namespace Flex_Qt { -File_Play_Widget::Config::Config() { - log_path = ""; -} -Psc::JSON File_Play_Widget::Config::to_json() { - return VAR_JSON_1(log_path); -} -void File_Play_Widget::Config::from_json(Psc::JSON* that_json) { - Get_J(log_path) -} -void File_Play_Widget::save() { - Config config; - config.log_path = path_select->path().toStdString(); - save(config); -} -void File_Play_Widget::save(Config& config) { - auto json_file = get_config_path(); - std::ofstream ofs(json_file, std::ios::out | std::ios::trunc); - ofs << config.to_json().to_json_string(); - ofs.close(); -} -File_Play_Widget::File_Play_Widget(std::string_view id) : Base_Cache(id) { - auto layout = new QVBoxLayout(this); - layout->setContentsMargins(4, 4, 4, 4); - layout->setSpacing(6); - path_select = new File_Tool2("回放文件"); - layout->addWidget(path_select); - progress_bar = new QProgressBar(); - progress_bar->setRange(0, 1000); - progress_bar->setValue(0); - layout->addWidget(progress_bar); - speed_show = new Text_Shower(); - speed_show->set_title("回放速度显示"); - layout->addWidget(speed_show); - confirm_button = new QPushButton("确定"); - layout->addWidget(confirm_button); - QObject::connect(confirm_button, &QPushButton::clicked, [this]() { - if (init) { - Message::show( - Message::warning, - "已经初始化完成过", - this, - 3000, - Message::Top_Right); - return; - } - QString qpath = path_select->path(); - if (qpath.isEmpty()) { - Message::show( - Message::error, - "路径不能为空", - this, - 3000, - Message::Top_Right); - return; - } - std::filesystem::path path = qpath.toStdString(); - try { - // 如果是文件路径 - std::filesystem::path parent = path.parent_path(); - if (!parent.empty() && !std::filesystem::exists(parent)) { - if (!std::filesystem::create_directories(parent)) { - Message::show( - Message::error, - "目录创建失败", - this, - 3000, - Message::Top_Right); - return; - } - } - // 如果文件不存在就创建 - if (!std::filesystem::exists(path)) { - std::ofstream ofs(path.string(), std::ios::binary); - if (!ofs) { - Message::show( - Message::error, - "文件创建失败", - this, - 3000, - Message::Top_Right); - return; - } - } - } - catch (const std::exception& e) { - Message::show( - Message::error, - QString("路径错误: ") + e.what(), - this, - 3000, - Message::Top_Right); - return; - } - Message::show( - Message::success, - "初始化成功", - this, - 2000, - Message::Top_Right); - // 保存初始化成功的配置文件 - save(); - }); - auto json_file = get_config_path(); - Config config; - if (!std::filesystem::exists(json_file)) { - save(config); - } - auto tt = Psc::try_parse_json_file(json_file).and_then([&config](Psc::JSON&& json) -> Psc::expected { - config.from_json(&json); - return {}; - }); - if (!tt) { - Message::show( - Message::success, - "配置文件加载错误!", - this, - 2000, - Message::Top_Right); - } - path_select->set_path(QString::fromStdString(config.log_path)); -} -void File_Play_Widget::start(size_t chunk_size, std::chrono::milliseconds interval) { - QString path = path_select->path(); - if (path.isEmpty()) { - Message::show(Message::error, QString("路径为空"), this, 3000, - Message::Top_Right); - return; - } - try { - file_player.open(path.toStdString()); - } - catch (std::exception& e) { - Message::show(Message::error, QString("文件打开失败: ") + e.what(), this, - 3000, Message::Top_Right); - return; - } - speed.clear(); - progress_bar->setValue(0); - timer = new QTimer(this); - timer->setInterval(interval.count()); - connect(timer, &QTimer::timeout, this, [this, chunk_size]() { - std::vector buffer(chunk_size); - size_t n = file_player.read(buffer.data(), chunk_size); - if (n == 0 || file_player.eof()) { - timer->stop(); - file_player.close(); - progress_bar->setValue(1000); - return; - } - speed.update(n); - speed_show->set_text( - QString::fromStdString(speed.to_json().to_json_string())); - double p = file_player.progress(); - progress_bar->setValue(static_cast(p * 1000)); - }); - timer->start(); -} -Test_File_Play_Widget::Test_File_Play_Widget() { - auto layout = new QVBoxLayout(this); - file_play_widget = new File_Play_Widget("Test_File_Play_Widget"); - layout->addWidget(file_play_widget); - layout->addStretch(); - interval_select = new Value_Select_Simple(); - chunk_select = new Value_Select_Simple(); - interval_select->set_value(50); - chunk_select->set_value(4096); - interval_select->set_title("时间间隔(ms)"); - chunk_select->set_title("块大小(byte)"); - start_button = new QPushButton("开始回放"); - layout->addWidget(interval_select); - layout->addWidget(chunk_select); - layout->addWidget(start_button); - connect(start_button, &QPushButton::clicked, this, [this]() { - file_play_widget->speed.clear(); - size_t chunk = chunk_select->get_value(); - int interval = interval_select->get_value(); - file_play_widget->start(chunk, std::chrono::milliseconds(interval)); - }); -} -} diff --git a/Widget/Qt/File_Player_Widget.h b/Widget/Qt/File_Player_Widget.h deleted file mode 100644 index aef7e31..0000000 --- a/Widget/Qt/File_Player_Widget.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include "File_Tool2.h" -#include "Message.h" -#include "Text_Shower.h" -#include "Value_Select.h" -#include "global.h" -#include "Psc_Cpp_Core/Base/File_Helper.h" -#include "Psc_Cpp_Core/Statistics/Statistics.h" -namespace Flex_Qt { -class File_Play_Widget : public QWidget, public Base_Cache { -public: - explicit File_Play_Widget(std::string_view id); - void start(size_t chunk_size, std::chrono::milliseconds interval); - struct Config { - std::string log_path; - Config(); - Psc::JSON to_json(); - void from_json(Psc::JSON* that_json); - }; - void save(); - void save(Config& config); - File_Tool2* path_select{}; - QProgressBar* progress_bar{}; - Text_Shower* speed_show{}; - Psc::Speed_Statistics speed; - Psc::File_Player file_player; - QPushButton* confirm_button{}; - QTimer* timer{}; -}; -class Test_File_Play_Widget : public QWidget { -public: - File_Play_Widget* file_play_widget{}; - Value_Select_Simple* interval_select; - Value_Select_Simple* chunk_select; - QPushButton* start_button{}; - Test_File_Play_Widget(); -}; -} diff --git a/Widget/Qt/File_Tool.cpp b/Widget/Qt/File_Tool.cpp deleted file mode 100644 index d2d85a1..0000000 --- a/Widget/Qt/File_Tool.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "File_Tool.h" -namespace Flex_Qt { -File_Tool::File_Tool(const QString& title, Mode mode, QWidget* parent) : QWidget(parent), mode_(mode) { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - title_label = new QLabel(title, this); - path_edit = new QLineEdit(this); - path_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - browse_btn = new QPushButton("选择", this); - browse_btn->setFixedWidth(48); - set_help_text(browse_btn, "点击打开文件\n支持手动输入路径"); - clear_btn = new QPushButton("清空", this); - clear_btn->setFixedWidth(48); - set_help_text(clear_btn, "点击清空当前文件内容"); - backup_clear_btn = new QPushButton("备份清空", this); - backup_clear_btn->setFixedWidth(72); - set_help_text(backup_clear_btn, "点击清空,并且备份当前文件"); - auto layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(4); - if (!title.isEmpty()) - layout->addWidget(title_label); - layout->addWidget(path_edit); - layout->addWidget(browse_btn); - layout->addWidget(clear_btn); - layout->addWidget(backup_clear_btn); - // 选择路径 - connect(browse_btn, &QPushButton::clicked, this, [this]() { - QString selected; - switch (mode_) { - case Mode::OpenFile: - selected = QFileDialog::getOpenFileName(this, "Select File"); - break; - case Mode::SaveFile: - selected = QFileDialog::getSaveFileName(this, "Save File"); - break; - case Mode::Directory: - selected = QFileDialog::getExistingDirectory(this, "Select Directory"); - break; - } - if (!selected.isEmpty()) { - path_edit->setText(selected); - emit path_changed(selected); - } - }); - // 清空文件 - connect(clear_btn, &QPushButton::clicked, this, [this]() { - const QString p = path_edit->text(); - if (p.isEmpty()) - return; - QFileInfo info(p); - if (!info.exists() || !info.isFile()) { - Message::show(Message::error, "文件不存在!", - this, 2000, Message::Top_Right); - return; - } - QFile file(p); - if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - Message::show(Message::error, "无法清空文件!", - this, 2000, Message::Top_Right); - return; - } - file.close(); - Message::show(Message::success, "文件已清空", - this, 1500, Message::Top_Right); - }); - // 备份并清空 - connect(backup_clear_btn, &QPushButton::clicked, this, [this]() { - const QString p = path_edit->text(); - if (p.isEmpty()) - return; - QFileInfo info(p); - if (!info.exists() || !info.isFile()) { - Message::show(Message::error, "文件不存在!", - this, 2000, Message::Top_Right); - return; - } - QString backup_path = - info.absolutePath() + "/" + - info.completeBaseName() + "_" + - QDateTime::currentDateTime().toString("yyyy_MM_dd_hh_mm_ss") + - "." + info.suffix(); - if (!QFile::copy(p, backup_path)) { - Message::show(Message::error, "备份失败!", - this, 2000, Message::Top_Right); - return; - } - QFile file(p); - if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - Message::show(Message::error, "清空失败!", - this, 2000, Message::Top_Right); - return; - } - file.close(); - Message::show(Message::success, "已备份并清空", - this, 1500, Message::Top_Right); - }); - connect(path_edit, &QLineEdit::editingFinished, this, - [this]() { - emit path_changed(path_edit->text()); - }); -} -void File_Tool::set_title(const QString& t) { - title_label->setText(t); - title_label->setVisible(!t.isEmpty()); -} -QString File_Tool::path() const { - return path_edit->text(); -} -void File_Tool::set_path(const QString& p) { - path_edit->setText(p); - emit path_changed(p); -} -} diff --git a/Widget/Qt/File_Tool.h b/Widget/Qt/File_Tool.h deleted file mode 100644 index 4fa9925..0000000 --- a/Widget/Qt/File_Tool.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Message.h" -#include "global.h" -namespace Flex_Qt { -class File_Tool : public QWidget { - Q_OBJECT -public: - enum class Mode { - OpenFile, - SaveFile, - Directory - }; - explicit File_Tool(const QString& title = {}, Mode mode = Mode::OpenFile, QWidget* parent = nullptr); - void set_title(const QString& t); - [[nodiscard]] QString path() const; - void set_path(const QString& p); - signals : - - void path_changed(const QString&); -private: - Mode mode_; - QLabel* title_label{}; - QLineEdit* path_edit{}; - QPushButton* browse_btn{}; - QPushButton* clear_btn{}; - QPushButton* backup_clear_btn{}; -}; -} diff --git a/Widget/Qt/File_Tool2.h b/Widget/Qt/File_Tool2.h deleted file mode 100644 index 14c41b5..0000000 --- a/Widget/Qt/File_Tool2.h +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Message.h" -namespace Flex_Qt { -class File_Tool2 : public QWidget { - Q_OBJECT -public: - enum class Mode { - OpenFile, - SaveFile, - Directory - }; - explicit File_Tool2(const QString& title = {}, - Mode mode = Mode::OpenFile, - QWidget* parent = nullptr) : QWidget(parent), mode_(mode) { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - title_label = new QLabel(title, this); - path_edit = new QLineEdit(this); - path_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - browse_btn = new QPushButton("选择", this); - browse_btn->setFixedWidth(48); - open_file_btn = new QPushButton("文件", this); - open_file_btn->setFixedWidth(40); - open_dir_btn = new QPushButton("目录", this); - open_dir_btn->setFixedWidth(40); - auto layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(4); - if (!title.isEmpty()) - layout->addWidget(title_label); - layout->addWidget(path_edit); - layout->addWidget(browse_btn); - layout->addWidget(open_file_btn); - layout->addWidget(open_dir_btn); - // 选择路径 - connect(browse_btn, &QPushButton::clicked, this, [this]() { - QString selected; - switch (mode_) { - case Mode::OpenFile: - selected = QFileDialog::getOpenFileName(this, "Select File"); - break; - case Mode::SaveFile: - selected = QFileDialog::getSaveFileName(this, "Save File"); - break; - case Mode::Directory: - selected = QFileDialog::getExistingDirectory(this, "Select Directory"); - break; - } - if (!selected.isEmpty()) { - path_edit->setText(selected); - emit path_changed(selected); - } - }); - // 打开文件 - connect(open_file_btn, &QPushButton::clicked, this, [this]() { - const QString p = path_edit->text(); - if (p.isEmpty()) - return; - QFileInfo info(p); - if (!info.exists() || !info.isFile()) { - Message::show(Message::error, "文件不存在!", - this, 2000, Message::Top_Right); - return; - } - QDesktopServices::openUrl( - QUrl::fromLocalFile(info.absoluteFilePath())); - }); - // 打开目录 - connect(open_dir_btn, &QPushButton::clicked, this, [this]() { - const QString p = path_edit->text(); - if (p.isEmpty()) - return; - QFileInfo info(p); - if (!info.exists()) { - Message::show(Message::error, "目录不存在!", - this, 2000, Message::Top_Right); - return; - } - QString dir_path = info.isDir() - ? info.absoluteFilePath() - : info.absolutePath(); - QDesktopServices::openUrl( - QUrl::fromLocalFile(dir_path)); - }); - connect(path_edit, &QLineEdit::editingFinished, this, - [this]() { - emit path_changed(path_edit->text()); - }); - } - void set_title(const QString& t) { - title_label->setText(t); - title_label->setVisible(!t.isEmpty()); - } - [[nodiscard]] QString path() const { - return path_edit->text(); - } - void set_path(const QString& p) { - path_edit->setText(p); - emit path_changed(p); - } - signals : - - void path_changed(const QString&); -private: - Mode mode_; - QLabel* title_label{}; - QLineEdit* path_edit{}; - QPushButton* browse_btn{}; - QPushButton* open_file_btn{}; - QPushButton* open_dir_btn{}; -}; -} diff --git a/Widget/Qt/Message.cpp b/Widget/Qt/Message.cpp deleted file mode 100644 index 5cc999a..0000000 --- a/Widget/Qt/Message.cpp +++ /dev/null @@ -1,372 +0,0 @@ -#include "Message.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace Flex_Qt::Message { -static Config global_config; -class Toast; -class Resize_Watcher; -static std::unordered_map>> containers; -static std::unordered_map> watchers; -static std::unordered_map>> queues; -/* -------------------- 工具函数 -------------------- */ -static bool is_dark_palette() { - QColor c = QApplication::palette().window().color(); - return c.lightness() < 128; -} -static QColor interpolate(const QColor& a, const QColor& b, double t) { - return QColor( - a.red() + (b.red() - a.red()) * t, - a.green() + (b.green() - a.green()) * t, - a.blue() + (b.blue() - a.blue()) * t, - a.alpha() + (b.alpha() - a.alpha()) * t); -} -struct Theme_Colors { - QColor bg; - QColor text; - QColor progress_bg; - QColor progress_fg; -}; -static Theme_Colors theme_for(Type t) { - bool dark; - if (global_config.theme == Theme_Mode::Auto) - dark = is_dark_palette(); - else - dark = (global_config.theme == Theme_Mode::Dark); - QColor base; - switch (t) { - case success: - base = QColor("#52C41A"); - break; - case error: - base = QColor("#F5222D"); - break; - case warning: - base = QColor("#FAAD14"); - break; - default: - base = QColor("#1890FF"); - break; - } - Theme_Colors c; - if (dark) { - c.bg = base.darker(250); - c.bg.setAlpha(210); - c.text = Qt::white; - c.progress_fg = base; - c.progress_bg = QColor(255, 255, 255, 30); - } - else { - c.bg = base.lighter(180); - c.bg.setAlpha(220); - c.text = QColor(30, 30, 30); - c.progress_fg = base.darker(110); - c.progress_bg = QColor(0, 0, 0, 20); - } - return c; -} -/* -------------------- 毛玻璃 -------------------- */ -static QPixmap blur_pixmap(const QPixmap& src, int radius) { - QGraphicsScene scene; - QGraphicsPixmapItem item; - item.setPixmap(src); - QGraphicsBlurEffect blur; - blur.setBlurRadius(radius); - item.setGraphicsEffect(&blur); - scene.addItem(&item); - QImage result(src.size(), QImage::Format_ARGB32); - result.fill(Qt::transparent); - QPainter painter(&result); - scene.render(&painter); - return QPixmap::fromImage(result); -} -static QPixmap generate_noise(int w, int h) { - QImage img(w, h, QImage::Format_ARGB32); - for (int y = 0; y < h; ++y) - for (int x = 0; x < w; ++x) { - int gray = QRandomGenerator::global()->bounded(20); - img.setPixelColor(x, y, QColor(255, 255, 255, gray)); - } - return QPixmap::fromImage(img); -} -/* -------------------- Toast -------------------- */ -class Toast : public QWidget { -public: - Toast(Type t, - const QString& text, - QWidget* parent, - int duration) : QWidget(parent), - type(t), - duration_ms(duration) { - setAttribute(Qt::WA_DeleteOnClose); - setWindowFlags(Qt::FramelessWindowHint); - auto shadow = new QGraphicsDropShadowEffect(this); - shadow->setBlurRadius(30); - shadow->setOffset(0, 8); - shadow->setColor(QColor(0, 0, 0, 120)); - setGraphicsEffect(shadow); - opacity = new QGraphicsOpacityEffect(this); - setGraphicsEffect(opacity); - opacity->setOpacity(0); - fade = new QPropertyAnimation(opacity, "opacity", this); - fade->setDuration(200 * global_config.animation_speed); - move_anim = new QPropertyAnimation(this, "pos", this); - move_anim->setDuration(400 * global_config.animation_speed); - move_anim->setEasingCurve(QEasingCurve::OutBack); - label = new QLabel(text, this); - label->setWordWrap(true); - label->setMaximumWidth(global_config.max_width); - progress = new QProgressBar(this); - progress->setRange(0, duration_ms); - progress->setValue(duration_ms); - progress->setTextVisible(false); - progress->setFixedHeight(3); - auto layout = new QVBoxLayout(this); - layout->setContentsMargins(16, 12, 16, 8); - layout->addWidget(label); - layout->addWidget(progress); - adjustSize(); - apply_theme(theme_for(type)); - start_timer(); - } - void appear_from(const QPoint& start, const QPoint& end) { - prepare_blur(); - move(start); - show(); - fade->setStartValue(0); - fade->setEndValue(1); - fade->start(); - move_anim->setStartValue(start); - move_anim->setEndValue(end); - move_anim->start(); - } - void move_to(const QPoint& target) { - if (pos() == target) - return; - move_anim->stop(); - move_anim->setStartValue(pos()); - move_anim->setEndValue(target); - move_anim->start(); - } - void disappear() { - fade->setStartValue(1); - fade->setEndValue(0); - connect(fade, &QPropertyAnimation::finished, - this, &QWidget::deleteLater); - fade->start(); - } -protected: - void mousePressEvent(QMouseEvent*) override { - disappear(); - } - void enterEvent(QEvent*) override { - if (timer) - timer->stop(); - } - void leaveEvent(QEvent*) override { - if (timer) - timer->start(); - } - void paintEvent(QPaintEvent* e) override { - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - QRectF r = rect(); - QPainterPath path; - path.addRoundedRect(r, 12, 12); - // 1️⃣ 裁剪圆角区域 - painter.setClipPath(path); - // 2️⃣ 画毛玻璃 - if (global_config.enable_blur && !blurred_background.isNull()) { - painter.drawPixmap(r.toRect(), blurred_background); - } - // 3️⃣ 半透明背景 - painter.fillPath(path, current_theme.bg); - // 4️⃣ Acrylic 噪点 - if (global_config.acrylic_mode) { - painter.drawPixmap(r.toRect(), - generate_noise(width(), height())); - } - // 5️⃣ 解除裁剪 - painter.setClipping(false); - // 6️⃣ 调用基类,让子控件正常绘制 - QWidget::paintEvent(e); - } -private: - void prepare_blur() { - if (!global_config.enable_blur) - return; - QWidget* p = parentWidget(); - if (!p) - return; - QPixmap grab = p->grab(geometry()); - blurred_background = blur_pixmap(grab, 20); - } - void apply_theme(const Theme_Colors& c) { - current_theme = c; - label->setStyleSheet(QString( - "background:transparent;color:%1;") - .arg(c.text.name())); - progress->setStyleSheet(QString( - "QProgressBar{background:%1;border:none;}" - "QProgressBar::chunk{background:%2;border-radius:2px;}") - .arg(c.progress_bg.name(QColor::HexArgb)) - .arg(c.progress_fg.name())); - } - void start_timer() { - if (!timer) { - timer = new QTimer(this); - timer->setInterval(16); - connect(timer, &QTimer::timeout, this, [this]() { - elapsed_ms += 16; - int remain = duration_ms - elapsed_ms; - progress->setValue(std::max(0, remain)); - if (remain <= 0) { - timer->stop(); - disappear(); - } - }); - } - timer->start(); - } - Type type; - int duration_ms; - int elapsed_ms = 0; - QLabel* label{}; - QProgressBar* progress{}; - QTimer* timer{}; - QGraphicsOpacityEffect* opacity{}; - QPropertyAnimation* fade{}; - QPropertyAnimation* move_anim{}; - Theme_Colors current_theme; - QPixmap blurred_background; -}; -/* -------------------- 布局 -------------------- */ -static QWidget* top_parent(QWidget* w) { - while (w && w->parentWidget()) - w = w->parentWidget(); - return w; -} -static void relayout(QWidget* top, Corner corner) { - auto& list = containers[top]; - constexpr int margin = 24; - constexpr int spacing = 16; - int y = (corner == Top_Left || corner == Top_Right) - ? margin - : top->height() - margin; - for (auto& toast : list) { - if (!toast) - continue; - QPoint target; - if (corner == Top_Left) { - target = {margin, y}; - y += toast->height() + spacing; - } - else if (corner == Top_Right) { - target = {top->width() - toast->width() - margin, y}; - y += toast->height() + spacing; - } - else if (corner == Bottom_Left) { - y -= toast->height(); - target = {margin, y}; - y -= spacing; - } - else { - y -= toast->height(); - target = {top->width() - toast->width() - margin, y}; - y -= spacing; - } - toast->move_to(target); - } -} -static void process_queue(QWidget* top, Corner corner) { - if (queues[top].empty()) - return; - auto item = std::move(queues[top].front()); - queues[top].pop(); - auto* toast = new Toast( - item.first, - item.second, - top, - global_config.default_duration); - auto& list = containers[top]; - constexpr int margin = 24; - constexpr int spacing = 16; - // --------- 1️⃣ 计算最终位置 ---------- - int y = (corner == Top_Left || corner == Top_Right) - ? margin - : top->height() - margin; - for (auto& t : list) { - if (!t) - continue; - if (corner == Top_Left || corner == Top_Right) - y += t->height() + spacing; - else - y -= t->height() + spacing; - } - QPoint final_pos; - if (corner == Top_Left) - final_pos = QPoint(margin, y); - else if (corner == Top_Right) - final_pos = QPoint(top->width() - toast->width() - margin, y); - else if (corner == Bottom_Left) - final_pos = QPoint(margin, y - toast->height()); - else - final_pos = QPoint(top->width() - toast->width() - margin, - y - toast->height()); - // --------- 2️⃣ 立即定位到 final ---------- - toast->move(final_pos); - // --------- 3️⃣ 加入容器 ---------- - list.push_back(toast); - // --------- 4️⃣ 计算飞入起点 ---------- - QPoint start = final_pos; - if (corner == Top_Right || corner == Bottom_Right) - start.setX(top->width()); - else - start.setX(-toast->width()); - // --------- 5️⃣ 飞入 ---------- - toast->appear_from(start, final_pos); - // --------- 6️⃣ 超限处理 ---------- - if (list.size() > global_config.max_count) { - auto old = list.front(); - list.erase(list.begin()); - if (old) - old->disappear(); - } - // --------- 7️⃣ 旧 toast 重排 ---------- - relayout(top, corner); -} -/* -------------------- 公共接口 -------------------- */ -void show(Type type, - const QString& text, - QWidget* parent, - int, - Corner corner) { - if (!parent) - return; - QWidget* top = top_parent(parent); - if (!top) - return; - queues[top].push({type, text}); - QTimer::singleShot(global_config.queue_interval, - top, - [top, corner]() { - process_queue(top, corner); - }); -} -void set_config(const Config& cfg) { - global_config = cfg; -} -} diff --git a/Widget/Qt/Message.h b/Widget/Qt/Message.h deleted file mode 100644 index 71019c2..0000000 --- a/Widget/Qt/Message.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -namespace Flex_Qt::Message { -enum Type { - success, - error, - warning, - info -}; -enum Corner { - Top_Left, - Top_Right, - Bottom_Left, - Bottom_Right -}; -enum class Theme_Mode { - Light, - Dark, - Auto -}; -struct Config { - Corner default_corner = Top_Right; - int default_duration = 3000; - int max_count = 5; - int max_width = 360; - int queue_interval = 120; - Theme_Mode theme = Theme_Mode::Auto; - bool enable_blur = true; - bool acrylic_mode = false; - double animation_speed = 1.0; -}; -void set_config(const Config& cfg); -void show(Type type, - const QString& text, - QWidget* parent, - int duration_ms = -1, - Corner corner = Top_Right); -} diff --git a/Widget/Qt/Text_Shower.cpp b/Widget/Qt/Text_Shower.cpp deleted file mode 100644 index d84ed3e..0000000 --- a/Widget/Qt/Text_Shower.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "Text_Shower.h" -#include -#include -#include -namespace Flex_Qt { -Text_Shower::Text_Shower(QWidget* parent) : QWidget(parent) { - setAttribute(Qt::WA_TranslucentBackground); - // 宽度交给布局,高度最小 - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); -} -void Text_Shower::set_text(const QString& text) { - m_text = text; - updateGeometry(); // 通知布局重新计算 - update(); -} -void Text_Shower::set_title(const QString& title) { - m_title = title; - updateGeometry(); - update(); -} -void Text_Shower::set_max_width(int w) { - m_max_width = w; - updateGeometry(); -} -bool Text_Shower::hasHeightForWidth() const { - return true; -} -int Text_Shower::heightForWidth(int width) const { - width = std::min(width, m_max_width); - return calculate_height(width); -} -QSize Text_Shower::sizeHint() const { - int w = std::min(400, m_max_width); - return QSize(w, calculate_height(w)); -} -QSize Text_Shower::minimumSizeHint() const { - return QSize(120, 40); -} -int Text_Shower::calculate_height(int width) const { - QFontMetrics fm(font()); - int content_width = width - m_padding * 2; - if (content_width <= 0) - return 40; - QRect text_rect = fm.boundingRect( - QRect(0, 0, content_width, 10000), - Qt::TextWordWrap, - m_text); - int height = text_rect.height(); - if (!m_title.isEmpty()) { - QFont title_font = font(); - title_font.setBold(true); - QFontMetrics title_fm(title_font); - height += title_fm.height() + 6; - } - height += m_padding * 2; - return height; -} -void Text_Shower::paintEvent(QPaintEvent*) { - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - QRect r = rect(); - painter.setBrush(QColor(255, 255, 255)); - painter.setPen(QPen(QColor(0, 0, 0), 1)); - painter.drawRoundedRect(r.adjusted(0, 0, -1, -1), m_radius, m_radius); - int y = m_padding; - if (!m_title.isEmpty()) { - QFont title_font = font(); - title_font.setBold(true); - painter.setFont(title_font); - QFontMetrics title_fm(title_font); - painter.drawText(m_padding, - y + title_fm.ascent(), - m_title); - y += title_fm.height() + 6; - painter.setFont(font()); - } - QRect text_rect(m_padding, y, - width() - m_padding * 2, - height() - y - m_padding); - painter.drawText(text_rect, - Qt::AlignLeft | Qt::TextWordWrap, - m_text); -} -} diff --git a/Widget/Qt/Text_Shower.h b/Widget/Qt/Text_Shower.h deleted file mode 100644 index 195c032..0000000 --- a/Widget/Qt/Text_Shower.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include -#include -namespace Flex_Qt { -class Text_Shower : public QWidget { - Q_OBJECT -public: - explicit Text_Shower(QWidget* parent = nullptr); - void set_text(const QString& text); - void set_title(const QString& title); - void set_max_width(int w); - [[nodiscard]] QSize sizeHint() const override; - [[nodiscard]] QSize minimumSizeHint() const override; - [[nodiscard]] bool hasHeightForWidth() const override; - [[nodiscard]] int heightForWidth(int width) const override; -protected: - void paintEvent(QPaintEvent*) override; -private: - [[nodiscard]] int calculate_height(int width) const; -private: - QString m_text; - QString m_title; - int m_padding = 8; - int m_radius = 8; - int m_max_width = 600; // 可选上限 -}; -} diff --git a/Widget/Qt/Value_Select.cpp b/Widget/Qt/Value_Select.cpp deleted file mode 100644 index afc16a6..0000000 --- a/Widget/Qt/Value_Select.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "Value_Select.h" -#include -namespace Flex_Qt {} -#ifdef _USE_GTEST -#include -#include -#include -// TEST(Enum_Select, xor1233) { -// int argc = 0; -// QApplication app(argc, nullptr); -// -// -// QWidget w; -// -// w.show(); -// app.exec(); -// } -#endif diff --git a/Widget/Qt/Value_Select.h b/Widget/Qt/Value_Select.h deleted file mode 100644 index fcb62fd..0000000 --- a/Widget/Qt/Value_Select.h +++ /dev/null @@ -1,154 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include "magic_enum/magic_enum.hpp" -namespace Flex_Qt { -// 用于选择一个值 -template -class Value_Select_Simple : public QWidget { -public: - QLabel* label; - QLineEdit* number_input; - void set_title(const QString& title) const { - label->setText(title); - } - [[nodiscard]] QString get_title() const { - return label->text(); - } - void set_value(Value_Type value) { - number_input->setText(QString::number(value)); - } - Value_Type get_value() { - auto str = number_input->text(); - if constexpr (std::is_integral_v) { - bool ok = false; - if constexpr (std::is_signed_v) { - auto v = str.toLongLong(&ok); - if (!ok) - throw std::runtime_error("Invalid integer"); - return static_cast(v); - } - else { - auto v = str.toULongLong(&ok); - if (!ok) - throw std::runtime_error("Invalid unsigned integer"); - return static_cast(v); - } - } - else if constexpr (std::is_floating_point_v) { - bool ok = false; - auto v = str.toDouble(&ok); - if (!ok) - throw std::runtime_error("Invalid float"); - return static_cast(v); - } - else { - static_assert(sizeof(Value_Type) == 0, "Unsupported Value_Type"); - } - return Value_Type(); - } - explicit Value_Select_Simple(QWidget* parent = nullptr) : QWidget(parent) { - label = new QLabel(this); - number_input = new QLineEdit(this); - auto layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - layout->addWidget(label); - layout->addWidget(number_input); - } -}; -// 选择带枚举单位的值 -template -class Value_Select : public QWidget { -public: - Value_Select_Simple* number; - QComboBox* unit; - void set_title(const QString& title) const { - number->set_title(title); - } - [[nodiscard]] QString get_title() const { - return number->get_title(); - } - explicit Value_Select(QWidget* parent = nullptr) : QWidget(parent) { - unit = new QComboBox(this); - number = new Value_Select_Simple; - for (auto ev : magic_enum::enum_values()) { - unit->addItem(enum_name(ev), static_cast(ev)); - } - auto layout = new QHBoxLayout(this); - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - layout->addWidget(number); - layout->addWidget(unit); - } - Value_Select& set_default_unit(Enum_Type value) { - int idx = unit->findData(static_cast(value)); - if (idx >= 0) - unit->setCurrentIndex(idx); - return *this; - } - void set_number_value(Value_Type value) { - number->set_value(value); - } - Enum_Type unit_enum() { - return from_value(unit->currentData().toInt()); - } - virtual Value_Type value() { - return number->get_value() * uint_value(unit_enum()); - } - virtual Value_Type uint_value(Enum_Type enum_val) { - return 1; - } -protected: - Enum_Type from_name(const QString& name) { - auto v = magic_enum::enum_cast(name.toStdString()); - if (!v) - throw std::runtime_error("Invalid enum name"); - return *v; - } - Enum_Type from_value(int value) { - auto v = magic_enum::enum_cast(value); - if (!v) - throw std::runtime_error("Invalid enum value"); - return *v; - } - [[nodiscard]] QString enum_name(Enum_Type value) { - return QString::fromStdString(std::string(magic_enum::enum_name(value))); - } - [[nodiscard]] QString enum_type_name() const { - return QString::fromStdString( - std::string(magic_enum::enum_type_name())); - } -}; -enum class Memory_Size_Uint : size_t { - Byte, - KB, - MB, - GB -}; -class Byte_Select : public Value_Select { -public: - size_t uint_value(Memory_Size_Uint e) override { - static constexpr size_t table[] = { - 1ull, 1024ull, 1024ull * 1024ull, - 1024ull * 1024ull * 1024ull - }; - return table[static_cast(e)]; - } -}; -enum class Frequent_Uint : size_t { - HZ, - KHZ, - MHZ, -}; -class Frequent_Select : public Value_Select { -public: - size_t uint_value(Frequent_Uint e) override { - static constexpr size_t table[] = {1ull, 1000ull, 1000ull * 1000ull}; - return table[static_cast(e)]; - } -}; -} diff --git a/Widget/Qt/export.h b/Widget/Qt/export.h deleted file mode 100644 index 6fff996..0000000 --- a/Widget/Qt/export.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include "File_Gather_Widget.h" -#include "File_Player_Widget.h" -#include "File_Tool.h" -#include "File_Tool2.h" -#include "Message.h" -#include "Text_Shower.h" -#include "Value_Select.h" -#include "global.h" diff --git a/Widget/Qt/global.cpp b/Widget/Qt/global.cpp deleted file mode 100644 index ca46420..0000000 --- a/Widget/Qt/global.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "global.h" -#include -namespace Flex_Qt { -void set_help_text(QWidget* widget, const QString& text) { - widget->setToolTip(text); - widget->setStatusTip(text); - widget->setWhatsThis(text); -} -std::string get_config_dir() { - std::string ret = Psc::get_exe_dir() + "/psc_config"; - Psc::create_dir_if_not_exists(ret); - return ret; -} -Base_Cache::Base_Cache(std::string_view id) : id(id) {} -std::string Base_Cache::get_config_path() const { - return get_config_dir() + "/" + id + "_config.json"; -} -} diff --git a/Widget/Qt/global.h b/Widget/Qt/global.h deleted file mode 100644 index 8c6bdbb..0000000 --- a/Widget/Qt/global.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include -#include -#include -#include "../global.h" -namespace Flex_Qt { -void set_help_text(QWidget* widget, const QString& text); -std::string get_config_dir(); -class Base_Cache { -public: - std::string id; - Base_Cache(std::string_view id); - std::string get_config_path() const; - std::atomic_bool init = false; -}; -} diff --git a/Widget/Qt/功能性ui.txt b/Widget/Qt/功能性ui.txt deleted file mode 100644 index e69de29..0000000 diff --git a/Widget/base/CircularLinkedList.hpp b/Widget/base/CircularLinkedList.hpp deleted file mode 100644 index 107877f..0000000 --- a/Widget/base/CircularLinkedList.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once -#include -namespace Flex_Qt { -template -struct Circular_Linked_List_Node { - Circular_Linked_List_Node *prev = nullptr, *next = nullptr; - T data; -}; -template -class Circular_Linked_List { -public: - Circular_Linked_List_Node* head = nullptr; - Circular_Linked_List_Node* cur = nullptr; - void init(const std::vector& data_list) { - head = new Circular_Linked_List_Node(); - head->data = data_list.front(); - Circular_Linked_List_Node* prev = head; - int n = data_list.size(); - for (int i = 1; i < n - 1; i++) { - auto node = new Circular_Linked_List_Node(); - node->data = data_list[i]; - node->prev = prev; - prev->next = node; - prev = node; - } - auto tail = new Circular_Linked_List_Node(); - tail->data = data_list.back(); - tail->prev = prev; - prev->next = tail; - tail->next = head; - head->prev = tail; - cur = head; - } - Circular_Linked_List_Node* move(int step = 1) { - if (step == 0) return nullptr; - return step > 0 ? next(step) : prev(-step); - } - Circular_Linked_List_Node* next(int step = 1) { - if (step <= 0) return nullptr; - for (int i = 0; i < step; i++) { - cur = cur->next; - } - return cur; - } - Circular_Linked_List_Node* prev(int step = 1) { - if (step <= 0) return nullptr; - for (int i = 0; i < step; i++) { - cur = cur->prev; - } - return cur; - } - void insert_next(const T& t, Circular_Linked_List_Node* that = nullptr) { - if (that == nullptr) that = cur; - auto node = new Circular_Linked_List_Node(); - node->data = t; - node->next = that->next; - node->prev = that; - that->next = node; - } - void insert_prev(const T& t, Circular_Linked_List_Node* that = nullptr) { - if (that == nullptr) that = cur; - auto node = new Circular_Linked_List_Node(); - node->data = t; - node->prev = that->prev; - node->next = that; - that->prev = node; - } - std::vector*> to_vector() { - if (head == nullptr) return {}; - std::vector*> ret; - Circular_Linked_List_Node* cur = head; - do { - ret.push_back(cur); - cur = cur->next; - } - while (cur != head); - return ret; - } - void clear() { - if (head == nullptr) return; - Circular_Linked_List_Node* cur = head; - do { - Circular_Linked_List_Node* temp = cur; - cur = cur->next; - delete temp; - } - while (cur != head); - head = nullptr; - } - ~Circular_Linked_List() { - clear(); - } -}; -} diff --git a/Widget/base/Circular_Linked_List.hpp b/Widget/base/Circular_Linked_List.hpp deleted file mode 100644 index 0e7532c..0000000 --- a/Widget/base/Circular_Linked_List.hpp +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once -Flex_Qt { - template - struct Circular_Linked_List_Node { - Circular_Linked_List_Node *prev = nullptr, *next = nullptr; - T data; - }; - template - class Circular_Linked_List { - public: - Circular_Linked_List_Node* head = nullptr; - Circular_Linked_List_Node* cur = nullptr; - void init(const std::vector& data_list) { - head = new Circular_Linked_List_Node(); - head->data = data_list.front(); - Circular_Linked_List_Node * prev = head; - int n = data_list.size(); - for (int i = 1; i < n - 1; i++) { - auto node = new Circular_Linked_List_Node(); - node->data = data_list[i]; - node->prev = prev; - prev->next = node; - prev = node; - } - auto tail = new Circular_Linked_List_Node(); - tail->data = data_list.back(); - tail->prev = prev; - prev->next = tail; - tail->next = head; - head->prev = tail; - cur = head; - } - Circular_Linked_List_Node* move(int step = 1) { - if (step == 0) - return nullptr; - return step > 0 ? next(step) : prev(-step); - } - Circular_Linked_List_Node* next(int step = 1) { - if (step <= 0) - return nullptr; - for (int i = 0; i < step; i++) { - cur = cur->next; - } - return cur; - } - Circular_Linked_List_Node* prev(int step = 1) { - if (step <= 0) - return nullptr; - for (int i = 0; i < step; i++) { - cur = cur->prev; - } - return cur; - } - void insert_next(const T& t, Circular_Linked_List_Node* that = nullptr) { - if (that == nullptr) - that = cur; - auto node = new Circular_Linked_List_Node(); - node->data = t; - node->next = that->next; - node->prev = that; - that->next = node; - } - void insert_prev(const T& t, Circular_Linked_List_Node* that = nullptr) { - if (that == nullptr) - that = cur; - auto node = new Circular_Linked_List_Node(); - node->data = t; - node->prev = that->prev; - node->next = that; - that->prev = node; - } - std::vector*> to_vector() { - if (head == nullptr) - return {}; - std::vector*> ret; - Circular_Linked_List_Node * cur = head; - do { - ret.push_back(cur); - cur = cur->next; - } - while (cur != head); - return ret; - } - void clear() { - if (head == nullptr) - return; - Circular_Linked_List_Node * cur = head; - do { - Circular_Linked_List_Node * temp = cur; - cur = cur->next; - delete temp; - } - while (cur != head); - head = nullptr; - } - ~Circular_Linked_List() { - clear(); - } - }; -} // Flex_Qt diff --git a/Widget/base/File_Dialog/File_Dialog.cpp b/Widget/base/File_Dialog/File_Dialog.cpp deleted file mode 100644 index ba2b9f1..0000000 --- a/Widget/base/File_Dialog/File_Dialog.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "File_Dialog.h" -#include -namespace Flex_Qt { - File_Dialog::File_Dialog(QWidget * parent) : QWidget(parent) - { - // setAttribute(Qt::WA_OpaquePaintEvent); - } - File_Dialog::~File_Dialog() {} - void File_Folder::draw(int index, QPainter* painter) - { - static QImage file_folder = QImage(":fileFolder.png"); - int x = 10 + 20 * deep; - int y = 10 + 30 * index; - // painter->drawImage(x, y, file_folder); - painter->drawImage(0, 0, file_folder); - painter->drawText(x + 20, y + 10, name); - } - void File_Dialog::paintEvent(QPaintEvent* event) - { - QWidget::paintEvent(event); - QPainter painter(this); - int index = 0; - for (File_Folder*& root : roots) { - std::queue que; - root->deep = 0; - que.push(root); - while (!que.empty()) { - File_Folder* cur = que.front(); - que.pop(); - int n = cur->sons.size(); - cur->draw(index++, &painter); - for (int i = 0; i < n; ++i) { - if (cur->is_show_sons) { - cur->sons[i]->deep = cur->deep + 1; - que.push(cur->sons[i]); - } - } - } - } - painter.end(); - } -} // Flex_Qt diff --git a/Widget/base/File_Dialog/File_Dialog.h b/Widget/base/File_Dialog/File_Dialog.h deleted file mode 100644 index 1c98e34..0000000 --- a/Widget/base/File_Dialog/File_Dialog.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "../global.h" -#include "third_party/Renderive/Widget/base/Node.hpp" -#include "third_party/Renderive/Widget/component/Tree/Tree_Model.h" -namespace Flex_Qt { -class File_Folder : public Node { -public: - QString name; - bool is_show_sons = false; - int deep = 0; - void draw(int index, QPainter* painter); -}; -class File_Dialog : public QWidget, public Node_Manager, public Psc::Singleton { -public: - explicit File_Dialog(QWidget* parent = nullptr); - ~File_Dialog() override; -protected: - void paintEvent(QPaintEvent* event) override; -}; -} // Flex_Qt diff --git a/Widget/base/File_Dialog/icon/FileFolder.qrc b/Widget/base/File_Dialog/icon/FileFolder.qrc deleted file mode 100644 index 86119ff..0000000 --- a/Widget/base/File_Dialog/icon/FileFolder.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - fileFolder.png - arrowDown.png - - \ No newline at end of file diff --git a/Widget/base/File_Dialog/icon/arrowDown.png b/Widget/base/File_Dialog/icon/arrowDown.png deleted file mode 100644 index b56a075..0000000 Binary files a/Widget/base/File_Dialog/icon/arrowDown.png and /dev/null differ diff --git a/Widget/base/File_Dialog/icon/fileFolder.png b/Widget/base/File_Dialog/icon/fileFolder.png deleted file mode 100644 index 68f2f79..0000000 Binary files a/Widget/base/File_Dialog/icon/fileFolder.png and /dev/null differ diff --git a/Widget/base/Generate_Mock_Data.cpp b/Widget/base/Generate_Mock_Data.cpp deleted file mode 100644 index dc9f84f..0000000 --- a/Widget/base/Generate_Mock_Data.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include "Generate_Mock_Data.h" -#include -namespace Flex_Qt { -namespace { -std::default_random_engine& mock_data_random_engine() { - static thread_local std::default_random_engine engine(std::random_device{}()); - return engine; -} -} -void fill_data(Range value_range, std::span output) { - if (value_range.origin > value_range.target) { - std::swap(value_range.origin, value_range.target); - } - std::uniform_real_distribution dist(value_range.origin, value_range.target); - for (auto& value : output) { - value = dist(mock_data_random_engine()); - } -} -std::vector get_data(Range value_range, int size) { - std::vector ret(size); - fill_data(value_range, ret); - return ret; -} -double get_data(Range value_range) { - if (value_range.origin > value_range.target) { - std::swap(value_range.origin, value_range.target); - } - std::uniform_real_distribution dist(value_range.origin, value_range.target); - return dist(mock_data_random_engine()); -} -std::vector get_data(int value, int size) { - std::vector ret(size); - for (auto& v : ret) { - v = value; - } - return ret; -} -std::vector get_colored_data(int size) { - std::vector ret(size); - for (int i = 0; i < size; ++i) { - ret[i] = i; - } - return ret; -} -} // Flex_Qt diff --git a/Widget/base/Generate_Mock_Data.h b/Widget/base/Generate_Mock_Data.h deleted file mode 100644 index 16c0705..0000000 --- a/Widget/base/Generate_Mock_Data.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include -#include -#include "global.h" -#include "third_party/Renderive/Widget/Qt/global.h" -namespace Flex_Qt { -void WIDGET_API fill_data(Range value_range, std::span output); -std::vector WIDGET_API get_data(Range value_range, int size); -double WIDGET_API get_data(Range value_range); -std::vector WIDGET_API get_data(int value, int size); -std::vector WIDGET_API get_colored_data(int size); -} // Flex_Qt diff --git a/Widget/base/Graphic.cpp b/Widget/base/Graphic.cpp deleted file mode 100644 index 7c8442c..0000000 --- a/Widget/base/Graphic.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "Graphic.h" -#include -namespace Flex_Qt { -void Opengl_Renderable::draw() {} -Graphic::Graphic() { - setSurfaceType(OpenGLSurface); -} -bool Graphic::event(QEvent* event) { - bool ret = QWindow::event(event); - switch (event->type()) { - case QEvent::Resize: { - auto e = reinterpret_cast(event); - QSize size = e->size(); - for (Painter_Renderable* b : painter_buffers) { - b->resize_buffers(size); - } - if (first_resize) - first_resize = false; - break; - } - default: { - break; - } - } - return ret; -} -} // Flex_Qt diff --git a/Widget/base/Graphic.h b/Widget/base/Graphic.h deleted file mode 100644 index a14ce67..0000000 --- a/Widget/base/Graphic.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -#include "./global.h" -namespace Flex_Qt { -class WIDGET_API Graphic_Renderable { -public: - virtual ~Graphic_Renderable() = default; -}; -class Painter_Renderable : public Graphic_Renderable { -public: - std::unique_ptr buffer1{}; - std::unique_ptr buffer2{}; - bool it = true; - void resize_buffers(const QSize& size) { - buffer1 = std::make_unique(size); - buffer2 = std::make_unique(size); - } - void draw() { - if (!buffer1 || !buffer2) - return; - it = !it; - QPixmap* cur = it ? buffer1.get() : buffer2.get(); - QPainter painter(cur); - painter.fillRect(cur->rect(), Qt::red); - } - void update_texture() { - QPixmap* cur = it ? buffer1.get() : buffer2.get(); - Q_UNUSED(cur) - } -}; -class WIDGET_API Opengl_Renderable : public Graphic_Renderable { -public: - void draw(); -}; -class Graphic : public QWindow { -public: - Graphic(); - std::vector renderables; - std::vector painter_buffers; - std::vector opengl_buffers; - bool first_resize = true; -protected: - bool event(QEvent*) override; -public: - virtual void create_renderables() {}; - void render() { - if (first_resize) - return; - for (Opengl_Renderable* b : opengl_buffers) { - b->draw(); - } - for (Painter_Renderable* b : painter_buffers) { - b->draw(); - b->update_texture(); - } - } -}; -} // Flex_Qt diff --git a/Widget/base/Node.hpp b/Widget/base/Node.hpp deleted file mode 100644 index 702066c..0000000 --- a/Widget/base/Node.hpp +++ /dev/null @@ -1,113 +0,0 @@ -#pragma once -#include -#include -#include -namespace Flex_Qt { -template -class Node { -public: - explicit Node() = default; - int index() { - if (!father) - return -1; - auto found = std::find(father->sons.begin(), father->sons.end(), static_cast(this)); - return found == father->sons.end() ? -1 : static_cast(std::distance(father->sons.begin(), found)); - } - bool root() { - return !father; - } - bool leaf() { - return sons.empty(); - } - bool first() { - if (!father) - return false; - return this == father->sons.front(); - } - bool last() { - if (!father) - return false; - return this == father->sons.back(); - } - That* previous() { - if (!father) - return nullptr; - int i = index() - 1; - if (i < 0) - return nullptr; - return father->sons[i]; - } - That* next() { - if (!father) - return nullptr; - int i = index() + 1; - if (i < 0 || i >= static_cast(father->sons.size())) - return nullptr; - return father->sons[i]; - } - That* last_child() { - if (sons.empty()) - return nullptr; - return sons.back(); - } - That* first_child() { - if (sons.empty()) - return nullptr; - return sons.front(); - } - That* root_node() { - That* ret = static_cast(this); - while (ret->father != nullptr) { - ret = ret->father; - } - return ret; - } - int deep() { - int result = 0; - That* current = static_cast(this); - while (current->father != nullptr) { - current = current->father; - ++result; - } - return result; - } - // 遍历值 - std::vector deep_traversed() { - std::vector ret; - ret.push_back(static_cast(this)); - for (auto& child : sons) { - std::vector descendants = child->deep_traversed(); - ret.insert(ret.end(), descendants.begin(), descendants.end()); - } - return ret; - } - std::vector sequence_traversed() { - std::vector ret; - std::queue que; - That* that = static_cast(this); - que.push(that); - while (!que.empty()) { - That* cur = que.front(); - que.pop(); - int n = static_cast(cur->sons.size()); - ret.push_back(cur); - for (int i = 0; i < n; ++i) { - que.push(cur->sons[i]); - } - } - return ret; - } - std::vector descendants() { - std::vector&& ret = sequence_traversed(); - ret.erase(ret.begin()); - return ret; - } - That* father = nullptr; - std::vector sons; -}; -template -class Node_Manager { -public: - std::vector roots; -}; -} // Flex_Qt diff --git a/Widget/base/RollObject.h b/Widget/base/RollObject.h deleted file mode 100644 index abf934e..0000000 --- a/Widget/base/RollObject.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef Toolbox_Roll_Widget_H -#define Toolbox_Roll_Widget_H -#include -#include -#include -#include -#include -namespace Flex_Qt { -template -class Roll_Object : QObject { -public: - explicit Roll_Object(QObject* parent = nullptr) : QObject(parent) {} - explicit Roll_Object(std::vector widgets, std::function enter_func, - std::function leave_func, QObject* parent) : - widgets(std::move(widgets)), enter_func(enter_func), leave_func(leave_func), QObject(parent) { - if (!this->widgets.empty() && enter_func) enter_func(this->widgets[index]); - } - int index = 0; - std::vector widgets; - std::function enter_func; - std::function leave_func; - T* cur() { - if (widgets.empty()) return nullptr; - return widgets[index]; - } - void set_cur(T* cur) { - if (widgets.empty()) return; - auto it = std::find(widgets.begin(), widgets.end(), cur); - if (it == widgets.end()) return; - int new_index = static_cast(std::distance(widgets.begin(), it)); - if (leave_func) leave_func(widgets[index]); - index = new_index; - if (enter_func) enter_func(widgets[index]); - widgets[index]->update(); - } - void roll_right() { - if (widgets.empty()) return; - if (leave_func) leave_func(widgets[index]); - widgets[index]->update(); - if (widgets.back() != widgets[index]) { - index++; - } - else { - index = 0; - } - if (enter_func) enter_func(widgets[index]); - widgets[index]->update(); - } - void roll_left() { - if (widgets.empty()) return; - if (leave_func) leave_func(widgets[index]); - widgets[index]->update(); - if (widgets.front() != widgets[index]) { - index--; - } - else { - index = static_cast(widgets.size()) - 1; - } - if (enter_func) enter_func(widgets[index]); - widgets[index]->update(); - } - QHBoxLayout* hbox_layout(int space) { - auto ret = new QHBoxLayout; - ret->setMargin(0); - ret->setSpacing(space); - for (auto widget : widgets) { - ret->addWidget(widget, 1); - } - return ret; - } -}; -} -#endif - - - diff --git a/Widget/base/Roll_Object.h b/Widget/base/Roll_Object.h deleted file mode 100644 index 79488c0..0000000 --- a/Widget/base/Roll_Object.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once -#include "global.h" -namespace Flex_Qt { - template - class Roll_Object : QObject { - public: - explicit Roll_Object(QObject* parent = nullptr) : QObject(parent) {} - explicit Roll_Object(std::vector values, std::function enter, std::function leave, QObject* parent) : QObject(parent), widgets(std::move(values)), enter_func(std::move(enter)), leave_func(std::move(leave)) { - if (enter_func && !widgets.empty()) - enter_func(widgets.front()); - } - int index = 0; - std::vector widgets; - std::function enter_func; - std::function leave_func; - T* cur() { - if (widgets.empty()) - return nullptr; - return widgets[static_cast(index)]; - } - void set_cur(T* value) { - if (widgets.empty()) - return; - auto found = std::find(widgets.begin(), widgets.end(), value); - if (found == widgets.end()) - return; - if (leave_func) - leave_func(widgets[static_cast(index)]); - index = static_cast(std::distance(widgets.begin(), found)); - if (enter_func) - enter_func(widgets[static_cast(index)]); - widgets[static_cast(index)]->update(); - } - void roll_right() { - if (widgets.empty()) - return; - if (leave_func) - leave_func(widgets[static_cast(index)]); - widgets[static_cast(index)]->update(); - index = (index + 1) % static_cast(widgets.size()); - if (enter_func) - enter_func(widgets[static_cast(index)]); - widgets[static_cast(index)]->update(); - } - void roll_left() { - if (widgets.empty()) - return; - if (leave_func) - leave_func(widgets[static_cast(index)]); - widgets[static_cast(index)]->update(); - index = index ? index - 1 : static_cast(widgets.size()) - 1; - if (enter_func) - enter_func(widgets[static_cast(index)]); - widgets[static_cast(index)]->update(); - } - QHBoxLayout* hbox_layout(int space) { - auto ret = new QHBoxLayout; - ret->setMargin(0); - ret->setSpacing(space); - for (T* widget : widgets) - ret->addWidget(widget, 1); - return ret; - } - }; -} // Flex_Qt diff --git a/Widget/base/Select_Color_Dialog/Select_ColorDialog_p.h b/Widget/base/Select_Color_Dialog/Select_ColorDialog_p.h deleted file mode 100644 index 5834148..0000000 --- a/Widget/base/Select_Color_Dialog/Select_ColorDialog_p.h +++ /dev/null @@ -1,327 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Select_Color_Dialog.h" -namespace Flex_Qt { -void rgb2hsv(QRgb rgb, int& h, int& s, int& v); -class Q_Color_Well : public QWidget { - Q_OBJECT -public: - Q_Color_Well(QWidget* parent, int r, int c, const QRgb* vals) : values(vals) { - nrows = r; - ncols = c; - setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); - setFocusPolicy(Qt::StrongFocus); - } - [[nodiscard]] int selected_column() const { - return sel_col; - } - [[nodiscard]] int selected_row() const { - return sel_row; - } - virtual void setCurrent(int row, int col); - virtual void set_selected(int row, int col); - [[nodiscard]] inline int row_at(int y) const { - return y / cellh; - } - [[nodiscard]] inline int column_at(int x) const { - if (isRightToLeft()) - return ncols - (x / cellw) - 1; - return x / cellw; - } - [[nodiscard]] inline int row_y(int row) const { - return cellh * row; - } - [[nodiscard]] inline int column_x(int column) const { - if (isRightToLeft()) - return cellw * (ncols - column - 1); - return cellw * column; - } - [[nodiscard]] inline QRect cell_rect() const { - return {0, 0, cellw, cellh}; - } - [[nodiscard]] inline QSize grid_size() const { - return {ncols * cellw, nrows * cellh}; - } - [[nodiscard]] QRect cell_geometry(int row, int column) const { - QRect r; - if (row >= 0 && row < nrows && column >= 0 && column < ncols) - r.setRect(column_x(column), row_y(row), cellw, cellh); - return r; - } - inline void update_cell(int row, int column) { - update(cell_geometry(row, column)); - } - void paint_cell(QPainter*, int row, int col, const QRect&); - const QRgb* values; - bool mouse_pressed = false; - QPoint press_pos{}; - QPoint old_current{-1, -1}; - int nrows; - int ncols; - int cellw = 28; - int cellh = 24; - int cur_row = 0; - int cur_col = 0; - int sel_row = -1; - int sel_col = -1; - int cell_margin = 3; // margin -signals : - void color_changed(int index, QRgb color); - void selected(int row, int col); - void current_changed(int row, int col); -protected: - void paint_cell_contents(QPainter*, int row, int col, const QRect&); - void mousePressEvent(QMouseEvent* e) override; - void mouseMoveEvent(QMouseEvent* e) override; - void mouseReleaseEvent(QMouseEvent* e) override; - void dragEnterEvent(QDragEnterEvent* e) override; - void dragLeaveEvent(QDragLeaveEvent* e) override; - void dragMoveEvent(QDragMoveEvent* e) override; - void dropEvent(QDropEvent* e) override; - void keyPressEvent(QKeyEvent*) override; - void focusInEvent(QFocusEvent*) override; - void focusOutEvent(QFocusEvent*) override; - void paintEvent(QPaintEvent*) override; - void resizeEvent(QResizeEvent* event) override; -}; -class Q_Color_Picker : public QFrame { - Q_OBJECT -public: - explicit Q_Color_Picker(QWidget* parent); - ~Q_Color_Picker() override; - void set_cross_visible(bool visible); -public -slots : - void set_col(int h, int s); -signals : - void new_col(int h, int s); -protected: - void paintEvent(QPaintEvent*) override; - void mouseMoveEvent(QMouseEvent*) override; - void mousePressEvent(QMouseEvent*) override; - void resizeEvent(QResizeEvent*) override; - int hue; - int sat; - QPoint col_pt(); - int hue_pt(const QPoint& pt); - int sat_pt(const QPoint& pt); - void set_col(const QPoint& pt); - QPixmap pix; - bool cross_visible; -}; -class Q_Color_Luminance_Picker : public QWidget { - Q_OBJECT -public: - explicit Q_Color_Luminance_Picker(QWidget* parent = nullptr); - ~Q_Color_Luminance_Picker() override; -public -slots : - void set_col(int h, int s, int v); - void set_col(int h, int s); -signals : - void new_hsv(int h, int s, int v); -protected: - void paintEvent(QPaintEvent*) override; - void mouseMoveEvent(QMouseEvent*) override; - void mousePressEvent(QMouseEvent*) override; - enum { - foff = 3, - coff = 4 - }; // frame and contents offset - int val; - int hue; - int sat; - int y_to_val(int y); - int val_to_y(int val); - void set_val(int v); - QPixmap* pix; -}; -class Q_Col_Spin_Box : public QSpinBox { -public: - explicit Q_Col_Spin_Box(QWidget* parent) : QSpinBox(parent) { - setRange(0, 255); - } - void setValue(int i) { - const QSignalBlocker blocker(this); - QSpinBox::setValue(i); - } -}; -class Q_Color_Show_Label; -class Q_Color_Shower : public QWidget { - Q_OBJECT -public: - explicit Q_Color_Shower(Select_Color_Dialog* parent); - void set_hsv(int h, int s, int v); - [[nodiscard]] int current_alpha() const { - return alpha_ed->value(); - } - void set_current_alpha(int a) { - alpha_ed->setValue(a); - rgb_ed(); - } - void show_alpha(bool b); - [[nodiscard]] bool is_alpha_visible() const; - [[nodiscard]] QRgb current_color() const { - return cur_col; - } - [[nodiscard]] QColor current_q_color() const { - return cur_q_color; - } - void retranslate_strings(); - void update_q_color(); -public -slots : - void set_rgb(QRgb rgb); -signals : - void new_col(QRgb rgb); - void current_color_changed(const QColor& color); -private -slots : - void rgb_ed(); - void hsv_ed(); - void html_ed(); -private: - void show_current_color(); - int hue{}, sat{}, val{}; - QRgb cur_col; - QColor cur_q_color; - QLabel* lbl_hue{}; - QLabel* lbl_sat{}; - QLabel* lbl_val{}; - QLabel* lbl_red{}; - QLabel* lbl_green{}; - QLabel* lbl_blue{}; - QLabel* lbl_html{}; - Q_Col_Spin_Box* h_ed{}; - Q_Col_Spin_Box* s_ed{}; - Q_Col_Spin_Box* v_ed{}; - Q_Col_Spin_Box* r_ed{}; - Q_Col_Spin_Box* g_ed{}; - Q_Col_Spin_Box* b_ed{}; - Q_Col_Spin_Box* alpha_ed{}; - QLabel* alpha_lab{}; - QLineEdit* ht_ed{}; - Q_Color_Show_Label* lab{}; - bool rgb_original{}; - Select_Color_Dialog* color_dialog{}; - QGridLayout* gl{}; -}; -class Q_Color_Show_Label : public QFrame { - Q_OBJECT -public: - explicit Q_Color_Show_Label(QWidget* parent) : QFrame(parent) { - setFrameStyle(QFrame::Panel | QFrame::Sunken); - setAcceptDrops(true); - mouse_pressed = false; - } - void set_color(QColor c) { - col = std::move(c); - } -signals : - void color_dropped(QRgb); -protected: - void paintEvent(QPaintEvent*) override; - void mousePressEvent(QMouseEvent* e) override; - void mouseMoveEvent(QMouseEvent* e) override; - void mouseReleaseEvent(QMouseEvent* e) override; - void dragEnterEvent(QDragEnterEvent* e) override; - void dragLeaveEvent(QDragLeaveEvent* e) override; - void dropEvent(QDropEvent* e) override; - QColor col; - bool mouse_pressed; - QPoint press_pos; -}; -class Select_Color_Dialog_Private; -class Q_Color_Picking_Event_Filter : public QWindow { -public: - // #如果出现黑屏的情况可能是开启了wayland, - // sudo nano /etc/gdm3/custom.conf - QColor grab_screen_color(const QPoint& p) { - // 获取当前的屏幕对象 - QScreen* screen = QGuiApplication::screenAt(p); // 获取光标所在的屏幕 - if (!screen) { - std::cout << "如果未能找到屏幕,返回无效颜色"; - return QColor(); - } - // 截取屏幕上 (p.x(), p.y()) 坐标的 1x1 区域 - QPixmap pixmap = screen->grabWindow(0, p.x(), p.y(), 1, 1); - QImage image = pixmap.toImage(); - if (image.isNull()) { - std::cout << "如果无法获取图像,返回无效颜色"; - return QColor(); - } - return image.pixelColor(0, 0); // 返回 (0, 0) 位置的颜色 - } - explicit Q_Color_Picking_Event_Filter(Select_Color_Dialog_Private* dp) : m_dp(dp) { - resize(200, 200); - // setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool); - setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool); - // setAttribute(Qt::WA_TranslucentBackground); - // setWindowOpacity(0.0); - setVisible(false); - } - void update_pos(); - bool eventFilter(QObject*, QEvent* event) override; - void start_get_screen(); - void stop_get_screen(); -protected: - Select_Color_Dialog_Private* m_dp; -}; -class Select_Color_Dialog_Private { -public: - enum { - color_columns = 8, - standardColorRows = 6, - customColorRows = 2 - }; - enum Set_Color_Mode { - ShowColor = 0x1, - SelectColor = 0x2, - SetColorAll = ShowColor | SelectColor - }; - QRgb standard_rgb[standardColorRows * color_columns]{}, customRgb[customColorRows * color_columns]{}; - Select_Color_Dialog* q{}; - Q_Color_Shower* cs{}; - Q_Color_Well *standard{}, *custom{}; - Q_Color_Picker* cp{}; - Q_Color_Luminance_Picker* lp{}; - Q_Color_Picking_Event_Filter* q_color_picking_event_filter{}; - ~Select_Color_Dialog_Private() { - delete q_color_picking_event_filter; - } - explicit Select_Color_Dialog_Private(Select_Color_Dialog* select_color_dialog); - void set_current_color(const QColor& color) const { - auto rgb = color.rgb(); - int h, s, v; - rgb2hsv(rgb, h, s, v); - cp->set_col(h, s); - lp->set_col(h, s, v); - cs->set_rgb(rgb); - } - QColor current_color() { - return cs->current_color(); - } -}; -} // Flex_Qt diff --git a/Widget/base/Select_Color_Dialog/Select_Color_Dialog.cpp b/Widget/base/Select_Color_Dialog/Select_Color_Dialog.cpp deleted file mode 100644 index a442ae8..0000000 --- a/Widget/base/Select_Color_Dialog/Select_Color_Dialog.cpp +++ /dev/null @@ -1,922 +0,0 @@ -#include -#include "Select_ColorDialog_p.h" -namespace Flex_Qt { - void rgb2hsv(QRgb rgb, int& h, int& s, int& v) - { - QColor c; - c.setRgb(rgb); - c.getHsv(&h, &s, &v); - } - void Q_Color_Well::paintEvent(QPaintEvent* e) - { - QRect r = e->rect(); - int cx = r.x(); - int cy = r.y(); - int ch = r.height(); - int cw = r.width(); - int colfirst = column_at(cx); - int collast = column_at(cx + cw); - int rowfirst = row_at(cy); - int rowlast = row_at(cy + ch); - if (isRightToLeft()) { - int t = colfirst; - colfirst = collast; - collast = t; - } - QPainter painter(this); - QPainter* p = &painter; - QRect rect(0, 0, cellw, cellh); - if (collast < 0 || collast >= ncols) - collast = ncols - 1; - if (rowlast < 0 || rowlast >= nrows) - rowlast = nrows - 1; - // Go through the rows - for (int r = rowfirst; r <= rowlast; ++r) { - // get row position and height - int rowp = row_y(r); - // Go through the columns in the row r - // if we know from where to where, go through [colfirst, collast], - // else go through all of them - for (int c = colfirst; c <= collast; ++c) { - // get position and width of column c - int colp = column_x(c); - // Translate painter and draw the cell - rect.translate(colp, rowp); - paint_cell(p, r, c, rect); - rect.translate(-colp, -rowp); - } - } - } - void Q_Color_Well::resizeEvent(QResizeEvent* event) - { - // std::cout << "sizeHint == " << size(); - cellw = width() / ncols; - cellh = height() / nrows; - if (cellw > cellh) - cellw = cellh; - if (cellh > cellw) - cellh = cellw; - QWidget::resizeEvent(event); - } - void Q_Color_Well::paint_cell(QPainter* p, int row, int col, const QRect& rect) - { - const QPalette& g = palette(); - QStyleOptionFrame opt; - opt.initFrom(this); - int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt); - opt.lineWidth = dfw; - opt.midLineWidth = 1; - opt.rect = rect.adjusted(cell_margin, cell_margin, -cell_margin, -cell_margin); - opt.palette = g; - opt.state = QStyle::State_Enabled | QStyle::State_Sunken; - style()->drawPrimitive(QStyle::PE_Frame, &opt, p, this); - // cell_margin += dfw; - if ((row == cur_row) && (col == cur_col)) { - // if (hasFocus()) - // { - QStyleOptionFocusRect opt; - opt.palette = g; - opt.rect = rect; - opt.state = QStyle::State_None | QStyle::State_KeyboardFocusChange; - style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, this); - // } - } - paint_cell_contents(p, row, col, opt.rect.adjusted(dfw, dfw, -dfw, -dfw)); - } - /* - Sets the cell currently having the focus. This is not necessarily - the same as the currently selected cell. -*/ - void Q_Color_Well::setCurrent(int row, int col) - { - if ((cur_row == row) && (cur_col == col)) - return; - if (row < 0 || col < 0) - row = col = -1; - int old_row = cur_row; - int old_col = cur_col; - cur_row = row; - cur_col = col; - update_cell(old_row, old_col); - update_cell(cur_row, cur_col); - emit current_changed(cur_row, cur_col); - } - /* - Sets the currently selected cell to \a row, \a column. If \a row or - \a column are less than zero, the current cell is unselected. - - Does not set the position of the focus indicator. -*/ - void Q_Color_Well::set_selected(int row, int col) - { - int old_row = sel_row; - int old_col = sel_col; - if (row < 0 || col < 0) - row = col = -1; - sel_col = col; - sel_row = row; - update_cell(old_row, old_col); - update_cell(sel_row, sel_col); - if (row >= 0) { - emit selected(row, col); - } -#if QT_CONFIG(menu) - if (isVisible() && qobject_cast(parentWidget())) - parentWidget()->close(); -#endif - } - void Q_Color_Well::focusInEvent(QFocusEvent*) - { - update_cell(cur_row, cur_col); - emit current_changed(cur_row, cur_col); - } - void Q_Color_Well::focusOutEvent(QFocusEvent*) - { - update_cell(cur_row, cur_col); - } - void Q_Color_Well::keyPressEvent(QKeyEvent* e) - { - switch (e->key()) { - // Look at the key code - case Qt::Key_Left: // If 'left arrow'-key, - if (cur_col > 0) // and cr't not in leftmost col - setCurrent(cur_row, cur_col - 1); // set cr't to next left column - break; - case Qt::Key_Right: // Correspondingly... - if (cur_col < ncols - 1) - setCurrent(cur_row, cur_col + 1); - break; - case Qt::Key_Up: - if (cur_row > 0) - setCurrent(cur_row - 1, cur_col); - break; - case Qt::Key_Down: - if (cur_row < nrows - 1) - setCurrent(cur_row + 1, cur_col); - break; -#if 0 - // bad idea that shouldn't have been implemented; very counterintuitive - case Qt::Key_Return: - case Qt::Key_Enter: - /* - ignore the key, so that the dialog get it, but still select - the current row/col - */ - e->ignore(); - // fallthrough intended -#endif - case Qt::Key_Space: - set_selected(cur_row, cur_col); - break; - default: // If not an interesting key, - e->ignore(); // we don't accept the event - return; - } - } - int Q_Color_Luminance_Picker::y_to_val(int y) - { - int d = height() - 2 * coff - 1; - return 255 - (y - coff) * 255 / d; - } - int Q_Color_Luminance_Picker::val_to_y(int v) - { - int d = height() - 2 * coff - 1; - return coff + (255 - v) * d / 255; - } - Q_Color_Luminance_Picker::Q_Color_Luminance_Picker(QWidget * parent) : QWidget(parent) - { - hue = 100; - val = 100; - sat = 100; - pix = nullptr; - // setAttribute(WA_NoErase, true); - } - Q_Color_Luminance_Picker::~Q_Color_Luminance_Picker() - { - delete pix; - } - void Q_Color_Luminance_Picker::mouseMoveEvent(QMouseEvent* m) - { - set_val(y_to_val(m->y())); - } - void Q_Color_Luminance_Picker::mousePressEvent(QMouseEvent* m) - { - set_val(y_to_val(m->y())); - } - void Q_Color_Luminance_Picker::set_val(int v) - { - if (val == v) - return; - val = qMax(0, qMin(v, 255)); - delete pix; - pix = nullptr; - repaint(); - emit new_hsv(hue, sat, val); - } - // receives from a hue,sat chooser and relays. - void Q_Color_Luminance_Picker::set_col(int h, int s) - { - set_col(h, s, val); - emit new_hsv(h, s, val); - } - void Q_Color_Luminance_Picker::paintEvent(QPaintEvent*) - { - int w = width() - 5; - QRect r(0, foff, w, height() - 2 * foff); - int wi = r.width() - 2; - int hi = r.height() - 2; - if (!pix || pix->height() != hi || pix->width() != wi) { - delete pix; - QImage img(wi, hi, QImage::Format_RGB32); - int y; - uint* pixel = (uint*)img.scanLine(0); - for (y = 0; y < hi; y++) { - uint* end = pixel + wi; - std::fill(pixel, end, QColor::fromHsv(hue, sat, y_to_val(y + coff)).rgb()); - pixel = end; - } - pix = new QPixmap(QPixmap::fromImage(img)); - } - QPainter p(this); - p.drawPixmap(1, coff, *pix); - const QPalette& g = palette(); - qDrawShadePanel(&p, r, g, true); - p.setPen(g.windowText().color()); - p.setBrush(g.windowText()); - QPolygon a; - int y = val_to_y(val); - a.setPoints(3, w, y, w + 5, y + 5, w + 5, y - 5); - p.eraseRect(w, 0, 5, height()); - p.drawPolygon(a); - } - void Q_Color_Luminance_Picker::set_col(int h, int s, int v) - { - val = v; - hue = h; - sat = s; - delete pix; - pix = nullptr; - repaint(); - } - QPoint Q_Color_Picker::col_pt() - { - QRect r = contentsRect(); - return QPoint((360 - hue) * (r.width() - 1) / 360, (255 - sat) * (r.height() - 1) / 255); - } - int Q_Color_Picker::hue_pt(const QPoint& pt) - { - QRect r = contentsRect(); - return 360 - pt.x() * 360 / (r.width() - 1); - } - int Q_Color_Picker::sat_pt(const QPoint& pt) - { - QRect r = contentsRect(); - return 255 - pt.y() * 255 / (r.height() - 1); - } - void Q_Color_Picker::set_col(const QPoint& pt) - { - set_col(hue_pt(pt), sat_pt(pt)); - } - Q_Color_Picker::Q_Color_Picker(QWidget * parent) : QFrame(parent), cross_visible(true) - { - hue = 0; - sat = 0; - set_col(150, 255); - setAttribute(Qt::WA_NoSystemBackground); - // setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); - } - Q_Color_Picker::~Q_Color_Picker() = default; - void Q_Color_Picker::set_cross_visible(bool visible) - { - if (cross_visible != visible) { - cross_visible = visible; - update(); - } - } - void Q_Color_Picker::set_col(int h, int s) - { - int nhue = qMin(qMax(0, h), 359); - int nsat = qMin(qMax(0, s), 255); - if (nhue == hue && nsat == sat) - return; - QRect r(col_pt(), QSize(20, 20)); - hue = nhue; - sat = nsat; - r = r.united(QRect(col_pt(), QSize(20, 20))); - r.translate(contentsRect().x() - 9, contentsRect().y() - 9); - // update(r); - repaint(r); - } - void Q_Color_Picker::mouseMoveEvent(QMouseEvent* m) - { - QPoint p = m->pos() - contentsRect().topLeft(); - set_col(p); - emit new_col(hue, sat); - } - void Q_Color_Picker::mousePressEvent(QMouseEvent* m) - { - QPoint p = m->pos() - contentsRect().topLeft(); - set_col(p); - emit new_col(hue, sat); - } - void Q_Color_Picker::paintEvent(QPaintEvent*) - { - QPainter p(this); - drawFrame(&p); - QRect r = contentsRect(); - p.drawPixmap(r.topLeft(), pix); - if (cross_visible) { - QPoint pt = col_pt() + r.topLeft(); - p.setPen(Qt::black); - p.fillRect(pt.x() - 9, pt.y(), 20, 2, Qt::black); - p.fillRect(pt.x(), pt.y() - 9, 2, 20, Qt::black); - } - } - void Q_Color_Picker::resizeEvent(QResizeEvent* ev) - { - QFrame::resizeEvent(ev); - int w = width() - frameWidth() * 2; - int h = height() - frameWidth() * 2; - QImage img(w, h, QImage::Format_RGB32); - int x, y; - uint* pixel = (uint*)img.scanLine(0); - for (y = 0; y < h; y++) { - const uint* end = pixel + w; - x = 0; - while (pixel < end) { - QPoint p(x, y); - QColor c; - c.setHsv(hue_pt(p), sat_pt(p), 200); - *pixel = c.rgb(); - ++pixel; - ++x; - } - } - pix = QPixmap::fromImage(img); - } - void Q_Color_Show_Label::paintEvent(QPaintEvent* e) - { - QPainter p(this); - drawFrame(&p); - p.fillRect(contentsRect() & e->rect(), col); - } - void Q_Color_Shower::show_alpha(bool b) - { - alpha_lab->setVisible(b); - alpha_ed->setVisible(b); - } - inline bool Q_Color_Shower::is_alpha_visible() const - { - return alpha_lab->isVisible(); - } - void Q_Color_Show_Label::mousePressEvent(QMouseEvent* e) - { - mouse_pressed = true; - press_pos = e->pos(); - } - void Q_Color_Show_Label::mouseMoveEvent(QMouseEvent* e) - { -#if !QT_CONFIG(draganddrop) - Q_UNUSED(e); -#else - if (!mouse_pressed) - return; - if ((press_pos - e->pos()).manhattanLength() > QApplication::startDragDistance()) { - QMimeData* mime = new QMimeData; - mime->setColorData(col); - QPixmap pix(30, 20); - pix.fill(col); - QPainter p(&pix); - p.drawRect(0, 0, pix.width() - 1, pix.height() - 1); - p.end(); - QDrag* drg = new QDrag(this); - drg->setMimeData(mime); - drg->setPixmap(pix); - mouse_pressed = false; - drg->exec(Qt::CopyAction); - } -#endif - } - void Q_Color_Show_Label::dragEnterEvent(QDragEnterEvent* e) - { - if (qvariant_cast(e->mimeData()->colorData()).isValid()) - e->accept(); - else - e->ignore(); - } - void Q_Color_Show_Label::dragLeaveEvent(QDragLeaveEvent*) {} - void Q_Color_Show_Label::dropEvent(QDropEvent* e) - { - QColor color = qvariant_cast(e->mimeData()->colorData()); - if (color.isValid()) { - col = color; - repaint(); - emit color_dropped(col.rgb()); - e->accept(); - } - else { - e->ignore(); - } - } - void Q_Color_Picking_Event_Filter::update_pos() - { - QPoint mouse_pos = QCursor::pos(); - setPosition(mouse_pos + QPoint{-100, -100}); - // move(mouse_pos + QPoint{-100, -100}); - QColor color = grab_screen_color(mouse_pos); - // std::cout << color; - m_dp->cs->set_rgb(color.rgb()); - } - bool Q_Color_Picking_Event_Filter::eventFilter(QObject* object, QEvent* event) - { - switch (event->type()) { - case QEvent::MouseMove: { - update_pos(); - return true; - break; - } - case QEvent::MouseButtonPress: { - stop_get_screen(); - return true; - break; - } - case QEvent::KeyPress: { - QKeyEvent* key_event = static_cast(event); - if (key_event->key() == Qt::Key_Escape) { - // std::cout << "Escape pressed, stopping color picking"; - stop_get_screen(); - } - break; - } - default: - break; - } - return false; // Don't block the event from reaching the rest of the application - } - void Q_Color_Picking_Event_Filter::start_get_screen() - { - auto q = m_dp->q; - q->setMouseTracking(true); - q->grabKeyboard(); - q->grabMouse(Qt::CrossCursor); - QApplication::instance()->installEventFilter(this); -#ifdef WIN32 - this->show(); -#endif - update_pos(); - } - void Q_Color_Picking_Event_Filter::stop_get_screen() - { - auto q = m_dp->q; - q->setMouseTracking(false); - q->releaseKeyboard(); - q->releaseMouse(); - QApplication::instance()->removeEventFilter(this); -#ifdef WIN32 - this->hide(); -#endif - } - Select_Color_Dialog_Private::Select_Color_Dialog_Private(Select_Color_Dialog * select_color_dialog) : q(select_color_dialog) - { - q_color_picking_event_filter = new Q_Color_Picking_Event_Filter(this); - auto main_lay = new QVBoxLayout(select_color_dialog); - auto up_lay = new QHBoxLayout; - auto low_lay = new QHBoxLayout; - main_lay->addLayout(up_lay); - main_lay->addLayout(low_lay); - auto left_lay = new QVBoxLayout; - auto right_lay = new QVBoxLayout; - up_lay->addLayout(left_lay, 3); - up_lay->addLayout(right_lay, 4); - auto h = new QHBoxLayout; - right_lay->addLayout(h, 4); - int i = 0; - for (int g = 0; g < 4; ++g) - for (int r = 0; r < 4; ++r) - for (int b = 0; b < 3; ++b) - standard_rgb[i++] = qRgb(r * 255 / 3, g * 255 / 3, b * 255 / 2); - std::fill(customRgb, customRgb + customColorRows * color_columns, 0xffffffff); - standard = new Q_Color_Well(q, standardColorRows, color_columns, standard_rgb); - custom = new Q_Color_Well(q, customColorRows, color_columns, customRgb); - auto lbl_basic_colors = new QLabel("基本颜色:"); - lbl_basic_colors->setBuddy(standard); - left_lay->addWidget(lbl_basic_colors); - left_lay->addWidget(standard, 6); - auto screen_color_picker_button = new QPushButton("选择屏幕颜色"); - left_lay->addWidget(screen_color_picker_button); - auto lbl_custom_colors = new QLabel("自定义颜色:"); - left_lay->addWidget(lbl_custom_colors); - left_lay->addWidget(custom, 2); - auto add_cus_bt = new QPushButton("添加当前颜色为自定义颜色"); - QObject::connect(add_cus_bt, &QPushButton::clicked, [this]() { - const int i = custom->cur_row + customColorRows * custom->cur_col; - customRgb[i] = cs->current_color(); - custom->update_cell(custom->cur_row, custom->cur_col); - }); - auto add_current = new QPushButton("添加自定义为当前颜色"); - QObject::connect(add_current, &QPushButton::clicked, [this]() { - const int i = custom->cur_row + customColorRows * custom->cur_col; - if (i > 0 && i < customColorRows * color_columns) { - cs->set_rgb(customRgb[i]); - } - }); - left_lay->addWidget(add_cus_bt); - left_lay->addWidget(add_current); - cp = new Q_Color_Picker(q); - cp->setFrameStyle(QFrame::Panel + QFrame::Sunken); - h->addWidget(cp, 11); - lp = new Q_Color_Luminance_Picker(q); - h->addWidget(lp, 1); - cs = new Q_Color_Shower(q); - right_lay->addWidget(cs, 3); - auto select_null = new QPushButton("选择空"); - auto ok = new QPushButton("确定"); - auto cancel = new QPushButton("取消"); - low_lay->addWidget(select_null); - low_lay->addWidget(ok); - low_lay->addWidget(cancel); - QObject::connect(select_null, &QPushButton::clicked, [this]() { - void finished(int result); - q->emit - finished(-1); - }); - QObject::connect(ok, &QPushButton::clicked, [this]() { - q->emit - accept(); - }); - QObject::connect(cancel, &QPushButton::clicked, [this]() { - q->emit - reject(); - }); - QObject::connect(screen_color_picker_button, &QPushButton::clicked, [this]() { - q_color_picking_event_filter->start_get_screen(); - }); - QObject::connect(standard, &Q_Color_Well::current_changed, [this](int r, int c) { - const int i = r + standardColorRows * c; - set_current_color(standard_rgb[i]); - }); - QObject::connect(cp, SIGNAL(new_col(int, int)), lp, SLOT(set_col(int, int))); - QObject::connect(lp, &Q_Color_Luminance_Picker::new_hsv, q, [this](int h, int s, int v) { - cs->set_hsv(h, s, v); - cp->set_col(h, s); - lp->set_col(h, s, v); - }); - } - void Q_Color_Show_Label::mouseReleaseEvent(QMouseEvent*) - { - if (!mouse_pressed) - return; - mouse_pressed = false; - } - Q_Color_Shower::Q_Color_Shower(Select_Color_Dialog * parent) : QWidget(parent) - { - color_dialog = parent; - cur_col = qRgb(255, 255, 255); - cur_q_color = Qt::white; - gl = new QGridLayout(this); - const int s = gl->spacing(); - gl->setContentsMargins(s, s, s, s); - lab = new Q_Color_Show_Label(this); -#ifdef QT_SMALL_COLORDIALOG - lab->setMinimumHeight(60); -#endif - lab->setMinimumWidth(60); - // For QVGA screens only the comboboxes and color label are visible. - // For n_hd screens only color and luminence pickers and color label are visible. -#if !defined(QT_SMALL_COLORDIALOG) - gl->addWidget(lab, 0, 0, -1, 1); -#else - gl->addWidget(lab, 0, 0, 1, -1); -#endif - connect(lab, SIGNAL(color_dropped(QRgb)), this, SIGNAL(new_col(QRgb))); - connect(lab, SIGNAL(color_dropped(QRgb)), this, SLOT(set_rgb(QRgb))); - h_ed = new Q_Col_Spin_Box(this); - h_ed->setRange(0, 359); - lbl_hue = new QLabel(this); -#ifndef QT_NO_SHORTCUT - lbl_hue->setBuddy(h_ed); -#endif - lbl_hue->setAlignment(Qt::AlignRight | Qt::AlignVCenter); -#if !defined(QT_SMALL_COLORDIALOG) - gl->addWidget(lbl_hue, 0, 1); - gl->addWidget(h_ed, 0, 2); -#else - gl->addWidget(lbl_hue, 1, 0); - gl->addWidget(h_ed, 2, 0); -#endif - s_ed = new Q_Col_Spin_Box(this); - lbl_sat = new QLabel(this); -#ifndef QT_NO_SHORTCUT - lbl_sat->setBuddy(s_ed); -#endif - lbl_sat->setAlignment(Qt::AlignRight | Qt::AlignVCenter); -#if !defined(QT_SMALL_COLORDIALOG) - gl->addWidget(lbl_sat, 1, 1); - gl->addWidget(s_ed, 1, 2); -#else - gl->addWidget(lbl_sat, 1, 1); - gl->addWidget(s_ed, 2, 1); -#endif - v_ed = new Q_Col_Spin_Box(this); - lbl_val = new QLabel(this); -#ifndef QT_NO_SHORTCUT - lbl_val->setBuddy(v_ed); -#endif - lbl_val->setAlignment(Qt::AlignRight | Qt::AlignVCenter); -#if !defined(QT_SMALL_COLORDIALOG) - gl->addWidget(lbl_val, 2, 1); - gl->addWidget(v_ed, 2, 2); -#else - gl->addWidget(lbl_val, 1, 2); - gl->addWidget(v_ed, 2, 2); -#endif - r_ed = new Q_Col_Spin_Box(this); - lbl_red = new QLabel(this); -#ifndef QT_NO_SHORTCUT - lbl_red->setBuddy(r_ed); -#endif - lbl_red->setAlignment(Qt::AlignRight | Qt::AlignVCenter); -#if !defined(QT_SMALL_COLORDIALOG) - gl->addWidget(lbl_red, 0, 3); - gl->addWidget(r_ed, 0, 4); -#else - gl->addWidget(lbl_red, 3, 0); - gl->addWidget(r_ed, 4, 0); -#endif - g_ed = new Q_Col_Spin_Box(this); - lbl_green = new QLabel(this); -#ifndef QT_NO_SHORTCUT - lbl_green->setBuddy(g_ed); -#endif - lbl_green->setAlignment(Qt::AlignRight | Qt::AlignVCenter); -#if !defined(QT_SMALL_COLORDIALOG) - gl->addWidget(lbl_green, 1, 3); - gl->addWidget(g_ed, 1, 4); -#else - gl->addWidget(lbl_green, 3, 1); - gl->addWidget(g_ed, 4, 1); -#endif - b_ed = new Q_Col_Spin_Box(this); - lbl_blue = new QLabel(this); -#ifndef QT_NO_SHORTCUT - lbl_blue->setBuddy(b_ed); -#endif - lbl_blue->setAlignment(Qt::AlignRight | Qt::AlignVCenter); -#if !defined(QT_SMALL_COLORDIALOG) - gl->addWidget(lbl_blue, 2, 3); - gl->addWidget(b_ed, 2, 4); -#else - gl->addWidget(lbl_blue, 3, 2); - gl->addWidget(b_ed, 4, 2); -#endif - alpha_ed = new Q_Col_Spin_Box(this); - alpha_lab = new QLabel(this); -#ifndef QT_NO_SHORTCUT - alpha_lab->setBuddy(alpha_ed); -#endif - alpha_lab->setAlignment(Qt::AlignRight | Qt::AlignVCenter); -#if !defined(QT_SMALL_COLORDIALOG) - gl->addWidget(alpha_lab, 3, 1, 1, 3); - gl->addWidget(alpha_ed, 3, 4); -#else - gl->addWidget(alpha_lab, 1, 3, 3, 1); - gl->addWidget(alpha_ed, 4, 3); -#endif - alpha_ed->hide(); - alpha_lab->hide(); - lbl_html = new QLabel(this); - ht_ed = new QLineEdit(this); -#ifndef QT_NO_SHORTCUT - lbl_html->setBuddy(ht_ed); -#endif -#if QT_CONFIG(regularexpression) - QRegularExpression reg_exp(QStringLiteral("#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})")); - QRegularExpressionValidator* validator = new QRegularExpressionValidator(reg_exp, this); - ht_ed->setValidator(validator); -#elif !defined(QT_NO_REGEXP) - QRegExp reg_exp(QStringLiteral("#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})")); - QRegExpValidator* validator = new QRegExpValidator(reg_exp, this); - ht_ed->setValidator(validator); -#else - ht_ed->setReadOnly(true); -#endif - ht_ed->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); - lbl_html->setAlignment(Qt::AlignRight | Qt::AlignVCenter); -#if defined(QT_SMALL_COLORDIALOG) - gl->addWidget(lbl_html, 5, 0); - gl->addWidget(ht_ed, 5, 1, 1, /*colspan=*/2); -#else - gl->addWidget(lbl_html, 5, 1); - gl->addWidget(ht_ed, 5, 2, 1, /*colspan=*/3); -#endif - connect(h_ed, SIGNAL(valueChanged(int)), this, SLOT(hsv_ed())); - connect(s_ed, SIGNAL(valueChanged(int)), this, SLOT(hsv_ed())); - connect(v_ed, SIGNAL(valueChanged(int)), this, SLOT(hsv_ed())); - connect(r_ed, SIGNAL(valueChanged(int)), this, SLOT(rgb_ed())); - connect(g_ed, SIGNAL(valueChanged(int)), this, SLOT(rgb_ed())); - connect(b_ed, SIGNAL(valueChanged(int)), this, SLOT(rgb_ed())); - connect(alpha_ed, SIGNAL(valueChanged(int)), this, SLOT(rgb_ed())); - connect(ht_ed, SIGNAL(textEdited(QString)), this, SLOT(html_ed())); - retranslate_strings(); - } - void Q_Color_Well::paint_cell_contents(QPainter* p, int row, int col, const QRect& r) - { - int i = row + col * nrows; - p->fillRect(r, QColor(values[i])); - } - void Q_Color_Well::mousePressEvent(QMouseEvent* e) - { - old_current = QPoint(selected_row(), selected_column()); - QPoint pos = e->pos(); - setCurrent(row_at(pos.y()), column_at(pos.x())); - mouse_pressed = true; - press_pos = e->pos(); - } - void Q_Color_Well::mouseMoveEvent(QMouseEvent* e) - { -#if QT_CONFIG(draganddrop) - if (!mouse_pressed) - return; - if ((press_pos - e->pos()).manhattanLength() > QApplication::startDragDistance()) { - setCurrent(old_current.x(), old_current.y()); - int i = row_at(press_pos.y()) + column_at(press_pos.x()) * nrows; - QColor col(values[i]); - QMimeData* mime = new QMimeData; - mime->setColorData(col); - QPixmap pix(cellw, cellh); - pix.fill(col); - QPainter p(&pix); - p.drawRect(0, 0, pix.width() - 1, pix.height() - 1); - p.end(); - QDrag* drg = new QDrag(this); - drg->setMimeData(mime); - drg->setPixmap(pix); - mouse_pressed = false; - drg->exec(Qt::CopyAction); - } -#endif - } -#if QT_CONFIG(draganddrop) - void Q_Color_Well::dragEnterEvent(QDragEnterEvent* e) { - if (qvariant_cast(e->mimeData()->colorData()).isValid()) - e->accept(); - else - e->ignore(); - } - void Q_Color_Well::dragLeaveEvent(QDragLeaveEvent*) { - if (hasFocus()) - parentWidget()->setFocus(); - } - void Q_Color_Well::dragMoveEvent(QDragMoveEvent* e) { - if (qvariant_cast(e->mimeData()->colorData()).isValid()) { - setCurrent(row_at(e->pos().y()), column_at(e->pos().x())); - e->accept(); - } - else { - e->ignore(); - } - } - void Q_Color_Well::dropEvent(QDropEvent* e) { - QColor col = qvariant_cast(e->mimeData()->colorData()); - if (col.isValid()) { - int i = row_at(e->pos().y()) + column_at(e->pos().x()) * nrows; - emit color_changed(i, col.rgb()); - e->accept(); - } - else { - e->ignore(); - } - } -#endif // QT_CONFIG(draganddrop) - void Q_Color_Well::mouseReleaseEvent(QMouseEvent* e) - { - if (!mouse_pressed) - return; - set_selected(cur_row, cur_col); - mouse_pressed = false; - } - void Q_Color_Shower::rgb_ed() - { - rgb_original = true; - cur_col = qRgba(r_ed->value(), g_ed->value(), b_ed->value(), current_alpha()); - rgb2hsv(current_color(), hue, sat, val); - h_ed->setValue(hue); - s_ed->setValue(sat); - v_ed->setValue(val); - ht_ed->setText(QColor(cur_col).name()); - show_current_color(); - emit new_col(current_color()); - update_q_color(); - } - void Q_Color_Shower::hsv_ed() - { - rgb_original = false; - hue = h_ed->value(); - sat = s_ed->value(); - val = v_ed->value(); - QColor c; - c.setHsv(hue, sat, val); - cur_col = c.rgb(); - r_ed->setValue(qRed(current_color())); - g_ed->setValue(qGreen(current_color())); - b_ed->setValue(qBlue(current_color())); - ht_ed->setText(c.name()); - show_current_color(); - emit new_col(current_color()); - update_q_color(); - } - void Q_Color_Shower::html_ed() - { - QColor c; - QString t = ht_ed->text(); - c.setNamedColor(t); - if (!c.isValid()) - return; - cur_col = qRgba(c.red(), c.green(), c.blue(), current_alpha()); - rgb2hsv(cur_col, hue, sat, val); - h_ed->setValue(hue); - s_ed->setValue(sat); - v_ed->setValue(val); - r_ed->setValue(qRed(current_color())); - g_ed->setValue(qGreen(current_color())); - b_ed->setValue(qBlue(current_color())); - show_current_color(); - emit new_col(current_color()); - update_q_color(); - } - void Q_Color_Shower::set_rgb(QRgb rgb) - { - rgb_original = true; - cur_col = rgb; - rgb2hsv(current_color(), hue, sat, val); - h_ed->setValue(hue); - s_ed->setValue(sat); - v_ed->setValue(val); - r_ed->setValue(qRed(current_color())); - g_ed->setValue(qGreen(current_color())); - b_ed->setValue(qBlue(current_color())); - ht_ed->setText(QColor(rgb).name()); - show_current_color(); - update_q_color(); - } - void Q_Color_Shower::set_hsv(int h, int s, int v) - { - if (h < -1 || (uint)s > 255 || (uint)v > 255) - return; - rgb_original = false; - hue = h; - val = v; - sat = s; - QColor c; - c.setHsv(hue, sat, val); - cur_col = c.rgb(); - h_ed->setValue(hue); - s_ed->setValue(sat); - v_ed->setValue(val); - r_ed->setValue(qRed(current_color())); - g_ed->setValue(qGreen(current_color())); - b_ed->setValue(qBlue(current_color())); - ht_ed->setText(c.name()); - show_current_color(); - update_q_color(); - } - void Q_Color_Shower::retranslate_strings() - { - lbl_hue->setText(Select_Color_Dialog::tr("Hu&e:")); - lbl_sat->setText(Select_Color_Dialog::tr("&Sat:")); - lbl_val->setText(Select_Color_Dialog::tr("&Val:")); - lbl_red->setText(Select_Color_Dialog::tr("&Red:")); - lbl_green->setText(Select_Color_Dialog::tr("&Green:")); - lbl_blue->setText(Select_Color_Dialog::tr("Bl&ue:")); - alpha_lab->setText(Select_Color_Dialog::tr("A&lpha channel:")); - lbl_html->setText(Select_Color_Dialog::tr("&HTML:")); - } - void Q_Color_Shower::update_q_color() - { - QColor old_q_color(cur_q_color); - cur_q_color.setRgba(qRgba(qRed(cur_col), qGreen(cur_col), qBlue(cur_col), current_alpha())); - if (cur_q_color != old_q_color) - emit current_color_changed(cur_q_color); - } - void Q_Color_Shower::show_current_color() - { - lab->set_color(current_color()); - lab->repaint(); - } - Select_Color_Dialog::Select_Color_Dialog() - { - d_ptr = new Select_Color_Dialog_Private(this); - } - Select_Color_Dialog::~Select_Color_Dialog() - { - delete d_ptr; - } - void Select_Color_Dialog::set_current_color(const QColor& color) const - { - d_ptr->set_current_color(color); - } - QColor Select_Color_Dialog::current_color() const - { - return d_ptr->current_color(); - } -} // Flex_Qt diff --git a/Widget/base/Select_Color_Dialog/Select_Color_Dialog.h b/Widget/base/Select_Color_Dialog/Select_Color_Dialog.h deleted file mode 100644 index f321f7a..0000000 --- a/Widget/base/Select_Color_Dialog/Select_Color_Dialog.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include -#include "../global.h" -namespace Flex_Qt { -class Select_Color_Dialog_Private; -class WIDGET_API Select_Color_Dialog : public QDialog { - QOBJECT_H -public: - Select_Color_Dialog(); - ~Select_Color_Dialog() override; - Select_Color_Dialog_Private* d_ptr{}; - void set_current_color(const QColor& color) const; - [[nodiscard]] QColor current_color() const; -}; -} // Flex_Qt diff --git a/Widget/base/Singleton_Widget.hpp b/Widget/base/Singleton_Widget.hpp deleted file mode 100644 index 8de39d0..0000000 --- a/Widget/base/Singleton_Widget.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include - -namespace Flex_Qt { - -template -class Singleton_Widget { -public: - static T* instance() { - if (!instance_) - qInfo() << "error Singleton_Widget not created" << instance_; - return instance_; - } - - Singleton_Widget() { - if (instance_) - qInfo() << "error Singleton_Widget duplicated" << instance_; - instance_ = static_cast(this); - } - - virtual ~Singleton_Widget() = default; - Singleton_Widget(T&&) = delete; - Singleton_Widget(const T&) = delete; - void operator=(const T&) = delete; - -protected: - static T* instance_; -}; - -template -T* Singleton_Widget::instance_ = nullptr; - -} // namespace Flex_Qt diff --git a/Widget/base/Virtual_Keyboard/Input_Core.cpp b/Widget/base/Virtual_Keyboard/Input_Core.cpp deleted file mode 100644 index d0db03a..0000000 --- a/Widget/base/Virtual_Keyboard/Input_Core.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "Input_Core.h" -extern int qInitResources_dict(); -namespace Flex_Qt { -Input_Core::Input_Core(QObject* parent) : QObject(parent) {} -Input_Core::~Input_Core() {} -bool Input_Core::get_enable() { - return m_able; -} -void Input_Core::set_enable(bool able) { - m_able = able; - im_flush_cache(); - emit signal_input_able(able); -} -bool Input_Core::init(int max_spell_len, int max_out_len) { - qInitResources_dict(); - QString path = QString::fromStdString(Psc::get_exe_dir()); - QFile file_pinyin(dict_path); - if (!file_pinyin.exists()) { - QFile::copy(":/dict_pinyin.dat", path + "/" + dict_path); - QFile::setPermissions(path, QFileDevice::ReadOther | QFileDevice::WriteOther); - } - QFile file_user(dict_user_path); - if (!file_user.exists()) { - QFile::copy(":/dict_pinyin_user.dat", path + "/" + dict_user_path); - QFile::setPermissions(path, QFileDevice::ReadOther | QFileDevice::WriteOther); - } - m_spell_len = max_spell_len; - m_out_len = max_out_len; - bool ret = im_open_decoder(QString("%1/" + dict_path).arg(path).toLocal8Bit().data(), - QString("%1/" + dict_user_path).arg(path).toLocal8Bit().data()); - if (!ret) - return ret; - im_set_max_lens(static_cast(m_spell_len), static_cast(m_out_len)); - reset_search(); - m_able = ret; - return ret; -} -void Input_Core::deinit() { - im_close_decoder(); -} -void Input_Core::reset_search() { - if (m_able) - im_reset_search(); -} -unsigned int Input_Core::search(const QString& spell) { - if (!m_able) - return 0; - QByteArray bytearray; - char* pinyin; - bytearray = spell.toUtf8(); - pinyin = bytearray.data(); - size_t candnum = im_search(pinyin, static_cast(bytearray.size())); - if (static_cast(candnum) < m_out_len) { - return static_cast(candnum); - } - return static_cast(m_out_len); -} -int Input_Core::cur_search_pos() { - const uint16* start_pos; - size_t pos_len; - pos_len = im_get_spl_start_pos(start_pos); - return static_cast(pos_len); -} -std::vector Input_Core::get_candidate(unsigned int candnum) { - std::vector text_list; - if (candnum == 0) - return text_list; - char16* cand_buf = new char16[m_out_len]; - for (unsigned int i = 0; i < candnum; i++) { - char16* cand; - cand = im_get_candidate(i, cand_buf, static_cast(m_out_len)); - if (cand) { - text_list.push_back(QString::fromUtf16(cand)); - } - else { - continue; - } - } - delete[] cand_buf; - // std::cout< -#include -#include -#include -#include "googlepinyin/atomdictbase.h" -#include "googlepinyin/dictbuilder.h" -#include "googlepinyin/dictdef.h" -#include "googlepinyin/dictlist.h" -#include "googlepinyin/dicttrie.h" -#include "googlepinyin/lpicache.h" -#include "googlepinyin/matrixsearch.h" -#include "googlepinyin/mystdlib.h" -#include "googlepinyin/ngram.h" -#include "googlepinyin/pinyinime.h" -#include "googlepinyin/searchutility.h" -#include "googlepinyin/spellingtable.h" -#include "googlepinyin/spellingtrie.h" -#include "googlepinyin/splparser.h" -#include "googlepinyin/sync.h" -#include "googlepinyin/userdict.h" -#include "googlepinyin/utf16char.h" -#include "googlepinyin/utf16reader.h" -using namespace ime_pinyin; -namespace Flex_Qt { -class Input_Core : public QObject { - Q_OBJECT - Q_PROPERTY(bool m_able READ get_enable WRITE set_enable NOTIFY signal_input_able) -public: - explicit Input_Core(QObject* parent = nullptr); - ~Input_Core() override; - bool init(int max_spell_len = 64, int max_out_len = 64); - void deinit(); - unsigned int search(const QString& spell); - int cur_search_pos(); - void reset_search(); - bool get_enable(); - void set_enable(bool able); - std::vector get_candidate(unsigned int cnadnum); -signals : - void signal_input_able(bool); -private: - bool m_able = false; - int m_spell_len; - int m_out_len; - const QString dict_path = "dict_pinyin.dat"; - const QString dict_user_path = "dict_pinyin_user.dat"; -}; -} // Flex_Qt diff --git a/Widget/base/Virtual_Keyboard/Virtual_Keyboard.cpp b/Widget/base/Virtual_Keyboard/Virtual_Keyboard.cpp deleted file mode 100644 index fba7187..0000000 --- a/Widget/base/Virtual_Keyboard/Virtual_Keyboard.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include "Virtual_Keyboard.h" -#include -#include -#include -namespace Flex_Qt { -Key_Button::Key_Button() { - /*支持长按*/ - // this->setAutoRepeat(true); - // this->setAutoRepeatDelay(500); - // this->setAutoRepeatInterval(100); - connect(this, &QPushButton::pressed, [&]() { - virtual_keyboard->handle_Key_Press(this); - }); -} -Virtual_Keyboard::Virtual_Keyboard(QWidget* parent) : QWidget(parent) { - this->setStyleSheet( - "QPushButton{" - "font: 16pt 黑体;" - "font-size: 26px;" - "color: white;" - "margin: 2px;" - "border-radius: 5px;" - "background: #00C78C;}" - "QPushButton:pressed{" - "background: #F0FFFF ;}" - "QListWidget::Item:hover { background: #00C78C; color: white; }" - "QListWidget {outline: none; border:1px solid #00000000; color: black; }" - "QLineEdit {outline: none; border:1px solid #00000000; color: black;}"); - QSize screen_size = QGuiApplication::primaryScreen()->size(); - resize(screen_size / 2); - main_layout = new QVBoxLayout(this); - size_policy.setHorizontalPolicy(QSizePolicy::Preferred); - size_policy.setVerticalPolicy(QSizePolicy::Preferred); - size_policy.setHorizontalStretch(1); - size_policy.setVerticalStretch(0); - english = create_english(); - chinese = create_chinese(); - symbol = create_symbol(); - main_layout->addWidget(english); - main_layout->addWidget(chinese); - main_layout->addWidget(symbol); - cur_widget = english; - chinese->hide(); - symbol->hide(); - setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::Tool | Qt::WindowDoesNotAcceptFocus); - core = new Input_Core(this); - if (!core->init()) { - std::cout << "字典加载失败,请将dict文件移至工作目录"; - } - /* 设置为列表显示模式 */ - list_widget->setViewMode(QListView::ListMode); - /* 从左往右排列 */ - list_widget->setFlow(QListView::LeftToRight); - /* 屏蔽水平滑动条 */ - list_widget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - /* 屏蔽垂直滑动条 */ - list_widget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - /* 设置为像素滚动 */ - list_widget->setHorizontalScrollMode(QListWidget::ScrollPerPixel); - /* 设置鼠标左键拖动 */ - QScroller::grabGesture(list_widget, QScroller::LeftMouseButtonGesture); - // 设置不可选中 - connect(edit, &QLineEdit::selectionChanged, [=] { - edit->deselect(); - }); - // 中文输入 - connect(edit, &QLineEdit::textChanged, [=](const QString& text) { - /* 单个字符过长引发崩溃 - * 处理:单个字符限制长度为10 - */ - if (text.isEmpty()) { - return; - } - if (text.length() >= 10) { - if (is_single_char(text)) { - QString deal_text = text.mid(0, 10); - get_candidate_list(deal_text); - return; - } - get_candidate_list(text); - return; - } - else { - get_candidate_list(text); - } - }); - connect(list_widget, &QListWidget::itemClicked, [=](QListWidgetItem* item) { - QKeyEvent key_press(QEvent::KeyPress, Qt::Key_unknown, Qt::NoModifier, item->text()); - QCoreApplication::sendEvent(input_widget, &key_press); - list_widget->clear(); - edit->clear(); - }); -} -Virtual_Keyboard::~Virtual_Keyboard() {} -bool Virtual_Keyboard::is_single_char(QString spell) { - bool ret = true; - for (auto s : spell) { - if (s != spell[0]) { - ret = false; - break; - } - } - return ret; -} -void Virtual_Keyboard::set_edit(QWidget* edit) { - this->input_widget = edit; - this->input_widget->installEventFilter(this); -} -void Virtual_Keyboard::get_candidate_list(const QString spell) { - unsigned int cand = core->search(spell); - if (cand == 0) { - return; - } - std::vector ret = core->get_candidate(cand); - if (ret.empty()) { - return; - } - list_widget->clear(); - for (const QString& candidate : ret) - list_widget->addItem(candidate); -} -void Virtual_Keyboard::handle_Key_Press(Key_Button* button) { - if (state == Chinese) { - if (button->key != Qt::Key_Backspace) { - edit->insert(button->text); - } - else { - if (!edit->text().isEmpty()) { - edit->backspace(); - } - else { - list_widget->clear(); - QKeyEvent key_press(QEvent::KeyPress, button->key, button->modifiers, button->text); - QCoreApplication::sendEvent(input_widget, &key_press); - } - } - } - else { - if (button->is_text) { - QKeyEvent key_press(QEvent::KeyPress, button->key, button->modifiers, button->text); - if (input_widget) { - QCoreApplication::sendEvent(input_widget, &key_press); - } - else { - qWarning("VirtualKeyBoard input_widget == NULL!"); - } - } - } -} -bool Virtual_Keyboard::eventFilter(QObject* watched, QEvent* event) { - bool ok = false; - if (QApplication::focusWidget() == watched && event->type() == QEvent::MouseButtonRelease) { - ok = true; - } - if (event->type() == QEvent::FocusIn) { - ok = true; - } - if (ok) { - QWidget* w = qobject_cast(watched); - set_edit(w); - QPoint pos = w->mapToGlobal(QPoint(0, 0)); - QSize screen_size = QGuiApplication::primaryScreen()->size(); - int keyboard_width = width(); - int keyboard_height = height(); - int screen_width = screen_size.width(); - int screen_height = screen_size.height(); - int x = pos.x(); - int y = pos.y() + w->height(); - if (x + keyboard_width > screen_width) { - setFixedWidth(screen_width - pos.x() - w->width()); - } - if (y + keyboard_height > screen_height) { - setFixedHeight(screen_height - pos.y() - w->height()); - } - move(x, y); - show(); - } - if (event->type() == QEvent::FocusOut) { - this->hide(); - } - return QObject::eventFilter(watched, event); -} -void Virtual_Keyboard::mousePressEvent(QMouseEvent* event) { - if (moving) - return; - if (event->button() == Qt::LeftButton) { - moving = true; - start_pos = pos(); - start_global_pos = event->globalPos(); - QApplication::setOverrideCursor(Qt::ClosedHandCursor); - } - event->accept(); -} -void Virtual_Keyboard::mouseMoveEvent(QMouseEvent* event) { - if (!moving) - return; - move(start_pos + event->globalPos() - start_global_pos); - event->accept(); -} -void Virtual_Keyboard::mouseReleaseEvent(QMouseEvent* event) { - if (!moving) - return; - moving = false; - event->accept(); - QApplication::restoreOverrideCursor(); -} -} // Flex_Qt diff --git a/Widget/base/Virtual_Keyboard/Virtual_Keyboard.h b/Widget/base/Virtual_Keyboard/Virtual_Keyboard.h deleted file mode 100644 index 11373a9..0000000 --- a/Widget/base/Virtual_Keyboard/Virtual_Keyboard.h +++ /dev/null @@ -1,306 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Input_Core.h" -namespace Flex_Qt { -class Virtual_Keyboard; -class Key_Button : public QPushButton { -public: - explicit Key_Button(); - Qt::Key key; - QString text; - Qt::KeyboardModifiers modifiers = Qt::NoModifier; - bool is_text = false; - Virtual_Keyboard* virtual_keyboard{}; -}; -class Virtual_Keyboard : public QWidget, public Psc::Singleton { -public: - explicit Virtual_Keyboard(QWidget* parent = nullptr); - ~Virtual_Keyboard() override; - bool eventFilter(QObject* watched, QEvent* event) override; - void set_edit(QWidget* edit); - void get_candidate_list(QString spell); - bool is_single_char(QString spell); - void handle_Key_Press(Key_Button* button); - bool moving = false; - QPoint start_pos, start_global_pos; - void mousePressEvent(QMouseEvent* event) override; - void mouseMoveEvent(QMouseEvent* event) override; - void mouseReleaseEvent(QMouseEvent* event) override; -public: - enum State { - English, - Chinese, - } state = English; - QWidget* input_widget{}; - Input_Core* core; - Key_Button* - create_text_key(const QString& show_text, const QString& text, Qt::Key key, Qt::KeyboardModifiers modifiers, - QHBoxLayout* layout) { - auto t = create_text_key_button(text, key, layout, true); - t->setText(show_text); - t->modifiers = modifiers; - return t; - } - QSizePolicy size_policy; - Key_Button* create_text_key_button(const QString& text, Qt::Key key, QHBoxLayout* layout, bool is_text = true) { - auto ret = new Key_Button; - ret->setObjectName(text); - ret->key = key; - ret->text = text; - ret->is_text = is_text; - layout->addWidget(ret); - ret->setSizePolicy(size_policy); - ret->virtual_keyboard = this; - return ret; - } - QWidget *english, *chinese, *symbol, *cur_widget{}; - QVBoxLayout* main_layout; - QLineEdit* edit{}; - QListWidget* list_widget{}; - QWidget* create_chinese() { - auto ret = new QWidget; - auto main_layout = new QVBoxLayout(ret); - QFont font; - font.setFamily("黑体"); // 设置字体为黑体 - font.setPointSize(16); // 设置字体大小为 16pt - QSizePolicy size_policy2(QSizePolicy::Preferred, QSizePolicy::Preferred); - edit = new QLineEdit; - edit->setSizePolicy(size_policy2); - list_widget = new QListWidget; - list_widget->setSizePolicy(size_policy2); - edit->setFont(font); - list_widget->setFont(font); - int line_height = QFontMetrics(font).lineSpacing() + 8; - edit->setFixedHeight(line_height); - list_widget->setFixedHeight(line_height); - auto line0 = new QHBoxLayout; - line0->addWidget(edit, 3); - line0->addWidget(list_widget, 5); - main_layout->addLayout(line0); - auto line1 = new QHBoxLayout(); - main_layout->addLayout(line1, 5); - create_text_key("q", "q", Qt::Key_Q, Qt::NoModifier, line1); - create_text_key("w", "w", Qt::Key_W, Qt::NoModifier, line1); - create_text_key("e", "e", Qt::Key_E, Qt::NoModifier, line1); - create_text_key("r", "r", Qt::Key_R, Qt::NoModifier, line1); - create_text_key("t", "t", Qt::Key_T, Qt::NoModifier, line1); - create_text_key("y", "y", Qt::Key_Y, Qt::NoModifier, line1); - create_text_key("u", "u", Qt::Key_U, Qt::NoModifier, line1); - create_text_key("i", "i", Qt::Key_I, Qt::NoModifier, line1); - create_text_key("o", "o", Qt::Key_O, Qt::NoModifier, line1); - create_text_key("p", "p", Qt::Key_P, Qt::NoModifier, line1); - auto line2 = new QHBoxLayout(); - main_layout->addLayout(line2, 5); - create_text_key("a", "a", Qt::Key_A, Qt::NoModifier, line2); - create_text_key("s", "s", Qt::Key_S, Qt::NoModifier, line2); - create_text_key("d", "d", Qt::Key_D, Qt::NoModifier, line2); - create_text_key("f", "f", Qt::Key_F, Qt::NoModifier, line2); - create_text_key("g", "g", Qt::Key_G, Qt::NoModifier, line2); - create_text_key("h", "h", Qt::Key_H, Qt::NoModifier, line2); - create_text_key("j", "j", Qt::Key_J, Qt::NoModifier, line2); - create_text_key("k", "k", Qt::Key_K, Qt::NoModifier, line2); - create_text_key("l", "l", Qt::Key_L, Qt::NoModifier, line2); - auto line3 = new QHBoxLayout(); - main_layout->addLayout(line3, 5); - create_text_key("z", "z", Qt::Key_Z, Qt::NoModifier, line3); - create_text_key("x", "x", Qt::Key_X, Qt::NoModifier, line3); - create_text_key("c", "c", Qt::Key_C, Qt::NoModifier, line3); - create_text_key("v", "v", Qt::Key_V, Qt::NoModifier, line3); - create_text_key("b", "b", Qt::Key_B, Qt::NoModifier, line3); - create_text_key("n", "n", Qt::Key_N, Qt::NoModifier, line3); - create_text_key("m", "m", Qt::Key_M, Qt::NoModifier, line3); - create_text_key("Backspace", "\b", Qt::Key_Backspace, Qt::NoModifier, line3); - auto line4 = new QHBoxLayout(); - main_layout->addLayout(line4, 5); - auto change_to_123 = new QPushButton; - line4->addWidget(change_to_123, 1); - change_to_123->setSizePolicy(size_policy); - change_to_123->setText("?123"); - connect(change_to_123, &Key_Button::clicked, [this, change_to_123]() { - cur_widget->hide(); - symbol->show(); - }); - auto change_to_english = new QPushButton; - change_to_english->setText("En"); - change_to_english->setSizePolicy(size_policy); - line4->addWidget(change_to_english, 1); - connect(change_to_english, &Key_Button::clicked, [&, change_to_english]() { - cur_widget->hide(); - english->show(); - cur_widget = english; - state = English; - }); - auto space = create_text_key(" ", " ", Qt::Key_Space, Qt::NoModifier, line4); - QSizePolicy size_policy1(QSizePolicy::Preferred, QSizePolicy::Preferred); - size_policy1.setHorizontalStretch(5); - space->setSizePolicy(size_policy1); - auto hide = new QPushButton; - hide->setText("隐藏"); - hide->setSizePolicy(size_policy); - line4->addWidget(hide, 1); - connect(hide, &Key_Button::clicked, this, &QWidget::hide); - return ret; - } - QWidget* create_english() { - auto ret = new QWidget; - auto main_layout = new QVBoxLayout(ret); - auto line1 = new QHBoxLayout(); - main_layout->addLayout(line1); - create_text_key("q", "q", Qt::Key_Q, Qt::NoModifier, line1); - create_text_key("w", "w", Qt::Key_W, Qt::NoModifier, line1); - create_text_key("e", "e", Qt::Key_E, Qt::NoModifier, line1); - create_text_key("r", "r", Qt::Key_R, Qt::NoModifier, line1); - create_text_key("t", "t", Qt::Key_T, Qt::NoModifier, line1); - create_text_key("y", "y", Qt::Key_Y, Qt::NoModifier, line1); - create_text_key("u", "u", Qt::Key_U, Qt::NoModifier, line1); - create_text_key("i", "i", Qt::Key_I, Qt::NoModifier, line1); - create_text_key("o", "o", Qt::Key_O, Qt::NoModifier, line1); - create_text_key("p", "p", Qt::Key_P, Qt::NoModifier, line1); - auto line2 = new QHBoxLayout(); - main_layout->addLayout(line2); - create_text_key("a", "a", Qt::Key_A, Qt::NoModifier, line2); - create_text_key("s", "s", Qt::Key_S, Qt::NoModifier, line2); - create_text_key("d", "d", Qt::Key_D, Qt::NoModifier, line2); - create_text_key("f", "f", Qt::Key_F, Qt::NoModifier, line2); - create_text_key("g", "g", Qt::Key_G, Qt::NoModifier, line2); - create_text_key("h", "h", Qt::Key_H, Qt::NoModifier, line2); - create_text_key("j", "j", Qt::Key_J, Qt::NoModifier, line2); - create_text_key("k", "k", Qt::Key_K, Qt::NoModifier, line2); - create_text_key("l", "l", Qt::Key_L, Qt::NoModifier, line2); - auto line3 = new QHBoxLayout(); - main_layout->addLayout(line3); - auto caps_lock = new QPushButton; - line3->addWidget(caps_lock, 1); - caps_lock->setSizePolicy(size_policy); - caps_lock->setText("大写"); - connect(caps_lock, &QPushButton::clicked, [this, caps_lock]() { - if (caps_lock->text() == "大写") { - for (auto child : english->findChildren()) { - if ((child->text.size() == 1) && child->text.isLower()) { - QString&& text = child->text.toUpper(); - child->setText(text); - child->text = text; - } - } - caps_lock->setText("小写"); - } - else { - for (auto child : english->findChildren()) { - if ((child->text.size() == 1) && child->text.isUpper()) { - QString&& text = child->text.toLower(); - child->setText(text); - child->text = text; - } - } - caps_lock->setText("大写"); - } - }); - create_text_key("z", "z", Qt::Key_Z, Qt::NoModifier, line3); - create_text_key("x", "x", Qt::Key_X, Qt::NoModifier, line3); - create_text_key("c", "c", Qt::Key_C, Qt::NoModifier, line3); - create_text_key("v", "v", Qt::Key_V, Qt::NoModifier, line3); - create_text_key("b", "b", Qt::Key_B, Qt::NoModifier, line3); - create_text_key("n", "n", Qt::Key_N, Qt::NoModifier, line3); - create_text_key("m", "m", Qt::Key_M, Qt::NoModifier, line3); - create_text_key("Backspace", "\b", Qt::Key_Backspace, Qt::NoModifier, line3); - auto line4 = new QHBoxLayout(); - main_layout->addLayout(line4); - auto change_to_123 = new QPushButton; - line4->addWidget(change_to_123, 1); - change_to_123->setSizePolicy(size_policy); - change_to_123->setText("?123"); - connect(change_to_123, &Key_Button::clicked, [this, change_to_123]() { - cur_widget->hide(); - symbol->show(); - }); - auto change_to_ch = new QPushButton; - change_to_ch->setText("中文"); - change_to_ch->setSizePolicy(size_policy); - line4->addWidget(change_to_ch, 1); - connect(change_to_ch, &Key_Button::clicked, [&]() { - cur_widget->hide(); - chinese->show(); - cur_widget = chinese; - state = Chinese; - }); - auto space = create_text_key(" ", " ", Qt::Key_Space, Qt::NoModifier, line4); - QSizePolicy size_policy1(QSizePolicy::Preferred, QSizePolicy::Preferred); - size_policy1.setHorizontalStretch(5); - space->setSizePolicy(size_policy1); - auto hide = new QPushButton; - hide->setText("隐藏"); - hide->setSizePolicy(size_policy); - line4->addWidget(hide, 1); - connect(hide, &Key_Button::clicked, this, &QWidget::hide); - return ret; - } - QWidget* create_symbol() { - auto ret = new QWidget; - auto main_layout = new QVBoxLayout(ret); - auto line1 = new QHBoxLayout(); - main_layout->addLayout(line1); - create_text_key("1", "1", Qt::Key_1, Qt::NoModifier, line1); - create_text_key("2", "2", Qt::Key_2, Qt::NoModifier, line1); - create_text_key("3", "3", Qt::Key_3, Qt::NoModifier, line1); - create_text_key("4", "4", Qt::Key_4, Qt::NoModifier, line1); - create_text_key("5", "5", Qt::Key_5, Qt::NoModifier, line1); - create_text_key("6", "6", Qt::Key_6, Qt::NoModifier, line1); - create_text_key("7", "7", Qt::Key_7, Qt::NoModifier, line1); - create_text_key("8", "8", Qt::Key_8, Qt::NoModifier, line1); - create_text_key("9", "9", Qt::Key_9, Qt::NoModifier, line1); - create_text_key("0", "0", Qt::Key_0, Qt::NoModifier, line1); - auto line2 = new QHBoxLayout(); - main_layout->addLayout(line2); - create_text_key("!", "!", Qt::Key_1, Qt::ShiftModifier, line2); - create_text_key("@", "@", Qt::Key_2, Qt::ShiftModifier, line2); - create_text_key("#", "#", Qt::Key_3, Qt::ShiftModifier, line2); - create_text_key("%", "%", Qt::Key_5, Qt::ShiftModifier, line2); - create_text_key("&&", "&", Qt::Key_7, Qt::ShiftModifier, line2); - create_text_key("*", "*", Qt::Key_8, Qt::ShiftModifier, line2); - create_text_key("(", "(", Qt::Key_9, Qt::ShiftModifier, line2); - create_text_key(")", ")", Qt::Key_0, Qt::ShiftModifier, line2); - create_text_key("-", "-", Qt::Key_Minus, Qt::NoModifier, line2); - auto line3 = new QHBoxLayout(); - main_layout->addLayout(line3); - create_text_key("_", "_", Qt::Key_Underscore, Qt::ShiftModifier, line3); - create_text_key(":", ":", Qt::Key_Colon, Qt::ShiftModifier, line3); - create_text_key(";", ";", Qt::Key_Semicolon, Qt::NoModifier, line3); - create_text_key("/", "/", Qt::Key_Slash, Qt::NoModifier, line3); - create_text_key(".", ".", Qt::Key_Period, Qt::NoModifier, line3); - create_text_key(",", ",", Qt::Key_Comma, Qt::NoModifier, line3); - create_text_key("?", "?", Qt::Key_Question, Qt::ShiftModifier, line3); - create_text_key("Backspace", "\b", Qt::Key_Backspace, Qt::NoModifier, line3); - auto line4 = new QHBoxLayout(); - main_layout->addLayout(line4); - auto back = new QPushButton; - back->setText("返回"); - back->setSizePolicy(size_policy); - line4->addWidget(back, 1); - connect(back, &Key_Button::clicked, [&]() { - symbol->hide(); - cur_widget->show(); - }); - auto space = create_text_key(" ", " ", Qt::Key_Space, Qt::NoModifier, line4); - QSizePolicy size_policy1(QSizePolicy::Preferred, QSizePolicy::Preferred); - size_policy1.setHorizontalStretch(5); - space->setSizePolicy(size_policy1); - auto hide = new QPushButton; - hide->setText("隐藏"); - hide->setSizePolicy(size_policy); - line4->addWidget(hide, 1); - connect(hide, &Key_Button::clicked, this, &QWidget::hide); - return ret; - } -}; -} // Flex_Qt diff --git a/Widget/base/Virtual_Keyboard/dict/dict.qrc b/Widget/base/Virtual_Keyboard/dict/dict.qrc deleted file mode 100644 index ac999e5..0000000 --- a/Widget/base/Virtual_Keyboard/dict/dict.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - dict_pinyin.dat - dict_pinyin_user.dat - - diff --git a/Widget/base/Virtual_Keyboard/dict/dict_pinyin.dat b/Widget/base/Virtual_Keyboard/dict/dict_pinyin.dat deleted file mode 100644 index 311ab24..0000000 Binary files a/Widget/base/Virtual_Keyboard/dict/dict_pinyin.dat and /dev/null differ diff --git a/Widget/base/Virtual_Keyboard/dict/dict_pinyin_user.dat b/Widget/base/Virtual_Keyboard/dict/dict_pinyin_user.dat deleted file mode 100644 index dca7368..0000000 Binary files a/Widget/base/Virtual_Keyboard/dict/dict_pinyin_user.dat and /dev/null differ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/atomdictbase.h b/Widget/base/Virtual_Keyboard/googlepinyin/atomdictbase.h deleted file mode 100644 index ba344f0..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/atomdictbase.h +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * This class defines AtomDictBase class which is the base class for all atom - * dictionaries. Atom dictionaries are managed by the decoder class - * MatrixSearch. - * - * When the user appends a new character to the Pinyin string, all enabled atom - * dictionaries' extend_dict() will be called at least once to get candidates - * ended in this step (the information of starting step is also given in the - * parameter). Usually, when extend_dict() is called, a MileStoneHandle object - * returned by a previous calling for a earlier step is given to speed up the - * look-up process, and a new MileStoneHandle object will be returned if - * the extension is successful. - * - * A returned MileStoneHandle object should keep alive until Function - * reset_milestones() is called and this object is noticed to be reset. - * - * Usually, the atom dictionary can use step information to manage its - * MileStoneHandle objects, or it can make the objects in ascendant order to - * make the reset easier. - * - * When the decoder loads the dictionary, it will give a starting lemma id for - * this atom dictionary to map a inner id to a global id. Global ids should be - * used when an atom dictionary talks to any component outside. - */ -#ifndef PINYINIME_INCLUDE_ATOMDICTBASE_H__ -#define PINYINIME_INCLUDE_ATOMDICTBASE_H__ -#include -#include "./dictdef.h" -#include "./searchutility.h" -namespace ime_pinyin { -class AtomDictBase { -public: - virtual ~AtomDictBase() { - } - /** - * Load an atom dictionary from a file. - * - * @param file_name The file name to load dictionary. - * @param start_id The starting id used for this atom dictionary. - * @param end_id The end id (included) which can be used for this atom - * dictionary. User dictionary will always use the last id space, so it can - * ignore this paramter. All other atom dictionaries should check this - * parameter. - * @return True if succeed. - */ - virtual bool load_dict(const char* file_name, LemmaIdType start_id, - LemmaIdType end_id) = 0; - /** - * Close this atom dictionary. - * - * @return True if succeed. - */ - virtual bool close_dict() = 0; - /** - * Get the total number of lemmas in this atom dictionary. - * - * @return The total number of lemmas. - */ - virtual size_t number_of_lemmas() = 0; - /** - * This function is called by the decoder when user deletes a character from - * the input string, or begins a new input string. - * - * Different atom dictionaries may implement this function in different way. - * an atom dictionary can use one of these two parameters (or both) to reset - * its corresponding MileStoneHandle objects according its detailed - * implementation. - * - * For example, if an atom dictionary uses step information to manage its - * MileStoneHandle objects, parameter from_step can be used to identify which - * objects should be reset; otherwise, if another atom dictionary does not - * use the detailed step information, it only uses ascendant handles - * (according to step. For the same step, earlier call, smaller handle), it - * can easily reset those MileStoneHandle which are larger than from_handle. - * - * The decoder always reset the decoding state by step. So when it begins - * resetting, it will call reset_milestones() of its atom dictionaries with - * the step information, and the MileStoneHandle objects returned by the - * earliest calling of extend_dict() for that step. - * - * If an atom dictionary does not implement incremental search, this function - * can be totally ignored. - * - * @param from_step From which step(included) the MileStoneHandle - * objects should be reset. - * @param from_handle The ealiest MileStoneHandle object for step from_step - */ - virtual void reset_milestones(uint16 from_step, - MileStoneHandle from_handle) = 0; - /** - * Used to extend in this dictionary. The handle returned should keep valid - * until reset_milestones() is called. - * - * @param from_handle Its previous returned extended handle without the new - * spelling id, it can be used to speed up the extending. - * @param dep The paramter used for extending. - * @param lpi_items Used to fill in the lemmas matched. - * @param lpi_max The length of the buffer - * @param lpi_num Used to return the newly added items. - * @return The new mile stone for this extending. 0 if fail. - */ - virtual MileStoneHandle extend_dict(MileStoneHandle from_handle, - const DictExtPara* dep, - LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num) = 0; - /** - * Get lemma items with scores according to a spelling id stream. - * This atom dictionary does not need to sort the returned items. - * - * @param splid_str The spelling id stream buffer. - * @param splid_str_len The length of the spelling id stream buffer. - * @param lpi_items Used to return matched lemma items with scores. - * @param lpi_max The maximum size of the buffer to return result. - * @return The number of matched items which have been filled in to lpi_items. - */ - virtual size_t get_lpis(const uint16* splid_str, uint16 splid_str_len, - LmaPsbItem* lpi_items, size_t lpi_max) = 0; - /** - * Get a lemma string (The Chinese string) by the given lemma id. - * - * @param id_lemma The lemma id to get the string. - * @param str_buf The buffer to return the Chinese string. - * @param str_max The maximum size of the buffer. - * @return The length of the string, 0 if fail. - */ - virtual uint16 get_lemma_str(LemmaIdType id_lemma, char16* str_buf, - uint16 str_max) = 0; - /** - * Get the full spelling ids for the given lemma id. - * If the given buffer is too short, return 0. - * - * @param splids Used to return the spelling ids. - * @param splids_max The maximum buffer length of splids. - * @param arg_valid Used to indicate if the incoming parameters have been - * initialized are valid. If it is true, the splids and splids_max are valid - * and there may be half ids in splids to be updated to full ids. In this - * case, splids_max is the number of valid ids in splids. - * @return The number of ids in the buffer. - */ - virtual uint16 get_lemma_splids(LemmaIdType id_lemma, uint16* splids, - uint16 splids_max, bool arg_valid) = 0; - /** - * Function used for prediction. - * No need to sort the newly added items. - * - * @param last_hzs The last n Chinese chracters(called Hanzi), its length - * should be less than or equal to kMaxPredictSize. - * @param hzs_len specifies the length(<= kMaxPredictSize) of the history. - * @param npre_items Used used to return the result. - * @param npre_max The length of the buffer to return result - * @param b4_used Number of prediction result (from npre_items[-b4_used]) - * from other atom dictionaries. A atom ditionary can just ignore it. - * @return The number of prediction result from this atom dictionary. - */ - virtual size_t predict(const char16 last_hzs[], uint16 hzs_len, - NPredictItem* npre_items, size_t npre_max, - size_t b4_used) = 0; - /** - * Add a lemma to the dictionary. If the dictionary allows to add new - * items and this item does not exist, add it. - * - * @param lemma_str The Chinese string of the lemma. - * @param splids The spelling ids of the lemma. - * @param lemma_len The length of the Chinese lemma. - * @param count The frequency count for this lemma. - */ - virtual LemmaIdType put_lemma(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count) = 0; - /** - * Update a lemma's occuring count. - * - * @param lemma_id The lemma id to update. - * @param delta_count The frequnecy count to ajust. - * @param selected Indicate whether this lemma is selected by user and - * submitted to target edit box. - * @return The id if succeed, 0 if fail. - */ - virtual LemmaIdType update_lemma(LemmaIdType lemma_id, int16 delta_count, - bool selected) = 0; - /** - * Get the lemma id for the given lemma. - * - * @param lemma_str The Chinese string of the lemma. - * @param splids The spelling ids of the lemma. - * @param lemma_len The length of the lemma. - * @return The matched lemma id, or 0 if fail. - */ - virtual LemmaIdType get_lemma_id(char16 lemma_str[], uint16 splids[], - uint16 lemma_len) = 0; - /** - * Get the lemma score. - * - * @param lemma_id The lemma id to get score. - * @return The score of the lemma, or 0 if fail. - */ - virtual LmaScoreType get_lemma_score(LemmaIdType lemma_id) = 0; - /** - * Get the lemma score. - * - * @param lemma_str The Chinese string of the lemma. - * @param splids The spelling ids of the lemma. - * @param lemma_len The length of the lemma. - * @return The score of the lamm, or 0 if fail. - */ - virtual LmaScoreType get_lemma_score(char16 lemma_str[], uint16 splids[], - uint16 lemma_len) = 0; - /** - * If the dictionary allowed, remove a lemma from it. - * - * @param lemma_id The id of the lemma to remove. - * @return True if succeed. - */ - virtual bool remove_lemma(LemmaIdType lemma_id) = 0; - /** - * Get the total occuring count of this atom dictionary. - * - * @return The total occuring count of this atom dictionary. - */ - virtual size_t get_total_lemma_count() = 0; - /** - * Set the total occuring count of other atom dictionaries. - * - * @param count The total occuring count of other atom dictionaies. - */ - virtual void set_total_lemma_count_of_others(size_t count) = 0; - /** - * Notify this atom dictionary to flush the cached data to persistent storage - * if necessary. - */ - virtual void flush_cache() = 0; -}; -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_ATOMDICTBASE_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/dictbuilder.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/dictbuilder.cpp deleted file mode 100644 index ca475a1..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/dictbuilder.cpp +++ /dev/null @@ -1,890 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "dictbuilder.h" -#include -#include -#include -#include -#include "dicttrie.h" -#include "mystdlib.h" -#include "ngram.h" -#include "searchutility.h" -#include "spellingtable.h" -#include "spellingtrie.h" -#include "splparser.h" -#include "utf16reader.h" -namespace ime_pinyin { -#ifdef ___BUILD_MODEL___ -static const size_t kReadBufLen = 512; -static const size_t kSplTableHashLen = 2000; -// Compare a SingleCharItem, first by Hanzis, then by spelling ids, then by -// frequencies. -int cmp_scis_hz_splid_freq(const void* p1, const void* p2) { - const SingleCharItem *s1, *s2; - s1 = static_cast(p1); - s2 = static_cast(p2); - if (s1->hz < s2->hz) - return -1; - if (s1->hz > s2->hz) - return 1; - if (s1->splid.half_splid < s2->splid.half_splid) - return -1; - if (s1->splid.half_splid > s2->splid.half_splid) - return 1; - if (s1->splid.full_splid < s2->splid.full_splid) - return -1; - if (s1->splid.full_splid > s2->splid.full_splid) - return 1; - if (s1->freq > s2->freq) - return -1; - if (s1->freq < s2->freq) - return 1; - return 0; -} -int cmp_scis_hz_splid(const void* p1, const void* p2) { - const SingleCharItem *s1, *s2; - s1 = static_cast(p1); - s2 = static_cast(p2); - if (s1->hz < s2->hz) - return -1; - if (s1->hz > s2->hz) - return 1; - if (s1->splid.half_splid < s2->splid.half_splid) - return -1; - if (s1->splid.half_splid > s2->splid.half_splid) - return 1; - if (s1->splid.full_splid < s2->splid.full_splid) - return -1; - if (s1->splid.full_splid > s2->splid.full_splid) - return 1; - return 0; -} -int cmp_lemma_entry_hzs(const void* p1, const void* p2) { - size_t size1 = utf16_strlen(((const LemmaEntry*)p1)->hanzi_str); - size_t size2 = utf16_strlen(((const LemmaEntry*)p2)->hanzi_str); - if (size1 < size2) - return -1; - else if (size1 > size2) - return 1; - return utf16_strcmp(((const LemmaEntry*)p1)->hanzi_str, - ((const LemmaEntry*)p2)->hanzi_str); -} -int compare_char16(const void* p1, const void* p2) { - if (*((const char16*)p1) < *((const char16*)p2)) - return -1; - if (*((const char16*)p1) > *((const char16*)p2)) - return 1; - return 0; -} -int compare_py(const void* p1, const void* p2) { - int ret = utf16_strcmp(((const LemmaEntry*)p1)->spl_idx_arr, - ((const LemmaEntry*)p2)->spl_idx_arr); - if (0 != ret) - return ret; - return static_cast(((const LemmaEntry*)p2)->freq) - - static_cast(((const LemmaEntry*)p1)->freq); -} -// First hanzi, if the same, then Pinyin -int cmp_lemma_entry_hzspys(const void* p1, const void* p2) { - size_t size1 = utf16_strlen(((const LemmaEntry*)p1)->hanzi_str); - size_t size2 = utf16_strlen(((const LemmaEntry*)p2)->hanzi_str); - if (size1 < size2) - return -1; - else if (size1 > size2) - return 1; - int ret = utf16_strcmp(((const LemmaEntry*)p1)->hanzi_str, - ((const LemmaEntry*)p2)->hanzi_str); - if (0 != ret) - return ret; - ret = utf16_strcmp(((const LemmaEntry*)p1)->spl_idx_arr, - ((const LemmaEntry*)p2)->spl_idx_arr); - return ret; -} -int compare_splid2(const void* p1, const void* p2) { - int ret = utf16_strcmp(((const LemmaEntry*)p1)->spl_idx_arr, - ((const LemmaEntry*)p2)->spl_idx_arr); - return ret; -} -DictBuilder::DictBuilder() { - lemma_arr_ = NULL; - lemma_num_ = 0; - scis_ = NULL; - scis_num_ = 0; - lma_nodes_le0_ = NULL; - lma_nodes_ge1_ = NULL; - lma_nds_used_num_le0_ = 0; - lma_nds_used_num_ge1_ = 0; - homo_idx_buf_ = NULL; - homo_idx_num_eq1_ = 0; - homo_idx_num_gt1_ = 0; - top_lmas_ = NULL; - top_lmas_num_ = 0; - spl_table_ = NULL; - spl_parser_ = NULL; -} -DictBuilder::~DictBuilder() { - free_resource(); -} -bool DictBuilder::alloc_resource(size_t lma_num) { - if (0 == lma_num) - return false; - free_resource(); - lemma_num_ = lma_num; - lemma_arr_ = new LemmaEntry[lemma_num_]; - top_lmas_num_ = 0; - top_lmas_ = new LemmaEntry[kTopScoreLemmaNum]; - // New the scis_ buffer to the possible maximum size. - scis_num_ = lemma_num_ * kMaxLemmaSize; - scis_ = new SingleCharItem[scis_num_]; - // The root and first level nodes is less than kMaxSpellingNum + 1 - lma_nds_used_num_le0_ = 0; - lma_nodes_le0_ = new LmaNodeLE0[kMaxSpellingNum + 1]; - // Other nodes is less than lemma_num - lma_nds_used_num_ge1_ = 0; - lma_nodes_ge1_ = new LmaNodeGE1[lemma_num_]; - homo_idx_buf_ = new LemmaIdType[lemma_num_]; - spl_table_ = new SpellingTable(); - spl_parser_ = new SpellingParser(); - if (NULL == lemma_arr_ || NULL == top_lmas_ || - NULL == scis_ || NULL == spl_table_ || - NULL == spl_parser_ || NULL == lma_nodes_le0_ || - NULL == lma_nodes_ge1_ || NULL == homo_idx_buf_) { - free_resource(); - return false; - } - memset(lemma_arr_, 0, sizeof(LemmaEntry) * lemma_num_); - memset(scis_, 0, sizeof(SingleCharItem) * scis_num_); - memset(lma_nodes_le0_, 0, sizeof(LmaNodeLE0) * (kMaxSpellingNum + 1)); - memset(lma_nodes_ge1_, 0, sizeof(LmaNodeGE1) * lemma_num_); - memset(homo_idx_buf_, 0, sizeof(LemmaIdType) * lemma_num_); - spl_table_->init_table(kMaxPinyinSize, kSplTableHashLen, true); - return true; -} -char16* DictBuilder::read_valid_hanzis(const char* fn_validhzs, size_t* num) { - if (NULL == fn_validhzs || NULL == num) - return NULL; - *num = 0; - FILE* fp = fopen(fn_validhzs, "rb"); - if (NULL == fp) - return NULL; - char16 utf16header; - if (fread(&utf16header, sizeof(char16), 1, fp) != 1 || - 0xfeff != utf16header) { - fclose(fp); - return NULL; - } - fseek(fp, 0, SEEK_END); - *num = ftell(fp) / sizeof(char16); - assert(*num >= 1); - *num -= 1; - char16* hzs = new char16[*num]; - if (NULL == hzs) { - fclose(fp); - return NULL; - } - fseek(fp, 2, SEEK_SET); - if (fread(hzs, sizeof(char16), *num, fp) != *num) { - fclose(fp); - delete[] hzs; - return NULL; - } - fclose(fp); - myqsort(hzs, *num, sizeof(char16), compare_char16); - return hzs; -} -bool DictBuilder::hz_in_hanzis_list(const char16* hzs, size_t hzs_len, - char16 hz) { - if (NULL == hzs) - return false; - char16* found; - found = static_cast( - mybsearch(&hz, hzs, hzs_len, sizeof(char16), compare_char16)); - if (NULL == found) - return false; - assert(*found == hz); - return true; -} -// The caller makes sure that the parameters are valid. -bool DictBuilder::str_in_hanzis_list(const char16* hzs, size_t hzs_len, - const char16* str, size_t str_len) { - if (NULL == hzs || NULL == str) - return false; - for (size_t pos = 0; pos < str_len; pos++) { - if (!hz_in_hanzis_list(hzs, hzs_len, str[pos])) - return false; - } - return true; -} -void DictBuilder::get_top_lemmas() { - top_lmas_num_ = 0; - if (NULL == lemma_arr_) - return; - for (size_t pos = 0; pos < lemma_num_; pos++) { - if (0 == top_lmas_num_) { - top_lmas_[0] = lemma_arr_[pos]; - top_lmas_num_ = 1; - continue; - } - if (lemma_arr_[pos].freq > top_lmas_[top_lmas_num_ - 1].freq) { - if (kTopScoreLemmaNum > top_lmas_num_) - top_lmas_num_ += 1; - size_t move_pos; - for (move_pos = top_lmas_num_ - 1; move_pos > 0; move_pos--) { - top_lmas_[move_pos] = top_lmas_[move_pos - 1]; - if (0 == move_pos - 1 || - (move_pos - 1 > 0 && - top_lmas_[move_pos - 2].freq > lemma_arr_[pos].freq)) { - break; - } - } - assert(move_pos > 0); - top_lmas_[move_pos - 1] = lemma_arr_[pos]; - } - else if (kTopScoreLemmaNum > top_lmas_num_) { - top_lmas_[top_lmas_num_] = lemma_arr_[pos]; - top_lmas_num_ += 1; - } - } - if (kPrintDebug0) { - printf("\n------Top Lemmas------------------\n"); - for (size_t pos = 0; pos < top_lmas_num_; pos++) { - printf("--%d, idx:%06d, score:%.5f\n", pos, top_lmas_[pos].idx_by_hz, - top_lmas_[pos].freq); - } - } -} -void DictBuilder::free_resource() { - if (NULL != lemma_arr_) - delete[] lemma_arr_; - if (NULL != scis_) - delete[] scis_; - if (NULL != lma_nodes_le0_) - delete[] lma_nodes_le0_; - if (NULL != lma_nodes_ge1_) - delete[] lma_nodes_ge1_; - if (NULL != homo_idx_buf_) - delete[] homo_idx_buf_; - if (NULL != spl_table_) - delete spl_table_; - if (NULL != spl_parser_) - delete spl_parser_; - lemma_arr_ = NULL; - scis_ = NULL; - lma_nodes_le0_ = NULL; - lma_nodes_ge1_ = NULL; - homo_idx_buf_ = NULL; - spl_table_ = NULL; - spl_parser_ = NULL; - lemma_num_ = 0; - lma_nds_used_num_le0_ = 0; - lma_nds_used_num_ge1_ = 0; - homo_idx_num_eq1_ = 0; - homo_idx_num_gt1_ = 0; -} -size_t DictBuilder::read_raw_dict(const char* fn_raw, - const char* fn_validhzs, - size_t max_item) { - if (NULL == fn_raw) - return 0; - Utf16Reader utf16_reader; - if (!utf16_reader.open(fn_raw, kReadBufLen * 10)) - return false; - char16 read_buf[kReadBufLen]; - // Read the number of lemmas in the file - size_t lemma_num = 240000; - // allocate resource required - if (!alloc_resource(lemma_num)) { - utf16_reader.close(); - } - // Read the valid Hanzi list. - char16* valid_hzs = NULL; - size_t valid_hzs_num = 0; - valid_hzs = read_valid_hanzis(fn_validhzs, &valid_hzs_num); - // Begin reading the lemma entries - for (size_t i = 0; i < max_item; i++) { - // read next entry - if (!utf16_reader.readline(read_buf, kReadBufLen)) { - lemma_num = i; - break; - } - size_t token_size; - char16* token; - char16* to_tokenize = read_buf; - // Get the Hanzi string - token = utf16_strtok(to_tokenize, &token_size, &to_tokenize); - if (NULL == token) { - free_resource(); - utf16_reader.close(); - return false; - } - size_t lemma_size = utf16_strlen(token); - if (lemma_size > kMaxLemmaSize) { - i--; - continue; - } - if (lemma_size > 4) { - i--; - continue; - } - // Copy to the lemma entry - utf16_strcpy(lemma_arr_[i].hanzi_str, token); - lemma_arr_[i].hz_str_len = token_size; - // Get the freq string - token = utf16_strtok(to_tokenize, &token_size, &to_tokenize); - if (NULL == token) { - free_resource(); - utf16_reader.close(); - return false; - } - lemma_arr_[i].freq = utf16_atof(token); - if (lemma_size > 1 && lemma_arr_[i].freq < 60) { - i--; - continue; - } - // Get GBK mark, if no valid Hanzi list available, all items which contains - // GBK characters will be discarded. Otherwise, all items which contains - // characters outside of the valid Hanzi list will be discarded. - token = utf16_strtok(to_tokenize, &token_size, &to_tokenize); - assert(NULL != token); - int gbk_flag = utf16_atoi(token); - if (NULL == valid_hzs || 0 == valid_hzs_num) { - if (0 != gbk_flag) { - i--; - continue; - } - } - else { - if (!str_in_hanzis_list(valid_hzs, valid_hzs_num, - lemma_arr_[i].hanzi_str, lemma_arr_[i].hz_str_len)) { - i--; - continue; - } - } - // Get spelling String - bool spelling_not_support = false; - for (size_t hz_pos = 0; hz_pos < (size_t)lemma_arr_[i].hz_str_len; - hz_pos++) { - // Get a Pinyin - token = utf16_strtok(to_tokenize, &token_size, &to_tokenize); - if (NULL == token) { - free_resource(); - utf16_reader.close(); - return false; - } - assert(utf16_strlen(token) <= kMaxPinyinSize); - utf16_strcpy_tochar(lemma_arr_[i].pinyin_str[hz_pos], token); - format_spelling_str(lemma_arr_[i].pinyin_str[hz_pos]); - // Put the pinyin to the spelling table - if (!spl_table_->put_spelling(lemma_arr_[i].pinyin_str[hz_pos], - lemma_arr_[i].freq)) { - spelling_not_support = true; - break; - } - } - // The whole line must have been parsed fully, otherwise discard this one. - token = utf16_strtok(to_tokenize, &token_size, &to_tokenize); - if (spelling_not_support || NULL != token) { - i--; - continue; - } - } - delete[] valid_hzs; - utf16_reader.close(); - printf("read successfully, lemma num: %zd\n", lemma_num); - return lemma_num; -} -bool DictBuilder::build_dict(const char* fn_raw, - const char* fn_validhzs, - DictTrie* dict_trie) { - if (NULL == fn_raw || NULL == dict_trie) - return false; - lemma_num_ = read_raw_dict(fn_raw, fn_validhzs, 240000); - if (0 == lemma_num_) - return false; - // Arrange the spelling table, and build a spelling tree - // The size of an spelling. '\0' is included. If the spelling table is - // initialized to calculate the spelling scores, the last char in the - // spelling string will be score, and it is also included in spl_item_size. - size_t spl_item_size; - size_t spl_num; - const char* spl_buf; - spl_buf = spl_table_->arrange(&spl_item_size, &spl_num); - if (NULL == spl_buf) { - free_resource(); - return false; - } - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - if (!spl_trie.construct(spl_buf, spl_item_size, spl_num, - spl_table_->get_score_amplifier(), - spl_table_->get_average_score())) { - free_resource(); - return false; - } - printf("spelling tree construct successfully.\n"); - // Convert the spelling string to idxs - for (size_t i = 0; i < lemma_num_; i++) { - for (size_t hz_pos = 0; hz_pos < (size_t)lemma_arr_[i].hz_str_len; - hz_pos++) { - uint16 spl_idxs[2]; - uint16 spl_start_pos[3]; - bool is_pre = true; - int spl_idx_num = - spl_parser_->splstr_to_idxs(lemma_arr_[i].pinyin_str[hz_pos], - strlen(lemma_arr_[i].pinyin_str[hz_pos]), - spl_idxs, spl_start_pos, 2, is_pre); - assert(1 == spl_idx_num); - if (spl_trie.is_half_id(spl_idxs[0])) { - uint16 num = spl_trie.half_to_full(spl_idxs[0], spl_idxs); - assert(0 != num); - } - lemma_arr_[i].spl_idx_arr[hz_pos] = spl_idxs[0]; - } - } - // Sort the lemma items according to the hanzi, and give each unique item a - // id - sort_lemmas_by_hz(); - scis_num_ = build_scis(); - // Construct the dict list - dict_trie->dict_list_ = new DictList(); - bool dl_success = dict_trie->dict_list_->init_list(scis_, scis_num_, - lemma_arr_, lemma_num_); - assert(dl_success); - // Construct the NGram information - NGram& ngram = NGram::get_instance(); - ngram.build_unigram(lemma_arr_, lemma_num_, - lemma_arr_[lemma_num_ - 1].idx_by_hz + 1); - // sort the lemma items according to the spelling idx string - myqsort(lemma_arr_, lemma_num_, sizeof(LemmaEntry), compare_py); - get_top_lemmas(); -#ifdef ___DO_STATISTICS___ - stat_init(); -#endif - lma_nds_used_num_le0_ = 1; // The root node - bool dt_success = construct_subset(static_cast(lma_nodes_le0_), - lemma_arr_, 0, lemma_num_, 0); - if (!dt_success) { - free_resource(); - return false; - } -#ifdef ___DO_STATISTICS___ - stat_print(); -#endif - // Move the node data and homo data to the DictTrie - dict_trie->root_ = new LmaNodeLE0[lma_nds_used_num_le0_]; - dict_trie->nodes_ge1_ = new LmaNodeGE1[lma_nds_used_num_ge1_]; - size_t lma_idx_num = homo_idx_num_eq1_ + homo_idx_num_gt1_ + top_lmas_num_; - dict_trie->lma_idx_buf_ = new unsigned char[lma_idx_num * kLemmaIdSize]; - assert(NULL != dict_trie->root_); - assert(NULL != dict_trie->lma_idx_buf_); - dict_trie->lma_node_num_le0_ = lma_nds_used_num_le0_; - dict_trie->lma_node_num_ge1_ = lma_nds_used_num_ge1_; - dict_trie->lma_idx_buf_len_ = lma_idx_num * kLemmaIdSize; - dict_trie->top_lmas_num_ = top_lmas_num_; - memcpy(dict_trie->root_, lma_nodes_le0_, - sizeof(LmaNodeLE0) * lma_nds_used_num_le0_); - memcpy(dict_trie->nodes_ge1_, lma_nodes_ge1_, - sizeof(LmaNodeGE1) * lma_nds_used_num_ge1_); - for (size_t pos = 0; pos < homo_idx_num_eq1_ + homo_idx_num_gt1_; pos++) { - id_to_charbuf(dict_trie->lma_idx_buf_ + pos * kLemmaIdSize, - homo_idx_buf_[pos]); - } - for (size_t pos = homo_idx_num_eq1_ + homo_idx_num_gt1_; - pos < lma_idx_num; pos++) { - LemmaIdType idx = - top_lmas_[pos - homo_idx_num_eq1_ - homo_idx_num_gt1_].idx_by_hz; - id_to_charbuf(dict_trie->lma_idx_buf_ + pos * kLemmaIdSize, idx); - } - if (kPrintDebug0) { - printf("homo_idx_num_eq1_: %d\n", homo_idx_num_eq1_); - printf("homo_idx_num_gt1_: %d\n", homo_idx_num_gt1_); - printf("top_lmas_num_: %d\n", top_lmas_num_); - } - free_resource(); - if (kPrintDebug0) { - printf("Building dict succeds\n"); - } - return dt_success; -} -void DictBuilder::id_to_charbuf(unsigned char* buf, LemmaIdType id) { - if (NULL == buf) - return; - for (size_t pos = 0; pos < kLemmaIdSize; pos++) { - (buf)[pos] = (unsigned char)(id >> (pos * 8)); - } -} -void DictBuilder::set_son_offset(LmaNodeGE1* node, size_t offset) { - node->son_1st_off_l = static_cast(offset); - node->son_1st_off_h = static_cast(offset >> 16); -} -void DictBuilder::set_homo_id_buf_offset(LmaNodeGE1* node, size_t offset) { - node->homo_idx_buf_off_l = static_cast(offset); - node->homo_idx_buf_off_h = static_cast(offset >> 16); -} -// All spelling strings will be converted to upper case, except that -// spellings started with "ZH"/"CH"/"SH" will be converted to -// "Zh"/"Ch"/"Sh" -void DictBuilder::format_spelling_str(char* spl_str) { - if (NULL == spl_str) - return; - uint16 pos = 0; - while ('\0' != spl_str[pos]) { - if (spl_str[pos] >= 'a' && spl_str[pos] <= 'z') - spl_str[pos] = spl_str[pos] - 'a' + 'A'; - if (1 == pos && 'H' == spl_str[pos]) { - if ('C' == spl_str[0] || 'S' == spl_str[0] || 'Z' == spl_str[0]) { - spl_str[pos] = 'h'; - } - } - pos++; - } -} -LemmaIdType DictBuilder::sort_lemmas_by_hz() { - if (NULL == lemma_arr_ || 0 == lemma_num_) - return 0; - myqsort(lemma_arr_, lemma_num_, sizeof(LemmaEntry), cmp_lemma_entry_hzs); - lemma_arr_[0].idx_by_hz = 1; - LemmaIdType idx_max = 1; - for (size_t i = 1; i < lemma_num_; i++) { - if (utf16_strcmp(lemma_arr_[i].hanzi_str, lemma_arr_[i - 1].hanzi_str)) { - idx_max++; - lemma_arr_[i].idx_by_hz = idx_max; - } - else { - idx_max++; - lemma_arr_[i].idx_by_hz = idx_max; - } - } - return idx_max + 1; -} -size_t DictBuilder::build_scis() { - if (NULL == scis_ || lemma_num_ * kMaxLemmaSize > scis_num_) - return 0; - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - // This first one is blank, because id 0 is invalid. - scis_[0].freq = 0; - scis_[0].hz = 0; - scis_[0].splid.full_splid = 0; - scis_[0].splid.half_splid = 0; - scis_num_ = 1; - // Copy the hanzis to the buffer - for (size_t pos = 0; pos < lemma_num_; pos++) { - size_t hz_num = lemma_arr_[pos].hz_str_len; - for (size_t hzpos = 0; hzpos < hz_num; hzpos++) { - scis_[scis_num_].hz = lemma_arr_[pos].hanzi_str[hzpos]; - scis_[scis_num_].splid.full_splid = lemma_arr_[pos].spl_idx_arr[hzpos]; - scis_[scis_num_].splid.half_splid = - spl_trie.full_to_half(scis_[scis_num_].splid.full_splid); - if (1 == hz_num) - scis_[scis_num_].freq = lemma_arr_[pos].freq; - else - scis_[scis_num_].freq = 0.000001; - scis_num_++; - } - } - myqsort(scis_, scis_num_, sizeof(SingleCharItem), cmp_scis_hz_splid_freq); - // Remove repeated items - size_t unique_scis_num = 1; - for (size_t pos = 1; pos < scis_num_; pos++) { - if (scis_[pos].hz == scis_[pos - 1].hz && - scis_[pos].splid.full_splid == scis_[pos - 1].splid.full_splid) - continue; - scis_[unique_scis_num] = scis_[pos]; - scis_[unique_scis_num].splid.half_splid = - spl_trie.full_to_half(scis_[pos].splid.full_splid); - unique_scis_num++; - } - scis_num_ = unique_scis_num; - // Update the lemma list. - for (size_t pos = 0; pos < lemma_num_; pos++) { - size_t hz_num = lemma_arr_[pos].hz_str_len; - for (size_t hzpos = 0; hzpos < hz_num; hzpos++) { - SingleCharItem key; - key.hz = lemma_arr_[pos].hanzi_str[hzpos]; - key.splid.full_splid = lemma_arr_[pos].spl_idx_arr[hzpos]; - key.splid.half_splid = spl_trie.full_to_half(key.splid.full_splid); - SingleCharItem* found; - found = static_cast(mybsearch(&key, scis_, - unique_scis_num, - sizeof(SingleCharItem), - cmp_scis_hz_splid)); - assert(found); - lemma_arr_[pos].hanzi_scis_ids[hzpos] = - static_cast(found - scis_); - lemma_arr_[pos].spl_idx_arr[hzpos] = found->splid.full_splid; - } - } - return scis_num_; -} -bool DictBuilder::construct_subset(void* parent, LemmaEntry* lemma_arr, - size_t item_start, size_t item_end, - size_t level) { - if (level >= kMaxLemmaSize || item_end <= item_start) - return false; - // 1. Scan for how many sons - size_t parent_son_num = 0; - // LemmaNode *son_1st = NULL; - // parent.num_of_son = 0; - LemmaEntry* lma_last_start = lemma_arr_ + item_start; - uint16 spl_idx_node = lma_last_start->spl_idx_arr[level]; - // Scan for how many sons to be allocaed - for (size_t i = item_start + 1; i < item_end; i++) { - LemmaEntry* lma_current = lemma_arr + i; - uint16 spl_idx_current = lma_current->spl_idx_arr[level]; - if (spl_idx_current != spl_idx_node) { - parent_son_num++; - spl_idx_node = spl_idx_current; - } - } - parent_son_num++; -#ifdef ___DO_STATISTICS___ - // Use to indicate whether all nodes of this layer have no son. - bool allson_noson = true; - assert(level < kMaxLemmaSize); - if (parent_son_num > max_sonbuf_len_[level]) - max_sonbuf_len_[level] = parent_son_num; - total_son_num_[level] += parent_son_num; - total_sonbuf_num_[level] += 1; - if (parent_son_num == 1) - sonbufs_num1_++; - else - sonbufs_numgt1_++; - total_lma_node_num_ += parent_son_num; -#endif - // 2. Update the parent's information - // Update the parent's son list; - LmaNodeLE0* son_1st_le0 = NULL; // only one of le0 or ge1 is used - LmaNodeGE1* son_1st_ge1 = NULL; // only one of le0 or ge1 is used. - if (0 == level) { // the parent is root - (static_cast(parent))->son_1st_off = - lma_nds_used_num_le0_; - son_1st_le0 = lma_nodes_le0_ + lma_nds_used_num_le0_; - lma_nds_used_num_le0_ += parent_son_num; - assert(parent_son_num <= 65535); - (static_cast(parent))->num_of_son = - static_cast(parent_son_num); - } - else if (1 == level) { // the parent is a son of root - (static_cast(parent))->son_1st_off = - lma_nds_used_num_ge1_; - son_1st_ge1 = lma_nodes_ge1_ + lma_nds_used_num_ge1_; - lma_nds_used_num_ge1_ += parent_son_num; - assert(parent_son_num <= 65535); - (static_cast(parent))->num_of_son = - static_cast(parent_son_num); - } - else { - set_son_offset((static_cast(parent)), - lma_nds_used_num_ge1_); - son_1st_ge1 = lma_nodes_ge1_ + lma_nds_used_num_ge1_; - lma_nds_used_num_ge1_ += parent_son_num; - assert(parent_son_num <= 255); - (static_cast(parent))->num_of_son = - (unsigned char)parent_son_num; - } - // 3. Now begin to construct the son one by one - size_t son_pos = 0; - lma_last_start = lemma_arr_ + item_start; - spl_idx_node = lma_last_start->spl_idx_arr[level]; - size_t homo_num = 0; - if (lma_last_start->spl_idx_arr[level + 1] == 0) - homo_num = 1; - size_t item_start_next = item_start; - for (size_t i = item_start + 1; i < item_end; i++) { - LemmaEntry* lma_current = lemma_arr_ + i; - uint16 spl_idx_current = lma_current->spl_idx_arr[level]; - if (spl_idx_current == spl_idx_node) { - if (lma_current->spl_idx_arr[level + 1] == 0) - homo_num++; - } - else { - // Construct a node - LmaNodeLE0* node_cur_le0 = NULL; // only one of them is valid - LmaNodeGE1* node_cur_ge1 = NULL; - if (0 == level) { - node_cur_le0 = son_1st_le0 + son_pos; - node_cur_le0->spl_idx = spl_idx_node; - node_cur_le0->homo_idx_buf_off = homo_idx_num_eq1_ + homo_idx_num_gt1_; - node_cur_le0->son_1st_off = 0; - homo_idx_num_eq1_ += homo_num; - } - else { - node_cur_ge1 = son_1st_ge1 + son_pos; - node_cur_ge1->spl_idx = spl_idx_node; - set_homo_id_buf_offset(node_cur_ge1, - (homo_idx_num_eq1_ + homo_idx_num_gt1_)); - set_son_offset(node_cur_ge1, 0); - homo_idx_num_gt1_ += homo_num; - } - if (homo_num > 0) { - LemmaIdType* idx_buf = homo_idx_buf_ + homo_idx_num_eq1_ + - homo_idx_num_gt1_ - homo_num; - if (0 == level) { - assert(homo_num <= 65535); - node_cur_le0->num_of_homo = static_cast(homo_num); - } - else { - assert(homo_num <= 255); - node_cur_ge1->num_of_homo = (unsigned char)homo_num; - } - for (size_t homo_pos = 0; homo_pos < homo_num; homo_pos++) { - idx_buf[homo_pos] = lemma_arr_[item_start_next + homo_pos].idx_by_hz; - } -#ifdef ___DO_STATISTICS___ - if (homo_num > max_homobuf_len_[level]) - max_homobuf_len_[level] = homo_num; - total_homo_num_[level] += homo_num; -#endif - } - if (i - item_start_next > homo_num) { - void* next_parent; - if (0 == level) - next_parent = static_cast(node_cur_le0); - else - next_parent = static_cast(node_cur_ge1); - construct_subset(next_parent, lemma_arr, - item_start_next + homo_num, i, level + 1); -#ifdef ___DO_STATISTICS___ - total_node_hasson_[level] += 1; - allson_noson = false; -#endif - } - // for the next son - lma_last_start = lma_current; - spl_idx_node = spl_idx_current; - item_start_next = i; - homo_num = 0; - if (lma_current->spl_idx_arr[level + 1] == 0) - homo_num = 1; - son_pos++; - } - } - // 4. The last one to construct - LmaNodeLE0* node_cur_le0 = NULL; // only one of them is valid - LmaNodeGE1* node_cur_ge1 = NULL; - if (0 == level) { - node_cur_le0 = son_1st_le0 + son_pos; - node_cur_le0->spl_idx = spl_idx_node; - node_cur_le0->homo_idx_buf_off = homo_idx_num_eq1_ + homo_idx_num_gt1_; - node_cur_le0->son_1st_off = 0; - homo_idx_num_eq1_ += homo_num; - } - else { - node_cur_ge1 = son_1st_ge1 + son_pos; - node_cur_ge1->spl_idx = spl_idx_node; - set_homo_id_buf_offset(node_cur_ge1, - (homo_idx_num_eq1_ + homo_idx_num_gt1_)); - set_son_offset(node_cur_ge1, 0); - homo_idx_num_gt1_ += homo_num; - } - if (homo_num > 0) { - LemmaIdType* idx_buf = homo_idx_buf_ + homo_idx_num_eq1_ + - homo_idx_num_gt1_ - homo_num; - if (0 == level) { - assert(homo_num <= 65535); - node_cur_le0->num_of_homo = static_cast(homo_num); - } - else { - assert(homo_num <= 255); - node_cur_ge1->num_of_homo = (unsigned char)homo_num; - } - for (size_t homo_pos = 0; homo_pos < homo_num; homo_pos++) { - idx_buf[homo_pos] = lemma_arr[item_start_next + homo_pos].idx_by_hz; - } -#ifdef ___DO_STATISTICS___ - if (homo_num > max_homobuf_len_[level]) - max_homobuf_len_[level] = homo_num; - total_homo_num_[level] += homo_num; -#endif - } - if (item_end - item_start_next > homo_num) { - void* next_parent; - if (0 == level) - next_parent = static_cast(node_cur_le0); - else - next_parent = static_cast(node_cur_ge1); - construct_subset(next_parent, lemma_arr, - item_start_next + homo_num, item_end, level + 1); -#ifdef ___DO_STATISTICS___ - total_node_hasson_[level] += 1; - allson_noson = false; -#endif - } -#ifdef ___DO_STATISTICS___ - if (allson_noson) { - total_sonbuf_allnoson_[level] += 1; - total_node_in_sonbuf_allnoson_[level] += parent_son_num; - } -#endif - assert(son_pos + 1 == parent_son_num); - return true; -} -#ifdef ___DO_STATISTICS___ -void DictBuilder::stat_init() { - memset(max_sonbuf_len_, 0, sizeof(size_t) * kMaxLemmaSize); - memset(max_homobuf_len_, 0, sizeof(size_t) * kMaxLemmaSize); - memset(total_son_num_, 0, sizeof(size_t) * kMaxLemmaSize); - memset(total_node_hasson_, 0, sizeof(size_t) * kMaxLemmaSize); - memset(total_sonbuf_num_, 0, sizeof(size_t) * kMaxLemmaSize); - memset(total_sonbuf_allnoson_, 0, sizeof(size_t) * kMaxLemmaSize); - memset(total_node_in_sonbuf_allnoson_, 0, sizeof(size_t) * kMaxLemmaSize); - memset(total_homo_num_, 0, sizeof(size_t) * kMaxLemmaSize); - sonbufs_num1_ = 0; - sonbufs_numgt1_ = 0; - total_lma_node_num_ = 0; -} -void DictBuilder::stat_print() { - printf("\n------------STAT INFO-------------\n"); - printf("[root is layer -1]\n"); - printf(".. max_sonbuf_len per layer(from layer 0):\n "); - for (size_t i = 0; i < kMaxLemmaSize; i++) - printf("%d, ", max_sonbuf_len_[i]); - printf("-, \n"); - printf(".. max_homobuf_len per layer:\n -, "); - for (size_t i = 0; i < kMaxLemmaSize; i++) - printf("%d, ", max_homobuf_len_[i]); - printf("\n"); - printf(".. total_son_num per layer:\n "); - for (size_t i = 0; i < kMaxLemmaSize; i++) - printf("%d, ", total_son_num_[i]); - printf("-, \n"); - printf(".. total_node_hasson per layer:\n 1, "); - for (size_t i = 0; i < kMaxLemmaSize; i++) - printf("%d, ", total_node_hasson_[i]); - printf("\n"); - printf(".. total_sonbuf_num per layer:\n "); - for (size_t i = 0; i < kMaxLemmaSize; i++) - printf("%d, ", total_sonbuf_num_[i]); - printf("-, \n"); - printf(".. total_sonbuf_allnoson per layer:\n "); - for (size_t i = 0; i < kMaxLemmaSize; i++) - printf("%d, ", total_sonbuf_allnoson_[i]); - printf("-, \n"); - printf(".. total_node_in_sonbuf_allnoson per layer:\n "); - for (size_t i = 0; i < kMaxLemmaSize; i++) - printf("%d, ", total_node_in_sonbuf_allnoson_[i]); - printf("-, \n"); - printf(".. total_homo_num per layer:\n 0, "); - for (size_t i = 0; i < kMaxLemmaSize; i++) - printf("%d, ", total_homo_num_[i]); - printf("\n"); - printf(".. son buf allocation number with only 1 son: %d\n", sonbufs_num1_); - printf(".. son buf allocation number with more than 1 son: %d\n", - sonbufs_numgt1_); - printf(".. total lemma node number: %d\n", total_lma_node_num_ + 1); -} -#endif // ___DO_STATISTICS___ -#endif // ___BUILD_MODEL___ -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/dictbuilder.h b/Widget/base/Virtual_Keyboard/googlepinyin/dictbuilder.h deleted file mode 100644 index 774eca7..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/dictbuilder.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_DICTBUILDER_H__ -#define PINYINIME_INCLUDE_DICTBUILDER_H__ -#include -#include "./dictdef.h" -#include "./dictlist.h" -#include "./spellingtable.h" -#include "./spellingtrie.h" -#include "./splparser.h" -#include "./utf16char.h" -namespace ime_pinyin { -#ifdef ___BUILD_MODEL___ -#define ___DO_STATISTICS___ -class DictTrie; -class DictBuilder { -private: - // The raw lemma array buffer. - LemmaEntry* lemma_arr_; - size_t lemma_num_; - // Used to store all possible single char items. - // Two items may have the same Hanzi while their spelling ids are different. - SingleCharItem* scis_; - size_t scis_num_; - // In the tree, root's level is -1. - // Lemma nodes for root, and level 0 - LmaNodeLE0* lma_nodes_le0_; - // Lemma nodes for layers whose levels are deeper than 0 - LmaNodeGE1* lma_nodes_ge1_; - // Number of used lemma nodes - size_t lma_nds_used_num_le0_; - size_t lma_nds_used_num_ge1_; - // Used to store homophonies' ids. - LemmaIdType* homo_idx_buf_; - // Number of homophonies each of which only contains one Chinese character. - size_t homo_idx_num_eq1_; - // Number of homophonies each of which contains more than one character. - size_t homo_idx_num_gt1_; - // The items with highest scores. - LemmaEntry* top_lmas_; - size_t top_lmas_num_; - SpellingTable* spl_table_; - SpellingParser* spl_parser_; -#ifdef ___DO_STATISTICS___ - size_t max_sonbuf_len_[kMaxLemmaSize]; - size_t max_homobuf_len_[kMaxLemmaSize]; - size_t total_son_num_[kMaxLemmaSize]; - size_t total_node_hasson_[kMaxLemmaSize]; - size_t total_sonbuf_num_[kMaxLemmaSize]; - size_t total_sonbuf_allnoson_[kMaxLemmaSize]; - size_t total_node_in_sonbuf_allnoson_[kMaxLemmaSize]; - size_t total_homo_num_[kMaxLemmaSize]; - size_t sonbufs_num1_; // Number of son buffer with only 1 son - size_t sonbufs_numgt1_; // Number of son buffer with more 1 son; - size_t total_lma_node_num_; - void stat_init(); - void stat_print(); -#endif -public: - DictBuilder(); - ~DictBuilder(); - // Build dictionary trie from the file fn_raw. File fn_validhzs provides - // valid chars. If fn_validhzs is NULL, only chars in GB2312 will be - // included. - bool build_dict(const char* fn_raw, const char* fn_validhzs, - DictTrie* dict_trie); -private: - // Fill in the buffer with id. The caller guarantees that the paramters are - // vaild. - void id_to_charbuf(unsigned char* buf, LemmaIdType id); - // Update the offset of sons for a node. - void set_son_offset(LmaNodeGE1* node, size_t offset); - // Update the offset of homophonies' ids for a node. - void set_homo_id_buf_offset(LmaNodeGE1* node, size_t offset); - // Format a speling string. - void format_spelling_str(char* spl_str); - // Sort the lemma_arr by the hanzi string, and give each of unique items - // a id. Why we need to sort the lemma list according to their Hanzi string - // is to find items started by a given prefix string to do prediction. - // Actually, the single char items are be in other order, for example, - // in spelling id order, etc. - // Return value is next un-allocated idx available. - LemmaIdType sort_lemmas_by_hz(); - // Build the SingleCharItem list, and fill the hanzi_scis_ids in the - // lemma buffer lemma_arr_. - // This function should be called after the lemma array is ready. - // Return the number of unique SingleCharItem elements. - size_t build_scis(); - // Construct a subtree using a subset of the spelling array (from - // item_star to item_end) - // parent is the parent node to update the necessary information - // parent can be a member of LmaNodeLE0 or LmaNodeGE1 - bool construct_subset(void* parent, LemmaEntry* lemma_arr, - size_t item_start, size_t item_end, size_t level); - // Read valid Chinese Hanzis from the given file. - // num is used to return number of chars. - // The return buffer is sorted and caller needs to free the returned buffer. - char16* read_valid_hanzis(const char* fn_validhzs, size_t* num); - // Read a raw dictionary. max_item is the maximum number of items. If there - // are more items in the ditionary, only the first max_item will be read. - // Returned value is the number of items successfully read from the file. - size_t read_raw_dict(const char* fn_raw, const char* fn_validhzs, - size_t max_item); - // Try to find if a character is in hzs buffer. - bool hz_in_hanzis_list(const char16* hzs, size_t hzs_len, char16 hz); - // Try to find if all characters in str are in hzs buffer. - bool str_in_hanzis_list(const char16* hzs, size_t hzs_len, - const char16* str, size_t str_len); - // Get these lemmas with toppest scores. - void get_top_lemmas(); - // Allocate resource to build dictionary. - // lma_num is the number of items to be loaded - bool alloc_resource(size_t lma_num); - // Free resource. - void free_resource(); -}; -#endif // ___BUILD_MODEL___ -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_DICTBUILDER_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/dictdef.h b/Widget/base/Virtual_Keyboard/googlepinyin/dictdef.h deleted file mode 100644 index 5d49ef6..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/dictdef.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_DICTDEF_H__ -#define PINYINIME_INCLUDE_DICTDEF_H__ -#include -#include "./utf16char.h" -namespace ime_pinyin { -// Enable the following line when building the binary dictionary model. -// #define ___BUILD_MODEL___ -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef signed char int8; -typedef short int16; -typedef int int32; -typedef long long int64; -typedef unsigned long long uint64; -const bool kPrintDebug0 = false; -const bool kPrintDebug1 = false; -const bool kPrintDebug2 = false; -// The max length of a lemma. -const size_t kMaxLemmaSize = 8; -// The max length of a Pinyin (spelling). -const size_t kMaxPinyinSize = 6; -// The number of half spelling ids. For Chinese Pinyin, there 30 half ids. -// See SpellingTrie.h for details. -const size_t kHalfSpellingIdNum = 29; -// The maximum number of full spellings. For Chinese Pinyin, there are only -// about 410 spellings. -// If change this value is bigger(needs more bits), please also update -// other structures like SpellingNode, to make sure than a spelling id can be -// stored. -// -1 is because that 0 is never used. -const size_t kMaxSpellingNum = 512 - kHalfSpellingIdNum - 1; -const size_t kMaxSearchSteps = 40; -// One character predicts its following characters. -const size_t kMaxPredictSize = (kMaxLemmaSize - 1); -// LemmaIdType must always be size_t. -typedef size_t LemmaIdType; -const size_t kLemmaIdSize = 3; // Actually, a Id occupies 3 bytes in storage. -const size_t kLemmaIdComposing = 0xffffff; -typedef uint16 LmaScoreType; -typedef uint16 KeyScoreType; -// Number of items with highest score are kept for prediction purpose. -const size_t kTopScoreLemmaNum = 10; -const size_t kMaxPredictNumByGt3 = 1; -const size_t kMaxPredictNumBy3 = 2; -const size_t kMaxPredictNumBy2 = 2; -// The last lemma id (included) for the system dictionary. The system -// dictionary's ids always start from 1. -const LemmaIdType kSysDictIdEnd = 500000; -// The first lemma id for the user dictionary. -const LemmaIdType kUserDictIdStart = 500001; -// The last lemma id (included) for the user dictionary. -const LemmaIdType kUserDictIdEnd = 600000; -typedef struct { - uint16 half_splid : 5; - uint16 full_splid : 11; -} SpellingId, *PSpellingId; -/** - * We use different node types for different layers - * Statistical data of the building result for a testing dictionary: - * root, level 0, level 1, level 2, level 3 - * max son num of one node: 406 280 41 2 - - * max homo num of one node: 0 90 23 2 2 - * total node num of a layer: 1 406 31766 13516 993 - * total homo num of a layer: 9 5674 44609 12667 995 - * - * The node number for root and level 0 won't be larger than 500 - * According to the information above, two kinds of nodes can be used; one for - * root and level 0, the other for these layers deeper than 0. - * - * LE = less and equal, - * A node occupies 16 bytes. so, totallly less than 16 * 500 = 8K - */ -struct LmaNodeLE0 { - uint32 son_1st_off; - uint32 homo_idx_buf_off; - uint16 spl_idx; - uint16 num_of_son; - uint16 num_of_homo; -}; -/** - * GE = great and equal - * A node occupies 8 bytes. - */ -struct LmaNodeGE1 { - uint16 son_1st_off_l; // Low bits of the son_1st_off - uint16 homo_idx_buf_off_l; // Low bits of the homo_idx_buf_off_1 - uint16 spl_idx; - unsigned char num_of_son; // number of son nodes - unsigned char num_of_homo; // number of homo words - unsigned char son_1st_off_h; // high bits of the son_1st_off - unsigned char homo_idx_buf_off_h; // high bits of the homo_idx_buf_off -}; -#ifdef ___BUILD_MODEL___ -struct SingleCharItem { - float freq; - char16 hz; - SpellingId splid; -}; -struct LemmaEntry { - LemmaIdType idx_by_py; - LemmaIdType idx_by_hz; - char16 hanzi_str[kMaxLemmaSize + 1]; - // The SingleCharItem id for each Hanzi. - uint16 hanzi_scis_ids[kMaxLemmaSize]; - uint16 spl_idx_arr[kMaxLemmaSize + 1]; - char pinyin_str[kMaxLemmaSize][kMaxPinyinSize + 1]; - unsigned char hz_str_len; - float freq; -}; -#endif // ___BUILD_MODEL___ -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_DICTDEF_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/dictlist.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/dictlist.cpp deleted file mode 100644 index f517a34..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/dictlist.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "dictlist.h" -#include -#include -#include -#include "mystdlib.h" -#include "ngram.h" -#include "searchutility.h" -namespace ime_pinyin { -DictList::DictList() { - initialized_ = false; - scis_num_ = 0; - scis_hz_ = NULL; - scis_splid_ = NULL; - buf_ = NULL; - spl_trie_ = SpellingTrie::get_cpinstance(); - assert(kMaxLemmaSize == 8); - cmp_func_[0] = cmp_hanzis_1; - cmp_func_[1] = cmp_hanzis_2; - cmp_func_[2] = cmp_hanzis_3; - cmp_func_[3] = cmp_hanzis_4; - cmp_func_[4] = cmp_hanzis_5; - cmp_func_[5] = cmp_hanzis_6; - cmp_func_[6] = cmp_hanzis_7; - cmp_func_[7] = cmp_hanzis_8; -} -DictList::~DictList() { - free_resource(); -} -bool DictList::alloc_resource(size_t buf_size, size_t scis_num) { - // Allocate memory - buf_ = static_cast(malloc(buf_size * sizeof(char16))); - if (NULL == buf_) - return false; - scis_num_ = scis_num; - scis_hz_ = static_cast(malloc(scis_num_ * sizeof(char16))); - if (NULL == scis_hz_) - return false; - scis_splid_ = static_cast(malloc(scis_num_ * sizeof(SpellingId))); - if (NULL == scis_splid_) - return false; - return true; -} -void DictList::free_resource() { - if (NULL != buf_) - free(buf_); - buf_ = NULL; - if (NULL != scis_hz_) - free(scis_hz_); - scis_hz_ = NULL; - if (NULL != scis_splid_) - free(scis_splid_); - scis_splid_ = NULL; -} -#ifdef ___BUILD_MODEL___ -bool DictList::init_list(const SingleCharItem* scis, size_t scis_num, - const LemmaEntry* lemma_arr, size_t lemma_num) { - if (NULL == scis || 0 == scis_num || NULL == lemma_arr || 0 == lemma_num) - return false; - initialized_ = false; - if (NULL != buf_) - free(buf_); - // calculate the size - size_t buf_size = calculate_size(lemma_arr, lemma_num); - if (0 == buf_size) - return false; - if (!alloc_resource(buf_size, scis_num)) - return false; - fill_scis(scis, scis_num); - // Copy the related content from the array to inner buffer - fill_list(lemma_arr, lemma_num); - initialized_ = true; - return true; -} -size_t DictList::calculate_size(const LemmaEntry* lemma_arr, size_t lemma_num) { - size_t last_hz_len = 0; - size_t list_size = 0; - size_t id_num = 0; - for (size_t i = 0; i < lemma_num; i++) { - if (0 == i) { - last_hz_len = lemma_arr[i].hz_str_len; - assert(last_hz_len > 0); - assert(lemma_arr[0].idx_by_hz == 1); - id_num++; - start_pos_[0] = 0; - start_id_[0] = id_num; - last_hz_len = 1; - list_size += last_hz_len; - } - else { - size_t current_hz_len = lemma_arr[i].hz_str_len; - assert(current_hz_len >= last_hz_len); - if (current_hz_len == last_hz_len) { - list_size += current_hz_len; - id_num++; - } - else { - for (size_t len = last_hz_len; len < current_hz_len - 1; len++) { - start_pos_[len] = start_pos_[len - 1]; - start_id_[len] = start_id_[len - 1]; - } - start_pos_[current_hz_len - 1] = list_size; - id_num++; - start_id_[current_hz_len - 1] = id_num; - last_hz_len = current_hz_len; - list_size += current_hz_len; - } - } - } - for (size_t i = last_hz_len; i <= kMaxLemmaSize; i++) { - if (0 == i) { - start_pos_[0] = 0; - start_id_[0] = 1; - } - else { - start_pos_[i] = list_size; - start_id_[i] = id_num; - } - } - return start_pos_[kMaxLemmaSize]; -} -void DictList::fill_scis(const SingleCharItem* scis, size_t scis_num) { - assert(scis_num_ == scis_num); - for (size_t pos = 0; pos < scis_num_; pos++) { - scis_hz_[pos] = scis[pos].hz; - scis_splid_[pos] = scis[pos].splid; - } -} -void DictList::fill_list(const LemmaEntry* lemma_arr, size_t lemma_num) { - size_t current_pos = 0; - utf16_strncpy(buf_, lemma_arr[0].hanzi_str, - lemma_arr[0].hz_str_len); - current_pos = lemma_arr[0].hz_str_len; - size_t id_num = 1; - for (size_t i = 1; i < lemma_num; i++) { - utf16_strncpy(buf_ + current_pos, lemma_arr[i].hanzi_str, - lemma_arr[i].hz_str_len); - id_num++; - current_pos += lemma_arr[i].hz_str_len; - } - assert(current_pos == start_pos_[kMaxLemmaSize]); - assert(id_num == start_id_[kMaxLemmaSize]); -} -char16* DictList::find_pos2_startedbyhz(char16 hz_char) { - char16* found_2w = static_cast(mybsearch(&hz_char, buf_ + start_pos_[1], - (start_pos_[2] - start_pos_[1]) / 2, - sizeof(char16) * 2, cmp_hanzis_1)); - if (NULL == found_2w) - return NULL; - while (found_2w > buf_ + start_pos_[1] && *found_2w == *(found_2w - 1)) - found_2w -= 2; - return found_2w; -} -#endif // ___BUILD_MODEL___ -char16* DictList::find_pos_startedbyhzs(const char16 last_hzs[], - size_t word_len, int (*cmp_func)(const void*, const void*)) { - char16* found_w = static_cast(mybsearch(last_hzs, buf_ + start_pos_[word_len - 1], - (start_pos_[word_len] - start_pos_[word_len - 1]) / word_len, - sizeof(char16) * word_len, cmp_func)); - if (NULL == found_w) - return NULL; - while (found_w > buf_ + start_pos_[word_len - 1] && - cmp_func(found_w, found_w - word_len) == 0) - found_w -= word_len; - return found_w; -} -size_t DictList::predict(const char16 last_hzs[], uint16 hzs_len, - NPredictItem* npre_items, size_t npre_max, - size_t b4_used) { - assert(hzs_len <= kMaxPredictSize && hzs_len > 0); - // 1. Prepare work - int (*cmp_func)(const void*, const void*) = cmp_func_[hzs_len - 1]; - NGram& ngram = NGram::get_instance(); - size_t item_num = 0; - // 2. Do prediction - for (uint16 pre_len = 1; pre_len <= kMaxPredictSize + 1 - hzs_len; - pre_len++) { - uint16 word_len = hzs_len + pre_len; - char16* w_buf = find_pos_startedbyhzs(last_hzs, word_len, cmp_func); - if (NULL == w_buf) - continue; - while (w_buf < buf_ + start_pos_[word_len] && - cmp_func(w_buf, last_hzs) == 0 && - item_num < npre_max) { - memset(npre_items + item_num, 0, sizeof(NPredictItem)); - utf16_strncpy(npre_items[item_num].pre_hzs, w_buf + hzs_len, pre_len); - npre_items[item_num].psb = - ngram.get_uni_psb((size_t)(w_buf - buf_ - start_pos_[word_len - 1]) / word_len + start_id_[word_len - 1]); - npre_items[item_num].his_len = hzs_len; - item_num++; - w_buf += word_len; - } - } - size_t new_num = 0; - for (size_t i = 0; i < item_num; i++) { - // Try to find it in the existing items - size_t e_pos; - for (e_pos = 1; e_pos <= b4_used; e_pos++) { - if (utf16_strncmp((*(npre_items - e_pos)).pre_hzs, npre_items[i].pre_hzs, - kMaxPredictSize) == 0) - break; - } - if (e_pos <= b4_used) - continue; - // If not found, append it to the buffer - npre_items[new_num] = npre_items[i]; - new_num++; - } - return new_num; -} -uint16 DictList::get_lemma_str(LemmaIdType id_lemma, char16* str_buf, - uint16 str_max) { - if (!initialized_ || id_lemma >= start_id_[kMaxLemmaSize] || NULL == str_buf || str_max <= 1) - return 0; - // Find the range - for (uint16 i = 0; i < kMaxLemmaSize; i++) { - if (i + 1 > str_max - 1) - return 0; - if (start_id_[i] <= id_lemma && start_id_[i + 1] > id_lemma) { - size_t id_span = id_lemma - start_id_[i]; - uint16* buf = buf_ + start_pos_[i] + id_span * (i + 1); - for (uint16 len = 0; len <= i; len++) { - str_buf[len] = buf[len]; - } - str_buf[i + 1] = (char16)'\0'; - return i + 1; - } - } - return 0; -} -uint16 DictList::get_splids_for_hanzi(char16 hanzi, uint16 half_splid, - uint16* splids, uint16 max_splids) { - char16* hz_found = static_cast(mybsearch(&hanzi, scis_hz_, scis_num_, sizeof(char16), cmp_hanzis_1)); - assert(NULL != hz_found && hanzi == *hz_found); - // Move to the first one. - while (hz_found > scis_hz_ && hanzi == *(hz_found - 1)) - hz_found--; - // First try to found if strict comparison result is not zero. - char16* hz_f = hz_found; - bool strict = false; - while (hz_f < scis_hz_ + scis_num_ && hanzi == *hz_f) { - uint16 pos = hz_f - scis_hz_; - if (0 == half_splid || scis_splid_[pos].half_splid == half_splid) { - strict = true; - } - hz_f++; - } - uint16 found_num = 0; - while (hz_found < scis_hz_ + scis_num_ && hanzi == *hz_found) { - uint16 pos = hz_found - scis_hz_; - if (0 == half_splid || - (strict && scis_splid_[pos].half_splid == half_splid) || - (!strict && spl_trie_->half_full_compatible(half_splid, scis_splid_[pos].full_splid))) { - assert(found_num + 1 < max_splids); - splids[found_num] = scis_splid_[pos].full_splid; - found_num++; - } - hz_found++; - } - return found_num; -} -LemmaIdType DictList::get_lemma_id(const char16* str, uint16 str_len) { - if (NULL == str || str_len > kMaxLemmaSize) - return 0; - char16* found = find_pos_startedbyhzs(str, str_len, cmp_func_[str_len - 1]); - if (NULL == found) - return 0; - assert(found > buf_); - assert(static_cast(found - buf_) >= start_pos_[str_len - 1]); - return static_cast(start_id_[str_len - 1] + - (found - buf_ - start_pos_[str_len - 1]) / str_len); -} -void DictList::convert_to_hanzis(char16* str, uint16 str_len) { - assert(NULL != str); - for (uint16 str_pos = 0; str_pos < str_len; str_pos++) { - str[str_pos] = scis_hz_[str[str_pos]]; - } -} -void DictList::convert_to_scis_ids(char16* str, uint16 str_len) { - assert(NULL != str); - for (uint16 str_pos = 0; str_pos < str_len; str_pos++) { - str[str_pos] = 0x100; - } -} -bool DictList::save_list(FILE* fp) { - if (!initialized_ || NULL == fp) - return false; - if (NULL == buf_ || 0 == start_pos_[kMaxLemmaSize] || - NULL == scis_hz_ || NULL == scis_splid_ || 0 == scis_num_) - return false; - if (fwrite(&scis_num_, sizeof(uint32), 1, fp) != 1) - return false; - if (fwrite(start_pos_, sizeof(uint32), kMaxLemmaSize + 1, fp) != - kMaxLemmaSize + 1) - return false; - if (fwrite(start_id_, sizeof(uint32), kMaxLemmaSize + 1, fp) != - kMaxLemmaSize + 1) - return false; - if (fwrite(scis_hz_, sizeof(char16), scis_num_, fp) != scis_num_) - return false; - if (fwrite(scis_splid_, sizeof(SpellingId), scis_num_, fp) != scis_num_) - return false; - if (fwrite(buf_, sizeof(char16), start_pos_[kMaxLemmaSize], fp) != - start_pos_[kMaxLemmaSize]) - return false; - return true; -} -bool DictList::load_list(FILE* fp) { - if (NULL == fp) - return false; - initialized_ = false; - if (fread(&scis_num_, sizeof(uint32), 1, fp) != 1) - return false; - if (fread(start_pos_, sizeof(uint32), kMaxLemmaSize + 1, fp) != - kMaxLemmaSize + 1) - return false; - if (fread(start_id_, sizeof(uint32), kMaxLemmaSize + 1, fp) != - kMaxLemmaSize + 1) - return false; - free_resource(); - if (!alloc_resource(start_pos_[kMaxLemmaSize], scis_num_)) - return false; - if (fread(scis_hz_, sizeof(char16), scis_num_, fp) != scis_num_) - return false; - if (fread(scis_splid_, sizeof(SpellingId), scis_num_, fp) != scis_num_) - return false; - if (fread(buf_, sizeof(char16), start_pos_[kMaxLemmaSize], fp) != - start_pos_[kMaxLemmaSize]) - return false; - initialized_ = true; - return true; -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/dictlist.h b/Widget/base/Virtual_Keyboard/googlepinyin/dictlist.h deleted file mode 100644 index 9ea5646..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/dictlist.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_DICTLIST_H__ -#define PINYINIME_INCLUDE_DICTLIST_H__ -#include -#include -#include "./dictdef.h" -#include "./searchutility.h" -#include "./spellingtrie.h" -#include "./utf16char.h" -namespace ime_pinyin { -class DictList { -private: - bool initialized_; - const SpellingTrie* spl_trie_; - // Number of SingCharItem. The first is blank, because id 0 is invalid. - uint32 scis_num_; - char16* scis_hz_; - SpellingId* scis_splid_; - // The large memory block to store the word list. - char16* buf_; - // Starting position of those words whose lengths are i+1, counted in - // char16 - uint32 start_pos_[kMaxLemmaSize + 1]; - uint32 start_id_[kMaxLemmaSize + 1]; - int (*cmp_func_[kMaxLemmaSize])(const void*, const void*); - bool alloc_resource(size_t buf_size, size_t scim_num); - void free_resource(); -#ifdef ___BUILD_MODEL___ - // Calculate the requsted memory, including the start_pos[] buffer. - size_t calculate_size(const LemmaEntry* lemma_arr, size_t lemma_num); - void fill_scis(const SingleCharItem* scis, size_t scis_num); - // Copy the related content to the inner buffer - // It should be called after calculate_size() - void fill_list(const LemmaEntry* lemma_arr, size_t lemma_num); - // Find the starting position for the buffer of those 2-character Chinese word - // whose first character is the given Chinese character. - char16* find_pos2_startedbyhz(char16 hz_char); -#endif - // Find the starting position for the buffer of those words whose lengths are - // word_len. The given parameter cmp_func decides how many characters from - // beginning will be used to compare. - char16* find_pos_startedbyhzs(const char16 last_hzs[], - size_t word_Len, - int (*cmp_func)(const void*, const void*)); -public: - DictList(); - ~DictList(); - bool save_list(FILE* fp); - bool load_list(FILE* fp); -#ifdef ___BUILD_MODEL___ - // Init the list from the LemmaEntry array. - // lemma_arr should have been sorted by the hanzi_str, and have been given - // ids from 1 - bool init_list(const SingleCharItem* scis, size_t scis_num, - const LemmaEntry* lemma_arr, size_t lemma_num); -#endif - // Get the hanzi string for the given id - uint16 get_lemma_str(LemmaIdType id_hz, char16* str_buf, uint16 str_max); - void convert_to_hanzis(char16* str, uint16 str_len); - void convert_to_scis_ids(char16* str, uint16 str_len); - // last_hzs stores the last n Chinese characters history, its length should be - // less or equal than kMaxPredictSize. - // hzs_len specifies the length(<= kMaxPredictSize). - // predict_buf is used to store the result. - // buf_len specifies the buffer length. - // b4_used specifies how many items before predict_buf have been used. - // Returned value is the number of newly added items. - size_t predict(const char16 last_hzs[], uint16 hzs_len, - NPredictItem* npre_items, size_t npre_max, - size_t b4_used); - // If half_splid is a valid half spelling id, return those full spelling - // ids which share this half id. - uint16 get_splids_for_hanzi(char16 hanzi, uint16 half_splid, - uint16* splids, uint16 max_splids); - LemmaIdType get_lemma_id(const char16* str, uint16 str_len); -}; -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_DICTLIST_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/dicttrie.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/dicttrie.cpp deleted file mode 100644 index 66e8508..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/dicttrie.cpp +++ /dev/null @@ -1,794 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "dicttrie.h" -#include -#include -#include -#include "dictbuilder.h" -#include "lpicache.h" -#include "mystdlib.h" -#include "ngram.h" -namespace ime_pinyin { -DictTrie::DictTrie() { - spl_trie_ = SpellingTrie::get_cpinstance(); - root_ = NULL; - splid_le0_index_ = NULL; - lma_node_num_le0_ = 0; - nodes_ge1_ = NULL; - lma_node_num_ge1_ = 0; - lma_idx_buf_ = NULL; - lma_idx_buf_len_ = 0; - total_lma_num_ = 0; - top_lmas_num_ = 0; - dict_list_ = NULL; - parsing_marks_ = NULL; - mile_stones_ = NULL; - reset_milestones(0, kFirstValidMileStoneHandle); -} -DictTrie::~DictTrie() { - free_resource(true); -} -void DictTrie::free_resource(bool free_dict_list) { - if (NULL != root_) - free(root_); - root_ = NULL; - if (NULL != splid_le0_index_) - free(splid_le0_index_); - splid_le0_index_ = NULL; - if (NULL != nodes_ge1_) - free(nodes_ge1_); - nodes_ge1_ = NULL; - if (NULL != lma_idx_buf_) - free(lma_idx_buf_); - lma_idx_buf_ = NULL; - if (free_dict_list) { - if (NULL != dict_list_) { - delete dict_list_; - } - dict_list_ = NULL; - } - if (parsing_marks_) - delete[] parsing_marks_; - parsing_marks_ = NULL; - if (mile_stones_) - delete[] mile_stones_; - mile_stones_ = NULL; - reset_milestones(0, kFirstValidMileStoneHandle); -} -inline size_t DictTrie::get_son_offset(const LmaNodeGE1* node) { - return ((size_t)node->son_1st_off_l + ((size_t)node->son_1st_off_h << 16)); -} -inline size_t DictTrie::get_homo_idx_buf_offset(const LmaNodeGE1* node) { - return ((size_t)node->homo_idx_buf_off_l + - ((size_t)node->homo_idx_buf_off_h << 16)); -} -inline LemmaIdType DictTrie::get_lemma_id(size_t id_offset) { - LemmaIdType id = 0; - for (uint16 pos = kLemmaIdSize - 1; pos > 0; pos--) - id = (id << 8) + lma_idx_buf_[id_offset * kLemmaIdSize + pos]; - id = (id << 8) + lma_idx_buf_[id_offset * kLemmaIdSize]; - return id; -} -#ifdef ___BUILD_MODEL___ -bool DictTrie::build_dict(const char* fn_raw, const char* fn_validhzs) { - DictBuilder* dict_builder = new DictBuilder(); - free_resource(true); - return dict_builder->build_dict(fn_raw, fn_validhzs, this); -} -bool DictTrie::save_dict(FILE* fp) { - if (NULL == fp) - return false; - if (fwrite(&lma_node_num_le0_, sizeof(uint32), 1, fp) != 1) - return false; - if (fwrite(&lma_node_num_ge1_, sizeof(uint32), 1, fp) != 1) - return false; - if (fwrite(&lma_idx_buf_len_, sizeof(uint32), 1, fp) != 1) - return false; - if (fwrite(&top_lmas_num_, sizeof(uint32), 1, fp) != 1) - return false; - if (fwrite(root_, sizeof(LmaNodeLE0), lma_node_num_le0_, fp) != lma_node_num_le0_) - return false; - if (fwrite(nodes_ge1_, sizeof(LmaNodeGE1), lma_node_num_ge1_, fp) != lma_node_num_ge1_) - return false; - if (fwrite(lma_idx_buf_, sizeof(unsigned char), lma_idx_buf_len_, fp) != - lma_idx_buf_len_) - return false; - return true; -} -bool DictTrie::save_dict(const char* filename) { - if (NULL == filename) - return false; - if (NULL == root_ || NULL == dict_list_) - return false; - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - NGram& ngram = NGram::get_instance(); - FILE* fp = fopen(filename, "wb"); - if (NULL == fp) - return false; - if (!spl_trie.save_spl_trie(fp) || !dict_list_->save_list(fp) || - !save_dict(fp) || !ngram.save_ngram(fp)) { - fclose(fp); - return false; - } - fclose(fp); - return true; -} -#endif // ___BUILD_MODEL___ -bool DictTrie::load_dict(FILE* fp) { - if (NULL == fp) - return false; - if (fread(&lma_node_num_le0_, sizeof(uint32), 1, fp) != 1) - return false; - if (fread(&lma_node_num_ge1_, sizeof(uint32), 1, fp) != 1) - return false; - if (fread(&lma_idx_buf_len_, sizeof(uint32), 1, fp) != 1) - return false; - if (fread(&top_lmas_num_, sizeof(uint32), 1, fp) != 1 || - top_lmas_num_ >= lma_idx_buf_len_) - return false; - free_resource(false); - root_ = static_cast(malloc(lma_node_num_le0_ * sizeof(LmaNodeLE0))); - nodes_ge1_ = static_cast(malloc(lma_node_num_ge1_ * sizeof(LmaNodeGE1))); - lma_idx_buf_ = (unsigned char*)malloc(lma_idx_buf_len_); - total_lma_num_ = lma_idx_buf_len_ / kLemmaIdSize; - size_t buf_size = SpellingTrie::get_instance().get_spelling_num() + 1; - assert(lma_node_num_le0_ <= buf_size); - splid_le0_index_ = static_cast(malloc(buf_size * sizeof(uint16))); - // Init the space for parsing. - parsing_marks_ = new ParsingMark[kMaxParsingMark]; - mile_stones_ = new MileStone[kMaxMileStone]; - reset_milestones(0, kFirstValidMileStoneHandle); - if (NULL == root_ || NULL == nodes_ge1_ || NULL == lma_idx_buf_ || - NULL == splid_le0_index_ || NULL == parsing_marks_ || - NULL == mile_stones_) { - free_resource(false); - return false; - } - if (fread(root_, sizeof(LmaNodeLE0), lma_node_num_le0_, fp) != lma_node_num_le0_) - return false; - if (fread(nodes_ge1_, sizeof(LmaNodeGE1), lma_node_num_ge1_, fp) != lma_node_num_ge1_) - return false; - if (fread(lma_idx_buf_, sizeof(unsigned char), lma_idx_buf_len_, fp) != - lma_idx_buf_len_) - return false; - // The quick index for the first level sons - uint16 last_splid = kFullSplIdStart; - size_t last_pos = 0; - for (size_t i = 1; i < lma_node_num_le0_; i++) { - for (uint16 splid = last_splid; splid < root_[i].spl_idx; splid++) - splid_le0_index_[splid - kFullSplIdStart] = last_pos; - splid_le0_index_[root_[i].spl_idx - kFullSplIdStart] = - static_cast(i); - last_splid = root_[i].spl_idx; - last_pos = i; - } - for (uint16 splid = last_splid + 1; - splid < buf_size + kFullSplIdStart; splid++) { - assert(static_cast(splid - kFullSplIdStart) < buf_size); - splid_le0_index_[splid - kFullSplIdStart] = last_pos + 1; - } - return true; -} -bool DictTrie::load_dict(const char* filename, LemmaIdType start_id, - LemmaIdType end_id) { - if (NULL == filename || end_id <= start_id) - return false; - FILE* fp = fopen(filename, "rb"); - if (NULL == fp) - return false; - free_resource(true); - dict_list_ = new DictList(); - if (NULL == dict_list_) { - fclose(fp); - return false; - } - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - NGram& ngram = NGram::get_instance(); - if (!spl_trie.load_spl_trie(fp) || !dict_list_->load_list(fp) || - !load_dict(fp) || !ngram.load_ngram(fp) || - total_lma_num_ > end_id - start_id + 1) { - free_resource(true); - fclose(fp); - return false; - } - fclose(fp); - return true; -} -bool DictTrie::load_dict_fd(int sys_fd, long start_offset, - long length, LemmaIdType start_id, - LemmaIdType end_id) { - if (start_offset < 0 || length <= 0 || end_id <= start_id) - return false; - FILE* fp = fdopen(sys_fd, "rb"); - if (NULL == fp) - return false; - if (-1 == fseek(fp, start_offset, SEEK_SET)) { - fclose(fp); - return false; - } - free_resource(true); - dict_list_ = new DictList(); - if (NULL == dict_list_) { - fclose(fp); - return false; - } - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - NGram& ngram = NGram::get_instance(); - if (!spl_trie.load_spl_trie(fp) || !dict_list_->load_list(fp) || - !load_dict(fp) || !ngram.load_ngram(fp) || - ftell(fp) < start_offset + length || - total_lma_num_ > end_id - start_id + 1) { - free_resource(true); - fclose(fp); - return false; - } - fclose(fp); - return true; -} -size_t DictTrie::fill_lpi_buffer(LmaPsbItem lpi_items[], size_t lpi_max, - LmaNodeLE0* node) { - size_t lpi_num = 0; - NGram& ngram = NGram::get_instance(); - for (size_t homo = 0; homo < (size_t)node->num_of_homo; homo++) { - lpi_items[lpi_num].id = get_lemma_id(node->homo_idx_buf_off + - homo); - lpi_items[lpi_num].lma_len = 1; - lpi_items[lpi_num].psb = - static_cast(ngram.get_uni_psb(lpi_items[lpi_num].id)); - lpi_num++; - if (lpi_num >= lpi_max) - break; - } - return lpi_num; -} -size_t DictTrie::fill_lpi_buffer(LmaPsbItem lpi_items[], size_t lpi_max, - size_t homo_buf_off, LmaNodeGE1* node, - uint16 lma_len) { - size_t lpi_num = 0; - NGram& ngram = NGram::get_instance(); - for (size_t homo = 0; homo < (size_t)node->num_of_homo; homo++) { - lpi_items[lpi_num].id = get_lemma_id(homo_buf_off + homo); - lpi_items[lpi_num].lma_len = lma_len; - lpi_items[lpi_num].psb = - static_cast(ngram.get_uni_psb(lpi_items[lpi_num].id)); - lpi_num++; - if (lpi_num >= lpi_max) - break; - } - return lpi_num; -} -void DictTrie::reset_milestones(uint16 from_step, MileStoneHandle from_handle) { - if (0 == from_step) { - parsing_marks_pos_ = 0; - mile_stones_pos_ = kFirstValidMileStoneHandle; - } - else { - if (from_handle > 0 && from_handle < mile_stones_pos_) { - mile_stones_pos_ = from_handle; - MileStone* mile_stone = mile_stones_ + from_handle; - parsing_marks_pos_ = mile_stone->mark_start; - } - } -} -MileStoneHandle DictTrie::extend_dict(MileStoneHandle from_handle, - const DictExtPara* dep, - LmaPsbItem* lpi_items, size_t lpi_max, - size_t* lpi_num) { - if (NULL == dep) - return 0; - // from LmaNodeLE0 (root) to LmaNodeLE0 - if (0 == from_handle) { - assert(0 == dep->splids_extended); - return extend_dict0(from_handle, dep, lpi_items, lpi_max, lpi_num); - } - // from LmaNodeLE0 to LmaNodeGE1 - if (1 == dep->splids_extended) - return extend_dict1(from_handle, dep, lpi_items, lpi_max, lpi_num); - // From LmaNodeGE1 to LmaNodeGE1 - return extend_dict2(from_handle, dep, lpi_items, lpi_max, lpi_num); -} -MileStoneHandle DictTrie::extend_dict0(MileStoneHandle from_handle, - const DictExtPara* dep, - LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num) { - assert(NULL != dep && 0 == from_handle); - *lpi_num = 0; - MileStoneHandle ret_handle = 0; - uint16 splid = dep->splids[dep->splids_extended]; - uint16 id_start = dep->id_start; - uint16 id_num = dep->id_num; - LpiCache& lpi_cache = LpiCache::get_instance(); - bool cached = lpi_cache.is_cached(splid); - // 2. Begin exgtending - // 2.1 Get the LmaPsbItem list - LmaNodeLE0* node = root_; - size_t son_start = splid_le0_index_[id_start - kFullSplIdStart]; - size_t son_end = splid_le0_index_[id_start + id_num - kFullSplIdStart]; - for (size_t son_pos = son_start; son_pos < son_end; son_pos++) { - assert(1 == node->son_1st_off); - LmaNodeLE0* son = root_ + son_pos; - assert(son->spl_idx >= id_start && son->spl_idx < id_start + id_num); - if (!cached && *lpi_num < lpi_max) { - bool need_lpi = true; - if (spl_trie_->is_half_id_yunmu(splid) && son_pos != son_start) - need_lpi = false; - if (need_lpi) - *lpi_num += fill_lpi_buffer(lpi_items + (*lpi_num), - lpi_max - *lpi_num, son); - } - // If necessary, fill in a new mile stone. - if (son->spl_idx == id_start) { - if (mile_stones_pos_ < kMaxMileStone && - parsing_marks_pos_ < kMaxParsingMark) { - parsing_marks_[parsing_marks_pos_].node_offset = son_pos; - parsing_marks_[parsing_marks_pos_].node_num = id_num; - mile_stones_[mile_stones_pos_].mark_start = parsing_marks_pos_; - mile_stones_[mile_stones_pos_].mark_num = 1; - ret_handle = mile_stones_pos_; - parsing_marks_pos_++; - mile_stones_pos_++; - } - } - if (son->spl_idx >= id_start + id_num - 1) - break; - } - // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_, - // mile_stones_pos_); - return ret_handle; -} -MileStoneHandle DictTrie::extend_dict1(MileStoneHandle from_handle, - const DictExtPara* dep, - LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num) { - assert(NULL != dep && from_handle > 0 && from_handle < mile_stones_pos_); - MileStoneHandle ret_handle = 0; - // 1. If this is a half Id, get its corresponding full starting Id and - // number of full Id. - size_t ret_val = 0; - uint16 id_start = dep->id_start; - uint16 id_num = dep->id_num; - // 2. Begin extending. - MileStone* mile_stone = mile_stones_ + from_handle; - for (uint16 h_pos = 0; h_pos < mile_stone->mark_num; h_pos++) { - ParsingMark p_mark = parsing_marks_[mile_stone->mark_start + h_pos]; - uint16 ext_num = p_mark.node_num; - for (uint16 ext_pos = 0; ext_pos < ext_num; ext_pos++) { - LmaNodeLE0* node = root_ + p_mark.node_offset + ext_pos; - size_t found_start = 0; - size_t found_num = 0; - for (size_t son_pos = 0; son_pos < (size_t)node->num_of_son; son_pos++) { - assert(node->son_1st_off <= lma_node_num_ge1_); - LmaNodeGE1* son = nodes_ge1_ + node->son_1st_off + son_pos; - if (son->spl_idx >= id_start && son->spl_idx < id_start + id_num) { - if (*lpi_num < lpi_max) { - size_t homo_buf_off = get_homo_idx_buf_offset(son); - *lpi_num += fill_lpi_buffer(lpi_items + (*lpi_num), - lpi_max - *lpi_num, homo_buf_off, son, - 2); - } - // If necessary, fill in the new DTMI - if (0 == found_num) { - found_start = son_pos; - } - found_num++; - } - if (son->spl_idx >= id_start + id_num - 1 || son_pos == (size_t)node->num_of_son - 1) { - if (found_num > 0) { - if (mile_stones_pos_ < kMaxMileStone && - parsing_marks_pos_ < kMaxParsingMark) { - parsing_marks_[parsing_marks_pos_].node_offset = - node->son_1st_off + found_start; - parsing_marks_[parsing_marks_pos_].node_num = found_num; - if (0 == ret_val) - mile_stones_[mile_stones_pos_].mark_start = - parsing_marks_pos_; - parsing_marks_pos_++; - } - ret_val++; - } - break; - } // for son_pos - } // for ext_pos - } // for h_pos - } - if (ret_val > 0) { - mile_stones_[mile_stones_pos_].mark_num = ret_val; - ret_handle = mile_stones_pos_; - mile_stones_pos_++; - ret_val = 1; - } - // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_, - // mile_stones_pos_); - return ret_handle; -} -MileStoneHandle DictTrie::extend_dict2(MileStoneHandle from_handle, - const DictExtPara* dep, - LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num) { - assert(NULL != dep && from_handle > 0 && from_handle < mile_stones_pos_); - MileStoneHandle ret_handle = 0; - // 1. If this is a half Id, get its corresponding full starting Id and - // number of full Id. - size_t ret_val = 0; - uint16 id_start = dep->id_start; - uint16 id_num = dep->id_num; - // 2. Begin extending. - MileStone* mile_stone = mile_stones_ + from_handle; - for (uint16 h_pos = 0; h_pos < mile_stone->mark_num; h_pos++) { - ParsingMark p_mark = parsing_marks_[mile_stone->mark_start + h_pos]; - uint16 ext_num = p_mark.node_num; - for (uint16 ext_pos = 0; ext_pos < ext_num; ext_pos++) { - LmaNodeGE1* node = nodes_ge1_ + p_mark.node_offset + ext_pos; - size_t found_start = 0; - size_t found_num = 0; - for (size_t son_pos = 0; son_pos < (size_t)node->num_of_son; son_pos++) { - assert(node->son_1st_off_l > 0 || node->son_1st_off_h > 0); - LmaNodeGE1* son = nodes_ge1_ + get_son_offset(node) + son_pos; - if (son->spl_idx >= id_start && son->spl_idx < id_start + id_num) { - if (*lpi_num < lpi_max) { - size_t homo_buf_off = get_homo_idx_buf_offset(son); - *lpi_num += fill_lpi_buffer(lpi_items + (*lpi_num), - lpi_max - *lpi_num, homo_buf_off, son, - dep->splids_extended + 1); - } - // If necessary, fill in the new DTMI - if (0 == found_num) { - found_start = son_pos; - } - found_num++; - } - if (son->spl_idx >= id_start + id_num - 1 || son_pos == (size_t)node->num_of_son - 1) { - if (found_num > 0) { - if (mile_stones_pos_ < kMaxMileStone && - parsing_marks_pos_ < kMaxParsingMark) { - parsing_marks_[parsing_marks_pos_].node_offset = - get_son_offset(node) + found_start; - parsing_marks_[parsing_marks_pos_].node_num = found_num; - if (0 == ret_val) - mile_stones_[mile_stones_pos_].mark_start = - parsing_marks_pos_; - parsing_marks_pos_++; - } - ret_val++; - } - break; - } - } // for son_pos - } // for ext_pos - } // for h_pos - if (ret_val > 0) { - mile_stones_[mile_stones_pos_].mark_num = ret_val; - ret_handle = mile_stones_pos_; - mile_stones_pos_++; - } - // printf("----- parsing marks: %d, mile stone: %d \n", parsing_marks_pos_, - // mile_stones_pos_); - return ret_handle; -} -bool DictTrie::try_extend(const uint16* splids, uint16 splid_num, - LemmaIdType id_lemma) { - if (0 == splid_num || NULL == splids) - return false; - void* node = root_ + splid_le0_index_[splids[0] - kFullSplIdStart]; - for (uint16 pos = 1; pos < splid_num; pos++) { - if (1 == pos) { - LmaNodeLE0* node_le0 = reinterpret_cast(node); - LmaNodeGE1* node_son; - uint16 son_pos; - for (son_pos = 0; son_pos < static_cast(node_le0->num_of_son); - son_pos++) { - assert(node_le0->son_1st_off <= lma_node_num_ge1_); - node_son = nodes_ge1_ + node_le0->son_1st_off + son_pos; - if (node_son->spl_idx == splids[pos]) - break; - } - if (son_pos < node_le0->num_of_son) - node = reinterpret_cast(node_son); - else - return false; - } - else { - LmaNodeGE1* node_ge1 = reinterpret_cast(node); - LmaNodeGE1* node_son; - uint16 son_pos; - for (son_pos = 0; son_pos < static_cast(node_ge1->num_of_son); - son_pos++) { - assert(node_ge1->son_1st_off_l > 0 || node_ge1->son_1st_off_h > 0); - node_son = nodes_ge1_ + get_son_offset(node_ge1) + son_pos; - if (node_son->spl_idx == splids[pos]) - break; - } - if (son_pos < node_ge1->num_of_son) - node = reinterpret_cast(node_son); - else - return false; - } - } - if (1 == splid_num) { - LmaNodeLE0* node_le0 = reinterpret_cast(node); - size_t num_of_homo = (size_t)node_le0->num_of_homo; - for (size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++) { - LemmaIdType id_this = get_lemma_id(node_le0->homo_idx_buf_off + homo_pos); - char16 str[2]; - get_lemma_str(id_this, str, 2); - if (id_this == id_lemma) - return true; - } - } - else { - LmaNodeGE1* node_ge1 = reinterpret_cast(node); - size_t num_of_homo = (size_t)node_ge1->num_of_homo; - for (size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++) { - size_t node_homo_off = get_homo_idx_buf_offset(node_ge1); - if (get_lemma_id(node_homo_off + homo_pos) == id_lemma) - return true; - } - } - return false; -} -size_t DictTrie::get_lpis(const uint16* splid_str, uint16 splid_str_len, - LmaPsbItem* lma_buf, size_t max_lma_buf) { - if (splid_str_len > kMaxLemmaSize) - return 0; -#define MAX_EXTENDBUF_LEN 200 - size_t* node_buf1[MAX_EXTENDBUF_LEN]; // use size_t for data alignment - size_t* node_buf2[MAX_EXTENDBUF_LEN]; - LmaNodeLE0** node_fr_le0 = - reinterpret_cast(node_buf1); // Nodes from. - LmaNodeLE0** node_to_le0 = - reinterpret_cast(node_buf2); // Nodes to. - LmaNodeGE1** node_fr_ge1 = NULL; - LmaNodeGE1** node_to_ge1 = NULL; - size_t node_fr_num = 1; - size_t node_to_num = 0; - node_fr_le0[0] = root_; - if (NULL == node_fr_le0[0]) - return 0; - size_t spl_pos = 0; - while (spl_pos < splid_str_len) { - uint16 id_num = 1; - uint16 id_start = splid_str[spl_pos]; - // If it is a half id - if (spl_trie_->is_half_id(splid_str[spl_pos])) { - id_num = spl_trie_->half_to_full(splid_str[spl_pos], &id_start); - assert(id_num > 0); - } - // Extend the nodes - if (0 == spl_pos) { - // From LmaNodeLE0 (root) to LmaNodeLE0 nodes - for (size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++) { - LmaNodeLE0* node = node_fr_le0[node_fr_pos]; - assert(node == root_ && 1 == node_fr_num); - size_t son_start = splid_le0_index_[id_start - kFullSplIdStart]; - size_t son_end = - splid_le0_index_[id_start + id_num - kFullSplIdStart]; - for (size_t son_pos = son_start; son_pos < son_end; son_pos++) { - assert(1 == node->son_1st_off); - LmaNodeLE0* node_son = root_ + son_pos; - assert(node_son->spl_idx >= id_start && node_son->spl_idx < id_start + id_num); - if (node_to_num < MAX_EXTENDBUF_LEN) { - node_to_le0[node_to_num] = node_son; - node_to_num++; - } - // id_start + id_num - 1 is the last one, which has just been - // recorded. - if (node_son->spl_idx >= id_start + id_num - 1) - break; - } - } - spl_pos++; - if (spl_pos >= splid_str_len || node_to_num == 0) - break; - // Prepare the nodes for next extending - // next time, from LmaNodeLE0 to LmaNodeGE1 - LmaNodeLE0** node_tmp = node_fr_le0; - node_fr_le0 = node_to_le0; - node_to_le0 = NULL; - node_to_ge1 = reinterpret_cast(node_tmp); - } - else if (1 == spl_pos) { - // From LmaNodeLE0 to LmaNodeGE1 nodes - for (size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++) { - LmaNodeLE0* node = node_fr_le0[node_fr_pos]; - for (size_t son_pos = 0; son_pos < (size_t)node->num_of_son; - son_pos++) { - assert(node->son_1st_off <= lma_node_num_ge1_); - LmaNodeGE1* node_son = nodes_ge1_ + node->son_1st_off + son_pos; - if (node_son->spl_idx >= id_start && node_son->spl_idx < id_start + id_num) { - if (node_to_num < MAX_EXTENDBUF_LEN) { - node_to_ge1[node_to_num] = node_son; - node_to_num++; - } - } - // id_start + id_num - 1 is the last one, which has just been - // recorded. - if (node_son->spl_idx >= id_start + id_num - 1) - break; - } - } - spl_pos++; - if (spl_pos >= splid_str_len || node_to_num == 0) - break; - // Prepare the nodes for next extending - // next time, from LmaNodeGE1 to LmaNodeGE1 - node_fr_ge1 = node_to_ge1; - node_to_ge1 = reinterpret_cast(node_fr_le0); - node_fr_le0 = NULL; - node_to_le0 = NULL; - } - else { - // From LmaNodeGE1 to LmaNodeGE1 nodes - for (size_t node_fr_pos = 0; node_fr_pos < node_fr_num; node_fr_pos++) { - LmaNodeGE1* node = node_fr_ge1[node_fr_pos]; - for (size_t son_pos = 0; son_pos < (size_t)node->num_of_son; - son_pos++) { - assert(node->son_1st_off_l > 0 || node->son_1st_off_h > 0); - LmaNodeGE1* node_son = nodes_ge1_ + get_son_offset(node) + son_pos; - if (node_son->spl_idx >= id_start && node_son->spl_idx < id_start + id_num) { - if (node_to_num < MAX_EXTENDBUF_LEN) { - node_to_ge1[node_to_num] = node_son; - node_to_num++; - } - } - // id_start + id_num - 1 is the last one, which has just been - // recorded. - if (node_son->spl_idx >= id_start + id_num - 1) - break; - } - } - spl_pos++; - if (spl_pos >= splid_str_len || node_to_num == 0) - break; - // Prepare the nodes for next extending - // next time, from LmaNodeGE1 to LmaNodeGE1 - LmaNodeGE1** node_tmp = node_fr_ge1; - node_fr_ge1 = node_to_ge1; - node_to_ge1 = node_tmp; - } - // The number of node for next extending - node_fr_num = node_to_num; - node_to_num = 0; - } // while - if (0 == node_to_num) - return 0; - NGram& ngram = NGram::get_instance(); - size_t lma_num = 0; - // If the length is 1, and the splid is a one-char Yunmu like 'a', 'o', 'e', - // only those candidates for the full matched one-char id will be returned. - if (1 == splid_str_len && spl_trie_->is_half_id_yunmu(splid_str[0])) - node_to_num = node_to_num > 0 ? 1 : 0; - for (size_t node_pos = 0; node_pos < node_to_num; node_pos++) { - size_t num_of_homo = 0; - if (spl_pos <= 1) { - // Get from LmaNodeLE0 nodes - LmaNodeLE0* node_le0 = node_to_le0[node_pos]; - num_of_homo = (size_t)node_le0->num_of_homo; - for (size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++) { - size_t ch_pos = lma_num + homo_pos; - lma_buf[ch_pos].id = - get_lemma_id(node_le0->homo_idx_buf_off + homo_pos); - lma_buf[ch_pos].lma_len = 1; - lma_buf[ch_pos].psb = - static_cast(ngram.get_uni_psb(lma_buf[ch_pos].id)); - if (lma_num + homo_pos >= max_lma_buf - 1) - break; - } - } - else { - // Get from LmaNodeGE1 nodes - LmaNodeGE1* node_ge1 = node_to_ge1[node_pos]; - num_of_homo = (size_t)node_ge1->num_of_homo; - for (size_t homo_pos = 0; homo_pos < num_of_homo; homo_pos++) { - size_t ch_pos = lma_num + homo_pos; - size_t node_homo_off = get_homo_idx_buf_offset(node_ge1); - lma_buf[ch_pos].id = get_lemma_id(node_homo_off + homo_pos); - lma_buf[ch_pos].lma_len = splid_str_len; - lma_buf[ch_pos].psb = - static_cast(ngram.get_uni_psb(lma_buf[ch_pos].id)); - if (lma_num + homo_pos >= max_lma_buf - 1) - break; - } - } - lma_num += num_of_homo; - if (lma_num >= max_lma_buf) { - lma_num = max_lma_buf; - break; - } - } - return lma_num; -} -uint16 DictTrie::get_lemma_str(LemmaIdType id_lemma, char16* str_buf, - uint16 str_max) { - return dict_list_->get_lemma_str(id_lemma, str_buf, str_max); -} -uint16 DictTrie::get_lemma_splids(LemmaIdType id_lemma, uint16* splids, - uint16 splids_max, bool arg_valid) { - char16 lma_str[kMaxLemmaSize + 1]; - uint16 lma_len = get_lemma_str(id_lemma, lma_str, kMaxLemmaSize + 1); - assert((!arg_valid && splids_max >= lma_len) || lma_len == splids_max); - uint16 spl_mtrx[kMaxLemmaSize * 5]; - uint16 spl_start[kMaxLemmaSize + 1]; - spl_start[0] = 0; - uint16 try_num = 1; - for (uint16 pos = 0; pos < lma_len; pos++) { - uint16 cand_splids_this = 0; - if (arg_valid && spl_trie_->is_full_id(splids[pos])) { - spl_mtrx[spl_start[pos]] = splids[pos]; - cand_splids_this = 1; - } - else { - cand_splids_this = dict_list_->get_splids_for_hanzi(lma_str[pos], - arg_valid ? splids[pos] : 0, spl_mtrx + spl_start[pos], - kMaxLemmaSize * 5 - spl_start[pos]); - assert(cand_splids_this > 0); - } - spl_start[pos + 1] = spl_start[pos] + cand_splids_this; - try_num *= cand_splids_this; - } - for (uint16 try_pos = 0; try_pos < try_num; try_pos++) { - uint16 mod = 1; - for (uint16 pos = 0; pos < lma_len; pos++) { - uint16 radix = spl_start[pos + 1] - spl_start[pos]; - splids[pos] = spl_mtrx[spl_start[pos] + try_pos / mod % radix]; - mod *= radix; - } - if (try_extend(splids, lma_len, id_lemma)) - return lma_len; - } - return 0; -} -void DictTrie::set_total_lemma_count_of_others(size_t count) { - NGram& ngram = NGram::get_instance(); - ngram.set_total_freq_none_sys(count); -} -void DictTrie::convert_to_hanzis(char16* str, uint16 str_len) { - return dict_list_->convert_to_hanzis(str, str_len); -} -void DictTrie::convert_to_scis_ids(char16* str, uint16 str_len) { - return dict_list_->convert_to_scis_ids(str, str_len); -} -LemmaIdType DictTrie::get_lemma_id(const char16 lemma_str[], uint16 lemma_len) { - if (NULL == lemma_str || lemma_len > kMaxLemmaSize) - return 0; - return dict_list_->get_lemma_id(lemma_str, lemma_len); -} -size_t DictTrie::predict_top_lmas(size_t his_len, NPredictItem* npre_items, - size_t npre_max, size_t b4_used) { - NGram& ngram = NGram::get_instance(); - size_t item_num = 0; - size_t top_lmas_id_offset = lma_idx_buf_len_ / kLemmaIdSize - top_lmas_num_; - size_t top_lmas_pos = 0; - while (item_num < npre_max && top_lmas_pos < top_lmas_num_) { - memset(npre_items + item_num, 0, sizeof(NPredictItem)); - LemmaIdType top_lma_id = get_lemma_id(top_lmas_id_offset + top_lmas_pos); - top_lmas_pos += 1; - if (dict_list_->get_lemma_str(top_lma_id, - npre_items[item_num].pre_hzs, - kMaxLemmaSize - 1) == 0) { - continue; - } - npre_items[item_num].psb = ngram.get_uni_psb(top_lma_id); - npre_items[item_num].his_len = his_len; - item_num++; - } - return item_num; -} -size_t DictTrie::predict(const char16* last_hzs, uint16 hzs_len, - NPredictItem* npre_items, size_t npre_max, - size_t b4_used) { - return dict_list_->predict(last_hzs, hzs_len, npre_items, npre_max, b4_used); -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/dicttrie.h b/Widget/base/Virtual_Keyboard/googlepinyin/dicttrie.h deleted file mode 100644 index cd98e9a..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/dicttrie.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_DICTTRIE_H__ -#define PINYINIME_INCLUDE_DICTTRIE_H__ -#include -#include "./atomdictbase.h" -#include "./dictdef.h" -#include "./dictlist.h" -#include "./searchutility.h" -namespace ime_pinyin { -class DictTrie : AtomDictBase { -private: - struct ParsingMark { - size_t node_offset : 24; - size_t node_num : 8; // Number of nodes with this spelling id given - // by spl_id. If spl_id is a Shengmu, for nodes - // in the first layer of DictTrie, it equals to - // SpellingTrie::shm2full_num(); but for those - // nodes which are not in the first layer, - // node_num < SpellingTrie::shm2full_num(). - // For a full spelling id, node_num = 1; - }; - // Used to indicate an extended mile stone. - // An extended mile stone is used to mark a partial match in the dictionary - // trie to speed up further potential extending. - // For example, when the user inputs "w", a mile stone is created to mark the - // partial match status, so that when user inputs another char 'm', it will be - // faster to extend search space based on this mile stone. - // - // For partial match status of "wm", there can be more than one sub mile - // stone, for example, "wm" can be matched to "wanm", "wom", ..., etc, so - // there may be more one parsing mark used to mark these partial matchings. - // A mile stone records the starting position in the mark list and number of - // marks. - struct MileStone { - uint16 mark_start; - uint16 mark_num; - }; - DictList* dict_list_; - const SpellingTrie* spl_trie_; - LmaNodeLE0* root_; // Nodes for root and the first layer. - LmaNodeGE1* nodes_ge1_; // Nodes for other layers. - // An quick index from spelling id to the LmaNodeLE0 node buffer, or - // to the root_ buffer. - // Index length: - // SpellingTrie::get_instance().get_spelling_num() + 1. The last one is used - // to get the end. - // All Shengmu ids are not indexed because they will be converted into - // corresponding full ids. - // So, given an id splid, the son is: - // root_[splid_le0_index_[splid - kFullSplIdStart]] - uint16* splid_le0_index_; - uint32 lma_node_num_le0_; - uint32 lma_node_num_ge1_; - // The first part is for homophnies, and the last top_lma_num_ items are - // lemmas with highest scores. - unsigned char* lma_idx_buf_; - uint32 lma_idx_buf_len_; // The total size of lma_idx_buf_ in byte. - uint32 total_lma_num_; // Total number of lemmas in this dictionary. - uint32 top_lmas_num_; // Number of lemma with highest scores. - // Parsing mark list used to mark the detailed extended statuses. - ParsingMark* parsing_marks_; - // The position for next available mark. - uint16 parsing_marks_pos_; - // Mile stone list used to mark the extended status. - MileStone* mile_stones_; - // The position for the next available mile stone. We use positions (except 0) - // as handles. - MileStoneHandle mile_stones_pos_; - // Get the offset of sons for a node. - inline size_t get_son_offset(const LmaNodeGE1* node); - // Get the offset of homonious ids for a node. - inline size_t get_homo_idx_buf_offset(const LmaNodeGE1* node); - // Get the lemma id by the offset. - inline LemmaIdType get_lemma_id(size_t id_offset); - void free_resource(bool free_dict_list); - bool load_dict(FILE* fp); - // Given a LmaNodeLE0 node, extract the lemmas specified by it, and fill - // them into the lpi_items buffer. - // This function is called by the search engine. - size_t fill_lpi_buffer(LmaPsbItem lpi_items[], size_t max_size, - LmaNodeLE0* node); - // Given a LmaNodeGE1 node, extract the lemmas specified by it, and fill - // them into the lpi_items buffer. - // This function is called by inner functions extend_dict0(), extend_dict1() - // and extend_dict2(). - size_t fill_lpi_buffer(LmaPsbItem lpi_items[], size_t max_size, - size_t homo_buf_off, LmaNodeGE1* node, - uint16 lma_len); - // Extend in the trie from level 0. - MileStoneHandle extend_dict0(MileStoneHandle from_handle, - const DictExtPara* dep, LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num); - // Extend in the trie from level 1. - MileStoneHandle extend_dict1(MileStoneHandle from_handle, - const DictExtPara* dep, LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num); - // Extend in the trie from level 2. - MileStoneHandle extend_dict2(MileStoneHandle from_handle, - const DictExtPara* dep, LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num); - // Try to extend the given spelling id buffer, and if the given id_lemma can - // be successfully gotten, return true; - // The given spelling ids are all valid full ids. - bool try_extend(const uint16* splids, uint16 splid_num, LemmaIdType id_lemma); -#ifdef ___BUILD_MODEL___ - bool save_dict(FILE* fp); -#endif // ___BUILD_MODEL___ - static const int kMaxMileStone = 100; - static const int kMaxParsingMark = 600; - static const MileStoneHandle kFirstValidMileStoneHandle = 1; - friend class DictParser; - friend class DictBuilder; -public: - DictTrie(); - ~DictTrie(); -#ifdef ___BUILD_MODEL___ - // Construct the tree from the file fn_raw. - // fn_validhzs provide the valid hanzi list. If fn_validhzs is - // NULL, only chars in GB2312 will be included. - bool build_dict(const char* fn_raw, const char* fn_validhzs); - // Save the binary dictionary - // Actually, the SpellingTrie/DictList instance will be also saved. - bool save_dict(const char* filename); -#endif // ___BUILD_MODEL___ - void convert_to_hanzis(char16* str, uint16 str_len); - void convert_to_scis_ids(char16* str, uint16 str_len); - // Load a binary dictionary - // The SpellingTrie instance/DictList will be also loaded - bool load_dict(const char* filename, LemmaIdType start_id, - LemmaIdType end_id); - bool load_dict_fd(int sys_fd, long start_offset, long length, - LemmaIdType start_id, LemmaIdType end_id); - bool close_dict() { - return true; - } - size_t number_of_lemmas() { - return 0; - } - void reset_milestones(uint16 from_step, MileStoneHandle from_handle); - MileStoneHandle extend_dict(MileStoneHandle from_handle, - const DictExtPara* dep, - LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num); - size_t get_lpis(const uint16* splid_str, uint16 splid_str_len, - LmaPsbItem* lpi_items, size_t lpi_max); - uint16 get_lemma_str(LemmaIdType id_lemma, char16* str_buf, uint16 str_max); - uint16 get_lemma_splids(LemmaIdType id_lemma, uint16* splids, - uint16 splids_max, bool arg_valid); - size_t predict(const char16* last_hzs, uint16 hzs_len, - NPredictItem* npre_items, size_t npre_max, - size_t b4_used); - LemmaIdType put_lemma(char16 /*lemma_str*/[], uint16 /*splids*/[], - uint16 /*lemma_len*/, uint16 /*count*/) { - return 0; - } - LemmaIdType update_lemma(LemmaIdType /*lemma_id*/, int16 /*delta_count*/, - bool /*selected*/) { - return 0; - } - LemmaIdType get_lemma_id(char16 /*lemma_str*/[], uint16 /*splids*/[], - uint16 /*lemma_len*/) { - return 0; - } - LmaScoreType get_lemma_score(LemmaIdType /*lemma_id*/) { - return 0; - } - LmaScoreType get_lemma_score(char16 /*lemma_str*/[], uint16 /*splids*/[], - uint16 /*lemma_len*/) { - return 0; - } - bool remove_lemma(LemmaIdType /*lemma_id*/) { - return false; - } - size_t get_total_lemma_count() { - return 0; - } - void set_total_lemma_count_of_others(size_t count); - void flush_cache() { - } - LemmaIdType get_lemma_id(const char16 lemma_str[], uint16 lemma_len); - // Fill the lemmas with highest scores to the prediction buffer. - // his_len is the history length to fill in the prediction buffer. - size_t predict_top_lmas(size_t his_len, NPredictItem* npre_items, - size_t npre_max, size_t b4_used); -}; -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_DICTTRIE_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/googlepinyin.pro b/Widget/base/Virtual_Keyboard/googlepinyin/googlepinyin.pro deleted file mode 100644 index c7994e6..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/googlepinyin.pro +++ /dev/null @@ -1,43 +0,0 @@ -QT -= gui - -TARGET = googlepinyin -TEMPLATE = lib -CONFIG += staticlib - -SOURCES += \ - dictbuilder.cpp \ - dictlist.cpp \ - dicttrie.cpp \ - lpicache.cpp \ - matrixsearch.cpp \ - mystdlib.cpp \ - ngram.cpp \ - pinyinime.cpp \ - searchutility.cpp \ - spellingtable.cpp \ - spellingtrie.cpp \ - splparser.cpp \ - sync.cpp \ - userdict.cpp \ - utf16char.cpp \ - utf16reader.cpp - -HEADERS += \ - atomdictbase.h \ - dictbuilder.h \ - dictdef.h \ - dictlist.h \ - dicttrie.h \ - lpicache.h \ - matrixsearch.h \ - mystdlib.h \ - ngram.h \ - pinyinime.h \ - searchutility.h \ - spellingtable.h \ - spellingtrie.h \ - splparser.h \ - sync.h \ - userdict.h \ - utf16char.h \ - utf16reader.h diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/lpicache.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/lpicache.cpp deleted file mode 100644 index 697de36..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/lpicache.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "lpicache.h" -#include -namespace ime_pinyin { -LpiCache* LpiCache::instance_ = NULL; -LpiCache::LpiCache() { - lpi_cache_ = new LmaPsbItem[kFullSplIdStart * kMaxLpiCachePerId]; - lpi_cache_len_ = new uint16[kFullSplIdStart]; - assert(NULL != lpi_cache_); - assert(NULL != lpi_cache_len_); - for (uint16 id = 0; id < kFullSplIdStart; id++) - lpi_cache_len_[id] = 0; -} -LpiCache::~LpiCache() { - if (NULL != lpi_cache_) - delete[] lpi_cache_; - if (NULL != lpi_cache_len_) - delete[] lpi_cache_len_; -} -LpiCache& LpiCache::get_instance() { - if (NULL == instance_) { - instance_ = new LpiCache(); - assert(NULL != instance_); - } - return *instance_; -} -bool LpiCache::is_cached(uint16 splid) { - if (splid >= kFullSplIdStart) - return false; - return lpi_cache_len_[splid] != 0; -} -size_t LpiCache::put_cache(uint16 splid, LmaPsbItem lpi_items[], - size_t lpi_num) { - uint16 num = kMaxLpiCachePerId; - if (num > lpi_num) - num = static_cast(lpi_num); - LmaPsbItem* lpi_cache_this = lpi_cache_ + splid * kMaxLpiCachePerId; - for (uint16 pos = 0; pos < num; pos++) - lpi_cache_this[pos] = lpi_items[pos]; - lpi_cache_len_[splid] = num; - return num; -} -size_t LpiCache::get_cache(uint16 splid, LmaPsbItem lpi_items[], - size_t lpi_max) { - if (lpi_max > lpi_cache_len_[splid]) - lpi_max = lpi_cache_len_[splid]; - LmaPsbItem* lpi_cache_this = lpi_cache_ + splid * kMaxLpiCachePerId; - for (uint16 pos = 0; pos < lpi_max; pos++) { - lpi_items[pos] = lpi_cache_this[pos]; - } - return lpi_max; -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/lpicache.h b/Widget/base/Virtual_Keyboard/googlepinyin/lpicache.h deleted file mode 100644 index 5d4df8b..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/lpicache.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_ANDPY_INCLUDE_LPICACHE_H__ -#define PINYINIME_ANDPY_INCLUDE_LPICACHE_H__ -#include -#include "./searchutility.h" -#include "./spellingtrie.h" -namespace ime_pinyin { -// Used to cache LmaPsbItem list for half spelling ids. -class LpiCache { -private: - static LpiCache* instance_; - static const int kMaxLpiCachePerId = 15; - LmaPsbItem* lpi_cache_; - uint16* lpi_cache_len_; -public: - LpiCache(); - ~LpiCache(); - static LpiCache& get_instance(); - // Test if the LPI list of the given splid has been cached. - // If splid is a full spelling id, it returns false, because we only cache - // list for half ids. - bool is_cached(uint16 splid); - // Put LPI list to cahce. If the length of the list, lpi_num, is longer than - // the cache buffer. the list will be truncated, and function returns the - // maximum length of the cache buffer. - // Note: splid must be a half id, and lpi_items must be not NULL. The - // caller of this function should guarantee this. - size_t put_cache(uint16 splid, LmaPsbItem lpi_items[], size_t lpi_num); - // Get the cached list for the given half id. - // Return the length of the cached buffer. - // Note: splid must be a half id, and lpi_items must be not NULL. The - // caller of this function should guarantee this. - size_t get_cache(uint16 splid, LmaPsbItem lpi_items[], size_t lpi_max); -}; -} // namespace ime_pinyin -#endif // PINYINIME_ANDPY_INCLUDE_LPICACHE_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/matrixsearch.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/matrixsearch.cpp deleted file mode 100644 index af282db..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/matrixsearch.cpp +++ /dev/null @@ -1,1705 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "matrixsearch.h" -#include -#include -#include -#include -#include "lpicache.h" -#include "mystdlib.h" -#include "ngram.h" -#include "userdict.h" -namespace ime_pinyin { -#define PRUMING_SCORE 8000.0 -MatrixSearch::MatrixSearch() { - inited_ = false; - spl_trie_ = SpellingTrie::get_cpinstance(); - reset_pointers_to_null(); - pys_decoded_len_ = 0; - mtrx_nd_pool_used_ = 0; - dmi_pool_used_ = 0; - xi_an_enabled_ = false; - dmi_c_phrase_ = false; - assert(kMaxSearchSteps > 0); - max_sps_len_ = kMaxSearchSteps - 1; - max_hzs_len_ = kMaxSearchSteps; -} -MatrixSearch::~MatrixSearch() { - free_resource(); -} -void MatrixSearch::reset_pointers_to_null() { - dict_trie_ = NULL; - user_dict_ = NULL; - spl_parser_ = NULL; - share_buf_ = NULL; - // The following four buffers are used for decoding, and they are based on - // share_buf_, no need to delete them. - mtrx_nd_pool_ = NULL; - dmi_pool_ = NULL; - matrix_ = NULL; - dep_ = NULL; - // Based on share_buf_, no need to delete them. - npre_items_ = NULL; -} -bool MatrixSearch::alloc_resource() { - free_resource(); - dict_trie_ = new DictTrie(); - user_dict_ = static_cast(new UserDict()); - spl_parser_ = new SpellingParser(); - size_t mtrx_nd_size = sizeof(MatrixNode) * kMtrxNdPoolSize; - mtrx_nd_size = align_to_size_t(mtrx_nd_size) / sizeof(size_t); - size_t dmi_size = sizeof(DictMatchInfo) * kDmiPoolSize; - dmi_size = align_to_size_t(dmi_size) / sizeof(size_t); - size_t matrix_size = sizeof(MatrixRow) * kMaxRowNum; - matrix_size = align_to_size_t(matrix_size) / sizeof(size_t); - size_t dep_size = sizeof(DictExtPara); - dep_size = align_to_size_t(dep_size) / sizeof(size_t); - // share_buf's size is determined by the buffers for search. - share_buf_ = new size_t[mtrx_nd_size + dmi_size + matrix_size + dep_size]; - if (NULL == dict_trie_ || NULL == user_dict_ || NULL == spl_parser_ || - NULL == share_buf_) - return false; - // The buffers for search are based on the share buffer - mtrx_nd_pool_ = reinterpret_cast(share_buf_); - dmi_pool_ = reinterpret_cast(share_buf_ + mtrx_nd_size); - matrix_ = reinterpret_cast(share_buf_ + mtrx_nd_size + dmi_size); - dep_ = reinterpret_cast(share_buf_ + mtrx_nd_size + dmi_size + matrix_size); - // The prediction buffer is also based on the share buffer. - npre_items_ = reinterpret_cast(share_buf_); - npre_items_len_ = (mtrx_nd_size + dmi_size + matrix_size + dep_size) * - sizeof(size_t) / sizeof(NPredictItem); - return true; -} -void MatrixSearch::free_resource() { - if (NULL != dict_trie_) - delete dict_trie_; - if (NULL != user_dict_) - delete user_dict_; - if (NULL != spl_parser_) - delete spl_parser_; - if (NULL != share_buf_) - delete[] share_buf_; - reset_pointers_to_null(); -} -bool MatrixSearch::init(const char* fn_sys_dict, const char* fn_usr_dict) { - if (NULL == fn_sys_dict || NULL == fn_usr_dict) - return false; - if (!alloc_resource()) - return false; - if (!dict_trie_->load_dict(fn_sys_dict, 1, kSysDictIdEnd)) - return false; - // If engine fails to load the user dictionary, reset the user dictionary - // to NULL. - if (!user_dict_->load_dict(fn_usr_dict, kUserDictIdStart, kUserDictIdEnd)) { - delete user_dict_; - user_dict_ = NULL; - } - else { - user_dict_->set_total_lemma_count_of_others(NGram::kSysDictTotalFreq); - } - reset_search0(); - inited_ = true; - return true; -} -bool MatrixSearch::init_fd(int sys_fd, long start_offset, long length, - const char* fn_usr_dict) { - if (NULL == fn_usr_dict) - return false; - if (!alloc_resource()) - return false; - if (!dict_trie_->load_dict_fd(sys_fd, start_offset, length, 1, kSysDictIdEnd)) - return false; - if (!user_dict_->load_dict(fn_usr_dict, kUserDictIdStart, kUserDictIdEnd)) { - delete user_dict_; - user_dict_ = NULL; - } - else { - user_dict_->set_total_lemma_count_of_others(NGram::kSysDictTotalFreq); - } - reset_search0(); - inited_ = true; - return true; -} -void MatrixSearch::init_user_dictionary(const char* fn_usr_dict) { - assert(inited_); - if (NULL != user_dict_) { - delete user_dict_; - user_dict_ = NULL; - } - if (NULL != fn_usr_dict) { - user_dict_ = static_cast(new UserDict()); - if (!user_dict_->load_dict(fn_usr_dict, kUserDictIdStart, kUserDictIdEnd)) { - delete user_dict_; - user_dict_ = NULL; - } - } - reset_search0(); -} -bool MatrixSearch::is_user_dictionary_enabled() const { - return NULL != user_dict_; -} -void MatrixSearch::set_max_lens(size_t max_sps_len, size_t max_hzs_len) { - if (0 != max_sps_len) - max_sps_len_ = max_sps_len; - if (0 != max_hzs_len) - max_hzs_len_ = max_hzs_len; -} -void MatrixSearch::close() { - flush_cache(); - free_resource(); - inited_ = false; -} -void MatrixSearch::flush_cache() { - if (NULL != user_dict_) - user_dict_->flush_cache(); -} -void MatrixSearch::set_xi_an_switch(bool xi_an_enabled) { - xi_an_enabled_ = xi_an_enabled; -} -bool MatrixSearch::get_xi_an_switch() { - return xi_an_enabled_; -} -bool MatrixSearch::reset_search() { - if (!inited_) - return false; - return reset_search0(); -} -bool MatrixSearch::reset_search0() { - if (!inited_) - return false; - pys_decoded_len_ = 0; - mtrx_nd_pool_used_ = 0; - dmi_pool_used_ = 0; - // Get a MatrixNode from the pool - matrix_[0].mtrx_nd_pos = mtrx_nd_pool_used_; - matrix_[0].mtrx_nd_num = 1; - mtrx_nd_pool_used_ += 1; - // Update the node, and make it to be a starting node - MatrixNode* node = mtrx_nd_pool_ + matrix_[0].mtrx_nd_pos; - node->id = 0; - node->score = 0; - node->from = NULL; - node->step = 0; - node->dmi_fr = (PoolPosType)-1; - matrix_[0].dmi_pos = 0; - matrix_[0].dmi_num = 0; - matrix_[0].dmi_has_full_id = 1; - matrix_[0].mtrx_nd_fixed = node; - lma_start_[0] = 0; - fixed_lmas_ = 0; - spl_start_[0] = 0; - fixed_hzs_ = 0; - dict_trie_->reset_milestones(0, 0); - if (NULL != user_dict_) - user_dict_->reset_milestones(0, 0); - return true; -} -bool MatrixSearch::reset_search(size_t ch_pos, bool clear_fixed_this_step, - bool clear_dmi_this_step, - bool clear_mtrx_this_step) { - if (!inited_ || ch_pos > pys_decoded_len_ || ch_pos >= kMaxRowNum) - return false; - if (0 == ch_pos) { - reset_search0(); - } - else { - // Prepare mile stones of this step to clear. - MileStoneHandle* dict_handles_to_clear = NULL; - if (clear_dmi_this_step && matrix_[ch_pos].dmi_num > 0) { - dict_handles_to_clear = dmi_pool_[matrix_[ch_pos].dmi_pos].dict_handles; - } - // If there are more steps, and this step is not allowed to clear, find - // milestones of next step. - if (pys_decoded_len_ > ch_pos && !clear_dmi_this_step) { - dict_handles_to_clear = NULL; - if (matrix_[ch_pos + 1].dmi_num > 0) { - dict_handles_to_clear = - dmi_pool_[matrix_[ch_pos + 1].dmi_pos].dict_handles; - } - } - if (NULL != dict_handles_to_clear) { - dict_trie_->reset_milestones(ch_pos, dict_handles_to_clear[0]); - if (NULL != user_dict_) - user_dict_->reset_milestones(ch_pos, dict_handles_to_clear[1]); - } - pys_decoded_len_ = ch_pos; - if (clear_dmi_this_step) { - dmi_pool_used_ = matrix_[ch_pos - 1].dmi_pos + matrix_[ch_pos - 1].dmi_num; - matrix_[ch_pos].dmi_num = 0; - } - else { - dmi_pool_used_ = matrix_[ch_pos].dmi_pos + matrix_[ch_pos].dmi_num; - } - if (clear_mtrx_this_step) { - mtrx_nd_pool_used_ = matrix_[ch_pos - 1].mtrx_nd_pos + matrix_[ch_pos - 1].mtrx_nd_num; - matrix_[ch_pos].mtrx_nd_num = 0; - } - else { - mtrx_nd_pool_used_ = matrix_[ch_pos].mtrx_nd_pos + matrix_[ch_pos].mtrx_nd_num; - } - // Modify fixed_hzs_ - if (fixed_hzs_ > 0 && - ((kLemmaIdComposing != lma_id_[0]) || - (kLemmaIdComposing == lma_id_[0] && - spl_start_[c_phrase_.length] <= ch_pos))) { - size_t fixed_ch_pos = ch_pos; - if (clear_fixed_this_step) - fixed_ch_pos = fixed_ch_pos > 0 ? fixed_ch_pos - 1 : 0; - while (NULL == matrix_[fixed_ch_pos].mtrx_nd_fixed && fixed_ch_pos > 0) - fixed_ch_pos--; - fixed_lmas_ = 0; - fixed_hzs_ = 0; - if (fixed_ch_pos > 0) { - while (spl_start_[fixed_hzs_] < fixed_ch_pos) - fixed_hzs_++; - assert(spl_start_[fixed_hzs_] == fixed_ch_pos); - while (lma_start_[fixed_lmas_] < fixed_hzs_) - fixed_lmas_++; - assert(lma_start_[fixed_lmas_] == fixed_hzs_); - } - // Re-search the Pinyin string for the unlocked lemma - // which was previously fixed. - // - // Prepare mile stones of this step to clear. - MileStoneHandle* dict_handles_to_clear = NULL; - if (clear_dmi_this_step && ch_pos == fixed_ch_pos && - matrix_[fixed_ch_pos].dmi_num > 0) { - dict_handles_to_clear = dmi_pool_[matrix_[fixed_ch_pos].dmi_pos].dict_handles; - } - // If there are more steps, and this step is not allowed to clear, find - // milestones of next step. - if (pys_decoded_len_ > fixed_ch_pos && !clear_dmi_this_step) { - dict_handles_to_clear = NULL; - if (matrix_[fixed_ch_pos + 1].dmi_num > 0) { - dict_handles_to_clear = - dmi_pool_[matrix_[fixed_ch_pos + 1].dmi_pos].dict_handles; - } - } - if (NULL != dict_handles_to_clear) { - dict_trie_->reset_milestones(fixed_ch_pos, dict_handles_to_clear[0]); - if (NULL != user_dict_) - user_dict_->reset_milestones(fixed_ch_pos, dict_handles_to_clear[1]); - } - pys_decoded_len_ = fixed_ch_pos; - if (clear_dmi_this_step && ch_pos == fixed_ch_pos) { - dmi_pool_used_ = matrix_[fixed_ch_pos - 1].dmi_pos + matrix_[fixed_ch_pos - 1].dmi_num; - matrix_[fixed_ch_pos].dmi_num = 0; - } - else { - dmi_pool_used_ = matrix_[fixed_ch_pos].dmi_pos + - matrix_[fixed_ch_pos].dmi_num; - } - if (clear_mtrx_this_step && ch_pos == fixed_ch_pos) { - mtrx_nd_pool_used_ = matrix_[fixed_ch_pos - 1].mtrx_nd_pos + matrix_[fixed_ch_pos - 1].mtrx_nd_num; - matrix_[fixed_ch_pos].mtrx_nd_num = 0; - } - else { - mtrx_nd_pool_used_ = matrix_[fixed_ch_pos].mtrx_nd_pos + matrix_[fixed_ch_pos].mtrx_nd_num; - } - for (uint16 re_pos = fixed_ch_pos; re_pos < ch_pos; re_pos++) { - add_char(pys_[re_pos]); - } - } - else if (fixed_hzs_ > 0 && kLemmaIdComposing == lma_id_[0]) { - for (uint16 subpos = 0; subpos < c_phrase_.sublma_num; subpos++) { - uint16 splpos_begin = c_phrase_.sublma_start[subpos]; - uint16 splpos_end = c_phrase_.sublma_start[subpos + 1]; - for (uint16 splpos = splpos_begin; splpos < splpos_end; splpos++) { - // If ch_pos is in this spelling - uint16 spl_start = c_phrase_.spl_start[splpos]; - uint16 spl_end = c_phrase_.spl_start[splpos + 1]; - if (ch_pos >= spl_start && ch_pos < spl_end) { - // Clear everything after this position - c_phrase_.chn_str[splpos] = static_cast('\0'); - c_phrase_.sublma_start[subpos + 1] = splpos; - c_phrase_.sublma_num = subpos + 1; - c_phrase_.length = splpos; - if (splpos == splpos_begin) { - c_phrase_.sublma_num = subpos; - } - } - } - } - // Extend the composing phrase. - reset_search0(); - dmi_c_phrase_ = true; - uint16 c_py_pos = 0; - while (c_py_pos < spl_start_[c_phrase_.length]) { - bool b_ac_tmp = add_char(pys_[c_py_pos]); - assert(b_ac_tmp); - c_py_pos++; - } - dmi_c_phrase_ = false; - lma_id_num_ = 1; - fixed_lmas_ = 1; - fixed_lmas_no1_[0] = 0; // A composing string is always modified. - fixed_hzs_ = c_phrase_.length; - lma_start_[1] = fixed_hzs_; - lma_id_[0] = kLemmaIdComposing; - matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ + - matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos; - } - } - return true; -} -void MatrixSearch::del_in_pys(size_t start, size_t len) { - while (start < kMaxRowNum - len && '\0' != pys_[start]) { - pys_[start] = pys_[start + len]; - start++; - } -} -size_t MatrixSearch::search(const char* py, size_t py_len) { - if (!inited_ || NULL == py) - return 0; - // If the search Pinyin string is too long, it will be truncated. - if (py_len > kMaxRowNum - 1) - py_len = kMaxRowNum - 1; - // Compare the new string with the previous one. Find their prefix to - // increase search efficiency. - size_t ch_pos = 0; - for (ch_pos = 0; ch_pos < pys_decoded_len_; ch_pos++) { - if ('\0' == py[ch_pos] || py[ch_pos] != pys_[ch_pos]) - break; - } - bool clear_fix = true; - if (ch_pos == pys_decoded_len_) - clear_fix = false; - reset_search(ch_pos, clear_fix, false, false); - memcpy(pys_ + ch_pos, py + ch_pos, py_len - ch_pos); - pys_[py_len] = '\0'; - while ('\0' != pys_[ch_pos]) { - if (!add_char(py[ch_pos])) { - pys_decoded_len_ = ch_pos; - break; - } - ch_pos++; - } - // Get spelling ids and starting positions. - get_spl_start_id(); - // If there are too many spellings, remove the last letter until the spelling - // number is acceptable. - while (spl_id_num_ > 9) { - py_len--; - reset_search(py_len, false, false, false); - pys_[py_len] = '\0'; - get_spl_start_id(); - } - prepare_candidates(); - if (kPrintDebug0) { - printf("--Matrix Node Pool Used: %d\n", mtrx_nd_pool_used_); - printf("--DMI Pool Used: %d\n", dmi_pool_used_); - if (kPrintDebug1) { - for (PoolPosType pos = 0; pos < dmi_pool_used_; pos++) { - debug_print_dmi(pos, 1); - } - } - } - return ch_pos; -} -size_t MatrixSearch::delsearch(size_t pos, bool is_pos_in_splid, - bool clear_fixed_this_step) { - if (!inited_) - return 0; - size_t reset_pos = pos; - // Out of range for both Pinyin mode and Spelling id mode. - if (pys_decoded_len_ <= pos) { - del_in_pys(pos, 1); - reset_pos = pys_decoded_len_; - // Decode the string after the un-decoded position - while ('\0' != pys_[reset_pos]) { - if (!add_char(pys_[reset_pos])) { - pys_decoded_len_ = reset_pos; - break; - } - reset_pos++; - } - get_spl_start_id(); - prepare_candidates(); - return pys_decoded_len_; - } - // Spelling id mode, but out of range. - if (is_pos_in_splid && spl_id_num_ <= pos) - return pys_decoded_len_; - // Begin to handle two modes respectively. - // Pinyin mode by default - size_t c_py_len = 0; // The length of composing phrase's Pinyin - size_t del_py_len = 1; - if (!is_pos_in_splid) { - // Pinyin mode is only allowed to delete beyond the fixed lemmas. - if (fixed_lmas_ > 0 && pos < spl_start_[lma_start_[fixed_lmas_]]) - return pys_decoded_len_; - del_in_pys(pos, 1); - // If the deleted character is just the one after the last fixed lemma - if (pos == spl_start_[lma_start_[fixed_lmas_]]) { - // If all fixed lemmas have been merged, and the caller of the function - // request to unlock the last fixed lemma. - if (kLemmaIdComposing == lma_id_[0] && clear_fixed_this_step) { - // Unlock the last sub lemma in the composing phrase. Because it is not - // easy to unlock it directly. Instead, we re-decode the modified - // composing phrase. - c_phrase_.sublma_num--; - c_phrase_.length = c_phrase_.sublma_start[c_phrase_.sublma_num]; - reset_pos = spl_start_[c_phrase_.length]; - c_py_len = reset_pos; - } - } - } - else { - del_py_len = spl_start_[pos + 1] - spl_start_[pos]; - del_in_pys(spl_start_[pos], del_py_len); - if (pos >= lma_start_[fixed_lmas_]) { - c_py_len = 0; - reset_pos = spl_start_[pos + 1] - del_py_len; - } - else { - c_py_len = spl_start_[lma_start_[fixed_lmas_]] - del_py_len; - reset_pos = c_py_len; - if (c_py_len > 0) - merge_fixed_lmas(pos); - } - } - if (c_py_len > 0) { - assert(c_phrase_.length > 0 && c_py_len == c_phrase_.spl_start[c_phrase_.sublma_start[c_phrase_.sublma_num]]); - // The composing phrase is valid, reset all search space, - // and begin a new search which will only extend the composing - // phrase. - reset_search0(); - dmi_c_phrase_ = true; - // Extend the composing phrase. - uint16 c_py_pos = 0; - while (c_py_pos < c_py_len) { - bool b_ac_tmp = add_char(pys_[c_py_pos]); - assert(b_ac_tmp); - c_py_pos++; - } - dmi_c_phrase_ = false; - // Fixd the composing phrase as the first choice. - lma_id_num_ = 1; - fixed_lmas_ = 1; - fixed_lmas_no1_[0] = 0; // A composing string is always modified. - fixed_hzs_ = c_phrase_.length; - lma_start_[1] = fixed_hzs_; - lma_id_[0] = kLemmaIdComposing; - matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ + - matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos; - } - else { - // Reseting search only clear pys_decoded_len_, but the string is kept. - reset_search(reset_pos, clear_fixed_this_step, false, false); - } - // Decode the string after the delete position. - while ('\0' != pys_[reset_pos]) { - if (!add_char(pys_[reset_pos])) { - pys_decoded_len_ = reset_pos; - break; - } - reset_pos++; - } - get_spl_start_id(); - prepare_candidates(); - return pys_decoded_len_; -} -size_t MatrixSearch::get_candidate_num() { - if (!inited_ || 0 == pys_decoded_len_ || - 0 == matrix_[pys_decoded_len_].mtrx_nd_num) - return 0; - return 1 + lpi_total_; -} -char16* MatrixSearch::get_candidate(size_t cand_id, char16* cand_str, - size_t max_len) { - if (!inited_ || 0 == pys_decoded_len_ || NULL == cand_str) - return NULL; - if (0 == cand_id) { - return get_candidate0(cand_str, max_len, NULL, false); - } - else { - cand_id--; - } - // For this case: the current sentence is a word only, and the user fixed it, - // so the result will be fixed to the sentence space, and - // lpi_total_ will be set to 0. - if (0 == lpi_total_) { - return get_candidate0(cand_str, max_len, NULL, false); - } - LemmaIdType id = lpi_items_[cand_id].id; - char16 s[kMaxLemmaSize + 1]; - uint16 s_len = lpi_items_[cand_id].lma_len; - if (s_len > 1) { - s_len = get_lemma_str(id, s, kMaxLemmaSize + 1); - } - else { - // For a single character, Hanzi is ready. - s[0] = lpi_items_[cand_id].hanzi; - s[1] = static_cast(0); - } - if (s_len > 0 && max_len > s_len) { - utf16_strncpy(cand_str, s, s_len); - cand_str[s_len] = (char16)'\0'; - return cand_str; - } - return NULL; -} -void MatrixSearch::update_dict_freq() { - if (NULL != user_dict_) { - // Update the total frequency of all lemmas, including system lemmas and - // user dictionary lemmas. - size_t total_freq = user_dict_->get_total_lemma_count(); - dict_trie_->set_total_lemma_count_of_others(total_freq); - } -} -bool MatrixSearch::add_lma_to_userdict(uint16 lma_fr, uint16 lma_to, - float score) { - if (lma_to - lma_fr <= 1 || NULL == user_dict_) - return false; - char16 word_str[kMaxLemmaSize + 1]; - uint16 spl_ids[kMaxLemmaSize]; - uint16 spl_id_fr = 0; - for (uint16 pos = lma_fr; pos < lma_to; pos++) { - LemmaIdType lma_id = lma_id_[pos]; - if (is_user_lemma(lma_id)) { - user_dict_->update_lemma(lma_id, 1, true); - } - uint16 lma_len = lma_start_[pos + 1] - lma_start_[pos]; - utf16_strncpy(spl_ids + spl_id_fr, spl_id_ + lma_start_[pos], lma_len); - uint16 tmp = get_lemma_str(lma_id, word_str + spl_id_fr, - kMaxLemmaSize + 1 - spl_id_fr); - assert(tmp == lma_len); - tmp = get_lemma_splids(lma_id, spl_ids + spl_id_fr, lma_len, true); - if (tmp != lma_len) { - return false; - } - spl_id_fr += lma_len; - } - assert(spl_id_fr <= kMaxLemmaSize); - return user_dict_->put_lemma(static_cast(word_str), spl_ids, - spl_id_fr, 1); -} -void MatrixSearch::debug_print_dmi(PoolPosType dmi_pos, uint16 nest_level) { - if (dmi_pos >= dmi_pool_used_) - return; - DictMatchInfo* dmi = dmi_pool_ + dmi_pos; - if (1 == nest_level) { - printf("-----------------%d\'th DMI node begin----------->\n", dmi_pos); - } - if (dmi->dict_level > 1) { - debug_print_dmi(dmi->dmi_fr, nest_level + 1); - } - printf("---%d\n", dmi->dict_level); - printf(" MileStone: %x, %x\n", dmi->dict_handles[0], dmi->dict_handles[1]); - printf(" Spelling : %s, %d\n", SpellingTrie::get_instance().get_spelling_str(dmi->spl_id), dmi->spl_id); - printf(" Total Pinyin Len: %d\n", dmi->splstr_len); - if (1 == nest_level) { - printf("<----------------%d\'th DMI node end--------------\n\n", dmi_pos); - } -} -bool MatrixSearch::try_add_cand0_to_userdict() { - size_t new_cand_num = get_candidate_num(); - if (fixed_hzs_ > 0 && 1 == new_cand_num) { - float score_from = 0; - uint16 lma_id_from = 0; - uint16 pos = 0; - bool modified = false; - while (pos < fixed_lmas_) { - if (lma_start_[pos + 1] - lma_start_[lma_id_from] > - static_cast(kMaxLemmaSize)) { - float score_to_add = - mtrx_nd_pool_[matrix_[spl_start_[lma_start_[pos]]] - .mtrx_nd_pos] - .score - - score_from; - if (modified) { - score_to_add += 1.0; - if (score_to_add > NGram::kMaxScore) { - score_to_add = NGram::kMaxScore; - } - add_lma_to_userdict(lma_id_from, pos, score_to_add); - } - lma_id_from = pos; - score_from += score_to_add; - // Clear the flag for next user lemma. - modified = false; - } - if (0 == fixed_lmas_no1_[pos]) { - modified = true; - } - pos++; - } - // Single-char word is not allowed to add to userdict. - if (lma_start_[pos] - lma_start_[lma_id_from] > 1) { - float score_to_add = - mtrx_nd_pool_[matrix_[spl_start_[lma_start_[pos]]] - .mtrx_nd_pos] - .score - - score_from; - if (modified) { - score_to_add += 1.0; - if (score_to_add > NGram::kMaxScore) { - score_to_add = NGram::kMaxScore; - } - add_lma_to_userdict(lma_id_from, pos, score_to_add); - } - } - } - return true; -} -// Choose a candidate, and give new candidates for next step. -// If user finishes selection, we will try to communicate with user dictionary -// to add new items or update score of some existing items. -// -// Basic rule: -// 1. If user selects the first choice: -// 1.1. If the first choice is not a sentence, instead, it is a lemma: -// 1.1.1. If the first choice is a user lemma, notify the user -// dictionary that a user lemma is hit, and add occuring count -// by 1. -// 1.1.2. If the first choice is a system lemma, do nothing. -// 1.2. If the first choice is a sentence containing more than one lemma: -// 1.2.1. The whole sentence will be added as a user lemma. If the -// sentence contains user lemmas, -> hit, and add occuring count -// by 1. -size_t MatrixSearch::choose(size_t cand_id) { - if (!inited_ || 0 == pys_decoded_len_) - return 0; - if (0 == cand_id) { - fixed_hzs_ = spl_id_num_; - matrix_[spl_start_[fixed_hzs_]].mtrx_nd_fixed = mtrx_nd_pool_ + - matrix_[spl_start_[fixed_hzs_]].mtrx_nd_pos; - for (size_t pos = fixed_lmas_; pos < lma_id_num_; pos++) { - fixed_lmas_no1_[pos] = 1; - } - fixed_lmas_ = lma_id_num_; - lpi_total_ = 0; // Clean all other candidates. - // 1. It is the first choice - if (1 == lma_id_num_) { - // 1.1. The first choice is not a sentence but a lemma - if (is_user_lemma(lma_id_[0])) { - // 1.1.1. The first choice is a user lemma, notify the user dictionary - // that it is hit. - if (NULL != user_dict_) - user_dict_->update_lemma(lma_id_[0], 1, true); - } - else { - // 1.1.2. do thing for a system lemma. - } - } - else { - // 1.2. The first choice is a sentence. - // 1.2.1 Try to add the whole sentence to user dictionary, the whole - // sentence may be splitted into many items. - if (NULL != user_dict_) { - try_add_cand0_to_userdict(); - } - } - update_dict_freq(); - return 1; - } - else { - cand_id--; - } - // 2. It is not the full sentence candidate. - // Find the length of the candidate. - LemmaIdType id_chosen = lpi_items_[cand_id].id; - LmaScoreType score_chosen = lpi_items_[cand_id].psb; - size_t cand_len = lpi_items_[cand_id].lma_len; - assert(cand_len > 0); - // Notify the atom dictionary that this item is hit. - if (is_user_lemma(id_chosen)) { - if (NULL != user_dict_) { - user_dict_->update_lemma(id_chosen, 1, true); - } - update_dict_freq(); - } - // 3. Fixed the chosen item. - // 3.1 Get the steps number. - size_t step_fr = spl_start_[fixed_hzs_]; - size_t step_to = spl_start_[fixed_hzs_ + cand_len]; - // 3.2 Save the length of the original string. - size_t pys_decoded_len = pys_decoded_len_; - // 3.2 Reset the space of the fixed part. - reset_search(step_to, false, false, true); - // 3.3 For the last character of the fixed part, the previous DMI - // information will be kept, while the MTRX information will be re-extended, - // and only one node will be extended. - matrix_[step_to].mtrx_nd_num = 0; - LmaPsbItem lpi_item; - lpi_item.psb = score_chosen; - lpi_item.id = id_chosen; - PoolPosType step_to_dmi_fr = match_dmi(step_to, - spl_id_ + fixed_hzs_, cand_len); - // assert(step_to_dmi_fr != static_cast(-1)); - extend_mtrx_nd(matrix_[step_fr].mtrx_nd_fixed, &lpi_item, 1, - step_to_dmi_fr, step_to); - matrix_[step_to].mtrx_nd_fixed = mtrx_nd_pool_ + matrix_[step_to].mtrx_nd_pos; - mtrx_nd_pool_used_ = matrix_[step_to].mtrx_nd_pos + - matrix_[step_to].mtrx_nd_num; - if (id_chosen == lma_id_[fixed_lmas_]) - fixed_lmas_no1_[fixed_lmas_] = 1; - else - fixed_lmas_no1_[fixed_lmas_] = 0; - lma_id_[fixed_lmas_] = id_chosen; - lma_start_[fixed_lmas_ + 1] = lma_start_[fixed_lmas_] + cand_len; - fixed_lmas_++; - fixed_hzs_ = fixed_hzs_ + cand_len; - while (step_to != pys_decoded_len) { - bool b = add_char(pys_[step_to]); - assert(b); - step_to++; - } - if (fixed_hzs_ < spl_id_num_) { - prepare_candidates(); - } - else { - lpi_total_ = 0; - if (NULL != user_dict_) { - try_add_cand0_to_userdict(); - } - } - return get_candidate_num(); -} -size_t MatrixSearch::cancel_last_choice() { - if (!inited_ || 0 == pys_decoded_len_) - return 0; - size_t step_start = 0; - if (fixed_hzs_ > 0) { - size_t step_end = spl_start_[fixed_hzs_]; - MatrixNode* end_node = matrix_[step_end].mtrx_nd_fixed; - assert(NULL != end_node); - step_start = end_node->from->step; - if (step_start > 0) { - DictMatchInfo* dmi = dmi_pool_ + end_node->dmi_fr; - fixed_hzs_ -= dmi->dict_level; - } - else { - fixed_hzs_ = 0; - } - reset_search(step_start, false, false, false); - while (pys_[step_start] != '\0') { - bool b = add_char(pys_[step_start]); - assert(b); - step_start++; - } - prepare_candidates(); - } - return get_candidate_num(); -} -size_t MatrixSearch::get_fixedlen() { - if (!inited_ || 0 == pys_decoded_len_) - return 0; - return fixed_hzs_; -} -bool MatrixSearch::prepare_add_char(char ch) { - if (pys_decoded_len_ >= kMaxRowNum - 1 || - (!spl_parser_->is_valid_to_parse(ch) && ch != '\'')) - return false; - if (dmi_pool_used_ >= kDmiPoolSize) - return false; - pys_[pys_decoded_len_] = ch; - pys_decoded_len_++; - MatrixRow* mtrx_this_row = matrix_ + pys_decoded_len_; - mtrx_this_row->mtrx_nd_pos = mtrx_nd_pool_used_; - mtrx_this_row->mtrx_nd_num = 0; - mtrx_this_row->dmi_pos = dmi_pool_used_; - mtrx_this_row->dmi_num = 0; - mtrx_this_row->dmi_has_full_id = 0; - return true; -} -bool MatrixSearch::is_split_at(uint16 pos) { - return !spl_parser_->is_valid_to_parse(pys_[pos - 1]); -} -void MatrixSearch::fill_dmi(DictMatchInfo* dmi, MileStoneHandle* handles, - PoolPosType dmi_fr, uint16 spl_id, - uint16 node_num, unsigned char dict_level, - bool splid_end_split, unsigned char splstr_len, - unsigned char all_full_id) { - dmi->dict_handles[0] = handles[0]; - dmi->dict_handles[1] = handles[1]; - dmi->dmi_fr = dmi_fr; - dmi->spl_id = spl_id; - dmi->dict_level = dict_level; - dmi->splid_end_split = splid_end_split ? 1 : 0; - dmi->splstr_len = splstr_len; - dmi->all_full_id = all_full_id; - dmi->c_phrase = 0; -} -bool MatrixSearch::add_char(char ch) { - if (!prepare_add_char(ch)) - return false; - return add_char_qwerty(); -} -bool MatrixSearch::add_char_qwerty() { - matrix_[pys_decoded_len_].mtrx_nd_num = 0; - bool spl_matched = false; - uint16 longest_ext = 0; - // Extend the search matrix, from the oldest unfixed row. ext_len means - // extending length. - for (uint16 ext_len = kMaxPinyinSize + 1; ext_len > 0; ext_len--) { - if (ext_len > pys_decoded_len_ - spl_start_[fixed_hzs_]) - continue; - // Refer to the declaration of the variable dmi_has_full_id for the - // explanation of this piece of code. In one word, it is used to prevent - // from the unwise extending of "shoud ou" but allow the reasonable - // extending of "heng ao", "lang a", etc. - if (ext_len > 1 && 0 != longest_ext && - 0 == matrix_[pys_decoded_len_ - ext_len].dmi_has_full_id) { - if (xi_an_enabled_) - continue; - else - break; - } - uint16 oldrow = pys_decoded_len_ - ext_len; - // 0. If that row is before the last fixed step, ignore. - if (spl_start_[fixed_hzs_] > oldrow) - continue; - // 1. Check if that old row has valid MatrixNode. If no, means that row is - // not a boundary, either a word boundary or a spelling boundary. - // If it is for extending composing phrase, it's OK to ignore the 0. - if (0 == matrix_[oldrow].mtrx_nd_num && !dmi_c_phrase_) - continue; - // 2. Get spelling id(s) for the last ext_len chars. - uint16 spl_idx; - bool is_pre = false; - spl_idx = spl_parser_->get_splid_by_str(pys_ + oldrow, - ext_len, &is_pre); - if (is_pre) - spl_matched = true; - if (0 == spl_idx) - continue; - bool splid_end_split = is_split_at(oldrow + ext_len); - // 3. Extend the DMI nodes of that old row - // + 1 is to extend an extra node from the root - for (PoolPosType dmi_pos = matrix_[oldrow].dmi_pos; - dmi_pos < matrix_[oldrow].dmi_pos + matrix_[oldrow].dmi_num + 1; - dmi_pos++) { - DictMatchInfo* dmi = dmi_pool_ + dmi_pos; - if (dmi_pos == matrix_[oldrow].dmi_pos + matrix_[oldrow].dmi_num) { - dmi = NULL; // The last one, NULL means extending from the root. - } - else { - // If the dmi is covered by the fixed arrange, ignore it. - if (fixed_hzs_ > 0 && - pys_decoded_len_ - ext_len - dmi->splstr_len < - spl_start_[fixed_hzs_]) { - continue; - } - // If it is not in mode for composing phrase, and the source DMI node - // is marked for composing phrase, ignore this node. - if (dmi->c_phrase != 0 && !dmi_c_phrase_) { - continue; - } - } - // For example, if "gao" is extended, "g ao" is not allowed. - // or "zh" has been passed, "z h" is not allowed. - // Both word and word-connection will be prevented. - if (longest_ext > ext_len) { - if (NULL == dmi && 0 == matrix_[oldrow].dmi_has_full_id) { - continue; - } - // "z h" is not allowed. - if (NULL != dmi && spl_trie_->is_half_id(dmi->spl_id)) { - continue; - } - } - dep_->splids_extended = 0; - if (NULL != dmi) { - uint16 prev_ids_num = dmi->dict_level; - if ((!dmi_c_phrase_ && prev_ids_num >= kMaxLemmaSize) || - (dmi_c_phrase_ && prev_ids_num >= kMaxRowNum)) { - continue; - } - DictMatchInfo* d = dmi; - while (d) { - dep_->splids[--prev_ids_num] = d->spl_id; - if ((PoolPosType)-1 == d->dmi_fr) - break; - d = dmi_pool_ + d->dmi_fr; - } - assert(0 == prev_ids_num); - dep_->splids_extended = dmi->dict_level; - } - dep_->splids[dep_->splids_extended] = spl_idx; - dep_->ext_len = ext_len; - dep_->splid_end_split = splid_end_split; - dep_->id_num = 1; - dep_->id_start = spl_idx; - if (spl_trie_->is_half_id(spl_idx)) { - // Get the full id list - dep_->id_num = spl_trie_->half_to_full(spl_idx, &(dep_->id_start)); - assert(dep_->id_num > 0); - } - uint16 new_dmi_num; - new_dmi_num = extend_dmi(dep_, dmi); - if (new_dmi_num > 0) { - if (dmi_c_phrase_) { - dmi_pool_[dmi_pool_used_].c_phrase = 1; - } - matrix_[pys_decoded_len_].dmi_num += new_dmi_num; - dmi_pool_used_ += new_dmi_num; - if (!spl_trie_->is_half_id(spl_idx)) - matrix_[pys_decoded_len_].dmi_has_full_id = 1; - } - // If get candiate lemmas, try to extend the path - if (lpi_total_ > 0) { - uint16 fr_row; - if (NULL == dmi) { - fr_row = oldrow; - } - else { - assert(oldrow >= dmi->splstr_len); - fr_row = oldrow - dmi->splstr_len; - } - for (PoolPosType mtrx_nd_pos = matrix_[fr_row].mtrx_nd_pos; - mtrx_nd_pos < matrix_[fr_row].mtrx_nd_pos + - matrix_[fr_row].mtrx_nd_num; - mtrx_nd_pos++) { - MatrixNode* mtrx_nd = mtrx_nd_pool_ + mtrx_nd_pos; - extend_mtrx_nd(mtrx_nd, lpi_items_, lpi_total_, - dmi_pool_used_ - new_dmi_num, pys_decoded_len_); - if (longest_ext == 0) - longest_ext = ext_len; - } - } - } // for dmi_pos - } // for ext_len - mtrx_nd_pool_used_ += matrix_[pys_decoded_len_].mtrx_nd_num; - if (dmi_c_phrase_) - return true; - return (matrix_[pys_decoded_len_].mtrx_nd_num != 0 || spl_matched); -} -void MatrixSearch::prepare_candidates() { - // Get candiates from the first un-fixed step. - uint16 lma_size_max = kMaxLemmaSize; - if (lma_size_max > spl_id_num_ - fixed_hzs_) - lma_size_max = spl_id_num_ - fixed_hzs_; - uint16 lma_size = lma_size_max; - // If the full sentense candidate's unfixed part may be the same with a normal - // lemma. Remove the lemma candidate in this case. - char16 fullsent[kMaxLemmaSize + 1]; - char16* pfullsent = NULL; - uint16 sent_len; - pfullsent = get_candidate0(fullsent, kMaxLemmaSize + 1, &sent_len, true); - // If the unfixed part contains more than one ids, it is not necessary to - // check whether a lemma's string is the same to the unfixed part of the full - // sentence candidate, so, set it to NULL; - if (sent_len > kMaxLemmaSize) - pfullsent = NULL; - lpi_total_ = 0; - size_t lpi_num_full_match = 0; // Number of items which are fully-matched. - while (lma_size > 0) { - size_t lma_num; - lma_num = get_lpis(spl_id_ + fixed_hzs_, lma_size, - lpi_items_ + lpi_total_, - size_t(kMaxLmaPsbItems - lpi_total_), - pfullsent, lma_size == lma_size_max); - if (lma_num > 0) { - lpi_total_ += lma_num; - // For next lemma candidates which are not the longest, it is not - // necessary to compare with the full sentence candiate. - pfullsent = NULL; - } - if (lma_size == lma_size_max) { - lpi_num_full_match = lpi_total_; - } - lma_size--; - } - // Sort those partially-matched items by their unified scores. - myqsort(lpi_items_ + lpi_num_full_match, lpi_total_ - lpi_num_full_match, - sizeof(LmaPsbItem), cmp_lpi_with_unified_psb); - if (kPrintDebug0) { - printf("-----Prepare candidates, score:\n"); - for (size_t a = 0; a < lpi_total_; a++) { - printf("[%03zu]%d ", a, lpi_items_[a].psb); - if ((a + 1) % 6 == 0) - printf("\n"); - } - printf("\n"); - } - if (kPrintDebug0) { - printf("--- lpi_total_ = %zu\n", lpi_total_); - } -} -const char* MatrixSearch::get_pystr(size_t* decoded_len) { - if (!inited_ || NULL == decoded_len) - return NULL; - *decoded_len = pys_decoded_len_; - return pys_; -} -void MatrixSearch::merge_fixed_lmas(size_t del_spl_pos) { - if (fixed_lmas_ == 0) - return; - // Update spelling segmentation information first. - spl_id_num_ -= 1; - uint16 del_py_len = spl_start_[del_spl_pos + 1] - spl_start_[del_spl_pos]; - for (size_t pos = del_spl_pos; pos <= spl_id_num_; pos++) { - spl_start_[pos] = spl_start_[pos + 1] - del_py_len; - if (pos == spl_id_num_) - break; - spl_id_[pos] = spl_id_[pos + 1]; - } - // Begin to merge. - uint16 phrase_len = 0; - // Update the spelling ids to the composing phrase. - // We need to convert these ids into full id in the future. - memcpy(c_phrase_.spl_ids, spl_id_, spl_id_num_ * sizeof(uint16)); - memcpy(c_phrase_.spl_start, spl_start_, (spl_id_num_ + 1) * sizeof(uint16)); - // If composing phrase has not been created, first merge all fixed - // lemmas into a composing phrase without deletion. - if (fixed_lmas_ > 1 || kLemmaIdComposing != lma_id_[0]) { - uint16 bp = 1; // Begin position of real fixed lemmas. - // There is no existing composing phrase. - if (kLemmaIdComposing != lma_id_[0]) { - c_phrase_.sublma_num = 0; - bp = 0; - } - uint16 sub_num = c_phrase_.sublma_num; - for (uint16 pos = bp; pos <= fixed_lmas_; pos++) { - c_phrase_.sublma_start[sub_num + pos - bp] = lma_start_[pos]; - if (lma_start_[pos] > del_spl_pos) { - c_phrase_.sublma_start[sub_num + pos - bp] -= 1; - } - if (pos == fixed_lmas_) - break; - uint16 lma_len; - char16* lma_str = c_phrase_.chn_str + - c_phrase_.sublma_start[sub_num] + phrase_len; - lma_len = get_lemma_str(lma_id_[pos], lma_str, kMaxRowNum - phrase_len); - assert(lma_len == lma_start_[pos + 1] - lma_start_[pos]); - phrase_len += lma_len; - } - assert(phrase_len == lma_start_[fixed_lmas_]); - c_phrase_.length = phrase_len; // will be deleted by 1 - c_phrase_.sublma_num += fixed_lmas_ - bp; - } - else { - for (uint16 pos = 0; pos <= c_phrase_.sublma_num; pos++) { - if (c_phrase_.sublma_start[pos] > del_spl_pos) { - c_phrase_.sublma_start[pos] -= 1; - } - } - phrase_len = c_phrase_.length; - } - assert(phrase_len > 0); - if (1 == phrase_len) { - // After the only one is deleted, nothing will be left. - fixed_lmas_ = 0; - return; - } - // Delete the Chinese character in the merged phrase. - // The corresponding elements in spl_ids and spl_start of the - // phrase have been deleted. - char16* chn_str = c_phrase_.chn_str + del_spl_pos; - for (uint16 pos = 0; - pos < c_phrase_.sublma_start[c_phrase_.sublma_num] - del_spl_pos; - pos++) { - chn_str[pos] = chn_str[pos + 1]; - } - c_phrase_.length -= 1; - // If the deleted spelling id is in a sub lemma which contains more than - // one id, del_a_sub will be false; but if the deleted id is in a sub lemma - // which only contains 1 id, the whole sub lemma needs to be deleted, so - // del_a_sub will be true. - bool del_a_sub = false; - for (uint16 pos = 1; pos <= c_phrase_.sublma_num; pos++) { - if (c_phrase_.sublma_start[pos - 1] == - c_phrase_.sublma_start[pos]) { - del_a_sub = true; - } - if (del_a_sub) { - c_phrase_.sublma_start[pos - 1] = - c_phrase_.sublma_start[pos]; - } - } - if (del_a_sub) - c_phrase_.sublma_num -= 1; - return; -} -void MatrixSearch::get_spl_start_id() { - lma_id_num_ = 0; - lma_start_[0] = 0; - spl_id_num_ = 0; - spl_start_[0] = 0; - if (!inited_ || 0 == pys_decoded_len_ || - 0 == matrix_[pys_decoded_len_].mtrx_nd_num) - return; - // Calculate number of lemmas and spellings - // Only scan those part which is not fixed. - lma_id_num_ = fixed_lmas_; - spl_id_num_ = fixed_hzs_; - MatrixNode* mtrx_nd = mtrx_nd_pool_ + matrix_[pys_decoded_len_].mtrx_nd_pos; - while (mtrx_nd != mtrx_nd_pool_) { - if (fixed_hzs_ > 0) { - if (mtrx_nd->step <= spl_start_[fixed_hzs_]) - break; - } - // Update the spelling segamentation information - unsigned char word_splstr_len = 0; - PoolPosType dmi_fr = mtrx_nd->dmi_fr; - if ((PoolPosType)-1 != dmi_fr) - word_splstr_len = dmi_pool_[dmi_fr].splstr_len; - while ((PoolPosType)-1 != dmi_fr) { - spl_start_[spl_id_num_ + 1] = mtrx_nd->step - - (word_splstr_len - dmi_pool_[dmi_fr].splstr_len); - spl_id_[spl_id_num_] = dmi_pool_[dmi_fr].spl_id; - spl_id_num_++; - dmi_fr = dmi_pool_[dmi_fr].dmi_fr; - } - // Update the lemma segmentation information - lma_start_[lma_id_num_ + 1] = spl_id_num_; - lma_id_[lma_id_num_] = mtrx_nd->id; - lma_id_num_++; - mtrx_nd = mtrx_nd->from; - } - // Reverse the result of spelling info - for (size_t pos = fixed_hzs_; - pos < fixed_hzs_ + (spl_id_num_ - fixed_hzs_ + 1) / 2; pos++) { - if (spl_id_num_ + fixed_hzs_ - pos != pos + 1) { - spl_start_[pos + 1] ^= spl_start_[spl_id_num_ - pos + fixed_hzs_]; - spl_start_[spl_id_num_ - pos + fixed_hzs_] ^= spl_start_[pos + 1]; - spl_start_[pos + 1] ^= spl_start_[spl_id_num_ - pos + fixed_hzs_]; - spl_id_[pos] ^= spl_id_[spl_id_num_ + fixed_hzs_ - pos - 1]; - spl_id_[spl_id_num_ + fixed_hzs_ - pos - 1] ^= spl_id_[pos]; - spl_id_[pos] ^= spl_id_[spl_id_num_ + fixed_hzs_ - pos - 1]; - } - } - // Reverse the result of lemma info - for (size_t pos = fixed_lmas_; - pos < fixed_lmas_ + (lma_id_num_ - fixed_lmas_ + 1) / 2; pos++) { - assert(lma_id_num_ + fixed_lmas_ - pos - 1 >= pos); - if (lma_id_num_ + fixed_lmas_ - pos > pos + 1) { - lma_start_[pos + 1] ^= lma_start_[lma_id_num_ - pos + fixed_lmas_]; - lma_start_[lma_id_num_ - pos + fixed_lmas_] ^= lma_start_[pos + 1]; - lma_start_[pos + 1] ^= lma_start_[lma_id_num_ - pos + fixed_lmas_]; - lma_id_[pos] ^= lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_]; - lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_] ^= lma_id_[pos]; - lma_id_[pos] ^= lma_id_[lma_id_num_ - 1 - pos + fixed_lmas_]; - } - } - for (size_t pos = fixed_lmas_ + 1; pos <= lma_id_num_; pos++) { - if (pos < lma_id_num_) - lma_start_[pos] = lma_start_[pos - 1] + - (lma_start_[pos] - lma_start_[pos + 1]); - else - lma_start_[pos] = lma_start_[pos - 1] + lma_start_[pos] - - lma_start_[fixed_lmas_]; - } - // Find the last fixed position - fixed_hzs_ = 0; - for (size_t pos = spl_id_num_; pos > 0; pos--) { - if (NULL != matrix_[spl_start_[pos]].mtrx_nd_fixed) { - fixed_hzs_ = pos; - break; - } - } - return; -} -size_t MatrixSearch::get_spl_start(const uint16*& spl_start) { - get_spl_start_id(); - spl_start = spl_start_; - return spl_id_num_; -} -size_t MatrixSearch::extend_dmi(DictExtPara* dep, DictMatchInfo* dmi_s) { - if (dmi_pool_used_ >= kDmiPoolSize) - return 0; - if (dmi_c_phrase_) - return extend_dmi_c(dep, dmi_s); - LpiCache& lpi_cache = LpiCache::get_instance(); - uint16 splid = dep->splids[dep->splids_extended]; - bool cached = false; - if (0 == dep->splids_extended) - cached = lpi_cache.is_cached(splid); - // 1. If this is a half Id, get its corresponding full starting Id and - // number of full Id. - size_t ret_val = 0; - PoolPosType mtrx_dmi_fr = (PoolPosType)-1; // From which dmi node - lpi_total_ = 0; - MileStoneHandle from_h[3]; - from_h[0] = 0; - from_h[1] = 0; - if (0 != dep->splids_extended) { - from_h[0] = dmi_s->dict_handles[0]; - from_h[1] = dmi_s->dict_handles[1]; - } - // 2. Begin exgtending in the system dictionary - size_t lpi_num = 0; - MileStoneHandle handles[2]; - handles[0] = handles[1] = 0; - if (from_h[0] > 0 || NULL == dmi_s) { - handles[0] = dict_trie_->extend_dict(from_h[0], dep, lpi_items_, - kMaxLmaPsbItems, &lpi_num); - } - if (handles[0] > 0) - lpi_total_ = lpi_num; - if (NULL == dmi_s) { - // from root - assert(0 != handles[0]); - mtrx_dmi_fr = dmi_pool_used_; - } - // 3. Begin extending in the user dictionary - if (NULL != user_dict_ && (from_h[1] > 0 || NULL == dmi_s)) { - handles[1] = user_dict_->extend_dict(from_h[1], dep, - lpi_items_ + lpi_total_, - kMaxLmaPsbItems - lpi_total_, - &lpi_num); - if (handles[1] > 0) { - if (kPrintDebug0) { - for (size_t t = 0; t < lpi_num; t++) { - printf("--Extend in user dict: uid:%zu uscore:%d\n", lpi_items_[lpi_total_ + t].id, - lpi_items_[lpi_total_ + t].psb); - } - } - lpi_total_ += lpi_num; - } - } - if (0 != handles[0] || 0 != handles[1]) { - if (dmi_pool_used_ >= kDmiPoolSize) - return 0; - DictMatchInfo* dmi_add = dmi_pool_ + dmi_pool_used_; - if (NULL == dmi_s) { - fill_dmi(dmi_add, handles, - (PoolPosType)-1, splid, - 1, 1, dep->splid_end_split, dep->ext_len, - spl_trie_->is_half_id(splid) ? 0 : 1); - } - else { - fill_dmi(dmi_add, handles, - dmi_s - dmi_pool_, splid, 1, - dmi_s->dict_level + 1, dep->splid_end_split, - dmi_s->splstr_len + dep->ext_len, - spl_trie_->is_half_id(splid) ? 0 : dmi_s->all_full_id); - } - ret_val = 1; - } - if (!cached) { - if (0 == lpi_total_) - return ret_val; - if (kPrintDebug0) { - printf("--- lpi_total_ = %zu\n", lpi_total_); - } - myqsort(lpi_items_, lpi_total_, sizeof(LmaPsbItem), cmp_lpi_with_psb); - if (NULL == dmi_s && spl_trie_->is_half_id(splid)) - lpi_total_ = lpi_cache.put_cache(splid, lpi_items_, lpi_total_); - } - else { - assert(spl_trie_->is_half_id(splid)); - lpi_total_ = lpi_cache.get_cache(splid, lpi_items_, kMaxLmaPsbItems); - } - return ret_val; -} -size_t MatrixSearch::extend_dmi_c(DictExtPara* dep, DictMatchInfo* dmi_s) { - lpi_total_ = 0; - uint16 pos = dep->splids_extended; - assert(dmi_c_phrase_); - if (pos >= c_phrase_.length) - return 0; - uint16 splid = dep->splids[pos]; - if (splid == c_phrase_.spl_ids[pos]) { - DictMatchInfo* dmi_add = dmi_pool_ + dmi_pool_used_; - MileStoneHandle handles[2]; // Actually never used. - if (NULL == dmi_s) - fill_dmi(dmi_add, handles, - (PoolPosType)-1, splid, - 1, 1, dep->splid_end_split, dep->ext_len, - spl_trie_->is_half_id(splid) ? 0 : 1); - else - fill_dmi(dmi_add, handles, - dmi_s - dmi_pool_, splid, 1, - dmi_s->dict_level + 1, dep->splid_end_split, - dmi_s->splstr_len + dep->ext_len, - spl_trie_->is_half_id(splid) ? 0 : dmi_s->all_full_id); - if (pos == c_phrase_.length - 1) { - lpi_items_[0].id = kLemmaIdComposing; - lpi_items_[0].psb = 0; // 0 is bigger than normal lemma score. - lpi_total_ = 1; - } - return 1; - } - return 0; -} -size_t MatrixSearch::extend_mtrx_nd(MatrixNode* mtrx_nd, LmaPsbItem lpi_items[], - size_t lpi_num, PoolPosType dmi_fr, - size_t res_row) { - assert(NULL != mtrx_nd); - matrix_[res_row].mtrx_nd_fixed = NULL; - if (mtrx_nd_pool_used_ >= kMtrxNdPoolSize - kMaxNodeARow) - return 0; - if (0 == mtrx_nd->step) { - // Because the list is sorted, if the source step is 0, it is only - // necessary to pick up the first kMaxNodeARow items. - if (lpi_num > kMaxNodeARow) - lpi_num = kMaxNodeARow; - } - MatrixNode* mtrx_nd_res_min = mtrx_nd_pool_ + matrix_[res_row].mtrx_nd_pos; - for (size_t pos = 0; pos < lpi_num; pos++) { - float score = mtrx_nd->score + lpi_items[pos].psb; - if (pos > 0 && score - PRUMING_SCORE > mtrx_nd_res_min->score) - break; - // Try to add a new node - size_t mtrx_nd_num = matrix_[res_row].mtrx_nd_num; - MatrixNode* mtrx_nd_res = mtrx_nd_res_min + mtrx_nd_num; - bool replace = false; - // Find its position - while (mtrx_nd_res > mtrx_nd_res_min && score < (mtrx_nd_res - 1)->score) { - if (static_cast(mtrx_nd_res - mtrx_nd_res_min) < kMaxNodeARow) - *mtrx_nd_res = *(mtrx_nd_res - 1); - mtrx_nd_res--; - replace = true; - } - if (replace || (mtrx_nd_num < kMaxNodeARow && matrix_[res_row].mtrx_nd_pos + mtrx_nd_num < kMtrxNdPoolSize)) { - mtrx_nd_res->id = lpi_items[pos].id; - mtrx_nd_res->score = score; - mtrx_nd_res->from = mtrx_nd; - mtrx_nd_res->dmi_fr = dmi_fr; - mtrx_nd_res->step = res_row; - if (matrix_[res_row].mtrx_nd_num < kMaxNodeARow) - matrix_[res_row].mtrx_nd_num++; - } - } - return matrix_[res_row].mtrx_nd_num; -} -PoolPosType MatrixSearch::match_dmi(size_t step_to, uint16 spl_ids[], - uint16 spl_id_num) { - if (pys_decoded_len_ < step_to || 0 == matrix_[step_to].dmi_num) { - return static_cast(-1); - } - for (PoolPosType dmi_pos = 0; dmi_pos < matrix_[step_to].dmi_num; dmi_pos++) { - DictMatchInfo* dmi = dmi_pool_ + matrix_[step_to].dmi_pos + dmi_pos; - if (dmi->dict_level != spl_id_num) - continue; - bool matched = true; - for (uint16 spl_pos = 0; spl_pos < spl_id_num; spl_pos++) { - if (spl_ids[spl_id_num - spl_pos - 1] != dmi->spl_id) { - matched = false; - break; - } - dmi = dmi_pool_ + dmi->dmi_fr; - } - if (matched) { - return matrix_[step_to].dmi_pos + dmi_pos; - } - } - return static_cast(-1); -} -char16* MatrixSearch::get_candidate0(char16* cand_str, size_t max_len, - uint16* retstr_len, - bool only_unfixed) { - if (pys_decoded_len_ == 0 || - matrix_[pys_decoded_len_].mtrx_nd_num == 0) - return NULL; - LemmaIdType idxs[kMaxRowNum]; - size_t id_num = 0; - MatrixNode* mtrx_nd = mtrx_nd_pool_ + matrix_[pys_decoded_len_].mtrx_nd_pos; - if (kPrintDebug0) { - printf("--- sentence score: %f\n", mtrx_nd->score); - } - if (kPrintDebug1) { - printf("==============Sentence DMI (reverse order) begin===========>>\n"); - } - while (mtrx_nd != NULL) { - idxs[id_num] = mtrx_nd->id; - id_num++; - if (kPrintDebug1) { - printf("---MatrixNode [step: %d, lma_idx: %zu, total score:%.5f]\n", - mtrx_nd->step, mtrx_nd->id, mtrx_nd->score); - debug_print_dmi(mtrx_nd->dmi_fr, 1); - } - mtrx_nd = mtrx_nd->from; - } - if (kPrintDebug1) { - printf("<<==============Sentence DMI (reverse order) end=============\n"); - } - size_t ret_pos = 0; - do { - id_num--; - if (0 == idxs[id_num]) - continue; - char16 str[kMaxLemmaSize + 1]; - uint16 str_len = get_lemma_str(idxs[id_num], str, kMaxLemmaSize + 1); - if (str_len > 0 && ((!only_unfixed && max_len - ret_pos > str_len) || (only_unfixed && max_len - ret_pos + fixed_hzs_ > str_len))) { - if (!only_unfixed) - utf16_strncpy(cand_str + ret_pos, str, str_len); - else if (ret_pos >= fixed_hzs_) - utf16_strncpy(cand_str + ret_pos - fixed_hzs_, str, str_len); - ret_pos += str_len; - } - else { - return NULL; - } - } - while (id_num != 0); - if (!only_unfixed) { - if (NULL != retstr_len) - *retstr_len = ret_pos; - cand_str[ret_pos] = (char16)'\0'; - } - else { - if (NULL != retstr_len) - *retstr_len = ret_pos - fixed_hzs_; - cand_str[ret_pos - fixed_hzs_] = (char16)'\0'; - } - return cand_str; -} -size_t MatrixSearch::get_lpis(const uint16* splid_str, size_t splid_str_len, - LmaPsbItem* lma_buf, size_t max_lma_buf, - const char16* pfullsent, bool sort_by_psb) { - if (splid_str_len > kMaxLemmaSize) - return 0; - size_t num1 = dict_trie_->get_lpis(splid_str, splid_str_len, - lma_buf, max_lma_buf); - size_t num2 = 0; - if (NULL != user_dict_) { - num2 = user_dict_->get_lpis(splid_str, splid_str_len, - lma_buf + num1, max_lma_buf - num1); - } - size_t num = num1 + num2; - if (0 == num) - return 0; - // Remove repeated items. - if (splid_str_len > 1) { - LmaPsbStrItem* lpsis = reinterpret_cast(lma_buf + num); - size_t lpsi_num = (max_lma_buf - num) * sizeof(LmaPsbItem) / - sizeof(LmaPsbStrItem); - // assert(lpsi_num > num); - if (num > lpsi_num) - num = lpsi_num; - lpsi_num = num; - for (size_t pos = 0; pos < lpsi_num; pos++) { - lpsis[pos].lpi = lma_buf[pos]; - get_lemma_str(lma_buf[pos].id, lpsis[pos].str, kMaxLemmaSize + 1); - } - myqsort(lpsis, lpsi_num, sizeof(LmaPsbStrItem), cmp_lpsi_with_str); - size_t remain_num = 0; - for (size_t pos = 0; pos < lpsi_num; pos++) { - if (pos > 0 && utf16_strcmp(lpsis[pos].str, lpsis[pos - 1].str) == 0) { - if (lpsis[pos].lpi.psb < lpsis[pos - 1].lpi.psb) { - assert(remain_num > 0); - lma_buf[remain_num - 1] = lpsis[pos].lpi; - } - continue; - } - if (NULL != pfullsent && utf16_strcmp(lpsis[pos].str, pfullsent) == 0) - continue; - lma_buf[remain_num] = lpsis[pos].lpi; - remain_num++; - } - // Update the result number - num = remain_num; - } - else { - // For single character, some characters have more than one spelling, for - // example, "de" and "di" are all valid for a Chinese character, so when - // the user input "d", repeated items are generated. - // For single character lemmas, Hanzis will be gotten - for (size_t pos = 0; pos < num; pos++) { - char16 hanzis[2]; - get_lemma_str(lma_buf[pos].id, hanzis, 2); - lma_buf[pos].hanzi = hanzis[0]; - } - myqsort(lma_buf, num, sizeof(LmaPsbItem), cmp_lpi_with_hanzi); - size_t remain_num = 0; - for (size_t pos = 0; pos < num; pos++) { - if (pos > 0 && lma_buf[pos].hanzi == lma_buf[pos - 1].hanzi) { - if (NULL != pfullsent && - static_cast(0) == pfullsent[1] && - lma_buf[pos].hanzi == pfullsent[0]) - continue; - if (lma_buf[pos].psb < lma_buf[pos - 1].psb) { - assert(remain_num > 0); - assert(lma_buf[remain_num - 1].hanzi == lma_buf[pos].hanzi); - lma_buf[remain_num - 1] = lma_buf[pos]; - } - continue; - } - if (NULL != pfullsent && - static_cast(0) == pfullsent[1] && - lma_buf[pos].hanzi == pfullsent[0]) - continue; - lma_buf[remain_num] = lma_buf[pos]; - remain_num++; - } - num = remain_num; - } - if (sort_by_psb) { - myqsort(lma_buf, num, sizeof(LmaPsbItem), cmp_lpi_with_psb); - } - return num; -} -uint16 MatrixSearch::get_lemma_str(LemmaIdType id_lemma, char16* str_buf, - uint16 str_max) { - uint16 str_len = 0; - if (is_system_lemma(id_lemma)) { - str_len = dict_trie_->get_lemma_str(id_lemma, str_buf, str_max); - } - else if (is_user_lemma(id_lemma)) { - if (NULL != user_dict_) { - str_len = user_dict_->get_lemma_str(id_lemma, str_buf, str_max); - } - else { - str_len = 0; - str_buf[0] = static_cast('\0'); - } - } - else if (is_composing_lemma(id_lemma)) { - if (str_max <= 1) - return 0; - str_len = c_phrase_.sublma_start[c_phrase_.sublma_num]; - if (str_len > str_max - 1) - str_len = str_max - 1; - utf16_strncpy(str_buf, c_phrase_.chn_str, str_len); - str_buf[str_len] = (char16)'\0'; - return str_len; - } - return str_len; -} -uint16 MatrixSearch::get_lemma_splids(LemmaIdType id_lemma, uint16* splids, - uint16 splids_max, bool arg_valid) { - uint16 splid_num = 0; - if (arg_valid) { - for (splid_num = 0; splid_num < splids_max; splid_num++) { - if (spl_trie_->is_half_id(splids[splid_num])) - break; - } - if (splid_num == splids_max) - return splid_num; - } - if (is_system_lemma(id_lemma)) { - splid_num = dict_trie_->get_lemma_splids(id_lemma, splids, splids_max, - arg_valid); - } - else if (is_user_lemma(id_lemma)) { - if (NULL != user_dict_) { - splid_num = user_dict_->get_lemma_splids(id_lemma, splids, splids_max, - arg_valid); - } - else { - splid_num = 0; - } - } - else if (is_composing_lemma(id_lemma)) { - if (c_phrase_.length > splids_max) { - return 0; - } - for (uint16 pos = 0; pos < c_phrase_.length; pos++) { - splids[pos] = c_phrase_.spl_ids[pos]; - if (spl_trie_->is_half_id(splids[pos])) { - return 0; - } - } - } - return splid_num; -} -size_t MatrixSearch::inner_predict(const char16* fixed_buf, uint16 fixed_len, - char16 predict_buf[][kMaxPredictSize + 1], - size_t buf_len) { - size_t res_total = 0; - memset(npre_items_, 0, sizeof(NPredictItem) * npre_items_len_); - // In order to shorten the comments, j-character candidates predicted by - // i-character prefix are called P(i,j). All candiates predicted by - // i-character prefix are called P(i,*) - // Step 1. Get P(kMaxPredictSize, *) and sort them, here - // P(kMaxPredictSize, *) == P(kMaxPredictSize, 1) - for (size_t len = fixed_len; len > 0; len--) { - // How many blank items are available - size_t this_max = npre_items_len_ - res_total; - size_t res_this; - // If the history is longer than 1, and we can not get prediction from - // lemmas longer than 2, in this case, we will add lemmas with - // highest scores as the prediction result. - if (fixed_len > 1 && 1 == len && 0 == res_total) { - // Try to find if recent n (n>1) characters can be a valid lemma in system - // dictionary. - bool nearest_n_word = false; - for (size_t nlen = 2; nlen <= fixed_len; nlen++) { - if (dict_trie_->get_lemma_id(fixed_buf + fixed_len - nlen, nlen) > 0) { - nearest_n_word = true; - break; - } - } - res_this = dict_trie_->predict_top_lmas(nearest_n_word ? len : 0, - npre_items_ + res_total, - this_max, res_total); - res_total += res_this; - } - // How many blank items are available - this_max = npre_items_len_ - res_total; - res_this = 0; - if (!kOnlyUserDictPredict) { - res_this = - dict_trie_->predict(fixed_buf + fixed_len - len, len, - npre_items_ + res_total, this_max, - res_total); - } - if (NULL != user_dict_) { - res_this = res_this + - user_dict_->predict(fixed_buf + fixed_len - len, len, - npre_items_ + res_total + res_this, - this_max - res_this, res_total + res_this); - } - if (kPredictLimitGt1) { - myqsort(npre_items_ + res_total, res_this, sizeof(NPredictItem), - cmp_npre_by_score); - if (len > 3) { - if (res_this > kMaxPredictNumByGt3) - res_this = kMaxPredictNumByGt3; - } - else if (3 == len) { - if (res_this > kMaxPredictNumBy3) - res_this = kMaxPredictNumBy3; - } - else if (2 == len) { - if (res_this > kMaxPredictNumBy2) - res_this = kMaxPredictNumBy2; - } - } - res_total += res_this; - } - res_total = remove_duplicate_npre(npre_items_, res_total); - if (kPreferLongHistoryPredict) { - myqsort(npre_items_, res_total, sizeof(NPredictItem), - cmp_npre_by_hislen_score); - } - else { - myqsort(npre_items_, res_total, sizeof(NPredictItem), - cmp_npre_by_score); - } - if (buf_len < res_total) { - res_total = buf_len; - } - if (kPrintDebug2) { - printf("/////////////////Predicted Items Begin////////////////////>>\n"); - for (size_t i = 0; i < res_total; i++) { - printf("---"); - for (size_t j = 0; j < kMaxPredictSize; j++) { - printf("%d ", npre_items_[i].pre_hzs[j]); - } - printf("\n"); - } - printf("< kMaxPredictSize || 0 == buf_len) - return 0; - return inner_predict(fixed_buf, fixed_len, predict_buf, buf_len); -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/matrixsearch.h b/Widget/base/Virtual_Keyboard/googlepinyin/matrixsearch.h deleted file mode 100644 index 325fd32..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/matrixsearch.h +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_ANDPY_INCLUDE_MATRIXSEARCH_H__ -#define PINYINIME_ANDPY_INCLUDE_MATRIXSEARCH_H__ -#include -#include "./atomdictbase.h" -#include "./dicttrie.h" -#include "./searchutility.h" -#include "./spellingtrie.h" -#include "./splparser.h" -namespace ime_pinyin { -static const size_t kMaxRowNum = kMaxSearchSteps; -typedef struct { - // MileStoneHandle objects for the system and user dictionaries. - MileStoneHandle dict_handles[2]; - // From which DMI node. -1 means it's from root. - PoolPosType dmi_fr; - // The spelling id for the Pinyin string from the previous DMI to this node. - // If it is a half id like Shengmu, the node pointed by dict_node is the first - // node with this Shengmu, - uint16 spl_id; - // What's the level of the dict node. Level of root is 0, but root is never - // recorded by dict_node. - unsigned char dict_level : 7; - // If this node is for composing phrase, this bit is 1. - unsigned char c_phrase : 1; - // Whether the spl_id is parsed with a split character at the end. - unsigned char splid_end_split : 1; - // What's the length of the spelling string for this match, for the whole - // word. - unsigned char splstr_len : 7; - // Used to indicate whether all spelling ids from the root are full spelling - // ids. This information is useful for keymapping mode(not finished). Because - // in this mode, there is no clear boundaries, we prefer those results which - // have full spelling ids. - unsigned char all_full_id : 1; -} DictMatchInfo, *PDictMatchInfo; -typedef struct MatrixNode { - LemmaIdType id; - float score; - MatrixNode* from; - // From which DMI node. Used to trace the spelling segmentation. - PoolPosType dmi_fr; - uint16 step; -} MatrixNode, *PMatrixNode; -typedef struct { - // The MatrixNode position in the matrix pool - PoolPosType mtrx_nd_pos; - // The DictMatchInfo position in the DictMatchInfo pool. - PoolPosType dmi_pos; - uint16 mtrx_nd_num; - uint16 dmi_num : 15; - // Used to indicate whether there are dmi nodes in this step with full - // spelling id. This information is used to decide whether a substring of a - // valid Pinyin should be extended. - // - // Example1: shoudao - // When the last char 'o' is added, the parser will find "dao" is a valid - // Pinyin, and because all dmi nodes at location 'd' (including those for - // "shoud", and those for "d") have Shengmu id only, so it is not necessary - // to extend "ao", otherwise the result may be "shoud ao", that is not - // reasonable. - // - // Example2: hengao - // When the last 'o' is added, the parser finds "gao" is a valid Pinyin. - // Because some dmi nodes at 'g' has Shengmu ids (hen'g and g), but some dmi - // nodes at 'g' has full ids ('heng'), so it is necessary to extend "ao", thus - // "heng ao" can also be the result. - // - // Similarly, "ganga" is expanded to "gang a". - // - // For Pinyin string "xian", because "xian" is a valid Pinyin, because all dmi - // nodes at 'x' only have Shengmu ids, the parser will not try "x ian" (and it - // is not valid either). If the parser uses break in the loop, the result - // always be "xian"; but if the parser uses continue in the loop, "xi an" will - // also be tried. This behaviour can be set via the function - // set_xi_an_switch(). - uint16 dmi_has_full_id : 1; - // Points to a MatrixNode of the current step to indicate which choice the - // user selects. - MatrixNode* mtrx_nd_fixed; -} MatrixRow, *PMatrixRow; -// When user inputs and selects candidates, the fixed lemma ids are stored in -// lma_id_ of class MatrixSearch, and fixed_lmas_ is used to indicate how many -// lemmas from the beginning are fixed. If user deletes Pinyin characters one -// by one from the end, these fixed lemmas can be unlocked one by one when -// necessary. Whenever user deletes a Chinese character and its spelling string -// in these fixed lemmas, all fixed lemmas will be merged together into a unit -// named ComposingPhrase with a lemma id kLemmaIdComposing, and this composing -// phrase will be the first lemma in the sentence. Because it contains some -// modified lemmas (by deleting a character), these merged lemmas are called -// sub lemmas (sublma), and each of them are represented individually, so that -// when user deletes Pinyin characters from the end, these sub lemmas can also -// be unlocked one by one. -typedef struct { - uint16 spl_ids[kMaxRowNum]; - uint16 spl_start[kMaxRowNum]; - char16 chn_str[kMaxRowNum]; // Chinese string. - uint16 sublma_start[kMaxRowNum]; // Counted in Chinese characters. - size_t sublma_num; - uint16 length; // Counted in Chinese characters. -} ComposingPhrase, *TComposingPhrase; -class MatrixSearch { -private: - // If it is true, prediction list by string whose length is greater than 1 - // will be limited to a reasonable number. - static const bool kPredictLimitGt1 = false; - // If it is true, the engine will prefer long history based prediction, - // for example, when user inputs "BeiJing", we prefer "DaXue", etc., which are - // based on the two-character history. - static const bool kPreferLongHistoryPredict = true; - // If it is true, prediction will only be based on user dictionary. this flag - // is for debug purpose. - static const bool kOnlyUserDictPredict = false; - // The maximum buffer to store LmaPsbItems. - static const size_t kMaxLmaPsbItems = 1450; - // How many rows for each step. - static const size_t kMaxNodeARow = 5; - // The maximum length of the sentence candidates counted in chinese - // characters - static const size_t kMaxSentenceLength = 16; - // The size of the matrix node pool. - static const size_t kMtrxNdPoolSize = 200; - // The size of the DMI node pool. - static const size_t kDmiPoolSize = 800; - // Used to indicate whether this object has been initialized. - bool inited_; - // Spelling trie. - const SpellingTrie* spl_trie_; - // Used to indicate this switcher status: when "xian" is parseed, should - // "xi an" also be extended. Default is false. - // These cases include: xia, xian, xiang, zhuan, jiang..., etc. The string - // should be valid for a FULL spelling, or a combination of two spellings, - // first of which is a FULL id too. So even it is true, "da" will never be - // split into "d a", because "d" is not a full spelling id. - bool xi_an_enabled_; - // System dictionary. - DictTrie* dict_trie_; - // User dictionary. - AtomDictBase* user_dict_; - // Spelling parser. - SpellingParser* spl_parser_; - // The maximum allowed length of spelling string (such as a Pinyin string). - size_t max_sps_len_; - // The maximum allowed length of a result Chinese string. - size_t max_hzs_len_; - // Pinyin string. Max length: kMaxRowNum - 1 - char pys_[kMaxRowNum]; - // The length of the string that has been decoded successfully. - size_t pys_decoded_len_; - // Shared buffer for multiple purposes. - size_t* share_buf_; - MatrixNode* mtrx_nd_pool_; - PoolPosType mtrx_nd_pool_used_; // How many nodes used in the pool - DictMatchInfo* dmi_pool_; - PoolPosType dmi_pool_used_; // How many items used in the pool - MatrixRow* matrix_; // The first row is for starting - DictExtPara* dep_; // Parameter used to extend DMI nodes. - NPredictItem* npre_items_; // Used to do prediction - size_t npre_items_len_; - // The starting positions and lemma ids for the full sentence candidate. - size_t lma_id_num_; - uint16 lma_start_[kMaxRowNum]; // Counted in spelling ids. - LemmaIdType lma_id_[kMaxRowNum]; - size_t fixed_lmas_; - // If fixed_lmas_ is bigger than i, Element i is used to indicate whether - // the i'th lemma id in lma_id_ is the first candidate for that step. - // If all candidates are the first one for that step, the whole string can be - // decoded by the engine automatically, so no need to add it to user - // dictionary. (We are considering to add it to user dictionary in the - // future). - uint8 fixed_lmas_no1_[kMaxRowNum]; - // Composing phrase - ComposingPhrase c_phrase_; - // If dmi_c_phrase_ is true, the decoder will try to match the - // composing phrase (And definitely it will match successfully). If it - // is false, the decoder will try to match lemmas items in dictionaries. - bool dmi_c_phrase_; - // The starting positions and spelling ids for the first full sentence - // candidate. - size_t spl_id_num_; // Number of splling ids - uint16 spl_start_[kMaxRowNum]; // Starting positions - uint16 spl_id_[kMaxRowNum]; // Spelling ids - // Used to remember the last fixed position, counted in Hanzi. - size_t fixed_hzs_; - // Lemma Items with possibility score, two purposes: - // 1. In Viterbi decoding, this buffer is used to get all possible candidates - // for current step; - // 2. When the search is done, this buffer is used to get candiates from the - // first un-fixed step and show them to the user. - LmaPsbItem lpi_items_[kMaxLmaPsbItems]; - size_t lpi_total_; - // Assign the pointers with NULL. The caller makes sure that all pointers are - // not valid before calling it. This function only will be called in the - // construction function and free_resource(). - void reset_pointers_to_null(); - bool alloc_resource(); - void free_resource(); - // Reset the search space totally. - bool reset_search0(); - // Reset the search space from ch_pos step. For example, if the original - // input Pinyin is "an", reset_search(1) will reset the search space to the - // result of "a". If the given position is out of range, return false. - // if clear_fixed_this_step is true, and the ch_pos step is a fixed step, - // clear its fixed status. if clear_dmi_his_step is true, clear the DMI nodes. - // If clear_mtrx_this_sTep is true, clear the mtrx nodes of this step. - // The DMI nodes will be kept. - // - // Note: this function should not destroy content of pys_. - bool reset_search(size_t ch_pos, bool clear_fixed_this_step, - bool clear_dmi_this_step, bool clear_mtrx_this_step); - // Delete a part of the content in pys_. - void del_in_pys(size_t start, size_t len); - // Delete a spelling id and its corresponding Chinese character, and merge - // the fixed lemmas into the composing phrase. - // del_spl_pos indicates which spelling id needs to be delete. - // This function will update the lemma and spelling segmentation information. - // The caller guarantees that fixed_lmas_ > 0 and del_spl_pos is within - // the fixed lemmas. - void merge_fixed_lmas(size_t del_spl_pos); - // Get spelling start posistions and ids. The result will be stored in - // spl_id_num_, spl_start_[], spl_id_[]. - // fixed_hzs_ will be also assigned. - void get_spl_start_id(); - // Get all lemma ids with match the given spelling id stream(shorter than the - // maximum length of a word). - // If pfullsent is not NULL, means the full sentence candidate may be the - // same with the coming lemma string, if so, remove that lemma. - // The result is sorted in descendant order by the frequency score. - size_t get_lpis(const uint16* splid_str, size_t splid_str_len, - LmaPsbItem* lma_buf, size_t max_lma_buf, - const char16* pfullsent, bool sort_by_psb); - uint16 get_lemma_str(LemmaIdType id_lemma, char16* str_buf, uint16 str_max); - uint16 get_lemma_splids(LemmaIdType id_lemma, uint16* splids, - uint16 splids_max, bool arg_valid); - // Extend a DMI node with a spelling id. ext_len is the length of the rows - // to extend, actually, it is the size of the spelling string of splid. - // return value can be 1 or 0. - // 1 means a new DMI is filled in (dmi_pool_used_ is the next blank DMI in - // the pool). - // 0 means either the dmi node can not be extended with splid, or the splid - // is a Shengmu id, which is only used to get lpi_items, or the result node - // in DictTrie has no son, it is not nccessary to keep the new DMI. - // - // This function modifies the content of lpi_items_ and lpi_total_. - // lpi_items_ is used to get the LmaPsbItem list, lpi_total_ returns the size. - // The function's returned value has no relation with the value of lpi_num. - // - // If dmi == NULL, this function will extend the root node of DictTrie - // - // This function will not change dmi_nd_pool_used_. Please change it after - // calling this function if necessary. - // - // The caller should guarantees that NULL != dep. - size_t extend_dmi(DictExtPara* dep, DictMatchInfo* dmi_s); - // Extend dmi for the composing phrase. - size_t extend_dmi_c(DictExtPara* dep, DictMatchInfo* dmi_s); - // Extend a MatrixNode with the give LmaPsbItem list. - // res_row is the destination row number. - // This function does not change mtrx_nd_pool_used_. Please change it after - // calling this function if necessary. - // return 0 always. - size_t extend_mtrx_nd(MatrixNode* mtrx_nd, LmaPsbItem lpi_items[], - size_t lpi_num, PoolPosType dmi_fr, size_t res_row); - // Try to find a dmi node at step_to position, and the found dmi node should - // match the given spelling id strings. - PoolPosType match_dmi(size_t step_to, uint16 spl_ids[], uint16 spl_id_num); - bool add_char(char ch); - bool prepare_add_char(char ch); - // Called after prepare_add_char, so the input char has been saved. - bool add_char_qwerty(); - // Prepare candidates from the last fixed hanzi position. - void prepare_candidates(); - // Is the character in step pos a splitter character? - // The caller guarantees that the position is valid. - bool is_split_at(uint16 pos); - void fill_dmi(DictMatchInfo* dmi, MileStoneHandle* handles, - PoolPosType dmi_fr, - uint16 spl_id, uint16 node_num, unsigned char dict_level, - bool splid_end_split, unsigned char splstr_len, - unsigned char all_full_id); - size_t inner_predict(const char16 fixed_scis_ids[], uint16 scis_num, - char16 predict_buf[][kMaxPredictSize + 1], - size_t buf_len); - // Add the first candidate to the user dictionary. - bool try_add_cand0_to_userdict(); - // Add a user lemma to the user dictionary. This lemma is a subset of - // candidate 0. lma_from is from which lemma in lma_ids_, lma_num is the - // number of lemmas to be combined together as a new lemma. The caller - // gurantees that the combined new lemma's length is less or equal to - // kMaxLemmaSize. - bool add_lma_to_userdict(uint16 lma_from, uint16 lma_num, float score); - // Update dictionary frequencies. - void update_dict_freq(); - void debug_print_dmi(PoolPosType dmi_pos, uint16 nest_level); -public: - MatrixSearch(); - ~MatrixSearch(); - bool init(const char* fn_sys_dict, const char* fn_usr_dict); - bool init_fd(int sys_fd, long start_offset, long length, - const char* fn_usr_dict); - void init_user_dictionary(const char* fn_usr_dict); - bool is_user_dictionary_enabled() const; - void set_max_lens(size_t max_sps_len, size_t max_hzs_len); - void close(); - void flush_cache(); - void set_xi_an_switch(bool xi_an_enabled); - bool get_xi_an_switch(); - // Reset the search space. Equivalent to reset_search(0). - // If inited, always return true; - bool reset_search(); - // Search a Pinyin string. - // Return value is the position successfully parsed. - size_t search(const char* py, size_t py_len); - // Used to delete something in the Pinyin string kept by the engine, and do - // a re-search. - // Return value is the new length of Pinyin string kept by the engine which - // is parsed successfully. - // If is_pos_in_splid is false, pos is used to indicate that pos-th Pinyin - // character needs to be deleted. If is_pos_in_splid is true, all Pinyin - // characters for pos-th spelling id needs to be deleted. - // If the deleted character(s) is just after a fixed lemma or sub lemma in - // composing phrase, clear_fixed_this_step indicates whether we needs to - // unlock the last fixed lemma or sub lemma. - // If is_pos_in_splid is false, and pos-th character is in the range for the - // fixed lemmas or composing string, this function will do nothing and just - // return the result of the previous search. - size_t delsearch(size_t pos, bool is_pos_in_splid, - bool clear_fixed_this_step); - // Get the number of candiates, called after search(). - size_t get_candidate_num(); - // Get the Pinyin string stored by the engine. - // *decoded_len returns the length of the successfully decoded string. - const char* get_pystr(size_t* decoded_len); - // Get the spelling boundaries for the first sentence candidate. - // Number of spellings will be returned. The number of valid elements in - // spl_start is one more than the return value because the last one is used - // to indicate the beginning of the next un-input speling. - // For a Pinyin "women", the returned value is 2, spl_start is [0, 2, 5] . - size_t get_spl_start(const uint16*& spl_start); - // Get one candiate string. If full sentence candidate is available, it will - // be the first one. - char16* get_candidate(size_t cand_id, char16* cand_str, size_t max_len); - // Get the first candiate, which is a "full sentence". - // retstr_len is not NULL, it will be used to return the string length. - // If only_unfixed is true, only unfixed part will be fetched. - char16* get_candidate0(char16* cand_str, size_t max_len, - uint16* retstr_len, bool only_unfixed); - // Choose a candidate. The decoder will do a search after the fixed position. - size_t choose(size_t cand_id); - // Cancel the last choosing operation, and return the new number of choices. - size_t cancel_last_choice(); - // Get the length of fixed Hanzis. - size_t get_fixedlen(); - size_t get_predicts(const char16 fixed_buf[], - char16 predict_buf[][kMaxPredictSize + 1], - size_t buf_len); -}; -} // namespace ime_pinyin -#endif // PINYINIME_ANDPY_INCLUDE_MATRIXSEARCH_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/mystdlib.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/mystdlib.cpp deleted file mode 100644 index 1d3ff01..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/mystdlib.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -namespace ime_pinyin { -// For debug purpose. You can add a fixed version of qsort and bsearch functions -// here so that the output will be totally the same under different platforms. -void myqsort(void* p, size_t n, size_t es, - int (*cmp)(const void*, const void*)) { - qsort(p, n, es, cmp); -} -void* mybsearch(const void* k, const void* b, - size_t n, size_t es, - int (*cmp)(const void*, const void*)) { - return bsearch(k, b, n, es, cmp); -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/mystdlib.h b/Widget/base/Virtual_Keyboard/googlepinyin/mystdlib.h deleted file mode 100644 index dd9e0cb..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/mystdlib.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_MYSTDLIB_H__ -#define PINYINIME_INCLUDE_MYSTDLIB_H__ -#include -namespace ime_pinyin { -void myqsort(void* p, size_t n, size_t es, - int (*cmp)(const void*, const void*)); -void* mybsearch(const void* key, const void* base, - size_t nmemb, size_t size, - int (*compar)(const void*, const void*)); -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_MYSTDLIB_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/ngram.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/ngram.cpp deleted file mode 100644 index 4f2b64e..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/ngram.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "ngram.h" -#include -#include -#include -#include -#include -#include "mystdlib.h" -namespace ime_pinyin { -#define ADD_COUNT 0.3 -int comp_double(const void* p1, const void* p2) { - if (*static_cast(p1) < *static_cast(p2)) - return -1; - if (*static_cast(p1) > *static_cast(p2)) - return 1; - return 0; -} -inline double distance(double freq, double code) { - // return fabs(freq - code); - return freq * fabs(log(freq) - log(code)); -} -// Find the index of the code value which is nearest to the given freq -int qsearch_nearest(double code_book[], double freq, int start, int end) { - if (start == end) - return start; - if (start + 1 == end) { - if (distance(freq, code_book[end]) > distance(freq, code_book[start])) - return start; - return end; - } - int mid = (start + end) / 2; - if (code_book[mid] > freq) - return qsearch_nearest(code_book, freq, start, mid); - else - return qsearch_nearest(code_book, freq, mid, end); -} -size_t update_code_idx(double freqs[], size_t num, double code_book[], - CODEBOOK_TYPE* code_idx) { - size_t changed = 0; - for (size_t pos = 0; pos < num; pos++) { - CODEBOOK_TYPE idx; - idx = qsearch_nearest(code_book, freqs[pos], 0, kCodeBookSize - 1); - if (idx != code_idx[pos]) - changed++; - code_idx[pos] = idx; - } - return changed; -} -double recalculate_kernel(double freqs[], size_t num, double code_book[], - CODEBOOK_TYPE* code_idx) { - double ret = 0; - size_t* item_num = new size_t[kCodeBookSize]; - assert(item_num); - memset(item_num, 0, sizeof(size_t) * kCodeBookSize); - double* cb_new = new double[kCodeBookSize]; - assert(cb_new); - memset(cb_new, 0, sizeof(double) * kCodeBookSize); - for (size_t pos = 0; pos < num; pos++) { - ret += distance(freqs[pos], code_book[code_idx[pos]]); - cb_new[code_idx[pos]] += freqs[pos]; - item_num[code_idx[pos]] += 1; - } - for (size_t code = 0; code < kCodeBookSize; code++) { - assert(item_num[code] > 0); - code_book[code] = cb_new[code] / item_num[code]; - } - delete[] item_num; - delete[] cb_new; - return ret; -} -void iterate_codes(double freqs[], size_t num, double code_book[], - CODEBOOK_TYPE* code_idx) { - size_t iter_num = 0; - double delta_last = 0; - do { - size_t changed = update_code_idx(freqs, num, code_book, code_idx); - double delta = recalculate_kernel(freqs, num, code_book, code_idx); - if (kPrintDebug0) { - printf("---Unigram codebook iteration: %zu : %zu, %.9f\n", - iter_num, changed, delta); - } - iter_num++; - if (iter_num > 1 && - (delta == 0 || fabs(delta_last - delta) / fabs(delta) < 0.000000001)) - break; - delta_last = delta; - } - while (true); -} -NGram* NGram::instance_ = NULL; -NGram::NGram() { - initialized_ = false; - idx_num_ = 0; - lma_freq_idx_ = NULL; - sys_score_compensation_ = 0; -#ifdef ___BUILD_MODEL___ - freq_codes_df_ = NULL; -#endif - freq_codes_ = NULL; -} -NGram::~NGram() { - if (NULL != lma_freq_idx_) - free(lma_freq_idx_); -#ifdef ___BUILD_MODEL___ - if (NULL != freq_codes_df_) - free(freq_codes_df_); -#endif - if (NULL != freq_codes_) - free(freq_codes_); -} -NGram& NGram::get_instance() { - if (NULL == instance_) - instance_ = new NGram(); - return *instance_; -} -bool NGram::save_ngram(FILE* fp) { - if (!initialized_ || NULL == fp) - return false; - if (0 == idx_num_ || NULL == freq_codes_ || NULL == lma_freq_idx_) - return false; - if (fwrite(&idx_num_, sizeof(uint32), 1, fp) != 1) - return false; - if (fwrite(freq_codes_, sizeof(LmaScoreType), kCodeBookSize, fp) != - kCodeBookSize) - return false; - if (fwrite(lma_freq_idx_, sizeof(CODEBOOK_TYPE), idx_num_, fp) != idx_num_) - return false; - return true; -} -bool NGram::load_ngram(FILE* fp) { - if (NULL == fp) - return false; - initialized_ = false; - if (fread(&idx_num_, sizeof(uint32), 1, fp) != 1) - return false; - if (NULL != lma_freq_idx_) - free(lma_freq_idx_); - if (NULL != freq_codes_) - free(freq_codes_); - lma_freq_idx_ = static_cast(malloc(idx_num_ * sizeof(CODEBOOK_TYPE))); - freq_codes_ = static_cast(malloc(kCodeBookSize * sizeof(LmaScoreType))); - if (NULL == lma_freq_idx_ || NULL == freq_codes_) - return false; - if (fread(freq_codes_, sizeof(LmaScoreType), kCodeBookSize, fp) != - kCodeBookSize) - return false; - if (fread(lma_freq_idx_, sizeof(CODEBOOK_TYPE), idx_num_, fp) != idx_num_) - return false; - initialized_ = true; - total_freq_none_sys_ = 0; - return true; -} -void NGram::set_total_freq_none_sys(size_t freq_none_sys) { - total_freq_none_sys_ = freq_none_sys; - if (0 == total_freq_none_sys_) { - sys_score_compensation_ = 0; - } - else { - double factor = static_cast(kSysDictTotalFreq) / (kSysDictTotalFreq + total_freq_none_sys_); - sys_score_compensation_ = static_cast( - log(factor) * kLogValueAmplifier); - } -} -// The caller makes sure this oject is initialized. -float NGram::get_uni_psb(LemmaIdType lma_id) { - return static_cast(freq_codes_[lma_freq_idx_[lma_id]]) + - sys_score_compensation_; -} -float NGram::convert_psb_to_score(double psb) { - float score = static_cast( - log(psb) * static_cast(kLogValueAmplifier)); - if (score > static_cast(kMaxScore)) { - score = static_cast(kMaxScore); - } - return score; -} -#ifdef ___BUILD_MODEL___ -bool NGram::build_unigram(LemmaEntry* lemma_arr, size_t lemma_num, - LemmaIdType next_idx_unused) { - if (NULL == lemma_arr || 0 == lemma_num || next_idx_unused <= 1) - return false; - double total_freq = 0; - double* freqs = new double[next_idx_unused]; - if (NULL == freqs) - return false; - freqs[0] = ADD_COUNT; - total_freq += freqs[0]; - LemmaIdType idx_now = 0; - for (size_t pos = 0; pos < lemma_num; pos++) { - if (lemma_arr[pos].idx_by_hz == idx_now) - continue; - idx_now++; - assert(lemma_arr[pos].idx_by_hz == idx_now); - freqs[idx_now] = lemma_arr[pos].freq; - if (freqs[idx_now] <= 0) - freqs[idx_now] = 0.3; - total_freq += freqs[idx_now]; - } - double max_freq = 0; - idx_num_ = idx_now + 1; - assert(idx_now + 1 == next_idx_unused); - for (size_t pos = 0; pos < idx_num_; pos++) { - freqs[pos] = freqs[pos] / total_freq; - assert(freqs[pos] > 0); - if (freqs[pos] > max_freq) - max_freq = freqs[pos]; - } - // calculate the code book - if (NULL == freq_codes_df_) - freq_codes_df_ = new double[kCodeBookSize]; - assert(freq_codes_df_); - memset(freq_codes_df_, 0, sizeof(double) * kCodeBookSize); - if (NULL == freq_codes_) - freq_codes_ = new LmaScoreType[kCodeBookSize]; - assert(freq_codes_); - memset(freq_codes_, 0, sizeof(LmaScoreType) * kCodeBookSize); - size_t freq_pos = 0; - for (size_t code_pos = 0; code_pos < kCodeBookSize; code_pos++) { - bool found = true; - while (found) { - found = false; - double cand = freqs[freq_pos]; - for (size_t i = 0; i < code_pos; i++) - if (freq_codes_df_[i] == cand) { - found = true; - break; - } - if (found) - freq_pos++; - } - freq_codes_df_[code_pos] = freqs[freq_pos]; - freq_pos++; - } - myqsort(freq_codes_df_, kCodeBookSize, sizeof(double), comp_double); - if (NULL == lma_freq_idx_) - lma_freq_idx_ = new CODEBOOK_TYPE[idx_num_]; - assert(lma_freq_idx_); - iterate_codes(freqs, idx_num_, freq_codes_df_, lma_freq_idx_); - delete[] freqs; - if (kPrintDebug0) { - printf("\n------Language Model Unigram Codebook------\n"); - } - for (size_t code_pos = 0; code_pos < kCodeBookSize; code_pos++) { - double log_score = log(freq_codes_df_[code_pos]); - float final_score = convert_psb_to_score(freq_codes_df_[code_pos]); - if (kPrintDebug0) { - printf("code:%d, probability:%.9f, log score:%.3f, final score: %.3f\n", - code_pos, freq_codes_df_[code_pos], log_score, final_score); - } - freq_codes_[code_pos] = static_cast(final_score); - } - initialized_ = true; - return true; -} -#endif -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/ngram.h b/Widget/base/Virtual_Keyboard/googlepinyin/ngram.h deleted file mode 100644 index 37c9a72..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/ngram.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_NGRAM_H__ -#define PINYINIME_INCLUDE_NGRAM_H__ -#include -#include -#include "./dictdef.h" -namespace ime_pinyin { -typedef unsigned char CODEBOOK_TYPE; -static const size_t kCodeBookSize = 256; -class NGram { -public: - // The maximum score of a lemma item. - static const LmaScoreType kMaxScore = 0x3fff; - // In order to reduce the storage size, the original log value is amplified by - // kScoreAmplifier, and we use LmaScoreType to store. - // After this process, an item with a lower score has a higher frequency. - static const int kLogValueAmplifier = -800; - // System words' total frequency. It is not the real total frequency, instead, - // It is only used to adjust system lemmas' scores when the user dictionary's - // total frequency changes. - // In this version, frequencies of system lemmas are fixed. We are considering - // to make them changable in next version. - static const size_t kSysDictTotalFreq = 100000000; -private: - static NGram* instance_; - bool initialized_; - uint32 idx_num_; - size_t total_freq_none_sys_; - // Score compensation for system dictionary lemmas. - // Because after user adds some user lemmas, the total frequency changes, and - // we use this value to normalize the score. - float sys_score_compensation_; -#ifdef ___BUILD_MODEL___ - double* freq_codes_df_; -#endif - LmaScoreType* freq_codes_; - CODEBOOK_TYPE* lma_freq_idx_; -public: - NGram(); - ~NGram(); - static NGram& get_instance(); - bool save_ngram(FILE* fp); - bool load_ngram(FILE* fp); - // Set the total frequency of all none system dictionaries. - void set_total_freq_none_sys(size_t freq_none_sys); - float get_uni_psb(LemmaIdType lma_id); - // Convert a probability to score. Actually, the score will be limited to - // kMaxScore, but at runtime, we also need float expression to get accurate - // value of the score. - // After the conversion, a lower score indicates a higher probability of the - // item. - static float convert_psb_to_score(double psb); -#ifdef ___BUILD_MODEL___ - // For constructing the unigram mode model. - bool build_unigram(LemmaEntry* lemma_arr, size_t num, - LemmaIdType next_idx_unused); -#endif -}; -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_NGRAM_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/pinyinime.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/pinyinime.cpp deleted file mode 100644 index dffa986..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/pinyinime.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "pinyinime.h" -#include -#include "dicttrie.h" -#include "matrixsearch.h" -#include "spellingtrie.h" -#ifdef __cplusplus -extern "C" { -#endif -using namespace ime_pinyin; -// The maximum number of the prediction items. -static const size_t kMaxPredictNum = 500; -// Used to search Pinyin string and give the best candidate. -MatrixSearch* matrix_search = NULL; -char16 predict_buf[kMaxPredictNum][kMaxPredictSize + 1]; -bool im_open_decoder(const char* fn_sys_dict, const char* fn_usr_dict) { - if (NULL != matrix_search) - delete matrix_search; - matrix_search = new MatrixSearch(); - if (NULL == matrix_search) { - return false; - } - return matrix_search->init(fn_sys_dict, fn_usr_dict); -} -bool im_open_decoder_fd(int sys_fd, long start_offset, long length, - const char* fn_usr_dict) { - if (NULL != matrix_search) - delete matrix_search; - matrix_search = new MatrixSearch(); - if (NULL == matrix_search) - return false; - return matrix_search->init_fd(sys_fd, start_offset, length, fn_usr_dict); -} -void im_close_decoder() { - if (NULL != matrix_search) { - matrix_search->close(); - delete matrix_search; - } - matrix_search = NULL; -} -void im_set_max_lens(size_t max_sps_len, size_t max_hzs_len) { - if (NULL != matrix_search) { - matrix_search->set_max_lens(max_sps_len, max_hzs_len); - } -} -void im_flush_cache() { - if (NULL != matrix_search) - matrix_search->flush_cache(); -} -// To be updated. -size_t im_search(const char* pybuf, size_t pylen) { - if (NULL == matrix_search) - return 0; - matrix_search->search(pybuf, pylen); - return matrix_search->get_candidate_num(); -} -size_t im_delsearch(size_t pos, bool is_pos_in_splid, - bool clear_fixed_this_step) { - if (NULL == matrix_search) - return 0; - matrix_search->delsearch(pos, is_pos_in_splid, clear_fixed_this_step); - return matrix_search->get_candidate_num(); -} -void im_reset_search() { - if (NULL == matrix_search) - return; - matrix_search->reset_search(); -} -// To be removed -size_t im_add_letter(char) { - return 0; -} -const char* im_get_sps_str(size_t* decoded_len) { - if (NULL == matrix_search) - return NULL; - return matrix_search->get_pystr(decoded_len); -} -char16* im_get_candidate(size_t cand_id, char16* cand_str, - size_t max_len) { - if (NULL == matrix_search) - return NULL; - return matrix_search->get_candidate(cand_id, cand_str, max_len); -} -size_t im_get_spl_start_pos(const uint16*& spl_start) { - if (NULL == matrix_search) - return 0; - return matrix_search->get_spl_start(spl_start); -} -size_t im_choose(size_t choice_id) { - if (NULL == matrix_search) - return 0; - return matrix_search->choose(choice_id); -} -size_t im_cancel_last_choice() { - if (NULL == matrix_search) - return 0; - return matrix_search->cancel_last_choice(); -} -size_t im_get_fixed_len() { - if (NULL == matrix_search) - return 0; - return matrix_search->get_fixedlen(); -} -// To be removed -bool im_cancel_input() { - return true; -} -size_t im_get_predicts(const char16* his_buf, - char16 (*&pre_buf)[kMaxPredictSize + 1]) { - if (NULL == his_buf) - return 0; - size_t fixed_len = utf16_strlen(his_buf); - const char16* fixed_ptr = his_buf; - if (fixed_len > kMaxPredictSize) { - fixed_ptr += fixed_len - kMaxPredictSize; - fixed_len = kMaxPredictSize; - } - pre_buf = predict_buf; - return matrix_search->get_predicts(his_buf, pre_buf, kMaxPredictNum); -} -void im_enable_shm_as_szm(bool enable) { - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - spl_trie.szm_enable_shm(enable); -} -void im_enable_ym_as_szm(bool enable) { - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - spl_trie.szm_enable_ym(enable); -} -void im_init_user_dictionary(const char* fn_usr_dict) { - if (!matrix_search) - return; - matrix_search->flush_cache(); - matrix_search->init_user_dictionary(fn_usr_dict); -} -bool im_is_user_dictionary_enabled(void) { - return NULL != matrix_search ? matrix_search->is_user_dictionary_enabled() : false; -} -#ifdef __cplusplus -} -#endif diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/pinyinime.h b/Widget/base/Virtual_Keyboard/googlepinyin/pinyinime.h deleted file mode 100644 index 703e9a1..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/pinyinime.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_ANDPYIME_H__ -#define PINYINIME_INCLUDE_ANDPYIME_H__ -#include -#include "./dictdef.h" -#ifdef __cplusplus -extern "C" { -#endif -namespace ime_pinyin { -/** - * Open the decoder engine via the system and user dictionary file names. - * - * @param fn_sys_dict The file name of the system dictionary. - * @param fn_usr_dict The file name of the user dictionary. - * @return true if open the decoder engine successfully. - */ -bool im_open_decoder(const char* fn_sys_dict, const char* fn_usr_dict); -/** - * Open the decoder engine via the system dictionary FD and user dictionary - * file name. Because on Android, the system dictionary is embedded in the - * whole application apk file. - * - * @param sys_fd The file in which the system dictionary is embedded. - * @param start_offset The starting position of the system dictionary in the - * file sys_fd. - * @param length The length of the system dictionary in the file sys_fd, - * counted in byte. - * @return true if succeed. - */ -bool im_open_decoder_fd(int sys_fd, long start_offset, long length, - const char* fn_usr_dict); -/** - * Close the decoder engine. - */ -void im_close_decoder(); -/** - * Set maximum limitations for decoding. If this function is not called, - * default values will be used. For example, due to screen size limitation, - * the UI engine of the IME can only show a certain number of letters(input) - * to decode, and a certain number of Chinese characters(output). If after - * user adds a new letter, the input or the output string is longer than the - * limitations, the engine will discard the recent letter. - * - * @param max_sps_len Maximum length of the spelling string(Pinyin string). - * @max_hzs_len Maximum length of the decoded Chinese character string. - */ -void im_set_max_lens(size_t max_sps_len, size_t max_hzs_len); -/** - * Flush cached data to persistent memory. Because at runtime, in order to - * achieve best performance, some data is only store in memory. - */ -void im_flush_cache(); -/** - * Use a spelling string(Pinyin string) to search. The engine will try to do - * an incremental search based on its previous search result, so if the new - * string has the same prefix with the previous one stored in the decoder, - * the decoder will only continue the search from the end of the prefix. - * If the caller needs to do a brand new search, please call im_reset_search() - * first. Calling im_search() is equivalent to calling im_add_letter() one by - * one. - * - * @param sps_buf The spelling string buffer to decode. - * @param sps_len The length of the spelling string buffer. - * @return The number of candidates. - */ -size_t im_search(const char* sps_buf, size_t sps_len); -/** - * Make a delete operation in the current search result, and make research if - * necessary. - * - * @param pos The posistion of char in spelling string to delete, or the - * position of spelling id in result string to delete. - * @param is_pos_in_splid Indicate whether the pos parameter is the position - * in the spelling string, or the position in the result spelling id string. - * @return The number of candidates. - */ -size_t im_delsearch(size_t pos, bool is_pos_in_splid, - bool clear_fixed_this_step); -/** - * Reset the previous search result. - */ -void im_reset_search(); -/** - * Add a Pinyin letter to the current spelling string kept by decoder. If the - * decoder fails in adding the letter, it will do nothing. im_get_sps_str() - * can be used to get the spelling string kept by decoder currently. - * - * @param ch The letter to add. - * @return The number of candidates. - */ -size_t im_add_letter(char ch); -/** - * Get the spelling string kept by the decoder. - * - * @param decoded_len Used to return how many characters in the spelling - * string is successfully parsed. - * @return The spelling string kept by the decoder. - */ -const char* im_get_sps_str(size_t* decoded_len); -/** - * Get a candidate(or choice) string. - * - * @param cand_id The id to get a candidate. Started from 0. Usually, id 0 - * is a sentence-level candidate. - * @param cand_str The buffer to store the candidate. - * @param max_len The maximum length of the buffer. - * @return cand_str if succeeds, otherwise NULL. - */ -char16* im_get_candidate(size_t cand_id, char16* cand_str, - size_t max_len); -/** - * Get the segmentation information(the starting positions) of the spelling - * string. - * - * @param spl_start Used to return the starting posistions. - * @return The number of spelling ids. If it is L, there will be L+1 valid - * elements in spl_start, and spl_start[L] is the posistion after the end of - * the last spelling id. - */ -size_t im_get_spl_start_pos(const uint16*& spl_start); -/** - * Choose a candidate and make it fixed. If the candidate does not match - * the end of all spelling ids, new candidates will be provided from the - * first unfixed position. If the candidate matches the end of the all - * spelling ids, there will be only one new candidates, or the whole fixed - * sentence. - * - * @param cand_id The id of candidate to select and make it fixed. - * @return The number of candidates. If after the selection, the whole result - * string has been fixed, there will be only one candidate. - */ -size_t im_choose(size_t cand_id); -/** - * Cancel the last selection, or revert the last operation of im_choose(). - * - * @return The number of candidates. - */ -size_t im_cancel_last_choice(); -/** - * Get the number of fixed spelling ids, or Chinese characters. - * - * @return The number of fixed spelling ids, of Chinese characters. - */ -size_t im_get_fixed_len(); -/** - * Cancel the input state and reset the search workspace. - */ -bool im_cancel_input(); -/** - * Get prediction candiates based on the given fixed Chinese string as the - * history. - * - * @param his_buf The history buffer to do the prediction. It should be ended - * with '\0'. - * @param pre_buf Used to return prediction result list. - * @return The number of predicted result string. - */ -size_t im_get_predicts(const char16* his_buf, - char16 (*&pre_buf)[kMaxPredictSize + 1]); -/** - * Enable Shengmus in ShouZiMu mode. - */ -void im_enable_shm_as_szm(bool enable); -/** - * Enable Yunmus in ShouZiMu mode. - */ -void im_enable_ym_as_szm(bool enable); -/** - * Initializes or uninitializes the user dictionary. - * - * @param fn_usr_dict The file name of the user dictionary. - */ -void im_init_user_dictionary(const char* fn_usr_dict); -/** - * Returns the current status of user dictinary. - */ -bool im_is_user_dictionary_enabled(void); -} // namespace ime_pinyin -#ifdef __cplusplus -} -#endif -#endif // PINYINIME_INCLUDE_ANDPYIME_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/searchutility.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/searchutility.cpp deleted file mode 100644 index 0605208..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/searchutility.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "searchutility.h" -#include -#include "mystdlib.h" -namespace ime_pinyin { -bool is_system_lemma(LemmaIdType lma_id) { - return (0 < lma_id && lma_id <= kSysDictIdEnd); -} -bool is_user_lemma(LemmaIdType lma_id) { - return (kUserDictIdStart <= lma_id && lma_id <= kUserDictIdEnd); -} -bool is_composing_lemma(LemmaIdType lma_id) { - return (kLemmaIdComposing == lma_id); -} -int cmp_lpi_with_psb(const void* p1, const void* p2) { - if ((static_cast(p1))->psb > - (static_cast(p2))->psb) - return 1; - if ((static_cast(p1))->psb < - (static_cast(p2))->psb) - return -1; - return 0; -} -int cmp_lpi_with_unified_psb(const void* p1, const void* p2) { - const LmaPsbItem* item1 = static_cast(p1); - const LmaPsbItem* item2 = static_cast(p2); - // The real unified psb is psb1 / lma_len1 and psb2 * lma_len2 - // But we use psb1 * lma_len2 and psb2 * lma_len1 to get better - // precision. - size_t up1 = item1->psb * (item2->lma_len); - size_t up2 = item2->psb * (item1->lma_len); - if (up1 < up2) { - return -1; - } - if (up1 > up2) { - return 1; - } - return 0; -} -int cmp_lpi_with_id(const void* p1, const void* p2) { - if ((static_cast(p1))->id < - (static_cast(p2))->id) - return -1; - if ((static_cast(p1))->id > - (static_cast(p2))->id) - return 1; - return 0; -} -int cmp_lpi_with_hanzi(const void* p1, const void* p2) { - if ((static_cast(p1))->hanzi < - (static_cast(p2))->hanzi) - return -1; - if ((static_cast(p1))->hanzi > - (static_cast(p2))->hanzi) - return 1; - return 0; -} -int cmp_lpsi_with_str(const void* p1, const void* p2) { - return utf16_strcmp((static_cast(p1))->str, - (static_cast(p2))->str); -} -int cmp_hanzis_1(const void* p1, const void* p2) { - if (*static_cast(p1) < - *static_cast(p2)) - return -1; - if (*static_cast(p1) > - *static_cast(p2)) - return 1; - return 0; -} -int cmp_hanzis_2(const void* p1, const void* p2) { - return utf16_strncmp(static_cast(p1), - static_cast(p2), 2); -} -int cmp_hanzis_3(const void* p1, const void* p2) { - return utf16_strncmp(static_cast(p1), - static_cast(p2), 3); -} -int cmp_hanzis_4(const void* p1, const void* p2) { - return utf16_strncmp(static_cast(p1), - static_cast(p2), 4); -} -int cmp_hanzis_5(const void* p1, const void* p2) { - return utf16_strncmp(static_cast(p1), - static_cast(p2), 5); -} -int cmp_hanzis_6(const void* p1, const void* p2) { - return utf16_strncmp(static_cast(p1), - static_cast(p2), 6); -} -int cmp_hanzis_7(const void* p1, const void* p2) { - return utf16_strncmp(static_cast(p1), - static_cast(p2), 7); -} -int cmp_hanzis_8(const void* p1, const void* p2) { - return utf16_strncmp(static_cast(p1), - static_cast(p2), 8); -} -int cmp_npre_by_score(const void* p1, const void* p2) { - if ((static_cast(p1))->psb > - (static_cast(p2))->psb) - return 1; - if ((static_cast(p1))->psb < - (static_cast(p2))->psb) - return -1; - return 0; -} -int cmp_npre_by_hislen_score(const void* p1, const void* p2) { - if ((static_cast(p1))->his_len < - (static_cast(p2))->his_len) - return 1; - if ((static_cast(p1))->his_len > - (static_cast(p2))->his_len) - return -1; - if ((static_cast(p1))->psb > - (static_cast(p2))->psb) - return 1; - if ((static_cast(p1))->psb < - (static_cast(p2))->psb) - return -1; - return 0; -} -int cmp_npre_by_hanzi_score(const void* p1, const void* p2) { - int ret_v = (utf16_strncmp((static_cast(p1))->pre_hzs, - (static_cast(p2))->pre_hzs, kMaxPredictSize)); - if (0 != ret_v) - return ret_v; - if ((static_cast(p1))->psb > - (static_cast(p2))->psb) - return 1; - if ((static_cast(p1))->psb < - (static_cast(p2))->psb) - return -1; - return 0; -} -size_t remove_duplicate_npre(NPredictItem* npre_items, size_t npre_num) { - if (NULL == npre_items || 0 == npre_num) - return 0; - myqsort(npre_items, npre_num, sizeof(NPredictItem), cmp_npre_by_hanzi_score); - size_t remain_num = 1; // The first one is reserved. - for (size_t pos = 1; pos < npre_num; pos++) { - if (utf16_strncmp(npre_items[pos].pre_hzs, - npre_items[remain_num - 1].pre_hzs, - kMaxPredictSize) != 0) { - if (remain_num != pos) { - npre_items[remain_num] = npre_items[pos]; - } - remain_num++; - } - } - return remain_num; -} -size_t align_to_size_t(size_t size) { - size_t s = sizeof(size_t); - return (size + s - 1) / s * s; -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/searchutility.h b/Widget/base/Virtual_Keyboard/googlepinyin/searchutility.h deleted file mode 100644 index 605ef01..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/searchutility.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_ANDPY_INCLUDE_SEARCHCOMMON_H__ -#define PINYINIME_ANDPY_INCLUDE_SEARCHCOMMON_H__ -#include -#include "./spellingtrie.h" -namespace ime_pinyin { -// Type used to identify the size of a pool, such as id pool, etc. -typedef uint16 PoolPosType; -// Type used to identify a parsing mile stone in an atom dictionary. -typedef uint16 MileStoneHandle; -// Type used to express a lemma and its probability score. -typedef struct { - size_t id : (kLemmaIdSize * 8); - size_t lma_len : 4; - uint16 psb; // The score, the lower psb, the higher possibility. - // For single character items, we may also need Hanzi. - // For multiple characer items, ignore it. - char16 hanzi; -} LmaPsbItem, *PLmaPsbItem; -// LmaPsbItem extended with string. -typedef struct { - LmaPsbItem lpi; - char16 str[kMaxLemmaSize + 1]; -} LmaPsbStrItem, *PLmaPsbStrItem; -typedef struct { - float psb; - char16 pre_hzs[kMaxPredictSize]; - uint16 his_len; // The length of the history used to do the prediction. -} NPredictItem, *PNPredictItem; -// Parameter structure used to extend in a dictionary. All dictionaries -// receives the same DictExtPara and a dictionary specific MileStoneHandle for -// extending. -// -// When the user inputs a new character, AtomDictBase::extend_dict() will be -// called at least once for each dictionary. -// -// For example, when the user inputs "wm", extend_dict() will be called twice, -// and the DictExtPara parameter are as follows respectively: -// 1. splids = {w, m}; splids_extended = 1; ext_len = 1; step_no = 1; -// splid_end_split = false; id_start = wa(the first id start with 'w'); -// id_num = number of ids starting with 'w'. -// 2. splids = {m}; splids_extended = 0; ext_len = 1; step_no = 1; -// splid_end_split = false; id_start = wa; id_num = number of ids starting with -// 'w'. -// -// For string "women", one of the cases of the DictExtPara parameter is: -// splids = {wo, men}, splids_extended = 1, ext_len = 3 (length of "men"), -// step_no = 4; splid_end_split = false; id_start = men, id_num = 1. -// -typedef struct { - // Spelling ids for extending, there are splids_extended + 1 ids in the - // buffer. - // For a normal lemma, there can only be kMaxLemmaSize spelling ids in max, - // but for a composing phrase, there can kMaxSearchSteps spelling ids. - uint16 splids[kMaxSearchSteps]; - // Number of ids that have been used before. splids[splids_extended] is the - // newly added id for the current extension. - uint16 splids_extended; - // The step span of the extension. It is also the size of the string for - // the newly added spelling id. - uint16 ext_len; - // The step number for the current extension. It is also the ending position - // in the input Pinyin string for the substring of spelling ids in splids[]. - // For example, when the user inputs "women", step_no = 4. - // This parameter may useful to manage the MileStoneHandle list for each - // step. When the user deletes a character from the string, MileStoneHandle - // objects for the the steps after that character should be reset; when the - // user begins a new string, all MileStoneHandle objects should be reset. - uint16 step_no; - // Indicate whether the newly added spelling ends with a splitting character - bool splid_end_split; - // If the newly added id is a half id, id_start is the first id of the - // corresponding full ids; if the newly added id is a full id, id_start is - // that id. - uint16 id_start; - // If the newly added id is a half id, id_num is the number of corresponding - // ids; if it is a full id, id_num == 1. - uint16 id_num; -} DictExtPara, *PDictExtPara; -bool is_system_lemma(LemmaIdType lma_id); -bool is_user_lemma(LemmaIdType lma_id); -bool is_composing_lemma(LemmaIdType lma_id); -int cmp_lpi_with_psb(const void* p1, const void* p2); -int cmp_lpi_with_unified_psb(const void* p1, const void* p2); -int cmp_lpi_with_id(const void* p1, const void* p2); -int cmp_lpi_with_hanzi(const void* p1, const void* p2); -int cmp_lpsi_with_str(const void* p1, const void* p2); -int cmp_hanzis_1(const void* p1, const void* p2); -int cmp_hanzis_2(const void* p1, const void* p2); -int cmp_hanzis_3(const void* p1, const void* p2); -int cmp_hanzis_4(const void* p1, const void* p2); -int cmp_hanzis_5(const void* p1, const void* p2); -int cmp_hanzis_6(const void* p1, const void* p2); -int cmp_hanzis_7(const void* p1, const void* p2); -int cmp_hanzis_8(const void* p1, const void* p2); -int cmp_npre_by_score(const void* p1, const void* p2); -int cmp_npre_by_hislen_score(const void* p1, const void* p2); -int cmp_npre_by_hanzi_score(const void* p1, const void* p2); -size_t remove_duplicate_npre(NPredictItem* npre_items, size_t npre_num); -size_t align_to_size_t(size_t size); -} // namespace ime_pinyin -#endif // PINYINIME_ANDPY_INCLUDE_SEARCHCOMMON_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/spellingtable.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/spellingtable.cpp deleted file mode 100644 index 121ac17..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/spellingtable.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "spellingtable.h" -#include -#include -#include -#include -#include -namespace ime_pinyin { -#ifdef ___BUILD_MODEL___ -const char SpellingTable:: -kNotSupportList[kNotSupportNum][kMaxSpellingSize + 1] = {"HM", "HNG", "NG"}; -// "" is the biggest, so that all empty strings will be moved to the end -// _eb mean empty is biggest -int compare_raw_spl_eb(const void* p1, const void* p2) { - if ('\0' == (static_cast(p1))->str[0]) - return 1; - if ('\0' == (static_cast(p2))->str[0]) - return -1; - return strcmp((static_cast(p1))->str, - (static_cast(p2))->str); -} -size_t get_odd_next(size_t value) { - size_t v_next = value; - while (true) { - size_t v_next_sqrt = (size_t)sqrt(v_next); - bool is_odd = true; - for (size_t v_dv = 2; v_dv < v_next_sqrt + 1; v_dv++) { - if (v_next % v_dv == 0) { - is_odd = false; - break; - } - } - if (is_odd) - return v_next; - v_next++; - } - // never reach here - return 0; -} -SpellingTable::SpellingTable() { - need_score_ = false; - raw_spellings_ = NULL; - spelling_buf_ = NULL; - spelling_num_ = 0; - total_freq_ = 0; - frozen_ = true; -} -SpellingTable::~SpellingTable() { - free_resource(); -} -size_t SpellingTable::get_hash_pos(const char* spelling_str) { - size_t hash_pos = 0; - for (size_t pos = 0; pos < spelling_size_; pos++) { - if ('\0' == spelling_str[pos]) - break; - hash_pos += (size_t)spelling_str[pos]; - } - hash_pos = hash_pos % spelling_max_num_; - return hash_pos; -} -size_t SpellingTable::hash_pos_next(size_t hash_pos) { - hash_pos += 123; - hash_pos = hash_pos % spelling_max_num_; - return hash_pos; -} -void SpellingTable::free_resource() { - if (NULL != raw_spellings_) - delete[] raw_spellings_; - raw_spellings_ = NULL; - if (NULL != spelling_buf_) - delete[] spelling_buf_; - spelling_buf_ = NULL; -} -bool SpellingTable::init_table(size_t pure_spl_size, size_t spl_max_num, - bool need_score) { - if (pure_spl_size == 0 || spl_max_num == 0) - return false; - need_score_ = need_score; - free_resource(); - spelling_size_ = pure_spl_size + 1; - if (need_score) - spelling_size_ += 1; - spelling_max_num_ = get_odd_next(spl_max_num); - spelling_num_ = 0; - raw_spellings_ = new RawSpelling[spelling_max_num_]; - spelling_buf_ = new char[spelling_max_num_ * (spelling_size_)]; - if (NULL == raw_spellings_ || NULL == spelling_buf_) { - free_resource(); - return false; - } - memset(raw_spellings_, 0, spelling_max_num_ * sizeof(RawSpelling)); - memset(spelling_buf_, 0, spelling_max_num_ * (spelling_size_)); - frozen_ = false; - total_freq_ = 0; - return true; -} -bool SpellingTable::put_spelling(const char* spelling_str, double freq) { - if (frozen_ || NULL == spelling_str) - return false; - for (size_t pos = 0; pos < kNotSupportNum; pos++) { - if (strcmp(spelling_str, kNotSupportList[pos]) == 0) { - return false; - } - } - total_freq_ += freq; - size_t hash_pos = get_hash_pos(spelling_str); - raw_spellings_[hash_pos].str[spelling_size_ - 1] = '\0'; - if (strncmp(raw_spellings_[hash_pos].str, spelling_str, - spelling_size_ - 1) == 0) { - raw_spellings_[hash_pos].freq += freq; - return true; - } - size_t hash_pos_ori = hash_pos; - while (true) { - if (strncmp(raw_spellings_[hash_pos].str, - spelling_str, spelling_size_ - 1) == 0) { - raw_spellings_[hash_pos].freq += freq; - return true; - } - if ('\0' == raw_spellings_[hash_pos].str[0]) { - raw_spellings_[hash_pos].freq += freq; - strncpy(raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1); - raw_spellings_[hash_pos].str[spelling_size_ - 1] = '\0'; - spelling_num_++; - return true; - } - hash_pos = hash_pos_next(hash_pos); - if (hash_pos_ori == hash_pos) - return false; - } - // never reach here - return false; -} -bool SpellingTable::contain(const char* spelling_str) { - if (NULL == spelling_str || NULL == spelling_buf_ || frozen_) - return false; - size_t hash_pos = get_hash_pos(spelling_str); - if ('\0' == raw_spellings_[hash_pos].str[0]) - return false; - if (strncmp(raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1) == 0) - return true; - size_t hash_pos_ori = hash_pos; - while (true) { - hash_pos = hash_pos_next(hash_pos); - if (hash_pos_ori == hash_pos) - return false; - if ('\0' == raw_spellings_[hash_pos].str[0]) - return false; - if (strncmp(raw_spellings_[hash_pos].str, spelling_str, spelling_size_ - 1) == 0) - return true; - } - // never reach here - return false; -} -const char* SpellingTable::arrange(size_t* item_size, size_t* spl_num) { - if (NULL == raw_spellings_ || NULL == spelling_buf_ || - NULL == item_size || NULL == spl_num) - return NULL; - qsort(raw_spellings_, spelling_max_num_, sizeof(RawSpelling), - compare_raw_spl_eb); - // After sorting, only the first spelling_num_ items are valid. - // Copy them to the destination buffer. - for (size_t pos = 0; pos < spelling_num_; pos++) { - strncpy(spelling_buf_ + pos * spelling_size_, raw_spellings_[pos].str, - spelling_size_); - } - if (need_score_) { - if (kPrintDebug0) - printf("------------Spelling Possiblities--------------\n"); - double max_score = 0; - double min_score = 0; - // After sorting, only the first spelling_num_ items are valid. - for (size_t pos = 0; pos < spelling_num_; pos++) { - raw_spellings_[pos].freq /= total_freq_; - if (need_score_) { - if (0 == pos) { - max_score = raw_spellings_[0].freq; - min_score = max_score; - } - else { - if (raw_spellings_[pos].freq > max_score) - max_score = raw_spellings_[pos].freq; - if (raw_spellings_[pos].freq < min_score) - min_score = raw_spellings_[pos].freq; - } - } - } - if (kPrintDebug0) - printf("-----max psb: %f, min psb: %f\n", max_score, min_score); - max_score = log(max_score); - min_score = log(min_score); - if (kPrintDebug0) - printf("-----max log value: %f, min log value: %f\n", - max_score, min_score); - // The absolute value of min_score is bigger than that of max_score because - // both of them are negative after log function. - score_amplifier_ = 1.0 * 255 / min_score; - double average_score = 0; - for (size_t pos = 0; pos < spelling_num_; pos++) { - double score = log(raw_spellings_[pos].freq) * score_amplifier_; - assert(score >= 0); - average_score += score; - // Because of calculation precision issue, score might be a little bigger - // than 255 after being amplified. - if (score > 255) - score = 255; - char* this_spl_buf = spelling_buf_ + pos * spelling_size_; - this_spl_buf[spelling_size_ - 1] = - static_cast((unsigned char)score); - if (kPrintDebug0) { - printf("---pos:%d, %s, psb:%d\n", pos, this_spl_buf, - (unsigned char)this_spl_buf[spelling_size_ - 1]); - } - } - average_score /= spelling_num_; - assert(average_score <= 255); - average_score_ = static_cast(average_score); - if (kPrintDebug0) - printf("\n----Score Amplifier: %f, Average Score: %d\n", score_amplifier_, - average_score_); - } - *item_size = spelling_size_; - *spl_num = spelling_num_; - frozen_ = true; - return spelling_buf_; -} -float SpellingTable::get_score_amplifier() { - return static_cast(score_amplifier_); -} -unsigned char SpellingTable::get_average_score() { - return average_score_; -} -#endif // ___BUILD_MODEL___ -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/spellingtable.h b/Widget/base/Virtual_Keyboard/googlepinyin/spellingtable.h deleted file mode 100644 index abdd189..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/spellingtable.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_SPELLINGTABLE_H__ -#define PINYINIME_INCLUDE_SPELLINGTABLE_H__ -#include -#include "./dictdef.h" -namespace ime_pinyin { -#ifdef ___BUILD_MODEL___ -const size_t kMaxSpellingSize = kMaxPinyinSize; -typedef struct { - char str[kMaxSpellingSize + 1]; - double freq; -} RawSpelling, *PRawSpelling; -// This class is used to store the spelling strings -// The length of the input spelling string should be less or equal to the -// spelling_size_ (set by init_table). If the input string is too long, -// we only keep its first spelling_size_ chars. -class SpellingTable { -private: - static const size_t kNotSupportNum = 3; - static const char kNotSupportList[kNotSupportNum][kMaxSpellingSize + 1]; - bool need_score_; - size_t spelling_max_num_; - RawSpelling* raw_spellings_; - // Used to store spelling strings. If the spelling table needs to calculate - // score, an extra char after each spelling string is the score. - // An item with a lower score has a higher probability. - char* spelling_buf_; - size_t spelling_size_; - double total_freq_; - size_t spelling_num_; - double score_amplifier_; - unsigned char average_score_; - // If frozen is true, put_spelling() and contain() are not allowed to call. - bool frozen_; - size_t get_hash_pos(const char* spelling_str); - size_t hash_pos_next(size_t hash_pos); - void free_resource(); -public: - SpellingTable(); - ~SpellingTable(); - // pure_spl_size is the pure maximum spelling string size. For example, - // "zhuang" is the longgest item in Pinyin, so pure_spl_size should be 6. - // spl_max_num is the maximum number of spelling strings to store. - // need_score is used to indicate whether the caller needs to calculate a - // score for each spelling. - bool init_table(size_t pure_spl_size, size_t spl_max_num, bool need_score); - // Put a spelling string to the table. - // It always returns false if called after arrange() withtout a new - // init_table() operation. - // freq is the spelling's occuring count. - // If the spelling has been in the table, occuring count will accumulated. - bool put_spelling(const char* spelling_str, double spl_count); - // Test whether a spelling string is in the table. - // It always returns false, when being called after arrange() withtout a new - // init_table() operation. - bool contain(const char* spelling_str); - // Sort the spelling strings and put them from the begin of the buffer. - // Return the pointer of the sorted spelling strings. - // item_size and spl_num return the item size and number of spelling. - // Because each spelling uses a '\0' as terminator, the returned item_size is - // at least one char longer than the spl_size parameter specified by - // init_table(). If the table is initialized to calculate score, item_size - // will be increased by 1, and current_spl_str[item_size - 1] stores an - // unsinged char score. - // An item with a lower score has a higher probability. - // Do not call put_spelling() and contains() after arrange(). - const char* arrange(size_t* item_size, size_t* spl_num); - float get_score_amplifier(); - unsigned char get_average_score(); -}; -#endif // ___BUILD_MODEL___ -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_SPELLINGTABLE_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/spellingtrie.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/spellingtrie.cpp deleted file mode 100644 index 91501a6..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/spellingtrie.cpp +++ /dev/null @@ -1,702 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include "dictdef.h" -#ifdef _WIN32 -#define snprintf _snprintf -#endif -#ifdef ___BUILD_MODEL___ -#include "spellingtable.h" -#endif -#include "spellingtrie.h" -namespace ime_pinyin { -SpellingTrie* SpellingTrie::instance_ = NULL; -// z/c/s is for Zh/Ch/Sh -const char SpellingTrie::kHalfId2Sc_[kFullSplIdStart + 1] = -"0ABCcDEFGHIJKLMNOPQRSsTUVWXYZz"; -// Bit 0 : is it a Shengmu char? -// Bit 1 : is it a Yunmu char? (one char is a Yunmu) -// Bit 2 : is it enabled in ShouZiMu(first char) mode? -unsigned char SpellingTrie::char_flags_[] = { -// a b c d e f g -0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, -// h i j k l m n -0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, -// o p q r s t -0x02, 0x01, 0x01, 0x01, 0x01, 0x01, -// u v w x y z -0x00, 0x00, 0x01, 0x01, 0x01, 0x01}; -int compare_spl(const void* p1, const void* p2) { - return strcmp((const char*)(p1), (const char*)(p2)); -} -SpellingTrie::SpellingTrie() { - spelling_buf_ = NULL; - spelling_size_ = 0; - spelling_num_ = 0; - spl_ym_ids_ = NULL; - splstr_queried_ = NULL; - splstr16_queried_ = NULL; - root_ = NULL; - dumb_node_ = NULL; - splitter_node_ = NULL; - instance_ = NULL; - ym_buf_ = NULL; - f2h_ = NULL; - szm_enable_shm(true); - szm_enable_ym(true); -#ifdef ___BUILD_MODEL___ - node_num_ = 0; -#endif -} -SpellingTrie::~SpellingTrie() { - if (NULL != spelling_buf_) - delete[] spelling_buf_; - if (NULL != splstr_queried_) - delete[] splstr_queried_; - if (NULL != splstr16_queried_) - delete[] splstr16_queried_; - if (NULL != spl_ym_ids_) - delete[] spl_ym_ids_; - if (NULL != root_) { - free_son_trie(root_); - delete root_; - } - if (NULL != dumb_node_) { - delete[] dumb_node_; - } - if (NULL != splitter_node_) { - delete[] splitter_node_; - } - if (NULL != instance_) { - delete instance_; - instance_ = NULL; - } - if (NULL != ym_buf_) - delete[] ym_buf_; - if (NULL != f2h_) - delete[] f2h_; -} -bool SpellingTrie::if_valid_id_update(uint16* splid) const { - if (NULL == splid || 0 == *splid) - return false; - if (*splid >= kFullSplIdStart) - return true; - if (*splid < kFullSplIdStart) { - char ch = kHalfId2Sc_[*splid]; - if (ch > 'Z') { - return true; - } - else { - if (szm_is_enabled(ch)) { - return true; - } - else if (is_yunmu_char(ch)) { - assert(h2f_num_[*splid] > 0); - *splid = h2f_start_[*splid]; - return true; - } - } - } - return false; -} -bool SpellingTrie::is_half_id(uint16 splid) const { - if (0 == splid || splid >= kFullSplIdStart) - return false; - return true; -} -bool SpellingTrie::is_full_id(uint16 splid) const { - if (splid < kFullSplIdStart || splid >= kFullSplIdStart + spelling_num_) - return false; - return true; -} -bool SpellingTrie::half_full_compatible(uint16 half_id, uint16 full_id) const { - uint16 half_fr_full = full_to_half(full_id); - if (half_fr_full == half_id) - return true; - // &~0x20 is used to conver the char to upper case. - // So that Zh/Ch/Sh(whose char is z/c/s) can be matched with Z/C/S. - char ch_f = (kHalfId2Sc_[half_fr_full] & (~0x20)); - char ch_h = kHalfId2Sc_[half_id]; - if (ch_f == ch_h) - return true; - return false; -} -bool SpellingTrie::is_half_id_yunmu(uint16 splid) const { - if (0 == splid || splid >= kFullSplIdStart) - return false; - char ch = kHalfId2Sc_[splid]; - // If ch >= 'a', that means the half id is one of Zh/Ch/Sh - if (ch >= 'a') { - return false; - } - return char_flags_[ch - 'A'] & kHalfIdYunmuMask; -} -bool SpellingTrie::is_shengmu_char(char ch) const { - return char_flags_[ch - 'A'] & kHalfIdShengmuMask; -} -bool SpellingTrie::is_yunmu_char(char ch) const { - return char_flags_[ch - 'A'] & kHalfIdYunmuMask; -} -bool SpellingTrie::is_szm_char(char ch) const { - return is_shengmu_char(ch) || is_yunmu_char(ch); -} -bool SpellingTrie::szm_is_enabled(char ch) const { - return char_flags_[ch - 'A'] & kHalfIdSzmMask; -} -void SpellingTrie::szm_enable_shm(bool enable) { - if (enable) { - for (char ch = 'A'; ch <= 'Z'; ch++) { - if (is_shengmu_char(ch)) - char_flags_[ch - 'A'] = char_flags_[ch - 'A'] | kHalfIdSzmMask; - } - } - else { - for (char ch = 'A'; ch <= 'Z'; ch++) { - if (is_shengmu_char(ch)) - char_flags_[ch - 'A'] = char_flags_[ch - 'A'] & (kHalfIdSzmMask ^ 0xff); - } - } -} -void SpellingTrie::szm_enable_ym(bool enable) { - if (enable) { - for (char ch = 'A'; ch <= 'Z'; ch++) { - if (is_yunmu_char(ch)) - char_flags_[ch - 'A'] = char_flags_[ch - 'A'] | kHalfIdSzmMask; - } - } - else { - for (char ch = 'A'; ch <= 'Z'; ch++) { - if (is_yunmu_char(ch)) - char_flags_[ch - 'A'] = char_flags_[ch - 'A'] & (kHalfIdSzmMask ^ 0xff); - } - } -} -bool SpellingTrie::is_szm_enabled(char ch) const { - return char_flags_[ch - 'A'] & kHalfIdSzmMask; -} -const SpellingTrie* SpellingTrie::get_cpinstance() { - return &get_instance(); -} -SpellingTrie& SpellingTrie::get_instance() { - if (NULL == instance_) - instance_ = new SpellingTrie(); - return *instance_; -} -uint16 SpellingTrie::half2full_num(uint16 half_id) const { - if (NULL == root_ || half_id >= kFullSplIdStart) - return 0; - return h2f_num_[half_id]; -} -uint16 SpellingTrie::half_to_full(uint16 half_id, uint16* spl_id_start) const { - if (NULL == spl_id_start || NULL == root_ || half_id >= kFullSplIdStart) - return 0; - *spl_id_start = h2f_start_[half_id]; - return h2f_num_[half_id]; -} -uint16 SpellingTrie::full_to_half(uint16 full_id) const { - if (NULL == root_ || full_id < kFullSplIdStart || - full_id > spelling_num_ + kFullSplIdStart) - return 0; - return f2h_[full_id - kFullSplIdStart]; -} -void SpellingTrie::free_son_trie(SpellingNode* node) { - if (NULL == node) - return; - for (size_t pos = 0; pos < node->num_of_son; pos++) { - free_son_trie(node->first_son + pos); - } - if (NULL != node->first_son) - delete[] node->first_son; -} -bool SpellingTrie::construct(const char* spelling_arr, size_t item_size, - size_t item_num, float score_amplifier, - unsigned char average_score) { - if (spelling_arr == NULL) - return false; - memset(h2f_start_, 0, sizeof(uint16) * kFullSplIdStart); - memset(h2f_num_, 0, sizeof(uint16) * kFullSplIdStart); - // If the arr is the same as the buf, means this function is called by - // load_table(), the table data are ready; otherwise the array should be - // saved. - if (spelling_arr != spelling_buf_) { - if (NULL != spelling_buf_) - delete[] spelling_buf_; - spelling_buf_ = new char[item_size * item_num]; - if (NULL == spelling_buf_) - return false; - memcpy(spelling_buf_, spelling_arr, sizeof(char) * item_size * item_num); - } - spelling_size_ = item_size; - spelling_num_ = item_num; - score_amplifier_ = score_amplifier; - average_score_ = average_score; - if (NULL != splstr_queried_) - delete[] splstr_queried_; - splstr_queried_ = new char[spelling_size_]; - if (NULL == splstr_queried_) - return false; - if (NULL != splstr16_queried_) - delete[] splstr16_queried_; - splstr16_queried_ = new char16[spelling_size_]; - if (NULL == splstr16_queried_) - return false; - // First, sort the buf to ensure they are in ascendant order - qsort(spelling_buf_, spelling_num_, spelling_size_, compare_spl); -#ifdef ___BUILD_MODEL___ - node_num_ = 1; -#endif - root_ = new SpellingNode(); - memset(root_, 0, sizeof(SpellingNode)); - dumb_node_ = new SpellingNode(); - memset(dumb_node_, 0, sizeof(SpellingNode)); - dumb_node_->score = average_score_; - splitter_node_ = new SpellingNode(); - memset(splitter_node_, 0, sizeof(SpellingNode)); - splitter_node_->score = average_score_; - memset(level1_sons_, 0, sizeof(SpellingNode*) * kValidSplCharNum); - root_->first_son = construct_spellings_subset(0, spelling_num_, 0, root_); - // Root's score should be cleared. - root_->score = 0; - if (NULL == root_->first_son) - return false; - h2f_start_[0] = h2f_num_[0] = 0; - if (!build_f2h()) - return false; -#ifdef ___BUILD_MODEL___ - if (kPrintDebug0) { - printf("---SpellingTrie Nodes: %d\n", (int)node_num_); - } - return build_ym_info(); -#else - return true; -#endif -} -#ifdef ___BUILD_MODEL___ -const char* SpellingTrie::get_ym_str(const char* spl_str) { - bool start_ZCS = false; - if (is_shengmu_char(*spl_str)) { - if ('Z' == *spl_str || 'C' == *spl_str || 'S' == *spl_str) - start_ZCS = true; - spl_str += 1; - if (start_ZCS && 'h' == *spl_str) - spl_str += 1; - } - return spl_str; -} -bool SpellingTrie::build_ym_info() { - bool sucess; - SpellingTable* spl_table = new SpellingTable(); - sucess = spl_table->init_table(kMaxPinyinSize - 1, 2 * kMaxYmNum, false); - assert(sucess); - for (uint16 pos = 0; pos < spelling_num_; pos++) { - const char* spl_str = spelling_buf_ + spelling_size_ * pos; - spl_str = get_ym_str(spl_str); - if ('\0' != spl_str[0]) { - sucess = spl_table->put_spelling(spl_str, 0); - assert(sucess); - } - } - size_t ym_item_size; // '\0' is included - size_t ym_num; - const char* ym_buf; - ym_buf = spl_table->arrange(&ym_item_size, &ym_num); - if (NULL != ym_buf_) - delete[] ym_buf_; - ym_buf_ = new char[ym_item_size * ym_num]; - if (NULL == ym_buf_) { - delete spl_table; - return false; - } - memcpy(ym_buf_, ym_buf, sizeof(char) * ym_item_size * ym_num); - ym_size_ = ym_item_size; - ym_num_ = ym_num; - delete spl_table; - // Generate the maping from the spelling ids to the Yunmu ids. - if (spl_ym_ids_) - delete spl_ym_ids_; - spl_ym_ids_ = new uint8[spelling_num_ + kFullSplIdStart]; - if (NULL == spl_ym_ids_) - return false; - memset(spl_ym_ids_, 0, sizeof(uint8) * (spelling_num_ + kFullSplIdStart)); - for (uint16 id = 1; id < spelling_num_ + kFullSplIdStart; id++) { - const char* str = get_spelling_str(id); - str = get_ym_str(str); - if ('\0' != str[0]) { - uint8 ym_id = get_ym_id(str); - spl_ym_ids_[id] = ym_id; - assert(ym_id > 0); - } - else { - spl_ym_ids_[id] = 0; - } - } - return true; -} -#endif -SpellingNode* SpellingTrie::construct_spellings_subset( -size_t item_start, size_t item_end, size_t level, SpellingNode* parent) { - if (level >= spelling_size_ || item_end <= item_start || NULL == parent) - return NULL; - SpellingNode* first_son = NULL; - uint16 num_of_son = 0; - unsigned char min_son_score = 255; - const char* spelling_last_start = spelling_buf_ + spelling_size_ * item_start; - char char_for_node = spelling_last_start[level]; - assert((char_for_node >= 'A' && char_for_node <= 'Z') || - 'h' == char_for_node); - // Scan the array to find how many sons - for (size_t i = item_start + 1; i < item_end; i++) { - const char* spelling_current = spelling_buf_ + spelling_size_ * i; - char char_current = spelling_current[level]; - if (char_current != char_for_node) { - num_of_son++; - char_for_node = char_current; - } - } - num_of_son++; - // Allocate memory -#ifdef ___BUILD_MODEL___ - node_num_ += num_of_son; -#endif - first_son = new SpellingNode[num_of_son]; - memset(first_son, 0, sizeof(SpellingNode) * num_of_son); - // Now begin construct tree - size_t son_pos = 0; - spelling_last_start = spelling_buf_ + spelling_size_ * item_start; - char_for_node = spelling_last_start[level]; - bool spelling_endable = true; - if (spelling_last_start[level + 1] != '\0') - spelling_endable = false; - size_t item_start_next = item_start; - for (size_t i = item_start + 1; i < item_end; i++) { - const char* spelling_current = spelling_buf_ + spelling_size_ * i; - char char_current = spelling_current[level]; - assert(is_valid_spl_char(char_current)); - if (char_current != char_for_node) { - // Construct a node - SpellingNode* node_current = first_son + son_pos; - node_current->char_this_node = char_for_node; - // For quick search in the first level - if (0 == level) - level1_sons_[char_for_node - 'A'] = node_current; - if (spelling_endable) { - node_current->spelling_idx = kFullSplIdStart + item_start_next; - } - if (spelling_last_start[level + 1] != '\0' || i - item_start_next > 1) { - size_t real_start = item_start_next; - if (spelling_last_start[level + 1] == '\0') - real_start++; - node_current->first_son = - construct_spellings_subset(real_start, i, level + 1, - node_current); - if (real_start == item_start_next + 1) { - uint16 score_this = static_cast( - spelling_last_start[spelling_size_ - 1]); - if (score_this < node_current->score) - node_current->score = score_this; - } - } - else { - node_current->first_son = NULL; - node_current->score = static_cast( - spelling_last_start[spelling_size_ - 1]); - } - if (node_current->score < min_son_score) - min_son_score = node_current->score; - bool is_half = false; - if (level == 0 && is_szm_char(char_for_node)) { - node_current->spelling_idx = - static_cast(char_for_node - 'A' + 1); - if (char_for_node > 'C') - node_current->spelling_idx++; - if (char_for_node > 'S') - node_current->spelling_idx++; - h2f_num_[node_current->spelling_idx] = i - item_start_next; - is_half = true; - } - else if (level == 1 && char_for_node == 'h') { - char ch_level0 = spelling_last_start[0]; - uint16 part_id = 0; - if (ch_level0 == 'C') - part_id = 'C' - 'A' + 1 + 1; - else if (ch_level0 == 'S') - part_id = 'S' - 'A' + 1 + 2; - else if (ch_level0 == 'Z') - part_id = 'Z' - 'A' + 1 + 3; - if (0 != part_id) { - node_current->spelling_idx = part_id; - h2f_num_[node_current->spelling_idx] = i - item_start_next; - is_half = true; - } - } - if (is_half) { - if (h2f_num_[node_current->spelling_idx] > 0) - h2f_start_[node_current->spelling_idx] = - item_start_next + kFullSplIdStart; - else - h2f_start_[node_current->spelling_idx] = 0; - } - // for next sibling - spelling_last_start = spelling_current; - char_for_node = char_current; - item_start_next = i; - spelling_endable = true; - if (spelling_current[level + 1] != '\0') - spelling_endable = false; - son_pos++; - } - } - // the last one - SpellingNode* node_current = first_son + son_pos; - node_current->char_this_node = char_for_node; - // For quick search in the first level - if (0 == level) - level1_sons_[char_for_node - 'A'] = node_current; - if (spelling_endable) { - node_current->spelling_idx = kFullSplIdStart + item_start_next; - } - if (spelling_last_start[level + 1] != '\0' || - item_end - item_start_next > 1) { - size_t real_start = item_start_next; - if (spelling_last_start[level + 1] == '\0') - real_start++; - node_current->first_son = - construct_spellings_subset(real_start, item_end, level + 1, - node_current); - if (real_start == item_start_next + 1) { - uint16 score_this = static_cast( - spelling_last_start[spelling_size_ - 1]); - if (score_this < node_current->score) - node_current->score = score_this; - } - } - else { - node_current->first_son = NULL; - node_current->score = static_cast( - spelling_last_start[spelling_size_ - 1]); - } - if (node_current->score < min_son_score) - min_son_score = node_current->score; - assert(son_pos + 1 == num_of_son); - bool is_half = false; - if (level == 0 && szm_is_enabled(char_for_node)) { - node_current->spelling_idx = static_cast(char_for_node - 'A' + 1); - if (char_for_node > 'C') - node_current->spelling_idx++; - if (char_for_node > 'S') - node_current->spelling_idx++; - h2f_num_[node_current->spelling_idx] = item_end - item_start_next; - is_half = true; - } - else if (level == 1 && char_for_node == 'h') { - char ch_level0 = spelling_last_start[0]; - uint16 part_id = 0; - if (ch_level0 == 'C') - part_id = 'C' - 'A' + 1 + 1; - else if (ch_level0 == 'S') - part_id = 'S' - 'A' + 1 + 2; - else if (ch_level0 == 'Z') - part_id = 'Z' - 'A' + 1 + 3; - if (0 != part_id) { - node_current->spelling_idx = part_id; - h2f_num_[node_current->spelling_idx] = item_end - item_start_next; - is_half = true; - } - } - if (is_half) { - if (h2f_num_[node_current->spelling_idx] > 0) - h2f_start_[node_current->spelling_idx] = - item_start_next + kFullSplIdStart; - else - h2f_start_[node_current->spelling_idx] = 0; - } - parent->num_of_son = num_of_son; - parent->score = min_son_score; - return first_son; -} -bool SpellingTrie::save_spl_trie(FILE* fp) { - if (NULL == fp || NULL == spelling_buf_) - return false; - if (fwrite(&spelling_size_, sizeof(uint32), 1, fp) != 1) - return false; - if (fwrite(&spelling_num_, sizeof(uint32), 1, fp) != 1) - return false; - if (fwrite(&score_amplifier_, sizeof(float), 1, fp) != 1) - return false; - if (fwrite(&average_score_, sizeof(unsigned char), 1, fp) != 1) - return false; - if (fwrite(spelling_buf_, sizeof(char) * spelling_size_, - spelling_num_, fp) != spelling_num_) - return false; - return true; -} -bool SpellingTrie::load_spl_trie(FILE* fp) { - if (NULL == fp) - return false; - if (fread(&spelling_size_, sizeof(uint32), 1, fp) != 1) - return false; - if (fread(&spelling_num_, sizeof(uint32), 1, fp) != 1) - return false; - if (fread(&score_amplifier_, sizeof(float), 1, fp) != 1) - return false; - if (fread(&average_score_, sizeof(unsigned char), 1, fp) != 1) - return false; - if (NULL != spelling_buf_) - delete[] spelling_buf_; - spelling_buf_ = new char[spelling_size_ * spelling_num_]; - if (NULL == spelling_buf_) - return false; - if (fread(spelling_buf_, sizeof(char) * spelling_size_, - spelling_num_, fp) != spelling_num_) - return false; - return construct(spelling_buf_, spelling_size_, spelling_num_, - score_amplifier_, average_score_); -} -bool SpellingTrie::build_f2h() { - if (NULL != f2h_) - delete[] f2h_; - f2h_ = new uint16[spelling_num_]; - if (NULL == f2h_) - return false; - for (uint16 hid = 0; hid < kFullSplIdStart; hid++) { - for (uint16 fid = h2f_start_[hid]; - fid < h2f_start_[hid] + h2f_num_[hid]; fid++) - f2h_[fid - kFullSplIdStart] = hid; - } - return true; -} -size_t SpellingTrie::get_spelling_num() { - return spelling_num_; -} -uint8 SpellingTrie::get_ym_id(const char* ym_str) { - if (NULL == ym_str || NULL == ym_buf_) - return 0; - for (uint8 pos = 0; pos < ym_num_; pos++) - if (strcmp(ym_buf_ + ym_size_ * pos, ym_str) == 0) - return pos + 1; - return 0; -} -const char* SpellingTrie::get_spelling_str(uint16 splid) { - splstr_queried_[0] = '\0'; - if (splid >= kFullSplIdStart) { - splid -= kFullSplIdStart; - snprintf(splstr_queried_, spelling_size_, "%s", - spelling_buf_ + splid * spelling_size_); - } - else { - if (splid == 'C' - 'A' + 1 + 1) { - snprintf(splstr_queried_, spelling_size_, "%s", "Ch"); - } - else if (splid == 'S' - 'A' + 1 + 2) { - snprintf(splstr_queried_, spelling_size_, "%s", "Sh"); - } - else if (splid == 'Z' - 'A' + 1 + 3) { - snprintf(splstr_queried_, spelling_size_, "%s", "Zh"); - } - else { - if (splid > 'C' - 'A' + 1) - splid--; - if (splid > 'S' - 'A' + 1) - splid--; - splstr_queried_[0] = 'A' + splid - 1; - splstr_queried_[1] = '\0'; - } - } - return splstr_queried_; -} -const char16* SpellingTrie::get_spelling_str16(uint16 splid) { - splstr16_queried_[0] = '\0'; - if (splid >= kFullSplIdStart) { - splid -= kFullSplIdStart; - for (size_t pos = 0; pos < spelling_size_; pos++) { - splstr16_queried_[pos] = static_cast(spelling_buf_[splid * spelling_size_ + pos]); - } - } - else { - if (splid == 'C' - 'A' + 1 + 1) { - splstr16_queried_[0] = static_cast('C'); - splstr16_queried_[1] = static_cast('h'); - splstr16_queried_[2] = static_cast('\0'); - } - else if (splid == 'S' - 'A' + 1 + 2) { - splstr16_queried_[0] = static_cast('S'); - splstr16_queried_[1] = static_cast('h'); - splstr16_queried_[2] = static_cast('\0'); - } - else if (splid == 'Z' - 'A' + 1 + 3) { - splstr16_queried_[0] = static_cast('Z'); - splstr16_queried_[1] = static_cast('h'); - splstr16_queried_[2] = static_cast('\0'); - } - else { - if (splid > 'C' - 'A' + 1) - splid--; - if (splid > 'S' - 'A' + 1) - splid--; - splstr16_queried_[0] = 'A' + splid - 1; - splstr16_queried_[1] = '\0'; - } - } - return splstr16_queried_; -} -size_t SpellingTrie::get_spelling_str16(uint16 splid, char16* splstr16, - size_t splstr16_len) { - if (NULL == splstr16 || splstr16_len < kMaxPinyinSize + 1) - return 0; - if (splid >= kFullSplIdStart) { - splid -= kFullSplIdStart; - for (size_t pos = 0; pos <= kMaxPinyinSize; pos++) { - splstr16[pos] = static_cast(spelling_buf_[splid * spelling_size_ + pos]); - if (static_cast('\0') == splstr16[pos]) { - return pos; - } - } - } - else { - if (splid == 'C' - 'A' + 1 + 1) { - splstr16[0] = static_cast('C'); - splstr16[1] = static_cast('h'); - splstr16[2] = static_cast('\0'); - return 2; - } - else if (splid == 'S' - 'A' + 1 + 2) { - splstr16[0] = static_cast('S'); - splstr16[1] = static_cast('h'); - splstr16[2] = static_cast('\0'); - return 2; - } - else if (splid == 'Z' - 'A' + 1 + 3) { - splstr16[0] = static_cast('Z'); - splstr16[1] = static_cast('h'); - splstr16[2] = static_cast('\0'); - return 2; - } - else { - if (splid > 'C' - 'A' + 1) - splid--; - if (splid > 'S' - 'A' + 1) - splid--; - splstr16[0] = 'A' + splid - 1; - splstr16[1] = '\0'; - return 1; - } - } - // Not reachable. - return 0; -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/spellingtrie.h b/Widget/base/Virtual_Keyboard/googlepinyin/spellingtrie.h deleted file mode 100644 index d526696..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/spellingtrie.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_SPELLINGTRIE_H__ -#define PINYINIME_INCLUDE_SPELLINGTRIE_H__ -#include -#include -#include "./dictdef.h" -namespace ime_pinyin { -static const unsigned short kFullSplIdStart = kHalfSpellingIdNum + 1; -// Node used for the trie of spellings -struct SpellingNode { - SpellingNode* first_son; - // The spelling id for each node. If you need more bits to store - // spelling id, please adjust this structure. - uint16 spelling_idx : 11; - uint16 num_of_son : 5; - char char_this_node; - unsigned char score; -}; -class SpellingTrie { -private: - static const int kMaxYmNum = 64; - static const size_t kValidSplCharNum = 26; - static const uint16 kHalfIdShengmuMask = 0x01; - static const uint16 kHalfIdYunmuMask = 0x02; - static const uint16 kHalfIdSzmMask = 0x04; - // Map from half spelling id to single char. - // For half ids of Zh/Ch/Sh, map to z/c/s (low case) respectively. - // For example, 1 to 'A', 2 to 'B', 3 to 'C', 4 to 'c', 5 to 'D', ..., - // 28 to 'Z', 29 to 'z'. - // [0] is not used to achieve better efficiency. - static const char kHalfId2Sc_[kFullSplIdStart + 1]; - static unsigned char char_flags_[]; - static SpellingTrie* instance_; - // The spelling table - char* spelling_buf_; - // The size of longest spelling string, includes '\0' and an extra char to - // store score. For example, "zhuang" is the longgest item in Pinyin list, - // so spelling_size_ is 8. - // Structure: The string ended with '\0' + score char. - // An item with a lower score has a higher probability. - uint32 spelling_size_; - // Number of full spelling ids. - uint32 spelling_num_; - float score_amplifier_; - unsigned char average_score_; - // The Yunmu id list for the spelling ids (for half ids of Shengmu, - // the Yunmu id is 0). - // The length of the list is spelling_num_ + kFullSplIdStart, - // so that spl_ym_ids_[splid] is the Yunmu id of the splid. - uint8* spl_ym_ids_; - // The Yunmu table. - // Each Yunmu will be assigned with Yunmu id from 1. - char* ym_buf_; - size_t ym_size_; // The size of longest Yunmu string, '\0'included. - size_t ym_num_; - // The spelling string just queried - char* splstr_queried_; - // The spelling string just queried - char16* splstr16_queried_; - // The root node of the spelling tree - SpellingNode* root_; - // If a none qwerty key such as a fnction key like ENTER is given, this node - // will be used to indicate that this is not a QWERTY node. - SpellingNode* dumb_node_; - // If a splitter key is pressed, this node will be used to indicate that this - // is a splitter key. - SpellingNode* splitter_node_; - // Used to get the first level sons. - SpellingNode* level1_sons_[kValidSplCharNum]; - // The full spl_id range for specific half id. - // h2f means half to full. - // A half id can be a ShouZiMu id (id to represent the first char of a full - // spelling, including Shengmu and Yunmu), or id of zh/ch/sh. - // [1..kFullSplIdStart-1] is the arrange of half id. - uint16 h2f_start_[kFullSplIdStart]; - uint16 h2f_num_[kFullSplIdStart]; - // Map from full id to half id. - uint16* f2h_; -#ifdef ___BUILD_MODEL___ - // How many node used to build the trie. - size_t node_num_; -#endif - SpellingTrie(); - void free_son_trie(SpellingNode* node); - // Construct a subtree using a subset of the spelling array (from - // item_star to item_end). - // Member spelliing_buf_ and spelling_size_ should be valid. - // parent is used to update its num_of_son and score. - SpellingNode* construct_spellings_subset(size_t item_start, size_t item_end, - size_t level, SpellingNode* parent); - bool build_f2h(); - // The caller should guarantee ch >= 'A' && ch <= 'Z' - bool is_shengmu_char(char ch) const; - // The caller should guarantee ch >= 'A' && ch <= 'Z' - bool is_yunmu_char(char ch) const; -#ifdef ___BUILD_MODEL___ - // Given a spelling string, return its Yunmu string. - // The caller guaratees spl_str is valid. - const char* get_ym_str(const char* spl_str); - // Build the Yunmu list, and the mapping relation between the full ids and the - // Yunmu ids. This functin is called after the spelling trie is built. - bool build_ym_info(); -#endif - friend class SpellingParser; - friend class SmartSplParser; - friend class SmartSplParser2; -public: - ~SpellingTrie(); - inline static bool is_valid_spl_char(char ch) { - return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); - } - // The caller guarantees that the two chars are valid spelling chars. - inline static bool is_same_spl_char(char ch1, char ch2) { - return ch1 == ch2 || ch1 - ch2 == 'a' - 'A' || ch2 - ch1 == 'a' - 'A'; - } - // Construct the tree from the input pinyin array - // The given string list should have been sorted. - // score_amplifier is used to convert a possibility value into score. - // average_score is the average_score of all spellings. The dumb node is - // assigned with this score. - bool construct(const char* spelling_arr, size_t item_size, size_t item_num, - float score_amplifier, unsigned char average_score); - // Test if the given id is a valid spelling id. - // If function returns true, the given splid may be updated like this: - // When 'A' is not enabled in ShouZiMu mode, the parsing result for 'A' is - // first given as a half id 1, but because 'A' is a one-char Yunmu and - // it is a valid id, it needs to updated to its corresponding full id. - bool if_valid_id_update(uint16* splid) const; - // Test if the given id is a half id. - bool is_half_id(uint16 splid) const; - bool is_full_id(uint16 splid) const; - // Test if the given id is a one-char Yunmu id (obviously, it is also a half - // id), such as 'A', 'E' and 'O'. - bool is_half_id_yunmu(uint16 splid) const; - // Test if this char is a ShouZiMu char. This ShouZiMu char may be not enabled. - // For Pinyin, only i/u/v is not a ShouZiMu char. - // The caller should guarantee that ch >= 'A' && ch <= 'Z' - bool is_szm_char(char ch) const; - // Test If this char is enabled in ShouZiMu mode. - // The caller should guarantee that ch >= 'A' && ch <= 'Z' - bool szm_is_enabled(char ch) const; - // Enable/disable Shengmus in ShouZiMu mode(using the first char of a spelling - // to input). - void szm_enable_shm(bool enable); - // Enable/disable Yunmus in ShouZiMu mode. - void szm_enable_ym(bool enable); - // Test if this char is enabled in ShouZiMu mode. - // The caller should guarantee ch >= 'A' && ch <= 'Z' - bool is_szm_enabled(char ch) const; - // Return the number of full ids for the given half id. - uint16 half2full_num(uint16 half_id) const; - // Return the number of full ids for the given half id, and fill spl_id_start - // to return the first full id. - uint16 half_to_full(uint16 half_id, uint16* spl_id_start) const; - // Return the corresponding half id for the given full id. - // Not frequently used, low efficient. - // Return 0 if fails. - uint16 full_to_half(uint16 full_id) const; - // To test whether a half id is compatible with a full id. - // Generally, when half_id == full_to_half(full_id), return true. - // But for "Zh, Ch, Sh", if fussy mode is on, half id for 'Z' is compatible - // with a full id like "Zhe". (Fussy mode is not ready). - bool half_full_compatible(uint16 half_id, uint16 full_id) const; - static const SpellingTrie* get_cpinstance(); - static SpellingTrie& get_instance(); - // Save to the file stream - bool save_spl_trie(FILE* fp); - // Load from the file stream - bool load_spl_trie(FILE* fp); - // Get the number of spellings - size_t get_spelling_num(); - // Return the Yunmu id for the given Yunmu string. - // If the string is not valid, return 0; - uint8 get_ym_id(const char* ym_str); - // Get the readonly Pinyin string for a given spelling id - const char* get_spelling_str(uint16 splid); - // Get the readonly Pinyin string for a given spelling id - const char16* get_spelling_str16(uint16 splid); - // Get Pinyin string for a given spelling id. Return the length of the - // string, and fill-in '\0' at the end. - size_t get_spelling_str16(uint16 splid, char16* splstr16, - size_t splstr16_len); -}; -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_SPELLINGTRIE_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/splparser.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/splparser.cpp deleted file mode 100644 index e1bdb1f..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/splparser.cpp +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "splparser.h" -#include -namespace ime_pinyin { -SpellingParser::SpellingParser() { - spl_trie_ = SpellingTrie::get_cpinstance(); -} -bool SpellingParser::is_valid_to_parse(char ch) { - return SpellingTrie::is_valid_spl_char(ch); -} -uint16 SpellingParser::splstr_to_idxs(const char* splstr, uint16 str_len, - uint16 spl_idx[], uint16 start_pos[], - uint16 max_size, bool& last_is_pre) { - if (NULL == splstr || 0 == max_size || 0 == str_len) - return 0; - if (!SpellingTrie::is_valid_spl_char(splstr[0])) - return 0; - last_is_pre = false; - const SpellingNode* node_this = spl_trie_->root_; - uint16 str_pos = 0; - uint16 idx_num = 0; - if (NULL != start_pos) - start_pos[0] = 0; - bool last_is_splitter = false; - while (str_pos < str_len) { - char char_this = splstr[str_pos]; - // all characters outside of [a, z] are considered as splitters - if (!SpellingTrie::is_valid_spl_char(char_this)) { - // test if the current node is endable - uint16 id_this = node_this->spelling_idx; - if (spl_trie_->if_valid_id_update(&id_this)) { - spl_idx[idx_num] = id_this; - idx_num++; - str_pos++; - if (NULL != start_pos) - start_pos[idx_num] = str_pos; - if (idx_num >= max_size) - return idx_num; - node_this = spl_trie_->root_; - last_is_splitter = true; - continue; - } - else { - if (last_is_splitter) { - str_pos++; - if (NULL != start_pos) - start_pos[idx_num] = str_pos; - continue; - } - else { - return idx_num; - } - } - } - last_is_splitter = false; - SpellingNode* found_son = NULL; - if (0 == str_pos) { - if (char_this >= 'a') - found_son = spl_trie_->level1_sons_[char_this - 'a']; - else - found_son = spl_trie_->level1_sons_[char_this - 'A']; - } - else { - SpellingNode* first_son = node_this->first_son; - // Because for Zh/Ch/Sh nodes, they are the last in the buffer and - // frequently used, so we scan from the end. - for (int i = 0; i < node_this->num_of_son; i++) { - SpellingNode* this_son = first_son + i; - if (SpellingTrie::is_same_spl_char( - this_son->char_this_node, char_this)) { - found_son = this_son; - break; - } - } - } - // found, just move the current node pointer to the the son - if (NULL != found_son) { - node_this = found_son; - } - else { - // not found, test if it is endable - uint16 id_this = node_this->spelling_idx; - if (spl_trie_->if_valid_id_update(&id_this)) { - // endable, remember the index - spl_idx[idx_num] = id_this; - idx_num++; - if (NULL != start_pos) - start_pos[idx_num] = str_pos; - if (idx_num >= max_size) - return idx_num; - node_this = spl_trie_->root_; - continue; - } - else { - return idx_num; - } - } - str_pos++; - } - uint16 id_this = node_this->spelling_idx; - if (spl_trie_->if_valid_id_update(&id_this)) { - // endable, remember the index - spl_idx[idx_num] = id_this; - idx_num++; - if (NULL != start_pos) - start_pos[idx_num] = str_pos; - } - last_is_pre = !last_is_splitter; - return idx_num; -} -uint16 SpellingParser::splstr_to_idxs_f(const char* splstr, uint16 str_len, - uint16 spl_idx[], uint16 start_pos[], - uint16 max_size, bool& last_is_pre) { - uint16 idx_num = splstr_to_idxs(splstr, str_len, spl_idx, start_pos, - max_size, last_is_pre); - for (uint16 pos = 0; pos < idx_num; pos++) { - if (spl_trie_->is_half_id_yunmu(spl_idx[pos])) { - spl_trie_->half_to_full(spl_idx[pos], spl_idx + pos); - if (pos == idx_num - 1) { - last_is_pre = false; - } - } - } - return idx_num; -} -uint16 SpellingParser::splstr16_to_idxs(const char16* splstr, uint16 str_len, - uint16 spl_idx[], uint16 start_pos[], - uint16 max_size, bool& last_is_pre) { - if (NULL == splstr || 0 == max_size || 0 == str_len) - return 0; - if (!SpellingTrie::is_valid_spl_char(splstr[0])) - return 0; - last_is_pre = false; - const SpellingNode* node_this = spl_trie_->root_; - uint16 str_pos = 0; - uint16 idx_num = 0; - if (NULL != start_pos) - start_pos[0] = 0; - bool last_is_splitter = false; - while (str_pos < str_len) { - char16 char_this = splstr[str_pos]; - // all characters outside of [a, z] are considered as splitters - if (!SpellingTrie::is_valid_spl_char(char_this)) { - // test if the current node is endable - uint16 id_this = node_this->spelling_idx; - if (spl_trie_->if_valid_id_update(&id_this)) { - spl_idx[idx_num] = id_this; - idx_num++; - str_pos++; - if (NULL != start_pos) - start_pos[idx_num] = str_pos; - if (idx_num >= max_size) - return idx_num; - node_this = spl_trie_->root_; - last_is_splitter = true; - continue; - } - else { - if (last_is_splitter) { - str_pos++; - if (NULL != start_pos) - start_pos[idx_num] = str_pos; - continue; - } - else { - return idx_num; - } - } - } - last_is_splitter = false; - SpellingNode* found_son = NULL; - if (0 == str_pos) { - if (char_this >= 'a') - found_son = spl_trie_->level1_sons_[char_this - 'a']; - else - found_son = spl_trie_->level1_sons_[char_this - 'A']; - } - else { - SpellingNode* first_son = node_this->first_son; - // Because for Zh/Ch/Sh nodes, they are the last in the buffer and - // frequently used, so we scan from the end. - for (int i = 0; i < node_this->num_of_son; i++) { - SpellingNode* this_son = first_son + i; - if (SpellingTrie::is_same_spl_char( - this_son->char_this_node, char_this)) { - found_son = this_son; - break; - } - } - } - // found, just move the current node pointer to the the son - if (NULL != found_son) { - node_this = found_son; - } - else { - // not found, test if it is endable - uint16 id_this = node_this->spelling_idx; - if (spl_trie_->if_valid_id_update(&id_this)) { - // endable, remember the index - spl_idx[idx_num] = id_this; - idx_num++; - if (NULL != start_pos) - start_pos[idx_num] = str_pos; - if (idx_num >= max_size) - return idx_num; - node_this = spl_trie_->root_; - continue; - } - else { - return idx_num; - } - } - str_pos++; - } - uint16 id_this = node_this->spelling_idx; - if (spl_trie_->if_valid_id_update(&id_this)) { - // endable, remember the index - spl_idx[idx_num] = id_this; - idx_num++; - if (NULL != start_pos) - start_pos[idx_num] = str_pos; - } - last_is_pre = !last_is_splitter; - return idx_num; -} -uint16 SpellingParser::splstr16_to_idxs_f(const char16* splstr, uint16 str_len, - uint16 spl_idx[], uint16 start_pos[], - uint16 max_size, bool& last_is_pre) { - uint16 idx_num = splstr16_to_idxs(splstr, str_len, spl_idx, start_pos, - max_size, last_is_pre); - for (uint16 pos = 0; pos < idx_num; pos++) { - if (spl_trie_->is_half_id_yunmu(spl_idx[pos])) { - spl_trie_->half_to_full(spl_idx[pos], spl_idx + pos); - if (pos == idx_num - 1) { - last_is_pre = false; - } - } - } - return idx_num; -} -uint16 SpellingParser::get_splid_by_str(const char* splstr, uint16 str_len, - bool* is_pre) { - if (NULL == is_pre) - return 0; - uint16 spl_idx[2]; - uint16 start_pos[3]; - if (splstr_to_idxs(splstr, str_len, spl_idx, start_pos, 2, *is_pre) != 1) - return 0; - if (start_pos[1] != str_len) - return 0; - return spl_idx[0]; -} -uint16 SpellingParser::get_splid_by_str_f(const char* splstr, uint16 str_len, - bool* is_pre) { - if (NULL == is_pre) - return 0; - uint16 spl_idx[2]; - uint16 start_pos[3]; - if (splstr_to_idxs(splstr, str_len, spl_idx, start_pos, 2, *is_pre) != 1) - return 0; - if (start_pos[1] != str_len) - return 0; - if (spl_trie_->is_half_id_yunmu(spl_idx[0])) { - spl_trie_->half_to_full(spl_idx[0], spl_idx); - *is_pre = false; - } - return spl_idx[0]; -} -uint16 SpellingParser::get_splids_parallel(const char* splstr, uint16 str_len, - uint16 splidx[], uint16 max_size, - uint16& full_id_num, bool& is_pre) { - if (max_size <= 0 || !is_valid_to_parse(splstr[0])) - return 0; - splidx[0] = get_splid_by_str(splstr, str_len, &is_pre); - full_id_num = 0; - if (0 != splidx[0]) { - if (splidx[0] >= kFullSplIdStart) - full_id_num = 1; - return 1; - } - return 0; -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/splparser.h b/Widget/base/Virtual_Keyboard/googlepinyin/splparser.h deleted file mode 100644 index e4aeed8..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/splparser.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_SPLPARSER_H__ -#define PINYINIME_INCLUDE_SPLPARSER_H__ -#include "./dictdef.h" -#include "./spellingtrie.h" -namespace ime_pinyin { -class SpellingParser { -protected: - const SpellingTrie* spl_trie_; -public: - SpellingParser(); - // Given a string, parse it into a spelling id stream. - // If the whole string are sucessfully parsed, last_is_pre will be true; - // if the whole string is not fullly parsed, last_is_pre will return whether - // the last part of the string is a prefix of a full spelling string. For - // example, given string "zhengzhon", "zhon" is not a valid speling, but it is - // the prefix of "zhong". - // - // If splstr starts with a character not in ['a'-z'] (it is a split char), - // return 0. - // Split char can only appear in the middle of the string or at the end. - uint16 splstr_to_idxs(const char* splstr, uint16 str_len, uint16 splidx[], - uint16 start_pos[], uint16 max_size, bool& last_is_pre); - // Similar to splstr_to_idxs(), the only difference is that splstr_to_idxs() - // convert single-character Yunmus into half ids, while this function converts - // them into full ids. - uint16 splstr_to_idxs_f(const char* splstr, uint16 str_len, uint16 splidx[], - uint16 start_pos[], uint16 max_size, bool& last_is_pre); - // Similar to splstr_to_idxs(), the only difference is that this function - // uses char16 instead of char8. - uint16 splstr16_to_idxs(const char16* splstr, uint16 str_len, uint16 splidx[], - uint16 start_pos[], uint16 max_size, bool& last_is_pre); - // Similar to splstr_to_idxs_f(), the only difference is that this function - // uses char16 instead of char8. - uint16 splstr16_to_idxs_f(const char16* splstr16, uint16 str_len, - uint16 splidx[], uint16 start_pos[], - uint16 max_size, bool& last_is_pre); - // If the given string is a spelling, return the id, others, return 0. - // If the give string is a single char Yunmus like "A", and the char is - // enabled in ShouZiMu mode, the returned spelling id will be a half id. - // When the returned spelling id is a half id, *is_pre returns whether it - // is a prefix of a full spelling string. - uint16 get_splid_by_str(const char* splstr, uint16 str_len, bool* is_pre); - // If the given string is a spelling, return the id, others, return 0. - // If the give string is a single char Yunmus like "a", no matter the char - // is enabled in ShouZiMu mode or not, the returned spelling id will be - // a full id. - // When the returned spelling id is a half id, *p_is_pre returns whether it - // is a prefix of a full spelling string. - uint16 get_splid_by_str_f(const char* splstr, uint16 str_len, bool* is_pre); - // Splitter chars are not included. - bool is_valid_to_parse(char ch); - // When auto-correction is not enabled, get_splid_by_str() will be called to - // return the single result. When auto-correction is enabled, this function - // will be called to get the results. Auto-correction is not ready. - // full_id_num returns number of full spelling ids. - // is_pre returns whether the given string is the prefix of a full spelling - // string. - // If splstr starts with a character not in [a-zA-Z] (it is a split char), - // return 0. - // Split char can only appear in the middle of the string or at the end. - // The caller should guarantee NULL != splstr && str_len > 0 && NULL != splidx - uint16 get_splids_parallel(const char* splstr, uint16 str_len, - uint16 splidx[], uint16 max_size, - uint16& full_id_num, bool& is_pre); -}; -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_SPLPARSER_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/sync.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/sync.cpp deleted file mode 100644 index 7b07e31..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/sync.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "sync.h" -#include -#include -#ifdef ___SYNC_ENABLED___ -namespace ime_pinyin { -Sync::Sync() : userdict_(NULL), - dictfile_(NULL), - last_count_(0) {}; -Sync::~Sync() { -} -bool Sync::begin(const char* filename) { - if (userdict_) { - finish(); - } - if (!filename) { - return false; - } - dictfile_ = strdup(filename); - if (!dictfile_) { - return false; - } - userdict_ = new UserDict(); - if (!userdict_) { - free(dictfile_); - dictfile_ = NULL; - return false; - } - if (userdict_->load_dict((const char*)dictfile_, kUserDictIdStart, - kUserDictIdEnd) == false) { - delete userdict_; - userdict_ = NULL; - free(dictfile_); - dictfile_ = NULL; - return false; - } - userdict_->set_limit(kUserDictMaxLemmaCount, kUserDictMaxLemmaSize, kUserDictRatio); - return true; -} -int Sync::put_lemmas(char16* lemmas, int len) { - return userdict_->put_lemmas_no_sync_from_utf16le_string(lemmas, len); -} -int Sync::get_lemmas(char16* str, int size) { - return userdict_->get_sync_lemmas_in_utf16le_string_from_beginning(str, size, &last_count_); -} -int Sync::get_last_got_count() { - return last_count_; -} -int Sync::get_total_count() { - return userdict_->get_sync_count(); -} -void Sync::clear_last_got() { - if (last_count_ < 0) { - return; - } - userdict_->clear_sync_lemmas(0, last_count_); - last_count_ = 0; -} -void Sync::finish() { - if (userdict_) { - userdict_->close_dict(); - delete userdict_; - userdict_ = NULL; - free(dictfile_); - dictfile_ = NULL; - last_count_ = 0; - } -} -int Sync::get_capacity() { - UserDict::UserDictStat stat; - userdict_->state(&stat); - return stat.limit_lemma_count - stat.lemma_count; -} -} // namespace ime_pinyin -#endif diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/sync.h b/Widget/base/Virtual_Keyboard/googlepinyin/sync.h deleted file mode 100644 index 551104f..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/sync.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_SYNC_H__ -#define PINYINIME_INCLUDE_SYNC_H__ -#define ___SYNC_ENABLED___ -#ifdef ___SYNC_ENABLED___ -#include "userdict.h" -namespace ime_pinyin { -// Class for user dictionary synchronization -// This class is not thread safe -// Normal invoking flow will be -// begin() -> -// put_lemmas() x N -> -// { -// get_lemmas() -> -// [ get_last_got_count() ] -> -// clear_last_got() -> -// } x N -> -// finish() -class Sync { -public: - Sync(); - ~Sync(); - static const int kUserDictMaxLemmaCount = 5000; - static const int kUserDictMaxLemmaSize = 200000; - static const int kUserDictRatio = 20; - bool begin(const char* filename); - // Merge lemmas downloaded from sync server into local dictionary - // lemmas, lemmas string encoded in UTF16LE - // len, length of lemmas string - // Return how many lemmas merged successfully - int put_lemmas(char16* lemmas, int len); - // Get local new user lemmas into UTF16LE string - // str, buffer ptr to store new user lemmas - // size, size of buffer - // Return length of returned buffer in measure of UTF16LE - int get_lemmas(char16* str, int size); - // Return lemmas count in last get_lemmas() - int get_last_got_count(); - // Return total lemmas count need get_lemmas() - int get_total_count(); - // Clear lemmas got by recent get_lemmas() - void clear_last_got(); - void finish(); - int get_capacity(); -private: - UserDict* userdict_; - char* dictfile_; - int last_count_; -}; -} // namespace ime_pinyin -#endif -#endif // PINYINIME_INCLUDE_SYNC_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/userdict.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/userdict.cpp deleted file mode 100644 index 00ad80d..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/userdict.cpp +++ /dev/null @@ -1,2078 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "userdict.h" -#include -#include -#include -#include "ngram.h" -#include "splparser.h" -#ifdef ___DEBUG_PERF___ -#include -#endif -#ifdef _WIN32 -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#ifndef _WIN32 -#include -#endif -#include -#ifdef _WIN32 -#undef max -#undef min -#include -#include -#else -#include -#endif -#include -namespace ime_pinyin { -#ifdef _WIN32 -static int gettimeofday(struct timeval* tp, void*) { - const qint64 current_msecs_since_epoch = QDateTime::currentMSecsSinceEpoch(); - tp->tv_sec = (long)(current_msecs_since_epoch / 1000); - tp->tv_usec = (long)((current_msecs_since_epoch % 1000) * 1000); - return 0; -} -#endif -#ifdef ___DEBUG_PERF___ -static uint64 _ellapse_ = 0; -static struct timeval _tv_start_, _tv_end_; -#define DEBUG_PERF_BEGIN \ - do { \ - gettimeofday(&_tv_start_, NULL); \ - } \ - while (0) -#define DEBUG_PERF_END \ - do { \ - gettimeofday(&_tv_end_, NULL); \ - _ellapse_ = (_tv_end_.tv_sec - _tv_start_.tv_sec) * 1000000 + \ - (_tv_end_.tv_usec - _tv_start_.tv_usec); \ - } \ - while (0) -#define LOGD_PERF(message) \ - ALOGD("PERFORMANCE[%s] %llu usec.", message, _ellapse_); -#else -#define DEBUG_PERF_BEGIN -#define DEBUG_PERF_END -#define LOGD_PERF(message) -#endif -// XXX File load and write are thread-safe by g_mutex_ -#ifdef _WIN32 -static QMutex g_mutex_; -#define pthread_mutex_lock(MUTEX) ((MUTEX)->lock()) -#define pthread_mutex_unlock(MUTEX) ((MUTEX)->unlock()) -#define pthread_mutex_trylock(MUTEX) (!(MUTEX)->tryLock(0)) -#else -static pthread_mutex_t g_mutex_ = PTHREAD_MUTEX_INITIALIZER; -#endif -static struct timeval g_last_update_ = {0, 0}; -inline uint32 UserDict::get_dict_file_size(UserDictInfo* info) { - return (4 + info->lemma_size + (info->lemma_count << 3) -#ifdef ___PREDICT_ENABLED___ - + (info->lemma_count << 2) -#endif -#ifdef ___SYNC_ENABLED___ - + (info->sync_count << 2) -#endif - + sizeof(*info)); -} -inline LmaScoreType UserDict::translate_score(int raw_score) { - // 1) ori_freq: original user frequency - uint32 ori_freq = extract_score_freq(raw_score); - // 2) lmt_off: lmt index (week offset for example) - uint64 lmt_off = ((raw_score & 0xffff0000) >> 16); - if (kUserDictLMTBitWidth < 16) { - uint64 mask = ~(1 << kUserDictLMTBitWidth); - lmt_off &= mask; - } - // 3) now_off: current time index (current week offset for example) - // assuming load_time_ is around current time - uint64 now_off = load_time_.tv_sec; - now_off = (now_off - kUserDictLMTSince) / kUserDictLMTGranularity; - now_off = (now_off << (64 - kUserDictLMTBitWidth)); - now_off = (now_off >> (64 - kUserDictLMTBitWidth)); - // 4) factor: decide expand-factor - int delta = now_off - lmt_off; - if (delta > 4) - delta = 4; - int factor = 80 - (delta << 4); - double tf = (double)(dict_info_.total_nfreq + total_other_nfreq_); - return (LmaScoreType)(log((double)factor * (double)ori_freq / tf) * NGram::kLogValueAmplifier); -} -inline int UserDict::extract_score_freq(int raw_score) { - // Frequence stored in lowest 16 bits - int freq = (raw_score & 0x0000ffff); - return freq; -} -inline uint64 UserDict::extract_score_lmt(int raw_score) { - uint64 lmt = ((raw_score & 0xffff0000) >> 16); - if (kUserDictLMTBitWidth < 16) { - uint64 mask = ~(1 << kUserDictLMTBitWidth); - lmt &= mask; - } - lmt = lmt * kUserDictLMTGranularity + kUserDictLMTSince; - return lmt; -} -inline int UserDict::build_score(uint64 lmt, int freq) { - lmt = (lmt - kUserDictLMTSince) / kUserDictLMTGranularity; - lmt = (lmt << (64 - kUserDictLMTBitWidth)); - lmt = (lmt >> (64 - kUserDictLMTBitWidth)); - uint16 lmt16 = (uint16)lmt; - int s = freq; - s &= 0x0000ffff; - s = (lmt16 << 16) | s; - return s; -} -inline int64 UserDict::utf16le_atoll(uint16* s, int len) { - int64 ret = 0; - if (len <= 0) - return ret; - int flag = 1; - const uint16* endp = s + len; - if (*s == '-') { - flag = -1; - s++; - } - else if (*s == '+') { - s++; - } - while (*s >= '0' && *s <= '9' && s < endp) { - ret += ret * 10 + (*s) - '0'; - s++; - } - return ret * flag; -} -inline int UserDict::utf16le_lltoa(int64 v, uint16* s, int size) { - if (!s || size <= 0) - return 0; - uint16* endp = s + size; - int ret_len = 0; - if (v < 0) { - *(s++) = '-'; - ++ret_len; - v *= -1; - } - uint16* b = s; - while (s < endp && v != 0) { - *(s++) = '0' + (v % 10); - v = v / 10; - ++ret_len; - } - if (v != 0) - return 0; - --s; - while (b < s) { - *b = *s; - ++b, --s; - } - return ret_len; -} -inline void UserDict::set_lemma_flag(uint32 offset, uint8 flag) { - offset &= kUserDictOffsetMask; - lemmas_[offset] |= flag; -} -inline char UserDict::get_lemma_flag(uint32 offset) { - offset &= kUserDictOffsetMask; - return (char)(lemmas_[offset]); -} -inline char UserDict::get_lemma_nchar(uint32 offset) { - offset &= kUserDictOffsetMask; - return (char)(lemmas_[offset + 1]); -} -inline uint16* UserDict::get_lemma_spell_ids(uint32 offset) { - offset &= kUserDictOffsetMask; - return (uint16*)(lemmas_ + offset + 2); -} -inline uint16* UserDict::get_lemma_word(uint32 offset) { - offset &= kUserDictOffsetMask; - uint8 nchar = get_lemma_nchar(offset); - return (uint16*)(lemmas_ + offset + 2 + (nchar << 1)); -} -inline LemmaIdType UserDict::get_max_lemma_id() { - // When a lemma is deleted, we don't not claim its id back for - // simplicity and performance - return start_id_ + dict_info_.lemma_count - 1; -} -inline bool UserDict::is_valid_lemma_id(LemmaIdType id) { - if (id >= start_id_ && id <= get_max_lemma_id()) - return true; - return false; -} -inline bool UserDict::is_valid_state() { - if (state_ == USER_DICT_NONE) - return false; - return true; -} -UserDict::UserDict() : start_id_(0), - version_(0), - lemmas_(NULL), - offsets_(NULL), - scores_(NULL), - ids_(NULL), -#ifdef ___PREDICT_ENABLED___ - predicts_(NULL), -#endif -#ifdef ___SYNC_ENABLED___ - syncs_(NULL), - sync_count_size_(0), -#endif - offsets_by_id_(NULL), - lemma_count_left_(0), - lemma_size_left_(0), - dict_file_(NULL), - state_(USER_DICT_NONE) { - memset(&dict_info_, 0, sizeof(dict_info_)); - memset(&load_time_, 0, sizeof(load_time_)); -#ifdef ___CACHE_ENABLED___ - cache_init(); -#endif -} -UserDict::~UserDict() { - close_dict(); -} -bool UserDict::load_dict(const char* file_name, LemmaIdType start_id, - LemmaIdType end_id) { -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_BEGIN; -#endif - dict_file_ = strdup(file_name); - if (!dict_file_) - return false; - start_id_ = start_id; - if (false == validate(file_name) && false == reset(file_name)) { - goto error; - } - if (false == load(file_name, start_id)) { - goto error; - } - state_ = USER_DICT_SYNC; - gettimeofday(&load_time_, NULL); -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_END; - LOGD_PERF("load_dict"); -#endif - return true; -error: - free((void*)dict_file_); - dict_file_ = NULL; - start_id_ = 0; - return false; -} -bool UserDict::close_dict() { - if (state_ == USER_DICT_NONE) - return true; - if (state_ == USER_DICT_SYNC) - goto out; - // If dictionary is written back by others, - // we can not simply write back here - // To do a safe flush, we have to discard all newly added - // lemmas and try to reload dict file. - pthread_mutex_lock(&g_mutex_); - if (load_time_.tv_sec > g_last_update_.tv_sec || - (load_time_.tv_sec == g_last_update_.tv_sec && - load_time_.tv_usec > g_last_update_.tv_usec)) { - write_back(); - gettimeofday(&g_last_update_, NULL); - } - pthread_mutex_unlock(&g_mutex_); -out: - free((void*)dict_file_); - free(lemmas_); - free(offsets_); - free(offsets_by_id_); - free(scores_); - free(ids_); -#ifdef ___PREDICT_ENABLED___ - free(predicts_); -#endif - version_ = 0; - dict_file_ = NULL; - lemmas_ = NULL; -#ifdef ___SYNC_ENABLED___ - syncs_ = NULL; - sync_count_size_ = 0; -#endif - offsets_ = NULL; - offsets_by_id_ = NULL; - scores_ = NULL; - ids_ = NULL; -#ifdef ___PREDICT_ENABLED___ - predicts_ = NULL; -#endif - memset(&dict_info_, 0, sizeof(dict_info_)); - lemma_count_left_ = 0; - lemma_size_left_ = 0; - state_ = USER_DICT_NONE; - return true; -} -size_t UserDict::number_of_lemmas() { - return dict_info_.lemma_count; -} -void UserDict::reset_milestones(uint16 from_step, MileStoneHandle from_handle) { - return; -} -MileStoneHandle UserDict::extend_dict(MileStoneHandle from_handle, - const DictExtPara* dep, - LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num) { - if (is_valid_state() == false) - return 0; - bool need_extend = false; -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_BEGIN; -#endif - *lpi_num = _get_lpis(dep->splids, dep->splids_extended + 1, - lpi_items, lpi_max, &need_extend); -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_END; - LOGD_PERF("extend_dict"); -#endif - return ((*lpi_num > 0 || need_extend) ? 1 : 0); -} -int UserDict::is_fuzzy_prefix_spell_id( -const uint16* id1, uint16 len1, const UserDictSearchable* searchable) { - if (len1 < searchable->splids_len) - return 0; - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - uint32 i = 0; - for (i = 0; i < searchable->splids_len; i++) { - const char py1 = *spl_trie.get_spelling_str(id1[i]); - uint16 off = 8 * (i % 4); - const char py2 = ((searchable->signature[i / 4] & (0xff << off)) >> off); - if (py1 == py2) - continue; - return 0; - } - return 1; -} -int UserDict::fuzzy_compare_spell_id( -const uint16* id1, uint16 len1, const UserDictSearchable* searchable) { - if (len1 < searchable->splids_len) - return -1; - if (len1 > searchable->splids_len) - return 1; - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - uint32 i = 0; - for (i = 0; i < len1; i++) { - const char py1 = *spl_trie.get_spelling_str(id1[i]); - uint16 off = 8 * (i % 4); - const char py2 = ((searchable->signature[i / 4] & (0xff << off)) >> off); - if (py1 == py2) - continue; - if (py1 > py2) - return 1; - return -1; - } - return 0; -} -bool UserDict::is_prefix_spell_id( -const uint16* fullids, uint16 fulllen, -const UserDictSearchable* searchable) { - if (fulllen < searchable->splids_len) - return false; - uint32 i = 0; - for (; i < searchable->splids_len; i++) { - uint16 start_id = searchable->splid_start[i]; - uint16 count = searchable->splid_count[i]; - if (fullids[i] >= start_id && fullids[i] < start_id + count) - continue; - else - return false; - } - return true; -} -bool UserDict::equal_spell_id( -const uint16* fullids, uint16 fulllen, -const UserDictSearchable* searchable) { - if (fulllen != searchable->splids_len) - return false; - uint32 i = 0; - for (; i < fulllen; i++) { - uint16 start_id = searchable->splid_start[i]; - uint16 count = searchable->splid_count[i]; - if (fullids[i] >= start_id && fullids[i] < start_id + count) - continue; - else - return false; - } - return true; -} -int32 UserDict::locate_first_in_offsets(const UserDictSearchable* searchable) { - int32 begin = 0; - int32 end = dict_info_.lemma_count - 1; - int32 middle = -1; - int32 first_prefix = middle; - int32 last_matched = middle; - while (begin <= end) { - middle = (begin + end) >> 1; - uint32 offset = offsets_[middle]; - uint8 nchar = get_lemma_nchar(offset); - const uint16* splids = get_lemma_spell_ids(offset); - int cmp = fuzzy_compare_spell_id(splids, nchar, searchable); - int pre = is_fuzzy_prefix_spell_id(splids, nchar, searchable); - if (pre) - first_prefix = middle; - if (cmp < 0) { - begin = middle + 1; - } - else if (cmp > 0) { - end = middle - 1; - } - else { - end = middle - 1; - last_matched = middle; - } - } - return first_prefix; -} -void UserDict::prepare_locate(UserDictSearchable* searchable, - const uint16* splid_str, - uint16 splid_str_len) { - searchable->splids_len = splid_str_len; - memset(searchable->signature, 0, sizeof(searchable->signature)); - SpellingTrie& spl_trie = SpellingTrie::get_instance(); - uint32 i = 0; - for (; i < splid_str_len; i++) { - if (spl_trie.is_half_id(splid_str[i])) { - searchable->splid_count[i] = - spl_trie.half_to_full(splid_str[i], - &(searchable->splid_start[i])); - } - else { - searchable->splid_count[i] = 1; - searchable->splid_start[i] = splid_str[i]; - } - const unsigned char py = *spl_trie.get_spelling_str(splid_str[i]); - searchable->signature[i >> 2] |= (py << (8 * (i % 4))); - } -} -size_t UserDict::get_lpis(const uint16* splid_str, uint16 splid_str_len, - LmaPsbItem* lpi_items, size_t lpi_max) { - return _get_lpis(splid_str, splid_str_len, lpi_items, lpi_max, NULL); -} -size_t UserDict::_get_lpis(const uint16* splid_str, - uint16 splid_str_len, LmaPsbItem* lpi_items, - size_t lpi_max, bool* need_extend) { - bool tmp_extend; - if (!need_extend) - need_extend = &tmp_extend; - *need_extend = false; - if (is_valid_state() == false) - return 0; - if (lpi_max <= 0) - return 0; - if (0 == pthread_mutex_trylock(&g_mutex_)) { - if (load_time_.tv_sec < g_last_update_.tv_sec || - (load_time_.tv_sec == g_last_update_.tv_sec && - load_time_.tv_usec < g_last_update_.tv_usec)) { - // Others updated disk file, have to reload - pthread_mutex_unlock(&g_mutex_); - flush_cache(); - } - else { - pthread_mutex_unlock(&g_mutex_); - } - } - else { - } - UserDictSearchable searchable; - prepare_locate(&searchable, splid_str, splid_str_len); - uint32 max_off = dict_info_.lemma_count; -#ifdef ___CACHE_ENABLED___ - int32 middle; - uint32 start, count; - bool cached = cache_hit(&searchable, &start, &count); - if (cached) { - middle = start; - max_off = start + count; - } - else { - middle = locate_first_in_offsets(&searchable); - start = middle; - } -#else - int32 middle = locate_first_in_offsets(&searchable); -#endif - if (middle == -1) { -#ifdef ___CACHE_ENABLED___ - if (!cached) - cache_push(USER_DICT_MISS_CACHE, &searchable, 0, 0); -#endif - return 0; - } - size_t lpi_current = 0; - bool fuzzy_break = false; - bool prefix_break = false; - while ((size_t)middle < max_off && !fuzzy_break && !prefix_break) { - if (lpi_current >= lpi_max) - break; - uint32 offset = offsets_[middle]; - // Ignore deleted lemmas - if (offset & kUserDictOffsetFlagRemove) { - middle++; - continue; - } - uint8 nchar = get_lemma_nchar(offset); - uint16* splids = get_lemma_spell_ids(offset); -#ifdef ___CACHE_ENABLED___ - if (!cached && 0 != fuzzy_compare_spell_id(splids, nchar, &searchable)) { -#else - if (0 != fuzzy_compare_spell_id(splids, nchar, &searchable)) { -#endif - fuzzy_break = true; - } - if (prefix_break == false) { - if (is_fuzzy_prefix_spell_id(splids, nchar, &searchable)) { - if (*need_extend == false && - is_prefix_spell_id(splids, nchar, &searchable)) { - *need_extend = true; - } - } - else { - prefix_break = true; - } - } - if (equal_spell_id(splids, nchar, &searchable) == true) { - lpi_items[lpi_current].psb = translate_score(scores_[middle]); - lpi_items[lpi_current].id = ids_[middle]; - lpi_items[lpi_current].lma_len = nchar; - lpi_current++; - } - middle++; - } -#ifdef ___CACHE_ENABLED___ - if (!cached) { - count = middle - start; - cache_push(USER_DICT_CACHE, &searchable, start, count); - } -#endif - return lpi_current; -} -uint16 UserDict::get_lemma_str(LemmaIdType id_lemma, char16* str_buf, - uint16 str_max) { - if (is_valid_state() == false) - return 0; - if (is_valid_lemma_id(id_lemma) == false) - return 0; - uint32 offset = offsets_by_id_[id_lemma - start_id_]; - uint8 nchar = get_lemma_nchar(offset); - char16* str = get_lemma_word(offset); - uint16 m = nchar < str_max - 1 ? nchar : str_max - 1; - int i = 0; - for (; i < m; i++) { - str_buf[i] = str[i]; - } - str_buf[i] = 0; - return m; -} -uint16 UserDict::get_lemma_splids(LemmaIdType id_lemma, uint16* splids, - uint16 splids_max, bool arg_valid) { - if (is_valid_lemma_id(id_lemma) == false) - return 0; - uint32 offset = offsets_by_id_[id_lemma - start_id_]; - uint8 nchar = get_lemma_nchar(offset); - const uint16* ids = get_lemma_spell_ids(offset); - int i = 0; - for (; i < nchar && i < splids_max; i++) - splids[i] = ids[i]; - return i; -} -size_t UserDict::predict(const char16 last_hzs[], uint16 hzs_len, - NPredictItem* npre_items, size_t npre_max, - size_t b4_used) { - uint32 new_added = 0; -#ifdef ___PREDICT_ENABLED___ - int32 end = dict_info_.lemma_count - 1; - int j = locate_first_in_predicts((const uint16*)last_hzs, hzs_len); - if (j == -1) - return 0; - while (j <= end) { - uint32 offset = predicts_[j]; - // Ignore deleted lemmas - if (offset & kUserDictOffsetFlagRemove) { - j++; - continue; - } - uint32 nchar = get_lemma_nchar(offset); - uint16* words = get_lemma_word(offset); - uint16* splids = get_lemma_spell_ids(offset); - if (nchar <= hzs_len) { - j++; - continue; - } - if (memcmp(words, last_hzs, hzs_len << 1) == 0) { - if (new_added >= npre_max) { - return new_added; - } - uint32 cpy_len = - (nchar < kMaxPredictSize ? (nchar << 1) : (kMaxPredictSize << 1)) - (hzs_len << 1); - npre_items[new_added].his_len = hzs_len; - npre_items[new_added].psb = get_lemma_score(words, splids, nchar); - memcpy(npre_items[new_added].pre_hzs, words + hzs_len, cpy_len); - if ((cpy_len >> 1) < kMaxPredictSize) { - npre_items[new_added].pre_hzs[cpy_len >> 1] = 0; - } - new_added++; - } - else { - break; - } - j++; - } -#endif - return new_added; -} -int32 UserDict::locate_in_offsets(char16 lemma_str[], uint16 splid_str[], - uint16 lemma_len) { - int32 max_off = dict_info_.lemma_count; - UserDictSearchable searchable; - prepare_locate(&searchable, splid_str, lemma_len); -#ifdef ___CACHE_ENABLED___ - int32 off; - uint32 start, count; - bool cached = load_cache(&searchable, &start, &count); - if (cached) { - off = start; - max_off = start + count; - } - else { - off = locate_first_in_offsets(&searchable); - start = off; - } -#else - int32 off = locate_first_in_offsets(&searchable); -#endif - if (off == -1) { - return off; - } - while (off < max_off) { - uint32 offset = offsets_[off]; - if (offset & kUserDictOffsetFlagRemove) { - off++; - continue; - } - uint16* splids = get_lemma_spell_ids(offset); -#ifdef ___CACHE_ENABLED___ - if (!cached && 0 != fuzzy_compare_spell_id(splids, lemma_len, &searchable)) - break; -#else - if (0 != fuzzy_compare_spell_id(splids, lemma_len, &searchable)) - break; -#endif - if (equal_spell_id(splids, lemma_len, &searchable) == true) { - uint16* str = get_lemma_word(offset); - uint32 i = 0; - for (i = 0; i < lemma_len; i++) { - if (str[i] == lemma_str[i]) - continue; - break; - } - if (i < lemma_len) { - off++; - continue; - } -#ifdef ___CACHE_ENABLED___ - // No need to save_cache here, since current function is invoked by - // put_lemma. It's rarely possible for a user input same lemma twice. - // That means first time user type a new lemma, it is newly added into - // user dictionary, then it's possible that user type the same lemma - // again. - // Another reason save_cache can not be invoked here is this function - // aborts when lemma is found, and it never knows the count. -#endif - return off; - } - off++; - } - return -1; -} -#ifdef ___PREDICT_ENABLED___ -uint32 UserDict::locate_where_to_insert_in_predicts( -const uint16* words, int lemma_len) { - int32 begin = 0; - int32 end = dict_info_.lemma_count - 1; - int32 middle = end; - uint32 last_matched = middle; - while (begin <= end) { - middle = (begin + end) >> 1; - uint32 offset = offsets_[middle]; - uint8 nchar = get_lemma_nchar(offset); - const uint16* ws = get_lemma_word(offset); - uint32 minl = nchar < lemma_len ? nchar : lemma_len; - uint32 k = 0; - int cmp = 0; - for (; k < minl; k++) { - if (ws[k] < words[k]) { - cmp = -1; - break; - } - else if (ws[k] > words[k]) { - cmp = 1; - break; - } - } - if (cmp == 0) { - if (nchar < lemma_len) - cmp = -1; - else if (nchar > lemma_len) - cmp = 1; - } - if (cmp < 0) { - begin = middle + 1; - last_matched = middle; - } - else if (cmp > 0) { - end = middle - 1; - } - else { - end = middle - 1; - last_matched = middle; - } - } - return last_matched; -} -int32 UserDict::locate_first_in_predicts(const uint16* words, int lemma_len) { - int32 begin = 0; - int32 end = dict_info_.lemma_count - 1; - int32 middle = -1; - int32 last_matched = middle; - while (begin <= end) { - middle = (begin + end) >> 1; - uint32 offset = offsets_[middle]; - uint8 nchar = get_lemma_nchar(offset); - const uint16* ws = get_lemma_word(offset); - uint32 minl = nchar < lemma_len ? nchar : lemma_len; - uint32 k = 0; - int cmp = 0; - for (; k < minl; k++) { - if (ws[k] < words[k]) { - cmp = -1; - break; - } - else if (ws[k] > words[k]) { - cmp = 1; - break; - } - } - if (cmp == 0) { - if (nchar >= lemma_len) - last_matched = middle; - if (nchar < lemma_len) - cmp = -1; - else if (nchar > lemma_len) - cmp = 1; - } - if (cmp < 0) { - begin = middle + 1; - } - else if (cmp > 0) { - end = middle - 1; - } - else { - end = middle - 1; - } - } - return last_matched; -} -#endif -LemmaIdType UserDict::get_lemma_id(char16 lemma_str[], uint16 splids[], - uint16 lemma_len) { - int32 off = locate_in_offsets(lemma_str, splids, lemma_len); - if (off == -1) { - return 0; - } - return ids_[off]; -} -LmaScoreType UserDict::get_lemma_score(LemmaIdType lemma_id) { - if (is_valid_state() == false) - return 0; - if (is_valid_lemma_id(lemma_id) == false) - return 0; - return translate_score(_get_lemma_score(lemma_id)); -} -LmaScoreType UserDict::get_lemma_score(char16 lemma_str[], uint16 splids[], - uint16 lemma_len) { - if (is_valid_state() == false) - return 0; - return translate_score(_get_lemma_score(lemma_str, splids, lemma_len)); -} -int UserDict::_get_lemma_score(LemmaIdType lemma_id) { - if (is_valid_state() == false) - return 0; - if (is_valid_lemma_id(lemma_id) == false) - return 0; - uint32 offset = offsets_by_id_[lemma_id - start_id_]; - uint32 nchar = get_lemma_nchar(offset); - uint16* spl = get_lemma_spell_ids(offset); - uint16* wrd = get_lemma_word(offset); - int32 off = locate_in_offsets(wrd, spl, nchar); - if (off == -1) { - return 0; - } - return scores_[off]; -} -int UserDict::_get_lemma_score(char16 lemma_str[], uint16 splids[], - uint16 lemma_len) { - if (is_valid_state() == false) - return 0; - int32 off = locate_in_offsets(lemma_str, splids, lemma_len); - if (off == -1) { - return 0; - } - return scores_[off]; -} -#ifdef ___SYNC_ENABLED___ -void UserDict::remove_lemma_from_sync_list(uint32 offset) { - offset &= kUserDictOffsetMask; - uint32 i = 0; - for (; i < dict_info_.sync_count; i++) { - unsigned int off = (syncs_[i] & kUserDictOffsetMask); - if (off == offset) - break; - } - if (i < dict_info_.sync_count) { - syncs_[i] = syncs_[dict_info_.sync_count - 1]; - dict_info_.sync_count--; - } -} -#endif -#ifdef ___PREDICT_ENABLED___ -void UserDict::remove_lemma_from_predict_list(uint32 offset) { - offset &= kUserDictOffsetMask; - uint32 i = 0; - for (; i < dict_info_.lemma_count; i++) { - unsigned int off = (predicts_[i] & kUserDictOffsetMask); - if (off == offset) { - predicts_[i] |= kUserDictOffsetFlagRemove; - break; - } - } -} -#endif -bool UserDict::remove_lemma_by_offset_index(int offset_index) { - if (is_valid_state() == false) - return 0; - int32 off = offset_index; - if (off == -1) { - return false; - } - uint32 offset = offsets_[off]; - uint32 nchar = get_lemma_nchar(offset); - offsets_[off] |= kUserDictOffsetFlagRemove; -#ifdef ___SYNC_ENABLED___ - // Remove corresponding sync item - remove_lemma_from_sync_list(offset); -#endif -#ifdef ___PREDICT_ENABLED___ - remove_lemma_from_predict_list(offset); -#endif - dict_info_.free_count++; - dict_info_.free_size += (2 + (nchar << 2)); - if (state_ < USER_DICT_OFFSET_DIRTY) - state_ = USER_DICT_OFFSET_DIRTY; - return true; -} -bool UserDict::remove_lemma(LemmaIdType lemma_id) { - if (is_valid_state() == false) - return 0; - if (is_valid_lemma_id(lemma_id) == false) - return false; - uint32 offset = offsets_by_id_[lemma_id - start_id_]; - uint32 nchar = get_lemma_nchar(offset); - uint16* spl = get_lemma_spell_ids(offset); - uint16* wrd = get_lemma_word(offset); - int32 off = locate_in_offsets(wrd, spl, nchar); - return remove_lemma_by_offset_index(off); -} -void UserDict::flush_cache() { - LemmaIdType start_id = start_id_; - if (!dict_file_) - return; - const char* file = strdup(dict_file_); - if (!file) - return; - close_dict(); - load_dict(file, start_id, kUserDictIdEnd); - free((void*)file); -#ifdef ___CACHE_ENABLED___ - cache_init(); -#endif - return; -} -bool UserDict::reset(const char* file) { - FILE* fp = fopen(file, "w+"); - if (!fp) { - return false; - } - uint32 version = kUserDictVersion; - size_t wred = fwrite(&version, 1, 4, fp); - UserDictInfo info; - memset(&info, 0, sizeof(info)); - // By default, no limitation for lemma count and size - // thereby, reclaim_ratio is never used - wred += fwrite(&info, 1, sizeof(info), fp); - if (wred != sizeof(info) + sizeof(version)) { - fclose(fp); - unlink(file); - return false; - } - fclose(fp); - return true; -} -bool UserDict::validate(const char* file) { - // b is ignored in POSIX compatible os including Linux - // while b is important flag for Windows to specify binary mode - FILE* fp = fopen(file, "rb"); - if (!fp) { - return false; - } - size_t size; - size_t readed; - uint32 version; - UserDictInfo dict_info; - // validate - int err = fseek(fp, 0, SEEK_END); - if (err) { - goto error; - } - size = ftell(fp); - if (size < 4 + sizeof(dict_info)) { - goto error; - } - err = fseek(fp, 0, SEEK_SET); - if (err) { - goto error; - } - readed = fread(&version, 1, sizeof(version), fp); - if (readed < sizeof(version)) { - goto error; - } - if (version != kUserDictVersion) { - goto error; - } - err = fseek(fp, -1 * sizeof(dict_info), SEEK_END); - if (err) { - goto error; - } - readed = fread(&dict_info, 1, sizeof(dict_info), fp); - if (readed != sizeof(dict_info)) { - goto error; - } - if (size != get_dict_file_size(&dict_info)) { - goto error; - } - fclose(fp); - return true; -error: - fclose(fp); - return false; -} -bool UserDict::load(const char* file, LemmaIdType start_id) { - if (0 != pthread_mutex_trylock(&g_mutex_)) { - return false; - } - // b is ignored in POSIX compatible os including Linux - // while b is important flag for Windows to specify binary mode - FILE* fp = fopen(file, "rb"); - if (!fp) { - pthread_mutex_unlock(&g_mutex_); - return false; - } - size_t readed, toread; - UserDictInfo dict_info; - uint8* lemmas = NULL; - uint32* offsets = NULL; -#ifdef ___SYNC_ENABLED___ - uint32* syncs = NULL; -#endif - uint32* scores = NULL; - uint32* ids = NULL; - uint32* offsets_by_id = NULL; -#ifdef ___PREDICT_ENABLED___ - uint32* predicts = NULL; -#endif - size_t i; - int err; - err = fseek(fp, -1 * sizeof(dict_info), SEEK_END); - if (err) - goto error; - readed = fread(&dict_info, 1, sizeof(dict_info), fp); - if (readed != sizeof(dict_info)) - goto error; - lemmas = (uint8*)malloc( - dict_info.lemma_size + - (kUserDictPreAlloc * (2 + (kUserDictAverageNchar << 2)))); - if (!lemmas) - goto error; - offsets = (uint32*)malloc((dict_info.lemma_count + kUserDictPreAlloc) << 2); - if (!offsets) - goto error; -#ifdef ___PREDICT_ENABLED___ - predicts = (uint32*)malloc((dict_info.lemma_count + kUserDictPreAlloc) << 2); - if (!predicts) - goto error; -#endif -#ifdef ___SYNC_ENABLED___ - syncs = (uint32*)malloc((dict_info.sync_count + kUserDictPreAlloc) << 2); - if (!syncs) - goto error; -#endif - scores = (uint32*)malloc((dict_info.lemma_count + kUserDictPreAlloc) << 2); - if (!scores) - goto error; - ids = (uint32*)malloc((dict_info.lemma_count + kUserDictPreAlloc) << 2); - if (!ids) - goto error; - offsets_by_id = (uint32*)malloc( - (dict_info.lemma_count + kUserDictPreAlloc) << 2); - if (!offsets_by_id) - goto error; - err = fseek(fp, 4, SEEK_SET); - if (err) - goto error; - readed = 0; - while (readed < dict_info.lemma_size && !ferror(fp) && !feof(fp)) { - readed += fread(lemmas + readed, 1, dict_info.lemma_size - readed, fp); - } - if (readed < dict_info.lemma_size) - goto error; - toread = (dict_info.lemma_count << 2); - readed = 0; - while (readed < toread && !ferror(fp) && !feof(fp)) { - readed += fread((((uint8*)offsets) + readed), 1, toread - readed, fp); - } - if (readed < toread) - goto error; -#ifdef ___PREDICT_ENABLED___ - toread = (dict_info.lemma_count << 2); - readed = 0; - while (readed < toread && !ferror(fp) && !feof(fp)) { - readed += fread((((uint8*)predicts) + readed), 1, toread - readed, fp); - } - if (readed < toread) - goto error; -#endif - readed = 0; - while (readed < toread && !ferror(fp) && !feof(fp)) { - readed += fread((((uint8*)scores) + readed), 1, toread - readed, fp); - } - if (readed < toread) - goto error; -#ifdef ___SYNC_ENABLED___ - toread = (dict_info.sync_count << 2); - readed = 0; - while (readed < toread && !ferror(fp) && !feof(fp)) { - readed += fread((((uint8*)syncs) + readed), 1, toread - readed, fp); - } - if (readed < toread) - goto error; -#endif - for (i = 0; i < dict_info.lemma_count; i++) { - ids[i] = start_id + i; - offsets_by_id[i] = offsets[i]; - } - lemmas_ = lemmas; - offsets_ = offsets; -#ifdef ___SYNC_ENABLED___ - syncs_ = syncs; - sync_count_size_ = dict_info.sync_count + kUserDictPreAlloc; -#endif - offsets_by_id_ = offsets_by_id; - scores_ = scores; - ids_ = ids; -#ifdef ___PREDICT_ENABLED___ - predicts_ = predicts; -#endif - lemma_count_left_ = kUserDictPreAlloc; - lemma_size_left_ = kUserDictPreAlloc * (2 + (kUserDictAverageNchar << 2)); - memcpy(&dict_info_, &dict_info, sizeof(dict_info)); - state_ = USER_DICT_SYNC; - fclose(fp); - pthread_mutex_unlock(&g_mutex_); - return true; -error: - if (lemmas) - free(lemmas); - if (offsets) - free(offsets); -#ifdef ___SYNC_ENABLED___ - if (syncs) - free(syncs); -#endif - if (scores) - free(scores); - if (ids) - free(ids); - if (offsets_by_id) - free(offsets_by_id); -#ifdef ___PREDICT_ENABLED___ - if (predicts) - free(predicts); -#endif - fclose(fp); - pthread_mutex_unlock(&g_mutex_); - return false; -} -void UserDict::write_back() { - // XXX write back is only allowed from close_dict due to thread-safe sake - if (state_ == USER_DICT_NONE || state_ == USER_DICT_SYNC) - return; - int fd = open(dict_file_, O_WRONLY); - if (fd == -1) - return; - switch (state_) { - case USER_DICT_DEFRAGMENTED: - write_back_all(fd); - break; - case USER_DICT_LEMMA_DIRTY: - write_back_lemma(fd); - break; - case USER_DICT_OFFSET_DIRTY: - write_back_offset(fd); - break; - case USER_DICT_SCORE_DIRTY: - write_back_score(fd); - break; -#ifdef ___SYNC_ENABLED___ - case USER_DICT_SYNC_DIRTY: - write_back_sync(fd); - break; -#endif - default: - break; - } - // It seems truncate is not need on Linux, Windows except Mac - // I am doing it here anyway for safety. - off_t cur = lseek(fd, 0, SEEK_CUR); -#ifndef _WIN32 - ftruncate(fd, cur); -#endif - close(fd); - state_ = USER_DICT_SYNC; -} -#ifdef ___SYNC_ENABLED___ -void UserDict::write_back_sync(int fd) { - int err = lseek(fd, 4 + dict_info_.lemma_size + (dict_info_.lemma_count << 3) -#ifdef ___PREDICT_ENABLED___ - + (dict_info_.lemma_count << 2) -#endif - , - SEEK_SET); - if (err == -1) - return; - write(fd, syncs_, dict_info_.sync_count << 2); - write(fd, &dict_info_, sizeof(dict_info_)); -} -#endif -void UserDict::write_back_offset(int fd) { - int err = lseek(fd, 4 + dict_info_.lemma_size, SEEK_SET); - if (err == -1) - return; - write(fd, offsets_, dict_info_.lemma_count << 2); -#ifdef ___PREDICT_ENABLED___ - write(fd, predicts_, dict_info_.lemma_count << 2); -#endif - write(fd, scores_, dict_info_.lemma_count << 2); -#ifdef ___SYNC_ENABLED___ - write(fd, syncs_, dict_info_.sync_count << 2); -#endif - write(fd, &dict_info_, sizeof(dict_info_)); -} -void UserDict::write_back_score(int fd) { - int err = lseek(fd, 4 + dict_info_.lemma_size + (dict_info_.lemma_count << 2) -#ifdef ___PREDICT_ENABLED___ - + (dict_info_.lemma_count << 2) -#endif - , - SEEK_SET); - if (err == -1) - return; - write(fd, scores_, dict_info_.lemma_count << 2); -#ifdef ___SYNC_ENABLED___ - write(fd, syncs_, dict_info_.sync_count << 2); -#endif - write(fd, &dict_info_, sizeof(dict_info_)); -} -void UserDict::write_back_lemma(int fd) { - int err = lseek(fd, 4, SEEK_SET); - if (err == -1) - return; - // New lemmas are always appended, no need to write whole lemma block - size_t need_write = kUserDictPreAlloc * - (2 + (kUserDictAverageNchar << 2)) - - lemma_size_left_; - err = lseek(fd, dict_info_.lemma_size - need_write, SEEK_CUR); - if (err == -1) - return; - write(fd, lemmas_ + dict_info_.lemma_size - need_write, need_write); - write(fd, offsets_, dict_info_.lemma_count << 2); -#ifdef ___PREDICT_ENABLED___ - write(fd, predicts_, dict_info_.lemma_count << 2); -#endif - write(fd, scores_, dict_info_.lemma_count << 2); -#ifdef ___SYNC_ENABLED___ - write(fd, syncs_, dict_info_.sync_count << 2); -#endif - write(fd, &dict_info_, sizeof(dict_info_)); -} -void UserDict::write_back_all(int fd) { - // XXX lemma_size is handled differently in writeall - // and writelemma. I update lemma_size and lemma_count in different - // places for these two cases. Should fix it to make it consistent. - int err = lseek(fd, 4, SEEK_SET); - if (err == -1) - return; - write(fd, lemmas_, dict_info_.lemma_size); - write(fd, offsets_, dict_info_.lemma_count << 2); -#ifdef ___PREDICT_ENABLED___ - write(fd, predicts_, dict_info_.lemma_count << 2); -#endif - write(fd, scores_, dict_info_.lemma_count << 2); -#ifdef ___SYNC_ENABLED___ - write(fd, syncs_, dict_info_.sync_count << 2); -#endif - write(fd, &dict_info_, sizeof(dict_info_)); -} -#ifdef ___CACHE_ENABLED___ -bool UserDict::load_cache(UserDictSearchable* searchable, - uint32* offset, uint32* length) { - UserDictCache* cache = &caches_[searchable->splids_len - 1]; - if (cache->head == cache->tail) - return false; - uint16 j, sig_len = kMaxLemmaSize / 4; - uint16 i = cache->head; - while (1) { - j = 0; - for (; j < sig_len; j++) { - if (cache->signatures[i][j] != searchable->signature[j]) - break; - } - if (j < sig_len) { - i++; - if (i >= kUserDictCacheSize) - i -= kUserDictCacheSize; - if (i == cache->tail) - break; - continue; - } - *offset = cache->offsets[i]; - *length = cache->lengths[i]; - return true; - } - return false; -} -void UserDict::save_cache(UserDictSearchable* searchable, - uint32 offset, uint32 length) { - UserDictCache* cache = &caches_[searchable->splids_len - 1]; - uint16 next = cache->tail; - cache->offsets[next] = offset; - cache->lengths[next] = length; - uint16 sig_len = kMaxLemmaSize / 4; - uint16 j = 0; - for (; j < sig_len; j++) { - cache->signatures[next][j] = searchable->signature[j]; - } - if (++next >= kUserDictCacheSize) { - next -= kUserDictCacheSize; - } - if (next == cache->head) { - cache->head++; - if (cache->head >= kUserDictCacheSize) { - cache->head -= kUserDictCacheSize; - } - } - cache->tail = next; -} -void UserDict::reset_cache() { - memset(caches_, 0, sizeof(caches_)); -} -bool UserDict::load_miss_cache(UserDictSearchable* searchable) { - UserDictMissCache* cache = &miss_caches_[searchable->splids_len - 1]; - if (cache->head == cache->tail) - return false; - uint16 j, sig_len = kMaxLemmaSize / 4; - uint16 i = cache->head; - while (1) { - j = 0; - for (; j < sig_len; j++) { - if (cache->signatures[i][j] != searchable->signature[j]) - break; - } - if (j < sig_len) { - i++; - if (i >= kUserDictMissCacheSize) - i -= kUserDictMissCacheSize; - if (i == cache->tail) - break; - continue; - } - return true; - } - return false; -} -void UserDict::save_miss_cache(UserDictSearchable* searchable) { - UserDictMissCache* cache = &miss_caches_[searchable->splids_len - 1]; - uint16 next = cache->tail; - uint16 sig_len = kMaxLemmaSize / 4; - uint16 j = 0; - for (; j < sig_len; j++) { - cache->signatures[next][j] = searchable->signature[j]; - } - if (++next >= kUserDictMissCacheSize) { - next -= kUserDictMissCacheSize; - } - if (next == cache->head) { - cache->head++; - if (cache->head >= kUserDictMissCacheSize) { - cache->head -= kUserDictMissCacheSize; - } - } - cache->tail = next; -} -void UserDict::reset_miss_cache() { - memset(miss_caches_, 0, sizeof(miss_caches_)); -} -void UserDict::cache_init() { - reset_cache(); - reset_miss_cache(); -} -bool UserDict::cache_hit(UserDictSearchable* searchable, - uint32* offset, uint32* length) { - bool hit = load_miss_cache(searchable); - if (hit) { - *offset = 0; - *length = 0; - return true; - } - hit = load_cache(searchable, offset, length); - if (hit) { - return true; - } - return false; -} -void UserDict::cache_push(UserDictCacheType type, - UserDictSearchable* searchable, - uint32 offset, uint32 length) { - switch (type) { - case USER_DICT_MISS_CACHE: - save_miss_cache(searchable); - break; - case USER_DICT_CACHE: - save_cache(searchable, offset, length); - break; - default: - break; - } -} -#endif -void UserDict::defragment(void) { -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_BEGIN; -#endif - if (is_valid_state() == false) - return; - // Fixup offsets_, set REMOVE flag to lemma's flag if needed - size_t first_freed = 0; - size_t first_inuse = 0; - while (first_freed < dict_info_.lemma_count) { - // Find first freed offset - while ((offsets_[first_freed] & kUserDictOffsetFlagRemove) == 0 && - first_freed < dict_info_.lemma_count) { - first_freed++; - } - if (first_freed < dict_info_.lemma_count) { - // Save REMOVE flag to lemma flag - int off = offsets_[first_freed]; - set_lemma_flag(off, kUserDictLemmaFlagRemove); - } - else { - break; - } - // Find first inuse offse after first_freed - first_inuse = first_freed + 1; - while ((offsets_[first_inuse] & kUserDictOffsetFlagRemove) && - (first_inuse < dict_info_.lemma_count)) { - // Save REMOVE flag to lemma flag - int off = offsets_[first_inuse]; - set_lemma_flag(off, kUserDictLemmaFlagRemove); - first_inuse++; - } - if (first_inuse >= dict_info_.lemma_count) { - break; - } - // Swap offsets_ - int tmp = offsets_[first_inuse]; - offsets_[first_inuse] = offsets_[first_freed]; - offsets_[first_freed] = tmp; - // Move scores_, no need to swap - tmp = scores_[first_inuse]; - scores_[first_inuse] = scores_[first_freed]; - scores_[first_freed] = tmp; - // Swap ids_ - LemmaIdType tmpid = ids_[first_inuse]; - ids_[first_inuse] = ids_[first_freed]; - ids_[first_freed] = tmpid; - // Go on - first_freed++; - } -#ifdef ___PREDICT_ENABLED___ - // Fixup predicts_ - first_freed = 0; - first_inuse = 0; - while (first_freed < dict_info_.lemma_count) { - // Find first freed offset - while ((predicts_[first_freed] & kUserDictOffsetFlagRemove) == 0 && - first_freed < dict_info_.lemma_count) { - first_freed++; - } - if (first_freed >= dict_info_.lemma_count) - break; - // Find first inuse offse after first_freed - first_inuse = first_freed + 1; - while ((predicts_[first_inuse] & kUserDictOffsetFlagRemove) && (first_inuse < dict_info_.lemma_count)) { - first_inuse++; - } - if (first_inuse >= dict_info_.lemma_count) { - break; - } - // Swap offsets_ - int tmp = predicts_[first_inuse]; - predicts_[first_inuse] = predicts_[first_freed]; - predicts_[first_freed] = tmp; - // Go on - first_freed++; - } -#endif - dict_info_.lemma_count = first_freed; - // Fixup lemmas_ - size_t begin = 0; - size_t end = 0; - size_t dst = 0; - int total_size = dict_info_.lemma_size + lemma_size_left_; - int total_count = dict_info_.lemma_count + lemma_count_left_; - size_t real_size = total_size - lemma_size_left_; - while (dst < real_size) { - unsigned char flag = get_lemma_flag(dst); - unsigned char nchr = get_lemma_nchar(dst); - if ((flag & kUserDictLemmaFlagRemove) == 0) { - dst += nchr * 4 + 2; - continue; - } - break; - } - if (dst >= real_size) - return; - end = dst; - while (end < real_size) { - begin = end + get_lemma_nchar(end) * 4 + 2; - repeat: - // not used any more - if (begin >= real_size) - break; - unsigned char flag = get_lemma_flag(begin); - unsigned char nchr = get_lemma_nchar(begin); - if (flag & kUserDictLemmaFlagRemove) { - begin += nchr * 4 + 2; - goto repeat; - } - end = begin + nchr * 4 + 2; - while (end < real_size) { - unsigned char eflag = get_lemma_flag(end); - unsigned char enchr = get_lemma_nchar(end); - if ((eflag & kUserDictLemmaFlagRemove) == 0) { - end += enchr * 4 + 2; - continue; - } - break; - } - memmove(lemmas_ + dst, lemmas_ + begin, end - begin); - for (size_t j = 0; j < dict_info_.lemma_count; j++) { - if (offsets_[j] >= begin && offsets_[j] < end) { - offsets_[j] -= (begin - dst); - offsets_by_id_[ids_[j] - start_id_] = offsets_[j]; - } -#ifdef ___PREDICT_ENABLED___ - if (predicts_[j] >= begin && predicts_[j] < end) { - predicts_[j] -= (begin - dst); - } -#endif - } -#ifdef ___SYNC_ENABLED___ - for (size_t j = 0; j < dict_info_.sync_count; j++) { - if (syncs_[j] >= begin && syncs_[j] < end) { - syncs_[j] -= (begin - dst); - } - } -#endif - dst += (end - begin); - } - dict_info_.free_count = 0; - dict_info_.free_size = 0; - dict_info_.lemma_size = dst; - lemma_size_left_ = total_size - dict_info_.lemma_size; - lemma_count_left_ = total_count - dict_info_.lemma_count; - // XXX Without following code, - // offsets_by_id_ is not reordered. - // That's to say, all removed lemmas' ids are not collected back. - // There may not be room for addition of new lemmas due to - // offsests_by_id_ reason, although lemma_size_left_ is fixed. - // By default, we do want defrag as fast as possible, because - // during defrag procedure, other peers can not write new lemmas - // to user dictionary file. - // XXX If write-back is invoked immediately after - // this defragment, no need to fix up following in-mem data. - for (uint32 i = 0; i < dict_info_.lemma_count; i++) { - ids_[i] = start_id_ + i; - offsets_by_id_[i] = offsets_[i]; - } - state_ = USER_DICT_DEFRAGMENTED; -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_END; - LOGD_PERF("defragment"); -#endif -} -#ifdef ___SYNC_ENABLED___ -void UserDict::clear_sync_lemmas(unsigned int start, unsigned int end) { - if (is_valid_state() == false) - return; - if (end > dict_info_.sync_count) - end = dict_info_.sync_count; - memmove(syncs_ + start, syncs_ + end, (dict_info_.sync_count - end) << 2); - dict_info_.sync_count -= (end - start); - if (state_ < USER_DICT_SYNC_DIRTY) - state_ = USER_DICT_SYNC_DIRTY; -} -int UserDict::get_sync_count() { - if (is_valid_state() == false) - return 0; - return dict_info_.sync_count; -} -LemmaIdType UserDict::put_lemma_no_sync(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count, uint64 lmt) { - int again = 0; -begin: - LemmaIdType id; - uint32* syncs_bak = syncs_; - syncs_ = NULL; - id = _put_lemma(lemma_str, splids, lemma_len, count, lmt); - syncs_ = syncs_bak; - if (id == 0 && again == 0) { - if ((dict_info_.limit_lemma_count > 0 && - dict_info_.lemma_count >= dict_info_.limit_lemma_count) || - (dict_info_.limit_lemma_size > 0 && - dict_info_.lemma_size + (2 + (lemma_len << 2)) > dict_info_.limit_lemma_size)) { - // XXX Always reclaim and defrag in sync code path - // sync thread is background thread and ok with heavy work - reclaim(); - defragment(); - flush_cache(); - again = 1; - goto begin; - } - } - return id; -} -int UserDict::put_lemmas_no_sync_from_utf16le_string(char16* lemmas, int len) { - int newly_added = 0; - SpellingParser* spl_parser = new SpellingParser(); - if (!spl_parser) { - return 0; - } -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_BEGIN; -#endif - char16* ptr = lemmas; - // Extract pinyin,words,frequence,last_mod_time - char16 *p = ptr, *py16 = ptr; - char16* hz16 = NULL; - int py16_len = 0; - uint16 splid[kMaxLemmaSize]; - int splid_len = 0; - int hz16_len = 0; - char16* fr16 = NULL; - int fr16_len = 0; - while (p - ptr < len) { - // Pinyin - py16 = p; - splid_len = 0; - while (*p != 0x2c && (p - ptr) < len) { - if (*p == 0x20) - splid_len++; - p++; - } - splid_len++; - if (p - ptr == len) - break; - py16_len = p - py16; - if (kMaxLemmaSize < splid_len) { - break; - } - bool is_pre; - int splidl = spl_parser->splstr16_to_idxs_f( - py16, py16_len, splid, NULL, kMaxLemmaSize, is_pre); - if (splidl != splid_len) - break; - // Phrase - hz16 = ++p; - while (*p != 0x2c && (p - ptr) < len) { - p++; - } - hz16_len = p - hz16; - if (hz16_len != splid_len) - break; - // Frequency - fr16 = ++p; - fr16_len = 0; - while (*p != 0x2c && (p - ptr) < len) { - p++; - } - fr16_len = p - fr16; - uint32 intf = (uint32)utf16le_atoll(fr16, fr16_len); - // Last modified time - fr16 = ++p; - fr16_len = 0; - while (*p != 0x3b && (p - ptr) < len) { - p++; - } - fr16_len = p - fr16; - uint64 last_mod = utf16le_atoll(fr16, fr16_len); - put_lemma_no_sync(hz16, splid, splid_len, intf, last_mod); - newly_added++; - p++; - } -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_END; - LOGD_PERF("put_lemmas_no_sync_from_utf16le_string"); -#endif - return newly_added; -} -int UserDict::get_sync_lemmas_in_utf16le_string_from_beginning( -char16* str, int size, int* count) { - int len = 0; - *count = 0; - int left_len = size; - if (is_valid_state() == false) - return len; - SpellingTrie* spl_trie = &SpellingTrie::get_instance(); - if (!spl_trie) { - return 0; - } - uint32 i; - for (i = 0; i < dict_info_.sync_count; i++) { - int offset = syncs_[i]; - uint32 nchar = get_lemma_nchar(offset); - uint16* spl = get_lemma_spell_ids(offset); - uint16* wrd = get_lemma_word(offset); - int score = _get_lemma_score(wrd, spl, nchar); - static char score_temp[32], *pscore_temp = score_temp; - static char16 temp[256], *ptemp = temp; - pscore_temp = score_temp; - ptemp = temp; - uint32 j; - // Add pinyin - for (j = 0; j < nchar; j++) { - int ret_len = spl_trie->get_spelling_str16( - spl[j], ptemp, temp + sizeof(temp) - ptemp); - if (ret_len <= 0) - break; - ptemp += ret_len; - if (ptemp < temp + sizeof(temp) - 1) { - *(ptemp++) = ' '; - } - else { - j = 0; - break; - } - } - if (j < nchar) { - continue; - } - ptemp--; - if (ptemp < temp + sizeof(temp) - 1) { - *(ptemp++) = ','; - } - else { - continue; - } - // Add phrase - for (j = 0; j < nchar; j++) { - if (ptemp < temp + sizeof(temp) - 1) { - *(ptemp++) = wrd[j]; - } - else { - break; - } - } - if (j < nchar) { - continue; - } - if (ptemp < temp + sizeof(temp) - 1) { - *(ptemp++) = ','; - } - else { - continue; - } - // Add frequency - uint32 intf = extract_score_freq(score); - int ret_len = utf16le_lltoa(intf, ptemp, temp + sizeof(temp) - ptemp); - if (ret_len <= 0) - continue; - ptemp += ret_len; - if (ptemp < temp + sizeof(temp) - 1) { - *(ptemp++) = ','; - } - else { - continue; - } - // Add last modified time - uint64 last_mod = extract_score_lmt(score); - ret_len = utf16le_lltoa(last_mod, ptemp, temp + sizeof(temp) - ptemp); - if (ret_len <= 0) - continue; - ptemp += ret_len; - if (ptemp < temp + sizeof(temp) - 1) { - *(ptemp++) = ';'; - } - else { - continue; - } - // Write to string - int need_len = ptemp - temp; - if (need_len > left_len) - break; - memcpy(str + len, temp, need_len * 2); - left_len -= need_len; - len += need_len; - (*count)++; - } - if (len > 0) { - if (state_ < USER_DICT_SYNC_DIRTY) - state_ = USER_DICT_SYNC_DIRTY; - } - return len; -} -#endif -bool UserDict::state(UserDictStat* stat) { - if (is_valid_state() == false) - return false; - if (!stat) - return false; - stat->version = version_; - stat->file_name = dict_file_; - stat->load_time.tv_sec = load_time_.tv_sec; - stat->load_time.tv_usec = load_time_.tv_usec; - pthread_mutex_lock(&g_mutex_); - stat->last_update.tv_sec = g_last_update_.tv_sec; - stat->last_update.tv_usec = g_last_update_.tv_usec; - pthread_mutex_unlock(&g_mutex_); - stat->disk_size = get_dict_file_size(&dict_info_); - stat->lemma_count = dict_info_.lemma_count; - stat->lemma_size = dict_info_.lemma_size; - stat->delete_count = dict_info_.free_count; - stat->delete_size = dict_info_.free_size; -#ifdef ___SYNC_ENABLED___ - stat->sync_count = dict_info_.sync_count; -#endif - stat->limit_lemma_count = dict_info_.limit_lemma_count; - stat->limit_lemma_size = dict_info_.limit_lemma_size; - stat->reclaim_ratio = dict_info_.reclaim_ratio; - return true; -} -void UserDict::set_limit(uint32 max_lemma_count, - uint32 max_lemma_size, uint32 reclaim_ratio) { - dict_info_.limit_lemma_count = max_lemma_count; - dict_info_.limit_lemma_size = max_lemma_size; - if (reclaim_ratio > 100) - reclaim_ratio = 100; - dict_info_.reclaim_ratio = reclaim_ratio; -} -void UserDict::reclaim() { - if (is_valid_state() == false) - return; - switch (dict_info_.reclaim_ratio) { - case 0: - return; - case 100: - // TODO: CLEAR to be implemented - assert(false); - return; - default: - break; - } - // XXX Reclaim is only based on count, not size - uint32 count = dict_info_.lemma_count; - int rc = count * dict_info_.reclaim_ratio / 100; - UserDictScoreOffsetPair* score_offset_pairs = NULL; - score_offset_pairs = (UserDictScoreOffsetPair*)malloc( - sizeof(UserDictScoreOffsetPair) * rc); - if (score_offset_pairs == NULL) { - return; - } - for (int i = 0; i < rc; i++) { - int s = scores_[i]; - score_offset_pairs[i].score = s; - score_offset_pairs[i].offset_index = i; - } - for (int i = (rc + 1) / 2; i >= 0; i--) - shift_down(score_offset_pairs, i, rc); - for (uint32 i = rc; i < dict_info_.lemma_count; i++) { - int s = scores_[i]; - if (s < score_offset_pairs[0].score) { - score_offset_pairs[0].score = s; - score_offset_pairs[0].offset_index = i; - shift_down(score_offset_pairs, 0, rc); - } - } - for (int i = 0; i < rc; i++) { - int off = score_offset_pairs[i].offset_index; - remove_lemma_by_offset_index(off); - } - if (rc > 0) { - if (state_ < USER_DICT_OFFSET_DIRTY) - state_ = USER_DICT_OFFSET_DIRTY; - } - free(score_offset_pairs); -} -inline void UserDict::swap(UserDictScoreOffsetPair* sop, int i, int j) { - int s = sop[i].score; - int p = sop[i].offset_index; - sop[i].score = sop[j].score; - sop[i].offset_index = sop[j].offset_index; - sop[j].score = s; - sop[j].offset_index = p; -} -void UserDict::shift_down(UserDictScoreOffsetPair* sop, int i, int n) { - int par = i; - while (par < n) { - int left = par * 2 + 1; - int right = left + 1; - if (left >= n && right >= n) - break; - if (right >= n) { - if (sop[left].score > sop[par].score) { - swap(sop, left, par); - par = left; - continue; - } - } - else if (sop[left].score > sop[right].score && - sop[left].score > sop[par].score) { - swap(sop, left, par); - par = left; - continue; - } - else if (sop[right].score > sop[left].score && - sop[right].score > sop[par].score) { - swap(sop, right, par); - par = right; - continue; - } - break; - } -} -LemmaIdType UserDict::put_lemma(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count) { - return _put_lemma(lemma_str, splids, lemma_len, count, time(NULL)); -} -LemmaIdType UserDict::_put_lemma(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count, uint64 lmt) { -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_BEGIN; -#endif - if (is_valid_state() == false) - return 0; - int32 off = locate_in_offsets(lemma_str, splids, lemma_len); - if (off != -1) { - int delta_score = count - scores_[off]; - dict_info_.total_nfreq += delta_score; - scores_[off] = build_score(lmt, count); - if (state_ < USER_DICT_SCORE_DIRTY) - state_ = USER_DICT_SCORE_DIRTY; -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_END; - LOGD_PERF("_put_lemma(update)"); -#endif - return ids_[off]; - } - else { - if ((dict_info_.limit_lemma_count > 0 && - dict_info_.lemma_count >= dict_info_.limit_lemma_count) || - (dict_info_.limit_lemma_size > 0 && - dict_info_.lemma_size + (2 + (lemma_len << 2)) > dict_info_.limit_lemma_size)) { - // XXX Don't defragment here, it's too time-consuming. - return 0; - } - int flushed = 0; - if (lemma_count_left_ == 0 || - lemma_size_left_ < (size_t)(2 + (lemma_len << 2))) { - // XXX When there is no space for new lemma, we flush to disk - // flush_cache() may be called by upper user - // and better place shoule be found instead of here - flush_cache(); - flushed = 1; - // Or simply return and do nothing - // return 0; - } -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_END; - LOGD_PERF(flushed ? "_put_lemma(flush+add)" : "_put_lemma(add)"); -#endif - LemmaIdType id = append_a_lemma(lemma_str, splids, lemma_len, count, lmt); -#ifdef ___SYNC_ENABLED___ - if (syncs_ && id != 0) { - queue_lemma_for_sync(id); - } -#endif - return id; - } - return 0; -} -#ifdef ___SYNC_ENABLED___ -void UserDict::queue_lemma_for_sync(LemmaIdType id) { - if (dict_info_.sync_count < sync_count_size_) { - syncs_[dict_info_.sync_count++] = offsets_by_id_[id - start_id_]; - } - else { - uint32* syncs = (uint32*)realloc( - syncs_, (sync_count_size_ + kUserDictPreAlloc) << 2); - if (syncs) { - sync_count_size_ += kUserDictPreAlloc; - syncs_ = syncs; - syncs_[dict_info_.sync_count++] = offsets_by_id_[id - start_id_]; - } - } -} -#endif -LemmaIdType UserDict::update_lemma(LemmaIdType lemma_id, int16 delta_count, - bool selected) { -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_BEGIN; -#endif - if (is_valid_state() == false) - return 0; - if (is_valid_lemma_id(lemma_id) == false) - return 0; - uint32 offset = offsets_by_id_[lemma_id - start_id_]; - uint8 lemma_len = get_lemma_nchar(offset); - char16* lemma_str = get_lemma_word(offset); - uint16* splids = get_lemma_spell_ids(offset); - int32 off = locate_in_offsets(lemma_str, splids, lemma_len); - if (off != -1) { - int score = scores_[off]; - int count = extract_score_freq(score); - uint64 lmt = extract_score_lmt(score); - if (count + delta_count > kUserDictMaxFrequency || - count + delta_count < count) { - delta_count = kUserDictMaxFrequency - count; - } - count += delta_count; - dict_info_.total_nfreq += delta_count; - if (selected) { - lmt = time(NULL); - } - scores_[off] = build_score(lmt, count); - if (state_ < USER_DICT_SCORE_DIRTY) - state_ = USER_DICT_SCORE_DIRTY; -#ifdef ___DEBUG_PERF___ - DEBUG_PERF_END; - LOGD_PERF("update_lemma"); -#endif -#ifdef ___SYNC_ENABLED___ - queue_lemma_for_sync(ids_[off]); -#endif - return ids_[off]; - } - return 0; -} -size_t UserDict::get_total_lemma_count() { - return dict_info_.total_nfreq; -} -void UserDict::set_total_lemma_count_of_others(size_t count) { - total_other_nfreq_ = count; -} -LemmaIdType UserDict::append_a_lemma(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count, uint64 lmt) { - LemmaIdType id = get_max_lemma_id() + 1; - size_t offset = dict_info_.lemma_size; - if (offset > kUserDictOffsetMask) - return 0; - lemmas_[offset] = 0; - lemmas_[offset + 1] = (uint8)lemma_len; - for (size_t i = 0; i < lemma_len; i++) { - *((uint16*)&lemmas_[offset + 2 + (i << 1)]) = splids[i]; - *((char16*)&lemmas_[offset + 2 + (lemma_len << 1) + (i << 1)]) = lemma_str[i]; - } - uint32 off = dict_info_.lemma_count; - offsets_[off] = offset; - scores_[off] = build_score(lmt, count); - ids_[off] = id; -#ifdef ___PREDICT_ENABLED___ - predicts_[off] = offset; -#endif - offsets_by_id_[id - start_id_] = offset; - dict_info_.lemma_count++; - dict_info_.lemma_size += (2 + (lemma_len << 2)); - lemma_count_left_--; - lemma_size_left_ -= (2 + (lemma_len << 2)); - // Sort - UserDictSearchable searchable; - prepare_locate(&searchable, splids, lemma_len); - size_t i = 0; - while (i < off) { - offset = offsets_[i]; - uint32 nchar = get_lemma_nchar(offset); - uint16* spl = get_lemma_spell_ids(offset); - if (0 <= fuzzy_compare_spell_id(spl, nchar, &searchable)) - break; - i++; - } - if (i != off) { - uint32 temp = offsets_[off]; - memmove(offsets_ + i + 1, offsets_ + i, (off - i) << 2); - offsets_[i] = temp; - temp = scores_[off]; - memmove(scores_ + i + 1, scores_ + i, (off - i) << 2); - scores_[i] = temp; - temp = ids_[off]; - memmove(ids_ + i + 1, ids_ + i, (off - i) << 2); - ids_[i] = temp; - } -#ifdef ___PREDICT_ENABLED___ - uint32 j = 0; - uint16* words_new = get_lemma_word(predicts_[off]); - j = locate_where_to_insert_in_predicts(words_new, lemma_len); - if (j != off) { - uint32 temp = predicts_[off]; - memmove(predicts_ + j + 1, predicts_ + j, (off - j) << 2); - predicts_[j] = temp; - } -#endif - if (state_ < USER_DICT_LEMMA_DIRTY) - state_ = USER_DICT_LEMMA_DIRTY; -#ifdef ___CACHE_ENABLED___ - cache_init(); -#endif - dict_info_.total_nfreq += count; - return id; -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/userdict.h b/Widget/base/Virtual_Keyboard/googlepinyin/userdict.h deleted file mode 100644 index ee7fb9e..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/userdict.h +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_USERDICT_H__ -#define PINYINIME_INCLUDE_USERDICT_H__ -#define ___CACHE_ENABLED___ -#define ___SYNC_ENABLED___ -#define ___PREDICT_ENABLED___ -// Debug performance for operations -// #define ___DEBUG_PERF___ -#ifdef _WIN32 -#include // timeval -#else -#include -#endif -#include "atomdictbase.h" -namespace ime_pinyin { -class UserDict : public AtomDictBase { -public: - UserDict(); - ~UserDict(); - bool load_dict(const char* file_name, LemmaIdType start_id, - LemmaIdType end_id); - bool close_dict(); - size_t number_of_lemmas(); - void reset_milestones(uint16 from_step, MileStoneHandle from_handle); - MileStoneHandle extend_dict(MileStoneHandle from_handle, - const DictExtPara* dep, LmaPsbItem* lpi_items, - size_t lpi_max, size_t* lpi_num); - size_t get_lpis(const uint16* splid_str, uint16 splid_str_len, - LmaPsbItem* lpi_items, size_t lpi_max); - uint16 get_lemma_str(LemmaIdType id_lemma, char16* str_buf, - uint16 str_max); - uint16 get_lemma_splids(LemmaIdType id_lemma, uint16* splids, - uint16 splids_max, bool arg_valid); - size_t predict(const char16 last_hzs[], uint16 hzs_len, - NPredictItem* npre_items, size_t npre_max, - size_t b4_used); - // Full spelling ids are required - LemmaIdType put_lemma(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count); - LemmaIdType update_lemma(LemmaIdType lemma_id, int16 delta_count, - bool selected); - LemmaIdType get_lemma_id(char16 lemma_str[], uint16 splids[], - uint16 lemma_len); - LmaScoreType get_lemma_score(LemmaIdType lemma_id); - LmaScoreType get_lemma_score(char16 lemma_str[], uint16 splids[], - uint16 lemma_len); - bool remove_lemma(LemmaIdType lemma_id); - size_t get_total_lemma_count(); - void set_total_lemma_count_of_others(size_t count); - void flush_cache(); - void set_limit(uint32 max_lemma_count, uint32 max_lemma_size, - uint32 reclaim_ratio); - void reclaim(); - void defragment(); -#ifdef ___SYNC_ENABLED___ - void clear_sync_lemmas(unsigned int start, unsigned int end); - int get_sync_count(); - LemmaIdType put_lemma_no_sync(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count, uint64 lmt); - /** - * Add lemmas encoded in UTF-16LE into dictionary without adding sync flag. - * - * @param lemmas in format of 'wo men,WM,0.32;da jia,DJ,0.12' - * @param len length of lemmas string in UTF-16LE - * @return newly added lemma count - */ - int put_lemmas_no_sync_from_utf16le_string(char16* lemmas, int len); - /** - * Get lemmas need sync to a UTF-16LE string of above format. - * Note: input buffer (str) must not be too small. If str is too small to - * contain single one lemma, there might be a dead loop. - * - * @param str buffer to write lemmas - * @param size buffer size in UTF-16LE - * @param count output value of lemma returned - * @return UTF-16LE string length - */ - int get_sync_lemmas_in_utf16le_string_from_beginning( - char16* str, int size, int* count); -#endif - struct UserDictStat { - uint32 version; - const char* file_name; - struct timeval load_time; - struct timeval last_update; - uint32 disk_size; - uint32 lemma_count; - uint32 lemma_size; - uint32 delete_count; - uint32 delete_size; -#ifdef ___SYNC_ENABLED___ - uint32 sync_count; -#endif - uint32 reclaim_ratio; - uint32 limit_lemma_count; - uint32 limit_lemma_size; - }; - bool state(UserDictStat* stat); -private: - uint32 total_other_nfreq_; - struct timeval load_time_; - LemmaIdType start_id_; - uint32 version_; - uint8* lemmas_; - // In-Memory-Only flag for each lemma - static const uint8 kUserDictLemmaFlagRemove = 1; - // Inuse lemmas' offset - uint32* offsets_; - // Highest bit in offset tells whether corresponding lemma is removed - static const uint32 kUserDictOffsetFlagRemove = (1 << 31); - // Maximum possible for the offset - static const uint32 kUserDictOffsetMask = ~(kUserDictOffsetFlagRemove); - // Bit width for last modified time, from 1 to 16 - static const uint32 kUserDictLMTBitWidth = 16; - // Granularity for last modified time in second - static const uint32 kUserDictLMTGranularity = 60 * 60 * 24 * 7; - // Maximum frequency count - static const uint16 kUserDictMaxFrequency = 0xFFFF; -#define COARSE_UTC(year, month, day, hour, minute, second) \ - ( \ - (year - 1970) * 365 * 24 * 60 * 60 + \ - (month - 1) * 30 * 24 * 60 * 60 + \ - (day - 1) * 24 * 60 * 60 + \ - (hour - 0) * 60 * 60 + \ - (minute - 0) * 60 + \ - (second - 0)) - static const uint64 kUserDictLMTSince = COARSE_UTC(2009, 1, 1, 0, 0, 0); - // Correspond to offsets_ - uint32* scores_; - // Following two fields are only valid in memory - uint32* ids_; -#ifdef ___PREDICT_ENABLED___ - uint32* predicts_; -#endif -#ifdef ___SYNC_ENABLED___ - uint32* syncs_; - size_t sync_count_size_; -#endif - uint32* offsets_by_id_; - size_t lemma_count_left_; - size_t lemma_size_left_; - const char* dict_file_; - // Be sure size is 4xN - struct UserDictInfo { - // When limitation reached, how much percentage will be reclaimed (1 ~ 100) - uint32 reclaim_ratio; - // maximum lemma count, 0 means no limitation - uint32 limit_lemma_count; - // Maximum lemma size, it's different from - // whole disk file size or in-mem dict size - // 0 means no limitation - uint32 limit_lemma_size; - // Total lemma count including deleted and inuse - // Also indicate offsets_ size - uint32 lemma_count; - // Total size of lemmas including used and freed - uint32 lemma_size; - // Freed lemma count - uint32 free_count; - // Freed lemma size in byte - uint32 free_size; -#ifdef ___SYNC_ENABLED___ - uint32 sync_count; -#endif - int32 total_nfreq; - } dict_info_; - static const uint32 kUserDictVersion = 0x0ABCDEF0; - static const uint32 kUserDictPreAlloc = 32; - static const uint32 kUserDictAverageNchar = 8; - enum UserDictState { - // Keep in order - USER_DICT_NONE = 0, - USER_DICT_SYNC, -#ifdef ___SYNC_ENABLED___ - USER_DICT_SYNC_DIRTY, -#endif - USER_DICT_SCORE_DIRTY, - USER_DICT_OFFSET_DIRTY, - USER_DICT_LEMMA_DIRTY, - USER_DICT_DEFRAGMENTED, - } state_; - struct UserDictSearchable { - uint16 splids_len; - uint16 splid_start[kMaxLemmaSize]; - uint16 splid_count[kMaxLemmaSize]; - // Compact inital letters for both FuzzyCompareSpellId and cache system - uint32 signature[kMaxLemmaSize / 4]; - }; -#ifdef ___CACHE_ENABLED___ - enum UserDictCacheType { - USER_DICT_CACHE, - USER_DICT_MISS_CACHE, - }; - static const int kUserDictCacheSize = 4; - static const int kUserDictMissCacheSize = kMaxLemmaSize - 1; - struct UserDictMissCache { - uint32 signatures[kUserDictMissCacheSize][kMaxLemmaSize / 4]; - uint16 head, tail; - } miss_caches_[kMaxLemmaSize]; - struct UserDictCache { - uint32 signatures[kUserDictCacheSize][kMaxLemmaSize / 4]; - uint32 offsets[kUserDictCacheSize]; - uint32 lengths[kUserDictCacheSize]; - // Ring buffer - uint16 head, tail; - } caches_[kMaxLemmaSize]; - void cache_init(); - void cache_push(UserDictCacheType type, - UserDictSearchable* searchable, - uint32 offset, uint32 length); - bool cache_hit(UserDictSearchable* searchable, - uint32* offset, uint32* length); - bool load_cache(UserDictSearchable* searchable, - uint32* offset, uint32* length); - void save_cache(UserDictSearchable* searchable, - uint32 offset, uint32 length); - void reset_cache(); - bool load_miss_cache(UserDictSearchable* searchable); - void save_miss_cache(UserDictSearchable* searchable); - void reset_miss_cache(); -#endif - LmaScoreType translate_score(int f); - int extract_score_freq(int raw_score); - uint64 extract_score_lmt(int raw_score); - inline int build_score(uint64 lmt, int freq); - inline int64 utf16le_atoll(uint16* s, int len); - inline int utf16le_lltoa(int64 v, uint16* s, int size); - LemmaIdType _put_lemma(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count, uint64 lmt); - size_t _get_lpis(const uint16* splid_str, uint16 splid_str_len, - LmaPsbItem* lpi_items, size_t lpi_max, bool* need_extend); - int _get_lemma_score(char16 lemma_str[], uint16 splids[], uint16 lemma_len); - int _get_lemma_score(LemmaIdType lemma_id); - int is_fuzzy_prefix_spell_id(const uint16* id1, uint16 len1, - const UserDictSearchable* searchable); - bool is_prefix_spell_id(const uint16* fullids, - uint16 fulllen, const UserDictSearchable* searchable); - uint32 get_dict_file_size(UserDictInfo* info); - bool reset(const char* file); - bool validate(const char* file); - bool load(const char* file, LemmaIdType start_id); - bool is_valid_state(); - bool is_valid_lemma_id(LemmaIdType id); - LemmaIdType get_max_lemma_id(); - void set_lemma_flag(uint32 offset, uint8 flag); - char get_lemma_flag(uint32 offset); - char get_lemma_nchar(uint32 offset); - uint16* get_lemma_spell_ids(uint32 offset); - uint16* get_lemma_word(uint32 offset); - // Prepare searchable to fasten locate process - void prepare_locate(UserDictSearchable* searchable, - const uint16* splids, uint16 len); - // Compare initial letters only - int32 fuzzy_compare_spell_id(const uint16* id1, uint16 len1, - const UserDictSearchable* searchable); - // Compare exactly two spell ids - // First argument must be a full id spell id - bool equal_spell_id(const uint16* fullids, - uint16 fulllen, const UserDictSearchable* searchable); - // Find first item by initial letters - int32 locate_first_in_offsets(const UserDictSearchable* searchable); - LemmaIdType append_a_lemma(char16 lemma_str[], uint16 splids[], - uint16 lemma_len, uint16 count, uint64 lmt); - // Check if a lemma is in dictionary - int32 locate_in_offsets(char16 lemma_str[], - uint16 splid_str[], uint16 lemma_len); - bool remove_lemma_by_offset_index(int offset_index); -#ifdef ___PREDICT_ENABLED___ - uint32 locate_where_to_insert_in_predicts(const uint16* words, - int lemma_len); - int32 locate_first_in_predicts(const uint16* words, int lemma_len); - void remove_lemma_from_predict_list(uint32 offset); -#endif -#ifdef ___SYNC_ENABLED___ - void queue_lemma_for_sync(LemmaIdType id); - void remove_lemma_from_sync_list(uint32 offset); - void write_back_sync(int fd); -#endif - void write_back_score(int fd); - void write_back_offset(int fd); - void write_back_lemma(int fd); - void write_back_all(int fd); - void write_back(); - struct UserDictScoreOffsetPair { - int score; - uint32 offset_index; - }; - inline void swap(UserDictScoreOffsetPair* sop, int i, int j); - void shift_down(UserDictScoreOffsetPair* sop, int i, int n); - // On-disk format for each lemma - // +-------------+ - // | Version (4) | - // +-------------+ - // +-----------+-----------+--------------------+-------------------+ - // | Spare (1) | Nchar (1) | Splids (2 x Nchar) | Lemma (2 x Nchar) | - // +-----------+-----------+--------------------+-------------------+ - // ... - // +-----------------------+ +-------------+ <---Offset of offset - // | Offset1 by_splids (4) | ... | OffsetN (4) | - // +-----------------------+ +-------------+ -#ifdef ___PREDICT_ENABLED___ - // +----------------------+ +-------------+ - // | Offset1 by_lemma (4) | ... | OffsetN (4) | - // +----------------------+ +-------------+ -#endif - // +------------+ +------------+ - // | Score1 (4) | ... | ScoreN (4) | - // +------------+ +------------+ -#ifdef ___SYNC_ENABLED___ - // +-------------+ +-------------+ - // | NewAdd1 (4) | ... | NewAddN (4) | - // +-------------+ +-------------+ -#endif - // +----------------+ - // | Dict Info (4x) | - // +----------------+ -}; -} // namespace ime_pinyin -#endif diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/utf16char.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/utf16char.cpp deleted file mode 100644 index b62348f..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/utf16char.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "utf16char.h" -#include -namespace ime_pinyin { -#ifdef __cplusplus -extern "C" { -#endif -char16* utf16_strtok(char16* utf16_str, size_t* token_size, - char16** utf16_str_next) { - if (NULL == utf16_str || NULL == token_size || NULL == utf16_str_next) { - return NULL; - } - // Skip the splitters - size_t pos = 0; - while ((char16)' ' == utf16_str[pos] || (char16)'\n' == utf16_str[pos] || (char16)'\t' == utf16_str[pos]) - pos++; - utf16_str += pos; - pos = 0; - while ((char16)'\0' != utf16_str[pos] && (char16)' ' != utf16_str[pos] && (char16)'\n' != utf16_str[pos] && (char16)'\t' != utf16_str[pos]) { - pos++; - } - char16* ret_val = utf16_str; - if ((char16)'\0' == utf16_str[pos]) { - *utf16_str_next = NULL; - if (0 == pos) - return NULL; - } - else { - *utf16_str_next = utf16_str + pos + 1; - } - utf16_str[pos] = (char16)'\0'; - *token_size = pos; - return ret_val; -} -int utf16_atoi(const char16* utf16_str) { - if (NULL == utf16_str) - return 0; - int value = 0; - int sign = 1; - size_t pos = 0; - if ((char16)'-' == utf16_str[pos]) { - sign = -1; - pos++; - } - while ((char16)'0' <= utf16_str[pos] && - (char16)'9' >= utf16_str[pos]) { - value = value * 10 + static_cast(utf16_str[pos] - (char16)'0'); - pos++; - } - return value * sign; -} -float utf16_atof(const char16* utf16_str) { - // A temporary implemetation. - char char8[256]; - if (utf16_strlen(utf16_str) >= 256) - return 0; - utf16_strcpy_tochar(char8, utf16_str); - return atof(char8); -} -size_t utf16_strlen(const char16* utf16_str) { - if (NULL == utf16_str) - return 0; - size_t size = 0; - while ((char16)'\0' != utf16_str[size]) - size++; - return size; -} -int utf16_strcmp(const char16* str1, const char16* str2) { - size_t pos = 0; - while (str1[pos] == str2[pos] && (char16)'\0' != str1[pos]) - pos++; - return static_cast(str1[pos]) - static_cast(str2[pos]); -} -int utf16_strncmp(const char16* str1, const char16* str2, size_t size) { - size_t pos = 0; - while (pos < size && str1[pos] == str2[pos] && (char16)'\0' != str1[pos]) - pos++; - if (pos == size) - return 0; - return static_cast(str1[pos]) - static_cast(str2[pos]); -} -// we do not consider overlapping -char16* utf16_strcpy(char16* dst, const char16* src) { - if (NULL == src || NULL == dst) - return NULL; - char16* cp = dst; - while ((char16)'\0' != *src) { - *cp = *src; - cp++; - src++; - } - *cp = *src; - return dst; -} -char16* utf16_strncpy(char16* dst, const char16* src, size_t size) { - if (NULL == src || NULL == dst || 0 == size) - return NULL; - if (src == dst) - return dst; - char16* cp = dst; - if (dst < src || (dst > src && dst >= src + size)) { - while (size-- && (*cp++ = *src++)) - ; - } - else { - cp += size - 1; - src += size - 1; - while (size-- && (*cp-- == *src--)) - ; - } - return dst; -} -// We do not handle complicated cases like overlapping, because in this -// codebase, it is not necessary. -char* utf16_strcpy_tochar(char* dst, const char16* src) { - if (NULL == src || NULL == dst) - return NULL; - char* cp = dst; - while ((char16)'\0' != *src) { - *cp = static_cast(*src); - cp++; - src++; - } - *cp = *src; - return dst; -} -#ifdef __cplusplus -} -#endif -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/utf16char.h b/Widget/base/Virtual_Keyboard/googlepinyin/utf16char.h deleted file mode 100644 index e20e9ac..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/utf16char.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_UTF16CHAR_H__ -#define PINYINIME_INCLUDE_UTF16CHAR_H__ -#include -namespace ime_pinyin { -#ifdef __cplusplus -extern "C" { -#endif -typedef unsigned short char16; -// Get a token from utf16_str, -// Returned pointer is a '\0'-terminated utf16 string, or NULL -// *utf16_str_next returns the next part of the string for further tokenizing -char16* utf16_strtok(char16* utf16_str, size_t* token_size, - char16** utf16_str_next); -int utf16_atoi(const char16* utf16_str); -float utf16_atof(const char16* utf16_str); -size_t utf16_strlen(const char16* utf16_str); -int utf16_strcmp(const char16* str1, const char16* str2); -int utf16_strncmp(const char16* str1, const char16* str2, size_t size); -char16* utf16_strcpy(char16* dst, const char16* src); -char16* utf16_strncpy(char16* dst, const char16* src, size_t size); -char* utf16_strcpy_tochar(char* dst, const char16* src); -#ifdef __cplusplus -} -#endif -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_UTF16CHAR_H__ diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/utf16reader.cpp b/Widget/base/Virtual_Keyboard/googlepinyin/utf16reader.cpp deleted file mode 100644 index 9d73159..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/utf16reader.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "utf16reader.h" -namespace ime_pinyin { -#define MIN_BUF_LEN 128 -#define MAX_BUF_LEN 65535 -Utf16Reader::Utf16Reader() { - fp_ = NULL; - buffer_ = NULL; - buffer_total_len_ = 0; - buffer_next_pos_ = 0; - buffer_valid_len_ = 0; -} -Utf16Reader::~Utf16Reader() { - if (NULL != fp_) - fclose(fp_); - if (NULL != buffer_) - delete[] buffer_; -} -bool Utf16Reader::open(const char* filename, size_t buffer_len) { - if (filename == NULL) - return false; - if (buffer_len < MIN_BUF_LEN) - buffer_len = MIN_BUF_LEN; - else if (buffer_len > MAX_BUF_LEN) - buffer_len = MAX_BUF_LEN; - buffer_total_len_ = buffer_len; - if (NULL != buffer_) - delete[] buffer_; - buffer_ = new char16[buffer_total_len_]; - if (NULL == buffer_) - return false; - if ((fp_ = fopen(filename, "rb")) == NULL) - return false; - // the UTF16 file header, skip - char16 header; - if (fread(&header, sizeof(header), 1, fp_) != 1 || header != 0xfeff) { - fclose(fp_); - fp_ = NULL; - return false; - } - return true; -} -char16* Utf16Reader::readline(char16* read_buf, size_t max_len) { - if (NULL == fp_ || NULL == read_buf || 0 == max_len) - return NULL; - size_t ret_len = 0; - do { - if (buffer_valid_len_ == 0) { - buffer_next_pos_ = 0; - buffer_valid_len_ = fread(buffer_, sizeof(char16), - buffer_total_len_, fp_); - if (buffer_valid_len_ == 0) { - if (0 == ret_len) - return NULL; - read_buf[ret_len] = (char16)'\0'; - return read_buf; - } - } - for (size_t i = 0; i < buffer_valid_len_; i++) { - if (i == max_len - 1 || - buffer_[buffer_next_pos_ + i] == (char16)'\n') { - if (ret_len + i > 0 && read_buf[ret_len + i - 1] == (char16)'\r') { - read_buf[ret_len + i - 1] = (char16)'\0'; - } - else { - read_buf[ret_len + i] = (char16)'\0'; - } - i++; - buffer_next_pos_ += i; - buffer_valid_len_ -= i; - if (buffer_next_pos_ == buffer_total_len_) { - buffer_next_pos_ = 0; - buffer_valid_len_ = 0; - } - return read_buf; - } - else { - read_buf[ret_len + i] = buffer_[buffer_next_pos_ + i]; - } - } - ret_len += buffer_valid_len_; - buffer_valid_len_ = 0; - } - while (true); - // Never reach here - return NULL; -} -bool Utf16Reader::close() { - if (NULL != fp_) - fclose(fp_); - fp_ = NULL; - if (NULL != buffer_) - delete[] buffer_; - buffer_ = NULL; - return true; -} -} // namespace ime_pinyin diff --git a/Widget/base/Virtual_Keyboard/googlepinyin/utf16reader.h b/Widget/base/Virtual_Keyboard/googlepinyin/utf16reader.h deleted file mode 100644 index b2f99df..0000000 --- a/Widget/base/Virtual_Keyboard/googlepinyin/utf16reader.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef PINYINIME_INCLUDE_UTF16READER_H__ -#define PINYINIME_INCLUDE_UTF16READER_H__ -#include -#include "./utf16char.h" -namespace ime_pinyin { -class Utf16Reader { -private: - FILE* fp_; - char16* buffer_; - size_t buffer_total_len_; - size_t buffer_next_pos_; - // Always less than buffer_total_len_ - buffer_next_pos_ - size_t buffer_valid_len_; -public: - Utf16Reader(); - ~Utf16Reader(); - // filename is the name of the file to open. - // buffer_len specifies how long buffer should be allocated to speed up the - // future reading - bool open(const char* filename, size_t buffer_len); - char16* readline(char16* read_buf, size_t max_len); - bool close(); -}; -} // namespace ime_pinyin -#endif // PINYINIME_INCLUDE_UTF16READER_H__ diff --git a/Widget/base/algorithm.hpp b/Widget/base/algorithm.hpp deleted file mode 100644 index 6318e13..0000000 --- a/Widget/base/algorithm.hpp +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace Flex_Qt { -#define LOWER(offset) l_lower(spaces[offset]) -#define UPPER(offset) l_upper(spaces[offset]) - template - - int binary_search(double value, T** spaces, int space_size, std::function& l_lower, std::function& l_upper) - { - int start_index = 0, end_index = space_size - 1; - if (start_index == end_index) - return start_index; - double min = LOWER(start_index), max = UPPER(end_index); - if (value < min) { - // std::cout << QString("warnning binary_search value:%1 < %2").arg(value).arg(min); - return start_index; - } - if (value > max) { - // std::cout << QString("warnning binary_search value:%1 > %2").arg(value).arg(max); - return end_index; - } - while (start_index != end_index) { - if (start_index + 1 == end_index) { - double mid = (UPPER(start_index) + LOWER(end_index)) / 2.0; - if (value < mid) - return start_index; - return end_index; - } - int m = (start_index + end_index) / 2; - double lower = m != 0 ? (UPPER(m - 1) + LOWER(m)) / 2.0 : min; - double upper = m != space_size - 1 ? (UPPER(m) + LOWER(m + 1)) / 2.0 : max; - // std::cout << " lower == " << lower << " upper == " << upper << "midIndex == " << m << " value == " << value; - // std::cout << " start_index == " << start_index << " end_index == " << end_index; - if (value < lower) { - end_index = m; - } - else if (value > upper) { - start_index = m; - } - else { - return m; - } - } - std::cout << QString("warnning start_index:%1, end_index:%2").arg(start_index).arg(end_index).toStdString(); - return start_index; - } -#undef LOWER -#undef UPPER - static int binary_search(double value, const std::vector& data, bool& ok) - { - if (data.empty()) { - ok = false; - return -1; // 返回 -1 表示数组为空 - } - // 判断排序顺序 - bool ascending_order = data[0] < data[data.size() - 1]; - int left = 0; - int right = data.size() - 1; - // 二分查找 - while (left <= right) { - int mid = left + (right - left) / 2; - if (mid < data.size() - 1) { - if (ascending_order) { - if (data[mid] <= value && data[mid + 1] > value) { - ok = true; - return mid; - } - else if (data[mid] < value) { - left = mid + 1; - } - else { - right = mid - 1; - } - } - else { - // 处理降序排列的情况 - if (data[mid] >= value && data[mid + 1] < value) { - ok = true; - return mid; - } - else if (data[mid] > value) { - left = mid + 1; - } - else { - right = mid - 1; - } - } - } - else { - break; // 如果 mid 已经是最后一个元素,不再继续查找 - } - } - ok = false; - // 如果找不到,则返回 -1,表示 value 不在区间内 - return -1; - } -} // Flex_Qt diff --git a/Widget/base/export.h b/Widget/base/export.h deleted file mode 100644 index 141150b..0000000 --- a/Widget/base/export.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "CircularLinkedList.hpp" -#include "File_Dialog/File_Dialog.h" -#include "Generate_Mock_Data.h" -#include "Graphic.h" -#include "Node.hpp" -#include "Roll_Object.h" -#include "Select_Color_Dialog/Select_Color_Dialog.h" -#include "Singleton_Widget.hpp" -#include "Virtual_Keyboard/Virtual_Keyboard.h" -#include "algorithm.hpp" -#include "view/FileFolderBar.h" diff --git a/Widget/base/global.h b/Widget/base/global.h deleted file mode 100644 index 874df89..0000000 --- a/Widget/base/global.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include "../global.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/Widget/base/view/FileFolderBar.cpp b/Widget/base/view/FileFolderBar.cpp deleted file mode 100644 index 81d5973..0000000 --- a/Widget/base/view/FileFolderBar.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "FileFolderBar.h" -#include -#include -namespace Flex_Qt { -File_Folder_Bar::File_Folder_Bar(QWidget* parent) : QWidget(parent) { - //setAttribute(Qt::WA_OpaquePaintEvent); -} -File_Folder_Bar::~File_Folder_Bar() {} -void File_Folder_Bar::paintEvent(QPaintEvent* event) { - QWidget::paintEvent(event); - QPainter painter(this); - int index = 0; - for (File_Folder*& root : roots) { - std::queue que; - root->deep = 0; - que.push(root); - while (!que.empty()) { - File_Folder* cur = que.front(); - que.pop(); - int n = cur->sons.size(); - cur->draw(index++, &painter); - for (int i = 0; i < n; ++i) { - if (cur->is_show_sons) { - cur->sons[i]->deep = cur->deep + 1; - que.push(cur->sons[i]); - } - } - } - } - painter.end(); -} -} diff --git a/Widget/base/view/FileFolderBar.h b/Widget/base/view/FileFolderBar.h deleted file mode 100644 index 27da33d..0000000 --- a/Widget/base/view/FileFolderBar.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef Toolbox_File_Folder_Bar_H -#define Toolbox_File_Folder_Bar_H -#include -#include "../File_Dialog/File_Dialog.h" -namespace Flex_Qt { -class File_Folder_Bar : public QWidget, public Node_Manager { - Q_OBJECT -public: - explicit File_Folder_Bar(QWidget* parent = nullptr); - ~File_Folder_Bar() override; -protected: - void paintEvent(QPaintEvent* event) override; -}; -} -#endif - - - diff --git a/Widget/base/view/icon/FileFolder.qrc b/Widget/base/view/icon/FileFolder.qrc deleted file mode 100644 index 86119ff..0000000 --- a/Widget/base/view/icon/FileFolder.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - fileFolder.png - arrowDown.png - - \ No newline at end of file diff --git a/Widget/base/view/icon/arrowDown.png b/Widget/base/view/icon/arrowDown.png deleted file mode 100644 index b56a075..0000000 Binary files a/Widget/base/view/icon/arrowDown.png and /dev/null differ diff --git a/Widget/base/view/icon/fileFolder.png b/Widget/base/view/icon/fileFolder.png deleted file mode 100644 index 68f2f79..0000000 Binary files a/Widget/base/view/icon/fileFolder.png and /dev/null differ diff --git a/Widget/component/Background.h b/Widget/component/Background.h deleted file mode 100644 index ae6458f..0000000 --- a/Widget/component/Background.h +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once -#include "global.h" -enum class Mouse_State { - Default, - Pressed, - Entered -}; -struct Border { - QColor border_color = Qt::red; - int len = 4; -}; -using Handle_Mouse = std::function; -struct Background : Paintable { - QGraphicsDropShadowEffect shadow_effect; - Border* border{}; - std::map map; - Qt::SizeMode mode = Qt::RelativeSize; - qreal radius = 0.1; - bool enter = false; - Mouse_State mouse_state = Mouse_State::Default; - std::vector mouse_handlers; - void set_border(const QColor& border_color, int len = 1) { - if (!border) - border = new Border; - border->border_color = border_color; - border->len = len; - } - void set_effect(QWidget* that) { - shadow_effect.setBlurRadius(10); // 设置模糊半径 - shadow_effect.setOffset(5, 5); // 设置阴影偏移量(x, y) - shadow_effect.setColor(Qt::black); // 设置阴影颜色 - that->setGraphicsEffect(&shadow_effect); - } - void set_color(const QColor& color) { - map[Mouse_State::Default] = color; - double r = color.red(); - double g = color.green(); - double b = color.blue(); - // int alpha = color.alpha(); - double upper = 1.6; - double lower = 0.4; - auto ur = qMin(255, (int)(r * upper)); - auto ug = qMin(255, (int)(g * upper)); - auto ub = qMin(255, (int)(b * upper)); - int lr = (int)(r * lower); - int lg = (int)(g * lower); - int lb = (int)(b * lower); - map[Mouse_State::Pressed] = QColor(ur, ug, ub); - map[Mouse_State::Entered] = QColor(lr, lg, lb); - } - Event_Type mouse_event(QEvent::Type t, QMouseEvent* e) override { - if (t == QEvent::MouseButtonPress) { - mouse_state = Mouse_State::Pressed; - } - else if (t == QEvent::MouseButtonRelease) { - if (enter) - mouse_state = Mouse_State::Entered; - else - mouse_state = Mouse_State::Default; - } - for (auto& handler : mouse_handlers) { - handler(t, e); - } - return Event_Type::refresh; - } - Event_Type event(QEvent::Type t, QEvent* e) override { - if (t == QEvent::Enter) { - enter = true; - mouse_state = Mouse_State::Entered; - return Event_Type::refresh; - } - else if (t == QEvent::Leave) { - enter = false; - mouse_state = Mouse_State::Default; - return Event_Type::refresh; - } - return Paintable::event(t, e); - } - void paint(QPainter* painter, QRect rect) override { - painter->save(); - int half_pen_width = 0; - QRect adjusted_rect = rect.adjusted(half_pen_width, half_pen_width, -half_pen_width, -half_pen_width); - qreal x_radius, y_radius; - get_rounded_rect_radius(adjusted_rect, x_radius, y_radius); - QPainterPath border_path; - border_path.addRoundedRect(adjusted_rect, x_radius, y_radius); - QRect inner_rect = adjusted_rect; - if (border) { - inner_rect.adjust(border->len, border->len, -border->len, -border->len); - } - // 内部区域边距 - QPainterPath inner_path; - inner_path.addRoundedRect(inner_rect, x_radius, y_radius); - QColor c = map[mouse_state]; - painter->setPen(Qt::NoPen); - if (c.isValid()) { - painter->save(); - if (border) { - painter->setBrush(border->border_color); - painter->drawPath(border_path); - } - painter->setBrush(c); - painter->drawPath(inner_path); - painter->restore(); - } - else { - if (border) { - border_path = border_path.subtracted(inner_path); - painter->setBrush(border->border_color); - painter->drawPath(border_path); - } - } - painter->restore(); - } - void set_radius(Qt::SizeMode mode, qreal value) { - this->mode = mode; - this->radius = value; - } -protected: - void get_rounded_rect_radius(const QRect& rect, qreal& x_radius, qreal& y_radius) const { - if (mode == Qt::RelativeSize) { - x_radius = rect.width() * radius; - y_radius = rect.height() * radius; - } - else { - x_radius = radius; - y_radius = radius; - } - } -}; diff --git a/Widget/component/Base/Base.h b/Widget/component/Base/Base.h deleted file mode 100644 index 60bacbd..0000000 --- a/Widget/component/Base/Base.h +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once -#include -#include -namespace Flex_Qt { -enum class Direction { - First, - Middle, - Last, - Default -}; -class Layout_Item { -public: - enum Size_Policy { - Get_Main_By_Cross = 1, - Cross_Expand = 2, - Grow = 4, - Shrink = 8, - Ignore = 16 - }; - Direction direction = Direction::Default; - QFlags size_policy; - bool use_get_main_by_cros = false; - virtual int get_main_by_cros(int cros) { - return cros; - } - virtual ~Layout_Item() = default; - [[nodiscard]] int x() const { - return _x; - } - [[nodiscard]] int y() const { - return _y; - } - [[nodiscard]] int w() const { - return _w; - } - [[nodiscard]] int h() const { - return _h; - } - void set_x(int x) { - _x = x; - } - void set_y(int y) { - _y = y; - } - void set_w(int w) { - _w = w; - } - void set_h(int h) { - _h = h; - } - void set_size(int w, int h) { - _w = w; - _h = h; - } - void set_size(QSize size) { - _w = size.width(); - _h = size.height(); - } - virtual QSize sizeHint() const { - return QSize(_w, _h); - } - virtual QSize minimumSize() const { - return QSize(_w, _h); - } - virtual QSize maximumSize() const { - return QSize(_w, _h); - } - [[nodiscard]] QRect rect() const { - return {_x, _y, _w, _h}; - } -protected: - int _x = 0, _y = 0, _w = 0, _h = 0; -}; -class E : public Layout_Item { -public: - virtual ~E() = default; - virtual void paint(QPainter* painter, QRect r, QPaintEvent* event) {} - virtual void event(QEvent::Type t, QEvent* e) {} - void update() { - need_update = true; - } - bool need_update = false; -}; -} diff --git a/Widget/component/Base/Delegate.h b/Widget/component/Base/Delegate.h deleted file mode 100644 index 71b6c48..0000000 --- a/Widget/component/Base/Delegate.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -#include -#include -namespace Flex_Qt { -template -class Delegate { -public: - std::vector handlers; - Delegate& operator+=(const Handler_Type& handler) { - if (std::find(handlers.begin(), handlers.end(), handler) == handlers.end()) { - handlers.push_back(handler); - } - return *this; - } - Delegate& operator-=(const Handler_Type& handler) { - auto it = std::find(handlers.begin(), handlers.end(), handler); - if (it != handlers.end()) { - handlers.erase(it); // 移除对应的处理程序 - } - return *this; - } - template - void invoke(Args&&... args) const { - for (auto& handler : handlers) { - handler(std::forward(args)...); // 完美转发参数 - } - } -}; -using Mouse_Press_Event_Handler = std::function; -} diff --git a/Widget/component/Base/Layout.cpp b/Widget/component/Base/Layout.cpp deleted file mode 100644 index 0d0d26e..0000000 --- a/Widget/component/Base/Layout.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include "Layout.h" -#include -namespace Flex_Qt { -struct Horizontal_Traits { - static int get_main(const Layout_Item* i) { - return i->x(); - } - static void set_main(Layout_Item* i, int v) { - i->set_x(v); - } - static int get_cros(const Layout_Item* i) { - return i->y(); - } - static void set_cros(Layout_Item* i, int v) { - i->set_y(v); - } - static int get_main_len(const Layout_Item* i) { - return i->w(); - } - static void set_main_len(Layout_Item* i, int v) { - i->set_w(v); - } - static int get_cros_len(const Layout_Item* i) { - return i->h(); - } - static void set_cros_len(Layout_Item* i, int v) { - i->set_h(v); - } - static int main_prefix(const QMargins& m) { - return m.left(); - } - static int main_suffix(const QMargins& m) { - return m.right(); - } - static int cros_prefix(const QMargins& m) { - return m.top(); - } - static int cros_suffix(const QMargins& m) { - return m.bottom(); - } - static int main_length(const Layout* l) { - return l->w(); - } - static int cros_length(const Layout* l) { - return l->h(); - } -}; -struct Vertical_Traits { - static int get_main(const Layout_Item* i) { - return i->y(); - } - static void set_main(Layout_Item* i, int v) { - i->set_y(v); - } - static int get_cros(const Layout_Item* i) { - return i->x(); - } - static void set_cros(Layout_Item* i, int v) { - i->set_x(v); - } - static int get_main_len(const Layout_Item* i) { - return i->h(); - } - static void set_main_len(Layout_Item* i, int v) { - i->set_h(v); - } - static int get_cros_len(const Layout_Item* i) { - return i->w(); - } - static void set_cros_len(Layout_Item* i, int v) { - i->set_w(v); - } - static int main_prefix(const QMargins& m) { - return m.top(); - } - static int main_suffix(const QMargins& m) { - return m.bottom(); - } - static int cros_prefix(const QMargins& m) { - return m.left(); - } - static int cros_suffix(const QMargins& m) { - return m.right(); - } - static int main_length(const Layout* l) { - return l->h(); - } - static int cros_length(const Layout* l) { - return l->w(); - } -}; -// TODO: maxsize mainsize 不知道怎么和 grow shrink 合并处理 -template -void Layout::layout_impl() { - int main_prefix = T::main_prefix(margins); - int main_suffix = T::main_suffix(margins); - int cros_prefix = T::cros_prefix(margins); - int cros_suffix = T::cros_suffix(margins); - int main_length = T::main_length(this); - int cros_length = T::cros_length(this); - int cros_max = cros_length - cros_prefix - cros_suffix; - int total_main = main_prefix + main_suffix; - std::vector grow_items; - std::vector shrink_items; - // ---------- 第一遍:初始化尺寸 & 收集 grow / shrink ---------- - for (auto* item : items) { - auto size = item->sizeHint(); - auto& flags = item->size_policy; - item->set_size(size); - if (flags.testFlag(Cross_Expand)) { - T::set_cros_len(item, cros_max); - } - if (flags.testFlag(Get_Main_By_Cross)) { - int cros_len = T::get_cros_len(item); - int main_len = item->get_main_by_cros(cros_len); - T::set_main_len(item, main_len); - } - total_main += T::get_main_len(item); - // 明确语义:Grow / Shrink 不允许同时生效 - if (flags.testFlag(Grow) && !flags.testFlag(Shrink)) { - grow_items.push_back(item); - } - else if (flags.testFlag(Shrink)) { - shrink_items.push_back(item); - } - } - int available = main_length - total_main; - // ---------- Grow ---------- - if (available > 0 && !grow_items.empty()) { - int count = grow_items.size(); - int each = available / count; - int remain = available % count; - for (int i = 0; i < grow_items.size(); ++i) { - auto* item = grow_items[i]; - int delta = each + (i < remain ? 1 : 0); - int len = T::get_main_len(item); - T::set_main_len(item, len + delta); - } - available = 0; - } - // ---------- Shrink(按比例,修正版本) ---------- - if (available < 0 && !shrink_items.empty()) { - int deficit = -available; - int shrink_cap = 0; - for (auto* item : shrink_items) { - shrink_cap += T::get_main_len(item); - } - if (shrink_cap > 0) { - int actual_shrink = std::min(deficit, shrink_cap); - int remain = actual_shrink; - for (int i = 0; i < shrink_items.size(); ++i) { - auto* item = shrink_items[i]; - int cur = T::get_main_len(item); - int delta = actual_shrink * cur / shrink_cap; - if (i == shrink_items.size() - 1) - delta = remain; // 吃掉误差 - delta = std::min(delta, cur); - T::set_main_len(item, cur - delta); - remain -= delta; - } - available += actual_shrink; - } - } - // ---------- 最后一步:设置每个 item 的位置 ---------- - int main_pos = main_prefix; - for (Layout_Item* item : items) { - auto dr = item->direction; - if (dr == Direction::Default) { - dr = direction; - if (dr == Direction::Default) { - dr = Direction::Middle; - } - } - if (dr == Direction::Middle) { - int cur = T::get_cros_len(item); - auto middle = cros_prefix + (cros_length - cros_prefix - cros_suffix) / 2; - auto pos = middle - cur / 2; - T::set_cros(item, pos); - } - else if (dr == Direction::First) { - T::set_cros(item, cros_prefix); - } - else if (dr == Direction::Last) { - int cur = T::get_cros_len(item); - auto last = cros_length - cros_suffix; - auto pos = last - cur; - T::set_cros(item, pos); - } - else { - std::cout << "未知的类型 " << VAR_STR_1(dr) << LOG_POS << std::endl; - std::terminate(); - } - T::set_main(item, main_pos); - main_pos += T::get_main_len(item) + space; - } -} -void Layout::layout() { - if (orientation == Qt::Horizontal) - layout_impl(); - else - layout_impl(); -} -} diff --git a/Widget/component/Base/Layout.h b/Widget/component/Base/Layout.h deleted file mode 100644 index b97c3c2..0000000 --- a/Widget/component/Base/Layout.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "global.h" -namespace Flex_Qt { -class Layout : public Layout_Item { -public: - explicit Layout(Qt::Orientation orientation = Qt::Horizontal) : orientation(orientation) {} - int space = 8; - QMargins margins = {8, 8, 8, 8}; - std::vector items; - Qt::Orientation orientation = Qt::Horizontal; - void layout(); - Direction direction = Direction::Default; -protected: - template - void layout_impl(); -}; -} diff --git a/Widget/component/Base/export.h b/Widget/component/Base/export.h deleted file mode 100644 index 99b9935..0000000 --- a/Widget/component/Base/export.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "Base.h" -#include "Delegate.h" -#include "Layout.h" -#include "global.h" -#include "impl.h" diff --git a/Widget/component/Base/global.h b/Widget/component/Base/global.h deleted file mode 100644 index 1528546..0000000 --- a/Widget/component/Base/global.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "Base.h" -#include "Delegate.h" -#include "../SVG.h" diff --git a/Widget/component/Base/impl.h b/Widget/component/Base/impl.h deleted file mode 100644 index 89d69b7..0000000 --- a/Widget/component/Base/impl.h +++ /dev/null @@ -1,139 +0,0 @@ -#pragma once -#include "global.h" -namespace Flex_Qt { -class Border : public E { -public: - int width = 4; - QPen pen = QPen(); - QColor color = Qt::red; - std::optional filled_color = QColor(200, 0, 0); - Border() {} - Border(int width, QPen pen, QColor color) : width(width), pen(pen), color(color) {} - void paint(QPainter* painter, QRect r, QPaintEvent* event) override { - pen.setColor(color); - pen.setWidth(width); - painter->setPen(pen); - // if (filled_color.has_value()) { - // painter->fillRect(r, filled_color.value()); - // } - painter->drawRect(r); - } -}; -class Icon : public E { -public: - SVG_Image_Render svg; - Icon() { - svg.set_path(":/you_jian_tou.svg").set_color(Qt::red).create(); - } - void paint(QPainter* painter, QRect r, QPaintEvent* event) override { - svg.render(painter, r); - } - [[nodiscard]] QSize sizeHint() const override { - return {20, 20}; - } -}; -class Icon2 : public E { -public: - QIcon icon; - Icon2(QIcon icon) : icon(icon) {} - Icon2() = default; - void paint(QPainter* painter, QRect r, QPaintEvent* event) override { - icon.paint(painter, r); - } - [[nodiscard]] QSize sizeHint() const override { - return {20, 20}; - } -}; -// https://runebook.dev/zh/docs/qt/qtextlayout/draw -class Text : public E { -public: - QFont font; - QFontMetrics font_metrics; - QMargins margins; - QString text; - QPen pen = QPen(); - Text() : font_metrics(font) {} - [[nodiscard]] QSize sizeHint() const override { - auto w = font_metrics.horizontalAdvance(text); - auto h = font_metrics.height(); - return {w + margins.left() + margins.right(), h + margins.top() + margins.bottom()}; - } - void paint(QPainter* painter, QRect r, QPaintEvent* event = nullptr) override { - int x = r.left() + margins.left(); - int y = r.top() + margins.top() + font_metrics.height(); - painter->drawText(x, y, text); - } -}; -class Button : public E { -public: - Border border; - Text text; - Icon icon; - QMargins inter_margin; - Delegate press_event; - QRect rect; - Layout layout = Layout(Qt::Horizontal); - Button() { - layout.space = 16; - text.text = "123456"; - icon.use_get_main_by_cros = true; - icon.size_policy.setFlag(Cross_Expand); - icon.size_policy.setFlag(Get_Main_By_Cross); - layout.items.push_back(&icon); - layout.items.push_back(&text); - }; - void paint(QPainter* painter, QRect r, QPaintEvent* event) override { - border.paint(painter, r, event); - auto r_icon = icon.rect(); - auto r_text = text.rect(); - painter->setPen(QPen(Qt::blue)); - painter->drawRect(r_icon); - painter->drawRect(r_text); - icon.paint(painter, r_icon, event); - text.paint(painter, r_text, event); - } - void event(QEvent::Type t, QEvent* e) override { - if (t == QEvent::MouseButtonPress) { - QMouseEvent* me = static_cast(e); - if (rect.contains(me->pos())) { - press_event.invoke(me); - } - } - if (t == QEvent::Enter) { - border.color = Qt::blue; - update(); - } - if (t == QEvent::Leave) { - border.color = Qt::black; - update(); - } - if (t == QEvent::Resize) { - QResizeEvent* resize = static_cast(e); - layout.set_size(resize->size()); - layout.layout(); - auto r_icon = icon.rect(); - auto r_text = text.rect(); - // std::cout << "resize" << r_icon << " " << r_text; - } - } -}; -template -class W : public QWidget { -public: - E* inter; - template - W(Args&&... args) : inter(new T(std::forward(args)...)) {} - bool event(QEvent* e) override { - inter->event(e->type(), e); - if (inter->need_update) { - update(); - inter->need_update = false; - } - return QWidget::event(e); - } - void paintEvent(QPaintEvent* event) override { - QPainter painter(this); - inter->paint(&painter, rect(), event); - } -}; -} diff --git a/Widget/component/Button.h b/Widget/component/Button.h deleted file mode 100644 index afb0f5c..0000000 --- a/Widget/component/Button.h +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once -#include -#include "Background.h" -#include "Content.h" -// #define SETTER3(class_name, Type, prop, value) \ -// Type prop; -// -// #define SETTER2(class_name, Type, prop) \ -// class_name& set_##prop(const Type& prop) { this->##prop = prop; return *this;} \ -// Type prop; -// -// #define SETTER(Type, prop, value) \ -// auto& set_##prop(const Type& prop) { this->##prop = prop; return *this;} \ -// Type prop = value; -struct Button : Base { - Q_OBJECT -public: - Background background; - Content content; - Button() { - paintAbles.push_back(&background); - paintAbles.push_back(&content); - } - [[nodiscard]] QSize sizeHint() const override { - auto ret = content.sizeHint(); - if (background.border) { - int a = background.border->len * 2; - ret += QSize(a, a); - } - return ret; - } -}; -inline Button* create_icon(const QString& path, const QColor& background, const Handle_Mouse& f) { - auto ret = new Button(); - ret->content.set_icon(path, QColor(Qt::color0)); - ret->background.set_color(background); - ret->background.mouse_handlers.push_back(f); - return ret; -}; -struct Switch_Button : Base { - Q_OBJECT -public: - Background background; - Content content1; - Content content2; - Switch_Button() { - paintAbles.push_back(&background); - paintAbles.push_back(&content1); - paintAbles.push_back(&content2); - content1.show = true; - content2.show = false; - } - [[nodiscard]] QSize sizeHint() const override { - auto ret = content1.show ? content1.sizeHint() : content2.sizeHint(); - if (background.border) { - int a = background.border->len * 2; - ret += QSize(a, a); - } - return ret; - } -}; -inline Switch_Button* create_switch_icon(const QColor& background, const QString& path, const Handle_Mouse& f, - const QString& path2, const Handle_Mouse& f2) { - auto ret = new Switch_Button(); - ret->content1.set_icon(path, QColor(Qt::color0)); - ret->content2.set_icon(path2, QColor(Qt::color0)); - ret->background.set_color(background); - ret->background.mouse_handlers.push_back([ret, f, f2](QEvent::Type t, QMouseEvent* e) { - if (t == QEvent::MouseButtonPress) { - if (ret->content1.show) { - f(t, e); - } - else { - f2(t, e); - } - std::swap(ret->content1.show, ret->content2.show); - ret->update(); - } - }); - return ret; -} diff --git a/Widget/component/Combo_Box.h b/Widget/component/Combo_Box.h deleted file mode 100644 index 303ef9b..0000000 --- a/Widget/component/Combo_Box.h +++ /dev/null @@ -1,205 +0,0 @@ -#pragma once -#include -#include -#include "global.h" -#include "Psc_Cpp_Core/Base/global_include.h" -class Combo_Box : public QComboBox { -public: - Combo_Box() { - setStyle(new Style()); - setView(new view()); - setItemDelegate(new comboboxdelegate()); - QWidget* container = this->findChild(); - if (container) { - container->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint); - container->setAttribute(Qt::WA_TranslucentBackground); - } - } - class Style : public QProxyStyle { - public: - void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption* option, QPainter* painter, - const QWidget* widget) const override { - // 先调用默认的绘制 - auto t = qobject_cast(widget); - if (!t) - return; - if (option->type == QStyleOption::SO_FocusRect) { - const QStyleOptionComboBox* opt = qstyleoption_cast(option); - // QProxyStyle::drawPrimitive(element, option, painter, widget); - } - else { - std::cout << Psc::enum_int_to_string(option->type).value(); - } - if (element == QStyle::PE_FrameFocusRect) { - // QProxyStyle::drawPrimitive(element, option, painter, widget); - } - else { - std::cout << "drawPrimitive == " << element; - } - } - void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, - const QWidget* widget) const override { - auto t = qobject_cast(widget); - if (!t) - return; - auto opt = qstyleoption_cast(option); - // 控制当前选项外部的边框 - if (control == QStyle::CC_ComboBox) { - QPen pen; - painter->setPen(pen); - painter->drawRoundedRect(widget->rect().adjusted(0, 0, -1, -2), 4, 4); - // QProxyStyle::drawComplexControl(control, option, painter, widget); - } - else { - std::cout << "line_edit drawComplexControl " << control; - } - } - void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, - const QWidget* widget) const override { - auto t = qobject_cast(widget); - if (!t) - return; - auto opt = qstyleoption_cast(option); - // 当前选择的选项 - if (element == QStyle::CE_ComboBoxLabel) { - QProxyStyle::drawControl(element, option, painter, widget); - } - else { - std::cout << "line_edit drawControl " << element; - } - } - QRect subElementRect(SubElement element, const QStyleOption* option, const QWidget* widget) const override { - auto t = qobject_cast(widget); - if (!t) - return QProxyStyle::subElementRect(element, option, widget); - auto opt = qstyleoption_cast(option); - QRect ret = QProxyStyle::subElementRect(element, option, widget); - // 这里可以自定义返回不同的 QRect 以控制子元素的大小或位置 - if (element == QStyle::SE_ComboBoxLayoutItem) { - // rect.adjust(5, 5, -5, -5); // 例如,让文本内容区域缩小一点 - // return rect.adjusted(5, 5, -5, -5); - return ret; - } - else { - std::cout << "line_edit subElementRect " << element; - } - return ret; - } - QRect subControlRect(ComplexControl cc, const QStyleOptionComplex* option, SubControl sc, - const QWidget* widget) const override { - auto ret = QProxyStyle::subControlRect(cc, option, sc, widget); - auto opt = qstyleoption_cast(option); - if (cc == QStyle::CC_ComboBox) { - if (sc == SC_ComboBoxArrow) { - // std::cout << "This is the dropdown arrow button area: " << ret; - } - else if (sc == SC_ComboBoxListBoxPopup) { - // std::cout << "This is the edit box area: " << ret; - } - else if (sc == QStyle::SC_ScrollBarSubLine) { - // std::cout << "QStyle::SC_ScrollBarSubLine: " << ret; - } - else if (sc == QStyle::SC_ScrollBarAddLine) { - // std::cout << "QStyle::SC_ScrollBarSubLine: " << ret; - } - else { - std::cout << "Other subcontrol: " << sc; - } - } - else { - std::cout << "QRect subControlRect ??????? : " << sc; - } - return ret; - } - }; - class view : public QListView { - public: - view(QWidget* parent = nullptr) : QListView(parent) { - // 构造函数内容 - } - [[nodiscard]] QSize viewportSizeHint() const override { - return QListView::viewportSizeHint(); - } - protected: - void paintEvent(QPaintEvent* e) override { - QPainter painter(this->viewport()); - auto s = this->viewport()->objectName(); - // 绘制背景色 - // painter.setBrush(Qt::blue); - // painter.drawRoundedRect(rect(), 4, 4); // 使用白色填充整个视图区域 - // 调用基类的 paintEvent 以确保默认绘制行为 - QListView::paintEvent(e); - } - }; - class comboboxdelegate : public QStyledItemDelegate { - public: - explicit comboboxdelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) {} - ~comboboxdelegate() {} - void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override { - QStyledItemDelegate::paint(painter, option, index); - // if (index.isValid()) - // { - // painter->save(); - // QString name = index.data(Qt::DisplayRole).toString(); - // QVariant icondata = index.data(Qt::DecorationRole); - // QIcon icon = icondata.value(); - // QString number = index.data(Qt::UserRole).toString(); - // bool isonline = index.data(Qt::UserRole + 1).toBool(); - // std::cout << name << number << isonline; - // QRectF rect; - // rect.setX(option.rect.x()); - // rect.setY(option.rect.y()); - // rect.setWidth(option.rect.width() - 1); - // rect.setHeight(option.rect.height() - 1); - // QPainterPath path; - // path.moveTo(rect.topRight() - QPointF(radius, 0)); - // path.lineTo(rect.topLeft() + QPointF(radius, 0)); - // path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius)); - // path.lineTo(rect.bottomLeft() + QPointF(0, -radius)); - // path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0)); - // path.lineTo(rect.bottomRight() - QPointF(radius, 0)); - // path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius)); - // path.lineTo(rect.topRight() + QPointF(0, radius)); - // path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0)); - // if (option.state.testFlag(QStyle::State_Selected)) - // { - // painter->setPen(QPen(Qt::blue)); - // painter->setBrush(QColor(0, 255, 127)); - // painter->drawPath(path); - // } else if (option.state.testFlag(QStyle::State_Raised)) - // { - // painter->setPen(QPen(Qt::green)); - // painter->setBrush(QColor(0, 127, 255)); - // painter->drawPath(path); - // } else - // { - // painter->setPen(QPen(Qt::gray)); - // painter->setBrush(QColor(255, 255, 255)); - // painter->drawPath(path); - // } - // QRect icon_rect = QRect(rect.left() + 3, rect.top() + 3, 30, 30); - // QRect name_rect = QRect(icon_rect.right() + 5, rect.top() + 3, rect.width() - 80, 20); - // QRect circle = QRect(name_rect.right() + 5, name_rect.top(), 10, 10); - // QRect number_rect = QRect(name_rect.x(), name_rect.y() + 20, 100, 20); - // std::cout << icon_rect << name_rect << circle << number_rect; - // painter->drawEllipse(circle); - // painter->setPen(QPen(QColor(0, 0, 0))); - // painter->setFont(QFont("微软雅黑", 9, QFont::Bold)); - // painter->drawText(name_rect, Qt::AlignLeft, name); - // painter->drawText(number_rect, Qt::AlignLeft, number); - // painter->drawPixmap(icon_rect, icon.pixmap(icon_rect.size())); - // painter->restore(); - // } else - // { - // std::cout << "index is vaild?"; - // } - } - [[nodiscard]] QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override { - Q_UNUSED(option) - Q_UNUSED(index) - return QStyledItemDelegate::sizeHint(option, index); - } - private: - qreal radius = 8; - }; -}; diff --git a/Widget/component/Content.h b/Widget/component/Content.h deleted file mode 100644 index 8e7b0b2..0000000 --- a/Widget/component/Content.h +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once -#include -#include -#include "SVG.h" -#include "global.h" -struct Text { - QFont font; - QPen pen; - QString text; - Text(QString text, QPen pen = QPen(), const QFont& font = QFont()) : - text(std::move(text)), - pen(std::move(pen)), - font(font) { - } -}; -// 水平布局 -struct Content : Paintable { - Text* text{}; - SVG_Image_Render* icon{}; - Layout layout; - enum Plottable { - Plottable_Icon, - Plottable_Text, - }; - [[nodiscard]] QSize sizeHint() const override { - QSize ret{0, 0}; - ret += QSize{layout.prefix + layout.suffix, layout.second_prefix + layout.second_suffix}; - if (text) { - QFontMetrics fm(text->font); - ret += QSize{fm.horizontalAdvance(text->text), fm.height()}; - } - return ret; - } - void set_icon(const QString& icon_path, const QColor& icon_color) { - icon = new SVG_Image_Render(); - icon->set_path(icon_path).set_color(icon_color).create(); - } - Content() { - layout.set_margin(4); - layout.main_type = Layout::Center_Space; - layout.second_type = Layout::Center_Space; - } - Event_Type resize_event(QResizeEvent* e) override { - layout.infos.clear(); - int a = qMin(e->size().width(), e->size().height()); - if (icon) { - Layout_Info t(Plottable_Icon, Layout_Item_Type::Fixed, Layout_Item_Type2::Fixed, a, a); - layout.infos.push_back(t); - } - if (text) { - QFontMetrics fm(text->font); - int len = fm.horizontalAdvance(text->text); - Layout_Info t(Plottable_Text, Layout_Item_Type::Fixed, Layout_Item_Type2::Expand, len, 0); - layout.infos.push_back(t); - } - layout.cacl(e->size().width(), e->size().height()); - return Event_Type::refresh; - } - void paint(QPainter* painter, QRect rect) override { - painter->save(); - if (icon) { - auto pos = layout.get(Plottable_Icon).value(); - QRect r = pos.h_rect(); - // painter->drawRect(r); - icon->render(painter, r); - } - if (text) { - painter->setPen(text->pen); - painter->setFont(text->font); - auto pos = layout.get(Plottable_Text).value(); - QRect r = pos.h_rect(); - // painter->drawRect(r); - painter->drawText(r, Qt::AlignCenter, text->text); - } - painter->restore(); - } -}; diff --git a/Widget/component/Input.h b/Widget/component/Input.h deleted file mode 100644 index da1bc33..0000000 --- a/Widget/component/Input.h +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once -#include "global.h" -// https://blog.csdn.net/MrHHHHHH/article/details/134182253 -class Input : public QLineEdit { -public: - explicit Input(QWidget* parent = nullptr) : QLineEdit(parent) { - setStyle(new Style()); - setFrame(true); - // 当光标的位置在文本编辑器中改变时,这个信号会被触发。old和new参数分别表示光标改变前后的位置。 - connect(this, &QLineEdit::cursorPositionChanged, this, [=](int n_old, int n_new) { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "n_old :" << n_old << "n_new :" << n_new; - }); - // 当用户完成文本编辑(例如按下Enter键或点击其他区域使编辑结束)时,这个信号会被触发。 - connect(this, &QLineEdit::editingFinished, this, [=]() { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); - }); - // 当用户在文本编辑器中按下Enter键时,这个信号会被触发。 - connect(this, &QLineEdit::returnPressed, this, [=]() { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); - }); - // 当文本编辑器中的选区发生变化时,这个信号会被触发。例如,当用户选择或取消选择文本时。 - connect(this, &QLineEdit::selectionChanged, this, [=]() { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); - }); - // 当文本编辑器中的文本发生更改时,这个信号会被触发。参数text是改变后的文本内容。 - connect(this, &QLineEdit::textChanged, this, [=](const QString& text) { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << text; - }); - // 当文本编辑器开始编辑新的文本时,这个信号会被触发。参数text是当前编辑的文本内容。 - connect(this, &QLineEdit::textEdited, this, [=](const QString& text) { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << text; - }); - // update(); - } - QString unit = "MHZ"; - QFont font; - QPen pen; - QColor focus_color = Qt::red; - QColor default_color = Qt::black; -protected: - void paintEvent(QPaintEvent* event) override { - QLineEdit::paintEvent(event); // 调用原始绘制 - auto fm = QFontMetrics(font); - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing, true); - int w = width(); - int h = height(); - int pen_w = 1; - if (QApplication::focusWidget() == this) { - painter.setPen(QPen(focus_color, pen_w)); - } - else { - painter.setPen(QPen(default_color, pen_w)); - } - painter.drawRoundedRect(rect(), h / 4, h / 4); - painter.setPen(pen); - painter.setFont(font); - int unit_width = fm.horizontalAdvance(unit); - int th = fm.height(); - int x = rect().right() - unit_width - 5; // 计算单位的绘制位置 - painter.drawText(x, height() / 2 + th / 2, unit); - setTextMargins(0, 0, unit_width + 4, 0); // 右边留出单位的空间 - } - class Style : public QProxyStyle { - public: - void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption* option, QPainter* painter, - const QWidget* widget) const override { - // 先调用默认的绘制 - auto t = qobject_cast(widget); - if (!t) - return; - static bool it = true; - // QProxyStyle::drawPrimitive(element, option, painter, widget); - // std::cout << "t->hasFrame() == " << t->hasFrame(); - if (it) { - // QProxyStyle::drawPrimitive(element, option, painter, widget); - it = false; - } - // 行编辑器边框 - if (element == PE_PanelLineEdit) { - // - } - // 行编辑器边框 - if (element == PE_FrameLineEdit) { - // std::cout << "line_edit drawPrimitive " << element; - // std::cout << "width " << option->rect.width(); - } - } - void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, - const QWidget* widget) const override { - // auto t = qobject_cast(widget); - // if (!t) return; - // std::cout << "line_edit drawComplexControl " << control; - // QProxyStyle::drawComplexControl(control, option, painter, widget); - } - void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, - const QWidget* widget) const override { - // auto t = qobject_cast(widget); - // std::cout << "line_edit drawControl " << element; - // QProxyStyle::drawControl(element, option, painter, widget); - // if (!t) return; - } - // void drawItemText(QPainter* painter, const QRect& rect, int flags, const QPalette& pal, bool enabled, - // const QString& text, QPalette::ColorRole text_role) const override { - // - // - // } - // void drawItemPixmap(QPainter* painter, const QRect& rect, int alignment, const QPixmap& pixmap) const - // override { - // - // } - QRect subElementRect(SubElement element, const QStyleOption* option, const QWidget* widget) const override { - auto t = qobject_cast(widget); - if (!t) { - return QProxyStyle::subElementRect(element, option, widget); - } - // std::cout << "line_edit subElementRect " << element; - // 这里可以自定义返回不同的 QRect 以控制子元素的大小或位置 - if (element == SE_LineEditContents) { - QRect rect = QProxyStyle::subElementRect(element, option, widget); - // rect.adjust(5, 5, -5, -5); // 例如,让文本内容区域缩小一点 - return rect; - } - return QProxyStyle::subElementRect(element, option, widget); - } - }; -}; diff --git a/Widget/component/SVG.cpp b/Widget/component/SVG.cpp deleted file mode 100644 index 5ffdd37..0000000 --- a/Widget/component/SVG.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "SVG.h" -#include -#include "private_psc_global_include/export.h" -void SVG_Image_Render::render(QPainter* painter, const QRectF& rect) { - render(painter, rect, _color); -} -void SVG_Image_Render::render(QPainter* painter) { - QSvgRenderer renderer(change_color(_color)); - renderer.render(painter); -} -void SVG_Image_Render::render(QPainter* painter, const QRectF& rect, const QColor& color) { - QSvgRenderer renderer(change_color(color)); - renderer.render(painter, rect); -} -QImage SVG_Image_Render::to_image(QSize size, const QColor& color) { - QImage image(size, QImage::Format_ARGB32); - image.fill(Qt::transparent); - QPainter painter(&image); - QSvgRenderer renderer(change_color(color)); - renderer.render(&painter, QRectF(QPointF(0, 0), QSizeF(size))); - return image; -} -QPixmap SVG_Image_Render::to_pixmap(QSize size, const QColor& color) { - return QPixmap::fromImage(to_image(size, color)); -} -QByteArray SVG_Image_Render::change_color(const QColor& color) { - QDomElement root = doc.documentElement(); - auto text = color.name(QColor::HexRgb).toUpper(); - root.setAttribute("fill", text); - if (color.alpha() != 255) { - root.setAttribute("fill-opacity", QString::number(color.alphaF())); - } - QByteArray ret; - QTextStream out_stream(&ret); - doc.save(out_stream, 4); - return ret; -} -SVG_Image_Render& SVG_Image_Render::create() { - QFile file(_path); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - std::cout << VAR_STR_1(_path.toStdString()) + "无法打开! " + LOG_POS; - return *this; - } - QTextStream in(&file); - QString svg_content = in.readAll(); - file.close(); - doc.setContent(svg_content); - return *this; -} diff --git a/Widget/component/SVG.h b/Widget/component/SVG.h deleted file mode 100644 index 40ec74b..0000000 --- a/Widget/component/SVG.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once -#include -#include "global.h" -struct SVG_Image_Render { - SVG_Image_Render& set_path(const QString& path) { - this->_path = path; - return *this; - } - SVG_Image_Render& set_color(const QColor& color) { - this->_color = color; - return *this; - } - SVG_Image_Render& create(); - void render(QPainter* painter); - void render(QPainter* painter, const QRectF& rect); - void render(QPainter* painter, const QRectF& rect, const QColor& color); - QImage to_image(QSize size, const QColor& c); - QPixmap to_pixmap(QSize size, const QColor& c); - const QColor& get_color() { - return _color; - }; -protected: - QString _path; - QColor _color = QColor(Qt::red); - QDomDocument doc; - QByteArray change_color(const QColor& color); -}; diff --git a/Widget/component/Table/Base_Info.cpp b/Widget/component/Table/Base_Info.cpp deleted file mode 100644 index e55cf16..0000000 --- a/Widget/component/Table/Base_Info.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "Base_Info.h" -#include "third_party/Renderive/Widget/base/Generate_Mock_Data.h" -#include "third_party/Renderive/Widget/Qt/global.h" -namespace Flex_Qt { -Base_Info::Base_Info(int len, QString content) : len(len), content(std::move(content)) { - Range r{155, 255}; - QColor random_color(get_data(r), get_data(r), get_data(r)); - background_color = random_color; -} -void Base_Info::paint(QPainter* painter, QRect rect) { - painter->fillRect(rect, background_color); - painter->drawText(rect, Qt::AlignCenter, content); -} -} diff --git a/Widget/component/Table/Base_Info.h b/Widget/component/Table/Base_Info.h deleted file mode 100644 index 1a5e7e6..0000000 --- a/Widget/component/Table/Base_Info.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "global.h" -namespace Flex_Qt { -struct Base_Info { - virtual ~Base_Info() = default; - int len; - QString content{}; - bool hide = false; - QColor background_color; - explicit Base_Info(int len, QString content); - [[nodiscard]] QString to_string() const { - return QString("w:%1, content:%2").arg(len).arg(content); - } - virtual void paint(QPainter* painter, QRect rect); -}; -struct Row_Info : Base_Info { - explicit Row_Info(int h, const QString& content) : Base_Info(h, content) {} - int h() { - return len; - } - QString to_string() { - return QString("h:%1, content:%2").arg(len).arg(content); - } -}; -struct Col_Info : Base_Info { - explicit Col_Info(int w, const QString& content) : Base_Info(w, content) {} - int w() { - return len; - } -}; -} diff --git a/Widget/component/Table/Base_Table_Data.cpp b/Widget/component/Table/Base_Table_Data.cpp deleted file mode 100644 index c2153f1..0000000 --- a/Widget/component/Table/Base_Table_Data.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "Base_Table_Data.h" -#include "Table_View.h" -#include "third_party/Renderive/Widget/base/Generate_Mock_Data.h" -namespace Flex_Qt { -Base_Table_Data::Base_Table_Data() { - parent = this; -} -Table_Paint_Data::Table_Paint_Data(QIcon ic, QString t) { - Range r{155, 255}; - QColor random_color(get_data(r), get_data(r), get_data(r)); - background_color = random_color; - icon = Icon2(ic); - text.text = t; - layout.items.push_back(&icon.value()); - layout.items.push_back(&text); -} -Table_Paint_Data::Table_Paint_Data(QString t) { - Range r{155, 255}; - QColor random_color(get_data(r), get_data(r), get_data(r)); - background_color = random_color; - text.text = t; - layout.items.push_back(&text); -} -void Table_Paint_Data::update(bool show, Table_View* view, QPainter* painter, QRect rect) { - painter->fillRect(rect, background_color); - layout.set_x(rect.left()); - layout.set_y(rect.top()); - layout.set_w(rect.width()); - layout.set_h(rect.height()); - layout.layout(); - text.paint(painter, text.rect(), nullptr); - if (icon.has_value()) { - icon.value().paint(painter, icon.value().rect(), nullptr); - } - // painter->drawText(text.rect(), Qt::AlignCenter, text.text); -} -void Widget_Data::update(bool show, Table_View* view, QPainter* painter, QRect rect) { - // auto tl = view->to_inside_pos(rect.topLeft()); - // auto br = view->to_inside_pos(rect.bottomRight()); - auto tl = rect.topLeft() - view->get_view_rect().topLeft(); - auto br = tl + QPoint(rect.width(), rect.height()); - QRect r(tl, br); - // std::cout << r << "\n"; - if (show) { - widget->setParent(view->container); - widget->show(); - widget->installEventFilter(view); - widget->setGeometry(r); - } - else { - widget->setParent(nullptr); - widget->hide(); - widget->removeEventFilter(view); - } -} -} diff --git a/Widget/component/Table/Base_Table_Data.h b/Widget/component/Table/Base_Table_Data.h deleted file mode 100644 index 8ccba6c..0000000 --- a/Widget/component/Table/Base_Table_Data.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "../Base/Layout.h" -#include "../Base/global.h" -#include "global.h" -#include "third_party/Renderive/Widget/component/export.h" -namespace Flex_Qt { -class Icon2; -class Table_View; -struct Table_Edit_Able { - QString content; -}; -struct Base_Table_Data { - virtual ~Base_Table_Data() = default; - Base_Table_Data* parent{}; - Base_Table_Data(); - virtual void update(bool show, Table_View* view, QPainter* painter, QRect rect) {}; -}; -struct Table_Paint_Data : Base_Table_Data, Table_Edit_Able { - QColor background_color; - Table_Paint_Data(QIcon icon, QString text); - Table_Paint_Data(QString text); - std::optional icon; - Text text; - Layout layout; - void update(bool show, Table_View* view, QPainter* painter, QRect rect) override; -}; -struct Widget_Data : Base_Table_Data { - QWidget* widget{}; - void update(bool show, Table_View* view, QPainter* painter, QRect rect) override; -}; -} diff --git a/Widget/component/Table/Base_Table_Model.cpp b/Widget/component/Table/Base_Table_Model.cpp deleted file mode 100644 index 3104650..0000000 --- a/Widget/component/Table/Base_Table_Model.cpp +++ /dev/null @@ -1,315 +0,0 @@ -#include "Base_Table_Model.h" -#include "Base_Info.h" -#include "Base_Table_Data.h" -namespace Flex_Qt { -struct Row_Info; -Pos get_pos(Base_Info** infos, int n, int space, int pos, int margin) { - int cur_line_pos = margin; - int last_i = 0; - for (int i = 0; i < n - 1; ++i) { - auto cur = infos[i]; - if (cur->hide) { - continue; - } - int step = cur->len + space; - if (cur_line_pos + step > pos) { - return {i, cur_line_pos, pos - cur_line_pos}; - } - cur_line_pos += step; - last_i = i; - } - return {std::max(0, n - 1), cur_line_pos, pos - cur_line_pos}; -} -Base_Table_Model::Base_Table_Model() {} -Row_Info* Base_Table_Model::create_row_info(int h) { - return new Row_Info(h, ""); -} -Col_Info* Base_Table_Model::create_col_info(int w) { - return new Col_Info(w, ""); -} -// 核心位置计算 -int Memory_Table_Model::cell_x(int index) { - if (index == 0) - return 0; - int ret = 0; - for (int i = 0; i < index; i++) { - auto cur = col_info_list[i]; - if (cur->hide) - continue; - ret += cur->len + col_space; - } - return ret; -} -int Memory_Table_Model::cell_y(int index) { - if (index == 0) - return 0; - int ret = 0; - for (int i = 0; i < index; i++) { - auto cur = row_info_list[i]; - if (cur->hide) - continue; - ret += cur->len + row_space; - } - return ret; -} -int Memory_Table_Model::row_span_len(int row, int row_span) { - int ret = -row_space; - for (int i = 0; i < row_span; i++) { - auto cur = row_info_list[row + i]; - if (cur->hide) - continue; - ret += cur->len + row_space; - } - return ret; -} -int Memory_Table_Model::col_span_len(int col, int col_span) { - int ret = -col_space; - for (int i = 0; i < col_span; i++) { - auto cur = col_info_list[col + i]; - if (cur->hide) - continue; - ret += cur->len + col_space; - } - return ret; -} -Pos Memory_Table_Model::get_col(int x) { - return get_pos((Base_Info**)col_info_list.data(), col_info_list.size(), col_space, x, 0); -} -Pos Memory_Table_Model::get_row(int y) { - return get_pos((Base_Info**)row_info_list.data(), row_info_list.size(), row_space, y, 0); -} -std::vector> exchange_row_col(const std::vector>& data) { - std::vector> ret; - int m = data.size(); - int n = data.front().size(); - for (int i = 0; i < n; ++i) { - std::vector t; - for (int j = 0; j < m; ++j) { - t.push_back(data[j][i]); - } - ret.push_back(t); - } - return ret; -}; -enum Cell_Type { - Merge_head, - Merge_Cell, - Normal -}; -Cell_Type cell_type(const std::vector>& data, int col, int row) { - auto that = data[col][row]; - if (that->parent != that) - return Merge_Cell; - if (data[col + 1][row]->parent == that) - return Merge_head; - if (data[col][row + 1]->parent == that) - return Merge_head; - return Normal; -} -Cell_Info Base_Table_Model::get_span(int xi, int yi) { - return Cell_Info(xi, yi, col_span_len(xi, 1), row_span_len(yi, 1)); -} -Find_Ret Base_Table_Model::find_parent(Base_Table_Data* parent, int xi, int yi) { - return Find_Ret(xi, yi); -} -void Memory_Table_Model::split(int row, int col, int row_span, int col_span) { - for (int i = 0; i < col_span; ++i) { - for (int j = 0; j < row_span; ++j) { - auto cur = data[col + i][row + j]; - cur->parent = cur; - } - } -} -void Memory_Table_Model::merge(int row, int col, int row_span, int col_span) { - auto start = data[col][row]; - for (int i = 0; i < row_span; ++i) { - for (int j = 0; j < col_span; ++j) { - if (i == 0 && j == 0) - continue; - int cur_row = row + i; - int cur_col = col + j; - auto cur = data[cur_col][cur_row]; - cur->parent = start; - } - } -} -// parent 是复刻他上一行的parent -bool Memory_Table_Model::insert_row(int pos, const std::vector& infos, const std::vector>& d, Edge_Expand_Type t) { - int col_num = col_info_list.size(); - int insert_row_num = infos.size(); - if (!d.empty() && d.front().size() != col_num) { - std::cout << VAR_STR_2(d.front().size(), col_num) << " " << LOG_POS; - return false; - } - // 行结构转列结构 - auto insert_col_list = exchange_row_col(d); - for (int col = 0; col < col_num; ++col) { - Base_Table_Data* prev = nullptr; - Base_Table_Data* next = nullptr; - Base_Table_Data* par = nullptr; - int row_num = total_row(); - if (pos - 1 > 0 && pos - 1 < row_num) { - prev = data[col][pos - 1]; - } - if (pos < row_num) { - next = data[col][pos]; - } - if (t == Edge_Expand_Type::Positive) { - if (prev && prev->parent != prev) { - par = prev->parent; - } - } - else if (t == Edge_Expand_Type::Negative) { - if (next && next->parent != next) { - par = next->parent; - } - } - else if (t == Edge_Expand_Type::None) { - if (next && prev && prev->parent == next->parent) { - par = prev->parent; - } - } - for (int j = 0; j < insert_row_num; ++j) { - auto cur = insert_col_list[col][j]; - cur->parent = par ? par : cur; - } - data[col].insert(data[col].begin() + pos, insert_col_list[col].begin(), insert_col_list[col].end()); - } - row_info_list.insert(row_info_list.begin() + pos, infos.begin(), infos.end()); - return true; -} -bool Memory_Table_Model::insert_col(int pos, const std::vector& infos, const std::vector>& d, Edge_Expand_Type t) { - int row_num = row_info_list.size(); - int insert_col_num = infos.size(); - if (!d.empty() && d.front().size() != row_num) { - std::cout << VAR_STR_2(d.front().size(), row_num) << " " << LOG_POS; - return false; - } - for (int row = 0; row < row_num; ++row) { - Base_Table_Data* prev = nullptr; - Base_Table_Data* next = nullptr; - Base_Table_Data* par = nullptr; - int col_num = total_col(); - if (pos - 1 > 0 && pos - 1 < col_num) { - prev = data[pos - 1][row]; - } - if (pos < col_num) { - next = data[pos][row]; - } - if (t == Edge_Expand_Type::Positive) { - if (prev && prev->parent != prev) { - par = prev->parent; - } - } - else if (t == Edge_Expand_Type::Negative) { - if (next && next->parent != next) { - par = next->parent; - } - } - else if (t == Edge_Expand_Type::None) { - if (next && prev && prev->parent == next->parent) { - par = prev->parent; - } - } - for (int col = 0; col < insert_col_num; ++col) { - auto cur = d[col][row]; - cur->parent = par ? par : cur; - } - } - data.insert(data.begin() + pos, d.begin(), d.end()); - col_info_list.insert(col_info_list.begin() + pos, infos.begin(), infos.end()); - return true; -} -bool Memory_Table_Model::remove_row(int pos, int num) { - if (pos + num >= row_info_list.size()) { - std::cout << VAR_STR_3(pos, num, row_info_list.size()) << " " << LOG_POS; - return false; - } - for (auto& col : data) { - for (auto item = col.begin() + pos; item != col.begin() + pos + num; ++item) - delete *item; - col.erase(col.begin() + pos, col.begin() + pos + num); - } - for (int i = 0; i < num; ++i) { - delete row_info_list[pos + i]; - } - row_info_list.erase(row_info_list.begin() + pos, row_info_list.begin() + pos + num); - return true; -} -bool Memory_Table_Model::remove_col(int pos, int num) { - if (pos + num >= col_info_list.size()) { - std::cout << VAR_STR_3(pos, num, col_info_list.size()) << " " << LOG_POS; - return false; - } - for (auto column = data.begin() + pos; column != data.begin() + pos + num; ++column) { - for (auto* item : *column) - delete item; - } - data.erase(data.begin() + pos, data.begin() + pos + num); - for (int i = 0; i < num; ++i) { - delete col_info_list[pos + i]; - } - col_info_list.erase(col_info_list.begin() + pos, col_info_list.begin() + pos + num); - return true; -} -Cell_Info Memory_Table_Model::get_span(int xi, int yi) { - int col_num = data.size(); - int row_num = data.front().size(); - Base_Table_Data* that = data[xi][yi]; - int col_span = 1; - int row_span = 1; - int sw = col_info_list[xi]->len; - int sh = row_info_list[yi]->len; - while (true) { - int index = xi + col_span; - if (index >= col_num) - break; - auto cur = data[index][yi]; - if (cur->parent != that) { - break; - } - sw += col_info_list[index]->len + col_space; - col_span++; - } - while (true) { - int index = yi + row_span; - if (index >= row_num) - break; - auto cur = data[xi][index]; - if (cur->parent != that) { - break; - } - sh += row_info_list[index]->len + row_space; - row_span++; - } - return {col_span, row_span, sw, sh}; -} -Find_Ret Memory_Table_Model::find_parent(Base_Table_Data* parent, int xi, int yi) { - int cur_x = xi; - int cur_y = yi; - if (xi != 0) { - while (true) { - auto cur = data[cur_x - 1][yi]; - if (cur->parent != parent && cur->parent != nullptr) { - break; - } - cur_x--; - if (cur_x == 0) - break; - } - } - if (yi != 0) { - while (true) { - auto cur = data[xi][cur_y - 1]; - if (cur->parent != parent && cur->parent != nullptr) { - break; - } - cur_y--; - if (cur_y == 0) - break; - } - } - // std::cout << "find_parent: " << data[xi][yi]->content << " " << cur_x << " " << cur_y; - return {cur_x, cur_y}; -} -} diff --git a/Widget/component/Table/Base_Table_Model.h b/Widget/component/Table/Base_Table_Model.h deleted file mode 100644 index 0124487..0000000 --- a/Widget/component/Table/Base_Table_Model.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once -#include "global.h" -namespace Flex_Qt { -// 主要包含 行列位置的核心位置计算 -// using T_Data = std::shared_ptr; -struct Edit_Func { - virtual ~Edit_Func() = default; - virtual bool insert_row(int pos, const std::vector& infos, const std::vector>& data, Edge_Expand_Type t) { - return true; - } - virtual bool insert_col(int pos, const std::vector& infos, const std::vector>& data, Edge_Expand_Type t) { - return true; - } - virtual bool remove_row(int pos, int num) { - return true; - } - virtual bool remove_col(int pos, int num) { - return true; - } - virtual void merge(int row, int col, int row_span, int col_span) {} - virtual void split(int row, int col, int row_span, int col_span) {} -}; -struct Base_Table_Model { - virtual ~Base_Table_Model() = default; - Base_Table_Model(); - int width() { - return col_span_len(0, total_col()); - } - int height() { - return row_span_len(0, total_row()); - } - // 重载这两个函数可以实现使用自己自定义的 Row_Info Col_Info - virtual Row_Info* create_row_info(int h); - virtual Col_Info* create_col_info(int w); - virtual Base_Table_Data* get_table_data(int col, int row) = 0; - virtual Col_Info* get_col_info(int pos) = 0; - virtual Row_Info* get_row_info(int pos) = 0; - // 表格绝对位置计算函数 - virtual Pos get_col(int x) = 0; - virtual Pos get_row(int y) = 0; - virtual int cell_x(int index) = 0; - virtual int cell_y(int index) = 0; - virtual int total_row() = 0; - virtual int total_col() = 0; - virtual int row_span_len(int row, int row_span) = 0; - virtual int col_span_len(int col, int col_span) = 0; - virtual Cell_Info get_span(int xi, int yi); // 获取某一位置,隶属于哪一个大格子(合并单元格场景下) - virtual Find_Ret find_parent(Base_Table_Data* parent, int xi, int yi); // 从xi,yi位置寻找到其隶属于的大格子(合并单元格场景下) - int col_space = 14; - int row_space = 14; - int col_min_w = 8; - int row_min_h = 8; -}; -Pos get_pos(Base_Info** infos, int n, int space, int pos, int margin); -// 直接把数据放在内存里的模型 -struct Memory_Table_Model : Base_Table_Model, Edit_Func { - void split(int row, int col, int row_span, int col_span) override; - void merge(int row, int col, int row_span, int col_span) override; - bool insert_row(int pos, const std::vector& infos, const std::vector>& data, Edge_Expand_Type) override; - bool insert_col(int pos, const std::vector& infos, const std::vector>& data, Edge_Expand_Type) override; - bool remove_row(int pos, int num) override; - bool remove_col(int pos, int num) override; - // 表格区域绝对位置计算 - Pos get_col(int x) override; - Pos get_row(int y) override; - int cell_x(int index) override; - int cell_y(int index) override; - int total_row() override { - return row_info_list.size(); - } - int total_col() override { - return col_info_list.size(); - } - int row_span_len(int row, int row_span) override; - int col_span_len(int col, int col_span) override; - Cell_Info get_span(int xi, int yi) override; - Find_Ret find_parent(Base_Table_Data* parent, int xi, int yi) override; - Row_Info* get_row_info(int pos) override { - return row_info_list[pos]; - } - Col_Info* get_col_info(int pos) override { - return col_info_list[pos]; - } - Base_Table_Data* get_table_data(int col, int row) override { - return data[col][row]; - } -protected: - std::vector col_info_list; - std::vector row_info_list; - std::vector> data; - friend Table_View* create_table_view(); - friend Table_View* create_table_view2(); -}; -} diff --git a/Widget/component/Table/Table_View.cpp b/Widget/component/Table/Table_View.cpp deleted file mode 100644 index 21e9988..0000000 --- a/Widget/component/Table/Table_View.cpp +++ /dev/null @@ -1,512 +0,0 @@ -#include "Table_View.h" -#include -#include -#include "Base_Info.h" -#include "Base_Table_Data.h" -namespace Flex_Qt { -QPoint Table_View::to_inside_pos(QPoint widget_pos) { - auto rect = get_view_rect(); - return widget_pos + this->_view_pos - QPoint(rect.left(), rect.top()); -} -QPoint Table_View::to_widget_pos(QPoint inside_pos) { - auto rect = get_view_rect(); - return inside_pos - this->_view_pos + QPoint(rect.left(), rect.top()); -} -QRect Table_View::get_view_rect() { - int left = row_info_w + row_info_inside_space + left_margin; - int top = col_info_h + col_info_inside_space + top_margin; - int right = (v_bar.show ? static_cast(v_bar.w) : 0) + right_margin; - int bottom = (h_bar.show ? static_cast(h_bar.h) : 0) + bottom_margin; - QRect all_view_rect = QRect(left, top, width() - left - right, height() - top - bottom); - return all_view_rect; -} -Table_View::Table_View() { - setAttribute(Qt::WA_Hover); - setMouseTracking(true); - edit = new QTextEdit(); - container = new Container(this); - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); -} -void Table_View::resizeEvent(QResizeEvent* event) { - QRect vr = get_view_rect(); - h_bar.start = vr.x(); - h_bar.resize(vr.width(), vr.width(), model->width()); - v_bar.start = vr.y(); - v_bar.resize(vr.height(), vr.height(), model->height()); - container->setGeometry(vr); - QWidget::resizeEvent(event); -} -bool Table_View::eventFilter(QObject* obj, QEvent* event) { - if (event->type() == QEvent::Enter) { - setCursor(Qt::ArrowCursor); - } - return QObject::eventFilter(obj, event); -} -void Table_View::paintEvent(QPaintEvent* event) { - static QImage img(":/jian_hao.png"); - static QImage img2(":/jia_hao.png"); - static int space = 4; - QPainter painter(this); - // 视图位置转换为绝对位置 - QRect cells_widget_rect = get_view_rect(); - QPen pen(Qt::black, 1); - painter.setPen(pen); - painter.drawRect(cells_widget_rect.adjusted(-1, -1, 0, 0)); - auto inside_sta_pos = to_inside_pos(cells_widget_rect.topLeft()); - auto inside_end_pos = to_inside_pos(cells_widget_rect.bottomRight()); - Pos x_sta = model->get_col(inside_sta_pos.rx()); - Pos y_sta = model->get_row(inside_sta_pos.ry()); - Pos x_end = model->get_col(inside_end_pos.rx()); - Pos y_end = model->get_row(inside_end_pos.ry()); - struct Paint_Cache { - int cell_abs_pos; - int index; - Base_Info* info; - }; - // 计算横着每个格子起点的绝对位置 - int xsi = x_sta.index; - int max_col_num = std::min(x_end.index - x_sta.index + 1, model->total_col()); - int col_num = 0; - std::vector xs; - { - int cur_x = x_sta.cell_pos; - for (int i = 0; i < max_col_num; ++i) { - auto cur = model->get_col_info(xsi + i); - if (cur->hide) - continue; - xs.push_back({cur_x, i, cur}); - cur_x += cur->len + model->col_space; - } - col_num = xs.size(); - } - // 计算竖着每个格子起点的绝对位置 - int ysi = y_sta.index; - int max_row_num = std::min(y_end.index - y_sta.index + 1, model->total_row()); - int row_num = 0; - std::vector ys; - { - int cur_y = y_sta.cell_pos; - for (int i = 0; i < max_row_num; ++i) { - auto cur = model->get_row_info(ysi + i); - if (cur->hide) - continue; - ys.push_back({cur_y, i, cur}); - cur_y += cur->len + model->row_space; - } - row_num = ys.size(); - } - // 绘制表头 水平 - { - painter.setPen(Qt::black); - int end_y = cells_widget_rect.y() - col_info_inside_space; - int sta_y = end_y - col_info_h; - { - QPoint s = QPoint(cells_widget_rect.x(), sta_y); - QPoint e = QPoint(cells_widget_rect.right(), end_y); - painter.setClipRect(QRect(s, e)); - } - std::vector middle_xs(col_num + 1); - for (int i = 0; i < col_num; ++i) { - auto& xd = xs[i]; - int sta_x = to_widget_pos({xd.cell_abs_pos, 0}).rx(); - int end_x = to_widget_pos({xd.cell_abs_pos + xd.info->len, 0}).rx(); - if (i == 0) { - middle_xs[0] = sta_x - model->row_space / 2; - } - middle_xs[i + 1] = end_x + model->row_space / 2; - QRect re(QPoint(sta_x, sta_y), QPoint(end_x, end_y)); - xd.info->paint(&painter, re); - } - { - QPoint s = QPoint(cells_widget_rect.x(), sta_y); - painter.setClipRect(QRect(s, cells_widget_rect.bottomRight())); - } - painter.setPen(Qt::black); - for (int i = 0; i < col_num; ++i) { - int middle_x = middle_xs[i]; - painter.drawLine(QPoint(middle_x, 0), QPoint(middle_x, height())); - } - } - // 绘制表头 竖直 - { - painter.setPen(Qt::black); - int end_x = cells_widget_rect.x() - row_info_inside_space; - int sta_x = end_x - row_info_w; - { - QPoint s = QPoint(sta_x, cells_widget_rect.y()); - QPoint e = QPoint(end_x, cells_widget_rect.bottom()); - painter.setClipRect(QRect(s, e)); - } - std::vector middle_ys(row_num); - for (int i = 0; i < row_num; ++i) { - auto& yd = ys[i]; - int sta_y = to_widget_pos({0, yd.cell_abs_pos}).ry(); - int end_y = to_widget_pos({0, yd.cell_abs_pos + yd.info->len}).ry(); - middle_ys[i] = end_y + model->col_space / 2; - QRect re(QPoint(sta_x, sta_y), QPoint(end_x, end_y)); - yd.info->paint(&painter, re); - } - { - QPoint s = QPoint(sta_x, cells_widget_rect.y()); - painter.setClipRect(QRect(s, cells_widget_rect.bottomRight())); - } - painter.setPen(Qt::black); - for (int i = 0; i < row_num; ++i) { - int middle_y = middle_ys[i]; - painter.drawLine(QPoint(0, middle_y), QPoint(width(), middle_y)); - } - } - // 绘制滚动条 - if (h_bar.show) { - h_bar.draw(&painter); - } - if (v_bar.show) { - v_bar.draw(&painter); - } - std::set set; - // 绘制小方格 - painter.setClipRect(cells_widget_rect); - painter.setPen(Qt::black); - for (auto& xd : xs) { - for (auto& yd : ys) { - int xi = xsi + xd.index; - int yi = ysi + yd.index; - auto cur_cell = model->get_table_data(xi, yi); - QPoint cur_inside_sta_pos; - QPoint cur_inside_end_pos; - auto show_cell = cur_cell; - bool show = true; - if (cur_cell->parent != nullptr && cur_cell->parent != cur_cell) { - auto r = model->find_parent(cur_cell->parent, xi, yi); - if ( - r.col_index < xsi || - r.row_index < ysi) { - if (set.find(cur_cell->parent) == set.end()) { - set.insert(cur_cell->parent); - int sxi = r.col_index; - int syi = r.row_index; - show = true; - auto info = model->get_span(sxi, syi); - int x = model->cell_x(sxi); - int y = model->cell_y(syi); - cur_inside_sta_pos = {x, y}; - cur_inside_end_pos = {x + info.sw, y + info.sh}; - show_cell = model->get_table_data(sxi, syi); - } - else { - show = false; - } - } - } - else { - auto info = model->get_span(xi, yi); - cur_inside_sta_pos = {xd.cell_abs_pos, yd.cell_abs_pos}; - cur_inside_end_pos = {xd.cell_abs_pos + info.sw, yd.cell_abs_pos + info.sh}; - } - QPoint cur_widget_sta_pos = to_widget_pos(cur_inside_sta_pos); - QPoint cur_widget_end_pos = to_widget_pos(cur_inside_end_pos); - QRect cur_view_rect = QRect(cur_widget_sta_pos, cur_widget_end_pos); - show_cell->update(show, this, &painter, cur_view_rect); - } - } -} -bool Table_View::event(QEvent* e) { - if ( - e->type() == QEvent::MouseButtonPress || - e->type() == QEvent::MouseMove || - e->type() == QEvent::MouseButtonRelease || - e->type() == QEvent::MouseButtonDblClick) { - auto event = static_cast(e); - mouse_event(event, event->type()); - return true; - } - return QWidget::event(e); -} -void Table_View::leaveEvent(QEvent* event) { - QWidget::leaveEvent(event); -} -void Table_View::mouse_event(QMouseEvent* event, QEvent::Type type) { - QRect cells_widget_rect = get_view_rect(); - auto pos = event->pos(); - auto abs_pos = to_inside_pos(pos); - Pos px = model->get_col(abs_pos.x()); - Pos py = model->get_row(abs_pos.y()); - bool drag_on_col_space = false; - bool drag_on_row_space = false; - Col_Info* cur_col{}; - Row_Info* cur_row{}; - if (model->total_col() != 0) { - cur_col = model->get_col_info(px.index); - if (use_drag_w && px.offset > cur_col->len && px.offset < cur_col->len + model->col_space) { - drag_on_col_space = true; - } - } - if (model->total_row() != 0) { - cur_row = model->get_row_info(py.index); - if (use_drag_h && py.offset > cur_row->len && py.offset < cur_row->len + model->row_space) { - drag_on_row_space = true; - } - } - bool on_h_slider = h_bar.get_slider_rect(width(), height()).contains(event->pos()); - bool on_v_slider = v_bar.get_slider_rect(width(), height()).contains(event->pos()); - bool on_cells_view = cells_widget_rect.contains(pos); - if (cur_col && cur_row) { - auto cur_cell = model->get_table_data(px.index, py.index); - auto parent_pos = model->find_parent(cur_cell->parent, px.index, py.index); - auto show_cell = model->get_table_data(parent_pos.col_index, parent_pos.row_index); - int sci = parent_pos.col_index; - int sri = parent_pos.row_index; - auto sx = model->cell_x(sci); - auto sy = model->cell_y(sri); - auto info = model->get_span(parent_pos.col_index, parent_pos.row_index); - QPoint s_sta = to_widget_pos({sx, sy}); - QPoint s_end = to_widget_pos({sx + info.sw, sy + info.sh}); - QRect srect = QRect(s_sta, s_end); - if (type == QEvent::MouseButtonDblClick) { - if (on_cells_view && srect.contains(s_sta)) { - edit->setGeometry(srect); - prev_data = show_cell; - auto ttd = dynamic_cast(show_cell); - if (ttd) { - edit->setText(ttd->content); - edit->setParent(this); - edit->show(); - } - } - } - } - if (type == QEvent::MouseButtonPress) { - // std::cout << "cur_cell " << cur_cell->content ; - // std::cout << "cur_cell_parent "<< (cur_cell->parent ? cur_cell->parent->content : "nullptr"); - edit->hide(); - if (prev_data) { - auto ttd = dynamic_cast(prev_data); - if (ttd) { - ttd->content = edit->toPlainText(); - prev_data = nullptr; - update(); - } - } - // std::cout << log; - if (is_ctrl_pressed()) { - is_dragging = true; - drag_type = Table_Move; - setCursor(Qt::OpenHandCursor); - } - else if (on_h_slider) { - is_dragging = true; - drag_type = H_scrollBar; - setCursor(Qt::SizeHorCursor); - } - else if (on_v_slider) { - is_dragging = true; - drag_type = V_scrollBar; - setCursor(Qt::SizeVerCursor); - } - else if (drag_on_col_space) { - is_dragging = true; - drag_type = H_Expand; - col_expand = cur_col; - start_expand_len = col_expand->len; - setCursor(Qt::SplitHCursor); - } - else if (drag_on_row_space) { - is_dragging = true; - drag_type = V_Expand; - row_expand = cur_row; - start_expand_len = row_expand->len; - setCursor(Qt::SplitVCursor); - } - else { - setCursor(Qt::ArrowCursor); - } - if (is_dragging) { - start_pos = event->pos(); - save_pos = _view_pos; - } - } - else if (type == QEvent::MouseButtonRelease) { - is_dragging = false; - if (drag_on_col_space) { - setCursor(Qt::SplitHCursor); - } - else if (drag_on_row_space) { - setCursor(Qt::SplitVCursor); - } - else if (on_h_slider) { - setCursor(Qt::SizeHorCursor); - } - else if (on_v_slider) { - setCursor(Qt::SizeVerCursor); - } - else { - setCursor(Qt::ArrowCursor); - } - } - else if (type == QEvent::MouseMove) { - if (is_ctrl_pressed()) { - if (is_dragging) { - setCursor(Qt::ClosedHandCursor); - } - else { - setCursor(Qt::OpenHandCursor); - } - } - else { - if (!is_dragging) { - if (drag_on_col_space) { - setCursor(Qt::SplitHCursor); - } - else if (drag_on_row_space) { - setCursor(Qt::SplitVCursor); - } - else if (on_h_slider) { - setCursor(Qt::SizeHorCursor); - } - else if (on_v_slider) { - setCursor(Qt::SizeVerCursor); - } - else { - setCursor(Qt::ArrowCursor); - } - } - } - if (!is_dragging) - return; - QPoint cur_pos = event->pos(); - int delta_x = cur_pos.x() - start_pos.x(); // 计算X轴的拖动距离 - int delta_y = cur_pos.y() - start_pos.y(); // 计算Y轴的拖动距离 - if (drag_type == Table_Move && is_ctrl_pressed()) { - int end_x = save_pos.x() - delta_x; - int end_y = save_pos.y() - delta_y; - _view_pos.setX(end_x); - _view_pos.setY(end_y); - h_bar.set_view_pos(_view_pos.rx()); - v_bar.set_view_pos(_view_pos.ry()); - } - else if (drag_type == H_scrollBar) { - int end_x = save_pos.x() + delta_x / h_bar.rate(); - _view_pos.setX(end_x); - h_bar.set_view_pos(end_x); - } - else if (drag_type == V_scrollBar) { - int end_y = save_pos.y() + delta_y / v_bar.rate(); - _view_pos.setY(end_y); - v_bar.set_view_pos(end_y); - } - else if (drag_type == H_Expand) { - col_expand->len = std::max(model->col_min_w, start_expand_len + delta_x); - } - else if (drag_type == V_Expand) { - row_expand->len = std::max(model->row_min_h, start_expand_len + delta_y); - } - update(); - } -} -void Table_View::wheelEvent(QWheelEvent* event) { - int single_step = 12; - double v_steps = event->angleDelta().y() / 120; - v_bar.set_view_pos(v_bar.get_view_pos() - v_steps * single_step); - double h_steps = event->angleDelta().x() / 120; - h_bar.set_view_pos(h_bar.get_view_pos() - h_steps * single_step); - _view_pos.setX(h_bar.view_pos()); - _view_pos.setY(v_bar.view_pos()); - update(); -} -} -#ifdef YC_USE_GTEST -#include -TEST(Table, get_pos_test) { - std::vector info_list; - // 4 2 1 - // 4 6 7 - info_list.push_back(new Base_info(4, "")); - info_list.push_back(new Base_info(1, "")); - auto size = static_cast(info_list.size()); - auto d = info_list.data(); - std::vector> combined_data = { - {Base_Table_Info::Pos{0, 0, -7}, -7}, - {Base_Table_Info::Pos{0, 0, 4}, 4}, - {Base_Table_Info::Pos{1, 6, 1}, 7}, - {Base_Table_Info::Pos{1, 6, 2}, 8}, - }; - for (auto it : combined_data) { - auto answer = it.first; - auto input = it.second; - auto pos = get_pos(d, size, 2, input, 0); - EXPECT_TRUE(pos == answer) << "输入:" << input << "\n" - << "结果:" + pos.to_string() << "\n" - << "期望:" + answer.to_string() << "\n"; - } -} -// 测试 Matrix 类的基本操作 -TEST(MatrixTest, BasicOperations) { - // 初始化一个 3x3 矩阵 - Table mat; - mat.data = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; - // 测试 total_row 和 total_col - EXPECT_EQ(mat.total_row(), 3); - EXPECT_EQ(mat.total_col(), 3); - // 测试 at 方法 - EXPECT_EQ(mat.at(0, 0), 1); - EXPECT_EQ(mat.at(1, 1), 5); - EXPECT_EQ(mat.at(2, 2), 9); - // 测试 row 方法 - std::vector row_0 = mat.row(0); - EXPECT_EQ(row_0.size(), 3); - EXPECT_EQ(row_0[0], 1); - EXPECT_EQ(row_0[1], 2); - EXPECT_EQ(row_0[2], 3); - // 测试 col 方法 - std::vector col_0 = mat.col(0); - EXPECT_EQ(col_0.size(), 3); - EXPECT_EQ(col_0[0], 1); - EXPECT_EQ(col_0[1], 4); - EXPECT_EQ(col_0[2], 7); - // 测试 sub_matrix 方法 - Table sub_mat = mat.sub_table(0, 0, 2, 2); - EXPECT_EQ(sub_mat.total_row(), 2); - EXPECT_EQ(sub_mat.total_col(), 2); - EXPECT_EQ(sub_mat.at(0, 0), 1); - EXPECT_EQ(sub_mat.at(1, 1), 5); -} -TEST(MatrixTest, SubMatrix) { - // 测试提取子矩阵 - Table mat; - mat.data = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; - Table sub_mat = mat.sub_table(1, 1, 2, 2); - EXPECT_EQ(sub_mat.total_row(), 2); - EXPECT_EQ(sub_mat.total_col(), 2); - EXPECT_EQ(sub_mat.at(0, 0), 5); - EXPECT_EQ(sub_mat.at(0, 1), 6); - EXPECT_EQ(sub_mat.at(1, 0), 8); - EXPECT_EQ(sub_mat.at(1, 1), 9); -} -TEST(MatrixTest, EmptyMatrix) { - // 测试空矩阵 - Table mat; - EXPECT_EQ(mat.total_row(), 0); - EXPECT_EQ(mat.total_col(), 0); -} -TEST(MatrixTest, SingleElementMatrix) { - // 测试 1x1 矩阵 - Table mat; - mat.data = {{42}}; - EXPECT_EQ(mat.total_row(), 1); - EXPECT_EQ(mat.total_col(), 1); - EXPECT_EQ(mat.at(0, 0), 42); -} -#include -#ifdef _WINDOWS -#include -#endif -int main() { - QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); -#ifdef _WINDOWS -SetConsoleOutputCP (CP_UTF8); -#endif -testing::InitGoogleTest(); -RUN_ALL_TESTS(); - return 0; -} -#endif diff --git a/Widget/component/Table/Table_View.h b/Widget/component/Table/Table_View.h deleted file mode 100644 index a9cf604..0000000 --- a/Widget/component/Table/Table_View.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once -#include "Base_Table_Model.h" -#include "global.h" -#include "scroll.h" -#include -namespace Flex_Qt { -/* - 使用Data更好 因为使用Data如果你想用指针你依然可以传入指针 - 表格功能分析 - 1. 拖动改变大小 - 2. 合并单元格 - 3. 内嵌控件 - 首先是表格数据结构 包含位置和 ui计算 - 表格自身内容绘制 自定义组件嵌入 - 合并单元格通过 合并入控制 - 表格也是model view 格式 - view 根据model的接口 两个rect计算需要绘制的元素以及位置 然后 开始绘制 - */ -class Container : public QWidget { -public: - Container(QWidget* parent = nullptr) : QWidget(parent) { - setMouseTracking(true); - setWindowFlag(Qt::WindowTransparentForInput, true); // 透传所有输入事件 - // 使该控件对所有事件透明,事件会传递给下层控件或父控件 - // setAttribute(Qt::WA_TransparentForMouseEvents); - setAttribute(Qt::WA_InputMethodTransparent); - } - void paintEvent(QPaintEvent* event) override { - QPainter painter(this); - painter.fillRect(rect(), QColor(200, 200, 200, 100)); - painter.end(); - } - void mousePressEvent(QMouseEvent* event) override { - event->ignore(); // 不拦截,交给子控件或父控件处理 - } - void mouseReleaseEvent(QMouseEvent* event) override { - event->ignore(); - } - void mouseMoveEvent(QMouseEvent* event) override { - event->ignore(); - } -}; -class Table_View : public QWidget { -public: - Table_View(); - Container* container; - Base_Table_Model* model{}; - V_Scroll_Bar v_bar; - H_Scroll_Bar h_bar; - QTextEdit* edit; - // inside and outside - int col_info_h = 30; - int row_info_w = 30; - int col_info_inside_space = 10; - int row_info_inside_space = 10; - int h_bar_space = 10; - int v_bar_space = 10; - int top_margin = 10; - int left_margin = 10; - int right_margin = 10; - int bottom_margin = 10; - QPoint to_inside_pos(QPoint widget_pos); - QPoint to_widget_pos(QPoint inside_pos); - QRect get_view_rect(); - static bool is_ctrl_pressed() { - if (Qt::ControlModifier& QApplication::keyboardModifiers()) { - return true; - } - else { - return false; - } - } - enum Drag_Type { - Table_Move, - H_scrollBar, - V_scrollBar, - V_Expand, - H_Expand, - } drag_type{}; - bool is_dragging = false; - QPoint start_pos; - QPoint _view_pos = {0, 0}; - QPoint save_pos; - Col_Info* col_expand{}; - Row_Info* row_expand{}; - int start_expand_len{}; - Base_Table_Data* prev_data{}; - bool use_drag_h = true; - bool use_drag_w = true; -protected: - bool event(QEvent* event) override; - bool eventFilter(QObject* obj, QEvent* event) override; - void paintEvent(QPaintEvent* event) override; - void resizeEvent(QResizeEvent* event) override; - void wheelEvent(QWheelEvent* event) override; - void mouse_event(QMouseEvent* event, QEvent::Type type); - void leaveEvent(QEvent* event) override; -}; -} diff --git a/Widget/component/Table/export.h b/Widget/component/Table/export.h deleted file mode 100644 index b72e32f..0000000 --- a/Widget/component/Table/export.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include "Base_Info.h" -#include "Base_Table_Data.h" -#include "Base_Table_Model.h" -#include "Table_View.h" -#include "global.h" -#include "scroll.h" diff --git a/Widget/component/Table/global.cpp b/Widget/component/Table/global.cpp deleted file mode 100644 index b1ed688..0000000 --- a/Widget/component/Table/global.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "global.h" -namespace Flex_Qt {} diff --git a/Widget/component/Table/global.h b/Widget/component/Table/global.h deleted file mode 100644 index 9f556dd..0000000 --- a/Widget/component/Table/global.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace Flex_Qt { -struct Base_Table_Data; -struct Base_Info; -struct Row_Info; -struct Col_Info; -class Table_View; -struct Cell_Info { - int col_idx, row_idx; - int sw, sh; -}; -struct Pos { - int index; // 头的索引 - int cell_pos; // index位置的块 头的绝对位置 - int offset; // 相对于块头的偏移 - [[nodiscard]] int pos() const { - return cell_pos + offset; - } - Pos(int index, int cell_pos, int offset) : index(index), cell_pos(cell_pos), offset(offset) {} - bool operator==(const Pos& p) const { - return p.cell_pos == cell_pos && index == p.index && offset == p.offset; - } - bool operator!=(const Pos& pos) const { - return !operator==(pos); - } - QString to_string() const { - return QString("index:%1 pos:%2 offset:%3").arg(index).arg(cell_pos).arg(offset); - } -}; -struct Find_Ret { - int col_index; - int row_index; - QString to_string() const { - return QString("Find_Ret(%1, %2)").arg(col_index).arg(row_index); - } -}; -// 纯虚函数 -enum class Edge_Expand_Type { - Positive, // 顺着坐标轴方向拓展 - Negative, // 逆着坐标轴方向拓展 - None // 不进行边缘拓展 -}; -} diff --git a/Widget/component/Table/scroll.cpp b/Widget/component/Table/scroll.cpp deleted file mode 100644 index bb2962b..0000000 --- a/Widget/component/Table/scroll.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "scroll.h" -namespace Flex_Qt { -void V_Scroll_Bar::draw(QPainter* painter) { - auto device = painter->device(); - double ww = device->width(); - double hh = device->height(); - painter->save(); - auto bar_rect = get_bar_rect(ww, hh); - painter->setClipRect(bar_rect); - painter->fillRect(bar_rect, background_color); - painter->fillRect(get_slider_rect(ww, hh), slider_color); - painter->restore(); -} -QRect V_Scroll_Bar::get_slider_rect(int ww, int hh) { - double x = ww - w; - QRect slider(x, pos() + start, w, slider_len()); - return slider; -} -QRect V_Scroll_Bar::get_bar_rect(int ww, int hh) { - double x = ww - w; - QRect bar_rect(x, 0 + start, w, bar_len()); - return bar_rect; -} -void H_Scroll_Bar::draw(QPainter* painter) { - auto device = painter->device(); - double ww = device->width(); - double hh = device->height(); - painter->save(); - auto bar_rect = get_bar_rect(ww, hh); - painter->setClipRect(bar_rect); - painter->fillRect(bar_rect, background_color); - painter->fillRect(get_slider_rect(ww, hh), slider_color); - painter->restore(); -} -QRect H_Scroll_Bar::get_slider_rect(int ww, int hh) { - double y = hh - h; - QRect slider_rect(pos() + start, y, slider_len(), h); - return slider_rect; -} -QRect H_Scroll_Bar::get_bar_rect(int ww, int hh) { - double y = hh - h; - QRect bar_rect(0 + start, y, bar_len(), h); - return bar_rect; -} -} diff --git a/Widget/component/Table/scroll.h b/Widget/component/Table/scroll.h deleted file mode 100644 index aee1296..0000000 --- a/Widget/component/Table/scroll.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include -#include -#include -namespace Flex_Qt { -class Base_Scroll_Bar { -public: - // 距离控件起点的位置 - int start = 0; - double get_view_pos() { - return this->_view_pos; - } - void set_view_pos(int view_pos) { - this->_view_pos = view_pos; - } - void resize(int bar_len, int view_len, int owner_len) { - this->_bar_len = bar_len; - this->view_len = view_len; - this->owner_len = owner_len; - } - bool show = true; - QColor background_color = Qt::gray; - QColor slider_color = Qt::black; -protected: - // 主位置情况 - double owner_len = 1; - double _view_pos = 0; - double view_len = 1; - // 滚动条位置情况 - double _bar_len = 1; // 滚动条长度 -public: - double rate() { - return _bar_len / owner_len; - } - double bar_len() { - return _bar_len; - } - double pos() { - return _view_pos * _bar_len / owner_len; - } - double view_pos() { - return _view_pos; - } - double slider_len() { - return view_len * _bar_len / owner_len; - } -}; -// 向下 -class V_Scroll_Bar : public Base_Scroll_Bar { -public: - double w = 8; - void draw(QPainter* painter); - QRect get_slider_rect(int ww, int hh); - QRect get_bar_rect(int ww, int hh); -}; -// 向下 -class H_Scroll_Bar : public Base_Scroll_Bar { -public: - double h = 8; - void draw(QPainter* painter); - QRect get_slider_rect(int ww, int hh); - QRect get_bar_rect(int ww, int hh); -}; -} diff --git a/Widget/component/Tree/Tree_Model.cpp b/Widget/component/Tree/Tree_Model.cpp deleted file mode 100644 index cee569e..0000000 --- a/Widget/component/Tree/Tree_Model.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "Tree_Model.h" -#include -#include -#include -#include -namespace Flex_Qt { -int Tree_Node::get_deep() { - int ret = -1; - Tree_Node* cur = static_cast(this); - while (cur) { - cur = cur->par; - ret++; - } - return ret; -} -Tree_Node::Tree_Node() {} -int Tree_Node::index() { - auto found = std::find(par->sons.begin(), par->sons.end(), static_cast(this)); - return found == par->sons.end() ? -1 : static_cast(std::distance(par->sons.begin(), found)); -} -bool Tree_Node::is_root() { - return par == nullptr; -} -bool Tree_Node::is_leaf() { - return !sons.size(); -} -bool Tree_Node::is_first() { - return index() == 0; -} -bool Tree_Node::is_last() { - return index() == par->sons.size() - 1; -} -Tree_Node* Tree_Node::previous() { - if (is_first()) - return nullptr; - return par->sons[index() - 1]; -} -Tree_Node* Tree_Node::next() { - if (is_last()) - return nullptr; - return par->sons[index() + 1]; -} -Tree_Node* Tree_Node::last_child() { - if (is_leaf()) - std::cout << "last_child() error"; - return sons[sons.size() - 1]; -} -Tree_Node* Tree_Node::first_child() { - if (is_leaf()) - std::cout << "first_child() error"; - return sons[0]; -} -Tree_Node* Tree_Node::root() { - Tree_Node * ret = static_cast(this); - while (ret->par != nullptr) { - ret = ret->par; - } - return ret; -} -std::vector Tree_Node::deep_traversed() { - std::vector result; - if (!this) - return result; - std::stack stack; - stack.push(this); - while (!stack.empty()) { - Tree_Node * node = stack.top(); - stack.pop(); - result.push_back(node); - // 逆序压入子节点,保证从左到右的遍历顺序 - for (int i = node->sons.size() - 1; i >= 0; --i) { - stack.push(node->sons[i]); - } - } - return result; -} -std::vector Tree_Node::sequence_traversed() { - std::vector ret; - std::queue que; - Tree_Node * that = this; - que.push(that); - while (!que.empty()) { - Tree_Node * cur = que.front(); - que.pop(); - int n = cur->sons.size(); - ret.push_back(cur); - for (int i = 0; i < n; ++i) { - que.push(cur->sons[i]); - } - } - return ret; -} -std::vector Tree_Node::descendants() { - std::vector&& ret = sequence_traversed(); - ret.erase(ret.begin()); - return ret; -} -std::vector deep_traversed(const std::vector& nodes) { - std::vector result; - if (nodes.empty()) - return result; - std::stack stack; - for (Tree_Node * node : nodes) - { - if (node) - stack.push(node); - } - while (!stack.empty()) { - Tree_Node * node = stack.top(); - stack.pop(); - result.push_back(node); - // 逆序压入子节点,保证从左到右的遍历顺序 - for (int i = node->sons.size() - 1; i >= 0; --i) { - stack.push(node->sons[i]); - } - } - return result; -} -#define ReMain (pos - total_height) -int Tree_Model::height() { - int total_height = 0; - std::stack> stack; - for (Tree_Node * node : roots) - { - if (node) - stack.push({node, 0}); - } - Tree_Node * cur{}; - int deep{}; - while (!stack.empty()) { - auto t = stack.top(); - cur = t.first; - deep = t.second; - stack.pop(); - if (cur->expand) { - for (int i = cur->sons.size() - 1; i >= 0; --i) { - stack.push({cur->sons[i], deep + 1}); - } - } - total_height += cur->height + space; - } - return total_height; -} -Tree_Pos get_pos(int pos, const std::vector& roots, int space) { - int total_height = 0; - std::stack> stack; - for (Tree_Node * node : roots) - { - if (node) - stack.push({node, 0}); - } - Tree_Node * cur{}; - int deep{}; - while (!stack.empty()) { - auto t = stack.top(); - cur = t.first; - deep = t.second; - if (ReMain < cur->height) { - return Tree_Pos{cur, deep, total_height, ReMain, stack}; - } - stack.pop(); - if (cur->expand) { - for (int i = cur->sons.size() - 1; i >= 0; --i) { - stack.push({cur->sons[i], deep + 1}); - } - } - total_height += cur->height + space; - } - return Tree_Pos{cur, deep, total_height, ReMain, stack}; -} -void select_node(const std::vector& roots, int view_y, int length, int space, Node_Call_Back call_back) { - auto ret = get_pos(view_y, roots, space); - std::stack>& stack = ret.rest; - int cur_inside_y = ret.node_pos; - int cur_inside_end = cur_inside_y + length; - while (!stack.empty()) { - auto [cur, depth] = stack.top(); - stack.pop(); - if (cur->expand) { - for (int i = cur->sons.size() - 1; i >= 0; --i) { - stack.push({cur->sons[i], depth + 1}); - } - } - call_back(cur, depth, cur_inside_y); - cur_inside_y += cur->height + space; - if (cur_inside_y > cur_inside_end) { - break; - } - } -} -} diff --git a/Widget/component/Tree/Tree_Model.h b/Widget/component/Tree/Tree_Model.h deleted file mode 100644 index 1ff3af0..0000000 --- a/Widget/component/Tree/Tree_Model.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -namespace Flex_Qt { -class Tree_Node { -public: - explicit Tree_Node(); - // 判断状态 - int index(); - bool is_root(); - bool is_leaf(); - bool is_first(); - bool is_last(); - Tree_Node* previous(); - Tree_Node* next(); - Tree_Node* last_child(); - Tree_Node* first_child(); - Tree_Node* root(); - int get_deep(); - // 遍历值 - std::vector deep_traversed(); - std::vector sequence_traversed(); - std::vector descendants(); - Tree_Node* par = nullptr; - std::vector sons; - QString text; - bool expand = true; - int height = 20; - void add_child(Tree_Node* child) { - sons.push_back(child); - child->par = this; - } -}; -struct Tree_Pos { - Tree_Node* p{}; - int depth{}; - int node_pos{}; - int offset{}; - int pos() { - return node_pos + offset; - } - std::stack> rest; -}; -class Tree_Model { -public: - std::vector roots; - int tab_pixel_size = 8; - int png_len = 20; - int tab_width = 10; - int space = 4; - int height(); - int width() { - return 1000; - } -}; -Tree_Pos get_pos(int pos, const std::vector& roots, int space); -std::vector deep_traversed(const std::vector& nodes); -using Node_Call_Back = const std::function&; -void select_node(const std::vector& roots, int view_y, int length, int space, Node_Call_Back call_back); -} diff --git a/Widget/component/Tree/Tree_View.cpp b/Widget/component/Tree/Tree_View.cpp deleted file mode 100644 index fecf89b..0000000 --- a/Widget/component/Tree/Tree_View.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "Tree_View.h" -#include -#include -#include -#include -#include -#include "../../component/SVG.h" -#include "Tree_Model.h" -namespace Flex_Qt { -Tree_View* create_Tree_View() { - auto cn = [](const QString& text) { - auto ret = new Tree_Node(); - ret->text = text; - return ret; - }; - auto ret = new Tree_View(); - auto& roots = ret->model->roots; - int a1 = 10; - int a2 = 4; - int a3 = 10; - for (int i1 = 0; i1 < a1; i1++) { - QString t1 = QString("%1").arg(i1); - auto n1 = cn(t1); - for (int i2 = 0; i2 < a2; i2++) { - QString t2 = t1 + QString("_%1").arg(i2); - auto n2 = cn(t2); - for (int i3 = 0; i3 < a3; i3++) { - QString t3 = t2 + QString("_%1").arg(i3); - auto n3 = cn(t3); - n2->add_child(n3); - } - n1->add_child(n2); - } - roots.push_back(n1); - } - return ret; -} -QPoint Tree_View::to_inside_pos(QPoint widget_pos) { - auto rect = get_view_rect(); - return widget_pos + this->_view_pos - QPoint(rect.left(), rect.top()); -} -QPoint Tree_View::to_widget_pos(QPoint inside_pos) { - auto rect = get_view_rect(); - return inside_pos - this->_view_pos + QPoint(rect.left(), rect.top()); -} -QRect Tree_View::get_view_rect() { - int w = width() - left_margin - right_margin; - int h = height() - top_margin - bottom_margin; - return QRect(left_margin, top_margin, w, h); -} -Tree_View::Tree_View() { - _view_pos = {0, 0}; - //_view_pos = {0, 0}; - model = new Tree_Model(); -} -void Tree_View::paintEvent(QPaintEvent* event) { - QPainter painter(this); - QRect view_rect = get_view_rect(); - painter.drawRect(view_rect); - // painter.fillRect(rect(), Qt::yellow); - auto& roots = model->roots; - QFontMetrics fm(font); - static auto expand = SVG_Image_Render().set_path(":/you_jian_tou.svg").create().to_image({model->png_len, model->png_len}, Qt::black); - static auto retract = expand.transformed(QTransform().rotate(90)); - painter.setClipRect(view_rect); - select_node(roots, _view_pos.y(), view_rect.height(), model->space, [&](Tree_Node* cur, int depth, int cur_inside_y) { - int x = depth * model->tab_width; - int cur_h = cur->height; - { - // 绘制箭头 - QPoint sta = {x, cur_inside_y}; - QPoint end = {x + model->png_len, cur_inside_y + model->png_len}; - QPoint wsta = to_widget_pos(sta); - QPoint wend = to_widget_pos(end); - QRect r(wsta, wend); - painter.drawRect(r); - painter.drawImage(r.topLeft(), cur->expand ? expand : retract); - } - { - // 绘制文字 - x += model->png_len; - QPoint sta = {x, cur_inside_y + cur_h}; - painter.drawText(to_widget_pos(sta), cur->text); - } - }); - h_bar.draw(&painter); - v_bar.draw(&painter); - QWidget::paintEvent(event); -} -void Tree_View::mouse_event(QMouseEvent* event, QEvent::Type type) { - QRect view_rect = get_view_rect(); - QPoint pos = event->pos(); - bool on_h_slider = h_bar.get_slider_rect(width(), height()).contains(event->pos()); - bool on_v_slider = v_bar.get_slider_rect(width(), height()).contains(event->pos()); - if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick) { - select_node(model->roots, _view_pos.y(), view_rect.height(), model->space, [&](Tree_Node* cur, int depth, int cur_inside_y) { - int x = depth * model->tab_width; - int cur_h = cur->height; - QPoint sta = {x, cur_inside_y}; - QPoint end = {x + model->png_len, cur_inside_y + model->png_len}; - QPoint wsta = to_widget_pos(sta); - QPoint wend = to_widget_pos(end); - QRect r(wsta, wend); - if (r.contains(pos)) { - cur->expand = !cur->expand; - std::cout << "1111111 1 " << cur->expand; - update(); - } - }); - } - if (type == QEvent::MouseButtonPress) { - if (on_h_slider) { - is_dragging = true; - drag_type = H_scrollBar; - setCursor(Qt::SizeHorCursor); - } - else if (on_v_slider) { - is_dragging = true; - drag_type = V_scrollBar; - setCursor(Qt::SizeVerCursor); - } - else { - setCursor(Qt::ArrowCursor); - } - if (is_dragging) { - start_pos = event->pos(); - save_pos = _view_pos; - } - } - else if (type == QEvent::MouseButtonRelease) { - if (on_h_slider) { - setCursor(Qt::SizeHorCursor); - } - else if (on_v_slider) { - setCursor(Qt::SizeVerCursor); - } - else { - setCursor(Qt::ArrowCursor); - } - } - else if (type == QEvent::MouseMove) { - if (on_h_slider) { - setCursor(Qt::SizeHorCursor); - } - else if (on_v_slider) { - setCursor(Qt::SizeVerCursor); - } - else { - setCursor(Qt::ArrowCursor); - } - if (!is_dragging) - return; - QPoint cur_pos = event->pos(); - int delta_x = cur_pos.x() - start_pos.x(); // 计算X轴的拖动距离 - int delta_y = cur_pos.y() - start_pos.y(); // 计算Y轴的拖动距离 - if (drag_type == H_scrollBar) { - int end_x = save_pos.x() + delta_x / h_bar.rate(); - _view_pos.setX(end_x); - h_bar.set_view_pos(end_x); - } - else if (drag_type == V_scrollBar) { - int end_y = save_pos.y() + delta_y / v_bar.rate(); - _view_pos.setY(end_y); - v_bar.set_view_pos(end_y); - } - else { - setCursor(Qt::ArrowCursor); - } - update(); - } -} -bool Tree_View::event(QEvent* e) { - if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseMove || - e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::MouseButtonDblClick) { - auto event = static_cast(e); - mouse_event(event, event->type()); - return true; - } - return QWidget::event(e); -} -void Tree_View::resizeEvent(QResizeEvent* event) { - QRect cells_view_rect = get_view_rect(); - h_bar.start = cells_view_rect.x(); - h_bar.resize(cells_view_rect.width(), cells_view_rect.width(), model->width()); - v_bar.start = cells_view_rect.y(); - v_bar.resize(cells_view_rect.height(), cells_view_rect.height(), model->height()); - QWidget::resizeEvent(event); -} -void Tree_View::wheelEvent(QWheelEvent* event) { - double single_step = 12; - double v_steps = event->angleDelta().y() / 120.0; - v_bar.set_view_pos(v_bar.get_view_pos() - v_steps * single_step); - double h_steps = event->angleDelta().x() / 120.0; - h_bar.set_view_pos(h_bar.get_view_pos() - h_steps * single_step); - _view_pos.setX(h_bar.view_pos()); - _view_pos.setY(v_bar.view_pos()); - update(); -} -} diff --git a/Widget/component/Tree/Tree_View.h b/Widget/component/Tree/Tree_View.h deleted file mode 100644 index 19248f4..0000000 --- a/Widget/component/Tree/Tree_View.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include "../Table/scroll.h" -namespace Flex_Qt { -class Tree_Model; -class Tree_View : public QWidget { -public: - Tree_Model* model{}; - int left_margin = 30, right_margin = 30, top_margin = 30, bottom_margin = 30; - QFont font; - QPen pen; - Tree_View(); - QRect get_view_rect(); - QPoint to_inside_pos(QPoint widget_pos); - QPoint to_widget_pos(QPoint inside_pos); - V_Scroll_Bar v_bar; - H_Scroll_Bar h_bar; - enum Drag_Type { - H_scrollBar, - V_scrollBar - } drag_type{}; - bool is_dragging = false; - QPoint start_pos; - QPoint save_pos; - QPoint _view_pos = {0, 0}; -protected: - void paintEvent(QPaintEvent* event) override; - bool event(QEvent* event) override; - void mouse_event(QMouseEvent* event, QEvent::Type type); - void resizeEvent(QResizeEvent* event) override; - void wheelEvent(QWheelEvent* event) override; -}; -Tree_View* create_Tree_View(); -} diff --git a/Widget/component/Tree/export.h b/Widget/component/Tree/export.h deleted file mode 100644 index 670716b..0000000 --- a/Widget/component/Tree/export.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -#include "Tree_Model.h" -#include "Tree_View.h" diff --git a/Widget/component/effect.cpp b/Widget/component/effect.cpp deleted file mode 100644 index 22db192..0000000 --- a/Widget/component/effect.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "effect.h" -#include -#include -#include -void Wave_effect::draw(QPainter* painter) { - auto r = boundingRect(); - // r.adjusted(-10, -10, 10, 10); - // painter->setBrush(Qt::NoBrush); - painter->fillRect(r, Qt::yellow); - drawSource(painter); -} -QRectF Wave_effect::boundingRectFor(const QRectF& source_rect) const { - auto r = QGraphicsEffect::boundingRectFor(source_rect); - return r.adjusted(-10, -10, 10, 10); - // return QGraphicsEffect::boundingRectFor(source_rect); -} diff --git a/Widget/component/effect.h b/Widget/component/effect.h deleted file mode 100644 index f93047b..0000000 --- a/Widget/component/effect.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -#include -// https://blog.csdn.net/kenfan1647/article/details/116198981 -class Wave_effect : public QGraphicsEffect { -protected: - void draw(QPainter* painter) override; -public: - QRectF boundingRectFor(const QRectF& source_rect) const override; -}; diff --git a/Widget/component/export.h b/Widget/component/export.h deleted file mode 100644 index 20f9e55..0000000 --- a/Widget/component/export.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "Background.h" -#include "Base/export.h" -#include "Button.h" -#include "Combo_Box.h" -#include "Content.h" -#include "Input.h" -#include "SVG.h" -#include "Table/export.h" -#include "Tree/export.h" -#include "effect.h" -#include "frameless/export.h" -#include "global.h" -#include "simple_widget.h" diff --git a/Widget/component/frameless/Frame_Less_Widget.cpp b/Widget/component/frameless/Frame_Less_Widget.cpp deleted file mode 100644 index 1ead5e0..0000000 --- a/Widget/component/frameless/Frame_Less_Widget.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "Frame_Less_Widget.h" -#include -#include -#include -#include -using change_size = std::function; -Frame_Less_Widget::Frame_Less_Widget(QWidget* parent) : QWidget(parent) { - setMouseTracking(true); - setAttribute(Qt::WA_Hover); - setAttribute(Qt::WA_TranslucentBackground); - // setAttribute(Qt::WA_Mapped); - setWindowFlags( - Qt::Window | - Qt::FramelessWindowHint | - Qt::WindowSystemMenuHint | - Qt::WindowMinimizeButtonHint | - Qt::WindowMaximizeButtonHint); - space = 0; - radius = 16; - top_margin = 16; - bottom_margin = 16; - right_margin = 16; - left_margin = 16; - shapes = { - Qt::SizeFDiagCursor, Qt::SizeVerCursor, Qt::SizeBDiagCursor, - Qt::SizeHorCursor, Qt::ArrowCursor, Qt::SizeHorCursor, - Qt::SizeBDiagCursor, Qt::SizeVerCursor, Qt::SizeFDiagCursor, - Qt::ArrowCursor - }; - change_sizes = { - [this]() { - // R11 - setGeometry(start_x + dx, start_y + dy, qMax(start_w - dx, get_min_width()), qMax(start_h - dy, get_min_height())); - }, - [this]() { - // R12 - setGeometry(start_x, start_y + dy, qMax(start_w, get_min_width()), qMax(start_h - dy, get_min_height())); - }, - [this]() { - // R13 - setGeometry(start_x, start_y + dy, qMax(start_w + dx, get_min_width()), qMax(start_h - dy, get_min_height())); - }, - [this]() { - // R21 - setGeometry(start_x + dx, start_y, qMax(start_w - dx, get_min_width()), qMax(start_h, get_min_height())); - }, - []() { - // R22 - }, - [this]() { - // R23 - setGeometry(start_x, start_y, qMax(start_w + dx, get_min_width()), qMax(start_h, get_min_height())); - }, - [this]() { - // R31 - setGeometry(start_x + dx, start_y, qMax(start_w - dx, get_min_width()), qMax(start_h + dy, get_min_height())); - }, - [this]() { - // R32 - setGeometry(start_x, start_y, qMax(start_w, get_min_width()), qMax(start_h + dy, get_min_height())); - }, - [this]() { - // R33 - setGeometry(start_x, start_y, qMax(start_w + dx, get_min_width()), qMax(start_h + dy, get_min_height())); - }, - []() { - // null - } - }; -} -int Frame_Less_Widget::get_min_width() { - return 0; -} -int Frame_Less_Widget::get_min_height() { - return 0; -} -void Frame_Less_Widget::paintEvent(QPaintEvent* event) { - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - painter.fillRect(rect(), QColor(255, 255, 255, 1)); // 不能改 让他不是透明的 // painter.fillRect(r11, Qt::blue); - // painter.fillRect(r12, Qt::darkCyan); - // painter.fillRect(r13, Qt::green); - // painter.fillRect(r21, Qt::gray); - // painter.fillRect(r22, Qt::red); - // painter.fillRect(r23, Qt::darkGreen); - // painter.fillRect(r31, Qt::black); - // painter.fillRect(r32, Qt::darkRed); - // painter.fillRect(r33, Qt::darkBlue); 否则改变大小失效 - // https://blog.csdn.net/liushuaitong/article/details/122117384 - // https://www.cnblogs.com/linuxAndMcu/p/11057347.html - QRect rect = r22; - // painter.drawRoundedRect(rect, radius, radius); - // 画阴影边框 - auto color = background_color; - // int x_radius = r22.width(); - // int y_radius = r22.height(); - int x_radius = radius; - int y_radius = radius; - int mul = 2; - int n = top_margin / mul; - auto max = double(n * n * n); - double value = background_color.alpha(); - for (int i = 0; i < n; i++) { - if (i == 0) { - painter.setPen(Qt::NoPen); - QColor b = QColor::fromRgb(background_color.red(), background_color.green(), background_color.blue()); - painter.setBrush(b); - painter.drawRoundedRect(rect, x_radius, y_radius); - painter.setBrush(Qt::NoBrush); - } - else { - double rate = (i * i * i) / max; - color.setAlpha(static_cast(value * (1 - rate))); - painter.setBrush(color); - painter.drawRoundedRect(rect.adjusted(-i * mul, -i * mul, i * mul, i * mul), x_radius, y_radius); - } - } - painter.end(); -} -bool Frame_Less_Widget::event(QEvent* event) { - if (event->type() == QEvent::HoverMove) { - auto* hover_event = static_cast(event); - // std::cout << hover_event->pos(); - QMouseEvent mouse_event(QEvent::MouseMove, hover_event->pos(), - Qt::NoButton, Qt::NoButton, Qt::NoModifier); - mouseMoveEvent(&mouse_event); - } - return QWidget::event(event); -} -void Frame_Less_Widget::set_pos() { - x1 = 0; - x2 = x1 + left_margin + space; - x3 = width() - right_margin - space; - y1 = 0; - y2 = y1 + top_margin + space; - y3 = height() - bottom_margin - space; -} -void Frame_Less_Widget::set_rs() { - int w1 = x2 - x1, w2 = x3 - x2, w3 = width() - x3; - int h1 = y2 - y1, h2 = y3 - y2, h3 = height() - y3; - r11.setRect(x1, y1, w1, h1); - r12.setRect(x2, y1, w2, h1); - r13.setRect(x3, y1, w3, h1); - r21.setRect(x1, y2, w1, h2); - r22.setRect(x2, y2, w2, h2); - r23.setRect(x3, y2, w3, h2); - r31.setRect(x1, y3, w1, h3); - r32.setRect(x2, y3, w2, h3); - r33.setRect(x3, y3, w3, h3); -} -void Frame_Less_Widget::mousePressEvent(QMouseEvent* event) { - auto pos = event->pos(); - if (event->button() != Qt::LeftButton) - return; - if (changing_size) - return; - if (drag_moving) - return; - cur_r = get_rect_type(pos); - if (cur_r != Drag_R) { - changing_size = true; - setCursor(shapes[cur_r]); - } - else { - drag_moving = true; - setCursor(Qt::ClosedHandCursor); - } - if (changing_size || drag_moving) { - start_x = this->x(); - start_y = this->y(); - start_global_x = event->globalPos().x(); - start_global_y = event->globalPos().y(); - start_w = width(); - start_h = height(); - } -} -void Frame_Less_Widget::mouseReleaseEvent(QMouseEvent* event) { - if (changing_size) { - changing_size = false; - } - if (drag_moving) { - drag_moving = false; - setCursor(Qt::OpenHandCursor); - } -} -void Frame_Less_Widget::mouseMoveEvent(QMouseEvent* event) { - Rect_Type ret = get_rect_type(event->pos()); - if (ret == Drag_R) { - if (!drag_moving) { - setCursor(Qt::OpenHandCursor); - } - } - else { - setCursor(shapes[ret]); - } - if (!changing_size && !drag_moving) { - return; - } - const QPoint& cur_global_pos = event->globalPos(); - dx = cur_global_pos.x() - start_global_x; - dy = cur_global_pos.y() - start_global_y; - if (changing_size) { - change_sizes[cur_r](); - } - else if (drag_moving) { - move(start_x + dx, start_y + dy); - } -} -Rect_Type Frame_Less_Widget::get_rect_type(const QPoint& p) const { - if (p.y() < y2) { - if (p.x() < x2) - return R11; - if (p.x() > x3) - return R13; - if (p.x() < (x2 + x3) / 4) - return Drag_R; - return R12; - } - if (p.y() > y3) { - if (p.x() < x2) - return R31; - if (p.x() > x3) - return R33; - return R32; - } - if (p.x() < x2) - return R21; - if (p.x() > x3) - return R23; - return R22; -} -void Frame_Less_Widget::resizeEvent(QResizeEvent* event) { - if (isMaximized()) { - QRect screen_size = screen()->availableGeometry().adjusted(-left_margin, -top_margin, right_margin, bottom_margin); - setGeometry(screen_size); - } - set_pos(); - set_rs(); -} -void Frame_Less_Widget::showEvent(QShowEvent* event) { - QWidget::showEvent(event); -} diff --git a/Widget/component/frameless/Frame_Less_Widget.h b/Widget/component/frameless/Frame_Less_Widget.h deleted file mode 100644 index e377f20..0000000 --- a/Widget/component/frameless/Frame_Less_Widget.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -enum Rect_Type { R11, - R12, - R13, - R21, - R22, - R23, - R31, - R32, - R33, - null, - Drag_R }; -using change_size = std::function; -class Frame_Less_Widget : public QWidget { -public: - explicit Frame_Less_Widget(QWidget* parent = nullptr); - int top_margin; - int bottom_margin; - int right_margin; - int left_margin; - int space; - QRect r11, r12, r13, r21, r22, r23, r31, r32, r33; - int x1{}, x2{}, x3{}, y1{}, y2{}, y3{}; - bool changing_size = false; - bool drag_moving = false; - Rect_Type cur_r = null; - int start_x{}; - int start_y{}; - int start_global_x{}; - int start_global_y{}; - int start_w{}; - int start_h{}; - int dx{}, dy{}; - std::vector shapes; - std::vector change_sizes; - int radius; - QColor background_color = QColor(150, 150, 150, 130); - virtual int get_min_width(); - virtual int get_min_height(); - void set_pos(); - void set_rs(); - [[nodiscard]] Rect_Type get_rect_type(const QPoint& pos) const; - // window->showFullScreen(); - // window->showNormal(); - // window->showMinimized(); - // window->showMaximized(); -protected: - void paintEvent(QPaintEvent* event) override; - void mousePressEvent(QMouseEvent* event) override; - void mouseReleaseEvent(QMouseEvent* event) override; - bool event(QEvent* event) override; - void resizeEvent(QResizeEvent* event) override; - void mouseMoveEvent(QMouseEvent* event) override; - void showEvent(QShowEvent* event) override; -}; diff --git a/Widget/component/frameless/export.h b/Widget/component/frameless/export.h deleted file mode 100644 index fb123fc..0000000 --- a/Widget/component/frameless/export.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "Frame_Less_Widget.h" diff --git a/Widget/component/global.h b/Widget/component/global.h deleted file mode 100644 index d5575dc..0000000 --- a/Widget/component/global.h +++ /dev/null @@ -1,209 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../global.h" -enum class Layout_Item_Type { - Fixed, - Expand -}; -enum class Layout_Item_Type2 { - Fixed, - Expand -}; -// 用于线性布局的元素 -struct Layout_Info { - Layout_Info() = default; - Layout_Item_Type main_type{}; - Layout_Item_Type2 second_type{}; - Layout_Info(int key, Layout_Item_Type main_type, Layout_Item_Type2 second_type, int main_value, int second_value) : - main_type(main_type), - second_type(second_type) { - this->key = key; - if (main_type == Layout_Item_Type::Fixed) { - len = main_value; - } - else { - weight = main_value; - } - second_len = second_value; - } - int len{}; // 线性布局主要位置 - int second_len{}; // 线性布局次要位置 - int weight{}; // 主要位置权重布局 - bool hide = false; - int key{}; -}; -struct Layout { - int prefix = 8, suffix = 8; - int space = 8; - int second_prefix = 8, second_suffix = 8; - std::vector infos; - enum Type { - Prefix_Space, - Surfix_Space, - Center_Space - }; - void set_margin(int margin) { - prefix = margin; - suffix = margin; - second_prefix = margin; - second_suffix = margin; - } - Type main_type = Prefix_Space; - Type second_type = Prefix_Space; - typedef QFlags Alignment; - struct Pos { - int start; - int len; - int second_start; - int second_len; - QRect h_rect() { - return {start, second_start, len, second_len}; - } - QRect v_rect() { - return {second_start, start, second_len, len}; - } - }; - std::map cache; - std::optional get(int key) { - auto iter = cache.find(key); - if (iter == cache.end()) { - return std::nullopt; - } - return iter->second; - } - void cacl(int len, int second_len) { - std::vector ret(infos.size()); - int total_fixed_pixel_size = 0; - int total_weight = 0; - int show_size = 0; - int n = infos.size(); - for (int i = 0; i < n; ++i) { - auto& info = infos[i]; - if (info.hide) { - continue; - } - if (info.main_type == Layout_Item_Type::Fixed) { - total_fixed_pixel_size += info.len; - } - if (info.main_type == Layout_Item_Type::Expand) { - total_weight += info.weight; - } - show_size++; - } - int show_width = total_fixed_pixel_size + (show_size - 1) * space; - int remain = len - show_width - (prefix + suffix); - int main_cur_pos = 0; - if (main_type == Type::Prefix_Space) { - main_cur_pos = prefix; - } - if (main_type == Type::Center_Space) { - main_cur_pos = (len - show_width) / 2; - } - if (main_type == Type::Surfix_Space) { - main_cur_pos = len - show_width - suffix; - } - for (int i = 0; i < n; ++i) { - auto& info = infos[i]; - if (info.hide) - continue; - auto& pos = ret[i]; - int cur_len = info.main_type == Layout_Item_Type::Fixed ? info.len : static_cast((double)remain * (double)info.weight / (double)total_weight); - pos.start = main_cur_pos; - pos.len = cur_len; - int info_second_len{}; - if (info.second_type == Layout_Item_Type2::Fixed) { - info_second_len = info.second_len; - } - if (info.second_type == Layout_Item_Type2::Expand) { - info_second_len = second_len - second_prefix - second_suffix; - } - if (second_type == Type::Prefix_Space) { - pos.second_len = second_prefix; - } - if (second_type == Type::Center_Space) { - pos.second_start = (second_len - info_second_len) / 2; - } - if (second_type == Type::Surfix_Space) { - pos.second_start = second_len - info_second_len - second_suffix; - } - pos.second_len = info_second_len; - main_cur_pos += space + cur_len; - } - cache.clear(); - for (int i = 0; i < n; ++i) { - auto key = infos[i].key; - cache[key] = ret[i]; - } - } -}; -enum class Event_Type { - refresh, - Nothing -}; -struct Paintable { - Paintable() = default; - virtual QSize sizeHint() const { - return {24, 24}; - } - virtual ~Paintable() = default; - virtual void paint(QPainter* painter, QRect rect) = 0; - // 鼠标操作 - virtual Event_Type mouse_event(QEvent::Type t, QMouseEvent* e) { - return Event_Type::Nothing; - } - virtual Event_Type resize_event(QResizeEvent* e) { - return Event_Type::Nothing; - } - virtual Event_Type event(QEvent::Type t, QEvent* e) { - if (t == QEvent::Resize) { - return resize_event(dynamic_cast(e)); - } - if ( - t == QEvent::MouseButtonPress || - t == QEvent::MouseButtonRelease || - t == QEvent::MouseMove || - t == QEvent::MouseButtonDblClick) { - return mouse_event(t, dynamic_cast(e)); - } - return Event_Type::Nothing; - } - bool show = true; -}; -struct Base : QWidget { - std::vector paintAbles; - void paintEvent(QPaintEvent* event) override { - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - QRect rect = event->rect(); - for (auto paint_able : paintAbles) { - if (paint_able->show) { - paint_able->paint(&painter, rect); - } - } - painter.end(); - } - bool event(QEvent* e) override { - auto t = e->type(); - for (Paintable* paint_able : paintAbles) { - Event_Type r = paint_able->event(t, e); - if (r == Event_Type::refresh) { - update(); - } - } - return QWidget::event(e); - } -}; diff --git a/Widget/component/simple_widget.cpp b/Widget/component/simple_widget.cpp deleted file mode 100644 index da1bc33..0000000 --- a/Widget/component/simple_widget.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#pragma once -#include "global.h" -// https://blog.csdn.net/MrHHHHHH/article/details/134182253 -class Input : public QLineEdit { -public: - explicit Input(QWidget* parent = nullptr) : QLineEdit(parent) { - setStyle(new Style()); - setFrame(true); - // 当光标的位置在文本编辑器中改变时,这个信号会被触发。old和new参数分别表示光标改变前后的位置。 - connect(this, &QLineEdit::cursorPositionChanged, this, [=](int n_old, int n_new) { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "n_old :" << n_old << "n_new :" << n_new; - }); - // 当用户完成文本编辑(例如按下Enter键或点击其他区域使编辑结束)时,这个信号会被触发。 - connect(this, &QLineEdit::editingFinished, this, [=]() { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); - }); - // 当用户在文本编辑器中按下Enter键时,这个信号会被触发。 - connect(this, &QLineEdit::returnPressed, this, [=]() { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); - }); - // 当文本编辑器中的选区发生变化时,这个信号会被触发。例如,当用户选择或取消选择文本时。 - connect(this, &QLineEdit::selectionChanged, this, [=]() { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << this->text(); - }); - // 当文本编辑器中的文本发生更改时,这个信号会被触发。参数text是改变后的文本内容。 - connect(this, &QLineEdit::textChanged, this, [=](const QString& text) { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << text; - }); - // 当文本编辑器开始编辑新的文本时,这个信号会被触发。参数text是当前编辑的文本内容。 - connect(this, &QLineEdit::textEdited, this, [=](const QString& text) { - // std::cout.noquote() << "[" << __FILE__ << __LINE__ << "]" << "text :" << text; - }); - // update(); - } - QString unit = "MHZ"; - QFont font; - QPen pen; - QColor focus_color = Qt::red; - QColor default_color = Qt::black; -protected: - void paintEvent(QPaintEvent* event) override { - QLineEdit::paintEvent(event); // 调用原始绘制 - auto fm = QFontMetrics(font); - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing, true); - int w = width(); - int h = height(); - int pen_w = 1; - if (QApplication::focusWidget() == this) { - painter.setPen(QPen(focus_color, pen_w)); - } - else { - painter.setPen(QPen(default_color, pen_w)); - } - painter.drawRoundedRect(rect(), h / 4, h / 4); - painter.setPen(pen); - painter.setFont(font); - int unit_width = fm.horizontalAdvance(unit); - int th = fm.height(); - int x = rect().right() - unit_width - 5; // 计算单位的绘制位置 - painter.drawText(x, height() / 2 + th / 2, unit); - setTextMargins(0, 0, unit_width + 4, 0); // 右边留出单位的空间 - } - class Style : public QProxyStyle { - public: - void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption* option, QPainter* painter, - const QWidget* widget) const override { - // 先调用默认的绘制 - auto t = qobject_cast(widget); - if (!t) - return; - static bool it = true; - // QProxyStyle::drawPrimitive(element, option, painter, widget); - // std::cout << "t->hasFrame() == " << t->hasFrame(); - if (it) { - // QProxyStyle::drawPrimitive(element, option, painter, widget); - it = false; - } - // 行编辑器边框 - if (element == PE_PanelLineEdit) { - // - } - // 行编辑器边框 - if (element == PE_FrameLineEdit) { - // std::cout << "line_edit drawPrimitive " << element; - // std::cout << "width " << option->rect.width(); - } - } - void drawComplexControl(ComplexControl control, const QStyleOptionComplex* option, QPainter* painter, - const QWidget* widget) const override { - // auto t = qobject_cast(widget); - // if (!t) return; - // std::cout << "line_edit drawComplexControl " << control; - // QProxyStyle::drawComplexControl(control, option, painter, widget); - } - void drawControl(ControlElement element, const QStyleOption* option, QPainter* painter, - const QWidget* widget) const override { - // auto t = qobject_cast(widget); - // std::cout << "line_edit drawControl " << element; - // QProxyStyle::drawControl(element, option, painter, widget); - // if (!t) return; - } - // void drawItemText(QPainter* painter, const QRect& rect, int flags, const QPalette& pal, bool enabled, - // const QString& text, QPalette::ColorRole text_role) const override { - // - // - // } - // void drawItemPixmap(QPainter* painter, const QRect& rect, int alignment, const QPixmap& pixmap) const - // override { - // - // } - QRect subElementRect(SubElement element, const QStyleOption* option, const QWidget* widget) const override { - auto t = qobject_cast(widget); - if (!t) { - return QProxyStyle::subElementRect(element, option, widget); - } - // std::cout << "line_edit subElementRect " << element; - // 这里可以自定义返回不同的 QRect 以控制子元素的大小或位置 - if (element == SE_LineEditContents) { - QRect rect = QProxyStyle::subElementRect(element, option, widget); - // rect.adjust(5, 5, -5, -5); // 例如,让文本内容区域缩小一点 - return rect; - } - return QProxyStyle::subElementRect(element, option, widget); - } - }; -}; diff --git a/Widget/component/simple_widget.h b/Widget/component/simple_widget.h deleted file mode 100644 index 6349ccc..0000000 --- a/Widget/component/simple_widget.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include "Background.h" -#include "effect.h" -#include "global.h" -struct Wave : Paintable { - QColor color = Qt::blue; - QGraphicsDropShadowEffect shadow_effect; - Wave() { - shadow_effect.setBlurRadius(10); // 设置模糊半径 - shadow_effect.setOffset(5, 5); // 设置阴影偏移量(x, y) - shadow_effect.setColor(Qt::black); // 设置阴影颜色 - } - void paint(QPainter* painter, QRect rect) override { - } -}; -template -struct Wrapper : QMainWindow { - Wrapper() { - resize(400, 400); - auto* w = new Widget(); - auto* ww = static_cast(w); - ww->setParent(this); - ww->setFixedSize(200, 200); - ww->move(100, 100); - } -}; -class Wave_Widget : public QWidget { - Q_OBJECT -public: - explicit Wave_Widget(QWidget* parent = nullptr) : QWidget(parent), m_offset(0) { - setFixedSize(400, 300); // 设置窗口大小 - // 定时器:每隔一段时间更新一次动画 - m_timer = new QTimer(this); - connect(m_timer, &QTimer::timeout, this, &Wave_Widget::update_wave); - m_timer->start(16); // 约60fps - // 初始化动画 - m_animation = new QPropertyAnimation(this, "wavePosition"); - m_animation->setDuration(1000); - m_animation->setLoopCount(-1); // 无限循环 - m_animation->setEasingCurve(QEasingCurve::Linear); - } -protected: - void paintEvent(QPaintEvent* event) override { - QPainter painter(this); - painter.setBrush(Qt::blue); - // 通过 m_offset 控制波浪的 y 坐标 - int y = 150 + 50 * std::sin(m_offset); // 使用正弦波函数产生波浪效果 - painter.drawEllipse(QPoint(200, y), 20, 20); // 绘制一个圆形 - QWidget::paintEvent(event); - } -private slots: - void update_wave() { - // 每次更新时间,更新 m_offset 以形成波动效果 - m_offset += 0.1; - if (m_offset > 2 * (3.14159265358979323846)) { - m_offset = 0; // 重新从0开始 - } - update(); // 更新界面 - } -private: - float m_offset; // 波动的偏移量 - QTimer* m_timer; - QPropertyAnimation* m_animation; -}; diff --git a/Widget/component/style文档.md b/Widget/component/style文档.md deleted file mode 100644 index 050ff75..0000000 --- a/Widget/component/style文档.md +++ /dev/null @@ -1,5 +0,0 @@ -https://doc.qt.io/qt-5/qstyleoption.html - -qstyleoption_cast () -enum QStyleOption::OptionType 枚举到具体子类的映射 -https://doc.qt.io/qt-5/qstyleoption.html#OptionType-enum \ No newline at end of file diff --git a/Widget/export.h b/Widget/export.h deleted file mode 100644 index c4c173d..0000000 --- a/Widget/export.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#include "base/export.h" -#include "component/export.h" -#include "Qt/export.h" diff --git a/Widget/global.h b/Widget/global.h deleted file mode 100644 index 4e6472c..0000000 --- a/Widget/global.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "Psc_Cpp_Core/system/export.h" -#include "Psc_Cpp_Core/Base/global_include.h" -#include "Psc_Cpp_Core/Base/JSON.h" -#include -#if defined(_WIN32) -# if defined(WIDGET_BUILD_SHARED) -# define WIDGET_API __declspec(dllexport) -# elif defined(WIDGET_USE_SHARED) -# define WIDGET_API __declspec(dllimport) -# else -# define WIDGET_API -# endif -#else -# define WIDGET_API __attribute__((visibility("default"))) -#endif -namespace Flex_Qt { -struct Range { - double origin; - double target; - [[nodiscard]] double size() const { - return target > origin ? target - origin : origin - target; - } - [[nodiscard]] double length() const { - return target - origin; - } - [[nodiscard]] double middle() const { - return origin + (target - origin) / 2.0; - } - bool operator==(const Range& other) const { - return origin == other.origin && target == other.target; - } - bool operator!=(const Range& other) const { - return !(*this == other); - } - [[nodiscard]] bool contain(double value) const { - if (origin < target) - return value > origin - 0.0001 && value < target + 0.0001; - return value > target - 0.0001 && value < origin + 0.0001; - } -}; -} diff --git a/Widget/resource/icon b/Widget/resource/icon deleted file mode 100644 index 0f9362d..0000000 --- a/Widget/resource/icon +++ /dev/null @@ -1,13 +0,0 @@ - - -https://blog.csdn.net/yuan2019035055/article/details/145653647 - - - - -// GIF 动画 -https://zhuanlan.zhihu.com/p/349035523 - - -// 主要在这里找的图标 -https://fonts.google.com/icons?icon.query=filter+&icon.size=24&icon.color=%235985E1 \ No newline at end of file diff --git a/Widget/resource/resource.qrc b/Widget/resource/resource.qrc deleted file mode 100644 index 2a51b83..0000000 --- a/Widget/resource/resource.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - you_jian_tou.svg - - - diff --git a/Widget/resource/you_jian_tou.svg b/Widget/resource/you_jian_tou.svg deleted file mode 100644 index ea286c4..0000000 --- a/Widget/resource/you_jian_tou.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/export.h b/export.h index dec4d42..171dc9a 100644 --- a/export.h +++ b/export.h @@ -10,27 +10,20 @@ #include #include #include -#include "Core2/export.h" +#include "render_2D/export.h" #include "Qt/plot/export.h" #include "Widget/export.h" - namespace renderive { - template using Node = Flex_Qt::Node; - template using Node_Manager = Flex_Qt::Node_Manager; - template using Roll_Object = Flex_Qt::Roll_Object; - template using Singleton_Widget = Flex_Qt::Singleton_Widget; - using Select_Color_Dialog = Flex_Qt::Select_Color_Dialog; using Virtual_Keyboard = Flex_Qt::Virtual_Keyboard; - inline Color qt_to_color(const QColor& color) { if (!color.isValid()) return Color::transparent(); @@ -41,11 +34,9 @@ inline Color qt_to_color(const QColor& color) { static_cast(color.alpha()) }; } - inline QColor to_qcolor(Color color) { return QColor(color.r, color.g, color.b, color.a); } - inline Line_Style qt_to_line_style(Qt::PenStyle style) { switch (style) { case Qt::NoPen: @@ -60,7 +51,6 @@ inline Line_Style qt_to_line_style(Qt::PenStyle style) { return Line_Style::Solid; } } - inline Line_Cap qt_to_line_cap(Qt::PenCapStyle cap) { switch (cap) { case Qt::SquareCap: @@ -72,7 +62,6 @@ inline Line_Cap qt_to_line_cap(Qt::PenCapStyle cap) { return Line_Cap::Butt; } } - inline Qt::PenCapStyle to_qt_line_cap(Line_Cap cap) { switch (cap) { case Line_Cap::Square: @@ -84,7 +73,6 @@ inline Qt::PenCapStyle to_qt_line_cap(Line_Cap cap) { return Qt::FlatCap; } } - inline Line_Join qt_to_line_join(Qt::PenJoinStyle join) { switch (join) { case Qt::BevelJoin: @@ -97,7 +85,6 @@ inline Line_Join qt_to_line_join(Qt::PenJoinStyle join) { return Line_Join::Miter; } } - inline Qt::PenJoinStyle to_qt_line_join(Line_Join join) { switch (join) { case Line_Join::Bevel: @@ -109,7 +96,6 @@ inline Qt::PenJoinStyle to_qt_line_join(Line_Join join) { return Qt::MiterJoin; } } - inline Qt::PenStyle to_qt_pen_style(Line_Style style) { switch (style) { case Line_Style::None: @@ -122,18 +108,17 @@ inline Qt::PenStyle to_qt_pen_style(Line_Style style) { return Qt::SolidLine; } } - inline Pen qt_to_pen(const QPen& pen) { - return Pen{qt_to_color(pen.color()), pen.widthF(), qt_to_line_style(pen.style()), - qt_to_line_cap(pen.capStyle()), qt_to_line_join(pen.joinStyle())}; + return Pen{ + qt_to_color(pen.color()), pen.widthF(), qt_to_line_style(pen.style()), + qt_to_line_cap(pen.capStyle()), qt_to_line_join(pen.joinStyle()) + }; } - inline Pen qt_to_pen(const QColor& color) { if (!color.isValid()) return Pen{.style = Line_Style::None}; return Pen{qt_to_color(color)}; } - inline QPen to_qpen(const Pen& pen) { QPen ret(to_qcolor(pen.color)); ret.setWidthF(pen.width); @@ -142,53 +127,43 @@ inline QPen to_qpen(const Pen& pen) { ret.setJoinStyle(to_qt_line_join(pen.join)); return ret; } - inline Brush qt_to_brush(const QBrush& brush) { if (brush.style() == Qt::NoBrush) return Brush{}; return Brush{qt_to_color(brush.color()), Brush_Style::Solid}; } - inline Brush qt_to_brush(const QColor& color) { if (!color.isValid()) return Brush{}; return Brush{qt_to_color(color), Brush_Style::Solid}; } - inline QBrush to_qbrush(const Brush& brush) { if (!brush.enabled()) return QBrush(Qt::NoBrush); return QBrush(to_qcolor(brush.color)); } - inline std::string qt_to_string(const QString& text) { QByteArray bytes = text.toUtf8(); return std::string(bytes.constData(), static_cast(bytes.size())); } - inline QString to_qstring(std::string_view text) { return QString::fromUtf8(text.data(), static_cast(text.size())); } - inline Orientation qt_to_orientation(Qt::Orientation orientation) { return orientation == Qt::Horizontal ? Orientation::Horizontal : Orientation::Vertical; } - inline Qt::Orientation to_qt_orientation(Orientation orientation) { return orientation == Orientation::Horizontal ? Qt::Horizontal : Qt::Vertical; } - inline Time_Of_Day qt_to_time_of_day(const QTime& time) { return {time.isValid() ? time.msecsSinceStartOfDay() : -1}; } - namespace detail { inline std::default_random_engine& mock_data_random_engine() { static thread_local std::default_random_engine engine(std::random_device{}()); return engine; } } // namespace detail - inline void fill_data(Range value_range, std::span output) { if (value_range.origin > value_range.target) std::swap(value_range.origin, value_range.target); @@ -196,29 +171,24 @@ inline void fill_data(Range value_range, std::span output) { for (double& value : output) value = dist(detail::mock_data_random_engine()); } - inline std::vector get_data(Range value_range, int size) { std::vector ret(static_cast(std::max(0, size))); fill_data(value_range, ret); return ret; } - inline double get_data(Range value_range) { if (value_range.origin > value_range.target) std::swap(value_range.origin, value_range.target); std::uniform_real_distribution dist(value_range.origin, value_range.target); return dist(detail::mock_data_random_engine()); } - inline std::vector get_data(int value, int size) { return std::vector(size, value); } - inline std::vector get_colored_data(int size) { std::vector ret(size); for (int i = 0; i < size; ++i) ret[i] = i; return ret; } - } // namespace renderive diff --git a/main.cmake b/main.cmake index d2b1bd7..d6095d4 100644 --- a/main.cmake +++ b/main.cmake @@ -45,7 +45,7 @@ set(qt_libraries Qt5::QuickWidgets ) set(root_dir "${CMAKE_CURRENT_LIST_DIR}") -# Kernel is the only rendering architecture used by Core2. +# Kernel is the only rendering architecture used by render_2D. add_library(Renderive_Kernel STATIC "${root_dir}/Kernel/src/renderive/renderable/Renderable_Task_Graph.cpp" "${root_dir}/Kernel/src/renderive/renderable/base/Renderable_Base.cpp" @@ -55,15 +55,15 @@ target_include_directories(Renderive_Kernel PUBLIC "${root_dir}/Kernel/src") target_compile_features(Renderive_Kernel PUBLIC cxx_std_20) target_link_libraries(Renderive_Kernel PRIVATE Taskflow::Taskflow Threads::Threads) file(GLOB_RECURSE renderive_core2_sources CONFIGURE_DEPENDS - "${root_dir}/Core2/*.cpp" - "${root_dir}/Core2/*.h" - "${root_dir}/Core2/*.hpp" + "${root_dir}/render_2D/*.cpp" + "${root_dir}/render_2D/*.h" + "${root_dir}/render_2D/*.hpp" ) list(FILTER renderive_core2_sources EXCLUDE REGEX "[/\\\\]tests[/\\\\]") -add_library(Renderive_Core2 STATIC ${renderive_core2_sources}) -target_include_directories(Renderive_Core2 PUBLIC "${root_dir}") -target_compile_features(Renderive_Core2 PUBLIC cxx_std_20) -target_link_libraries(Renderive_Core2 +add_library(Renderive_render_2D STATIC ${renderive_core2_sources}) +target_include_directories(Renderive_render_2D PUBLIC "${root_dir}") +target_compile_features(Renderive_render_2D PUBLIC cxx_std_20) +target_link_libraries(Renderive_render_2D PUBLIC Renderive_Kernel PRIVATE blend2d::blend2d ) @@ -82,7 +82,7 @@ add_library(Renderive_Qt STATIC ${renderive_qt_sources}) set_property(TARGET Renderive_Qt PROPERTY AUTOMOC ON) target_include_directories(Renderive_Qt PUBLIC "${root_dir}") target_compile_features(Renderive_Qt PUBLIC cxx_std_20) -target_link_libraries(Renderive_Qt PUBLIC Renderive_Core2 ${qt_libraries}) +target_link_libraries(Renderive_Qt PUBLIC Renderive_render_2D ${qt_libraries}) unset(Psc_Widget_src) append_glob_source(Psc_Widget_src "${root_dir}/Widget") add_library(Psc_Widget STATIC ${Psc_Widget_src}) @@ -100,19 +100,19 @@ add_executable(Renderive_Kernel_Tests EXCLUDE_FROM_ALL target_compile_definitions(Renderive_Kernel_Tests PRIVATE RENDERIVE_WITH_GTEST) target_link_libraries(Renderive_Kernel_Tests PRIVATE Renderive_Kernel GTest::GTest) add_test(NAME Renderive_Kernel_Tests COMMAND Renderive_Kernel_Tests) -add_executable(Renderive_Core2_Tests EXCLUDE_FROM_ALL +add_executable(Renderive_render_2D_Tests EXCLUDE_FROM_ALL "${root_dir}/Kernel/tests/main.cpp" - "${root_dir}/Core2/tests/Core2_Integration_Tests.cpp" - "${root_dir}/Core2/tests/Core2_Frame_Pipeline_Tests.cpp" + "${root_dir}/render_2D/tests/render_2D_Integration_Tests.cpp" + "${root_dir}/render_2D/tests/render_2D_Frame_Pipeline_Tests.cpp" ) -target_link_libraries(Renderive_Core2_Tests PRIVATE - Renderive_Core2 +target_link_libraries(Renderive_render_2D_Tests PRIVATE + Renderive_render_2D GTest::GTest blend2d::blend2d ) -add_test(NAME Renderive_Core2_Tests COMMAND Renderive_Core2_Tests) +add_test(NAME Renderive_render_2D_Tests COMMAND Renderive_render_2D_Tests) add_executable(Renderive_Qt_Tests EXCLUDE_FROM_ALL - "${root_dir}/Core2/tests/Qt_Bridge_Tests.cpp" + "${root_dir}/render_2D/tests/Qt_Bridge_Tests.cpp" ) target_link_libraries(Renderive_Qt_Tests PRIVATE Renderive_Qt GTest::GTest) get_filename_component(renderive_qt_runtime_root "${Qt5_DIR}/../../.." ABSOLUTE) @@ -125,7 +125,7 @@ add_test(NAME Renderive_Qt_Tests ) if (MSVC) target_compile_options(Renderive_Kernel PRIVATE /utf-8) - target_compile_options(Renderive_Core2 PRIVATE /utf-8) + target_compile_options(Renderive_render_2D PRIVATE /utf-8) target_compile_options(Renderive_Qt PRIVATE /utf-8) endif () if (NOT TARGET Adminive::Nlohmann) diff --git a/radio/component/ProgressBar.cpp b/radio/component/ProgressBar.cpp deleted file mode 100644 index 55f31a7..0000000 --- a/radio/component/ProgressBar.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "ProgressBar.h" -#include -#include -#include -#include -#include - -Progress_Bar::Progress_Bar(const std::vector& tick_list, QWidget *parent) : QWidget(parent), tick_list(tick_list) { - setAttribute(Qt::WA_OpaquePaintEvent, true); - timer = startTimer(30); -} - -double Progress_Bar::get_draw_width(double value) { - int n = tick_list.size(); - if (n < 2 || QWidget::width() <= 0) - return 0.0; - if (!std::isfinite(value)) - value = tick_list.front().value; - int i = 1; - for(; i < n - 1; ++i) { - double cur = tick_list[i].value; - if(value < cur || qFuzzyCompare(value, cur)) { - break; - } - } - int lower_offset = i - 1; - int upper_offset = i; - double lower = tick_list[lower_offset].value; - double upper = tick_list[upper_offset].value; - double w_step = (double)QWidget::width()/(double)(n-1); - double last_rate = upper == lower ? 0.0 : (value - lower)/(upper - lower); - last_rate = std::clamp(last_rate, 0.0, 1.0); - double draw_width = w_step * (last_rate + lower_offset); - return std::clamp(draw_width, 0.0, (double)QWidget::width()); -} -void Progress_Bar::setValue(double value) { - if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, [this, value]() { - setValue(value); - }, Qt::QueuedConnection); - return; - } - this->value = value; - update(); -} -void Progress_Bar::paintEvent(QPaintEvent *event) { - Q_UNUSED(event) - QPainter painter(this); - painter.setPen(Qt::NoPen); - painter.fillRect(rect(), QApplication::style()->standardPalette().brush(QPalette::Window)); - painter.setPen(QPen(Qt::black)); - auto w = (double)QWidget::width(); - auto hh = (double)height()/2; - int n = tick_list.size(); - int tick_w = 1; - double draw_width = get_draw_width(value); - int fill_width = std::max(0, static_cast(draw_width) - tick_w - 4); - if (fill_width > 0) - painter.fillRect(0, 0, fill_width, height()/2, Qt::black); - int cur_x = 0; - int tick_step = std::max(1, tick_w + (int)tick_space_w); - while(cur_x + tick_w + 4 < draw_width){ - painter.fillRect(cur_x, 0, tick_w, height()/2, Qt::gray); - cur_x += tick_step; - } - int line_y = (int)hh + 2; - int marker_x = std::clamp(cur_x - (int)tick_space_w, 0, std::max(0, QWidget::width() - 4)); - painter.fillRect(marker_x, 0, 4, line_y, Qt::yellow); - painter.drawLine(0, line_y , (int)w, line_y); - QFont font; - font.setBold(true); - QFontMetrics fm(font); - for(int i = 0; i < n; ++i){ - int tick_x = (int)((double)(QWidget::width() * i)/(double)(n - 1)); - int text_w = fm.horizontalAdvance( tick_list[i].text); - int text_x; - if(i == n - 1) { - text_x = tick_x - text_w; - tick_x -=1; - } else if( i == 0) { - text_x = tick_x; - } else { - text_x = tick_x - text_w/2; - } - painter.setPen(Qt::black); - painter.drawLine(tick_x, line_y, tick_x, (line_y + 5)); - painter.setPen(tick_list[i].color); - painter.setFont(font); - painter.drawText(QRectF(text_x, line_y, text_w, line_y), Qt::AlignCenter, tick_list[i].text); - } -} - -void Progress_Bar::timerEvent(QTimerEvent *event) { - if(event->timerId() == timer) { - if(set_value) set_value(); - update(); - } - QObject::timerEvent(event); -} diff --git a/radio/component/ProgressBar.h b/radio/component/ProgressBar.h deleted file mode 100644 index f487313..0000000 --- a/radio/component/ProgressBar.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef Progress_Bar_H -#define Progress_Bar_H -#include -#include -#include "../Global.h" -struct Tick { - QString text; - QColor color; - double value = 0; - Tick(QString text, QColor color) : text(std::move(text)), color(std::move(color)) { - QString that = (this->text.startsWith('+') || this->text.startsWith('-') || this->text.startsWith('<') || this->text.startsWith('>')) ? this->text.mid(1) : this->text; - value = that.toDouble(); - } - Tick(QString text, QColor color, double value) : text(std::move(text)), color(std::move(color)), value(value) { - } -}; -class Progress_Bar : public QWidget { -public: - explicit Progress_Bar(const std::vector& tick_list, QWidget *parent = nullptr); - double tick_space_w = 1; - double value = 0; - int timer; - std::function set_value = nullptr; - double get_draw_width(double value); - void setValue(double value); -protected: - void paintEvent(QPaintEvent *event) override; - void timerEvent(QTimerEvent *event) override; - std::vector tick_list; -}; -#endif diff --git a/Core2/axis/Axis.cpp b/render_2D/axis/Axis.cpp similarity index 100% rename from Core2/axis/Axis.cpp rename to render_2D/axis/Axis.cpp diff --git a/Core2/axis/Axis.h b/render_2D/axis/Axis.h similarity index 100% rename from Core2/axis/Axis.h rename to render_2D/axis/Axis.h diff --git a/Core2/base/Types.cpp b/render_2D/base/Types.cpp similarity index 100% rename from Core2/base/Types.cpp rename to render_2D/base/Types.cpp diff --git a/Core2/base/Types.h b/render_2D/base/Types.h similarity index 100% rename from Core2/base/Types.h rename to render_2D/base/Types.h diff --git a/Core2/event/Event.h b/render_2D/event/Event.h similarity index 100% rename from Core2/event/Event.h rename to render_2D/event/Event.h diff --git a/Core2/export.h b/render_2D/export.h similarity index 100% rename from Core2/export.h rename to render_2D/export.h diff --git a/Core2/plot/Plot_Core.cpp b/render_2D/plot/Plot_Core.cpp similarity index 100% rename from Core2/plot/Plot_Core.cpp rename to render_2D/plot/Plot_Core.cpp diff --git a/Core2/plot/Plot_Core.h b/render_2D/plot/Plot_Core.h similarity index 100% rename from Core2/plot/Plot_Core.h rename to render_2D/plot/Plot_Core.h diff --git a/Core2/plottable/Curve_Sampling.h b/render_2D/plottable/Curve_Sampling.h similarity index 100% rename from Core2/plottable/Curve_Sampling.h rename to render_2D/plottable/Curve_Sampling.h diff --git a/Core2/plottable/Heatmaps.cpp b/render_2D/plottable/Heatmaps.cpp similarity index 100% rename from Core2/plottable/Heatmaps.cpp rename to render_2D/plottable/Heatmaps.cpp diff --git a/Core2/plottable/Hover_Tooltip.h b/render_2D/plottable/Hover_Tooltip.h similarity index 100% rename from Core2/plottable/Hover_Tooltip.h rename to render_2D/plottable/Hover_Tooltip.h diff --git a/Core2/plottable/Overlays.cpp b/render_2D/plottable/Overlays.cpp similarity index 100% rename from Core2/plottable/Overlays.cpp rename to render_2D/plottable/Overlays.cpp diff --git a/Core2/plottable/Performance_Overlay.cpp b/render_2D/plottable/Performance_Overlay.cpp similarity index 100% rename from Core2/plottable/Performance_Overlay.cpp rename to render_2D/plottable/Performance_Overlay.cpp diff --git a/Core2/plottable/Performance_Overlay.h b/render_2D/plottable/Performance_Overlay.h similarity index 100% rename from Core2/plottable/Performance_Overlay.h rename to render_2D/plottable/Performance_Overlay.h diff --git a/Core2/plottable/Plottables.h b/render_2D/plottable/Plottables.h similarity index 100% rename from Core2/plottable/Plottables.h rename to render_2D/plottable/Plottables.h diff --git a/Core2/plottable/Spectrum.cpp b/render_2D/plottable/Spectrum.cpp similarity index 100% rename from Core2/plottable/Spectrum.cpp rename to render_2D/plottable/Spectrum.cpp diff --git a/Core2/render/Blend2D_Cache.cpp b/render_2D/render/Blend2D_Cache.cpp similarity index 100% rename from Core2/render/Blend2D_Cache.cpp rename to render_2D/render/Blend2D_Cache.cpp diff --git a/Core2/render/Blend2D_Cache.h b/render_2D/render/Blend2D_Cache.h similarity index 100% rename from Core2/render/Blend2D_Cache.h rename to render_2D/render/Blend2D_Cache.h diff --git a/Core2/renderable/Renderable.cpp b/render_2D/renderable/Renderable.cpp similarity index 100% rename from Core2/renderable/Renderable.cpp rename to render_2D/renderable/Renderable.cpp diff --git a/Core2/renderable/Renderable.h b/render_2D/renderable/Renderable.h similarity index 100% rename from Core2/renderable/Renderable.h rename to render_2D/renderable/Renderable.h diff --git a/Core2/tests/Qt_Bridge_Tests.cpp b/render_2D/tests/Qt_Bridge_Tests.cpp similarity index 100% rename from Core2/tests/Qt_Bridge_Tests.cpp rename to render_2D/tests/Qt_Bridge_Tests.cpp diff --git a/Core2/tests/Core2_Frame_Pipeline_Tests.cpp b/render_2D/tests/render_2D_Frame_Pipeline_Tests.cpp similarity index 98% rename from Core2/tests/Core2_Frame_Pipeline_Tests.cpp rename to render_2D/tests/render_2D_Frame_Pipeline_Tests.cpp index 734f312..997fb8e 100644 --- a/Core2/tests/Core2_Frame_Pipeline_Tests.cpp +++ b/render_2D/tests/render_2D_Frame_Pipeline_Tests.cpp @@ -1,20 +1,15 @@ -#include "Core2/export.h" - +#include "render_2D/export.h" #include - #include #include #include #include - namespace renderive { namespace { - TEST(Renderive_Core2_Frame_Pipeline, ManualLifecycleSeparatesPrepareRefreshAndRender) { Plot_Core plot(Frame_Control_Mode::Manual); plot.init(); plot.set_viewport_size({96, 54}); - ASSERT_TRUE(plot.prepare_frame()); auto snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.mode, Frame_Control_Mode::Manual); @@ -24,7 +19,6 @@ TEST(Renderive_Core2_Frame_Pipeline, ManualLifecycleSeparatesPrepareRefreshAndRe EXPECT_EQ(snapshot.consumed_frame_count, 0u); EXPECT_EQ(snapshot.pending_frame_count, 1u); EXPECT_EQ(snapshot.latest_sequence, 1u); - ASSERT_TRUE(plot.refresh_manual_frame()); snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.last_event, "refresh_succeeded"); @@ -32,7 +26,6 @@ TEST(Renderive_Core2_Frame_Pipeline, ManualLifecycleSeparatesPrepareRefreshAndRe EXPECT_EQ(snapshot.consumed_frame_count, 0u); EXPECT_EQ(snapshot.pending_frame_count, 0u); EXPECT_EQ(snapshot.latest_sequence, 1u); - ASSERT_TRUE(plot.render_prepared_frame()); snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.last_event, "rendered"); @@ -42,13 +35,11 @@ TEST(Renderive_Core2_Frame_Pipeline, ManualLifecycleSeparatesPrepareRefreshAndRe EXPECT_EQ(snapshot.latest_sequence, 1u); EXPECT_EQ(plot.diagnostics().refresh.frame_count, 1u); } - TEST(Renderive_Core2_Frame_Pipeline, HighFrequencyLowLatencyLifecycleExposesKernelTiming) { Plot_Core plot(Frame_Control_Mode::Low_Latency); plot.init(); plot.set_viewport_size({96, 54}); plot.set_max_render_fps(1'000'000'000.0); - ASSERT_TRUE(plot.prepare_frame()); auto snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.last_event, "published"); @@ -58,7 +49,6 @@ TEST(Renderive_Core2_Frame_Pipeline, HighFrequencyLowLatencyLifecycleExposesKern EXPECT_EQ(snapshot.produced_frame_count, 1u); EXPECT_EQ(snapshot.consumed_frame_count, 0u); EXPECT_EQ(snapshot.pending_frame_count, 1u); - ASSERT_TRUE(plot.render_prepared_frame()); snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.last_event, "lifecycle_completed"); @@ -73,13 +63,11 @@ TEST(Renderive_Core2_Frame_Pipeline, HighFrequencyLowLatencyLifecycleExposesKern std::max(snapshot.target_interval_ns, snapshot.bottleneck_duration_ns)); EXPECT_GE(snapshot.end_to_end_ns, snapshot.paint_duration_ns); EXPECT_GE(snapshot.end_to_end_ns, snapshot.render_duration_ns); - const auto refresh = plot.refresh_feedback_snapshot(); EXPECT_DOUBLE_EQ(refresh.frequency_hz, snapshot.frequency_hz); EXPECT_EQ(refresh.frame_count, snapshot.consumed_frame_count); EXPECT_EQ(refresh.next_refresh_interval_ns, snapshot.next_refresh_interval_ns); } - TEST(Renderive_Core2_Frame_Pipeline, LowLatencyConsumerFeedbackFlowsThroughCore2IntoKernelScheduling) { Plot_Core plot(Frame_Control_Mode::Low_Latency); plot.init(); @@ -119,12 +107,10 @@ TEST(Renderive_Core2_Frame_Pipeline, LowLatencyLimitsCanBeClearedIndependently) EXPECT_EQ(snapshot.next_refresh_interval_ns, snapshot.bottleneck_duration_ns); EXPECT_TRUE(snapshot.limit_state == "paint_limited" || snapshot.limit_state == "render_limited"); } - TEST(Renderive_Core2_Frame_Pipeline, LowLatencyReplacementRetiresOldFrameWithoutPhantomPendingFrame) { Plot_Core plot(Frame_Control_Mode::Low_Latency); plot.init(); plot.set_viewport_size({64, 40}); - ASSERT_TRUE(plot.prepare_frame()); ASSERT_TRUE(plot.prepare_frame()); auto snapshot = plot.frame_observer_snapshot(); @@ -133,7 +119,6 @@ TEST(Renderive_Core2_Frame_Pipeline, LowLatencyReplacementRetiresOldFrameWithout EXPECT_EQ(snapshot.dropped_frame_count, 1u); EXPECT_EQ(snapshot.pending_frame_count, 1u); EXPECT_EQ(snapshot.latest_sequence, 2u); - ASSERT_TRUE(plot.render_prepared_frame()); snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.last_event, "lifecycle_completed"); @@ -143,12 +128,10 @@ TEST(Renderive_Core2_Frame_Pipeline, LowLatencyReplacementRetiresOldFrameWithout EXPECT_EQ(snapshot.pending_frame_count, 0u); EXPECT_EQ(snapshot.latest_sequence, 2u); } - TEST(Renderive_Core2_Frame_Pipeline, LowLatencyDiscardAndEmptyRenderRemainObservable) { Plot_Core plot(Frame_Control_Mode::Low_Latency); plot.init(); plot.set_viewport_size({64, 40}); - ASSERT_TRUE(plot.prepare_frame()); ASSERT_TRUE(plot.discard_pending_frame()); auto snapshot = plot.frame_observer_snapshot(); @@ -158,7 +141,6 @@ TEST(Renderive_Core2_Frame_Pipeline, LowLatencyDiscardAndEmptyRenderRemainObserv EXPECT_EQ(snapshot.dropped_frame_count, 1u); EXPECT_EQ(snapshot.pending_frame_count, 0u); EXPECT_EQ(snapshot.latest_sequence, 1u); - EXPECT_FALSE(plot.render_prepared_frame()); snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.last_event, "swap_failed"); @@ -166,12 +148,10 @@ TEST(Renderive_Core2_Frame_Pipeline, LowLatencyDiscardAndEmptyRenderRemainObserv EXPECT_EQ(snapshot.pending_frame_count, 0u); EXPECT_EQ(snapshot.latest_sequence, 1u); } - TEST(Renderive_Core2_Frame_Pipeline, ManualDiscardAndFailedRefreshUpdateObserverState) { Plot_Core plot(Frame_Control_Mode::Manual); plot.init(); plot.set_viewport_size({64, 40}); - ASSERT_TRUE(plot.prepare_frame()); ASSERT_TRUE(plot.discard_pending_frame()); auto snapshot = plot.frame_observer_snapshot(); @@ -181,7 +161,6 @@ TEST(Renderive_Core2_Frame_Pipeline, ManualDiscardAndFailedRefreshUpdateObserver EXPECT_EQ(snapshot.pending_frame_count, 0u); EXPECT_EQ(snapshot.latest_sequence, 1u); const auto last_paint_duration_ns = snapshot.paint_duration_ns; - EXPECT_FALSE(plot.refresh_manual_frame()); snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.last_event, "refresh_failed"); @@ -190,12 +169,10 @@ TEST(Renderive_Core2_Frame_Pipeline, ManualDiscardAndFailedRefreshUpdateObserver EXPECT_EQ(snapshot.latest_sequence, 1u); EXPECT_EQ(snapshot.paint_duration_ns, last_paint_duration_ns); } - TEST(Renderive_Core2_Frame_Pipeline, PlaybackPreservesQueueDepthAndEmptyAcquireFailure) { Plot_Core plot(Frame_Control_Mode::Playback); plot.init(); plot.set_viewport_size({64, 40}); - ASSERT_TRUE(plot.prepare_frame()); ASSERT_TRUE(plot.prepare_frame()); ASSERT_TRUE(plot.prepare_frame()); @@ -203,7 +180,6 @@ TEST(Renderive_Core2_Frame_Pipeline, PlaybackPreservesQueueDepthAndEmptyAcquireF EXPECT_EQ(snapshot.produced_frame_count, 3u); EXPECT_EQ(snapshot.pending_frame_count, 3u); EXPECT_EQ(snapshot.latest_sequence, 3u); - ASSERT_TRUE(plot.render_prepared_frame()); ASSERT_TRUE(plot.render_prepared_frame()); ASSERT_TRUE(plot.render_prepared_frame()); @@ -215,7 +191,6 @@ TEST(Renderive_Core2_Frame_Pipeline, PlaybackPreservesQueueDepthAndEmptyAcquireF const auto last_paint_duration_ns = snapshot.paint_duration_ns; const auto last_render_duration_ns = snapshot.render_duration_ns; const auto last_queue_wait_ns = snapshot.queue_wait_ns; - EXPECT_FALSE(plot.render_prepared_frame()); snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.last_event, "queue_empty"); @@ -226,19 +201,16 @@ TEST(Renderive_Core2_Frame_Pipeline, PlaybackPreservesQueueDepthAndEmptyAcquireF EXPECT_EQ(snapshot.render_duration_ns, last_render_duration_ns); EXPECT_EQ(snapshot.queue_wait_ns, last_queue_wait_ns); } - TEST(Renderive_Core2_Frame_Pipeline, PlaybackFullCyclePreservesPreviouslyQueuedFrames) { Plot_Core plot(Frame_Control_Mode::Playback); plot.init(); plot.set_viewport_size({96, 54}); - ASSERT_TRUE(plot.prepare_frame()); ASSERT_TRUE(plot.prepare_frame()); ASSERT_TRUE(plot.prepare_frame()); auto snapshot = plot.frame_observer_snapshot(); ASSERT_EQ(snapshot.pending_frame_count, 3u); ASSERT_EQ(snapshot.produced_frame_count, 3u); - ASSERT_TRUE(plot.render_frame(true)); snapshot = plot.frame_observer_snapshot(); EXPECT_EQ(snapshot.mode, Frame_Control_Mode::Playback); @@ -251,11 +223,12 @@ TEST(Renderive_Core2_Frame_Pipeline, PlaybackFullCyclePreservesPreviouslyQueuedF EXPECT_FALSE(plot.discard_pending_frame()); EXPECT_EQ(plot.frame_observer_snapshot().pending_frame_count, 3u); } - TEST(Renderive_Core2_Frame_Pipeline, EveryModeHonorsActiveDirtyAndForceRenderGates) { - constexpr std::array modes{Frame_Control_Mode::Manual, - Frame_Control_Mode::Low_Latency, - Frame_Control_Mode::Playback}; + constexpr std::array modes{ + Frame_Control_Mode::Manual, + Frame_Control_Mode::Low_Latency, + Frame_Control_Mode::Playback + }; for (const auto mode : modes) { Plot_Core plot(mode); plot.init(); @@ -263,7 +236,6 @@ TEST(Renderive_Core2_Frame_Pipeline, EveryModeHonorsActiveDirtyAndForceRenderGat EXPECT_FALSE(plot.view_active()); EXPECT_FALSE(plot.render_frame(false)); EXPECT_EQ(plot.frame_observer_snapshot().observation_count, 0u); - plot.activate_view(); ASSERT_TRUE(plot.render_frame(false)); const auto completed = plot.frame_observer_snapshot(); @@ -271,7 +243,6 @@ TEST(Renderive_Core2_Frame_Pipeline, EveryModeHonorsActiveDirtyAndForceRenderGat EXPECT_EQ(completed.consumed_frame_count, 1u); EXPECT_FALSE(plot.render_frame(false)); EXPECT_EQ(plot.frame_observer_snapshot().consumed_frame_count, 1u); - plot.deactivate_view(); plot.set_background_color(Color{8, 16, 24, 255}); EXPECT_FALSE(plot.render_frame(false)); @@ -279,7 +250,6 @@ TEST(Renderive_Core2_Frame_Pipeline, EveryModeHonorsActiveDirtyAndForceRenderGat EXPECT_EQ(plot.frame_observer_snapshot().consumed_frame_count, 2u); } } - TEST(Renderive_Core2_Frame_Pipeline, FrequencyConfigurationRejectsInvalidValuesAndWrongModes) { Plot_Core low_latency(Frame_Control_Mode::Low_Latency); EXPECT_THROW(low_latency.set_max_render_fps(0.0), std::invalid_argument); @@ -290,7 +260,6 @@ TEST(Renderive_Core2_Frame_Pipeline, FrequencyConfigurationRejectsInvalidValuesA std::invalid_argument); low_latency.set_max_render_fps(1'000.0); EXPECT_DOUBLE_EQ(low_latency.max_render_fps(), 1'000.0); - Plot_Core manual(Frame_Control_Mode::Manual); Plot_Core playback(Frame_Control_Mode::Playback); EXPECT_THROW(manual.set_max_render_fps(60.0), std::logic_error); @@ -298,6 +267,5 @@ TEST(Renderive_Core2_Frame_Pipeline, FrequencyConfigurationRejectsInvalidValuesA EXPECT_FALSE(playback.refresh_manual_frame()); EXPECT_FALSE(playback.discard_pending_frame()); } - } // namespace } // namespace renderive diff --git a/Core2/tests/Core2_Integration_Tests.cpp b/render_2D/tests/render_2D_Integration_Tests.cpp similarity index 79% rename from Core2/tests/Core2_Integration_Tests.cpp rename to render_2D/tests/render_2D_Integration_Tests.cpp index f048d84..64f8c41 100644 --- a/Core2/tests/Core2_Integration_Tests.cpp +++ b/render_2D/tests/render_2D_Integration_Tests.cpp @@ -1,17 +1,13 @@ -#include "Core2/export.h" -#include "Core2/plottable/Curve_Sampling.h" -#include "Core2/render/Blend2D_Cache.h" - +#include "render_2D/export.h" +#include "render_2D/plottable/Curve_Sampling.h" +#include "render_2D/render/Blend2D_Cache.h" #include - #include #include #include #include - namespace renderive { namespace { - TEST(Renderive_Core2, RootIdentityAndRefreshDiagnosticsComeFromKernelState) { Plot_Core plot; plot.init(); @@ -19,7 +15,6 @@ TEST(Renderive_Core2, RootIdentityAndRefreshDiagnosticsComeFromKernelState) { ASSERT_TRUE(root); root->set_object_name("renamed-root"); EXPECT_EQ(plot.root_renderable(), root); - plot.set_viewport_size({32, 24}); plot.activate_view(); plot.set_max_render_fps(144.0); @@ -28,7 +23,6 @@ TEST(Renderive_Core2, RootIdentityAndRefreshDiagnosticsComeFromKernelState) { EXPECT_DOUBLE_EQ(diagnostics.refresh.frequency_hz, 144.0); EXPECT_EQ(diagnostics.refresh.frame_count, 1u); } - TEST(Renderive_Core2, EveryCurveInterpolationModeHasDistinctSamplingSemantics) { const std::array edge_values{0.0, 10.0}; const Range domain{0.0, 1.0}; @@ -52,13 +46,11 @@ TEST(Renderive_Core2, EveryCurveInterpolationModeHasDistinctSamplingSemantics) { EXPECT_DOUBLE_EQ(step_left[1].value, 0.0); EXPECT_DOUBLE_EQ(step_right[1].coordinate, 0.0); EXPECT_DOUBLE_EQ(step_right[1].value, 10.0); - const std::array curved_values{0.0, 10.0, 0.0, 10.0}; const auto cubic = detail::curve_sampling::interpolate( curved_values, {0.0, 3.0}, Line_Interpolation_Mode::Cubic_Value); ASSERT_EQ(cubic.size(), 13u); EXPECT_NEAR(cubic[2].value, 5.625, 1e-9); - const std::array visible_values{}; const Axis_Transform visible_x{{4.0, 6.0}, 0.0, 100.0}; const Axis_Transform visible_y{{0.0, 1.0}, 0.0, 100.0}; @@ -70,7 +62,6 @@ TEST(Renderive_Core2, EveryCurveInterpolationModeHasDistinctSamplingSemantics) { EXPECT_LE(clipped.front().x, 0.0); EXPECT_GE(clipped.back().x, 100.0); } - TEST(Renderive_Core2, BicubicHeatmapUsesRealCubicResampling) { const std::array source{ pack_rgba(255, 0, 0), pack_rgba(0, 0, 0), pack_rgba(255, 255, 255), pack_rgba(0, 0, 255), @@ -99,43 +90,39 @@ TEST(Renderive_Core2, BicubicHeatmapUsesRealCubicResampling) { EXPECT_EQ(bilinear.size(), bicubic.size()); EXPECT_NE(bilinear, bicubic); } - TEST(Renderive_Core2, KernelSceneRendersBusinessObjectsIntoBlend2DFrame) { Plot_Core plot; plot.init(); plot.set_viewport_size({320, 180}); plot.activate_view(); - const auto root = plot.root_renderable(); ASSERT_TRUE(root); auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal) - .set_x(32) - .set_y(150) - .set_pixel_length(270) - .set_coord_range({88.0, 108.0}) - .build(); + .set_x(32) + .set_y(150) + .set_pixel_length(270) + .set_coord_range({88.0, 108.0}) + .build(); frequency_axis->set_locale({','}); frequency_axis->set_label_rotation_degrees(15); EXPECT_EQ(frequency_axis->tick_label(88.5), "88,5 Hz"); frequency_axis->set_label_precision(4); EXPECT_EQ(frequency_axis->tick_label(1'234'567.0), "1,2346 MHz"); auto power_axis = Axis::Builder(root, Orientation::Vertical) - .set_x(32) - .set_y(8) - .set_pixel_length(142) - .set_coord_range({-120.0, 0.0}) - .build(); + .set_x(32) + .set_y(8) + .set_pixel_length(142) + .set_coord_range({-120.0, 0.0}) + .build(); auto spectrum = Spectrum::Builder(root, frequency_axis, power_axis) - .set_frequency_range({88.0, 108.0}) - .set_frequency_point_size(64) - .set_max_hold_visible(true) - .build(); - + .set_frequency_range({88.0, 108.0}) + .set_frequency_point_size(64) + .set_max_hold_visible(true) + .build(); std::vector samples(64); for (std::size_t index = 0; index < samples.size(); ++index) samples[index] = -100.0 + static_cast(index % 24) * 3.0; spectrum->update_samples(samples); - ASSERT_TRUE(plot.render_frame()); bool saw_frame = false; bool saw_drawn_pixel = false; @@ -157,10 +144,8 @@ TEST(Renderive_Core2, KernelSceneRendersBusinessObjectsIntoBlend2DFrame) { EXPECT_TRUE(saw_drawn_pixel); EXPECT_EQ(plot.diagnostics().refresh.frame_count, 1u); EXPECT_FALSE(plot.render_frame()); - spectrum->update_samples(samples); EXPECT_TRUE(plot.render_frame()); - frequency_axis->set_use_wheel(true); const Range before_zoom = frequency_axis->coord_range(); Wheel_Event wheel; @@ -170,21 +155,19 @@ TEST(Renderive_Core2, KernelSceneRendersBusinessObjectsIntoBlend2DFrame) { EXPECT_TRUE(wheel.is_accepted()); EXPECT_LT(frequency_axis->coord_range().size(), before_zoom.size()); EXPECT_TRUE(plot.render_frame()); - plot.remove_renderable(spectrum); EXPECT_TRUE(plot.render_frame(true)); EXPECT_FALSE(plot.render_frame()); } - TEST(Renderive_Core2, TimeAxisUsesOneFontStateAndFormatsConfiguredLabels) { Plot_Core plot; plot.init(); const auto root = plot.root_renderable(); auto axis = Time_Axis::Builder(root, Orientation::Horizontal) - .set_time_format("hh-mm-ss.zzz") - .set_font(Font{18.0, 700, true}) - .set_tick_label_spacing_px(17) - .build(); + .set_time_format("hh-mm-ss.zzz") + .set_font(Font{18.0, 700, true}) + .set_tick_label_spacing_px(17) + .build(); ASSERT_TRUE(axis); const int tick = axis->append_time(Time_Of_Day{3'723'045}); EXPECT_EQ(axis->tick_label(tick), "01-02-03.045"); @@ -192,7 +175,6 @@ TEST(Renderive_Core2, TimeAxisUsesOneFontStateAndFormatsConfiguredLabels) { EXPECT_EQ(axis->unit_text_font(), axis->font()); EXPECT_EQ(axis->tick_label_spacing_px(), 17); } - TEST(Renderive_Core2, PerformanceOverlayConsumesKernelFrameDiagnostics) { Plot_Core plot; plot.init(); @@ -205,7 +187,6 @@ TEST(Renderive_Core2, PerformanceOverlayConsumesKernelFrameDiagnostics) { ASSERT_TRUE(overlay); set_performance_plot_name(plot, "integration"); set_performance_overlay_enabled(plot, true); - ASSERT_TRUE(plot.render_frame(true)); const auto snapshot = overlay->display_snapshot(); ASSERT_TRUE(snapshot); @@ -215,7 +196,6 @@ TEST(Renderive_Core2, PerformanceOverlayConsumesKernelFrameDiagnostics) { EXPECT_EQ(snapshot->frame_count, 1u); EXPECT_DOUBLE_EQ(plot.max_render_fps(), 120.0); } - TEST(Renderive_Core2, AllFrameControlModesUseKernelStrategiesAndExposeObservers) { Plot_Core manual(Frame_Control_Mode::Manual); manual.init(); @@ -230,7 +210,6 @@ TEST(Renderive_Core2, AllFrameControlModesUseKernelStrategiesAndExposeObservers) manual_observer = manual.frame_observer_snapshot(); EXPECT_EQ(manual_observer.last_event, "rendered"); EXPECT_EQ(manual_observer.consumed_frame_count, 1u); - Plot_Core low_latency(Frame_Control_Mode::Low_Latency); low_latency.init(); low_latency.set_viewport_size({64, 40}); @@ -240,7 +219,6 @@ TEST(Renderive_Core2, AllFrameControlModesUseKernelStrategiesAndExposeObservers) EXPECT_EQ(low_latency.frame_control_mode(), Frame_Control_Mode::Low_Latency); EXPECT_EQ(low_observer.last_event, "lifecycle_completed"); EXPECT_EQ(low_observer.consumed_frame_count, 1u); - Plot_Core playback(Frame_Control_Mode::Playback); playback.init(); playback.set_viewport_size({64, 40}); @@ -257,31 +235,29 @@ TEST(Renderive_Core2, AllFrameControlModesUseKernelStrategiesAndExposeObservers) EXPECT_EQ(playback_observer.pending_frame_count, 2u); EXPECT_EQ(playback_observer.consumed_frame_count, 1u); } - TEST(Renderive_Core2, RetainedAxisAndTimeAxisApisRoundTripWithoutWebAdapters) { Plot_Core plot; plot.init(); const auto root = plot.root_renderable(); ASSERT_TRUE(root); - const auto axis = Axis::Builder(root, Orientation::Vertical) - .set_x(31) - .set_y(17) - .set_pixel_length(240) - .set_tick_length(13) - .set_sub_tick_length(7) - .set_color({10, 20, 30, 255}) - .set_unit_text("dB") - .set_unit_text_font({15.0, 650, true}) - .set_unit_text_pen({Color{40, 50, 60, 255}, 2.0}) - .set_unit_text_background_brush( - {Color{3, 4, 5, 255}, Brush_Style::Solid}) - .set_label_rotation_degrees(27) - .set_coord_range({-120.0, -20.0}) - .set_label_precision(4) - .set_use_wheel(true) - .set_use_drag(true) - .build(); + .set_x(31) + .set_y(17) + .set_pixel_length(240) + .set_tick_length(13) + .set_sub_tick_length(7) + .set_color({10, 20, 30, 255}) + .set_unit_text("dB") + .set_unit_text_font({15.0, 650, true}) + .set_unit_text_pen({Color{40, 50, 60, 255}, 2.0}) + .set_unit_text_background_brush( + {Color{3, 4, 5, 255}, Brush_Style::Solid}) + .set_label_rotation_degrees(27) + .set_coord_range({-120.0, -20.0}) + .set_label_precision(4) + .set_use_wheel(true) + .set_use_drag(true) + .build(); ASSERT_TRUE(axis); EXPECT_EQ(axis->x(), 31); EXPECT_EQ(axis->y(), 17); @@ -300,7 +276,6 @@ TEST(Renderive_Core2, RetainedAxisAndTimeAxisApisRoundTripWithoutWebAdapters) { EXPECT_EQ(axis->label_precision(), 4); EXPECT_TRUE(axis->use_wheel()); EXPECT_TRUE(axis->use_drag()); - axis->set_locale({','}); axis->set_coord_start(-100.0); axis->set_coord_length(80.0); @@ -310,17 +285,16 @@ TEST(Renderive_Core2, RetainedAxisAndTimeAxisApisRoundTripWithoutWebAdapters) { EXPECT_GT(axis->pixel_sample_count(), 0); EXPECT_GT(axis->tick_step(axis->coord_range()), 0.0); EXPECT_GE(axis->sub_tick_count(axis->tick_step(axis->coord_range())), 0); - const auto time_axis = Time_Axis::Builder(root, Orientation::Horizontal) - .set_x(12) - .set_y(280) - .set_pixel_length(300) - .set_visible_time_point_count(32) - .set_tick_label_spacing_px(19) - .set_time_format("hh:mm:ss.zzz") - .set_font({16.0, 700, true}) - .set_newest_at_axis_start(true) - .build(); + .set_x(12) + .set_y(280) + .set_pixel_length(300) + .set_visible_time_point_count(32) + .set_tick_label_spacing_px(19) + .set_time_format("hh:mm:ss.zzz") + .set_font({16.0, 700, true}) + .set_newest_at_axis_start(true) + .build(); ASSERT_TRUE(time_axis); const int first = time_axis->append_time({3'723'004}); const int second = time_axis->append_time({3'724'005}); @@ -334,7 +308,6 @@ TEST(Renderive_Core2, RetainedAxisAndTimeAxisApisRoundTripWithoutWebAdapters) { EXPECT_EQ(time_axis->tick_to_time(second), (Time_Of_Day{3'724'005})); EXPECT_EQ(time_axis->tick_label(first), "01:02:03.004"); } - TEST(Renderive_Core2, RetainedSpectrumApisRoundTripAndMarkersRemainObservable) { Plot_Core plot; plot.init(); @@ -342,26 +315,25 @@ TEST(Renderive_Core2, RetainedSpectrumApisRoundTripAndMarkersRemainObservable) { plot.activate_view(); const auto root = plot.root_renderable(); const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal) - .set_x(30).set_y(210).set_pixel_length(300) - .set_coord_range({90.0, 110.0}).build(); + .set_x(30).set_y(210).set_pixel_length(300) + .set_coord_range({90.0, 110.0}).build(); const auto power = Axis::Builder(root, Orientation::Vertical) - .set_x(30).set_y(20).set_pixel_length(190) - .set_coord_range({-20.0, -120.0}).build(); + .set_x(30).set_y(20).set_pixel_length(190) + .set_coord_range({-20.0, -120.0}).build(); auto spectrum = Spectrum::Builder(root, frequency, power) - .set_frequency_range({90.0, 110.0}) - .set_frequency_point_size(4) - .set_center_frequency(100.0) - .set_sweep_frequency_range({96.0, 104.0}) - .set_max_hold_visible(true) - .set_min_hold_visible(true) - .set_max_marker_visible(true) - .set_use_min_marker(true) - .set_sweep_region_visible(true) - .set_visible_range_only(false) - .set_interpolation_mode(Line_Interpolation_Mode::Cubic_Value) - .build(); + .set_frequency_range({90.0, 110.0}) + .set_frequency_point_size(4) + .set_center_frequency(100.0) + .set_sweep_frequency_range({96.0, 104.0}) + .set_max_hold_visible(true) + .set_min_hold_visible(true) + .set_max_marker_visible(true) + .set_use_min_marker(true) + .set_sweep_region_visible(true) + .set_visible_range_only(false) + .set_interpolation_mode(Line_Interpolation_Mode::Cubic_Value) + .build(); ASSERT_TRUE(spectrum); - spectrum->set_max_brush({Color{1, 2, 3, 80}, Brush_Style::Solid}); spectrum->set_current_brush({Color{4, 5, 6, 90}, Brush_Style::Solid}); spectrum->set_min_brush({Color{7, 8, 9, 100}, Brush_Style::Solid}); @@ -372,7 +344,6 @@ TEST(Renderive_Core2, RetainedSpectrumApisRoundTripAndMarkersRemainObservable) { spectrum->set_marker_pen({Color{44, 55, 66, 255}, 1.5}); spectrum->set_middle_frequency_pen({Color{77, 88, 99, 255}, 1.25}); spectrum->set_sweep_region_brush({Color{12, 34, 56, 70}, Brush_Style::Solid}); - EXPECT_EQ(spectrum->frequency_axis(), frequency); EXPECT_EQ(spectrum->power_axis(), power); EXPECT_EQ(spectrum->frequency_point_size(), 4); @@ -390,7 +361,6 @@ TEST(Renderive_Core2, RetainedSpectrumApisRoundTripAndMarkersRemainObservable) { EXPECT_EQ(spectrum->current_pen(), (Pen{Color{40, 50, 60, 255}, 2.5})); EXPECT_EQ(spectrum->sweep_region_brush(), (Brush{Color{12, 34, 56, 70}, Brush_Style::Solid})); - std::pmr::vector samples{std::pmr::get_default_resource()}; samples.assign({-100.0, -80.0, -70.0, -50.0}); spectrum->update_samples(std::move(samples)); @@ -401,7 +371,6 @@ TEST(Renderive_Core2, RetainedSpectrumApisRoundTripAndMarkersRemainObservable) { EXPECT_TRUE(valid); EXPECT_DOUBLE_EQ(spectrum->power_at(200.0, valid), 0.0); EXPECT_FALSE(valid); - spectrum->add_custom_marker(96.0); spectrum->add_custom_line_marker(102.0); EXPECT_EQ(spectrum->selectable_line_marker_count(), 2); @@ -419,7 +388,6 @@ TEST(Renderive_Core2, RetainedSpectrumApisRoundTripAndMarkersRemainObservable) { EXPECT_EQ(spectrum->selected_marker_index(), -1); EXPECT_TRUE(plot.render_frame(true)); } - TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) { Plot_Core plot; plot.init(); @@ -427,22 +395,21 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) { plot.activate_view(); const auto root = plot.root_renderable(); const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal) - .set_x(40).set_y(250).set_pixel_length(340) - .set_coord_range({0.0, 4.0}).build(); + .set_x(40).set_y(250).set_pixel_length(340) + .set_coord_range({0.0, 4.0}).build(); const auto power = Axis::Builder(root, Orientation::Vertical) - .set_x(40).set_y(20).set_pixel_length(230) - .set_coord_range({0.0, -120.0}).build(); + .set_x(40).set_y(20).set_pixel_length(230) + .set_coord_range({0.0, -120.0}).build(); const auto time = Time_Axis::Builder(root, Orientation::Vertical) - .set_x(40).set_y(20).set_pixel_length(230) - .set_visible_time_point_count(8).build(); - + .set_x(40).set_y(20).set_pixel_length(230) + .set_visible_time_point_count(8).build(); auto waterfall = Waterfall::Builder(root, frequency, time) - .set_frequency_range({0.0, 4.0}) - .set_power_range({-120.0, 0.0}) - .set_frequency_bin_count(4) - .set_visible_range_only(false) - .set_interpolation_mode(Image_Interpolation_Mode::Bicubic) - .build(); + .set_frequency_range({0.0, 4.0}) + .set_power_range({-120.0, 0.0}) + .set_frequency_bin_count(4) + .set_visible_range_only(false) + .set_interpolation_mode(Image_Interpolation_Mode::Bicubic) + .build(); ASSERT_TRUE(waterfall); EXPECT_EQ(waterfall->frequency_axis(), frequency); EXPECT_EQ(waterfall->time_axis(), time); @@ -459,15 +426,14 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) { EXPECT_EQ(waterfall->row_count(), 2U); EXPECT_EQ(waterfall->stored_point_count(), 8U); EXPECT_EQ(waterfall->rendered_cell_count(), 8U); - auto afterglow = Afterglow::Builder(root, frequency, power) - .set_frequency_range({0.0, 4.0}) - .set_power_range({-120.0, 0.0}) - .set_frequency_bin_count(4) - .set_power_bin_count(8) - .set_interpolate_power_bins(false) - .set_decay_rate(0.35) - .build(); + .set_frequency_range({0.0, 4.0}) + .set_power_range({-120.0, 0.0}) + .set_frequency_bin_count(4) + .set_power_bin_count(8) + .set_interpolate_power_bins(false) + .set_decay_rate(0.35) + .build(); ASSERT_TRUE(afterglow); EXPECT_EQ(afterglow->frequency_axis(), frequency); EXPECT_EQ(afterglow->power_axis(), power); @@ -486,16 +452,15 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) { EXPECT_EQ(afterglow->rendered_cell_count(), 32U); afterglow->set_attenuation_rate(2.0); EXPECT_DOUBLE_EQ(afterglow->attenuation_rate(), 1.0); - auto sweep = Sweep_Spectrum::Builder(root, frequency, power) - .set_frequency_range({0.0, 8.0}) - .set_bins_per_block(4) - .set_block_num(2) - .set_pen({Color{1, 120, 220, 255}, 2.0}) - .set_current_frequency_pen({Color{240, 80, 20, 255}, 3.0}) - .set_visible_range_only(false) - .set_interpolation_mode(Line_Interpolation_Mode::Step_Right) - .build(); + .set_frequency_range({0.0, 8.0}) + .set_bins_per_block(4) + .set_block_num(2) + .set_pen({Color{1, 120, 220, 255}, 2.0}) + .set_current_frequency_pen({Color{240, 80, 20, 255}, 3.0}) + .set_visible_range_only(false) + .set_interpolation_mode(Line_Interpolation_Mode::Step_Right) + .build(); ASSERT_TRUE(sweep); EXPECT_EQ(sweep->frequency_axis(), frequency); EXPECT_EQ(sweep->power_axis(), power); @@ -512,10 +477,9 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) { EXPECT_EQ(sweep->stored_block_count(), 2U); EXPECT_EQ(sweep->stored_point_count(), 8U); EXPECT_GT(sweep->rendered_point_count(), 0U); - auto trace = Frequency_Trace::Builder(root, time, power) - .set_pen({Color{120, 240, 80, 255}, 2.0}) - .build(); + .set_pen({Color{120, 240, 80, 255}, 2.0}) + .build(); ASSERT_TRUE(trace); trace->append_sample(Time_Of_Day{3000}, -80.0); trace->append_sample(Time_Of_Day{4000}, -70.0); @@ -525,7 +489,6 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) { EXPECT_EQ(trace->rendered_point_count(), 2U); EXPECT_TRUE(plot.render_frame(true)); } - TEST(Renderive_Core2, RetainedSelectionAndConstellationApisDriveInteractionAndLayout) { Plot_Core plot; plot.init(); @@ -533,17 +496,17 @@ TEST(Renderive_Core2, RetainedSelectionAndConstellationApisDriveInteractionAndLa plot.activate_view(); const auto root = plot.root_renderable(); const auto horizontal = Axis::Builder(root, Orientation::Horizontal) - .set_x(30).set_y(230).set_pixel_length(300) - .set_coord_range({-3.0, 3.0}).build(); + .set_x(30).set_y(230).set_pixel_length(300) + .set_coord_range({-3.0, 3.0}).build(); const auto vertical = Axis::Builder(root, Orientation::Vertical) - .set_x(30).set_y(20).set_pixel_length(210) - .set_coord_range({3.0, -3.0}).build(); + .set_x(30).set_y(20).set_pixel_length(210) + .set_coord_range({3.0, -3.0}).build(); auto selection = Selection_Rectangle_Overlay::Builder(root, horizontal, vertical) - .set_font({14.0, 600, true}) - .set_font_pen({Color{20, 220, 180, 255}, 2.0}) - .set_rect_brush({Color{20, 80, 220, 60}, Brush_Style::Solid}) - .set_border_pen({Color{240, 200, 60, 255}, 2.0, Line_Style::Dash}) - .build(); + .set_font({14.0, 600, true}) + .set_font_pen({Color{20, 220, 180, 255}, 2.0}) + .set_rect_brush({Color{20, 80, 220, 60}, Brush_Style::Solid}) + .set_border_pen({Color{240, 200, 60, 255}, 2.0, Line_Style::Dash}) + .build(); ASSERT_TRUE(selection); EXPECT_EQ(selection->label_font(), (Font{14.0, 600, true})); EXPECT_EQ(selection->label_pen(), (Pen{Color{20, 220, 180, 255}, 2.0})); @@ -551,7 +514,6 @@ TEST(Renderive_Core2, RetainedSelectionAndConstellationApisDriveInteractionAndLa (Brush{Color{20, 80, 220, 60}, Brush_Style::Solid})); EXPECT_EQ(selection->selection_border_pen(), (Pen{Color{240, 200, 60, 255}, 2.0, Line_Style::Dash})); - Pointer_Event press(Event_Type::Pointer_Press); press.position = {80.0, 70.0}; press.button = Mouse_Button::Left; @@ -572,16 +534,15 @@ TEST(Renderive_Core2, RetainedSelectionAndConstellationApisDriveInteractionAndLa EXPECT_TRUE(selection->selected_regions().empty()); selection->set_horizontal_axis(horizontal); selection->set_vertical_axis(vertical); - auto constellation = Constellation_Diagram::Builder(root, horizontal, vertical) - .set_i_range({-2.0, 2.0}) - .set_q_range({-3.0, 3.0}) - .set_point_color({80, 220, 255, 255}) - .set_anchor_color({255, 180, 40, 255}) - .set_point_lifetime_ms(2000) - .set_type(Constellation_Diagram_Type::Psk16) - .set_phase_offset_radians(0.25) - .build(); + .set_i_range({-2.0, 2.0}) + .set_q_range({-3.0, 3.0}) + .set_point_color({80, 220, 255, 255}) + .set_anchor_color({255, 180, 40, 255}) + .set_point_lifetime_ms(2000) + .set_type(Constellation_Diagram_Type::Psk16) + .set_phase_offset_radians(0.25) + .build(); ASSERT_TRUE(constellation); EXPECT_EQ(constellation->i_axis(), horizontal); EXPECT_EQ(constellation->q_axis(), vertical); @@ -598,6 +559,5 @@ TEST(Renderive_Core2, RetainedSelectionAndConstellationApisDriveInteractionAndLa EXPECT_EQ(vertical->coord_range(), (Range{3.0, -3.0})); EXPECT_TRUE(plot.render_frame(true)); } - } // namespace } // namespace renderive diff --git a/web.cmake b/web.cmake index bc8c85a..70049b2 100644 --- a/web.cmake +++ b/web.cmake @@ -15,7 +15,7 @@ target_include_directories(Renderive_Web PUBLIC "${root_dir}") target_compile_features(Renderive_Web PUBLIC cxx_std_20) target_compile_definitions(Renderive_Web PRIVATE NOMINMAX) target_link_libraries(Renderive_Web PRIVATE - Renderive_Core2 + Renderive_render_2D Renderive_Kernel Adminive::Nlohmann Drogon::Drogon @@ -26,9 +26,9 @@ add_executable(Renderive_Web_Server "${root_dir}/web_server/main.cpp") target_compile_features(Renderive_Web_Server PRIVATE cxx_std_20) target_link_libraries(Renderive_Web_Server PRIVATE Renderive_Web) add_custom_target(Renderive_Web_Assets - COMMAND "${CMAKE_COMMAND}" -E copy_directory - "${root_dir}/webapp" - "${CMAKE_CURRENT_BINARY_DIR}/webapp" + # COMMAND "${CMAKE_COMMAND}" -E copy_directory + # "${root_dir}/webapp" + # "${CMAKE_CURRENT_BINARY_DIR}/webapp" COMMAND "${CMAKE_COMMAND}" -E copy_directory "${root_dir}/webapp_gallery" "${CMAKE_CURRENT_BINARY_DIR}/webapp_gallery" diff --git a/web_server/Gallery_Plot_Session.cpp b/web_server/Gallery_Plot_Session.cpp index 9c2fd85..85cbad5 100644 --- a/web_server/Gallery_Plot_Session.cpp +++ b/web_server/Gallery_Plot_Session.cpp @@ -1,12 +1,9 @@ #include "Gallery_Plot_Session.h" - #include "Gallery_Protocol.h" #include "Pixel_Frame.h" #include "Web_Performance_Log.h" -#include "Core2/export.h" - +#include "render_2D/export.h" #include - #include #include #include @@ -24,42 +21,33 @@ #include #include #include - namespace renderive::web { namespace { - template const T& state_value(const Gallery_State& state, std::string_view id) { return std::get(state.values.at(std::string(id))); } - double number_value(const Gallery_State& state, std::string_view id) { return state_value(state, id); } - std::uint64_t milliseconds_to_ns(double milliseconds) { return milliseconds > 0.0 ? static_cast(std::llround(milliseconds * 1'000'000.0)) : 0; } std::uint64_t frequency_to_ns(double frequency_hz) { return frequency_hz > 0.0 ? static_cast(std::llround(1'000'000'000.0 / frequency_hz)) : 0; } - int integer_value(const Gallery_State& state, std::string_view id) { return static_cast(std::lround(number_value(state, id))); } - bool bool_value(const Gallery_State& state, std::string_view id) { return state_value(state, id); } - const std::string& string_value(const Gallery_State& state, std::string_view id) { return state_value(state, id); } - bool has_value(const Gallery_State& state, std::string_view id) { return state.values.contains(id); } - int hex_digit(char value) { if (value >= '0' && value <= '9') return value - '0'; @@ -67,35 +55,39 @@ int hex_digit(char value) { return value - 'a' + 10; return value - 'A' + 10; } - Color color_from_hex(std::string_view value, std::uint8_t alpha = 255) { const auto channel = [value](std::size_t offset) { return static_cast(hex_digit(value[offset]) * 16 + - hex_digit(value[offset + 1])); + hex_digit(value[offset + 1])); }; return {channel(1), channel(3), channel(5), alpha}; } - Color blend(Color first, Color second, double amount) { const auto channel = [amount](std::uint8_t a, std::uint8_t b) { return static_cast(std::clamp( std::lround(a + (b - a) * amount), 0L, 255L)); }; - return {channel(first.r, second.r), channel(first.g, second.g), - channel(first.b, second.b), channel(first.a, second.a)}; + return { + channel(first.r, second.r), channel(first.g, second.g), + channel(first.b, second.b), channel(first.a, second.a) + }; } - Color_Map gallery_color_map(std::string_view palette) { std::array stops{ Color{5, 10, 25, 255}, Color{20, 52, 112, 255}, Color{39, 196, 181, 255}, Color{242, 201, 76, 255}, Color{255, 76, 106, 255} }; if (palette == "Ember") { - stops = {Color{10, 5, 8, 255}, Color{62, 18, 30, 255}, Color{153, 47, 39, 255}, - Color{244, 132, 48, 255}, Color{255, 238, 166, 255}}; - } else if (palette == "Grayscale") { - stops = {Color{0, 0, 0, 255}, Color{52, 52, 52, 255}, Color{112, 112, 112, 255}, - Color{188, 188, 188, 255}, Color{255, 255, 255, 255}}; + stops = { + Color{10, 5, 8, 255}, Color{62, 18, 30, 255}, Color{153, 47, 39, 255}, + Color{244, 132, 48, 255}, Color{255, 238, 166, 255} + }; + } + else if (palette == "Grayscale") { + stops = { + Color{0, 0, 0, 255}, Color{52, 52, 52, 255}, Color{112, 112, 112, 255}, + Color{188, 188, 188, 255}, Color{255, 255, 255, 255} + }; } std::vector colors; colors.reserve(256); @@ -109,20 +101,17 @@ Color_Map gallery_color_map(std::string_view palette) { result.set_colors(std::move(colors)); return result; } - Time_Of_Day current_time_of_day() { constexpr std::int64_t day_ms = 24LL * 60LL * 60LL * 1000LL; const auto now = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count(); + std::chrono::system_clock::now().time_since_epoch()) + .count(); return {now % day_ms}; } - double gaussian(double x, double center, double width) { const double normalized = (x - center) / width; return std::exp(-0.5 * normalized * normalized); } - Line_Interpolation_Mode line_mode(std::string_view value) { if (value == "Nearest_Sample") return Line_Interpolation_Mode::Nearest_Sample; @@ -136,7 +125,6 @@ Line_Interpolation_Mode line_mode(std::string_view value) { return Line_Interpolation_Mode::Cubic_Value; return Line_Interpolation_Mode::Linear_Value; } - Image_Interpolation_Mode image_mode(std::string_view value) { if (value == "Bilinear") return Image_Interpolation_Mode::Bilinear; @@ -144,7 +132,6 @@ Image_Interpolation_Mode image_mode(std::string_view value) { return Image_Interpolation_Mode::Bicubic; return Image_Interpolation_Mode::Nearest; } - Constellation_Diagram_Type constellation_mode(std::string_view value) { if (value == "PSK4") return Constellation_Diagram_Type::Psk4; @@ -152,13 +139,11 @@ Constellation_Diagram_Type constellation_mode(std::string_view value) { return Constellation_Diagram_Type::Psk16; return Constellation_Diagram_Type::Psk8; } - std::optional action_number(const Gallery_Action_Request& request) { if (!request.argument || !std::holds_alternative(*request.argument)) return std::nullopt; return std::get(*request.argument); } - Frame_Control_Mode core_frame_mode(Gallery_Frame_Mode mode) { switch (mode) { case Gallery_Frame_Mode::Manual: @@ -170,7 +155,6 @@ Frame_Control_Mode core_frame_mode(Gallery_Frame_Mode mode) { } return Frame_Control_Mode::Low_Latency; } - std::string_view frame_mode_name(Gallery_Frame_Mode mode) { switch (mode) { case Gallery_Frame_Mode::Manual: @@ -182,14 +166,11 @@ std::string_view frame_mode_name(Gallery_Frame_Mode mode) { } return "low_latency"; } - } // namespace - struct Gallery_Pixel_Copy { Pixel_Frame_Copy image; Color background; }; - class Gallery_Scene final { public: Gallery_Scene(std::uint64_t session_id, std::string case_id, Gallery_State state, @@ -212,23 +193,27 @@ public: update_model(); (void)plot_.render_frame(true); } - - ~Gallery_Scene() { plot_.deactivate_view(); } - + ~Gallery_Scene() { + plot_.deactivate_view(); + } Gallery_Scene(const Gallery_Scene&) = delete; Gallery_Scene& operator=(const Gallery_Scene&) = delete; - - [[nodiscard]] const std::string& case_id() const noexcept { return case_id_; } - [[nodiscard]] const Gallery_State& state() const noexcept { return state_; } - [[nodiscard]] Gallery_Frame_Mode frame_mode() const noexcept { return frame_mode_; } + [[nodiscard]] const std::string& case_id() const noexcept { + return case_id_; + } + [[nodiscard]] const Gallery_State& state() const noexcept { + return state_; + } + [[nodiscard]] Gallery_Frame_Mode frame_mode() const noexcept { + return frame_mode_; + } [[nodiscard]] bool can_render_automatically() const noexcept { return automatic_low_latency_ && frame_mode_ == Gallery_Frame_Mode::Low_Latency && - plot_.view_active(); + plot_.view_active(); } [[nodiscard]] std::uint64_t kernel_refresh_interval_ns() const { return plot_.refresh_feedback_snapshot().next_refresh_interval_ns; } - void set_client_metrics(double transport_fps, double presentation_fps, std::uint64_t buffered_bytes, std::uint64_t changed_pixel_frames, @@ -242,38 +227,28 @@ public: std::uint64_t overwritten_pixel_frames, double last_pixel_receive_age_ms, double last_pixel_change_age_ms) noexcept { - client_transport_fps_ = std::isfinite(transport_fps) ? - std::clamp(transport_fps, 0.0, 100000.0) : 0.0; - client_presentation_fps_ = std::isfinite(presentation_fps) ? - std::clamp(presentation_fps, 0.0, 100000.0) : 0.0; + client_transport_fps_ = std::isfinite(transport_fps) ? std::clamp(transport_fps, 0.0, 100000.0) : 0.0; + client_presentation_fps_ = std::isfinite(presentation_fps) ? std::clamp(presentation_fps, 0.0, 100000.0) : 0.0; client_buffered_bytes_ = buffered_bytes; client_changed_pixel_frames_ = changed_pixel_frames; client_duplicate_pixel_frames_ = duplicate_pixel_frames; client_frame_request_timeout_count_ = frame_request_timeout_count; - client_frame_round_trip_ms_ = std::isfinite(frame_round_trip_ms) ? - std::max(0.0, frame_round_trip_ms) : 0.0; - client_display_interval_ms_ = std::isfinite(display_interval_ms) ? - std::max(0.0, display_interval_ms) : 0.0; - client_display_interval_latest_ms_ = std::isfinite(display_interval_latest_ms) ? - std::max(0.0, display_interval_latest_ms) : 0.0; - client_display_interval_p95_ms_ = std::isfinite(display_interval_p95_ms) ? - std::max(0.0, display_interval_p95_ms) : 0.0; - client_display_jitter_ms_ = std::isfinite(display_jitter_ms) ? - std::max(0.0, display_jitter_ms) : 0.0; + client_frame_round_trip_ms_ = std::isfinite(frame_round_trip_ms) ? std::max(0.0, frame_round_trip_ms) : 0.0; + client_display_interval_ms_ = std::isfinite(display_interval_ms) ? std::max(0.0, display_interval_ms) : 0.0; + client_display_interval_latest_ms_ = std::isfinite(display_interval_latest_ms) ? std::max(0.0, display_interval_latest_ms) : 0.0; + client_display_interval_p95_ms_ = std::isfinite(display_interval_p95_ms) ? std::max(0.0, display_interval_p95_ms) : 0.0; + client_display_jitter_ms_ = std::isfinite(display_jitter_ms) ? std::max(0.0, display_jitter_ms) : 0.0; client_overwritten_pixel_frames_ = overwritten_pixel_frames; - client_last_pixel_receive_age_ms_ = std::isfinite(last_pixel_receive_age_ms) ? - std::max(0.0, last_pixel_receive_age_ms) : 0.0; - client_last_pixel_change_age_ms_ = std::isfinite(last_pixel_change_age_ms) ? - std::max(0.0, last_pixel_change_age_ms) : 0.0; + client_last_pixel_receive_age_ms_ = std::isfinite(last_pixel_receive_age_ms) ? std::max(0.0, last_pixel_receive_age_ms) : 0.0; + client_last_pixel_change_age_ms_ = std::isfinite(last_pixel_change_age_ms) ? std::max(0.0, last_pixel_change_age_ms) : 0.0; apply_consumer_feedback(); } - [[nodiscard]] bool requires_rebuild(const Gallery_State& candidate) const { const auto changed = [this, &candidate](std::string_view id) { const auto current = state_.values.find(id); const auto next = candidate.values.find(id); return current != state_.values.end() && next != candidate.values.end() && - current->second != next->second; + current->second != next->second; }; if (case_id_ == "frequency_trace") return changed("trace_pen") || changed("trace_pen_width"); @@ -283,22 +258,20 @@ public: return changed("color_map"); return false; } - void set_state(Gallery_State state) { const bool render_schedule_changed = frame_mode_ == Gallery_Frame_Mode::Low_Latency && - (bool_value(state_, "frequency_limit_enabled") != bool_value(state, "frequency_limit_enabled") || - number_value(state_, "max_render_fps") != number_value(state, "max_render_fps") || - bool_value(state_, "consumer_feedback_enabled") != bool_value(state, "consumer_feedback_enabled") || - bool_value(state_, "consumer_pixel_feedback_enabled") != bool_value(state, "consumer_pixel_feedback_enabled") || - bool_value(state_, "consumer_presentation_feedback_enabled") != bool_value(state, "consumer_presentation_feedback_enabled") || - bool_value(state_, "consumer_manual_feedback_enabled") != bool_value(state, "consumer_manual_feedback_enabled") || - number_value(state_, "consumer_manual_fps") != number_value(state, "consumer_manual_fps")); + (bool_value(state_, "frequency_limit_enabled") != bool_value(state, "frequency_limit_enabled") || + number_value(state_, "max_render_fps") != number_value(state, "max_render_fps") || + bool_value(state_, "consumer_feedback_enabled") != bool_value(state, "consumer_feedback_enabled") || + bool_value(state_, "consumer_pixel_feedback_enabled") != bool_value(state, "consumer_pixel_feedback_enabled") || + bool_value(state_, "consumer_presentation_feedback_enabled") != bool_value(state, "consumer_presentation_feedback_enabled") || + bool_value(state_, "consumer_manual_feedback_enabled") != bool_value(state, "consumer_manual_feedback_enabled") || + number_value(state_, "consumer_manual_fps") != number_value(state, "consumer_manual_fps")); state_ = std::move(state); apply_state(); if (render_schedule_changed) render_history_.clear(); } - void resize(Size size) { const Size previous = plot_.viewport_size(); plot_.set_viewport_size(size); @@ -308,7 +281,6 @@ public: event.new_size = size; plot_.dispatch_event(event); } - void dispatch(const Event& event) { if (event.type == Event_Type::Show) plot_.activate_view(); @@ -316,12 +288,10 @@ public: plot_.deactivate_view(); plot_.dispatch_event(event); } - void remove_primary() { if (primary_) plot_.remove_renderable(primary_); } - bool render_latest_frame() { if (!plot_.view_active()) return false; @@ -333,7 +303,6 @@ public: rendered_since_last_pixel_ = true; return rendered; } - [[nodiscard]] std::optional copy_latest_pixels() { if (!plot_.view_active()) return std::nullopt; @@ -346,17 +315,14 @@ public: plot_.with_frame([©](Image_View image) { copy.image = copy_pixel_frame(image); }); - return copy.image.empty() ? std::nullopt : - std::optional(std::move(copy)); + return copy.image.empty() ? std::nullopt : std::optional(std::move(copy)); } - void record_pixel_response(std::chrono::steady_clock::time_point request_started, std::chrono::steady_clock::time_point encode_started, std::chrono::steady_clock::time_point encode_finished, std::size_t pixel_bytes) { record_pixel_performance(request_started, encode_started, encode_finished, pixel_bytes); } - [[nodiscard]] std::string action(const Gallery_Action_Request& request, bool& recognized) { last_action_result_.clear(); @@ -426,7 +392,7 @@ public: if (request.id == "axis_set_length") { if (numeric_domain_axis_) numeric_domain_axis_->set_coord_length(number_value(state_, "coord_target") - - number_value(state_, "coord_origin")); + number_value(state_, "coord_origin")); return "已通过 Axis::set_coord_length 应用当前跨度"; } if (request.id == "axis_probe") @@ -434,7 +400,7 @@ public: if (request.id == "append_time" && time_axis_) { const int tick = time_axis_->append_time(current_time_of_day()); last_action_result_ = "tick=" + std::to_string(tick) + - ", ms=" + std::to_string(time_axis_->tick_to_time(tick).milliseconds); + ", ms=" + std::to_string(time_axis_->tick_to_time(tick).milliseconds); return "Time_Axis 时间点已追加并回读"; } if (spectrum_) { @@ -522,12 +488,13 @@ public: if (request.id == "append_tick_row") { const int tick = time_axis_->append_time(current_time_of_day()); waterfall_->append_row(tick, spectrum_values(waterfall_->frequency_bin_count(), - waterfall_->power_range())); + waterfall_->power_range())); return "Waterfall 已通过 int tick 重载追加一行"; } if (request.id == "rebind_axes") { last_action_result_ = waterfall_->frequency_axis() && waterfall_->time_axis() - ? "frequency_axis/time_axis valid" : "axis invalid"; + ? "frequency_axis/time_axis valid" + : "axis invalid"; return "Waterfall 轴绑定已回读"; } } @@ -538,7 +505,8 @@ public: } if (request.id == "rebind_axes") { last_action_result_ = afterglow_->frequency_axis() && afterglow_->power_axis() - ? "frequency_axis/power_axis valid" : "axis invalid"; + ? "frequency_axis/power_axis valid" + : "axis invalid"; return "Afterglow 轴绑定已回读"; } } @@ -549,7 +517,8 @@ public: } if (request.id == "rebind_axes") { last_action_result_ = sweep_->frequency_axis() && sweep_->power_axis() - ? "frequency_axis/power_axis valid" : "axis invalid"; + ? "frequency_axis/power_axis valid" + : "axis invalid"; return "Sweep_Spectrum 轴绑定已回读"; } } @@ -565,7 +534,8 @@ public: } if (request.id == "read_axes") { last_action_result_ = trace_->time_axis() && trace_->value_axis() - ? "time_axis/value_axis valid" : "axis invalid"; + ? "time_axis/value_axis valid" + : "axis invalid"; return "Frequency_Trace 轴绑定已回读"; } } @@ -580,19 +550,18 @@ public: } if (request.id == "read_axes") { last_action_result_ = constellation_->i_axis() && constellation_->q_axis() - ? "i_axis/q_axis valid" : "axis invalid"; + ? "i_axis/q_axis valid" + : "axis invalid"; return "Constellation 轴绑定已回读"; } } recognized = false; return {}; } - void record_action_notice_if_empty(std::string_view notice) { if (last_action_result_.empty()) last_action_result_ = notice; } - [[nodiscard]] std::string telemetry_json() const { const auto observer = plot_.frame_observer_snapshot(); const auto telemetry_now = std::chrono::steady_clock::now(); @@ -607,105 +576,122 @@ public: {"case", case_id_}, {"frame_mode", frame_mode_name(frame_mode_)}, {"frame_index", frame_index_}, - {"viewport", {{"width", plot_.viewport_size().width}, - {"height", plot_.viewport_size().height}}}, + { + "viewport", { + {"width", plot_.viewport_size().width}, + {"height", plot_.viewport_size().height} + } + }, {"view_active", plot_.view_active()}, {"kernel_frame_count", plot_.diagnostics().refresh.frame_count}, - {"performance", { - {"render_attempt_count", render_attempt_count_}, - {"successful_render_count", successful_render_count_}, - {"failed_render_count", render_attempt_count_ - successful_render_count_}, - {"measured_fps", render_fps}, - {"lifetime_average_fps", static_cast(successful_render_count_) / elapsed_seconds}, - {"last_render_ms", last_render_ms_}, - {"average_render_ms", successful_render_count_ == 0 ? 0.0 : - total_render_ms_ / static_cast(successful_render_count_)}, - {"maximum_render_ms", maximum_render_ms_}, - {"pixel_response_fps", pixel_fps}, - {"last_pixel_snapshot_ms", last_pixel_snapshot_ms_}, - {"last_pixel_encode_ms", last_pixel_encode_ms_}, - {"average_pixel_encode_ms", pixel_frame_count_ == 0 ? 0.0 : - total_pixel_encode_ms_ / static_cast(pixel_frame_count_)}, - {"maximum_pixel_encode_ms", maximum_pixel_encode_ms_}, - {"last_pixel_request_ms", last_pixel_request_ms_}, - {"last_pixel_bytes", last_pixel_bytes_}, - {"pixel_payload_megabytes_per_second", pixel_megabytes_per_second}, - {"automatic_low_latency_scheduler", - automatic_low_latency_ && frame_mode_ == Gallery_Frame_Mode::Low_Latency}, - {"kernel_paint_ms", static_cast(observer.paint_duration_ns) / 1e6}, - {"kernel_render_ms", static_cast(observer.render_duration_ns) / 1e6}, - {"kernel_bottleneck_ms", static_cast(observer.bottleneck_duration_ns) / 1e6}, - {"kernel_end_to_end_ms", static_cast(observer.end_to_end_ns) / 1e6} - }}, - {"kernel_observer", { - {"mode", frame_mode_name(frame_mode_)}, - {"last_event", observer.last_event}, - {"limit_state", observer.limit_state}, - {"configured_frequency_hz", observer.frequency_hz}, - {"observation_count", observer.observation_count}, - {"produced_frame_count", observer.produced_frame_count}, - {"consumed_frame_count", observer.consumed_frame_count}, - {"dropped_frame_count", observer.dropped_frame_count}, - {"failed_operation_count", observer.failed_operation_count}, - {"pending_frame_count", observer.pending_frame_count}, - {"latest_sequence", observer.latest_sequence}, - {"paint_duration_ns", observer.paint_duration_ns}, - {"render_duration_ns", observer.render_duration_ns}, - {"target_interval_ns", observer.target_interval_ns}, - {"frequency_limit_enabled", observer.frequency_limit_enabled}, - {"consumer_feedback_enabled", observer.consumer_feedback_enabled}, - {"consumer_feedback_master_enabled", - frame_mode_ == Gallery_Frame_Mode::Low_Latency && - bool_value(state_, "consumer_feedback_enabled")}, - {"consumer_pixel_feedback_enabled", - frame_mode_ == Gallery_Frame_Mode::Low_Latency && - bool_value(state_, "consumer_pixel_feedback_enabled")}, - {"consumer_presentation_feedback_enabled", - frame_mode_ == Gallery_Frame_Mode::Low_Latency && - bool_value(state_, "consumer_presentation_feedback_enabled")}, - {"consumer_manual_feedback_enabled", - frame_mode_ == Gallery_Frame_Mode::Low_Latency && - bool_value(state_, "consumer_manual_feedback_enabled")}, - {"consumer_manual_fps", frame_mode_ == Gallery_Frame_Mode::Low_Latency ? - number_value(state_, "consumer_manual_fps") : 0.0}, - {"consumer_feedback_source", consumer_feedback_source_}, - {"consumer_pixel_interval_ns", consumer_pixel_interval_ns_}, - {"consumer_presentation_interval_ns", consumer_presentation_interval_ns_}, - {"consumer_manual_interval_ns", consumer_manual_interval_ns_}, - {"bottleneck_duration_ns", observer.bottleneck_duration_ns}, - {"consumer_sample_interval_ns", observer.consumer_sample_interval_ns}, - {"consumer_smoothed_interval_ns", observer.consumer_smoothed_interval_ns}, - {"consumer_variation_ns", observer.consumer_variation_ns}, - {"consumer_safety_interval_ns", observer.consumer_safety_interval_ns}, - {"consumer_interval_ns", observer.consumer_interval_ns}, - {"next_refresh_interval_ns", observer.next_refresh_interval_ns}, - {"paint_lease_wait_ns", observer.paint_lease_wait_ns}, - {"paint_state_wait_ns", observer.paint_state_wait_ns}, - {"publish_state_wait_ns", observer.publish_state_wait_ns}, - {"ready_wait_ns", observer.ready_wait_ns}, - {"frame_age_at_render_ns", observer.frame_age_at_render_ns}, - {"render_lease_wait_ns", observer.render_lease_wait_ns}, - {"render_state_wait_ns", observer.render_state_wait_ns}, - {"render_finish_state_wait_ns", observer.render_finish_state_wait_ns}, - {"queue_wait_ns", observer.queue_wait_ns}, - {"end_to_end_ns", observer.end_to_end_ns} - }}, - {"client_performance", { - {"transport_fps", client_transport_fps_}, - {"presentation_fps", client_presentation_fps_}, - {"websocket_buffered_bytes", client_buffered_bytes_}, - {"changed_pixel_frames", client_changed_pixel_frames_}, - {"duplicate_pixel_frames", client_duplicate_pixel_frames_}, - {"frame_request_timeout_count", client_frame_request_timeout_count_}, - {"frame_round_trip_ms", client_frame_round_trip_ms_}, - {"display_interval_ms", client_display_interval_ms_}, - {"display_interval_latest_ms", client_display_interval_latest_ms_}, - {"display_interval_p95_ms", client_display_interval_p95_ms_}, - {"display_jitter_ms", client_display_jitter_ms_}, - {"overwritten_pixel_frames", client_overwritten_pixel_frames_}, - {"last_pixel_receive_age_ms", client_last_pixel_receive_age_ms_}, - {"last_pixel_change_age_ms", client_last_pixel_change_age_ms_} - }}, + { + "performance", { + {"render_attempt_count", render_attempt_count_}, + {"successful_render_count", successful_render_count_}, + {"failed_render_count", render_attempt_count_ - successful_render_count_}, + {"measured_fps", render_fps}, + {"lifetime_average_fps", static_cast(successful_render_count_) / elapsed_seconds}, + {"last_render_ms", last_render_ms_}, + {"average_render_ms", successful_render_count_ == 0 ? 0.0 : total_render_ms_ / static_cast(successful_render_count_)}, + {"maximum_render_ms", maximum_render_ms_}, + {"pixel_response_fps", pixel_fps}, + {"last_pixel_snapshot_ms", last_pixel_snapshot_ms_}, + {"last_pixel_encode_ms", last_pixel_encode_ms_}, + {"average_pixel_encode_ms", pixel_frame_count_ == 0 ? 0.0 : total_pixel_encode_ms_ / static_cast(pixel_frame_count_)}, + {"maximum_pixel_encode_ms", maximum_pixel_encode_ms_}, + {"last_pixel_request_ms", last_pixel_request_ms_}, + {"last_pixel_bytes", last_pixel_bytes_}, + {"pixel_payload_megabytes_per_second", pixel_megabytes_per_second}, + { + "automatic_low_latency_scheduler", + automatic_low_latency_ && frame_mode_ == Gallery_Frame_Mode::Low_Latency + }, + {"kernel_paint_ms", static_cast(observer.paint_duration_ns) / 1e6}, + {"kernel_render_ms", static_cast(observer.render_duration_ns) / 1e6}, + {"kernel_bottleneck_ms", static_cast(observer.bottleneck_duration_ns) / 1e6}, + {"kernel_end_to_end_ms", static_cast(observer.end_to_end_ns) / 1e6} + } + }, + { + "kernel_observer", { + {"mode", frame_mode_name(frame_mode_)}, + {"last_event", observer.last_event}, + {"limit_state", observer.limit_state}, + {"configured_frequency_hz", observer.frequency_hz}, + {"observation_count", observer.observation_count}, + {"produced_frame_count", observer.produced_frame_count}, + {"consumed_frame_count", observer.consumed_frame_count}, + {"dropped_frame_count", observer.dropped_frame_count}, + {"failed_operation_count", observer.failed_operation_count}, + {"pending_frame_count", observer.pending_frame_count}, + {"latest_sequence", observer.latest_sequence}, + {"paint_duration_ns", observer.paint_duration_ns}, + {"render_duration_ns", observer.render_duration_ns}, + {"target_interval_ns", observer.target_interval_ns}, + {"frequency_limit_enabled", observer.frequency_limit_enabled}, + {"consumer_feedback_enabled", observer.consumer_feedback_enabled}, + { + "consumer_feedback_master_enabled", + frame_mode_ == Gallery_Frame_Mode::Low_Latency && + bool_value(state_, "consumer_feedback_enabled") + }, + { + "consumer_pixel_feedback_enabled", + frame_mode_ == Gallery_Frame_Mode::Low_Latency && + bool_value(state_, "consumer_pixel_feedback_enabled") + }, + { + "consumer_presentation_feedback_enabled", + frame_mode_ == Gallery_Frame_Mode::Low_Latency && + bool_value(state_, "consumer_presentation_feedback_enabled") + }, + { + "consumer_manual_feedback_enabled", + frame_mode_ == Gallery_Frame_Mode::Low_Latency && + bool_value(state_, "consumer_manual_feedback_enabled") + }, + {"consumer_manual_fps", frame_mode_ == Gallery_Frame_Mode::Low_Latency ? number_value(state_, "consumer_manual_fps") : 0.0}, + {"consumer_feedback_source", consumer_feedback_source_}, + {"consumer_pixel_interval_ns", consumer_pixel_interval_ns_}, + {"consumer_presentation_interval_ns", consumer_presentation_interval_ns_}, + {"consumer_manual_interval_ns", consumer_manual_interval_ns_}, + {"bottleneck_duration_ns", observer.bottleneck_duration_ns}, + {"consumer_sample_interval_ns", observer.consumer_sample_interval_ns}, + {"consumer_smoothed_interval_ns", observer.consumer_smoothed_interval_ns}, + {"consumer_variation_ns", observer.consumer_variation_ns}, + {"consumer_safety_interval_ns", observer.consumer_safety_interval_ns}, + {"consumer_interval_ns", observer.consumer_interval_ns}, + {"next_refresh_interval_ns", observer.next_refresh_interval_ns}, + {"paint_lease_wait_ns", observer.paint_lease_wait_ns}, + {"paint_state_wait_ns", observer.paint_state_wait_ns}, + {"publish_state_wait_ns", observer.publish_state_wait_ns}, + {"ready_wait_ns", observer.ready_wait_ns}, + {"frame_age_at_render_ns", observer.frame_age_at_render_ns}, + {"render_lease_wait_ns", observer.render_lease_wait_ns}, + {"render_state_wait_ns", observer.render_state_wait_ns}, + {"render_finish_state_wait_ns", observer.render_finish_state_wait_ns}, + {"queue_wait_ns", observer.queue_wait_ns}, + {"end_to_end_ns", observer.end_to_end_ns} + } + }, + { + "client_performance", { + {"transport_fps", client_transport_fps_}, + {"presentation_fps", client_presentation_fps_}, + {"websocket_buffered_bytes", client_buffered_bytes_}, + {"changed_pixel_frames", client_changed_pixel_frames_}, + {"duplicate_pixel_frames", client_duplicate_pixel_frames_}, + {"frame_request_timeout_count", client_frame_request_timeout_count_}, + {"frame_round_trip_ms", client_frame_round_trip_ms_}, + {"display_interval_ms", client_display_interval_ms_}, + {"display_interval_latest_ms", client_display_interval_latest_ms_}, + {"display_interval_p95_ms", client_display_interval_p95_ms_}, + {"display_jitter_ms", client_display_jitter_ms_}, + {"overwritten_pixel_frames", client_overwritten_pixel_frames_}, + {"last_pixel_receive_age_ms", client_last_pixel_receive_age_ms_}, + {"last_pixel_change_age_ms", client_last_pixel_change_age_ms_} + } + }, {"last_action_result", last_action_result_} }; if (frame_mode_ == Gallery_Frame_Mode::Low_Latency) { @@ -740,16 +726,18 @@ public: {"consumer_safety_interval_ns", observer.consumer_safety_interval_ns}, {"consumer_interval_ns", observer.consumer_interval_ns}, {"scheduler_interval_ns", scheduler_interval_ns}, - {"scheduler_frequency_hz", scheduler_interval_ns == 0 ? 0.0 : - 1'000'000'000.0 / static_cast(scheduler_interval_ns)} + {"scheduler_frequency_hz", scheduler_interval_ns == 0 ? 0.0 : 1'000'000'000.0 / static_cast(scheduler_interval_ns)} }; } if (primary_) { telemetry["renderable"] = { {"object_name", primary_->object_name()}, {"visible", primary_->is_visible()}, - {"cache_mode", primary_->get_cache_mode() == Renderable_Cache_Mode::Direct - ? "Direct" : "Local_Pixel"} + { + "cache_mode", primary_->get_cache_mode() == Renderable_Cache_Mode::Direct + ? "Direct" + : "Local_Pixel" + } }; } if (const auto overlay = plot_.performance_overlay()) { @@ -765,12 +753,16 @@ public: {"start_coord", numeric_domain_axis_->start_coord()}, {"end_coord", numeric_domain_axis_->end_coord()}, {"center_pixel", numeric_domain_axis_->coord_to_pixel(center)}, - {"center_roundtrip", numeric_domain_axis_->pixel_to_coord( - numeric_domain_axis_->coord_to_pixel(center))}, + { + "center_roundtrip", numeric_domain_axis_->pixel_to_coord( + numeric_domain_axis_->coord_to_pixel(center)) + }, {"pixel_samples", numeric_domain_axis_->pixel_sample_count()}, {"tick_step", numeric_domain_axis_->tick_step(range)}, - {"sub_tick_count", numeric_domain_axis_->sub_tick_count( - numeric_domain_axis_->tick_step(range))}, + { + "sub_tick_count", numeric_domain_axis_->sub_tick_count( + numeric_domain_axis_->tick_step(range)) + }, {"center_label", numeric_domain_axis_->tick_label(center)} }; } @@ -785,7 +777,7 @@ public: const int selected = spectrum_->selected_marker_index(); if (selected >= 0 && selected < spectrum_->selectable_line_marker_count()) telemetry["spectrum"]["selected_marker_frequency"] = - spectrum_->marker_frequency(selected); + spectrum_->marker_frequency(selected); } if (selection_) telemetry["selection_regions"] = selection_->selected_regions().size(); @@ -825,67 +817,76 @@ public: } if (constellation_) { const std::string& constellation_type = string_value(state_, "constellation_type"); - const int anchor_count = constellation_type == "PSK4" ? 4 : - constellation_type == "PSK16" ? 16 : 8; + const int anchor_count = constellation_type == "PSK4" ? 4 : constellation_type == "PSK16" ? 16 : 8; telemetry["constellation"] = { {"point_count", constellation_->point_count()}, {"anchor_count", anchor_count}, - {"rendered_point_count", constellation_->point_count() + - static_cast(anchor_count)}, + { + "rendered_point_count", constellation_->point_count() + + static_cast(anchor_count) + }, {"point_lifetime_ms", constellation_->point_lifetime_ms()} }; } if (case_id_ == "axis_lab") { telemetry["axis_lab"] = { - {"domain_axis_pixel_samples", numeric_domain_axis_ ? - numeric_domain_axis_->pixel_sample_count() : 0}, + {"domain_axis_pixel_samples", numeric_domain_axis_ ? numeric_domain_axis_->pixel_sample_count() : 0}, {"time_axis_point_count", time_axis_ ? time_axis_->time_point_count() : 0} }; } - if (spectrum_) - telemetry["data_shape"] = {{"input_points", spectrum_->sample_count()}, - {"rendered_elements", spectrum_->rendered_point_count()}, - {"unit", "points"}}; + telemetry["data_shape"] = { + {"input_points", spectrum_->sample_count()}, + {"rendered_elements", spectrum_->rendered_point_count()}, + {"unit", "points"} + }; else if (waterfall_) - telemetry["data_shape"] = {{"input_points", waterfall_->stored_point_count()}, - {"rendered_elements", waterfall_->rendered_cell_count()}, - {"unit", "cells"}}; + telemetry["data_shape"] = { + {"input_points", waterfall_->stored_point_count()}, + {"rendered_elements", waterfall_->rendered_cell_count()}, + {"unit", "cells"} + }; else if (afterglow_) - telemetry["data_shape"] = {{"input_points", afterglow_->latest_spectrum_point_count()}, - {"rendered_elements", afterglow_->rendered_cell_count()}, - {"unit", "cells"}}; + telemetry["data_shape"] = { + {"input_points", afterglow_->latest_spectrum_point_count()}, + {"rendered_elements", afterglow_->rendered_cell_count()}, + {"unit", "cells"} + }; else if (sweep_) - telemetry["data_shape"] = {{"input_points", sweep_->stored_point_count()}, - {"rendered_elements", sweep_->rendered_point_count()}, - {"unit", "points"}}; + telemetry["data_shape"] = { + {"input_points", sweep_->stored_point_count()}, + {"rendered_elements", sweep_->rendered_point_count()}, + {"unit", "points"} + }; else if (trace_) - telemetry["data_shape"] = {{"input_points", trace_->sample_count()}, - {"rendered_elements", trace_->rendered_point_count()}, - {"unit", "points"}}; + telemetry["data_shape"] = { + {"input_points", trace_->sample_count()}, + {"rendered_elements", trace_->rendered_point_count()}, + {"unit", "points"} + }; else if (constellation_) { const std::string& constellation_type = string_value(state_, "constellation_type"); - const std::size_t anchors = constellation_type == "PSK4" ? 4U : - constellation_type == "PSK16" ? 16U : 8U; - telemetry["data_shape"] = {{"input_points", constellation_->point_count()}, - {"rendered_elements", constellation_->point_count() + anchors}, - {"unit", "points"}}; + const std::size_t anchors = constellation_type == "PSK4" ? 4U : constellation_type == "PSK16" ? 16U : 8U; + telemetry["data_shape"] = { + {"input_points", constellation_->point_count()}, + {"rendered_elements", constellation_->point_count() + anchors}, + {"unit", "points"} + }; } else - telemetry["data_shape"] = {{"input_points", 0}, - {"rendered_elements", numeric_domain_axis_ ? - numeric_domain_axis_->pixel_sample_count() : 0}, - {"unit", "axis samples"}}; + telemetry["data_shape"] = { + {"input_points", 0}, + {"rendered_elements", numeric_domain_axis_ ? numeric_domain_axis_->pixel_sample_count() : 0}, + {"unit", "axis samples"} + }; return telemetry.dump(); } - private: using Performance_Clock = std::chrono::steady_clock; struct Pixel_Performance_Sample { Performance_Clock::time_point time; std::size_t bytes; }; - static void record_timestamp(std::deque& history, Performance_Clock::time_point now) { history.push_back(now); @@ -893,16 +894,14 @@ private: while (history.size() > 2 && history.front() < oldest) history.pop_front(); } - static double recent_rate(const std::deque& history, Performance_Clock::time_point now) { if (history.size() < 2 || now - history.back() > std::chrono::seconds(1)) return 0.0; const double seconds = - std::chrono::duration(history.back() - history.front()).count(); + std::chrono::duration(history.back() - history.front()).count(); return seconds > 0.0 ? static_cast(history.size() - 1) / seconds : 0.0; } - static void record_pixel_sample(std::deque& history, Performance_Clock::time_point now, std::size_t bytes) { @@ -911,23 +910,21 @@ private: while (history.size() > 2 && history.front().time < oldest) history.pop_front(); } - static double recent_pixel_rate(const std::deque& history, Performance_Clock::time_point now) { if (history.size() < 2 || now - history.back().time > std::chrono::seconds(1)) return 0.0; const double seconds = - std::chrono::duration(history.back().time - history.front().time).count(); + std::chrono::duration(history.back().time - history.front().time).count(); return seconds > 0.0 ? static_cast(history.size() - 1) / seconds : 0.0; } - static double recent_pixel_megabytes_per_second( const std::deque& history, Performance_Clock::time_point now) { if (history.size() < 2 || now - history.back().time > std::chrono::seconds(1)) return 0.0; const double seconds = - std::chrono::duration(history.back().time - history.front().time).count(); + std::chrono::duration(history.back().time - history.front().time).count(); if (seconds <= 0.0) return 0.0; std::size_t bytes{}; @@ -935,7 +932,6 @@ private: bytes += history[index].bytes; return static_cast(bytes) / seconds / 1e6; } - void apply_consumer_feedback() { if (frame_mode_ != Gallery_Frame_Mode::Low_Latency) return; @@ -976,12 +972,11 @@ private: } plot_.set_consumer_feedback({interval_ns}); } - void record_performance(std::chrono::steady_clock::time_point started, bool rendered) { const auto finished = std::chrono::steady_clock::now(); ++render_attempt_count_; const double duration_ms = - std::chrono::duration(finished - started).count(); + std::chrono::duration(finished - started).count(); last_render_ms_ = duration_ms; maximum_render_ms_ = std::max(maximum_render_ms_, duration_ms); if (rendered) { @@ -991,32 +986,30 @@ private: } maybe_log_performance(finished); } - void record_pixel_performance(Performance_Clock::time_point request_started, Performance_Clock::time_point encode_started, Performance_Clock::time_point encode_finished, std::size_t pixel_bytes) { last_pixel_snapshot_ms_ = - std::chrono::duration(encode_started - request_started).count(); + std::chrono::duration(encode_started - request_started).count(); last_pixel_encode_ms_ = - std::chrono::duration(encode_finished - encode_started).count(); + std::chrono::duration(encode_finished - encode_started).count(); last_pixel_request_ms_ = - std::chrono::duration(encode_finished - request_started).count(); + std::chrono::duration(encode_finished - request_started).count(); maximum_pixel_encode_ms_ = std::max(maximum_pixel_encode_ms_, last_pixel_encode_ms_); total_pixel_encode_ms_ += last_pixel_encode_ms_; last_pixel_bytes_ = pixel_bytes; ++pixel_frame_count_; record_pixel_sample(pixel_history_, encode_finished, pixel_bytes); } - void maybe_log_performance(Performance_Clock::time_point now) { if (now - last_performance_log_ < std::chrono::seconds(1)) return; last_performance_log_ = now; const auto observer = plot_.frame_observer_snapshot(); const auto unix_ms = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count(); + std::chrono::system_clock::now().time_since_epoch()) + .count(); const double pixel_fps = recent_pixel_rate(pixel_history_, now); const double pixel_megabytes_per_second = recent_pixel_megabytes_per_second( pixel_history_, now); @@ -1030,8 +1023,7 @@ private: {"frame_mode", frame_mode_name(frame_mode_)}, {"configured_fps", low_latency ? plot_.max_render_fps() : 0.0}, {"automatic_scheduler_interval_ns", scheduler_interval_ns}, - {"automatic_scheduler_fps", scheduler_interval_ns == 0 ? 0.0 : - 1'000'000'000.0 / static_cast(scheduler_interval_ns)}, + {"automatic_scheduler_fps", scheduler_interval_ns == 0 ? 0.0 : 1'000'000'000.0 / static_cast(scheduler_interval_ns)}, {"automatic_scheduler_limit_source", low_latency ? observer.limit_state : "not_applicable"}, {"frequency_limit_enabled", low_latency && observer.frequency_limit_enabled}, {"consumer_feedback_enabled", low_latency && observer.consumer_feedback_enabled}, @@ -1062,8 +1054,10 @@ private: {"pixel_payload_bytes", last_pixel_bytes_}, {"pixel_payload_megabytes_per_second", pixel_megabytes_per_second}, {"websocket_buffered_bytes", client_buffered_bytes_}, - {"automatic_low_latency_scheduler", - automatic_low_latency_ && frame_mode_ == Gallery_Frame_Mode::Low_Latency}, + { + "automatic_low_latency_scheduler", + automatic_low_latency_ && frame_mode_ == Gallery_Frame_Mode::Low_Latency + }, {"successful_render_count", successful_render_count_}, {"failed_render_count", render_attempt_count_ - successful_render_count_}, {"pixel_frame_count", pixel_frame_count_}, @@ -1099,66 +1093,71 @@ private: }; write_web_performance_log(line.dump()); } - void build_axes() { constexpr Color axis_color{118, 145, 184, 255}; - const Range coordinate_range{number_value(state_, "coord_origin"), - number_value(state_, "coord_target")}; + const Range coordinate_range{ + number_value(state_, "coord_origin"), + number_value(state_, "coord_target") + }; if (case_id_ == "frequency_trace") { time_axis_ = Time_Axis::Builder(axes_node_, Orientation::Horizontal) - .set_visible_time_point_count(integer_value(state_, "time_visible_count")) - .set_tick_label_spacing_px(integer_value(state_, "time_label_spacing")) - .set_time_format(string_value(state_, "time_format")) - .set_color(axis_color) - .build(); - } else if (case_id_ == "sweep_spectrum" || case_id_ == "constellation") { - numeric_domain_axis_ = Axis::Builder(axes_node_, Orientation::Horizontal) - .set_coord_range(coordinate_range) - .set_use_wheel(true) - .set_use_drag(true) - .set_color(axis_color) - .build(); - } else { - numeric_domain_axis_ = Frequency_Axis::Builder(axes_node_, Orientation::Horizontal) - .set_coord_range(coordinate_range) - .set_use_wheel(true) - .set_use_drag(true) - .set_color(axis_color) - .build(); + .set_visible_time_point_count(integer_value(state_, "time_visible_count")) + .set_tick_label_spacing_px(integer_value(state_, "time_label_spacing")) + .set_time_format(string_value(state_, "time_format")) + .set_color(axis_color) + .build(); + } + else if (case_id_ == "sweep_spectrum" || case_id_ == "constellation") { + numeric_domain_axis_ = Axis::Builder(axes_node_, Orientation::Horizontal) + .set_coord_range(coordinate_range) + .set_use_wheel(true) + .set_use_drag(true) + .set_color(axis_color) + .build(); + } + else { + numeric_domain_axis_ = Frequency_Axis::Builder(axes_node_, Orientation::Horizontal) + .set_coord_range(coordinate_range) + .set_use_wheel(true) + .set_use_drag(true) + .set_color(axis_color) + .build(); } - if (case_id_ == "waterfall") { time_axis_ = Time_Axis::Builder(axes_node_, Orientation::Vertical) - .set_visible_time_point_count(integer_value(state_, "time_visible_count")) - .set_tick_label_spacing_px(integer_value(state_, "time_label_spacing")) - .set_time_format(string_value(state_, "time_format")) - .set_color(axis_color) - .build(); - } else { + .set_visible_time_point_count(integer_value(state_, "time_visible_count")) + .set_tick_label_spacing_px(integer_value(state_, "time_label_spacing")) + .set_time_format(string_value(state_, "time_format")) + .set_color(axis_color) + .build(); + } + else { Range value_range{-120.0, -20.0}; if (case_id_ == "frequency_trace") - value_range = {number_value(state_, "trace_value_min"), - number_value(state_, "trace_value_max")}; + value_range = { + number_value(state_, "trace_value_min"), + number_value(state_, "trace_value_max") + }; else if (case_id_ == "constellation") - value_range = {number_value(state_, "q_origin"), - number_value(state_, "q_target")}; + value_range = { + number_value(state_, "q_origin"), + number_value(state_, "q_target") + }; value_axis_ = Axis::Builder(axes_node_, Orientation::Vertical) - .set_coord_range(value_range) - .set_label_precision(case_id_ == "constellation" ? 2 : 0) - .set_color(axis_color) - .build(); + .set_coord_range(value_range) + .set_label_precision(case_id_ == "constellation" ? 2 : 0) + .set_color(axis_color) + .build(); } - if (case_id_ == "axis_lab") { time_axis_ = Time_Axis::Builder(axes_node_, Orientation::Horizontal) - .set_visible_time_point_count(integer_value(state_, "time_visible_count")) - .set_tick_label_spacing_px(integer_value(state_, "time_label_spacing")) - .set_time_format(string_value(state_, "time_format")) - .set_color({69, 221, 190, 255}) - .build(); + .set_visible_time_point_count(integer_value(state_, "time_visible_count")) + .set_tick_label_spacing_px(integer_value(state_, "time_label_spacing")) + .set_time_format(string_value(state_, "time_format")) + .set_color({69, 221, 190, 255}) + .build(); } } - void build_primary() { if (case_id_ == "axis_lab") { primary_ = numeric_domain_axis_; @@ -1166,96 +1165,114 @@ private: } if (case_id_ == "spectrum" || case_id_ == "selection_overlay") { spectrum_ = Spectrum::Builder(data_node_, - std::static_pointer_cast(numeric_domain_axis_), - value_axis_) - .set_frequency_range({number_value(state_, "frequency_origin"), - number_value(state_, "frequency_target")}) - .set_frequency_point_size(integer_value(state_, "frequency_point_size")) - .set_center_frequency(number_value(state_, "center_frequency")) - .set_sweep_frequency_range({number_value(state_, "sweep_origin"), - number_value(state_, "sweep_target")}) - .build(); + std::static_pointer_cast(numeric_domain_axis_), + value_axis_) + .set_frequency_range({ + number_value(state_, "frequency_origin"), + number_value(state_, "frequency_target") + }) + .set_frequency_point_size(integer_value(state_, "frequency_point_size")) + .set_center_frequency(number_value(state_, "center_frequency")) + .set_sweep_frequency_range({ + number_value(state_, "sweep_origin"), + number_value(state_, "sweep_target") + }) + .build(); primary_ = spectrum_; if (case_id_ == "selection_overlay") { selection_ = Selection_Rectangle_Overlay::Builder( - overlay_node_, numeric_domain_axis_, value_axis_) - .build(); + overlay_node_, numeric_domain_axis_, value_axis_) + .build(); primary_ = selection_; } return; } if (case_id_ == "waterfall") { waterfall_ = Waterfall::Builder(data_node_, - std::static_pointer_cast(numeric_domain_axis_), - time_axis_) - .set_frequency_range({number_value(state_, "frequency_origin"), - number_value(state_, "frequency_target")}) - .set_power_range({number_value(state_, "power_origin"), - number_value(state_, "power_target")}) - .set_frequency_bin_count(integer_value(state_, "frequency_bin_count")) - .set_color_map(gallery_color_map(string_value(state_, "color_map"))) - .build(); + std::static_pointer_cast(numeric_domain_axis_), + time_axis_) + .set_frequency_range({ + number_value(state_, "frequency_origin"), + number_value(state_, "frequency_target") + }) + .set_power_range({ + number_value(state_, "power_origin"), + number_value(state_, "power_target") + }) + .set_frequency_bin_count(integer_value(state_, "frequency_bin_count")) + .set_color_map(gallery_color_map(string_value(state_, "color_map"))) + .build(); primary_ = waterfall_; return; } if (case_id_ == "afterglow") { afterglow_ = Afterglow::Builder(data_node_, - std::static_pointer_cast(numeric_domain_axis_), - value_axis_) - .set_frequency_range({number_value(state_, "frequency_origin"), - number_value(state_, "frequency_target")}) - .set_power_range({number_value(state_, "power_origin"), - number_value(state_, "power_target")}) - .set_frequency_bin_count(integer_value(state_, "frequency_point_size")) - .set_power_bin_count(integer_value(state_, "power_point_size")) - .set_color_map(gallery_color_map(string_value(state_, "color_map"))) - .build(); + std::static_pointer_cast(numeric_domain_axis_), + value_axis_) + .set_frequency_range({ + number_value(state_, "frequency_origin"), + number_value(state_, "frequency_target") + }) + .set_power_range({ + number_value(state_, "power_origin"), + number_value(state_, "power_target") + }) + .set_frequency_bin_count(integer_value(state_, "frequency_point_size")) + .set_power_bin_count(integer_value(state_, "power_point_size")) + .set_color_map(gallery_color_map(string_value(state_, "color_map"))) + .build(); primary_ = afterglow_; return; } if (case_id_ == "sweep_spectrum") { sweep_ = Sweep_Spectrum::Builder(data_node_, numeric_domain_axis_, value_axis_) - .set_frequency_range({number_value(state_, "frequency_origin"), - number_value(state_, "frequency_target")}) - .set_bins_per_block(integer_value(state_, "bins_per_block")) - .set_block_num(integer_value(state_, "block_count")) - .build(); + .set_frequency_range({ + number_value(state_, "frequency_origin"), + number_value(state_, "frequency_target") + }) + .set_bins_per_block(integer_value(state_, "bins_per_block")) + .set_block_num(integer_value(state_, "block_count")) + .build(); primary_ = sweep_; return; } if (case_id_ == "frequency_trace") { trace_ = Frequency_Trace::Builder(data_node_, time_axis_, value_axis_) - .set_pen({color_from_hex(string_value(state_, "trace_pen")), - number_value(state_, "trace_pen_width"), Line_Style::Solid, - Line_Cap::Round, Line_Join::Round}) - .build(); + .set_pen({ + color_from_hex(string_value(state_, "trace_pen")), + number_value(state_, "trace_pen_width"), Line_Style::Solid, + Line_Cap::Round, Line_Join::Round + }) + .build(); primary_ = trace_; return; } if (case_id_ == "constellation") { constellation_ = Constellation_Diagram::Builder(data_node_, numeric_domain_axis_, value_axis_) - .set_i_range({number_value(state_, "i_origin"), - number_value(state_, "i_target")}) - .set_q_range({number_value(state_, "q_origin"), - number_value(state_, "q_target")}) - .set_type(constellation_mode(string_value(state_, "constellation_type"))) - .set_phase_offset_radians(number_value(state_, "phase_offset")) - .build(); + .set_i_range({ + number_value(state_, "i_origin"), + number_value(state_, "i_target") + }) + .set_q_range({ + number_value(state_, "q_origin"), + number_value(state_, "q_target") + }) + .set_type(constellation_mode(string_value(state_, "constellation_type"))) + .set_phase_offset_radians(number_value(state_, "phase_offset")) + .build(); primary_ = constellation_; } } - std::shared_ptr horizontal_axis() const { - return numeric_domain_axis_ ? std::static_pointer_cast(numeric_domain_axis_) - : std::static_pointer_cast(time_axis_); + return numeric_domain_axis_ + ? std::static_pointer_cast(numeric_domain_axis_) + : std::static_pointer_cast(time_axis_); } - std::shared_ptr vertical_axis() const { if (case_id_ == "waterfall") return time_axis_; return value_axis_; } - void apply_layout() { const Size viewport = plot_.viewport_size(); const int left = viewport.width < 440 ? 48 : 62; @@ -1267,7 +1284,6 @@ private: const int x_offset = integer_value(state_, "axis_x_offset"); const int y_offset = integer_value(state_, "axis_y_offset"); const double length_rate = number_value(state_, "axis_length_percent") / 100.0; - if (const auto horizontal = horizontal_axis()) { horizontal->set_x(left + x_offset); horizontal->set_y(top + height + y_offset); @@ -1286,7 +1302,6 @@ private: time_axis_->set_pixel_length(static_cast(width)); } } - void apply_axis_style(const std::shared_ptr& axis) { if (!axis) return; @@ -1295,30 +1310,31 @@ private: axis->set_color(color_from_hex(string_value(state_, "axis_color"))); axis->set_locale({string_value(state_, "decimal_separator").front()}); axis->set_unit_text(string_value(state_, "unit_text")); - axis->set_unit_text_font({number_value(state_, "unit_font_size"), - integer_value(state_, "unit_font_weight"), - bool_value(state_, "unit_font_italic")}); + axis->set_unit_text_font({ + number_value(state_, "unit_font_size"), + integer_value(state_, "unit_font_weight"), + bool_value(state_, "unit_font_italic") + }); axis->set_unit_text_pen({color_from_hex(string_value(state_, "unit_pen_color"))}); axis->set_unit_text_background_brush( {color_from_hex(string_value(state_, "unit_background_color")), Brush_Style::Solid}); axis->set_label_rotation_degrees(integer_value(state_, "label_rotation")); } - void apply_axes() { const bool horizontal = string_value(state_, "axis_orientation") == "Horizontal"; if (const auto main = horizontal_axis()) main->set_orientation(horizontal ? Orientation::Horizontal : Orientation::Vertical); if (const auto other = vertical_axis()) other->set_orientation(horizontal ? Orientation::Vertical : Orientation::Horizontal); - apply_axis_style(horizontal_axis()); apply_axis_style(vertical_axis()); if (case_id_ == "axis_lab") apply_axis_style(time_axis_); - if (numeric_domain_axis_) { - numeric_domain_axis_->set_coord_range({number_value(state_, "coord_origin"), - number_value(state_, "coord_target")}); + numeric_domain_axis_->set_coord_range({ + number_value(state_, "coord_origin"), + number_value(state_, "coord_target") + }); numeric_domain_axis_->set_label_precision(integer_value(state_, "label_precision")); numeric_domain_axis_->set_use_wheel(bool_value(state_, "use_wheel")); numeric_domain_axis_->set_use_drag(bool_value(state_, "use_drag")); @@ -1332,7 +1348,6 @@ private: } apply_layout(); } - void apply_state() { plot_.set_background_color(color_from_hex(string_value(state_, "background_color"))); if (frame_mode_ == Gallery_Frame_Mode::Low_Latency) { @@ -1355,15 +1370,18 @@ private: apply_specific_state(); plot_.notify_model_dirty(); } - void apply_specific_state() { if (spectrum_) { spectrum_->set_frequency_point_size(integer_value(state_, "frequency_point_size")); - spectrum_->set_frequency_range({number_value(state_, "frequency_origin"), - number_value(state_, "frequency_target")}); + spectrum_->set_frequency_range({ + number_value(state_, "frequency_origin"), + number_value(state_, "frequency_target") + }); spectrum_->set_center_frequency(number_value(state_, "center_frequency")); - spectrum_->set_sweep_frequency_range({number_value(state_, "sweep_origin"), - number_value(state_, "sweep_target")}); + spectrum_->set_sweep_frequency_range({ + number_value(state_, "sweep_origin"), + number_value(state_, "sweep_target") + }); spectrum_->set_max_hold_visible(bool_value(state_, "max_hold_visible")); spectrum_->set_min_hold_visible(bool_value(state_, "min_hold_visible")); spectrum_->set_max_marker_visible(bool_value(state_, "max_marker_visible")); @@ -1375,15 +1393,21 @@ private: spectrum_->set_current_brush({color_from_hex(string_value(state_, "current_brush"), 76), Brush_Style::Solid}); spectrum_->set_min_brush({color_from_hex(string_value(state_, "min_brush"), 76), Brush_Style::Solid}); spectrum_->set_max_pen({color_from_hex(string_value(state_, "max_pen")), 1.2}); - spectrum_->set_current_pen({color_from_hex(string_value(state_, "current_pen")), 2.0, - Line_Style::Solid, Line_Cap::Round, Line_Join::Round}); + spectrum_->set_current_pen({ + color_from_hex(string_value(state_, "current_pen")), 2.0, + Line_Style::Solid, Line_Cap::Round, Line_Join::Round + }); spectrum_->set_min_pen({color_from_hex(string_value(state_, "min_pen")), 1.2}); spectrum_->set_selected_marker_pen({color_from_hex(string_value(state_, "selected_marker_pen")), 2.0}); spectrum_->set_marker_pen({color_from_hex(string_value(state_, "marker_pen")), 1.2}); - spectrum_->set_middle_frequency_pen({color_from_hex(string_value(state_, "middle_frequency_pen")), - 1.0, Line_Style::Dash}); - spectrum_->set_sweep_region_brush({color_from_hex(string_value(state_, "sweep_region_brush"), 80), - Brush_Style::Solid}); + spectrum_->set_middle_frequency_pen({ + color_from_hex(string_value(state_, "middle_frequency_pen")), + 1.0, Line_Style::Dash + }); + spectrum_->set_sweep_region_brush({ + color_from_hex(string_value(state_, "sweep_region_brush"), 80), + Brush_Style::Solid + }); spectrum_->set_use_hover_info(bool_value(state_, "hover_enabled")); spectrum_->set_hover_tooltip_font({number_value(state_, "hover_font_size"), 500, false}); spectrum_->set_tooltip_text_pen({color_from_hex(string_value(state_, "hover_text_color"))}); @@ -1393,16 +1417,24 @@ private: if (selection_) { selection_->set_label_font({number_value(state_, "selection_font_size"), 500, false}); selection_->set_label_pen({color_from_hex(string_value(state_, "selection_label_pen"))}); - selection_->set_selection_brush({color_from_hex(string_value(state_, "selection_brush"), 70), - Brush_Style::Solid}); - selection_->set_selection_border_pen({color_from_hex(string_value(state_, "selection_border")), - 1.0, Line_Style::Dash}); + selection_->set_selection_brush({ + color_from_hex(string_value(state_, "selection_brush"), 70), + Brush_Style::Solid + }); + selection_->set_selection_border_pen({ + color_from_hex(string_value(state_, "selection_border")), + 1.0, Line_Style::Dash + }); } if (waterfall_) { - waterfall_->set_frequency_range({number_value(state_, "frequency_origin"), - number_value(state_, "frequency_target")}); - waterfall_->set_power_range({number_value(state_, "power_origin"), - number_value(state_, "power_target")}); + waterfall_->set_frequency_range({ + number_value(state_, "frequency_origin"), + number_value(state_, "frequency_target") + }); + waterfall_->set_power_range({ + number_value(state_, "power_origin"), + number_value(state_, "power_target") + }); waterfall_->set_frequency_bin_count(integer_value(state_, "frequency_bin_count")); waterfall_->set_visible_range_only(bool_value(state_, "visible_range_only")); waterfall_->set_interpolation_mode(image_mode(string_value(state_, "image_interpolation"))); @@ -1413,18 +1445,24 @@ private: {color_from_hex(string_value(state_, "hover_background"), 230), Brush_Style::Solid}); } if (afterglow_) { - afterglow_->set_frequency_range({number_value(state_, "frequency_origin"), - number_value(state_, "frequency_target")}); - afterglow_->set_power_range({number_value(state_, "power_origin"), - number_value(state_, "power_target")}); + afterglow_->set_frequency_range({ + number_value(state_, "frequency_origin"), + number_value(state_, "frequency_target") + }); + afterglow_->set_power_range({ + number_value(state_, "power_origin"), + number_value(state_, "power_target") + }); afterglow_->set_frequency_point_size(integer_value(state_, "frequency_point_size")); afterglow_->set_power_point_size(integer_value(state_, "power_point_size")); afterglow_->set_interpolate(bool_value(state_, "interpolate_power")); afterglow_->set_attenuation_rate(number_value(state_, "attenuation_rate")); } if (sweep_) { - sweep_->set_frequency_range({number_value(state_, "frequency_origin"), - number_value(state_, "frequency_target")}); + sweep_->set_frequency_range({ + number_value(state_, "frequency_origin"), + number_value(state_, "frequency_target") + }); sweep_->set_bins_per_block(integer_value(state_, "bins_per_block")); sweep_->set_block_count(integer_value(state_, "block_count")); sweep_->set_pen({color_from_hex(string_value(state_, "sweep_pen")), 1.8}); @@ -1433,8 +1471,10 @@ private: sweep_->set_interpolation_mode(line_mode(string_value(state_, "line_interpolation"))); } if (trace_ && value_axis_) - value_axis_->set_coord_range({number_value(state_, "trace_value_min"), - number_value(state_, "trace_value_max")}); + value_axis_->set_coord_range({ + number_value(state_, "trace_value_min"), + number_value(state_, "trace_value_max") + }); if (constellation_) { constellation_->set_i_range({number_value(state_, "i_origin"), number_value(state_, "i_target")}); constellation_->set_q_range({number_value(state_, "q_origin"), number_value(state_, "q_target")}); @@ -1442,14 +1482,17 @@ private: constellation_->set_anchor_color(color_from_hex(string_value(state_, "anchor_color"))); constellation_->set_point_lifetime_ms(integer_value(state_, "point_lifetime_ms")); if (numeric_domain_axis_) - numeric_domain_axis_->set_coord_range({number_value(state_, "i_origin"), - number_value(state_, "i_target")}); + numeric_domain_axis_->set_coord_range({ + number_value(state_, "i_origin"), + number_value(state_, "i_target") + }); if (value_axis_) - value_axis_->set_coord_range({number_value(state_, "q_origin"), - number_value(state_, "q_target")}); + value_axis_->set_coord_range({ + number_value(state_, "q_origin"), + number_value(state_, "q_target") + }); } } - std::vector spectrum_values(int count, Range power_range = {-120.0, -20.0}) const { count = std::max(count, 2); std::vector values(static_cast(count)); @@ -1457,42 +1500,37 @@ private: for (int index = 0; index < count; ++index) { const double x = static_cast(index) / (count - 1); const double noise = std::sin(index * 11.71 + time * 2.9) * - std::sin(index * 0.19 + time * 0.7) * 4.0; + std::sin(index * 0.19 + time * 0.7) * 4.0; const double signal = 58.0 * gaussian(x, 0.32 + std::sin(time) * 0.04, 0.035) + - 45.0 * gaussian(x, 0.57, 0.07) + - 32.0 * gaussian(x, 0.78, 0.018); + 45.0 * gaussian(x, 0.57, 0.07) + + 32.0 * gaussian(x, 0.78, 0.018); values[static_cast(index)] = - std::clamp(-112.0 + noise + signal, std::min(power_range.origin, power_range.target), - std::max(power_range.origin, power_range.target)); + std::clamp(-112.0 + noise + signal, std::min(power_range.origin, power_range.target), + std::max(power_range.origin, power_range.target)); } return values; } - void push_spectrum_samples() { spectrum_->update_samples(spectrum_values(spectrum_->frequency_point_size())); } - void push_waterfall_row() { waterfall_->append_row(current_time_of_day(), spectrum_values(waterfall_->frequency_bin_count(), waterfall_->power_range())); } - void push_afterglow_spectrum() { afterglow_->append_spectrum(spectrum_values(afterglow_->frequency_point_size(), afterglow_->power_range())); } - void push_sweep_block() { const int count = sweep_->bins_per_block(); std::vector block(static_cast(std::max(count, 1))); for (int index = 0; index < count; ++index) { const double x = static_cast(index) / std::max(1, count - 1); block[static_cast(index)] = -104.0 + 68.0 * gaussian(x, 0.5, 0.16) + - std::sin(frame_index_ * 0.2 + index) * 4.0; + std::sin(frame_index_ * 0.2 + index) * 4.0; } sweep_->append_block(block); } - void push_trace_sample() { const double lower = number_value(state_, "trace_value_min"); const double upper = number_value(state_, "trace_value_max"); @@ -1500,7 +1538,6 @@ private: const double amplitude = std::abs(upper - lower) * 0.42; trace_->append_sample(current_time_of_day(), center + amplitude * std::sin(frame_index_ * 0.12)); } - void push_constellation_points() { const std::string& mode = string_value(state_, "constellation_type"); const int count = mode == "PSK4" ? 4 : mode == "PSK16" ? 16 : 8; @@ -1509,11 +1546,12 @@ private: const int anchor = static_cast((frame_index_ * 7 + index * 5) % count); const double angle = phase + 2.0 * std::numbers::pi * anchor / count; const double noise = std::sin(frame_index_ * 0.31 + index * 1.73) * 0.055; - constellation_->append_point({std::cos(angle) + noise, - std::sin(angle) - noise * 0.7}); + constellation_->append_point({ + std::cos(angle) + noise, + std::sin(angle) - noise * 0.7 + }); } } - void update_model() { if (spectrum_) push_spectrum_samples(); @@ -1531,12 +1569,10 @@ private: time_axis_->append_time(current_time_of_day()); ++frame_index_; } - static std::string invalid_argument(bool& recognized) { recognized = false; return {}; } - std::uint64_t session_id_{}; std::string case_id_; Gallery_State state_; @@ -1596,29 +1632,26 @@ private: bool rendered_since_last_pixel_{}; std::string last_action_result_; }; - struct Gallery_Plot_Session::Impl { explicit Impl(bool enable_automatic_low_latency) : automatic_low_latency(enable_automatic_low_latency), session_id(next_session_id()) {} - ~Impl() { render_worker.request_stop(); scheduler_condition.notify_all(); } - static std::uint64_t next_session_id() noexcept { static std::atomic next{1}; return next.fetch_add(1, std::memory_order_relaxed); } - void ensure_render_worker() { if (!automatic_low_latency || render_worker.joinable()) return; render_worker = std::jthread( - [this](std::stop_token stop) { run_automatic_renderer(stop); }); + [this](std::stop_token stop) { + run_automatic_renderer(stop); + }); } - bool update_client_metrics(std::string_view message) { if (!scene) return false; @@ -1661,7 +1694,6 @@ struct Gallery_Plot_Session::Impl { finite_metric("last_pixel_change_age_ms")); return true; } - [[nodiscard]] std::unique_lock acquire_foreground_lock() { foreground_waiters.fetch_add(1, std::memory_order_release); scheduler_condition.notify_all(); @@ -1670,7 +1702,6 @@ struct Gallery_Plot_Session::Impl { scheduler_condition.notify_all(); return lock; } - void run_automatic_renderer(std::stop_token stop) { using Clock = std::chrono::steady_clock; std::unique_lock lock(mutex); @@ -1702,7 +1733,7 @@ struct Gallery_Plot_Session::Impl { if (now < coarse_deadline) { scheduler_condition.wait_until(lock, coarse_deadline, [this, &stop, revision, active_generation] { return stop.stop_requested() || scheduler_revision != revision || scene_generation != active_generation || - foreground_waiters.load(std::memory_order_acquire) != 0 || !scene || !scene->can_render_automatically(); + foreground_waiters.load(std::memory_order_acquire) != 0 || !scene || !scene->can_render_automatically(); }); continue; } @@ -1717,23 +1748,23 @@ struct Gallery_Plot_Session::Impl { last_render_started = started; } } - static bool affects_render_schedule(const Web_Event& event) { return std::visit( [](const auto& value) { using T = std::decay_t; if constexpr (std::is_same_v) { return false; - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { return value.kind != Gallery_Request_Kind::Catalog && - value.kind != Gallery_Request_Kind::Observe; - } else { + value.kind != Gallery_Request_Kind::Observe; + } + else { return true; } }, event); } - std::unique_ptr scene; std::mutex mutex; std::condition_variable scheduler_condition; @@ -1743,15 +1774,16 @@ struct Gallery_Plot_Session::Impl { std::uint64_t session_id{}; std::atomic foreground_waiters{}; std::jthread render_worker; - std::optional handle_gallery(const Gallery_Request& request) { if (request.kind == Gallery_Request_Kind::Catalog) return Web_Response{Web_Response_Type::Json, Gallery_Protocol::catalog_json()}; if (request.kind == Gallery_Request_Kind::Open) { const auto open = Gallery_Protocol::open_request(request.message); if (!open) - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::error_json("未知的 gallery case 或 frame_mode", "case")}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::error_json("未知的 gallery case 或 frame_mode", "case") + }; scene = std::make_unique( session_id, open->case_id, Gallery_Protocol::default_state(open->case_id, open->frame_mode), @@ -1759,23 +1791,29 @@ struct Gallery_Plot_Session::Impl { ++scene_generation; if (scene->frame_mode() == Gallery_Frame_Mode::Low_Latency) ensure_render_worker(); - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::case_json(scene->case_id(), scene->state(), - scene->telemetry_json(), - "Core2/Kernel 独立画布已创建", - scene->frame_mode())}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::case_json(scene->case_id(), scene->state(), + scene->telemetry_json(), + "render_2D/Kernel 独立画布已创建", + scene->frame_mode()) + }; } if (!scene) - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::error_json("请先发送 gallery_open")}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::error_json("请先发送 gallery_open") + }; if (request.kind == Gallery_Request_Kind::Observe) { if (update_client_metrics(request.message)) { ++scheduler_revision; scheduler_condition.notify_all(); } - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::observer_json( - scene->case_id(), scene->frame_mode(), scene->telemetry_json())}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::observer_json( + scene->case_id(), scene->frame_mode(), scene->telemetry_json()) + }; } if (request.kind == Gallery_Request_Kind::Patch) { auto patch = Gallery_Protocol::apply_patch(scene->case_id(), scene->state(), @@ -1790,24 +1828,31 @@ struct Gallery_Plot_Session::Impl { std::move(*patch.candidate), mode, automatic_low_latency); ++scene_generation; - } else { + } + else { scene->set_state(std::move(*patch.candidate)); } - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::case_json(scene->case_id(), scene->state(), - scene->telemetry_json(), - "控件 API 已由后端应用", - scene->frame_mode())}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::case_json(scene->case_id(), scene->state(), + scene->telemetry_json(), + "控件 API 已由后端应用", + scene->frame_mode()) + }; } const auto action = Gallery_Protocol::action_request(request.message); if (!action) - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::error_json("gallery_action 格式无效")}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::error_json("gallery_action 格式无效") + }; if (!Gallery_Protocol::action_available(scene->case_id(), scene->frame_mode(), action->id)) - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::error_json( - "动作不属于当前画布或帧策略", "action")}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::error_json( + "动作不属于当前画布或帧策略", "action") + }; if (action->id == "reset") { const std::string id = scene->case_id(); const auto mode = scene->frame_mode(); @@ -1815,10 +1860,12 @@ struct Gallery_Plot_Session::Impl { session_id, id, Gallery_Protocol::default_state(id, mode), mode, automatic_low_latency); ++scene_generation; - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::case_json(id, scene->state(), - scene->telemetry_json(), - "本图已恢复后端默认值", mode)}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::case_json(id, scene->state(), + scene->telemetry_json(), + "本图已恢复后端默认值", mode) + }; } if (action->id == "rebuild_renderable") { const std::string id = scene->case_id(); @@ -1828,24 +1875,29 @@ struct Gallery_Plot_Session::Impl { scene = std::make_unique(session_id, id, std::move(state), mode, automatic_low_latency); ++scene_generation; - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::case_json(id, scene->state(), - scene->telemetry_json(), - "Renderable 已移除并通过 Builder 重建", mode)}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::case_json(id, scene->state(), + scene->telemetry_json(), + "Renderable 已移除并通过 Builder 重建", mode) + }; } bool recognized{}; const std::string notice = scene->action(*action, recognized); if (!recognized) - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::error_json("动作不属于当前画布或参数无效", - "action")}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::error_json("动作不属于当前画布或参数无效", + "action") + }; scene->record_action_notice_if_empty(notice); - return Web_Response{Web_Response_Type::Json, - Gallery_Protocol::case_json(scene->case_id(), scene->state(), - scene->telemetry_json(), notice, - scene->frame_mode())}; + return Web_Response{ + Web_Response_Type::Json, + Gallery_Protocol::case_json(scene->case_id(), scene->state(), + scene->telemetry_json(), notice, + scene->frame_mode()) + }; } - std::optional handle_frame_request() { const auto request_started = std::chrono::steady_clock::now(); std::optional copy; @@ -1859,7 +1911,6 @@ struct Gallery_Plot_Session::Impl { } if (!copy) return std::nullopt; - const auto encode_started = std::chrono::steady_clock::now(); std::string pixels = encode_pixel_frame(copy->image, copy->background); const auto encode_finished = std::chrono::steady_clock::now(); @@ -1869,11 +1920,12 @@ struct Gallery_Plot_Session::Impl { scene->record_pixel_response(request_started, encode_started, encode_finished, pixels.size()); } - return pixels.empty() ? std::nullopt : - std::optional(Web_Response{ - Web_Response_Type::Pixels, std::move(pixels)}); + return pixels.empty() + ? std::nullopt + : std::optional(Web_Response{ + Web_Response_Type::Pixels, std::move(pixels) + }); } - std::optional handle(const Web_Event& event) { if (std::holds_alternative(event)) return handle_frame_request(); @@ -1886,15 +1938,19 @@ struct Gallery_Plot_Session::Impl { using T = std::decay_t; if constexpr (std::is_same_v) { return handle_gallery(value); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { return std::nullopt; - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { if (scene) scene->resize(value.size); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { if (scene) scene->dispatch(value); - } else if constexpr (std::is_base_of_v) { + } + else if constexpr (std::is_base_of_v) { if (scene) scene->dispatch(value); } @@ -1909,15 +1965,11 @@ struct Gallery_Plot_Session::Impl { return response; } }; - Gallery_Plot_Session::Gallery_Plot_Session() : Gallery_Plot_Session(false) {} - Gallery_Plot_Session::Gallery_Plot_Session(bool automatic_low_latency) : impl_(std::make_unique(automatic_low_latency)) {} Gallery_Plot_Session::~Gallery_Plot_Session() = default; - std::optional Gallery_Plot_Session::handle(const Web_Event& event) { return impl_->handle(event); } - } // namespace renderive::web diff --git a/web_server/Pixel_Frame.h b/web_server/Pixel_Frame.h index 25d5669..e8f4c30 100644 --- a/web_server/Pixel_Frame.h +++ b/web_server/Pixel_Frame.h @@ -1,30 +1,21 @@ #pragma once - -#include "Core2/base/Types.h" - +#include "render_2D/base/Types.h" #include #include #include - namespace renderive::web { - inline constexpr std::size_t pixel_frame_header_size = 16; - struct Pixel_Frame_Copy { int width{}; int height{}; std::vector pixels; - [[nodiscard]] bool empty() const noexcept { return width <= 0 || height <= 0 || pixels.empty(); } }; - [[nodiscard]] Pixel_Frame_Copy copy_pixel_frame(Image_View image); - [[nodiscard]] std::string encode_pixel_frame(Image_View image, Color background = Color::black()); [[nodiscard]] std::string encode_pixel_frame(const Pixel_Frame_Copy& image, Color background = Color::black()); - } // namespace renderive::web diff --git a/web_server/Web_Event.h b/web_server/Web_Event.h index 194c13e..8c3dde8 100644 --- a/web_server/Web_Event.h +++ b/web_server/Web_Event.h @@ -1,53 +1,37 @@ #pragma once - -#include "Core2/event/Event.h" - +#include "render_2D/event/Event.h" #include #include - namespace renderive::web { - struct Frame_Request {}; - struct Viewport_Resize { Size size; }; - enum class Demo_Mode : std::uint8_t { Am, Fm, Usb, Lsb }; - struct Set_Demo_Mode { Demo_Mode mode = Demo_Mode::Fm; }; - struct Set_Center_Frequency { double megahertz = 102.5; }; - struct Set_Bandwidth { double kilohertz = 1200.0; }; - struct Set_Gain { double decibels{}; }; - struct Set_Max_Hold { bool enabled{}; }; - struct Set_Smoothing { bool enabled{}; }; - struct Clear_Selection {}; - enum class Gallery_Request_Kind : std::uint8_t { Catalog, Open, Patch, Action, Observe }; - struct Gallery_Request { Gallery_Request_Kind kind = Gallery_Request_Kind::Catalog; std::string message; }; - using Web_Event = std::variant; - } // namespace renderive::web diff --git a/web_server/Web_Plot_Session.cpp b/web_server/Web_Plot_Session.cpp index e4528f9..c6852fb 100644 --- a/web_server/Web_Plot_Session.cpp +++ b/web_server/Web_Plot_Session.cpp @@ -1,8 +1,6 @@ #include "Web_Plot_Session.h" - #include "Pixel_Frame.h" -#include "Core2/export.h" - +#include "render_2D/export.h" #include #include #include @@ -11,19 +9,18 @@ #include #include #include - namespace renderive::web { namespace { - Color blend(Color first, Color second, double amount) { const auto channel = [amount](std::uint8_t a, std::uint8_t b) { return static_cast(std::clamp( std::lround(a + (b - a) * amount), 0L, 255L)); }; - return {channel(first.r, second.r), channel(first.g, second.g), - channel(first.b, second.b), channel(first.a, second.a)}; + return { + channel(first.r, second.r), channel(first.g, second.g), + channel(first.b, second.b), channel(first.a, second.a) + }; } - Color_Map radio_color_map() { constexpr Color stops[] = { {3, 7, 18, 255}, {16, 52, 105, 255}, {23, 163, 184, 255}, @@ -39,22 +36,18 @@ Color_Map radio_color_map() { } return Color_Map(std::move(colors)); } - Time_Of_Day current_time_of_day() { constexpr std::int64_t day_ms = 24LL * 60LL * 60LL * 1000LL; const auto now = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()) - .count(); + std::chrono::system_clock::now().time_since_epoch()) + .count(); return {now % day_ms}; } - double gaussian(double x, double center, double width) { const double normalized = (x - center) / width; return std::exp(-0.5 * normalized * normalized); } - } // namespace - struct Web_Plot_Session::Impl { Plot_Core plot; std::shared_ptr spectrum_frequency_axis; @@ -68,97 +61,95 @@ struct Web_Plot_Session::Impl { double gain_db = 8.0; std::uint64_t frame_index{}; std::mutex mutex; - Impl() { plot.init(); plot.set_background_color({3, 7, 18, 255}); plot.set_max_render_fps(30.0); plot.set_viewport_size({960, 600}); - const auto root = plot.root_renderable(); const auto data = plot.create_renderable_node(root, "Web_Data"); const auto axes = plot.create_renderable_node(root, "Web_Axes"); const auto overlay = plot.create_renderable_node(root, "Web_Overlay"); axes->set_cache_mode(Renderable_Cache_Mode::Local_Pixel); - constexpr Color axis_color{93, 116, 151, 255}; const Range initial_frequency{101'300'000.0, 103'700'000.0}; spectrum_frequency_axis = - Frequency_Axis::Builder(axes, Orientation::Horizontal) - .set_coord_range(initial_frequency) - .set_label_precision(2) - .set_tick_length(8) - .set_sub_tick_length(4) - .set_color(axis_color) - .set_use_wheel(true) - .set_use_drag(true) - .build(); + Frequency_Axis::Builder(axes, Orientation::Horizontal) + .set_coord_range(initial_frequency) + .set_label_precision(2) + .set_tick_length(8) + .set_sub_tick_length(4) + .set_color(axis_color) + .set_use_wheel(true) + .set_use_drag(true) + .build(); spectrum_power_axis = - Axis::Builder(axes, Orientation::Vertical) - .set_coord_range({-20.0, -120.0}) - .set_label_precision(0) - .set_tick_length(-8) - .set_sub_tick_length(-4) - .set_color(axis_color) - .set_unit_text("dBm") - .build(); + Axis::Builder(axes, Orientation::Vertical) + .set_coord_range({-20.0, -120.0}) + .set_label_precision(0) + .set_tick_length(-8) + .set_sub_tick_length(-4) + .set_color(axis_color) + .set_unit_text("dBm") + .build(); waterfall_frequency_axis = - Frequency_Axis::Builder(axes, Orientation::Horizontal) - .set_coord_range(initial_frequency) - .set_label_precision(2) - .set_tick_length(8) - .set_sub_tick_length(4) - .set_color(axis_color) - .set_use_wheel(true) - .set_use_drag(true) - .build(); + Frequency_Axis::Builder(axes, Orientation::Horizontal) + .set_coord_range(initial_frequency) + .set_label_precision(2) + .set_tick_length(8) + .set_sub_tick_length(4) + .set_color(axis_color) + .set_use_wheel(true) + .set_use_drag(true) + .build(); waterfall_time_axis = - Time_Axis::Builder(axes, Orientation::Vertical) - .set_visible_time_point_count(72) - .set_tick_label_spacing_px(34) - .set_time_format("mm:ss") - .set_tick_length(-8) - .set_sub_tick_length(-4) - .set_color(axis_color) - .build(); - + Time_Axis::Builder(axes, Orientation::Vertical) + .set_visible_time_point_count(72) + .set_tick_label_spacing_px(34) + .set_time_format("mm:ss") + .set_tick_length(-8) + .set_sub_tick_length(-4) + .set_color(axis_color) + .build(); spectrum = Spectrum::Builder(data, spectrum_frequency_axis, spectrum_power_axis) - .set_frequency_range(initial_frequency) - .set_frequency_point_size(768) - .set_center_frequency(102'500'000.0) - .set_sweep_frequency_range({102'200'000.0, 102'800'000.0}) - .set_max_marker_visible(true) - .set_sweep_region_visible(true) - .set_interpolation_mode(Line_Interpolation_Mode::Cubic_Value) - .build(); - spectrum->set_current_pen({Color{57, 224, 177, 255}, 2.0, Line_Style::Solid, - Line_Cap::Round, Line_Join::Round}); + .set_frequency_range(initial_frequency) + .set_frequency_point_size(768) + .set_center_frequency(102'500'000.0) + .set_sweep_frequency_range({102'200'000.0, 102'800'000.0}) + .set_max_marker_visible(true) + .set_sweep_region_visible(true) + .set_interpolation_mode(Line_Interpolation_Mode::Cubic_Value) + .build(); + spectrum->set_current_pen({ + Color{57, 224, 177, 255}, 2.0, Line_Style::Solid, + Line_Cap::Round, Line_Join::Round + }); spectrum->set_current_brush({Color{31, 174, 145, 32}, Brush_Style::Solid}); spectrum->set_max_pen({Color{250, 204, 21, 210}, 1.0}); - spectrum->set_middle_frequency_pen({Color{56, 189, 248, 220}, 1.0, - Line_Style::Dash}); - + spectrum->set_middle_frequency_pen({ + Color{56, 189, 248, 220}, 1.0, + Line_Style::Dash + }); waterfall = Waterfall::Builder(data, waterfall_frequency_axis, waterfall_time_axis) - .set_frequency_range(initial_frequency) - .set_power_range({-120.0, -20.0}) - .set_frequency_bin_count(768) - .set_interpolation_mode(Image_Interpolation_Mode::Bilinear) - .set_color_map(radio_color_map()) - .build(); + .set_frequency_range(initial_frequency) + .set_power_range({-120.0, -20.0}) + .set_frequency_bin_count(768) + .set_interpolation_mode(Image_Interpolation_Mode::Bilinear) + .set_color_map(radio_color_map()) + .build(); selection = Selection_Rectangle_Overlay::Builder( overlay, spectrum_frequency_axis, spectrum_power_axis) - .set_rect_brush({Color{56, 189, 248, 36}, Brush_Style::Solid}) - .set_border_pen({Color{125, 211, 252, 230}, 1.0, Line_Style::Dash}) - .build(); - + .set_rect_brush({Color{56, 189, 248, 36}, Brush_Style::Solid}) + .set_border_pen({Color{125, 211, 252, 230}, 1.0, Line_Style::Dash}) + .build(); apply_layout(plot.viewport_size()); plot.activate_view(); update_model(); (void)plot.render_frame(true); } - - ~Impl() { plot.deactivate_view(); } - + ~Impl() { + plot.deactivate_view(); + } void apply_layout(Size viewport) { const int left = viewport.width < 620 ? 54 : 72; const int right = viewport.width < 620 ? 44 : 70; @@ -170,7 +161,6 @@ struct Web_Plot_Session::Impl { const int spectrum_height = std::max(1, available_height * 43 / 100); const int waterfall_y = top + spectrum_height + gap; const int waterfall_height = std::max(1, viewport.height - waterfall_y - bottom); - spectrum_frequency_axis->set_x(left); spectrum_frequency_axis->set_y(top + spectrum_height); spectrum_frequency_axis->set_pixel_length(static_cast(content_width)); @@ -184,7 +174,6 @@ struct Web_Plot_Session::Impl { waterfall_time_axis->set_y(waterfall_y); waterfall_time_axis->set_pixel_length(static_cast(waterfall_height)); } - void update_model() { constexpr int sample_count = 768; const double time = static_cast(frame_index) * 0.075; @@ -192,28 +181,28 @@ struct Web_Plot_Session::Impl { for (int index = 0; index < sample_count; ++index) { const double x = static_cast(index) / (sample_count - 1); const double noise = std::sin(index * 12.9898 + frame_index * 0.371) * - std::sin(index * 0.137 + frame_index * 0.071); + std::sin(index * 0.137 + frame_index * 0.071); double signal{}; switch (mode) { case Demo_Mode::Am: signal = 66.0 * gaussian(x, 0.5, 0.008) + - 39.0 * gaussian(x, 0.42, 0.018) + - 39.0 * gaussian(x, 0.58, 0.018); + 39.0 * gaussian(x, 0.42, 0.018) + + 39.0 * gaussian(x, 0.58, 0.018); break; case Demo_Mode::Fm: { const double moving = 0.5 + std::sin(time) * 0.035; signal = 58.0 * gaussian(x, moving, 0.055) + - 25.0 * gaussian(x, moving - 0.11, 0.023) + - 25.0 * gaussian(x, moving + 0.11, 0.023); + 25.0 * gaussian(x, moving - 0.11, 0.023) + + 25.0 * gaussian(x, moving + 0.11, 0.023); break; } case Demo_Mode::Usb: signal = 61.0 * gaussian(x, 0.57, 0.045) + - 28.0 * gaussian(x, 0.68, 0.025); + 28.0 * gaussian(x, 0.68, 0.025); break; case Demo_Mode::Lsb: signal = 61.0 * gaussian(x, 0.43, 0.045) + - 28.0 * gaussian(x, 0.32, 0.025); + 28.0 * gaussian(x, 0.32, 0.025); break; } samples[index] = std::clamp(-110.0 + noise * 4.5 + signal + gain_db, @@ -224,7 +213,6 @@ struct Web_Plot_Session::Impl { waterfall->append_row(current_time_of_day(), samples); ++frame_index; } - void set_center_frequency(double megahertz) { const double center = megahertz * 1'000'000.0; const double bandwidth = spectrum_frequency_axis->coord_range().size(); @@ -233,11 +221,12 @@ struct Web_Plot_Session::Impl { waterfall_frequency_axis->set_coord_range(range); spectrum->set_frequency_range(range); spectrum->set_center_frequency(center); - spectrum->set_sweep_frequency_range({center - bandwidth * 0.125, - center + bandwidth * 0.125}); + spectrum->set_sweep_frequency_range({ + center - bandwidth * 0.125, + center + bandwidth * 0.125 + }); waterfall->set_frequency_range(range); } - void set_bandwidth(double kilohertz) { const double center = spectrum->center_frequency(); const double bandwidth = kilohertz * 1000.0; @@ -245,11 +234,12 @@ struct Web_Plot_Session::Impl { spectrum_frequency_axis->set_coord_range(range); waterfall_frequency_axis->set_coord_range(range); spectrum->set_frequency_range(range); - spectrum->set_sweep_frequency_range({center - bandwidth * 0.125, - center + bandwidth * 0.125}); + spectrum->set_sweep_frequency_range({ + center - bandwidth * 0.125, + center + bandwidth * 0.125 + }); waterfall->set_frequency_range(range); } - std::optional render_pixels() { if (!plot.view_active()) return std::nullopt; @@ -263,7 +253,6 @@ struct Web_Plot_Session::Impl { }); return pixels.empty() ? std::nullopt : std::optional(std::move(pixels)); } - std::optional handle(const Web_Event& event) { std::lock_guard lock(mutex); return std::visit( @@ -273,7 +262,8 @@ struct Web_Plot_Session::Impl { auto pixels = render_pixels(); if (pixels) return Web_Response{Web_Response_Type::Pixels, std::move(*pixels)}; - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { const Size previous = plot.viewport_size(); plot.set_viewport_size(value.size); apply_layout(value.size); @@ -281,34 +271,45 @@ struct Web_Plot_Session::Impl { resized.old_size = previous; resized.new_size = value.size; plot.dispatch_event(resized); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { if (value.type == Event_Type::Show) plot.activate_view(); else if (value.type == Event_Type::Hide) plot.deactivate_view(); plot.dispatch_event(value); - } else if constexpr (std::is_base_of_v) { + } + else if constexpr (std::is_base_of_v) { plot.dispatch_event(value); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { mode = value.mode; plot.notify_model_dirty(); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { set_center_frequency(value.megahertz); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { set_bandwidth(value.kilohertz); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { gain_db = value.decibels; plot.notify_model_dirty(); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { spectrum->set_max_hold_visible(value.enabled); - } else if constexpr (std::is_same_v) { + } + else if constexpr (std::is_same_v) { spectrum->set_interpolation_mode( - value.enabled ? Line_Interpolation_Mode::Cubic_Value - : Line_Interpolation_Mode::Nearest_Sample); + value.enabled + ? Line_Interpolation_Mode::Cubic_Value + : Line_Interpolation_Mode::Nearest_Sample); waterfall->set_interpolation_mode( - value.enabled ? Image_Interpolation_Mode::Bilinear - : Image_Interpolation_Mode::Nearest); - } else if constexpr (std::is_same_v) { + value.enabled + ? Image_Interpolation_Mode::Bilinear + : Image_Interpolation_Mode::Nearest); + } + else if constexpr (std::is_same_v) { selection->clear_selected_regions(); } return std::nullopt; @@ -316,12 +317,9 @@ struct Web_Plot_Session::Impl { event); } }; - Web_Plot_Session::Web_Plot_Session() : impl_(std::make_unique()) {} Web_Plot_Session::~Web_Plot_Session() = default; - std::optional Web_Plot_Session::handle(const Web_Event& event) { return impl_->handle(event); } - } // namespace renderive::web diff --git a/webapp/app.js b/webapp/app.js deleted file mode 100644 index 8474959..0000000 --- a/webapp/app.js +++ /dev/null @@ -1,352 +0,0 @@ -"use strict"; - -const elements = { - canvas: document.getElementById("render-canvas"), - stage: document.getElementById("canvas-stage"), - overlay: document.getElementById("stream-overlay"), - overlayTitle: document.getElementById("overlay-title"), - overlayDetail: document.getElementById("overlay-detail"), - connectionDot: document.getElementById("connection-dot"), - connectionLabel: document.getElementById("connection-label"), - connectionEndpoint: document.getElementById("connection-endpoint"), - reconnect: document.getElementById("reconnect-button"), - fps: document.getElementById("fps-value"), - latency: document.getElementById("latency-value"), - resolution: document.getElementById("resolution-value"), - throughput: document.getElementById("throughput-value"), - frameCounter: document.getElementById("frame-counter"), - frequency: document.getElementById("frequency-value"), - tuneDown: document.getElementById("tune-down"), - tuneUp: document.getElementById("tune-up"), - modeLabel: document.getElementById("mode-label"), - modeButtons: [...document.querySelectorAll(".mode-button")], - bandwidth: document.getElementById("bandwidth"), - bandwidthValue: document.getElementById("bandwidth-value"), - gain: document.getElementById("gain"), - gainValue: document.getElementById("gain-value"), - maxHold: document.getElementById("max-hold"), - smoothing: document.getElementById("smoothing"), - clearSelection: document.getElementById("clear-selection"), - pause: document.getElementById("pause-button"), - pauseLabel: document.getElementById("pause-label") -}; - -const state = { - socket: null, - reconnectTimer: 0, - frameTimeout: 0, - framePending: false, - requestStarted: 0, - lastFrameAt: 0, - smoothedFps: 0, - frameCount: 0, - paused: false, - requestedWidth: 960, - requestedHeight: 600 -}; - -const context = elements.canvas.getContext("2d", {alpha: false, desynchronized: true}); -const query = new URLSearchParams(window.location.search); -const endpoint = query.get("ws") || "ws://127.0.0.1:8848/renderive"; -elements.connectionEndpoint.textContent = endpoint; - -function setConnectionState(kind, title, detail) { - elements.connectionDot.classList.remove("online", "offline"); - if (kind) - elements.connectionDot.classList.add(kind); - elements.connectionLabel.textContent = title; - elements.overlayTitle.textContent = title; - elements.overlayDetail.textContent = detail; - if (kind !== "online") - elements.overlay.classList.remove("hidden"); -} - -function sendEvent(type, payload = {}) { - if (!state.socket || state.socket.readyState !== WebSocket.OPEN) - return false; - state.socket.send(JSON.stringify({category: "event", type, ...payload})); - return true; -} - -function currentFrequency() { - return Number(elements.frequency.dataset.value); -} - -function setFrequency(value, notify = true) { - const frequency = Math.max(1, Math.min(6000, Number(value.toFixed(3)))); - elements.frequency.dataset.value = String(frequency); - elements.frequency.textContent = frequency.toFixed(3); - if (notify) - sendEvent("control", {control: "center_frequency_mhz", value: frequency}); -} - -function activeMode() { - return elements.modeButtons.find(button => button.classList.contains("active"))?.dataset.mode || "FM"; -} - -function buttonEnabled(button) { - return button.getAttribute("aria-pressed") === "true"; -} - -function setToggle(button, enabled, notify = true) { - button.setAttribute("aria-pressed", String(enabled)); - button.classList.toggle("active", enabled); - if (!notify) - return; - const control = button === elements.maxHold ? "max_hold" : "smoothing"; - sendEvent("control", {control, value: enabled}); -} - -function sendControlSnapshot() { - sendEvent("control", {control: "mode", value: activeMode()}); - sendEvent("control", {control: "center_frequency_mhz", value: currentFrequency()}); - sendEvent("control", {control: "bandwidth_khz", value: Number(elements.bandwidth.value)}); - sendEvent("control", {control: "gain_db", value: Number(elements.gain.value)}); - sendEvent("control", {control: "max_hold", value: buttonEnabled(elements.maxHold)}); - sendEvent("control", {control: "smoothing", value: buttonEnabled(elements.smoothing)}); -} - -function syncViewport() { - const bounds = elements.stage.getBoundingClientRect(); - const width = Math.max(240, Math.min(1920, Math.round(bounds.width))); - const height = Math.max(180, Math.min(1200, Math.round(bounds.height))); - if (width === state.requestedWidth && height === state.requestedHeight) - return; - state.requestedWidth = width; - state.requestedHeight = height; - elements.canvas.width = width; - elements.canvas.height = height; - sendEvent("resize", {width, height}); -} - -function streamActive() { - return !state.paused && !document.hidden; -} - -function clearFrameRequest() { - window.clearTimeout(state.frameTimeout); - state.frameTimeout = 0; - state.framePending = false; -} - -function requestFrame() { - if (!streamActive() || state.framePending) - return; - if (!sendEvent("frame")) - return; - state.requestStarted = performance.now(); - state.framePending = true; - window.clearTimeout(state.frameTimeout); - state.frameTimeout = window.setTimeout(() => { - state.frameTimeout = 0; - if (!state.framePending) - return; - state.framePending = false; - if (!streamActive() || state.socket?.readyState !== WebSocket.OPEN) - return; - sendEvent("show"); - requestFrame(); - }, 2000); -} - -function syncStreamActivity() { - const active = streamActive(); - if (!active) { - state.lastFrameAt = 0; - state.smoothedFps = 0; - elements.fps.textContent = "0.0"; - } - if (!state.socket || state.socket.readyState !== WebSocket.OPEN) - return; - sendEvent(active ? "show" : "hide"); - if (active) - requestFrame(); -} - -function drawPixelFrame(buffer) { - clearFrameRequest(); - if (!(buffer instanceof ArrayBuffer) || buffer.byteLength < 16) - throw new Error("像素帧长度无效"); - const bytes = new Uint8Array(buffer); - if (bytes[0] !== 82 || bytes[1] !== 86 || bytes[2] !== 80 || bytes[3] !== 49) - throw new Error("像素帧标识无效"); - const view = new DataView(buffer); - const width = view.getUint32(4, true); - const height = view.getUint32(8, true); - const stride = view.getUint32(12, true); - if (!width || !height || stride !== width * 4 || buffer.byteLength !== 16 + stride * height) - throw new Error("像素帧尺寸无效"); - - if (elements.canvas.width !== width || elements.canvas.height !== height) { - elements.canvas.width = width; - elements.canvas.height = height; - } - const pixels = new Uint8ClampedArray(buffer, 16, width * height * 4); - context.putImageData(new ImageData(pixels, width, height), 0, 0); - - const now = performance.now(); - const elapsed = state.lastFrameAt ? now - state.lastFrameAt : 0; - if (elapsed > 0) { - const instantaneous = 1000 / elapsed; - state.smoothedFps = state.smoothedFps ? state.smoothedFps * 0.82 + instantaneous * 0.18 : instantaneous; - } - const roundTrip = Math.max(0, now - state.requestStarted); - const megabitsPerSecond = roundTrip > 0 ? buffer.byteLength * 8 / roundTrip / 1000 : 0; - state.lastFrameAt = now; - state.frameCount += 1; - - elements.fps.textContent = state.smoothedFps.toFixed(1); - elements.latency.textContent = roundTrip.toFixed(1); - elements.resolution.textContent = `${width} × ${height}`; - elements.throughput.textContent = megabitsPerSecond.toFixed(1); - elements.frameCounter.textContent = state.frameCount.toLocaleString("zh-CN"); - elements.overlay.classList.add("hidden"); - requestFrame(); -} - -function connect() { - window.clearTimeout(state.reconnectTimer); - clearFrameRequest(); - if (state.socket && state.socket.readyState < WebSocket.CLOSING) - state.socket.close(1000, "reconnect"); - - setConnectionState("", "正在连接", "建立纯 WebSocket 像素通道"); - const socket = new WebSocket(endpoint); - state.socket = socket; - socket.binaryType = "arraybuffer"; - - socket.addEventListener("open", () => { - if (socket !== state.socket) - return; - setConnectionState("online", "通道在线", "等待首个 RGBA 像素帧"); - elements.connectionLabel.textContent = "通道在线"; - syncViewport(); - sendEvent("resize", {width: state.requestedWidth, height: state.requestedHeight}); - sendControlSnapshot(); - syncStreamActivity(); - }); - - socket.addEventListener("message", event => { - if (socket !== state.socket) - return; - try { - drawPixelFrame(event.data); - } catch (error) { - clearFrameRequest(); - setConnectionState("offline", "帧协议错误", error.message); - socket.close(1003, "invalid pixel frame"); - } - }); - - socket.addEventListener("close", event => { - if (socket !== state.socket) - return; - clearFrameRequest(); - setConnectionState("offline", "通道离线", event.reason || `WebSocket 已关闭 (${event.code})`); - state.reconnectTimer = window.setTimeout(connect, 1200); - }); - - socket.addEventListener("error", () => { - if (socket === state.socket) - setConnectionState("offline", "连接失败", "确认 Renderive_Web_Server 正在监听 8848 端口"); - }); -} - -function canvasPosition(event) { - const bounds = elements.canvas.getBoundingClientRect(); - return { - x: (event.clientX - bounds.left) * elements.canvas.width / bounds.width, - y: (event.clientY - bounds.top) * elements.canvas.height / bounds.height - }; -} - -function modifiers(event) { - return (event.ctrlKey ? 1 : 0) | (event.shiftKey ? 2 : 0) | - (event.altKey ? 4 : 0) | (event.metaKey ? 8 : 0); -} - -function mouseButton(button) { - return button === 0 ? "left" : button === 2 ? "right" : button === 1 ? "middle" : "none"; -} - -function pointerPayload(event) { - const position = canvasPosition(event); - return {x: position.x, y: position.y, button: mouseButton(event.button), - buttons: event.buttons & 7, modifiers: modifiers(event)}; -} - -elements.canvas.addEventListener("pointerdown", event => { - elements.canvas.focus({preventScroll: true}); - elements.canvas.setPointerCapture(event.pointerId); - sendEvent("pointer_press", pointerPayload(event)); -}); -elements.canvas.addEventListener("pointermove", event => sendEvent("pointer_move", pointerPayload(event))); -elements.canvas.addEventListener("pointerup", event => { - sendEvent("pointer_release", pointerPayload(event)); - if (elements.canvas.hasPointerCapture(event.pointerId)) - elements.canvas.releasePointerCapture(event.pointerId); -}); -elements.canvas.addEventListener("pointerleave", () => sendEvent("leave")); -elements.canvas.addEventListener("contextmenu", event => event.preventDefault()); -elements.canvas.addEventListener("wheel", event => { - event.preventDefault(); - const position = canvasPosition(event); - sendEvent("wheel", {x: position.x, y: position.y, buttons: event.buttons & 7, - modifiers: modifiers(event), pixelDeltaX: -event.deltaX, pixelDeltaY: -event.deltaY, - angleDeltaX: -event.deltaX, angleDeltaY: -event.deltaY}); -}, {passive: false}); - -function normalizedKey(key) { - return key === " " ? "Space" : key; -} -elements.canvas.addEventListener("keydown", event => { - sendEvent("key_press", {key: normalizedKey(event.key), nativeKey: event.keyCode || 0, - modifiers: modifiers(event), repeat: event.repeat}); -}); -elements.canvas.addEventListener("keyup", event => { - sendEvent("key_release", {key: normalizedKey(event.key), nativeKey: event.keyCode || 0, - modifiers: modifiers(event), repeat: false}); -}); - -elements.tuneDown.addEventListener("click", () => setFrequency(currentFrequency() - 0.1)); -elements.tuneUp.addEventListener("click", () => setFrequency(currentFrequency() + 0.1)); -elements.modeButtons.forEach(button => button.addEventListener("click", () => { - elements.modeButtons.forEach(candidate => candidate.classList.toggle("active", candidate === button)); - elements.modeLabel.textContent = button.dataset.mode === "FM" ? "FM WIDE" : `${button.dataset.mode} MODE`; - sendEvent("control", {control: "mode", value: button.dataset.mode}); -})); -elements.bandwidth.addEventListener("input", () => { - const value = Number(elements.bandwidth.value); - elements.bandwidthValue.textContent = `${value} kHz`; - sendEvent("control", {control: "bandwidth_khz", value}); -}); -elements.gain.addEventListener("input", () => { - const value = Number(elements.gain.value); - elements.gainValue.textContent = `${value >= 0 ? "+" : ""}${value} dB`; - sendEvent("control", {control: "gain_db", value}); -}); -elements.maxHold.addEventListener("click", () => setToggle(elements.maxHold, !buttonEnabled(elements.maxHold))); -elements.smoothing.addEventListener("click", () => setToggle(elements.smoothing, !buttonEnabled(elements.smoothing))); -elements.clearSelection.addEventListener("click", () => sendEvent("control", {control: "clear_selection"})); -elements.pause.addEventListener("click", () => { - state.paused = !state.paused; - elements.pause.setAttribute("aria-pressed", String(state.paused)); - elements.pause.classList.toggle("paused", state.paused); - elements.pauseLabel.textContent = state.paused ? "PAUSED" : "LIVE"; - syncStreamActivity(); -}); -elements.reconnect.addEventListener("click", connect); - -let resizeFrame = 0; -new ResizeObserver(() => { - cancelAnimationFrame(resizeFrame); - resizeFrame = requestAnimationFrame(syncViewport); -}).observe(elements.stage); - -document.addEventListener("visibilitychange", syncStreamActivity); -window.addEventListener("beforeunload", () => { - sendEvent("hide"); -}); - -syncViewport(); -connect(); diff --git a/webapp/index.html b/webapp/index.html deleted file mode 100644 index fe87dd5..0000000 --- a/webapp/index.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - Renderive Web Receiver - - - -
-
-
- -
-
RENDERIVE
-
WEB RECEIVER / KERNEL LINK
-
-
-
- CORE2KERNELWEBSOCKETRGBA -
-
- -
- 正在连接 - ws://127.0.0.1:8848/renderive -
- -
-
- -
- - -
-
-
-
REAL-TIME PIXEL STREAM
-

宽带频谱监视器

-
滚轮缩放 · 拖动坐标轴 · 在频谱区拖拽框选
-
-
-
FRAME RATE0.0 fps
-
FRAME RTT ms
-
RESOLUTION— × —
-
EFFECTIVE PIXEL RATE0.0 Mb/s
-
-
- -
- -
SPECTRUM / dBm
-
WATERFALL / UTC
-
-
- 等待像素流 - 请先启动 Renderive_Web_Server -
-
- -
-
WS ONLY事件 ↑ / 像素 ↓
-
0PIXEL FRAMES
-
- -
-
-
-
- - - diff --git a/webapp/styles.css b/webapp/styles.css deleted file mode 100644 index 8733b7e..0000000 --- a/webapp/styles.css +++ /dev/null @@ -1,245 +0,0 @@ -:root { - color-scheme: dark; - --bg: #02050c; - --panel: #07101d; - --panel-soft: #0a1524; - --line: rgba(128, 157, 196, 0.15); - --line-strong: rgba(128, 157, 196, 0.28); - --text: #e9f1fb; - --muted: #7890ad; - --faint: #4e627d; - --cyan: #38bdf8; - --green: #39e0b1; - --yellow: #f4cf58; - --danger: #fb7185; - --radius: 15px; - font-family: Inter, "Segoe UI", "Microsoft YaHei UI", sans-serif; -} - -* { box-sizing: border-box; } - -html, body { - width: 100%; - min-width: 320px; - min-height: 100%; - margin: 0; - background: var(--bg); - color: var(--text); -} - -body { - overflow: hidden; - background: - radial-gradient(circle at 72% 15%, rgba(21, 97, 130, 0.14), transparent 32%), - radial-gradient(circle at 15% 80%, rgba(24, 119, 94, 0.09), transparent 28%), - #02050c; -} - -button, input { font: inherit; } -button { color: inherit; } - -.app-shell { - display: grid; - grid-template-rows: 74px minmax(0, 1fr); - width: 100vw; - height: 100vh; - min-height: 620px; -} - -.topbar { - display: grid; - grid-template-columns: minmax(240px, 1fr) auto minmax(280px, 1fr); - align-items: center; - gap: 26px; - padding: 0 24px; - border-bottom: 1px solid var(--line); - background: rgba(3, 8, 16, 0.92); - box-shadow: 0 12px 38px rgba(0, 0, 0, 0.22); - backdrop-filter: blur(18px); - z-index: 5; -} - -.brand-block, .connection-summary, .transport-strip, -.frequency-stepper, .section-heading, .receiver-header, -.receiver-footer, .switch-row { display: flex; align-items: center; } - -.brand-block { gap: 13px; } -.brand-mark { - display: flex; - align-items: flex-end; - gap: 3px; - width: 34px; - height: 34px; - padding: 7px; - border: 1px solid rgba(56, 189, 248, 0.35); - border-radius: 9px; - background: linear-gradient(145deg, rgba(56, 189, 248, 0.14), rgba(57, 224, 177, 0.04)); - box-shadow: inset 0 0 20px rgba(56, 189, 248, 0.06); -} -.brand-mark span { width: 4px; border-radius: 4px; background: var(--cyan); box-shadow: 0 0 8px rgba(56, 189, 248, 0.55); } -.brand-mark span:nth-child(1) { height: 8px; } -.brand-mark span:nth-child(2) { height: 19px; background: var(--green); } -.brand-mark span:nth-child(3) { height: 13px; } -.brand-name { font-size: 15px; font-weight: 760; letter-spacing: 0.2em; } -.brand-caption { margin-top: 3px; color: var(--muted); font-size: 9px; letter-spacing: 0.16em; } - -.transport-strip { gap: 10px; color: #8297b0; font-family: Consolas, monospace; font-size: 9px; letter-spacing: 0.1em; } -.transport-strip i { width: 18px; height: 1px; background: linear-gradient(90deg, transparent, var(--faint)); position: relative; } -.transport-strip i::after { content: ""; position: absolute; right: 0; top: -2px; border-left: 4px solid var(--faint); border-top: 2px solid transparent; border-bottom: 2px solid transparent; } - -.connection-summary { justify-self: end; gap: 11px; min-width: 272px; justify-content: flex-end; } -.connection-summary strong { display: block; font-size: 11px; letter-spacing: 0.08em; } -.connection-summary small { display: block; margin-top: 3px; color: var(--muted); font: 9px Consolas, monospace; } -.connection-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--yellow); box-shadow: 0 0 14px rgba(244, 207, 88, 0.55); } -.connection-dot.online { background: var(--green); box-shadow: 0 0 14px rgba(57, 224, 177, 0.65); } -.connection-dot.offline { background: var(--danger); box-shadow: 0 0 14px rgba(251, 113, 133, 0.45); } -.icon-button { - width: 32px; height: 32px; border: 1px solid var(--line-strong); border-radius: 8px; - background: rgba(255, 255, 255, 0.025); cursor: pointer; transition: 160ms ease; -} -.icon-button:hover { border-color: rgba(56, 189, 248, 0.55); color: var(--cyan); background: rgba(56, 189, 248, 0.08); } - -.workspace { - display: grid; - grid-template-columns: 286px minmax(0, 1fr); - gap: 14px; - min-height: 0; - padding: 14px; -} - -.control-deck, .receiver-panel { - border: 1px solid var(--line); - border-radius: var(--radius); - background: linear-gradient(160deg, rgba(10, 21, 36, 0.97), rgba(5, 12, 22, 0.97)); - box-shadow: 0 18px 50px rgba(0, 0, 0, 0.27), inset 0 1px rgba(255, 255, 255, 0.025); -} - -.control-deck { display: flex; flex-direction: column; min-height: 0; overflow: hidden; } -.frequency-card { padding: 22px 20px 19px; border-bottom: 1px solid var(--line); background: linear-gradient(145deg, rgba(56, 189, 248, 0.065), transparent 65%); } -.section-kicker { color: var(--muted); font-size: 9px; font-weight: 700; letter-spacing: 0.17em; } -.frequency-readout { display: flex; align-items: baseline; gap: 7px; margin: 12px 0 15px; } -.frequency-readout span { color: #f1f8ff; font: 32px/1 Consolas, "SFMono-Regular", monospace; letter-spacing: -0.06em; text-shadow: 0 0 22px rgba(56, 189, 248, 0.19); } -.frequency-readout em { color: var(--cyan); font: normal 10px Consolas, monospace; } -.frequency-stepper { justify-content: space-between; gap: 8px; } -.frequency-stepper button { - width: 37px; height: 30px; border: 1px solid var(--line-strong); border-radius: 8px; - background: rgba(255, 255, 255, 0.025); font-size: 18px; cursor: pointer; -} -.frequency-stepper button:hover { border-color: var(--cyan); color: var(--cyan); } -.frequency-stepper span { color: var(--faint); font-size: 8px; letter-spacing: 0.08em; } -.frequency-stepper strong { color: #a8bbd1; font-weight: 600; } - -.control-section { padding: 17px 20px; border-bottom: 1px solid var(--line); } -.section-heading { justify-content: space-between; margin-bottom: 13px; color: #adbed2; font-size: 9px; font-weight: 700; letter-spacing: 0.12em; } -.section-heading small, .section-heading output { color: var(--cyan); font: 9px Consolas, monospace; letter-spacing: 0; } -.mode-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; } -.mode-button { - height: 32px; border: 1px solid var(--line); border-radius: 7px; background: rgba(255,255,255,0.02); - color: #7188a5; font: 10px Consolas, monospace; cursor: pointer; transition: 150ms ease; -} -.mode-button:hover { color: #c9d9ea; border-color: var(--line-strong); } -.mode-button.active { border-color: rgba(57, 224, 177, 0.48); color: var(--green); background: rgba(57, 224, 177, 0.09); box-shadow: inset 0 0 16px rgba(57, 224, 177, 0.04); } - -.range-section input { width: 100%; accent-color: var(--green); cursor: pointer; } -input[type="range"] { height: 3px; margin: 3px 0 9px; } -.range-scale { display: flex; justify-content: space-between; color: #465b74; font: 8px Consolas, monospace; } - -.switch-list { padding-top: 6px; padding-bottom: 6px; } -.switch-row { justify-content: space-between; width: 100%; padding: 10px 0; border: 0; background: none; cursor: pointer; text-align: left; } -.switch-row + .switch-row { border-top: 1px solid rgba(128, 157, 196, 0.08); } -.switch-row span b { display: block; color: #aabed4; font-size: 9px; letter-spacing: 0.11em; } -.switch-row span small { display: block; margin-top: 3px; color: var(--faint); font-size: 9px; } -.switch-row > i { position: relative; width: 31px; height: 16px; border: 1px solid #304259; border-radius: 10px; background: #0a111b; transition: 160ms ease; } -.switch-row > i::after { content: ""; position: absolute; top: 2px; left: 2px; width: 10px; height: 10px; border-radius: 50%; background: #647892; transition: 160ms ease; } -.switch-row.active > i { border-color: rgba(57, 224, 177, 0.55); background: rgba(57, 224, 177, 0.12); } -.switch-row.active > i::after { left: 16px; background: var(--green); box-shadow: 0 0 8px rgba(57, 224, 177, 0.65); } - -.deck-actions { display: grid; grid-template-columns: 1fr 88px; gap: 8px; margin-top: auto; padding: 15px 20px; } -.deck-actions button { height: 36px; border-radius: 8px; cursor: pointer; font-size: 9px; font-weight: 700; letter-spacing: 0.08em; } -.secondary-action { border: 1px solid var(--line-strong); background: rgba(255,255,255,0.025); color: #8da2ba; } -.secondary-action:hover { color: var(--cyan); border-color: rgba(56, 189, 248, 0.45); } -.live-action { border: 1px solid rgba(57, 224, 177, 0.38); background: rgba(57, 224, 177, 0.075); color: var(--green); } -.live-action.paused { border-color: rgba(244, 207, 88, 0.4); background: rgba(244, 207, 88, 0.08); color: var(--yellow); } -.live-pulse { display: inline-block; width: 6px; height: 6px; margin-right: 7px; border-radius: 50%; background: currentColor; box-shadow: 0 0 8px currentColor; } - -.receiver-panel { display: grid; grid-template-rows: auto minmax(0, 1fr) 45px; min-width: 0; min-height: 0; overflow: hidden; } -.receiver-header { justify-content: space-between; gap: 25px; min-height: 76px; padding: 14px 20px; border-bottom: 1px solid var(--line); } -.receiver-header h1 { margin: 5px 0 0; font-size: 17px; font-weight: 600; letter-spacing: 0.04em; } -.interaction-hint { margin-top: 5px; color: #526983; font-size: 8px; letter-spacing: 0.04em; } -.metric-rack { display: grid; grid-template-columns: repeat(4, minmax(92px, auto)); } -.metric-rack > div { padding: 2px 16px; border-left: 1px solid var(--line); } -.metric-rack small { display: block; color: var(--faint); font-size: 8px; letter-spacing: 0.1em; } -.metric-rack strong { display: block; margin-top: 5px; color: #bfd0e3; font: 10px Consolas, monospace; white-space: nowrap; } -.metric-rack > div:first-child strong { color: var(--green); } - -.canvas-stage { - position: relative; - min-width: 0; - min-height: 0; - margin: 12px; - overflow: hidden; - border: 1px solid rgba(90, 122, 162, 0.2); - border-radius: 11px; - background: - linear-gradient(rgba(50, 81, 118, 0.06) 1px, transparent 1px), - linear-gradient(90deg, rgba(50, 81, 118, 0.06) 1px, transparent 1px), - #030812; - background-size: 32px 32px; - box-shadow: inset 0 0 45px rgba(0,0,0,0.32); -} -#render-canvas { display: block; width: 100%; height: 100%; outline: none; image-rendering: auto; cursor: crosshair; } -#render-canvas:focus { box-shadow: inset 0 0 0 1px rgba(56, 189, 248, 0.32); } -.stage-label { position: absolute; right: 13px; z-index: 2; display: flex; align-items: center; gap: 7px; color: #637b98; font: 8px Consolas, monospace; letter-spacing: 0.08em; pointer-events: none; } -.stage-label span { width: 5px; height: 5px; border-radius: 50%; background: var(--green); box-shadow: 0 0 8px rgba(57,224,177,0.5); } -.spectrum-label { top: 10px; } -.waterfall-label { top: 51%; } -.waterfall-label span { background: var(--cyan); box-shadow: 0 0 8px rgba(56,189,248,0.55); } - -.stream-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 9px; background: rgba(3, 8, 18, 0.77); backdrop-filter: blur(3px); transition: opacity 220ms ease, visibility 220ms ease; z-index: 3; } -.stream-overlay.hidden { opacity: 0; visibility: hidden; pointer-events: none; } -.stream-overlay strong { color: #c7d7e8; font-size: 12px; letter-spacing: 0.06em; } -.stream-overlay span { color: var(--muted); font-size: 10px; } -.loader-ring { width: 28px; height: 28px; border: 2px solid rgba(56, 189, 248, 0.14); border-top-color: var(--cyan); border-radius: 50%; animation: spin 900ms linear infinite; } -@keyframes spin { to { transform: rotate(360deg); } } - -.receiver-footer { gap: 24px; padding: 0 17px; border-top: 1px solid var(--line); color: var(--muted); } -.receiver-footer > div { display: flex; align-items: center; gap: 7px; } -.receiver-footer strong { color: #a4b8ce; font: 9px Consolas, monospace; } -.receiver-footer small { color: var(--faint); font-size: 8px; } -.footer-led { width: 6px; height: 6px; border-radius: 50%; background: var(--green); box-shadow: 0 0 8px rgba(57,224,177,.6); } -.signal-meter { height: 18px; gap: 3px !important; margin-left: auto; align-items: flex-end !important; } -.signal-meter span { width: 3px; border-radius: 2px; background: linear-gradient(var(--green), #147b69); animation: meter 1.4s ease-in-out infinite alternate; } -.signal-meter span:nth-child(1), .signal-meter span:nth-child(8) { height: 4px; } -.signal-meter span:nth-child(2), .signal-meter span:nth-child(7) { height: 7px; animation-delay: -0.5s; } -.signal-meter span:nth-child(3), .signal-meter span:nth-child(6) { height: 11px; animation-delay: -0.8s; } -.signal-meter span:nth-child(4), .signal-meter span:nth-child(5) { height: 16px; animation-delay: -0.2s; } -@keyframes meter { to { transform: scaleY(.45); opacity: .45; } } -.footer-note { color: #455a73; font: 8px Consolas, monospace; letter-spacing: 0.1em; } - -@media (max-width: 1050px) { - .topbar { grid-template-columns: 1fr auto; } - .transport-strip { display: none; } - .metric-rack { grid-template-columns: repeat(2, minmax(100px, auto)); row-gap: 8px; } - .workspace { grid-template-columns: 250px minmax(0, 1fr); } - .control-section { padding-left: 16px; padding-right: 16px; } - .frequency-card, .deck-actions { padding-left: 16px; padding-right: 16px; } -} - -@media (max-width: 760px) { - body { overflow: auto; } - .app-shell { height: auto; min-height: 100vh; grid-template-rows: auto 1fr; } - .topbar { min-height: 68px; grid-template-columns: 1fr; gap: 8px; padding: 12px 16px; } - .connection-summary { justify-self: stretch; justify-content: flex-start; min-width: 0; } - .connection-summary .icon-button { margin-left: auto; } - .workspace { grid-template-columns: 1fr; padding: 9px; } - .control-deck { overflow: visible; } - .receiver-panel { min-height: 620px; } - .receiver-header { align-items: flex-start; flex-direction: column; } - .metric-rack { width: 100%; grid-template-columns: repeat(2, 1fr); } - .metric-rack > div { padding-left: 10px; } - .canvas-stage { min-height: 460px; } -} - -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; } -}