Editable images into a text view

Try wrapping your changes in willChangeValueForKey: and didChangeValueForKey:.

I enclosed the modification between willChangeValueForKey and didChangeValueForKey for the key value bound to the text view – without result: no change, and no error.

Of course I controlled first that everything was OK by logging the property bound to the text view at this point of the code: the log displays the correct “string” of the text contents.

” ” ”

BTW, this unexpected particularity may be the solution to one of my future problems: I have to prevent temporary changes to the text (insertion of strings) to be recorded as permanent by the property. I thought I would have to delete every insertion made before quitting the text (hell) and I was looking to some of “stop watching changes for this key” method.

So I tried to insert raw text somewhere in the text, between two random character, and I saw that the property is not informed of the changes. Good point! But this adds some of uneasiness, too. Why are some changes recorded and others not?

Regards,

PS - With each passing week, my code is less Applescript and more Cocoa (with more Objective-C added). I suppose it’s good sign.

Read up on key-value observing.

Yes, I could read for hours, but I don’t find why a text changing by keyboard differs from setting its contents programmatically – is it that some events (mouse down, key down, and so on) are recorded and other not? Even so, your method to force the property to be notified should work.

No, it’s because some are changed via accessors, and some change ivars directly.

And how does the programmer knows it? From my point of view, I never “set” something to my editor: the text is installed by an array controller, and the bindings points to the current selection of this controller.

Until know, I didn’t set anything, and the properties were always updated when changes were made in the text: typing, drag-and-dropping, cutting and pasting, all was done “in background” by the NSTextView. So it’s the first time I try to set something directly – you mean, when ivars are set directly, there is no notifications?

replaceCharactersInRange_withAttributedString_ seems to be an accessor, why is the property not notified?

Hey, wait a minute: as I have two versions of the text, I switch between them doing so:

        my gTextView's bind_toObject_withKeyPath_options_("attributedString", gCardController, "selection.cShortText", missing value)

Is it possible that this call does not automatically make selection.cShortText an observer of gTextView ?

Yes.

Ok Shane, I give up.

I admit that the couple willChangeValueForKey: and didChangeValueForKey: should force my property to be updated. Maybe the key is misspelled, and it is a syntax problem.

The textView (gTextView) is bound to the current NSMutDic item of a controller (gCardController). The key of the NSMutDic (the text to update) is cLongText. So what is the correct key?

or what else? :confused:

Sorry, but I think I give up too. Every time I think I know what you’re doing here, you confuse me :slight_smile:

No problem, Shane, I often confuse myself. :slight_smile:

I’ll think about this problem and come back when I’ll be able to express it clearly.

I wrote a simple AppleScript to make NSAttributedString with NSTextAttachment.
The attached image is NSImageNameComputer and appended upside down.
Is there any mistake?


--
--	Created by: Takaaki Naganoya
--	Created on: 2020/07/22
--
--	Copyright © 2020 Piyomaru Software, All Rights Reserved
--

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions

set anAttachment to current application's NSTextAttachment's alloc()'s init()
anAttachment's setImage:(current application's NSImage's imageNamed:(current application's NSImageNameComputer))
anAttachment's setBounds:(current application's NSMakeRect(0, 0, 36, 36))
set img1Str to current application's NSAttributedString's attributedStringWithAttachment:anAttachment

set anAssrStr to makeRTFfromParameters("Piyomaru Software", 24) of me

img1Str's appendAttributedString:anAssrStr
img1Str



on makeRTFfromParameters(aStr as string, aFontSize as real)
	set aVal1 to current application's NSFont's fontWithName:"Helvetica" |size|:aFontSize
	set aKey1 to (current application's NSFontAttributeName)
	
	set aVal2 to current application's NSColor's blackColor()
	set aKey2 to (current application's NSForegroundColorAttributeName)
	
	set aVal3 to 0
	set akey3 to (current application's NSKernAttributeName)
	
	set keyList to {aKey1, aKey2, akey3}
	set valList to {aVal1, aVal2, aVal3}
	set attrsDictionary to current application's NSMutableDictionary's dictionaryWithObjects:valList forKeys:keyList
	
	set attrStr to current application's NSMutableAttributedString's alloc()'s initWithString:aStr attributes:attrsDictionary
	return attrStr
end makeRTFfromParameters


Your code produces an image the right way up here. Where are you viewing the result?

This is the result image.

Foce flip processing version is here.

Saving computer image returns appropriate results.


use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

--Get Computer Icon
set anImage to current application's NSImage's imageNamed:(current application's NSImageNameComputer)

set aDesktopPath to (current application's NSProcessInfo's processInfo()'s environment()'s objectForKey:("HOME"))'s stringByAppendingString:"/Desktop/"
set savePath to aDesktopPath's stringByAppendingString:((current application's NSUUID's UUID()'s UUIDString())'s stringByAppendingString:".png")

set fRes to saveNSImageAtPathAsPNG(anImage, savePath) of me


on saveNSImageAtPathAsPNG(anImage, outPath)
	set imageRep to anImage's TIFFRepresentation()
	set aRawimg to current application's NSBitmapImageRep's imageRepWithData:imageRep
	set pathString to current application's NSString's stringWithString:outPath
	set newPath to pathString's stringByExpandingTildeInPath()
	set myNewImageData to (aRawimg's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value))
	set aRes to (myNewImageData's writeToFile:newPath atomically:true) as boolean
	return aRes
end saveNSImageAtPathAsPNG


macOS 10.13: Upside Down
macOS 10.14: Upside Down
macOS 10.15: Normal
macOS 10.16: Normal

Hmm…

Looks like there’s been a change in view flipping.

https://stackoverflow.com/questions/49649553/the-image-of-nstextattachment-is-flipped

Assign the image to an NSTextAttachmentCell, not the NSTextAttachment.

This post solved.


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
use tvLib : script "tvLib"

set aCell to current application's NSTextAttachmentCell's alloc()'s initImageCell:(current application's NSImage's imageNamed:(current application's NSImageNameComputer))
set anAttachment to current application's NSTextAttachment's alloc()'s initWithData:(missing value) ofType:(missing value)
anAttachment's setAttachmentCell:aCell
anAttachment's setBounds:(current application's NSMakeRect(0, 0, 36, 36))
set img1Str to current application's NSAttributedString's attributedStringWithAttachment:anAttachment

set anAssrStr to makeRTFfromParameters("Piyomaru Software", 24) of me

img1Str's appendAttributedString:anAssrStr

dispAttrStr("Main message", "Sub message", img1Str, 400, 80) of tvLib



on makeRTFfromParameters(aStr as string, aFontSize as real)
	set aVal1 to current application's NSFont's fontWithName:"Helvetica" |size|:aFontSize
	set aKey1 to (current application's NSFontAttributeName)
	
	set aVal2 to current application's NSColor's blackColor()
	set aKey2 to (current application's NSForegroundColorAttributeName)
	
	set aVal3 to 0
	set akey3 to (current application's NSKernAttributeName)
	
	set keyList to {aKey1, aKey2, akey3}
	set valList to {aVal1, aVal2, aVal3}
	set attrsDictionary to current application's NSMutableDictionary's dictionaryWithObjects:valList forKeys:keyList
	
	set attrStr to current application's NSMutableAttributedString's alloc()'s initWithString:aStr attributes:attrsDictionary
	return attrStr
end makeRTFfromParameters


What happens if you use your original code, but change this:

anAttachment's setImage:(current application's NSImage's imageNamed:(current application's NSImageNameComputer))

to this:

anAttachment's attachmentCell()'s setImage:(current application's NSImage's imageNamed:(current application's NSImageNameComputer))

Like this?


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
use tvLib : script "tvLib"

set anImage to (current application's NSImage's imageNamed:(current application's NSImageNameComputer))

set anAttachment to current application's NSTextAttachment's alloc()'s init()
anAttachment's attachmentCell()'s setImage:anImage
anAttachment's setBounds:(current application's NSMakeRect(0, 0, 32, 32))

set img1Str to current application's NSAttributedString's attributedStringWithAttachment:anAttachment

set anAssrStr to makeRTFfromParameters("Piyomaru Software", 32, "Times") of me

img1Str's appendAttributedString:anAssrStr

dispAttrStr("Main message", "Sub message", img1Str, 400, 80) of tvLib



on makeRTFfromParameters(aStr as string, aFontSize as real, aFontName as string)
	set aVal1 to current application's NSFont's fontWithName:aFontName |size|:aFontSize
	set aKey1 to (current application's NSFontAttributeName)
	
	set aVal2 to current application's NSColor's blackColor()
	set aKey2 to (current application's NSForegroundColorAttributeName)
	
	set aVal3 to 0
	set akey3 to (current application's NSKernAttributeName)
	
	set keyList to {aKey1, aKey2, akey3}
	set valList to {aVal1, aVal2, aVal3}
	set attrsDictionary to current application's NSMutableDictionary's dictionaryWithObjects:valList forKeys:keyList
	
	set attrStr to current application's NSMutableAttributedString's alloc()'s initWithString:aStr attributes:attrsDictionary
	return attrStr
end makeRTFfromParameters


Yes. An attachment should already have a cell, so you shouldn’t need to make another one.