Initial commit for real hidpi support
Note: This commit has only been tested on MacOS Changes: - Icons now use the native hidpi support from Gtk (through Icon Theme) - Icons are now directly generated from scalable file (i.e. SVG file) - Widget sizes are scaled based on DPI and scale factor - Font size is scaled based on DPI and scale factor
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2018 Jean-Christophe FRISCH <natureh.510@gmail.com>
|
||||
* Copyright (c) 2022 Pierre CABRERA <pierre.cab@gmail.com>
|
||||
*
|
||||
* RawTherapee is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -23,37 +24,69 @@
|
||||
|
||||
#include "options.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using SurfaceCache = std::map<std::string, Cairo::RefPtr<Cairo::ImageSurface>>;
|
||||
|
||||
SurfaceCache surfaceCache;
|
||||
|
||||
}
|
||||
|
||||
RTSurface::RTSurface() :
|
||||
surface(new Cairo::ImageSurface(nullptr, false))
|
||||
{
|
||||
// Initialize "back" parameters from RTScalable
|
||||
dpiBack = RTScalable::getDPI();
|
||||
scaleBack = RTScalable::getScale();
|
||||
|
||||
// Initialize other private parameters
|
||||
type = RTSurface::InvalidType;
|
||||
name = "";
|
||||
icon_size = Gtk::ICON_SIZE_INVALID;
|
||||
}
|
||||
|
||||
RTSurface::RTSurface(const Glib::ustring& fileName, const Glib::ustring& rtlFileName) :
|
||||
RTSurface::RTSurface(const Glib::ustring &icon_name, const Gtk::IconSize iconSize) :
|
||||
RTSurface()
|
||||
{
|
||||
setImage(fileName, rtlFileName);
|
||||
// Create surface
|
||||
surface = RTScalable::loadSurfaceFromIcon(icon_name, iconSize);
|
||||
|
||||
if (surface) {
|
||||
// Save private parameters
|
||||
type = RTSurface::IconType;
|
||||
name = icon_name;
|
||||
icon_size = iconSize;
|
||||
}
|
||||
}
|
||||
|
||||
void RTSurface::setImage(const Glib::ustring& fileName, const Glib::ustring& rtlFileName)
|
||||
RTSurface::RTSurface(const Glib::ustring &fname) :
|
||||
RTSurface()
|
||||
{
|
||||
const Glib::ustring& imageName =
|
||||
!rtlFileName.empty() && getDirection() == Gtk::TEXT_DIR_RTL
|
||||
? rtlFileName
|
||||
: fileName;
|
||||
// Create surface based on file extension
|
||||
const auto pos = fname.find_last_of('.');
|
||||
|
||||
changeImage (imageName);
|
||||
if (pos >= 0 && pos < fname.length()) {
|
||||
const auto fext = fname.substr(pos + 1, fname.length()).lowercase();
|
||||
|
||||
// Case where fname is a PNG file
|
||||
if (fext == "png") {
|
||||
// Create surface from PNG file
|
||||
surface = RTScalable::loadSurfaceFromPNG(fname);
|
||||
|
||||
if (surface) {
|
||||
// Save private parameter
|
||||
type = RTSurface::PNGType;
|
||||
name = fname;
|
||||
}
|
||||
}
|
||||
|
||||
// Case where fname is a SVG file
|
||||
if (fext == "svg") {
|
||||
// Create surface from SVG file
|
||||
surface = RTScalable::loadSurfaceFromSVG(fname);
|
||||
|
||||
if (surface) {
|
||||
// Save private parameter
|
||||
type = RTSurface::SVGType;
|
||||
name = fname;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RTSurface::getWidth() const
|
||||
int RTSurface::getWidth()
|
||||
{
|
||||
return
|
||||
surface
|
||||
@@ -61,7 +94,7 @@ int RTSurface::getWidth() const
|
||||
: -1;
|
||||
}
|
||||
|
||||
int RTSurface::getHeight() const
|
||||
int RTSurface::getHeight()
|
||||
{
|
||||
return
|
||||
surface
|
||||
@@ -69,77 +102,156 @@ int RTSurface::getHeight() const
|
||||
: -1;
|
||||
}
|
||||
|
||||
bool RTSurface::hasSurface() const
|
||||
bool RTSurface::hasSurface()
|
||||
{
|
||||
return static_cast<bool>(surface);
|
||||
}
|
||||
|
||||
Cairo::RefPtr<const Cairo::ImageSurface> RTSurface::get() const
|
||||
Cairo::RefPtr<Cairo::ImageSurface> RTSurface::get()
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
if (dpiBack != RTScalable::getDPI() ||
|
||||
scaleBack != RTScalable::getScale()) {
|
||||
switch (type) {
|
||||
case RTSurface::IconType :
|
||||
surface = RTScalable::loadSurfaceFromIcon(name, icon_size);
|
||||
break;
|
||||
case RTSurface::PNGType :
|
||||
surface = RTScalable::loadSurfaceFromPNG(name);
|
||||
break;
|
||||
case RTSurface::SVGType :
|
||||
surface = RTScalable::loadSurfaceFromSVG(name);
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
const Cairo::RefPtr<Cairo::ImageSurface>& RTSurface::get()
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
|
||||
void RTSurface::init()
|
||||
{
|
||||
dpiBack = getDPI();
|
||||
scaleBack = getScale();
|
||||
}
|
||||
|
||||
void RTSurface::updateImages()
|
||||
{
|
||||
const double tweakedDpi = getTweakedDPI();
|
||||
|
||||
for (auto& entry : surfaceCache) {
|
||||
entry.second = loadImage(entry.first, tweakedDpi);
|
||||
}
|
||||
}
|
||||
|
||||
void RTSurface::setDPInScale(const double newDPI, const int newScale)
|
||||
{
|
||||
if (
|
||||
getScale() != newScale
|
||||
|| (
|
||||
getScale() == 1
|
||||
&& getDPI() != newDPI
|
||||
)
|
||||
) {
|
||||
setDPInScale(newDPI, newScale);
|
||||
dpiBack = getDPI();
|
||||
scaleBack = getScale();
|
||||
|
||||
updateImages();
|
||||
}
|
||||
}
|
||||
|
||||
void RTSurface::changeImage(const Glib::ustring& imageName)
|
||||
{
|
||||
const SurfaceCache::const_iterator iterator = surfaceCache.find(imageName);
|
||||
|
||||
if (iterator != surfaceCache.end()) {
|
||||
surface = iterator->second;
|
||||
} else {
|
||||
surface = loadImage(imageName, getTweakedDPI());
|
||||
|
||||
// HOMBRE: As of now, GDK_SCALE is forced to 1, so setting the Cairo::ImageSurface scale is not required
|
||||
// Anyway, this might be of use one day
|
||||
/*
|
||||
double x=0., y=0.;
|
||||
cairo_surface_get_device_scale(surface->cobj(), &x, &y);
|
||||
if (getScale() == 2) {
|
||||
cairo_surface_set_device_scale(surface->cobj(), 0.5, 0.5); // Not sure if it should be 0.5 or 2.0 here !
|
||||
surface->flush();
|
||||
// Save new DPI and scale
|
||||
dpiBack = RTScalable::getDPI();
|
||||
scaleBack = RTScalable::getScale();
|
||||
}
|
||||
*/
|
||||
|
||||
surfaceCache.emplace(imageName, surface);
|
||||
return surface;
|
||||
}
|
||||
|
||||
RTPixbuf::RTPixbuf()
|
||||
{
|
||||
// Initialize "back" parameters from RTScalable
|
||||
dpiBack = RTPixbuf::getDPI();
|
||||
scaleBack = RTPixbuf::getScale();
|
||||
|
||||
// Initialize other private parameters
|
||||
type = RTPixbuf::InvalidType;
|
||||
name = "";
|
||||
icon_size = Gtk::ICON_SIZE_INVALID;
|
||||
}
|
||||
|
||||
RTPixbuf::RTPixbuf(const Glib::ustring &icon_name, const Gtk::IconSize iconSize) :
|
||||
RTPixbuf()
|
||||
{
|
||||
// Create surface
|
||||
const Cairo::RefPtr<Cairo::ImageSurface> surface = RTScalable::loadSurfaceFromIcon(icon_name, iconSize);
|
||||
|
||||
if (surface) {
|
||||
// Create pixbuf from surface
|
||||
pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height());
|
||||
|
||||
// Save private parameters
|
||||
type = RTPixbuf::IconType;
|
||||
name = icon_name;
|
||||
icon_size = iconSize;
|
||||
}
|
||||
}
|
||||
|
||||
double RTSurface::dpiBack = 0.;
|
||||
RTPixbuf::RTPixbuf(const Glib::ustring &fname) :
|
||||
RTPixbuf()
|
||||
{
|
||||
// Create surface based on file extension
|
||||
const auto pos = fname.find_last_of('.');
|
||||
|
||||
int RTSurface::scaleBack = 0;
|
||||
if (pos >= 0 && pos < fname.length()) {
|
||||
const auto fext = fname.substr(pos + 1, fname.length()).lowercase();
|
||||
|
||||
// Case where fname is a PNG file
|
||||
if (fext == "png") {
|
||||
// Create surface from PNG file
|
||||
const Cairo::RefPtr<Cairo::ImageSurface> surface = RTScalable::loadSurfaceFromPNG(fname);
|
||||
|
||||
if (surface) {
|
||||
// Create pixbuf from surface
|
||||
pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height());
|
||||
|
||||
// Save private parameter
|
||||
type = RTPixbuf::PNGType;
|
||||
name = fname;
|
||||
}
|
||||
}
|
||||
|
||||
// Case where fname is a SVG file
|
||||
if (fext == "svg") {
|
||||
// Create surface from SVG file
|
||||
const Cairo::RefPtr<Cairo::ImageSurface> surface = RTScalable::loadSurfaceFromSVG(fname);
|
||||
|
||||
if (surface) {
|
||||
// Create pixbuf from surface
|
||||
pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height());
|
||||
|
||||
// Save private parameter
|
||||
type = RTPixbuf::SVGType;
|
||||
name = fname;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RTPixbuf::getWidth()
|
||||
{
|
||||
return
|
||||
pixbuf
|
||||
? pixbuf->get_width()
|
||||
: -1;
|
||||
}
|
||||
|
||||
int RTPixbuf::getHeight()
|
||||
{
|
||||
return
|
||||
pixbuf
|
||||
? pixbuf->get_height()
|
||||
: -1;
|
||||
}
|
||||
|
||||
bool RTPixbuf::hasPixbuf()
|
||||
{
|
||||
return static_cast<bool>(pixbuf);
|
||||
}
|
||||
|
||||
Glib::RefPtr<Gdk::Pixbuf> RTPixbuf::get()
|
||||
{
|
||||
if (dpiBack != RTScalable::getDPI() ||
|
||||
scaleBack != RTScalable::getScale()) {
|
||||
Cairo::RefPtr<Cairo::ImageSurface> surface;
|
||||
|
||||
// Surface needs to be regenerated
|
||||
switch (type) {
|
||||
case RTPixbuf::IconType :
|
||||
surface = RTScalable::loadSurfaceFromIcon(name, icon_size);
|
||||
pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height());
|
||||
break;
|
||||
case RTPixbuf::PNGType :
|
||||
surface = RTScalable::loadSurfaceFromPNG(name);
|
||||
pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height());
|
||||
break;
|
||||
case RTPixbuf::SVGType :
|
||||
surface = RTScalable::loadSurfaceFromSVG(name);
|
||||
pixbuf = Gdk::Pixbuf::create(surface, 0, 0, surface->get_width(), surface->get_height());
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
// Save new DPI and scale
|
||||
dpiBack = RTScalable::getDPI();
|
||||
scaleBack = RTScalable::getScale();
|
||||
}
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
Reference in New Issue
Block a user