├── .gitignore
├── CHANGELOG.txt
├── LICENSE.txt
├── README.txt
├── doc
├── guide.txt
├── libtest.txt
├── port.txt
└── pyjs_changes.zip
├── libtest.py
├── pyjsdl
├── __init__.py
├── app.py
├── color.py
├── constants.py
├── cursors.py
├── display.py
├── draw.py
├── env.py
├── event.py
├── font.py
├── image.py
├── key.py
├── mask.py
├── mixer.py
├── mouse.py
├── pyjsarray.py
├── pyjsobj.py
├── rect.py
├── sprite.py
├── surface.py
├── surfarray.py
├── time.py
├── transform.py
├── util.py
├── vector.py
└── version.py
└── test
├── __init__.py
├── color_test.py
├── cursor_test.py
├── draw_test.py
├── event_test.py
├── libtest.py
├── mask_test.py
├── rect_test.py
├── sprite_test.py
├── surface_test.py
├── surfarray_test.py
├── time_test.py
├── transform_test.py
└── vector_test.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.pyo
3 | *.jpg
4 | *~
5 |
--------------------------------------------------------------------------------
/CHANGELOG.txt:
--------------------------------------------------------------------------------
1 | 0.27_dev
2 | -refactor mouse positioning.
3 | -add mouse get_focused method.
4 | -add display resize method.
5 |
6 | 0.27 2025-01-18
7 | -revise surface alpha.
8 | -update transform to preserve surface alpha.
9 | -add vector copy method.
10 | -revise mixer set_num_channels method.
11 | -refactor mixer music rewind method.
12 | -revise mixer channel play promise handling.
13 | -add activeevent.
14 | -add closeevent.
15 | -add display set_icon.
16 | -update color object.
17 | -revise sprite to optimize.
18 | -revise vector elementwise object.
19 | -revise vector operator methods.
20 | -revise vector object instantiation.
21 |
22 | 0.26 2022-04-18
23 | -revise event set_blocked processing.
24 | -revise event object for performance.
25 | -refactor event handler for performance.
26 | -add key set_repeat method.
27 | -revise key event handler.
28 | -update key event handler.
29 | -update surface blit with optional rect return.
30 | -add surface alpha methods.
31 | -add surface blits method.
32 |
33 | 0.25 2021-11-07
34 | -revise sprite orderedupdates.
35 | -add sprite group alias.
36 | -refactor sprite collide methods.
37 | -add sprite layeredupdates.
38 | -add cursors get_cursor_types.
39 | -add canvas contextmenu handler.
40 | -add vector object.
41 | -revise mixer processing.
42 | -add mixer music object.
43 | -add mixer channel endevent.
44 | -add mixer channel queue.
45 |
46 | 0.24 2021-04-28
47 | -revise rect move/inflate args processing.
48 | -revise rect attributes.
49 | -revise ndarray shape for inheritance.
50 | -add env check.
51 | -revise quit method to stop mixer.
52 | -revise quit method to stop timers.
53 | -update time set_timer for event argument.
54 | -revise app to use webkit2.
55 | -update for python 2/3 compatibility.
56 |
57 | 0.23 2021-04-06
58 | -update event handling.
59 | -update surface get_at to return color object.
60 | -refactor surface colorkey methods.
61 | -revise sprite blit process.
62 | -update mask for optimization.
63 | -update ndarray and bitset for optimization.
64 | -update time wait to properly delay callback.
65 | -revise requestanimationframe shim.
66 | -update clock with performance time.
67 | -update clock tick with performance time.
68 | -update asynchronous loop process to optimize.
69 | -update for python 2/3 compatibility.
70 |
71 | 0.22 2019-04-06
72 | -add display set_callback method.
73 | -update Canvas handling of callback change.
74 | -add time set_timer method.
75 | -update sprite to revise member groups.
76 | -update sprite argument handling.
77 | -update sprite collide_mask to use mask.overlap.
78 | -refactor rect for optimization.
79 | -update display setup to accept callback function or object with run method.
80 | -update rect to define __slots__.
81 | -add mouse set_cursor and get_cursor methods.
82 | -add surface toDataURL method.
83 | -update mouse set_cursor to use custom image.
84 | -update surface set_at to optimize.
85 | -update mouse set_cursor to use cursor data.
86 | -update transform rotozoom to optimize.
87 | -update display update method (_update) to optimize.
88 | -update surface blit method (_blit_clear) to optimize.
89 | -update draw arc of nonequal dimension to process properly.
90 | -update draw ellipse to use float scale argument.
91 | -update draw arc to optimize.
92 | -update asynchronous loop process to optimize.
93 | -refactor time clock object.
94 | -revise with absolute import statements.
95 | -add display methods getAbsoluteLeft/getAbsoluteTop/getScrollLeft/getScrollTop.
96 | -add touch event support.
97 | -update font with minor rendering adjustment.
98 | -update font to include initiation from a file.
99 | -update event peek option of all types.
100 | -update event methods to optimize.
101 | -update color constructor to accept hex '#rrggbb' argument.
102 | -update draw methods to optimize context state change.
103 | -update draw methods to optimize with optional rect return.
104 | -add app.py to launch app in webkit on desktop.
105 |
106 | 0.21 2015-04-12
107 | -update font to improve fonts access.
108 | -add rect.contains method.
109 | -update image load methods for imagedata objects.
110 | -add display.setup_images method.
111 | -add key.name method.
112 | -add mask.toString method.
113 | -update display.update to properly handle clipping.
114 | -update surface.blit with clipping.
115 | -update rect union methods to process properly.
116 | -add rect iter method.
117 | -add rect collide methods - collidelistall, collidedict, and collidedictall.
118 | -add sprite collide methods - collide_rect_ratio, collide_circle, and collide_circle_ratio.
119 | -refactor to isolate pyjs.
120 | -refactor for optimization.
121 | -correct event.pump to maintain queue.
122 | -update IE9+ compatibility files in pyjs_changes.zip.
123 | -add mousewheel event listener.
124 | -release under MIT license.
125 |
126 | 0.20 2014-11-09
127 | -add rect union methods.
128 | -update methods to use rect intersection.
129 | -correct surface subsurface rect access.
130 | -add rect rectPool to utilize a rect pool.
131 | -update sprite draw for performance.
132 | -update sprite collide methods processing.
133 | -add rect clamp methods.
134 | -update display setup callback function.
135 | -update display repaint process.
136 | -add mixer.
137 |
138 | 0.19 2014-08-20
139 | -update bitset array to avoid js reserved work.
140 | -update quit function to terminate program iteration.
141 | -update transform.rotozoom for correct scaling.
142 | -add env.pyjs_mode with strict/optimized bool attributes to check pyjs-S/-O mode.
143 | -correct modifier keys keyevent detect with pyjs -S compilation (worked in -O) with sets membership testing of onKeyDown keycode that appears due to js/pyjs numeric difference.
144 | -update display event to properly clear modifier keys held with onMouseLeave event.
145 | -update display set_caption/get_caption to access Canvas element id.
146 | -add display.get_active method.
147 | -restructure event handler to isolate from UserEvent and JEvent objects.
148 | -update display.update for performance.
149 | -update event eventtype list as a set object.
150 | -update rect inflate/inflate_ip positioning.
151 |
152 | 0.18 2014-02-27
153 | -update Pyjsarray typedarray constructor for Chrome compatibility.
154 | -update Surface constructor to int convert argument.
155 | -update Transform.rotate positioning.
156 | -update Transform rotate/flip to restore context.
157 | -add Textbox/Textarea resize method.
158 | -update Surface.resize for width/height attributes.
159 | -update Canvas.resize to align elements.
160 | -update Canvas to subclass Surface.
161 | -update Canvas with buffered surface optional.
162 | -add display.is_canvas and update Canvas blit.
163 | -update Surface constructor to take optional arguments.
164 | -update Event.poll noevent return.
165 | -update Surface.get_at to return color tuple.
166 | -update Rect attribute positioning.
167 | -add Rect equality and nonzero methods.
168 | -add util.Pyjs_Mode to check Pyjs compilation mode.
169 | -add Color object.
170 | -update to use Color object.
171 | -update Rect constructor.
172 | -update draw methods with minor adjustments.
173 | -update Mask.fill method.
174 | -update to use Rect object.
175 | -update Sprite group update to account for member changes.
176 | -update util.Timer for output to textarea rather than console logger.
177 | -update Surfarray array2d PyImageInteger processing.
178 | -update Surfarray make_surface method.
179 | -add draw.ellipse method.
180 | -update Pyjsarray Typedarray constructor when type not implemented.
181 | -change license from GPL to LGPL.
182 |
183 | 0.17 2013-11-01
184 | -update Pyjsarray ImageData object for IE compatibility.
185 | -add util.call to call unbound methods.
186 | -update Surface.blit to int convert argument.
187 | -update Rect.inflate and Rect.inflate_ip for proper positioning.
188 | -add Textbox/Textarea and display.textbox_init for text input.
189 | -update mouse positioning with page scroll position.
190 | -update Surfarray.blit_array.
191 | -add Pyjsarray Ndarray methods.
192 |
193 | 0.16 2013-09-01
194 | -add Surfarray using Pyjsarray.
195 | -update Pyjsarray with Ndarray and ImageData objects.
196 | -update image.load
197 | -update display.update rect processing
198 | -add display.update_rect method
199 | -update display.update/display.update_rect/surface._blit_clear rect clipping
200 |
201 | 0.15 2013-07-30
202 | -add Mask using Pyjsarray and Pyjsbitset.
203 | -add Pyjsarray and Pyjsbitset based on JavaScript TypedArray object.
204 | -add Surface get_at/set_at using Canvas getImageData and putImageData.
205 | -update Surface.subarray.
206 | -update Canvas and Surface to use pyjamas.Canvas.HTML5Canvas.
207 | -update Rect.createIntersection.
208 | -update pyjs_changes.zip - Pyjs git update for HTML5canvas usage.
209 |
210 | 0.14 2013-05-15
211 | -add Font rendering to canvas.
212 | -update Event so key event works in IE browser.
213 | -update Display.update rect argument for pyjs -O compilation.
214 | -update Event key handling for IE browser.
215 | -update Sprite Group __contains__ to work with pyjs.
216 | -update Surface.blit to take rect argument and return rect.
217 | -update Surface.fill color argument.
218 | -update pyjs_changes.zip.
219 |
220 | 0.13 2013-05-04
221 | -add key events to Canvas.
222 | -update Event for process JS key events.
223 | -update Mouse methods variable.
224 |
225 | 0.12 2013-04-29
226 | -add mouse events to Canvas.
227 | -update Event to process JS mouse events.
228 | -update Mouse.get_pressed and Mouse.get_pos for JS mouse events.
229 | -update Time.wait to use JS Timeout.
230 |
231 | 0.11 2013-04-26
232 | -update Sprite.clear to allow callable argument.
233 | -update Surface._blit_clear with clipping.
234 | -update Surface.blits to directly call drawImage.
235 | -update Surface.fill rect argument.
236 | -update Draw.arc, Transform.rotate, and Rect with int() division.
237 |
238 | 0.10 2013-04-24
239 | -initial release
240 |
241 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 James Garnon
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | Pyjsdl - Python-to-JavaScript Multimedia Framework
2 |
3 | Pyjsdl module is modelled on Pygame/SDL commands that wraps JavaScript functionality including HTML5 canvas. The module permits scripts coded in Python/Pygame to compile to JavaScript using the Pyjs compiler (http://pyjs.org), allowing deployment of JavaScript applications without extensive editing of the script. The module supports a substantial portion of Pygame functionality. Information concerning use of the Pyjsdl module is included in doc/guide.txt.
4 |
5 | The Pyjsdl-ts package (https://gatc.ca/projects/pyjsdl-ts/) is a port of Pyjsdl that compiles to JavaScript using the Transcrypt compiler (https://www.transcrypt.org/), information is included in doc/port.txt.
6 |
7 | Pyjsdl is released under the MIT License, see LICENSE.txt for further information.
8 |
9 | Pyjsdl page: https://gatc.ca/projects/pyjsdl/
10 | Pyjsdl docs: https://gatc.ca/projects/pyjsdl/doc/
11 |
12 |
--------------------------------------------------------------------------------
/doc/guide.txt:
--------------------------------------------------------------------------------
1 | Pyjsdl Module Guide
2 |
3 | Pyjsdl module is modelled on Pygame/SDL commands that wraps JavaScript functionality including HTML5 canvas. To use Pyjsdl module, place pyjsdl folder in the script folder or on the module path. Import pyjsdl into the Python script, or use the statement 'import pyjsdl as pygame' to maintain the Pygame commands. During pyjsdl initiation, use the statement pyjsdl.display.setup(run, images) to provide the canvas the main function to execute at a timed interval and program images to preload, where the 'run' function contains statements derived from the main loop to be repeated each frame and 'images' is a list of image paths in the form ['./images/img.png'].
4 |
5 | Python code using Pyjsdl is compiled to a JavaScript application with the Pyjs compiler (http://pyjs.org). Install Pyjs from https://github.com/pyjs/pyjs repository, for instance to install into a virtualenv:
6 |
7 | virtualenv -p python2 env
8 | source env/bin/activate
9 | pip install git+https://github.com/pyjs/pyjs.git#egg=pyjs
10 |
11 | After installation, check pyjs_changes.zip in the package for required changes. Compile the Python code using pyjsbuild. The code can be compiled in strict (-S) mode for maximum Python compatibility:
12 |
13 | pyjsbuild -S --dynamic-link script.py -o output
14 |
15 | The code can be compiled in optimized (-O) mode for enhanced performance with reduced Python compatibility, optionally with --enable-descriptor-proto/--enable-operator-funcs:
16 |
17 | pyjsbuild -O --dynamic-link script.py -o output
18 |
19 | Some additional changes to the Python script may be necessary for Pyjs compilation. A web application can be deployed following compilation to JavaScript, which can run in a web browser on a pc or mobile. To run on a local HTTP server, use command 'python3 -m http.server' and browse to localhost:8000. During development, use the web browser devtools console that displays print and error output, and to maintain updated development changes set devtools to open with cache disabled. The app can also run on the desktop using the app.py script, check instructions within the script.
20 |
21 | Further information is available on the Pyjsdl project page (https://gatc.ca/projects/pyjsdl/) and in the API documentation (https://gatc.ca/projects/pyjsdl/doc/).
22 |
23 |
--------------------------------------------------------------------------------
/doc/libtest.txt:
--------------------------------------------------------------------------------
1 | Libtest
2 |
3 | The libtest script tests the functionality of the Pyjsdl library, capable of running with Pyjs/Pyjsdl or Python/Pygame. To test Pyjsdl, the system should have Pyjs installed and the pyjsdl folder on script path. The libtest.py script in package root executes the tests in the test folder. Pyjs compiled code is run in web browser from libtest.html in output folder with local server running. Tests are compiled with Pyjs in strict mode for maximum Python compatibility, optimized for reduced Python compatibility with performance, or optimized mode with --enable-descriptor-proto/--enable-operator-funcs options to restore some Python compatibility.
4 |
5 | Build in strict mode:
6 |
7 | 'pyjsbuild -S --dynamic-link libtest.py -o outputs'
8 |
9 | Build in optimized mode:
10 |
11 | 'pyjsbuild -O --dynamic-link libtest.py -o outputo'
12 |
13 | Build in optimized mode with feature options:
14 |
15 | 'pyjsbuild -O --dynamic-link --enable-descriptor-proto --enable-operator-funcs libtest.py -o outputopf'
16 |
17 |
--------------------------------------------------------------------------------
/doc/port.txt:
--------------------------------------------------------------------------------
1 | Pyjsdl - Python-to-JavaScript Multimedia Framework
2 |
3 | The pyjsdl-ts package is a port of pyjsdl (https://gatc.ca/projects/pyjsdl/) module with the same functionality. Pyjsdl module is modelled on Pygame/SDL commands that wraps JavaScript functionality including HTML5 canvas. The module permits scripts coded in Python/Pygame to compile to JavaScript using the Transcrypt compiler (https://www.transcrypt.org/), allowing deployment of JavaScript applications without extensive editing of the script.
4 |
5 | Pyjsdl page: https://gatc.ca/projects/pyjsdl-ts/
6 | Pyjsdl docs: https://gatc.ca/projects/pyjsdl-ts/doc/
7 |
8 |
--------------------------------------------------------------------------------
/doc/pyjs_changes.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jggatc/pyjsdl/1ba9e5ca68807bd73cc03e933e931bc08f28e934/doc/pyjs_changes.zip
--------------------------------------------------------------------------------
/libtest.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | """
4 | Libtest
5 |
6 | Check doc/libtest.txt for information.
7 |
8 |
9 | tests = ['surface_test',
10 | 'rect_test',
11 | 'draw_test',
12 | 'transform_test',
13 | 'surfarray_test',
14 | 'mask_test',
15 | 'color_test',
16 | 'cursor_test',
17 | 'sprite_test',
18 | 'event_test',
19 | 'time_test',
20 | 'vector_test']
21 | """
22 |
23 |
24 | tests = [] #test specific module if added to tests list, default all tests
25 | catch_exception = True #exception in test caught, set to False to raise exception
26 |
27 |
28 | import sys
29 | sys.dont_write_bytecode = True
30 |
31 | from test import libtest
32 |
33 | libtest.main(tests, catch_exception)
34 |
35 |
--------------------------------------------------------------------------------
/pyjsdl/__init__.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Python-to-JavaScript Multimedia Framework
2 | #Copyright (c) 2013 James Garnon
3 | #
4 | #Permission is hereby granted, free of charge, to any person obtaining a copy
5 | #of this software and associated documentation files (the "Software"), to deal
6 | #in the Software without restriction, including without limitation the rights
7 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | #copies of the Software, and to permit persons to whom the Software is
9 | #furnished to do so, subject to the following conditions:
10 | #
11 | #The above copyright notice and this permission notice shall be included in
12 | #all copies or substantial portions of the Software.
13 | #
14 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 | #THE SOFTWARE.
21 |
22 | """
23 | **Pyjsdl - Pyjs Canvas Library**
24 | """
25 |
26 | __version__ = '0.27'
27 |
28 | from pyjsdl import env
29 | from pyjsdl import util
30 | from pyjsdl.display import Display
31 | from pyjsdl.surface import Surface
32 | from pyjsdl.rect import Rect
33 | from pyjsdl.image import Image
34 | from pyjsdl.event import Event
35 | from pyjsdl.key import Key
36 | from pyjsdl.mouse import Mouse
37 | from pyjsdl.color import Color
38 | from pyjsdl.mixer import Mixer
39 | from pyjsdl.time import Time
40 | from pyjsdl.vector import Vector2
41 | from pyjsdl import draw
42 | from pyjsdl import transform
43 | from pyjsdl import surface
44 | from pyjsdl import surfarray
45 | from pyjsdl import mask
46 | from pyjsdl import font
47 | from pyjsdl import sprite
48 | from pyjsdl import cursors
49 | from pyjsdl import version
50 | from pyjsdl.constants import *
51 |
52 |
53 | __docformat__ = 'restructuredtext'
54 |
55 |
56 | _initialized = False
57 |
58 | def init():
59 | """
60 | Initialize module.
61 | """
62 | global time, display, image, event, key, mouse, mixer, _initialized
63 | if _initialized:
64 | return
65 | else:
66 | _initialized = True
67 | event = Event()
68 | env.set_env('event', event)
69 | time = Time()
70 | display = Display()
71 | image = Image()
72 | mixer = Mixer()
73 | mouse = Mouse()
74 | key = Key()
75 |
76 | init()
77 |
78 |
79 | def setup(callback, images=None):
80 | """
81 | Initialize module for script execution.
82 |
83 | Argument include callback function to run and optional images list to preload.
84 | Callback function can also be an object with a run method to call.
85 | The images can be image URL, or file-like object or base64 data in format (name.ext,data).
86 | """
87 | display.setup(callback, images)
88 |
89 |
90 | def set_callback(callback):
91 | """
92 | Set callback function.
93 |
94 | Argument callback function to run.
95 | Callback function can also be an object with a run method to call.
96 | """
97 | display.set_callback(callback)
98 |
99 |
100 | def setup_images(images):
101 | """
102 | Add images to image preload list.
103 |
104 | The argument is an image or list of images representing an image URL, or file-like object or base64 data in format (name.ext,data).
105 | Image preloading occurs at setup call.
106 | """
107 | display.set_images(images)
108 |
109 |
110 | def quit():
111 | """
112 | Terminates canvas repaint and callback function.
113 | """
114 | canvas = display.get_canvas()
115 | canvas.stop()
116 | mixer.quit()
117 | time._stop_timers()
118 |
119 |
120 | class error(RuntimeError):
121 | """
122 | Exception object.
123 | """
124 | pass
125 |
126 |
127 | def bounding_rect_return(setting):
128 | """
129 | Bounding rect return.
130 |
131 | Set whether blit/draw return bounding Rect.
132 | Setting (bool) defaults to True on module initialization.
133 | """
134 | surface.bounding_rect_return(setting)
135 | draw.bounding_rect_return(setting)
136 |
137 |
--------------------------------------------------------------------------------
/pyjsdl/app.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | #Pyjsdl - Copyright (C) 2013
4 | #Released under the MIT License
5 |
6 | """
7 | Pyjsdl App
8 |
9 | Script launches HTML app on desktop using Gtk/Webkit.
10 | Copy app script to the application root and optionally rename.
11 | Run the script once to create an ini file and edit to configure.
12 |
13 | Tested under Linux Gnome desktop with the installed packages:
14 | gir1.2-webkit2-4.0, python-gi (py2), python3-gi (py3).
15 | On other OS, additional installation steps may be required.
16 | """
17 |
18 | import gi
19 | gi.require_version('Gtk', '3.0')
20 | gi.require_version('WebKit2', '4.0')
21 | from gi.repository import Gtk, WebKit2
22 | import multiprocessing
23 | import os.path
24 | import sys
25 |
26 | if sys.version_info.major >= 3:
27 | from socketserver import TCPServer
28 | from http.server import SimpleHTTPRequestHandler
29 | else:
30 | from SocketServer import TCPServer
31 | from SimpleHTTPServer import SimpleHTTPRequestHandler
32 |
33 |
34 | class Server(TCPServer):
35 |
36 | allow_reuse_address = True
37 |
38 | def __init__(self, port):
39 | TCPServer.__init__(self, ("", port), SimpleHTTPRequestHandler)
40 | self.process = multiprocessing.Process(target=self.serve_forever)
41 |
42 | def initiate(self):
43 | self.process.daemon = True
44 | self.process.start()
45 |
46 | def terminate(self):
47 | self.process.terminate()
48 |
49 |
50 | class QuietServer(Server):
51 | def __init__(self, port):
52 | TCPServer.__init__(self, ("", port), QuietHandler)
53 | self.process = multiprocessing.Process(target=self.serve_forever)
54 |
55 |
56 | class QuietHandler(SimpleHTTPRequestHandler):
57 |
58 | def log_message(self, format, *args):
59 | pass
60 |
61 |
62 | class App(object):
63 |
64 | def __init__(self, config):
65 | self.config = config
66 | self.window = Gtk.Window()
67 | self.window.resize(self.config.width+16,self.config.height+16)
68 | if self.config.app_name is not None:
69 | self.window.set_title(self.config.app_name)
70 | else:
71 | title = self.config.app_uri.split('/')[-1].split('.')[0]
72 | self.window.set_title(title.capitalize())
73 | self.window.connect('destroy', Gtk.main_quit)
74 | self.web = None
75 | self.server = None
76 |
77 | def webview_setup(self):
78 | self.web = WebKit2.WebView()
79 | uri = 'http://%s:%d/%s' % (self.config.server_ip,
80 | self.config.server_port,
81 | self.config.app_uri)
82 | self.web.load_uri(uri)
83 | self.window.add(self.web)
84 |
85 | def webview(self):
86 | self.webview_setup()
87 | self.window.show_all()
88 | Gtk.main()
89 |
90 | def server_enable(self):
91 | if not self.server:
92 | if self.config.server_log:
93 | self.server = Server(self.config.server_port)
94 | else:
95 | self.server = QuietServer(self.config.server_port)
96 | self.server.initiate()
97 |
98 | def server_disable(self):
99 | if self.server:
100 | self.server.terminate()
101 |
102 |
103 | class Config(object):
104 |
105 | def __init__(self):
106 | self.server_ip = 'localhost'
107 | self.server_port = 8000
108 | self.server_log = False
109 | self.app_uri = None
110 | self.app_name = None
111 | self.width = 500
112 | self.height = 500
113 | self.config_name = sys.argv[0].split('.')[0]+'.ini'
114 | if os.path.exists(self.config_name):
115 | cfg_setting = self.read_ini()
116 | else:
117 | self.create_ini()
118 | print('Enter configuration info in %s.' % self.config_name)
119 | sys.exit()
120 | for setting in cfg_setting:
121 | if setting == 'app_uri':
122 | self.app_uri = cfg_setting['app_uri'].strip()
123 | if setting == 'app_name':
124 | self.app_name = cfg_setting['app_name'].strip()
125 | if setting == 'window_width':
126 | self.width = int(cfg_setting['window_width'].strip())
127 | if setting == 'window_height':
128 | self.height = int(cfg_setting['window_height'].strip())
129 | if setting == 'server_ip':
130 | self.server_ip = cfg_setting['server_ip'].strip()
131 | if setting == 'server_port':
132 | self.server_port = int(cfg_setting['server_port'].strip())
133 | if setting == 'server_log':
134 | server_log = cfg_setting['server_log'].strip().lower()
135 | self.server_log = {'true':True, 'false':False}[server_log]
136 |
137 | def create_ini(self):
138 | f = open(self.config_name, 'w')
139 | f.write('#App Configuration\n\n')
140 | f.write('app_uri output/app.html\n\n')
141 | f.write('app_name App\n\n')
142 | f.write('window_width 500\n\n')
143 | f.write('window_height 500\n\n')
144 | f.write('server_ip localhost\n\n')
145 | f.write('server_port 8000\n\n')
146 | f.write('server_log false\n\n')
147 | f.close()
148 |
149 | def read_ini(self):
150 | cfg_file = open(self.config_name)
151 | cfg = [ln.strip().split(' ',1) for ln in cfg_file if ln[:1].isalpha()]
152 | cfg = dict(cfg)
153 | cfg_file.close()
154 | return cfg
155 |
156 |
157 | def main():
158 | config = Config()
159 | app = App(config)
160 | app.server_enable()
161 | app.webview()
162 | app.server_disable()
163 |
164 |
165 | if __name__ == '__main__':
166 | main()
167 |
168 |
--------------------------------------------------------------------------------
/pyjsdl/color.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Color module**
6 |
7 | The module provides a color object.
8 | """
9 |
10 | from pyjsdl.pyjsobj import Color as _Color
11 |
12 |
13 | class Color(_Color):
14 | """
15 | Color object.
16 | """
17 |
18 | def __init__(self, *color):
19 | """
20 | Initialize Color object.
21 |
22 | Alternative arguments:
23 |
24 | * r,g,b,a
25 | * r,g,b
26 | * (r,g,b,a)
27 | * (r,g,b)
28 | * integer argb
29 | * html string '#rrggbb[aa]'
30 | * hex string '0xrrggbb[aa]'
31 | * Color
32 |
33 | Color has the attributes::
34 |
35 | r, g, b, a
36 |
37 | Operator functionality in --optimized mode (-O) requires --enable-operator-funcs.
38 | Module initialization places Color in module's namespace.
39 | """
40 | ln = len(color)
41 | if ln == 1:
42 | _color = color[0]
43 | if hasattr(_color, '__len__'):
44 | ln = len(_color)
45 | else:
46 | _color = color
47 | if ln == 4:
48 | self.r = _color[0]
49 | self.g = _color[1]
50 | self.b = _color[2]
51 | self.a = _color[3]
52 | elif ln == 3:
53 | self.r = _color[0]
54 | self.g = _color[1]
55 | self.b = _color[2]
56 | self.a = 255
57 | else:
58 | if not hasattr(_color, 'startswith'):
59 | self.r = (_color>>16) & 0xff
60 | self.g = (_color>>8) & 0xff
61 | self.b = _color & 0xff
62 | self.a = (_color>>24) & 0xff
63 | else:
64 | _color = _color.lower()
65 | if _color.startswith('#'):
66 | _color = _color.lstrip('#')
67 | elif _color.startswith('0x'):
68 | _color = _color.lstrip('0x')
69 | if len(_color) == 6:
70 | _color += 'ff'
71 | self.r = int(_color[0:2], 16)
72 | self.g = int(_color[2:4], 16)
73 | self.b = int(_color[4:6], 16)
74 | self.a = int(_color[6:8], 16)
75 |
76 | def __str__(self):
77 | return "rgba(%d, %d, %d, %f)" % (self.r, self.g, self.b, self.a/255.0)
78 |
79 | def __repr__(self):
80 | return "(%d, %d, %d, %d)" % (self.r, self.g, self.b, self.a)
81 |
82 | def __getitem__(self, index):
83 | return {0:self.r, 1:self.g, 2:self.b, 3:self.a}[index]
84 |
85 | def __setitem__(self, index, val):
86 | self.__setattr__({0:'r', 1:'g', 2:'b', 3:'a'}[index], val)
87 |
88 | def __iter__(self):
89 | return iter([self.r, self.g, self.b, self.a])
90 |
91 | def __len__(self):
92 | return 4
93 |
94 | def __eq__(self, other):
95 | if hasattr(other, 'a'):
96 | return ( self.r == other.r and
97 | self.g == other.g and
98 | self.b == other.b and
99 | self.a == other.a )
100 | else:
101 | if len(other) == 4:
102 | return ( self.a == other[3] and
103 | self.r == other[0] and
104 | self.g == other[1] and
105 | self.b == other[2] )
106 | else:
107 | return ( self.r == other[0] and
108 | self.g == other[1] and
109 | self.b == other[2] )
110 |
111 | def __ne__(self, other):
112 | if hasattr(other, 'a'):
113 | return ( self.r != other.r or
114 | self.g != other.g or
115 | self.b != other.b or
116 | self.a != other.a )
117 | else:
118 | if len(other) == 4:
119 | return ( self.a != other[3] or
120 | self.r != other[0] or
121 | self.g != other[1] or
122 | self.b != other[2] )
123 | else:
124 | return ( self.r != other[0] or
125 | self.g != other[1] or
126 | self.b != other[2] )
127 |
128 | def __add__(self, other):
129 | r = self.r + other.r
130 | if r > 255: r = 255
131 | g = self.g + other.g
132 | if g > 255: g = 255
133 | b = self.b + other.b
134 | if b > 255: b = 255
135 | a = self.a + other.a
136 | if a > 255: a = 255
137 | return self.__class__(r,g,b,a)
138 |
139 | def __sub__(self, other):
140 | r = self.r - other.r
141 | if r < 0: r = 0
142 | g = self.g - other.g
143 | if g < 0: g = 0
144 | b = self.b - other.b
145 | if b < 0: b = 0
146 | a = self.a - other.a
147 | if a < 0: a = 0
148 | return self.__class__(r,g,b,a)
149 |
150 | def __mul__(self, other):
151 | r = self.r * other.r
152 | if r > 255: r = 255
153 | g = self.g * other.g
154 | if g > 255: g = 255
155 | b = self.b * other.b
156 | if b > 255: b = 255
157 | a = self.a * other.a
158 | if a > 255: a = 255
159 | return self.__class__(r,g,b,a)
160 |
161 | def __floordiv__(self, other):
162 | if other.r != 0: r = int(self.r // other.r)
163 | else: r = 0
164 | if other.g != 0: g = int(self.g // other.g)
165 | else: g = 0
166 | if other.b != 0: b = int(self.b // other.b)
167 | else: b = 0
168 | if other.a != 0: a = int(self.a // other.a)
169 | else: a = 0
170 | return self.__class__(r,g,b,a)
171 |
172 | def __mod__(self, other):
173 | if other.r != 0: r = self.r % other.r
174 | else: r = 0
175 | if other.g != 0: g = self.g % other.g
176 | else: g = 0
177 | if other.b != 0: b = self.b % other.b
178 | else: b = 0
179 | if other.a != 0: a = self.a % other.a
180 | else: a = 0
181 | return self.__class__(r,g,b,a)
182 |
183 | def __iadd__(self, other):
184 | self.r += other.r
185 | if self.r > 255: self.r = 255
186 | self.g += other.g
187 | if self.g > 255: self.g = 255
188 | self.b += other.b
189 | if self.b > 255: self.b = 255
190 | self.a += other.a
191 | if self.a > 255: self.a = 255
192 | return self
193 |
194 | def __isub__(self, other):
195 | self.r -= other.r
196 | if self.r < 0: self.r = 0
197 | self.g -= other.g
198 | if self.g < 0: self.g = 0
199 | self.b -= other.b
200 | if self.b < 0: self.b = 0
201 | self.a -= other.a
202 | if self.a < 0: self.a = 0
203 | return self
204 |
205 | def __imul__(self, other):
206 | self.r *= other.r
207 | if self.r > 255: self.r = 255
208 | self.g *= other.g
209 | if self.g > 255: self.g = 255
210 | self.b *= other.b
211 | if self.b > 255: self.b = 255
212 | self.a *= other.a
213 | if self.a > 255: self.a = 255
214 | return self
215 |
216 | def __ifloordiv__(self, other):
217 | if other.r != 0: self.r //= other.r
218 | else: self.r = 0
219 | if other.g != 0: self.g //= other.g
220 | else: self.g = 0
221 | if other.b != 0: self.b //= other.b
222 | else: self.b = 0
223 | if other.a != 0: self.a //= other.a
224 | else: self.a = 0
225 | return self
226 |
227 | def __imod__(self, other):
228 | if other.r != 0: self.r %= other.r
229 | else: self.r = 0
230 | if other.g != 0: self.g %= other.g
231 | else: self.g = 0
232 | if other.b != 0: self.b %= other.b
233 | else: self.b = 0
234 | if other.a != 0: self.a %= other.a
235 | else: self.a = 0
236 | return self
237 |
238 | def __invert__(self):
239 | return self.__class__(~self.r + 256,
240 | ~self.g + 256,
241 | ~self.b + 256,
242 | ~self.a + 256)
243 |
244 | def normalize(self):
245 | """
246 | Return normalized color values.
247 | """
248 | return (self.r / 255.0,
249 | self.g / 255.0,
250 | self.b / 255.0,
251 | self.a / 255.0)
252 |
253 | def correct_gamma(self, gamma):
254 | """
255 | Return gamma-corrected Color.
256 | """
257 | return self.__class__(int(round((((self.r) / 255.0)**gamma) * 255.0)),
258 | int(round((((self.g) / 255.0)**gamma) * 255.0)),
259 | int(round((((self.b) / 255.0)**gamma) * 255.0)),
260 | int(round((((self.a) / 255.0)**gamma) * 255.0)))
261 |
262 | def premul_alpha(self):
263 | """
264 | Return alpha-multipled Color.
265 | """
266 | return self.__class__(int(round(self.r * (self.a/255.0))),
267 | int(round(self.g * (self.a/255.0))),
268 | int(round(self.b * (self.a/255.0))),
269 | self.a)
270 |
271 | def lerp(self, color, t):
272 | """
273 | Return a Color linear interpolated by t to the given color.
274 | """
275 | if t < 0.0 or t > 1.0:
276 | raise ValueError('Argument t must be in range 0 to 1')
277 | if hasattr(color, 'a'):
278 | return self.__class__(int(round(self.r * (1-t) + color.r * t)),
279 | int(round(self.g * (1-t) + color.g * t)),
280 | int(round(self.b * (1-t) + color.b * t)),
281 | int(round(self.a * (1-t) + color.a * t)))
282 | else:
283 | if len(color) == 3:
284 | return self.__class__(int(round(self.r * (1-t) + color[0] * t)),
285 | int(round(self.g * (1-t) + color[1] * t)),
286 | int(round(self.b * (1-t) + color[2] * t)),
287 | int(round(self.a * (1-t) + 255 * t)))
288 | elif len(color) == 4:
289 | return self.__class__(int(round(self.r * (1-t) + color[0] * t)),
290 | int(round(self.g * (1-t) + color[1] * t)),
291 | int(round(self.b * (1-t) + color[2] * t)),
292 | int(round(self.a * (1-t) + color[3] * t)))
293 | else:
294 | raise ValueError('invalid color argument')
295 |
296 | def update(self, *color):
297 | """
298 | Update color values.
299 | """
300 | ln = len(color)
301 | if ln == 1:
302 | _color = color[0]
303 | if hasattr(_color, '__len__'):
304 | ln = len(_color)
305 | else:
306 | _color = color
307 | if ln == 4:
308 | self.r = _color[0]
309 | self.g = _color[1]
310 | self.b = _color[2]
311 | self.a = _color[3]
312 | elif ln == 3:
313 | self.r = _color[0]
314 | self.g = _color[1]
315 | self.b = _color[2]
316 | self.a = 255
317 | else:
318 | if not hasattr(_color, 'startswith'):
319 | self.r = (_color>>16) & 0xff
320 | self.g = (_color>>8) & 0xff
321 | self.b = _color & 0xff
322 | self.a = (_color>>24) & 0xff
323 | else:
324 | _color = _color.lower()
325 | if _color.startswith('#'):
326 | _color = _color.lstrip('#')
327 | elif _color.startswith('0x'):
328 | _color = _color.lstrip('0x')
329 | if len(_color) == 6:
330 | _color += 'ff'
331 | self.r = int(_color[0:2], 16)
332 | self.g = int(_color[2:4], 16)
333 | self.b = int(_color[4:6], 16)
334 | self.a = int(_color[6:8], 16)
335 |
336 | def _get_cmy(self):
337 | return _rgb_to_cmy(self.r, self.g, self.b)
338 |
339 | def _set_cmy(self, val):
340 | self.r, self.g, self.b = _cmy_to_rgb(*val)
341 |
342 | def _get_hsva(self):
343 | return _rgba_to_hsva(self.r, self.g, self.b, self.a)
344 |
345 | def _set_hsva(self, val):
346 | self.r, self.g, self.b, self.a = _hsva_to_rgba(*val)
347 |
348 | def _get_hsla(self):
349 | return _rgba_to_hsla(self.r, self.g, self.b, self.a)
350 |
351 | def _set_hsla(self, val):
352 | self.r, self.g, self.b, self.a = _hsla_to_rgba(*val)
353 |
354 | cmy = property(_get_cmy, _set_cmy)
355 | "CMY color."
356 |
357 | hsva = property(_get_hsva, _set_hsva)
358 | "HSVA color."
359 |
360 | hsla = property(_get_hsla, _set_hsla)
361 | "HSLA color."
362 |
363 |
364 | def _rgb_to_cmy(r, g, b):
365 | r, g, b = r/255.0, g/255.0, b/255.0
366 | c, m, y = 1-r, 1-g, 1-b
367 | return (c, m, y)
368 |
369 |
370 | def _cmy_to_rgb(c, m, y):
371 | r, g, b = 1-c, 1-m, 1-y
372 | return (int(r*255), int(g*255), int(b*255))
373 |
374 |
375 | def _rgba_to_hsva(r, g, b, a):
376 | r, g, b, a = r/255.0, g/255.0, b/255.0, a/255.0
377 | c_max = max(r, g, b)
378 | c_min = min(r, g, b)
379 | delta = c_max - c_min
380 | if delta == 0:
381 | h = 0.0
382 | elif c_max == r:
383 | h = (60 * ((g - b) / delta) + 360) % 360.0
384 | elif c_max == g:
385 | h = (60 * ((b - r) / delta) + 120) % 360.0
386 | elif c_max == b:
387 | h = (60 * ((r - g) / delta) + 240) % 360.0
388 | if c_max == 0:
389 | s = 0.0
390 | else:
391 | s = (delta / c_max)
392 | v = c_max
393 | return h, s*100.0, v*100.0, a*100.0
394 |
395 |
396 | def _hsva_to_rgba(h, s, v, a):
397 | h, s, v, a = h/360.0, s/100.0, v/100.0, a/100.0
398 | i = int(h*6.0)
399 | f = (h*6.0) - i
400 | p = (v * (1.0 - s))
401 | q = (v * (1.0 - s * f))
402 | t = (v * (1.0 - (s * (1.0-f))))
403 | i %= 6
404 | if i == 0:
405 | r, g, b = v, t, p
406 | elif i == 1:
407 | r, g, b = q, v, p
408 | elif i == 2:
409 | r, g, b = p, v, t
410 | elif i == 3:
411 | r, g, b = p, q, v
412 | elif i == 4:
413 | r, g, b = t, p, v
414 | elif i == 5:
415 | r, g, b = v, p, q
416 | return int(r*255), int(g*255), int(b*255), int(a*255)
417 |
418 |
419 | def _rgba_to_hsla(r, g, b, a):
420 | r, g, b, a = r/255.0, g/255.0, b/255.0, a/255.0
421 | cmax = max(r, g, b)
422 | cmin = min(r, g, b)
423 | delta = cmax - cmin
424 | l = (cmax + cmin) / 2.0
425 | if delta == 0:
426 | s = 0.0
427 | else:
428 | s = delta / (1-abs(2*l-1))
429 | if delta == 0:
430 | h = 0.0
431 | elif cmax == r:
432 | h = (60 * ((g - b) / delta) + 360) % 360.0
433 | elif cmax == g:
434 | h = (60 * ((b - r) / delta) + 120) % 360.0
435 | elif cmax == b:
436 | h = (60 * ((r - g) / delta) + 240) % 360.0
437 | return h, s*100.0, l*100.0, a*100.0
438 |
439 |
440 | def _hsla_to_rgba(h, s, l, a):
441 | h, s, l, a = h/360.0, s/100.0, l/100.0, a/100.0
442 | if l < 0.5:
443 | q = l * (1+s)
444 | else:
445 | q = l + s - l * s
446 | p = 2 * l - q
447 | t = h + 1.0/3.0
448 | if t < 0.0: t += 1.0
449 | elif t > 1.0: t -= 1.0
450 | if t < 1.0/6.0:
451 | r = p + (q - p) * 6.0 * t
452 | elif t < 1.0/2.0:
453 | r = q
454 | elif t < 2.0/3.0:
455 | r = p + (q - p) * (2.0/3.0-t) * 6.0
456 | else:
457 | r = p
458 | t = h
459 | if t < 0.0: t += 1.0
460 | elif t > 1.0: t -= 1.0
461 | if t < 1.0/6.0:
462 | g = p + (q - p) * 6.0 * t
463 | elif t < 1.0/2.0:
464 | g = q
465 | elif t < 2.0/3.0:
466 | g = p + (q - p) * (2.0/3.0-t) * 6.0
467 | else:
468 | g = p
469 | t = h - 1.0/3.0
470 | if t < 0.0: t += 1.0
471 | elif t > 1.0: t -= 1.0
472 | if t < 1.0/6.0:
473 | b = p + (q - p) * 6.0 * t
474 | elif t < 1.0/2.0:
475 | b = q
476 | elif t < 2.0/3.0:
477 | b = p + (q - p) * (2.0/3.0-t) * 6.0
478 | else:
479 | b = p
480 | return int(r*255), int(g*255), int(b*255), int(a*255)
481 |
482 |
--------------------------------------------------------------------------------
/pyjsdl/constants.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Constants**
6 |
7 | Constants are defined as in Pygame/SDL and JavaScript events. Examine constants.py for information on the constants. The constant variables are imported into the Pyjsdl module namespace.
8 | """
9 |
10 |
11 | KMOD_ALT = 4
12 | KMOD_CAPS = 0
13 | KMOD_CTRL = 2
14 | KMOD_LALT = 4
15 | KMOD_LCTRL = 2
16 | KMOD_LMETA = 0
17 | KMOD_LSHIFT = 1
18 | KMOD_META = 0
19 | KMOD_MODE = 0
20 | KMOD_NONE = 0
21 | KMOD_NUM = 0
22 | KMOD_RALT = 4
23 | KMOD_RCTRL = 2
24 | KMOD_RMETA = 0
25 | KMOD_RSHIFT = 1
26 | KMOD_SHIFT = 1
27 | K_0 = 48
28 | K_1 = 49
29 | K_2 = 50
30 | K_3 = 51
31 | K_4 = 52
32 | K_5 = 53
33 | K_6 = 54
34 | K_7 = 55
35 | K_8 = 56
36 | K_9 = 57
37 | K_ALT = 18
38 | K_AMPERSAND = 38
39 | K_ASTERISK = 42
40 | K_AT = 64
41 | K_BACKQUOTE = 96
42 | K_BACKSLASH = 92
43 | K_BACKSPACE = 8
44 | K_BREAK = 0x40000048
45 | K_CAPSLOCK = 0x40000039
46 | K_CARET = 94
47 | K_CLEAR = 0x4000009c
48 | K_COLON = 58
49 | K_COMMA = 44
50 | K_CTRL = 17
51 | K_DELETE = 127
52 | K_DOLLAR = 36
53 | K_DOWN = 0x40000051
54 | K_END = 0x4000004d
55 | K_EQUALS = 61
56 | K_ESCAPE = 27
57 | K_EURO = 0x400000b4
58 | K_EXCLAIM = 33
59 | K_F1 = 0x4000003a
60 | K_F2 = 0x4000003b
61 | K_F3 = 0x4000003c
62 | K_F4 = 0x4000003d
63 | K_F5 = 0x4000003e
64 | K_F6 = 0x4000003f
65 | K_F7 = 0x40000040
66 | K_F8 = 0x40000041
67 | K_F9 = 0x40000042
68 | K_F10 = 0x40000043
69 | K_F11 = 0x40000044
70 | K_F12 = 0x40000045
71 | K_F13 = 0x40000068
72 | K_F14 = 0x40000069
73 | K_F15 = 0x4000006a
74 | K_GREATER = 62
75 | K_HASH = 35
76 | K_HELP = 0x40000075
77 | K_HOME = 0x4000004a
78 | K_INSERT = 0x40000049
79 | K_KP0 = 0x40000062
80 | K_KP1 = 0x40000059
81 | K_KP2 = 0x4000005a
82 | K_KP3 = 0x4000005b
83 | K_KP4 = 0x4000005c
84 | K_KP5 = 0x4000005d
85 | K_KP6 = 0x4000005e
86 | K_KP7 = 0x4000005f
87 | K_KP8 = 0x40000060
88 | K_KP9 = 0x40000061
89 | K_KP_DIVIDE = 0x40000054
90 | K_KP_ENTER = 0x40000058
91 | K_KP_EQUALS = 0x40000067
92 | K_KP_MINUS = 0x40000056
93 | K_KP_MULTIPLY = 0x40000055
94 | K_KP_PERIOD = 0x40000063
95 | K_KP_PLUS = 0x40000057
96 | K_LALT = 18
97 | K_LCTRL = 17
98 | K_LEFT = 0x40000050
99 | K_LEFTBRACKET = 91
100 | K_LEFTPAREN = 40
101 | K_LESS = 60
102 | K_LMETA = 0x400000e3
103 | K_LSHIFT = 16
104 | K_LSUPER = 0x400000e3
105 | K_MENU = 0x40000076
106 | K_MINUS = 45
107 | K_MODE = 0x40000101
108 | K_NUMLOCK = 0x40000053
109 | K_PAGEDOWN = 0x4000004e
110 | K_PAGEUP = 0x4000004b
111 | K_PAUSE = 0x40000048
112 | K_PERIOD = 46
113 | K_PLUS = 43
114 | K_POWER = 0x40000066
115 | K_PRINT = 0x40000046
116 | K_QUESTION = 63
117 | K_QUOTE = 39
118 | K_QUOTEDBL = 34
119 | K_RALT = 18
120 | K_RCTRL = 17
121 | K_RETURN = 13
122 | K_RIGHT = 0x4000004F
123 | K_RIGHTBRACKET = 93
124 | K_RIGHTPAREN = 41
125 | K_RMETA = 0x400000e3
126 | K_RSHIFT = 16
127 | K_RSUPER = 0x400000e3
128 | K_SCROLLOCK = 0x40000047
129 | K_SCROLLLOCK = 0x40000047
130 | K_SEMICOLON = 59
131 | K_SHIFT = 16
132 | K_SLASH = 92
133 | K_SPACE = 32
134 | K_SYSREQ = 0x4000009a
135 | K_TAB = 9
136 | K_UNDERSCORE = 95
137 | K_UNKNOWN = 0
138 | K_UP = 0x40000052
139 | K_a = 97
140 | K_b = 98
141 | K_c = 99
142 | K_d = 100
143 | K_e = 101
144 | K_f = 102
145 | K_g = 103
146 | K_h = 104
147 | K_i = 105
148 | K_j = 106
149 | K_k = 107
150 | K_l = 108
151 | K_m = 109
152 | K_n = 110
153 | K_o = 111
154 | K_p = 112
155 | K_q = 113
156 | K_r = 114
157 | K_s = 115
158 | K_t = 116
159 | K_u = 117
160 | K_v = 118
161 | K_w = 119
162 | K_x = 120
163 | K_y = 121
164 | K_z = 122
165 | MOUSEBUTTONDOWN = 5
166 | MOUSEBUTTONUP = 6
167 | MOUSEMOTION = 4
168 | KEYDOWN = 2
169 | KEYUP = 3
170 | ACTIVEEVENT = 32768
171 | APPFOCUSMOUSE = 0
172 | APPMOUSEFOCUS = 0
173 | APPINPUTFOCUS = 1
174 | APPACTIVE = 2
175 | DOUBLEBUF = 0x40000000
176 | FULLSCREEN = -0x80000000
177 | HWACCEL = 256
178 | HWPALETTE = 0x20000000
179 | HWSURFACE = 1
180 | NOEVENT = 0
181 | NOFRAME = 32
182 | NUMEVENTS = 32
183 | OPENGL = 2
184 | QUIT = 12
185 | RESIZABLE = 16
186 | RLEACCEL = 16384
187 | RLEACCELOK = 8192
188 | SRCALPHA = 65536
189 | SRCCOLORKEY = 4096
190 | SWSURFACE = 0
191 | SYSWMEVENT = 13
192 | USEREVENT = 24
193 |
194 |
--------------------------------------------------------------------------------
/pyjsdl/cursors.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Cursors module**
6 |
7 | The module provides access to mouse cursors.
8 | """
9 |
10 | from pyjsdl.surface import Surface
11 | from pyjsdl.color import Color
12 | from pyjsdl import constants as Const
13 |
14 |
15 | arrow = diamond = broken_x = tri_left = tri_right = ()
16 | "Unimplemented variables."
17 |
18 |
19 | def compile(strings, black='X', white='.', xor='o'):
20 | """
21 | Compile binary data from cursor string.
22 |
23 | Arguments cursor string, and optional symbols representing colors.
24 | Data represents black and white pixels, xor color defaulting to black.
25 | Data should be a string list of width divisible by 8.
26 | Return cursor data and mask, can be used with mouse.set_cursor.
27 | """
28 | data = []
29 | mask = []
30 | dbit = {black:1, white:0, xor:1}
31 | mbit = {black:1, white:1, xor:0}
32 | string = ''.join(strings)
33 | for i in range(0, len(string), 8):
34 | s = string[i:i+8]
35 | db = mb = 0
36 | if s != ' ':
37 | for j in range(8):
38 | c = s[j]
39 | if c == ' ':
40 | continue
41 | if dbit[c]:
42 | db |= 0x01<<7-j
43 | if mbit[c]:
44 | mb |= 0x01<<7-j
45 | data.append(int(db))
46 | mask.append(int(mb))
47 | return tuple(data), tuple(mask)
48 |
49 |
50 | def create_cursor(size, data, mask):
51 | """
52 | Create cursor image from binary data.
53 |
54 | Arguments cursor size and its binary data and mask.
55 | Return surface, can be used with mouse.set_cursor.
56 | """
57 | surface = Surface(size, Const.SRCALPHA)
58 | black = Color(0,0,0,255)
59 | white = Color(255,255,255,255)
60 | x = y = 0
61 | for i in range(len(data)):
62 | if data[i] or mask[i]:
63 | for j in range(8):
64 | if data[i] & 0x01<<7-j:
65 | surface.setFillStyle(black)
66 | surface.fillRect(x+j, y, 1, 1)
67 | elif mask[i] & 0x01<<7-j:
68 | surface.setFillStyle(white)
69 | surface.fillRect(x+j, y, 1, 1)
70 | x += 8
71 | if x >= size[0]:
72 | x = 0
73 | y += 1
74 | return surface
75 |
76 |
77 | def get_cursor_types():
78 | #https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
79 | """
80 | Return list of cursor types from CSS Cursor API.
81 | """
82 | types = ['default', 'auto', 'none', 'context-menu', 'help',
83 | 'pointer', 'progress', 'wait', 'cell', 'crosshair',
84 | 'text', 'vertical-text', 'alias', 'copy', 'move',
85 | 'no-drop', 'not-allowed', 'e-resize', 'n-resize',
86 | 'ne-resize', 'nw-resize', 's-resize', 'se-resize',
87 | 'sw-resize', 'w-resize', 'ew-resize', 'ns-resize',
88 | 'nesw-resize', 'nwse-resize', 'col-resize',
89 | 'row-resize', 'all-scroll', 'zoom-in', 'zoom-out',
90 | 'grab', 'grabbing']
91 | return types
92 |
93 |
--------------------------------------------------------------------------------
/pyjsdl/draw.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Draw module**
6 |
7 | The module provides functions to draw shapes on a surface.
8 | """
9 |
10 | from math import pi as _pi
11 | from pyjsdl.rect import Rect
12 | from pyjsdl.color import Color
13 |
14 |
15 | _return_rect = True
16 |
17 |
18 | def rect(surface, color, rect, width=0):
19 | """
20 | Draw rectangle shape.
21 |
22 | Arguments include surface to draw, color, Rect.
23 | Optional width argument of outline, which defaults to 0 for filled shape.
24 | Return bounding Rect.
25 | """
26 | if hasattr(rect, 'width'):
27 | _rect = rect
28 | else:
29 | _rect = Rect(rect)
30 | if width:
31 | surface.setLineWidth(width)
32 | if surface._stroke_style != color:
33 | surface._stroke_style = color
34 | if hasattr(color, 'a'):
35 | surface.setStrokeStyle(color)
36 | else:
37 | surface.setStrokeStyle(Color(color))
38 | surface.strokeRect(_rect.x, _rect.y, _rect.width, _rect.height)
39 | else:
40 | if surface._fill_style != color:
41 | surface._fill_style = color
42 | if hasattr(color, 'a'):
43 | surface.setFillStyle(color)
44 | else:
45 | surface.setFillStyle(Color(color))
46 | surface.fillRect(_rect.x, _rect.y, _rect.width, _rect.height)
47 | if not _return_rect:
48 | return None
49 | if surface._display:
50 | return surface._display._surface_rect.clip(_rect)
51 | else:
52 | return surface.get_rect().clip(_rect)
53 |
54 |
55 | def circle(surface, color, position, radius, width=0):
56 | """
57 | Draw circular shape.
58 |
59 | Arguments include surface to draw, color, position and radius.
60 | Optional width argument of outline, which defaults to 0 for filled shape.
61 | Return bounding Rect.
62 | """
63 | surface.beginPath()
64 | surface.arc(position[0], position[1], radius, 0, 2*_pi, False)
65 | if width:
66 | surface.setLineWidth(width)
67 | if surface._stroke_style != color:
68 | surface._stroke_style = color
69 | if hasattr(color, 'a'):
70 | surface.setStrokeStyle(color)
71 | else:
72 | surface.setStrokeStyle(Color(color))
73 | surface.stroke()
74 | else:
75 | if surface._fill_style != color:
76 | surface._fill_style = color
77 | if hasattr(color, 'a'):
78 | surface.setFillStyle(color)
79 | else:
80 | surface.setFillStyle(Color(color))
81 | surface.fill()
82 | if not _return_rect:
83 | return None
84 | if surface._display:
85 | return surface._display._surface_rect.clip(
86 | Rect(position[0]-radius, position[1]-radius, 2*radius, 2*radius))
87 | else:
88 | return surface.get_rect().clip(
89 | Rect(position[0]-radius, position[1]-radius, 2*radius, 2*radius))
90 |
91 |
92 | def ellipse(surface, color, rect, width=0):
93 | """
94 | Draw ellipse shape.
95 |
96 | Arguments include surface to draw, color, and rect.
97 | Optional width argument of outline, which defaults to 0 for filled shape.
98 | Return bounding Rect.
99 | """
100 | if hasattr(rect, 'width'):
101 | _rect = rect
102 | else:
103 | _rect = Rect(rect)
104 | surface.saveContext()
105 | surface.translate(_rect.x + int(_rect.width/2),
106 | _rect.y + int(_rect.height/2))
107 | if _rect.width >= _rect.height:
108 | surface.scale(_rect.width / (_rect.height*1.0), 1)
109 | radius = int(_rect.height/2)
110 | else:
111 | surface.scale(1, _rect.height / (_rect.width*1.0))
112 | radius = int(_rect.width/2)
113 | surface.beginPath()
114 | surface.arc(0, 0, radius, 0, 2*_pi, False)
115 | if width:
116 | surface.setLineWidth(width)
117 | if surface._stroke_style != color:
118 | surface._stroke_style = color
119 | if hasattr(color, 'a'):
120 | surface.setStrokeStyle(color)
121 | else:
122 | surface.setStrokeStyle(Color(color))
123 | surface.stroke()
124 | else:
125 | if surface._fill_style != color:
126 | surface._fill_style = color
127 | if hasattr(color, 'a'):
128 | surface.setFillStyle(color)
129 | else:
130 | surface.setFillStyle(Color(color))
131 | surface.fill()
132 | surface.restoreContext()
133 | if not _return_rect:
134 | return None
135 | if surface._display:
136 | return surface._display._surface_rect.clip(_rect)
137 | else:
138 | return surface.get_rect().clip(_rect)
139 |
140 |
141 | def arc(surface, color, rect, start_angle, stop_angle, width=1):
142 | """
143 | Draw arc shape.
144 |
145 | Arguments include surface to draw, color, rect, start_angle, stop_angle.
146 | Optional width argument of outline.
147 | Return bounding Rect.
148 | """
149 | if hasattr(rect, 'width'):
150 | _rect = rect
151 | else:
152 | _rect = Rect(rect)
153 | if _rect.width == _rect.height:
154 | surface.beginPath()
155 | surface.arc(_rect.x + int(_rect.width/2), _rect.y + int(_rect.height/2),
156 | int(_rect.width/2), -start_angle, -stop_angle, True)
157 | if width:
158 | surface.setLineWidth(width)
159 | if surface._stroke_style != color:
160 | surface._stroke_style = color
161 | if hasattr(color, 'a'):
162 | surface.setStrokeStyle(color)
163 | else:
164 | surface.setStrokeStyle(Color(color))
165 | surface.stroke()
166 | else:
167 | surface.closePath()
168 | if surface._fill_style != color:
169 | surface._fill_style = color
170 | if hasattr(color, 'a'):
171 | surface.setFillStyle(color)
172 | else:
173 | surface.setFillStyle(Color(color))
174 | surface.fill()
175 | else:
176 | surface.saveContext()
177 | surface.translate(_rect.x + int(_rect.width/2),
178 | _rect.y + int(_rect.height/2))
179 | if _rect.width >= _rect.height:
180 | surface.scale(_rect.width / (_rect.height*1.0), 1)
181 | radius = int(_rect.height/2)
182 | else:
183 | surface.scale(1, _rect.height / (_rect.width*1.0))
184 | radius = int(_rect.width/2)
185 | surface.beginPath()
186 | surface.arc(0, 0, radius, -start_angle, -stop_angle, True)
187 | if width:
188 | surface.setLineWidth(width)
189 | if surface._stroke_style != color:
190 | surface._stroke_style = color
191 | if hasattr(color, 'a'):
192 | surface.setStrokeStyle(color)
193 | else:
194 | surface.setStrokeStyle(Color(color))
195 | surface.stroke()
196 | else:
197 | surface.closePath()
198 | if surface._fill_style != color:
199 | surface._fill_style = color
200 | if hasattr(color, 'a'):
201 | surface.setFillStyle(color)
202 | else:
203 | surface.setFillStyle(Color(color))
204 | surface.fill()
205 | surface.restoreContext()
206 | if not _return_rect:
207 | return None
208 | if surface._display:
209 | return surface._display._surface_rect.clip(_rect)
210 | else:
211 | return surface.get_rect().clip(_rect)
212 |
213 |
214 | def polygon(surface, color, pointlist, width=0):
215 | """
216 | Draw polygon shape.
217 |
218 | Arguments include surface to draw, color, and pointlist.
219 | Optional width argument of outline, which defaults to 0 for filled shape.
220 | Return bounding Rect.
221 | """
222 | surface.beginPath()
223 | surface.moveTo(*pointlist[0])
224 | for point in pointlist[1:]:
225 | surface.lineTo(*point)
226 | surface.closePath()
227 | if width:
228 | surface.setLineWidth(width)
229 | if surface._stroke_style != color:
230 | surface._stroke_style = color
231 | if hasattr(color, 'a'):
232 | surface.setStrokeStyle(color)
233 | else:
234 | surface.setStrokeStyle(Color(color))
235 | surface.stroke()
236 | else:
237 | if surface._fill_style != color:
238 | surface._fill_style = color
239 | if hasattr(color, 'a'):
240 | surface.setFillStyle(color)
241 | else:
242 | surface.setFillStyle(Color(color))
243 | surface.fill()
244 | if not _return_rect:
245 | return None
246 | xpts = [pt[0] for pt in pointlist]
247 | ypts = [pt[1] for pt in pointlist]
248 | xmin, xmax = min(xpts), max(xpts)
249 | ymin, ymax = min(ypts), max(ypts)
250 | if surface._display:
251 | return surface._display._surface_rect.clip(
252 | Rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1))
253 | else:
254 | return surface.get_rect().clip(
255 | Rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1))
256 |
257 |
258 | def line(surface, color, point1, point2, width=1):
259 | """
260 | Draw line.
261 |
262 | Arguments include surface to draw, color, point1, point2.
263 | Optional width argument of line.
264 | Return bounding Rect.
265 | """
266 | surface.beginPath()
267 | surface.moveTo(*point1)
268 | surface.lineTo(*point2)
269 | surface.setLineWidth(width)
270 | if surface._stroke_style != color:
271 | surface._stroke_style = color
272 | if hasattr(color, 'a'):
273 | surface.setStrokeStyle(color)
274 | else:
275 | surface.setStrokeStyle(Color(color))
276 | surface.stroke()
277 | if not _return_rect:
278 | return None
279 | xpts = [pt[0] for pt in (point1,point2)]
280 | ypts = [pt[1] for pt in (point1,point2)]
281 | xmin, xmax = min(xpts), max(xpts)
282 | ymin, ymax = min(ypts), max(ypts)
283 | if surface._display:
284 | return surface._display._surface_rect.clip(
285 | Rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1))
286 | else:
287 | return surface.get_rect().clip(
288 | Rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1))
289 |
290 |
291 | def lines(surface, color, closed, pointlist, width=1):
292 | """
293 | Draw interconnected lines.
294 |
295 | Arguments include surface to draw, color, closed, and pointlist.
296 | Optional width argument of line.
297 | Return bounding Rect.
298 | """
299 | surface.beginPath()
300 | surface.moveTo(*pointlist[0])
301 | for point in pointlist[1:]:
302 | surface.lineTo(*point)
303 | if closed:
304 | surface.closePath()
305 | surface.setLineWidth(width)
306 | if surface._stroke_style != color:
307 | surface._stroke_style = color
308 | if hasattr(color, 'a'):
309 | surface.setStrokeStyle(color)
310 | else:
311 | surface.setStrokeStyle(Color(color))
312 | surface.stroke()
313 | if not _return_rect:
314 | return None
315 | xpts = [pt[0] for pt in pointlist]
316 | ypts = [pt[1] for pt in pointlist]
317 | xmin, xmax = min(xpts), max(xpts)
318 | ymin, ymax = min(ypts), max(ypts)
319 | if surface._display:
320 | return surface._display._surface_rect.clip(
321 | Rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1))
322 | else:
323 | return surface.get_rect().clip(
324 | Rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1))
325 |
326 |
327 | def aaline(surface, color, point1, point2, blend=1):
328 | """
329 | Draw line.
330 |
331 | Arguments include surface to draw, color, point1, point2.
332 | Return bounding Rect.
333 | """
334 | rect = line(surface, color, point1, point2)
335 | return rect
336 |
337 |
338 | def aalines(surface, color, closed, pointlist, blend=1):
339 | """
340 | Draw interconnected lines.
341 |
342 | Arguments include surface to draw, color, closed, and pointlist.
343 | Return bounding Rect.
344 | """
345 | rect = lines(surface, color, closed, pointlist)
346 | return rect
347 |
348 |
349 | def bounding_rect_return(setting):
350 | """
351 | Bounding rect return.
352 |
353 | Set whether draw functions return bounding Rect.
354 | Setting (bool) defaults to True on module initialization.
355 | """
356 | global _return_rect
357 | _return_rect = setting
358 |
359 |
360 | #depreciated
361 | set_return = bounding_rect_return
362 |
363 |
--------------------------------------------------------------------------------
/pyjsdl/env.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | import os, sys
5 |
6 |
7 | if os.name != 'pyjs':
8 | print('Use Pyjs to compile script to a JS app')
9 | sys.exit()
10 |
11 |
12 | canvas = None
13 |
14 | frame = None
15 |
16 | pyjs_mode = None
17 |
18 | event = None
19 |
20 |
21 | def get_canvas():
22 | """
23 | Return Canvas object.
24 | """
25 | return canvas
26 |
27 |
28 | def get_frame():
29 | """
30 | Return Webpage frame.
31 | """
32 | return frame
33 |
34 |
35 | def get_pyjsmode():
36 | """
37 | Return Pyjs mode object.
38 | """
39 | return pyjs_mode
40 |
41 |
42 | def set_env(key, val):
43 | setattr(sys.modules[__name__], key, val)
44 |
45 |
--------------------------------------------------------------------------------
/pyjsdl/font.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Font module**
6 |
7 | The module provides font access and rendering on a surface.
8 | """
9 |
10 | from math import ceil as _ceil
11 | from pyjsdl.surface import Surface
12 | from pyjsdl.color import Color
13 | from pyjsdl.pyjsobj import HTML5Canvas
14 |
15 |
16 | _initialized = False
17 | _surf = None
18 |
19 |
20 | def init():
21 | """
22 | Initialize font module.
23 | """
24 | global _surf, _initialized, match_font
25 | if _initialized:
26 | return
27 | try:
28 | _surf = HTML5Canvas(1,1)
29 | _surf.measureText('x')
30 | except:
31 | _surf = None
32 | _initialized = True
33 | init()
34 |
35 |
36 | def quit():
37 | """
38 | Unintialize font module.
39 | """
40 | global _surf, _initialized
41 | _surf = None
42 | _initialized = False
43 |
44 |
45 | def get_init():
46 | """
47 | Check if font module is initialized.
48 | """
49 | return _initialized
50 |
51 |
52 | def get_default_font():
53 | """
54 | Return default font.
55 | """
56 | return Font._font[0]
57 |
58 |
59 | def get_fonts():
60 | """
61 | Return font names, which have fallback fonts if unavailable.
62 | """
63 | return Font._font
64 |
65 |
66 | def match_font(name):
67 | """
68 | Find system font.
69 |
70 | Argument name is a font name, or comma-delimited string of font names.
71 | Return font string in compliant format.
72 | """
73 | fallback = False
74 | font = [fn.strip().lower() for fn in name.split(',')]
75 | for i, fn in enumerate(font):
76 | if fn in Font._font:
77 | fallback = True
78 | continue
79 | else:
80 | f = ''.join(c for c in fn if c.isalnum())
81 | if f in Font._font_alt:
82 | font[i] = Font._font[Font._font_alt[f]]
83 | fallback = True
84 | if not fallback:
85 | font.append(Font._font[0])
86 | font = ','.join(font)
87 | return font
88 |
89 |
90 | class Font(object):
91 | """
92 | Font object.
93 | """
94 |
95 | _font = [
96 | 'arial', 'bitstream vera sans', 'bitstream vera serif',
97 | 'book antiqua', 'comic sans ms', 'courier new', 'courier',
98 | 'dejavu sans', 'dejavu sans mono', 'dejavu serif',
99 | 'freesans', 'garamond', 'georgia', 'helvetica',
100 | 'impact', 'liberation sans', 'liberation serif',
101 | 'lucida console', 'lucida serif', 'nimbus mono l',
102 | 'nimbus roman no9 l', 'nimbus sans l', 'palatino',
103 | 'times new roman', 'times', 'tahoma', 'verdana',
104 | 'cursive', 'monospace', 'sans-serif', 'serif']
105 |
106 | _font_alt = {
107 | 'arial': 0, 'bitstreamverasans': 1, 'bitstreamveraserif': 2,
108 | 'bookantiqua': 3, 'comicsansms': 4, 'couriernew': 5, 'courier': 6,
109 | 'dejavusans': 7, 'dejavusansmono': 8, 'dejavuserif': 9,
110 | 'freesans': 10, 'garamond': 11, 'georgia': 12, 'helvetica': 13,
111 | 'impact': 14, 'liberationsans': 15, 'liberationserif': 16,
112 | 'lucidaconsole': 17, 'lucidaserif': 18, 'nimbusmonol': 19,
113 | 'nimbusromanno9l': 20, 'nimbussansl': 21, 'palatino': 22,
114 | 'timesnewroman': 23, 'times': 24, 'tahoma': 25, 'verdana': 26,
115 | 'cursive': 27, 'monospace': 28, 'sansserif': 29, 'serif': 30}
116 |
117 | _font_family = [
118 | ['arial', 'helvetica', 'liberation sans', 'nimbus sans l',
119 | 'freesans', 'tahoma', 'sans-serif'],
120 | ['verdana', 'bitstream vera sans', 'dejavu sans', 'sans-serif'],
121 | ['impact', 'sans-serif'],
122 | ['comic sans ms', 'cursive', 'sans-serif'],
123 | ['courier new', 'courier', 'lucida console',
124 | 'dejavu sans mono', 'monospace'],
125 | ['times new roman', 'times', 'liberation serif',
126 | 'nimbus roman no9 l', 'serif'],
127 | ['garamond', 'book antiqua', 'palatino',
128 | 'liberation serif', 'nimbus roman no9 l', 'serif'],
129 | ['georgia', 'bitstream vera serif', 'lucida serif',
130 | 'liberation serif', 'dejavu serif', 'serif']]
131 |
132 | def __init__(self, name, size):
133 | """
134 | Return Font object.
135 |
136 | Arguments include name of a font and size of font. The name argument can be a string of comma-delimited names to specify fallbacks and use a default font if none found. A font can be loaded from a filename 'fontname.ext' that was set in a css file; note: load process may be delayed a frame.
137 |
138 | Example of font file declaration:
139 |
140 | # Add css file link to app.html section:
141 |
142 |
143 | # Add font-face to app.css:
144 | # (note:font-family is lowercase filename w/o ext)
145 | @font-face {
146 | font-family: 'freesansbold';
147 | src: url('freesansbold.ttf');
148 | }
149 | """
150 | if not name:
151 | font = [Font._font[0]]
152 | else:
153 | font = [fn.strip().lower() for fn in name.split(',')]
154 | load_custom_font = False
155 | fallback = None
156 | for i, fn in enumerate(font):
157 | if '.' in fn:
158 | fn = fn.split('.')[0]
159 | font[i] = fn
160 | load_custom_font = True
161 | if fn in Font._font:
162 | if not fallback:
163 | fallback = fn
164 | else:
165 | f = ''.join(c for c in fn if c.isalnum())
166 | if f in Font._font_alt:
167 | font[i] = Font._font[Font._font_alt[f]]
168 | if not fallback:
169 | fallback = font[i]
170 | if fallback:
171 | for ff in Font._font_family:
172 | if fallback in ff:
173 | font.extend(f for f in ff if f not in font)
174 | break
175 | else:
176 | font.extend(Font._font_family[0])
177 | self.fontname = ','.join(font)
178 | self.fontsize = size
179 | self.bold = ''
180 | self.italic = ''
181 | self.fontstyle = self.bold + ' ' + self.italic
182 | self.underline = False
183 | self.char_size = None
184 | if load_custom_font:
185 | self.render('x')
186 | self._nonimplemented_methods()
187 |
188 | def __str__(self):
189 | return "%s(%r)" % (self.__class__, self.__dict__)
190 |
191 | def __repr__(self):
192 | return "%s(%r)" % (self.__class__, self.__dict__)
193 |
194 | def render(self, text, antialias=True, color=(0,0,0),
195 | background=None, surface=None): #optional surface for text rendering
196 | """
197 | Render text onto surface.
198 |
199 | Arguments are text to render, and optional antialias, RGB color of text, RGB color of background, and surface for text rendering.
200 | """
201 | if not surface:
202 | w,h = self.size(text)
203 | surf = Surface((w,h))
204 | else:
205 | surf = surface
206 | w,h = surface.width, surface.height
207 | if background:
208 | surf.setFillStyle(Color(background))
209 | surf.fillRect(0,0,w,h)
210 | surf.setFont('%s %dpx %s' % (self.fontstyle,
211 | self.fontsize,
212 | self.fontname))
213 | # if antialias: pass
214 | surf.setFillStyle(Color(color))
215 | surf.setTextAlign('center')
216 | surf.setTextBaseline('middle')
217 | surf.fillText(text,w/2,h/2)
218 | if self.underline:
219 | surf.setLineWidth(self.fontsize/20)
220 | surf.setStrokeStyle(Color(color))
221 | surf.beginPath()
222 | surf.moveTo(0, h*0.85)
223 | surf.lineTo(w, h*0.85)
224 | surf.stroke()
225 | return surf
226 |
227 | def size(self, text):
228 | """
229 | Return size (width, height) of rendered text.
230 | """
231 | if _surf: #>IE9 - use exception if HTML5Canvas not implemented
232 | _surf.setFont('%s %dpx %s' % (self.fontstyle,
233 | self.fontsize,
234 | self.fontname))
235 | x = _surf.measureText(text)
236 | else: #estimate
237 | x = self._size_estimate(text)
238 | if x < 1:
239 | x = 1
240 | y = int(self.fontsize * 1.2)
241 | return (x, y)
242 |
243 | def _size_estimate(self, text=None): #for browsers HTML5Canvas not implemented
244 | if not self.char_size:
245 | self.char_size = self._get_char_size()
246 | self.fontname = ','.join(Font._font_family[0])
247 | self.fontstyle = ''
248 | size = []
249 | for char in text:
250 | try:
251 | size.append(self.char_size[char] * self.fontsize)
252 | except KeyError:
253 | size.append(self.char_size['x'] * self.fontsize)
254 | x = _ceil( sum(size) )
255 | return x
256 |
257 | def set_underline(self, setting=True):
258 | """
259 | Set font underline style.
260 |
261 | Optional setting argument, default to True.
262 | """
263 | self.underline = setting
264 |
265 | def get_underline(self):
266 | """
267 | Check if font is underlined.
268 | """
269 | return self.underline
270 |
271 | def set_bold(self, setting=True):
272 | """
273 | Set font bold style.
274 |
275 | Optional setting argument, default to True.
276 | """
277 | self.bold = {True:'bold', False:''}[setting]
278 | self.fontstyle = self.bold + ' ' + self.italic
279 |
280 | def get_bold(self):
281 | """
282 | Check if font is bold.
283 | """
284 | if self.bold:
285 | return True
286 | else:
287 | return False
288 |
289 | def set_italic(self, setting=True):
290 | """
291 | Set font italic style.
292 |
293 | Optional setting argument, default to True.
294 | """
295 | self.italic = {True:'italic', False:''}[setting]
296 | self.fontstyle = self.bold + ' ' + self.italic
297 |
298 | def get_italic(self):
299 | """
300 | Check if font is italized.
301 | """
302 | if self.italic:
303 | return True
304 | else:
305 | return False
306 |
307 | def get_linesize(self):
308 | """
309 | Return linesize of font.
310 | """
311 | return int(self.fontsize*1.2)
312 |
313 | def _nonimplemented_methods(self):
314 | self.metrics = lambda *arg: []
315 | self.get_height = lambda *arg: 0
316 | self.get_ascent = lambda *arg: 0
317 | self.get_descent = lambda *arg: 0
318 |
319 | def _get_char_size(self, font=None): #for browsers HTML5Canvas not implemented
320 | if not font:
321 | return {'a': 0.6, 'b': 0.6, 'c': 0.5, 'd': 0.6, 'e': 0.6, 'f': 0.3, 'g': 0.6, 'h': 0.6, 'i': 0.2, 'j': 0.2, 'k': 0.5, 'l': 0.2, 'm': 0.8, 'n': 0.6, 'o': 0.6, 'p': 0.6, 'q': 0.6, 'r': 0.3, 's': 0.5, 't': 0.3, 'u': 0.6, 'v': 0.5, 'w': 0.7, 'x': 0.5, 'y': 0.5, 'z': 0.5, 'A': 0.7, 'B': 0.7, 'C': 0.7, 'D': 0.7, 'E': 0.7, 'F': 0.6, 'G': 0.8, 'H': 0.7, 'I': 0.3, 'J': 0.5, 'K': 0.7, 'L': 0.6, 'M': 0.8, 'N': 0.7, 'O': 0.8, 'P': 0.7, 'Q': 0.8, 'R': 0.7, 'S': 0.7, 'T': 0.6, 'U': 0.7, 'V': 0.7, 'W': 0.9, 'X': 0.7, 'Y': 0.7, 'Z': 0.6, '0': 0.6, '1': 0.6, '2': 0.6, '3': 0.6, '4': 0.6, '5': 0.6, '6': 0.6, '7': 0.6, '8': 0.6, '9': 0.6, '.': 0.3, ',': 0.3, ':': 0.3, ';': 0.3, '?': 0.6, '~': 0.6, '!': 0.3, '@': 1, '#': 0.6, '$': 0.6, '%': 0.9, '^': 0.5, '&': 0.7, '=': 0.6, '+': 0.6, '-': 0.3, '*': 0.4, '/': 0.3, '\\': 0.3, '_': 0.6, '<': 0.6, '>': 0.6, '(': 0.3, ')': 0.3, '{': 0.3, '}': 0.3, '[': 0.3, ']': 0.3, "'": 0.2, '"': 0.4, ' ': 0.3}
322 | else:
323 | fontsize = 10
324 | _surf.setFont('%dpx %s' % (fontsize, font)) #generated font='arial'
325 | char_size = {}
326 | for chrs in ('abcdefghijklmnopqrstuvwxyz',
327 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
328 | '0123456789',
329 | '.,:;?~!@#$%^&=+-*/\_<>(){}[]\'\" '):
330 | for char in chrs:
331 | char_size[char] = float(_surf.measureText(char)/fontsize)
332 | return char_size
333 |
334 |
335 | class SysFont(Font):
336 | """
337 | SysFont object.
338 | """
339 |
340 | def __init__(self, name, size, bold=False, italic=False):
341 | """
342 | Return SysFont subclassed of Font.
343 |
344 | Arguments include name of a system font and size of font, with optional bold and italic style. The name argument can be a string of comma-delimited names to specify fallbacks and use a default font if none found.
345 | """
346 | Font.__init__(self,name,size)
347 | self.bold = {True:'bold', False:''}[bold]
348 | self.italic = {True:'italic', False:''}[bold]
349 | self.fontstyle = self.bold + ' ' + self.italic
350 |
351 |
--------------------------------------------------------------------------------
/pyjsdl/image.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Image module**
6 |
7 | The module provides function to load images and convert them to surface objects.
8 | """
9 |
10 | import os
11 | from pyjsdl.surface import Surface, Surf
12 | from pyjsdl import env
13 | import pyjsdl
14 |
15 |
16 | class Image(object):
17 | """
18 | Image object.
19 | """
20 |
21 | def __init__(self):
22 | """
23 | Initialize Image module.
24 |
25 | Module initialization creates pyjsdl.image instance.
26 | """
27 | self.images = None
28 |
29 | def load(self, img_file, namehint=None):
30 | """
31 | Retrieve image from preloaded images.
32 |
33 | The img_file argument is an image URL, or an image data object whereby namehint argument is used to retrieve the image.
34 | Return the image as a Surface.
35 | """
36 | if not namehint:
37 | image = self.get_image(img_file)
38 | else:
39 | image = self.get_image(namehint)
40 | surface = self.convert_image(image)
41 | return surface
42 |
43 | def get_image(self, img_file):
44 | """
45 | Return the original image.
46 | """
47 | if self.images is None:
48 | self.images = {}
49 | for img in env.canvas.images:
50 | self.images[os.path.normpath(img)] = env.canvas.images[img]
51 | img_file = os.path.normpath(img_file)
52 | try:
53 | image = self.images[img_file]
54 | except KeyError:
55 | raise pyjsdl.error("Failed to retrieve image file %s" % img_file)
56 | return image
57 |
58 | def convert_image(self, image):
59 | """
60 | Return the image as a Surface.
61 | """
62 | if env.canvas._isCanvas:
63 | surface = Surface((image.width,image.height))
64 | surface.drawImage(image, 0, 0)
65 | else:
66 | surface = Surf(image)
67 | return surface
68 |
69 |
--------------------------------------------------------------------------------
/pyjsdl/key.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Key module**
6 |
7 | The module provides keyboard functionality.
8 | """
9 |
10 | from pyjsdl import env
11 | from pyjsdl import constants as Const
12 |
13 |
14 | class Key(object):
15 | """
16 | Key object.
17 | """
18 |
19 | def __init__(self):
20 | """
21 | Provides methods to access the key function.
22 |
23 | Module initialization creates pyjsdl.key instance.
24 | """
25 | self.keyPress = env.event.keyPress
26 | self.keyMod = env.event.keyMod
27 | self.alt = Const.K_ALT
28 | self.ctrl = Const.K_CTRL
29 | self.shift = Const.K_SHIFT
30 | self._keys = {}
31 | self._nonimplemented_methods()
32 |
33 | def name(self, keycode):
34 | """
35 | Return name of key of a keycode.
36 | """
37 | if not self._keys:
38 | for keyname in dir(Const):
39 | if keyname.startswith('K_'):
40 | name = keyname.split('_')[1].lower()
41 | if len(name) != 1:
42 | self._keys[getattr(Const, keyname)] = name
43 | if keycode in self._keys:
44 | return self._keys[keycode]
45 | else:
46 | return chr(keycode)
47 |
48 | def get_mods(self):
49 | """
50 | Return int modifier keys alt|ctrl|shift.
51 | """
52 | return (self.keyMod[self.alt][self.keyPress[self.alt]] |
53 | self.keyMod[self.ctrl][self.keyPress[self.ctrl]] |
54 | self.keyMod[self.shift][self.keyPress[self.shift]])
55 |
56 | def set_repeat(self, delay=0, interval=0):
57 | """
58 | Set key repeat.
59 |
60 | Set key repeat delay (ms) and interval (ms) settings.
61 | Key repeat initially disabled.
62 | """
63 | if delay < 0 or interval < 0:
64 | raise ValueError('repeat settings must be positive integers')
65 | if not delay:
66 | env.event.keyRepeat[0] = 0
67 | env.event.keyRepeat[1] = 0
68 | else:
69 | env.event.keyRepeat[0] = delay
70 | if interval:
71 | env.event.keyRepeat[1] = interval
72 | else:
73 | env.event.keyRepeat[1] = delay
74 | return None
75 |
76 | def get_repeat(self):
77 | """
78 | Get key repeat settings.
79 | """
80 | return env.event.keyRepeat
81 |
82 | def _nonimplemented_methods(self):
83 | self.get_focused = lambda *arg: None
84 | self.get_pressed = lambda *arg: None
85 | self.set_mods = lambda *arg: None
86 |
87 |
88 | _code = {'Backquote':Const.K_BACKQUOTE, 'Backslash':Const.K_BACKSLASH,
89 | 'Backspace':Const.K_BACKSPACE, 'BracketLeft':Const.K_LEFTBRACKET,
90 | 'BracketRight':Const.K_RIGHTBRACKET, 'Comma':Const.K_COMMA,
91 | 'Digit0':Const.K_0, 'Digit1':Const.K_1, 'Digit2':Const.K_2,
92 | 'Digit3':Const.K_3, 'Digit4':Const.K_4, 'Digit5':Const.K_5,
93 | 'Digit6':Const.K_6, 'Digit7':Const.K_7, 'Digit8':Const.K_8,
94 | 'Digit9':Const.K_8, 'Equal':Const.K_EQUALS,
95 | 'KeyA':Const.K_a, 'KeyB':Const.K_b, 'KeyC':Const.K_c,
96 | 'KeyD':Const.K_d, 'KeyE':Const.K_e, 'KeyF':Const.K_f,
97 | 'KeyG':Const.K_g, 'KeyH':Const.K_h, 'KeyI':Const.K_i,
98 | 'KeyJ':Const.K_j, 'KeyK':Const.K_k, 'KeyL':Const.K_l,
99 | 'KeyM':Const.K_m, 'KeyN':Const.K_n, 'KeyO':Const.K_o,
100 | 'KeyP':Const.K_p, 'KeyQ':Const.K_q, 'KeyR':Const.K_r,
101 | 'KeyS':Const.K_s, 'KeyT':Const.K_t, 'KeyU':Const.K_u,
102 | 'KeyV':Const.K_v, 'KeyW':Const.K_w, 'KeyX':Const.K_x,
103 | 'KeyY':Const.K_y, 'KeyZ':Const.K_z, 'Minus':Const.K_MINUS,
104 | 'Period':Const.K_PERIOD, 'Quote':Const.K_QUOTE,
105 | 'Semicolon':Const.K_SEMICOLON, 'Slash':Const.K_SLASH,
106 | 'AltLeft':Const.K_LALT, 'AltRight':Const.K_RALT,
107 | 'CapsLock':Const.K_CAPSLOCK, 'ContextMenu':Const.K_MENU,
108 | 'ControlLeft':Const.K_LCTRL, 'ControlRight':Const.K_RCTRL,
109 | 'Enter':Const.K_RETURN, 'MetaLeft':Const.K_LMETA,
110 | 'MetaRight':Const.K_RMETA, 'ShiftLeft':Const.K_LSHIFT,
111 | 'ShiftRight':Const.K_RSHIFT, 'Space':Const.K_SPACE,
112 | 'Tab':Const.K_TAB, 'Delete':Const.K_DELETE, 'End':Const.K_END,
113 | 'Help':Const.K_HELP, 'Home':Const.K_HOME, 'Insert':Const.K_INSERT,
114 | 'PageDown':Const.K_PAGEDOWN, 'PageUp':Const.K_PAGEUP,
115 | 'ArrowDown':Const.K_DOWN, 'ArrowLeft':Const.K_LEFT,
116 | 'ArrowRight':Const.K_RIGHT, 'ArrowUp':Const.K_UP,
117 | 'NumLock':Const.K_NUMLOCK, 'Numpad0':Const.K_KP0,
118 | 'Numpad1':Const.K_KP1, 'Numpad2':Const.K_KP2,
119 | 'Numpad3':Const.K_KP3, 'Numpad4':Const.K_KP4,
120 | 'Numpad5':Const.K_KP5, 'Numpad6':Const.K_KP6,
121 | 'Numpad7':Const.K_KP7, 'Numpad8':Const.K_KP8,
122 | 'Numpad9':Const.K_KP9, 'NumpadAdd':Const.K_KP_PLUS,
123 | 'NumpadDecimal':Const.K_KP_PERIOD, 'NumpadDivide':Const.K_KP_DIVIDE,
124 | 'NumpadEnter':Const.K_KP_ENTER, 'NumpadEqual':Const.K_KP_EQUALS,
125 | 'NumpadMultiply':Const.K_KP_MULTIPLY, 'NumpadSubtract':Const.K_KP_MINUS,
126 | 'F1':Const.K_F1, 'F2':Const.K_F2, 'F3':Const.K_F3,
127 | 'F4':Const.K_F4, 'F5':Const.K_F5, 'F6':Const.K_F6,
128 | 'F7':Const.K_F7, 'F8':Const.K_F8, 'F9':Const.K_F9,
129 | 'F10':Const.K_F10, 'F11':Const.K_F11, 'F12':Const.K_F12,
130 | 'PrintScreen':Const.K_PRINT, 'ScrollLock':Const.K_SCROLLOCK,
131 | 'Pause':Const.K_PAUSE, 'Escape':Const.K_ESCAPE,
132 | 'Unidentified':Const.K_UNKNOWN}
133 |
134 | _modKey = {'Alt':Const.K_ALT , 'Control':Const.K_CTRL, 'Shift':Const.K_SHIFT}
135 |
136 | _modKeyCode = {Const.K_ALT, Const.K_CTRL, Const.K_SHIFT}
137 |
138 | _specialKey = {'ArrowUp':Const.K_UP, 'ArrowDown':Const.K_DOWN,
139 | 'ArrowLeft':Const.K_LEFT, 'ArrowRight':Const.K_RIGHT,
140 | 'Up':Const.K_UP, 'Down':Const.K_DOWN,
141 | 'Left':Const.K_LEFT, 'Right':Const.K_RIGHT,
142 | 'Home':Const.K_HOME, 'End':Const.K_END,
143 | 'PageUp':Const.K_PAGEUP, 'PageDown':Const.K_PAGEDOWN,
144 | 'Backspace':Const.K_BACKSPACE, 'Delete':Const.K_DELETE,
145 | 'Insert':Const.K_INSERT, 'Clear':Const.K_CLEAR,
146 | 'Escape':Const.K_ESCAPE, 'Esc':Const.K_ESCAPE,
147 | 'CapsLock':Const.K_CAPSLOCK, 'Meta':Const.K_LMETA,
148 | 'ContextMenu':Const.K_MENU, 'PrintScreen':Const.K_PRINT,
149 | 'ScrollLock':Const.K_SCROLLLOCK, 'Pause':Const.K_PAUSE,
150 | 'NumLock':Const.K_NUMLOCK,
151 | 'F1':Const.K_F1, 'F2':Const.K_F2, 'F3':Const.K_F3,
152 | 'F4':Const.K_F4, 'F5':Const.K_F5, 'F6':Const.K_F6,
153 | 'F7':Const.K_F7, 'F8':Const.K_F8, 'F9':Const.K_F9,
154 | 'F10':Const.K_F10, 'F11':Const.K_F11, 'F12':Const.K_F12,
155 | 'Alt':Const.K_ALT , 'Control':Const.K_CTRL, 'Shift':Const.K_SHIFT}
156 |
157 | _specialKeyCode = {38:Const.K_UP, 40:Const.K_DOWN,
158 | 37:Const.K_LEFT, 39:Const.K_RIGHT,
159 | 36:Const.K_HOME, 35:Const.K_END,
160 | 33:Const.K_PAGEUP, 34:Const.K_PAGEDOWN,
161 | 8:Const.K_BACKSPACE, 46:Const.K_DELETE,
162 | 45:Const.K_INSERT, 12:Const.K_CLEAR,
163 | 13:Const.K_RETURN, 9:Const.K_TAB,
164 | 27:Const.K_ESCAPE, 20:Const.K_CAPSLOCK,
165 | 92:Const.K_LMETA, 93:Const.K_MENU,
166 | 44:Const.K_PRINT, 145:Const.K_SCROLLLOCK,
167 | 19:Const.K_PAUSE, 144:Const.K_NUMLOCK,
168 | 112:Const.K_F1, 113:Const.K_F2, 114:Const.K_F3,
169 | 115:Const.K_F4, 116:Const.K_F5, 117:Const.K_F6,
170 | 118:Const.K_F7, 119:Const.K_F8, 120:Const.K_F9,
171 | 121:Const.K_F10, 122:Const.K_F11, 123:Const.K_F12,
172 | 18:Const.K_ALT, 17:Const.K_CTRL, 16:Const.K_SHIFT}
173 |
174 |
--------------------------------------------------------------------------------
/pyjsdl/mask.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Mask module**
6 |
7 | The module provides surface mask functionality.
8 | """
9 |
10 | from pyjsdl.pyjsarray import BitSet
11 | from pyjsdl.color import Color
12 | import sys
13 |
14 | if sys.version_info < (3,):
15 | from pyjsdl.util import _range as range
16 |
17 |
18 | def from_surface(surface, threshold=127):
19 | """
20 | Mask from surface.
21 |
22 | Return Mask derived from surface using alpha transparency.
23 | Optional argument to set alpha threshold.
24 | """
25 | mask = Mask((surface.width, surface.height))
26 | if not mask.bit:
27 | return None
28 | pixels = surface.impl.getImageData(0, 0, surface.width, surface.height)
29 | width, height = surface.width*4, surface.height
30 | for y in range(0, height):
31 | xpix = 0
32 | i = (y*width)+3
33 | for x in range(0, width, 4):
34 | if surface._getPixel(pixels, i+x) > threshold:
35 | mask.set_at((xpix,y))
36 | xpix += 1
37 | return mask
38 |
39 |
40 | def from_threshold(surface, color, threshold=(0,0,0,255)):
41 | """
42 | Mask from surface.
43 |
44 | Return Mask from surface using a given color.
45 | Optional threshold argument to set color range and alpha threshold.
46 | """
47 | mask = Mask((surface.width, surface.height))
48 | if not mask.bit:
49 | return None
50 | pixels = surface.impl.getImageData(0, 0, surface.width, surface.height)
51 | if threshold == (0,0,0,255):
52 | color = Color(color)
53 | color = (color.r,color.g,color.b)
54 | width, height = surface.width*4, surface.height
55 | for y in range(0, height):
56 | xpix = 0
57 | i = y*width
58 | for x in range(0, width, 4):
59 | ix = i+x
60 | if (surface._getPixel(pixels, ix) == color[0] and
61 | surface._getPixel(pixels, ix+1) == color[1] and
62 | surface._getPixel(pixels, ix+2) == color[2] and
63 | surface._getPixel(pixels, ix+3) >= threshold[3]):
64 | mask.set_at((xpix,y))
65 | xpix += 1
66 | else:
67 | color = Color(color)
68 | col = {}
69 | for i, c in enumerate(('r','g','b')):
70 | if threshold[i]:
71 | col[c+'1'] = color[i] - threshold[i] - 1
72 | col[c+'2'] = color[i] + threshold[i] + 1
73 | else:
74 | col[c+'1'] = color[i] - 1
75 | col[c+'2'] = color[i] + 1
76 | col['a'] = threshold[3] - 1
77 | width, height = surface.width*4, surface.height
78 | for y in range(0, height):
79 | xpix = 0
80 | i = y*width
81 | for x in range(0, width, 4):
82 | ix = i+x
83 | if ((col['r1'] < surface._getPixel(pixels, ix) < col['r2']) and
84 | (col['g1'] < surface._getPixel(pixels, ix+1) < col['g2']) and
85 | (col['b1'] < surface._getPixel(pixels, ix+2) < col['b2']) and
86 | (surface._getPixel(pixels, ix+3) > col['a'])):
87 | mask.set_at((xpix,y))
88 | xpix += 1
89 | return mask
90 |
91 |
92 | class Mask(object):
93 | """
94 | Mask object.
95 | """
96 |
97 | def __init__(self, size):
98 | """
99 | Initialize Mask object.
100 |
101 | The size argument is (width, height) of the mask.
102 | The mask is represented by a list of Bitset.
103 | """
104 | self.width = int(size[0])
105 | self.height = int(size[1])
106 | self.bit = []
107 | for bitset in range(self.height):
108 | self.bit.append(BitSet(self.width))
109 |
110 | def __str__(self):
111 | return self.toString()
112 |
113 | def __repr__(self):
114 | return "%s(%r)" % (self.__class__, self.__dict__)
115 |
116 | def get_size(self):
117 | """
118 | Return width, height of mask.
119 | """
120 | return (self.width, self.height)
121 |
122 | def get_at(self, pos):
123 | """
124 | Return bit setting for given pos.
125 | """
126 | return self.bit[pos[1]].get(pos[0])
127 |
128 | def set_at(self, pos, value=1):
129 | """
130 | Set bit for given pos.
131 |
132 | Optional value to set bit, either 1 or 0, defaults to 1.
133 | """
134 | self.bit[pos[1]].set(pos[0], value)
135 | return None
136 |
137 | def fill(self):
138 | """
139 | Fill mask.
140 | """
141 | for bitset in self.bit:
142 | bitset.fill()
143 | return None
144 |
145 | def clear(self):
146 | """
147 | Clear mask.
148 | """
149 | for bitset in self.bit:
150 | bitset.clear()
151 | return None
152 |
153 | def invert(self):
154 | """
155 | Invert bit value in mask.
156 | """
157 | for bitset in self.bit:
158 | bitset.flip(0,self.width)
159 | return None
160 |
161 | def count(self):
162 | """
163 | Return count of true bits in mask.
164 | """
165 | true_bits = 0
166 | for bitset in self.bit:
167 | true_bits += bitset.cardinality()
168 | return true_bits
169 |
170 | def overlap(self, mask, offset):
171 | """
172 | Check mask overlap.
173 |
174 | Return True if mask at offset position overlap with this mask.
175 | """
176 | if offset[0] > 0:
177 | x1 = offset[0]
178 | x2 = 0
179 | else:
180 | x1 = 0
181 | x2 = -offset[0]
182 | if offset[1] > 0:
183 | y1 = offset[1]
184 | y2 = 0
185 | else:
186 | y1 = 0
187 | y2 = -offset[1]
188 | w = min(self.width-x1, mask.width-x2)
189 | h = min(self.height-y1, mask.height-y2)
190 | if w > 0 and h > 0:
191 | for y in range(h):
192 | if self.bit[y1+y].get(x1, x1+w).intersects(
193 | mask.bit[y2+y].get(x2, x2+w)):
194 | return True
195 | return None
196 |
197 | def toString(self, bit=('1','0')):
198 | """
199 | Return string representation of mask.
200 |
201 | Optional bit argument specify bit character.
202 | """
203 | cbit = {True:bit[0], False:bit[1]}
204 | cbitset = []
205 | for bitset in self.bit:
206 | cbitset.append('\n')
207 | cbitset.extend([cbit[bitset.get(i)]
208 | for i in range(self.width)])
209 | bitstr = ''.join(cbitset)
210 | return bitstr
211 |
212 |
--------------------------------------------------------------------------------
/pyjsdl/mouse.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Mouse module**
6 |
7 | The module provides mouse functionality.
8 | """
9 |
10 | from pyjsdl import env
11 | from pyjsdl import cursors
12 | from pyjsdl.pyjsobj import DOM
13 |
14 |
15 | class Mouse(object):
16 | """
17 | Mouse object.
18 | """
19 |
20 | def __init__(self):
21 | """
22 | Provides methods to access the mouse function.
23 |
24 | Module initialization creates pyjsdl.mouse instance.
25 | """
26 | self.mousePos = env.event.mousePos
27 | self.mousePosPre = env.event.mousePosPre
28 | self.mousePosRel = env.event.mousePosRel
29 | self.mousePress = env.event.mousePress
30 | self._cursorVisible = True
31 | self._cursor = 'default'
32 | self._nonimplemented_methods()
33 |
34 | def get_pressed(self):
35 | """
36 | Return state of mouse buttons as a tuple of bool for button1,2,3.
37 | """
38 | return (self.mousePress[0],
39 | self.mousePress[1],
40 | self.mousePress[2])
41 |
42 | def get_pos(self):
43 | """
44 | Return x,y of mouse pointer.
45 |
46 | If the pointer is not in canvas, returns -1,-1
47 | """
48 | if self.mousePos['x'] != -1:
49 | return (self.mousePos['x'] + env.frame.scrollLeft,
50 | self.mousePos['y'] + env.frame.scrollTop)
51 | else:
52 | return (self.mousePos['x'], self.mousePos['y'])
53 |
54 | def get_rel(self):
55 | """
56 | Return relative x,y change of mouse position since last call.
57 | """
58 | if self.mousePos['x'] != -1:
59 | rel = (self.mousePos['x'] - self.mousePosRel['x'],
60 | self.mousePos['y'] - self.mousePosRel['y'])
61 | self.mousePosRel['x'] = self.mousePos['x']
62 | self.mousePosRel['y'] = self.mousePos['y']
63 | return rel
64 | else:
65 | return (0, 0)
66 |
67 | def set_visible(self, visible):
68 | """
69 | Set mouse cursor visibility according to visible bool argument.
70 |
71 | Return previous cursor visibility state.
72 | """
73 | visible_pre = self._cursorVisible
74 | if visible:
75 | DOM.setStyleAttribute(env.canvas.getElement(),
76 | 'cursor', self._cursor)
77 | self._cursorVisible = True
78 | else:
79 | DOM.setStyleAttribute(env.canvas.getElement(),
80 | 'cursor', 'none')
81 | self._cursorVisible = False
82 | return visible_pre
83 |
84 | def get_focused(self):
85 | """
86 | Check if mouse has focus.
87 | """
88 | return self.mousePos['x'] != -1
89 |
90 | def set_cursor(self, *cursor):
91 | """
92 | Set mouse cursor.
93 |
94 | Alternative arguments:
95 | * system cursor or cursor object
96 | * image url or surface, hotspot (x,y), and optional fallback
97 | * size, hotspot, data, mask, and optional fallback
98 | Refer to cursors module for details.
99 | """
100 | args = len(cursor)
101 | if args == 1:
102 | self._cursor = cursor[0]
103 | elif args in (2,3):
104 | if isinstance(cursor[0], str):
105 | url = cursor[0]
106 | else:
107 | url = cursor[0].toDataURL()
108 | hotspot = cursor[1]
109 | if args == 2:
110 | fallback = 'default'
111 | else:
112 | fallback = cursor[2]
113 | self._cursor = 'url("%s") %d %d, %s' % (url,
114 | hotspot[0],
115 | hotspot[1],
116 | fallback)
117 | elif args in (4,5):
118 | size = cursor[0]
119 | hotspot = cursor[1]
120 | data = cursor[2]
121 | mask = cursor[3]
122 | if args == 4:
123 | fallback = 'default'
124 | else:
125 | fallback = cursor[4]
126 | surface = cursors.create_cursor(size, data, mask)
127 | url = surface.toDataURL()
128 | self._cursor = 'url("%s") %d %d, %s' % (url,
129 | hotspot[0],
130 | hotspot[1],
131 | fallback)
132 | else:
133 | self._cursor = 'default'
134 | if self._cursorVisible:
135 | DOM.setStyleAttribute(env.canvas.getElement(),
136 | 'cursor', self._cursor)
137 |
138 | def get_cursor(self):
139 | """
140 | Return cursor object.
141 | """
142 | return self._cursor
143 |
144 | def _nonimplemented_methods(self):
145 | self.set_pos = lambda *arg: None
146 |
147 |
--------------------------------------------------------------------------------
/pyjsdl/pyjsobj.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Pyjsobj module**
6 |
7 | The module provides JavaScript functionality.
8 | """
9 |
10 | from pyjamas import DOM
11 | from pyjamas import Window
12 | from pyjamas.ui.RootPanel import RootPanel
13 | from pyjamas.ui.FocusPanel import SimplePanel
14 | from pyjamas.ui.VerticalPanel import VerticalPanel
15 | from pyjamas.Canvas.Color import Color
16 | from pyjamas.Canvas.ImageLoader import loadImages
17 | from pyjamas.ui.TextBox import TextBox
18 | from pyjamas.ui.TextArea import TextArea
19 | from pyjamas.ui import Event
20 | from pyjamas.Canvas.HTML5Canvas import HTML5Canvas as _HTML5Canvas
21 | from pyjamas.media.Audio import Audio
22 | from __pyjamas__ import JS, doc, wnd
23 |
24 |
25 | class MouseWheelHandler(object):
26 |
27 | _listener = {}
28 |
29 | def __init__(self):
30 | element = self.getElement()
31 | if hasattr(element, 'onwheel'):
32 | self._mousewheel = 'wheel'
33 | elif hasattr(element, 'onmousewheel'):
34 | self._mousewheel = 'mousewheel'
35 | else:
36 | self._mousewheel = 'DOMMouseScroll'
37 |
38 | def addMouseWheelListener(self):
39 | element = self.getElement()
40 | listener = lambda event: self.onMouseWheel(event)
41 | self._listener[self] = listener
42 | element.addEventListener(self._mousewheel, listener)
43 |
44 | def removeMouseWheelListener(self):
45 | element = self.getElement()
46 | listener = self._listener[self]
47 | del self._listener[self]
48 | element.removeEventListener(self._mousewheel, listener)
49 |
50 | def onMouseWheel(self, event):
51 | pass
52 |
53 |
54 | class VisibilityChangeHandler(object):
55 |
56 | _listener = {}
57 |
58 | def __init__(self):
59 | self._visibilitychange = 'visibilitychange'
60 | self._pagehide = 'pagehide'
61 | wnd().onunload = None
62 | wnd().onbeforeunload = None
63 |
64 | def addVisibilityChangeListener(self):
65 | listener = lambda event: self.onVisibilityChange(event)
66 | self._listener[self._visibilitychange] = listener
67 | doc().addEventListener(self._visibilitychange, listener)
68 |
69 | def removeVisibilityChangeListener(self):
70 | listener = self._listener[self._visibilitychange]
71 | del self._listener[self._visibilitychange]
72 | doc().removeEventListener(self._visibilitychange, listener)
73 |
74 | def addPageHideListener(self):
75 | listener = lambda event: self.onPageHide(event)
76 | self._listener[self._pagehide] = listener
77 | wnd().addEventListener(self._pagehide, listener)
78 |
79 | def removePageHideListener(self):
80 | listener = self._listener[self._pagehide]
81 | del self._listener[self._pagehide]
82 | wnd().removeEventListener(self._pagehide, listener)
83 |
84 | def onVisibilityChange(self, event):
85 | pass
86 |
87 | def onPageHide(self, event):
88 | pass
89 |
90 |
91 | class HTML5Canvas(_HTML5Canvas, MouseWheelHandler, VisibilityChangeHandler):
92 |
93 | def __init__(self, coordX, coordY, *args, **kwargs):
94 | _HTML5Canvas.__init__(self, coordX, coordY, *args, **kwargs)
95 | MouseWheelHandler.__init__(self)
96 | VisibilityChangeHandler.__init__(self)
97 |
98 | def addMouseListener(self, listener):
99 | _HTML5Canvas.addMouseListener(self, listener)
100 | self.addMouseWheelListener()
101 |
102 | def addKeyEventListener(self, obj):
103 | element = obj.getElement()
104 | element.setAttribute('tabindex','0')
105 | listener = lambda event: self.onKeyEvent(event)
106 | _listener[self] = listener
107 | element.addEventListener('keydown', listener)
108 |
109 | def removeKeyEventListener(self, obj):
110 | element = obj.getElement()
111 | listener = _listener[self]
112 | del _listener[self]
113 | element.removeEventListener('keydown', listener)
114 |
115 |
116 | _listener = {}
117 |
118 |
119 | def set_icon(icon):
120 | if hasattr(icon, 'canvas'):
121 | icon = icon.canvas.toDataURL()
122 | obj = JS('parent.document')
123 | link = obj.querySelector("link[rel~='icon']")
124 | if not link:
125 | link = obj.createElement('link')
126 | link.rel = 'icon'
127 | obj.head.appendChild(link)
128 | link.href = icon
129 |
130 |
131 | class Document(object):
132 |
133 | def getVisibility(self):
134 | return doc().hidden
135 |
136 | document = Document()
137 |
138 |
139 | def requestAnimationFrameInit():
140 | requestAnimationFramePolyfill()
141 | return wnd()
142 |
143 |
144 | def performanceNowInit():
145 | performanceNowPolyfill()
146 | return wnd()
147 |
148 |
149 | def requestAnimationFramePolyfill():
150 | JS(
151 | """
152 | // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
153 | // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
154 |
155 | // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
156 |
157 | // MIT license
158 |
159 | (function() {
160 | var lastTime = 0;
161 | var vendors = ['ms', 'moz', 'webkit', 'o'];
162 | for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
163 | window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
164 | window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
165 | || window[vendors[x]+'CancelRequestAnimationFrame'];
166 | }
167 |
168 | if (!window.requestAnimationFrame)
169 | window.requestAnimationFrame = function(callback, element) {
170 | var currTime = new Date().getTime();
171 | var timeToCall = Math.max(0, 16 - (currTime - lastTime));
172 | var id = window.setTimeout(function() { callback(currTime + timeToCall); },
173 | timeToCall);
174 | lastTime = currTime + timeToCall;
175 | return id;
176 | };
177 |
178 | if (!window.cancelAnimationFrame)
179 | window.cancelAnimationFrame = function(id) {
180 | clearTimeout(id);
181 | };
182 | }());
183 | """
184 | )
185 |
186 |
187 | def performanceNowPolyfill():
188 | JS(
189 | """
190 | // @license http://opensource.org/licenses/MIT
191 | // copyright Paul Irish 2015
192 |
193 |
194 | // Date.now() is supported everywhere except IE8. For IE8 we use the Date.now polyfill
195 | // github.com/Financial-Times/polyfill-service/blob/master/polyfills/Date.now/polyfill.js
196 | // as Safari 6 doesn't have support for NavigationTiming, we use a Date.now() timestamp for relative values
197 |
198 | // if you want values similar to what you'd get with real perf.now, place this towards the head of the page
199 | // but in reality, you're just getting the delta between now() calls, so it's not terribly important where it's placed
200 |
201 |
202 | (function(){
203 |
204 | if ("performance" in window == false) {
205 | window.performance = {};
206 | }
207 |
208 | Date.now = (Date.now || function () { // thanks IE8
209 | return new Date().getTime();
210 | });
211 |
212 | if ("now" in window.performance == false){
213 |
214 | var nowOffset = Date.now();
215 |
216 | if (performance.timing && performance.timing.navigationStart){
217 | nowOffset = performance.timing.navigationStart
218 | }
219 |
220 | window.performance.now = function now(){
221 | return Date.now() - nowOffset;
222 | }
223 | }
224 |
225 | })();
226 | """
227 | )
228 |
229 |
--------------------------------------------------------------------------------
/pyjsdl/surfarray.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Surfarray module**
6 |
7 | The module provides array access to surface pixel data.
8 | """
9 |
10 | from pyjsdl.surface import Surface
11 | from pyjsdl.pyjsarray import Ndarray
12 | from pyjsdl.pyjsarray import Uint8ClampedArray
13 | from pyjsdl.pyjsarray import Uint8Array
14 | from pyjsdl.pyjsarray import Uint32Array
15 | from pyjsdl.pyjsarray import ImageData
16 | from pyjsdl.pyjsarray import ImageMatrix
17 | import sys
18 |
19 | if sys.version_info < (3,):
20 | from pyjsdl.util import _range as range
21 |
22 |
23 | def array(surface):
24 | """
25 | Return data array of the Surface argument.
26 |
27 | Array consists of pixel data arranged by [y,x] in RGBA format.
28 | Data array most consistent to ImageData format.
29 | """
30 | imagedata = surface.impl.getImageData(0, 0, surface.width, surface.height)
31 | return ImageMatrix(imagedata)
32 |
33 |
34 | def array2d(surface, copydata=False):
35 | """
36 | Return data array of the Surface argument.
37 |
38 | Array consists of pixel data arranged by [x,y] in integer color format.
39 | Provides an interface to ImageData format.
40 | Creates a new formatted array if optional copydata argument is True.
41 | """
42 | imagedata = surface.impl.getImageData(0, 0, surface.width, surface.height)
43 | if not copydata:
44 | return ImageMatrixInteger(imagedata)
45 | else:
46 | return ImageInteger(imagedata)
47 |
48 |
49 | def array3d(surface, copydata=False):
50 | """
51 | Return data array of the Surface argument.
52 |
53 | Array consists of pixel data arranged by [x,y] in RGB format.
54 | Provides an interface to ImageData format.
55 | Creates a new formatted array if optional copydata argument is True.
56 | """
57 | imagedata = surface.impl.getImageData(0, 0, surface.width, surface.height)
58 | if not copydata:
59 | return ImageMatrixRGB(imagedata)
60 | else:
61 | return ImageRGB(imagedata)
62 |
63 |
64 | def array_alpha(surface, copydata=False):
65 | """
66 | Return data array of the Surface argument.
67 |
68 | Array consists of pixel data arranged by [x,y] of pixel alpha value.
69 | Provides an interface to ImageData format.
70 | Creates a new formatted array if optional copydata argument is True.
71 | """
72 | imagedata = surface.impl.getImageData(0, 0, surface.width, surface.height)
73 | if not copydata:
74 | return ImageMatrixAlpha(imagedata)
75 | else:
76 | return ImageAlpha(imagedata)
77 |
78 |
79 | def make_surface(array):
80 | """
81 | Generates image pixels from array data.
82 |
83 | Argument array containing image data.
84 | Return Surface generated from array.
85 | """
86 | surface = Surface((array._imagedata.width,array._imagedata.height))
87 | blit_array(surface, array)
88 | return surface
89 |
90 |
91 | def blit_array(surface, array):
92 | """
93 | Generates image pixels from array data.
94 |
95 | Arguments include destination Surface and array containing image data.
96 | """
97 | try:
98 | imagedata = array.getImageData()
99 | except (TypeError, AttributeError):
100 | imagedata = surface.impl.getImageData(0, 0, surface.width, surface.height)
101 | if len(array._shape) == 2:
102 | array2d = ImageMatrix(imagedata)
103 | for y in range(array2d.getHeight()):
104 | for x in range(array2d.getWidth()):
105 | value = array[x,y]
106 | array2d[y,x] = (value>>16 & 0xff,
107 | value>>8 & 0xff,
108 | value & 0xff,
109 | 255)
110 | imagedata = array2d.getImageData()
111 | else:
112 | imagedata.data.set(array.getArray())
113 | surface.impl.putImageData(imagedata, 0, 0, 0, 0, surface.width, surface.height)
114 | return None
115 |
116 |
117 | class ImageMatrixRGB(ImageMatrix):
118 | """
119 | Array of pixel data arranged by width/height in RGB format.
120 |
121 | Interface to ImageData.
122 | """
123 |
124 | shape = ImageMatrix.shape
125 |
126 | def __getitem__(self, index):
127 | index = list(index)
128 | index[0], index[1] = index[1], index[0]
129 | index = tuple(index)
130 | return ImageMatrix.__getitem__(self, index)
131 |
132 | def __setitem__(self, index, value):
133 | index = list(index)
134 | index[0], index[1] = index[1], index[0]
135 | index = tuple(index)
136 | ImageMatrix.__setitem__(self, index, value)
137 | return None
138 |
139 |
140 | class ImageRGB(Ndarray):
141 | """
142 | Array of pixel data arranged by width/height in RGB format.
143 |
144 | Array data derived from ImageData.
145 | """
146 |
147 | def __init__(self, imagedata):
148 | self._imagedata = ImageData(imagedata)
149 | array = Ndarray(self._imagedata.data)
150 | array.setshape(self._imagedata.height, self._imagedata.width, 4)
151 | try:
152 | data = Uint8ClampedArray(self._imagedata.height
153 | * self._imagedata.width * 3)
154 | except NotImplementedError:
155 | data = Uint8Array(self._imagedata.height
156 | * self._imagedata.width * 3)
157 | index = 0
158 | for x in range(self._imagedata.width):
159 | for y in range(self._imagedata.height):
160 | for i in range(3):
161 | data[index] = array[y, x, i]
162 | index += 1
163 | try:
164 | Ndarray.__init__(self, data, 'uint8c')
165 | except NotImplementedError:
166 | Ndarray.__init__(self, data, 'uint8')
167 | self.setshape(self._imagedata.width, self._imagedata.height, 3)
168 |
169 | shape = Ndarray.shape
170 |
171 | def getImageData(self):
172 | """
173 | Get ImageData.
174 | """
175 | index = 0
176 | for x in range(self._imagedata.height):
177 | for y in range(self._imagedata.width):
178 | for i in range(3):
179 | self._imagedata.data[index + i] = self[y, x, i]
180 | index += 4
181 | return self._imagedata.getImageData()
182 |
183 |
184 | class ImageMatrixAlpha(ImageMatrix):
185 | """
186 | Array of pixel data arranged by width/height of pixel alpha value.
187 |
188 | Interface to ImageData.
189 | """
190 |
191 | shape = ImageMatrix.shape
192 |
193 | def __getitem__(self, index):
194 | return ImageMatrix.__getitem__(self, (index[1], index[0], 3))
195 |
196 | def __setitem__(self, index, value):
197 | ImageMatrix.__setitem__(self, (index[1], index[0], 3), value)
198 | return None
199 |
200 |
201 | class ImageAlpha(Ndarray):
202 | """
203 | Array of pixel data arranged by width/height of pixel alpha value.
204 |
205 | Array data derived from ImageData.
206 | """
207 |
208 | def __init__(self, imagedata):
209 | self._imagedata = ImageData(imagedata)
210 | array = Ndarray(self._imagedata.data)
211 | array.setshape(self._imagedata.height, self._imagedata.width, 4)
212 | try:
213 | data = Uint8ClampedArray(self._imagedata.height
214 | * self._imagedata.width)
215 | except NotImplementedError:
216 | data = Uint8Array(self._imagedata.height
217 | * self._imagedata.width)
218 | index = 0
219 | for x in range(self._imagedata.width):
220 | for y in range(self._imagedata.height):
221 | data[index] = array[y, x, 3]
222 | index += 1
223 | try:
224 | Ndarray.__init__(self, data, 'uint8c')
225 | except NotImplementedError:
226 | Ndarray.__init__(self, data, 'uint8')
227 | self.setshape(self._imagedata.width, self._imagedata.height)
228 |
229 | shape = Ndarray.shape
230 |
231 | def getImageData(self):
232 | """
233 | Get ImageData.
234 | """
235 | index = 0
236 | for x in range(self._imagedata.height):
237 | for y in range(self._imagedata.width):
238 | self._imagedata.data[index + 3] = self[y, x]
239 | index += 4
240 | return self._imagedata.getImageData()
241 |
242 |
243 | class ImageMatrixInteger(ImageMatrix):
244 | """
245 | Array of pixel data arranged by width/height in integer color format.
246 |
247 | Interface to ImageData.
248 | """
249 |
250 | shape = ImageMatrix.shape
251 |
252 | def __getitem__(self, index):
253 | value = ImageMatrix.__getitem__(self, (index[1], index[0]))
254 | return value[0]<<16 | value[1]<<8 | value[2] | value[3]<<24
255 |
256 | def __setitem__(self, index, value):
257 | ImageMatrix.__setitem__(self, (index[1], index[0]),
258 | (value>>16 & 0xff,
259 | value>>8 & 0xff,
260 | value & 0xff,
261 | value>>24 & 0xff))
262 | return None
263 |
264 |
265 | class ImageInteger(Ndarray):
266 | """
267 | Array of pixel data arranged by width/height in integer color format.
268 |
269 | Array data derived from ImageData.
270 | """
271 |
272 | def __init__(self, imagedata):
273 | self._imagedata = ImageData(imagedata)
274 | array = Ndarray(self._imagedata.data)
275 | array.setshape(self._imagedata.height, self._imagedata.width, 4)
276 | data = Uint32Array(self._imagedata.height
277 | * self._imagedata.width)
278 | index = 0
279 | for x in range(self._imagedata.width):
280 | for y in range(self._imagedata.height):
281 | data[index] = (array[y, x, 0] << 16 |
282 | array[y, x, 1] << 8 |
283 | array[y, x, 2] |
284 | array[y, x, 3] << 24)
285 | index += 1
286 | Ndarray.__init__(self, data, 'uint32')
287 | self.setshape(self._imagedata.width, self._imagedata.height)
288 |
289 | shape = Ndarray.shape
290 |
291 | def getImageData(self):
292 | """
293 | Get ImageData.
294 | """
295 | index = 0
296 | for x in range(self._imagedata.height):
297 | for y in range(self._imagedata.width):
298 | dat = self[y, x]
299 | self._imagedata.data[index] = dat>>16 & 0xff
300 | self._imagedata.data[index + 1] = dat>>8 & 0xff
301 | self._imagedata.data[index + 2] = dat & 0xff
302 | self._imagedata.data[index + 3] = dat>>24 & 0xff
303 | index += 4
304 | return self._imagedata.getImageData()
305 |
306 |
--------------------------------------------------------------------------------
/pyjsdl/time.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Time module**
6 |
7 | The module provides time monitoring functionality.
8 | """
9 |
10 | from pyjsdl import env
11 | from pyjsdl.pyjsobj import performanceNowInit
12 | from __pyjamas__ import JS
13 |
14 |
15 | class Clock(object):
16 | """
17 | Clock object.
18 | """
19 |
20 | _wnd = None
21 |
22 | def __init__(self):
23 | """
24 | Initialize clock object.
25 | """
26 | self._time = self.time()
27 | self._time_init = self._time
28 | self._time_diff = 0
29 | self._framerate = 0
30 |
31 | def get_time(self):
32 | """
33 | Return time (in ms) between last two calls to tick().
34 | """
35 | return self._time_diff
36 |
37 | def tick(self, framerate=0):
38 | """
39 | Call once per program cycle.
40 |
41 | An optional framerate will add pause to limit rate.
42 | Returns ms since last call.
43 | """
44 | if self._framerate != framerate and not env.canvas._pause:
45 | self._framerate = framerate
46 | if framerate:
47 | env.canvas._framerate = 1000.0 / framerate
48 | else:
49 | env.canvas._framerate = 0.0
50 | self._time = self.time()
51 | self._time_diff = self._time - self._time_init
52 | self._time_init = self._time
53 | return self._time_diff
54 |
55 | def tick_busy_loop(self, framerate=0):
56 | """
57 | Call once per program cycle.
58 |
59 | An optional framerate will add pause to limit rate.
60 | Returns ms since last call.
61 | """
62 | return self.tick(framerate)
63 |
64 | def get_fps(self):
65 | """
66 | Return fps.
67 | """
68 | if not env.canvas._pause:
69 | return 1000.0 / env.canvas._frametime
70 | else:
71 | return 0.0
72 |
73 | def time(self):
74 | """
75 | Return system time (in ms).
76 | """
77 | return self._wnd.performance.now()
78 |
79 |
80 | class Time(object):
81 | """
82 | Time object.
83 | """
84 |
85 | _wnd = None
86 |
87 | def __init__(self):
88 | """
89 | Initialize time object.
90 | """
91 | self.Clock = Clock
92 | Time._wnd = performanceNowInit()
93 | Clock._wnd = Time._wnd
94 | self._time_init = self.time()
95 | self._framerate = 0
96 | self._timers = {}
97 | self.run = lambda: self.wait()
98 |
99 | def get_ticks(self):
100 | """
101 | Get time ticks.
102 |
103 | Return ms since program start.
104 | """
105 | return self.time() - self._time_init
106 |
107 | def delay(self, time):
108 | """
109 | Time delay.
110 |
111 | Pause for given time (in ms). Return ms paused.
112 | Suspends the program, preferably use time.wait.
113 | """
114 | start = self.time()
115 | while True:
116 | if self.time() - start > time:
117 | return self.time() - start
118 |
119 | def wait(self, time=0):
120 | """
121 | Wait function.
122 |
123 | Timeout program callback for given time (in ms).
124 | """
125 | if time:
126 | if not env.canvas._pause:
127 | self._framerate = env.canvas._framerate
128 | env.canvas._framerate = time * 10
129 | env.canvas._pause = True
130 | self.set_timeout(self, time)
131 | else:
132 | if env.canvas._pause:
133 | env.canvas._framerate = self._framerate
134 | env.canvas._rendertime = self.time()
135 | env.canvas._pause = False
136 | return time
137 |
138 | def set_timer(self, event, time, once=False):
139 | """
140 | Set timer.
141 |
142 | Post event on queue at time (ms) intervals.
143 | Optional argument once set no timer repeat, defaults to False.
144 | Disable timer with time of 0.
145 | """
146 | if hasattr(event, 'type'):
147 | eventType = event.type
148 | if eventType not in self._timers:
149 | self._timers[eventType] = _EventTimer(event)
150 | else:
151 | eventType = event
152 | if eventType not in self._timers:
153 | evt = env.event.Event(eventType)
154 | self._timers[eventType] = _EventTimer(evt)
155 | repeat = not once
156 | self._timers[eventType].set_timer(time, repeat)
157 |
158 | def _stop_timers(self):
159 | for eventType in self._timers:
160 | self._timers[eventType].set_timer(0, False)
161 |
162 | def time(self):
163 | """
164 | Return system time (in ms).
165 | """
166 | return self._wnd.performance.now()
167 |
168 | def set_timeout(self, obj, time):
169 | """
170 | Set timeout.
171 |
172 | Timeout time (in ms) before triggering obj.run method.
173 | Return timer id.
174 | """
175 | run = lambda: obj.run()
176 | id = JS("$wnd['setTimeout'](@{{run}}, @{{time}});")
177 | return id
178 |
179 | def clear_timeout(self, id):
180 | """
181 | Clear timeout.
182 |
183 | Argument timer id of set_timeout.
184 | """
185 | JS("$wnd['clearTimeout'](@{{id}});")
186 | return None
187 |
188 | def set_interval(self, obj, time):
189 | """
190 | Set interval timeout.
191 |
192 | Recurring timeout time (in ms) before triggering obj.run method.
193 | Return timer id.
194 | """
195 | run = lambda: obj.run()
196 | id = JS("$wnd['setInterval'](@{{run}}, @{{time}});")
197 | return id
198 |
199 | def clear_interval(self, id):
200 | """
201 | Clear interval timeout.
202 |
203 | Argument timer id of set_interval.
204 | """
205 | JS("$wnd['clearInterval'](@{{id}});")
206 | return None
207 |
208 |
209 | class _EventTimer:
210 |
211 | def __init__(self, event):
212 | self.event = event
213 | self.timer = None
214 | self.time = 0
215 | self.repeat = True
216 |
217 | def set_timer(self, time, repeat):
218 | if self.timer:
219 | self.repeat = False
220 | self.clear_timeout()
221 | if time:
222 | self.time = time
223 | self.repeat = repeat
224 | self.set_timeout()
225 |
226 | def set_timeout(self):
227 | run = lambda: self.run()
228 | timer = JS("$wnd['setTimeout'](@{{run}}, @{{self}}['time']);")
229 | self.timer = timer
230 |
231 | def clear_timeout(self):
232 | JS("$wnd['clearTimeout'](@{{self}}['timer']);")
233 | self.timer = None
234 |
235 | def run(self):
236 | env.event.post(self.event)
237 | if self.repeat:
238 | self.set_timeout()
239 |
240 |
--------------------------------------------------------------------------------
/pyjsdl/transform.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Transform module**
6 |
7 | The module provides surface transformation functionality.
8 | """
9 |
10 | from math import pi as _pi, fabs as _fabs, sin as _sin, cos as _cos, ceil as _ceil
11 | from pyjsdl.surface import Surface
12 |
13 |
14 | _deg_rad = _pi/180.0
15 |
16 |
17 | def rotate(surface, angle):
18 | """
19 | Return Surface rotated by the given angle.
20 | """
21 | if not angle:
22 | return surface.copy()
23 | theta = angle * _deg_rad
24 | width_i = surface.get_width()
25 | height_i = surface.get_height()
26 | cos_theta = _fabs( _cos(theta) )
27 | sin_theta = _fabs( _sin(theta) )
28 | width_f = int( (width_i * cos_theta) + (height_i * sin_theta) )
29 | height_f = int( (width_i * sin_theta) + (height_i * cos_theta) )
30 | surf = Surface((width_f, height_f))
31 | surf.saveContext()
32 | surf.translate(width_f/2.0, height_f/2.0)
33 | surf.rotate(-theta)
34 | surf.drawImage(surface.canvas, -width_i/2, -height_i/2)
35 | surf.restoreContext()
36 | surf._colorkey = surface._colorkey
37 | surf._alpha = surface._alpha
38 | return surf
39 |
40 |
41 | def rotozoom(surface, angle, size):
42 | """
43 | Return Surface rotated and resized by the given angle and size.
44 | """
45 | if not angle:
46 | width = int(surface.get_width() * size)
47 | height = int(surface.get_height() * size)
48 | return scale(surface, (width, height))
49 | theta = angle * _deg_rad
50 | width_i = int(surface.get_width() * size)
51 | height_i = int(surface.get_height() * size)
52 | cos_theta = _fabs( _cos(theta) )
53 | sin_theta = _fabs( _sin(theta) )
54 | width_f = int( _ceil((width_i * cos_theta) + (height_i * sin_theta)) )
55 | if width_f % 2:
56 | width_f += 1
57 | height_f = int( _ceil((width_i * sin_theta) + (height_i * cos_theta)) )
58 | if height_f % 2:
59 | height_f += 1
60 | surf = Surface((width_f, height_f))
61 | surf.saveContext()
62 | surf.translate(width_f/2.0, height_f/2.0)
63 | surf.rotate(-theta)
64 | surf.drawImage(surface.canvas,
65 | 0, 0, surface.get_width(), surface.get_height(),
66 | -width_i/2, -height_i/2, width_i, height_i)
67 | surf.restoreContext()
68 | surf._colorkey = surface._colorkey
69 | surf._alpha = surface._alpha
70 | return surf
71 |
72 |
73 | def scale(surface, size, dest=None):
74 | """
75 | Return Surface resized by the given size.
76 |
77 | An optional destination surface can be provided.
78 | """
79 | if not dest:
80 | surf = Surface(size)
81 | else:
82 | surf = dest
83 | surf.drawImage(surface.canvas,
84 | 0, 0, surface.get_width(), surface.get_height(),
85 | 0, 0, size[0], size[1])
86 | surf._colorkey = surface._colorkey
87 | surf._alpha = surface._alpha
88 | return surf
89 |
90 |
91 | def smoothscale(surface, size):
92 | """
93 | Return Surface resized by the given size.
94 |
95 | An optional destination surface can be provided.
96 | Calls scale().
97 | """
98 | return scale(surface, size)
99 |
100 |
101 | def scale2x(surface, dest=None):
102 | """
103 | Return Surface resized to twice its size.
104 |
105 | An optional destination surface can be provided.
106 | """
107 | return scale(surface,
108 | (surface.get_width()*2, surface.get_height()*2), dest)
109 |
110 |
111 | def flip(surface, xbool=True, ybool=False):
112 | """
113 | Return Surface that is flipped horizontally, vertically, or both.
114 | """
115 | surf = Surface((surface.get_width(), surface.get_height()))
116 | surf.saveContext()
117 | if xbool and ybool:
118 | surf.translate(surface.get_width(), surface.get_height())
119 | surf.scale(-1, -1)
120 | elif xbool:
121 | surf.translate(surface.get_width(), 0)
122 | surf.scale(-1, 1)
123 | elif ybool:
124 | surf.translate(0, surface.get_height())
125 | surf.scale(1, -1)
126 | surf.drawImage(surface.canvas, 0, 0)
127 | surf.restoreContext()
128 | surf._colorkey = surface._colorkey
129 | surf._alpha = surface._alpha
130 | return surf
131 |
132 |
--------------------------------------------------------------------------------
/pyjsdl/util.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | """
5 | **Util module**
6 |
7 | The module provides profiling functionality.
8 | """
9 |
10 | from pyjsdl.time import Time
11 | from pyjsdl.rect import Rect
12 | from pyjsdl import env
13 | from __pyjamas__ import JS, doc
14 |
15 |
16 | class Timer(object):
17 | """
18 | Simple profiling timer.
19 |
20 | Output log can be directed to 'console' or to 'textarea'.
21 | If output is to textarea, may specify log length.
22 | """
23 |
24 | def __init__(self, log='console', log_length=5):
25 | """
26 | Initialize timer object.
27 | """
28 | self.time = Time()
29 | self.time_i = self.get_time()
30 | self.dtime = []
31 | self.number = 0
32 | self.log = None
33 | self.log_list = None
34 | self.log_num = 0
35 | self.log_scroll = True
36 | self.set_log(log, log_length)
37 |
38 | def get_time(self):
39 | """
40 | Get current time.
41 | """
42 | return self.time.time()
43 |
44 | def set_time(self):
45 | """
46 | Set current time.
47 | """
48 | self.time_i = self.get_time()
49 |
50 | def lap_time(self, time_i=None, time_f=None, number=100, print_result=True):
51 | """
52 | Time lapsed since previous set_time.
53 |
54 | Optional arguments time_i and time_f, number of calls to average, and print_results to output.
55 | Return lapsed time on completion.
56 | """
57 | if time_i is None:
58 | time_i = self.time_i
59 | if time_f is None:
60 | time_f = self.get_time()
61 | self.dtime.append(time_f-time_i)
62 | self.number += 1
63 | if self.number >= number:
64 | t_ave = ( sum(self.dtime)/number )
65 | self.dtime = []
66 | self.number = 0
67 | if print_result:
68 | if self.log_type == 'console':
69 | self.log_num += 1
70 | entry = "Time %d: %s" % (self.log_num, t_ave)
71 | print(entry)
72 | else:
73 | self.log_num += 1
74 | entry = "Time %d: %s" % (self.log_num, t_ave)
75 | self.print_log(entry)
76 | return t_ave
77 |
78 | def set_log(self, log, log_length=5):
79 | """
80 | Set log output.
81 |
82 | Argument log can be 'console' or 'textarea'.
83 | """
84 | if log in ('console','textarea'):
85 | self.log_type = log
86 | if log == 'textarea':
87 | if not self.log:
88 | size = env.canvas.surface.width-5, 102
89 | self.log = env.canvas.surface._display.Textarea(size)
90 | self.log.setReadonly(True)
91 | self.log.addMouseListener(self)
92 | self.onMouseUp = lambda sender,x,y: None
93 | self.onMouseMove = lambda sender,x,y: None
94 | self.onMouseEnter = lambda sender: None
95 | self.log_list = ['' for i in range(log_length)]
96 | self.log.toggle(True)
97 | else:
98 | if self.log:
99 | self.log.toggle(False)
100 | self.log_list = []
101 |
102 | def onMouseDown(self, sender, x, y):
103 | """
104 | Control log scroll.
105 | """
106 | self.log_scroll = False
107 |
108 | def onMouseLeave(self, sender):
109 | """
110 | Control log scroll.
111 | """
112 | self.log_scroll = True
113 |
114 | def print_log(self, text):
115 | """
116 | Print text to output.
117 | """
118 | if self.log_type == 'console':
119 | print(text)
120 | else:
121 | self.log_list.pop(0)
122 | self.log_list.append(text+'\n')
123 | text = ''.join(self.log_list)
124 | self.log.setText(text)
125 | if self.log_scroll:
126 | self.log.setCursorPos(len(text))
127 |
128 |
129 | class PyjsMode:
130 | """
131 | Check Pyjs mode used to compile application.
132 |
133 | Attributes:
134 | strict/optimized to specify mode
135 | getattr_call/eq_call to specify functionality
136 | """
137 | def __init__(self):
138 | self.getattr_call = self.test_getattr()
139 | self.eq_call = self.test_eq()
140 | self.strict, self.optimized = self.test_mode()
141 |
142 | def test_mode(self):
143 | """
144 | Test if build mode is strict or optimized.
145 | """
146 | if self.getattr_call and self.eq_call:
147 | return True, False
148 | else:
149 | return False, True
150 |
151 | def test_getattr(self):
152 | """
153 | Test if object __getattr__ method is called.
154 | """
155 | return (Rect(0,0,20,20).center == (10,10))
156 |
157 | def test_eq(self):
158 | """
159 | Test if object __eq__ method is called.
160 | """
161 | return (Rect(0,0,20,20) == Rect(0,0,20,20))
162 |
163 | env.set_env('pyjs_mode', PyjsMode())
164 |
165 |
166 | def call(obj, func, args=()):
167 | """
168 | Call unbound method.
169 |
170 | Argument obj is the object, func is the unbound method, and optional args is a tuple of arguments for the method.
171 | Returns the method's return value.
172 | """
173 | return JS("@{{func}}.apply(@{{obj}}, @{{args}}['getArray']());")
174 |
175 |
176 | def createEvent(eventObject, eventType, eventOptions=None):
177 | """
178 | Create JavaScript event.
179 |
180 | For instance:
181 | MouseEvent type 'mousedown', handled as a MouseButtonDown event.
182 | PageTransitionEvent type 'pagehide', handled as a Quit event.
183 | Default options are {'bubbles':True, 'cancelable':True}.
184 | """
185 | opt = {'bubbles':True, 'cancelable':True}
186 | if eventOptions is not None:
187 | for key in eventOptions:
188 | opt[key] = eventOptions[key]
189 | options = JS("{}")
190 | for key in opt:
191 | val = opt[key]
192 | JS("@{{options}}[@{{key}}] = @{{val}}")
193 | event = JS("new @{{eventObject}}(@{{eventType}}, @{{options}})")
194 | return event
195 |
196 |
197 | def dispatchEvent(event, element=None):
198 | """
199 | Dispatch JavaScript event.
200 |
201 | The event is dispatched from the element.
202 | Default element is the canvas.
203 | """
204 | if element is None:
205 | element = doc().getElementsByTagName('canvas').item(0)
206 | if element is None:
207 | return False
208 | element.dispatchEvent(event)
209 | return True
210 |
211 |
212 | #code modified from pyjs
213 | class _dict(dict):
214 |
215 | def values(self):
216 | return dict.values(self).__iter__()
217 |
218 | def keys(self):
219 | return dict.__iter__(self)
220 |
221 | def items(self):
222 | return dict.items(self).__iter__()
223 |
224 |
225 | def _next(obj):
226 | return obj.next()
227 |
228 |
229 | try:
230 | _range = xrange
231 | except NameError:
232 | _range = range
233 |
234 |
--------------------------------------------------------------------------------
/pyjsdl/version.py:
--------------------------------------------------------------------------------
1 | #Pyjsdl - Copyright (C) 2013 James Garnon
2 | #Released under the MIT License
3 |
4 | from pyjsdl import __version__
5 |
6 |
7 | ver = __version__
8 | "Module version"
9 |
10 |
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jggatc/pyjsdl/1ba9e5ca68807bd73cc03e933e931bc08f28e934/test/__init__.py
--------------------------------------------------------------------------------
/test/color_test.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | env = None
4 | pg = None
5 |
6 |
7 | def init(environ):
8 | global env, pg
9 | env = environ
10 | pg = env['pg']
11 | tests = [test_color_constructor,
12 | test_color_update,
13 | test_color_get,
14 | test_color_comparison,
15 | test_color_operator,
16 | test_color_transform,
17 | test_color_conversion]
18 | return tests
19 |
20 |
21 | def _color_convert(color):
22 | if isinstance(color, tuple):
23 | if len(color) == 4:
24 | r, g, b, a = color[0], color[1], color[2], color[3]
25 | else:
26 | r, g, b, a = color[0], color[1], color[2], 255
27 | else:
28 | r, g, b, a = int((color>>16) & 0xff), int((color>>8) & 0xff), int(color & 0xff), int((color>>24) & 0xff)
29 | return r, g, b, a
30 |
31 |
32 | def _attr(color):
33 | return color.r, color.g, color.b, color.a
34 |
35 |
36 | def _rd(v1, v2, v3, v4=None):
37 | if v4 is None:
38 | return round(v1, 3), round(v2, 3), round(v3, 3)
39 | else:
40 | return round(v1, 3), round(v2, 3), round(v3, 3), round(v4, 3)
41 |
42 |
43 | def test_color_constructor():
44 | c = pg.Color(255, 0, 0)
45 | r, g, b, a = _color_convert((255, 0, 0))
46 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
47 | c = pg.Color(0, 255, 0, 255)
48 | r, g, b, a = _color_convert((0, 255, 0, 255))
49 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
50 | if env['platform'] in ('jvm', 'js'): #pg: integer is rgba, not argb
51 | c = pg.Color((0xff<<24)+255)
52 | r, g, b, a = _color_convert((0xff<<24)+255)
53 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
54 | if env['platform'] in ['jvm', 'pc']:
55 | c = pg.Color((255, 0, 0))
56 | r, g, b, a = _color_convert((255, 0, 0))
57 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
58 | c = pg.Color((0, 255, 0, 255))
59 | r, g, b, a = _color_convert((0, 255, 0, 255))
60 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
61 | c = pg.Color('0xff0000')
62 | assert (c.r, c.g, c.b, c.a) == (255, 0, 0, 255)
63 | c = pg.Color('0xff0000ff')
64 | assert (c.r, c.g, c.b, c.a) == (255, 0, 0, 255)
65 | c = pg.Color('#ff0000')
66 | assert (c.r, c.g, c.b, c.a) == (255, 0, 0, 255)
67 | c = pg.Color('#ff0000ff')
68 | assert (c.r, c.g, c.b, c.a) == (255, 0, 0, 255)
69 |
70 |
71 | def test_color_update():
72 | c = pg.Color(0, 0, 0)
73 | c.update(255, 0, 0)
74 | r, g, b, a = _color_convert((255, 0, 0))
75 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
76 | c.update(0, 255, 0, 255)
77 | r, g, b, a = _color_convert((0, 255, 0, 255))
78 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
79 | if env['platform'] in ('jvm', 'js'): #pg: integer is rgba, not argb
80 | c.update((0xff<<24)+255)
81 | r, g, b, a = _color_convert((0xff<<24)+255)
82 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
83 | if env['platform'] in ['jvm', 'pc']:
84 | c.update((255, 0, 0))
85 | r, g, b, a = _color_convert((255, 0, 0))
86 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
87 | c.update((0, 255, 0, 255))
88 | r, g, b, a = _color_convert((0, 255, 0, 255))
89 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
90 | c = pg.Color('0xff0000')
91 | assert (c.r, c.g, c.b, c.a) == (255, 0, 0, 255)
92 | c = pg.Color('0xff0000ff')
93 | assert (c.r, c.g, c.b, c.a) == (255, 0, 0, 255)
94 | c = pg.Color('#ff0000')
95 | assert (c.r, c.g, c.b, c.a) == (255, 0, 0, 255)
96 | c = pg.Color('#ff0000ff')
97 | assert (c.r, c.g, c.b, c.a) == (255, 0, 0, 255)
98 |
99 |
100 | def test_color_get():
101 | c = pg.Color(0, 255, 0, 255)
102 | r, g, b, a = 0, 255, 0, 255
103 | assert (c.r, c.g, c.b, c.a) == (r, g, b, a)
104 | assert (c[0], c[1], c[2], c[3]) == (r, g, b, a)
105 | if env['platform'] == 'jvm': #java.awt.Color
106 | assert (c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()) == (r, g, b, a)
107 | if not (env['platform'] == 'jvm' and sys.version_info[1] < 5):
108 | #jy2.2.1 issue with property assignment
109 | c[0] = 10
110 | c.g = 20
111 | assert (c.r, c.g, c.b, c.a) == (10, 20, b, a)
112 | assert (c[0], c[1], c[2], c[3]) == (10, 20, b, a)
113 | if env['platform'] == 'jvm': #java.awt.Color
114 | assert (c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()) == (10, 20, b, a)
115 | c = pg.Color(50, 100, 150, 200)
116 | for i, _c in enumerate(c):
117 | assert _c == {0:50, 1:100, 2:150, 3:200}[i]
118 | assert [_c for _c in c] == [50, 100, 150, 200]
119 |
120 |
121 | def test_color_comparison():
122 | c = pg.Color(255, 0, 0, 255)
123 | c1 = pg.Color(255, 0, 0, 255)
124 | c2 = pg.Color(0, 0, 0, 255)
125 | c3 = pg.Color(255, 0, 0)
126 | c4 = pg.Color(0, 0, 0)
127 | if env['executor'] != 'pyjs':
128 | #pyjs compares rect==tuple not __eq__
129 | assert c == (255, 0, 0, 255)
130 | assert c != (0, 0, 0, 255)
131 | assert c == (255, 0, 0)
132 | assert c != (0, 0, 0)
133 | if not env['pyjs_opt']:
134 | #pyjs -O __eq__ ignored
135 | assert c == pg.Color(255, 0, 0, 255)
136 | assert c != pg.Color(0, 0, 0, 255)
137 | assert c == pg.Color(255, 0, 0)
138 | assert c != pg.Color(0, 0, 0)
139 | assert c == c1
140 | assert c != c2
141 | assert c == c3
142 | assert c != c4
143 | assert c.r==c1.r and c.g==c1.g and c.b==c1.b and c.a==c1.a
144 | assert c.r!=c2.r and c.g==c2.g and c.b==c2.b and c.a==c2.a
145 | assert c.r==c3.r and c.g==c3.g and c.b==c3.b and c.a==c3.a
146 | assert c.r!=c4.r and c.g==c4.g and c.b==c4.b and c.a==c4.a
147 |
148 |
149 | def test_color_operator():
150 | if (env['pyjs_opt'] and not env['pyjs_attr']): #special methods ignored
151 | raise NotImplementedError
152 | if not env['pyjs_opt']:
153 | c1 = pg.Color(60, 220, 120, 100)
154 | c2 = pg.Color(40, 40, 40, 255)
155 | c3 = pg.Color(255, 0, 0, 100)
156 | assert c1 + c2 == pg.Color(100, 255, 160, 255)
157 | assert c1 + c3 == pg.Color(255, 220, 120, 200)
158 | assert c1 - c2 == pg.Color(20, 180, 80, 0)
159 | assert c1 - c3 == pg.Color(0, 220, 120, 0)
160 | assert c1 * c2 == pg.Color(255, 255, 255, 255)
161 | assert c1 * c3 == pg.Color(255, 0, 0, 255)
162 | assert c1 // c2 == pg.Color(1, 5, 3, 0)
163 | assert c1 // c3 == pg.Color(0, 0, 0, 1)
164 | assert c1 % c2 == pg.Color(20, 20, 0, 100)
165 | assert c1 % c3 == pg.Color(60, 0, 0, 0)
166 | c = pg.Color(0, 10, 20, 255)
167 | c += c1
168 | assert c == pg.Color(60, 230, 140, 255)
169 | c = pg.Color(0, 10, 20, 255)
170 | c -= c1
171 | assert c == pg.Color(0, 0, 0, 155)
172 | c = pg.Color(0, 10, 20, 255)
173 | c *= c1
174 | assert c == pg.Color(0, 255, 255, 255)
175 | c = pg.Color(0, 10, 20, 255)
176 | c //= c1
177 | assert c == pg.Color(0, 0, 0, 2)
178 | c = pg.Color(0, 10, 20, 255)
179 | c %= c1
180 | assert c == pg.Color(0, 10, 20, 55)
181 | c = pg.Color(0, 10, 20, 255)
182 | assert ~c == pg.Color(255, 245, 235, 0)
183 | if (env['pyjs_opt'] and env['pyjs_attr']):
184 | c1 = pg.Color(60, 220, 120, 100)
185 | c2 = pg.Color(40, 40, 40, 255)
186 | c3 = pg.Color(255, 0, 0, 100)
187 | assert _attr(c1 + c2) == (100, 255, 160, 255)
188 | assert _attr(c1 + c3) == (255, 220, 120, 200)
189 | assert _attr(c1 - c2) == (20, 180, 80, 0)
190 | assert _attr(c1 - c3) == (0, 220, 120, 0)
191 | assert _attr(c1 * c2) == (255, 255, 255, 255)
192 | assert _attr(c1 * c3) == (255, 0, 0, 255)
193 | assert _attr(c1 // c2) == (1, 5, 3, 0)
194 | assert _attr(c1 // c3) == (0, 0, 0, 1)
195 | assert _attr(c1 % c2) == (20, 20, 0, 100)
196 | assert _attr(c1 % c3) == (60, 0, 0, 0)
197 | c = pg.Color(0, 10, 20, 255)
198 | c += c1
199 | assert _attr(c) == (60, 230, 140, 255)
200 | c = pg.Color(0, 10, 20, 255)
201 | c -= c1
202 | assert _attr(c) == (0, 0, 0, 155)
203 | c = pg.Color(0, 10, 20, 255)
204 | c *= c1
205 | assert _attr(c) == (0, 255, 255, 255)
206 | c = pg.Color(0, 10, 20, 255)
207 | c //= c1
208 | assert _attr(c) == (0, 0, 0, 2)
209 | c = pg.Color(0, 10, 20, 255)
210 | c %= c1
211 | assert _attr(c) == (0, 10, 20, 55)
212 | c = pg.Color(0, 10, 20, 255)
213 | assert _attr(c.__invert__()) == (255, 245, 235, 0) #pyjs -O error with ~
214 |
215 |
216 | def test_color_transform():
217 | if not env['pyjs_opt']:
218 | c = pg.Color(0, 10, 100, 100)
219 | nr, ng, nb, na = c.normalize()
220 | assert (_rd( nr, ng, nb, na )) == (0.0, 0.039, 0.392, 0.392)
221 | c = pg.Color(255, 0, 100, 150)
222 | nc = c.normalize()
223 | nr, ng, nb, na = nc
224 | assert (_rd( nr, ng, nb, na )) == (1.0, 0.0, 0.392, 0.588)
225 | c = pg.Color(0, 10, 100, 100)
226 | assert c.premul_alpha() == pg.Color(0, 4, 39, 100)
227 | c = pg.Color(255, 0, 100, 150)
228 | assert c.premul_alpha() == pg.Color(150, 0, 59, 150)
229 | c = pg.Color(0, 10, 100, 100)
230 | assert c.correct_gamma(0.1) == pg.Color(0, 184, 232, 232)
231 | assert c.correct_gamma(0.9) == pg.Color(0, 14, 110, 110)
232 | assert c.correct_gamma(2.0) == pg.Color(0, 0, 39, 39)
233 | c = pg.Color(255, 0, 100, 150)
234 | assert c.correct_gamma(0.1) == pg.Color(255, 0, 232, 242)
235 | assert c.correct_gamma(0.9) == pg.Color(255, 0, 110, 158)
236 | assert c.correct_gamma(2.0) == pg.Color(255, 0, 39, 88)
237 | c1 = pg.Color(0, 10, 100, 100)
238 | c2 = pg.Color(0, 20, 200, 100)
239 | assert c1.lerp(c2, 0.0) == pg.Color(0, 10, 100, 100)
240 | assert c1.lerp(c2, 0.3) == pg.Color(0, 13, 130, 100)
241 | assert c1.lerp(c2, 0.5) == pg.Color(0, 15, 150, 100)
242 | assert c1.lerp(c2, 0.7) == pg.Color(0, 17, 170, 100)
243 | assert c1.lerp(c2, 1.0) == pg.Color(0, 20, 200, 100)
244 | c1 = pg.Color(50, 100, 150, 100)
245 | c2 = pg.Color(100, 200, 250, 200)
246 | assert c1.lerp(c2, 0.0) == pg.Color(50, 100, 150, 100)
247 | assert c1.lerp(c2, 0.3) == pg.Color(65, 130, 180, 130)
248 | assert c1.lerp(c2, 0.5) == pg.Color(75, 150, 200, 150)
249 | assert c1.lerp(c2, 0.7) == pg.Color(85, 170, 220, 170)
250 | assert c1.lerp(c2, 1.0) == pg.Color(100, 200, 250, 200)
251 | c1 = pg.Color(255, 0, 100, 150)
252 | c2 = (50, 100, 150, 200)
253 | assert c1.lerp(c2, 0.5) == pg.Color(153, 50, 125, 175)
254 | c1 = pg.Color(255, 0, 100, 150)
255 | c2 = (50, 100, 150)
256 | assert c1.lerp(c2, 0.5) == pg.Color(153, 50, 125, 203)
257 | if (env['pyjs_opt'] and env['pyjs_attr']):
258 | c = pg.Color(0, 10, 100, 100)
259 | nr, ng, nb, na = c.normalize()
260 | assert (_rd( nr, ng, nb, na )) == (0.0, 0.039, 0.392, 0.392)
261 | c = pg.Color(255, 0, 100, 150)
262 | nc = c.normalize()
263 | nr, ng, nb, na = nc
264 | assert (_rd( nr, ng, nb, na )) == (1.0, 0.0, 0.392, 0.588)
265 | c = pg.Color(0, 10, 100, 100)
266 | assert _attr(c.premul_alpha()) == (0, 4, 39, 100)
267 | c = pg.Color(255, 0, 100, 150)
268 | assert _attr(c.premul_alpha()) == (150, 0, 59, 150)
269 | c = pg.Color(0, 10, 100, 100)
270 | assert _attr(c.correct_gamma(0.1)) == (0, 184, 232, 232)
271 | assert _attr(c.correct_gamma(0.9)) == (0, 14, 110, 110)
272 | assert _attr(c.correct_gamma(2.0)) == (0, 0, 39, 39)
273 | c = pg.Color(255, 0, 100, 150)
274 | assert _attr(c.correct_gamma(0.1)) == (255, 0, 232, 242)
275 | assert _attr(c.correct_gamma(0.9)) == (255, 0, 110, 158)
276 | assert _attr(c.correct_gamma(2.0)) == (255, 0, 39, 88)
277 | c1 = pg.Color(0, 10, 100, 100)
278 | c2 = pg.Color(0, 20, 200, 100)
279 | assert _attr(c1.lerp(c2, 0.0)) == (0, 10, 100, 100)
280 | assert _attr(c1.lerp(c2, 0.3)) == (0, 13, 130, 100)
281 | assert _attr(c1.lerp(c2, 0.5)) == (0, 15, 150, 100)
282 | assert _attr(c1.lerp(c2, 0.7)) == (0, 17, 170, 100)
283 | assert _attr(c1.lerp(c2, 1.0)) == (0, 20, 200, 100)
284 | c1 = pg.Color(50, 100, 150, 100)
285 | c2 = pg.Color(100, 200, 250, 200)
286 | assert _attr(c1.lerp(c2, 0.0)) == (50, 100, 150, 100)
287 | assert _attr(c1.lerp(c2, 0.3)) == (65, 130, 180, 130)
288 | assert _attr(c1.lerp(c2, 0.5)) == (75, 150, 200, 150)
289 | assert _attr(c1.lerp(c2, 0.7)) == (85, 170, 220, 170)
290 | assert _attr(c1.lerp(c2, 1.0)) == (100, 200, 250, 200)
291 | c1 = pg.Color(255, 0, 100, 150)
292 | c2 = (50, 100, 150, 200)
293 | assert _attr(c1.lerp(c2, 0.5)) == (153, 50, 125, 175)
294 | c1 = pg.Color(255, 0, 100, 150)
295 | c2 = (50, 100, 150)
296 | assert _attr(c1.lerp(c2, 0.5)) == (153, 50, 125, 203)
297 |
298 |
299 | def test_color_conversion():
300 | if (env['pyjs_opt'] and not env['pyjs_attr']): #property ignored
301 | c = pg.Color(255, 0, 0)
302 | assert _attr(c) == (255, 0, 0, 255)
303 | assert c._get_cmy() == (0.0, 1.0, 1.0)
304 | assert c._get_hsva() == (0.0, 100.0, 100.0, 100.0)
305 | assert c._get_hsla() == (0.0, 100.0, 50.0, 100.0)
306 | c._set_cmy((0.1, 0.2, 0.3))
307 | _c, _m, _y = c._get_cmy()
308 | assert (_rd( _c, _m, _y )) == (0.102, 0.2, 0.302)
309 | assert _attr(c) == (229, 204, 178, 255)
310 | c._set_hsva((360.0, 100.0, 100.0, 100.0))
311 | assert c._get_hsva() == (0.0, 100.0, 100.0, 100.0)
312 | assert _attr(c) == (255, 0, 0, 255)
313 | c._set_hsla((50.0, 50.0, 50.0, 50.0))
314 | h, s, l, a = c._get_hsla()
315 | assert (_rd( h, s, l, a )) == (50.156, 50.394, 49.804, 49.804)
316 | assert _attr(c) == (191, 170, 63, 127)
317 | return
318 | c = pg.Color(255, 0, 0)
319 | if not env['pyjs_opt']:
320 | assert c == pg.Color(255, 0, 0, 255)
321 | else:
322 | assert _attr(c) == (255, 0, 0, 255)
323 | assert c.cmy == (0.0, 1.0, 1.0)
324 | assert c.hsva == (0.0, 100.0, 100.0, 100.0)
325 | assert c.hsla == (0.0, 100.0, 50.0, 100.0)
326 | c = pg.Color(10, 100, 200, 200)
327 | _c, _m, _y = c.cmy
328 | assert (_rd( _c, _m, _y )) == (0.961, 0.608, 0.216)
329 | h, s, v, a = c.hsva
330 | assert (_rd( h, s, v, a )) == (211.579, 95.0, 78.431, 78.431)
331 | h, s, l, a = c.hsla
332 | assert (_rd( h, s, l, a )) == (211.579, 90.476, 41.176, 78.431)
333 | if env['platform'] == 'jvm' and sys.version_info < (2,5):
334 | #jy2.2.1 issue with property assignment
335 | return
336 | c = pg.Color(255, 0, 0)
337 | assert c.cmy == (0.0, 1.0, 1.0)
338 | c.cmy = (0.1, 0.2, 0.3)
339 | _c, _m, _y = c.cmy
340 | assert (_rd( _c, _m, _y )) == (0.102, 0.2, 0.302)
341 | if not env['pyjs_opt']:
342 | assert c == pg.Color(229, 204, 178, 255)
343 | else:
344 | assert _attr(c) == (229, 204, 178, 255)
345 | c.cmy = (0.5, 0.5, 0.5)
346 | _c, _m, _y = c.cmy
347 | assert (_rd( _c, _m, _y )) == (0.502, 0.502, 0.502)
348 | if not env['pyjs_opt']:
349 | assert c == pg.Color(127, 127, 127, 255)
350 | else:
351 | assert _attr(c) == (127, 127, 127, 255)
352 | c.cmy = (0.0, 0.5, 1.0)
353 | _c, _m, _y = c.cmy
354 | assert (_rd( _c, _m, _y )) == (0.0, 0.502, 1.0)
355 | if not env['pyjs_opt']:
356 | assert c == pg.Color(255, 127, 0, 255)
357 | else:
358 | assert _attr(c) == (255, 127, 0, 255)
359 | c = pg.Color(255, 0, 0)
360 | assert c.hsva == (0.0, 100.0, 100.0, 100.0)
361 | c.hsva = (360.0, 100.0, 100.0, 100.0)
362 | assert c.hsva == (0.0, 100.0, 100.0, 100.0)
363 | if not env['pyjs_opt']:
364 | assert c == pg.Color(255, 0, 0, 255)
365 | else:
366 | assert _attr(c) == (255, 0, 0, 255)
367 | c.hsva = (60.0, 100.0, 100.0, 100.0)
368 | assert c.hsva == (60.0, 100.0, 100.0, 100.0)
369 | if not env['pyjs_opt']:
370 | assert c == pg.Color(255, 255, 0, 255)
371 | else:
372 | assert _attr(c) == (255, 255, 0, 255)
373 | c.hsva = (120.0, 100.0, 100.0, 100.0)
374 | assert c.hsva == (120.0, 100.0, 100.0, 100.0)
375 | if not env['pyjs_opt']:
376 | assert c == pg.Color(0, 255, 0, 255)
377 | else:
378 | assert _attr(c) == (0, 255, 0, 255)
379 | c.hsva = (0.0, 0.0, 0.0, 100.0)
380 | assert c.hsva == (0.0, 0.0, 0.0, 100.0)
381 | if not env['pyjs_opt']:
382 | assert c == pg.Color(0, 0, 0, 255)
383 | else:
384 | assert _attr(c) == (0, 0, 0, 255)
385 | c.hsva = (10.0, 100.0, 100.0, 100.0)
386 | h, s, v, a = c.hsva
387 | assert (_rd( h, s, v, a )) == (9.882, 100.0, 100.0, 100.0)
388 | if not env['pyjs_opt']:
389 | assert c == pg.Color(255, 42, 0, 255)
390 | else:
391 | assert _attr(c) == (255, 42, 0, 255)
392 | c = pg.Color(255, 0, 0)
393 | assert c.hsla == (0.0, 100.0, 50.0, 100.0)
394 | c.hsla = (360.0, 100.0, 100.0, 100.0)
395 | assert c.hsla == (0.0, 0.0, 100.0, 100.0)
396 | if not env['pyjs_opt']:
397 | assert c == pg.Color(255, 255, 255, 255)
398 | else:
399 | assert _attr(c) == (255, 255, 255, 255)
400 | c.hsla = (50.0, 50.0, 50.0, 50.0)
401 | h, s, l, a = c.hsla
402 | assert (_rd( h, s, l, a )) == (50.156, 50.394, 49.804, 49.804)
403 | if not env['pyjs_opt']:
404 | assert c == pg.Color(191, 170, 63, 127)
405 | else:
406 | assert _attr(c) == (191, 170, 63, 127)
407 | c.hsla = (0.0, 10.0, 20.0, 30.0)
408 | h, s, l, a = c.hsla
409 | assert (_rd( h, s, l, a )) == (0.0, 10.891, 19.804, 29.804)
410 | if not env['pyjs_opt']:
411 | assert c == pg.Color(56, 45, 45, 76)
412 | else:
413 | assert _attr(c) == (56, 45, 45, 76)
414 | c.hsla = (10.0, 20.0, 30.0, 40.0)
415 | h, s, l, a = c.hsla
416 | assert (_rd( h, s, l, a )) == (10.0, 19.737, 29.804, 40.0)
417 | if not env['pyjs_opt']:
418 | assert c == pg.Color(91, 66, 61, 102)
419 | else:
420 | assert _attr(c) == (91, 66, 61, 102)
421 |
422 |
--------------------------------------------------------------------------------
/test/cursor_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 |
4 |
5 | def init(environ):
6 | global env, pg
7 | env = environ
8 | pg = env['pg']
9 | tests = [test_cursor]
10 | return tests
11 |
12 |
13 | def test_cursor():
14 | cursor_str = ( '. .',
15 | ' . . ',
16 | ' .. ',
17 | ' .XX. ',
18 | ' .XX. ',
19 | ' .. ',
20 | ' . . ',
21 | '. .' )
22 | size = (8,8)
23 | hotspot = (0,0)
24 | cursor_dat = pg.cursors.compile(cursor_str)
25 | pg.mouse.set_cursor(size, hotspot, *cursor_dat)
26 | if env['platform'] in ('jvm', 'js'):
27 | data, mask = cursor_dat[0], cursor_dat[1]
28 | cursor_surf = pg.cursors.create_cursor(size, data, mask)
29 | pg.mouse.set_cursor(cursor_surf, hotspot)
30 | cc1 = cursor_surf.get_at((0,0))
31 | cc2 = cursor_surf.get_at((0,1))
32 | c1 = pg.Color(255,255,255,255)
33 | c2 = pg.Color(0,0,0,0)
34 | if not env['pyjs_opt']:
35 | assert cc1 == c1
36 | assert cc2 == c2
37 | else: #pyjs -O __eq__ ignored
38 | assert cc1.r==c1.r and cc1.g==c1.g and cc1.b==c1.b and cc1.a==c1.a
39 | assert cc2.r==c2.r and cc2.g==c2.g and cc2.b==c2.b and cc2.a==c2.a
40 |
41 |
--------------------------------------------------------------------------------
/test/draw_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 | surface = None
4 |
5 |
6 | def init(environ):
7 | global env, pg, surface
8 | env = environ
9 | pg = env['pg']
10 | surface = env['surface']
11 | tests = [test_draw_rect,
12 | test_draw_circle,
13 | test_draw_ellipse,
14 | test_draw_arc,
15 | test_draw_polygon,
16 | test_draw_line,
17 | test_draw_lines]
18 | return tests
19 |
20 |
21 | def test_draw_rect():
22 | data = [((10,6),0), ((10,8),1), ((10,10),1)], (5,8,10,5)
23 | surface.fill((0,0,0))
24 | rect = pg.draw.rect(surface, (255,0,0), (5,8,10,5))
25 | for pos in data[0]:
26 | c = surface.get_at(pos[0])
27 | c = {True:1,False:0}[c.r>0]
28 | assert c == pos[1]
29 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
30 | data = [((10,6),0), ((10,8),1), ((10,10),0)], (5,8,10,5)
31 | surface.fill((0,0,0))
32 | rect = pg.draw.rect(surface, (255,0,0,255), pg.Rect((5,8,10,5)), 1)
33 | for pos in data[0]:
34 | c = surface.get_at(pos[0])
35 | c = {True:1,False:0}[c.r>0]
36 | assert c == pos[1]
37 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
38 | data = [((3,0),1), ((3,2),1), ((3,4),0)], (0,0,5,3)
39 | surface.fill((0,0,0))
40 | rect = pg.draw.rect(surface, (255,0,0), (-5,-2,10,5))
41 | for pos in data[0]:
42 | c = surface.get_at(pos[0])
43 | c = {True:1,False:0}[c.r>0]
44 | assert c == pos[1]
45 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
46 |
47 |
48 | def test_draw_circle():
49 | data = [((10,0),0), ((10,5),1), ((10,10),1)], (5,5,10,10)
50 | surface.fill((0,0,0))
51 | rect = pg.draw.circle(surface, (255,0,0), (10,10), 5)
52 | data = [((10,0),0), ((10,5),1), ((10,10),0)], (5,5,10,10)
53 | surface.fill((0,0,0))
54 | rect = pg.draw.circle(surface, (255,0,0,255), (10,10), 5, 1)
55 | for pos in data[0]:
56 | c = surface.get_at(pos[0])
57 | c = {True:1,False:0}[c.r>0]
58 | assert c == pos[1]
59 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
60 |
61 |
62 | def test_draw_ellipse():
63 | data = [((10,6),1), ((10,8),1), ((10,10),0)], (5,5,10,5)
64 | surface.fill((0,0,0))
65 | rect = pg.draw.ellipse(surface, (255,0,0), (5,5,10,5))
66 | for pos in data[0]:
67 | c = surface.get_at(pos[0])
68 | c = {True:1,False:0}[c.r>0]
69 | assert c == pos[1]
70 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
71 |
72 |
73 | def test_draw_arc():
74 | data = [((10,0),0), ((10,5),1), ((10,10),0)], (5,5,11,6)
75 | surface.fill((0,0,0))
76 | rect = pg.draw.arc(surface, (255,0,0), (5,5,10,10), 0, 3.14)
77 | for pos in data[0]:
78 | c = surface.get_at(pos[0])
79 | c = {True:1,False:0}[c.r>0]
80 | assert c == pos[1]
81 | if env['platform'] not in ('jvm','js'):
82 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
83 | else: #update to new boundary process
84 | assert (rect.x,rect.y,rect.width,rect.height) == (5,5,10,10)
85 |
86 |
87 | def test_draw_polygon():
88 | data = [((10,4),0), ((10,6),1), ((10,8),1)], (5,5,11,11)
89 | surface.fill((0,0,0))
90 | rect = pg.draw.polygon(surface, (255,0,0), ((10,5),(15,15),(5,15)))
91 | for pos in data[0]:
92 | c = surface.get_at(pos[0])
93 | c = {True:1,False:0}[c.r>0]
94 | assert c == pos[1]
95 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
96 |
97 |
98 | def test_draw_line():
99 | data = [((10,6),0), ((10,8),1), ((10,10),0)], (5,8,11,1)
100 | surface.fill((0,0,0))
101 | rect = pg.draw.line(surface, (255,0,0), (5,8), (15,8), 1)
102 | for pos in data[0]:
103 | c = surface.get_at(pos[0])
104 | c = {True:1,False:0}[c.r>0]
105 | assert c == pos[1]
106 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
107 |
108 |
109 | def test_draw_lines():
110 | data = [((10,6),0), ((10,8),1), ((10,10),0)], (5,8,11,1)
111 | surface.fill((0,0,0))
112 | rect = pg.draw.lines(surface, (255,0,0), True, ((7,8),(5,8),(15,8)))
113 | for pos in data[0]:
114 | c = surface.get_at(pos[0])
115 | c = {True:1,False:0}[c.r>0]
116 | assert c == pos[1]
117 | assert (rect.x,rect.y,rect.width,rect.height) == data[1]
118 |
119 |
--------------------------------------------------------------------------------
/test/event_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 |
4 |
5 | def init(environ):
6 | global env, pg
7 | env = environ
8 | pg = env['pg']
9 | tests = [test_event_get,
10 | test_event_poll,
11 | test_event_wait,
12 | test_event_peek,
13 | test_event_clear,
14 | test_event_block,
15 | test_event_post]
16 | return tests
17 |
18 |
19 | def test_event_get():
20 | events = [pg.KEYDOWN, pg.MOUSEBUTTONDOWN, pg.USEREVENT]
21 | event_obj = {}
22 | for evt in events:
23 | event_obj[evt] = pg.event.Event(evt)
24 | pg.event.clear()
25 | assert pg.event.get() == []
26 | for evt in events:
27 | pg.event.post(event_obj[evt])
28 | evts = pg.event.get()
29 | assert [e.type for e in evts] == events
30 | for evt in events:
31 | pg.event.post(event_obj[evt])
32 | evts = pg.event.get(events[0])
33 | assert [e.type for e in evts] == events[:1]
34 | evts = pg.event.get()
35 | assert [e.type for e in evts] == events[1:]
36 | for evt in events:
37 | pg.event.post(event_obj[evt])
38 | evts = pg.event.get([events[1],events[2]])
39 | assert [e.type for e in evts] == events[1:]
40 | evts = pg.event.get()
41 | assert [e.type for e in evts] == events[:1]
42 |
43 |
44 | def test_event_poll():
45 | events = [pg.KEYDOWN, pg.MOUSEBUTTONDOWN, pg.USEREVENT]
46 | event_obj = {}
47 | for evt in events:
48 | event_obj[evt] = pg.event.Event(evt)
49 | pg.event.clear()
50 | assert pg.event.poll().type == pg.NOEVENT
51 | for evt in events:
52 | pg.event.post(event_obj[evt])
53 | evts = [pg.event.poll() for i in range(len(events))]
54 | assert [e.type for e in evts] == events
55 |
56 |
57 | def test_event_wait():
58 | events = [pg.KEYDOWN, pg.MOUSEBUTTONDOWN, pg.USEREVENT]
59 | event_obj = {}
60 | for evt in events:
61 | event_obj[evt] = pg.event.Event(evt)
62 | pg.event.clear()
63 | for evt in events:
64 | pg.event.post(event_obj[evt])
65 | evts = [pg.event.wait() for i in range(len(events))]
66 | assert [e.type for e in evts] == events
67 | assert pg.event.get() == []
68 | if env['platform'] != 'js': #waiting not implemented
69 | pg.time.set_timer(events[0], 30)
70 | evt = pg.event.wait()
71 | assert evt.type == events[0]
72 | pg.time.set_timer(events[0], 0)
73 |
74 |
75 | def test_event_peek():
76 | events = [pg.KEYDOWN, pg.MOUSEBUTTONDOWN, pg.USEREVENT]
77 | event_obj = {}
78 | for evt in events:
79 | event_obj[evt] = pg.event.Event(evt)
80 | pg.event.clear()
81 | for evt in events:
82 | assert pg.event.peek(evt) == False
83 | pg.event.post(event_obj[evt])
84 | assert pg.event.peek(evt) == True
85 |
86 |
87 | def test_event_clear():
88 | events = [pg.KEYDOWN, pg.MOUSEBUTTONDOWN, pg.USEREVENT]
89 | event_obj = {}
90 | for evt in events:
91 | event_obj[evt] = pg.event.Event(evt)
92 | pg.event.clear()
93 | for evt in events:
94 | pg.event.post(event_obj[evt])
95 | pg.event.clear()
96 | assert pg.event.get() == []
97 | for evt in events:
98 | pg.event.post(event_obj[evt])
99 | pg.event.clear(events[0])
100 | evts = pg.event.get()
101 | assert [e.type for e in evts] == events[1:]
102 | for evt in events:
103 | pg.event.post(event_obj[evt])
104 | pg.event.clear((events[0], events[1]))
105 | evts = pg.event.get()
106 | assert [e.type for e in evts] == events[2:]
107 |
108 |
109 | def test_event_block():
110 | events = [pg.KEYDOWN, pg.MOUSEBUTTONDOWN, pg.MOUSEMOTION]
111 | event_obj = {}
112 | for evt in events:
113 | event_obj[evt] = pg.event.Event(evt)
114 | for evt in events:
115 | pg.event.post(event_obj[evt])
116 | pg.event.set_blocked(events[2])
117 | pg.event.clear()
118 | for evt in events:
119 | pg.event.post(event_obj[evt])
120 | evts = pg.event.get()
121 | assert [e.type for e in evts] == events[:2]
122 | pg.event.set_allowed(None)
123 | pg.event.clear()
124 | for evt in events:
125 | pg.event.post(event_obj[evt])
126 | evts = pg.event.get()
127 | assert [e.type for e in evts] == events
128 |
129 |
130 | def test_event_post():
131 | events = [pg.KEYDOWN, pg.MOUSEBUTTONDOWN, pg.USEREVENT]
132 | event_obj = {}
133 | for evt in events:
134 | event_obj[evt] = pg.event.Event(evt)
135 | pg.event.clear()
136 | for evt in events:
137 | pg.event.post(event_obj[evt])
138 | evts = pg.event.get()
139 | assert [e.type for e in evts if e.type in events] == events
140 | evt_obj = pg.event.Event(pg.USEREVENT,{'x':1,'y':2,'z':3})
141 | pg.event.post(evt_obj)
142 | evts = pg.event.get()
143 | e = [ev for ev in evts if ev.type==pg.USEREVENT][0]
144 | assert (e.type==pg.USEREVENT and e.x==1 and e.y==2 and e.z==3)
145 |
146 |
--------------------------------------------------------------------------------
/test/libtest.py:
--------------------------------------------------------------------------------
1 | """
2 | Libtest
3 |
4 | Check doc/libtest.txt for information.
5 |
6 | pyjsmode:
7 | pyjsbuild -S: opt=False/attr=True
8 | pyjsbuild -O: opt=True/attr=False
9 | pyjsbuild -O descriptor-proto/operator-funcs: opt=True/attr=True
10 | """
11 |
12 | import os, sys
13 |
14 | if os.name in ('posix', 'nt', 'os2', 'ce', 'riscos'):
15 | os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
16 | import pygame as pg
17 | platform = 'pc'
18 | executor = 'python'
19 | library = 'pygame'
20 | elif os.name == 'java':
21 | import pyj2d as pg
22 | platform = 'jvm'
23 | executor = 'jython'
24 | library = 'pyj2d'
25 | else:
26 | import pyjsdl as pg
27 | platform = 'js'
28 | executor = 'pyjs'
29 | library = 'pyjsdl'
30 |
31 | from test import surface_test
32 | from test import rect_test
33 | from test import draw_test
34 | from test import transform_test
35 | from test import surfarray_test
36 | from test import mask_test
37 | from test import color_test
38 | from test import cursor_test
39 | from test import sprite_test
40 | from test import event_test
41 | from test import time_test
42 | from test import vector_test
43 |
44 |
45 | if executor in ('python', 'jython', 'pyjs'):
46 | has_assert = True
47 | if hasattr('', 'format'):
48 | _name = lambda f: f.__name__
49 | _str = lambda n, t, r: 'Test {} {} {}'.format(n, _name(t), r)
50 | else:
51 | _name = lambda f: f.__name__
52 | _str = lambda n, t, r: 'Test %3d %-30s %10s' % (n, _name(t), r)
53 |
54 |
55 | def set_pyjsmode():
56 | #pyjsbuild -S: opt=False/attr=True
57 | #pyjsbuild -O: opt=True/attr=False
58 | #pyjsbuild -O descriptor-proto/operator-funcs: opt=True/attr=True
59 | if executor == 'pyjs':
60 | pyjs_opt = pg.env.pyjs_mode.optimized
61 | pyjs_attr = pg.env.pyjs_mode.getattr_call
62 | else:
63 | pyjs_opt = False
64 | pyjs_attr = True
65 | return pyjs_opt, pyjs_attr
66 |
67 |
68 | class Log:
69 |
70 | def __init__(self):
71 | self._log = self._set_log()
72 | self._log_text = []
73 |
74 | def write(self, text):
75 | if self._log:
76 | self._log_text.append(text + '\n')
77 | self._log.setText(''.join(self._log_text))
78 | else:
79 | print(text)
80 |
81 | def _set_log(self):
82 | if platform == 'js':
83 | try:
84 | pg.display.textbox_init()
85 | log = pg.display.textarea
86 | log.resize(400, 500)
87 | log.toggle()
88 | except:
89 | log = None
90 | else:
91 | log = None
92 | return log
93 |
94 |
95 | lib_tests = [surface_test,
96 | rect_test,
97 | draw_test,
98 | transform_test,
99 | surfarray_test,
100 | mask_test,
101 | color_test,
102 | cursor_test,
103 | sprite_test,
104 | event_test,
105 | time_test,
106 | vector_test]
107 |
108 |
109 | lib_test_name = {'surface_test': surface_test,
110 | 'rect_test': rect_test,
111 | 'draw_test': draw_test,
112 | 'transform_test': transform_test,
113 | 'surfarray_test': surfarray_test,
114 | 'mask_test': mask_test,
115 | 'color_test': color_test,
116 | 'cursor_test': cursor_test,
117 | 'sprite_test': sprite_test,
118 | 'event_test': event_test,
119 | 'time_test': time_test,
120 | 'vector_test': vector_test}
121 |
122 |
123 | env = {}
124 | log = None
125 | tests = []
126 | test_num = -1
127 | tests_failed = []
128 | tests_success = True
129 | tests_skipped = False
130 | test_repeat = False
131 | catch_exc = True
132 |
133 |
134 | def tests_init():
135 | global log
136 | pg.init()
137 | width, height = 20,20
138 | display = pg.display.set_mode((width, height))
139 | surface = pg.Surface((width, height))
140 | pyjs_opt, pyjs_attr = set_pyjsmode()
141 | log = Log()
142 | env['pg'] = pg
143 | env['platform'] = platform
144 | env['executor'] = executor
145 | env['library'] = library
146 | env['log'] = log
147 | env['pyjs_opt'] = pyjs_opt
148 | env['pyjs_attr'] = pyjs_attr
149 | env['display'] = display
150 | env['surface'] = surface
151 | env['width'] = width
152 | env['height'] = height
153 | for tst in lib_tests:
154 | test_list = tst.init(env)
155 | tests.extend(test_list)
156 |
157 |
158 | def run_test():
159 | global tests_success, tests_failed, tests_skipped, test_repeat
160 | result = 'passed'
161 | try:
162 | ret = tests[test_num]()
163 | if ret is not None:
164 | if ret:
165 | test_repeat = True
166 | return
167 | else:
168 | test_repeat = False
169 | except AssertionError:
170 | result = 'failed'
171 | tests_success = False
172 | test_repeat = False
173 | tests_failed.append(test_num)
174 | except NotImplementedError:
175 | result = 'skipped'
176 | tests_skipped = True
177 | test_repeat = False
178 | except:
179 | result = 'error'
180 | tests_success = False
181 | test_repeat = False
182 | if test_num not in tests_failed:
183 | tests_failed.append(test_num)
184 | if not catch_exc:
185 | log.write(_str(test_num, tests[test_num], result))
186 | raise
187 | log.write(_str(test_num, tests[test_num], result))
188 |
189 |
190 | def run_tests():
191 | global test_num
192 | while True:
193 | if test_num < len(tests)-1:
194 | test_num += 1
195 | run_test()
196 | else:
197 | break
198 | test_complete()
199 |
200 |
201 | def run_tests_js():
202 | global test_num
203 | if test_num < len(tests)-1:
204 | if not test_repeat:
205 | test_num += 1
206 | run_test()
207 | else:
208 | test_complete()
209 |
210 |
211 | def test_complete():
212 | if tests_success:
213 | log.write('Tests passed.')
214 | else:
215 | log.write('Tests that failed: ' + str(tests_failed))
216 | if not tests_success or tests_skipped:
217 | log.write('\nCheck doc/libtest.txt for information.')
218 | pg.quit()
219 |
220 |
221 | def main(tests=None, catch_exception=None):
222 | if tests is not None:
223 | if isinstance(tests, list) and len(tests) > 0:
224 | lib_tests[:] = []
225 | for test in tests:
226 | _test = lib_test_name[test]
227 | lib_tests.append(_test)
228 | if catch_exception is not None:
229 | if catch_exception in (True, False):
230 | global catch_exc
231 | catch_exc = catch_exception
232 | tests_init()
233 | if env['platform'] in ('pc', 'jvm'):
234 | run_tests()
235 | else:
236 | if has_assert:
237 | pg.setup(run_tests_js)
238 | else:
239 | log.write('\nCheck doc/libtest.txt for information.')
240 |
241 |
242 | if __name__ == '__main__':
243 | main()
244 |
245 |
--------------------------------------------------------------------------------
/test/mask_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 |
4 |
5 | def init(environ):
6 | global env, pg
7 | env = environ
8 | pg = env['pg']
9 | tests = [test_mask,
10 | test_mask_from_surface,
11 | test_mask_from_threshold]
12 | return tests
13 |
14 |
15 | def test_mask():
16 | surface = pg.Surface((15,10),pg.SRCALPHA)
17 | pg.draw.rect(surface, (10,20,30), (0,0,4,3))
18 | mask = pg.mask.from_surface(surface)
19 | assert mask.get_size() == (15,10)
20 | assert mask.count() == 12
21 | assert mask.get_at((0,0)) == 1
22 | assert mask.get_at((4,0)) == 0
23 | mask.set_at((4,0))
24 | assert mask.get_at((4,0)) == 1
25 | assert mask.count() == 13
26 | assert bool(mask.overlap(mask, (0,0))) == True
27 | assert bool(mask.overlap(mask, (2,2))) == True
28 | assert bool(mask.overlap(mask, (5,5))) == False
29 | assert bool(mask.overlap(mask, (5,0))) == False
30 | assert bool(mask.overlap(mask, (0,5))) == False
31 | assert mask.get_at((8,0)) == 0
32 | mask.fill()
33 | assert mask.get_at((8,0)) == 1
34 | assert mask.count() == 150
35 | mask.clear()
36 | assert mask.get_at((8,0)) == 0
37 | assert mask.count() == 0
38 | mask.invert()
39 | assert mask.get_at((8,0)) == 1
40 | assert mask.count() == 150
41 |
42 |
43 | def test_mask_from_surface():
44 | surface = pg.Surface((15,10),pg.SRCALPHA)
45 | pg.draw.rect(surface, (10,20,30), (0,0,4,3))
46 | mask = pg.mask.from_surface(surface)
47 | assert mask.get_at((0,0)) == 1
48 | assert mask.get_at((3,0)) == 1
49 | assert mask.get_at((4,0)) == 0
50 | assert mask.get_at((0,1)) == 1
51 | assert mask.get_at((3,1)) == 1
52 | assert mask.get_at((4,1)) == 0
53 | assert mask.count() == 12
54 | mask = pg.mask.from_surface(surface,254)
55 | assert mask.get_at((0,0)) == 1
56 | assert mask.get_at((3,0)) == 1
57 | assert mask.get_at((4,0)) == 0
58 | assert mask.count() == 12
59 | mask = pg.mask.from_surface(surface,255)
60 | assert mask.get_at((0,0)) == 0
61 | assert mask.get_at((3,0)) == 0
62 | assert mask.get_at((4,0)) == 0
63 | assert mask.count() == 0
64 |
65 |
66 | def test_mask_from_threshold():
67 | surface = pg.Surface((15,10),pg.SRCALPHA)
68 | pg.draw.rect(surface, (50,100,150), (0,0,4,3))
69 | mask = pg.mask.from_threshold(surface, (50,100,150), (1,1,1,255))
70 | assert mask.get_at((0,0)) == 1
71 | assert mask.get_at((3,0)) == 1
72 | assert mask.get_at((4,0)) == 0
73 | assert mask.get_at((0,1)) == 1
74 | assert mask.get_at((3,1)) == 1
75 | assert mask.get_at((4,1)) == 0
76 | assert mask.count() == 12
77 | mask = pg.mask.from_threshold(surface, (50,100,150), (1,1,0,255))
78 | if env['platform'] in ('jvm', 'js'): #pg diff?
79 | assert mask.get_at((0,0)) == 1
80 | assert mask.get_at((3,0)) == 1
81 | assert mask.get_at((4,0)) == 0
82 | assert mask.count() == 12
83 | else:
84 | assert mask.count() == 0
85 | mask = pg.mask.from_threshold(surface, (50,100,150), (0,0,0,254))
86 | if env['platform'] in ('jvm', 'js'): #pg diff?
87 | assert mask.get_at((0,0)) == 1
88 | assert mask.get_at((3,0)) == 1
89 | assert mask.get_at((4,0)) == 0
90 | assert mask.count() == 12
91 | else:
92 | assert mask.count() == 0
93 | mask = pg.mask.from_threshold(surface, (50,100,150))
94 | if env['platform'] in ('jvm' 'js'): #pg diff?
95 | assert mask.get_at((0,0)) == 1
96 | assert mask.get_at((3,0)) == 1
97 | assert mask.get_at((4,0)) == 0
98 | assert mask.get_at((0,1)) == 1
99 | assert mask.get_at((3,1)) == 1
100 | assert mask.get_at((4,1)) == 0
101 | assert mask.count() == 12
102 | else:
103 | assert mask.count() == 0
104 |
105 |
--------------------------------------------------------------------------------
/test/rect_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 |
4 |
5 | def init(environ):
6 | global env, pg
7 | env = environ
8 | pg = env['pg']
9 | tests = [test_rect_constructor,
10 | test_rect_get,
11 | test_rect_comparison,
12 | test_rect_copy,
13 | test_rect_move,
14 | test_rect_inflate,
15 | test_rect_clip,
16 | test_rect_union,
17 | test_rect_collidepoint,
18 | test_rect_colliderect,
19 | test_rect_collidelist]
20 | return tests
21 |
22 |
23 | def test_rect_constructor():
24 | rect = pg.Rect(0,0,10,10)
25 | assert (rect.x,rect.y,rect.width,rect.height) == (0,0,10,10)
26 | rect = pg.Rect((0,0),(10,10))
27 | assert (rect.x,rect.y,rect.width,rect.height) == (0,0,10,10)
28 | rect = pg.Rect((0,0,10,10))
29 | assert (rect.x,rect.y,rect.width,rect.height) == (0,0,10,10)
30 | rect = pg.Rect(rect)
31 | assert (rect.x,rect.y,rect.width,rect.height) == (0,0,10,10)
32 | obj = pg.sprite.Sprite()
33 | obj.rect = rect
34 | rect = pg.Rect(obj)
35 | assert (rect.x,rect.y,rect.width,rect.height) == (0,0,10,10)
36 | assert (rect[0],rect[1],rect[2],rect[3]) == (0,0,10,10)
37 |
38 |
39 | def test_rect_get():
40 | rect = pg.Rect(0,0,10,10)
41 | rect.x,rect.y,rect.width,rect.height = 10,10,100,100
42 | assert (rect.x,rect.y,rect.width,rect.height) == (10,10,100,100)
43 | rect[0],rect[1],rect[2],rect[3] = 20,20,200,200
44 | assert (rect[0],rect[1],rect[2],rect[3]) == (20,20,200,200)
45 | r = pg.Rect(25,25,40,40)
46 | r.x = 30
47 | assert r.x==30 and (r.x,r.y,r.width,r.height)==(30,25,40,40)
48 | r.y = 40
49 | assert r.y==40 and (r.x,r.y,r.width,r.height)==(30,40,40,40)
50 | r.width = 50
51 | assert r.width==50 and (r.x,r.y,r.width,r.height)==(30,40,50,40)
52 | r.height = 60
53 | assert r.height==60 and (r.x,r.y,r.width,r.height)==(30,40,50,60)
54 | if not (env['pyjs_opt'] and not env['pyjs_attr']):
55 | #pyjs -O __getattr__/__setattr__ not called,
56 | #unless --enable-descriptor-proto option.
57 | r = pg.Rect(25,25,40,40)
58 | r.center = (10,20)
59 | assert r.center==(10,20) and (r.x,r.y,r.width,r.height)==(-10,0,40,40)
60 | r.centerx = 30
61 | assert r.centerx==30 and (r.x,r.y,r.width,r.height)==(10,0,40,40)
62 | r.centery = 40
63 | assert r.centery==40 and (r.x,r.y,r.width,r.height)==(10,20,40,40)
64 | r.top = 50
65 | assert r.top==50 and (r.x,r.y,r.width,r.height)==(10,50,40,40)
66 | r.left = 60
67 | assert r.left==60 and (r.x,r.y,r.width,r.height)==(60,50,40,40)
68 | r.bottom = 70
69 | assert r.bottom==70 and (r.x,r.y,r.width,r.height)==(60,30,40,40)
70 | r.right = 80
71 | assert r.right==80 and (r.x,r.y,r.width,r.height)==(40,30,40,40)
72 | r.topleft = (90,100)
73 | assert r.topleft==(90,100) and (r.x,r.y,r.width,r.height)==(90,100,40,40)
74 | r.bottomleft = (100,110)
75 | assert r.bottomleft==(100,110) and (r.x,r.y,r.width,r.height)==(100,70,40,40)
76 | r.topright = (120,130)
77 | assert r.topright==(120,130) and (r.x,r.y,r.width,r.height)==(80,130,40,40)
78 | r.bottomright = (140,150)
79 | assert r.bottomright==(140,150) and (r.x,r.y,r.width,r.height)==(100,110,40,40)
80 | r.midtop = (160,170)
81 | assert r.midtop==(160,170) and (r.x,r.y,r.width,r.height)==(140,170,40,40)
82 | r.midleft = (180,190)
83 | assert r.midleft==(180,190) and (r.x,r.y,r.width,r.height)==(180,170,40,40)
84 | r.midbottom = (200,210)
85 | assert r.midbottom==(200,210) and (r.x,r.y,r.width,r.height)==(180,170,40,40)
86 | r.midright = (220,230)
87 | assert r.midright==(220,230) and (r.x,r.y,r.width,r.height)==(180,210,40,40)
88 | r.size = (240,250)
89 | assert r.size==(240,250) and (r.x,r.y,r.width,r.height)==(180,210,240,250)
90 | r.w = 260
91 | assert r.w==260 and (r.x,r.y,r.width,r.height)==(180,210,260,250)
92 | r.h = 270
93 | assert r.h==270 and (r.x,r.y,r.width,r.height)==(180,210,260,270)
94 | r = pg.Rect(25,25,40,40)
95 | setattr(r, 'center', (10,20))
96 | assert getattr(r, 'center')==(10,20) and (r.x,r.y,r.width,r.height)==(-10,0,40,40)
97 |
98 |
99 | def test_rect_comparison():
100 | rect = pg.Rect(0,0,10,10)
101 | if env['platform'] != 'js':
102 | #pyjs compares rect==tuple not __eq__
103 | assert rect == (0,0,10,10)
104 | assert rect != (0,0,100,100)
105 | assert not (rect == (0,0,100,100))
106 | if not env['pyjs_opt']:
107 | #pyjs -O __eq__ not called
108 | assert rect == pg.Rect(0,0,10,10)
109 | assert rect != pg.Rect(0,0,100,100)
110 | assert not (rect == pg.Rect(0,0,100,100))
111 |
112 |
113 | def test_rect_copy():
114 | r1 = pg.Rect(0,0,100,100)
115 | r2 = r1.copy()
116 | if not env['pyjs_opt']:
117 | #pyjs -O __eq__ not called
118 | assert r1 == r2
119 | assert (r1.x,r1.y,r1.width,r1.height) == (r2.x,r2.y,r2.width,r2.height)
120 |
121 |
122 | def test_rect_move():
123 | r1 = pg.Rect(10,10,100,100)
124 | r2 = r1.move(10,5)
125 | assert (r1.x,r1.y) == (10,10) and (r2.x,r2.y) == (20,15)
126 | r1 = pg.Rect(10,10,100,100)
127 | r2 = r1.move((10,5))
128 | assert (r1.x,r1.y) == (10,10) and (r2.x,r2.y) == (20,15)
129 | r = pg.Rect(10,10,100,100)
130 | r.move_ip(10,5)
131 | assert (r.x,r.y) == (20,15)
132 | r = pg.Rect(10,10,100,100)
133 | r.move_ip((10,5))
134 | assert (r.x,r.y) == (20,15)
135 |
136 |
137 | def test_rect_inflate():
138 | r1 = pg.Rect(10,10,100,100)
139 | r2 = r1.inflate(10,20)
140 | assert (r1.width,r1.height) == (100,100) and (r2.width,r2.height) == (110,120)
141 | assert (r1.x,r1.y) == (10,10) and (r2.x,r2.y) == (5,0)
142 | r1 = pg.Rect(10,10,100,100)
143 | r2 = r1.inflate(-10,-20)
144 | assert (r1.width,r1.height) == (100,100) and (r2.width,r2.height) == (90,80)
145 | assert (r1.x,r1.y) == (10,10) and (r2.x,r2.y) == (15,20)
146 | r1 = pg.Rect(10,10,100,100)
147 | r2 = r1.inflate((10,20))
148 | assert (r1.width,r1.height) == (100,100) and (r2.width,r2.height) == (110,120)
149 | assert (r1.x,r1.y) == (10,10) and (r2.x,r2.y) == (5,0)
150 | r = pg.Rect(10,10,100,100)
151 | r.inflate_ip(10,20)
152 | assert (r.width,r.height) == (110,120)
153 | assert (r.x,r.y) == (5,0)
154 | r = pg.Rect(10,10,100,100)
155 | r.inflate_ip(-10,-20)
156 | assert (r.width,r.height) == (90,80)
157 | assert (r.x,r.y) == (15,20)
158 | r = pg.Rect(10,10,100,100)
159 | r.inflate_ip((10,20))
160 | assert (r.width,r.height) == (110,120)
161 | assert (r.x,r.y) == (5,0)
162 |
163 |
164 | def test_rect_clip():
165 | r1 = pg.Rect(0,0,100,150)
166 | r2 = pg.Rect(50,50,100,150)
167 | r3 = pg.Rect(200,200,50,100)
168 | r = r1.clip(r2)
169 | assert (r.x,r.y,r.width,r.height) == (50,50,50,100)
170 | r = r1.clip(r3)
171 | assert (r.x,r.y,r.width,r.height) == (0,0,0,0)
172 |
173 |
174 | def test_rect_union():
175 | r1 = pg.Rect(0,0,100,150)
176 | r2 = pg.Rect(50,50,100,150)
177 | r3 = pg.Rect(200,200,50,100)
178 | r4 = pg.Rect(-10,-10,50,100)
179 | r = r1.union(r2)
180 | assert (r.x,r.y,r.width,r.height) == (0,0,150,200)
181 | r = r1.copy()
182 | r.union_ip(r2)
183 | assert (r.x,r.y,r.width,r.height) == (0,0,150,200)
184 | r = r1.unionall([r2,r3,r4])
185 | assert (r.x,r.y,r.width,r.height) == (-10, -10, 260, 310)
186 | r = r1.copy()
187 | r.unionall_ip([r2,r3,r4])
188 | assert (r.x,r.y,r.width,r.height) == (-10, -10, 260, 310)
189 |
190 |
191 | def test_rect_collidepoint():
192 | r = pg.Rect(10,20,100,200)
193 | assert r.collidepoint((30,40)) == True
194 | assert r.collidepoint(50,60) == True
195 | assert r.collidepoint((5,5)) == False
196 |
197 |
198 | def test_rect_colliderect():
199 | r1 = pg.Rect(0,0,100,150)
200 | r2 = pg.Rect(50,50,100,150)
201 | r3 = pg.Rect(200,200,50,100)
202 | assert r1.colliderect(r2) == True
203 | assert r1.colliderect(r3) == False
204 |
205 |
206 | def test_rect_collidelist():
207 | r1 = pg.Rect(0,0,100,150)
208 | r2 = pg.Rect(50,50,100,150)
209 | r3 = pg.Rect(200,200,50,100)
210 | r4 = pg.Rect(75,80,50,50)
211 | assert r1.collidelist([r2,r3,r4]) == 0
212 | assert r1.collidelist([r3,r4,r2]) == 1
213 | assert r1.collidelist([r3]) == -1
214 |
215 |
--------------------------------------------------------------------------------
/test/sprite_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 |
4 |
5 | def init(environ):
6 | global env, pg
7 | env = environ
8 | pg = env['pg']
9 | tests = [test_sprite,
10 | test_sprite_group]
11 | return tests
12 |
13 |
14 | def test_sprite():
15 | Sprite = pg.sprite.Sprite
16 | Group = pg.sprite.Group
17 | g = [Group() for i in range(20)]
18 | sx, rx, i = {}, {}, 10
19 | sx[0] = Sprite()
20 | sx[1] = Sprite(*g)
21 | sx[2] = Sprite(g)
22 | sx[3] = Sprite([])
23 | sx[4] = Sprite(g[0])
24 | sx[5] = Sprite([g[0],g[1]])
25 | sx[6] = Sprite([g])
26 | sx[7] = Sprite([g],g)
27 | sx[8] = Sprite(g); sx[8].remove(g[0]); sx[8].remove([g[0],g[1]],g[10])
28 | sx[9] = Sprite(g); sx[9].kill()
29 | sx[0+i] = Sprite(); sx[0+i].add()
30 | sx[1+i] = Sprite(); sx[1+i].add(*g)
31 | sx[2+i] = Sprite(); sx[2+i].add(g)
32 | sx[3+i] = Sprite(); sx[3+i].add([])
33 | sx[4+i] = Sprite(); sx[4+i].add(g[0])
34 | sx[5+i] = Sprite(); sx[5+i].add([g[0],g[1]])
35 | sx[6+i] = Sprite(); sx[6+i].add([g])
36 | sx[7+i] = Sprite(); sx[7+i].add([g],g)
37 | sx[8+i] = Sprite(); sx[8+i].add(g); sx[8+i].remove(g[0]); sx[8+i].remove([g[0],g[1]],g[10])
38 | sx[9+i] = Sprite(); sx[9+i].add(g); sx[9+i].kill()
39 | rx[0] = rx[0+i] = [ 0, False ]
40 | rx[1] = rx[1+i] = [ 20, True ]
41 | rx[2] = rx[2+i] = [ 20, True ]
42 | rx[3] = rx[3+i] = [ 0, False ]
43 | rx[4] = rx[4+i] = [ 1, True ]
44 | rx[5] = rx[5+i] = [ 2, True ]
45 | rx[6] = rx[6+i] = [ 20, True ]
46 | rx[7] = rx[7+i] = [ 20, True ]
47 | rx[8] = rx[8+i] = [ 17, True ]
48 | rx[9] = rx[9+i] = [ 0, False ]
49 | for i in range(20):
50 | s,r = sx[i],rx[i]
51 | assert len(s.groups()) == r[0]
52 | assert s.alive() == r[1]
53 |
54 |
55 | def test_sprite_group():
56 | for Group in (pg.sprite.Group,
57 | pg.sprite.RenderUpdates,
58 | pg.sprite.OrderedUpdates,
59 | pg.sprite.LayeredUpdates):
60 | Sprite = pg.sprite.Sprite
61 | s = [Sprite() for i in range(20)]
62 | grp = Group(s)
63 | gx, rx, i = {}, {}, 12
64 | gx[0] = Group()
65 | gx[1] = Group(*s)
66 | gx[2] = Group(s)
67 | gx[3] = Group([])
68 | gx[4] = Group(s[0])
69 | gx[5] = Group([s[0],s[1]])
70 | gx[6] = Group([s])
71 | gx[7] = Group([s],s)
72 | gx[8] = Group(grp)
73 | gx[9] = Group([grp])
74 | gx[10] = Group(s); gx[8].remove(s[0]); gx[8].remove([s[0],s[1]],s[10])
75 | gx[11] = Group(s); gx[9].empty()
76 | gx[0+i] = Group(); gx[0+i].add()
77 | gx[1+i] = Group(); gx[1+i].add(*s)
78 | gx[2+i] = Group(); gx[2+i].add(s)
79 | gx[3+i] = Group(); gx[3+i].add([])
80 | gx[4+i] = Group(); gx[4+i].add(s[0])
81 | gx[5+i] = Group(); gx[5+i].add([s[0],s[1]])
82 | gx[6+i] = Group(); gx[6+i].add([s])
83 | gx[7+i] = Group(); gx[7+i].add([s],s)
84 | gx[8+i] = Group(); gx[8+i].add(grp)
85 | gx[9+i] = Group(); gx[9+i].add([grp])
86 | gx[10+i] = Group(s); gx[10+i].add(s); gx[10+i].remove(s[0]); gx[10+i].remove([s[0],s[1]],s[10])
87 | gx[11+i] = Group(s); gx[11+i].add(s); gx[11+i].empty()
88 | rx[0] = rx[0+i] = [ 0, False, False, False ]
89 | rx[1] = rx[1+i] = [ 20, True, True, True ]
90 | rx[2] = rx[2+i] = [ 20, True, True, True ]
91 | rx[3] = rx[3+i] = [ 0, False, False, False ]
92 | rx[4] = rx[4+i] = [ 1, True, False, False ]
93 | rx[5] = rx[5+i] = [ 2, True, False, False ]
94 | rx[6] = rx[6+i] = [ 20, True, True, True ]
95 | rx[7] = rx[7+i] = [ 20, True, True, True ]
96 | rx[8] = rx[8+i] = [ 20, True, True, True ]
97 | rx[9] = rx[9+i] = [ 20, True, True, True ]
98 | rx[10] = rx[10+i] = [ 17, False, False, True ]
99 | rx[11] = rx[11+i] = [ 0, False, False, False ]
100 | for x in range(i*2):
101 | g,r = gx[i],rx[i]
102 | assert len(g.sprites()) == r[0]
103 | assert g.has(s[0]) == r[1]
104 | assert g.has([s[0],s[1],s[2]]) == r[2]
105 | assert g.has([s[2],s[5]],s[6]) == r[3]
106 |
107 |
--------------------------------------------------------------------------------
/test/surface_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 | surface = None
4 | width = None
5 | height = None
6 |
7 |
8 | def init(environ):
9 | global env, pg, surface, width, height
10 | env = environ
11 | pg = env['pg']
12 | surface = env['surface']
13 | width = env['width']
14 | height = env['height']
15 | tests = [test_surface_get_size,
16 | test_surface_get_rect,
17 | test_surface_copy,
18 | test_surface_blit,
19 | test_surface_fill,
20 | test_surface_set_colorkey,
21 | test_surface_get_colorkey,
22 | test_surface_set_at,
23 | test_surface_get_at]
24 | return tests
25 |
26 |
27 | def _color_convert(color):
28 | if len(color) == 4:
29 | r,g,b,a = color[0],color[1],color[2],color[3]
30 | else:
31 | r,g,b,a = color[0],color[1],color[2],255
32 | return r,g,b,a
33 |
34 |
35 | def test_surface_get_size():
36 | assert surface.get_size() == (width,height)
37 | assert surface.get_width() == width
38 | assert surface.get_height() == height
39 |
40 |
41 | def test_surface_get_rect():
42 | rect = surface.get_rect()
43 | if env['platform'] != 'js': #pyjs compares rect==tuple not __eq__
44 | assert rect == (0,0,width,height)
45 | assert (rect.x,rect.y,rect.width,rect.height) == (0,0,width,height)
46 | rect = surface.get_rect(center=(15,15))
47 | assert (rect.x,rect.y,rect.width,rect.height) == (5,5,width,height)
48 |
49 |
50 | def test_surface_copy():
51 | new_surface = surface.copy()
52 | assert surface == surface
53 | assert surface != new_surface
54 | assert surface.get_size() == new_surface.get_size()
55 |
56 |
57 | def test_surface_blit():
58 | new_surface = pg.Surface((5,5))
59 | surface.fill((0,0,0))
60 | new_surface.fill((100,100,100))
61 | rect = surface.blit(new_surface, (1,0))
62 | if env['executor'] != 'pyjs':
63 | assert surface.get_at((0,0)) == (0,0,0,255)
64 | assert surface.get_at((1,0)) == (100,100,100,255)
65 | else:
66 | if not env['pyjs_opt']: #pyjs -s compares color==tuple not __eq__
67 | assert surface.get_at((0,0)) == pg.Color(0,0,0,255)
68 | assert surface.get_at((1,0)) == pg.Color(100,100,100,255)
69 | else: #pyjs -O __eq__ ignored
70 | c = surface.get_at((0,0))
71 | assert (c.r,c.g,c.b,c.a) == (0,0,0,255)
72 | c = surface.get_at((1,0))
73 | assert (c.r,c.g,c.b,c.a) == (100,100,100,255)
74 | assert (rect.x,rect.y,rect.width,rect.height) == (1,0,5,5)
75 |
76 |
77 | def test_surface_fill():
78 | color = (255,0,0), (0,255,0,255)
79 | for c in color:
80 | surface.fill((0,0,0))
81 | surface.fill(pg.Color(c))
82 | if env['executor'] != 'pyjs':
83 | assert surface.get_at((0,0)) == c
84 | else:
85 | cc = surface.get_at((0,0))
86 | assert (cc[0],cc[1],cc[2],cc[3]) == _color_convert(c)
87 |
88 |
89 | def test_surface_set_colorkey():
90 | color = (255,0,0), (0,255,0,255), None
91 | for c in color:
92 | surface.set_colorkey(c)
93 | if surface.get_colorkey():
94 | if not env['pyjs_opt']:
95 | assert pg.Color(*surface.get_colorkey()) == pg.Color(*c)
96 | else: #pyjs -O no __eq__ call
97 | r,g,b,a = pg.Color(*surface.get_colorkey())
98 | cr,cg,cb,ca = pg.Color(*c)
99 | assert r==cr and g==cg and b==cb and a==ca
100 |
101 |
102 | def test_surface_get_colorkey():
103 | surface.fill((0,0,0))
104 | surface.set_colorkey((0,0,0))
105 | assert surface.get_colorkey() == (0,0,0,255)
106 | surface.set_colorkey(None)
107 | assert surface.get_colorkey() is None
108 |
109 |
110 | def test_surface_set_at():
111 | color = (255,0,0), (0,255,0,255)
112 | for c in color:
113 | surface.fill((0,0,0))
114 | surface.set_at((0,0), c)
115 | if env['executor'] != 'pyjs':
116 | assert surface.get_at((0,0)) == c
117 | else: #pyjs compares color==tuple not __eq__
118 | cc = surface.get_at((0,0))
119 | assert (cc.r,cc.g,cc.b,cc.a) == _color_convert(c)
120 |
121 |
122 | def test_surface_get_at():
123 | color = (0,0,255,255)
124 | surface.fill((0,0,0))
125 | surface.set_at((0,0), (0,0,255,255))
126 | if env['executor'] != 'pyjs':
127 | assert surface.get_at((0,0)) == (0,0,255,255)
128 | assert surface.get_at((0,0)) == (0,0,255)
129 | else: #pyjs compares color==tuple not __eq__
130 | cc = surface.get_at((0,0))
131 | assert (cc.r,cc.g,cc.b,cc.a) == (0,0,255,255)
132 |
133 |
--------------------------------------------------------------------------------
/test/surfarray_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 |
4 |
5 | def init(environ):
6 | global env, pg
7 | env = environ
8 | pg = env['pg']
9 | tests = [test_surfarray_blit_array,
10 | test_surfarray_make_surface,
11 | test_surfarray_array2d,
12 | test_surfarray_array3d,
13 | test_surfarray_array_alpha]
14 | return tests
15 |
16 |
17 | def test_surfarray_blit_array():
18 | if env['platform'] == 'jvm':
19 | try:
20 | pg.surfarray._init()
21 | except ImportError:
22 | raise NotImplementedError
23 | surface = pg.Surface((15,10))
24 | surface.fill((0,0,0))
25 | array2d = pg.surfarray.array2d(surface)
26 | surface.fill((255,0,0))
27 | if env['executor'] != 'pyjs':
28 | assert surface.get_at((0,0)) == (255,0,0,255)
29 | else:
30 | c = surface.get_at((0,0))
31 | assert (c.r,c.g,c.b,c.a) == (255,0,0,255)
32 | pg.surfarray.blit_array(surface, array2d)
33 | if env['executor'] != 'pyjs':
34 | assert surface.get_at((0,0)) == (0,0,0,255)
35 | else:
36 | c = surface.get_at((0,0))
37 | assert (c.r,c.g,c.b,c.a) == (0,0,0,255)
38 | surface = pg.Surface((15,10))
39 | surface.fill((0,0,0))
40 | array3d = pg.surfarray.array3d(surface)
41 | surface.fill((255,0,0))
42 | if env['executor'] != 'pyjs':
43 | assert surface.get_at((0,0)) == (255,0,0,255)
44 | else:
45 | c = surface.get_at((0,0))
46 | assert (c.r,c.g,c.b,c.a) == (255,0,0,255)
47 | pg.surfarray.blit_array(surface, array3d)
48 | if env['executor'] != 'pyjs':
49 | assert surface.get_at((0,0)) == (0,0,0,255)
50 | else:
51 | c = surface.get_at((0,0))
52 | assert (c.r,c.g,c.b,c.a) == (0,0,0,255)
53 |
54 |
55 | def test_surfarray_make_surface():
56 | if env['platform'] == 'jvm':
57 | try:
58 | pg.surfarray._init()
59 | except ImportError:
60 | raise NotImplementedError
61 | surface = pg.Surface((15,10))
62 | surface.fill((255,0,0))
63 | if env['platform'] in ('jvm', 'js'):
64 | array2d = pg.surfarray.array2d(surface)
65 | surface2d = pg.surfarray.make_surface(array2d)
66 | if env['executor'] != 'pyjs':
67 | assert surface2d.get_size() == (15,10)
68 | assert surface2d.get_at((0,0)) == (255,0,0,255)
69 | else:
70 | c = surface.get_at((0,0))
71 | assert (c.r,c.g,c.b,c.a) == (255,0,0,255)
72 | array3d = pg.surfarray.array3d(surface)
73 | surface3d = pg.surfarray.make_surface(array3d)
74 | assert surface3d.get_size() == (15,10)
75 | if env['executor'] != 'pyjs':
76 | assert surface3d.get_at((0,0)) == (255,0,0,255)
77 | else:
78 | c = surface.get_at((0,0))
79 | assert (c.r,c.g,c.b,c.a) == (255,0,0,255)
80 |
81 |
82 | def test_surfarray_array2d():
83 | if env['platform'] == 'jvm':
84 | try:
85 | pg.surfarray._init()
86 | except ImportError:
87 | raise NotImplementedError
88 | surface = pg.Surface((15,10))
89 | surface.fill((0,0,0))
90 | array = pg.surfarray.array2d(surface)
91 | for i in range(10):
92 | array[0,i] = 255
93 | assert array[0,0] == 255
94 | assert array[0,1]>>24 & 0xff == 0
95 | if env['platform'] == 'jvm': #array has alpha
96 | assert array[1,0]>>24 & 0xff == 255
97 | surface2 = pg.Surface((15,10), pg.SRCALPHA)
98 | array2 = pg.surfarray.array2d(surface2)
99 | for i in range(10):
100 | array2[0,i] = 255
101 | assert array2[0,0] == 255
102 | assert array2[1,0] == 0
103 | if env['platform'] == 'js':
104 | array = pg.surfarray.array2d(surface, True)
105 | for i in range(10):
106 | array[0,i] = 255
107 | assert array[0,0] == 255
108 | surface2 = pg.Surface((15,10), pg.SRCALPHA)
109 | array2 = pg.surfarray.array2d(surface2, True)
110 | for i in range(10):
111 | array2[0,i] = 255
112 | assert array2[0,0] == 255
113 | assert array2[1,0] == 0
114 |
115 |
116 | def test_surfarray_array3d():
117 | if env['platform'] == 'jvm':
118 | try:
119 | pg.surfarray._init()
120 | except:
121 | raise NotImplementedError
122 | surface = pg.Surface((15,10))
123 | surface.fill((0,0,0))
124 | array = pg.surfarray.array3d(surface)
125 | if env['platform'] != 'js':
126 | assert array.shape == (15,10,3)
127 | else:
128 | if not env['pyjs_opt']:
129 | assert array.shape == (10,15,4)
130 | else:
131 | assert array.getshape() == (10,15,4)
132 | for i in range(10):
133 | array[0,i] = (0,0,255)
134 | assert array[0,0,2] == 255
135 | assert array[1,0,2] == 0
136 | if env['platform'] == 'js':
137 | array = pg.surfarray.array3d(surface, True)
138 | if not env['pyjs_opt']:
139 | assert array.shape == (15,10,3)
140 | else:
141 | assert array.getshape() == (15,10,3)
142 | for i in range(10):
143 | array[0,i] = (0,0,255)
144 | assert array[0,0,2] == 255
145 | assert array[1,0,2] == 0
146 |
147 |
148 | def test_surfarray_array_alpha():
149 | if env['platform'] == 'jvm':
150 | try:
151 | pg.surfarray._init()
152 | except ImportError:
153 | raise NotImplementedError
154 | surface = pg.Surface((15,10))
155 | surface.fill((0,0,0))
156 | array = pg.surfarray.array_alpha(surface)
157 | if env['platform'] != 'js':
158 | assert array.shape == (15,10)
159 | else:
160 | if not env['pyjs_opt']:
161 | assert array.shape == (10,15,4)
162 | else:
163 | assert array.getshape() == (10,15,4)
164 | assert array[1,1] & 0xff == 255
165 | surface2 = pg.Surface((15,10),pg.SRCALPHA)
166 | array2 = pg.surfarray.array_alpha(surface2)
167 | for i in range(10):
168 | array2[0,i] = 255
169 | assert array2[0,0] & 0xff == 255
170 | assert array2[1,0] & 0xff == 0
171 | if env['platform'] == 'js':
172 | array = pg.surfarray.array_alpha(surface)
173 | assert array[1,1] & 0xff == 255
174 | surface2 = pg.Surface((15,10),pg.SRCALPHA)
175 | array2 = pg.surfarray.array_alpha(surface2)
176 | for i in range(10):
177 | array2[0,i] = 255
178 | assert array2[0,0] & 0xff == 255
179 | assert array2[1,0] & 0xff == 0
180 |
181 |
--------------------------------------------------------------------------------
/test/time_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 | wait = 0
4 |
5 |
6 | def init(environ):
7 | global env, pg
8 | env = environ
9 | pg = env['pg']
10 | tests = [test_time_delay,
11 | test_time_wait,
12 | test_time_timer]
13 | return tests
14 |
15 |
16 | def test_time_delay():
17 | _time = 30
18 | t = pg.time.get_ticks()
19 | pg.time.delay(_time)
20 | assert (pg.time.get_ticks()-t) >= _time
21 |
22 |
23 | def test_time_wait():
24 | global wait
25 | _time = 30
26 | if env['platform'] != 'js':
27 | t = pg.time.get_ticks()
28 | pg.time.wait(_time)
29 | assert (pg.time.get_ticks()-t) >= _time
30 | else:
31 | if not wait:
32 | wait = pg.time.get_ticks()
33 | pg.time.wait(_time)
34 | return True
35 | else:
36 | assert (pg.time.get_ticks()-wait) >= _time
37 | wait = 0
38 | return False
39 |
40 |
41 | def test_time_timer():
42 | global wait
43 | _time = 30
44 | event = pg.USEREVENT
45 | if env['platform'] != 'js':
46 | t = pg.time.get_ticks()
47 | pg.event.clear()
48 | pg.time.set_timer(event, _time)
49 | evt = pg.event.wait()
50 | pg.time.set_timer(event, 0)
51 | assert evt.type == event
52 | assert (pg.time.get_ticks()-t) >= _time
53 | else:
54 | if not wait:
55 | wait = pg.time.get_ticks()
56 | pg.event.clear()
57 | pg.time.set_timer(event, _time)
58 | pg.time.wait(_time)
59 | return True
60 | else:
61 | evt = pg.event.get()[0]
62 | pg.time.set_timer(event, 0)
63 | assert evt.type == event
64 | assert (pg.time.get_ticks()-wait) >= _time
65 | wait = 0
66 | return False
67 |
68 |
--------------------------------------------------------------------------------
/test/transform_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 | surface = None
4 | width = None
5 | height = None
6 |
7 |
8 | def init(environ):
9 | global env, pg, surface, width, height
10 | env = environ
11 | pg = env['pg']
12 | surface = env['surface']
13 | width = env['width']
14 | height = env['height']
15 | tests = [test_transform_rotate,
16 | test_transform_rotozoom,
17 | test_transform_scale,
18 | test_transform_flip]
19 | return tests
20 |
21 |
22 | def test_transform_rotate():
23 | surface.fill((0,0,0))
24 | surface.fill((255,0,0), (0,0,width//2,height))
25 | surf = pg.transform.rotate(surface, 180)
26 | assert surf.get_size() == (width, height)
27 | assert surf.get_at((5,5)).r == 0 and surf.get_at((width-5,5)).r == 255
28 |
29 |
30 | def test_transform_rotozoom():
31 | surface.fill((0,0,0))
32 | surface.fill((255,0,0), (0,0,width//2,height))
33 | surf = pg.transform.rotozoom(surface, 180, 2.0)
34 | assert int(surf.get_width()/width) == 2 and int(surf.get_height()/height) == 2
35 | assert surf.get_at((5,5)).r == 0 and surf.get_at((width*2-5,5)).r == 255
36 |
37 |
38 |
39 | def test_transform_scale():
40 | surface.fill((0,0,0))
41 | surface.fill((255,0,0), (0,0,width//2,height))
42 | size = (width*2, height*2)
43 | surf = pg.transform.scale(surface, size)
44 | assert int(surf.get_width()/width) == 2 and int(surf.get_height()/height) == 2
45 | assert surf.get_at((5,5)).r == 255 and surf.get_at((width*2-5,5)).r == 0
46 | surf = pg.transform.smoothscale(surface, size)
47 | assert int(surf.get_width()/width) == 2 and int(surf.get_height()/height) == 2
48 | assert surf.get_at((5,5)).r == 255 and surf.get_at((width*2-5,5)).r == 0
49 | surf = pg.transform.scale2x(surface)
50 | assert int(surf.get_width()/width) == 2 and int(surf.get_height()/height) == 2
51 | assert surf.get_at((5,5)).r == 255 and surf.get_at((width*2-5,5)).r == 0
52 |
53 |
54 | def test_transform_flip():
55 | surface.fill((0,0,0))
56 | surface.fill((255,0,0), (0,0,width//2,height))
57 | surf = pg.transform.flip(surface, True, False)
58 | assert surf.get_size() == (width, height)
59 | assert surf.get_at((5,5)).r == 0 and surf.get_at((width-5,5)).r == 255
60 | surf = pg.transform.flip(surface, False, True)
61 | assert surf.get_size() == (width, height)
62 | assert surf.get_at((5,5)).r == 255 and surf.get_at((width-5,5)).r == 0
63 | surf = pg.transform.flip(surface, True, True)
64 | assert surf.get_size() == (width, height)
65 | assert surf.get_at((5,5)).r == 0 and surf.get_at((width-5,5)).r == 255
66 |
67 |
--------------------------------------------------------------------------------
/test/vector_test.py:
--------------------------------------------------------------------------------
1 | env = None
2 | pg = None
3 |
4 |
5 | def init(environ):
6 | global env, pg
7 | env = environ
8 | pg = env['pg']
9 | tests = [test_vector_constructor,
10 | test_vector_update,
11 | test_vector_get,
12 | test_vector_operator,
13 | test_vector_magnitude,
14 | test_vector_direction,
15 | test_vector_dot,
16 | test_vector_cross,
17 | test_vector_lerp]
18 | return tests
19 |
20 |
21 | def _rd(val):
22 | return round(val, 3)
23 |
24 |
25 | def test_vector_constructor():
26 | Vector2 = pg.Vector2
27 | v = Vector2(2.2, 3.0)
28 | assert v.x == 2.2 and v.y == 3.0
29 | v = Vector2((2.2, 3.0))
30 | assert v.x == 2.2 and v.y == 3.0
31 | v = Vector2(v)
32 | assert v.x == 2.2 and v.y == 3.0
33 |
34 |
35 | def test_vector_update():
36 | Vector2 = pg.Vector2
37 | v = Vector2(0.0, 0.0)
38 | v.update(2.2, 3.0)
39 | assert v.x == 2.2 and v.y == 3.0
40 | v.update((3.2, 4.0))
41 | assert v.x == 3.2 and v.y == 4.0
42 | v.update(v)
43 | assert v.x == 3.2 and v.y == 4.0
44 |
45 |
46 | def test_vector_get():
47 | Vector2 = pg.Vector2
48 | v = Vector2(0.0, 0.0)
49 | assert v.x == 0.0 and v.y == 0.0
50 | assert v[0] == 0.0 and v[1] == 0.0
51 | v.x = 1.0
52 | v.y = 1.0
53 | assert v.x == 1.0 and v.y == 1.0
54 | assert v[0] == 1.0 and v[1] == 1.0
55 | v[0] = 2.0
56 | v[1] = 2.0
57 | assert v.x == 2.0 and v.y == 2.0
58 | assert v[0] == 2.0 and v[1] == 2.0
59 | x, y = v[0], v[1]
60 | assert x == 2.0 and y == 2.0
61 | x, y = v
62 | assert x == 2.0 and y == 2.0
63 | vl = []
64 | for _v in v:
65 | vl.append(_v)
66 | assert vl[0] == 2.0 and vl[1] == 2.0
67 |
68 |
69 | def test_vector_operator():
70 | Vector2 = pg.Vector2
71 | v1 = Vector2(2.2, 3.0)
72 | v2 = Vector2(3.0, 4.0)
73 | if not (env['pyjs_opt'] and not env['pyjs_attr']):
74 | v = v1 + v2
75 | assert v.x == 5.2 and v.y == 7.0
76 | v = v1 + (5.0, 5.0)
77 | assert v.x == 7.2 and v.y == 8.0
78 | v = v1 - (1.0, 1.0)
79 | assert _rd(v.x) == 1.2 and v.y == 2.0
80 | v += v1
81 | assert _rd(v.x) == 3.4 and v.y == 5.0
82 | v -= (1.0, 1.0)
83 | assert _rd(v.x) == 2.4 and v.y == 4.0
84 | v = v1 * v2
85 | assert v == 18.6
86 | v = v1 * (3.0, 4.0)
87 | assert v == 18.6
88 | else:
89 | v = Vector2(v1)
90 | assert v.x == 2.2 and v.y == 3.0
91 | v.x = v.x + 1.0
92 | v.y = v.y + 2.0
93 | assert v.x == 3.2 and v.y == 5.0
94 | v.x += 0.5
95 | v.y -= 0.5
96 | assert v.x == 3.7 and v.y == 4.5
97 | if not (env['pyjs_opt'] and not env['pyjs_attr']):
98 | #-S / -O --enable-descriptor-proto --enable-operator-funcs
99 | #unable cmp vector to tuple
100 | el = v1.elementwise()
101 | v = el + v2
102 | assert v.x == 5.2 and v.y == 7.0
103 | v1 = Vector2(2.0, 3.0)
104 | v2 = Vector2(3.0, 4.0)
105 | vx = v1 + v2
106 | if not env['pyjs_opt']:
107 | assert vx == Vector2(5.0, 7.0)
108 | else: #__eq__ not called
109 | assert (vx.x, vx.y) == (5.0, 7.0)
110 | if not env['pyjs_opt']:
111 | assert (v1 + v2) == Vector2(5.0, 7.0)
112 | assert (v1 + (3.0,4.0)) == Vector2(5.0, 7.0)
113 | assert (v1 - v2) == Vector2(-1.0, -1.0)
114 | assert (v1 - (3.0,4.0)) == Vector2(-1.0, -1.0)
115 | assert (v1 * v2) == 18.0
116 | assert (v1 * (3.0,4.0)) == 18.0
117 | assert (v1 * 2) == Vector2(4.0, 6.0)
118 | assert (v1 / 2) == Vector2(1.0, 1.5)
119 | assert (v1 // 2) == Vector2(1.0, 1.0)
120 | if env['platform'] != 'js': ##
121 | assert ((2.0,3.0) + v2) == Vector2(5.0, 7.0)
122 | assert ((2.0,3.0) - v2) == Vector2(-1.0, -1.0)
123 | assert ((2.0,3.0) * v2) == 18.0
124 | assert (2 * v2) == Vector2(6.0, 8.0)
125 | v = Vector2(v1)
126 | v += v2
127 | assert v == Vector2(5.0, 7.0)
128 | v = Vector2(v1)
129 | v += (3.0,4.0)
130 | assert v == Vector2(5.0, 7.0)
131 | v = Vector2(v1)
132 | v -= v2
133 | assert v == Vector2(-1.0, -1.0)
134 | v = Vector2(v1)
135 | v -= (3.0,4.0)
136 | assert v == Vector2(-1.0, -1.0)
137 | v = Vector2(v1)
138 | v *= v2
139 | assert v == 18.0
140 | v = Vector2(v1)
141 | v *= (3.0,4.0)
142 | assert v == 18.0
143 | v = Vector2(v1)
144 | v *= 2
145 | assert v == Vector2(4.0, 6.0)
146 | v = Vector2(v1)
147 | v /= 2
148 | assert v == Vector2(1.0, 1.5)
149 | v = Vector2(v1)
150 | v //= 2
151 | assert v == Vector2(1.0, 1.0)
152 | v = Vector2(v1)
153 | el = v.elementwise()
154 | assert (el + v2) == Vector2(5.0, 7.0)
155 | assert (el - v2) == Vector2(-1.0, -1.0)
156 | assert (el * v2) == Vector2(6.0, 12.0)
157 | vx = (el / v2)
158 | assert (_rd(vx[0]), _rd(vx[1])) == (0.667, 0.75)
159 | assert (el // v2) == Vector2(0.0, 0.0)
160 | assert (v2 + el) == Vector2(5.0, 7.0)
161 | assert (v2 - el) == Vector2(1.0, 1.0)
162 | assert (v2 * el) == Vector2(6.0, 12.0)
163 | vx = (v2 / el)
164 | assert (_rd(vx[0]), _rd(vx[1])) == (1.5, 1.333)
165 | assert (v2 // el) == Vector2(1.0, 1.0)
166 | assert (el + (3.0,4.0)) == Vector2(5.0, 7.0)
167 | assert (el - (3.0,4.0)) == Vector2(-1.0, -1.0)
168 | assert (el * (3.0,4.0)) == Vector2(6.0, 12.0)
169 | vx = (el / (3.0,4.0))
170 | assert (_rd(vx[0]), _rd(vx[1])) == (0.667, 0.75)
171 | assert (el // (3.0,4.0)) == Vector2(0.0, 0.0)
172 | if env['platform'] != 'js':
173 | assert ((3.0,4.0) + el) == Vector2(5.0, 7.0)
174 | assert ((3.0,4.0) - el) == Vector2(1.0, 1.0)
175 | assert ((3.0,4.0) * el) == Vector2(6.0, 12.0)
176 | vx = ((3.0,4.0) / el)
177 | assert (_rd(vx[0]), _rd(vx[1])) == (1.5, 1.333)
178 | assert ((3.0,4.0) // el) == (1.0, 1.0)
179 | assert (el + 2) == Vector2(4.0, 5.0)
180 | assert (el - 2) == Vector2(0.0, 1.0)
181 | assert (el * 2) == Vector2(4.0, 6.0)
182 | assert (el / 2) == Vector2(1.0, 1.5)
183 | assert (el // 2) == Vector2(1.0, 1.0)
184 | assert (2 + el) == Vector2(4.0, 5.0)
185 | assert (2 - el) == Vector2(0.0, -1.0)
186 | assert (2 * el) == Vector2(4.0, 6.0)
187 | vx = (2 / el)
188 | assert (_rd(vx[0]), _rd(vx[1])) == (1.0, 0.667)
189 | assert (2 // el) == Vector2(1.0, 0.0)
190 | assert (v1 == v1) == True
191 | assert (v1 == v2) == False
192 | assert (v1 != v1) == False
193 | assert (v1 != v2) == True
194 | assert (v1 == Vector2(2.0,3.0)) == True
195 | assert (v1 == Vector2(3.0,4.0)) == False
196 | assert (v1 != Vector2(2.0,3.0)) == False
197 | assert (v1 != Vector2(3.0,4.0)) == True
198 | assert (v1 == 2) == False
199 | assert (v1 != 2) == True
200 | assert (el == el) == True
201 | assert (el != el) == False
202 | if env['platform'] != 'js': ##pyjs cmp obj identity
203 | assert (el == v1) == True
204 | assert (el == v2) == False
205 | assert (el != v1) == False
206 | assert (el != v2) == True
207 | assert (el == (2.0,3.0)) == True
208 | assert (el == (3.0,4.0)) == False
209 | assert (el != (2.0,3.0)) == False
210 | assert (el != (3.0,4.0)) == True
211 |
212 | def test_vector_magnitude():
213 | Vector2 = pg.Vector2
214 | v1 = Vector2(2.2, 3.0)
215 | v2 = Vector2(6.0, 8.0)
216 | if env['platform'] != 'js':
217 | assert _rd(v1.magnitude()) == _rd(v1.length()) == 3.720
218 | else: #length is js keyword
219 | assert _rd(v1.magnitude()) == 3.720
220 | assert _rd(v1.magnitude_squared()) == _rd(v1.length_squared()) == 13.84
221 | v = v1.normalize()
222 | assert _rd(v.x) == 0.591 and _rd(v.y) == 0.806
223 | v = Vector2(v1)
224 | v.normalize_ip()
225 | assert _rd(v.x) == 0.591 and _rd(v.y) == 0.806
226 | assert v.is_normalized() == True
227 | v.scale_to_length(10)
228 | assert _rd(v.x) == 5.914 and _rd(v.y) == 8.064
229 | assert _rd(v1.distance_to(v2)) == 6.28
230 | assert _rd(v1.distance_squared_to(v2)) == 39.44
231 |
232 |
233 | def test_vector_direction():
234 | Vector2 = pg.Vector2
235 | v1 = Vector2(2.0, 3.0)
236 | v2 = Vector2(6.0, 8.0)
237 | v3 = Vector2(0.0, 5.0)
238 | v4 = Vector2(0.0, -5.0)
239 | assert _rd(v1.angle_to(v2)) == -3.180
240 | assert _rd(v3.angle_to(v4)) == -180.0
241 | v = v1.rotate(30)
242 | assert _rd(v.x) == 0.232 and _rd(v.y) == 3.598
243 | # if env['platform'] in ('jvm', 'js'):
244 | v = v1.rotate_rad(1.0)
245 | assert _rd(v.x) == -1.444 and _rd(v.y) == 3.304
246 | v = Vector2(v1)
247 | v.rotate_ip(30)
248 | assert _rd(v.x) == 0.232 and _rd(v.y) == 3.598
249 | # if env['platform'] in ('jvm', 'js'):
250 | v = Vector2(v1)
251 | v.rotate_ip_rad(1.0)
252 | assert _rd(v.x) == -1.444 and _rd(v.y) == 3.304
253 | v = v1.reflect(v2)
254 | assert _rd(v.x) == -2.32 and _rd(v.y) == -2.76
255 | v = Vector2(v1)
256 | v.reflect_ip(v2)
257 | assert _rd(v.x) == -2.32 and _rd(v.y) == -2.76
258 | r = v1.as_polar()
259 | assert _rd(r[0]) == 3.606 and _rd(r[1]) == 56.310
260 | v = Vector2(v1)
261 | v.from_polar((3.606, 56.310))
262 | assert _rd(v.x) == 2.0 and _rd(v.y) == 3.0
263 |
264 |
265 | def test_vector_dot():
266 | Vector2 = pg.Vector2
267 | v1 = Vector2(2.0, 3.0)
268 | v2 = Vector2(2.0, 0.0)
269 | v3 = Vector2(0.0, 3.0)
270 | v4 = Vector2(-6.0, -8.0)
271 | v5 = Vector2(3.0, 4.0)
272 | assert v1.dot(v2) == 4.0
273 | assert v1.dot(v3) == 9.0
274 | assert v1.dot(v4) == -36.0
275 | assert v1.dot(v5) == 18.0
276 | if not (env['pyjs_opt'] and not env['pyjs_attr']):
277 | assert (v1 * v2) == 4.0
278 | assert (v1 * v3) == 9.0
279 | assert (v1 * v4) == -36.0
280 | assert (v1 * v5) == 18.0
281 |
282 |
283 | def test_vector_cross():
284 | Vector2 = pg.Vector2
285 | v1 = Vector2(2.0, 3.0)
286 | v2 = Vector2(2.0, 0.0)
287 | v3 = Vector2(0.0, 3.0)
288 | v4 = Vector2(-6.0, -8.0)
289 | v5 = Vector2(3.0, 4.0)
290 | assert v1.cross(v2) == -6.0
291 | assert v1.cross(v3) == 6.0
292 | assert v1.cross(v4) == 2.0
293 | assert v1.cross(v5) == -1.0
294 |
295 |
296 | def test_vector_lerp():
297 | Vector2 = pg.Vector2
298 | v1 = Vector2(2.0, 3.0)
299 | v2 = Vector2(6.0, 8.0)
300 | v = v1.lerp(v2, 0.0)
301 | assert _rd(v.x) == 2.0 and _rd(v.y) == 3.0
302 | v = v1.lerp(v2, 0.1)
303 | assert _rd(v.x) == 2.4 and _rd(v.y) == 3.5
304 | v = v1.lerp(v2, 0.5)
305 | assert _rd(v.x) == 4.0 and _rd(v.y) == 5.5
306 | v = v1.lerp(v2, 0.9)
307 | assert _rd(v.x) == 5.6 and _rd(v.y) == 7.5
308 | v = v1.lerp(v2, 1.0)
309 | assert _rd(v.x) == 6.0 and _rd(v.y) == 8.0
310 | v = v1.slerp(v2, 0.0)
311 | assert _rd(v.x) == 2.0 and _rd(v.y) == 3.0
312 | v = v1.slerp(v2, 0.1)
313 | assert _rd(v.x) == 2.374 and _rd(v.y) == 3.519
314 | v = v1.slerp(v2, 0.5)
315 | assert _rd(v.x) == 3.929 and _rd(v.y) == 5.553
316 | v = v1.slerp(v2, 0.9)
317 | assert _rd(v.x) == 5.575 and _rd(v.y) == 7.519
318 | v = v1.slerp(v2, 1.0)
319 | assert _rd(v.x) == 6.0 and _rd(v.y) == 8.0
320 | v = v1.slerp(v2, -0.5)
321 | assert _rd(v.x) == -3.929 and _rd(v.y) == -5.553
322 | v = v1.slerp(v2, -1.0)
323 | assert _rd(v.x) == 6.0 and _rd(v.y) == 8.0
324 | v = v1.slerp(v1, 0.5)
325 | assert _rd(v.x) == 2.0 and _rd(v.y) == 3.0
326 | if not (env['pyjs_opt'] and not env['pyjs_attr']):
327 | v = v1.slerp(v1*2.0, 0.5)
328 | assert _rd(v.x) == 3.0 and _rd(v.y) == 4.5
329 | v = v1.slerp(Vector2(-6.0, -8.0), 0.5)
330 | assert _rd(v.x) == -5.553 and _rd(v.y) == 3.929
331 | v = Vector2(5.0, 5.0).slerp(Vector2(-5.0, 5.0), 0.2)
332 | assert _rd(v.x) == 3.210 and _rd(v.y) == 6.300
333 |
334 |
--------------------------------------------------------------------------------