Page 1 of 1

How to change color of NSSearchField?

Posted: Sat Feb 18, 2017 11:31 am
by Wolfram
How can I change the background color of a NSSearchField?

Code: Select all

Global Window_0


Procedure OpenWindow_0(x = 0, y = 0, width = 450, height = 160)
  Window_0 = OpenWindow(#PB_Any, x, y, width, height, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  Frame.NSRect
  Frame\origin\x = 164
  Frame\origin\y = 10
  Frame\size\width = 120
  Frame\size\height = 25
  
  CocoaMessage(@SearchField, #Null, "NSSearchField alloc")
  
  CocoaMessage(0, SearchField, "initWithFrame:@", @Frame)
  
  CocoaMessage(@contentView, WindowID(Window_0), "contentView")
  
  CocoaMessage(0, contentView, "addSubview:", SearchField)
  
  CocoaMessage(0, SearchField, "cell")

  
EndProcedure

Procedure Window_0_Events(event)
  Select event
    Case #PB_Event_CloseWindow
      ProcedureReturn #False

    Case #PB_Event_Menu
      Select EventMenu()
	Case #PB_Menu_Quit
          ProcedureReturn #False
      EndSelect

    Case #PB_Event_Gadget
      Select EventGadget()
          
      EndSelect
  EndSelect
  ProcedureReturn #True
EndProcedure

OpenWindow_0()

Repeat
  event = WaitWindowEvent()
Until Window_0_Events(event) = #False

End

Re: How to change color of NSSearchField?

Posted: Sat Feb 18, 2017 4:40 pm
by wilbert
I doesn't seem to be easy.

This does something on my computer but only when I click on the search field.

Code: Select all

  Color = CocoaMessage(0, 0, "NSColor yellowColor")
  CocoaMessage(0, SearchField, "setBezelStyle:", 0)
  CocoaMessage(0, SearchField, "setBackgroundColor:", Color)

Re: How to change color of NSSearchField?

Posted: Sat Feb 18, 2017 6:15 pm
by Wolfram
wilbert wrote:I doesn't seem to be easy.

This does something on my computer but only when I click on the search field.

Code: Select all

  Color = CocoaMessage(0, 0, "NSColor yellowColor")
  CocoaMessage(0, SearchField, "setBezelStyle:", 0)
  CocoaMessage(0, SearchField, "setBackgroundColor:", Color)
Thanks Wilbert!
Here it is directly changed, but now it isn't round anymore.

I fond some information but I'm not able to translate it into PB.
https://www.64k-tec.de/2010/06/changing ... -controls/

Maybe it helps you.

Re: How to change color of NSSearchField?

Posted: Sun Feb 19, 2017 8:23 am
by Shardik
Wolfram wrote:Here it is directly changed, but now it isn't round anymore.
According to Apple's documentation Wilbert's method doesn't work with rounded NSSearchFields:
[color=#0040FF][u]Apple's API reference for drawsBackground[/u][/color] wrote:When the value of this property is YES, the cell draws its background color. In order to prevent inconsistent rendering, background color rendering is automatically disabled for rounded-bezel text fields.

You have to subclass the NSSeachFieldCell and set a callback on drawInteriorWithFrame:inView: to change the background color. Unfortunately Apple has changed some internals of the NSSearchField beginning with Yosemite, so that the following example currently only works up to Mavericks. I have tested the following example with PB 5.44 x86 and x64 in ASCII and Unicode mode on these MacOS versions (+ works, - doesn't work):
+ 10.6.8 (Snow Leopard, only x86)
+ 10.7.5 (Lion)
+ 10.9.5 (Mavericks)
- 10.10.5 (Yosemite)
- 10.12.3 (Sierra)

Code: Select all

EnableExplicit

Define ContentView.I
Define Frame.NSRect
Define SearchFieldCell.I
Define SearchField.I
Define SubclassedSearchFieldCell.I

ProcedureC SubclassedSearchFieldCellCallback(Object.I, Selector.I,
  x86.F, y86.F, Width86.F, Height86.F, ParentView.I, D1.D, D2.D, D3.D, D4.D,
  x64.D, y64.D, Width64.D, Height64.D)
  Protected CellFrame.NSRect
  Protected BackColor.I
  Protected Radius.CGFloat
  Protected SearchFieldWidth.CGFloat

  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    CellFrame\origin\x = x64 + 1
    CellFrame\origin\y = y64 + 3
    CellFrame\size\width = Width64 - 2
    CellFrame\size\height = Height64 - 5
  CompilerElse
    CellFrame\origin\x = x86 + 1
    CellFrame\origin\y = y86 + 3
    CellFrame\size\width = Width86 - 2
    CellFrame\size\height = Height86 - 5
  CompilerEndIf

  BackColor = CocoaMessage(0, 0, "NSColor yellowColor")
  Radius = CellFrame\size\height / 2.0
  CocoaMessage(0, BackColor, "setFill")
  CocoaMessage(0, CocoaMessage(0, 0,
    "NSBezierPath bezierPathWithRoundedRect:@", @CellFrame,
    "xRadius:@", @Radius,
    "yRadius:@", @Radius),
    "fill")

  ; ----- Draw search button
  SearchFieldWidth = CellFrame\size\width
  CellFrame\size\width = 20
  CocoaMessage(0, CocoaMessage(0, Object, "searchButtonCell"),
    "drawInteriorWithFrame:@", @CellFrame,
    "inView:", ParentView)

  ; ----- Draw cancel button
  CellFrame\origin\x = SearchFieldWidth - 20
  CocoaMessage(0, CocoaMessage(0, Object, "cancelButtonCell"),
    "drawInteriorWithFrame:@", @CellFrame,
    "inView:", ParentView)
EndProcedure

OpenWindow(0, 270, 100, 220, 50, "Colored NSSearchField")
 
; ----- Create NSSearchField
Frame\origin\x = 10
Frame\origin\y = 10
Frame\size\width = WindowWidth(0) - 20
Frame\size\height = 25
SearchField = CocoaMessage(0, 0, "NSSearchField alloc")
CocoaMessage(0, SearchField, "initWithFrame:@", @Frame)
ContentView = CocoaMessage(0, WindowID(0), "contentView")
CocoaMessage(0, ContentView, "addSubview:", SearchField)

; ----- Subclass NSSearchFieldCell
SearchFieldCell = CocoaMessage(0, SearchField, "cell")
SubclassedSearchFieldCell = objc_allocateClassPair_(CocoaMessage(0,
  SearchFieldCell, "class"), "SubclassedSearchFieldCell", 0)
objc_registerClassPair_(SubclassedSearchFieldCell)
object_setClass_(SearchFieldCell, SubclassedSearchFieldCell)
class_addMethod_(SubclassedSearchFieldCell,
  sel_registerName_("drawInteriorWithFrame:inView:"),
  @SubclassedSearchFieldCellCallback(), "v@:@@")

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Re: How to change color of NSSearchField?

Posted: Sun Feb 19, 2017 2:25 pm
by Wolfram
Nice!
But now the search string isn't shown if the search field lost it's focus.

Do you have any idea?

Re: How to change color of NSSearchField?

Posted: Tue Feb 28, 2017 9:27 pm
by Shardik
Wolfram wrote:But now the search string isn't shown if the search field lost it's focus.

Do you have any idea?
The following new code example displays the search string even when the search field lost it's focus (tested successfully on MacOS 10.6.8 'Snow Leopard' with PB 5.44 x86 in ASCII and Unicode mode and on MacOS 10.7.5 'Lion' with PB 5.44 x86 and x64 in ASCII and Unicode mode):

Code: Select all

EnableExplicit

#NSFocusRingOnly = 0

ImportC ""
  NSRectFill(*Rect.NSRect)
  NSSetFocusRingStyle(FocusRingPlacement.I)
EndImport

Define Frame.NSRect
Define SearchField.I
Define SearchFieldCell.I
Define SubclassedSearchFieldCell.I

ProcedureC SubclassedSearchFieldCellCallback(SearchFieldCell.I, Selector.I,
  x86.F, y86.F, Width86.F, Height86.F, SearchField.I, D1.D, D2.D, D3.D, D4.D,
  x64.D, y64.D, Width64.D, Height64.D)
  Protected BackColor.I
  Protected CellFrame.NSRect
  Protected Radius.CGFloat

  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    CellFrame\origin\x = x64 + 1
    CellFrame\origin\y = y64 + 3
    CellFrame\size\width = Width64 - 2
    CellFrame\size\height = Height64 - 5
  CompilerElse
    CellFrame\origin\x = x86 + 1
    CellFrame\origin\y = y86 + 3
    CellFrame\size\width = Width86 - 2
    CellFrame\size\height = Height86 - 5
  CompilerEndIf

  ; ----- Fill in back color
  BackColor = CocoaMessage(0, 0, "NSColor yellowColor")
  Radius = CellFrame\size\height / 2.0
  CocoaMessage(0, BackColor, "setFill")
  CocoaMessage(0, CocoaMessage(0, 0,
    "NSBezierPath bezierPathWithRoundedRect:@", @CellFrame,
    "xRadius:@", @Radius,
    "yRadius:@", @Radius),
    "fill")

  ; ----- Draw text content and buttons
  CellFrame\origin\x - 1
  CocoaMessage(0, SearchFieldCell,
    "drawInteriorWithFrame:@", @CellFrame,
    "inView:", SearchField)

  ; ----- Draw border around search field
  Radius + 1
  CocoaMessage(0, CocoaMessage(0, 0, "NSColor lightGrayColor"), "setStroke")
  CocoaMessage(0, CocoaMessage(0, 0,
    "NSBezierPath bezierPathWithRoundedRect:@", @CellFrame,
    "xRadius:@", @Radius,
    "yRadius:@", @Radius),
    "stroke")

  If CocoaMessage(0, SearchFieldCell, "showsFirstResponder")
    ; ----- Draw focus ring around search field
    CocoaMessage(0, 0, "NSGraphicsContext saveGraphicsState")
    NSSetFocusRingStyle(#NSFocusRingOnly)
    CocoaMessage(0, CocoaMessage(0, 0,
      "NSBezierPath bezierPathWithRoundedRect:@", @CellFrame,
      "xRadius:@", @Radius,
      "yRadius:@", @Radius),
      "fill")
    CocoaMessage(0, 0, "NSGraphicsContext restoreGraphicsState")
  EndIf
EndProcedure

OpenWindow(0, 270, 100, 220, 75, "Colored NSSearchField")
StringGadget(0, 70, 40, 80, 25, "")

; ----- Create NSSearchField
Frame\origin\x = 10
Frame\origin\y = 10
Frame\size\width = WindowWidth(0) - 20
Frame\size\height = 25
SearchField = CocoaMessage(0, 0, "NSSearchField alloc")
CocoaMessage(0, SearchField, "initWithFrame:@", @Frame)
CocoaMessage(0, CocoaMessage(0, WindowID(0), "contentView"),
  "addSubview:", SearchField)

; ----- Get NSSearchFieldCell
SearchFieldCell = CocoaMessage(0, SearchField, "cell")

; ----- Subclass NSSearchFieldCell
SubclassedSearchFieldCell = objc_allocateClassPair_(CocoaMessage(0,
  SearchFieldCell, "class"), "SubclassedSearchFieldCell", 0)
object_setClass_(SearchFieldCell, SubclassedSearchFieldCell)
objc_registerClassPair_(SubclassedSearchFieldCell)

; ----- Set callback in SearchFieldCell for method drawWithFrame:inView:
class_addMethod_(SubclassedSearchFieldCell,
  sel_registerName_("drawWithFrame:inView:"),
  @SubclassedSearchFieldCellCallback(), "v@:@@")

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Re: How to change color of NSSearchField?

Posted: Mon Feb 11, 2019 3:47 pm
by Wolfram
Unfortunately these code does't work anymore.
It works on OSX 10.7.5, PB 5.46, Xcode 4.6.3, but not on OSX 10.13.6, PB 5.46 /5.62, Xcode 8.3.3 / 10.
The callback is't called anymore.

Dose someone have a idea for a reason?

As Shardik says Apple made some changes on the NSSearchField, but I could find out what?

Re: How to change color of NSSearchField?

Posted: Wed Feb 13, 2019 8:48 pm
by Shardik
The following example works on MacOS 10.13.6 'High Sierra' with Xcode 10.1 and PB 5.46 x64 in ASCII and Unicode mode:

Code: Select all

EnableExplicit

Define ContentView.I
Define Rect.NSRect
Define SearchField.I

Procedure SetBackColor(SearchField.I, BackColor.I)
  Protected Alpha.CGFloat
  Protected Blue.CGFloat
  Protected CIColor.I
  Protected Filter.I
  Protected FilterArray.I
  Protected Green.CGFloat
  Protected Red.CGFloat

  Alpha = 1
  Red = Red(BackColor) / 255
  Green = Green(BackColor) / 255
  Blue = Blue(BackColor) / 255
  Filter = CocoaMessage(0, 0, "CIFilter filterWithName:$", @"CIFalseColor")
  CocoaMessage(0, Filter, "setDefaults")
  CIColor = CocoaMessage(0, 0, "CIColor colorWithRed:@", @Red,
    "green:@", @Green, "blue:@", @Blue)
  CocoaMessage(0, Filter,
    "setValue:", CIColor,
    "forKey:$", @"inputColor1")
  FilterArray = CocoaMessage(0, 0, "NSArray arrayWithObject:", Filter)
  CocoaMessage(0, SearchField, "setWantsLayer:", #YES)
  CocoaMessage(0, SearchField, "setContentFilters:", FilterArray)
EndProcedure

OpenWindow(0, 270, 100, 220, 45, "Colored NSSearchField")

; ----- Create NSSearchField
Rect\origin\x = 20
Rect\origin\y = 10
Rect\size\width = WindowWidth(0) - 40
Rect\size\height = 25
SearchField = CocoaMessage(0, 0, "NSSearchField alloc")
CocoaMessage(0, SearchField, "initWithFrame:@", @Rect)
ContentView = CocoaMessage(0, WindowID(0), "contentView")
CocoaMessage(0, ContentView, "addSubview:", SearchField)
SetBackColor(SearchField, $FFFF00)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow