Merged revision(s) 62539-62541 #f588bfbd67-#f588bfbd67, 62545 #7c70ec7fc5 from trunk:

cocoa: fixes for pattern brush drawing, by Yuriy Sydorov. bug #36565
........
cocoa: manual scroller no longer reports any mouse events (to prevent double events). This matches the TCocoaScrollView implementation. Forcefully syncing scroll position with position of scrollers :) before reporting to LCL. bug #36048
........
cocoa: adding support for small and large change parameters of a scrollbar
........
cocoa: checkbox and radiobuttons initial value are now set without change notification
........

git-svn-id: branches/fixes_2_0@62546 -
This commit is contained in:
dmitry 2020-01-14 01:41:38 +00:00
parent 81cf2717b8
commit 36b9cd3dbc
3 changed files with 151 additions and 135 deletions

View File

@ -119,16 +119,20 @@ type
property ColorRef: TColorRef read GetColorRef;
end;
TCocoaPatternColorMode = (cpmBitmap, cpmBrushColor, cpmContextColor);
{ TCocoaBrush }
TCocoaBrush = class(TCocoaColorObject)
strict private
FCGPattern: CGPatternRef;
FColored: Boolean;
FPatternColorMode: TCocoaPatternColorMode;
FBitmap: TCocoaBitmap;
FColor: NSColor;
FFgColor: TColorRef;
private
FImage: CGImageRef;
procedure DrawPattern(c: CGContextRef);
strict protected
procedure Clear;
@ -3090,11 +3094,8 @@ end;
procedure DrawBitmapPattern(info: UnivPtr; c: CGContextRef); MWPascal;
var
ABrush: TCocoaBrush absolute info;
AImage: CGImageRef;
begin
AImage := ABrush.FImage;
CGContextDrawImage(c, GetCGRect(0, 0, CGImageGetWidth(AImage), CGImageGetHeight(AImage)),
AImage);
ABrush.DrawPattern(c);
end;
procedure TCocoaBrush.SetHatchStyle(AHatch: PtrInt);
@ -3122,11 +3123,11 @@ begin
CGDataProvider := CGDataProviderCreateWithData(nil, @HATCH_DATA[AHatch], 8, nil);
FImage := CGImageMaskCreate(8, 8, 1, 1, 1, CGDataProvider, nil, 0);
CGDataProviderRelease(CGDataProvider);
FColored := False;
FPatternColorMode := cpmBrushColor;
if FCGPattern <> nil then CGPatternRelease(FCGPattern);
FCGPattern := CGPatternCreate(Self, GetCGRect(0, 0, 8, 8),
CGAffineTransformIdentity, 8.0, 8.0, kCGPatternTilingConstantSpacing,
Ord(FColored), ACallBacks);
0, ACallBacks);
end;
end;
@ -3134,6 +3135,7 @@ procedure TCocoaBrush.SetBitmap(ABitmap: TCocoaBitmap);
var
AWidth, AHeight: Integer;
ACallBacks: CGPatternCallbacks;
CGDataProvider: CGDataProviderRef;
begin
AWidth := ABitmap.Width;
AHeight := ABitmap.Height;
@ -3142,12 +3144,25 @@ begin
if (FBitmap <> nil) then FBitmap.Release;
FBitmap := TCocoaBitmap.Create(ABitmap);
if FImage <> nil then CGImageRelease(FImage);
FImage := CGImageCreateCopy(MacOSAll.CGImageRef( FBitmap.imageRep.CGImageForProposedRect_context_hints(nil, nil, nil)));
FColored := True;
if FBitmap.BitmapType = cbtMono then
begin
with FBitmap do
begin
CGDataProvider := CGDataProviderCreateWithData(nil, Data, DataSize, nil);
FImage := CGImageMaskCreate(Width, Height, BitsPerSample, BitsPerPixel, BytesPerRow, CGDataProvider, nil, 0);
CGDataProviderRelease(CGDataProvider);
end;
FPatternColorMode := cpmContextColor;
end
else
begin
FImage := CGImageCreateCopy(MacOSAll.CGImageRef( FBitmap.imageRep.CGImageForProposedRect_context_hints(nil, nil, nil)));
FPatternColorMode := cpmBitmap;
end;
if FCGPattern <> nil then CGPatternRelease(FCGPattern);
FCGPattern := CGPatternCreate(Self, GetCGRect(0, 0, AWidth, AHeight),
CGAffineTransformIdentity, CGFloat(AWidth), CGFloat(AHeight), kCGPatternTilingConstantSpacing,
Ord(FColored), ACallBacks);
Ord(FPatternColorMode = cpmBitmap), ACallBacks);
end;
procedure TCocoaBrush.SetImage(AImage: NSImage);
@ -3159,14 +3174,14 @@ begin
ACallBacks.drawPattern := @DrawBitmapPattern;
if FImage <> nil then CGImageRelease(FImage);
FImage := CGImageCreateCopy(MacOSAll.CGImageRef( AImage.CGImageForProposedRect_context_hints(nil, nil, nil)));
FColored := True;
FPatternColorMode := cpmBitmap;
Rect.origin.x := 0;
Rect.origin.y := 0;
Rect.size := CGSize(AImage.size);
if FCGPattern <> nil then CGPatternRelease(FCGPattern);
FCGPattern := CGPatternCreate(Self, Rect,
CGAffineTransformIdentity, Rect.size.width, Rect.size.height, kCGPatternTilingConstantSpacing,
Ord(FColored), ACallBacks);
1, ACallBacks);
end;
procedure TCocoaBrush.SetColor(AColor: NSColor);
@ -3274,6 +3289,22 @@ begin
end;
end;
procedure TCocoaBrush.DrawPattern(c: CGContextRef);
var
R: CGRect;
sR, sG, sB: single;
begin
R:=CGRectMake(0, 0, CGImageGetWidth(FImage), CGImageGetHeight(FImage));
if FPatternColorMode = cpmContextColor then
begin
CGContextSetRGBFillColor(c, Red/255, Green/255, Blue/255, 1);
CGContextFillRect(c, R);
ColorToRGBFloat(FFgColor, sR, sG, sB);
CGContextSetRGBFillColor(c, sR, sG, sB, 1);
end;
CGContextDrawImage(c, R, FImage);
end;
procedure TCocoaBrush.Clear;
begin
if FColor <> nil then
@ -3313,6 +3344,9 @@ var
AROP2: Integer;
APatternSpace: CGColorSpaceRef;
BaseSpace: CGColorSpaceRef;
sR, sG, sB: single;
sz: CGSize;
offset: TPoint;
begin
if ADC = nil then Exit;
@ -3333,12 +3367,38 @@ begin
if Assigned(FCGPattern) then
begin
if not FColored then
BaseSpace := CGColorSpaceCreateDeviceRGB
else
// Set proper pattern alignment
offset:=ADC.GetLogicalOffset;
with CGPointApplyAffineTransform(CGPointMake(0,0), CGContextGetCTM(ADC.CGContext)) do
begin
BaseSpace := nil;
RGBA[0] := 1.0;
sz.width:=x - offset.X;
sz.height:=y + offset.Y;
sz.width:=Round(sz.width) mod CGImageGetWidth(FImage);
sz.height:=Round(sz.height) mod CGImageGetHeight(FImage);
end;
CGContextSetPatternPhase(ADC.CGContext, sz);
case FPatternColorMode of
cpmBitmap:
begin
BaseSpace := nil;
RGBA[0] := 1.0;
end;
cpmBrushColor:
begin
BaseSpace := CGColorSpaceCreateDeviceRGB;
end;
cpmContextColor:
begin
BaseSpace := CGColorSpaceCreateDeviceRGB;
SetColor(ADC.BkColor, True);
FFgColor:=ColorToRGB(ADC.TextColor);
ColorToRGBFloat(FFgColor, sR, sG, sB);
RGBA[0]:=sR;
RGBA[1]:=sG;
RGBA[2]:=sB;
RGBA[3]:=1.0;
end;
end;
APatternSpace := CGColorSpaceCreatePattern(BaseSpace);
CGContextSetFillColorSpace(ADC.CGContext, APatternSpace);

View File

@ -67,7 +67,6 @@ type
fhscroll : NSScroller;
fvscroll : NSScroller;
public
isHosted: Boolean;
callback: ICommonCallback;
function lclGetCallback: ICommonCallback; override;
procedure lclClearCallback; override;
@ -93,17 +92,6 @@ type
function allocVerticalScroller(avisible: Boolean): NSScroller; message 'allocVerticalScroller:';
// mouse
function acceptsFirstMouse(event: NSEvent): LCLObjCBoolean; override;
procedure mouseDown(event: NSEvent); override;
procedure mouseUp(event: NSEvent); override;
procedure rightMouseDown(event: NSEvent); override;
procedure rightMouseUp(event: NSEvent); override;
procedure rightMouseDragged(event: NSEvent); override;
procedure otherMouseDown(event: NSEvent); override;
procedure otherMouseUp(event: NSEvent); override;
procedure otherMouseDragged(event: NSEvent); override;
procedure mouseDragged(event: NSEvent); override;
procedure mouseMoved(event: NSEvent); override;
procedure scrollWheel(event: NSEvent); override;
end;
{ TCocoaScrollBar }
@ -117,6 +105,8 @@ type
maxInt : Integer;
pageInt : Integer;
suppressLCLMouse: Boolean;
largeInc: Integer;
smallInc: Integer;
procedure actionScrolling(sender: NSObject); message 'actionScrolling:';
function IsHorizontal: Boolean; message 'IsHorizontal';
@ -139,15 +129,14 @@ type
procedure mouseDragged(event: NSEvent); override;
procedure mouseMoved(event: NSEvent); override;
procedure scrollWheel(event: NSEvent); override;
end;
{ TCocoaManualScrollHost }
TCocoaManualScrollHost = objcclass(TCocoaScrollView)
procedure setDocumentView(aview: NSView); override;
function lclContentView: NSView; override;
function lclClientFrame: TRect; override;
procedure scrollWheel(theEvent: NSEvent); override;
end;
function isMouseEventInScrollBar(host: TCocoaManualScrollView; event: NSEvent): Boolean;
@ -187,19 +176,26 @@ end;
function AdjustScrollerPage(sc: TCocoaScrollBar; prt: NSScrollerPart): Boolean;
var
adj : Integer;
adj : integer;
sz : Integer;
dlt : double;
v : double;
begin
Result := isIncDecPagePart(prt);
if not Result then Exit;
Result := false;
case prt of
NSScrollerDecrementPage: adj := -sc.largeInc;
NSScrollerIncrementPage: adj := sc.largeInc;
NSScrollerDecrementLine: adj := -sc.smallInc;
NSScrollerIncrementLine: adj := sc.smallInc;
else
adj := 0;
end;
if adj = 0 then Exit;
sz := sc.maxInt - sc.minInt - sc.pageInt;
if sz = 0 then Exit; // do nothing!
if sc.pageInt = 0 then dlt := 1 / sz
else dlt := sc.pageInt / sz;
if prt = NSScrollerDecrementPage then dlt := -dlt;
dlt := adj / sz;
v := sc.doubleValue;
v := v + dlt;
@ -292,13 +288,6 @@ end;
{ TCocoaManualScrollHost }
procedure TCocoaManualScrollHost.setDocumentView(aview: NSView);
begin
inherited setDocumentView(aview);
if Assigned(aview) and (aview.isKindOfClass(TCocoaManualScrollView)) then
TCocoaManualScrollView(aview).isHosted := true;
end;
function TCocoaManualScrollHost.lclContentView: NSView;
begin
if Assigned(documentView) then
@ -316,6 +305,16 @@ begin
else Result:=inherited lclClientFrame;
end;
procedure TCocoaManualScrollHost.scrollWheel(theEvent: NSEvent);
var
nr : NSResponder;
begin
nr := nextResponder;
// do not call inherited scrollWheel, it suppresses the scroll event
if Assigned(nr) then nr.scrollWheel(theEvent)
else inherited scrollWheel(theEvent);
end;
{ TCocoaManualScrollView }
function TCocoaManualScrollView.lclGetCallback: ICommonCallback;
@ -623,83 +622,6 @@ begin
end;
end;
procedure TCocoaManualScrollView.mouseDown(event: NSEvent);
begin
if isMouseEventInScrollBar(self, event) or not Assigned(callback) or not callback.MouseUpDownEvent(event) then
begin
inherited mouseDown(event);
end;
end;
procedure TCocoaManualScrollView.mouseUp(event: NSEvent);
begin
if isMouseEventInScrollBar(self, event) or not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited mouseUp(event);
end;
procedure TCocoaManualScrollView.rightMouseDown(event: NSEvent);
begin
if isMouseEventInScrollBar(self, event) or not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseDown(event);
end;
procedure TCocoaManualScrollView.rightMouseUp(event: NSEvent);
begin
if isMouseEventInScrollBar(self, event) or not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseUp(event);
end;
procedure TCocoaManualScrollView.rightMouseDragged(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited rightMouseDragged(event);
end;
procedure TCocoaManualScrollView.otherMouseDown(event: NSEvent);
begin
if isMouseEventInScrollBar(self, event) or not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited otherMouseDown(event);
end;
procedure TCocoaManualScrollView.otherMouseUp(event: NSEvent);
begin
if isMouseEventInScrollBar(self, event) or not Assigned(callback) or not callback.MouseUpDownEvent(event) then
inherited otherMouseUp(event);
end;
procedure TCocoaManualScrollView.otherMouseDragged(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited otherMouseDragged(event);
end;
procedure TCocoaManualScrollView.mouseDragged(event: NSEvent);
begin
if not Assigned(callback) or not callback.MouseMove(event) then
inherited mouseDragged(event);
end;
procedure TCocoaManualScrollView.mouseMoved(event: NSEvent);
begin
if isMouseEventInScrollBar(self, event) then
begin
inherited mouseMoved(event)
end
else if not Assigned(callback) or not callback.MouseMove(event) then
inherited mouseMoved(event);
end;
procedure TCocoaManualScrollView.scrollWheel(event: NSEvent);
begin
// when hosted, the processing of scrollWheel is duplciated
if not isHosted then
begin
if isMouseEventInScrollBar(self, event) or not Assigned(callback) or not callback.scrollWheel(event) then
inherited scrollWheel(event);
end;
end;
{ TCocoaScrollView }
function TCocoaScrollView.lclClientFrame: TRect;
@ -736,6 +658,10 @@ begin
if holdscroll>0 then Exit;
inc(holdscroll);
try
// update scrollers (this is required, if scrollWheel was called)
// so processing LM_xSCROLL will not cause any actually scrolling,
// as the current position will match!
self.reflectScrolledClipView(contentView);
if (dx<>0) and assigned(callback) then
callback.scroll(false, round(nw.origin.x));

View File

@ -329,6 +329,7 @@ procedure TextViewSetAllignment(txt: NSTextView; align: TAlignment);
procedure TextFieldSetAllignment(txt: NSTextField; align: TAlignment);
procedure TextFieldSetBorderStyle(txt: NSTextField; astyle: TBorderStyle);
procedure RadioButtonSwitchSiblings(checkedRadio: NSButton);
procedure ButtonSetState(btn: NSButton; NewState: TCheckBoxState);
procedure ScrollViewSetScrollStyles(AScroll: TCocoaScrollView; AStyles: TScrollStyle);
@ -447,6 +448,20 @@ begin
end;
end;
procedure ButtonSetState(btn: NSButton; NewState: TCheckBoxState);
const
buttonState: array [TcheckBoxState] of NSInteger =
(NSOffState, NSOnState, NSMixedState);
begin
if NewState = cbGrayed then
{$ifdef BOOLFIX}
btn.setAllowsMixedState_(Ord(true));
{$else}
btn.setAllowsMixedState(true);
{$endif}
btn.setState(buttonState[NewState]);
end;
procedure ScrollViewSetScrollStyles(AScroll: TCocoaScrollView; AStyles: TScrollStyle);
begin
AScroll.setHasVerticalScroller(VerticalScrollerVisible[AStyles]);
@ -773,7 +788,8 @@ end;
class function TCocoaWSCustomCheckBox.CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): TLCLIntfHandle;
var
btn: NSButton;
btn: TCocoaButton;
cb: IButtonCallback;
begin
btn := AllocButton(AWinControl, TLCLCheckBoxCallBack, AParams, 0, NSSwitchButton);
// changes in AllowGrayed are never sent to WS!
@ -784,6 +800,14 @@ begin
{$else}
NSButton(btn).setAllowsMixedState(true);
{$endif}
;
//todo: This place needs a cleanup!
// Assigning state, while having callback removed
// TCocoaButton.setState is causing OnChange event, if callback is not nil
cb := btn.callback;
btn.callback := nil;
ButtonSetState(btn, TCustomCheckBox(AWinControl).State);
btn.callback := cb;
Result := TLCLIntfHandle(btn);
end;
@ -820,16 +844,8 @@ class procedure TCocoaWSCustomCheckBox.SetState(
const
buttonState: array [TcheckBoxState] of NSInteger = (NSOffState, NSOnState, NSMixedState);
begin
if ACustomCheckBox.HandleAllocated then
begin
if NewState = cbGrayed then
{$ifdef BOOLFIX}
NSButton(ACustomCheckBox.Handle).setAllowsMixedState_(Ord(true));
{$else}
NSButton(ACustomCheckBox.Handle).setAllowsMixedState(true);
{$endif}
NSButton(ACustomCheckBox.Handle).setState(buttonState[NewState]);
end;
if not ACustomCheckBox.HandleAllocated then Exit;
ButtonSetState(NSButton(ACustomCheckBox.Handle), ACustomCheckBox.State);
end;
class procedure TCocoaWSCustomCheckBox.GetPreferredSize(
@ -872,18 +888,28 @@ end;
class function TCocoaWSRadioButton.CreateHandle(const AWinControl: TWinControl;
const AParams: TCreateParams): TLCLIntfHandle;
var
btn: NSButton;
btn: TCocoaButton;
cb: IButtonCallback;
begin
btn := AllocButton(AWinControl, TLCLRadioButtonCallback, AParams, 0, NSRadioButton);
Result := TLCLIntfHandle(btn);
//todo: this needs to be improved!
cb := btn.callback;
btn.callback := nil;
ButtonSetState(btn, TCustomCheckBox(AWinControl).State);
btn.callback := cb;
end;
class procedure TCocoaWSRadioButton.SetState(
const ACustomCheckBox: TCustomCheckBox; const NewState: TCheckBoxState);
var
btn : NSButton;
begin
if not ACustomCheckBox.HandleAllocated then Exit;
btn := NSButton(ACustomCheckBox.Handle);
if NewState = cbChecked then
RadioButtonSwitchSiblings(NSButton(ACustomCheckBox.Handle));
TCocoaWSCustomCheckBox.SetState(ACustomCheckBox, NewState);
RadioButtonSwitchSiblings(btn);
ButtonSetState(btn, NewState);
end;
{ TCocoaWSCustomStaticText }
@ -1939,6 +1965,10 @@ begin
scr.minInt:=TCustomScrollBar(AWinControl).Min;
scr.maxInt:=TCustomScrollBar(AWinControl).Max;
scr.pageInt:=TCustomScrollBar(AWinControl).PageSize;
scr.largeInc:=abs(TCustomScrollBar(AWinControl).LargeChange);
scr.smallInc:=abs(TCustomScrollBar(AWinControl).SmallChange);
if scr.largeInc=0 then scr.largeInc:=1;
if scr.smallInc=0 then scr.smallInc:=1;
Result:=TLCLIntfHandle(scr);