View Issue Details

IDProjectCategoryView StatusLast Update
0032828LazarusWidgetsetpublic2017-12-18 19:48
ReporterDavid Jenkins Assigned ToDmitry Boyarintsev  
PrioritynormalSeverityminorReproducibilityhave not tried
Status assignedResolutionopen 
Summary0032828: TListBox cocoa widgetset implementation missing functionality
Description1) Text entered in an editable ListBox field is not updated in widget
2) When listbox is in a scrollview the mouse and keyboard activity are not displayed in a Listbox edit field.
3) Now owner draw functionality.
Additional Information1) Add textDidChange() function to TCocoaTextField that calls callback.SendOnTextChanged so that updated text can be caught
2) When TCocoaFieldEditor is used within a NSScrollView the needsDisplay path doesn't work out quite right. This shows up when mouse and keyboard action in the fields doesn't result in updates (but if you mouse to another app and then come back the updates are shown). Overriding setNeedsDisplayInRect_avoidAdditionalLayout that calls the setNeedsDisplay of the parent fixes this.
3) Allow for owner draw by overriding TCooaListBox.drawRow_clipRect() and setting up a call to LCLSendDrawListItemMsg().

Patch attached.
TagsNo tags attached.
Fixed in Revision
LazTarget-
Widgetset
Attached Files

Activities

David Jenkins

2017-12-14 22:58

reporter  

ListBox.diff (2,808 bytes)   
Index: cocoaprivate.pp
===================================================================
--- cocoaprivate.pp	(revision 22606)
+++ cocoaprivate.pp	(revision 22655)
@@ -250,6 +250,7 @@
     // key
     //procedure keyDown(event: NSEvent); override; -> keyDown doesn't work in NSTextField
     procedure keyUp(event: NSEvent); override;
+    procedure textDidChange(notification: NSNotification); override;
   end;
 
   { TCocoaSecureTextField }
@@ -346,6 +347,7 @@
   public
     lastEditBox: NSTextField;
     function resignFirstResponder: Boolean; override;
+    procedure setNeedsDisplayInRect_avoidAdditionalLayout(rect: NSRect; flag: Boolean); override;
   end;
 
   { TCocoaWindow }
@@ -610,6 +612,8 @@
 
     procedure tableViewSelectionDidChange(notification: NSNotification); message 'tableViewSelectionDidChange:';
 
+    procedure drawRow_clipRect(row: NSInteger; clipRect: NSRect); override;
+
     procedure dealloc; override;
     procedure resetCursorRects; override;
 
@@ -1241,6 +1245,13 @@
   Result := inherited resignFirstResponder;
 end;
 
+procedure TCocoaFieldEditor.setNeedsDisplayInRect_avoidAdditionalLayout(rect: NSRect; flag: Boolean);
+begin
+  inherited setNeedsDisplayInRect_avoidAdditionalLayout(rect, flag);
+  if (lastEditBox <> nil) then
+    lastEditBox.setNeedsDisplay_(True);
+end;
+
 { TCocoaWindow }
 
 function TCocoaWindow.lclIsHandle: Boolean;
@@ -1966,6 +1977,12 @@
   inherited keyUp(event);
 end;
 
+procedure TCocoaTextField.textDidChange(notification: NSNotification);
+begin
+  if callback <> nil then
+    callback.SendOnTextChanged;
+end;
+
 { TCocoaTextView }
 
 function TCocoaTextView.lclIsHandle: Boolean;
@@ -2599,7 +2616,7 @@
   svHeight: CGFloat;
 begin
   svHeight := GetNSViewSuperViewHeight(Self);
-  if Assigned(superview)  then
+  if Assigned(superview) and not superview.isFlipped  then
   begin
     LCLToNSRect(r, svHeight, ns)
   end
@@ -2829,6 +2846,29 @@
   end;
 end;
 
+procedure TCocoaListBox.drawRow_clipRect(row: NSInteger; clipRect: NSRect);
+var
+  DrawStruct: TDrawListItemStruct;
+  ctx: TCocoaContext;
+  LCLObject: TCustomListBox;
+begin
+  inherited;
+  ctx := TCocoaContext.Create(NSGraphicsContext.currentContext);
+  DrawStruct.Area := NSRectToRect(rectOfRow(row));
+  DrawStruct.DC := HDC(ctx);
+  DrawStruct.ItemID :=  row;
+
+  LCLObject := TCustomListBox(callback.GetTarget);
+  DrawStruct.ItemState := [];
+  if isRowSelected(row) then
+    Include(DrawStruct.ItemState, odSelected);
+  if not LCLObject.Enabled then
+    Include(DrawStruct.ItemState, odDisabled);
+  if (LCLObject.Focused) and (LCLObject.ItemIndex = row) then
+    Include(DrawStruct.ItemState, odFocused);
+  LCLSendDrawListItemMsg(TWinControl(callback.GetTarget), @DrawStruct);
+end;
+
 procedure TCocoaListBox.dealloc;
 begin
   FreeAndNil(list);
ListBox.diff (2,808 bytes)   

Dmitry Boyarintsev

2017-12-16 04:49

developer   ~0104756

Last edited: 2017-12-17 00:00

View 3 revisions

thank you for the patch.
it has been *partially* applied in r56755.

a question:
* is there a project sample to demonstrate point 2)?

CudaText man

2017-12-16 12:28

reporter   ~0104758

Dmitry, can you maybe see buttons-small-size issue
0030577
?

David Jenkins

2017-12-18 15:34

reporter   ~0104805

I can try to create a sample project for this it was a little complex. It needs to be a listbox inside of a scrollwindow but may have some other dependencies that our program has that I didn't notice at the time. I tracked the problem down by stepping through OSX assembly code.

David Jenkins

2017-12-18 19:42

reporter   ~0104812

I cannot get the point 2 bug to repeat. I reverted my code base to where it was before I check in that change and it doesn't repeat there either. Back in October it repeated just fine and I spent 5 days rooting through Cocoa assembly code to figure out what was going on and create a patch.

The symptoms at the time where that when I tried to enter text I did not see any immediate change in the edit box. If I left the window, covered it with the window from another app, and then clicked on the window to re-activate it the text would show. I.e. invalidation/redrawing wasn't happening.

Stepping through code what I saw was that the Cocoa code was skipping the parent window of the FieldEditor when sending setNeedsDisplay down through the window child stack. Calling lasEditBox.setNeedsDisplay_(True) in TCocoaFieldEditor.setNeedsDisplayInRect_avoidAdditionalLayout() fixed that skip.

With that call removed in my current code base or reverting back to before the change I no longer see the lack of invalidation - key strokes immediately show up in the edit box.

If you prefer to skip this part of the code, in the patch it is lines

@@ -346,6 +347,7 @@
   public
     lastEditBox: NSTextField;
     function resignFirstResponder: Boolean; override;
+ procedure setNeedsDisplayInRect_avoidAdditionalLayout(rect: NSRect; flag: Boolean); override;
   end;
 
   { TCocoaWindow }


@@ -1241,6 +1245,13 @@
   Result := inherited resignFirstResponder;
 end;
 
+procedure TCocoaFieldEditor.setNeedsDisplayInRect_avoidAdditionalLayout(rect: NSRect; flag: Boolean);
+begin
+ inherited setNeedsDisplayInRect_avoidAdditionalLayout(rect, flag);
+ if (lastEditBox <> nil) then
+ lastEditBox.setNeedsDisplay_(True);
+end;
+
 { TCocoaWindow }
 
 function TCocoaWindow.lclIsHandle: Boolean;

David Jenkins

2017-12-18 19:48

reporter   ~0104814

I should add that the point 2 bug only showed up (back when it did) when the TListBox was inside a NSScrollView / ScrollBox. Other ListBoxen that didn't need to scroll never had the problem.

Issue History

Date Modified Username Field Change
2017-12-14 22:58 David Jenkins New Issue
2017-12-14 22:58 David Jenkins File Added: ListBox.diff
2017-12-15 15:15 Dmitry Boyarintsev Assigned To => Dmitry Boyarintsev
2017-12-15 15:15 Dmitry Boyarintsev Status new => assigned
2017-12-16 04:49 Dmitry Boyarintsev LazTarget => -
2017-12-16 04:49 Dmitry Boyarintsev Note Added: 0104756
2017-12-16 04:49 Dmitry Boyarintsev Status assigned => feedback
2017-12-16 04:50 Dmitry Boyarintsev Note Edited: 0104756 View Revisions
2017-12-16 12:28 CudaText man Note Added: 0104758
2017-12-17 00:00 Dmitry Boyarintsev Note Edited: 0104756 View Revisions
2017-12-18 15:34 David Jenkins Note Added: 0104805
2017-12-18 15:34 David Jenkins Status feedback => assigned
2017-12-18 19:42 David Jenkins Note Added: 0104812
2017-12-18 19:48 David Jenkins Note Added: 0104814