how to rotate textboxes in kivy and arrange them in polar

Viewed 74

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?

Here is a picture for better understanding:

import math
from kivy.uix.scatter import Scatter
from kivy.app import App
from kivy.graphics import *
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.button import Button

pi = math.pi

class RotateMe(Button):
    def __init__(self, **kwargs):
        Button.__init__(self, **kwargs)

        with self.canvas.before:
            PushMatrix()
            self.rot = Rotate(angle= 45, origin= self.center)

        with self.canvas.after:
            PopMatrix()

class Scat(Scatter):
    Window.size = (600, 600)
    def __init__(self,**kwargs):
        super(Scat,self).__init__(**kwargs)
        with self.canvas:
            p_x=0
            p_y=0
            b=0
            r=150
            div=20
            pt = []
            for i in range(div):
                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
                #print(p)
                pt.append(p_x)
                pt.append(p_y)
                if i>0:
                    Color(1,0,0,1)
                    #print(pt)
                    #Line(points=[pt[2*i-2],pt[2*i-1],pt[2*i],pt[2*i+1]],width=3)
                    self.add_widget(Button(text="hi",size=(50,30),pos=(pt[2*i-2],pt[2*i-1])))
                    #self.rotation(10)

class Main(App,Widget):
    def build(self):
        return Scat()

if __name__=="__main__":
    Main().run()
1 Answers

The difficulty is that the TextInput (as with many Kivy Widgets) has its own canvas instructions that define the box that is drawn for it. So, when you do the rotation, you are not affecting the canvas instructions that draw the box. You can fix that by using the kv language to redefine all the canvas instructions for the TextInput. Here is a modified version of your code that does that:

import math
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
from kivy.uix.widget import Widget

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
'''

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))

class Main(App,Widget):
    def build(self):
        Builder.load_string(kv)
        return Scat()

if __name__=="__main__":
    Main().run()

In the kv, the - in the <-RotatableTI> means do not use the default canvas instructions for the TextInput. So the canvas instructions in my kv string are mostly the default instructions (copied from style.kv), with the rotation stuff added. I also made Scat extend FloatLayout instead of Scatter for simplicity.

There was also an error in your angle calculations. I replaced:

2 * pi / div-1 * i

with:

2 * pi / (div-1) * i
Related