Source code for enamlnative.ios.bridge

"""
Copyright (c) 2017-2022, CodeLV.

Distributed under the terms of the MIT License.

The full license is in the file LICENSE, distributed with this software.

Created on June 21, 2017


"""
from atom.api import Atom
from enamlnative.core.bridge import (
    BridgeCallback,
    BridgeField,
    BridgeMethod,
    BridgeObject,
    Command,
    CACHE,
    msgpack_encoder,
)


[docs]class ObjcMethod(BridgeMethod): """Description of a method of a View (or subclass) in Objc. When called, this serializes the call, packs the arguments, and delegates handling to a bridge in Objc. To keep method calling similar to Swift instead of defining a method matching the signature with underscores like pyobjc and pyobjus the signature should be defined as follows: 1. The first argument, if any, should be a string. 2. Subsequent arguments should each be a dictionary of the available `subnames` and their types. For instance: UIView `insertSubview` has the following signatures: - (void)insertSubview:(UIView *)view atIndex:(NSInteger)index; - (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview; - (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview; This is defined in python like: insertSubview = ObjcMethod('UIView', dict(atIndex='NSInteger', aboveSubview='UIView', belowSubview='UIView')) Doing it this way it can be called like Swift, using kwargs view.insertSubview(subview, atIndex=3) view.insertSubview(subview, aboveSubview=above_view) """
[docs] def pack_args(self, obj, *args, **kwargs): """Arguments must be packed according to the kwargs passed and the signature defined. """ signature = self.__signature__ #: No arguments expected if not signature: return (self.name, []) #: Build args, first is a string, subsequent are dictionaries method_name = [self.name] bridge_args = [] for i, sig in enumerate(signature): if i == 0: method_name.append(":") bridge_args.append(msgpack_encoder(sig, args[0])) continue #: Sig is a dict so we must pull out the matching kwarg found = False for k in sig: if k in kwargs: method_name.append("{}:".format(k)) bridge_args.append(msgpack_encoder(sig[k], kwargs[k])) found = True break if not found: #: If we get here something is wrong raise ValueError( "Unexpected or missing argument at index {}. " "Expected {}".format(i, sig) ) return ("".join(method_name), bridge_args)
[docs]class ObjcProperty(BridgeField): """The superclass implementation is sufficient"""
[docs]class ObjcCallback(BridgeCallback, ObjcMethod): """Description of a callback method of a View (or subclass) in Objc. When called, it fires the connected callback. This is triggered when it receives an event from the bridge indicating the call has occured. """
[docs] def pack_args(self, obj, *args, **kwargs): return ObjcMethod.pack_args(self, obj, *args, **kwargs)
[docs]class ObjcBridgeObject(BridgeObject): """A proxy to a class in java. This sends the commands over the bridge for execution. The object is stored in a map with the given id and is valid until this object is deleted. Parameters ---------- __id__: Int If an __id__ keyward argument is passed during creation, this will assume the object was already created and only a reference to the object with the given id is needed. """
[docs] @classmethod def __init_subclass__(cls, *args, **kwargs): """Use the class name by default as everything should be unique.""" super().__init_subclass__(*args, **kwargs) cls.__nativeclass__ = cls.__name__
[docs] def __init__(self, *args, **kwargs): """Sends the event to create this View in Java""" __id__ = kwargs.get("__id__", None) #: Note: We SKIP the superclass here! if __id__ is not None: super(Atom, self).__init__(__id__=__id__) else: super(Atom, self).__init__() #: Send the event over the bridge to construct the view CACHE[self.__id__] = self if __id__ is None: self.__app__.send_event( Command.CREATE, #: method self.__id__, #: id to assign in bridge cache id(self), self.__nativeclass__, *self._pack_args(**kwargs) )
def _pack_args(self, *args, **kwargs): """Arguments must be packed according to the kwargs passed and the signature defined. """ signature = self.__signature__ #: No arguments expected if not signature or not kwargs: return ("init", []) #: Build args, first is a string, subsequent are dictionaries method_name = [] bridge_args = [] for i, sig in enumerate(signature): # if i == 0: # method_name.append(":") # bridge_args.append(msgpack_encoder(sig, args[0])) # continue #: Sig is a dict so we must pull out the matching kwarg found = False for k in sig: if k in kwargs: method_name.append("{}:".format(k)) bridge_args.append(msgpack_encoder(sig[k], kwargs[k])) found = True break if not found: #: If we get here something is wrong raise ValueError( "Unexpected or missing argument at index {}. " "Expected {}".format(i, sig) ) return ("".join(method_name), bridge_args)