Page 9 of 16

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Fri Jun 21, 2013 2:19 pm
by Shardik
Display 16 different informations for each mounted volume (tested on MacOS X 10.8.4 with PB 5.11 x86 and x64 and in both ASCII and Unicode mode):
- Volume name
- Localized volume name
- Volume partition format
- Space total on volume
- Space free on volume
- Is renaming possible?
- Is possible icon visible?
- File size limit
- Is volume ejectable?
- Is volume removable?
- Is volume an internal one?
- Has volume been automatically mounted?
- Is volume a local one?
- Is volume read-only?
- Creation date of volume
- UUID key of volume

Code: Select all

EnableExplicit

Structure VolumeEntry
  KeyName.S
  Format.S
  ColumnTitle.S
  ColumnWidth.I
EndStructure

If OSVersion() <= #PB_OS_MacOSX_10_5
  MessageRequester("Info", "Sorry, but this program needs at least OS X 10.6 (Snow Leopard) !")
  End
ElseIf OSVersion() = #PB_OS_MacOSX_10_6
  MessageRequester("Info", "Sorry, but OS X 10.6 (Snow Leopard) is only able to obtain the data for the first 5 columns!")
EndIf

NewList Volume.VolumeEntry()

Procedure DisplayVolumeInfos()
  Shared Volume.VolumeEntry()

  Protected CellContent.S
  Protected Error.I
  Protected FileManager.I
  Protected Format.S
  Protected i.I
  Protected j.I
  Protected KeyArray.I
  Protected NumColumns.I = ListSize(Volume())
  Protected NumVolumes.I
  Protected RowContent.S
  Protected Size.Q
  Protected URL.I
  Protected URLArray.I
  Protected Value.I

  FirstElement(Volume())
  KeyArray = CocoaMessage(0, 0, "NSArray arrayWithObject:$", @Volume()\KeyName)
  NextElement(Volume())
  
  If KeyArray
    For i = 1 To ListSize(Volume()) - 1
      KeyArray = CocoaMessage(0, KeyArray, "arrayByAddingObject:$", @Volume()\KeyName)
      NextElement(Volume())
    Next
    
    FileManager = CocoaMessage(0, 0, "NSFileManager defaultManager")
    
    If FileManager
      URLArray = CocoaMessage(0, FileManager, "mountedVolumeURLsIncludingResourceValuesForKeys:", KeyArray, "options:", 0)
      
      If URLArray
        NumVolumes = CocoaMessage(0, URLArray, "count")
        
        If NumVolumes > 0
          For j = 0 To NumVolumes - 1
            URL = CocoaMessage(0, URLArray, "objectAtIndex:", j)
            
            If URL
              FirstElement(Volume())

              For i = 0 To NumColumns - 1
                CellContent = ""

                Select Volume()\Format
                  Case "B" ; Boolean NSNumber
                    If CocoaMessage(0, URL, "getResourceValue:", @Value, "forKey:$", @Volume()\KeyName, "error:", @Error) = #YES
                      If Value
                        If CocoaMessage(0, Value, "boolValue")
                          CellContent = "Yes"
                        Else
                          CellContent = "No"
                        EndIf
                      EndIf
                    EndIf
                  Case "D" ; NSDate
                    If CocoaMessage(0, URL, "getResourceValue:", @Value, "forKey:$", @Volume()\KeyName, "error:", @Error) = #YES
                      If Value <> 0
                        CellContent = Left(PeekS(CocoaMessage(0, CocoaMessage(0, Value, "description"), "UTF8String"), -1, #PB_UTF8), 10)
                      EndIf
                    EndIf
                  Case "Q" ; NSNumber (Quad)
                    If CocoaMessage(0, URL, "getResourceValue:", @Value, "forKey:$", @Volume()\KeyName, "error:", @Error) = #YES
                      If Value
                        CocoaMessage(@Size, Value, "unsignedLongLongValue")

                        If Volume()\KeyName = "NSURLVolumeMaximumFileSizeKey"
                          If Size >> 30 < 1024
                            CellContent = Str(Size >> 30 + 1) + " GB"
                          Else
                            CellContent = Str((Size >> 60) & $FFFFFFFFFFFFFFFF + 1) + " EB"
                          EndIf
                        Else
                          CellContent = StrF(Size / 1024 / 1024 / 1024, 2)
                        EndIf
                      EndIf
                    EndIf
                  Case "S" ; NSString
                    If CocoaMessage(0, URL, "getResourceValue:", @Value, "forKey:$", @Volume()\KeyName, "error:", @Error) = #YES
                      If Value <> 0
                        CellContent = UCase(PeekS(CocoaMessage(0, Value, "UTF8String"), -1, #PB_UTF8))
                      EndIf
                    EndIf
                  Case "U" ; NSURL
                    CellContent = PeekS(CocoaMessage(0, CocoaMessage(0, URL, "path"), "UTF8String"), -1, #PB_UTF8)
                    CellContent = StringField(CellContent, CountString(CellContent, "/") + 1, "/")

                    If CellContent = ""
                      CellContent = "/"
                    EndIf
                EndSelect

                If i = 0
                  RowContent = CellContent
                Else
                  RowContent + #LF$ + CellContent
                EndIf

                NextElement(Volume())
              Next i
            EndIf

            AddGadgetItem(0, -1, RowContent)
          Next j
        EndIf
      EndIf
    EndIf
  EndIf
EndProcedure

Define ColumnWidth.S
Define ColumnWidthTotal.I
Define i.I
Define KeyName.S

Read.S KeyName

While KeyName <> ""
  AddElement(Volume())
  Volume()\KeyName = KeyName
  Read.S Volume()\ColumnTitle
  Read.S Volume()\Format  
  Read.S ColumnWidth
  Volume()\ColumnWidth = Val(ColumnWidth)
  ColumnWidthTotal + Volume()\ColumnWidth + 3
  Read.S KeyName
Wend


OpenWindow(0, 0, 0, ColumnWidthTotal + 22, 247, "Volume infos", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
FirstElement(Volume())
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20, Volume()\ColumnTitle, Volume()\ColumnWidth, #PB_ListIcon_GridLines)
NextElement(Volume())

For i = 1 To ListSize(Volume()) - 1
  AddGadgetColumn(0, i, Volume()\ColumnTitle, Volume()\ColumnWidth)
  NextElement(Volume())
Next

DisplayVolumeInfos()

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

End

DataSection
  Data.S "NSURLVolumeNameKey", "Volume name", "U", "150"
  Data.S "NSURLVolumeLocalizedNameKey", "Localized name", "U", "150"
  Data.S "NSURLVolumeLocalizedFormatDescriptionKey", "Partition format", "S", "215"
  Data.S "NSURLVolumeTotalCapacityKey", "Total [GB]", "Q", "55"
  Data.S "NSURLVolumeAvailableCapacityKey", "Free [GB]", "Q", "50"
  Data.S "NSURLVolumeSupportsRenamingKey", "Renamable", "B", "62"
  Data.S "NSURLVolumeIsBrowsableKey", "Icon visible", "B", "63"
  Data.S "NSURLVolumeMaximumFileSizeKey", "File size limit", "Q", "72"
  Data.S "NSURLVolumeIsEjectableKey", "Ejectable", "B", "50"
  Data.S "NSURLVolumeIsRemovableKey", "Removable", "B", "60"
  Data.S "NSURLVolumeIsInternalKey", "Internal", "B", "45"
  Data.S "NSURLVolumeIsAutomountedKey", "Automounted", "B", "74"
  Data.S "NSURLVolumeIsLocalKey", "Local", "B", "30"
  Data.S "NSURLVolumeIsReadOnlyKey", "Read only", "B", "55"
  Data.S "NSURLVolumeCreationDateKey", "Creation date", "D", "90"
  Data.S "NSURLVolumeUUIDStringKey", "UUID", "S", "300"
  Data.S ""
EndDataSection
Update 1: I had to change

Code: Select all

      CocoaMessage(0, KeyArray, "arrayByAddingObject:$", @Volume()\KeyName)
into

Code: Select all

      KeyArray = CocoaMessage(0, KeyArray, "arrayByAddingObject:$", @Volume()\KeyName)
because arrayByAddingObject: returns a new array that isn't guaranteed to be the same as the original. Therefore it's necassary to get the new array always into KeyArray. Thank you very much, Wilbert, for your kind PM pinpointing this error and explaining several alternatives, especially as it always worked the old way in all my tests.

Furthermore I changed the OS version check, so that on Snow Leopard this program will be run with the info that only the first 5 columns will be filled because the data for the other columns are only retrievable on at least Lion. On Leopard and older versions all data retrieving keywords are not supported and the program will be terminated with an info message!

Update 2: The column names for total and free volume space had to be swapped. Thank you for spotting that mistake, gwhuntoon!

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Sat Jun 22, 2013 2:02 pm
by gwhuntoon
:) Shardik, first off, awesome post. This will be very useful. Just one thing though, I think the volume free vs. total volume was mistyped and is swapped.

From this:

Code: Select all

  Data.S "NSURLVolumeAvailableCapacityKey", "Total [GB]", "Q", "55"
  Data.S "NSURLVolumeTotalCapacityKey", "Free [GB]", "Q", "50"
To this:

Code: Select all

  Data.S "NSURLVolumeAvailableCapacityKey", "Free [GB]", "Q", "55"
  Data.S "NSURLVolumeTotalCapacityKey", "Total [GB]", "Q", "50"

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Sat Jun 22, 2013 2:05 pm
by gwhuntoon
:oops: And actually I goofed and forgot to swap the column widths.

It should be this:

Code: Select all

  Data.S "NSURLVolumeAvailableCapacityKey", "Free [GB]", "Q", "50"
  Data.S "NSURLVolumeTotalCapacityKey", "Total [GB]", "Q", "55"

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Sat Jun 22, 2013 5:30 pm
by Mindphazer
Never mind !
Terrific post Shardik, thank you !!

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Wed Jun 26, 2013 6:18 am
by wilbert
A simple star rating example

Code: Select all

EnableExplicit

Enumeration
  #NSRelevancyLevelIndicatorStyle
  #NSContinuousCapacityLevelIndicatorStyle
  #NSDiscreteCapacityLevelIndicatorStyle
  #NSRatingLevelIndicatorStyle
EndEnumeration

Procedure CreateRatingIndicator(x, y, maxStars)
  Protected Indicator, Frame.NSRect, Value.d = maxStars
  Frame\origin\x = x
  Frame\origin\y = y
  Frame\size\width = maxStars * 13
  Frame\size\height = 13
  Indicator = CocoaMessage(0, CocoaMessage(0, 0, "NSLevelIndicator alloc"), "initWithFrame:@", @Frame)
  CocoaMessage(0, CocoaMessage(0, Indicator, "cell"), "setLevelIndicatorStyle:", #NSRatingLevelIndicatorStyle)
  CocoaMessage(0, Indicator, "setMaxValue:@", @Value)
  ProcedureReturn Indicator
EndProcedure

Global ContentView, RatingIndicator

If OpenWindow(0, 0, 0, 200, 100, "Rating example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ContentView = CocoaMessage(0, WindowID(0), "contentView")
  
  SpinGadget(0, 10, 10, 50, 25, 0, 10, #PB_Spin_Numeric)
  RatingIndicator = CreateRatingIndicator(10, 50, 10)
  CocoaMessage(0, ContentView, "addSubview:", RatingIndicator)
  
  SetGadgetState(0, 6); 6 stars   
  
  Repeat
    CocoaMessage(0, RatingIndicator, "setIntValue:", GetGadgetState(0))   
  Until WaitWindowEvent() = #PB_Event_CloseWindow
  
EndIf

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Sun Jul 14, 2013 7:06 pm
by Danilo
In addition to the tricks by wilbert and fsw, some more window fullscreen switches and a procedure to get window fullscreen state:

Code: Select all

;--[ Window fullscreen procedures ]----------------------------------------------------------------

Procedure EnableWindowFullscreenGadget(window)
    NewCollectionBehaviour = CocoaMessage(0, WindowID(window), "collectionBehavior") | $80
    CocoaMessage(0, WindowID(window), "setCollectionBehavior:", NewCollectionBehaviour)
EndProcedure

Procedure ToggleWindowFullscreen(window)
    CocoaMessage(0, WindowID(window), "toggleFullScreen:")
EndProcedure

Procedure EnterWindowFullscreen(window)
    CocoaMessage(0, WindowID(window), "enterFullScreenMode:")
EndProcedure

Procedure ExitWindowFullscreen(window)
    CocoaMessage(0, WindowID(window), "exitFullScreenMode:")
EndProcedure

Procedure IsWindowFullscreen(window)
    #NSFullScreenWindowMask = 1 << 14
    ProcedureReturn Bool( CocoaMessage(0, WindowID(window), "styleMask") & #NSFullScreenWindowMask )
EndProcedure

;--------------------------------------------------------------------------------------------------


Procedure.s BoolToYesNo(bool)
    If bool : ProcedureReturn "Yes" : Else : ProcedureReturn "No" : EndIf
EndProcedure

Macro UpdateText()
    SetGadgetText(4, "Fullscreen: " + BoolToYesNo(IsWindowFullscreen(0)) )
EndMacro

#WinFlags = #PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget|#PB_Window_MaximizeGadget|#PB_Window_MinimizeGadget|#PB_Window_Invisible

If OpenWindow(0, 0, 0, 220, 175, "Fullscreen Switch", #WinFlags)
    WindowBounds(0, 220, 175, #PB_Ignore, #PB_Ignore)
    
    EnableWindowFullscreenGadget(0)
    
    ;AddKeyboardShortcut(0,#PB_Shortcut_Control|#PB_Shortcut_Command|#PB_Shortcut_F,1) ; not required when using a menu
    
    CreateMenu(0,0)
    MenuTitle("View")
    MenuItem(1, "Toggle Fullscreen"  +Chr(9)+"Ctrl+Cmd+F") ; Standard OS X menu switch = Ctrl + Cmd + F
    
    ButtonGadget(0,10, 10,200,25,"Exit")
    ButtonGadget(1,10, 40,200,25,"Toggle fullscreen")
    ButtonGadget(2,10, 70,200,25,"Enter fullscreen")
    ButtonGadget(3,10,100,200,25,"Exit fullscreen")
    TextGadget  (4,10,140,200,25,"",#PB_Text_Center)
    
    HideWindow(0,#False)
    
    EnterWindowFullscreen(0)
    
    UpdateText()
    
    Repeat
        Select WaitWindowEvent()
            Case #PB_Event_CloseWindow
                End
            Case #PB_Event_Gadget
                Select EventGadget()
                    Case 0 : End
                    Case 1 : ToggleWindowFullscreen(0) : UpdateText()  ; Toggle fullscreen mode
                    Case 2 : EnterWindowFullscreen(0)  : UpdateText()  ; Enter  fullscreen mode
                    Case 3 : ExitWindowFullscreen(0)   : UpdateText()  ; Exit   fullscreen mode
                EndSelect
            Case #PB_Event_Menu
                Select EventMenu()
                    Case -1 : End
                    Case  1 : ToggleWindowFullscreen(0) : UpdateText() ; "Toggle fullscreen" menu update
                EndSelect
            Case #PB_Event_SizeWindow
                UpdateText()                                           ; Update fullscreen mode after resize
                                                                       ; ( catches fullscreen window button clicks )
        EndSelect
    ForEver  
EndIf
Ctrl+Cmd+F is used as default in most Mac OS X applications to toggle fullscreen mode.

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Aug 01, 2013 12:00 pm
by Danilo
Some functions for getting name and size for PB's gadget fonts, etc.:

Code: Select all

EnableExplicit


Procedure.s PeekNSString(string)
    ;
    ; converts NSString to PB string
    ;
    #NSASCIIStringEncoding   = 1
    #NSUTF8StringEncoding    = 4
    #NSUnicodeStringEncoding = 10
    
    Protected result.s, length, *buffer
    If string
        length = CocoaMessage(0,string,"length")
        If length
            length + 1
            length * SizeOf(Character)
            *buffer = AllocateMemory(length)
            If *buffer
                CompilerIf #PB_Compiler_Unicode
                    CocoaMessage(0,string,"getCString:@",@*buffer,"maxLength:@",@length,"encoding:",#NSUnicodeStringEncoding)
                    result = PeekS(*buffer,-1,#PB_Unicode)
                CompilerElse
                    CocoaMessage(0,string,"getCString:@",@*buffer,"maxLength:@",@length,"encoding:",#NSASCIIStringEncoding)
                    result = PeekS(*buffer,-1,#PB_Ascii)
                CompilerEndIf
                FreeMemory(*buffer)
            EndIf
        EndIf
    EndIf
    ProcedureReturn result
EndProcedure


Procedure.s GetFontName(FontID)
    ;
    ; returns the font name of FontID
    ;
    Protected name.s, string
    If FontID
        string = CocoaMessage(0,FontID,"displayName") ; "familyName" and "fontName" for internal use
                                                      ; use "displayName" for the real name
        If string
            ProcedureReturn PeekNSString(string)
        EndIf
    EndIf
EndProcedure



Procedure.s GetDefaultFontName()
    ;
    ; returns the font name used for ButtonGadget()
    ;
    ; call at program start to get the default font name for PB gadgets
    ;
    Protected name.s
    Protected win = OpenWindow(#PB_Any,0,0,0,0,"",#PB_Window_Invisible)
    If win
        Protected btn = ButtonGadget(#PB_Any,0,0,0,0,"text") ; alternative: TextGadget()
        If btn
            name = GetFontName( GetGadgetFont(btn) )
            FreeGadget(btn)
        EndIf
        CloseWindow(win)
    EndIf
    ProcedureReturn name
EndProcedure


Procedure.CGFloat GetFontSize(FontID)
    ;
    ; returns the font size of FontID
    ;
    Protected pointSize.CGFloat = 0.0
    If FontID
        CocoaMessage(@pointSize,FontID,"pointSize")
    EndIf
    ProcedureReturn pointSize
EndProcedure


Procedure.CGFloat GetDefaultFontSize()
    ;
    ; returns the font size used for ButtonGadget()
    ;
    ; call at program start to get the default font size for PB gadgets
    ;
    Protected size.CGFloat = 0.0
    Protected win = OpenWindow(#PB_Any,0,0,0,0,"",#PB_Window_Invisible)
    If win
        Protected btn = ButtonGadget(#PB_Any,0,0,0,0,"text") ; alternative: TextGadget()
        If btn
            size = GetFontSize( GetGadgetFont(btn) )
            FreeGadget(btn)
        EndIf
        CloseWindow(win)
    EndIf
    ProcedureReturn size
EndProcedure


Procedure IsFontFixedPitch(FontID)
    ;
    ; returns true if FontID is a monospaced font
    ;
    If FontID
        ProcedureReturn CocoaMessage(0,FontID,"isFixedPitch")
    EndIf
EndProcedure


Procedure.CGFloat GetSystemFontSize()
    ;
    ; returns Mac OS X default system font size
    ;
    Protected size.CGFLoat = 0.0
    CocoaMessage(@size,0,"NSFont systemFontSize")
    ProcedureReturn size
EndProcedure


Procedure.CGFloat GetSmallSystemFontSize()
    ;
    ; returns Mac OS X default small system font size
    ;
    Protected size.CGFLoat = 0.0
    CocoaMessage(@size,0,"NSFont smallSystemFontSize")
    ProcedureReturn size
EndProcedure


Procedure.CGFloat GetLabelFontSize()
    ;
    ; returns Mac OS X default font size used for labels (TextGadget in PB)
    ;
    Protected size.CGFLoat = 0.0
    CocoaMessage(@size,0,"NSFont labelFontSize")
    ProcedureReturn size
EndProcedure



Debug "Default PB font:"
Debug GetDefaultFontName()
Debug GetDefaultFontSize()


Debug "System font sizes:"
Debug GetSystemFontSize()
Debug GetSmallSystemFontSize()
Debug GetLabelFontSize()
Output:

Code: Select all

Default PB font:
Lucida Grande
12.0
System font sizes:
13.0
11.0
10.0
PB 5.20 beta 7 x86 & x64, Unicode & ASCII mode, tetsted on Mac OS X 10.8.4

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Aug 01, 2013 12:35 pm
by wilbert
@Danilo, your PeekNSString procedure works fine.
I'm wondering if there's any specific reason you did it this way compared to the way some previous examples did it

Code: Select all

Procedure.s PeekNSString(string)
  ProcedureReturn PeekS(CocoaMessage(0, string, "UTF8String"), -1, #PB_UTF8)
EndProcedure

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Thu Aug 01, 2013 6:38 pm
by Danilo
wilbert wrote:@Danilo, your PeekNSString procedure works fine.
I'm wondering if there's any specific reason you did it this way compared to the way some previous examples did it

Code: Select all

Procedure.s PeekNSString(string)
  ProcedureReturn PeekS(CocoaMessage(0, string, "UTF8String"), -1, #PB_UTF8)
EndProcedure
I just overlooked the "UTF8String" method in the API docs, only found "getCString". Checked again now, NSString::UTF8String is in the docs (at the very end),
so it is probably better to use your shorter and faster procedure. Thanks! :)

EDIT:
BTW, do we need to free the Mac OS X string pointer (NSString *) with "release" or "autorelease", or does the
garbage collector do this at program end? If we want to free object resources before program end, should we
call "release" or "autorelease" from NSObject?

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Fri Aug 02, 2013 11:19 am
by Danilo
Get default user language/locale settings:

Code: Select all

;
; get default user language/locale settings
;
; http://www.purebasic.fr/english/viewtopic.php?f=19&t=50795&start=137
;
;
; The language code is based on the ISO 639-x/IETF BCP 47 standard. ISO 639-1 defines two-character codes, such as “en” And “fr”,
; for the world’s most commonly used languages.
; If a two-letter ISO 639-1 code is not available, then ISO 639-2 three-letter identifiers are accepted as well,
; for example “haw” For Hawaiian. For more details, see http://www.loc.gov/standards/iso639-2/php/English_list.php
;
EnableExplicit

Macro release(object)
    CocoaMessage(0,object,"release")
EndMacro

Macro autorelease(object)
    CocoaMessage(0,object,"autorelease")
EndMacro


Procedure.s GetDefaultLanguage()
    Protected result.s, NSUserDefaults_defs, NSArray_languages, NSString_preferredLang
    
    NSUserDefaults_defs = CocoaMessage(0,0,"NSUserDefaults standardUserDefaults")
    If NSUserDefaults_defs
        NSArray_languages   = CocoaMessage(0,NSUserDefaults_defs,"objectForKey:$",@"AppleLanguages")
        If NSArray_languages
            NSString_preferredLang = CocoaMessage(0,NSArray_languages,"objectAtIndex:",0)
            If NSString_preferredLang
                result = PeekS(CocoaMessage(0, NSString_preferredLang, "UTF8String"), -1, #PB_UTF8)
                autorelease(NSString_preferredLang)
            EndIf
            autorelease(NSArray_languages)
        EndIf
        autorelease(NSUserDefaults_defs)
    EndIf
    ProcedureReturn result
EndProcedure

Procedure.s GetUserLocale()
    Protected result.s, NSUserDefaults_defs, NSString_locale

    NSUserDefaults_defs = CocoaMessage(0,0,"NSUserDefaults standardUserDefaults")
    If NSUserDefaults_defs
        NSString_locale  = CocoaMessage(0,NSUserDefaults_defs,"objectForKey:$",@"AppleLocale")
        If NSString_locale
            result = PeekS(CocoaMessage(0, NSString_locale, "UTF8String"), -1, #PB_UTF8)
            autorelease(NSString_locale)
        EndIf
        autorelease(NSUserDefaults_defs)
    EndIf
    ProcedureReturn result
EndProcedure


Procedure.s GetUserLanguage()
    ;
    ; by Shardik
    ;
    ; http://www.purebasic.fr/english/viewtopic.php?f=3&t=55750&start=3
    ;
    Protected result.s, CurrentLocale, LanguageCode, string
    CurrentLocale = CocoaMessage(0, 0, "NSLocale currentLocale")
    If CurrentLocale
        LanguageCode = CocoaMessage(0, CurrentLocale, "objectForKey:$", @"kCFLocaleLanguageCodeKey")
        If LanguageCode
            string = CocoaMessage(0, CurrentLocale, "displayNameForKey:$", @"kCFLocaleLanguageCodeKey", "value:", LanguageCode)
            If string
                result = PeekS(CocoaMessage(0, string, "UTF8String"), -1, #PB_UTF8)
                autorelease(string)
            EndIf
            autorelease(LanguageCode)
        EndIf
        autorelease(CurrentLocale)
    EndIf
    ProcedureReturn result
EndProcedure


Procedure.s GetUserLanguageIdentifier()
    ;
    ; by Shardik
    ;
    ; http://www.purebasic.fr/english/viewtopic.php?f=3&t=55750&start=3
    ;
    Protected result.s, CurrentLocale, LanguageCode, string
    CurrentLocale = CocoaMessage(0, 0, "NSLocale currentLocale")
    If CurrentLocale
        LanguageCode = CocoaMessage(0, CurrentLocale, "objectForKey:$", @"kCFLocaleIdentifierKey")
        If LanguageCode
            string = CocoaMessage(0, CurrentLocale, "displayNameForKey:$", @"kCFLocaleIdentifierKey", "value:", LanguageCode)
            If string
                result = PeekS(CocoaMessage(0, string, "UTF8String"), -1, #PB_UTF8)
                autorelease(string)
            EndIf
            autorelease(LanguageCode)
        EndIf
        autorelease(CurrentLocale)
    EndIf
    ProcedureReturn result
EndProcedure

Debug "GetDefaultLanguage:        "+GetDefaultLanguage()
Debug "GetUserLocale:             "+GetUserLocale()
Debug "GetUserLanguage:           "+GetUserLanguage()
Debug "GetUserLanguageIdentifier: "+GetUserLanguageIdentifier()
Output:

Code: Select all

GetDefaultLanguage:        de
GetUserLocale:             de_DE
GetUserLanguage:           Deutsch
GetUserLanguageIdentifier: Deutsch (Deutschland)
Mac OS X API docs wrote:The language code is based on the ISO 639-x/IETF BCP 47 standard. ISO 639-1 defines two-character codes, such as “en” And “fr”,
for the world’s most commonly used languages.
If a two-letter ISO 639-1 code is not available, then ISO 639-2 three-letter identifiers are accepted as well,
for example “haw” For Hawaiian. For more details, see http://www.loc.gov/standards/iso639-2/php/English_list.php

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Fri Aug 02, 2013 12:14 pm
by wilbert
Danilo wrote:
wilbert wrote:@Danilo, your PeekNSString procedure works fine.
I'm wondering if there's any specific reason you did it this way compared to the way some previous examples did it

Code: Select all

Procedure.s PeekNSString(string)
  ProcedureReturn PeekS(CocoaMessage(0, string, "UTF8String"), -1, #PB_UTF8)
EndProcedure
I just overlooked the "UTF8String" method in the API docs, only found "getCString". Checked again now, NSString::UTF8String is in the docs (at the very end),
so it is probably better to use your shorter and faster procedure. Thanks! :)

EDIT:
BTW, do we need to free the Mac OS X string pointer (NSString *) with "release" or "autorelease", or does the
garbage collector do this at program end? If we want to free object resources before program end, should we
call "release" or "autorelease" from NSObject?
The returned UTF8 string is automatically freed just like an object marked for autorelease (this means on (Wait)WindowEvent ) .
Usually you only need to free objects yourself that you created using alloc or new.

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Fri Aug 02, 2013 12:22 pm
by Danilo
wilbert wrote:The returned UTF8 string is automatically freed just like an object marked for autorelease (this means on (Wait)WindowEvent ) .
Thank you for this information!

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Fri Aug 02, 2013 9:44 pm
by Fred
wilbert wrote:Usually you only need to free objects yourself that you created using alloc or new.
or copy

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Sun Aug 11, 2013 8:35 pm
by Shardik
Get the number of currently visible rows in a ListIconGadget taking into account when a horizontal scrollbar is displayed (try to increase the window width: the horizontal scrollbar will be removed and the number of visible rows in the window title will be updated!):

Code: Select all

EnableExplicit

Procedure.I GetVisibleRows(ListIconID.I)
  Protected ContentView.I
  Protected EnclosingScrollView.I
  Protected VisibleRange.NSRange
  Protected VisibleRect.NSRect

  ; ----- Get scroll view inside of ListIconGadget
  EnclosingScrollView = CocoaMessage(0, GadgetID(ListIconID), "enclosingScrollView")
  
  If EnclosingScrollView
    ContentView = CocoaMessage(0, EnclosingScrollView, "contentView")
    ; ----- Get visible area
    ;       (automatically subtract horizontal scrollbar if shown) 
    CocoaMessage(@VisibleRect, ContentView, "documentVisibleRect")
    ; ----- Subtract border width
    If CocoaMessage(0, EnclosingScrollView, "borderType") > 0
      VisibleRect\size\height - 5
    EndIf
    ; ----- Get number of rows visible
    CocoaMessage(@VisibleRange, GadgetID(ListIconID), "rowsInRect:@", @VisibleRect)
    ProcedureReturn Int(VisibleRange\length)
  EndIf
EndProcedure

Define i.I

OpenWindow(0, 200, 100, 300, 95, "Get visible rows", #PB_Window_SystemMenu | #PB_Window_SizeGadget)
WindowBounds(0, WindowWidth(0), WindowHeight(0), WindowWidth(0) + 4, 500)
ListIconGadget(0, 10, 10, WindowWidth(0) - 20, WindowHeight(0) - 20, "Column 1", 130)
AddGadgetColumn(0, 1, "Column 2", 130)

For i = 1 To 20
  AddGadgetItem(0, -1, "Row " + Str(i) + ", Column 1" + #LF$ + "Row " + Str(i) + ", Column 2")
Next i

; -----Wait until ListIconGadget is initialized
While WindowEvent() : Wend

SetWindowTitle(0, "Visible rows: " + Str(GetVisibleRows(0)))

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_SizeWindow
      ResizeGadget(0, #PB_Ignore, #PB_Ignore, WindowWidth(0) - 20, WindowHeight(0) - 20)
      SetWindowTitle(0, "Visible rows: " + Str(GetVisibleRows(0)))
  EndSelect
ForEver
Update: In the procedure GetVisibleRows() I had to change one occurrence of GadgetID(0) to GadgetID(ListIconID).

Re: [PB Cocoa] Methods, Tips & Tricks

Posted: Sat Aug 31, 2013 7:12 am
by Danilo
Open Terminal and start console applications/scripts and shell commands (in new Terminal TAB):

Code: Select all

Procedure.s AppleScript(Script.s)
    ;
    ; by wilbert
    ;
    ; http://www.purebasic.fr/english/viewtopic.php?p=393553#p393553
    ;
    Protected retVal.s, strVal, numItems, i
    Protected aScript = CocoaMessage(0, CocoaMessage(0, CocoaMessage(0, 0, "NSAppleScript alloc"), "initWithSource:$", @Script), "autorelease")
    Protected eventDesc = CocoaMessage(0, aScript, "executeAndReturnError:", #nil)
    If eventDesc
        numItems = CocoaMessage(0, eventDesc, "numberOfItems")
        If numItems
            For i = 1 To numItems
                strVal = CocoaMessage(0, CocoaMessage(0, eventDesc, "descriptorAtIndex:", i), "stringValue")
                If strVal
                    retVal + PeekS(CocoaMessage(0, strVal, "UTF8String"), -1, #PB_UTF8)
                    If i <> numItems : retVal + #LF$ : EndIf
                EndIf
            Next
        Else
            strVal = CocoaMessage(0, eventDesc, "stringValue")
            If strVal : retVal = PeekS(CocoaMessage(0, strVal, "UTF8String"), -1, #PB_UTF8) : EndIf
        EndIf
    EndIf
    ProcedureReturn retVal 
EndProcedure



Procedure RunProgramInTerminal(program$,commandline$="",directory$="")
    If commandline$ : commandline$ = " "+commandline$ : EndIf
    If directory$   : directory$   = "cd \"+#DQUOTE$+directory$+"\"+#DQUOTE$+"; " : EndIf
    AppleScript("tell application "+#DQUOTE$+"Terminal"+#DQUOTE$+#CR$+
                "   activate"+#CR$+                                                                                                                          ; activate
                "   do script "+#DQUOTE$+directory$+"\"+#DQUOTE$+program$+"\"+#DQUOTE$+commandline$+#DQUOTE$+" in front window"+#CR$+                        ; run script
                "   activate"+#CR$+                                                                                                                          ; activate
                "end tell")
EndProcedure

Procedure RunProgramInNewTerminalTab(program$,commandline$="",directory$="")
    If commandline$ : commandline$ = " "+commandline$ : EndIf
    If directory$   : directory$   = "cd \"+#DQUOTE$+directory$+"\"+#DQUOTE$+"; " : EndIf
    AppleScript("tell application "+#DQUOTE$+"Terminal"+#DQUOTE$+#CR$+
                "   activate"+#CR$+                                                                                                                           ; activate
                "   tell application "+#DQUOTE$+"System Events"+#DQUOTE$+" To keystroke "+#DQUOTE$+"t"+#DQUOTE$+" using {command down}"+#CR$+"activate"+#CR$+ ; send CMD+t (new TAB)
                "   tell application "+#DQUOTE$+"System Events"+#DQUOTE$+" To keystroke "+#DQUOTE$+"k"+#DQUOTE$+" using {command down}"+#CR$+"activate"+#CR$+ ; send CMD+k (clear screen)
                "   do script "+#DQUOTE$+directory$+"\"+#DQUOTE$+program$+"\"+#DQUOTE$+commandline$+#DQUOTE$+" in front window"+#CR$+                         ; run script
                "   activate"+#CR$+                                                                                                                           ; activate
                "end tell")
EndProcedure


If ProgramParameter(0)=""
    RunProgramInNewTerminalTab("ls", "-l", #PB_Compiler_Home+"compilers/")      ; list contents of PB/compilers/ directory
    RunProgramInNewTerminalTab(#PB_Compiler_Home+"compilers/nasm", "-h")        ; nasm help
    RunProgramInNewTerminalTab(#PB_Compiler_Home+"compilers/pbcompiler", "-h")  ; pbcompiler help
    RunProgramInNewTerminalTab("ping", "127.0.0.1")                             ; ping                -> CTRL+C to quit
    RunProgramInNewTerminalTab("top")                                           ; list open processes -> CTRL+C to quit
    RunProgramInNewTerminalTab(ProgramFilename(),"-")                           ; run self
Else
    If OpenConsole()
        PrintN("Hello from PureBasic console application!")
    EndIf
EndIf
I would like the PureBasic IDE to start console programs like this, by opening a new Terminal TAB and running my compiled console app in it. :)