Native IOS widgets created in a plugin are badly supported

There are two ways to create a plugin using a subclass of an UIView (or a NSView on the Mac). Either you provide a valid id to the handle-getter (the behavior callback) or you implement the offscreen callback (REALcontrol), i.e., the redrawFunction (REALmobileControl) where you rely on the conversion of a REALgraphics to a CGContext. In either case you are not drawing Xojo graphics but CGContext graphics.

In runtime when you supply the id of the view (implement the handle-getter) Xojo will call the necessary Cocoa calls to draw the plugin widget (and does not call the redraw callback). It works great on the Mac. However, IOS is drawing the widget weird. As far as I can judge it id doing things that cannot be controlled. For example, placing the plugin instance on the top-half of the screen, it centers the widget.

So I tried to do it differently. Don’t implement the handle-getter so you can use the redraw callback. But calling

REALLoadObjectMethod((REALobject)graphics,"Handle(type As Integer) As Integer");

using type = 5 does not give a valid CGContext. Even if there is a way to get it, I doubt that the implementation of the redraw callback will allow the call to REALGetControlBounds since that does not even work in the Simulator.

I had mentioned months ago the lack of a working REALGetControlBounds; the notion that a widget for MacOS using the handle-getter works so nicely but not on IOS is another important concern.

Did you make a feedback case?
I didn’t notice the problem with UIView based control here.

But you do notice it now? Anyway, I am in the middle of development of the Lexing control for iOS. At first, I thought that it was me not doing the correct things. One of the difficulties is that the plugin will become the first responder so the keyboard will appear, which requires repositioning of the widget. Submitting the plugin in this unfinished state may backfire, particular when I would need to send a version without the handle-getter to show the invalid CGContext and another version with the handle-getter.

You know, in the past when I dealt with the development of the plugin for MacOS, I could send a compiled app to Joe R and he was quick to respond and fixed Xojo. He made it to work flawlessly. Nowadays, I am waiting for the REALGetControlBounds to be fixed (it is not, and was filed in feedback). So I presume that the fix for the handle-getter and the handle to the REALgraphics is not going to be addressed very soon.

It seems like I need supporting evidence from others to make these unforeseen bugs be fixed in a more timely manner. (I will try to submit a feedback for this, but I hold my breath). So if you have a case with one of your widgets that relies on an UIView then please let me (us) know.

Have you talked to Technical Support directly about this? If not, please reach out to them, Xojo: Contact Xojo

What are you getting then? Have you tried changing the definition to Handle(type As HandleTypes) As Ptr?

It’s implemented, although I don’t know if you will get the correct bounds depending on when you initially ask for it since it does depend on the constraints to be setup first. If there is still an issues with it we’ll take another look.

An invalid context means a null pointer. Also, Handle(type As HandleTypes) As Ptr with either type = 5 or type = 2 leads to an invalid context, i.e., null pointers. So what kind of type should be used?

Thanks, at runtime it shows. Cool, but in design time it does not. A feedback report on that was made months ago after you said it was fixed, see <https://xojo.com/issue/64302>.

So, given the lack of a context ref I’d like to stick to presenting the handle-getter with the ID of the plugin-view. I need to somehow figure a callback that would fire when constrains are altered and go from there and try to update the recent feedback: <https://xojo.com/issue/65113>. If the widget is not placed at the bottom-left the weird behaviors (black stripes from top to bottom), and a big black rectangle when one touches the widget causing it to get focus after the keyboard appears.

The auto layout to which the plugin is exposed drives me nuts. For example, when launching the build on the iPhone, the initial hard-coded size of the REALmobileControl (266,133) is maintained during construction and initialization of the plugin. First we get the following messages in the console:

PluginEntry of the Lexing plugin
InstallMobilePlugin called for the LexingControl Plugin
Registering of the color classes
Creating service facility connection with <private>
Activating service facility
Creating iPhone screen: iPhoneLayout

Then follows the construction callback of the plugin:

Service facility connection activation received.
Got dynamically the App_App
com.vanhoekplugins "Mobile Application"
Lexing_Construct Callback: instance = 3d16b80
in Lexing_InitProperties
out Lexing_InitProperties
in Lexing_EditorConstructor
leaving Lexing_EditorConstructor
leaving Lexing_Construct Callback: instance = 3d16b80

Init properties sets the default properties of the plugin and is followed by the creation of the subclassed UIView, which is called the editor. The editor functions as a superView that has embedded the UIScrollView containing the contentView. The plugin implements the handle getter

LexingIOS	Lexing_HandleGetter: handle (3e0c9c0)

So now the plugin depends on what Xojo is going to do. Xojo starts with calling the OpeningEvent that the plugin has subclassed. Note that Xojo will call this event twice, which as far as I can tell is a bug: see <https://xojo.com/issue/64201>. We circumvent that by a counter. This event is used to implement a ViewController like:

#if XOJO_TARGET_IOS
@interface ViewController ()
{

    BOOL keyboardShown;
    CGSize keyboardSize;
    CGSize offset;
    UIDeviceOrientation orientationAtShown;
    
    @public
    ScintillaView *editor;
    REALmobileControl *mobileControl;
    REALcontrolInstance mobileInstance;
}
@end

In the subclassed OpenEvent we call this:

void initViewController(REALcontrolInstance me, REALmobileControl *mc, ScintillaView *editor) {
    
    ViewController *controller = [[ViewController alloc] initWithNibName:nil bundle:nil];
    if(controller) {
        controller->mobileInstance = me;
        controller->mobileControl = mc;
    
        Data(me, data);
        data->controller = controller;
        controller->editor = editor;
        [controller loadView];
    // [controller viewDidLoad];
    }
    NSLog(@"leaving initViewController");
}

So the messages in the console become

counter = 1 of the Lexing_OpenEvent 1
loadView
leaving initViewController
REALGetControlBounds in origin and size: {{0, 0}, {266, 133}}
OpenEvent does not trigger -Open
leaving Lexing_OpenEvent
Lexing_SetText

After the call to the subclassed OpenEvent you should note that the setter properties of the plugin are being called by Xojo (not by the plugin). One such a setter is the Lexing_SetText. This Text property of the plugin was assigned with a long text in the IDE inspector pane. Note that load view is just doing:

- (void)loadView {
    NSLog(@"ViewController: loadView");
    [super loadView];
    self.view = editor;
    editor.scrollView.keyboardDismissMode =UIScrollViewKeyboardDismissModeInteractive;// UIScrollViewKeyboardDismissModeOnDrag;
    editor.scrollView.automaticallyAdjustsScrollIndicatorInsets = YES;
}

and also implements

- (void)updateViewConstraints {
    NSLog(@"updateViewConstraints");
    [super updateViewConstraints];
    
    [self interrogatedimensions];
}

“interrogatedimensions” simply spits out

updateViewConstraints
 editor.hasAmbiguousLayout 0
 [self.view bounds] {{0, 0}, {266, 133}}
 [self.view frame] {{0, 0}, {266, 133}}
 REALGetControlBounds {{0, 0}, {266, 133}}
 count of layoutGuides = 0
 editor.scrollView.contentOffset {0, 0}
 editor.scrollView.contentSize {100, 218}
 editor.scrollView.visibleSize {100, 10}

This still indicates that the updateViewConstraints does not show that text was taken into account, that the actual size of the View is not represented by the size set in the IDE. Only later when layoutViews is being called we get

 layoutSubViews
    [editor frame] {{54.666666666666657, 206.66666666666663}, {266, 399}}|
    editor.scrollView.contentOffset {0, 0}|
    editor.scrollView.contentSize {266, 399}|

But, the content view should be larger in size, given the text size. So what is going on? A whole lot because setting up the widget in the IDE is a pain. For example, sometimes you have width, height edging to none, then you also have top and right that can switch to left and bottom (if you drag along), but you cannot set top or right to edge nothing. “Nothing” in the popupmenu of Edge is not present. I want to set the edges to none just to be able to test what’s going on. Going on means that what should be text is completely black or part of it is black.

So my take on it is that without knowing the bounds of the widget in design-time, everything becomes a trial and error without logic. Xojo should provide better tools to let a developer figuring what is going on in how Xojo sets the constraints and how it might affect the 3-layer widget this plugin represents (On macOS everything just looks good). Am about to give up. Isn’t there any good example plugin? EyePlugin does not cut it because it draws with Xojo API’s and therefore does not define a UIView and NSView.

And another problem is when the hard-coded size of the plugin is changed. The change is effective in MacOS (desktop), but it does not affect the mobileControl when in runtime and debug-runtime. Both the REALcontrol and REALmobileControl were changed to 300, 500, but the messages like above (in IOS) gave 266,133. Tried to clear caches, but without avail.

Yikes

I think I figured a bit more with respect to how to use the auto layout. I have updated <https://xojo.com/issue/65113> with more specific info. I would really appreciate if an engineer can reproduce what I have described in this feedback report and if possible with some response.