Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

ObjectiveC integration into Codea — revised demo

in Examples Posts: 128

Hi, Codea Community.

With the newest Codea release in the app store, the ObjC functionality seems improved and wanted to share a new demo with examples of ObjC integration with standard Codea functionality.

Thanks to @jfperusse for his continued work on the ObjC bridge and helping me figure out how to integrate it in these examples.

Thanks to @RonJeffries for his sample spinning cube code I used in the demo.

Good luck and have fun! :-)


--# Main -- ObjcTest2 -- *Note: need to include "Cameras" dependencies to this project from Codea Craft menu in order to touch rotate 3D object function setup() viewer.mode = FULLSCREEN -- Create a new 3D Codea Craft scene scene = craft.scene() -- change the main camera position by "camera" properaty of scene scene.camera.z = -4 -- to actually change the camera's function (e.g. it's viewport) need to actually get the camera element of camera element scene.cameraElement = scene.camera:get(craft.camera) -- to change the scene camera's viewport (i.e. where 3D scene drawn on display) pass relative values x,y,width,height -- note: don't need to include the WIDTH/WIDTH or HEIGHT/HEIGHT expressions but written to illustrate using relative values scene.cameraElement:viewport((0.65*(WIDTH/WIDTH)),(0.15*(HEIGHT/HEIGHT)),(0.33*(WIDTH/WIDTH)),(0.5*(HEIGHT/HEIGHT))) -- Create a new 3D Codea entity to display in a 3D viewport portion of the screen Cube = scene:entity() Cube.model = craft.model.cube(vec3(1,1,1)) Cube.material = craft.material(asset.builtin.Materials.Basic) Cube.material.map = readImage(asset.builtin.Blocks.Missing) Cube.eulerAngles = vec3(0,0,0) scene.camera.z = -4 angle = 0 -- add OrbitViewer (come with Craft "Cameras" dependency attached) scene.camera:add(OrbitViewer, Cube.position, 10, 5, 20) --**Final part of setup below sets up ObjC code to work with Codea** --note: the next statement gets the actual UIViewController running in Codea local vc = objc.viewer --note: the next statement gets makes an instance (new) UI text view that you can use to make a GUI textbox uiTextView = objc.cls.UITextView() vc.view:addSubview_(uiTextView) --note: need to make the next ObjC statement false to allow use of advanced Apple ObjC display formatting constraints uiTextView.translatesAutoresizingMaskIntoConstraints = false -- Pin the trailing edge of the ObjC textbox (uiTextView) 20 in from right side of screen uiTextView.trailingAnchor:constraintEqualToAnchor_constant_(vc.view.trailingAnchor, -20).active = true -- Pin the top edge of the ObjC textbox (uiTextView) 20 down from top of screen) uiTextView.topAnchor:constraintEqualToAnchor_constant_(vc.view.topAnchor, 20).active = true -- Set the width and height of ObjC textbox (uiTextView) uiTextView.widthAnchor:constraintEqualToConstant_(400).active = true uiTextView.heightAnchor:constraintEqualToConstant_(200).active = true uiTextView.text = "Hello World." -- Apple's ObjC GUI objects like uiTextView allow lots of customization uiTextView.layer.cornerRadius = 8 -- placeholder variable for what user types in the textbox typedText="" --create a delegate to work with the UITextView that will sense when changes are made to the textbox Delegate = objc.delegate("UITextViewDelegate") function Delegate:textViewShouldBeginEditing_(objTextView) -- replace with false to prevent editing textbox return true end function Delegate:textViewDidChange_(objTextView) typedText = objTextView.text end -- set delegate to textView AFTER you've created the delegate above uiTextView.delegate = Delegate() -- SFSafariViewController is an ObjC fully-functional self-contained browser that you can resize & include in Codea app local URL = objc.cls.NSURL local url = URL:URLWithString_("http://www.google.com") local SFSafariViewController = objc.cls.SFSafariViewController local safariBrowser = SFSafariViewController:alloc():initWithURL_(url) vc:addChildViewController_(safariBrowser) vc.view:addSubview_(safariBrowser.view) safariBrowser.view.translatesAutoresizingMaskIntoConstraints = false safariBrowser.view.leadingAnchor:constraintEqualToAnchor_constant_(vc.view.leadingAnchor, 20).active = true safariBrowser.view.topAnchor:constraintEqualToAnchor_constant_(vc.view.topAnchor, 20).active = true safariBrowser.view.widthAnchor:constraintEqualToConstant_(450).active = true safariBrowser.view.heightAnchor:constraintEqualToConstant_(700).active = true end function update(dt) -- Update the Codea 3D Craft scene (physics, transforms etc) angle = angle + 1 Cube.eulerAngles = vec3(angle/10, angle, angle/5) scene:update(dt) end function draw() background(0) update(DeltaTime) -- Actually draw a 3d Codea Craft scene scene:draw() -- Use standard Codea Graphics to write to the screen what is in the ObjC Textbox fill(160, 223, 157) textWrapWidth(260) text(typedText, WIDTH/2 + 20, HEIGHT-200) end

Tagged:

Comments

  • Posts: 1,350

    Very cool. One thing I didn't understand, the (WIDTH/WIDTH) etc in this:

    scene.cameraelement:viewport((0.65*(WIDTH/WIDTH)),(0.15*(HEIGHT/HEIGHT)),(0.33*(WIDTH/WIDTH)),(0.5*(HEIGHT/HEIGHT)))
    

    What's up with that? Just documentation?

  • edited March 8 Posts: 128

    Yes, sorry, to be confusing, @RonJeffries. I probably should have left that out that syntax (a previous forum member wasn’t fond of it either on a prior post). I wanted to emphasize that the coordinates are relative coordinates and not actual x,y coordinates which confused me and wrote it that way to emphasize it to others who want to change the viewport’s size. I’ll change it for any future posts.

  • edited March 8 Posts: 2,689

    @SugarRay - loaded up and ran your demo, worked fine until I started playing with the Google window. Switched windows to Safari and Codea crashed. Ran again and didn’t crash, was able to access other sites. But it did crash when I switched windows to parallel Safari.

    P.s. submitted crash report via iPad system crash report.

    Copy to: @dave1707 @Simeon @jfperusse

  • Posts: 1,350

    I did see one crash as well, also submitted.

  • Posts: 128

    Thanks, and sorry, @Bri_G and @RonJeffries—when I tested out going to different sites it worked for me. When you stated that it crashed when you played with the Google window, did you mean when you went navigated to different websites or when you changed aspects of the web browser in the code and tried to run it?

  • Posts: 2,689

    @SugarRay - the first time I ran it I just scrolled the webpage window. I then switched to Safari in parellel and it was then that I got the Codea crash report. Maybe because it lost the focus?

    I thouhgt it might have been when I left Codea, as new versions of Codea always seem to crash the first time they are run. So I was thinking something in the linkage may have been lost in a similar manner.

    The second time it all seemed to be running but when I switched to parallel Safari I got the crash report again.

    Perhaps you can get feedback from @Simeon on what errors were involved.

  • Posts: 128

    Okay, thanks for clarifying, @Bri_G.

    @Simeon — is there a way we can save crash logs in Codea?

  • Posts: 1,350

    I'm not sure what I was doing when mine crashed. I'll try to pay more attention next time.

  • Posts: 128

    Thanks!

  • Posts: 1,795

    @SugarRay I haven’t played with it enough to hit any bugs.

    I just typed in some text and then double-tapped it to select it, and when it worked…

    IT WAS AMAZING.

    This is really, really great.

  • Posts: 128

    Wow, that’s great to hear @UberGoober! I think @jfperusse is continuing to work on refinements in the objective C bridge so should continue to get better and better :-) Have a good weekend.

  • Posts: 297

    @SugarRay @jfperusse Thanks for your hard work. The objc is very useful and the UITextView has all sorts of properties, but I have two problems that I don't know how anyone else has solved:

    • How Do I destroy it? A lot of usage scenarios are to pop up a text box, the user enters the text, determines the input, and then closes the pop up text box, but here, I tried a lot of ways, can make this text box disappear from the screen.
    • How to set a color by using objc.cls.UIColor, I tried several UIColor functions and found none of them worked(just like: objc.cls.uicolor:greenColor(), objc.cls.UIColor:colorWithHex("333333"))
  • Posts: 128

    Hi, @binaryblues. For the first question I have a solution (if you at least are looking just to hide the text box and not actually permanently destroy it):

    uiTextView.hidden = true

    (It sometimes is confusing to find things online in Apple’s documentation; if you go to the bottom of the UITextView documentation it states that UITextView inherits from UIScrollView and if you go to the bottom of that page’s documentation, it states UIScrollView inherits from UIView and you’ll find the “hidden” property listed no that page. Remember to choose the “ObjectiveC” form of the documentation on the top right of the web page (e.g. in Swift the property is called “isHidden” instead).

    For the second question, I believe it is just a current bug in the Codea Objective C bridge; I had written to @jfperusse before about trying to access the iOS Objective C system colors and none of them worked for me or him when he tried it. Will see if @jfperusse has any updates but may need to wait for future Codea Objective C bridge to be able to access the iOS Objective C system colors.

    Hope that helps :-)

  • Posts: 1,795

    @jfperusse I’m wondering if it’s possible to have something like an objc.my syntax for accessing custom classes and variables, where essentially in Codea everything after my is ignored, but once running in Xcode the objc environment would attach the custom classes and variables to those calls.

    So in Codea you’d write something like:


    local adjustMe = 4 adjustMe = objc.my.customMethod(adjustMe) --in Codea this always returns nil if adjustMe ~= nil then --more code end

    So essentially in Codea the syntax would replace everything tagged obj.my with nil, but in Xcode the syntax would access the actual methods and variables named (of course it’s up to the user to make sure those methods and variables exist).

    Would that be possible?

  • Posts: 297

    @SugarRay It works very well! Thanks! Now I can use it in Codea to make a powerful text box control with few lines of code!

  • Posts: 128

    You’re welcome, @binaryblues. Glad it worked :-)

  • Posts: 67

    Hi @SugarRay, @UberGoober.

    Sorry for the delay. For the colors, I confirm it is yet to be supported.

    For the objc.my suggestion, I am not sure I understand it right. If objc.my would result in nil, then wouldn't the following ".customMethod" cause an error?

    I believe you can already check if you are running from an exported project. Would that solve your problem?

  • Posts: 1,795

    @jfperusse I think maybe I explained the idea badly.

    So say I have a custom objective-C class called TurnManager that has an int called currentTurn and a function called setTurnNumber.

    If I wanted to use it to print the current turn in the middle of the screen I could do something like:


    local currentTurn = objc.my.TurnManager.currentTurn or 1 text( “turn: “..currentTurn, WIDTH/2, HEIGHT/2)

    Because Codea would read everything after objc.my as nil, this would always print out “turn: 1” when running in Codea, but when running in Xcode it would correctly show the value in TurnManager.currentTurn.

    That seems pretty conceptually straightforward for accessing custom variables in the objective-C environment—if they always evaluate to nil then we can provide default values inside Codea but have them use the real values in Xcode.

    Functions could work similarly:


    _ = objc.my.TurnManager.setTurnNumber(4)

    If Codea read everything after objc.my as nil, Codea would see this as assigning nil to an unused variable name, basically ignoring it entirely, but when run in the objective-C environment it would actually call the given function with a parameter of 4.

    I don’t know how plausible the objective-C side of things would be in these examples, but (again at least conceptually) on the Codea side turning everything after objc.my into nil would make it simple to write code that was basically ignored inside Codea but that functioned correctly inside Xcode.

  • Posts: 67

    @UberGoober One thing I had discussed with @Simeon was adding viewer.isStandalone which would allow you to easily tell if you are running from a compiled exported project. You could then do:

    local currentTurn = viewer.isStandalone and objc.TurnManager.currentTurn or 1

    If this works for you, you could temporarily use the sample under objc.info documentation until we make it available as viewer.isStandalone.

  • Posts: 1,795

    @jfperusse i’m glad to know it’s at least possible!

    Of course it’s your business what you’re interested in doing and not doing, and really I’m still just thrilled to have any objective-C bridge at all, but as far as this goes, my two cents is that objc.my is a good deal more lightweight than viewer.isStandalone and and, especially if I’m referencing a lot of custom classes, having viewer.isStandalone and all over the place will get pretty severely cluttered.

    I’m not married to objc.my specifically, mind you, I’d be happy with any prefix you thought appropriate, it would just be nice if it was, well, terse.

  • edited April 22 Posts: 67

    @UberGoober I understand your point :) The main reason I'm not comfortable with the objc.my approach is that I wouldn't expect a statement such as objc.my.someclass.somemethod to be nil when I look at it, I would expect it to give a nil reference error, when looking at it as a Lua programmer. But maybe there could be another way that would make it look like valid code?

    In more modern languages, this would be a perfect use for null coalescing operators. local currentTurn = obj.TurnManager?.currentTurn ?? 1

  • edited April 22 Posts: 1,795

    Hmm, seems like you should be able to communicate that meaning with a prefix. Might I suggest any of these:

    • objc.nullable
    • objc.optional
    • objc.opt
    • objc.question
    • objc.q

    …?

    I suppose it could also be a function:

    objc.custom(…custom reference here…)

    …which always either returns the reference or null, as in:


    local currentTurn = obj.custom(TurnManager.currentTurn)
Sign In or Register to comment.