Skip to content

Commit

Permalink
Replace ImageOpenDlg by gtk4-compatible version
Browse files Browse the repository at this point in the history
  • Loading branch information
bhennion committed Apr 21, 2024
1 parent 460e8fe commit c468236
Show file tree
Hide file tree
Showing 12 changed files with 195 additions and 291 deletions.
1 change: 0 additions & 1 deletion src/core/control/PageBackgroundChangeController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

#include "control/settings/PageTemplateSettings.h" // for PageTemplate...
#include "control/settings/Settings.h" // for Settings
#include "control/stockdlg/ImageOpenDlg.h" // for ImageOpenDlg
#include "gui/MainWindow.h" // for MainWindow
#include "gui/XournalView.h" // for XournalView
#include "gui/dialog/backgroundSelect/ImagesDialog.h" // for ImagesDialog
Expand Down
104 changes: 0 additions & 104 deletions src/core/control/stockdlg/ImageOpenDlg.cpp

This file was deleted.

32 changes: 0 additions & 32 deletions src/core/control/stockdlg/ImageOpenDlg.h

This file was deleted.

182 changes: 98 additions & 84 deletions src/core/control/tools/ImageHandler.cpp
Original file line number Diff line number Diff line change
@@ -1,131 +1,145 @@
#include "ImageHandler.h"

#include <algorithm> // for min
#include <memory> // for __shared_ptr_access, make...
#include <string> // for string
#include <utility> // for operator==, pair
#include <fstream>
#include <memory> // for __shared_ptr_access, make...
#include <sstream>
#include <string> // for string
#include <utility> // for operator==, pair

#include <glib-object.h> // for g_object_unref
#include <glib.h> // for g_error_free, g_free, GError

#include "control/Control.h" // for Control
#include "control/stockdlg/ImageOpenDlg.h" // for ImageOpenDlg
#include "control/tools/EditSelection.h" // for EditSelection
#include "gui/MainWindow.h" // for MainWindow
#include "gui/PageView.h" // for XojPageView
#include "gui/XournalView.h" // for XournalView
#include "model/Layer.h" // for Layer
#include "model/PageRef.h" // for PageRef
#include "model/XojPage.h" // for XojPage
#include "undo/InsertUndoAction.h" // for InsertUndoAction
#include "undo/UndoRedoHandler.h" // for UndoRedoHandler
#include "util/XojMsgBox.h" // for XojMsgBox
#include "util/i18n.h" // for _
#include "util/raii/GObjectSPtr.h" // for GObjectSPtr.h

ImageHandler::ImageHandler(Control* control, XojPageView* view): control(control), view(view) {}
#include "control/Control.h" // for Control
#include "control/tools/EditSelection.h" // for EditSelection
#include "gui/MainWindow.h" // for MainWindow
#include "gui/PageView.h" // for XojPageView
#include "gui/XournalView.h" // for XournalView
#include "gui/dialog/XojOpenDlg.h" // for showOpenImageDialog
#include "model/Image.h"
#include "model/Layer.h" // for Layer
#include "model/PageRef.h" // for PageRef
#include "model/XojPage.h" // for XojPage
#include "undo/InsertUndoAction.h" // for InsertUndoAction
#include "undo/UndoRedoHandler.h" // for UndoRedoHandler
#include "util/XojMsgBox.h" // for XojMsgBox
#include "util/i18n.h" // for _
#include "util/raii/GObjectSPtr.h" // for GObjectSPtr.h

ImageHandler::ImageHandler(Control* control): control(control) {}

ImageHandler::~ImageHandler() = default;


auto ImageHandler::chooseAndCreateImage(double x, double y) -> std::tuple<std::unique_ptr<Image>, int, int> {
const xoj::util::GObjectSPtr<GFile> fileObj(ImageOpenDlg::show(control->getGtkWindow(), control->getSettings()),
xoj::util::adopt);
if (!fileObj) {
return std::make_tuple(nullptr, 0, 0);
}

GFile* file = fileObj.get();
void ImageHandler::chooseAndCreateImage(std::function<void(std::unique_ptr<Image>)> callback) {
xoj::OpenDlg::showOpenImageDialog(control->getGtkWindow(), control->getSettings(),
[cb = std::move(callback), ctrl = control](fs::path p, bool) {
auto img = ImageHandler::createImageFromFile(p);

return createImageFromFile(file, x, y);
if (!img || img->getImageSize() == Image::NOSIZE) {
XojMsgBox::showErrorToUser(ctrl->getGtkWindow(),
_("Failed to load image"));
return;
}
cb(std::move(img));
});
}

auto ImageHandler::createImageFromFile(const fs::path& p) -> std::unique_ptr<Image> {

auto ImageHandler::createImageFromFile(GFile* file, double x, double y)
-> std::tuple<std::unique_ptr<Image>, int, int> {
// Load the image data from disk
GError* err = nullptr;
gchar* contents{};
gsize length{};
if (!g_file_load_contents(file, nullptr, &contents, &length, nullptr, &err)) {
g_error_free(err);
return std::make_tuple(nullptr, 0, 0);
}
auto fileToString = [](const fs::path& p) {
// This is the faster file dump I could come up with. Faster by 20% than g_file_load_contents (with -O3)
std::ifstream stream(p);

auto img = std::make_unique<Image>();
img->setX(x);
img->setY(y);
img->setImage(std::string(contents, length));
g_free(contents);
auto pos = stream.tellg();
stream.seekg(0, std::ios_base::end); // Go to the end
auto size = stream.tellg() - pos; // Get the size
stream.seekg(pos); // Go back

std::string s(as_unsigned(size), 0); // Allocate
stream.read(&s[0], size); // Dump
return s;
};

auto img = std::make_unique<Image>();
try {
img->setImage(fileToString(p));
} catch (const std::ios_base::failure& e) {
std::stringstream msg;
msg << _("Error while opening image file: ") << p.string() << '\n'
<< "Error code: " << e.code() << '\n'
<< "Explanatory string: " << e.what();
XojMsgBox::showErrorToUser(nullptr, msg.str());
return nullptr;
}
// Render the image.
// FIXME: this is horrible. We need an ImageView class...
(void)img->getImage();

const auto imgSize = img->getImageSize();
auto [width, height] = imgSize;
if (imgSize == Image::NOSIZE) {
XojMsgBox::showErrorToUser(this->control->getGtkWindow(),
_("Failed to load image, could not determine image size!"));
return std::make_tuple(nullptr, 0, 0);
}

return std::make_tuple(std::move(img), width, height);
return img;
}

auto ImageHandler::addImageToDocument(std::unique_ptr<Image> img, bool addUndoAction) -> bool {
PageRef const page = view->getPage();
bool ImageHandler::addImageToDocument(std::unique_ptr<Image> img, PageRef page, Control* control, bool addUndoAction) {
Layer* layer = page->getSelectedLayer();

if (addUndoAction) {
control->getUndoRedoHandler()->addUndoAction(std::make_unique<InsertUndoAction>(page, layer, img.get()));
}

XournalView* xournal = control->getWindow()->getXournal();
auto pageNr = xournal->getCurrentPage();
auto* view = xournal->getViewFor(pageNr);

if (view->getPage() != page) {
g_warning("Active page changed while you selected the image. Aborting.");
return false;
}

auto sel = SelectionFactory::createFromFloatingElement(control, page, layer, view, std::move(img));
control->getWindow()->getXournal()->setSelection(sel.release());

return true;
}

void ImageHandler::automaticScaling(Image* img, double x, double y, int width, int height) {
void ImageHandler::automaticScaling(Image& img, PageRef page) {
double zoom = 1;

PageRef const page = view->getPage();
double x = img.getX();
double y = img.getY();
auto [width, height] = img.getImageSize();

if (x + width > page->getWidth() || y + height > page->getHeight()) {
double const maxZoomX = (page->getWidth() - x) / width;
double const maxZoomY = (page->getHeight() - y) / height;
zoom = std::min(maxZoomX, maxZoomY);
}

img->setWidth(width * zoom);
img->setHeight(height * zoom);
img.setWidth(width * zoom);
img.setHeight(height * zoom);
}

auto ImageHandler::insertImageWithSize(const xoj::util::Rectangle<double>& space) -> bool {
auto [img, width, height] = ImageHandler::chooseAndCreateImage(space.x, space.y);
if (!img) {
return false;
}

if (static_cast<int>(space.width) != 0 && static_cast<int>(space.height) != 0) {
// scale down
const double scaling = std::min(space.height / height, space.width / width);
img->setWidth(scaling * width);
img->setHeight(scaling * height);

// center
if (img->getElementHeight() < space.height) {
img->setY(img->getY() + ((space.height - img->getElementHeight()) * 0.5));
}
if (img->getElementWidth() < space.width) {
img->setX(img->getX() + ((space.width - img->getElementWidth()) * 0.5));
void ImageHandler::insertImageWithSize(PageRef page, const xoj::util::Rectangle<double>& space) {
chooseAndCreateImage([space, page, ctrl = control](std::unique_ptr<Image> img) {
xoj_assert(img);
img->setX(space.x);
img->setY(space.y);
auto [width, height] = img->getImageSize();

if (static_cast<int>(space.width) != 0 && static_cast<int>(space.height) != 0) {
// scale down
const double scaling = std::min(space.height / height, space.width / width);
img->setWidth(scaling * width);
img->setHeight(scaling * height);

// center
if (img->getElementHeight() < space.height) {
img->setY(img->getY() + ((space.height - img->getElementHeight()) * 0.5));
}
if (img->getElementWidth() < space.width) {
img->setX(img->getX() + ((space.width - img->getElementWidth()) * 0.5));
}
} else {
// zero space is selected, scale original image size down to fit on the page
automaticScaling(*img, page);
}
} else {
// zero space is selected, scale original image size down to fit on the page
automaticScaling(img.get(), space.x, space.y, width, height);
}

return addImageToDocument(std::move(img), true);
addImageToDocument(std::move(img), page, ctrl, true);
});
}
Loading

0 comments on commit c468236

Please sign in to comment.