Support for fl_scroll() under macOS when GUI is scaled

This commit is contained in:
ManoloFLTK 2019-05-21 21:17:11 +02:00
parent 07f4fd4380
commit 9b80a38345
4 changed files with 13 additions and 33 deletions

View File

@ -3408,9 +3408,9 @@ void Fl_Cocoa_Window_Driver::make_current()
// it gets activated when needed (e.g., draw text) // it gets activated when needed (e.g., draw text)
CGContextSetShouldAntialias(gc, false); CGContextSetShouldAntialias(gc, false);
CGFloat hgt = [[fl_window contentView] frame].size.height; CGFloat hgt = [[fl_window contentView] frame].size.height;
CGContextTranslateCTM(gc, 0.5, hgt-0.5f);
CGContextScaleCTM(gc, 1.0f, -1.0f); // now 0,0 is top-left point of the window
float s = Fl::screen_driver()->scale(0); float s = Fl::screen_driver()->scale(0);
CGContextTranslateCTM(gc, 0.5f*s, hgt-0.5f*s);
CGContextScaleCTM(gc, 1.0f, -1.0f); // now 0,0 is top-left point of the window
CGContextScaleCTM(gc, s, s); // apply current scaling factor CGContextScaleCTM(gc, s, s); // apply current scaling factor
// for subwindows, limit drawing to inside of parent window // for subwindows, limit drawing to inside of parent window
// half pixel offset is necessary for clipping as done by fl_cgrectmake_cocoa() // half pixel offset is necessary for clipping as done by fl_cgrectmake_cocoa()

View File

@ -26,6 +26,7 @@
#include <FL/fl_draw.H> #include <FL/fl_draw.H>
#include <FL/Fl.H> #include <FL/Fl.H>
#include <FL/platform.H> #include <FL/platform.H>
#include <math.h>
/** /**
\cond DriverDev \cond DriverDev
@ -260,7 +261,9 @@ int Fl_Cocoa_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, i
{ {
CGImageRef img = CGImage_from_window_rect(src_x, src_y, src_w, src_h); CGImageRef img = CGImage_from_window_rect(src_x, src_y, src_w, src_h);
if (img) { if (img) {
((Fl_Quartz_Graphics_Driver*)fl_graphics_driver)->draw_CGImage(img,dest_x,dest_y,src_w,src_h,0,0,src_w,src_h); float s = Fl_Graphics_Driver::default_driver().scale();
((Fl_Quartz_Graphics_Driver*)fl_graphics_driver)->draw_CGImage(img,
dest_x, dest_y, lround(s*src_w), lround(s*src_h), 0, 0, src_w, src_h);
CFRelease(img); CFRelease(img);
} }
return 0; return 0;

View File

@ -280,32 +280,9 @@ void Fl_Quartz_Graphics_Driver::draw_CGImage(CGImageRef cgimg, int x, int y, int
CGContextClipToRect(gc_, CGRectOffset(rect, -0.5, -0.5 )); CGContextClipToRect(gc_, CGRectOffset(rect, -0.5, -0.5 ));
// move graphics context to origin of vertically reversed image // move graphics context to origin of vertically reversed image
// The 0.5 here cancels the 0.5 offset present in Quartz graphics contexts. // The 0.5 here cancels the 0.5 offset present in Quartz graphics contexts.
// Thus, image and surface pixels are in phase if there's no scaling. // Thus, image and surface pixels are in phase.
CGContextTranslateCTM(gc_, rect.origin.x - srcx - 0.5, rect.origin.y - srcy + sh - 0.5); CGContextTranslateCTM(gc_, rect.origin.x - srcx - 0.5, rect.origin.y - srcy + sh - 0.5);
CGContextScaleCTM(gc_, 1, -1); CGContextScaleCTM(gc_, 1, -1);
CGAffineTransform at = CGContextGetCTM(gc_);
if (at.a == at.d && at.b == 0 && at.c == 0) { // proportional scaling, no rotation
// We handle x2 and /2 scalings that occur when drawing to
// a double-resolution bitmap, and when drawing a double-resolution bitmap to display.
bool doit = false;
// phase image with display pixels
CGFloat deltax = 0, deltay = 0;
if (at.a == 2) { // make .tx and .ty have even values
deltax = (at.tx/2 - round(at.tx/2));
deltay = (at.ty/2 - round(at.ty/2));
doit = true;
} else if (at.a == 0.5) {
doit = true;
if (high_resolution()) { // make .tx and .ty have int or half-int values
deltax = -(at.tx*2 - round(at.tx*2));
deltay = (at.ty*2 - round(at.ty*2));
} else { // make .tx and .ty have integral values
deltax = (at.tx - round(at.tx))*2;
deltay = (at.ty - round(at.ty))*2;
}
}
if (doit) CGContextTranslateCTM(gc_, -deltax, -deltay);
}
CGContextDrawImage(gc_, CGRectMake(0, 0, sw, sh), cgimg); CGContextDrawImage(gc_, CGRectMake(0, 0, sw, sh), cgimg);
CGContextRestoreGState(gc_); CGContextRestoreGState(gc_);
} }

View File

@ -75,7 +75,7 @@ void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1) {
CGContextMoveToPoint(gc_, x, y); CGContextMoveToPoint(gc_, x, y);
CGContextAddLineToPoint(gc_, x1, y); CGContextAddLineToPoint(gc_, x1, y);
CGContextStrokePath(gc_); CGContextStrokePath(gc_);
if (high_resolution()) { if (high_resolution() || scale()>=2) {
/* On retina displays, all xyline() and yxline() functions produce lines that are half-unit /* On retina displays, all xyline() and yxline() functions produce lines that are half-unit
(or one pixel) too short at both ends. This is corrected by filling at both ends rectangles (or one pixel) too short at both ends. This is corrected by filling at both ends rectangles
of size one unit by line-width. of size one unit by line-width.
@ -92,7 +92,7 @@ void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
CGContextAddLineToPoint(gc_, x1, y); CGContextAddLineToPoint(gc_, x1, y);
CGContextAddLineToPoint(gc_, x1, y2); CGContextAddLineToPoint(gc_, x1, y2);
CGContextStrokePath(gc_); CGContextStrokePath(gc_);
if (high_resolution()) { if (high_resolution() || scale()>=2) {
CGContextFillRect(gc_, CGRectMake(x-0.5, y - quartz_line_width_/2, 1 , quartz_line_width_)); CGContextFillRect(gc_, CGRectMake(x-0.5, y - quartz_line_width_/2, 1 , quartz_line_width_));
CGContextFillRect(gc_, CGRectMake(x1 - quartz_line_width_/2, y2-0.5, quartz_line_width_, 1)); CGContextFillRect(gc_, CGRectMake(x1 - quartz_line_width_/2, y2-0.5, quartz_line_width_, 1));
} }
@ -106,7 +106,7 @@ void Fl_Quartz_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
CGContextAddLineToPoint(gc_, x1, y2); CGContextAddLineToPoint(gc_, x1, y2);
CGContextAddLineToPoint(gc_, x3, y2); CGContextAddLineToPoint(gc_, x3, y2);
CGContextStrokePath(gc_); CGContextStrokePath(gc_);
if (high_resolution()) { if (high_resolution() || scale()>=2) {
CGContextFillRect(gc_, CGRectMake(x-0.5, y - quartz_line_width_/2, 1 , quartz_line_width_)); CGContextFillRect(gc_, CGRectMake(x-0.5, y - quartz_line_width_/2, 1 , quartz_line_width_));
CGContextFillRect(gc_, CGRectMake(x3-0.5, y2 - quartz_line_width_/2, 1 , quartz_line_width_)); CGContextFillRect(gc_, CGRectMake(x3-0.5, y2 - quartz_line_width_/2, 1 , quartz_line_width_));
} }
@ -118,7 +118,7 @@ void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1) {
CGContextMoveToPoint(gc_, x, y); CGContextMoveToPoint(gc_, x, y);
CGContextAddLineToPoint(gc_, x, y1); CGContextAddLineToPoint(gc_, x, y1);
CGContextStrokePath(gc_); CGContextStrokePath(gc_);
if (high_resolution()) { if (high_resolution() || scale()>=2) {
CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1));
CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y1-0.5, quartz_line_width_, 1)); CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y1-0.5, quartz_line_width_, 1));
} }
@ -131,7 +131,7 @@ void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
CGContextAddLineToPoint(gc_, x, y1); CGContextAddLineToPoint(gc_, x, y1);
CGContextAddLineToPoint(gc_, x2, y1); CGContextAddLineToPoint(gc_, x2, y1);
CGContextStrokePath(gc_); CGContextStrokePath(gc_);
if (high_resolution()) { if (high_resolution() || scale()>=2) {
CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1));
CGContextFillRect(gc_, CGRectMake(x2-0.5, y1 - quartz_line_width_/2, 1 , quartz_line_width_)); CGContextFillRect(gc_, CGRectMake(x2-0.5, y1 - quartz_line_width_/2, 1 , quartz_line_width_));
} }
@ -145,7 +145,7 @@ void Fl_Quartz_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
CGContextAddLineToPoint(gc_, x2, y1); CGContextAddLineToPoint(gc_, x2, y1);
CGContextAddLineToPoint(gc_, x2, y3); CGContextAddLineToPoint(gc_, x2, y3);
CGContextStrokePath(gc_); CGContextStrokePath(gc_);
if (high_resolution()) { if (high_resolution() || scale()>=2) {
CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1)); CGContextFillRect(gc_, CGRectMake(x - quartz_line_width_/2, y-0.5, quartz_line_width_, 1));
CGContextFillRect(gc_, CGRectMake(x2 - quartz_line_width_/2, y3-0.5, quartz_line_width_, 1)); CGContextFillRect(gc_, CGRectMake(x2 - quartz_line_width_/2, y3-0.5, quartz_line_width_, 1));
} }