Skip to content

Commit

Permalink
Merge pull request #1749 from freakboy3742/iOS-probe
Browse files Browse the repository at this point in the history
Add an iOS tests_backend probe
  • Loading branch information
mhsmith authored Jan 29, 2023
2 parents 978885b + c877df4 commit ecfca36
Show file tree
Hide file tree
Showing 21 changed files with 342 additions and 96 deletions.
2 changes: 1 addition & 1 deletion changes/1439.bugfix.rst
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Changes in the root content of a window is now correctly applied on GTK.
Changes in the root content of a window are now correctly applied on GTK and iOS.
1 change: 1 addition & 0 deletions changes/1749.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
An initial iOS probe implementation was added.
1 change: 1 addition & 0 deletions iOS/MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ include CONTRIBUTING.md
include LICENSE
include README.rst
recursive-include tests *.py
recursive-include tests_backend *.py
7 changes: 7 additions & 0 deletions iOS/src/toga_iOS/command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class Command:
def __init__(self, interface):
self.interface = interface
self.native = []

def set_enabled(self, value):
pass
108 changes: 54 additions & 54 deletions iOS/src/toga_iOS/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
class Constraints:
def __init__(self, widget):
"""
A wrapper object storing the constraints required to position a widget
at a precise location in its container.
Args:
widget (:class: toga-iOS.Widget): The widget that should be constrained.
:param widget: The Widget implementation to be constrained.
"""
self._widget = widget
self.widget = widget
self._container = None

self.width_constraint = None
Expand All @@ -24,68 +25,67 @@ def __init__(self, widget):
self.left_constraint = None
self.top_constraint = None

@property
def widget(self):
return self._widget

@widget.setter
def widget(self, value):
self._widget = value

@property
def container(self):
return self._container

@container.setter
def container(self, value):
self._container = value
# print("Add constraints for", self.widget, 'in', self.container, self.widget.interface.layout)
self.left_constraint = NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501
self.widget.native,
NSLayoutAttributeLeft,
NSLayoutRelationEqual,
self.container.native,
NSLayoutAttributeLeft,
1.0,
10, # Use a dummy, non-zero value for now
)
self.container.native.addConstraint_(self.left_constraint)
if value is None and self.container:
# print("Remove constraints")
self.container.native.removeConstraint(self.width_constraint)
self.container.native.removeConstraint(self.height_constraint)
self.container.native.removeConstraint(self.left_constraint)
self.container.native.removeConstraint(self.top_constraint)
self._container = value
else:
self._container = value
# print("Add constraints for", self.widget, "in", self.container, self.widget.interface.layout)
self.left_constraint = NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501
self.widget.native,
NSLayoutAttributeLeft,
NSLayoutRelationEqual,
self.container.native,
NSLayoutAttributeLeft,
1.0,
10, # Use a dummy, non-zero value for now
)
self.container.native.addConstraint(self.left_constraint)

self.top_constraint = NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501
self.widget.native,
NSLayoutAttributeTop,
NSLayoutRelationEqual,
self.container.native,
NSLayoutAttributeTop,
1.0,
5, # Use a dummy, non-zero value for now
)
self.container.native.addConstraint_(self.top_constraint)
self.top_constraint = NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501
self.widget.native,
NSLayoutAttributeTop,
NSLayoutRelationEqual,
self.container.native,
NSLayoutAttributeTop,
1.0,
5, # Use a dummy, non-zero value for now
)
self.container.native.addConstraint(self.top_constraint)

self.width_constraint = NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501
self.widget.native,
NSLayoutAttributeRight,
NSLayoutRelationEqual,
self.widget.native,
NSLayoutAttributeLeft,
1.0,
50, # Use a dummy, non-zero value for now
)
self.container.native.addConstraint_(self.width_constraint)
self.width_constraint = NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501
self.widget.native,
NSLayoutAttributeRight,
NSLayoutRelationEqual,
self.widget.native,
NSLayoutAttributeLeft,
1.0,
50, # Use a dummy, non-zero value for now
)
self.container.native.addConstraint(self.width_constraint)

self.height_constraint = NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501
self.widget.native,
NSLayoutAttributeBottom,
NSLayoutRelationEqual,
self.widget.native,
NSLayoutAttributeTop,
1.0,
30, # Use a dummy, non-zero value for now
)
self.container.native.addConstraint_(self.height_constraint)
self.height_constraint = NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501
self.widget.native,
NSLayoutAttributeBottom,
NSLayoutRelationEqual,
self.widget.native,
NSLayoutAttributeTop,
1.0,
30, # Use a dummy, non-zero value for now
)
self.container.native.addConstraint(self.height_constraint)

def update(self, x, y, width, height):
# print("UPDATE", self.widget, 'in', self.container, 'to', x, y, width, height)
if self.container:
self.left_constraint.constant = x
self.top_constraint.constant = y
Expand Down
5 changes: 2 additions & 3 deletions iOS/src/toga_iOS/factory.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from . import dialogs
from .app import App, MainWindow
from .colors import native_color
from .command import Command
from .fonts import Font
from .icons import Icon
from .images import Image
Expand Down Expand Up @@ -31,8 +32,6 @@
from .widgets.webview import WebView
from .window import Window

# from .command import Command


def not_implemented(feature):
print(f"[iOS] Not implemented: {feature}") # pragma: nocover
Expand All @@ -42,7 +41,7 @@ def not_implemented(feature):
"not_implemented",
"App",
"MainWindow",
# 'Command',
"Command",
# Resources
"native_color", # colors
"Font",
Expand Down
6 changes: 3 additions & 3 deletions iOS/src/toga_iOS/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ def set_tab_index(self, tab_index):
def set_bounds(self, x, y, width, height):
offset_y = 0
if self.container:
offset_y = self.container.viewport.statusbar_height
offset_y = self.container.viewport.top_offset
elif self.viewport:
offset_y = self.viewport.statusbar_height
offset_y = self.viewport.top_offset
self.constraints.update(x, y + offset_y, width, height)

def set_alignment(self, alignment):
Expand Down Expand Up @@ -116,8 +116,8 @@ def remove_child(self, child):
child.container = None

def add_constraints(self):
self.native.translatesAutoresizingMaskIntoConstraints = False
self.constraints = Constraints(self)
self.native.translatesAutoresizingMaskIntoConstraints = False

def rehint(self):
pass
6 changes: 1 addition & 5 deletions iOS/src/toga_iOS/widgets/scrollcontainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ def update_content_size(self):
scrollable_content.interface.style.padding_top
+ scrollable_content.interface.style.padding_bottom
)
# pad the scrollview for the statusbar offset
padding_vertical = (
padding_vertical + scrollable_content.viewport.statusbar_height
)
else:
content_height = self.native.frame.size.height

Expand Down Expand Up @@ -109,7 +105,7 @@ def set_content(self, widget):
if self.interface.content is not None:
self.interface.content._impl.native.removeFromSuperview()
self.native.addSubview(widget.native)
widget.viewport = iOSViewport(self.native)
widget.viewport = iOSViewport(widget)

for child in widget.interface.children:
child._impl.container = widget
Expand Down
63 changes: 48 additions & 15 deletions iOS/src/toga_iOS/window.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
from toga_iOS.libs import UIApplication, UIScreen, UIViewController, UIWindow
from toga_iOS.libs import (
UIApplication,
UINavigationController,
UIScreen,
UIViewController,
UIWindow,
)


class iOSViewport:
def __init__(self, view):
self.view = view
def __init__(self, widget):
self.widget = widget
# iOS renders everything at 96dpi.
self.dpi = 96
self.baseline_dpi = self.dpi
Expand All @@ -17,15 +23,34 @@ def statusbar_height(self):
# the size will be 0.
return UIApplication.sharedApplication.statusBarFrame.size.height

@property
def navbar_height(self):
try:
return (
self.widget.controller.navigationController.navigationBar.frame.size.height
)
except AttributeError:
return 0

@property
def top_offset(self):
return self.statusbar_height + self.navbar_height

@property
def bottom_offset(self):
return self.kb_height

@property
def width(self):
return self.view.bounds.size.width
return self.widget.native.bounds.size.width

@property
def height(self):
# Remove the height of the keyboard and the titlebar
# from the available viewport height
return self.view.bounds.size.height - self.kb_height - self.statusbar_height
return (
self.widget.native.bounds.size.height - self.bottom_offset - self.top_offset
)


class Window:
Expand All @@ -35,6 +60,15 @@ def __init__(self, interface, title, position, size):

self.native = UIWindow.alloc().initWithFrame(UIScreen.mainScreen.bounds)

# The window has a UINavigationController to provide the navigation bar,
# and provide a stack of navigable content; this is initialized with a
# UIViewController to contain the actual content
self.controller = UIViewController.alloc().init()
self.navigation_controller = (
UINavigationController.alloc().initWithRootViewController(self.controller)
)
self.native.rootViewController = self.navigation_controller

self.set_title(title)

def clear_content(self):
Expand All @@ -43,26 +77,25 @@ def clear_content(self):
child._impl.container = None

def set_content(self, widget):
widget.viewport = iOSViewport(self.native)
widget.viewport = iOSViewport(self)

# Add all children to the content widget.
for child in widget.interface.children:
child._impl.container = widget

if getattr(widget, "controller", None):
self.controller = widget.controller
else:
self.controller = UIViewController.alloc().init()

self.native.rootViewController = self.controller
# Set the controller's view to be the new content widget
self.controller.view = widget.native

# The main window content needs to use the autoresizing mask so
# that it fills all the available space in the view.
widget.native.translatesAutoresizingMaskIntoConstraints = True

def get_title(self):
self.interface.factory.not_implemented("Window.get_title()")
return "?"
return str(self.navigation_controller.title)

def set_title(self, title):
self.interface.factory.not_implemented("Window.set_title()")
# The title is set on the controller of the topmost content
self.navigation_controller.topViewController.title = title

def get_position(self):
return (0, 0)
Expand Down
Empty file added iOS/tests_backend/__init__.py
Empty file.
Empty file.
Loading

0 comments on commit ecfca36

Please sign in to comment.