Reputation: 40
I have some Textinputs that arranged circular and i am looking for a way to spin the whole package of these widgets around their center like a wheel with dragging mouse on part of them. i try to combine some codes that i found in some pages but have no idea how to make this works properly.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.properties import NumericProperty
from kivy.core.window import Window
import math
pi = math.pi
kv = '''
<-RotatableTI>:
size_hint: None, None
canvas.before:
PushMatrix
Rotate:
angle: root.angle
axis: 0,0,1
origin: self.center
Color:
rgba: self.background_color
BorderImage:
border: self.border
pos: self.pos
size: self.size
source: self.background_active if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)
Color:
rgba:
(self.cursor_color
if self.focus and not self._cursor_blink
else (0, 0, 0, 0))
Rectangle:
pos: self._cursor_visual_pos
size: root.cursor_width, -self._cursor_visual_height
Color:
rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text else self.foreground_color)
canvas.after:
PopMatrix
<Dial>:
canvas:
Rotate:
angle: self.angle
origin: self.center
'''
Builder.load_string(kv)
class Circle(Widget):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
pass
class RotatableTI(TextInput):
angle = NumericProperty(0)
class Scat(FloatLayout,Widget):
Window.size = (600, 600)
def __init__(self, **kwargs):
super(Scat, self).__init__(**kwargs)
p_x = 0
p_y = 0
b = 0
r = 150
div = 20
pt = []
for i in range(div):
angle = 360.0 / (div - 1) * i
p_x = Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * r
p_y = Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * r
pt.append(p_x)
pt.append(p_y)
if i > 0:
self.add_widget(RotatableTI(text="hi" + str(i), size=(50, 30), pos=(p_x, p_y), angle=angle))
angle = NumericProperty(0)
def on_touch_down(self, touch):
y = (touch.y - self.center[1])
x = (touch.x - self.center[0])
calc = math.degrees(math.atan2(y, x))
self.prev_angle = calc if calc > 0 else 360+calc
self.tmp = self.angle
return super(Scat, self).on_touch_down(touch) # dispatch touch event futher
def on_touch_move(self, touch):
y = (touch.y - self.center[1])
x = (touch.x - self.center[0])
calc = math.degrees(math.atan2(y, x))
new_angle = calc if calc > 0 else 360+calc
self.angle = self.tmp + (new_angle-self.prev_angle)%360
class DialApp(App):
def build(self):
return Scat()
if __name__ == "__main__":
DialApp().run()
I want to array polar some textinputs in kivy but only find a way to rotate textinput with mouse dragging in scatter class. all of my try reached to a textinput that is not rotated and only when I type in it the text shows rotated(with not rotated textinput box!), and not looks good, so im looking for a better way, I could reach close to solution with buttons, but they are not exactly I want and just their position are polar, not their orirntation. is there any way for textInputs to array like described?
at the end im looking for a way have 3 or 4 of this whirling packages of textinputs and I am wondering mouse dragging would recognize which one of them selected perfectly or selected sometimes wrongly? because when i want spin one item in kivy with mouse, if select the outside of object`s border still can select and rotate it.
EDITED one step forward with response of dear John Anderson; but still works not good. i mention the problems below(under of the code) in the second picture.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.properties import NumericProperty
from kivy.core.window import Window
import math
pi = math.pi
kv = '''
<Scat>:
canvas.before:
PushMatrix
Rotate:
angle: self.angle
origin: self.center
canvas.after:
PopMatrix
<-RotatableTI>:
size_hint: None, None
canvas.before:
PushMatrix
Rotate:
angle: root.angle
axis: 0,0,1
origin: self.center
Color:
rgba: self.background_color
BorderImage:
border: self.border
pos: self.pos
size: self.size
source: self.background_active if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)
Color:
rgba:
(self.cursor_color
if self.focus and not self._cursor_blink
else (0, 0, 0, 0))
Rectangle:
pos: self._cursor_visual_pos
size: root.cursor_width, -self._cursor_visual_height
Color:
rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text else self.foreground_color)
canvas.after:
PopMatrix
canvas:
Rotate:
angle: self.angle
origin: self.center
'''
Builder.load_string(kv)
class Circle(Widget):
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
pass
class RotatableTI(TextInput):
angle = NumericProperty(0)
class Scat(FloatLayout):
Window.size = (600, 600)
def __init__(self, **kwargs):
super(Scat, self).__init__(**kwargs)
p_x = 0
p_y = 0
b = 0
r = 150
div = 20
pt = []
for i in range(div):
angle = 360.0 / (div - 1) * i
p_x = Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * r
p_y = Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * r
pt.append(p_x)
pt.append(p_y)
if i > 0:
self.add_widget(RotatableTI(text="hi" + str(i), size=(50, 30), pos=(p_x, p_y), angle=angle))
angle = NumericProperty(0)
def on_touch_down(self, touch):
y = (touch.y - self.center[1])
x = (touch.x - self.center[0])
calc = math.degrees(math.atan2(y, x))
self.prev_angle = calc if calc > 0 else 360+calc
self.tmp = self.angle
return super(Scat, self).on_touch_down(touch) # dispatch touch event futher
def on_touch_move(self, touch):
y = (touch.y - self.center[1])
x = (touch.x - self.center[0])
calc = math.degrees(math.atan2(y, x))
new_angle = calc if calc > 0 else 360+calc
self.angle = self.tmp + (new_angle-self.prev_angle)%360
class DialApp(App):
def build(self):
return Scat()
if __name__ == "__main__":
DialApp().run()
beside that ring except orbiting moves other directions(its center point is not permanent and can change it with dragging) that its not expected! [1]: https://i.sstatic.net/3jhQ8.png [2]: https://i.sstatic.net/Mrpf7.png
Upvotes: 0
Views: 113
Reputation: 38837
You almost have the rotation working. Just add this to your kv
:
<Scat>:
canvas.before:
PushMatrix
Rotate:
angle: self.angle
origin: self.center
canvas.after:
PopMatrix
Also,
class Scat(FloatLayout,Widget):
should be just:
class Scat(FloatLayout):
because FloatLayout
is a Widget
.
If you intend to use several Scat
Widgets, you should use collide_point() to determine which instance is being touched.
Upvotes: 1