ホームページ開発ツール>Xojo / Real Studio Trial and Error・CocoaのDeclareでツールバーを実装する・メニューに対応する

 Xojo / Real Studio Trial and Error

CocoaのDeclareでツールバーを実装する・メニューに対応する

目次
 はじめに

 以下は、Xojo Cocoaビルドについての話題です。

 NSToolbarのメニュー対応について、試してみました。

 なお検証には、Xojo 2017 Release 1.1を用いています。(Mac mini 2018 + macOS 10.14.6 Mojave)


 方針

 NSToolbarでは、ツールバーのモードが「テキストのみ」の場合と、ツールバーの横幅が狭くてアイテムが表示できない時のために、メニューが用意されています。
 「テキストのみ」モードでは、アイテムのラベルしか表示されないため、例えばセグメンテッドコントロールは、現在選択されている要素を示したり変更の指示をするために、メニューが使われます。
S Shot1
 ツールバーの横幅が狭くてアイテムが表示できない時のメニューは、オーバーフローメニューと呼ばれ、山かっこ(と、公式ページにはあった)が表示されているか否かで利用可能であるかが判ります。
S Shot2
 ただし、XojoでNSToolbar(のインスタンス)を表示した場合は、初期状態では表示されません。
 ツールバーのモードを変えると表示されることから、例によって、何らかの齟齬が発生しているものと思われます。
 なので、ウィンドウがアクティブになった辺りで、モードを別のものに変えてすぐに戻す処理を加えておくことで、表示されるようになります。

 次はメニュー本体ですが、オーバーフローメニューでしか使わないツールバーアイテムは、自身が既に持っているメニューをmenuFormRepresentationで呼び出し、必要な情報を追加してやることで対応できます。
 そうでない場合は、独自にメニュー作成後、付け替えます。
(注:テキストのみモードでは、メニュー付ツールバーアイテムのメニューも、アイコン用ではなく、こちらが使われます。)

 参考サイト(1):Setting a Toolbar Item’s Representation
(前後のページにも有用な情報があるので、一通り目を通しておいたほうがいいと思われます。)

 メニューは付加しただけでは有効になりませんが、ターゲット/アクションを設定することで有効になります。この辺は、通常のメニューと同じです。
 また、メニューの有効/無効(または常に無効)は、これも通常のメニュー同様、validateMenuItem:の戻り値で指定します。
 メニューのアクションは、今回はツールバーアイテムのアクションと同じメソッドを割り付け、タグで判別することとします。

 なお、サーチフィールドは、メニュー側に標準的な機能はないようで、例えばFinderはウィンドウ内に検索バーを表示、メール.appはウィンドウ幅を拡大して表示等、個別に対応している?ようです。
 このようなこともあって、今回はサーチフィールドについては常に無効とします。

 それと、これは実装してから判明したことですが、アクションに渡ってくる送出元(Sender)がサブメニューの場合、そこから(元の)メニューを辿る方法が分からなかったため、タグ番号からツールバーアイテムを取得してそこからメニューを取得するという、ややまどろっこしい方法をとりました。この辺は要調査ではあります。

 残りの(主な)方針は、以下の通りとしました。

 Xojoでの実装
【ソースコードのコピー&ペーストについて】
・ソースコード(グレー背景部分の全文)をコピーし、指定のオブジェクトにペーストすると、(新規作成して名前等を個別にコピー&ペーストしなくても)復元されます。
・ペーストはオブジェクトに行って下さい。オブジェクト内のEvent Handlers/Methods/Properties等にペーストしても、うまくいかない場合があります。
  1. Xojoで新規プロジェクトを作成
  2. Window1にListBox(名前はListBox1)、PushButton2個(名前はPushButton1とPushButton2)を追加(注:動作確認用であり、必須ではない。)
  3. 以下をPushButton1にペースト
    Sub Action() Handles Action
      SetButtonEnable(601,not GetButtonEnable(601))
    End Sub
    
  4. 以下をPushButton2にペースト
    Sub Action() Handles Action
      EnableNewWin = not EnableNewWin
    End Sub
    
  5. 以下をWindow1にペースト
    Sub Activate() Handles Activate
      // ツールバー縮小時のメニュー表示がなされないことの対策(モードを切り替えると(再描画が発生して?)表示される)
      ToolbarDispMode()
    End Sub
    
  6. 以下をWindow1にペースト
    Sub Open() Handles Open
      // ツールバー生成
      Dim t As NSToolbar = new NSToolbar(self.Handle, AddressOf ToolbarItemClicked, AddressOf ToolbarValidateMenuItem)
    End Sub
    
  7. 以下をWindow1にペースト
    Protected Function GetButtonEnable(tagNo As Integer) as Boolean
      // 指定されたタグ番号を持つアイテムを取得
      Dim pnt As Ptr = GetToolItem(tagNo)
      
      // 現在の有効/無効値を取得して返す
      Declare Function isEnabled Lib "Cocoa" Selector "isEnabled" (receiver As Ptr) As Boolean
      return isEnabled(pnt)
    End Function
    
  8. 以下をWindow1にペースト
    Protected Function GetToolItem(tagNo As Integer) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSStringFromClass Lib "Cocoa" (aClass As Ptr) As CFStringRef
      
      Declare Function myClass Lib "Cocoa" Selector "class" (receiver As Ptr) As Ptr
      Declare Function objectAtIndex Lib "Cocoa" Selector "objectAtIndex:" (receiver As Ptr, info As Integer) As Ptr
      Declare Function view Lib "Cocoa" Selector "view" (receiver As Ptr) As Ptr
      Declare Function tagForSegment Lib "Cocoa" Selector "tagForSegment:" (receiver As Ptr, seg As Integer) As Integer
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      
      // ツールバーの取得
      declare function toolbar lib "Cocoa" selector "toolbar" (obj_id as Integer) as Ptr
      Dim pnt1 As Ptr = toolbar(Window1.Handle)
      
      // ツールバーアイテム(配列)の取得
      declare function items lib "Cocoa" selector "items" (receiver As Ptr) as Ptr
      Dim pnt2 As Ptr = items(pnt1)
      
      // 配列の個数の取得
      declare function count lib "Cocoa" selector "count" (receiver As Ptr) as Integer
      Dim cnt As Integer = count(pnt2)
      
      Dim i, tag As Integer
      Dim pnt3, pnt4, cls1 As Ptr
      for i=0 to cnt-1
        // ツールバーアイテムを順番に取得
        pnt3 = objectAtIndex(pnt2, i)
        // viewの取得(コントロール類はviewで取得できる)
        pnt4 = view(pnt3)
        // コントロールのクラス名を文字列で取得
        cls1 = myClass(pnt4)
        if NSStringFromClass(cls1)="NSSegmentedControl" then  // セグメンテッドコントロール
          tag = tagForSegment(cell(pnt4),0)
          if tag=tagNo then  // 指定されたタグなら
            return pnt3  // ツールバーアイテムを返す
          end if
        end if
      next
    End Function
    
  9. 以下をWindow1にペースト
    Protected Function GetToolItemSearch() as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSStringFromClass Lib "Cocoa" (aClass As Ptr) As CFStringRef
      
      Declare Function myClass Lib "Cocoa" Selector "class" (receiver As Ptr) As Ptr
      Declare Function objectAtIndex Lib "Cocoa" Selector "objectAtIndex:" (receiver As Ptr, info As Integer) As Ptr
      Declare Function view Lib "Cocoa" Selector "view" (receiver As Ptr) As Ptr
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      
      // ツールバーの取得
      declare function toolbar lib "Cocoa" selector "toolbar" (obj_id as Integer) as Ptr
      Dim pnt1 As Ptr = toolbar(Window1.Handle)
      
      // ツールバーアイテム(配列)の取得
      declare function visibleItems lib "Cocoa" selector "visibleItems" (receiver As Ptr) as Ptr
      Dim pnt2 As Ptr = visibleItems(pnt1)
      
      // 配列の個数の取得
      declare function count lib "Cocoa" selector "count" (receiver As Ptr) as Integer
      Dim cnt As Integer = count(pnt2)
      
      Dim i As Integer
      Dim pnt3, pnt4, cls1 As Ptr
      for i=0 to cnt-1
        // ツールバーアイテムを順番に取得
        pnt3 = objectAtIndex(pnt2, i)
        // viewの取得(コントロール類はviewで取得できる)
        pnt4 = view(pnt3)
        // コントロールのクラス名を文字列で取得
        cls1 = myClass(pnt4)
        if NSStringFromClass(cls1)="NSSearchField" then  // サーチフィールドなら
          return cell(pnt4)  // サーチフィールドのセルを返す
        end if
      next
    End Function
    
  10. 以下をWindow1にペースト
    Protected Sub SetButtonEnable(tagNo As Integer, flg As Boolean)
      // 指定されたタグ番号を持つアイテムを取得
      Dim pnt As Ptr = GetToolItem(tagNo)
      
      // 値をセット
      Declare Sub setEnabled Lib "Cocoa" Selector "setEnabled:" (receiver As Ptr, selected As Boolean)
      setEnabled(pnt, flg)
    End Sub
    
  11. 以下をWindow1にペースト
    Protected Sub SetSegmentState(tag0 As Integer, menuitem As Ptr, idx As Integer)
      Declare Function objectAtIndex Lib "Cocoa" Selector "objectAtIndex:" (receiver As Ptr, idx As Integer) As Ptr
      Declare Sub setState Lib "Cocoa" Selector "setState:" (receiver As Ptr, flg As Integer)
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      
      // ツールバーアイテムの取得
      Dim segment0 As Ptr = GetToolItem(tag0)
      
      // セグメンテッドコントロールの取得
      Declare Function myView Lib "Cocoa" Selector "view" (receiver As Ptr) As Ptr
      Dim segment1 As Ptr  = myView(segment0)
      
      // ツールバーアイテムが持つメニューアイテムの取得
      Declare Function menuFormRepresentation Lib "Cocoa" Selector "menuFormRepresentation" (receiver As Ptr) As Ptr
      Dim menu1 As Ptr = menuFormRepresentation(segment0)
      
      // メニューアイテムが持つメニューの取得(各サブメニューアイテムはメニューに付加しているため)
      Declare Function submenu Lib "Cocoa" Selector "submenu" (receiver As Ptr) As Ptr
      Dim menuSub1 As Ptr = submenu(menu1)
      
      // 各サブメニューアイテムを配列で取得
      Declare Function itemArray Lib "Cocoa" Selector "itemArray" (receiver As Ptr) As Ptr
      Dim menuAry1 As Ptr = itemArray(menuSub1)
      
      // 配列要素数の取得
      Declare Function count Lib "Cocoa" Selector "count" (receiver As Ptr) As Integer
      Dim cnt As Integer = count(menuAry1)
      
      // 初めに全クリア
      for i As Integer = 0 to cnt-1
        setState(objectAtIndex(menuAry1, i), 0)  // メニュー
        setSelected(segment1, false, i)  // セグメントコントロール
      next
      
      // 指定されたアイテムをオンに
      setState(objectAtIndex(menuAry1, idx), 1)  // メニューアイテムはチェック
      setSelected(segment1, true, idx)  // セグメンテッドコントロールはプッシュ
    End Sub
    
  12. 以下をWindow1にペースト
    Protected Sub ToolbarDispMode()
      // 起動時に一度実行すればいいので、完了済であれば戻る
      if TBOFMdone=true then
        return
      end if
      
      // ツールバーの取得
      declare function toolbar lib "Cocoa" selector "toolbar" (obj_id as Integer) as Ptr
      Dim pnt1 As Ptr = toolbar(Window1.Handle)
      
      // 現在のモードを取得
      Declare Function displayMode Lib "Cocoa" Selector "displayMode" (receiver As Ptr) As Integer
      Dim mode As Integer = displayMode(pnt1)
      
      // 現在のモードと異なる値をセット
      Dim temp As Integer
      select case mode
      case 0
        temp=2
      case 1
        temp=2
      case 2
        temp=3
      case 3
        temp=1
      else
        temp=1
      end select
      
      // 現在のモードと異なる値をセット後、現在の値に戻す
      Declare Sub setDisplayMode Lib "Cocoa" Selector "setDisplayMode:" (receiver As Ptr, value As Integer)
      setDisplayMode(pnt1, temp)  // 0=Default, 1=Icon & Text, 2=Icon Only, 3=Text Only
      setDisplayMode(pnt1, mode)  // 0=Default, 1=Icon & Text, 2=Icon Only, 3=Text Only
      
      // 完了済フラグ・オン
      TBOFMdone=true
    End Sub
    
  13. 以下をWindow1にペースト
    Protected Sub ToolbarItemClicked(sender As Ptr)
      Declare Function description Lib "Cocoa" Selector "description" (receiver As Ptr) As CFStringRef
      Dim name As String = description(sender)
      if InStrB(name,"NSSegmentedControl")>0 then  // セグメンテッドコントロール(ボタン型やメニュー型を含む)
        
        Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
        Declare Function tagForSegment Lib "Cocoa" Selector "tagForSegment:" (receiver As Ptr, seg As Integer) As Integer
        Declare Function selectedSegment Lib "Cocoa" Selector "selectedSegment" (receiver As Ptr) As Integer
        Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
        Dim tagno As Integer = tagForSegment(cell(sender), selectedSegment(sender))
        select case tagno
        case 501
          Listbox1.AddRow "Selected Segment (Btn) = Icon View"
        case 502
          Listbox1.AddRow "Selected Segment (Btn) = List View"
        case 503
          Listbox1.AddRow "Selected Segment (Btn) = Column View"
        case 504
          Listbox1.AddRow "Selected Segment (Btn) = Flow View"  
        case 601
          setSelected(sender, false, 0)
          Listbox1.AddRow "Selected Button = Share"
        case 611
          setSelected(sender, false, 0)
          Listbox1.AddRow "Selected Button = Edit Tag"
        case 621
          setSelected(sender, false, 0)
          Listbox1.AddRow "Selected Button = Quick Look"
        case 701
          setSelected(sender, false, 0)
          Listbox1.AddRow "Selected Button = Go Left"
        case 702
          setSelected(sender, false, 1)
          Listbox1.AddRow "Selected Button = Go Right"
        end select
        
      elseif InStrB(name,"NSMenuItem")>0 then  // メニュー付きセグメンテッドコントロールのメニュー/テキストオンリー時のメニュー/オーバーフローメニュー
        
        Declare Function tag Lib "Cocoa" Selector "tag" (receiver As Ptr) As Integer
        Dim tagno As Integer = tag(sender)
        select case tagno  // メニュー(テキストオンリー時のメニュー/オーバーフローメニューのサブメニュー含む)
        case 101  // 名前
          Listbox1.AddRow "Selected Menu = 名前"
        case 102  // 種類
          Listbox1.AddRow "Selected Menu = 種類"
        case 104  // なし
          Listbox1.AddRow "Selected Menu = なし"
        case 201  // 新規フォルダ
          Listbox1.AddRow "Selected Menu = 新規フォルダ"
        case 202  // 新規ウィンドウで開く
          Listbox1.AddRow "Selected Menu = 新規ウィンドウで開く"
        case 901  // 開く 1
          Listbox1.AddRow "Selected Menu = 開く 1"
        case 902  // 開く 2
          Listbox1.AddRow "Selected Menu = 開く 2"
        case 206  // 閉じる
          Listbox1.AddRow "Selected Menu = 閉じる"
        end select
        
        select case tagno  // テキストオンリー時のメニュー/オーバーフローメニュー
        case 501
          Listbox1.AddRow "Selected Segment (Menu) = Icon View"
          SetSegmentState(501,sender,0)  // チェックマークとボタンプッシュの付け替え
        case 502
          Listbox1.AddRow "Selected Segment (Menu) = List View"
          SetSegmentState(501,sender,1)  // チェックマークとボタンプッシュの付け替え
        case 503
          Listbox1.AddRow "Selected Segment (Menu) = Column View"
          SetSegmentState(501,sender,2)  // チェックマークとボタンプッシュの付け替え
        case 504
          Listbox1.AddRow "Selected Segment (Menu) = Flow View"
          SetSegmentState(501,sender,3)  // チェックマークとボタンプッシュの付け替え
        case 601
          Listbox1.AddRow "Selected Button = Share"
        case 611
          Listbox1.AddRow "Selected Button = Edit Tag"
        case 621
          Listbox1.AddRow "Selected Button = Quick Look"
        case 701
          Listbox1.AddRow "Selected Button = Go Left"
        case 702
          Listbox1.AddRow "Selected Button = Go Right"
        end select
        
      elseif InStrB(name,"NSSearchField")>0 then  // サーチフィールド
        
        Declare Function stringValue Lib "Cocoa" Selector "stringValue" (receiver As Ptr) As CFStringRef
        Listbox1.AddRow "Search Word = "+stringValue(sender)  // 検索文字列
        
      else
        msgBox "No Define :"+name
      end if
    End Sub
    
  14. 以下をWindow1にペースト
    Protected Function ToolbarValidateMenuItem(sender As Ptr) as Boolean
      // このメソッドはメニューが表示される度に呼ばれる(?)ので、戻り値を指定すれば反映される。
      
      // デフォルトはEnable
      Dim enable As Boolean = true
      
      // 渡ってきたメニューアイテムからタグを取得
      Declare Function tag Lib "Cocoa" Selector "tag" (receiver As Ptr) As Integer
      Dim tagno As Integer = tag(sender)
      
      // メニューアイテム(タグ)ごとの処理
      select case tagno
      case 101  // 名前
      case 102  // 種類
      case 201  // 新規フォルダ
      case 202  // 新規ウィンドウで開く
        // フラグが無効ならDisableに
        if EnableNewWin then
          enable = false
        end if
      case 801  // サーチフィールドは常にDisable
        enable = false
      end select
      
      return enable
    End Function
    
  15. 以下をWindow1にペースト
    Private Property EnableNewWin as Boolean
    
  16. 以下をWindow1にペースト
    Protected Property TBOFMdone as Boolean = false
    
  17. 新規クラスを作成(名前は、ここでは「NSToolbar」とした。)
  18. 以下をNSToolbarにペースト
    Private Sub ActionDelegate(sender As Ptr)
    
  19. 以下をNSToolbarにペースト
    Private Function ActionDelegate1(sender As Ptr) as Boolean
    
  20. 以下をNSToolbarにペースト
    Public Sub Constructor(win As Integer, action As ActionDelegate, action1 As ActionDelegate1)
      // 外部指定されたパラメータを保持
      ActionHandler = action  // クラス生成元でActionを受け取るメソッドを登録
      ActionHandler1 = action1  // クラス生成元でActionを受け取るメソッドを登録
      
      // NSToolbarを継承したインスタンスを作成して、ウィンドウに貼り付ける
      makeToolbarInstance(win)
    End Sub
    
  21. 以下をNSToolbarにペースト
    Private Shared Sub actionEvent(id As Ptr, SEL As CString, sender As Ptr)
      // インスタンスメソッドに渡す
      ActionHandler.Invoke(sender)  // クラス生成元でActionを受け取るメソッドを呼び出す
    End Sub
    
  22. 以下をNSToolbarにペースト
    Private Shared Function makeBtnMenu(itemIdentifier As String) as Ptr
      Dim list(-1) As String
      
      select case itemIdentifier
      case ToolbarItemIdentifierSort
        list.Append "名前"
        list.Append "種類"
        list.Append "---"
        list.Append "なし"
        return makeMenu(itemIdentifier,list,101)
        
      case ToolbarItemIdentifierAction
        list.Append "新規フォルダ"
        list.Append "新規ウィンドウで開く"
        list.Append "sub:2:開く"
        list.Append "開く 1"
        list.Append "開く 2"
        list.Append "閉じる"
        return makeMenu(itemIdentifier,list,201)
        
      end select
    End Function
    
  23. 以下をNSToolbarにペースト
    Private Shared Function makeDelegate() as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      // Declare宣言
      Declare Function objc_allocateClassPair Lib "Cocoa" (superclass As Ptr, name As CString, extraBytes As Integer) as Ptr
      Declare Sub objc_registerClassPair Lib "Cocoa" (cls As Ptr)
      Declare Function class_addMethod Lib "Cocoa" (cls As Ptr, name As Ptr, imp As Ptr, types As CString) As Boolean
      
      // クラス名をmyNSToolbarDelegate(名前は任意。少なくとも今回のケースでは参照されない。)、メタクラス名をNSObjectにして、生成
      Dim newClassId As Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), "myNSToolbarDelegate", 0)
      // ランタイムに登録(参照を可能とするため)
      objc_registerClassPair newClassId
      // Delegateの対象となるメソッドを追加(toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:をXojo側で用意したtoolbarItemForItemIdentifierWillBeInsertedIntoToolbarメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:"), AddressOf toolbarItemForItemIdentifierWillBeInsertedIntoToolbar, "@@:@@c") then
        msgBox "error."
        return nil
      end if
      // Delegateの対象となるメソッドを追加(toolbarAllowedItemIdentifiers:をXojo側で用意したtoolbarAllowedItemIdentifiersメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("toolbarAllowedItemIdentifiers:"), AddressOf toolbarAllowedItemIdentifiers, "@@:@") then
        msgBox "error."
        return nil
      end if
      // Delegateの対象となるメソッドを追加(toolbarDefaultItemIdentifiers:をXojo側で用意したtoolbarDefaultItemIdentifiersメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("toolbarDefaultItemIdentifiers:"), AddressOf toolbarDefaultItemIdentifiers, "@@:@") then
        msgBox "error."
        return nil
      end if
      // Delegateの対象となるメソッドを追加(toolbarSelectableItemIdentifiers:をXojo側で用意したtoolbarSelectableItemIdentifiersメソッドで受け取る。)
      if not class_addMethod (newClassId, NSSelectorFromString("toolbarSelectableItemIdentifiers:"), AddressOf toolbarSelectableItemIdentifiers, "@@:@") then
        msgBox "error."
        return nil
      end if
      
      // 上記で生成したクラスのインスタンスを作成
      Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr
      Declare Function init Lib "Cocoa" selector "init" (obj_id As Ptr) As Ptr
      Dim delegateId As Ptr = init(alloc(newClassId))
      
      // インスタンスを返す
      return delegateId
    End Function
    
  24. 以下をNSToolbarにペースト
    Private Shared Function makeMenu(itemIdentifier As String, list() As String, tag0 As Integer) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      Declare Function init Lib "Cocoa" Selector "init" (receiver As Ptr) As Ptr
      Declare Function initWithTitleActKey Lib "Cocoa" Selector "initWithTitle:action:keyEquivalent:" (receiver As Ptr, title As CFStringRef, act As Ptr, key As CFStringRef) As Ptr
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      Declare Sub setTitle Lib "Cocoa" Selector "setTitle:" (receiver As Ptr, title As CFStringRef)
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      Declare Sub setTag Lib "Cocoa" Selector "setTag:" (receiver As Ptr, tag As Integer)
      Declare Sub setSubmenu Lib "Cocoa" Selector "setSubmenu:" (receiver As Ptr, item As Ptr)
      Declare Sub addItem Lib "Cocoa" Selector "addItem:" (receiver As Ptr, item As Ptr)
      Declare Function separatorItem Lib "Cocoa" Selector "separatorItem" (receiver As Ptr) As Ptr
      Declare Sub release Lib "Cocoa" Selector "release" (receiver As Ptr)
      
      // メニューの生成と初期化
      Dim menu1 As Ptr = NSClassFromString("NSMenu")
      menu1 = alloc(menu1)
      menu1 = init(menu1)
      
      // メニュー項目
      Dim menu2, menu20, menu21 As Ptr
      Dim pos, j, cnt As Integer
      pos=0
      do
        
        // メニュー項目クラスの取得
        menu2 = NSClassFromString("NSMenuItem")
        
        if list(pos)="---" then  // セパレータ
          
          menu2 = separatorItem(menu2)
          
        elseif Left(list(pos),4)="sub:" then  // サブメニューを持ったメニュー
          
          // メニュー項目の生成と初期化
          menu2 = alloc(menu2)
          menu2 = init(menu2)
          setTitle(menu2, NthField(list(pos),":",3))
          // Target/Actionを設定
          setTarget(menu2, makeTarget(itemIdentifier))
          setAction(menu2, NSSelectorFromString("action:"))
          // メニューの生成と初期化(サブメニューはメニューに付加する)
          menu20 = NSClassFromString("NSMenu")
          menu20 = alloc(menu20)
          menu20 = init(menu20)
          
          cnt=Val(NthField(list(pos),":",2))
          for j=1 to cnt
            
            // サブメニューを生成
            menu21 = NSClassFromString("NSMenuItem")
            menu21 = alloc(menu21)
            menu21 = initWithTitleActKey(menu21, list(pos+j), NSSelectorFromString("action:"), "")  // ここでActionも設定
            // Targetを設定
            setTarget(menu21, makeTarget(itemIdentifier))
            // タグ
            setTag(menu21, 900+j)  // タグだけ判別するので、同じActionメソッドを使用するメニュー間で固有の数値にする(今回の例では一つしかないので決め打ちしているが、複数ある場合は工夫が必要)
            // メニューにサブメニューを追加
            addItem(menu20, menu21)
            // 解放
            release(menu21)
            
          next
          pos=pos+cnt
          
          // メニュー項目にメニュー(サブメニューを持っている)をセット
          setSubmenu(menu2, menu20)
          // 解放
          release(menu20)
          
        else  // 通常のメニュー
          
          // メニュー項目の生成と初期化
          menu2 = alloc(menu2)
          menu2 = initWithTitleActKey(menu2, list(pos), NSSelectorFromString("action:"), "")  // ここでActionも設定
          // Targetを設定
          setTarget(menu2, makeTarget(itemIdentifier))
          // タグ
          setTag(menu2, tag0+pos)  // タグだけ判別するので、同じActionメソッドを使用するメニュー間で固有の数値にする
          
        end if
        
        // メニューにメニュー項目を追加
        addItem(menu1, menu2)
        
        // リストが終了したら抜ける
        pos=pos+1
        if pos>list.Ubound then
          exit
        end if
        
      loop
      
      // メニューを返す
      return menu1
    End Function
    
  25. 以下をNSToolbarにペースト
    Private Shared Function makeTbarMenu(itemIdentifier As String) as Ptr
      Dim list(-1) As String
      
      select case itemIdentifier
      case SegmentedControlToolbarItemIdentifier
        list.Append "Segment"  // オーバーフローメニューではタイトルとして使われる。
        list.Append "Seg 1"  // 以下は、テキストのみモードではドロップダウンメニュー、オーバーフローメニューではサブメニューとして使われる。
        list.Append "Seg 2"
        list.Append "Seg 3"
        list.Append "Seg 4"
        return makeTbarMenu2(itemIdentifier,list,501)
        
      case SegmentedControlPairToolbarItemIdentifier
        list.Append "Pair"  // オーバーフローメニューではタイトルとして使われる。
        list.Append "Pair 1"  // 以下は、テキストのみモードではドロップダウンメニュー、オーバーフローメニューではサブメニューとして使われる。
        list.Append "Pair 2"
        return makeTbarMenu2(itemIdentifier,list,701)
        
      case ToolbarItemIdentifierSort
        list.Append "Btn Menu 1"  // オーバーフローメニューではタイトルとして使われる。
        list.Append "名前"  // 以下は、テキストのみモードではドロップダウンメニュー、オーバーフローメニューではサブメニューとして使われる。
        list.Append "種類"
        list.Append "---"
        list.Append "なし"
        return makeTbarMenu2(itemIdentifier,list,101)
        
      case ToolbarItemIdentifierAction
        list.Append "Btn Menu 2"  // オーバーフローメニューではタイトルとして使われる。
        list.Append "新規フォルダ"  // 以下は、テキストのみモードではドロップダウンメニュー、オーバーフローメニューではサブメニューとして使われる。
        list.Append "新規ウィンドウで開く"
        list.Append "sub:2:開く"
        list.Append "開く 1"
        list.Append "開く 2"
        list.Append "閉じる"
        return makeTbarMenu2(itemIdentifier,list,201)
        
      end select
    End Function
    
  26. 以下をNSToolbarにペースト
    Private Shared Function makeTbarMenu2(itemIdentifier As String, list() As String, tag0 As Integer) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      // メニュー項目の生成と初期化
      Dim menu2 As Ptr = NSClassFromString("NSMenuItem")
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      Declare Function init Lib "Cocoa" Selector "init" (receiver As Ptr) As Ptr
      menu2 = init(alloc(menu2))
      Declare Sub setTitle Lib "Cocoa" Selector "setTitle:" (receiver As Ptr, title As CFStringRef)
      setTitle(menu2, list(0))
      Declare Sub setImage Lib "Cocoa" Selector "setImage:" (receiver As Ptr, img As Ptr)
      setImage(menu2, nil)  // メニューに付加するアイコン。オーバーフローメニューの場合はnilにしないと、タイトルがずれる(通常のメニューでも弊害はなさそう)
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      setTarget(menu2, makeTarget(itemIdentifier))
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      setAction(menu2, NSSelectorFromString("action:"))
      
      // リストの先頭は使用済なので削除する
      list.Remove(0)
      
      // サブメニュー生成
      Dim menu20 As Ptr = MakeMenu(itemIdentifier,list,tag0)
      
      // メニュー項目にメニュー(サブメニューを持っている)をセット
      Declare Sub setSubmenu Lib "Cocoa" Selector "setSubmenu:" (receiver As Ptr, item As Ptr)
      setSubmenu(menu2, menu20)
      
      // clean up
      Declare Sub release Lib "Cocoa" Selector "release" (receiver As Ptr)
      release(menu20)
      
      // メニュー項目を返す
      return menu2
    End Function
    
  27. 以下をNSToolbarにペースト
    Private Shared Function setToolItemSearch(itemIdentifier As String) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      
      // サーチフィールド初期化
      Dim search1 As Ptr = NSClassFromString("NSSearchField")
      search1 = alloc(search1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      search1 = initWithFrame(search1, NSMakeRect(0,0,150,24))
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル/ツールチップ設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, "NSSearchField")
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, "Search")
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:" (receiver As Ptr, text As CFStringRef)
      setToolTip(toolbarItem, "Search Your Document")
      
      // サーチフィールドクリック後、直ちに文字入力を可能とするための設定(2016.06.28追加)
      Declare Sub refusesFirstResponder Lib "Cocoa" Selector "setRefusesFirstResponder:" (receiver As Ptr, flg As Boolean)
      refusesFirstResponder(search1,true)
      
      // メニューのTarget/Action設定(テキストオンリー時のメニュー/オーバーフローメニュー対策)
      Declare Function menuFormRepresentation Lib "Cocoa" Selector "menuFormRepresentation" (receiver As Ptr) As Ptr
      Dim menuItem As Ptr = menuFormRepresentation(toolbarItem)  // 既存のmenuItemを持ってくる
      setTarget(menuItem, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      setAction(menuItem, NSSelectorFromString("action:"))
      Declare Sub setTagMenu Lib "Cocoa" Selector "setTag:" (receiver As Ptr, tag As Integer)
      setTagMenu(menuItem, 801)
      Declare Sub setImage Lib "Cocoa" Selector "setImage:" (receiver As Ptr, img As Ptr)
      setImage(menuItem, nil)
      
      // アイテムのビューにサーチフィールドを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, search1)
      
      // Target/Action設定
      setTarget(search1, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      setAction(search1, NSSelectorFromString("action:"))
      
      // 検索オプション設定
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Dim cell1 As Ptr = cell(search1)  // NSSearchFieldCellを取得
      Declare Sub setSendsWholeSearchString Lib "Cocoa" Selector "setSendsWholeSearchString:" (receiver As Ptr, flag As Boolean)
      setSendsWholeSearchString(cell1, true)  // false:キーストローク毎にActionが発生, true:Retrnキーを押した時点でActionが発生
      Declare Sub sendsSearchStringImmediately Lib "Cocoa" Selector "setSendsSearchStringImmediately:" (receiver As Ptr, flag As Boolean)
      sendsSearchStringImmediately(cell1, false)  // false:文字をある程度溜めてからActionが発生, true:文字を入力すると直ちにActionが発生
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
  28. 以下をNSToolbarにペースト
    Private Shared Function setToolItemSegment(itemIdentifier As String) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      Dim image0 As Ptr = NSClassFromString("NSImage")
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Dim image2 As Ptr = NSClassFromString("NSImage")
      Dim image3 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image0 = imageNamed(image0, "NSIconViewTemplate")
      image1 = imageNamed(image1, "NSListViewTemplate")
      image2 = imageNamed(image2, "NSColumnViewTemplate")
      image3 = imageNamed(image3, "NSFlowViewTemplate")
      
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,111,24))
      
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 4)
      
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image0, 0)
      setImage(segment1, image1, 1)
      setImage(segment1, image2, 2)
      setImage(segment1, image3, 3)
      
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As CGFloat, no As Integer)
      setWidth(segment1, 26, 0)
      setWidth(segment1, 26, 1)
      setWidth(segment1, 26, 2)
      setWidth(segment1, 26, 3)
      
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, true, 0)
      setSelected(segment1, false, 1)
      setSelected(segment1, false, 2)
      setSelected(segment1, false, 3)
      
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setTag Lib "Cocoa" Selector "setTag:forSegment:" (receiver As Ptr, tag As Integer, no As Integer)
      setTag(cell(segment1), 501, 0)
      setTag(cell(segment1), 502, 1)
      setTag(cell(segment1), 503, 2)
      setTag(cell(segment1), 504, 3)
      
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:forSegment:" (receiver As Ptr, text As CFStringRef, no As Integer)
      setToolTip(cell(segment1), "Segmented Control 0", 0)
      setToolTip(cell(segment1), "Segmented Control 1", 1)
      setToolTip(cell(segment1), "Segmented Control 2", 2)
      setToolTip(cell(segment1), "Segmented Control 3", 3)
      
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, "NSSegmentedControl")
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, "Segmented Control")
      'Declare Sub setTag2 Lib "Cocoa" Selector "setTag:" (receiver As Ptr, tag As Integer)
      'setTag2(toolbarItem, 500)
      
      // メニューのTarget/Action設定(テキストオンリー時のメニュー/オーバーフローメニュー対策)
      Dim menu1 As Ptr = makeTbarMenu(itemIdentifier)  // メニュー生成
      Declare Sub setMenuFormRepresentation Lib "Cocoa" Selector "setMenuFormRepresentation:" (receiver As Ptr, menu As Ptr)
      setMenuFormRepresentation(toolbarItem, menu1)  // 戻す
      
      // メニューにチェックマークをつける(ボタンと同じく、0番セグメントをオンに)
      Declare Function submenu Lib "Cocoa" Selector "submenu" (receiver As Ptr) As Ptr
      Dim menuSub1 As Ptr = submenu(menu1)
      Declare Function itemArray Lib "Cocoa" Selector "itemArray" (receiver As Ptr) As Ptr
      Dim menuAry1 As Ptr = itemArray(menuSub1)
      Declare Function objectAtIndex Lib "Cocoa" Selector "objectAtIndex:" (receiver As Ptr, idx As Integer) As Ptr
      Dim menuItem1 As Ptr = objectAtIndex(menuAry1, 0)
      Declare Sub setState Lib "Cocoa" Selector "setState:" (receiver As Ptr, flg As Integer)
      setState(menuItem1, 1)
      
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      setTarget(toolbarItem, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      setAction(toolbarItem, NSSelectorFromString("action:"))
      
      return toolbarItem
    End Function
    
  29. 以下をNSToolbarにペースト
    Private Shared Function setToolItemSegment1(itemIdentifier As String, label As String, labelL As String, tooltip As String, icon As String, tag As Integer) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image1 = imageNamed(image1, icon)
      
      // セグメンテッドコントロール初期化
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,38,24))
      
      // セグメント数/ラベル/選択状態/タグ設定
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 1)
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image1, 0)
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As CGFloat, no As Integer)
      setWidth(segment1, 34, 0)
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, false, 0)  // 非選択
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setTag Lib "Cocoa" Selector "setTag:forSegment:" (receiver As Ptr, tag As Integer, no As Integer)
      setTag(cell(segment1), tag, 0)  // タグだけ判別するので、同じActionメソッドを使用するセグメント間で固有の数値にする
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル/ツールチップ設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, label)
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, labelL)
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:" (receiver As Ptr, text As CFStringRef)
      setToolTip(toolbarItem, tooltip)
      
      // メニューのTarget/Action設定(テキストオンリー時のメニュー/オーバーフローメニュー対策)
      Declare Function menuFormRepresentation Lib "Cocoa" Selector "menuFormRepresentation" (receiver As Ptr) As Ptr
      Dim menuItem As Ptr = menuFormRepresentation(toolbarItem)  // 既存のmenuItemを持ってくる
      setTarget(menuItem, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      setAction(menuItem, NSSelectorFromString("action:"))
      Declare Sub setTagMenu Lib "Cocoa" Selector "setTag:" (receiver As Ptr, tag As Integer)
      setTagMenu(menuItem, tag)  // セグメントに設定したものと同じ数値にする
      Declare Sub setImage Lib "Cocoa" Selector "setImage:" (receiver As Ptr, img As Ptr)
      setImage(menuItem, nil)
      
      // アイテムのビューにセグメンテッドコントロールを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      // Target/Action設定
      setTarget(toolbarItem, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      setAction(toolbarItem, NSSelectorFromString("action:"))
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
  30. 以下をNSToolbarにペースト(メニューを示す下向き矢印の表示を、標準機能に改めた。(2021.05.11))
    Private Shared Function setToolItemSegment1Menu(itemIdentifier As String, label As String, labelL As String, tooltip As String, icon As String, menu As Ptr) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      // 標準イメージの取得
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image1 = imageNamed(image1, icon)
      Declare Sub setTemplate Lib "Cocoa" Selector "setTemplate:" (receiver As Ptr, flg As Boolean)
      setTemplate(image1, true)  // 選択時のカラー反転や、ディアクティベート時のグレー化
      
      // セグメンテッドコントロール初期化
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,40,22))
      
      // セグメント数/イメージ/選択状態/メニュー
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 1)
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image1, 0)
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As CGFloat, no As Integer)
      setWidth(segment1, 36, 0)
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, false, 0)  // 非選択
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setMenu Lib "Cocoa" Selector "setMenu:forSegment:" (receiver As Ptr, menu As Ptr, no As Integer)
      setMenu(cell(segment1), menu, 0)
      Declare Sub setShowsMenuIndicator Lib "Cocoa" Selector "setShowsMenuIndicator:forSegment:" (receiver As Ptr, flg As Boolean, no As Integer)
      setShowsMenuIndicator(segment1, true, 0)  // メニューを示す下向き矢印表示
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル/ツールチップ設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, label)
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, labelL)
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:" (receiver As Ptr, text As CFStringRef)
      setToolTip(toolbarItem, labelL)
      
      // メニューのTarget/Action設定(テキストオンリー時のメニュー/オーバーフローメニュー対策)
      Declare Sub setMenuFormRepresentation Lib "Cocoa" Selector "setMenuFormRepresentation:" (receiver As Ptr, menu As Ptr)
      setMenuFormRepresentation(toolbarItem, makeTbarMenu(itemIdentifier))  // 戻す
      
      // アイテムのビューにセグメンテッドコントロールを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
    以下の旧版は、実装方法の一つではあるので、参考まで。
    Private Shared Function setToolItemSegment1Menu(itemIdentifier As String, label As String, labelL As String, tooltip As String, icon As String, menu As Ptr) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      // イメージの生成(標準イメージを貼り付けるベース)
      Dim image0 As Ptr = NSClassFromString("NSImage")
      image0 = alloc(image0)
      Declare Function initWithSize Lib "Cocoa" Selector "initWithSize:" (receiver As Ptr, size As NSSize) As Ptr
      image0 = initWithSize(image0, NSMakeSize(40,24))
      
      // 標準イメージの取得
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Dim image2 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image1 = imageNamed(image1, icon)
      image2 = imageNamed(image2, "NSDropDownIndicatorTemplate")
      
      // イメージの合成
      Declare Sub lockFocus Lib "Cocoa" Selector "lockFocus" (receiver As Ptr)
      lockFocus(image0)
      Declare Sub compositeToPoint Lib "Cocoa" Selector "compositeToPoint:operation:" (receiver As Ptr, item1 As NSPoint, item2 As Integer)
      compositeToPoint(image1, NSMakePoint(5, 5), 2)
      compositeToPoint(image2, NSMakePoint(25, 10), 2)
      Declare Sub unlockFocus Lib "Cocoa" Selector "unlockFocus" (receiver As Ptr)
      unlockFocus(image0)
      
      Declare Sub setTemplate Lib "Cocoa" Selector "setTemplate:" (receiver As Ptr, flg As Boolean)
      setTemplate(image0, true)  // 選択時のカラー反転や、ディアクティベート時のグレー化
      
      // セグメンテッドコントロール初期化
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,40,22))
      
      // セグメント数/イメージ/選択状態/メニュー
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 1)
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image0, 0)
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As CGFloat, no As Integer)
      setWidth(segment1, 36, 0)
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, false, 0)  // 非選択
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setMenu Lib "Cocoa" Selector "setMenu:forSegment:" (receiver As Ptr, menu As Ptr, no As Integer)
      setMenu(cell(segment1), menu, 0)
      
      // アイテム初期化
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      // ラベル/ツールチップ設定
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, label)
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, labelL)
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:" (receiver As Ptr, text As CFStringRef)
      setToolTip(toolbarItem, labelL)
      
      // メニューのTarget/Action設定(テキストオンリー時のメニュー/オーバーフローメニュー対策)
      Declare Sub setMenuFormRepresentation Lib "Cocoa" Selector "setMenuFormRepresentation:" (receiver As Ptr, menu As Ptr)
      setMenuFormRepresentation(toolbarItem, makeTbarMenu(itemIdentifier))  // 戻す
      
      // アイテムのビューにセグメンテッドコントロールを設定
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      // 生成したアイテムを返す
      return toolbarItem
    End Function
    
  31. 以下をNSToolbarにペースト
    Private Shared Function setToolItemSegmentPair(itemIdentifier As String) as Ptr
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
      
      // 標準イメージの取得
      Dim image0 As Ptr = NSClassFromString("NSImage")
      Dim image1 As Ptr = NSClassFromString("NSImage")
      Declare Function imageNamed Lib "Cocoa" Selector "imageNamed:" (receiver As Ptr, name As CFStringRef) As Ptr
      image0 = imageNamed(image0, "NSGoLeftTemplate")
      image1 = imageNamed(image1, "NSGoRightTemplate")
      Declare Sub setTemplate Lib "Cocoa" Selector "setTemplate:" (receiver As Ptr, flg As Boolean)
      setTemplate(image0, true)  // 選択時のカラー反転や、ディアクティベート時のグレー化
      setTemplate(image1, true)  // 選択時のカラー反転や、ディアクティベート時のグレー化
      
      Dim segment1 As Ptr = NSClassFromString("NSSegmentedControl")
      segment1 = alloc(segment1)
      Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr
      segment1 = initWithFrame(segment1, NSMakeRect(0,0,51,24))
      
      Declare Sub setSegmentCount Lib "Cocoa" Selector "setSegmentCount:" (receiver As Ptr, cnt As Integer)
      setSegmentCount(segment1, 2)
      
      Declare Sub setSegmentStyle Lib "Cocoa" Selector "setSegmentStyle:" (receiver As Ptr, cnt As Integer)
      setSegmentStyle(segment1, 8)  // 8だとImageのTemplateが効かない > OS標準でもそのようなので仕様?
      
      Declare Sub setImage Lib "Cocoa" Selector "setImage:forSegment:" (receiver As Ptr, image As Ptr, no As Integer)
      setImage(segment1, image0, 0)
      setImage(segment1, image1, 1)
      
      Declare Sub setWidth Lib "Cocoa" Selector "setWidth:forSegment:" (receiver As Ptr, w As CGFloat, no As Integer)
      setWidth(segment1, 23, 0)
      setWidth(segment1, 23, 1)
      
      Declare Sub setSelected Lib "Cocoa" Selector "setSelected:forSegment:" (receiver As Ptr, selected As Boolean, no As Integer)
      setSelected(segment1, false, 0)
      setSelected(segment1, false, 1)
      
      Declare Function cell Lib "Cocoa" Selector "cell" (receiver As Ptr) As Ptr
      Declare Sub setTag Lib "Cocoa" Selector "setTag:forSegment:" (receiver As Ptr, tag As Integer, no As Integer)
      setTag(cell(segment1), 701, 0)
      setTag(cell(segment1), 702, 1)
      
      Declare Sub setToolTip Lib "Cocoa" Selector "setToolTip:forSegment:" (receiver As Ptr, text As CFStringRef, no As Integer)
      setToolTip(cell(segment1), "Segmented Control 0", 0)
      setToolTip(cell(segment1), "Segmented Control 1", 1)
      
      Dim toolbarItem As Ptr = NSClassFromString("NSToolbarItem")
      toolbarItem = alloc(toolbarItem)
      Declare Function initWithItemIdentifier Lib "Cocoa" Selector "initWithItemIdentifier:" (receiver As Ptr, identifier As CFStringRef) As Ptr
      toolbarItem = initWithItemIdentifier(toolbarItem, itemIdentifier)
      
      Declare Sub setLabel Lib "Cocoa" Selector "setLabel:" (receiver As Ptr, label As CFStringRef)
      setLabel(toolbarItem, "Button Pair")
      Declare Sub setPaletteLabel Lib "Cocoa" Selector "setPaletteLabel:" (receiver As Ptr, label As CFStringRef)
      setPaletteLabel(toolbarItem, "Button Pair")
      
      // メニューのTarget/Action設定(テキストオンリー時のメニュー/オーバーフローメニュー対策)
      Declare Sub setMenuFormRepresentation Lib "Cocoa" Selector "setMenuFormRepresentation:" (receiver As Ptr, menu As Ptr)
      setMenuFormRepresentation(toolbarItem, makeTbarMenu(itemIdentifier))  // 戻す
      
      Declare Sub setView Lib "Cocoa" Selector "setView:" (receiver As Ptr, actionTarget As Ptr)
      setView(toolbarItem, segment1)
      
      Declare Sub setTarget Lib "Cocoa" Selector "setTarget:" (receiver As Ptr, actionTarget As Ptr)
      setTarget(toolbarItem, makeTarget(itemIdentifier))  // Actionの受け口となるメソッドを定義
      Declare Sub setAction Lib "Cocoa" Selector "setAction:" (receiver As Ptr, actionEvent As Ptr)
      setAction(toolbarItem, NSSelectorFromString("action:"))
      
      return toolbarItem
    End Function
    
  32. 以下をNSToolbarにペースト
    Private Shared Function toolbarItemForItemIdentifierWillBeInsertedIntoToolbar(id as Ptr, sel as CString, toolbar As Ptr, itemIdentifier As CFStringRef, flag As Boolean) as Ptr
      
      if itemIdentifier = SearchToolbarItemIdentifier then
        return setToolItemSearch(itemIdentifier)
        
      elseif itemIdentifier = SegmentedControlToolbarItemIdentifier then
        return setToolItemSegment(itemIdentifier)
        
      elseif itemIdentifier = ToolbarItemIdentifierShare then
        return setToolItemSegment1(itemIdentifier,"Button 1","Button","Button","NSShareTemplate",601)
        
      elseif itemIdentifier = ToolbarItemIdentifierTag then
        return setToolItemSegment1(itemIdentifier,"Button 2","Button","Button","NSBookmarksTemplate",611)  // 本来はタグアイコンを代替使用
        
      elseif itemIdentifier = ToolbarItemIdentifierQuick then
        return setToolItemSegment1(itemIdentifier,"Button 3","Button","Button","NSQuickLookTemplate",621)
        
      elseif itemIdentifier = ToolbarItemIdentifierSort then
        return setToolItemSegment1Menu(itemIdentifier,"Btn Menu 1","Btn Menu 1","Btn Menu 1","NSHomeTemplate",makeBtnMenu(itemIdentifier))  // 本来はソートアイコンを代替使用
        
      elseif itemIdentifier = ToolbarItemIdentifierAction then
        return setToolItemSegment1Menu(itemIdentifier,"Btn Menu 2","Btn Menu 2","Btn Menu 2","NSActionTemplate",makeBtnMenu(itemIdentifier))
        
      elseif itemIdentifier = SegmentedControlPairToolbarItemIdentifier then
        return setToolItemSegmentPair(itemIdentifier)
        
      else
        return nil
      end if
    End Function
    
  33. 以下のNSToolbarのメソッドを前回プロジェクトからペースト
    ・makeTarget
    ・makeToolbarInstance
    ・toolbarAllowedItemIdentifiers
    ・toolbarDefaultItemIdentifiers
    ・toolbarSelectableItemIdentifiers
    ・validateMenuItem
  34. 以下のNSToolbarのプロパティを前回プロジェクトからペースト
    ・ActionHandler
    ・ActionHandler1
    ・SearchDelegateInstance
    ・SearchToolbarItemIdentifier
    ・SegmentedControlPairToolbarItemIdentifier
    ・SegmentedControlToolbarItemIdentifier
    ・TargetInstance
    ・ToolbarItemIdentifierAction
    ・ToolbarItemIdentifierQuick
    ・ToolbarItemIdentifierShare
    ・ToolbarItemIdentifierSort
    ・ToolbarItemIdentifierTag
  35. 他に、NSMakePoint/NSMakeRect/NSMakeSize(メソッド)、NSPoint/NSRect/NSSize(構造体)が必要ですが、それらはmacoslibからコピーさせて頂きました。(上記NSToolbarにコピーする。)
 実行してみたところ、付加したメニューが機能することを確認しました。
S Shot3


 おわりに

 メニュー対応は、アイコン向けとは別処理となって、漏れが出ないようにするのは結構メンドいです。

 また、「テキストのみ」モードでのメニューは、(例えば)Finderではマウスクリックで表示されますが、今回の実装では長押し(この場合は離すとメニューが消える)、またはクリック時に素早くマウスを動かさないと、表示されません。ちなみに、macoslibのサンプルでも同様でした。
 Xojoが間に一枚噛んでいることで、何らかの取りこぼしが発生している可能性もありますが、詳細は不明です。


 お世話になったサイト

 貴重な情報をご提供頂いている皆様に、お礼申し上げます。(以下、順不同)

 参考サイト(1):Setting a Toolbar Item’s Representation


 更新履歴

 2021.05.11 Xojoでの実装、の30項を変更。
 2020.03.09 新規作成


[Home]  [MacSoft]  [Donation]  [History]  [Privacy Policy]  [Affiliate Policy]