Page 7 of 16

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Mar 14, 2013 7:20 am
by wilbert
Disable selection highlighting of a ListIconGadget (OS X 10.6+)

Code: Select all

OpenWindow(0, 200, 100, 430, 100, "Disable highlight example")

ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20, "Name", 110)
CocoaMessage(0, GadgetID(0), "setSelectionHighlightStyle:", -1); ** don't highlight selection **

AddGadgetColumn(0, 1, "Address", GadgetWidth(0) - GetGadgetItemAttribute(0, 0, #PB_ListIcon_ColumnWidth) - 8)
AddGadgetItem(0, -1, "Harry Rannit" + #LF$ + "12 Parliament Way, Battle Street, By the Bay")
AddGadgetItem(0, -1, "Ginger Brokeit" + #LF$ + "130 PureBasic Road, BigTown, CodeCity")
AddGadgetItem(0, -1, "Didi Foundit" + #LF$ + "321 Logo Drive, Mouse House, Downtown")

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Sun Mar 31, 2013 7:05 am
by J. Baker
Insert text at the cursor position.

Code: Select all

If OpenWindow(0, 0, 0, 322, 180, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    EditorGadget(0, 8, 8, 306, 133)
    For a = 0 To 5
      AddGadgetItem(0, a, "Line "+Str(a))
    Next
    
    SetActiveGadget(0)
    
    ButtonGadget(1, 115, 150, 100, 25, "Insert Text")
    
 Repeat
   
   Event = WaitWindowEvent()
  
  If Event = #PB_Event_Gadget

      Select EventGadget()
          
        Case 1
          CocoaMessage(0, GadgetID(0), "insertText:$", @" My inserted test!")
          
      EndSelect
      
  EndIf
    
 Until Event = #PB_Event_CloseWindow
    
EndIf

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Tue Apr 02, 2013 3:21 pm
by wilbert
Set the text color of specific areas of an EditorGadget

Code: Select all

Procedure SetTextColorABGR(EditorGadget, Color, StartPosition, Length = -1, BackColor = #NO)
  Protected.CGFloat r,g,b,a
  Protected range.NSRange, textStorage.i
  If StartPosition > 0
    textStorage = CocoaMessage(0, GadgetID(EditorGadget), "textStorage")
    range\location = StartPosition - 1
    range\length = CocoaMessage(0, textStorage, "length") - range\location
    If range\length > 0
      If Length >= 0 And Length < range\length
        range\length = Length
      EndIf
      r = Red(Color) / 255
      g = Green(Color) / 255
      b = Blue(Color) / 255
      a = Alpha(Color) / 255
      Color = CocoaMessage(0, 0, "NSColor colorWithDeviceRed:@", @r, "green:@", @g, "blue:@", @b, "alpha:@", @a)
      If BackColor
        CocoaMessage(0, textStorage, "addAttribute:$", @"NSBackgroundColor", "value:", Color, "range:@", @range)
      Else
        CocoaMessage(0, textStorage, "addAttribute:$", @"NSColor", "value:", Color, "range:@", @range)
      EndIf
    EndIf
  EndIf
EndProcedure


; test the procedure

If OpenWindow(0, 0, 0, 322, 150, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  EditorGadget(0, 8, 8, 306, 133)
  SetGadgetText(0, "This is a test string to test if coloring" + #CRLF$ + "specific areas will work")
  
  SetTextColorABGR(0, $ff008000, 1); make entire text green
  SetTextColorABGR(0, $ff000080, 1, 7); make first seven characters red
  SetTextColorABGR(0, $ff00f0ff, 1, 4, #YES); set background color of first four characters 
      
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
The same but for TextGadget

Code: Select all

Procedure SetTextColorABGR(TextGadget, Color, StartPosition, Length = -1, BackColor = #NO)
  Protected.CGFloat r,g,b,a
  Protected range.NSRange, MAString.i
  If StartPosition > 0
    
    MAString = CocoaMessage(0, CocoaMessage(0, 0, "NSMutableAttributedString alloc"), "initWithAttributedString:", 
                            CocoaMessage(0, GadgetID(TextGadget), "attributedStringValue"))
    
    range\location = StartPosition - 1
    range\length = CocoaMessage(0, MAString, "length") - range\location
    If range\length > 0
      If Length >= 0 And Length < range\length
        range\length = Length
      EndIf
      r = Red(Color) / 255
      g = Green(Color) / 255
      b = Blue(Color) / 255
      a = Alpha(Color) / 255
      Color = CocoaMessage(0, 0, "NSColor colorWithDeviceRed:@", @r, "green:@", @g, "blue:@", @b, "alpha:@", @a)
      If BackColor
        CocoaMessage(0, MAString, "addAttribute:$", @"NSBackgroundColor", "value:", Color, "range:@", @range)
      Else
        CocoaMessage(0, MAString, "addAttribute:$", @"NSColor", "value:", Color, "range:@", @range)
      EndIf
    EndIf
    CocoaMessage(0, GadgetID(TextGadget), "setAttributedStringValue:", MAString)
  EndIf
EndProcedure


; test the procedure

If OpenWindow(0, 0, 0, 322, 150, "TextGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  TextGadget(0, 8, 8, 306, 133, "")
  SetGadgetText(0, "This is a test string to test if coloring" + #CRLF$ + "specific areas will work")
  
  SetTextColorABGR(0, $ff008000, 1); make entire text green
  SetTextColorABGR(0, $ff000080, 1, 7); make first seven characters red
  SetTextColorABGR(0, $ff00f0ff, 1, 4, #YES); set background color of first four characters 
      
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Sat Apr 06, 2013 8:29 pm
by Shardik
Display an alert (MessageRequester with OK button) specifying a predefined icon:

Code: Select all

EnableExplicit

#kOnSystemDisk = -32768
#kSystemIconsCreator = $6D616373

; ----- Predefined alert icons
#kGenericApplicationIcon =  $4150504C ; 'APPL'
#kAlertCautionIcon       =  $63617574 ; 'caut'
#kAlertNoteIcon          = $6E6F7465 ; 'note'
#kAlertStopIcon          = $73746F70 ; 'stop'

ImportC ""
  GetIconRef(StartVolume.W, Creator.L, IconID.L, *IconRef)
  ReleaseIconRef(IconRef.I)
EndImport

Procedure MessageRequesterEx(Title.S, Info.S, IconID.L)
  Protected Alert.I
  Protected IconRef.L
  Protected Image.I

  Alert = CocoaMessage(0, CocoaMessage(0, 0, "NSAlert new"), "autorelease")
  CocoaMessage(0, Alert, "setMessageText:$", @Title)
  CocoaMessage(0, Alert, "setInformativeText:$", @Info)
  
  If GetIconRef(#kOnSystemDisk, #kSystemIconsCreator, IconID, @IconRef) = 0
    Image = CocoaMessage(0, 0, "NSImage alloc")
    CocoaMessage(0, Image, "initWithIconRef:", IconRef)
    CocoaMessage(0, Alert, "setIcon:@", @Image)
    CocoaMessage(0, Alert, "runModal")
    CocoaMessage(0, Image, "release")
    ReleaseIconRef(IconRef)
  EndIf
EndProcedure

MessageRequesterEx("Icon demo 1", "Requester with app icon", #kGenericApplicationIcon)
MessageRequesterEx("Icon demo 2", "Requester with caution icon", #kAlertCautionIcon)
MessageRequesterEx("Icon demo 3", "Requester with note icon", #kAlertNoteIcon)
MessageRequesterEx("Icon demo 4", "Requester with stop icon", #kAlertStopIcon)
Update 1: I have added the ReleaseIconRef() function to properly decrease the icon reference count after displaying the requester and thus closing a memory leak.

Update 2: Wilbert sent me a PM with a simplified solution which doesn't need anymore to import the outdated Carbon functions. Thank you for that nice hint, Wilbert!

Code: Select all

EnableExplicit

Global Workspace.i = CocoaMessage(0, 0, "NSWorkspace sharedWorkspace")

Procedure MessageRequesterEx(Title.s, Info.s, Type.s)
  Protected Alert.i = CocoaMessage(0, CocoaMessage(0, 0, "NSAlert new"), "autorelease")
  CocoaMessage(0, Alert, "setMessageText:$", @Title)
  CocoaMessage(0, Alert, "setInformativeText:$", @Info)
  CocoaMessage(0, Alert, "setIcon:", CocoaMessage(0, Workspace, "iconForFileType:$", @Type))
  CocoaMessage(0, Alert, "runModal")
EndProcedure

MessageRequesterEx("Icon demo 1", "Requester with app icon", "'APPL'")
MessageRequesterEx("Icon demo 2", "Requester with caution icon", "'caut'")
MessageRequesterEx("Icon demo 3", "Requester with note icon", "'note'")
MessageRequesterEx("Icon demo 4", "Requester with stop icon", "'stop'")

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Mon Apr 08, 2013 8:58 pm
by Shardik
Get description of your time zone, whether daylight saving is activated, if yes the current time offset, and the date of the next daylight saving transition:

Code: Select all

EnableExplicit

Define DaylightSaving.I
Define Info.S
Define LastTransitionDate.D
Define NextTransitionDate.D
Define TimeOffsetInSeconds.D
Define TimeZoneObject.I

TimeZoneObject = CocoaMessage(0, 0, "NSTimeZone systemTimeZone")
CocoaMessage(@DaylightSaving, TimeZoneObject, "isDaylightSavingTime")

If DaylightSaving
  Info + "Daylight saving is activated." + #CR$
  CocoaMessage(@TimeOffsetInSeconds, TimeZoneObject, "daylightSavingTimeOffset")
  Info + "Time offset = " + Str(Int(TimeOffsetInSeconds) / 60) + " minutes" + #CR$
Else
  Info + "Daylight saving is deactivated."
EndIf

Info + "Time zone description: " + PeekS(CocoaMessage(0, CocoaMessage(0, TimeZoneObject, "description"), "UTF8String"), -1, #PB_UTF8) + #CR$

CocoaMessage(@NextTransitionDate, CocoaMessage(0, TimeZoneObject, "nextDaylightSavingTimeTransition"), "timeIntervalSince1970")
Info + "Next daylight saving transition: " + FormatDate("%yyyy-%mm-%dd %hh:%ii:%ss", Int(NextTransitionDate)) + #CR$

MessageRequester("Time zone infos", Info)

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Tue Apr 09, 2013 1:13 pm
by wilbert
Get all file names from a directory including all files in all of its subdirectories.

Code: Select all

Dir.s = #PB_Compiler_Home + "purelibraries"

FileManager = CocoaMessage(0, 0, "NSFileManager defaultManager")
DirEnum = CocoaMessage(0, FileManager, "enumeratorAtPath:$", @Dir)

File = CocoaMessage(0, DirEnum, "nextObject")
While File

  FileName.s = PeekS(CocoaMessage(0, File, "UTF8String"), -1, #PB_UTF8)
  Debug FileName
  
  File = CocoaMessage(0, DirEnum, "nextObject")
Wend

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Apr 11, 2013 8:26 am
by wilbert
Maybe not very useful for most users but this code example moves a PureBasic created window to a second screen if you have one and makes it fit the screen.

Code: Select all

Global Dim Screens.NSRect(0)

Procedure GetAvailableScreens()
  Protected ScreenArray = CocoaMessage(0, 0, "NSScreen screens")
  Protected i, NumScreens = CocoaMessage(0, ScreenArray, "count")
  ReDim Screens(NumScreens - 1)
  While i < NumScreens
    CocoaMessage(@Screens(i), CocoaMessage(0, ScreenArray, "objectAtIndex:", i), "frame")
    i + 1
  Wend
  ProcedureReturn NumScreens
EndProcedure

; test the code

NumScreens = GetAvailableScreens()
For i = 0 To NumScreens - 1
  Debug "Screen " + Str(i) + " : " + Str(Screens(i)\size\width) + " x " + Str(Screens(i)\size\height) + " px, offset x : " + Str(Screens(i)\origin\x)
Next

If NumScreens > 1
  OpenWindow(0, 0, 0, 0, 0, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
  CocoaMessage(0, WindowID(0), "setFrame:@", @Screens(1), "display:", #YES)
  
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
  
EndIf

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Apr 11, 2013 4:07 pm
by WilliamL
I'd like to give a big thanks to wilbert for this thread and to wilbert and Shardik for their contributions! :D

This thread is a valuable resource for Mac users and an important addition to Pure Basic.

Cocoa has become an easy to use replacement for Carbon for Mac users.

This is one of those changes that is an improvement in just about all ways.

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Apr 11, 2013 5:38 pm
by Polo
Indeed! It seems with that CocoaMessage function plenty of things can be done!
Maybe not the best place to ask, is it possible to list all fonts installed on the system? I remember asking for that before when only Carbon was available, maybe it's easier using Cocoa?

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Apr 11, 2013 6:36 pm
by wilbert
Thanks :D

And about the fonts, try this

Code: Select all

FontManager = CocoaMessage(0, 0, "NSFontManager sharedFontManager")
AvailableFontFamilies = CocoaMessage(0, FontManager, "availableFontFamilies")
FontCount = CocoaMessage(0, AvailableFontFamilies, "count")

i = 0
While i < FontCount
  FontName.s = PeekS(CocoaMessage(0, CocoaMessage(0, AvailableFontFamilies, "objectAtIndex:", i), "UTF8String"), -1, #PB_UTF8)
  Debug FontName
  i + 1
Wend

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Apr 11, 2013 6:54 pm
by Polo
Very short and work brilliantly, thanks a lot Wilbert!!! :)

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Wed Apr 24, 2013 3:19 pm
by Mindphazer
Hi all
I'm trying to find a way to sort a ListIconGadget when clicking on a column header...
I guess the answer is somewhere here: http://developer.apple.com/library/mac/ ... Views.html, but I can't find out

If any of those "Cocoa masters" (like wilbert or WilliamL) could help out, it would be greatly appreciated.....

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Wed Apr 24, 2013 9:44 pm
by Shardik
Mindphazer wrote:I'm trying to find a way to sort a ListIconGadget when clicking on a column header...
Perhaps "Cocoa master" Wilbert can improve the following code even further by defining a second delegate for sorting the contents automatically. Currently my code requires you to store the ListIcon contents into the linked list Table() and to do the sorting by yourself in the procedure SortListIcon().

And because of a PureBasic bug in Pseudotype P-ASCII the following code will not work in 64 bit mode with unicode enabled although in 32 bit mode with Unicode it does work. If you need 64 bit and unicode you have to use PokeS to poke the required strings with flag #PB_ASCII into a buffer and to hand over this buffer to the functions sel_registerName() and class_addMethod().

Code: Select all

EnableExplicit

ImportC ""
  sel_registerName(*MethodName)
  class_addMethod(Class.I, Selector.I, Implementation.I, *Types)
EndImport

Structure TableEntry
  Name.S
  Address.S
EndStructure

Enumeration #PB_Event_FirstCustomValue
  #PB_Event_ListIcon_SortAscending
  #PB_Event_ListIcon_SortDescending
EndEnumeration

Define AppDelegate.I
Define AscendingArrow.I
Define ColumnArray.I
Define DelegateClass.I
Define DescendingArrow.I
Define i.I
Define LastSortColumn.I
Define MethodName.S = "tableView:didClickTableColumn:"
Define *MethodNameBuffer
Define SortColumn.I
Define SortIsAscending.I
Define Types.S = "v@:@@"
Define *TypesBuffer

NewList Table.TableEntry()

ProcedureC LeftClickOnHeaderCellCallback(Object.I, Selector.I, View.I, Column.I)
  Shared AscendingArrow.I
  Shared DescendingArrow.I
  Shared SortColumn.I
  Shared SortIsAscending.I

  SortColumn = Column

  If SortIsAscending
    PostEvent(#PB_Event_ListIcon_SortDescending)
  Else
    PostEvent(#PB_Event_ListIcon_SortAscending)
  EndIf

  SortIsAscending ! 1
EndProcedure

Procedure SortListIcon(ListIconID.I, SortColumn.I)
  Shared Table()
  Shared SortIsAscending.I

  Protected ColumnIndex.I

  ColumnIndex = Val(PeekS(CocoaMessage(0, CocoaMessage(0, SortColumn, "identifier"), "UTF8String"), -1, #PB_UTF8))

  If SortIsAscending
    If ColumnIndex = 0
      SortStructuredList(Table(), #PB_Sort_Ascending, OffsetOf(TableEntry\Name), #PB_String)
    Else
      SortStructuredList(Table(), #PB_Sort_Ascending, OffsetOf(TableEntry\Address), #PB_String)
    EndIf
  Else
    If ColumnIndex = 0
      SortStructuredList(Table(), #PB_Sort_Descending, OffsetOf(TableEntry\Name), #PB_String)
    Else
      SortStructuredList(Table(), #PB_Sort_Descending, OffsetOf(TableEntry\Address), #PB_String)
    EndIf
  EndIf

  ClearGadgetItems(ListIconID)

  ForEach Table()
    AddGadgetItem(ListIconID, -1, Table()\Name + #LF$ + Table()\Address)
  Next
EndProcedure

*MethodNameBuffer = AllocateMemory(StringByteLength(MethodName, #PB_Ascii) + 1)
PokeS(*MethodNameBuffer, MethodName, -1, #PB_Ascii)
*TypesBuffer = AllocateMemory(StringByteLength(Types, #PB_Ascii) + 1)
PokeS(*TypesBuffer, Types, -1, #PB_Ascii)
AppDelegate = CocoaMessage(0, CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
DelegateClass = CocoaMessage(0, AppDelegate, "class")
class_addMethod(DelegateClass, sel_registerName(*MethodNameBuffer),  @LeftClickOnHeaderCellCallback(), *TypesBuffer)
FreeMemory(*MethodNameBuffer)
FreeMemory(*TypesBuffer)
OpenWindow(0, 200, 100, 430, 95, "Sort ListIcon with column click")

ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20, "Name", 110)
AddGadgetColumn(0, 1, "Address", GadgetWidth(0) - GetGadgetItemAttribute(0, 0, #PB_ListIcon_ColumnWidth) - 8)

For i = 1 To 3
  AddElement(Table())
  Read.S Table()\Name
  Read.S Table()\Address
Next i

ForEach Table()
  AddGadgetItem(0, -1, Table()\Name + #LF$ + Table()\Address)
Next

AscendingArrow = CocoaMessage(0, CocoaMessage(0, 0, "NSImage imageNamed:$", @"NSAscendingSortIndicator"), "retain")
DescendingArrow = CocoaMessage(0, CocoaMessage(0, 0, "NSImage imageNamed:$", @"NSDescendingSortIndicator"), "retain")

CocoaMessage(@ColumnArray, GadgetID(0), "tableColumns")
CocoaMessage(@SortColumn, ColumnArray, "objectAtIndex:", 0)
LastSortColumn = SortColumn
SortIsAscending = #True
SortListIcon(0, SortColumn)
CocoaMessage(0, GadgetID(0), "setIndicatorImage:", AscendingArrow, "inTableColumn:", SortColumn)
CocoaMessage(0, GadgetID(0), "setDelegate:", AppDelegate)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_ListIcon_SortAscending
      If SortColumn <> LastSortColumn
        CocoaMessage(0, GadgetID(0), "setIndicatorImage:", 0, "inTableColumn:", LastSortColumn)
        LastSortColumn = SortColumn
      EndIf
      SortListIcon(0, SortColumn)
      CocoaMessage(0, GadgetID(0), "setIndicatorImage:", AscendingArrow, "inTableColumn:", SortColumn)
    Case #PB_Event_ListIcon_SortDescending
      If SortColumn <> LastSortColumn
        CocoaMessage(0, GadgetID(0), "setIndicatorImage:", 0, "inTableColumn:", LastSortColumn)
        LastSortColumn = SortColumn
      EndIf

      SortListIcon(0, SortColumn)
      CocoaMessage(0, GadgetID(0), "setIndicatorImage:", DescendingArrow, "inTableColumn:", SortColumn)
  EndSelect
ForEver

End

DataSection
  Data.S "Harry Rannit"
  Data.S "12 Parliament Way, Battle Street, By the Bay"
  Data.S "Ginger Brokeit"
  Data.S "330 PureBasic Road, BigTown, CodeCity"
  Data.S "Didi Foundit"
  Data.S "231 Logo Drive, Mouse House, Downtown"
EndDataSection
Update 1: I had to retain the NSImages AscendingArrow and DescendingArrow in order to work in MountainLion. Thank you for your invaluable hint, Wilbert. And I implemented a workaround to circumvent PureBasic's Pseudotype bug in order to work in Unicode mode.

Update 2: For calculating the required size of the 2 buffers *MethodNameBuffer and *TypesBuffer I have changed Len() to StringByteLength() because in Unicode mode the buffers had the double size than would have been required...

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Apr 25, 2013 6:50 am
by wilbert
Shardik wrote:Currently my code requires you to store the ListIcon contents into the linked list Table() and to do the sorting by yourself in the procedure SortListIcon().
I think you would have to do it more or less that way.
The PureBasic gadget provides the data source for the table. If the data source doesn't have a sorting routine built in, it won't work.

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Apr 25, 2013 7:56 am
by Mindphazer
Thank you Shardik for your quick answer.... Though I'm afraid it doesn't work :
I've got an "invalid access memory" error when I click on a column header....
I'm not sure that the error line number is very useful as it's not the same on PureBasic 5.11 64, PureBasic 5.11 32, PureBasic 5.10 64... (always without Unicode)
Anyway, thank you for giving a try...