Last active
July 5, 2016 13:01
-
-
Save metawops/9cb00b95d018f96f8091df2516cddc24 to your computer and use it in GitHub Desktop.
NumberSpirals.pyui
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#---------------------------------------------------------- | |
# Title : Number Spirals Explorer | |
# Author : Stefan Wolfrum (@metawops) | |
# Date : June 2016 | |
# License: CC0 | |
#---------------------------------------------------------- | |
import ui | |
import math | |
import webbrowser | |
from sympy.ntheory import isprime, sieve | |
from platform import machine | |
#--- NumberSpiralView class | |
class numberSpiralView (ui.View): | |
def __init__(self): | |
# This will also be called without arguments when the view is loaded from a UI file. | |
# You don't have to call super. Note that this is called *before* the attributes | |
# defined in the UI file are set. Implement `did_load` to customize a view after | |
# it's been fully loaded from a UI file. | |
self.transform = ui.Transform.translation(self.center[0], self.center[1]) | |
device = machine() | |
if device == 'iPad6,7': # iPad Pro 12.9" | |
self.maxSpacing = 72.0 | |
elif (device == 'iPad6,4') or (device == 'iPad5,4'): # iPad Pro 9.7" or iPad Air 2 9.7" | |
self.maxSpacing = 51.0 | |
elif device == 'iPad5,1': # iPad mini 4 7.9" | |
self.maxSpacing = 51.0 | |
self.turns = 3.0 # initial number of turns of the spiral | |
self.spacing = self.maxSpacing / self.turns | |
self.maxTurns = 100.0 | |
self.drawAxis = False | |
self.drawDots = True | |
self.drawNumbers = True | |
self.autoSpacing = True | |
self.hilitePrimes = False | |
self.drawSpiral = True | |
self.primesOnly = False | |
self.drawCurve = False | |
self.curveParamA = 1.0 | |
self.curveParamB = 1.0 | |
self.curveParamC = 41.0 | |
self.maxA = self.maxB = self.maxC = 80.0 | |
self.spiralPath = ui.Path() | |
self.axisPath = ui.Path() | |
self.dotSize = 4.0 | |
self.numberOffsetX = 0.0 | |
self.numberOffsetY = 9.0 | |
self.primeDotColor = '#e00' | |
self.numbersColor = '#000' | |
self.curveColor = '#3af' | |
self.curveDotsColor = (0.0, 0.0, 1.0, 0.5) | |
self.spiralColor = '#999' | |
self.dotsColor = '#666' | |
self.backgroundColor = '#eee' | |
#self.numberFont = ('<system>', 12) | |
self.numberFont = ('HelveticaNeue-Light', 8) | |
def setup(self): | |
#print('setup()') | |
self.listOfPrimes = [i for i in sieve.primerange(2,10000)] | |
self.background_color = self.backgroundColor | |
def did_load(self): | |
# This will be called when a view has been fully loaded from a UI file. | |
self.setup() | |
def will_close(self): | |
# This will be called when a presented view is about to be dismissed. | |
# You might want to save data here. | |
pass | |
def draw(self): | |
# This will be called whenever the view's content needs to be drawn. | |
# You can use any of the ui module's drawing functions here to render | |
# content into the view's visible rectangle. | |
# Do not call this method directly, instead, if you need your view | |
# to redraw its content, call set_needs_display(). | |
self.axisPath = ui.Path() | |
self.spiralPath = ui.Path() | |
(self.cx, self.cy) = self.bounds.center() | |
if (self.drawAxis): | |
ui.set_color('black') | |
# x-Axis: | |
self.axisPath.move_to(0, self.cy) | |
self.axisPath.line_to(self.bounds[2], self.cy) | |
# y-Axis: | |
self.axisPath.move_to(self.cx, 0) | |
self.axisPath.line_to(self.cx, self.bounds[3]) | |
#self.axisPath.move_to(cx+self.spacing*2.0*math.pi, 0) | |
#self.axisPath.line_to(cx+self.spacing*2.0*math.pi, self.height) | |
self.axisPath.stroke() | |
if (self.drawSpiral): | |
ui.set_color(self.spiralColor) | |
t = 0.0 | |
max_t = self.turns * 2.0*math.pi | |
t_step = 0.08 # t_step constant for now but should be dynamic! | |
posx = posy = 0 | |
self.spiralPath.move_to(posx + self.cx, posy + self.cy) | |
while (t < max_t-t_step): | |
t = t + t_step | |
posx = self.spacing * t * math.cos(t) | |
posy = self.spacing * t * math.sin(t) | |
self.spiralPath.line_to(posx + self.cx, -posy + self.cy) | |
# finally make sure that the end of the path lies exactly on the x-Axis: | |
finalx = self.spacing * max_t * math.cos(max_t) | |
finaly = self.spacing * max_t * math.sin(max_t) | |
self.spiralPath.line_to(finalx + self.cx, finaly + self.cy) | |
self.spiralPath.stroke() | |
if (self.drawDots): | |
n = 0 | |
max_n = self.turns * self.turns | |
while (n <= max_n): | |
(x, y) = coordsForNumber(n) | |
dotx = self.cx + (x * self.spacing * 2*math.pi) | |
doty = self.cy + (y * self.spacing * 2*math.pi) | |
dotPath = ui.Path() | |
if self.hilitePrimes: | |
if (n in self.listOfPrimes): | |
ui.set_color(self.primeDotColor) | |
circlePath = ui.Path.oval(dotx-self.dotSize, doty-self.dotSize, 2*self.dotSize, 2*self.dotSize) | |
circlePath.fill() | |
if self.drawNumbers: | |
ui.draw_string(str(n), (dotx+self.dotSize+self.numberOffsetX, doty-(self.dotSize+self.numberOffsetY), 0, 0), self.numberFont, self.numbersColor) | |
else: | |
if not self.primesOnly: | |
ui.set_color(self.dotsColor) | |
circlePath = ui.Path.oval(dotx-self.dotSize, doty-self.dotSize, 2*self.dotSize, 2*self.dotSize) | |
circlePath.fill() | |
if self.drawNumbers: | |
ui.draw_string(str(n), (dotx+self.dotSize+self.numberOffsetX, doty-(self.dotSize+self.numberOffsetY), 0, 0), self.numberFont, self.numbersColor) | |
else: | |
if not self.primesOnly: | |
ui.set_color(self.dotsColor) | |
#dotPath.add_arc(dotx, doty, self.dotSize, 0, 2*math.pi) | |
#dotPath.fill() | |
circlePath = ui.Path.oval(dotx-self.dotSize, doty-self.dotSize, 2*self.dotSize, 2*self.dotSize) | |
circlePath.fill() | |
if self.drawNumbers: | |
ui.draw_string(str(n), (dotx+self.dotSize+self.numberOffsetX, doty-(self.dotSize+self.numberOffsetY), 0, 0), self.numberFont, self.numbersColor) | |
n = n + 1 | |
if self.drawCurve: | |
curvePath = ui.Path() | |
curvePath.line_width = 4.0 | |
curveDotsPath = ui.Path() | |
primesCounter = 0 | |
# first point (n=0) requires a move_to: | |
f_n = self.curveParamC # a*0*0 + b*0 + c | |
if (f_n in self.listOfPrimes): | |
primesCounter = primesCounter + 1 | |
(x, y) = coordsForNumber(f_n) | |
dotx = self.cx + (x * self.spacing * 2*math.pi) | |
doty = self.cy + (y * self.spacing * 2*math.pi) | |
curvePath.move_to(dotx, doty) | |
t = 1 | |
max_t = self.turns * self.turns | |
while (f_n < max_t): | |
f_n = self.curveParamA*t*t + self.curveParamB*t + self.curveParamC | |
if f_n < max_t: | |
if (f_n in self.listOfPrimes): | |
primesCounter = primesCounter + 1 | |
(x, y) = coordsForNumber(f_n) | |
dotx = self.cx + (x * self.spacing * 2*math.pi) | |
doty = self.cy + (y * self.spacing * 2*math.pi) | |
ui.set_color(self.curveColor) | |
curvePath.line_to(dotx, doty) | |
#curvePath.stroke() | |
#curveDotsPath = ui.Path() | |
#ui.set_color(self.curveDotsColor) | |
#curveDotsPath.add_arc(dotx, doty, self.dotSize+1, 0, 2*math.pi) | |
#curveDotsPath.fill() | |
t = t + 1.0 | |
curvePath.stroke() | |
# number of dots under curve | |
# number of primes under curve | |
ui.draw_string("Number of dots under curve: {:.0f}".format(t), (10, 10, 0, 0), ('Menlo-Regular', 10), self.dotsColor) | |
ui.draw_string("Number of primes under curve: {:.0f}".format(primesCounter) + " ({:.1f}%)".format(primesCounter*100/t), (10, 24, 0, 0), ('Menlo-Regular', 10), self.primeDotColor) | |
#self.superview['labelLongestPrimeStreak'].text = "{:.0f}".format(primesCounter) | |
def layout(self): | |
# This will be called when a view is resized. You should typically set the | |
# frames of the view's subviews here, if your layout requirements cannot | |
# be fulfilled with the standard auto-resizing (flex) attribute. | |
device = machine() | |
if self.width > self.height: | |
self.scrOrientation = 'landscape' | |
if device == 'iPad6,7': # iPad Pro 12.9" | |
self.maxSpacing = 72.0 | |
elif (device == 'iPad6,4') or (device == 'iPad5,4'): # iPad Pro 9.7" oder iPad Air 2 9.7" | |
self.maxSpacing = 51.0 | |
elif device == 'iPad5,1': # iPad mini 4 7.9" | |
self.maxSpacing = 51.0 | |
else: | |
self.scrOrientation = 'portrait' | |
if device == 'iPad6,7': # iPad Pro 12.9" | |
self.maxSpacing = 72.0 | |
elif (device == 'iPad6,4') or (device == 'iPad5,4'): # iPad Pro 9.7" oder iPad Air 2 9.7" | |
self.maxSpacing = 30.0 | |
elif device == 'iPad5,1': # iPad mini 4 7.9" | |
self.maxSpacing = 51.0 | |
self.spacing = (1.0/self.turns) * self.maxSpacing | |
self.set_needs_display() | |
def touch_began(self, touch): | |
# Called when a touch begins. | |
pass | |
def touch_moved(self, touch): | |
# Called when a touch moves. | |
pass | |
def touch_ended(self, touch): | |
# Called when a touch ends. | |
pass | |
def keyboard_frame_will_change(self, frame): | |
# Called when the on-screen keyboard appears/disappears | |
# Note: The frame is in screen coordinates. | |
pass | |
def keyboard_frame_did_change(self, frame): | |
# Called when the on-screen keyboard appears/disappears | |
# Note: The frame is in screen coordinates. | |
pass | |
# end of Class NumberSpiralView | |
#--- TextField delegate | |
class CurveParamTextFieldDelegate (object): | |
def textfield_should_begin_editing(self, textfield): | |
return True | |
def textfield_did_begin_editing(self, textfield): | |
pass | |
def textfield_did_end_editing(self, textfield): | |
sv = textfield.superview | |
spiralView = sv['spiralView'] | |
if textfield.name == 'textfieldA': | |
val = int(textfield.text) | |
sv['sliderA'].value = val/spiralView.maxA | |
spiralView.curveParamA = val | |
spiralView.set_needs_display() | |
elif textfield.name == 'textfieldB': | |
val = int(textfield.text) | |
sv['sliderB'].value = val/spiralView.maxB | |
spiralView.curveParamB = val | |
spiralView.set_needs_display() | |
elif textfield.name == 'textfieldC': | |
val = int(textfield.text) | |
sv['sliderC'].value = val/spiralView.maxC | |
spiralView.curveParamC = val | |
spiralView.set_needs_display() | |
def textfield_should_return(self, textfield): | |
textfield.end_editing() | |
return True | |
def textfield_should_change(self, textfield, range, replacement): | |
return True | |
def textfield_did_change(self, textfield): | |
pass | |
#--- Utilities ---------------------------------------------- | |
def coordsForNumber(n): | |
r = theta = math.sqrt(n) | |
x = r * math.cos(2*math.pi*theta) | |
y = -r * math.sin(2*math.pi*theta) | |
return (x, y) | |
#--- Slider change --------------------------------------- | |
def sliderAchanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.curveParamA = int(sender.value * spiralView.maxA) | |
v['textfieldA'].text = "{:.0f}".format(spiralView.curveParamA) | |
spiralView.set_needs_display() | |
def sliderBchanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.curveParamB = int(sender.value * spiralView.maxB) | |
v['textfieldB'].text = "{:.0f}".format(spiralView.curveParamB) | |
spiralView.set_needs_display() | |
def sliderCchanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.curveParamC = int(sender.value * spiralView.maxC) | |
v['textfieldC'].text = "{:.0f}".format(spiralView.curveParamC) | |
spiralView.set_needs_display() | |
def sliderSpacingChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.spacing = sender.value * spiralView.maxSpacing | |
v['labelSpacing'].text = "{:.1f}".format(spiralView.spacing) | |
spiralView.set_needs_display() | |
def sliderTurnsChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.turns = int(sender.value * spiralView.maxTurns) | |
if spiralView.turns == 0: | |
spiralView.turns = 1 | |
v['labelTurns'].text = "{:.0f}".format(spiralView.turns) | |
if v['switchAutoSpacing'].value: | |
spiralView.spacing = (1.0/spiralView.turns) * spiralView.maxSpacing | |
v['labelSpacing'].text = "{:.1f}".format(spiralView.spacing) | |
spiralView.set_needs_display() | |
# Settings dialog sliders | |
def sliderSettingsDotSizeChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.dotSize = int(sender.value * 9.0 + 1.0) | |
sender.superview['labelDotSize'].text = "{:.0f}".format(spiralView.dotSize) | |
spiralView.set_needs_display() | |
def sliderSettingsFontSizeChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.numberFont = ('HelveticaNeue-Light', sender.value * 23.0 + 8.0) | |
# Achtung! offset auch anpassen, proportional ... wie? | |
sender.superview['labelFontSize'].text = "{:.0f}".format(spiralView.numberFont[1]) | |
spiralView.set_needs_display() | |
#--- Switch change -------------------------------------- | |
def switchAutoSpacingChanged(sender): | |
v['sliderSpacing'].hidden = sender.value | |
spiralView = v['spiralView'] | |
if sender.value: | |
spiralView.spacing = (1.0/spiralView.turns) * spiralView.maxSpacing | |
else: | |
v['sliderSpacing'].value = spiralView.spacing/spiralView.maxSpacing | |
v['labelSpacing'].text = "{:.1f}".format(spiralView.spacing) | |
spiralView.set_needs_display() | |
def switchDrawAxisChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.drawAxis = sender.value | |
spiralView.set_needs_display() | |
def switchDrawDotsChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.drawDots = sender.value | |
v['labelDrawNumbers'].hidden = not sender.value | |
v['switchDrawNumbers'].hidden = not sender.value | |
v['labelHilitePrimes'].hidden = not sender.value | |
v['switchHilitePrimes'].hidden = not sender.value | |
if sender.value: # es wurde EINgeschaltet | |
# wenn HilitePrimes aus ist, darf PrimesOnly nicht sichtbar gemacht werden | |
if spiralView.hilitePrimes: | |
v['labelPrimesOnly'].hidden = not sender.value # False | |
v['switchPrimesOnly'].hidden = not sender.value # False | |
else: # es wurde AUSgeschaltet | |
# dann muss PrimesOnly immer auch ausgeblendet werden | |
v['labelPrimesOnly'].hidden = not sender.value # False | |
v['switchPrimesOnly'].hidden = not sender.value # False | |
spiralView.set_needs_display() | |
def switchDrawNumbersChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.drawNumbers = sender.value | |
spiralView.set_needs_display() | |
def switchHilitePrimesChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.hilitePrimes = sender.value | |
v['labelPrimesOnly'].hidden = not sender.value | |
v['switchPrimesOnly'].hidden = not sender.value | |
if not spiralView.hilitePrimes: | |
spiralView.primesOnly = False | |
v['switchPrimesOnly'].value = False | |
spiralView.set_needs_display() | |
def switchDrawSpiralChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.drawSpiral = sender.value | |
spiralView.set_needs_display() | |
def switchPrimesOnlyChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.primesOnly = sender.value | |
spiralView.set_needs_display() | |
def switchDrawCurveChanged(sender): | |
spiralView = v['spiralView'] | |
spiralView.drawCurve = sender.value | |
toggleCurveGUI(not spiralView.drawCurve) | |
spiralView.set_needs_display() | |
#--- Buttons ---------------------------------------------- | |
def buttonMetawopsTapped(sender): | |
webbrowser.open("safari-http://twitter.com/metawops") | |
# Show the settings dialog | |
def settingsButtonTapped(sender): | |
settingsView = ui.load_view('NumberSpiralsSettings.pyui') | |
spiralView = v['spiralView'] | |
settingsView['sliderDotSize'].value = (spiralView.dotSize-1.0)/9.0 | |
settingsView['labelDotSize'].text = "{:.0f}".format(spiralView.dotSize) | |
settingsView['sliderFontSize'].value = (spiralView.numberFont[1]-8.0)/23.0 | |
settingsView['labelFontSize'].text = "{:.0f}".format(spiralView.numberFont[1]) | |
settingsView.present('sheet') | |
#--- GUI helpers | |
def toggleCurveGUI(hideBool): | |
v['labelA'].hidden = hideBool | |
v['labelB'].hidden = hideBool | |
v['labelC'].hidden = hideBool | |
v['sliderA'].hidden = hideBool | |
v['sliderB'].hidden = hideBool | |
v['sliderC'].hidden = hideBool | |
v['textfieldA'].hidden = hideBool | |
v['textfieldB'].hidden = hideBool | |
v['textfieldC'].hidden = hideBool | |
#--- MAIN | |
if (machine()[:3] == 'iPa'): | |
v = ui.load_view('NumberSpirals.pyui') | |
spiralView = v['spiralView'] | |
v['sliderSpacing'].value = (spiralView.spacing)/spiralView.maxSpacing | |
v['labelSpacing'].text = "{:.1f}".format(spiralView.spacing) | |
v['sliderTurns'].value = (spiralView.turns)/spiralView.maxTurns | |
v['labelTurns'].text = "{:.0f}".format(spiralView.turns) | |
v['switchAutoSpacing'].value = spiralView.autoSpacing | |
v['sliderSpacing'].hidden = spiralView.autoSpacing | |
v['switchDrawAxis'].value = spiralView.drawAxis | |
v['switchDrawDots'].value = spiralView.drawDots | |
v['switchDrawNumbers'].value = spiralView.drawNumbers | |
v['switchHilitePrimes'].value = spiralView.hilitePrimes | |
v['switchDrawSpiral'].value = spiralView.drawSpiral | |
v['switchPrimesOnly'].value = spiralView.primesOnly | |
if (not spiralView.primesOnly): | |
v['labelPrimesOnly'].hidden = True | |
v['switchPrimesOnly'].hidden = True | |
v['switchDrawCurve'].value = spiralView.drawCurve | |
if (not spiralView.drawCurve): | |
toggleCurveGUI(True) | |
v['textfieldA'].delegate = CurveParamTextFieldDelegate() | |
v['textfieldB'].delegate = CurveParamTextFieldDelegate() | |
v['textfieldC'].delegate = CurveParamTextFieldDelegate() | |
v['sliderA'].value = spiralView.curveParamA / spiralView.maxA | |
v['textfieldA'].text = "{:.0f}".format(spiralView.curveParamA) | |
v['sliderB'].value = spiralView.curveParamB / spiralView.maxB | |
v['textfieldB'].text = "{:.0f}".format(spiralView.curveParamB) | |
v['sliderC'].value = spiralView.curveParamC / spiralView.maxC | |
v['textfieldC'].text = "{:.0f}".format(spiralView.curveParamC) | |
v.present('full_screen') | |
else: | |
print('Sorry, Number Spiral Explorer is iPad-only.') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"selected" : false, | |
"frame" : "{{0, 0}, {1270, 970}}", | |
"class" : "View", | |
"nodes" : [ | |
{ | |
"selected" : false, | |
"frame" : "{{964, 193}, {293, 34}}", | |
"class" : "Slider", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"continuous" : true, | |
"action" : "sliderSpacingChanged", | |
"frame" : "{{378, 402}, {200, 34}}", | |
"class" : "Slider", | |
"uuid" : "14BEF107-92A6-4490-B837-763FA4EEFA9A", | |
"value" : 0.5, | |
"name" : "sliderSpacing" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 161}, {134, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_name" : "<System>", | |
"frame" : "{{403, 403}, {150, 32}}", | |
"uuid" : "1C1C0234-66D2-4791-8726-3C44A1B3AB1E", | |
"text" : "Spacing", | |
"alignment" : "left", | |
"class" : "Label", | |
"font_size" : 18, | |
"name" : "label1" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{6, 6}, {950, 950}}", | |
"class" : "View", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"border_width" : 1, | |
"flex" : "WH", | |
"custom_class" : "numberSpiralView", | |
"frame" : "{{428, 369}, {100, 100}}", | |
"border_color" : "RGBA(0.563679,0.563679,0.563679,1.000000)", | |
"corner_radius" : 12, | |
"class" : "View", | |
"uuid" : "75147734-1377-4973-9391-22C9D76924ED", | |
"background_color" : "RGBA(0.839623,0.839623,0.839623,1.000000)", | |
"name" : "spiralView" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1129, 169}, {128, 24}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 14, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "C50B6C14-9F0D-439C-970C-7CECC9187813", | |
"text" : "Label", | |
"alignment" : "right", | |
"class" : "Label", | |
"name" : "labelSpacing", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 112}, {293, 34}}", | |
"class" : "Slider", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"action" : "sliderTurnsChanged", | |
"continuous" : true, | |
"frame" : "{{535, 468}, {200, 34}}", | |
"class" : "Slider", | |
"uuid" : "E4B50AFE-2925-4B56-85CC-E46490EB0A40", | |
"value" : 0.5, | |
"name" : "sliderTurns" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 82}, {150, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "2DB32B3C-ED81-4B50-B1D0-D2EC55727CB5", | |
"text" : "Turns", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "label2", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1129, 90}, {128, 24}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 14, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "DEDEBEE9-77AD-4FC8-8AF2-CB8E1EB46845", | |
"text" : "Label", | |
"alignment" : "right", | |
"class" : "Label", | |
"name" : "labelTurns", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1206, 226}, {51, 31}}", | |
"class" : "Switch", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"action" : "switchAutoSpacingChanged", | |
"frame" : "{{610, 470}, {51, 31}}", | |
"class" : "Switch", | |
"uuid" : "4740F7C5-9468-4BDA-90A2-B47B496A34A7", | |
"value" : true, | |
"name" : "switchAutoSpacing" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 226}, {234, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "F96998B1-835F-4478-9AE3-F817EB5BFD3F", | |
"text" : "Auto Spacing", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "label3", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1206, 324}, {51, 31}}", | |
"class" : "Switch", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"action" : "switchDrawAxisChanged", | |
"frame" : "{{610, 470}, {51, 31}}", | |
"class" : "Switch", | |
"uuid" : "F5AEC3CB-FEB1-436F-8116-4EE3D1343BDD", | |
"value" : false, | |
"name" : "switchDrawAxis" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 324}, {234, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "964EFD22-0953-4EA4-8ABF-1459579222DC", | |
"text" : "Draw Axis", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "label4", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1206, 363}, {51, 31}}", | |
"class" : "Switch", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"action" : "switchDrawDotsChanged", | |
"flex" : "L", | |
"frame" : "{{610, 470}, {51, 31}}", | |
"class" : "Switch", | |
"uuid" : "F9857D63-4F6C-4053-ADB4-F6D539630A05", | |
"value" : true, | |
"name" : "switchDrawDots" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 364}, {234, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "14622C3D-4B99-4563-9F65-72A5B07CA096", | |
"text" : "Draw Number Dots", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "label5", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1206, 402}, {51, 31}}", | |
"class" : "Switch", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"action" : "switchDrawNumbersChanged", | |
"frame" : "{{610, 470}, {51, 31}}", | |
"class" : "Switch", | |
"uuid" : "9202C51F-0137-4A96-A405-4799F2DA3405", | |
"value" : true, | |
"name" : "switchDrawNumbers" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{988, 401}, {210, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "D41E47BB-0A30-4FE8-B41E-F4704967B279", | |
"text" : "Draw Numbers", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "labelDrawNumbers", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1206, 441}, {51, 31}}", | |
"class" : "Switch", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"action" : "switchHilitePrimesChanged", | |
"frame" : "{{610, 470}, {51, 31}}", | |
"class" : "Switch", | |
"uuid" : "CE8DE121-E544-48D2-9967-CC9D6045FF35", | |
"value" : false, | |
"name" : "switchHilitePrimes" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{988, 440}, {210, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_name" : "<System>", | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "DF02276E-89B9-4AAB-A6B5-AD9D194F49E0", | |
"text" : "Highlight Primes", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "labelHilitePrimes", | |
"font_size" : 18 | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 6}, {219, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_name" : "<System-Bold>", | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "B4803AD5-FA89-4CCB-A068-F1BAD7D6C3B8", | |
"text" : "Number Spiral Explorer", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "label7", | |
"font_size" : 20 | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 37}, {125, 27}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"name" : "label8", | |
"font_name" : "<System>", | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "9BD4F8BC-8DEF-466C-B4AC-BFF12F056C6B", | |
"text" : "By Stefan Wolfrum,", | |
"alignment" : "left", | |
"class" : "Label", | |
"font_size" : 14, | |
"text_color" : "RGBA(0.507075,0.507075,0.507075,1.000000)" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1183, 9}, {30, 27}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"name" : "label9", | |
"font_name" : "<System>", | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "B65E8AF8-10B3-41D1-AC37-D3D21A8070B5", | |
"text" : "v0.9", | |
"alignment" : "right", | |
"class" : "Label", | |
"font_size" : 14, | |
"text_color" : "RGBA(0.507075,0.507075,0.507075,1.000000)" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1093, 37}, {80, 27}}", | |
"class" : "Button", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"action" : "buttonMetawopsTapped", | |
"flex" : "L", | |
"frame" : "{{595, 469}, {80, 32}}", | |
"title" : "@metawops", | |
"class" : "Button", | |
"uuid" : "7BB1F2E8-B4DA-47E9-A528-0E41E6133C10", | |
"font_size" : 14, | |
"name" : "button1" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1206, 285}, {51, 31}}", | |
"class" : "Switch", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"action" : "switchDrawSpiralChanged", | |
"frame" : "{{610, 470}, {51, 31}}", | |
"class" : "Switch", | |
"uuid" : "5DFAD3BE-A4E8-464E-9DE4-929AEC79B54D", | |
"value" : true, | |
"name" : "switchDrawSpiral" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 285}, {234, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_name" : "<System>", | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "37B0504A-6CE1-4373-B0B1-07DEDF9D3486", | |
"text" : "Draw Spiral", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "label10", | |
"font_size" : 18 | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1012, 480}, {186, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_name" : "<System>", | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "3DDAEE99-08E8-4F53-93FD-0D27F306E136", | |
"text" : "Primes only", | |
"alignment" : "left", | |
"class" : "Label", | |
"font_size" : 18, | |
"name" : "labelPrimesOnly" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1206, 481}, {51, 31}}", | |
"class" : "Switch", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"action" : "switchPrimesOnlyChanged", | |
"flex" : "L", | |
"frame" : "{{610, 470}, {51, 31}}", | |
"class" : "Switch", | |
"uuid" : "563091AE-FD20-45DF-8F1B-61E5BA64C613", | |
"value" : true, | |
"name" : "switchPrimesOnly" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1206, 533}, {51, 31}}", | |
"class" : "Switch", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"action" : "switchDrawCurveChanged", | |
"frame" : "{{610, 470}, {51, 31}}", | |
"class" : "Switch", | |
"uuid" : "BD03F69A-08CA-4FA4-BC7B-7C2B49F87AA2", | |
"value" : true, | |
"name" : "switchDrawCurve" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 533}, {180, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "E0E80932-2017-44F2-8FB6-13F34535B816", | |
"text" : "Draw Curve an²+bn+c", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "label11", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{998, 573}, {200, 34}}", | |
"class" : "Slider", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"continuous" : true, | |
"action" : "sliderAchanged", | |
"frame" : "{{535, 468}, {200, 34}}", | |
"class" : "Slider", | |
"uuid" : "4915C6D8-0D64-4CEE-9564-F3765E67203F", | |
"value" : 0.5, | |
"name" : "sliderA" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 573}, {37, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "1F206667-B1F1-49CB-9790-0DF0307135DA", | |
"text" : "a", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "labelA", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{998, 608}, {200, 34}}", | |
"class" : "Slider", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"continuous" : true, | |
"action" : "sliderBchanged", | |
"frame" : "{{535, 468}, {200, 34}}", | |
"class" : "Slider", | |
"uuid" : "2E66192C-5DBC-4709-AA17-0A94C26FA9B8", | |
"value" : 0.5, | |
"name" : "sliderB" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 608}, {37, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "3200D93A-3079-454A-91FF-EB69317CE6E2", | |
"text" : "b", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "labelB", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{964, 643}, {37, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_size" : 18, | |
"frame" : "{{560, 469}, {150, 32}}", | |
"uuid" : "E6AEA25B-08AE-4E97-9603-FAB33BC32EC7", | |
"text" : "c", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "labelC", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{998, 643}, {200, 34}}", | |
"class" : "Slider", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"continuous" : true, | |
"action" : "sliderCchanged", | |
"frame" : "{{535, 468}, {200, 34}}", | |
"class" : "Slider", | |
"uuid" : "82683FFC-D9A7-4ACE-AF11-2BBEB1FFF2A4", | |
"value" : 0.5, | |
"name" : "sliderC" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1200, 573}, {57, 32}}", | |
"class" : "TextField", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_name" : "<System>", | |
"frame" : "{{535, 469}, {200, 32}}", | |
"spellchecking_type" : "default", | |
"class" : "TextField", | |
"uuid" : "E0D36685-CC65-447D-B528-D67E3B190DB3", | |
"alignment" : "left", | |
"autocorrection_type" : "default", | |
"name" : "textfieldA", | |
"font_size" : 17 | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1200, 608}, {57, 32}}", | |
"class" : "TextField", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"name" : "textfieldB", | |
"frame" : "{{535, 469}, {200, 32}}", | |
"spellchecking_type" : "default", | |
"class" : "TextField", | |
"uuid" : "E0D36685-CC65-447D-B528-D67E3B190DB3", | |
"alignment" : "left", | |
"autocorrection_type" : "default", | |
"font_size" : 17, | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{1200, 644}, {57, 32}}", | |
"class" : "TextField", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "L", | |
"font_name" : "<System>", | |
"frame" : "{{535, 469}, {200, 32}}", | |
"spellchecking_type" : "default", | |
"class" : "TextField", | |
"uuid" : "E0D36685-CC65-447D-B528-D67E3B190DB3", | |
"alignment" : "left", | |
"autocorrection_type" : "default", | |
"font_size" : 17, | |
"name" : "textfieldC" | |
} | |
}, | |
{ | |
"selected" : true, | |
"frame" : "{{1226, 36}, {30, 30}}", | |
"class" : "Button", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"action" : "settingsButtonTapped", | |
"flex" : "L", | |
"font_size" : 15, | |
"frame" : "{{595, 469}, {80, 32}}", | |
"title" : "", | |
"class" : "Button", | |
"uuid" : "5393B48F-0E0B-417B-ABF8-A6919B99D3F0", | |
"name" : "buttonSettings", | |
"image_name" : "iob:ios7_gear_outline_32" | |
} | |
} | |
], | |
"attributes" : { | |
"name" : "Number Spirals", | |
"enabled" : true, | |
"border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)", | |
"background_color" : "RGBA(1.000000,1.000000,1.000000,1.000000)", | |
"tint_color" : "RGBA(0.000000,0.478000,1.000000,1.000000)", | |
"flex" : "" | |
} | |
} | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"selected" : false, | |
"frame" : "{{0, 0}, {320, 320}}", | |
"class" : "View", | |
"nodes" : [ | |
{ | |
"selected" : true, | |
"frame" : "{{6, 80}, {308, 34}}", | |
"class" : "Slider", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "W", | |
"action" : "sliderSettingsDotSizeChanged", | |
"continuous" : true, | |
"frame" : "{{60, 143}, {200, 34}}", | |
"class" : "Slider", | |
"uuid" : "902B44EF-0E87-4DCC-B201-A3754D776C1B", | |
"value" : 0.5, | |
"name" : "sliderDotSize" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{6, 40}, {150, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"font_name" : "<System>", | |
"frame" : "{{85, 144}, {150, 32}}", | |
"uuid" : "63950743-4086-477D-B6FD-B3432D88175C", | |
"text" : "Dots' size", | |
"alignment" : "left", | |
"class" : "Label", | |
"font_size" : 18, | |
"name" : "label1" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{6, 182}, {308, 34}}", | |
"class" : "Slider", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"flex" : "W", | |
"action" : "sliderSettingsFontSizeChanged", | |
"continuous" : true, | |
"frame" : "{{60, 143}, {200, 34}}", | |
"uuid" : "902B44EF-0E87-4DCC-B201-A3754D776C1B", | |
"class" : "Slider", | |
"value" : 0.5, | |
"name" : "sliderFontSize" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{6, 142}, {150, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"font_size" : 18, | |
"frame" : "{{85, 144}, {150, 32}}", | |
"uuid" : "63950743-4086-477D-B6FD-B3432D88175C", | |
"text" : "Font size", | |
"alignment" : "left", | |
"class" : "Label", | |
"name" : "label1", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{6, 6}, {308, 29}}", | |
"class" : "SegmentedControl", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"class" : "SegmentedControl", | |
"frame" : "{{100, 146}, {120, 29}}", | |
"uuid" : "63185922-A713-49C8-9B7F-84FAB934D57F", | |
"segments" : "Sizes|Colors|Other", | |
"name" : "segmentedcontrol1", | |
"flex" : "LR" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{243, 142}, {71, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"font_size" : 18, | |
"frame" : "{{85, 144}, {150, 32}}", | |
"uuid" : "792438F5-AB07-4B7F-A14E-8833E97C85F9", | |
"text" : "Label", | |
"alignment" : "right", | |
"class" : "Label", | |
"name" : "labelFontSize", | |
"font_name" : "<System>" | |
} | |
}, | |
{ | |
"selected" : false, | |
"frame" : "{{243, 43}, {71, 32}}", | |
"class" : "Label", | |
"nodes" : [ | |
], | |
"attributes" : { | |
"font_name" : "<System>", | |
"frame" : "{{85, 144}, {150, 32}}", | |
"uuid" : "792438F5-AB07-4B7F-A14E-8833E97C85F9", | |
"text" : "Label", | |
"alignment" : "right", | |
"class" : "Label", | |
"name" : "labelDotSize", | |
"font_size" : 18 | |
} | |
} | |
], | |
"attributes" : { | |
"flex" : "", | |
"enabled" : true, | |
"background_color" : "RGBA(1.000000,1.000000,1.000000,1.000000)", | |
"name" : "Preferences", | |
"tint_color" : "RGBA(0.000000,0.478000,1.000000,1.000000)", | |
"border_color" : "RGBA(0.000000,0.000000,0.000000,1.000000)" | |
} | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment