Merge lp:~codeforger/simplegc/checkbox into lp:simplegc

Proposed by Michael Rochester
Status: Merged
Approved by: Sam Bull
Approved revision: 202
Merged at revision: 209
Proposed branch: lp:~codeforger/simplegc/checkbox
Merge into: lp:simplegc
Diff against target: 284 lines (+253/-1)
3 files modified
sgc/example/test.py (+13/-1)
sgc/widgets/__init__.py (+1/-0)
sgc/widgets/toggle.py (+239/-0)
To merge this branch: bzr merge lp:~codeforger/simplegc/checkbox
Reviewer Review Type Date Requested Status
Sam Bull Approve
Review via email: mp+99347@code.launchpad.net

Description of the change

Added toggle button and changed __init__ to load it.

This branch was pulled prior to the Radio_button merge so the radio button is not in this branch.

During testing I substantially changed examples/test.py, this file does not need to be merged, I have left it in only to make reviewing the code easyer.

To post a comment you must log in.
Revision history for this message
Sam Bull (dreamsorcerer) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'sgc/example/test.py'
2--- sgc/example/test.py 2012-03-26 13:13:32 +0000
3+++ sgc/example/test.py 2012-03-26 15:04:29 +0000
4@@ -27,7 +27,7 @@
5
6 ver_no = "0.1.2"
7
8-screen = sgc.surface.Screen((640,480)) #, flags=OPENGL
9+screen = sgc.surface.Screen((940,480)) #, flags=OPENGL
10 clock = pygame.time.Clock()
11 pygame.scrap.init()
12
13@@ -54,6 +54,18 @@
14 title.rect.center = (screen.rect.w/2, 40)
15 title.add()
16
17+toggle2 = sgc.widgets.Toggle(label="Default", pos=(50,300))
18+toggle2.add(10)
19+toggle1 = sgc.widgets.Toggle(label="col@#FF0000 & active@True", pos=(50,400),
20+ col=(255,0,0), active=True)
21+toggle1.add(11)
22+toggle3 = sgc.widgets.Toggle(label="label_col@#00FF00", pos=(300,300),
23+ label_col=(0,255,0))
24+toggle3.add(12)
25+
26+
27+
28+
29 # Create input_box
30 input_box = sgc.widgets.InputBox(label="Input Box", default="default text...")
31 input_box.config(pos=(30,120))
32
33=== modified file 'sgc/widgets/__init__.py'
34--- sgc/widgets/__init__.py 2012-03-25 19:16:35 +0000
35+++ sgc/widgets/__init__.py 2012-03-26 15:04:29 +0000
36@@ -36,3 +36,4 @@
37 from radio_button import Radio
38 from scroll_box import ScrollBox
39 from settings import Keys
40+from toggle import Toggle
41
42=== added file 'sgc/widgets/toggle.py'
43--- sgc/widgets/toggle.py 1970-01-01 00:00:00 +0000
44+++ sgc/widgets/toggle.py 2012-03-26 15:04:29 +0000
45@@ -0,0 +1,239 @@
46+#!/usr/bin/env python
47+
48+# Copyright (C) 2012 Michael Rochester
49+
50+"""
51+Toggle Button widget, allows the user to change a boolean setting.
52+
53+"""
54+
55+import pygame
56+from pygame.locals import *
57+
58+from _locals import *
59+from _locals import focus
60+from base_widget import Simple
61+
62+class Toggle(Simple):
63+
64+ """
65+ A clickable check box button
66+
67+ Images:
68+ 'image': The default, background, unactive button state.
69+ 'active': The active, background, state
70+ 'handle': The image used for the handle
71+
72+ """
73+
74+ _can_focus = True
75+ _available_images = ("active", "handle")
76+ # Max_x: the max left and right pos for the handle
77+ # Handlep_x: the x axis location for the handle, if None 'slide' mode not active
78+ # mouse_x: (defined later) the position of the last event in 'slide' mode
79+ _settings_default = {"active": False, "label": "", "col":(118, 45, 215),
80+ "label_col": Font.col, "max_x":(0,0),
81+ "handle_x":None}
82+
83+ _draw_rect = False
84+
85+
86+ def _config(self, **kwargs):
87+ """
88+ label: ``str`` Text to be displayed to the right of the button
89+ col: ``tuple`` (r,g,b) The colour used for the 'active' image
90+ label_col: ``tuple`` (r,g,b) The colour for the buttons label
91+ active: ``bool`` Sets the active state to the value of itself (False is default)
92+ """
93+ # Label to the right of the button
94+ if "label" in kwargs:
95+ # Save string as new label
96+ self._settings["label"] = kwargs["label"]
97+ # Colour of 'over' image
98+ if "col" in kwargs:
99+ self._settings["col"] = kwargs["col"]
100+ # Colour of label
101+ if "label_col" in kwargs:
102+ self._settings["label_col"] = kwargs["label_col"]
103+ # Set as active.
104+ if "active" in kwargs:
105+ self._settings["active"] = kwargs["active"]
106+ self._draw()
107+
108+ def _draw(self, draw):
109+
110+ self._settings["size"] = (155,50) # A ratio of 3.1:1
111+
112+ # Calculate the handle size
113+ self._settings["handlesize"] = ((self._settings["size"][0]-
114+ (self._settings["size"][1]/10*3))/2,
115+ self._settings["size"][1]-
116+ self._settings["size"][1]/5)
117+
118+ # Calculate the max left and right pos for the handle
119+ self._settings["max_x"] = (self._settings["size"][1]/10,
120+ (self._settings["size"][0]-
121+ self._settings["size"][1]/10)-
122+ self._settings["handlesize"][0])
123+ # Render the lables
124+ label = Simple(Font["widget"].render(self._settings["label"], True,
125+ self._settings["label_col"]))
126+ label_on = Simple(Font["widget"].render("ON", True,
127+ (255,255,255)))
128+ label_off = Simple(Font["widget"].render("OFF", True,
129+ (255,255,255)))
130+ # Set size of widget based upon size of button and label
131+ if not hasattr(self, "image"):
132+ self._create_base_images((self._settings["size"][0] + 10 +
133+ label.rect.w,
134+ max(label.rect.height,
135+ self._settings["size"][1])))
136+
137+
138+
139+ # Draw handle
140+ self._images["handle"].fill(0) # Set to transparent
141+ draw.rect(self._images["handle"], (149,150,120), # Base rectangle
142+ (0,0,self._settings["handlesize"][0],
143+ self._settings["handlesize"][1]))
144+ for x in range(3): # Grips
145+ draw.line(self._images["handle"], (169,170,140),
146+ ((self._settings["handlesize"][0]/6)*(x+2),
147+ self._settings["handlesize"][1]-
148+ self._settings["handlesize"][1]/5),
149+ ((self._settings["handlesize"][0]/6)*(x+2),
150+ self._settings["handlesize"][1]/5))
151+
152+
153+
154+ # Set colours for use in loop
155+ colour = {"image":(55,54,45), "active":self._settings["col"]}
156+ for img in ["image","active"]: # Draw other images
157+ self._images[img].fill(0) # Set to transparent
158+
159+ draw.rect(self._images[img], colour[img], # Base rectangle
160+ (0,0,self._settings["size"][0],self._settings["size"][1]))
161+
162+ # Blit all text
163+ self._images[img].blit(label.image,
164+ (self._settings["size"][0]+ 10,
165+ self._settings["size"][1]/2-
166+ label.rect.h/2))
167+
168+
169+ self._images[img].blit(label_on.image,
170+ (self._settings["handlesize"][0]/2+
171+ self._settings["size"][1]/10-
172+ label_on.rect.w/2,
173+ self._settings["size"][1]/2-
174+ label_on.rect.h/2))
175+
176+
177+ self._images[img].blit(label_off.image,
178+ (self._settings["size"][0]-
179+ self._settings["handlesize"][0]/2-
180+ self._settings["size"][1]/10-
181+ label_off.rect.w/2,
182+ self._settings["size"][1]/2-
183+ label_off.rect.h/2))
184+ # Rerender text for new colour
185+ label_on = Simple(Font["widget"].render("ON", True,
186+ (0,0,1)))
187+ label_off = Simple(Font["widget"].render("OFF", True,
188+ (0,0,1)))
189+
190+ self._draw_button()
191+
192+ def _event(self, event):
193+ """Respond to events."""
194+ if event.type == MOUSEMOTION and event.buttons[0] == 1 and\
195+ self._settings["mouse_x"] is not None:
196+ if self._settings["handle_x"] is None : # If not in slide mode
197+ # If moved enough to go into slide mode
198+ if abs(self._settings["mouse_x"] - event.pos[0]) > 5:
199+ self._settings["handle_x"] = self._settings["max_x"][0]\
200+ if self._settings["active"] is False else \
201+ self._settings["max_x"][1]
202+ self._settings["mouse_x"] = event.pos[0]
203+ else: # If in slide mode
204+ # Move handle
205+ self._settings["handle_x"] += event.pos[0] - \
206+ self._settings["mouse_x"]
207+ self._settings["mouse_x"] = event.pos[0]
208+ # Ensure handle is not past max possitions
209+ if self._settings["handle_x"] > self._settings["max_x"][1]:
210+ self._settings["handle_x"] = self._settings["max_x"][1]
211+
212+ if self._settings["handle_x"] < self._settings["max_x"][0]:
213+ self._settings["handle_x"] = self._settings["max_x"][0]
214+
215+ self._draw_button() # Redraw for new handle
216+
217+ if event.type == MOUSEBUTTONDOWN and event.button == 1:
218+ # If mouse down on the handle
219+ if Rect(self._settings["max_x"][1 if self._settings["active"]
220+ else 0],
221+ self._settings["size"][1]/10,
222+ self._settings["handlesize"][0],
223+ self._settings["handlesize"][1]).collidepoint(
224+ (event.pos[0]-self.pos_abs[0],
225+ event.pos[1]-self.pos_abs[1])):
226+ self._settings["mouse_x"] = event.pos[0]
227+ else:
228+ self._settings["mouse_x"] = None
229+ if event.type == MOUSEBUTTONUP and event.button == 1:
230+ if self._settings["handle_x"] is not None: # If in slide mode
231+ # Determine if dropped in on/off position
232+ self._settings["active"] = False if \
233+ self._settings["handle_x"]-self._settings["max_x"][0] < \
234+ self._settings["max_x"][1]-self._settings["handle_x"] \
235+ else True
236+ self._settings["handle_x"] = None # Stop slide mode
237+ # Redraw in final position
238+ self._draw_button()
239+ else: # If not in slide mode
240+ if self.rect_abs.collidepoint(event.pos):
241+ # Flip switch
242+ self._settings["active"] = not self._settings["active"]
243+ self._draw_button()
244+
245+ elif event.type == KEYUP:
246+ if event.key in (13,32): # Enter or space key
247+ self._settings["active"] = not self._settings["active"]
248+ self._draw_button()
249+
250+ def _focus_enter(self, focus):
251+ """Draw rectangle when focus is gained from keyboard."""
252+ if focus == 1:
253+ self._draw_rect = True
254+ self._draw_button()
255+
256+ def _focus_exit(self):
257+ """Stop drawing rectangle when focus is lost."""
258+ self._draw_rect = False
259+ self._draw_button()
260+
261+ def _draw_button(self):
262+ """Draw the button."""
263+ if self._settings["active"] is False:
264+ self.image = self._images["image"].copy()
265+ else:
266+ self.image = self._images["active"].copy()
267+
268+ if self._settings["handle_x"] is not None:
269+ self.image.blit(self._images["handle"],
270+ (self._settings["handle_x"],self._settings["size"][1]/10))
271+ elif self._settings["active"] is False:
272+ self.image.blit(self._images["handle"],
273+ (self._settings["max_x"][0],self._settings["size"][1]/10))
274+ else:
275+ self.image.blit(self._images["handle"],
276+ (self._settings["max_x"][1],self._settings["size"][1]/10))
277+
278+ # Draw dotted rectangle to show keyboard focus
279+ if self._draw_rect:
280+ self._dotted_rect()
281+
282+ @property
283+ def active(self):
284+ return self._settings["active"]

Subscribers

People subscribed via source and target branches