diff --git a/languages/capturer_en_US.ts b/languages/capturer_en_US.ts index 7c49014..aca4157 100644 --- a/languages/capturer_en_US.ts +++ b/languages/capturer_en_US.ts @@ -4,32 +4,32 @@ Capturer - + Screenshot - + Record Video - + Record GIF - + Open Camera - + Settings - + Quit @@ -216,7 +216,7 @@ ScreenShoter - + Save Image diff --git a/languages/capturer_zh_CN.ts b/languages/capturer_zh_CN.ts index 4f4bb8f..1ae75b2 100644 --- a/languages/capturer_zh_CN.ts +++ b/languages/capturer_zh_CN.ts @@ -4,32 +4,32 @@ Capturer - + Screenshot 截图 - + Record Video 录屏 - + Record GIF 录GIF - + Open Camera 打开摄像头 - + Settings 设置 - + Quit 退出 @@ -223,7 +223,7 @@ ScreenShoter - + Save Image 保存图片 diff --git a/src/capturer-light.qss b/src/capturer-light.qss index 0fae670..f7ec15d 100644 --- a/src/capturer-light.qss +++ b/src/capturer-light.qss @@ -27,18 +27,18 @@ QComboBox QAbstractItemView { border: 1px solid #e4e7ed; } -QComboBox QListView { +QComboBox QAbstractItemView { background-color: #f9f9f9; border: 1px solid #dfdfdf; } -QComboBox QListView::item { +QComboBox QAbstractItemView::item { color: #50505f; } -QComboBox QListView::item:hover, -QComboBox QListView::item:selected, -QComboBox QListView::item:checked { +QComboBox QAbstractItemView::item:hover, +QComboBox QAbstractItemView::item:selected, +QComboBox QAbstractItemView::item:checked { background-color: #dfdfdf; } diff --git a/src/capturer.cpp b/src/capturer.cpp index 9b4255e..85bd385 100644 --- a/src/capturer.cpp +++ b/src/capturer.cpp @@ -7,7 +7,6 @@ #include #include #include "logging.h" -#include "imagewindow.h" #define SET_HOTKEY(X, Y) st(if(!X->setShortcut(Y, true)) error += tr("Failed to register hotkey:<%1>\n").arg(Y.toString());) @@ -20,11 +19,7 @@ Capturer::Capturer(QWidget *parent) recorder_ = new ScreenRecorder(ScreenRecorder::VIDEO, this); gifcptr_ = new ScreenRecorder(ScreenRecorder::GIF, this); - connect(sniper_, &ScreenShoter::FIX_IMAGE, [this](const QPixmap& image, const QPoint& pos) { - clipboard_history_.append(std::make_shared(image, pos)); - pin_idx_ = clipboard_history_.size() - 1; - pinLastImage(); - }); + connect(sniper_, &ScreenShoter::pinSnipped, this, &Capturer::pinPixmap); sys_tray_icon_ = new QSystemTrayIcon(this); @@ -32,7 +27,7 @@ Capturer::Capturer(QWidget *parent) connect(snip_sc_, &QHotkey::activated, sniper_, &ScreenShoter::start); pin_sc_ = new QHotkey(this); - connect(pin_sc_, &QHotkey::activated, this, &Capturer::pinLastImage); + connect(pin_sc_, &QHotkey::activated, this, &Capturer::pin); show_pin_sc_ = new QHotkey(this); connect(show_pin_sc_, &QHotkey::activated, this, &Capturer::showImages); @@ -60,7 +55,7 @@ Capturer::Capturer(QWidget *parent) connect(gifcptr_, &ScreenRecorder::SHOW_MESSAGE, this, &Capturer::showMessage); // clipboard - connect(QApplication::clipboard(), &QClipboard::dataChanged, this, &Capturer::clipboardChanged); + connect(QApplication::clipboard(), &QClipboard::dataChanged, [this]() { clipboard_changed_ = true; }); LOG(INFO) << "initialized."; } @@ -121,87 +116,108 @@ void Capturer::showMessage(const QString &title, const QString &msg, QSystemTray if(icon == QSystemTrayIcon::Critical) LOG(ERROR) << msg; } -void Capturer::clipboardChanged() +std::pair Capturer::clipboard_data() { const auto mimedata = QApplication::clipboard()->mimeData(); - // only image if(mimedata->hasHtml() && mimedata->hasImage()) { - LOG(INFO) << "IMAGE"; - - auto image_rect = mimedata->imageData().value().rect(); - image_rect.moveCenter(DisplayInfo::screens()[0]->geometry().center()); - clipboard_history_.append(make_shared(mimedata->imageData().value(), image_rect.topLeft())); - pin_idx_ = clipboard_history_.size() - 1; + return { DataFormat::PIXMAP, mimedata->imageData().value() }; } else if(mimedata->hasHtml()) { - LOG(INFO) << "HTML"; + return { DataFormat::HTML, mimedata->html() }; + } + else if(mimedata->hasFormat("application/x-snipped") && mimedata->hasImage()) { + QString type = mimedata->data("application/x-snipped"); + return (type == "copied") ? + std::pair{DataFormat::PIXMAP, mimedata->imageData().value()} : + std::pair{DataFormat::UNKNOWN, nullptr}; + } + else if(mimedata->hasUrls() + && QString("jpg;jpeg;png;JPG;JPEG;PNG;bmp;BMP;ico;ICO;gif;GIF").contains(QFileInfo(mimedata->urls()[0].fileName()).suffix())) { + return { DataFormat::URLS, mimedata->urls() }; + } + else if(mimedata->hasText()) { + return { DataFormat::TEXT, mimedata->text() }; + } + else if(mimedata->hasColor()) { + return { DataFormat::COLOR, mimedata->colorData().value() }; + } + else { + return { DataFormat::UNKNOWN, nullptr }; + } +} + +std::pair Capturer::to_pixmap(const std::pair& data_pair) +{ + auto& [type, data] = data_pair; + switch (type) + { + case DataFormat::PIXMAP: return { true, std::any_cast(data) }; + case DataFormat::HTML: + { QTextEdit view; view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view.setLineWrapMode(QTextEdit::NoWrap); - view.setHtml(mimedata->html()); + view.setHtml(std::any_cast(data)); view.setFixedSize(view.document()->size().toSize()); - clipboard_history_.append(make_shared(view.grab(), QCursor::pos())); - pin_idx_ = clipboard_history_.size() - 1; + return { true, view.grab() }; } - else if(mimedata->hasFormat("application/qpoint") && mimedata->hasImage()) { - LOG(INFO) << "SNIP"; - - auto pos = *reinterpret_cast(mimedata->data("application/qpoint").data()); - for(const auto& item : clipboard_history_) { - if(item->image().cacheKey() == mimedata->imageData().value().cacheKey()) { - return; - } - } - clipboard_history_.append(make_shared(mimedata->imageData().value(), pos)); - pin_idx_ = clipboard_history_.size() - 1; + case DataFormat::TEXT: + { + QLabel label(std::any_cast(data)); + label.setWordWrap(true); + label.setMargin(10); + label.setStyleSheet("background-color:white"); + label.setFont({ "Consolas", 12 }); + return { true, label.grab() }; } - - else if(mimedata->hasUrls() - && QString("jpg;jpeg;png;JPG;JPEG;PNG;bmp;BMP;ico;ICO;gif;GIF").contains(QFileInfo(mimedata->urls()[0].fileName()).suffix())) { - LOG(INFO) << "IMAGE URL"; - - QPixmap pixmap; - pixmap.load(mimedata->urls()[0].toLocalFile()); - auto image_rect = pixmap.rect(); - image_rect.moveCenter(DisplayInfo::screens()[0]->geometry().center()); - clipboard_history_.append(make_shared(pixmap, image_rect.topLeft())); - pin_idx_ = clipboard_history_.size() - 1; + case DataFormat::URLS: return { true, QPixmap(std::any_cast>(data)[0].toLocalFile()) }; + default: LOG(WARNING) << "not support"; return { false, {} }; } - else if(mimedata->hasText()) { - LOG(INFO) << "TEXT"; - - auto label = new QLabel(mimedata->text()); - label->setWordWrap(true); - label->setMargin(10); - label->setStyleSheet("background-color:white"); - label->setFont({"Consolas", 12}); +} - clipboard_history_.append(make_shared(label->grab(), QCursor::pos())); - pin_idx_ = clipboard_history_.size() - 1; +void Capturer::pin() +{ + auto& [fmt, data] = clipboard_data(); + if (clipboard_changed_) { + auto& [ok, pixmap] = to_pixmap({ fmt, data }); + if (ok) { + history_.append({ + fmt, + data, + std::make_shared( + pixmap, + DisplayInfo::screens()[0]->geometry().center() - QPoint{ pixmap.width(), pixmap.height() } / 2 + ) + }); + pin_idx_ = history_.size() - 1; + } } - else if(mimedata->hasColor()) { - // Do nothing. - LOG(WARNING) << "COLOR"; + else { + auto& [_1, _2, win] = history_[pin_idx_]; + if (win) { + win->show(); + } + pin_idx_ = std::clamp(pin_idx_-1, 0, history_.size() - 1); } + + clipboard_changed_ = false; } -void Capturer::pinLastImage() +void Capturer::pinPixmap(const QPixmap& image, const QPoint& pos) { - if(clipboard_history_.empty()) return; - - clipboard_history_[pin_idx_]->show(); - pin_idx_ = (pin_idx_ + clipboard_history_.size() - 1) % clipboard_history_.size(); + history_.append({ DataFormat::PIXMAP, image, std::make_shared(image, pos) }); + pin_idx_ = history_.size() - 1; } void Capturer::showImages() { images_visible_ = !images_visible_; - for(auto& window: clipboard_history_) { - images_visible_ ? window->show(false) : window->hide(); + for(auto& [_1, _2, win] : history_) { + images_visible_ && win ? win->show(false) : win->hide(); } } diff --git a/src/capturer.h b/src/capturer.h index 8550076..554ca2d 100644 --- a/src/capturer.h +++ b/src/capturer.h @@ -1,6 +1,7 @@ #ifndef CAPTURER_H #define CAPTURER_H +#include #include #include "screenshoter.h" #include "imagewindow.h" @@ -8,6 +9,7 @@ #include "qhotkey.h" #include "screenshoter.h" #include "settingdialog.h" +#include "imagewindow.h" template class LimitSizeVector : public std::vector { @@ -22,6 +24,10 @@ class LimitSizeVector : public std::vector { } }; +enum class DataFormat { + UNKNOWN, PIXMAP, HTML, TEXT, COLOR, URLS, SNIPPED +}; + class Capturer : public QWidget { Q_OBJECT @@ -31,7 +37,8 @@ class Capturer : public QWidget ~Capturer() override = default; private slots: - void pinLastImage(); + void pin(); + void pinPixmap(const QPixmap&, const QPoint&); void showImages(); void updateConfig(); @@ -40,30 +47,32 @@ private slots: QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 10000); - void clipboardChanged(); - private: void setupSystemTrayIcon(); - ScreenShoter * sniper_ = nullptr; - ScreenRecorder * recorder_ = nullptr; - ScreenRecorder* gifcptr_ = nullptr; + std::pair clipboard_data(); + std::pair to_pixmap(const std::pair&); + + ScreenShoter * sniper_{ nullptr }; + ScreenRecorder * recorder_ { nullptr }; + ScreenRecorder* gifcptr_{ nullptr }; - LimitSizeVector, 16> clipboard_history_; - size_t pin_idx_ = 0; + size_t pin_idx_{ 0 }; + bool clipboard_changed_{ false }; + LimitSizeVector>> history_; - QSystemTrayIcon *sys_tray_icon_ = nullptr; + QSystemTrayIcon *sys_tray_icon_ { nullptr }; - SettingWindow * setting_dialog_ = nullptr; + SettingWindow * setting_dialog_{ nullptr }; // hotkey - QHotkey *snip_sc_ = nullptr; - QHotkey *show_pin_sc_ = nullptr; - QHotkey *pin_sc_ = nullptr; - QHotkey *gif_sc_ = nullptr; - QHotkey *video_sc_ = nullptr; + QHotkey *snip_sc_{ nullptr }; + QHotkey *show_pin_sc_{ nullptr }; + QHotkey *pin_sc_ { nullptr }; + QHotkey *gif_sc_{ nullptr }; + QHotkey *video_sc_{ nullptr }; - bool images_visible_ = true; + bool images_visible_{ true }; }; #endif // CAPTURER_H diff --git a/src/capturer.qss b/src/capturer.qss index 5c0ec13..601b25e 100644 --- a/src/capturer.qss +++ b/src/capturer.qss @@ -25,14 +25,14 @@ QComboBox QAbstractItemView { border: 1px solid #e4e7ed; } -QComboBox QListView { +QComboBox QAbstractItemView { background-color: #fcfcfc; border: 1px solid #dfdfdf; padding: 5px; border-radius: 5px; } -QComboBox QListView::item { +QComboBox QAbstractItemView::item { border-radius: 5px; padding-left: 10px; height: 30px; @@ -40,9 +40,9 @@ QComboBox QListView::item { background-color: transparent; } -QComboBox QListView::item:hover, -QComboBox QListView::item:selected, -QComboBox QListView::item:checked { +QComboBox QAbstractItemView::item:hover, +QComboBox QAbstractItemView::item:selected, +QComboBox QAbstractItemView::item:checked { background-color: #f2f2f2; } diff --git a/src/core/canvas.cpp b/src/core/canvas.cpp index 446740a..2281c01 100644 --- a/src/core/canvas.cpp +++ b/src/core/canvas.cpp @@ -13,7 +13,7 @@ Canvas::Canvas(ImageEditMenu* menu, QWidget *parent) CHECK(menu); menu_ = menu; - connect(menu_, &ImageEditMenu::fix, [this]() { focusOn(nullptr); emit closed(); }); + connect(menu_, &ImageEditMenu::pin, [this]() { focusOn(nullptr); emit closed(); }); connect(menu_, &ImageEditMenu::ok, [this]() { // copy to clipboard QApplication::clipboard()->setPixmap(canvas_); diff --git a/src/menu/imageeditmenu.cpp b/src/menu/imageeditmenu.cpp index 89d05c8..48547e4 100644 --- a/src/menu/imageeditmenu.cpp +++ b/src/menu/imageeditmenu.cpp @@ -94,9 +94,9 @@ ImageEditMenu::ImageEditMenu(QWidget* parent, uint32_t groups) if (groups & SAVE_GROUP) { addSeparator(); - auto fix_btn = new IconButton(QPixmap(":/icon/res/pin"), { HEIGHT, HEIGHT }, { ICON_W, ICON_W }, false, this); - connect(fix_btn, &IconButton::clicked, [this]() { group_->uncheckAll(); fix(); hide(); }); - addButton(fix_btn); + auto pin_btn = new IconButton(QPixmap(":/icon/res/pin"), { HEIGHT, HEIGHT }, { ICON_W, ICON_W }, false, this); + connect(pin_btn, &IconButton::clicked, [this]() { group_->uncheckAll(); pin(); hide(); }); + addButton(pin_btn); auto save_btn = new IconButton(QPixmap(":/icon/res/save"), { HEIGHT, HEIGHT }, { ICON_W, ICON_W }, false, this); connect(save_btn, &IconButton::clicked, this, &ImageEditMenu::save); diff --git a/src/menu/imageeditmenu.h b/src/menu/imageeditmenu.h index 0947eab..c2e8cdc 100644 --- a/src/menu/imageeditmenu.h +++ b/src/menu/imageeditmenu.h @@ -44,7 +44,7 @@ class ImageEditMenu : public EditMenu signals: void save(); - void fix(); + void pin(); void ok(); void exit(); diff --git a/src/menu/stylemenu.cpp b/src/menu/stylemenu.cpp index e2ee95f..828adb5 100644 --- a/src/menu/stylemenu.cpp +++ b/src/menu/stylemenu.cpp @@ -37,7 +37,7 @@ StyleMenu::StyleMenu(int buttons, QWidget* parent) // font family font_family_ = new QComboBox(this); - font_family_->setView(new QListView()); + font_family_->setView(new QListView()); // qss font_family_->view()->window()->setWindowFlag(Qt::FramelessWindowHint); font_family_->view()->window()->setWindowFlag(Qt::NoDropShadowWindowHint); font_family_->view()->window()->setAttribute(Qt::WA_TranslucentBackground); diff --git a/src/pinned/imagewindow.h b/src/pinned/imagewindow.h index ee4edb1..db42bab 100644 --- a/src/pinned/imagewindow.h +++ b/src/pinned/imagewindow.h @@ -27,6 +27,8 @@ class ImageWindow : public QWidget { this->image(image); original_pos_ = pos; + + show(); } ~ImageWindow() override = default; @@ -45,27 +47,27 @@ public slots: void effectEnabled(); private: - void mousePressEvent(QMouseEvent *) override; - void mouseMoveEvent(QMouseEvent *) override; + void mousePressEvent(QMouseEvent*) override; + void mouseMoveEvent(QMouseEvent*) override; void mouseReleaseEvent(QMouseEvent*) override; void mouseDoubleClickEvent(QMouseEvent*) override; - void wheelEvent(QWheelEvent *) override; - void keyPressEvent(QKeyEvent *) override; - void keyReleaseEvent(QKeyEvent *) override; - void paintEvent(QPaintEvent *) override; - void contextMenuEvent(QContextMenuEvent *) override; - void moveEvent(QMoveEvent *) override; - void dropEvent(QDropEvent *) override; - void dragEnterEvent(QDragEnterEvent *) override; + void wheelEvent(QWheelEvent*) override; + void keyPressEvent(QKeyEvent*) override; + void keyReleaseEvent(QKeyEvent*) override; + void paintEvent(QPaintEvent*) override; + void contextMenuEvent(QContextMenuEvent*) override; + void moveEvent(QMoveEvent*) override; + void dropEvent(QDropEvent*) override; + void dragEnterEvent(QDragEnterEvent*) override; void registerShortcuts(); void moveMenu(); void initContextMenu(); - void update(Modified type); - QRect getShadowGeometry(QSize size); - QSize getShadowSize(QSize size) { return size + QSize{shadow_r_ * 2, shadow_r_ * 2}; } + void update(Modified); + QRect getShadowGeometry(QSize); + QSize getShadowSize(QSize size) { return size + QSize{ shadow_r_ * 2, shadow_r_ * 2 }; } WindowStatus status_{ WindowStatus::CREATED }; diff --git a/src/snip/screenshoter.cpp b/src/snip/screenshoter.cpp index 5478560..e9fe5d4 100644 --- a/src/snip/screenshoter.cpp +++ b/src/snip/screenshoter.cpp @@ -29,7 +29,7 @@ ScreenShoter::ScreenShoter(QWidget *parent) connect(menu_, &ImageEditMenu::save, this, &ScreenShoter::save); connect(menu_, &ImageEditMenu::ok, this, &ScreenShoter::copy); - connect(menu_, &ImageEditMenu::fix, this, &ScreenShoter::pin); + connect(menu_, &ImageEditMenu::pin, this, &ScreenShoter::pin); connect(menu_, &ImageEditMenu::exit, this, &ScreenShoter::exit); connect(menu_, &ImageEditMenu::graphChanged, [this](Graph graph) { @@ -128,7 +128,7 @@ void ScreenShoter::keyReleaseEvent(QKeyEvent *event) void ScreenShoter::mouseDoubleClickEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton && status_ >= SelectorStatus::CAPTURED) { - snipped(); + save2clipboard(snip(), false); exit(); } @@ -185,25 +185,22 @@ void ScreenShoter::paintEvent(QPaintEvent *event) Selector::paintEvent(event); } -QPixmap ScreenShoter::snipped() +QPixmap ScreenShoter::snip() { - auto mimedata = new QMimeData(); - auto position = selected().topLeft(); - auto&& image = snippedImage(); - mimedata->setData("application/qpoint", QByteArray().append(reinterpret_cast(&position), sizeof (QPoint))); - mimedata->setImageData(QVariant(image)); - // Ownership of the data is transferred to the clipboard: https://doc.qt.io/qt-5/qclipboard.html#setMimeData - QApplication::clipboard()->setMimeData(mimedata); - history_.push_back(selected()); history_idx_ = history_.size() - 1; - return image; + return canvas_->pixmap().copy(selected()); } -QPixmap ScreenShoter::snippedImage() +void ScreenShoter::save2clipboard(const QPixmap& image, bool pinned) { - return canvas_->pixmap().copy(selected()); + auto mimedata = new QMimeData(); + mimedata->setImageData(QVariant(image)); + mimedata->setData("application/x-snipped", QByteArray().append(pinned ? "pinned" : "copied")); + mimedata->setImageData(QVariant(image)); + // Ownership of the data is transferred to the clipboard: https://doc.qt.io/qt-5/qclipboard.html#setMimeData + QApplication::clipboard()->setMimeData(mimedata); } void ScreenShoter::save() @@ -224,25 +221,28 @@ void ScreenShoter::save() if (!filename.isEmpty()) { QFileInfo fileinfo(filename); save_path_ = fileinfo.absoluteDir().path(); - snippedImage().save(filename); + + snip().save(filename); + emit SHOW_MESSAGE("Capturer", "Path: " + filename); - - snipped(); - exit(); } } void ScreenShoter::copy() { - snipped(); + save2clipboard(snip(), false); exit(); } void ScreenShoter::pin() { - emit FIX_IMAGE(snipped(), { selected().topLeft() }); + auto& snipped = snip(); + + emit pinSnipped(snipped, { selected().topLeft() }); + + save2clipboard(snipped, true); exit(); } diff --git a/src/snip/screenshoter.h b/src/snip/screenshoter.h index 23928f7..6705513 100644 --- a/src/snip/screenshoter.h +++ b/src/snip/screenshoter.h @@ -22,7 +22,7 @@ class ScreenShoter : public Selector signals: void focusOnGraph(Graph); - void FIX_IMAGE(const QPixmap& image, const QPoint& pos); + void pinSnipped(const QPixmap& image, const QPoint& pos); void SHOW_MESSAGE(const QString& title, const QString& msg, QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 10000); @@ -33,14 +33,14 @@ public slots: void save(); void copy(); void pin(); - QPixmap snipped(); + QPixmap snip(); + void save2clipboard(const QPixmap&, bool); void updateTheme() { Selector::updateTheme(Config::instance()["snip"]["selector"]); } -private slots: void moveMenu(); protected: @@ -56,7 +56,6 @@ private slots: void moveMagnifier(); - QPixmap snippedImage(); QPixmap captured_screen_;