ASObjC Source List with Static Values

Ok, so here’s how you use a nib file (at least one way of doing it, but it’s the one that makes most sense to me…).

First, change the model. In the AppDelegate file’s ‘applicationWillFinishLaunching:’ handler, change the list of dictionaries to add a new value “nibName” that holds the name of the nib we want to invoke. It should look something like this:

set sidebarList to {{title:"Header 1", isHeader:true, nibName:""}, {title:"Line 1", isHeader:false, nibName:"Line1"}, {title:"Header 2", isHeader:true, nibName:""}, {title:"Line 2", isHeader:false, nibName:"Line2"}, {title:"Line 3", isHeader:false, nibName:"Line3"}, {title:"Header 3", isHeader:true, nibName:""}, {title:"Line 4", isHeader:false, nibName:"Line4"}}

Next, create a view controller. Add a new blank file to the project: Choose New File, scroll down to the ‘Other’ section, choose ‘Empty’, and then click the ‘Next’ Button. Name the file “MyViewController.applescript” (or whatever makes sense to you, with a .applescript extension). Open this new file and edit in the following:

script MyViewController
	property parent: class "NSViewController"

	on initWithNibName:nibName bundle:bundle
		continue initWithNibName:nibName bundle:bundle
	end

	on loadView()
		continue loadView()
	end
end script

The parent class has to be NSViewController (it defualts, I think, to NSObject), the name of the script is the name of the class you’ll invoke later, and you’ll need to override at least these two methods explicitly. continue is the AppleScript equivalent of ‘super’, so all you’re really doing here is telling the subclass to call the objective-C class implementations. You’ll probably need to do on override like this for any method you call explicitly from AppleScript, should you decide to expand.

Next, create your xib files. Choose New File, scroll down to the ‘User Interface’ section, choose ‘View’, and then click the ‘Next’ Button. Use the names in your data model (e.g., if a ‘nibName’ in the model is “Line2” you should have a name corresponding file Line2.xib; I believe Xcode will automatically add the xib extension). Construct the contents of the view as you see fit, then do this:

  1. In the xib view, click on File’s Owner
  2. Click on the Identity inspector, and make sure the file’s owner class is “MyViewController”, or whatever you named your view controller class. It has to correspond to the first line of the file: “script MyViewController”
  3. Click on the Connections inspector, and drag to connect the ‘view’ outlet of the File’s Owner to the top-level of the view you’ve created.

Of course, here you’ll have to do whatever bindings and connection you want to make for this particular view. Anything you set as a property in the view controller can be accessed by the view through the parent object, and that’s how you’ll pass data into the view. But I’m sure you can figure that out.

Now you’re ready to go: back in the AppDelegate file, change the ‘tableViewSelectionDidChange’ like so (note again that I’m using the classname ‘MyViewController’, but you may end up changing that):

on tableViewSelectionDidChange:aNotification
	set tableView to aNotification's object
	set selectedRowIdx to (tableView's selectedRow) as integer
	set rowData to arrayController's arrangedObjects's objectAtIndex:selectedRowIdx
	set theNibName to (rowData's nibName) as text
	if theNibName is not "" then
		set viewController to current application's class "MyViewController"'s alloc's initWithNibName:(rowData's nibName) bundle:(current application's NSBundle's mainBundle)
		viewController's loadView()
		set theView to viewController's view
		set theView's translatesAutoresizingMaskIntoConstraints to false
		set detailSubviews to (detailView's subviews) as list
		if detailSubviews is not {} then
			set oldLabel to item 1 of detailSubviews
			detailView's replaceSubview:oldLabel |with|:theView
		else
			detailView's addSubview:theView
		end

		(* set view constraints *)
		set constraintLeading to theView's leadingAnchor's constraintEqualToAnchor:(detailView's leadingAnchor)
		set constraintTop to theView's topAnchor's constraintEqualToAnchor:(detailView's topAnchor)
		set constraintBottom to theView's bottomAnchor's constraintEqualToAnchor:(detailView's bottomAnchor)
		set constraintTrailing to theView's trailingAnchor's constraintEqualToAnchor:(detailView's trailingAnchor)
		constraintLeading's setActive:true
		constraintTop's setActive:true
		constraintBottom's setActive:true
		constraintTrailing's setActive:true
    end if
end

All this does is create a view for the appropriate xib, load its view, and then add and constrain that view to the detailView, as before.

Just so it’s said, best practice would really be to eliminate the detailView object and use an NSLayoutGuide instead, but this approach strikes me as more accessible.

I suspect you’re doing it the hard way. Create the Nib in Interface Builder as normal, and set its owner to the owner of the table’s nib. Make any connections you need there. Somewhere early in your code run this:

set cell1Nib to current application's NSNib's initWithNibNamed:"<name of your nib>" bundle:(missing value)
myTableView's registerNib:call1Nib forIdentifier:"<some identifier>"

Then you can use that identifier in your tableView:viewForTableColumn:row: handler, and make any changes you need at that point.

Well, except these views are for the detail view, not part of the table view itself. It still might be a better approach; I think I saw you use this approach in some other thread at one point or another, and it crossed my mind to use it, but I’m just so $%^*#$ used to using view controllers that I balked. :rolleyes: Maybe tomorrow I’ll edit in a PS with your suggestion, just to see how it feels.

Yours would certainly be a better approach for adding custom table cell views, but neither Mark nor TheIaMon seems to want to go beyond the default image/textfield view.

thanks Ted, I’ll try something later and let you know the results

Well, I looked into it, and you’re right, we can skip the view controller entirely if we want, using this:

-- IBOutlet for the xib's view
property view:(missing value)

[...]

on tableViewSelectionDidChange:aNotification
[...]
	if theNibName is not "" then
		set theNib to current application's NSNib's alloc's initWithNibNamed:theNibName bundle:(missing value)
		theNib's instantiateWithOwner:me topLevelObjects:(missing value)

                (* the remainder is unchanged, except for pushing the view commands into a tell block *)
		set detailSubviews to (detailView's subviews) as list
		tell view
			set its translatesAutoresizingMaskIntoConstraints to false
			if detailSubviews is not {} then
				set oldview to item 1 of detailSubviews
				detailView's replaceSubview:oldView |with|:it
			else
				detailView's addSubview:it
			end

			set constraintLeading to its leadingAnchor's constraintEqualToAnchor:(detailView's leadingAnchor)
			set constraintTop to its topAnchor's constraintEqualToAnchor:(detailView's topAnchor)
			set constraintBottom to its bottomAnchor's constraintEqualToAnchor:(detailView's bottomAnchor)
			set constraintTrailing to its trailingAnchor's constraintEqualToAnchor:(detailView's trailingAnchor)
			constraintLeading's setActive:true
			constraintTop's setActive:true
			constraintBottom's setActive:true
			constraintTrailing's setActive:true
		end tell
	end if
end tableViewSelectionDidChange:

Whether this is advantageous or not would depend on how interactive the view is, I suppose: The more we have to interact with the view programmatically, the more properties and code we would have to cram into the app delegate script.

No, I’m just some random dude who stumbled across the StackOverflow example for which I am eternally grateful!!

I tried but lost in the process.
https://www.sendspace.com/file/vn1ej5

Quoting everything I said back at me and saying you got lost is unhelpful. It does’nt tell me anything about what you did or where you got lost. Please edit down quotes to the bare minimum that demonstrates a problem (or if you can’t, don’t include them at all) and expand what you yourself write to give more specific details.

I’ll take a look at the link, but please keep in mind that I’m here to assist you. Ultimately, you have to bang your head on what I write until you understand it, otherwise you’ll never be able to move forward on your own. I’ve already over-committed to this (because I found it interesting, and I like helping earnest people like you), but if you want someone to just do the project for you, you should contract it out.

Hi @Ted, thank you for taking your time and knowledge to help me and help others, you’re right in what you said, but I want to learn how things work and I don’t want anyone to do the project for me otherwise I will never learn to walk on my own legs, I edited the quotes I think my problem is item 3, I posted the project why you can point me out the mistake and not fix it for me anyway
Thank you for your time dedicated to this cause.

I see the problem. When you altered the ‘sidebarList’ variable in ‘applicationWillFinishLaunching_’, you accidentally deleted the two following lines:

		arrayController's addObjects:sidebarList
		arrayController's setSelectionIndex:1

that’s where the data is added to the array controller; without it the GUI has no data to work with.

You’re right, thanks!
Now I’m going to read Mark’s posts and the answers you gave him, maybe I’ll find the answer to my questions.:slight_smile:

Another question, is there any way to make Sidebar transparent?

Transparent? Transparent so that you can see what behind it? The desktop? Other windows? Some background image?

I suppose that could be done — I’ve never worked with transparency, but I imagine it’s possible — but I can’t imagine it would be a pleasant experience for the user. Is there a specific reason you want to do this?

Hi @TedW, some time ago, could you help me with something? Is there a way to insert icons in the sideBar titles?

I would love to know how to add icons on the left and key commands on the right… I’m still a little shady on exactly how the whole thing works. :slight_smile:

I’m looking for the same.