Reputation: 956
I'm trying to implement a simple toolbar. Right now I am stuck on the basics.
My current goal:
A toolbar which sits on the side of the app, and allows the user to add widgets to the main gui.
My current progress:
A white rectangle that sits in the correct location. Buttons which add the correct widgets. I need to position the buttons correctly.
It looks like ideally I'd like to use some kind of layout (Box?). However I can't work out how to embed this just on the rectangle.
I also don't know why what I've done so far doesn't work.
Current Code:
I'll attach a working piece of code, where the buttons aren't positioned correctly. I will happily provide minimal code if this is more helpful (just ask :) ).
Python code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import Property, NumericProperty, ReferenceListProperty,\
ObjectProperty
from kivy.graphics import Color, Ellipse, Line
from kivy.clock import Clock
import math
class GraphToolBar(Widget):
def add_buttons(self, game):
createNodeButton = Button(text = 'CreateNode', pos = (self.x,game.height))
createEdgeButton = Button(text = 'CreateEdge', pos = (self.x,0.8*game.height))
self.add_widget(createNodeButton)
self.add_widget(createEdgeButton)
def createNode(instance):
newNode = GraphNode()
game.add_widget(newNode)
print "Node Created"
def createEdge(instance):
newEdge = GraphEdge()
game.add_widget(newEdge)
print "Edge Created"
createNodeButton.bind(on_press=createNode)
createEdgeButton.bind(on_press=createEdge)
pass
class GraphInterface(Widget):
node = ObjectProperty(None)
toolbar = ObjectProperty(None)
def update(self, dt):
for widget in self.children:
if isinstance(widget, GraphEdge) and widget.collide_widget(self):
widget.check_connection()
def construct_toolbar(self):
self.toolbar.add_buttons(self)
class GraphNode(Widget):
r = NumericProperty(1.0)
def __init__(self, **kwargs):
self.size= [50,50]
self.pos = [175,125]
self.r = 1.0
super(GraphNode, self).__init__(**kwargs)
def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
if touch.grab_current == None:
self.r = 0.6
touch.grab(self)
return True
return super(GraphNode, self).on_touch_down(touch)
def on_touch_move(self, touch):
if touch.grab_current is self:
self.pos=[touch.x-25,touch.y-25]
for widget in self.parent.children:
if isinstance(widget, GraphEdge) and widget.collide_widget(self):
widget.snap_to_node(self)
def on_touch_up(self, touch):
if touch.grab_current is self:
touch.ungrab(self)
self.r = 1.0
# and finish up here
pass
class GraphEdge(Widget):
r = NumericProperty(1.0)
connected_point_0 = Property(False)
connected_point_1 = Property(False)
connected_node_0 = Widget()
connected_node_1 = Widget()
def __init__(self, **kwargs):
super(GraphEdge, self).__init__(**kwargs)
with self.canvas:
Color(self.r, 1, 1, 1)
self.line = Line(points=[100, 200, 200, 200], width = 2.0, close = True)
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
def snap_to_node(self, node):
if self.collide_widget(node):
distance_from_0 = [math.sqrt(((self.line.points[0]-node.center[0])**2 + (self.line.points[1]-node.center[1])**2))]*2
distance_from_1 = [math.sqrt(((self.line.points[2]-node.center[0])**2 + (self.line.points[3]-node.center[1])**2))]*2
if distance_from_0 < distance_from_1:
if (self.connected_point_0 is False):
print "collision"
if node is not self.connected_node_1:
self.connected_point_0 = True
self.connected_node_0 = node
self.line.points = node.center + self.line.points[2:]
self.size = [math.sqrt(((self.line.points[0]-self.line.points[2])**2 + (self.line.points[1]-self.line.points[3])**2))]*2
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
return True
elif distance_from_1 < distance_from_0:
if (self.connected_point_1 is False):
print "collision"
if node is not self.connected_node_0:
self.connected_point_1 = True
self.connected_node_1 = node
self.line.points = self.line.points[:-2] + node.center
self.size = [math.sqrt(((self.line.points[0]-self.line.points[2])**2 + (self.line.points[1]-self.line.points[3])**2))]*2
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
return True
pass
def check_connection(self):
if self.connected_point_0:
self.line.points = self.connected_node_0.center + self.line.points[2:]
self.size = [math.sqrt(((self.line.points[0]-self.line.points[2])**2 + (self.line.points[1]-self.line.points[3])**2))]*2
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
self.r = self.connected_node_1.r
if self.connected_point_1:
self.line.points = self.line.points[:2] + self.connected_node_1.center
self.size = [math.sqrt(((self.line.points[0]-self.line.points[2])**2 + (self.line.points[1]-self.line.points[3])**2))]*2
self.center = ((self.line.points[0]+self.line.points[2])/2,(self.line.points[1]+self.line.points[3])/2)
self.r = self.connected_node_1.r
class GraphApp(App):
def build(self):
game = GraphInterface()
game.construct_toolbar()
Clock.schedule_interval(game.update, 1.0/20.0)
return game
if __name__ == '__main__':
GraphApp().run()
.kv file:
#:kivy 1.0.9
<GraphInterface>:
node: graph_node
toolbar: graph_toolbar
GraphNode:
id: graph_node
center: self.parent.center
GraphToolBar:
id: graph_toolbar
size: root.width * 2/10, root.height
x: root.width * 8/10
y: 0
<GraphToolBar>:
size: 10,100
canvas:
Color:
rgba: (1,1,1,1)
Rectangle:
size: self.size
pos: self.pos
<GraphNode>:
size: 50, 50
canvas:
Color:
rgba: (root.r,1,1,1)
Ellipse:
pos: self.pos
size: self.size
<GraphEdge>:
size: self.size
center: self.center
canvas:
Color:
rgba: (root.r,1,1,1)
Line:
width: 2.0
close: True
Thanks for your patience!
Upvotes: 0
Views: 1440
Reputation: 529
If I understand you correctly, you just want to get those buttons onto the white rectangle. That can be easily done by using BoxLayout
, as you have mentioned. Just change this line
class GraphToolBar(Widget):
to this line
class GraphToolBar(BoxLayout):
Upvotes: 1