Skip to content

Commit e9f685c

Browse files
author
Tom De Smedt
committed
nodebox.gui layout fixes
1 parent 4e80ce2 commit e9f685c

File tree

2 files changed

+107
-18
lines changed

2 files changed

+107
-18
lines changed

examples/10-gui/05-layout.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Add the upper directory (where the nodebox module is) to the search path.
2+
import os, sys; sys.path.insert(0, os.path.join("..",".."))
3+
4+
from nodebox.graphics import *
5+
from nodebox.gui import *
6+
7+
# Comparison between Rows and Row containers.
8+
# Both are subclasses of Layout.
9+
10+
# Panel 1
11+
# Controls in a Rows layout are drawn below each other.
12+
# Rows.width defines the width of all controls (individual width is ignored).
13+
# Note how the second Field has a height and wrap=True,
14+
# which makes it a multi-line field with text wrapping.
15+
panel1 = Panel("Panel 1", x=30, y=350)
16+
panel1.append(
17+
Rows([
18+
Field(value="", hint="subject"),
19+
Field(value="", hint="message", height=70, id="field_msg1", wrap=True),
20+
Button("Send"),
21+
], width=200)
22+
)
23+
panel1.pack()
24+
25+
# Panel 2
26+
# Controls in a Row layout are drawn next to each other.
27+
# Row.width defines the width of all controls (individual width is ignored).
28+
# This means that each column has the same width.
29+
# Note the align=TOP, which vertically aligns each column at the top (default is CENTER).
30+
panel2 = Panel("Panel 2", x=30, y=200)
31+
panel2.append(
32+
Row([
33+
Field(value="", hint="message", height=70, id="field_msg2", wrap=True),
34+
Button("Send", width=400),
35+
], width=200, align=TOP)
36+
)
37+
panel2.pack()
38+
39+
# Panel 3
40+
# If you need columns of a different width, put a Layout in a column,
41+
# in other words a Row or Rows nested inside a Row or Rows.
42+
# Then put your controls in the nested layout,
43+
# the layout's width will override the column width setting.
44+
panel3 = Panel("Panel 3", x=30, y=30)
45+
panel3.append(
46+
Row([ # Field will be 200 wide, the Row column width setting.
47+
Field(value="", hint="message", height=70, id="field_msg2", wrap=True),
48+
("Actions:", Rows([
49+
Button("Send"), # However, buttons will be 100 wide,
50+
Button("Save") # because their Rows parent says so.
51+
], width=100))
52+
], width=200, align=TOP)
53+
)
54+
panel3.pack()
55+
56+
# Panel 4
57+
# Without layouts, you are free to draw controls wherever you want in a panel.
58+
# Panel.pack() will make sure that the panel fits snuggly around the controls.
59+
# In this case, we place a button on the panel, with a field above it (hence y=40).
60+
# The field has its own dimensions (width=300 and height=50).
61+
panel4 = Panel("Panel 4", x=400, y=30)
62+
panel4.extend([
63+
Field(value="", hint="message", y=40, width=300, height=50, id="field_msg3", wrap=True, reserved=[]),
64+
Button("Send")
65+
])
66+
panel4.pack()
67+
68+
# Note the reserved=[] with the field.
69+
# By default, fields have ENTER and TAB keys reserved:
70+
# enter fires Field.on_action(), tab moves away from the field.
71+
# By clearing the reserved list we can type enter and tab inside the field.
72+
73+
# Panel 5
74+
# If you don't pack the panel, you have to set its width and height manually,
75+
# as well as the position of all controls:
76+
panel5 = Panel("Panel 5", x=500, y=200, width=200, height=150)
77+
panel5.extend([
78+
Field(value="", hint="message", x=10, y=60, width=180, height=50, id="field_msg3", wrap=True),
79+
Button("Send", x=10, y=20, width=180)
80+
])
81+
82+
def draw(canvas):
83+
canvas.clear()
84+
85+
canvas.append(panel1)
86+
canvas.append(panel2)
87+
canvas.append(panel3)
88+
canvas.append(panel4)
89+
canvas.append(panel5)
90+
canvas.size = 800, 600
91+
canvas.run(draw)

nodebox/gui/controls.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -984,7 +984,7 @@ def draw(self):
984984
image(im7, 0, im4.height, height=self.height-im1.height-im4.height, color=clr)
985985
image(im8, self.width-im8.width, im4.height, height=self.height-im2.height-im5.height, color=clr)
986986
image(im9, im4.width, im6.height, width=self.width-im7.width-im8.width, height=self.height-im3.height-im6.height, color=clr)
987-
987+
988988
def on_mouse_enter(self, mouse):
989989
mouse.cursor = DEFAULT
990990

@@ -1090,14 +1090,15 @@ def __getattr__(self, k):
10901090
def apply(self, spacing=0):
10911091
""" Adjusts the position and size of the controls to match the layout.
10921092
"""
1093-
pass
1093+
self.width = max(control.width for control in self)
1094+
self.height = max(control.height for control in self)
10941095

10951096
def __repr__(self):
10961097
return "Layout(type=%s)" % repr(self.__class__.__name__.lower())
10971098

10981099
# Debug mode:
10991100
#def draw(self):
1100-
# rect(0, 0, self.width, self.height, fill=None, stroke=(1,1,1,0.5), strokestyle="dotted")
1101+
# rect(0, 0, self.width, self.height, fill=None, stroke=(0,0.5,1,1))
11011102

11021103
#--- Layout: Labeled ----------------------------------------------------------------------------------
11031104

@@ -1159,28 +1160,25 @@ def apply(self, spacing=10):
11591160
# adjusting mw at the start will make controls wider to line out with the total width,
11601161
# adjusting it at the end would just ensure that the layout is wide enough.
11611162
mw = max(mw, control.width)
1162-
w1 = max([caption.width for caption in self.captions])
1163-
w2 = max([control.width for control in self.controls])
1163+
w1 = max(caption.width for caption in self.captions)
1164+
w2 = max(control.width for control in self.controls)
11641165
w2 = min(w2, mw)
11651166
dx = 0
11661167
dy = 0
11671168
for caption, control in reversed(zip(self.captions, self.controls)):
1168-
caption.x = dx + w1 - caption.width # halign right.
1169-
control.x = dx + w1 + (w1>0 and spacing)
1170-
caption.y = dy + 0.5 * (control.height - caption.height) # valign center.
1171-
control.y = dy
11721169
if isinstance(control, Layout) and control.height > caption.height * 2:
11731170
caption.y = dy + control.height - caption.height # valign top.
11741171
if isinstance(control, (Label, Button, Slider, Field)):
11751172
control._set_width(mw)
11761173
control._pack()
1174+
caption.x = dx + w1 - caption.width # halign right.
1175+
control.x = dx + w1 + (w1>0 and spacing)
1176+
caption.y = dy + 0.5 * (control.height - caption.height) # valign center.
1177+
control.y = dy
11771178
dy += max(caption.height, control.height, 10) + spacing
1178-
self.width = w1 + w2 + (w1>0 and spacing)
1179+
self.width = w1 + max(w2, mw) + (w1>0 and spacing)
11791180
self.height = dy - spacing
11801181

1181-
#def draw(self):
1182-
# rect(0, 0, self.width, self.height, fill=None, stroke=[1,1,1,1])
1183-
11841182
TOP, CENTER = "top", "center"
11851183

11861184
class Row(Labeled):
@@ -1201,18 +1199,18 @@ def apply(self, spacing=10):
12011199
"""
12021200
mw = self._maxwidth
12031201
da = self._align==TOP and 1.0 or 0.5
1204-
h1 = max([control.height for control in self.controls])
1205-
h2 = max([caption.height for caption in self.captions])
1202+
h1 = max(control.height for control in self.controls)
1203+
h2 = max(caption.height for caption in self.captions)
12061204
dx = 0
12071205
dy = 0
12081206
for caption, control in zip(self.captions, self.controls):
1207+
if isinstance(control, (Label, Button, Slider, Field)):
1208+
control._set_width(mw)
1209+
control._pack()
12091210
caption.x = dx + 0.5 * max(control.width - caption.width, 0) # halign center
12101211
control.x = dx + 0.5 * max(caption.width - control.width, 0) # halign center
12111212
caption.y = dy + h1 + (h2>0 and spacing)
12121213
control.y = dy + da * (h1 - control.height) # valign center
1213-
if isinstance(control, (Label, Button, Slider, Field)):
1214-
control._set_width(mw)
1215-
control._pack()
12161214
dx += max(caption.width, control.width, 10) + spacing
12171215
self.width = dx - spacing
12181216
self.height = h1 + h2 + (h2>0 and spacing)

0 commit comments

Comments
 (0)