mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
257 lines
6.5 KiB
C++
257 lines
6.5 KiB
C++
#include <CtrlCore/CtrlCore.h>
|
|
|
|
#ifdef GUI_GTK
|
|
|
|
//#include <shellapi.h>
|
|
|
|
namespace Upp {
|
|
|
|
#define LTIMING(x) // RTIMING(x)
|
|
#define LLOG(x)
|
|
|
|
void SetSurface(SystemDraw& w, const Rect& dest, const RGBA *pixels, Size srcsz, Point poff)
|
|
{
|
|
w.FlushText();
|
|
Size dsz = dest.GetSize();
|
|
cairo_surface_t *surface = cairo_image_surface_create_for_data((byte *)pixels, CAIRO_FORMAT_ARGB32, dsz.cx, dsz.cy, 4 * dsz.cx);
|
|
cairo_set_source_surface(w, surface, dest.left, dest.top);
|
|
cairo_paint(w);
|
|
cairo_surface_destroy(surface);
|
|
}
|
|
|
|
struct ImageSysData {
|
|
Image img;
|
|
cairo_surface_t *surface = NULL;
|
|
|
|
void Init(const Image& m, cairo_surface_t *other);
|
|
~ImageSysData();
|
|
};
|
|
|
|
cairo_surface_t *CreateCairoSurface(const Image& img, cairo_surface_t *other)
|
|
{
|
|
Size isz = img.GetSize();
|
|
cairo_format_t fmt = CAIRO_FORMAT_ARGB32;
|
|
cairo_surface_t *surface = other ? cairo_surface_create_similar_image(other, fmt, isz.cx, isz.cy)
|
|
: cairo_image_surface_create(fmt, isz.cx, isz.cy);
|
|
cairo_surface_flush(surface);
|
|
byte *a = (byte *)cairo_image_surface_get_data(surface);
|
|
int stride = cairo_format_stride_for_width(fmt, isz.cx);
|
|
for(int yy = 0; yy < isz.cy; yy++) {
|
|
Copy((RGBA *)a, img[yy], isz.cx);
|
|
a += stride;
|
|
}
|
|
cairo_surface_mark_dirty(surface);
|
|
return surface;
|
|
}
|
|
|
|
cairo_surface_t *CreateCairoSurface(const Image& img)
|
|
{
|
|
return CreateCairoSurface(img, NULL);
|
|
}
|
|
|
|
void ImageSysData::Init(const Image& m, cairo_surface_t *other)
|
|
{
|
|
img = m;
|
|
surface = CreateCairoSurface(m, other);
|
|
SysImageRealized(img);
|
|
}
|
|
|
|
ImageSysData::~ImageSysData()
|
|
{
|
|
SysImageReleased(img);
|
|
cairo_surface_destroy(surface);
|
|
}
|
|
|
|
struct ImageSysDataMaker : LRUCache<ImageSysData, int64>::Maker {
|
|
Image img;
|
|
cairo_surface_t *other;
|
|
|
|
virtual int64 Key() const { return img.GetSerialId(); }
|
|
virtual int Make(ImageSysData& object) const { object.Init(img, other); return img.GetLength(); }
|
|
};
|
|
|
|
void SystemDraw::SysDrawImageOp(int x, int y, const Image& img, Color color)
|
|
{
|
|
GuiLock __;
|
|
FlushText();
|
|
if(img.GetLength() == 0)
|
|
return;
|
|
if(img.IsPaintOnceHint()) {
|
|
SetSurface(*this, x, y, img.GetWidth(), img.GetHeight(), ~img);
|
|
return;
|
|
}
|
|
LLOG("SysDrawImageOp " << img.GetSerialId() << ' ' << x << ", " << y << ", "<< img.GetSize());
|
|
ImageSysDataMaker m;
|
|
static LRUCache<ImageSysData, int64> cache;
|
|
static int Rsz;
|
|
Rsz += img.GetLength();
|
|
if(Rsz > 200 * 200) { // we do not want to do this for each small image painted...
|
|
Rsz = 0;
|
|
cache.Remove([](const ImageSysData& object) {
|
|
return object.img.GetRefCount() == 1;
|
|
});
|
|
}
|
|
LLOG("SysImage cache pixels " << cache.GetSize() << ", count " << cache.GetCount());
|
|
m.img = img;
|
|
m.other = cairo_get_target(cr);
|
|
ImageSysData& sd = cache.Get(m);
|
|
if(!IsNull(color)) {
|
|
SetColor(color);
|
|
cairo_mask_surface(cr, sd.surface, x, y);
|
|
}
|
|
else {
|
|
cairo_set_source_surface(cr, sd.surface, x, y);
|
|
cairo_paint(cr);
|
|
}
|
|
static Size ssz;
|
|
if(ssz.cx == 0)
|
|
ssz = Ctrl::GetVirtualScreenArea().GetSize();
|
|
cache.Shrink(4 * ssz.cx * ssz.cy, 1000); // Cache must be after Paint because of PaintOnly!
|
|
}
|
|
|
|
Draw& ImageDraw::Alpha()
|
|
{
|
|
if(!alpha_surface) {
|
|
alpha_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, isz.cx, isz.cy);
|
|
alpha.cr = cairo_create(alpha_surface);
|
|
// cairo_set_source_rgb(alpha.cr, 0, 0, 0);
|
|
// cairo_paint(alpha.cr);
|
|
}
|
|
return alpha;
|
|
}
|
|
|
|
void CairoGet(ImageBuffer& b, Size isz, cairo_surface_t *surface, cairo_surface_t *alpha_surface)
|
|
{
|
|
cairo_surface_flush(surface);
|
|
byte *a = (byte *)cairo_image_surface_get_data(surface);
|
|
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, isz.cx);
|
|
RGBA *t = b;
|
|
byte *aa = NULL;
|
|
if(alpha_surface) {
|
|
cairo_surface_flush(alpha_surface);
|
|
aa = (byte *)cairo_image_surface_get_data(alpha_surface);
|
|
}
|
|
for(int yy = 0; yy < isz.cy; yy++) {
|
|
RGBA *s = (RGBA *)a;
|
|
RGBA *e = s + isz.cx;
|
|
if(aa) {
|
|
RGBA *ss = (RGBA *)aa;
|
|
while(s < e) {
|
|
*t = *s++;
|
|
(t++)->a = (ss++)->r;
|
|
}
|
|
aa += stride;
|
|
b.SetKind(IMAGE_ALPHA);
|
|
}
|
|
else {
|
|
while(s < e) {
|
|
*t = *s++;
|
|
(t++)->a = 255;
|
|
}
|
|
b.SetKind(IMAGE_OPAQUE);
|
|
}
|
|
a += stride;
|
|
}
|
|
}
|
|
|
|
void ImageDraw::FetchStraight(ImageBuffer& b) const
|
|
{
|
|
ImageDraw *m = const_cast<ImageDraw *>(this);
|
|
m->FlushText();
|
|
if(alpha_surface)
|
|
m->alpha.FlushText();
|
|
CairoGet(b, isz, surface, alpha_surface);
|
|
}
|
|
|
|
ImageDraw::operator Image() const
|
|
{
|
|
ImageBuffer img(isz);
|
|
FetchStraight(img);
|
|
Premultiply(img);
|
|
return Image(img);
|
|
}
|
|
|
|
Image ImageDraw::GetStraight() const
|
|
{
|
|
ImageBuffer img(isz);
|
|
FetchStraight(img);
|
|
return Image(img);
|
|
}
|
|
|
|
void ImageDraw::Init(Size sz)
|
|
{
|
|
isz = sz;
|
|
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, isz.cx, isz.cy);
|
|
cr = cairo_create(surface);
|
|
// cairo_set_source_rgb(cr, 0, 0, 0);
|
|
// cairo_paint(cr);
|
|
alpha_surface = NULL;
|
|
del = true;
|
|
}
|
|
|
|
ImageDraw::ImageDraw(Size sz)
|
|
{
|
|
Init(sz);
|
|
}
|
|
|
|
ImageDraw::ImageDraw(int cx, int cy)
|
|
{
|
|
Init(Size(cx, cy));
|
|
}
|
|
|
|
ImageDraw::ImageDraw(cairo_t *cr_, Size sz)
|
|
{
|
|
isz = sz;
|
|
cr = cr_;
|
|
surface = cairo_get_target(cr);
|
|
alpha_surface = NULL;
|
|
del = false;
|
|
}
|
|
|
|
ImageDraw::~ImageDraw()
|
|
{
|
|
if(del) {
|
|
cairo_destroy(cr);
|
|
cairo_surface_destroy(surface);
|
|
if(alpha_surface) {
|
|
cairo_destroy(alpha.cr);
|
|
cairo_surface_destroy(alpha_surface);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BackDraw::Put(SystemDraw& w, int x, int y)
|
|
{
|
|
}
|
|
|
|
void BackDraw::Create(SystemDraw& w, int cx, int cy)
|
|
{
|
|
}
|
|
|
|
void BackDraw::Destroy()
|
|
{
|
|
}
|
|
|
|
#define FCURSOR_(x) { static Image h; ONCELOCK { h = CreateImage(Size(1, 1), Black); h.SetAuxData(x + 1); } return h; }
|
|
|
|
Image Image::Arrow() FCURSOR_(GDK_LEFT_PTR)
|
|
Image Image::Wait() FCURSOR_(GDK_WATCH)
|
|
Image Image::IBeam() FCURSOR_(GDK_XTERM)
|
|
Image Image::No() FCURSOR_(GDK_CIRCLE)
|
|
Image Image::SizeAll() FCURSOR_(GDK_FLEUR)
|
|
Image Image::SizeHorz() FCURSOR_(GDK_SB_H_DOUBLE_ARROW)
|
|
Image Image::SizeVert() FCURSOR_(GDK_SB_V_DOUBLE_ARROW)
|
|
Image Image::SizeTopLeft() FCURSOR_(GDK_TOP_LEFT_CORNER)
|
|
Image Image::SizeTop() FCURSOR_(GDK_TOP_SIDE)
|
|
Image Image::SizeTopRight() FCURSOR_(GDK_TOP_RIGHT_CORNER)
|
|
Image Image::SizeLeft() FCURSOR_(GDK_LEFT_SIDE)
|
|
Image Image::SizeRight() FCURSOR_(GDK_RIGHT_SIDE)
|
|
Image Image::SizeBottomLeft() FCURSOR_(GDK_BOTTOM_LEFT_CORNER)
|
|
Image Image::SizeBottom() FCURSOR_(GDK_BOTTOM_SIDE)
|
|
Image Image::SizeBottomRight() FCURSOR_(GDK_BOTTOM_RIGHT_CORNER)
|
|
Image Image::Cross() FCURSOR_(GDK_CROSSHAIR)
|
|
Image Image::Hand() FCURSOR_(GDK_HAND2)
|
|
|
|
}
|
|
|
|
#endif
|